aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorandroid-build-team Robot <android-build-team-robot@google.com>2020-04-28 20:21:33 +0000
committerandroid-build-team Robot <android-build-team-robot@google.com>2020-04-28 20:21:33 +0000
commit36e2a5887fe658e57741eb887194197e19d22242 (patch)
treedcd2a4ebf55e7c6f692cbed60509054eeaa46d98
parentdb74d7937f3a9503f0e2590ec24c3bcfbf259ce0 (diff)
parentc0736f6c497f1682a654a8bc1d72ff506afea72e (diff)
downloadike-android12-mainline-tzdata-release.tar.gz
Change-Id: I9e05059edc6da35c519bdf4931a51c742d377b9e
-rw-r--r--Android.bp23
-rw-r--r--Android.mk30
-rw-r--r--OWNERS2
-rw-r--r--TEST_MAPPING5
-rw-r--r--src/java/android/net/eap/EapSessionConfig.java234
-rw-r--r--src/java/android/net/ipsec/ike/ChildSaProposal.java171
-rw-r--r--src/java/android/net/ipsec/ike/ChildSessionCallback.java66
-rw-r--r--src/java/android/net/ipsec/ike/ChildSessionConfiguration.java130
-rw-r--r--src/java/android/net/ipsec/ike/ChildSessionOptions.java119
-rw-r--r--src/java/android/net/ipsec/ike/IkeFqdnIdentification.java76
-rw-r--r--src/java/android/net/ipsec/ike/IkeIdentification.java80
-rw-r--r--src/java/android/net/ipsec/ike/IkeIpv4AddrIdentification.java78
-rw-r--r--src/java/android/net/ipsec/ike/IkeIpv6AddrIdentification.java78
-rw-r--r--src/java/android/net/ipsec/ike/IkeKeyIdIdentification.java63
-rw-r--r--src/java/android/net/ipsec/ike/IkeManager.java94
-rw-r--r--src/java/android/net/ipsec/ike/IkeRfc822AddrIdentification.java76
-rw-r--r--src/java/android/net/ipsec/ike/IkeSaProposal.java209
-rw-r--r--src/java/android/net/ipsec/ike/IkeSession.java190
-rw-r--r--src/java/android/net/ipsec/ike/IkeSessionCallback.java57
-rw-r--r--src/java/android/net/ipsec/ike/IkeSessionConfiguration.java59
-rw-r--r--src/java/android/net/ipsec/ike/IkeSessionOptions.java416
-rw-r--r--src/java/android/net/ipsec/ike/SaProposal.java386
-rw-r--r--src/java/android/net/ipsec/ike/TransportModeChildSessionOptions.java67
-rw-r--r--src/java/android/net/ipsec/ike/TunnelModeChildSessionOptions.java260
-rw-r--r--src/java/android/net/ipsec/ike/exceptions/IkeException.java47
-rw-r--r--src/java/android/net/ipsec/ike/exceptions/IkeInternalException.java43
-rw-r--r--src/java/android/net/ipsec/ike/exceptions/IkeProtocolException.java182
-rw-r--r--src/java/com/android/ike/ikev2/ChildSessionOptions.java (renamed from tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapMsChapV2AwaitingEapFailureStateTest.java)18
-rw-r--r--src/java/com/android/ike/ikev2/ChildSessionStateMachine.java198
-rw-r--r--src/java/com/android/ike/ikev2/ChildSessionStateMachineFactory.java (renamed from src/java/com/android/internal/net/ipsec/ike/ChildSessionStateMachineFactory.java)44
-rw-r--r--src/java/com/android/ike/ikev2/IkeDhParams.java (renamed from src/java/com/android/internal/net/ipsec/ike/IkeDhParams.java)2
-rw-r--r--src/java/com/android/ike/ikev2/IkeIdentification.java196
-rw-r--r--src/java/com/android/ike/ikev2/IkeSessionOptions.java122
-rw-r--r--src/java/com/android/ike/ikev2/IkeSessionStateMachine.java952
-rw-r--r--src/java/com/android/ike/ikev2/IkeSocket.java (renamed from src/java/com/android/internal/net/ipsec/ike/IkeSocket.java)73
-rw-r--r--src/java/com/android/ike/ikev2/IkeTrafficSelector.java (renamed from src/java/android/net/ipsec/ike/IkeTrafficSelector.java)192
-rw-r--r--src/java/com/android/ike/ikev2/SaProposal.java597
-rw-r--r--src/java/com/android/ike/ikev2/SaRecord.java276
-rw-r--r--src/java/com/android/ike/ikev2/exceptions/AuthenticationFailedException.java (renamed from src/java/com/android/internal/net/ipsec/ike/exceptions/AuthenticationFailedException.java)28
-rw-r--r--src/java/com/android/ike/ikev2/exceptions/IkeException.java63
-rw-r--r--src/java/com/android/ike/ikev2/exceptions/InvalidMajorVersionException.java (renamed from src/java/com/android/internal/net/ipsec/ike/exceptions/InvalidMajorVersionException.java)36
-rw-r--r--src/java/com/android/ike/ikev2/exceptions/InvalidSyntaxException.java (renamed from src/java/com/android/internal/net/ipsec/ike/exceptions/InvalidSyntaxException.java)36
-rw-r--r--src/java/com/android/ike/ikev2/exceptions/NoValidProposalChosenException.java (renamed from src/java/com/android/internal/net/ipsec/ike/exceptions/NoValidProposalChosenException.java)36
-rw-r--r--src/java/com/android/ike/ikev2/exceptions/UnsupportedCriticalPayloadException.java44
-rw-r--r--src/java/com/android/ike/ikev2/message/IkeAuthDigitalSignPayload.java158
-rw-r--r--src/java/com/android/ike/ikev2/message/IkeAuthPayload.java (renamed from src/java/com/android/internal/net/ipsec/ike/message/IkeAuthPayload.java)43
-rw-r--r--src/java/com/android/ike/ikev2/message/IkeAuthPskPayload.java (renamed from src/java/com/android/internal/net/ipsec/ike/message/IkeAuthPskPayload.java)41
-rw-r--r--src/java/com/android/ike/ikev2/message/IkeCertPayload.java82
-rw-r--r--src/java/com/android/ike/ikev2/message/IkeCertX509CertPayload.java (renamed from src/java/com/android/internal/net/ipsec/ike/message/IkeCertX509CertPayload.java)18
-rw-r--r--src/java/com/android/ike/ikev2/message/IkeDeletePayload.java (renamed from src/java/com/android/internal/net/ipsec/ike/message/IkeDeletePayload.java)78
-rw-r--r--src/java/com/android/ike/ikev2/message/IkeEncryptedPayloadBody.java266
-rw-r--r--src/java/com/android/ike/ikev2/message/IkeHeader.java (renamed from src/java/com/android/internal/net/ipsec/ike/message/IkeHeader.java)61
-rw-r--r--src/java/com/android/ike/ikev2/message/IkeIdPayload.java (renamed from src/java/com/android/internal/net/ipsec/ike/message/IkeIdPayload.java)62
-rw-r--r--src/java/com/android/ike/ikev2/message/IkeKePayload.java (renamed from src/java/com/android/internal/net/ipsec/ike/message/IkeKePayload.java)59
-rw-r--r--src/java/com/android/ike/ikev2/message/IkeMessage.java443
-rw-r--r--src/java/com/android/ike/ikev2/message/IkeNoncePayload.java (renamed from src/java/com/android/internal/net/ipsec/ike/message/IkeNoncePayload.java)11
-rw-r--r--src/java/com/android/ike/ikev2/message/IkeNotifyPayload.java274
-rw-r--r--src/java/com/android/ike/ikev2/message/IkePayload.java (renamed from src/java/com/android/internal/net/ipsec/ike/message/IkePayload.java)86
-rw-r--r--src/java/com/android/ike/ikev2/message/IkePayloadFactory.java (renamed from src/java/com/android/internal/net/ipsec/ike/message/IkePayloadFactory.java)92
-rw-r--r--src/java/com/android/ike/ikev2/message/IkeSaPayload.java (renamed from src/java/com/android/internal/net/ipsec/ike/message/IkeSaPayload.java)759
-rw-r--r--src/java/com/android/ike/ikev2/message/IkeSkPayload.java142
-rw-r--r--src/java/com/android/ike/ikev2/message/IkeTsPayload.java100
-rw-r--r--src/java/com/android/ike/ikev2/message/IkeUnsupportedPayload.java (renamed from src/java/com/android/internal/net/ipsec/ike/message/IkeUnsupportedPayload.java)5
-rw-r--r--src/java/com/android/ike/ikev2/message/IkeVendorPayload.java (renamed from src/java/com/android/internal/net/ipsec/ike/message/IkeVendorPayload.java)4
-rw-r--r--src/java/com/android/ike/ikev2/utils/BigIntegerUtils.java (renamed from src/java/com/android/internal/net/utils/BigIntegerUtils.java)2
-rw-r--r--src/java/com/android/internal/net/crypto/KeyGenerationUtils.java81
-rw-r--r--src/java/com/android/internal/net/eap/EapAuthenticator.java177
-rw-r--r--src/java/com/android/internal/net/eap/EapResult.java112
-rw-r--r--src/java/com/android/internal/net/eap/IEapCallback.java56
-rw-r--r--src/java/com/android/internal/net/eap/crypto/Fips186_2Prf.java111
-rw-r--r--src/java/com/android/internal/net/eap/crypto/HmacSha256ByteSigner.java56
-rw-r--r--src/java/com/android/internal/net/eap/crypto/ParityBitUtil.java81
-rw-r--r--src/java/com/android/internal/net/eap/exceptions/EapInvalidPacketLengthException.java47
-rw-r--r--src/java/com/android/internal/net/eap/exceptions/EapInvalidRequestException.java44
-rw-r--r--src/java/com/android/internal/net/eap/exceptions/EapSilentException.java49
-rw-r--r--src/java/com/android/internal/net/eap/exceptions/InvalidEapCodeException.java36
-rw-r--r--src/java/com/android/internal/net/eap/exceptions/InvalidEapResponseException.java34
-rw-r--r--src/java/com/android/internal/net/eap/exceptions/UnsupportedEapTypeException.java53
-rw-r--r--src/java/com/android/internal/net/eap/exceptions/mschapv2/EapMsChapV2ParsingException.java42
-rw-r--r--src/java/com/android/internal/net/eap/exceptions/simaka/EapAkaInvalidAuthenticationResponse.java44
-rw-r--r--src/java/com/android/internal/net/eap/exceptions/simaka/EapSimAkaAuthenticationFailureException.java44
-rw-r--r--src/java/com/android/internal/net/eap/exceptions/simaka/EapSimAkaIdentityUnavailableException.java46
-rw-r--r--src/java/com/android/internal/net/eap/exceptions/simaka/EapSimAkaInvalidAtPaddingException.java51
-rw-r--r--src/java/com/android/internal/net/eap/exceptions/simaka/EapSimAkaInvalidAttributeException.java46
-rw-r--r--src/java/com/android/internal/net/eap/exceptions/simaka/EapSimAkaInvalidLengthException.java46
-rw-r--r--src/java/com/android/internal/net/eap/exceptions/simaka/EapSimAkaUnsupportedAttributeException.java51
-rw-r--r--src/java/com/android/internal/net/eap/exceptions/simaka/EapSimInvalidAtRandException.java49
-rw-r--r--src/java/com/android/internal/net/eap/exceptions/simaka/EapSimInvalidTypeDataException.java44
-rw-r--r--src/java/com/android/internal/net/eap/message/EapData.java193
-rw-r--r--src/java/com/android/internal/net/eap/message/EapMessage.java252
-rw-r--r--src/java/com/android/internal/net/eap/message/mschapv2/EapMsChapV2TypeData.java600
-rw-r--r--src/java/com/android/internal/net/eap/message/simaka/EapAkaAttributeFactory.java95
-rw-r--r--src/java/com/android/internal/net/eap/message/simaka/EapAkaPrimeAttributeFactory.java77
-rw-r--r--src/java/com/android/internal/net/eap/message/simaka/EapAkaPrimeTypeData.java95
-rw-r--r--src/java/com/android/internal/net/eap/message/simaka/EapAkaTypeData.java137
-rw-r--r--src/java/com/android/internal/net/eap/message/simaka/EapSimAkaAttribute.java1162
-rw-r--r--src/java/com/android/internal/net/eap/message/simaka/EapSimAkaAttributeFactory.java130
-rw-r--r--src/java/com/android/internal/net/eap/message/simaka/EapSimAkaTypeData.java205
-rw-r--r--src/java/com/android/internal/net/eap/message/simaka/EapSimAttributeFactory.java87
-rw-r--r--src/java/com/android/internal/net/eap/message/simaka/EapSimTypeData.java125
-rw-r--r--src/java/com/android/internal/net/eap/statemachine/EapAkaMethodStateMachine.java612
-rw-r--r--src/java/com/android/internal/net/eap/statemachine/EapAkaPrimeMethodStateMachine.java336
-rw-r--r--src/java/com/android/internal/net/eap/statemachine/EapMethodStateMachine.java105
-rw-r--r--src/java/com/android/internal/net/eap/statemachine/EapMsChapV2MethodStateMachine.java673
-rw-r--r--src/java/com/android/internal/net/eap/statemachine/EapSimAkaMethodStateMachine.java355
-rw-r--r--src/java/com/android/internal/net/eap/statemachine/EapSimMethodStateMachine.java604
-rw-r--r--src/java/com/android/internal/net/eap/statemachine/EapStateMachine.java371
-rw-r--r--src/java/com/android/internal/net/ipsec/ike/AbstractSessionStateMachine.java199
-rw-r--r--src/java/com/android/internal/net/ipsec/ike/ChildSessionStateMachine.java2268
-rw-r--r--src/java/com/android/internal/net/ipsec/ike/IkeEapAuthenticatorFactory.java40
-rw-r--r--src/java/com/android/internal/net/ipsec/ike/IkeLocalRequestScheduler.java119
-rw-r--r--src/java/com/android/internal/net/ipsec/ike/IkeSessionStateMachine.java4235
-rw-r--r--src/java/com/android/internal/net/ipsec/ike/SaRecord.java1098
-rw-r--r--src/java/com/android/internal/net/ipsec/ike/crypto/IkeCipher.java178
-rw-r--r--src/java/com/android/internal/net/ipsec/ike/crypto/IkeCombinedModeCipher.java209
-rw-r--r--src/java/com/android/internal/net/ipsec/ike/crypto/IkeCrypto.java57
-rw-r--r--src/java/com/android/internal/net/ipsec/ike/crypto/IkeMac.java93
-rw-r--r--src/java/com/android/internal/net/ipsec/ike/crypto/IkeMacIntegrity.java189
-rw-r--r--src/java/com/android/internal/net/ipsec/ike/crypto/IkeMacPrf.java152
-rw-r--r--src/java/com/android/internal/net/ipsec/ike/crypto/IkeNormalModeCipher.java124
-rw-r--r--src/java/com/android/internal/net/ipsec/ike/exceptions/InvalidKeException.java66
-rw-r--r--src/java/com/android/internal/net/ipsec/ike/exceptions/InvalidMessageIdException.java68
-rw-r--r--src/java/com/android/internal/net/ipsec/ike/exceptions/TemporaryFailureException.java54
-rw-r--r--src/java/com/android/internal/net/ipsec/ike/exceptions/TsUnacceptableException.java50
-rw-r--r--src/java/com/android/internal/net/ipsec/ike/exceptions/UnrecognizedIkeProtocolException.java41
-rw-r--r--src/java/com/android/internal/net/ipsec/ike/exceptions/UnsupportedCriticalPayloadException.java78
-rw-r--r--src/java/com/android/internal/net/ipsec/ike/message/IkeAuthDigitalSignPayload.java265
-rw-r--r--src/java/com/android/internal/net/ipsec/ike/message/IkeCertPayload.java175
-rw-r--r--src/java/com/android/internal/net/ipsec/ike/message/IkeConfigPayload.java767
-rw-r--r--src/java/com/android/internal/net/ipsec/ike/message/IkeEapPayload.java93
-rw-r--r--src/java/com/android/internal/net/ipsec/ike/message/IkeEncryptedPayloadBody.java390
-rw-r--r--src/java/com/android/internal/net/ipsec/ike/message/IkeInformationalPayload.java28
-rw-r--r--src/java/com/android/internal/net/ipsec/ike/message/IkeMessage.java981
-rw-r--r--src/java/com/android/internal/net/ipsec/ike/message/IkeNotifyPayload.java462
-rw-r--r--src/java/com/android/internal/net/ipsec/ike/message/IkeSkPayload.java207
-rw-r--r--src/java/com/android/internal/net/ipsec/ike/message/IkeSkfPayload.java175
-rw-r--r--src/java/com/android/internal/net/ipsec/ike/message/IkeTsPayload.java160
-rw-r--r--src/java/com/android/internal/net/ipsec/ike/utils/FdEventsReader.java270
-rw-r--r--src/java/com/android/internal/net/ipsec/ike/utils/PacketReader.java66
-rw-r--r--src/java/com/android/internal/net/ipsec/ike/utils/Retransmitter.java139
-rw-r--r--src/java/com/android/internal/net/utils/Log.java284
-rw-r--r--src/java/com/android/internal/net/utils/SimpleStateMachine.java85
-rw-r--r--tests/Android.mk18
-rw-r--r--tests/iketests/Android.bp39
-rw-r--r--tests/iketests/Android.mk35
-rw-r--r--tests/iketests/AndroidManifest.xml9
-rw-r--r--tests/iketests/assets/key/end-cert-key-a.key10
-rw-r--r--tests/iketests/assets/pem/end-cert-a.pem20
-rw-r--r--tests/iketests/assets/pem/end-cert-b.pem20
-rw-r--r--tests/iketests/assets/pem/end-cert-small.pem12
-rw-r--r--tests/iketests/assets/pem/intermediate-ca-b-one.pem21
-rw-r--r--tests/iketests/assets/pem/intermediate-ca-b-two.pem21
-rw-r--r--tests/iketests/assets/pem/self-signed-ca-a.pem20
-rw-r--r--tests/iketests/assets/pem/self-signed-ca-b.pem20
-rw-r--r--tests/iketests/assets/pem/self-signed-ca-small.pem12
-rw-r--r--tests/iketests/src/java/android/net/eap/EapSessionConfigTest.java115
-rw-r--r--tests/iketests/src/java/android/net/ipsec/ike/ChildSessionConfigurationTest.java164
-rw-r--r--tests/iketests/src/java/android/net/ipsec/ike/ChildSessionOptionsTest.java54
-rw-r--r--tests/iketests/src/java/android/net/ipsec/ike/IkeSessionOptionsTest.java258
-rw-r--r--tests/iketests/src/java/android/net/ipsec/ike/IkeSessionTest.java162
-rw-r--r--tests/iketests/src/java/android/net/ipsec/ike/TunnelModeChildSessionOptionsTest.java229
-rw-r--r--tests/iketests/src/java/android/net/ipsec/ike/exceptions/IkeProtocolExceptionTest.java58
-rw-r--r--tests/iketests/src/java/com/android/ike/ikev2/ChildSessionStateMachineTest.java139
-rw-r--r--tests/iketests/src/java/com/android/ike/ikev2/IkeSessionOptionsTest.java103
-rw-r--r--tests/iketests/src/java/com/android/ike/ikev2/IkeSessionStateMachineTest.java401
-rw-r--r--tests/iketests/src/java/com/android/ike/ikev2/IkeSocketTest.java (renamed from tests/iketests/src/java/com/android/internal/net/ipsec/ike/IkeSocketTest.java)45
-rw-r--r--tests/iketests/src/java/com/android/ike/ikev2/IkeTrafficSelectorTest.java (renamed from tests/iketests/src/java/android/net/ipsec/ike/IkeTrafficSelectorTest.java)144
-rw-r--r--tests/iketests/src/java/com/android/ike/ikev2/SaProposalTest.java (renamed from tests/iketests/src/java/android/net/ipsec/ike/SaProposalTest.java)146
-rw-r--r--tests/iketests/src/java/com/android/ike/ikev2/SaRecordTest.java (renamed from tests/iketests/src/java/com/android/internal/net/ipsec/ike/crypto/IkeMacPrfTest.java)75
-rw-r--r--tests/iketests/src/java/com/android/ike/ikev2/message/IkeAuthDigitalSignPayloadTest.java50
-rw-r--r--tests/iketests/src/java/com/android/ike/ikev2/message/IkeAuthPayloadTest.java (renamed from tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeAuthPayloadTest.java)40
-rw-r--r--tests/iketests/src/java/com/android/ike/ikev2/message/IkeAuthPskPayloadTest.java (renamed from tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeAuthPskPayloadTest.java)34
-rw-r--r--tests/iketests/src/java/com/android/ike/ikev2/message/IkeCertX509CertPayloadTest.java (renamed from tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeCertX509CertPayloadTest.java)5
-rw-r--r--tests/iketests/src/java/com/android/ike/ikev2/message/IkeDeletePayloadTest.java144
-rw-r--r--tests/iketests/src/java/com/android/ike/ikev2/message/IkeEncryptedPayloadBodyTest.java232
-rw-r--r--tests/iketests/src/java/com/android/ike/ikev2/message/IkeHeaderTest.java (renamed from tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeHeaderTest.java)39
-rw-r--r--tests/iketests/src/java/com/android/ike/ikev2/message/IkeIdPayloadTest.java113
-rw-r--r--tests/iketests/src/java/com/android/ike/ikev2/message/IkeKePayloadTest.java (renamed from tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeKePayloadTest.java)49
-rw-r--r--tests/iketests/src/java/com/android/ike/ikev2/message/IkeMessageTest.java218
-rw-r--r--tests/iketests/src/java/com/android/ike/ikev2/message/IkeNoncePayloadTest.java (renamed from tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeNoncePayloadTest.java)4
-rw-r--r--tests/iketests/src/java/com/android/ike/ikev2/message/IkeNotifyPayloadTest.java107
-rw-r--r--tests/iketests/src/java/com/android/ike/ikev2/message/IkeSaPayloadTest.java (renamed from tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeSaPayloadTest.java)309
-rw-r--r--tests/iketests/src/java/com/android/ike/ikev2/message/IkeSkPayloadTest.java (renamed from tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeSkPayloadTest.java)47
-rw-r--r--tests/iketests/src/java/com/android/ike/ikev2/message/IkeTsPayloadTest.java46
-rw-r--r--tests/iketests/src/java/com/android/ike/ikev2/message/TestUtils.java52
-rw-r--r--tests/iketests/src/java/com/android/ike/ikev2/utils/BigIntegerUtilsTest.java (renamed from tests/iketests/src/java/com/android/internal/net/utils/BigIntegerUtilsTest.java)2
-rw-r--r--tests/iketests/src/java/com/android/internal/net/TestUtils.java113
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/EapAkaPrimeTest.java382
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/EapAkaTest.java332
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/EapAuthenticatorTest.java256
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/EapErrorTest.java33
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/EapMethodEndToEndTest.java91
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/EapMsChapV2Test.java173
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/EapResponseTest.java70
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/EapSimTest.java298
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/EapSuccessTest.java54
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/EapTestUtils.java56
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/crypto/Fips186_2PrfTest.java67
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/crypto/HmacSha256ByteSignerTest.java93
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/crypto/ParityBitUtilTest.java65
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/message/EapDataTest.java95
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/message/EapMessageTest.java182
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/message/EapTestMessageDefinitions.java327
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/message/mschapv2/EapMsChapV2ChallengeRequestTest.java120
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/message/mschapv2/EapMsChapV2ChallengeResponseTest.java109
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/message/mschapv2/EapMsChapV2FailureRequestTest.java172
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/message/mschapv2/EapMsChapV2FailureResponseTest.java43
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/message/mschapv2/EapMsChapV2PacketDefinitions.java284
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/message/mschapv2/EapMsChapV2SuccessRequestTest.java187
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/message/mschapv2/EapMsChapV2SuccessResponseTest.java43
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/message/mschapv2/EapMsChapV2TypeDataTest.java154
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/message/simaka/EapAkaPrimeTypeDataTest.java142
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/message/simaka/EapAkaTypeDataTest.java176
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/message/simaka/EapSimAkaAttributeFactoryTest.java94
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/message/simaka/EapSimTypeDataTest.java176
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtAutnTest.java77
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtAutsTest.java77
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtBiddingTest.java99
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtClientErrorCodeTest.java83
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtCounterTest.java122
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtIdReqTest.java149
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtIdentityTest.java85
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtKdfInputTest.java78
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtKdfTest.java78
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtMacTest.java110
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtNonceMtTest.java91
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtNonceSTest.java92
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtNotificationTest.java109
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtPaddingTest.java81
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtRandAkaTest.java77
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtRandSimTest.java101
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtResTest.java117
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtSelectedVersionTest.java83
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtVersionListTest.java85
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/EapSimAkaAttributeTest.java53
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/EapTestAttributeDefinitions.java120
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/statemachine/CreatedStateTest.java79
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapAkaChallengeStateTest.java430
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapAkaCreatedStateTest.java110
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapAkaIdentityStateTest.java161
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapAkaMethodStateMachineTest.java152
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapAkaPrimeChallengeStateTest.java354
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapAkaPrimeCreatedStateTest.java85
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapAkaPrimeIdentityStateTest.java96
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapAkaPrimeMethodStateMachineTest.java74
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapAkaPrimeStateTest.java100
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapAkaPrimeTest.java78
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapAkaStateTest.java147
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapMsChapV2AwaitingEapSuccessStateTest.java54
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapMsChapV2ChallengeStateTest.java104
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapMsChapV2CreatedStateTest.java80
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapMsChapV2MethodStateMachineTest.java182
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapMsChapV2StateTest.java100
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapMsChapV2ValidateAuthenticatorStateTest.java173
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapSimAkaMethodStateMachineTest.java475
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapSimChallengeStateTest.java356
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapSimCreatedStateTest.java111
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapSimMethodStateMachineTest.java152
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapSimStartStateTest.java254
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapSimStateTest.java149
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapStateMachineTest.java81
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapStateTest.java128
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/statemachine/IdentityStateTest.java101
-rw-r--r--tests/iketests/src/java/com/android/internal/net/eap/statemachine/MethodStateTest.java204
-rw-r--r--tests/iketests/src/java/com/android/internal/net/ipsec/ike/ChildSessionStateMachineTest.java1646
-rw-r--r--tests/iketests/src/java/com/android/internal/net/ipsec/ike/IkeLocalRequestSchedulerTest.java130
-rw-r--r--tests/iketests/src/java/com/android/internal/net/ipsec/ike/IkeSessionStateMachineTest.java4036
-rw-r--r--tests/iketests/src/java/com/android/internal/net/ipsec/ike/SaRecordTest.java336
-rw-r--r--tests/iketests/src/java/com/android/internal/net/ipsec/ike/crypto/IkeCombinedModeCipherTest.java160
-rw-r--r--tests/iketests/src/java/com/android/internal/net/ipsec/ike/crypto/IkeMacIntegrityTest.java128
-rw-r--r--tests/iketests/src/java/com/android/internal/net/ipsec/ike/crypto/IkeNormalModeCipherTest.java164
-rw-r--r--tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeAuthDigitalSignPayloadTest.java161
-rw-r--r--tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeCertPayloadTest.java154
-rw-r--r--tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeConfigPayloadTest.java631
-rw-r--r--tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeDeletePayloadTest.java264
-rw-r--r--tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeEapPayloadTest.java68
-rw-r--r--tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeEncryptedPayloadBodyTest.java489
-rw-r--r--tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeIdPayloadTest.java210
-rw-r--r--tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeMessageTest.java935
-rw-r--r--tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeNotifyPayloadTest.java249
-rw-r--r--tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeSkfPayloadTest.java201
-rw-r--r--tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeTestUtils.java71
-rw-r--r--tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeTsPayloadTest.java143
-rw-r--r--tests/iketests/src/java/com/android/internal/net/ipsec/ike/testutils/CertUtils.java63
-rw-r--r--tests/iketests/src/java/com/android/internal/net/ipsec/ike/testutils/MockIpSecTestUtils.java91
-rw-r--r--tests/iketests/src/java/com/android/internal/net/ipsec/ike/utils/RetransmitterTest.java129
-rw-r--r--tests/iketests/src/java/com/android/internal/net/utils/LogTest.java60
-rw-r--r--tests/iketests/src/java/com/android/internal/net/utils/SimpleStateMachineTest.java96
288 files changed, 6245 insertions, 49554 deletions
diff --git a/Android.bp b/Android.bp
deleted file mode 100644
index 8d2d16ff..00000000
--- a/Android.bp
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2018 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.
-
-java_library {
- name: "ike",
- installable: true,
-
- aidl: {
- local_include_dirs: ["src/java"],
- },
- srcs: ["src/java/**/*.java"],
-}
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 00000000..14e9e9ee
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,30 @@
+# Copyright 2018 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.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/src/java
+LOCAL_SRC_FILES := \
+ $(call all-java-files-under, src/java)
+
+LOCAL_JAVA_LIBRARIES := bouncycastle NetworkStackBase
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := ike
+
+include $(BUILD_JAVA_LIBRARY)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/OWNERS b/OWNERS
index c0dd63c9..19fe35d7 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,5 +1,5 @@
benedictwong@google.com
-ckesting@google.com
+ek@google.com
evitayan@google.com
jchalard@google.com
lorenzo@google.com
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 71d96ff1..6534d884 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -3,10 +3,5 @@
{
"name": "FrameworksIkeTests"
}
- ],
- "postsubmit": [
- {
- "name": "FrameworksIkeTests"
- }
]
} \ No newline at end of file
diff --git a/src/java/android/net/eap/EapSessionConfig.java b/src/java/android/net/eap/EapSessionConfig.java
deleted file mode 100644
index a31a0fdf..00000000
--- a/src/java/android/net/eap/EapSessionConfig.java
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * Copyright (C) 2019 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 android.net.eap;
-
-import static com.android.internal.net.eap.message.EapData.EAP_TYPE_AKA;
-import static com.android.internal.net.eap.message.EapData.EAP_TYPE_AKA_PRIME;
-import static com.android.internal.net.eap.message.EapData.EAP_TYPE_MSCHAP_V2;
-import static com.android.internal.net.eap.message.EapData.EAP_TYPE_SIM;
-
-import android.telephony.TelephonyManager.UiccAppType;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.net.eap.message.EapData.EapMethod;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * EapSessionConfig represents a container for EAP method configs to be used within an IKEv2
- * session.
- *
- * <p>The EAP authentication server decides which EAP method is used, so clients are encouraged to
- * provide configs for several EAP methods.
- */
-public final class EapSessionConfig {
- @VisibleForTesting
- static final byte[] DEFAULT_IDENTITY = new byte[0];
-
- // IANA -> EapMethodConfig for that method
- public final Map<Integer, EapMethodConfig> eapConfigs;
- public final byte[] eapIdentity;
-
- @VisibleForTesting
- public EapSessionConfig(Map<Integer, EapMethodConfig> eapConfigs, byte[] eapIdentity) {
- this.eapConfigs = Collections.unmodifiableMap(eapConfigs);
- this.eapIdentity = eapIdentity;
- }
-
- /** This class can be used to incrementally construct an EapSessionConfig. */
- public static final class Builder {
- private final Map<Integer, EapMethodConfig> mEapConfigs;
- private byte[] mEapIdentity;
-
- /**
- * Constructs and returns a new Builder for constructing an EapSessionConfig.
- */
- public Builder() {
- mEapConfigs = new HashMap<>();
- mEapIdentity = DEFAULT_IDENTITY;
- }
-
- /**
- * Sets the client's EAP Identity.
- *
- * @param eapIdentity byte[] representing the client's EAP Identity
- * @return Builder this, to facilitate chaining.
- */
- public Builder setEapIdentity(byte[] eapIdentity) {
- this.mEapIdentity = eapIdentity.clone();
- return this;
- }
-
- /**
- * Sets the configuration for EAP SIM.
- *
- * @param subId int the client's subId to be authenticated
- * @param apptype the {@link UiccAppType} apptype to be used for authentication
- * @return Builder this, to facilitate chaining.
- */
- public Builder setEapSimConfig(int subId, @UiccAppType int apptype) {
- mEapConfigs.put(EAP_TYPE_SIM, new EapSimConfig(subId, apptype));
- return this;
- }
-
- /**
- * Sets the configuration for EAP AKA.
- *
- * @param subId int the client's subId to be authenticated
- * @param apptype the {@link UiccAppType} apptype to be used for authentication
- * @return Builder this, to facilitate chaining
- */
- public Builder setEapAkaConfig(int subId, @UiccAppType int apptype) {
- mEapConfigs.put(EAP_TYPE_AKA, new EapAkaConfig(subId, apptype));
- return this;
- }
-
- /**
- * Sets the configuration for EAP AKA'.
- *
- * @param subId int the client's subId to be authenticated
- * @param apptype the {@link UiccAppType} apptype to be used for authentication
- * @param networkName String the network name to be used for authentication. The String must
- * be a UTF-8 String value
- * @param allowMismatchedNetworkNames indicates whether the EAP library can ignore potential
- * mismatches between the given network name and that received in an EAP-AKA' session.
- * If false, mismatched network names will be handled as an Authentication Reject
- * message.
- * @return Builder this, to facilitate chaining
- */
- public Builder setEapAkaPrimeConfig(
- int subId,
- @UiccAppType int apptype,
- String networkName,
- boolean allowMismatchedNetworkNames) {
- mEapConfigs.put(
- EAP_TYPE_AKA_PRIME,
- new EapAkaPrimeConfig(
- subId, apptype, networkName, allowMismatchedNetworkNames));
- return this;
- }
-
- /**
- * Sets the configuration for EAP MSCHAPv2.
- *
- * @param username String the client account's username to be authenticated
- * @param password String the client account's password to be authenticated
- * @return Builder this, to faciliate chaining
- */
- public Builder setEapMsChapV2Config(String username, String password) {
- mEapConfigs.put(EAP_TYPE_MSCHAP_V2, new EapMsChapV2Config(username, password));
- return this;
- }
-
- /**
- * Constructs and returns an EapSessionConfig with the configurations applied to this
- * Builder.
- *
- * @return the EapSessionConfig constructed by this Builder
- * @throws IllegalStateException iff no EAP methods have been configured
- */
- public EapSessionConfig build() {
- if (mEapConfigs.isEmpty()) {
- throw new IllegalStateException("Must have at least one EAP method configured");
- }
-
- return new EapSessionConfig(mEapConfigs, mEapIdentity);
- }
- }
-
- /** EapMethodConfig represents a generic EAP method configuration. */
- public abstract static class EapMethodConfig {
- @EapMethod public final int methodType;
-
- protected EapMethodConfig(@EapMethod int methodType) {
- this.methodType = methodType;
- }
- }
-
- /**
- * EapUiccConfig represents the configs needed for EAP methods that rely on UICC cards for
- * authentication.
- */
- public abstract static class EapUiccConfig extends EapMethodConfig {
- public final int subId;
- public final int apptype;
-
- private EapUiccConfig(@EapMethod int methodType, int subId, @UiccAppType int apptype) {
- super(methodType);
- this.subId = subId;
- this.apptype = apptype;
- }
- }
-
- /**
- * EapSimConfig represents the configs needed for an EAP SIM session.
- */
- public static class EapSimConfig extends EapUiccConfig {
- @VisibleForTesting
- public EapSimConfig(int subId, @UiccAppType int apptype) {
- super(EAP_TYPE_SIM, subId, apptype);
- }
- }
-
- /**
- * EapAkaConfig represents the configs needed for an EAP AKA session.
- */
- public static class EapAkaConfig extends EapUiccConfig {
- @VisibleForTesting
- public EapAkaConfig(int subId, @UiccAppType int apptype) {
- super(EAP_TYPE_AKA, subId, apptype);
- }
- }
-
- /**
- * EapAkaPrimeConfig represents the configs needed for an EAP-AKA' session.
- */
- public static class EapAkaPrimeConfig extends EapAkaConfig {
- public final String networkName;
- public final boolean allowMismatchedNetworkNames;
-
- @VisibleForTesting
- public EapAkaPrimeConfig(
- int subId,
- @UiccAppType int apptype,
- String networkName,
- boolean allowMismatchedNetworkNames) {
- super(subId, apptype);
-
- this.networkName = networkName;
- this.allowMismatchedNetworkNames = allowMismatchedNetworkNames;
- }
- }
-
- /**
- * EapMsChapV2Config represents the configs needed for an EAP MSCHAPv2 session.
- */
- public static class EapMsChapV2Config extends EapMethodConfig {
- public final String username;
- public final String password;
-
- @VisibleForTesting
- public EapMsChapV2Config(String username, String password) {
- super(EAP_TYPE_MSCHAP_V2);
-
- this.username = username;
- this.password = password;
- }
- }
-}
diff --git a/src/java/android/net/ipsec/ike/ChildSaProposal.java b/src/java/android/net/ipsec/ike/ChildSaProposal.java
deleted file mode 100644
index c8851a71..00000000
--- a/src/java/android/net/ipsec/ike/ChildSaProposal.java
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Copyright (C) 2019 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 android.net.ipsec.ike;
-
-import com.android.internal.net.ipsec.ike.message.IkePayload;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload.DhGroupTransform;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload.EncryptionTransform;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload.EsnTransform;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload.IntegrityTransform;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload.Transform;
-
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * ChildSaProposal represents a user configured set contains cryptograhic algorithms and key
- * generating materials for negotiating an Child SA.
- *
- * <p>User must provide at least a valid ChildSaProposal when they are creating a new Child SA.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key Exchange
- * Protocol Version 2 (IKEv2)</a>
- */
-public final class ChildSaProposal extends SaProposal {
- private final EsnTransform[] mEsns;
-
- /**
- * Construct an instance of ChildSaProposal.
- *
- * <p>This constructor is either called by ChildSaPayload for building an inbound proposal from
- * a decoded packet, or called by the inner Builder to build an outbound proposal from user
- * provided parameters
- *
- * @param encryptionAlgos encryption algorithms
- * @param integrityAlgos integrity algorithms
- * @param dhGroups Diffie-Hellman Groups
- * @param esns ESN policies
- */
- public ChildSaProposal(
- EncryptionTransform[] encryptionAlgos,
- IntegrityTransform[] integrityAlgos,
- DhGroupTransform[] dhGroups,
- EsnTransform[] esns) {
- super(IkePayload.PROTOCOL_ID_ESP, encryptionAlgos, integrityAlgos, dhGroups);
- mEsns = esns;
- }
-
- /** Gets all ESN policies. */
- public EsnTransform[] getEsnTransforms() {
- return mEsns;
- }
-
- /**
- * Gets a copy of proposal without all proposed DH groups.
- *
- * <p>This is used to avoid negotiating DH Group for negotiating first Child SA.
- */
- public ChildSaProposal getCopyWithoutDhTransform() {
- return new ChildSaProposal(
- getEncryptionTransforms(),
- getIntegrityTransforms(),
- new DhGroupTransform[0],
- getEsnTransforms());
- }
-
- @Override
- public Transform[] getAllTransforms() {
- List<Transform> transformList = getAllTransformsAsList();
- transformList.addAll(Arrays.asList(mEsns));
-
- return transformList.toArray(new Transform[transformList.size()]);
- }
-
- @Override
- public boolean isNegotiatedFrom(SaProposal reqProposal) {
- return super.isNegotiatedFrom(reqProposal)
- && isTransformSelectedFrom(mEsns, ((ChildSaProposal) reqProposal).mEsns);
- }
-
- /**
- * This class can be used to incrementally construct a ChildSaProposal. ChildSaProposal
- * instances are immutable once built.
- *
- * <p>TODO: Support users to add algorithms from most preferred to least preferred.
- */
- public static final class Builder extends SaProposal.Builder {
- /**
- * Adds an encryption algorithm with specific key length to SA proposal being built.
- *
- * @param algorithm encryption algorithm to add to ChildSaProposal.
- * @param keyLength key length of algorithm. For algorithm that has fixed key length (e.g.
- * 3DES) only KEY_LEN_UNUSED is allowed.
- * @return Builder of ChildSaProposal.
- * @throws IllegalArgumentException if AEAD and non-combined mode algorithms are mixed.
- */
- public Builder addEncryptionAlgorithm(@EncryptionAlgorithm int algorithm, int keyLength) {
- validateAndAddEncryptAlgo(algorithm, keyLength);
- return this;
- }
-
- /**
- * Adds an integrity algorithm to SA proposal being built.
- *
- * @param algorithm integrity algorithm to add to ChildSaProposal.
- * @return Builder of ChildSaProposal.
- */
- public Builder addIntegrityAlgorithm(@IntegrityAlgorithm int algorithm) {
- addIntegrityAlgo(algorithm);
- return this;
- }
-
- /**
- * Adds a Diffie-Hellman Group to SA proposal being built.
- *
- * @param dhGroup to add to ChildSaProposal.
- * @return Builder of ChildSaProposal.
- */
- public Builder addDhGroup(@DhGroup int dhGroup) {
- addDh(dhGroup);
- return this;
- }
-
- private IntegrityTransform[] buildIntegAlgosOrThrow() {
- // When building Child SA Proposal with normal-mode ciphers, there is no contraint on
- // integrity algorithm. When building Child SA Proposal with combined-mode ciphers,
- // mProposedIntegrityAlgos must be either empty or only have INTEGRITY_ALGORITHM_NONE.
- for (IntegrityTransform transform : mProposedIntegrityAlgos) {
- if (transform.id != INTEGRITY_ALGORITHM_NONE && mHasAead) {
- throw new IllegalArgumentException(
- ERROR_TAG
- + "Only INTEGRITY_ALGORITHM_NONE can be"
- + " proposed with combined-mode ciphers in any proposal.");
- }
- }
-
- return mProposedIntegrityAlgos.toArray(
- new IntegrityTransform[mProposedIntegrityAlgos.size()]);
- }
-
- /**
- * Validates, builds and returns the ChildSaProposal
- *
- * @return the validated ChildSaProposal.
- * @throws IllegalArgumentException if ChildSaProposal is invalid.
- */
- public ChildSaProposal build() {
- EncryptionTransform[] encryptionTransforms = buildEncryptAlgosOrThrow();
- IntegrityTransform[] integrityTransforms = buildIntegAlgosOrThrow();
-
- return new ChildSaProposal(
- encryptionTransforms,
- integrityTransforms,
- mProposedDhGroups.toArray(new DhGroupTransform[mProposedDhGroups.size()]),
- new EsnTransform[] {new EsnTransform()});
- }
- }
-}
diff --git a/src/java/android/net/ipsec/ike/ChildSessionCallback.java b/src/java/android/net/ipsec/ike/ChildSessionCallback.java
deleted file mode 100644
index ec8722e6..00000000
--- a/src/java/android/net/ipsec/ike/ChildSessionCallback.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2019 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 android.net.ipsec.ike;
-
-import android.net.IpSecManager.PolicyDirection;
-import android.net.IpSecTransform;
-import android.net.ipsec.ike.exceptions.IkeException;
-
-/** Callback interface for receiving state changes of a Child Session. */
-public interface ChildSessionCallback {
- /**
- * Called when Child Session setup succeeds.
- *
- * @param sessionConfiguration the configuration information of Child Session negotiated during
- * Child creation.
- */
- void onOpened(ChildSessionConfiguration sessionConfiguration);
-
- /**
- * Called when either side has decided to close this Session and the deletion exchange
- * finishes.
- *
- * <p>This method will not be fired if this deletion is caused by a fatal error.
- */
- void onClosed();
-
- /**
- * Called if Child Session setup fails or Child Session is closed because of a fatal error.
- *
- * @param exception the detailed error.
- */
- void onClosedExceptionally(IkeException exception);
-
- /**
- * Called when a new {@link IpSecTransform} is created for this Child Session.
- *
- * @param ipSecTransform the created {@link IpSecTransform}
- * @param direction the direction of this {@link IpSecTransform}
- */
- void onIpSecTransformCreated(IpSecTransform ipSecTransform, @PolicyDirection int direction);
-
- /**
- * Called when a new {@link IpSecTransform} is deleted for this Child Session.
- *
- * <p>Users MUST remove the transform from the socket or interface. Otherwise the communication
- * on that socket or interface will fail.
- *
- * @param ipSecTransform the deleted {@link IpSecTransform}
- * @param direction the direction of this {@link IpSecTransform}
- */
- void onIpSecTransformDeleted(IpSecTransform ipSecTransform, @PolicyDirection int direction);
-}
diff --git a/src/java/android/net/ipsec/ike/ChildSessionConfiguration.java b/src/java/android/net/ipsec/ike/ChildSessionConfiguration.java
deleted file mode 100644
index 2ed9de2f..00000000
--- a/src/java/android/net/ipsec/ike/ChildSessionConfiguration.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (C) 2019 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 android.net.ipsec.ike;
-
-import static com.android.internal.net.ipsec.ike.message.IkeConfigPayload.CONFIG_ATTR_INTERNAL_IP4_ADDRESS;
-import static com.android.internal.net.ipsec.ike.message.IkeConfigPayload.CONFIG_ATTR_INTERNAL_IP4_NETMASK;
-import static com.android.internal.net.ipsec.ike.message.IkeConfigPayload.CONFIG_ATTR_INTERNAL_IP6_ADDRESS;
-
-import android.net.LinkAddress;
-
-import com.android.internal.net.ipsec.ike.message.IkeConfigPayload;
-import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttribute;
-import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv4Address;
-import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv4Netmask;
-import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv6Address;
-
-import java.util.Collections;
-import java.util.LinkedList;
-import java.util.List;
-
-/** ChildSessionConfiguration represents the negotiated configuration for a Child Session. */
-public final class ChildSessionConfiguration {
- private static final int IPv4_DEFAULT_PREFIX_LEN = 32;
-
- private final List<IkeTrafficSelector> mInboundTs;
- private final List<IkeTrafficSelector> mOutboundTs;
- private final List<LinkAddress> mInternalAddressList;
-
- /**
- * Construct an instance of {@link ChildSessionConfiguration}.
- *
- * <p>It is only supported to build a {@link ChildSessionConfiguration} with a Configure(Reply)
- * Payload.
- */
- public ChildSessionConfiguration(
- List<IkeTrafficSelector> inTs,
- List<IkeTrafficSelector> outTs,
- IkeConfigPayload configPayload) {
- this(inTs, outTs);
-
- if (configPayload.configType != IkeConfigPayload.CONFIG_TYPE_REPLY) {
- throw new IllegalArgumentException(
- "Cannot build ChildSessionConfiguration with configuration type: "
- + configPayload.configType);
- }
-
- // It is validated in IkeConfigPayload that a config reply only has at most one non-empty
- // netmask and netmask exists only when IPv4 internal address exists.
- ConfigAttributeIpv4Netmask netmaskAttr = null;
- for (ConfigAttribute att : configPayload.recognizedAttributeList) {
- if (att.attributeType == CONFIG_ATTR_INTERNAL_IP4_NETMASK && !att.isEmptyValue()) {
- netmaskAttr = (ConfigAttributeIpv4Netmask) att;
- }
- }
-
- for (ConfigAttribute att : configPayload.recognizedAttributeList) {
- if (att.isEmptyValue()) continue;
- switch (att.attributeType) {
- case CONFIG_ATTR_INTERNAL_IP4_ADDRESS:
- ConfigAttributeIpv4Address addressAttr = (ConfigAttributeIpv4Address) att;
- if (netmaskAttr != null) {
- mInternalAddressList.add(
- new LinkAddress(addressAttr.address, netmaskAttr.getPrefixLen()));
- } else {
- mInternalAddressList.add(
- new LinkAddress(addressAttr.address, IPv4_DEFAULT_PREFIX_LEN));
- }
- break;
- case CONFIG_ATTR_INTERNAL_IP4_NETMASK:
- // No action.
- break;
- case CONFIG_ATTR_INTERNAL_IP6_ADDRESS:
- mInternalAddressList.add(((ConfigAttributeIpv6Address) att).linkAddress);
- break;
- default:
- // TODO: Support DNS,Subnet and Dhcp4 attributes
- }
- }
- }
-
- /** Construct an instance of {@link ChildSessionConfiguration}. */
- public ChildSessionConfiguration(
- List<IkeTrafficSelector> inTs, List<IkeTrafficSelector> outTs) {
- mInboundTs = Collections.unmodifiableList(inTs);
- mOutboundTs = Collections.unmodifiableList(outTs);
- mInternalAddressList = new LinkedList<>();
- }
-
- /**
- * Returns the negotiated inbound traffic selectors.
- *
- * @return the inbound traffic selector.
- */
- public List<IkeTrafficSelector> getInboundTrafficSelectors() {
- return mInboundTs;
- }
-
- /**
- * Returns the negotiated outbound traffic selectors.
- *
- * @return the outbound traffic selector.
- */
- public List<IkeTrafficSelector> getOutboundTrafficSelectors() {
- return mOutboundTs;
- }
-
- /**
- * Returns the assigned internal addresses.
- *
- * @return assigned internal addresses, or empty list when no addresses are assigned by the
- * remote IKE server.
- */
- public List<LinkAddress> getInternalAddressList() {
- return mInternalAddressList;
- }
-}
diff --git a/src/java/android/net/ipsec/ike/ChildSessionOptions.java b/src/java/android/net/ipsec/ike/ChildSessionOptions.java
deleted file mode 100644
index 90a30053..00000000
--- a/src/java/android/net/ipsec/ike/ChildSessionOptions.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2019 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 android.net.ipsec.ike;
-
-import libcore.net.InetAddressUtils;
-
-import java.net.InetAddress;
-import java.util.LinkedList;
-import java.util.List;
-
-/**
- * This abstract class is the superclass of all classes representing a set of user configurations
- * for Child Session negotiation.
- */
-public abstract class ChildSessionOptions {
- private static final IkeTrafficSelector DEFAULT_TRAFFIC_SELECTOR_IPV4;
- // TODO: b/130765172 Add TRAFFIC_SELECTOR_IPV6 and instantiate it.
-
- static {
- DEFAULT_TRAFFIC_SELECTOR_IPV4 =
- buildDefaultTrafficSelector(
- IkeTrafficSelector.TRAFFIC_SELECTOR_TYPE_IPV4_ADDR_RANGE);
- }
-
- private final IkeTrafficSelector[] mLocalTrafficSelectors;
- private final IkeTrafficSelector[] mRemoteTrafficSelectors;
- private final ChildSaProposal[] mSaProposals;
- private final boolean mIsTransport;
-
- protected ChildSessionOptions(
- IkeTrafficSelector[] localTs,
- IkeTrafficSelector[] remoteTs,
- ChildSaProposal[] proposals,
- boolean isTransport) {
- mLocalTrafficSelectors = localTs;
- mRemoteTrafficSelectors = remoteTs;
- mSaProposals = proposals;
- mIsTransport = isTransport;
- }
-
- public IkeTrafficSelector[] getLocalTrafficSelectors() {
- return mLocalTrafficSelectors;
- }
-
- public IkeTrafficSelector[] getRemoteTrafficSelectors() {
- return mRemoteTrafficSelectors;
- }
-
- public ChildSaProposal[] getSaProposals() {
- return mSaProposals;
- }
-
- public boolean isTransportMode() {
- return mIsTransport;
- }
-
- /** This class represents common information for Child Sesison Options Builders. */
- protected abstract static class Builder {
- protected final List<IkeTrafficSelector> mLocalTsList = new LinkedList<>();
- protected final List<IkeTrafficSelector> mRemoteTsList = new LinkedList<>();
- protected final List<SaProposal> mSaProposalList = new LinkedList<>();
-
- protected Builder() {
- // Currently IKE library only accepts setting up Child SA that all ports and all
- // addresses are allowed on both sides. The protected traffic range is determined by the
- // socket or interface that the {@link IpSecTransform} is applied to.
- // TODO: b/130756765 Validate the current TS negotiation strategy.
- mLocalTsList.add(DEFAULT_TRAFFIC_SELECTOR_IPV4);
- mRemoteTsList.add(DEFAULT_TRAFFIC_SELECTOR_IPV4);
- // TODO: add IPv6 TS to ChildSessionOptions.
- }
-
- protected void validateAndAddSaProposal(ChildSaProposal proposal) {
- mSaProposalList.add(proposal);
- }
-
- protected void validateOrThrow() {
- if (mSaProposalList.isEmpty()) {
- throw new IllegalArgumentException(
- "ChildSessionOptions requires at least one Child SA proposal.");
- }
- }
- }
-
- private static IkeTrafficSelector buildDefaultTrafficSelector(
- @IkeTrafficSelector.TrafficSelectorType int tsType) {
- int startPort = IkeTrafficSelector.PORT_NUMBER_MIN;
- int endPort = IkeTrafficSelector.PORT_NUMBER_MAX;
- InetAddress startAddress = null;
- InetAddress endAddress = null;
- switch (tsType) {
- case IkeTrafficSelector.TRAFFIC_SELECTOR_TYPE_IPV4_ADDR_RANGE:
- startAddress = InetAddressUtils.parseNumericAddress("0.0.0.0");
- endAddress = InetAddressUtils.parseNumericAddress("255.255.255.255");
- break;
- case IkeTrafficSelector.TRAFFIC_SELECTOR_TYPE_IPV6_ADDR_RANGE:
- // TODO: Support it.
- throw new UnsupportedOperationException("Do not support IPv6.");
- default:
- throw new IllegalArgumentException("Invalid Traffic Selector type: " + tsType);
- }
-
- return new IkeTrafficSelector(tsType, startPort, endPort, startAddress, endAddress);
- }
-}
diff --git a/src/java/android/net/ipsec/ike/IkeFqdnIdentification.java b/src/java/android/net/ipsec/ike/IkeFqdnIdentification.java
deleted file mode 100644
index 393a0723..00000000
--- a/src/java/android/net/ipsec/ike/IkeFqdnIdentification.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2019 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 android.net.ipsec.ike;
-
-import android.annotation.NonNull;
-
-import java.nio.charset.Charset;
-import java.util.Objects;
-
-/** IkeFqdnIdentification represents ID information using a fully-qualified domain name (FQDN) */
-public class IkeFqdnIdentification extends IkeIdentification {
- private static final Charset ASCII = Charset.forName("US-ASCII");
-
- public final String fqdn;
-
- /**
- * Construct an instance of IkeFqdnIdentification from a decoded inbound packet.
- *
- * <p>All characters in the FQDN are ASCII.
- *
- * @param fqdnBytes FQDN in byte array.
- */
- public IkeFqdnIdentification(byte[] fqdnBytes) {
- super(ID_TYPE_FQDN);
- fqdn = new String(fqdnBytes, ASCII);
- }
-
- /**
- * Construct an instance of IkeFqdnIdentification with user provided fully-qualified domain name
- * (FQDN) for building outbound packet.
- *
- * <p>FQDN will be formatted as US-ASCII.
- *
- * @param fqdn user provided fully-qualified domain name (FQDN)
- */
- public IkeFqdnIdentification(@NonNull String fqdn) {
- super(ID_TYPE_FQDN);
- this.fqdn = fqdn;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(idType, fqdn);
- }
-
- @Override
- public boolean equals(Object o) {
- if (!(o instanceof IkeFqdnIdentification)) return false;
-
- return fqdn.equals(((IkeFqdnIdentification) o).fqdn);
- }
-
- /**
- * Retrieve the byte-representation of the FQDN.
- *
- * @return the byte-representation of the FQDN.
- */
- @Override
- public byte[] getEncodedIdData() {
- return fqdn.getBytes(ASCII);
- }
-}
diff --git a/src/java/android/net/ipsec/ike/IkeIdentification.java b/src/java/android/net/ipsec/ike/IkeIdentification.java
deleted file mode 100644
index 737df826..00000000
--- a/src/java/android/net/ipsec/ike/IkeIdentification.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2018 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 android.net.ipsec.ike;
-
-import android.annotation.IntDef;
-import android.util.ArraySet;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.Set;
-
-/**
- * IkeIdentification is abstract base class that represents the common information for all types of
- * IKE entity identification.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.5">RFC 7296, Internet Key Exchange
- * Protocol Version 2 (IKEv2)</a>
- */
-public abstract class IkeIdentification {
- // Set of supported ID types.
- private static final Set<Integer> SUPPORTED_ID_TYPES;
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({
- ID_TYPE_IPV4_ADDR,
- ID_TYPE_FQDN,
- ID_TYPE_RFC822_ADDR,
- ID_TYPE_IPV6_ADDR,
- ID_TYPE_DER_ASN1_DN,
- ID_TYPE_DER_ASN1_GN,
- ID_TYPE_KEY_ID
- })
- public @interface IdType {}
-
- public static final int ID_TYPE_IPV4_ADDR = 1;
- public static final int ID_TYPE_FQDN = 2;
- public static final int ID_TYPE_RFC822_ADDR = 3;
- public static final int ID_TYPE_IPV6_ADDR = 5;
- public static final int ID_TYPE_DER_ASN1_DN = 9;
- public static final int ID_TYPE_DER_ASN1_GN = 10;
- public static final int ID_TYPE_KEY_ID = 11;
-
- static {
- SUPPORTED_ID_TYPES = new ArraySet();
- SUPPORTED_ID_TYPES.add(ID_TYPE_IPV4_ADDR);
- SUPPORTED_ID_TYPES.add(ID_TYPE_FQDN);
- SUPPORTED_ID_TYPES.add(ID_TYPE_RFC822_ADDR);
- SUPPORTED_ID_TYPES.add(ID_TYPE_IPV6_ADDR);
- SUPPORTED_ID_TYPES.add(ID_TYPE_DER_ASN1_DN);
- SUPPORTED_ID_TYPES.add(ID_TYPE_DER_ASN1_GN);
- SUPPORTED_ID_TYPES.add(ID_TYPE_KEY_ID);
- }
-
- public final int idType;
-
- protected IkeIdentification(@IdType int type) {
- idType = type;
- }
-
- /**
- * Return the encoded identification data in a byte array.
- *
- * @return the encoded identification data.
- */
- public abstract byte[] getEncodedIdData();
-}
diff --git a/src/java/android/net/ipsec/ike/IkeIpv4AddrIdentification.java b/src/java/android/net/ipsec/ike/IkeIpv4AddrIdentification.java
deleted file mode 100644
index 350187ed..00000000
--- a/src/java/android/net/ipsec/ike/IkeIpv4AddrIdentification.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2019 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 android.net.ipsec.ike;
-
-import android.annotation.NonNull;
-
-import com.android.internal.net.ipsec.ike.exceptions.AuthenticationFailedException;
-
-import java.net.Inet4Address;
-import java.net.UnknownHostException;
-import java.util.Objects;
-
-/** IkeIpv4AddrIdentification represents ID information in IPv4 address ID type. */
-public final class IkeIpv4AddrIdentification extends IkeIdentification {
- public final Inet4Address ipv4Address;
-
- /**
- * Construct an instance of IkeIpv4AddrIdentification from a decoded inbound packet.
- *
- * @param ipv4AddrBytes IPv4 address in byte array.
- * @throws AuthenticationFailedException for decoding bytes error.
- */
- public IkeIpv4AddrIdentification(byte[] ipv4AddrBytes) throws AuthenticationFailedException {
- super(ID_TYPE_IPV4_ADDR);
- try {
- ipv4Address = (Inet4Address) (Inet4Address.getByAddress(ipv4AddrBytes));
- } catch (ClassCastException | UnknownHostException e) {
- throw new AuthenticationFailedException(e);
- }
- }
-
- /**
- * Construct an instance of IkeIpv4AddrIdentification with user provided IPv4 address for
- * building outbound packet.
- *
- * @param address user provided IPv4 address
- */
- public IkeIpv4AddrIdentification(@NonNull Inet4Address address) {
- super(ID_TYPE_IPV4_ADDR);
- ipv4Address = address;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(idType, ipv4Address);
- }
-
- @Override
- public boolean equals(Object o) {
- if (!(o instanceof IkeIpv4AddrIdentification)) return false;
-
- return ipv4Address.equals(((IkeIpv4AddrIdentification) o).ipv4Address);
- }
-
- /**
- * Retrieve the byte-representation of the IPv4 address.
- *
- * @return the byte-representation of the IPv4 address.
- */
- @Override
- public byte[] getEncodedIdData() {
- return ipv4Address.getAddress();
- }
-}
diff --git a/src/java/android/net/ipsec/ike/IkeIpv6AddrIdentification.java b/src/java/android/net/ipsec/ike/IkeIpv6AddrIdentification.java
deleted file mode 100644
index dfc7d5e3..00000000
--- a/src/java/android/net/ipsec/ike/IkeIpv6AddrIdentification.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2019 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 android.net.ipsec.ike;
-
-import android.annotation.NonNull;
-
-import com.android.internal.net.ipsec.ike.exceptions.AuthenticationFailedException;
-
-import java.net.Inet6Address;
-import java.net.UnknownHostException;
-import java.util.Objects;
-
-/** IkeIpv6AddrIdentification represents ID information in IPv6 address ID type. */
-public class IkeIpv6AddrIdentification extends IkeIdentification {
- public final Inet6Address ipv6Address;
-
- /**
- * Construct an instance of IkeIpv6AddrIdentification from a decoded inbound packet.
- *
- * @param ipv6AddrBytes IPv6 address in byte array.
- * @throws AuthenticationFailedException for decoding bytes error.
- */
- public IkeIpv6AddrIdentification(byte[] ipv6AddrBytes) throws AuthenticationFailedException {
- super(ID_TYPE_IPV6_ADDR);
- try {
- ipv6Address = (Inet6Address) (Inet6Address.getByAddress(ipv6AddrBytes));
- } catch (ClassCastException | UnknownHostException e) {
- throw new AuthenticationFailedException(e);
- }
- }
-
- /**
- * Construct an instance of IkeIpv6AddrIdentification with user provided IPv6 address for
- * building outbound packet.
- *
- * @param address user provided IPv6 address
- */
- public IkeIpv6AddrIdentification(@NonNull Inet6Address address) {
- super(ID_TYPE_IPV6_ADDR);
- ipv6Address = address;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(idType, ipv6Address);
- }
-
- @Override
- public boolean equals(Object o) {
- if (!(o instanceof IkeIpv6AddrIdentification)) return false;
-
- return ipv6Address.equals(((IkeIpv6AddrIdentification) o).ipv6Address);
- }
-
- /**
- * Retrieve the byte-representation of the IPv6 address.
- *
- * @return the byte-representation of the IPv6 address.
- */
- @Override
- public byte[] getEncodedIdData() {
- return ipv6Address.getAddress();
- }
-}
diff --git a/src/java/android/net/ipsec/ike/IkeKeyIdIdentification.java b/src/java/android/net/ipsec/ike/IkeKeyIdIdentification.java
deleted file mode 100644
index c229b9da..00000000
--- a/src/java/android/net/ipsec/ike/IkeKeyIdIdentification.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2019 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 android.net.ipsec.ike;
-
-import android.annotation.NonNull;
-
-import java.util.Objects;
-
-/**
- * This class represents IKE ID information in Key ID type.
- *
- * <p>This is an octet stream that may be used to pass vendor-specific information necessary to do
- * certain proprietary types of identification.
- */
-public final class IkeKeyIdIdentification extends IkeIdentification {
- public final byte[] keyId;
-
- /**
- * Construct an instance of IkeKeyIdIdentification with provided Key ID
- *
- * @param keyId Key ID in bytes
- */
- public IkeKeyIdIdentification(@NonNull byte[] keyId) {
- super(ID_TYPE_KEY_ID);
- this.keyId = keyId;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(idType, keyId);
- }
-
- @Override
- public boolean equals(Object o) {
- if (!(o instanceof IkeKeyIdIdentification)) return false;
-
- return keyId.equals(((IkeKeyIdIdentification) o).keyId);
- }
-
- /**
- * Retrieve the byte-representation of the FQDN.
- *
- * @return the byte-representation of the FQDN.
- */
- @Override
- public byte[] getEncodedIdData() {
- return keyId;
- }
-}
diff --git a/src/java/android/net/ipsec/ike/IkeManager.java b/src/java/android/net/ipsec/ike/IkeManager.java
deleted file mode 100644
index ef8b893b..00000000
--- a/src/java/android/net/ipsec/ike/IkeManager.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2019 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 android.net.ipsec.ike;
-
-import android.content.Context;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.net.utils.Log;
-
-import java.util.concurrent.Executor;
-
-/** This class contains methods for managing IKE sessions. */
-public final class IkeManager {
- private static final String IKE_TAG = "IKE";
- private static final boolean LOG_SENSITIVE = false;
-
- private static Log sIkeLog = new Log(IKE_TAG, LOG_SENSITIVE);
-
- private final Context mContext;
-
- /**
- * Construct an instance of {@link IkeManager}
- *
- * @param context the application context.
- */
- public IkeManager(Context context) {
- mContext = context;
- }
-
- /**
- * Construct an instance of {@link IkeSession} and start the IKE Session setup process.
- *
- * <p>This method will immediately return a management object {@link IkeSession} and
- * asynchronously initiate the IKE Session setup process. Users will be notified of the IKE
- * Session and Child Session negotiation results on the callback arguments.
- *
- * @param ikeSessionOptions the {@link IkeSessionOptions} that contains acceptable IKE Session
- * configurations.
- * @param firstChildSessionOptions the {@link ChildSessionOptions} that contains acceptable
- * first Child Session configurations.
- * @param userCbExecutor the {@link Executor} upon which all callbacks will be posted. For
- * security and consistency, the callbacks posted to this executor MUST be executed
- * serially, in the order they were posted.
- * @param ikeSessionCallback the {@link IkeSessionCallback} interface to notify users the state
- * changes of the IKE Session.
- * @param firstChildSessionCallback the {@link ChildSessionCallback} interface to notify users
- * the state changes of the Child Session.
- * @return an instance of {@link IkeSession}
- */
- public IkeSession openIkeSession(
- IkeSessionOptions ikeSessionOptions,
- ChildSessionOptions firstChildSessionOptions,
- Executor userCbExecutor,
- IkeSessionCallback ikeSessionCallback,
- ChildSessionCallback firstChildSessionCallback) {
- return new IkeSession(
- mContext,
- ikeSessionOptions,
- firstChildSessionOptions,
- userCbExecutor,
- ikeSessionCallback,
- firstChildSessionCallback);
- }
-
- /** Returns IKE logger. */
- public static Log getIkeLog() {
- return sIkeLog;
- }
-
- /** Injects IKE logger for testing. */
- @VisibleForTesting
- public static void setIkeLog(Log log) {
- sIkeLog = log;
- }
-
- /** Resets IKE logger. */
- @VisibleForTesting
- public static void resetIkeLog() {
- sIkeLog = new Log(IKE_TAG, LOG_SENSITIVE);
- }
-}
diff --git a/src/java/android/net/ipsec/ike/IkeRfc822AddrIdentification.java b/src/java/android/net/ipsec/ike/IkeRfc822AddrIdentification.java
deleted file mode 100644
index 2a93bea1..00000000
--- a/src/java/android/net/ipsec/ike/IkeRfc822AddrIdentification.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2019 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 android.net.ipsec.ike;
-
-import android.annotation.NonNull;
-
-import java.nio.charset.Charset;
-import java.util.Objects;
-
-/** This class represents IKE ID information in fully-qualified RFC 822 email address ID type. */
-public final class IkeRfc822AddrIdentification extends IkeIdentification {
- private static final Charset UTF8 = Charset.forName("UTF-8");
-
- public final String rfc822Name;
-
- /**
- * Construct an instance of IkeRfc822AddrIdentification from a decoded inbound packet.
- *
- * <p>All characters in the RFC 822 email address are UTF-8.
- *
- * @param rfc822NameBytes fully-qualified RFC 822 email address in byte array.
- */
- public IkeRfc822AddrIdentification(byte[] rfc822NameBytes) {
- super(ID_TYPE_RFC822_ADDR);
- rfc822Name = new String(rfc822NameBytes, UTF8);
- }
-
- /**
- * Construct an instance of IkeRfc822AddrIdentification with user provided fully-qualified RFC
- * 822 email address for building outbound packet.
- *
- * <p>rfc822Name will be formatted as UTF-8.
- *
- * @param rfc822Name user provided fully-qualified RFC 822 email address.
- */
- public IkeRfc822AddrIdentification(@NonNull String rfc822Name) {
- super(ID_TYPE_RFC822_ADDR);
- this.rfc822Name = rfc822Name;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(idType, rfc822Name);
- }
-
- @Override
- public boolean equals(Object o) {
- if (!(o instanceof IkeRfc822AddrIdentification)) return false;
-
- return rfc822Name.equals(((IkeRfc822AddrIdentification) o).rfc822Name);
- }
-
- /**
- * Retrieve the byte-representation of the the RFC 822 email address.
- *
- * @return the byte-representation of the RFC 822 email address.
- */
- @Override
- public byte[] getEncodedIdData() {
- return rfc822Name.getBytes(UTF8);
- }
-}
diff --git a/src/java/android/net/ipsec/ike/IkeSaProposal.java b/src/java/android/net/ipsec/ike/IkeSaProposal.java
deleted file mode 100644
index 1494f9d4..00000000
--- a/src/java/android/net/ipsec/ike/IkeSaProposal.java
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * Copyright (C) 2019 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 android.net.ipsec.ike;
-
-import android.util.ArraySet;
-
-import com.android.internal.net.ipsec.ike.message.IkePayload;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload.DhGroupTransform;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload.EncryptionTransform;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload.IntegrityTransform;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload.PrfTransform;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload.Transform;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.Set;
-
-/**
- * IkeSaProposal represents a user configured set contains cryptograhic algorithms and key
- * generating materials for negotiating an IKE SA.
- *
- * <p>User must provide at least a valid IkeSaProposal when they are creating a new IKE SA.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key Exchange
- * Protocol Version 2 (IKEv2)</a>
- */
-public final class IkeSaProposal extends SaProposal {
- private final PrfTransform[] mPseudorandomFunctions;
-
- /**
- * Construct an instance of IkeSaProposal.
- *
- * <p>This constructor is either called by IkeSaPayload for building an inbound proposal from a
- * decoded packet, or called by the inner Builder to build an outbound proposal from user
- * provided parameters
- *
- * @param encryptionAlgos encryption algorithms
- * @param prfs pseudorandom functions
- * @param integrityAlgos integrity algorithms
- * @param dhGroups Diffie-Hellman Groups
- */
- public IkeSaProposal(
- EncryptionTransform[] encryptionAlgos,
- PrfTransform[] prfs,
- IntegrityTransform[] integrityAlgos,
- DhGroupTransform[] dhGroups) {
- super(IkePayload.PROTOCOL_ID_IKE, encryptionAlgos, integrityAlgos, dhGroups);
- mPseudorandomFunctions = prfs;
- }
-
- /** Gets all PRFs. */
- public PrfTransform[] getPrfTransforms() {
- return mPseudorandomFunctions;
- }
-
- @Override
- public Transform[] getAllTransforms() {
- List<Transform> transformList = getAllTransformsAsList();
- transformList.addAll(Arrays.asList(mPseudorandomFunctions));
-
- return transformList.toArray(new Transform[transformList.size()]);
- }
-
- @Override
- public boolean isNegotiatedFrom(SaProposal reqProposal) {
- return super.isNegotiatedFrom(reqProposal)
- && isTransformSelectedFrom(
- mPseudorandomFunctions,
- ((IkeSaProposal) reqProposal).mPseudorandomFunctions);
- }
-
- /**
- * This class can be used to incrementally construct a IkeSaProposal. IkeSaProposal instances
- * are immutable once built.
- *
- * <p>TODO: Support users to add algorithms from most preferred to least preferred.
- */
- public static final class Builder extends SaProposal.Builder {
- // Use set to avoid adding repeated algorithms.
- private final Set<PrfTransform> mProposedPrfs = new ArraySet<>();
-
- /**
- * Adds an encryption algorithm with specific key length to SA proposal being built.
- *
- * @param algorithm encryption algorithm to add to IkeSaProposal.
- * @param keyLength key length of algorithm. For algorithm that has fixed key length (e.g.
- * 3DES) only KEY_LEN_UNUSED is allowed.
- * @return Builder of IkeSaProposal.
- * @throws IllegalArgumentException if AEAD and non-combined mode algorithms are mixed.
- */
- public Builder addEncryptionAlgorithm(@EncryptionAlgorithm int algorithm, int keyLength) {
- validateAndAddEncryptAlgo(algorithm, keyLength);
- return this;
- }
-
- /**
- * Adds an integrity algorithm to SA proposal being built.
- *
- * @param algorithm integrity algorithm to add to IkeSaProposal.
- * @return Builder of IkeSaProposal.
- */
- public Builder addIntegrityAlgorithm(@IntegrityAlgorithm int algorithm) {
- addIntegrityAlgo(algorithm);
- return this;
- }
-
- /**
- * Adds a Diffie-Hellman Group to SA proposal being built.
- *
- * @param dhGroup to add to IkeSaProposal.
- * @return Builder of IkeSaProposal.
- */
- public Builder addDhGroup(@DhGroup int dhGroup) {
- addDh(dhGroup);
- return this;
- }
-
- /**
- * Adds a pseudorandom function to SA proposal being built.
- *
- * @param algorithm pseudorandom function to add to IkeSaProposal.
- * @return Builder of IkeSaProposal.
- */
- public Builder addPseudorandomFunction(@PseudorandomFunction int algorithm) {
- // Construct PrfTransform and validate proposed algorithm during construction.
- mProposedPrfs.add(new PrfTransform(algorithm));
- return this;
- }
-
- private IntegrityTransform[] buildIntegAlgosOrThrow() {
- // When building IKE SA Proposal with normal-mode ciphers, mProposedIntegrityAlgos must
- // not be empty and must not have INTEGRITY_ALGORITHM_NONE. When building IKE SA
- // Proposal with combined-mode ciphers, mProposedIntegrityAlgos must be either empty or
- // only have INTEGRITY_ALGORITHM_NONE.
- if (mProposedIntegrityAlgos.isEmpty() && !mHasAead) {
- throw new IllegalArgumentException(
- ERROR_TAG
- + "Integrity algorithm "
- + "must be proposed with normal ciphers in IKE proposal.");
- }
-
- for (IntegrityTransform transform : mProposedIntegrityAlgos) {
- if ((transform.id == INTEGRITY_ALGORITHM_NONE) != mHasAead) {
- throw new IllegalArgumentException(
- ERROR_TAG
- + "Invalid integrity algorithm configuration"
- + " for this SA Proposal");
- }
- }
-
- return mProposedIntegrityAlgos.toArray(
- new IntegrityTransform[mProposedIntegrityAlgos.size()]);
- }
-
- private DhGroupTransform[] buildDhGroupsOrThrow() {
- if (mProposedDhGroups.isEmpty()) {
- throw new IllegalArgumentException(
- ERROR_TAG + "DH group must be proposed in IKE SA proposal.");
- }
-
- for (DhGroupTransform transform : mProposedDhGroups) {
- if (transform.id == DH_GROUP_NONE) {
- throw new IllegalArgumentException(
- ERROR_TAG + "None-value DH group invalid in IKE SA proposal");
- }
- }
-
- return mProposedDhGroups.toArray(new DhGroupTransform[mProposedDhGroups.size()]);
- }
-
- private PrfTransform[] buildPrfsOrThrow() {
- if (mProposedPrfs.isEmpty()) {
- throw new IllegalArgumentException(
- ERROR_TAG + "PRF must be proposed in IKE SA proposal.");
- }
- return mProposedPrfs.toArray(new PrfTransform[mProposedPrfs.size()]);
- }
-
- /**
- * Validates, builds and returns the IkeSaProposal
- *
- * @return the validated IkeSaProposal.
- * @throws IllegalArgumentException if IkeSaProposal is invalid.
- */
- public IkeSaProposal build() {
- EncryptionTransform[] encryptionTransforms = buildEncryptAlgosOrThrow();
- PrfTransform[] prfTransforms = buildPrfsOrThrow();
- IntegrityTransform[] integrityTransforms = buildIntegAlgosOrThrow();
- DhGroupTransform[] dhGroupTransforms = buildDhGroupsOrThrow();
-
- return new IkeSaProposal(
- encryptionTransforms, prfTransforms, integrityTransforms, dhGroupTransforms);
- }
- }
-}
diff --git a/src/java/android/net/ipsec/ike/IkeSession.java b/src/java/android/net/ipsec/ike/IkeSession.java
deleted file mode 100644
index 97fe061e..00000000
--- a/src/java/android/net/ipsec/ike/IkeSession.java
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * Copyright (C) 2019 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 android.net.ipsec.ike;
-
-import android.content.Context;
-import android.net.IpSecManager;
-import android.os.HandlerThread;
-import android.os.Looper;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.net.ipsec.ike.IkeSessionStateMachine;
-
-import dalvik.system.CloseGuard;
-
-import java.util.concurrent.Executor;
-
-/**
- * This class represents an IKE Session management object that allows for keying and management of
- * {@link IpSecTransform}s.
- *
- * <p>An IKE/Child Session represents an IKE/Child SA as well as its rekeyed successors. A Child
- * Session is bounded by the lifecycle of the IKE Session under which it is set up. Closing an IKE
- * Session implicitly closes any remaining Child Sessions under it.
- *
- * <p>An IKE procedure is one or multiple IKE message exchanges that are used to create, delete or
- * rekey an IKE Session or Child Session.
- *
- * <p>This class provides methods for user to initiate IKE procedures, such as the Creation and
- * Deletion of a Child Session, or the Deletion of the IKE session. All procedures (except for IKE
- * deletion) will be initiated sequentially after IKE Session is set up.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296">RFC 7296, Internet Key Exchange Protocol
- * Version 2 (IKEv2)</a>
- */
-public final class IkeSession implements AutoCloseable {
- private final CloseGuard mCloseGuard = CloseGuard.get();
-
- @VisibleForTesting final IkeSessionStateMachine mIkeSessionStateMachine;
-
- /** Package private */
- IkeSession(
- Context context,
- IkeSessionOptions ikeSessionOptions,
- ChildSessionOptions firstChildSessionOptions,
- Executor userCbExecutor,
- IkeSessionCallback ikeSessionCallback,
- ChildSessionCallback firstChildSessionCallback) {
- this(
- IkeThreadHolder.IKE_WORKER_THREAD.getLooper(),
- context,
- (IpSecManager) context.getSystemService(Context.IPSEC_SERVICE),
- ikeSessionOptions,
- firstChildSessionOptions,
- userCbExecutor,
- ikeSessionCallback,
- firstChildSessionCallback);
- }
-
- /** Package private */
- @VisibleForTesting
- IkeSession(
- Looper looper,
- Context context,
- IpSecManager ipSecManager,
- IkeSessionOptions ikeSessionOptions,
- ChildSessionOptions firstChildSessionOptions,
- Executor userCbExecutor,
- IkeSessionCallback ikeSessionCallback,
- ChildSessionCallback firstChildSessionCallback) {
- mIkeSessionStateMachine =
- new IkeSessionStateMachine(
- looper,
- context,
- ipSecManager,
- ikeSessionOptions,
- firstChildSessionOptions,
- userCbExecutor,
- ikeSessionCallback,
- firstChildSessionCallback);
- mIkeSessionStateMachine.openSession();
-
- mCloseGuard.open("open");
- }
-
- @Override
- public void finalize() {
- if (mCloseGuard != null) {
- mCloseGuard.warnIfOpen();
- }
- }
-
- /** Initialization-on-demand holder */
- private static class IkeThreadHolder {
- static final HandlerThread IKE_WORKER_THREAD;
-
- static {
- IKE_WORKER_THREAD = new HandlerThread("IkeWorkerThread");
- IKE_WORKER_THREAD.start();
- }
- }
-
- // TODO: b/133340675 Destroy the worker thread when there is no more alive {@link IkeSession}.
-
- /**
- * Asynchronously request a new Child Session.
- *
- * <p>Users MUST provide a unique {@link ChildSessionCallback} instance for each new Child
- * Session.
- *
- * <p>Upon setup, the {@link ChildSessionCallback#onOpened(ChildSessionConfiguration)} will be
- * fired.
- *
- * @param childSessionOptions the {@link ChildSessionOptions} that contains the Child Session
- * configurations to negotiate.
- * @param childSessionCallback the {@link ChildSessionCallback} interface to notify users the
- * state changes of the Child Session.
- * @throws IllegalArgumentException if the ChildSessionCallback is already in use.
- */
- public void openChildSession(
- ChildSessionOptions childSessionOptions, ChildSessionCallback childSessionCallback) {
- mIkeSessionStateMachine.openChildSession(childSessionOptions, childSessionCallback);
- }
-
- /**
- * Asynchronously delete a Child Session.
- *
- * <p>Upon closing, the {@link ChildSessionCallback#onClosed()} will be fired.
- *
- * @param childSessionCallback The {@link ChildSessionCallback} instance that uniquely identify
- * the Child Session.
- * @throws IllegalArgumentException if no Child Session found bound with this callback.
- */
- public void closeChildSession(ChildSessionCallback childSessionCallback) {
- mIkeSessionStateMachine.closeChildSession(childSessionCallback);
- }
-
- /**
- * Close the IKE session gracefully.
- *
- * <p>Implements {@link AutoCloseable#close()}
- *
- * <p>Upon closing, the {@link IkeSessionCallback#onClosed()} will be fired.
- *
- * <p>Closing an IKE Session implicitly closes any remaining Child Sessions negotiated under it.
- * Users SHOULD stop all outbound traffic that uses these Child Sessions({@link IpSecTransform}
- * pairs) before calling this method. Otherwise IPsec packets will be dropped due to the lack of
- * a valid {@link IpSecTransform}.
- *
- * <p>Closure of an IKE session will take priority over, and cancel other procedures waiting in
- * the queue (but will wait for ongoing locally initiated procedures to complete). After sending
- * the Delete request, the IKE library will wait until a Delete response is received or
- * retransmission timeout occurs.
- */
- @Override
- public void close() throws Exception {
- mCloseGuard.close();
- mIkeSessionStateMachine.closeSession();
- }
-
- /**
- * Terminate (forcibly close) the IKE session.
- *
- * <p>Upon closing, the {@link IkeSessionCallback#onClosed()} will be fired.
- *
- * <p>Closing an IKE Session implicitly closes any remaining Child Sessions negotiated under it.
- * Users SHOULD stop all outbound traffic that uses these Child Sessions({@link IpSecTransform}
- * pairs) before calling this method. Otherwise IPsec packets will be dropped due to the lack of
- * a valid {@link IpSecTransform}.
- *
- * <p>Forcible closure of an IKE session will take priority over, and cancel other procedures
- * waiting in the queue. It will also interrupt any ongoing locally initiated procedure.
- */
- public void kill() throws Exception {
- mCloseGuard.close();
- mIkeSessionStateMachine.killSession();
- }
-}
diff --git a/src/java/android/net/ipsec/ike/IkeSessionCallback.java b/src/java/android/net/ipsec/ike/IkeSessionCallback.java
deleted file mode 100644
index c2121e2d..00000000
--- a/src/java/android/net/ipsec/ike/IkeSessionCallback.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2019 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 android.net.ipsec.ike;
-
-import android.annotation.NonNull;
-import android.net.ipsec.ike.exceptions.IkeException;
-
-/** Callback interface for receiving state changes of an IKE Session. */
-public interface IkeSessionCallback {
- /**
- * Called when negotiation and authentication for this new IKE Session succeeds.
- *
- * @param sessionConfiguration the configuration information of IKE Session negotiated during
- * IKE setup.
- */
- void onOpened(@NonNull IkeSessionConfiguration sessionConfiguration);
-
- /**
- * Called when either side has decided to close this Session and the deletion exchange
- * finishes.
- *
- * <p>This method will not be fired if this deletion is caused by a fatal error.
- */
- void onClosed();
-
- /**
- * Called if IKE Session negotiation fails or IKE Session is closed because of a fatal error.
- *
- * @param exception the detailed error.
- */
- void onClosedExceptionally(IkeException exception);
-
- /**
- * Called if a recoverable error is encountered in an established IKE Session.
- *
- * <p>A potential risk is usually detected when IKE library receives a non-protected error
- * notification (e.g. INVALID_IKE_SPI) or a non-fatal error notification (e.g.
- * INVALID_MESSAGE_ID).
- *
- * @param exception the detailed error.
- */
- void onError(IkeException exception);
-}
diff --git a/src/java/android/net/ipsec/ike/IkeSessionConfiguration.java b/src/java/android/net/ipsec/ike/IkeSessionConfiguration.java
deleted file mode 100644
index 6bbef7d0..00000000
--- a/src/java/android/net/ipsec/ike/IkeSessionConfiguration.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2019 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 android.net.ipsec.ike;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/** IkeSessionConfiguration represents the negotiated configuration for a IKE Session. */
-public final class IkeSessionConfiguration {
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({EXTENSION_TYPE_FRAGMENTATION, EXTENSION_TYPE_MOBIKE})
- public @interface ExtensionType {}
-
- public static final int EXTENSION_TYPE_FRAGMENTATION = 1;
- public static final int EXTENSION_TYPE_MOBIKE = 2;
-
- /**
- * Gets remote(server) version information.
- *
- * @return application version of the remote server, or empty string if the remote server did
- * not provide the application version
- */
- @NonNull
- public String getRemoteApplicationVersion() {
- return "";
- }
-
- /**
- * Checks if an IKE extension is enabled.
- *
- * <p>An IKE extension is enabled when both sides can support it. This negotiation always
- * happens in IKE initial changes(IKE INIT and IKE AUTH).
- *
- * @param extensionType the extension type
- * @return {@code true} if this extension is enabled
- */
- public boolean isIkeExtensionEnabled(@ExtensionType int extensionType) {
- return false;
- }
-
- // TODO: Implement IkeSessionConfiguration.
-}
diff --git a/src/java/android/net/ipsec/ike/IkeSessionOptions.java b/src/java/android/net/ipsec/ike/IkeSessionOptions.java
deleted file mode 100644
index 020a8888..00000000
--- a/src/java/android/net/ipsec/ike/IkeSessionOptions.java
+++ /dev/null
@@ -1,416 +0,0 @@
-/*
- * Copyright (C) 2019 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 android.net.ipsec.ike;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.net.IpSecManager.UdpEncapsulationSocket;
-import android.net.eap.EapSessionConfig;
-
-import com.android.internal.net.ipsec.ike.message.IkePayload;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.net.InetAddress;
-import java.security.PrivateKey;
-import java.security.cert.TrustAnchor;
-import java.security.cert.X509Certificate;
-import java.security.interfaces.RSAPrivateKey;
-import java.util.LinkedList;
-import java.util.List;
-
-/**
- * IkeSessionOptions contains all user provided configurations for negotiating an IKE SA.
- *
- * <p>TODO: Make this doc more user-friendly.
- */
-public final class IkeSessionOptions {
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({IKE_AUTH_METHOD_PSK, IKE_AUTH_METHOD_PUB_KEY_SIGNATURE, IKE_AUTH_METHOD_EAP})
- public @interface IkeAuthMethod {}
-
- // Constants to describe user configured authentication methods.
- public static final int IKE_AUTH_METHOD_PSK = 1;
- public static final int IKE_AUTH_METHOD_PUB_KEY_SIGNATURE = 2;
- public static final int IKE_AUTH_METHOD_EAP = 3;
-
- private final InetAddress mServerAddress;
- private final UdpEncapsulationSocket mUdpEncapSocket;
- private final IkeSaProposal[] mSaProposals;
-
- private final IkeIdentification mLocalIdentification;
- private final IkeIdentification mRemoteIdentification;
-
- private final IkeAuthConfig mLocalAuthConfig;
- private final IkeAuthConfig mRemoteAuthConfig;
-
- private final boolean mIsIkeFragmentationSupported;
-
- private IkeSessionOptions(
- InetAddress serverAddress,
- UdpEncapsulationSocket udpEncapsulationSocket,
- IkeSaProposal[] proposals,
- IkeIdentification localIdentification,
- IkeIdentification remoteIdentification,
- IkeAuthConfig localAuthConfig,
- IkeAuthConfig remoteAuthConfig,
- boolean isIkeFragmentationSupported) {
- mServerAddress = serverAddress;
- mUdpEncapSocket = udpEncapsulationSocket;
- mSaProposals = proposals;
-
- mLocalIdentification = localIdentification;
- mRemoteIdentification = remoteIdentification;
-
- mLocalAuthConfig = localAuthConfig;
- mRemoteAuthConfig = remoteAuthConfig;
-
- mIsIkeFragmentationSupported = isIkeFragmentationSupported;
- }
-
- public InetAddress getServerAddress() {
- return mServerAddress;
- }
-
- public UdpEncapsulationSocket getUdpEncapsulationSocket() {
- return mUdpEncapSocket;
- }
-
- public IkeSaProposal[] getSaProposals() {
- return mSaProposals;
- }
-
- public IkeIdentification getLocalIdentification() {
- return mLocalIdentification;
- }
-
- public IkeIdentification getRemoteIdentification() {
- return mRemoteIdentification;
- }
-
- public IkeAuthConfig getLocalAuthConfig() {
- return mLocalAuthConfig;
- }
-
- public IkeAuthConfig getRemoteAuthConfig() {
- return mRemoteAuthConfig;
- }
-
- public boolean isIkeFragmentationSupported() {
- return mIsIkeFragmentationSupported;
- }
- /** This class contains common information of an IKEv2 authentication configuration. */
- public abstract static class IkeAuthConfig {
- @IkeAuthMethod public final int mAuthMethod;
-
- protected IkeAuthConfig(@IkeAuthMethod int authMethod) {
- mAuthMethod = authMethod;
- }
- }
-
- /**
- * This class represents the configuration to support IKEv2 pre-shared-key-based authentication
- * of local or remote side.
- */
- public static class IkeAuthPskConfig extends IkeAuthConfig {
- public final byte[] mPsk;
-
- private IkeAuthPskConfig(byte[] psk) {
- super(IKE_AUTH_METHOD_PSK);
- mPsk = psk;
- }
- }
-
- /**
- * This class represents the configuration to support IKEv2 public-key-signature-based
- * authentication of the remote side.
- */
- public static class IkeAuthDigitalSignRemoteConfig extends IkeAuthConfig {
- public final TrustAnchor mTrustAnchor;
-
- private IkeAuthDigitalSignRemoteConfig(TrustAnchor trustAnchor) {
- super(IKE_AUTH_METHOD_PUB_KEY_SIGNATURE);
- mTrustAnchor = trustAnchor;
- }
- }
-
- /**
- * This class represents the configuration to support IKEv2 public-key-signature-based
- * authentication of the local side.
- */
- public static class IkeAuthDigitalSignLocalConfig extends IkeAuthConfig {
- public final X509Certificate mEndCert;
- public final List<X509Certificate> mIntermediateCerts;
- public final PrivateKey mPrivateKey;
-
- private IkeAuthDigitalSignLocalConfig(
- X509Certificate clientEndCert,
- List<X509Certificate> clientIntermediateCerts,
- PrivateKey privateKey) {
- super(IKE_AUTH_METHOD_PUB_KEY_SIGNATURE);
- mEndCert = clientEndCert;
- mIntermediateCerts = clientIntermediateCerts;
- mPrivateKey = privateKey;
- }
- }
-
- /**
- * This class represents the configuration to support EAP authentication of the local side.
- *
- * <p>EAP MUST be used with IKEv2 public-key-based authentication of the responder to the
- * initiator. Currently IKE library does not support the IKEv2 protocol extension(RFC 5998)
- * which allows EAP methods that provide mutual authentication and key agreement to be used to
- * provide extensible responder authentication for IKEv2 based on methods other than public key
- * signatures.
- *
- * @see <a href="https://tools.ietf.org/html/rfc5998">RFC 5998, An Extension for EAP-Only
- * Authentication in IKEv2</a>
- */
- public static class IkeAuthEapConfig extends IkeAuthConfig {
- public final EapSessionConfig mEapConfig;
-
- private IkeAuthEapConfig(EapSessionConfig eapConfig) {
- super(IKE_AUTH_METHOD_EAP);
-
- mEapConfig = eapConfig;
- }
- }
-
- /** This class can be used to incrementally construct a IkeSessionOptions. */
- public static final class Builder {
- private final List<IkeSaProposal> mSaProposalList = new LinkedList<>();
-
- private InetAddress mServerAddress;
- private UdpEncapsulationSocket mUdpEncapSocket;
-
- private IkeIdentification mLocalIdentification;
- private IkeIdentification mRemoteIdentification;
-
- private IkeAuthConfig mLocalAuthConfig;
- private IkeAuthConfig mRemoteAuthConfig;
-
- private boolean mIsIkeFragmentationSupported = false;
-
- /**
- * Sets server address
- *
- * @param serverAddress IP address of remote IKE server.
- * @return Builder this, to facilitate chaining.
- */
- public Builder setServerAddress(@NonNull InetAddress serverAddress) {
- mServerAddress = serverAddress;
- return this;
- }
-
- /**
- * Sets UDP-Encapsulated socket
- *
- * @param udpEncapsulationSocket {@link IpSecManager.UdpEncapsulationSocket} for sending and
- * receiving IKE message.
- * @return Builder this, to facilitate chaining.
- */
- public Builder setUdpEncapsulationSocket(
- @NonNull UdpEncapsulationSocket udpEncapsulationSocket) {
- mUdpEncapSocket = udpEncapsulationSocket;
- return this;
- }
-
- /**
- * Sets local IKE identification.
- *
- * @param identification the local IKE identification.
- * @return Builder this, to facilitate chaining.
- */
- public Builder setLocalIdentification(IkeIdentification identification) {
- mLocalIdentification = identification;
- return this;
- }
-
- /**
- * Sets remote IKE identification.
- *
- * @param identification the remote IKE identification.
- * @return Builder this, to facilitate chaining.
- */
- public Builder setRemoteIdentification(IkeIdentification identification) {
- mRemoteIdentification = identification;
- return this;
- }
-
- /**
- * Adds an IKE SA proposal to IkeSessionOptions being built.
- *
- * @param proposal IKE SA proposal.
- * @return Builder this, to facilitate chaining.
- * @throws IllegalArgumentException if input proposal is not IKE SA proposal.
- */
- public Builder addSaProposal(IkeSaProposal proposal) {
- if (proposal.getProtocolId() != IkePayload.PROTOCOL_ID_IKE) {
- throw new IllegalArgumentException(
- "Expected IKE SA Proposal but received Child SA proposal");
- }
- mSaProposalList.add(proposal);
- return this;
- }
-
- /**
- * Uses pre-shared key to do IKE authentication.
- *
- * <p>Both client and server MUST be authenticated using the provided shared key. IKE
- * authentication will fail if the remote peer tries to use other authentication methods.
- *
- * <p>Users MUST declare only one authentication method. Calling this function will override
- * the previously set authentication configuration.
- *
- * @param sharedKey the shared key.
- * @return Builder this, to facilitate chaining.
- */
- public Builder setAuthPsk(@NonNull byte[] sharedKey) {
- mLocalAuthConfig = new IkeAuthPskConfig(sharedKey);
- mRemoteAuthConfig = new IkeAuthPskConfig(sharedKey);
- return this;
- }
-
- /**
- * Uses EAP to do IKE authentication.
- *
- * <p>EAP are typically used to authenticate the IKE client to the server. It MUST be used
- * in conjunction with a public-key-signature-based authentication of the server to the
- * client.
- *
- * <p>Users MUST declare only one authentication method. Calling this function will override
- * the previously set authentication configuration.
- *
- * @see <a href="https://tools.ietf.org/html/rfc5280">RFC 5280, Internet X.509 Public Key
- * Infrastructure Certificate and Certificate Revocation List (CRL) Profile</a>
- * @param serverCaCert the CA certificate for validating the received server certificate(s).
- * @return Builder this, to facilitate chaining.
- */
- public Builder setAuthEap(
- @NonNull X509Certificate serverCaCert, @NonNull EapSessionConfig eapConfig) {
- mLocalAuthConfig = new IkeAuthEapConfig(eapConfig);
-
- // The name constraints extension, defined in RFC 5280, indicates a name space within
- // which all subject names in subsequent certificates in a certification path MUST be
- // located.
- mRemoteAuthConfig =
- new IkeAuthDigitalSignRemoteConfig(
- new TrustAnchor(serverCaCert, null /*nameConstraints*/));
-
- // TODO: Investigate if we need to support the name constraints extension.
-
- return this;
- }
-
- /**
- * Uses certificate and digital signature to do IKE authentication.
- *
- * <p>The public key included by the client end certificate and the signature private key
- * MUST come from the same key pair.
- *
- * <p>The IKE library will use the strongest signature algorithm supported by both sides.
- *
- * <p>Currenly only RSA digital signature is supported.
- *
- * @param serverCaCert the CA certificate for validating the received server certificate(s).
- * @param clientEndCert the end certificate for remote server to verify the locally
- * generated signature.
- * @param clientPrivateKey private key to generate outbound digital signature. Only {@link
- * RSAPrivateKey} is supported.
- * @return Builder this, to facilitate chaining.
- */
- public Builder setAuthDigitalSignature(
- @NonNull X509Certificate serverCaCert,
- @NonNull X509Certificate clientEndCert,
- @NonNull PrivateKey clientPrivateKey) {
- return setAuthDigitalSignature(
- serverCaCert,
- clientEndCert,
- new LinkedList<X509Certificate>(),
- clientPrivateKey);
- }
-
- /**
- * Uses certificate and digital signature to do IKE authentication.
- *
- * <p>The public key included by the client end certificate and the signature private key
- * MUST come from the same key pair.
- *
- * <p>The IKE library will use the strongest signature algorithm supported by both sides.
- *
- * <p>Currenly only RSA digital signature is supported.
- *
- * @param serverCaCert the CA certificate for validating the received server certificate(s).
- * @param clientEndCert the end certificate for remote server to verify locally generated
- * signature.
- * @param clientIntermediateCerts intermediate certificates for the remote server to
- * validate the end certificate.
- * @param clientPrivateKey private key to generate outbound digital signature. Only {@link
- * RSAPrivateKey} is supported.
- * @return Builder this, to facilitate chaining.
- */
- public Builder setAuthDigitalSignature(
- @NonNull X509Certificate serverCaCert,
- @NonNull X509Certificate clientEndCert,
- @NonNull List<X509Certificate> clientIntermediateCerts,
- @NonNull PrivateKey clientPrivateKey) {
- if (!(clientPrivateKey instanceof RSAPrivateKey)) {
- throw new IllegalArgumentException("Unsupported private key type");
- }
-
- mLocalAuthConfig =
- new IkeAuthDigitalSignLocalConfig(
- clientEndCert, clientIntermediateCerts, clientPrivateKey);
- mRemoteAuthConfig =
- new IkeAuthDigitalSignRemoteConfig(
- new TrustAnchor(serverCaCert, null /*nameConstraints*/));
- return this;
- }
-
- /**
- * Validates, builds and returns the IkeSessionOptions
- *
- * @return IkeSessionOptions the validated IkeSessionOptions
- * @throws IllegalArgumentException if no IKE SA proposal is provided
- */
- public IkeSessionOptions build() {
- if (mSaProposalList.isEmpty()) {
- throw new IllegalArgumentException("IKE SA proposal not found");
- }
- if (mServerAddress == null
- || mUdpEncapSocket == null
- || mLocalIdentification == null
- || mRemoteIdentification == null
- || mLocalAuthConfig == null
- || mRemoteAuthConfig == null) {
- throw new IllegalArgumentException("Necessary parameter missing.");
- }
-
- return new IkeSessionOptions(
- mServerAddress,
- mUdpEncapSocket,
- mSaProposalList.toArray(new IkeSaProposal[mSaProposalList.size()]),
- mLocalIdentification,
- mRemoteIdentification,
- mLocalAuthConfig,
- mRemoteAuthConfig,
- mIsIkeFragmentationSupported);
- }
-
- // TODO: add methods for supporting IKE fragmentation.
- }
-}
diff --git a/src/java/android/net/ipsec/ike/SaProposal.java b/src/java/android/net/ipsec/ike/SaProposal.java
deleted file mode 100644
index 1e0b032e..00000000
--- a/src/java/android/net/ipsec/ike/SaProposal.java
+++ /dev/null
@@ -1,386 +0,0 @@
-/*
- * Copyright (C) 2018 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 android.net.ipsec.ike;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.util.ArraySet;
-import android.util.SparseArray;
-
-import com.android.internal.net.ipsec.ike.message.IkePayload;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload.DhGroupTransform;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload.EncryptionTransform;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload.IntegrityTransform;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload.PrfTransform;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload.Transform;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.Arrays;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Set;
-
-/**
- * SaProposal represents a user configured set contains cryptograhic algorithms and key generating
- * materials for negotiating an IKE or Child SA.
- *
- * <p>User must provide at least a valid SaProposal when they are creating a new IKE SA or Child SA.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key Exchange
- * Protocol Version 2 (IKEv2)</a>
- */
-public abstract class SaProposal {
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({
- ENCRYPTION_ALGORITHM_3DES,
- ENCRYPTION_ALGORITHM_AES_CBC,
- ENCRYPTION_ALGORITHM_AES_GCM_8,
- ENCRYPTION_ALGORITHM_AES_GCM_12,
- ENCRYPTION_ALGORITHM_AES_GCM_16
- })
- public @interface EncryptionAlgorithm {}
-
- public static final int ENCRYPTION_ALGORITHM_3DES = 3;
- public static final int ENCRYPTION_ALGORITHM_AES_CBC = 12;
- public static final int ENCRYPTION_ALGORITHM_AES_GCM_8 = 18;
- public static final int ENCRYPTION_ALGORITHM_AES_GCM_12 = 19;
- public static final int ENCRYPTION_ALGORITHM_AES_GCM_16 = 20;
-
- private static final SparseArray<String> SUPPORTED_ENCRYPTION_ALGO_TO_STR;
-
- static {
- SUPPORTED_ENCRYPTION_ALGO_TO_STR = new SparseArray<>();
- SUPPORTED_ENCRYPTION_ALGO_TO_STR.put(ENCRYPTION_ALGORITHM_3DES, "ENCR_3DES");
- SUPPORTED_ENCRYPTION_ALGO_TO_STR.put(ENCRYPTION_ALGORITHM_AES_CBC, "ENCR_AES_CBC");
- SUPPORTED_ENCRYPTION_ALGO_TO_STR.put(ENCRYPTION_ALGORITHM_AES_GCM_8, "ENCR_AES_GCM_8");
- SUPPORTED_ENCRYPTION_ALGO_TO_STR.put(ENCRYPTION_ALGORITHM_AES_GCM_12, "ENCR_AES_GCM_12");
- SUPPORTED_ENCRYPTION_ALGO_TO_STR.put(ENCRYPTION_ALGORITHM_AES_GCM_16, "ENCR_AES_GCM_16");
- }
-
- public static final int KEY_LEN_UNUSED = 0;
- public static final int KEY_LEN_AES_128 = 128;
- public static final int KEY_LEN_AES_192 = 192;
- public static final int KEY_LEN_AES_256 = 256;
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({PSEUDORANDOM_FUNCTION_HMAC_SHA1, PSEUDORANDOM_FUNCTION_AES128_XCBC})
- public @interface PseudorandomFunction {}
-
- public static final int PSEUDORANDOM_FUNCTION_HMAC_SHA1 = 2;
- public static final int PSEUDORANDOM_FUNCTION_AES128_XCBC = 4;
-
- private static final SparseArray<String> SUPPORTED_PRF_TO_STR;
-
- static {
- SUPPORTED_PRF_TO_STR = new SparseArray<>();
- SUPPORTED_PRF_TO_STR.put(PSEUDORANDOM_FUNCTION_HMAC_SHA1, "PRF_HMAC_SHA1");
- SUPPORTED_PRF_TO_STR.put(PSEUDORANDOM_FUNCTION_AES128_XCBC, "PRF_AES128_XCBC");
- }
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({
- INTEGRITY_ALGORITHM_NONE,
- INTEGRITY_ALGORITHM_HMAC_SHA1_96,
- INTEGRITY_ALGORITHM_AES_XCBC_96,
- INTEGRITY_ALGORITHM_HMAC_SHA2_256_128,
- INTEGRITY_ALGORITHM_HMAC_SHA2_384_192,
- INTEGRITY_ALGORITHM_HMAC_SHA2_512_256
- })
- public @interface IntegrityAlgorithm {}
-
- public static final int INTEGRITY_ALGORITHM_NONE = 0;
- public static final int INTEGRITY_ALGORITHM_HMAC_SHA1_96 = 2;
- public static final int INTEGRITY_ALGORITHM_AES_XCBC_96 = 5;
- public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_256_128 = 12;
- public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_384_192 = 13;
- public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_512_256 = 14;
-
- private static final SparseArray<String> SUPPORTED_INTEGRITY_ALGO_TO_STR;
-
- static {
- SUPPORTED_INTEGRITY_ALGO_TO_STR = new SparseArray<>();
- SUPPORTED_INTEGRITY_ALGO_TO_STR.put(INTEGRITY_ALGORITHM_NONE, "AUTH_NONE");
- SUPPORTED_INTEGRITY_ALGO_TO_STR.put(INTEGRITY_ALGORITHM_HMAC_SHA1_96, "AUTH_HMAC_SHA1_96");
- SUPPORTED_INTEGRITY_ALGO_TO_STR.put(INTEGRITY_ALGORITHM_AES_XCBC_96, "AUTH_AES_XCBC_96");
- SUPPORTED_INTEGRITY_ALGO_TO_STR.put(
- INTEGRITY_ALGORITHM_HMAC_SHA2_256_128, "AUTH_HMAC_SHA2_256_128");
- SUPPORTED_INTEGRITY_ALGO_TO_STR.put(
- INTEGRITY_ALGORITHM_HMAC_SHA2_384_192, "AUTH_HMAC_SHA2_384_192");
- SUPPORTED_INTEGRITY_ALGO_TO_STR.put(
- INTEGRITY_ALGORITHM_HMAC_SHA2_512_256, "AUTH_HMAC_SHA2_512_256");
- }
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({DH_GROUP_NONE, DH_GROUP_1024_BIT_MODP, DH_GROUP_2048_BIT_MODP})
- public @interface DhGroup {}
-
- public static final int DH_GROUP_NONE = 0;
- public static final int DH_GROUP_1024_BIT_MODP = 2;
- public static final int DH_GROUP_2048_BIT_MODP = 14;
-
- private static final SparseArray<String> SUPPORTED_DH_GROUP_TO_STR;
-
- static {
- SUPPORTED_DH_GROUP_TO_STR = new SparseArray<>();
- SUPPORTED_DH_GROUP_TO_STR.put(DH_GROUP_NONE, "DH_NONE");
- SUPPORTED_DH_GROUP_TO_STR.put(DH_GROUP_1024_BIT_MODP, "DH_1024_BIT_MODP");
- SUPPORTED_DH_GROUP_TO_STR.put(DH_GROUP_2048_BIT_MODP, "DH_2048_BIT_MODP");
- }
-
- @IkePayload.ProtocolId private final int mProtocolId;
- private final EncryptionTransform[] mEncryptionAlgorithms;
- private final IntegrityTransform[] mIntegrityAlgorithms;
- private final DhGroupTransform[] mDhGroups;
-
- protected SaProposal(
- @IkePayload.ProtocolId int protocol,
- EncryptionTransform[] encryptionAlgos,
- IntegrityTransform[] integrityAlgos,
- DhGroupTransform[] dhGroups) {
- mProtocolId = protocol;
- mEncryptionAlgorithms = encryptionAlgos;
- mIntegrityAlgorithms = integrityAlgos;
- mDhGroups = dhGroups;
- }
-
- /**
- * Check if the current SaProposal from the SA responder is consistent with the selected
- * reqProposal from the SA initiator.
- *
- * @param reqProposal selected SaProposal from SA initiator
- * @return if current SaProposal from SA responder is consistent with the selected reqProposal
- * from SA initiator.
- */
- public boolean isNegotiatedFrom(SaProposal reqProposal) {
- return this.mProtocolId == reqProposal.mProtocolId
- && isTransformSelectedFrom(mEncryptionAlgorithms, reqProposal.mEncryptionAlgorithms)
- && isTransformSelectedFrom(mIntegrityAlgorithms, reqProposal.mIntegrityAlgorithms)
- && isTransformSelectedFrom(mDhGroups, reqProposal.mDhGroups);
- }
-
- /** Package private */
- static boolean isTransformSelectedFrom(Transform[] selected, Transform[] selectFrom) {
- // If the selected proposal has multiple transforms with the same type, the responder MUST
- // choose a single one.
- if ((selected.length > 1) || (selected.length == 0) != (selectFrom.length == 0)) {
- return false;
- }
-
- if (selected.length == 0) return true;
-
- return Arrays.asList(selectFrom).contains(selected[0]);
- }
-
- @IkePayload.ProtocolId
- public int getProtocolId() {
- return mProtocolId;
- }
-
- public EncryptionTransform[] getEncryptionTransforms() {
- return mEncryptionAlgorithms;
- }
-
- public IntegrityTransform[] getIntegrityTransforms() {
- return mIntegrityAlgorithms;
- }
-
- public DhGroupTransform[] getDhGroupTransforms() {
- return mDhGroups;
- }
-
- protected List<Transform> getAllTransformsAsList() {
- List<Transform> transformList = new LinkedList<>();
-
- transformList.addAll(Arrays.asList(mEncryptionAlgorithms));
- transformList.addAll(Arrays.asList(mIntegrityAlgorithms));
- transformList.addAll(Arrays.asList(mDhGroups));
-
- return transformList;
- }
-
- /**
- * Return all SA Transforms in this SaProposal to be encoded for building an outbound IKE
- * message.
- *
- * <p>This method should be called by only IKE library.
- *
- * @return Array of Transforms to be encoded.
- */
- public abstract Transform[] getAllTransforms();
-
- /** This class is an abstract Builder for building a SaProposal */
- protected abstract static class Builder {
- protected static final String ERROR_TAG = "Invalid SA Proposal: ";
-
- // Use set to avoid adding repeated algorithms.
- protected final Set<EncryptionTransform> mProposedEncryptAlgos = new ArraySet<>();
- protected final Set<PrfTransform> mProposedPrfs = new ArraySet<>();
- protected final Set<IntegrityTransform> mProposedIntegrityAlgos = new ArraySet<>();
- protected final Set<DhGroupTransform> mProposedDhGroups = new ArraySet<>();
-
- protected boolean mHasAead = false;
-
- protected static boolean isAead(@EncryptionAlgorithm int algorithm) {
- switch (algorithm) {
- case ENCRYPTION_ALGORITHM_3DES:
- // Fall through
- case ENCRYPTION_ALGORITHM_AES_CBC:
- return false;
- case ENCRYPTION_ALGORITHM_AES_GCM_8:
- // Fall through
- case ENCRYPTION_ALGORITHM_AES_GCM_12:
- // Fall through
- case ENCRYPTION_ALGORITHM_AES_GCM_16:
- return true;
- default:
- // Won't hit here.
- throw new IllegalArgumentException("Unsupported Encryption Algorithm.");
- }
- }
-
- protected EncryptionTransform[] buildEncryptAlgosOrThrow() {
- if (mProposedEncryptAlgos.isEmpty()) {
- throw new IllegalArgumentException(
- ERROR_TAG + "Encryption algorithm must be proposed.");
- }
-
- return mProposedEncryptAlgos.toArray(
- new EncryptionTransform[mProposedEncryptAlgos.size()]);
- }
-
- protected void validateAndAddEncryptAlgo(
- @EncryptionAlgorithm int algorithm, int keyLength) {
- // Construct EncryptionTransform and validate proposed algorithm during
- // construction.
- EncryptionTransform encryptionTransform = new EncryptionTransform(algorithm, keyLength);
-
- // Validate that only one mode encryption algorithm has been proposed.
- boolean isCurrentAead = isAead(algorithm);
- if (!mProposedEncryptAlgos.isEmpty() && (mHasAead ^ isCurrentAead)) {
- throw new IllegalArgumentException(
- ERROR_TAG
- + "Proposal cannot has both normal ciphers "
- + "and combined-mode ciphers.");
- }
- if (isCurrentAead) mHasAead = true;
-
- mProposedEncryptAlgos.add(encryptionTransform);
- }
-
- protected void addIntegrityAlgo(@IntegrityAlgorithm int algorithm) {
- // Construct IntegrityTransform and validate proposed algorithm during
- // construction.
- mProposedIntegrityAlgos.add(new IntegrityTransform(algorithm));
- }
-
- protected void addDh(@DhGroup int dhGroup) {
- // Construct DhGroupTransform and validate proposed dhGroup during
- // construction.
- mProposedDhGroups.add(new DhGroupTransform(dhGroup));
- }
- }
-
- @Override
- @NonNull
- public String toString() {
- StringBuilder sb = new StringBuilder();
-
- sb.append(IkePayload.getProtocolTypeString(mProtocolId)).append(": ");
-
- int len = getAllTransforms().length;
- for (int i = 0; i < len; i++) {
- sb.append(getAllTransforms()[i].toString());
- if (i < len - 1) sb.append("|");
- }
-
- return sb.toString();
- }
-
- /**
- * Check if the provided algorithm is a supported encryption algorithm.
- *
- * @param algorithm IKE standard encryption algorithm id.
- * @return true if the provided algorithm is a supported encryption algorithm.
- */
- public static boolean isSupportedEncryptionAlgorithm(@EncryptionAlgorithm int algorithm) {
- return SUPPORTED_ENCRYPTION_ALGO_TO_STR.get(algorithm) != null;
- }
-
- /**
- * Check if the provided algorithm is a supported pseudorandom function.
- *
- * @param algorithm IKE standard pseudorandom function id.
- * @return true if the provided algorithm is a supported pseudorandom function.
- */
- public static boolean isSupportedPseudorandomFunction(@PseudorandomFunction int algorithm) {
- return SUPPORTED_PRF_TO_STR.get(algorithm) != null;
- }
-
- /**
- * Check if the provided algorithm is a supported integrity algorithm.
- *
- * @param algorithm IKE standard integrity algorithm id.
- * @return true if the provided algorithm is a supported integrity algorithm.
- */
- public static boolean isSupportedIntegrityAlgorithm(@IntegrityAlgorithm int algorithm) {
- return SUPPORTED_INTEGRITY_ALGO_TO_STR.get(algorithm) != null;
- }
-
- /**
- * Check if the provided group number is for a supported Diffie-Hellman Group.
- *
- * @param dhGroup IKE standard DH Group id.
- * @return true if the provided number is for a supported Diffie-Hellman Group.
- */
- public static boolean isSupportedDhGroup(@DhGroup int dhGroup) {
- return SUPPORTED_DH_GROUP_TO_STR.get(dhGroup) != null;
- }
-
- /** Return the encryption algorithm as a String. */
- public static String getEncryptionAlgorithmString(int algorithm) {
- if (isSupportedEncryptionAlgorithm(algorithm)) {
- return SUPPORTED_ENCRYPTION_ALGO_TO_STR.get(algorithm);
- }
- return "ENC_Unknown_" + algorithm;
- }
-
- /** Return the pseudorandom function as a String. */
- public static String getPseudorandomFunctionString(int algorithm) {
- if (isSupportedPseudorandomFunction(algorithm)) {
- return SUPPORTED_PRF_TO_STR.get(algorithm);
- }
- return "PRF_Unknown_" + algorithm;
- }
-
- /** Return the integrity algorithm as a String. */
- public static String getIntegrityAlgorithmString(int algorithm) {
- if (isSupportedIntegrityAlgorithm(algorithm)) {
- return SUPPORTED_INTEGRITY_ALGO_TO_STR.get(algorithm);
- }
- return "AUTH_Unknown_" + algorithm;
- }
-
- /** Return Diffie-Hellman Group as a String. */
- public static String getDhGroupString(int dhGroup) {
- if (isSupportedDhGroup(dhGroup)) {
- return SUPPORTED_DH_GROUP_TO_STR.get(dhGroup);
- }
- return "DH_Unknown_" + dhGroup;
- }
-}
diff --git a/src/java/android/net/ipsec/ike/TransportModeChildSessionOptions.java b/src/java/android/net/ipsec/ike/TransportModeChildSessionOptions.java
deleted file mode 100644
index 12e0601a..00000000
--- a/src/java/android/net/ipsec/ike/TransportModeChildSessionOptions.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2019 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 android.net.ipsec.ike;
-
-import android.annotation.NonNull;
-
-/**
- * This class contains all user provided configuration options for negotiating a transport mode
- * Child Session.
- */
-public final class TransportModeChildSessionOptions extends ChildSessionOptions {
- private TransportModeChildSessionOptions(
- IkeTrafficSelector[] localTs,
- IkeTrafficSelector[] remoteTs,
- ChildSaProposal[] proposals) {
- super(localTs, remoteTs, proposals, true /*isTransport*/);
- }
-
- /** This class can be used to incrementally construct a TransportModeChildSessionOptions. */
- public static final class Builder extends ChildSessionOptions.Builder {
- /** Create a Builder for negotiating a transport mode Child Session. */
- public Builder() {
- super();
- }
-
- /**
- * Adds an Child SA proposal to TransportModeChildSessionOptions being built.
- *
- * @param proposal Child SA proposal.
- * @return Builder this, to facilitate chaining.
- * @throws IllegalArgumentException if input proposal is not a Child SA proposal.
- */
- public Builder addSaProposal(@NonNull ChildSaProposal proposal) {
- validateAndAddSaProposal(proposal);
- return this;
- }
-
- /**
- * Validates, builds and returns the TransportModeChildSessionOptions.
- *
- * @return the validated TransportModeChildSessionOptions.
- * @throws IllegalArgumentException if no Child SA proposal is provided.
- */
- public TransportModeChildSessionOptions build() {
- validateOrThrow();
-
- return new TransportModeChildSessionOptions(
- mLocalTsList.toArray(new IkeTrafficSelector[mLocalTsList.size()]),
- mRemoteTsList.toArray(new IkeTrafficSelector[mRemoteTsList.size()]),
- mSaProposalList.toArray(new ChildSaProposal[mSaProposalList.size()]));
- }
- }
-}
diff --git a/src/java/android/net/ipsec/ike/TunnelModeChildSessionOptions.java b/src/java/android/net/ipsec/ike/TunnelModeChildSessionOptions.java
deleted file mode 100644
index cb8268cf..00000000
--- a/src/java/android/net/ipsec/ike/TunnelModeChildSessionOptions.java
+++ /dev/null
@@ -1,260 +0,0 @@
-/*
- * Copyright (C) 2019 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 android.net.ipsec.ike;
-
-import static android.system.OsConstants.AF_INET;
-import static android.system.OsConstants.AF_INET6;
-
-import android.annotation.NonNull;
-import android.net.LinkAddress;
-
-import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttribute;
-import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv4Address;
-import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv4Dhcp;
-import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv4Dns;
-import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv4Netmask;
-import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv4Subnet;
-import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv6Address;
-import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv6Dns;
-import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv6Subnet;
-
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.util.LinkedList;
-import java.util.List;
-
-/**
- * This class contains all user provided configuration options for negotiating a tunnel mode Child
- * Session.
- */
-public final class TunnelModeChildSessionOptions extends ChildSessionOptions {
- private final ConfigAttribute[] mConfigRequests;
-
- private TunnelModeChildSessionOptions(
- IkeTrafficSelector[] localTs,
- IkeTrafficSelector[] remoteTs,
- ChildSaProposal[] proposals,
- ConfigAttribute[] configRequests) {
- super(localTs, remoteTs, proposals, false /*isTransport*/);
- mConfigRequests = configRequests;
- }
-
- public ConfigAttribute[] getConfigurationRequests() {
- return mConfigRequests;
- }
-
- /** This class can be used to incrementally construct a TunnelModeChildSessionOptions. */
- public static final class Builder extends ChildSessionOptions.Builder {
- private static final int IPv4_DEFAULT_PREFIX_LEN = 32;
-
- private boolean mHasIp4AddressRequest;
- private List<ConfigAttribute> mConfigRequestList;
-
- /** Create a Builder for negotiating a transport mode Child Session. */
- public Builder() {
- super();
- mHasIp4AddressRequest = false;
- mConfigRequestList = new LinkedList<>();
- }
-
- /**
- * Adds an Child SA proposal to TunnelModeChildSessionOptions being built.
- *
- * @param proposal Child SA proposal.
- * @return Builder this, to facilitate chaining.
- * @throws IllegalArgumentException if input proposal is not a Child SA proposal.
- */
- public Builder addSaProposal(@NonNull ChildSaProposal proposal) {
- validateAndAddSaProposal(proposal);
- return this;
- }
-
- /**
- * Adds internal IP address requests to TunnelModeChildSessionOptions being built.
- *
- * @param addressFamily the address family. Only {@link OsConstants.AF_INET} and {@link
- * OsConstants.AF_INET6} are allowed.
- * @param numOfRequest the number of requests for this type of address.
- * @return Builder this, to facilitate chaining.
- */
- public Builder addInternalAddressRequest(int addressFamily, int numOfRequest) {
- if (addressFamily == AF_INET) {
- mHasIp4AddressRequest = true;
- for (int i = 0; i < numOfRequest; i++) {
- mConfigRequestList.add(new ConfigAttributeIpv4Address());
- }
- return this;
- } else if (addressFamily == AF_INET6) {
- for (int i = 0; i < numOfRequest; i++) {
- mConfigRequestList.add(new ConfigAttributeIpv6Address());
- }
- return this;
- } else {
- throw new IllegalArgumentException("Invalid address family: " + addressFamily);
- }
- }
-
- /**
- * Adds specific internal IP address request to TunnelModeChildSessionOptions being built.
- *
- * @param address the requested address.
- * @param prefixLen length of the InetAddress prefix. When requesting an IPv4 address,
- * prefixLen MUST be 32.
- * @return Builder this, to facilitate chaining.
- */
- public Builder addInternalAddressRequest(@NonNull InetAddress address, int prefixLen) {
- if (address instanceof Inet4Address) {
- if (prefixLen != IPv4_DEFAULT_PREFIX_LEN) {
- throw new IllegalArgumentException("Invalid IPv4 prefix length: " + prefixLen);
- }
- mHasIp4AddressRequest = true;
- mConfigRequestList.add(new ConfigAttributeIpv4Address((Inet4Address) address));
- return this;
- } else if (address instanceof Inet6Address) {
- mConfigRequestList.add(
- new ConfigAttributeIpv6Address(new LinkAddress(address, prefixLen)));
- return this;
- } else {
- throw new IllegalArgumentException("Invalid address " + address);
- }
- }
-
- /**
- * Adds internal DNS server requests to TunnelModeChildSessionOptions being built.
- *
- * @param addressFamily the address family. Only {@link OsConstants.AF_INET} and {@link
- * OsConstants.AF_INET6} are allowed.
- * @param numOfRequest the number of requests for this type of address.
- * @return Builder this, to facilitate chaining.
- */
- public Builder addInternalDnsServerRequest(int addressFamily, int numOfRequest) {
- if (addressFamily == AF_INET) {
- for (int i = 0; i < numOfRequest; i++) {
- mConfigRequestList.add(new ConfigAttributeIpv4Dns());
- }
- return this;
- } else if (addressFamily == AF_INET6) {
- for (int i = 0; i < numOfRequest; i++) {
- mConfigRequestList.add(new ConfigAttributeIpv6Dns());
- }
- return this;
- } else {
- throw new IllegalArgumentException("Invalid address family: " + addressFamily);
- }
- }
-
- /**
- * Adds internal DNS server requests to TunnelModeChildSessionOptions being built.
- *
- * @param address the requested DNS server address.
- * @return Builder this, to facilitate chaining.
- */
- public Builder addInternalDnsServerRequest(@NonNull InetAddress address) {
- if (address instanceof Inet4Address) {
- mConfigRequestList.add(new ConfigAttributeIpv4Dns((Inet4Address) address));
- return this;
- } else if (address instanceof Inet6Address) {
- mConfigRequestList.add(new ConfigAttributeIpv6Dns((Inet6Address) address));
- return this;
- } else {
- throw new IllegalArgumentException("Invalid address " + address);
- }
- }
-
- /**
- * Adds internal subnet requests to TunnelModeChildSessionOptions being built.
- *
- * @param addressFamily the address family. Only {@link OsConstants.AF_INET} and {@link
- * OsConstants.AF_INET6} are allowed.
- * @param numOfRequest the number of requests for this type of address.
- * @return Builder this, to facilitate chaining.
- */
- public Builder addInternalSubnetRequest(int addressFamily, int numOfRequest) {
- if (addressFamily == AF_INET) {
- for (int i = 0; i < numOfRequest; i++) {
- mConfigRequestList.add(new ConfigAttributeIpv4Subnet());
- }
- return this;
- } else if (addressFamily == AF_INET6) {
- for (int i = 0; i < numOfRequest; i++) {
- mConfigRequestList.add(new ConfigAttributeIpv6Subnet());
- }
- return this;
- } else {
- throw new IllegalArgumentException("Invalid address family: " + addressFamily);
- }
- }
-
- /**
- * Adds internal DHCP server requests to TunnelModeChildSessionOptions being built.
- *
- * <p>Only DHCP4 server requests are supported.
- *
- * @param addressFamily the address family. Only {@link OsConstants.AF_INET} is allowed.
- * @param numOfRequest the number of requests for this type of address.
- * @return Builder this, to facilitate chaining.
- */
- public Builder addInternalDhcpServerRequest(int addressFamily, int numOfRequest) {
- if (addressFamily == AF_INET) {
- for (int i = 0; i < numOfRequest; i++) {
- mConfigRequestList.add(new ConfigAttributeIpv4Dhcp());
- }
- return this;
- } else {
- throw new IllegalArgumentException("Invalid address family: " + addressFamily);
- }
- }
-
- /**
- * Adds internal DHCP server requests to TunnelModeChildSessionOptions being built.
- *
- * <p>Only DHCP4 server requests are supported.
- *
- * @param address the requested DHCP server address.
- * @return Builder this, to facilitate chaining.
- */
- public Builder addInternalDhcpServerRequest(@NonNull InetAddress address) {
- if (address instanceof Inet4Address) {
- mConfigRequestList.add(new ConfigAttributeIpv4Dhcp((Inet4Address) address));
- return this;
- } else {
- throw new IllegalArgumentException("Invalid address " + address);
- }
- }
-
- /**
- * Validates, builds and returns the TunnelModeChildSessionOptions.
- *
- * @return the validated TunnelModeChildSessionOptions.
- * @throws IllegalArgumentException if no Child SA proposal is provided.
- */
- public TunnelModeChildSessionOptions build() {
- validateOrThrow();
-
- if (mHasIp4AddressRequest) {
- mConfigRequestList.add(new ConfigAttributeIpv4Netmask());
- }
-
- return new TunnelModeChildSessionOptions(
- mLocalTsList.toArray(new IkeTrafficSelector[mLocalTsList.size()]),
- mRemoteTsList.toArray(new IkeTrafficSelector[mRemoteTsList.size()]),
- mSaProposalList.toArray(new ChildSaProposal[mSaProposalList.size()]),
- mConfigRequestList.toArray(new ConfigAttribute[mConfigRequestList.size()]));
- }
- }
-}
diff --git a/src/java/android/net/ipsec/ike/exceptions/IkeException.java b/src/java/android/net/ipsec/ike/exceptions/IkeException.java
deleted file mode 100644
index 867dcf5e..00000000
--- a/src/java/android/net/ipsec/ike/exceptions/IkeException.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2019 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 android.net.ipsec.ike.exceptions;
-
-/**
- * IkeException is a generic IKE library exception class that provides type safety for all the
- * IKE-library-related exception classes that extend from it.
- */
-public abstract class IkeException extends Exception {
- protected IkeException() {
- super();
- }
-
- protected IkeException(String message) {
- super(message);
- }
-
- protected IkeException(Throwable cause) {
- super(cause);
- }
-
- protected IkeException(String message, Throwable cause) {
- super(message, cause);
- }
-
- /**
- * Returns if this exception is caused by an IKE protocol error.
- *
- * @return true if this exception is caused by an IKE protocol error, false otherwise.
- */
- public boolean isProtocolException() {
- return this instanceof IkeProtocolException;
- }
-}
diff --git a/src/java/android/net/ipsec/ike/exceptions/IkeInternalException.java b/src/java/android/net/ipsec/ike/exceptions/IkeInternalException.java
deleted file mode 100644
index 29a5af94..00000000
--- a/src/java/android/net/ipsec/ike/exceptions/IkeInternalException.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2019 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 android.net.ipsec.ike.exceptions;
-
-/**
- * IkeInternalException represents all IKE-library-related exceptions that are not IKE protocol
- * error.
- */
-public final class IkeInternalException extends IkeException {
- /**
- * Constructs a new exception with the specified cause.
- *
- * @param cause the cause (which is saved for later retrieval by the {@link #getCause()}
- * method).
- */
- public IkeInternalException(Throwable cause) {
- super(cause);
- }
-
- /**
- * Constructs a new exception with the specified cause.
- *
- * @param message the descriptive message.
- * @param cause the cause (which is saved for later retrieval by the {@link #getCause()}
- * method).
- */
- public IkeInternalException(String message, Throwable cause) {
- super(message, cause);
- }
-}
diff --git a/src/java/android/net/ipsec/ike/exceptions/IkeProtocolException.java b/src/java/android/net/ipsec/ike/exceptions/IkeProtocolException.java
deleted file mode 100644
index f589a267..00000000
--- a/src/java/android/net/ipsec/ike/exceptions/IkeProtocolException.java
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Copyright (C) 2019 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 android.net.ipsec.ike.exceptions;
-
-import android.annotation.IntDef;
-
-import com.android.internal.net.ipsec.ike.message.IkeNotifyPayload;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.nio.ByteBuffer;
-
-/**
- * IkeProtocolException is an abstract class that represents the common information for all IKE
- * protocol errors.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.10.1">RFC 7296, Internet Key Exchange
- * Protocol Version 2 (IKEv2)</a>
- */
-public abstract class IkeProtocolException extends IkeException {
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({
- ERROR_TYPE_UNSUPPORTED_CRITICAL_PAYLOAD,
- ERROR_TYPE_INVALID_IKE_SPI,
- ERROR_TYPE_INVALID_MAJOR_VERSION,
- ERROR_TYPE_INVALID_SYNTAX,
- ERROR_TYPE_INVALID_MESSAGE_ID,
- ERROR_TYPE_NO_PROPOSAL_CHOSEN,
- ERROR_TYPE_INVALID_KE_PAYLOAD,
- ERROR_TYPE_AUTHENTICATION_FAILED,
- ERROR_TYPE_SINGLE_PAIR_REQUIRED,
- ERROR_TYPE_NO_ADDITIONAL_SAS,
- ERROR_TYPE_INTERNAL_ADDRESS_FAILURE,
- ERROR_TYPE_FAILED_CP_REQUIRED,
- ERROR_TYPE_TS_UNACCEPTABLE,
- ERROR_TYPE_INVALID_SELECTORS,
- ERROR_TYPE_TEMPORARY_FAILURE,
- ERROR_TYPE_CHILD_SA_NOT_FOUND,
- })
- public @interface ErrorType {}
-
- public static final int ERROR_TYPE_UNSUPPORTED_CRITICAL_PAYLOAD = 1;
- public static final int ERROR_TYPE_INVALID_IKE_SPI = 4;
- public static final int ERROR_TYPE_INVALID_MAJOR_VERSION = 5;
- public static final int ERROR_TYPE_INVALID_SYNTAX = 7;
- public static final int ERROR_TYPE_INVALID_MESSAGE_ID = 9;
- public static final int ERROR_TYPE_NO_PROPOSAL_CHOSEN = 14;
- public static final int ERROR_TYPE_INVALID_KE_PAYLOAD = 17;
- public static final int ERROR_TYPE_AUTHENTICATION_FAILED = 24;
- public static final int ERROR_TYPE_SINGLE_PAIR_REQUIRED = 34;
- public static final int ERROR_TYPE_NO_ADDITIONAL_SAS = 35;
- public static final int ERROR_TYPE_INTERNAL_ADDRESS_FAILURE = 36;
- public static final int ERROR_TYPE_FAILED_CP_REQUIRED = 37;
- public static final int ERROR_TYPE_TS_UNACCEPTABLE = 38;
- public static final int ERROR_TYPE_INVALID_SELECTORS = 39;
- public static final int ERROR_TYPE_TEMPORARY_FAILURE = 43;
- public static final int ERROR_TYPE_CHILD_SA_NOT_FOUND = 44;
-
- public static final byte[] ERROR_DATA_NOT_INCLUDED = new byte[0];
-
- private static final int INTEGER_BYTE_SIZE = 4;
-
- @ErrorType private final int mErrorType;
- private final byte[] mErrorData;
-
- protected IkeProtocolException(@ErrorType int code) {
- super();
- mErrorType = code;
- mErrorData = ERROR_DATA_NOT_INCLUDED;
- }
-
- protected IkeProtocolException(@ErrorType int code, String message) {
- super(message);
- mErrorType = code;
- mErrorData = ERROR_DATA_NOT_INCLUDED;
- }
-
- protected IkeProtocolException(@ErrorType int code, Throwable cause) {
- super(cause);
- mErrorType = code;
- mErrorData = ERROR_DATA_NOT_INCLUDED;
- }
-
- protected IkeProtocolException(@ErrorType int code, String message, Throwable cause) {
- super(message, cause);
- mErrorType = code;
- mErrorData = ERROR_DATA_NOT_INCLUDED;
- }
-
- // Construct an instance from a notify Payload.
- protected IkeProtocolException(@ErrorType int code, byte[] notifyData) {
- super();
-
- if (!isValidDataLength(notifyData.length)) {
- throw new IllegalArgumentException(
- "Invalid error data for error type: "
- + code
- + " Received error data size: "
- + notifyData.length);
- }
-
- mErrorType = code;
- mErrorData = notifyData;
- }
-
- protected abstract boolean isValidDataLength(int dataLen);
-
- protected static byte[] integerToByteArray(int integer, int arraySize) {
- if (arraySize > INTEGER_BYTE_SIZE) {
- throw new IllegalArgumentException(
- "Cannot convert integer to a byte array of length: " + arraySize);
- }
-
- ByteBuffer dataBuffer = ByteBuffer.allocate(INTEGER_BYTE_SIZE);
- dataBuffer.putInt(integer);
- dataBuffer.rewind();
-
- byte[] zeroPad = new byte[INTEGER_BYTE_SIZE - arraySize];
- byte[] byteData = new byte[arraySize];
- dataBuffer.get(zeroPad).get(byteData);
-
- return byteData;
- }
-
- protected static int byteArrayToInteger(byte[] byteArray) {
- if (byteArray == null || byteArray.length > INTEGER_BYTE_SIZE) {
- throw new IllegalArgumentException("Cannot convert the byte array to integer");
- }
-
- ByteBuffer dataBuffer = ByteBuffer.allocate(INTEGER_BYTE_SIZE);
- byte[] zeroPad = new byte[INTEGER_BYTE_SIZE - byteArray.length];
- dataBuffer.put(zeroPad).put(byteArray);
- dataBuffer.rewind();
-
- return dataBuffer.getInt();
- }
-
- /**
- * Returns the IKE standard protocol error type of this {@link IkeProtocolException} instance.
- *
- * @return the IKE standard protocol error type.
- */
- @ErrorType
- public int getErrorType() {
- return mErrorType;
- }
-
- /**
- * Returns the included error data of this {@link IkeProtocolException} instance.
- *
- * <p>Note that only few error types will go with an error data. This data has different meaning
- * with different error types. Users should first check if an error data is included before they
- * call this method.
- *
- * @return the included error data in byte array.
- */
- public byte[] getErrorData() {
- return mErrorData;
- }
-
- /**
- * Build an IKE Notification Payload for this {@link IkeProtocolException} instance.
- *
- * @return the notification payload.
- */
- public IkeNotifyPayload buildNotifyPayload() {
- return new IkeNotifyPayload(mErrorType, mErrorData);
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapMsChapV2AwaitingEapFailureStateTest.java b/src/java/com/android/ike/ikev2/ChildSessionOptions.java
index 1dd60c0c..b311c666 100644
--- a/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapMsChapV2AwaitingEapFailureStateTest.java
+++ b/src/java/com/android/ike/ikev2/ChildSessionOptions.java
@@ -14,16 +14,12 @@
* limitations under the License.
*/
-package com.android.internal.net.eap.statemachine;
+package com.android.ike.ikev2;
-import org.junit.Before;
-
-public class EapMsChapV2AwaitingEapFailureStateTest extends EapMsChapV2StateTest {
- @Before
- @Override
- public void setUp() {
- super.setUp();
-
- mStateMachine.transitionTo(mStateMachine.new AwaitingEapFailureState());
- }
+/**
+ * ChildSessionOptions contains user-provided Child SA proposals and negotiated Child SA
+ * information.
+ */
+public final class ChildSessionOptions {
+ // TODO: Implement it.
}
diff --git a/src/java/com/android/ike/ikev2/ChildSessionStateMachine.java b/src/java/com/android/ike/ikev2/ChildSessionStateMachine.java
new file mode 100644
index 00000000..81822d5c
--- /dev/null
+++ b/src/java/com/android/ike/ikev2/ChildSessionStateMachine.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2019 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.ike.ikev2;
+
+import android.os.Looper;
+import android.os.Message;
+
+import com.android.ike.ikev2.IkeSessionStateMachine.IChildSessionCallback;
+import com.android.ike.ikev2.SaRecord.ChildSaRecord;
+import com.android.ike.ikev2.exceptions.IkeException;
+import com.android.ike.ikev2.message.IkePayload;
+import com.android.ike.ikev2.message.IkeSaPayload;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.State;
+import com.android.internal.util.StateMachine;
+
+import java.util.List;
+
+/**
+ * ChildSessionStateMachine tracks states and manages exchanges of this Child Session.
+ *
+ * <p>ChildSessionStateMachine has two types of states. One type are states where there is no
+ * ongoing procedure affecting Child Session (non-procedure state), including Initial, Closed, Idle
+ * and Receiving. All other states are "procedure" states which are named as follows:
+ *
+ * <pre>
+ * State Name = [Procedure Type] + [Exchange Initiator] + [Exchange Type].
+ * - An IKE procedure consists of one or two IKE exchanges:
+ * Procedure Type = {CreateChild | DeleteChild | Info | RekeyChild | SimulRekeyChild}.
+ * - Exchange Initiator indicates whether local or remote peer is the exchange initiator:
+ * Exchange Initiator = {Local | Remote}
+ * - Exchange type defines the function of this exchange.
+ * Exchange Type = {Create | Delete}
+ * </pre>
+ */
+public class ChildSessionStateMachine extends StateMachine {
+ private static final String TAG = "ChildSessionStateMachine";
+
+ /** Receive request for negotiating first Child SA. */
+ private static final int CMD_HANDLE_FIRST_CHILD_EXCHANGE = 1;
+
+ private final ChildSessionOptions mChildSessionOptions;
+
+ /** Package private */
+ @VisibleForTesting ChildSaRecord mCurrentChildSaRecord;
+
+ private final State mInitial = new Initial();
+ private final State mClosed = new Closed();
+ private final State mIdle = new Idle();
+
+ /** Package private */
+ ChildSessionStateMachine(String name, Looper looper, ChildSessionOptions sessionOptions) {
+ super(name, looper);
+
+ mChildSessionOptions = sessionOptions;
+
+ addState(mInitial);
+ addState(mClosed);
+ addState(mIdle);
+
+ setInitialState(mInitial);
+ }
+
+ private void validateCreateChildResp(
+ List<IkePayload> reqPayloads, List<IkePayload> respPayloads) throws IkeException {
+ // TODO: Validate SA reponse against request and set negotiated SA in mChildSessionOptions.
+ return;
+ }
+
+ /**
+ * Receive requesting and responding payloads for negotiating first Child SA.
+ *
+ * <p>This method is called synchronously from IkeStateMachine. It proxies the synchronous call
+ * as an asynchronous job to the ChildStateMachine handler.
+ *
+ * @param reqPayloads SA negotiation related payloads in IKE_AUTH request.
+ * @param respPayloads SA negotiation related payloads in IKE_AUTH response.
+ * @param callback callback for notifying IkeSessionStateMachine the negotiation result.
+ */
+ public void handleFirstChildExchange(
+ List<IkePayload> reqPayloads,
+ List<IkePayload> respPayloads,
+ IChildSessionCallback callback) {
+ registerProvisionalChildSession(respPayloads, callback);
+
+ sendMessage(
+ CMD_HANDLE_FIRST_CHILD_EXCHANGE,
+ new FirstChildNegotiationData(reqPayloads, respPayloads, callback));
+ }
+
+ /**
+ * Register provisioning ChildSessionStateMachine in IChildSessionCallback
+ *
+ * <p>This method is for avoiding CHILD_SA_NOT_FOUND error in IkeSessionStateMachine when remote
+ * peer sends request for delete/rekey this Child SA before ChildSessionStateMachine sends
+ * FirstChildNegotiationData to itself.
+ */
+ private void registerProvisionalChildSession(
+ List<IkePayload> respPayloads, IChildSessionCallback callback) {
+ // When decoding responding IkeSaPayload in IkeSessionStateMachine, it is validated that
+ // IkeSaPayload has exactly one IkeSaPayload.Proposal.
+ IkeSaPayload saPayload = null;
+ for (IkePayload payload : respPayloads) {
+ if (payload.payloadType == IkePayload.PAYLOAD_TYPE_SA) {
+ saPayload = (IkeSaPayload) payload;
+ break;
+ }
+ }
+ if (saPayload == null) {
+ throw new IllegalArgumentException(
+ "Receive no SA payload for first Child SA negotiation.");
+ }
+ // IkeSaPayload.Proposal stores SPI in long type so as to be applied to both 8-byte IKE SPI
+ // and 4-byte Child SPI. Here we cast the stored SPI to int to represent a Child SPI.
+ int remoteGenSpi = (int) (saPayload.proposalList.get(0).spi);
+ callback.onCreateChildSa(remoteGenSpi, this);
+ }
+
+ /**
+ * FirstChildNegotiationData contains payloads for negotiating first Child SA in IKE_AUTH
+ * request and IKE_AUTH response and callback to notify IkeSessionStateMachine the SA
+ * negotiation result.
+ */
+ private static class FirstChildNegotiationData {
+ public final List<IkePayload> requestPayloads;
+ public final List<IkePayload> responsePayloads;
+ public final IChildSessionCallback childCallback;
+
+ FirstChildNegotiationData(
+ List<IkePayload> reqPayloads,
+ List<IkePayload> respPayloads,
+ IChildSessionCallback callback) {
+ requestPayloads = reqPayloads;
+ responsePayloads = respPayloads;
+ childCallback = callback;
+ }
+ }
+
+ /** Initial state of ChildSessionStateMachine. */
+ class Initial extends State {
+ @Override
+ public boolean processMessage(Message message) {
+ switch (message.what) {
+ // TODO: Handle local request for creating Child SA.
+ case CMD_HANDLE_FIRST_CHILD_EXCHANGE:
+ FirstChildNegotiationData childNegotiationData =
+ (FirstChildNegotiationData) message.obj;
+ try {
+ List<IkePayload> reqPayloads = childNegotiationData.requestPayloads;
+ List<IkePayload> respPayloads = childNegotiationData.responsePayloads;
+ validateCreateChildResp(reqPayloads, respPayloads);
+
+ mCurrentChildSaRecord =
+ ChildSaRecord.makeChildSaRecord(reqPayloads, respPayloads);
+ // TODO: Add mCurrentChildSaRecord in mSpiToSaRecordMap.
+ transitionTo(mIdle);
+ } catch (IkeException e) {
+ // TODO: Unregister remotely generated SPI and handle Child SA negotiation
+ // failure.
+ }
+ return HANDLED;
+ default:
+ return NOT_HANDLED;
+ }
+ }
+ }
+
+ /**
+ * Closed represents the state when this ChildSessionStateMachine is closed, and no further
+ * actions can be performed on it.
+ */
+ class Closed extends State {
+ // TODO: Implement it.
+ }
+
+ /**
+ * Idle represents a state when there is no ongoing IKE exchange affecting established Child SA.
+ */
+ class Idle extends State {
+ // TODO: Implement it.
+ }
+
+ // TODO: Add states to support creating additional Child SA, deleting Child SA and rekeying
+ // Child SA.
+}
diff --git a/src/java/com/android/internal/net/ipsec/ike/ChildSessionStateMachineFactory.java b/src/java/com/android/ike/ikev2/ChildSessionStateMachineFactory.java
index 5282d022..f182111f 100644
--- a/src/java/com/android/internal/net/ipsec/ike/ChildSessionStateMachineFactory.java
+++ b/src/java/com/android/ike/ikev2/ChildSessionStateMachineFactory.java
@@ -14,35 +14,22 @@
* limitations under the License.
*/
-package com.android.internal.net.ipsec.ike;
+package com.android.ike.ikev2;
-import android.content.Context;
-import android.net.IpSecManager;
-import android.net.ipsec.ike.ChildSessionCallback;
-import android.net.ipsec.ike.ChildSessionOptions;
import android.os.Looper;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.net.ipsec.ike.ChildSessionStateMachine.IChildSessionSmCallback;
-
-import java.util.concurrent.Executor;
/** Package private factory for making ChildSessionStateMachine. */
-// TODO: Make it a inner Creator class of ChildSessionStateMachine
+//TODO: Make it a inner Creator class of ChildSessionStateMachine
final class ChildSessionStateMachineFactory {
private static IChildSessionFactoryHelper sChildSessionHelper = new ChildSessionFactoryHelper();
/** Package private. */
static ChildSessionStateMachine makeChildSessionStateMachine(
- Looper looper,
- Context context,
- ChildSessionOptions sessionOptions,
- Executor userCbExecutor,
- ChildSessionCallback userCallbacks,
- IChildSessionSmCallback childSmCallback) {
- return sChildSessionHelper.makeChildSessionStateMachine(
- looper, context, sessionOptions, userCbExecutor, userCallbacks, childSmCallback);
+ String name, Looper looper, ChildSessionOptions sessionOptions) {
+ return sChildSessionHelper.makeChildSessionStateMachine(name, looper, sessionOptions);
}
@VisibleForTesting
@@ -58,12 +45,7 @@ final class ChildSessionStateMachineFactory {
*/
interface IChildSessionFactoryHelper {
ChildSessionStateMachine makeChildSessionStateMachine(
- Looper looper,
- Context context,
- ChildSessionOptions sessionOptions,
- Executor userCbExecutor,
- ChildSessionCallback userCallbacks,
- IChildSessionSmCallback childSmCallback);
+ String name, Looper looper, ChildSessionOptions sessionOptions);
}
/**
@@ -73,21 +55,9 @@ final class ChildSessionStateMachineFactory {
*/
static class ChildSessionFactoryHelper implements IChildSessionFactoryHelper {
public ChildSessionStateMachine makeChildSessionStateMachine(
- Looper looper,
- Context context,
- ChildSessionOptions sessionOptions,
- Executor userCbExecutor,
- ChildSessionCallback userCallbacks,
- IChildSessionSmCallback childSmCallback) {
+ String name, Looper looper, ChildSessionOptions sessionOptions) {
ChildSessionStateMachine childSession =
- new ChildSessionStateMachine(
- looper,
- context,
- (IpSecManager) context.getSystemService(Context.IPSEC_SERVICE),
- sessionOptions,
- userCbExecutor,
- userCallbacks,
- childSmCallback);
+ new ChildSessionStateMachine(name, looper, sessionOptions);
childSession.start();
return childSession;
}
diff --git a/src/java/com/android/internal/net/ipsec/ike/IkeDhParams.java b/src/java/com/android/ike/ikev2/IkeDhParams.java
index 44373fc9..604353a9 100644
--- a/src/java/com/android/internal/net/ipsec/ike/IkeDhParams.java
+++ b/src/java/com/android/ike/ikev2/IkeDhParams.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.internal.net.ipsec.ike;
+package com.android.ike.ikev2;
/** IkeDhParams contains Diffie-Hellman constants for IKEv2 supported DH Groups */
public class IkeDhParams {
diff --git a/src/java/com/android/ike/ikev2/IkeIdentification.java b/src/java/com/android/ike/ikev2/IkeIdentification.java
new file mode 100644
index 00000000..994a024f
--- /dev/null
+++ b/src/java/com/android/ike/ikev2/IkeIdentification.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2018 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.ike.ikev2;
+
+import android.annotation.IntDef;
+import android.util.ArraySet;
+
+import com.android.ike.ikev2.exceptions.AuthenticationFailedException;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.UnknownHostException;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * IkeIdentification is abstract base class that represents the common information for all types of
+ * IKE entity identification.
+ *
+ * <p>IkeIdentification can be user configured or be constructed from an inbound packet.
+ *
+ * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.5">RFC 7296, Internet Key Exchange
+ * Protocol Version 2 (IKEv2)</a>
+ */
+public abstract class IkeIdentification {
+ // Set of supported ID types.
+ private static final Set<Integer> SUPPORTED_ID_TYPES;
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({
+ ID_TYPE_IPV4_ADDR,
+ ID_TYPE_FQDN,
+ ID_TYPE_RFC822_ADDR,
+ ID_TYPE_IPV6_ADDR,
+ ID_TYPE_DER_ASN1_DN,
+ ID_TYPE_DER_ASN1_GN,
+ ID_TYPE_KEY_ID
+ })
+ public @interface IdType {}
+
+ public static final int ID_TYPE_IPV4_ADDR = 1;
+ public static final int ID_TYPE_FQDN = 2;
+ public static final int ID_TYPE_RFC822_ADDR = 3;
+ public static final int ID_TYPE_IPV6_ADDR = 5;
+ public static final int ID_TYPE_DER_ASN1_DN = 9;
+ public static final int ID_TYPE_DER_ASN1_GN = 10;
+ public static final int ID_TYPE_KEY_ID = 11;
+
+ static {
+ SUPPORTED_ID_TYPES = new ArraySet();
+ SUPPORTED_ID_TYPES.add(ID_TYPE_IPV4_ADDR);
+ SUPPORTED_ID_TYPES.add(ID_TYPE_FQDN);
+ SUPPORTED_ID_TYPES.add(ID_TYPE_RFC822_ADDR);
+ SUPPORTED_ID_TYPES.add(ID_TYPE_IPV6_ADDR);
+ SUPPORTED_ID_TYPES.add(ID_TYPE_DER_ASN1_DN);
+ SUPPORTED_ID_TYPES.add(ID_TYPE_DER_ASN1_GN);
+ SUPPORTED_ID_TYPES.add(ID_TYPE_KEY_ID);
+ }
+
+ public final int idType;
+
+ protected IkeIdentification(@IdType int type) {
+ idType = type;
+ }
+
+ /**
+ * Return the encoded identification data in a byte array.
+ *
+ * @return the encoded identification data.
+ */
+ public abstract byte[] getEncodedIdData();
+
+ /** IkeIpv4AddrIdentification represents ID information in IPv4 address ID type. */
+ public static class IkeIpv4AddrIdentification extends IkeIdentification {
+ public final Inet4Address ipv4Address;
+
+ /**
+ * Construct an instance of IkeIpv4AddrIdentification from decoding an inbound packet.
+ *
+ * @param ipv4AddrBytes IPv4 address in byte array.
+ * @throws AuthenticationFailedException for decoding bytes error.
+ */
+ public IkeIpv4AddrIdentification(byte[] ipv4AddrBytes)
+ throws AuthenticationFailedException {
+ super(ID_TYPE_IPV4_ADDR);
+ try {
+ ipv4Address = (Inet4Address) (Inet4Address.getByAddress(ipv4AddrBytes));
+ } catch (ClassCastException | UnknownHostException e) {
+ throw new AuthenticationFailedException(e);
+ }
+ }
+
+ /**
+ * Construct an instance of IkeIpv4AddrIdentification with user provided IPv4 address for
+ * building outbound packet.
+ *
+ * @param address user provided IPv4 address
+ */
+ public IkeIpv4AddrIdentification(Inet4Address address) {
+ super(ID_TYPE_IPV4_ADDR);
+ ipv4Address = address;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(idType, ipv4Address);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof IkeIpv4AddrIdentification)) return false;
+
+ return ipv4Address.equals(((IkeIpv4AddrIdentification) o).ipv4Address);
+ }
+
+ /**
+ * Retrieve the byte-representation of the IPv4 address.
+ *
+ * @return the byte-representation of the IPv4 address.
+ */
+ @Override
+ public byte[] getEncodedIdData() {
+ return ipv4Address.getAddress();
+ }
+ }
+
+ /** IkeIpv6AddrIdentification represents ID information in IPv6 address ID type. */
+ public static class IkeIpv6AddrIdentification extends IkeIdentification {
+ public final Inet6Address ipv6Address;
+
+ /**
+ * Construct an instance of IkeIpv6AddrIdentification from decoding an inbound packet.
+ *
+ * @param ipv6AddrBytes IPv6 address in byte array.
+ * @throws AuthenticationFailedException for decoding bytes error.
+ */
+ public IkeIpv6AddrIdentification(byte[] ipv6AddrBytes)
+ throws AuthenticationFailedException {
+ super(ID_TYPE_IPV6_ADDR);
+ try {
+ ipv6Address = (Inet6Address) (Inet6Address.getByAddress(ipv6AddrBytes));
+ } catch (ClassCastException | UnknownHostException e) {
+ throw new AuthenticationFailedException(e);
+ }
+ }
+
+ /**
+ * Construct an instance of IkeIpv6AddrIdentification with user provided IPv6 address for
+ * building outbound packet.
+ *
+ * @param address user provided IPv6 address
+ */
+ public IkeIpv6AddrIdentification(Inet6Address address) {
+ super(ID_TYPE_IPV6_ADDR);
+ ipv6Address = address;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(idType, ipv6Address);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof IkeIpv6AddrIdentification)) return false;
+
+ return ipv6Address.equals(((IkeIpv6AddrIdentification) o).ipv6Address);
+ }
+
+ /**
+ * Retrieve the byte-representation of the IPv6 address.
+ *
+ * @return the byte-representation of the IPv6 address.
+ */
+ @Override
+ public byte[] getEncodedIdData() {
+ return ipv6Address.getAddress();
+ }
+ }
+}
diff --git a/src/java/com/android/ike/ikev2/IkeSessionOptions.java b/src/java/com/android/ike/ikev2/IkeSessionOptions.java
new file mode 100644
index 00000000..9f2094f2
--- /dev/null
+++ b/src/java/com/android/ike/ikev2/IkeSessionOptions.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2019 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.ike.ikev2;
+
+import android.net.IpSecManager.UdpEncapsulationSocket;
+
+import com.android.ike.ikev2.message.IkePayload;
+
+import java.net.InetAddress;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * IkeSessionOptions contains all user provided configurations for negotiating an IKE SA.
+ *
+ * <p>TODO: Make this doc more user-friendly.
+ */
+public final class IkeSessionOptions {
+ private final InetAddress mServerAddress;
+ private final UdpEncapsulationSocket mUdpEncapSocket;
+ private final SaProposal[] mSaProposals;
+ private final boolean mIsIkeFragmentationSupported;
+
+ private IkeSessionOptions(
+ InetAddress serverAddress,
+ UdpEncapsulationSocket udpEncapsulationSocket,
+ SaProposal[] proposals,
+ boolean isIkeFragmentationSupported) {
+ mServerAddress = serverAddress;
+ mUdpEncapSocket = udpEncapsulationSocket;
+ mSaProposals = proposals;
+ mIsIkeFragmentationSupported = isIkeFragmentationSupported;
+ }
+
+ /** Package private */
+ InetAddress getServerAddress() {
+ return mServerAddress;
+ }
+ /** Package private */
+ UdpEncapsulationSocket getUdpEncapsulationSocket() {
+ return mUdpEncapSocket;
+ }
+ /** Package private */
+ SaProposal[] getSaProposals() {
+ return mSaProposals;
+ }
+ /** Package private */
+ boolean isIkeFragmentationSupported() {
+ return mIsIkeFragmentationSupported;
+ }
+
+ /** This class can be used to incrementally construct a IkeSessionOptions. */
+ public static final class Builder {
+ private final InetAddress mServerAddress;
+ private final UdpEncapsulationSocket mUdpEncapSocket;
+ private final List<SaProposal> mSaProposalList = new LinkedList<>();
+
+ private boolean mIsIkeFragmentationSupported = false;
+
+ /**
+ * Returns a new Builder for an IkeSessionOptions.
+ *
+ * @param serverAddress IP address of remote IKE server.
+ * @param udpEncapsulationSocket {@link IpSecManager.UdpEncapsulationSocket} for sending and
+ * receiving IKE message.
+ * @return Builder for an IkeSessionOptions.
+ */
+ public Builder(InetAddress serverAddress, UdpEncapsulationSocket udpEncapsulationSocket) {
+ mServerAddress = serverAddress;
+ mUdpEncapSocket = udpEncapsulationSocket;
+ }
+
+ /**
+ * Adds an IKE SA proposal to IkeSessionOptions being built.
+ *
+ * @param proposal IKE SA proposal.
+ * @return Builder for an IkeSessionOptions.
+ * @throws IllegalArgumentException if input proposal is not IKE SA proposal.
+ */
+ public Builder addSaProposal(SaProposal proposal) {
+ if (proposal.getProtocolId() != IkePayload.PROTOCOL_ID_IKE) {
+ throw new IllegalArgumentException(
+ "Expected IKE SA Proposal but received Child SA proposal");
+ }
+ mSaProposalList.add(proposal);
+ return this;
+ }
+
+ /**
+ * Validates, builds and returns the IkeSessionOptions
+ *
+ * @return IkeSessionOptions the validated IkeSessionOptions
+ * @throws IllegalStateException if no IKE SA proposal is provided
+ */
+ public IkeSessionOptions build() {
+ if (mSaProposalList.isEmpty()) {
+ throw new IllegalArgumentException("IKE SA proposal not found");
+ }
+ return new IkeSessionOptions(
+ mServerAddress,
+ mUdpEncapSocket,
+ mSaProposalList.toArray(new SaProposal[mSaProposalList.size()]),
+ mIsIkeFragmentationSupported);
+ }
+
+ // TODO: add methods for supporting IKE fragmentation.
+ }
+}
diff --git a/src/java/com/android/ike/ikev2/IkeSessionStateMachine.java b/src/java/com/android/ike/ikev2/IkeSessionStateMachine.java
new file mode 100644
index 00000000..b4a7b9c6
--- /dev/null
+++ b/src/java/com/android/ike/ikev2/IkeSessionStateMachine.java
@@ -0,0 +1,952 @@
+/*
+ * Copyright (C) 2019 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.ike.ikev2;
+
+import android.os.Looper;
+import android.os.Message;
+import android.system.ErrnoException;
+import android.util.LongSparseArray;
+import android.util.SparseArray;
+
+import com.android.ike.ikev2.SaRecord.IkeSaRecord;
+import com.android.ike.ikev2.exceptions.IkeException;
+import com.android.ike.ikev2.message.IkeHeader;
+import com.android.ike.ikev2.message.IkeKePayload;
+import com.android.ike.ikev2.message.IkeMessage;
+import com.android.ike.ikev2.message.IkeNoncePayload;
+import com.android.ike.ikev2.message.IkeNotifyPayload;
+import com.android.ike.ikev2.message.IkePayload;
+import com.android.ike.ikev2.message.IkeSaPayload;
+import com.android.ike.ikev2.message.IkeSaPayload.DhGroupTransform;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.State;
+import com.android.internal.util.StateMachine;
+
+import java.security.GeneralSecurityException;
+import java.security.SecureRandom;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * IkeSessionStateMachine tracks states and manages exchanges of this IKE session.
+ *
+ * <p>IkeSessionStateMachine has two types of states. One type are states where there is no ongoing
+ * procedure affecting IKE session (non-procedure state), including Initial, Closed, Idle and
+ * Receiving. All other states are "procedure" states which are named as follows:
+ *
+ * <pre>
+ * State Name = [Procedure Type] + [Exchange Initiator] + [Exchange Type].
+ * - An IKE procedure consists of one or two IKE exchanges:
+ * Procedure Type = {CreateIke | DeleteIke | Info | RekeyIke | SimulRekeyIke}.
+ * - Exchange Initiator indicates whether local or remote peer is the exchange initiator:
+ * Exchange Initiator = {Local | Remote}
+ * - Exchange type defines the function of this exchange. To make it more descriptive, we separate
+ * Delete Exchange from generic Informational Exchange:
+ * Exchange Type = {IkeInit | IkeAuth | Create | Delete | Info}
+ * </pre>
+ */
+public class IkeSessionStateMachine extends StateMachine {
+
+ private static final String TAG = "IkeSessionStateMachine";
+
+ /** Package private signals accessible for testing code. */
+ private static final int CMD_GENERAL_BASE = 0;
+ /** Receive encoded IKE packet on IkeSessionStateMachine. */
+ static final int CMD_RECEIVE_IKE_PACKET = CMD_GENERAL_BASE + 1;
+ /** Receive locally built payloads from Child Session for building outbound IKE message. */
+ static final int CMD_RECEIVE_OUTBOUND_CHILD_PAYLOADS = CMD_GENERAL_BASE + 2;
+ /** Receive encoded IKE packet with unrecognized IKE SPI on IkeSessionStateMachine. */
+ static final int CMD_RECEIVE_PACKET_INVALID_IKE_SPI = CMD_GENERAL_BASE + 3;
+ // TODO: Add signal for retransmission.
+
+ private static final int CMD_LOCAL_REQUEST_BASE = CMD_GENERAL_BASE + 100;
+ static final int CMD_LOCAL_REQUEST_CREATE_IKE = CMD_LOCAL_REQUEST_BASE + 1;
+ static final int CMD_LOCAL_REQUEST_DELETE_IKE = CMD_LOCAL_REQUEST_BASE + 2;
+ static final int CMD_LOCAL_REQUEST_REKEY_IKE = CMD_LOCAL_REQUEST_BASE + 3;
+ static final int CMD_LOCAL_REQUEST_INFO = CMD_LOCAL_REQUEST_BASE + 4;
+ static final int CMD_LOCAL_REQUEST_CREATE_CHILD = CMD_LOCAL_REQUEST_BASE + 5;
+ static final int CMD_LOCAL_REQUEST_DELETE_CHILD = CMD_LOCAL_REQUEST_BASE + 6;
+ static final int CMD_LOCAL_REQUEST_REKEY_CHILD = CMD_LOCAL_REQUEST_BASE + 7;
+ // TODO: Add signals for other procedure types and notificaitons.
+
+ // Remember locally assigned IKE SPIs to avoid SPI collision.
+ private static final Set<Long> ASSIGNED_LOCAL_IKE_SPI_SET = new HashSet<>();
+ private static final int MAX_ASSIGN_IKE_SPI_ATTEMPTS = 100;
+ private static final SecureRandom IKE_SPI_RANDOM = new SecureRandom();
+
+ private final IkeSessionOptions mIkeSessionOptions;
+ private final ChildSessionOptions mFirstChildSessionOptions;
+ /** Map that stores all IkeSaRecords, keyed by remotely generated IKE SPI. */
+ private final LongSparseArray<IkeSaRecord> mSpiToSaRecordMap;
+ /**
+ * Map that stores all ChildSessionStateMachines, keyed by remotely generated Child SPI for
+ * sending IPsec packet. Different SPIs may point to the same ChildSessionStateMachine if this
+ * Child Session is doing Rekey.
+ */
+ private final SparseArray<ChildSessionStateMachine> mSpiToChildSessionMap;
+
+ /**
+ * Package private socket that sends and receives encoded IKE message. Initialized in Initial
+ * State.
+ */
+ @VisibleForTesting IkeSocket mIkeSocket;
+
+ /** Package */
+ @VisibleForTesting IkeSaRecord mCurrentIkeSaRecord;
+ /** Package */
+ @VisibleForTesting IkeSaRecord mLocalInitNewIkeSaRecord;
+ /** Package */
+ @VisibleForTesting IkeSaRecord mRemoteInitNewIkeSaRecord;
+
+ /** Package */
+ @VisibleForTesting IkeSaRecord mIkeSaRecordSurviving;
+ /** Package */
+ @VisibleForTesting IkeSaRecord mIkeSaRecordAwaitingLocalDel;
+ /** Package */
+ @VisibleForTesting IkeSaRecord mIkeSaRecordAwaitingRemoteDel;
+
+ // States
+ private final State mInitial = new Initial();
+ private final State mClosed = new Closed();
+ private final State mIdle = new Idle();
+ private final State mReceiving = new Receiving();
+ private final State mCreateIkeLocalIkeInit = new CreateIkeLocalIkeInit();
+ private final State mCreateIkeLocalIkeAuth = new CreateIkeLocalIkeAuth();
+ private final State mRekeyIkeLocalCreate = new RekeyIkeLocalCreate();
+ private final State mSimulRekeyIkeLocalCreate = new SimulRekeyIkeLocalCreate();
+ private final State mSimulRekeyIkeLocalDeleteRemoteDelete =
+ new SimulRekeyIkeLocalDeleteRemoteDelete();
+ private final State mSimulRekeyIkeLocalDelete = new SimulRekeyIkeLocalDelete();
+ private final State mSimulRekeyIkeRemoteDelete = new SimulRekeyIkeRemoteDelete();
+ private final State mRekeyIkeLocalDelete = new RekeyIkeLocalDelete();
+ private final State mRekeyIkeRemoteDelete = new RekeyIkeRemoteDelete();
+ // TODO: Add InfoLocal and DeleteIkeLocal.
+
+ /** Package private constructor */
+ IkeSessionStateMachine(
+ String name,
+ Looper looper,
+ IkeSessionOptions ikeOptions,
+ ChildSessionOptions firstChildOptions) {
+ super(name, looper);
+ mIkeSessionOptions = ikeOptions;
+ mFirstChildSessionOptions = firstChildOptions;
+ // There are at most three IkeSaRecords co-existing during simultaneous rekeying.
+ mSpiToSaRecordMap = new LongSparseArray<>(3);
+ mSpiToChildSessionMap = new SparseArray<>();
+
+ addState(mInitial);
+ addState(mClosed);
+ addState(mCreateIkeLocalIkeInit);
+ addState(mCreateIkeLocalIkeAuth);
+ addState(mIdle);
+ addState(mReceiving);
+ addState(mRekeyIkeLocalCreate);
+ addState(mSimulRekeyIkeLocalCreate, mRekeyIkeLocalCreate);
+ addState(mSimulRekeyIkeLocalDeleteRemoteDelete);
+ addState(mSimulRekeyIkeLocalDelete, mSimulRekeyIkeLocalDeleteRemoteDelete);
+ addState(mSimulRekeyIkeRemoteDelete, mSimulRekeyIkeLocalDeleteRemoteDelete);
+ addState(mRekeyIkeLocalDelete);
+ addState(mRekeyIkeRemoteDelete);
+
+ setInitialState(mInitial);
+ }
+
+ // Generate IKE SPI. Throw an exception if it failed and handle this exception in current State.
+ private static Long getIkeSpiOrThrow() {
+ for (int i = 0; i < MAX_ASSIGN_IKE_SPI_ATTEMPTS; i++) {
+ long spi = IKE_SPI_RANDOM.nextLong();
+ if (ASSIGNED_LOCAL_IKE_SPI_SET.add(spi)) return spi;
+ }
+ throw new IllegalStateException("Failed to generate IKE SPI.");
+ }
+
+ private IkeMessage buildIkeInitReq() {
+ // TODO: Handle IKE SPI assigning error in CreateIkeLocalIkeInit State.
+
+ List<IkePayload> payloadList = new LinkedList<>();
+
+ // Generate IKE SPI
+ long initSpi = getIkeSpiOrThrow();
+ long respSpi = 0;
+
+ // It is validated in IkeSessionOptions.Builder to ensure IkeSessionOptions has at least one
+ // SaProposal and all SaProposals are valid for IKE SA negotiation.
+ SaProposal[] saProposals = mIkeSessionOptions.getSaProposals();
+
+ // Build SA Payload
+ IkeSaPayload saPayload = new IkeSaPayload(saProposals);
+ payloadList.add(saPayload);
+
+ // Build KE Payload using the first DH group number in the first SaProposal.
+ DhGroupTransform dhGroupTransform = saProposals[0].getDhGroupTransforms()[0];
+ IkeKePayload kePayload = new IkeKePayload(dhGroupTransform.id);
+ payloadList.add(kePayload);
+
+ // Build Nonce Payload
+ IkeNoncePayload noncePayload = new IkeNoncePayload();
+ payloadList.add(noncePayload);
+
+ // TODO: Add Notification Payloads according to user configurations.
+
+ // Build IKE header
+ IkeHeader ikeHeader =
+ new IkeHeader(
+ initSpi,
+ respSpi,
+ IkePayload.PAYLOAD_TYPE_SA,
+ IkeHeader.EXCHANGE_TYPE_IKE_SA_INIT,
+ false /*isResponseMsg*/,
+ true /*fromIkeInitiator*/,
+ 0 /*messageId*/);
+
+ return new IkeMessage(ikeHeader, payloadList);
+ }
+
+ private IkeMessage buildIkeAuthReq() {
+ // TODO: Build IKE_AUTH request according to mIkeSessionOptions and
+ // firstChildSessionOptions.
+ return null;
+ }
+
+ private IkeMessage buildIkeDeleteReq(IkeSaRecord ikeSaRecord) {
+ // TODO: Implement it.
+ return null;
+ }
+
+ private IkeMessage buildIkeDeleteResp(IkeSaRecord ikeSaRecord) {
+ // TODO: Implement it.
+ return null;
+ }
+
+ private IkeMessage buildIkeRekeyReq() {
+ // TODO: Implement it.
+ return null;
+ }
+
+ private IkeMessage buildIkeRekeyResp(IkeMessage reqMsg) {
+ // TODO: Implement it.
+ return null;
+ }
+
+ private void validateIkeInitResp(IkeMessage reqMsg, IkeMessage respMsg) throws IkeException {
+ // TODO: Validate ikeMessage against IKE_INIT request and set confiugration negotiation
+ // results
+ // in mIkeSessionOptions(e.g.NAT detecting result).
+ }
+
+ private void validateIkeAuthResp(IkeMessage reqMsg, IkeMessage respMsg) throws IkeException {
+ // TODO: Validate ikeMessage against IKE_AUTH request and mIkeSessionOptions.
+ }
+
+ private void validateIkeDeleteReq(IkeMessage ikeMessage) throws IkeException {
+ // TODO: Validate ikeMessage.
+ }
+
+ private void validateIkeDeleteResp(IkeMessage ikeMessage) throws IkeException {
+ // TODO: Validate ikeMessage.
+ }
+
+ private void validateIkeRekeyReq(IkeMessage ikeMessage) throws IkeException {
+ // TODO: Validate it againsr mIkeSessionOptions.
+ }
+
+ private void validateIkeRekeyResp(IkeMessage reqMsg, IkeMessage respMsg) throws IkeException {
+ // TODO: Validate ikeMessage against Rekey request.
+ }
+
+ // TODO: Add methods for building and validating general Informational packet.
+
+ private void addIkeSaRecord(IkeSaRecord record) {
+ mSpiToSaRecordMap.put(record.getRemoteSpi(), record);
+ }
+
+ private void removeIkeSaRecord(IkeSaRecord record) {
+ mSpiToSaRecordMap.remove(record.getRemoteSpi());
+ }
+
+ /**
+ * Receive IKE packet from remote server.
+ *
+ * <p>This method is called synchronously from IkeSocket. It proxies the synchronous call as an
+ * asynchronous job to the IkeSessionStateMachine handler.
+ *
+ * @param ikeHeader the decoded IKE header.
+ * @param ikePacketBytes the byte array of the entire received IKE packet.
+ */
+ public void receiveIkePacket(IkeHeader ikeHeader, byte[] ikePacketBytes) {
+ sendMessage(CMD_RECEIVE_IKE_PACKET, new ReceivedIkePacket(ikeHeader, ikePacketBytes));
+ }
+
+ /**
+ * ReceivedIkePacket is a package private data container consists of decoded IkeHeader and
+ * encoded IKE packet in a byte array.
+ */
+ static class ReceivedIkePacket {
+ /** Decoded IKE header */
+ public final IkeHeader ikeHeader;
+ /** Entire encoded IKE message including IKE header */
+ public final byte[] ikePacketBytes;
+
+ ReceivedIkePacket(IkeHeader ikeHeader, byte[] ikePacketBytes) {
+ this.ikeHeader = ikeHeader;
+ this.ikePacketBytes = ikePacketBytes;
+ }
+ }
+
+ /**
+ * Interface for ChildSessionStateMachine to notify IkeSessionStateMachine.
+ *
+ * <p>Package private so as to be injectable for testing.
+ */
+ interface IChildSessionCallback {
+ /** Notify that new Child SA is created. */
+ void onCreateChildSa(int remoteSpi, ChildSessionStateMachine childSession);
+ /** Notify that the Child SA is deleted. */
+ void onDeleteChildSa(int remoteSpi);
+ // TODO: Add methods for handling errors and sending out locally built payloads.
+ }
+
+ /**
+ * Callback for ChildSessionStateMachine to notify IkeSessionStateMachine.
+ *
+ * <p>Package private for being passed to only ChildSessionStateMachine.
+ */
+ class ChildSessionCallback implements IChildSessionCallback {
+ public void onCreateChildSa(int remoteSpi, ChildSessionStateMachine childSession) {
+ mSpiToChildSessionMap.put(remoteSpi, childSession);
+ }
+
+ public void onDeleteChildSa(int remoteSpi) {
+ mSpiToChildSessionMap.remove(remoteSpi);
+ }
+ }
+
+ /** Initial state of IkeSessionStateMachine. */
+ class Initial extends State {
+ @Override
+ public void enter() {
+ try {
+ mIkeSocket = IkeSocket.getIkeSocket(mIkeSessionOptions.getUdpEncapsulationSocket());
+ } catch (ErrnoException e) {
+ // TODO: handle exception and close IkeSession.
+ }
+ }
+
+ @Override
+ public boolean processMessage(Message message) {
+ switch (message.what) {
+ case CMD_LOCAL_REQUEST_CREATE_IKE:
+ transitionTo(mCreateIkeLocalIkeInit);
+ return HANDLED;
+ default:
+ return NOT_HANDLED;
+ }
+ }
+ }
+
+ /**
+ * Closed represents the state when this IkeSessionStateMachine is closed, and no further
+ * actions can be performed on it.
+ */
+ class Closed extends State {
+ // TODO:Implement it.
+ }
+
+ /**
+ * Idle represents a state when there is no ongoing IKE exchange affecting established IKE SA.
+ */
+ class Idle extends State {
+ @Override
+ public boolean processMessage(Message message) {
+ switch (message.what) {
+ case CMD_RECEIVE_IKE_PACKET:
+ deferMessage(message);
+ transitionTo(mReceiving);
+ return HANDLED;
+ case CMD_LOCAL_REQUEST_REKEY_IKE:
+ transitionTo(mRekeyIkeLocalCreate);
+ return HANDLED;
+ default:
+ return NOT_HANDLED;
+ // TODO: Add more cases for supporting local request.
+ }
+ }
+ }
+
+ /** Base state defines common behaviours when receiving an IKE packet. */
+ private abstract class BaseState extends State {
+ @Override
+ public boolean processMessage(Message message) {
+ switch (message.what) {
+ case CMD_RECEIVE_IKE_PACKET:
+ handleReceivedIkePacket(message);
+ return HANDLED;
+ default:
+ return NOT_HANDLED;
+ }
+ }
+
+ protected void handleReceivedIkePacket(Message message) {
+ ReceivedIkePacket receivedIkePacket = (ReceivedIkePacket) message.obj;
+ IkeHeader ikeHeader = receivedIkePacket.ikeHeader;
+ byte[] ikePacketBytes = receivedIkePacket.ikePacketBytes;
+ IkeSaRecord ikeSaRecord = getIkeSaRecordForPacket(ikeHeader);
+ try {
+ IkeMessage ikeMessage =
+ IkeMessage.decode(
+ mIkeSessionOptions, ikeSaRecord, ikeHeader, ikePacketBytes);
+ int messageType = ikeMessage.getMessageType();
+ // TODO: Handle fatal error notifications.
+ handleIkeMessage(ikeMessage, messageType, message);
+ } catch (IkeException e) {
+
+ } catch (GeneralSecurityException e) {
+ // IKE library failed on intergity checksum validation or on message decryption.
+ // TODO: Handle decrypting exception
+ }
+ }
+
+ // Default handler for decode errors in encrypted request.
+ protected void handleDecodingErrorInEncryptedRequest(
+ IkeException exception, IkeSaRecord ikeSaRecord) {
+ switch (exception.errorCode) {
+ case IkeNotifyPayload.NOTIFY_TYPE_UNSUPPORTED_CRITICAL_PAYLOAD:
+ // TODO: Send encrypted error notification.
+ return;
+ case IkeNotifyPayload.NOTIFY_TYPE_INVALID_MAJOR_VERSION:
+ // TODO: Send unencrypted error notification.
+ return;
+ case IkeNotifyPayload.NOTIFY_TYPE_INVALID_SYNTAX:
+ // TODO: Send encrypted error notification and close IKE session if Message ID
+ // and cryptogtaphic checksum were invalid.
+ return;
+ default:
+ // Won't hit this case.
+ throw new UnsupportedOperationException("Unknown error decoding IKE Message.");
+ }
+ }
+
+ // Default handler for decode errors in encrypted responses.
+ // NOTE: The DeleteIkeLocal state MUST override this state to avoid the possibility of an
+ // infinite loop.
+ protected void handleDecodingErrorInEncryptedResponse(
+ IkeException exception, IkeSaRecord ikeSaRecord) {
+ // All errors in parsing or processing reponse packets should cause the IKE library to
+ // initiate a Delete IKE Exchange.
+
+ // TODO: Initiate Delete IKE Exchange
+ }
+
+ protected IkeSaRecord getIkeSaRecordForPacket(IkeHeader ikeHeader) {
+ if (ikeHeader.fromIkeInitiator) {
+ return mSpiToSaRecordMap.get(ikeHeader.ikeInitiatorSpi);
+ } else {
+ return mSpiToSaRecordMap.get(ikeHeader.ikeResponderSpi);
+ }
+ }
+
+ protected abstract void handleIkeMessage(
+ IkeMessage ikeMessage, int messageType, Message message);
+ }
+
+ /**
+ * Receiving represents a state when idle IkeSessionStateMachine receives an incoming packet.
+ */
+ class Receiving extends BaseState {
+ @Override
+ protected void handleIkeMessage(IkeMessage ikeMessage, int messageType, Message message) {
+ switch (messageType) {
+ case IkeMessage.MESSAGE_TYPE_REKEY_IKE_REQ:
+ try {
+ validateIkeRekeyReq(ikeMessage);
+ // Reply
+ IkeMessage responseIkeMessage = buildIkeRekeyResp(ikeMessage);
+ // TODO: Encode and send out responseIkeMessage
+
+ mRemoteInitNewIkeSaRecord =
+ IkeSaRecord.makeNewIkeSaRecord(
+ mCurrentIkeSaRecord, ikeMessage, responseIkeMessage);
+ addIkeSaRecord(mRemoteInitNewIkeSaRecord);
+ transitionTo(mRekeyIkeRemoteDelete);
+ } catch (IkeException e) {
+ // TODO: Handle processing errors.
+ }
+ return;
+ // TODO: Add more cases for supporting local request.
+ default:
+ }
+ }
+ }
+
+ /**
+ * LocalNewExchangeBase represents the common behaviours when IKE library initiates a new
+ * exchange.
+ */
+ private abstract class LocalNewExchangeBase extends BaseState {
+ protected IkeMessage mRequestMsg;
+ protected byte[] mRequestPacket;
+
+ @Override
+ public void enter() {
+ mRequestMsg = buildRequest();
+ mRequestPacket = encodeRequest();
+ mIkeSocket.sendIkePacket(mRequestPacket, mIkeSessionOptions.getServerAddress());
+ // TODO: Send out packet and start retransmission timer.
+ }
+
+ @Override
+ public void exit() {
+ // TODO: Stop retransmission
+ mRequestMsg = null;
+ mRequestPacket = null;
+ }
+
+ protected abstract IkeMessage buildRequest();
+
+ // CreateIkeLocalInit should override encodeRequest() to encode unencrypted packet
+ protected byte[] encodeRequest() {
+ // TODO: encrypt and encode mRequestMsg
+ return new byte[0];
+ }
+ }
+
+ /** CreateIkeLocalIkeInit represents state when IKE library initiates IKE_INIT exchange. */
+ class CreateIkeLocalIkeInit extends LocalNewExchangeBase {
+
+ @Override
+ public void enter() {
+ super.enter();
+ mIkeSocket.registerIke(
+ mRequestMsg.ikeHeader.ikeInitiatorSpi, IkeSessionStateMachine.this);
+ }
+
+ @Override
+ protected IkeMessage buildRequest() {
+ return buildIkeInitReq();
+ }
+
+ @Override
+ protected byte[] encodeRequest() {
+ return mRequestMsg.encode();
+ }
+
+ @Override
+ public boolean processMessage(Message message) {
+ switch (message.what) {
+ case CMD_RECEIVE_IKE_PACKET:
+ handleReceivedIkePacket(message);
+ return HANDLED;
+ default:
+ return NOT_HANDLED;
+ }
+ }
+
+ protected void handleReceivedIkePacket(Message message) {
+ ReceivedIkePacket receivedIkePacket = (ReceivedIkePacket) message.obj;
+ IkeHeader ikeHeader = receivedIkePacket.ikeHeader;
+ byte[] ikePacketBytes = receivedIkePacket.ikePacketBytes;
+ try {
+ IkeMessage ikeMessage = IkeMessage.decode(ikeHeader, ikePacketBytes);
+ int messageType = ikeMessage.getMessageType();
+ // TODO: Handle fatal error notifications.
+ handleIkeMessage(ikeMessage, messageType, message);
+ } catch (IkeException e) {
+ // TODO:Since IKE_INIT is not protected, log and ignore this message.
+ }
+ }
+
+ @Override
+ protected void handleIkeMessage(IkeMessage ikeMessage, int messageType, Message message) {
+ switch (messageType) {
+ case IkeMessage.MESSAGE_TYPE_IKE_INIT_RESP:
+ try {
+ validateIkeInitResp(mRequestMsg, ikeMessage);
+ mCurrentIkeSaRecord =
+ IkeSaRecord.makeFirstIkeSaRecord(mRequestMsg, ikeMessage);
+ addIkeSaRecord(mCurrentIkeSaRecord);
+ transitionTo(mCreateIkeLocalIkeAuth);
+ } catch (IkeException e) {
+ // TODO: Handle processing errors.
+ }
+ return;
+ default:
+ // TODO: Handle unexpected message type.
+ }
+ }
+
+ @Override
+ public void exit() {
+ super.exit();
+ // TODO: Store IKE_INIT request and response in mIkeSessionOptions for IKE_AUTH
+ }
+ }
+
+ /** CreateIkeLocalIkeAuth represents state when IKE library initiates IKE_AUTH exchange. */
+ class CreateIkeLocalIkeAuth extends LocalNewExchangeBase {
+ @Override
+ protected IkeMessage buildRequest() {
+ return buildIkeAuthReq();
+ }
+
+ @Override
+ protected void handleIkeMessage(IkeMessage ikeMessage, int messageType, Message message) {
+ switch (messageType) {
+ // TODO: Handle EAP Authentication.
+ case IkeMessage.MESSAGE_TYPE_IKE_AUTH_RESP:
+ try {
+ validateIkeAuthResp(mRequestMsg, ikeMessage);
+
+ ChildSessionStateMachine firstChild =
+ ChildSessionStateMachineFactory.makeChildSessionStateMachine(
+ "ChildSessionStateMachine",
+ getHandler().getLooper(),
+ mFirstChildSessionOptions);
+ // TODO: Replace null input params to payload lists in IKE_AUTH request and
+ // IKE_AUTH response for negotiating Child SA.
+ firstChild.handleFirstChildExchange(null, null, new ChildSessionCallback());
+
+ transitionTo(mIdle);
+ } catch (IkeException e) {
+ // TODO: Handle processing errors.
+ }
+ return;
+ default:
+ // TODO: Add more cases for other packet types (e.g. for receiving and sending
+ // EAP).
+ }
+ }
+ }
+
+ /** RekeyIkeLocalCreate represents state when IKE library initiates Rekey IKE exchange. */
+ class RekeyIkeLocalCreate extends LocalNewExchangeBase {
+ @Override
+ public IkeMessage buildRequest() {
+ return buildIkeRekeyReq();
+ }
+
+ @Override
+ protected void handleIkeMessage(IkeMessage ikeMessage, int messageType, Message message) {
+ switch (messageType) {
+ case IkeMessage.MESSAGE_TYPE_REKEY_IKE_RESP:
+ try {
+ handleRekeyResp(ikeMessage);
+ transitionTo(mRekeyIkeLocalDelete);
+ } catch (IkeException e) {
+ // TODO: Handle processing errors.
+ }
+ return;
+ case IkeMessage.MESSAGE_TYPE_REKEY_IKE_REQ:
+ try {
+ validateIkeRekeyReq(ikeMessage);
+ // Reply
+ IkeMessage responseIkeMessage = buildIkeRekeyResp(ikeMessage);
+ mRemoteInitNewIkeSaRecord =
+ IkeSaRecord.makeNewIkeSaRecord(
+ mCurrentIkeSaRecord, ikeMessage, responseIkeMessage);
+ addIkeSaRecord(mRemoteInitNewIkeSaRecord);
+ // TODO: Encode and send responseIkeMessage.
+
+ transitionTo(mSimulRekeyIkeLocalCreate);
+ } catch (IkeException e) {
+ // TODO: Handle processing errors.
+ }
+ return;
+ default:
+ // TODO: Add more cases for other packet types.
+ }
+ }
+
+ // Is also called by SimulRekeyIkeLocalCreate to handle incoming rekey response.
+ protected void handleRekeyResp(IkeMessage ikeMessage) throws IkeException {
+ validateIkeRekeyResp(mRequestMsg, ikeMessage);
+ mLocalInitNewIkeSaRecord =
+ IkeSaRecord.makeNewIkeSaRecord(mCurrentIkeSaRecord, mRequestMsg, ikeMessage);
+ addIkeSaRecord(mLocalInitNewIkeSaRecord);
+ // TODO: Stop retransmission
+ }
+ }
+
+ /**
+ * SimulRekeyIkeLocalCreate represents the state where IKE library has replied to rekey request
+ * sent from the remote and is waiting for a rekey response for a locally initiated rekey
+ * request.
+ *
+ * <p>SimulRekeyIkeLocalCreate extends RekeyIkeLocalCreate so that it can call super class to
+ * validate incoming rekey response against locally initiated rekey request.
+ */
+ class SimulRekeyIkeLocalCreate extends RekeyIkeLocalCreate {
+ @Override
+ public void enter() {
+ // Do not send request.
+ }
+
+ @Override
+ public IkeMessage buildRequest() {
+ throw new UnsupportedOperationException(
+ "Do not support sending request in " + getCurrentState().getName());
+ }
+
+ @Override
+ public void exit() {
+ // Do nothing.
+ }
+
+ @Override
+ public boolean processMessage(Message message) {
+ switch (message.what) {
+ case CMD_RECEIVE_IKE_PACKET:
+ ReceivedIkePacket receivedIkePacket = (ReceivedIkePacket) message.obj;
+ IkeHeader ikeHeader = receivedIkePacket.ikeHeader;
+
+ if (mRemoteInitNewIkeSaRecord == getIkeSaRecordForPacket(ikeHeader)) {
+ deferMessage(message);
+ } else {
+ handleReceivedIkePacket(message);
+ }
+ return HANDLED;
+ default:
+ return NOT_HANDLED;
+ }
+ }
+
+ @Override
+ protected void handleIkeMessage(IkeMessage ikeMessage, int messageType, Message message) {
+ switch (messageType) {
+ case IkeMessage.MESSAGE_TYPE_DELETE_IKE_REQ:
+ deferMessage(message);
+ return;
+ case IkeMessage.MESSAGE_TYPE_REKEY_IKE_RESP:
+ try {
+ super.handleRekeyResp(ikeMessage);
+ transitionTo(mSimulRekeyIkeLocalDeleteRemoteDelete);
+ } catch (IkeException e) {
+ // TODO: Handle processing errors.
+ }
+ return;
+ default:
+ // TODO: Add more cases for other packet types.
+ }
+ }
+ }
+
+ /** RekeyIkeDeleteBase represents common behaviours of deleting stage during rekeying IKE SA. */
+ private abstract class RekeyIkeDeleteBase extends BaseState {
+ @Override
+ public boolean processMessage(Message message) {
+ switch (message.what) {
+ case CMD_RECEIVE_IKE_PACKET:
+ ReceivedIkePacket receivedIkePacket = (ReceivedIkePacket) message.obj;
+ IkeHeader ikeHeader = receivedIkePacket.ikeHeader;
+
+ // Request received on the new/surviving SA; treat it as acknowledgement that
+ // remote has successfully rekeyed.
+ if (mIkeSaRecordSurviving == getIkeSaRecordForPacket(ikeHeader)) {
+ deferMessage(message);
+ // TODO: Locally close old (and losing) IKE SAs.
+ finishRekey();
+ } else {
+ handleReceivedIkePacket(message);
+ }
+ return HANDLED;
+ default:
+ return NOT_HANDLED;
+ // TODO: Add more cases for other packet types.
+ }
+ }
+
+ protected void finishRekey() {
+ mCurrentIkeSaRecord = mIkeSaRecordSurviving;
+ mLocalInitNewIkeSaRecord = null;
+ mRemoteInitNewIkeSaRecord = null;
+
+ mIkeSaRecordSurviving = null;
+ mIkeSaRecordAwaitingLocalDel = null;
+ mIkeSaRecordAwaitingRemoteDel = null;
+ }
+ }
+
+ /**
+ * SimulRekeyIkeLocalDeleteRemoteDelete represents the deleting stage during simultaneous
+ * rekeying when IKE library is waiting for both a Delete request and a Delete response.
+ */
+ class SimulRekeyIkeLocalDeleteRemoteDelete extends RekeyIkeDeleteBase {
+ @Override
+ public void enter() {
+ // Detemine surviving IKE SA. According to RFC 7296: "The new IKE SA containing the
+ // lowest nonce SHOULD be deleted by the node that created it, and the other surviving
+ // new IKE SA MUST inherit all the Child SAs."
+ if (mLocalInitNewIkeSaRecord.compareTo(mRemoteInitNewIkeSaRecord) > 0) {
+ mIkeSaRecordSurviving = mLocalInitNewIkeSaRecord;
+ mIkeSaRecordAwaitingLocalDel = mCurrentIkeSaRecord;
+ mIkeSaRecordAwaitingRemoteDel = mRemoteInitNewIkeSaRecord;
+ } else {
+ mIkeSaRecordSurviving = mRemoteInitNewIkeSaRecord;
+ mIkeSaRecordAwaitingLocalDel = mLocalInitNewIkeSaRecord;
+ mIkeSaRecordAwaitingRemoteDel = mCurrentIkeSaRecord;
+ }
+ IkeMessage ikeMessage = buildIkeDeleteReq(mIkeSaRecordAwaitingLocalDel);
+ // TODO: Encode and send out delete request and start retransmission timer.
+ // TODO: Set timer awaiting for delete request.
+ }
+
+ @Override
+ protected void handleIkeMessage(IkeMessage ikeMessage, int messageType, Message message) {
+ IkeSaRecord ikeSaRecordForPacket = getIkeSaRecordForPacket(ikeMessage.ikeHeader);
+ switch (messageType) {
+ case IkeMessage.MESSAGE_TYPE_DELETE_IKE_REQ:
+ if (ikeSaRecordForPacket == mIkeSaRecordAwaitingRemoteDel) {
+ try {
+ validateIkeDeleteReq(ikeMessage);
+ IkeMessage respMsg = buildIkeDeleteResp(mIkeSaRecordAwaitingRemoteDel);
+ removeIkeSaRecord(mIkeSaRecordAwaitingRemoteDel);
+ // TODO: Encode and send response and close
+ // mIkeSaRecordAwaitingRemoteDel.
+ // TODO: Stop timer awating delete request.
+ transitionTo(mSimulRekeyIkeLocalDelete);
+ } catch (IkeException e) {
+ // TODO: Handle processing errors.
+ }
+ } else {
+ // TODO: The other side deletes wrong IKE SA and we should close whole IKE
+ // session.
+ }
+ return;
+ case IkeMessage.MESSAGE_TYPE_DELETE_IKE_RESP:
+ if (ikeSaRecordForPacket == mIkeSaRecordAwaitingLocalDel) {
+ try {
+ validateIkeDeleteResp(ikeMessage);
+ transitionTo(mSimulRekeyIkeRemoteDelete);
+ removeIkeSaRecord(mIkeSaRecordAwaitingLocalDel);
+ // TODO: Close mIkeSaRecordAwaitingLocalDel
+ // TODO: Stop retransmission timer
+ } catch (IkeException e) {
+ // TODO: Handle processing errors.
+ }
+ } else {
+ // TODO: Close whole IKE session
+ }
+ return;
+ default:
+ // TODO: Add more cases for other packet types.
+ }
+ }
+
+ @Override
+ public void exit() {
+ finishRekey();
+ // TODO: Stop retransmission timer and awaiting delete request timer.
+ }
+ }
+
+ /**
+ * SimulRekeyIkeLocalDelete represents the state when IKE library is waiting for a Delete
+ * response during simultaneous rekeying.
+ */
+ class SimulRekeyIkeLocalDelete extends RekeyIkeDeleteBase {
+ @Override
+ protected void handleIkeMessage(IkeMessage ikeMessage, int messageType, Message message) {
+ switch (messageType) {
+ case IkeMessage.MESSAGE_TYPE_DELETE_IKE_RESP:
+ try {
+ validateIkeDeleteResp(ikeMessage);
+ removeIkeSaRecord(mIkeSaRecordAwaitingLocalDel);
+ // TODO: Close mIkeSaRecordAwaitingLocalDel.
+ transitionTo(mIdle);
+ } catch (IkeException e) {
+ // TODO: Handle processing errors.
+ }
+ return;
+ default:
+ // TODO: Add more cases for other packet types.
+ }
+ }
+ }
+
+ /**
+ * SimulRekeyIkeRemoteDelete represents the state that waiting for a Delete request during
+ * simultaneous rekeying.
+ */
+ class SimulRekeyIkeRemoteDelete extends RekeyIkeDeleteBase {
+ // TODO: Implement methods for processing Delete response
+ @Override
+ protected void handleIkeMessage(IkeMessage ikeMessage, int messageType, Message message) {
+ switch (messageType) {
+ case IkeMessage.MESSAGE_TYPE_DELETE_IKE_REQ:
+ try {
+ validateIkeDeleteReq(ikeMessage);
+ IkeMessage respMsg = buildIkeDeleteResp(mIkeSaRecordAwaitingRemoteDel);
+ // TODO: Encode and send response and close mIkeSaRecordAwaitingRemoteDel
+ removeIkeSaRecord(mIkeSaRecordAwaitingRemoteDel);
+ transitionTo(mIdle);
+ } catch (IkeException e) {
+ // TODO: Handle processing errors.
+ }
+ return;
+ default:
+ // TODO: Add more cases for other packet types.
+ }
+ }
+ }
+
+ /**
+ * RekeyIkeLocalDelete represents the deleting stage when IKE library is initiating a Rekey
+ * procedure.
+ *
+ * <p>RekeyIkeLocalDelete and SimulRekeyIkeLocalDelete have same behaviours in processMessage().
+ * While RekeyIkeLocalDelete overrides enter() and exit() methods for initiating and finishing
+ * the deleting stage for IKE rekeying.
+ */
+ class RekeyIkeLocalDelete extends SimulRekeyIkeLocalDelete {
+ @Override
+ public void enter() {
+ mIkeSaRecordSurviving = mLocalInitNewIkeSaRecord;
+ mIkeSaRecordAwaitingLocalDel = mCurrentIkeSaRecord;
+ IkeMessage ikeMessage = buildIkeDeleteReq(mIkeSaRecordAwaitingLocalDel);
+ // TODO: Encode ikeMessage, send out packet and start retransmission timer.
+ }
+
+ @Override
+ public void exit() {
+ finishRekey();
+ // TODO: Stop retransmission.
+ }
+ }
+
+ /**
+ * RekeyIkeRemoteDelete represents the deleting stage when responding to a Rekey procedure.
+ *
+ * <p>RekeyIkeRemoteDelete and SimulRekeyIkeRemoteDelete have same behaviours in
+ * processMessage(). While RekeyIkeLocalDelete overrides enter() and exit() methods for waiting
+ * incoming delete request and for finishing the deleting stage for IKE rekeying.
+ */
+ class RekeyIkeRemoteDelete extends SimulRekeyIkeRemoteDelete {
+ @Override
+ public void enter() {
+ mIkeSaRecordSurviving = mRemoteInitNewIkeSaRecord;
+ mIkeSaRecordAwaitingRemoteDel = mCurrentIkeSaRecord;
+ // TODO: Set timer awaiting delete request.
+ }
+
+ @Override
+ public void exit() {
+ finishRekey();
+ // TODO: Stop timer awaiting delete request.
+ }
+ }
+}
diff --git a/src/java/com/android/internal/net/ipsec/ike/IkeSocket.java b/src/java/com/android/ike/ikev2/IkeSocket.java
index 2f853c7f..e235ab88 100644
--- a/src/java/com/android/internal/net/ipsec/ike/IkeSocket.java
+++ b/src/java/com/android/ike/ikev2/IkeSocket.java
@@ -14,23 +14,23 @@
* limitations under the License.
*/
-package com.android.internal.net.ipsec.ike;
+package com.android.ike.ikev2;
-import static android.net.ipsec.ike.IkeManager.getIkeLog;
import static android.system.OsConstants.F_SETFL;
import static android.system.OsConstants.SOCK_DGRAM;
import static android.system.OsConstants.SOCK_NONBLOCK;
import android.net.IpSecManager.UdpEncapsulationSocket;
-import android.net.ipsec.ike.exceptions.IkeProtocolException;
+import android.net.util.PacketReader;
import android.os.Handler;
import android.system.ErrnoException;
import android.system.Os;
+import android.util.Log;
import android.util.LongSparseArray;
+import com.android.ike.ikev2.exceptions.IkeException;
+import com.android.ike.ikev2.message.IkeHeader;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.net.ipsec.ike.message.IkeHeader;
-import com.android.internal.net.ipsec.ike.utils.PacketReader;
import java.io.FileDescriptor;
import java.io.IOException;
@@ -38,9 +38,7 @@ import java.net.InetAddress;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.Map;
-import java.util.Set;
/**
* IkeSocket sends and receives IKE packets via the user provided {@link UdpEncapsulationSocket}.
@@ -82,16 +80,18 @@ public final class IkeSocket extends PacketReader implements AutoCloseable {
// Package private map from locally generated IKE SPI to IkeSessionStateMachine instances.
@VisibleForTesting
- final LongSparseArray<IkeSessionStateMachine> mSpiToIkeSession = new LongSparseArray<>();
-
- // Package private set to store all running IKE Sessions that are using this IkeSocket instance.
- @VisibleForTesting final Set<IkeSessionStateMachine> mAliveIkeSessions = new HashSet<>();
-
+ final LongSparseArray<IkeSessionStateMachine> mSpiToIkeSession =
+ new LongSparseArray<>();
// UdpEncapsulationSocket for sending and receving IKE packet.
private final UdpEncapsulationSocket mUdpEncapSocket;
+ /** Package private */
+ @VisibleForTesting
+ int mRefCount;
+
private IkeSocket(UdpEncapsulationSocket udpEncapSocket, Handler handler) {
super(handler);
+ mRefCount = 1;
mUdpEncapSocket = udpEncapSocket;
}
@@ -102,31 +102,27 @@ public final class IkeSocket extends PacketReader implements AutoCloseable {
* udpEncapSocket. Otherwise, create and return a new IkeSocket instance.
*
* @param udpEncapSocket user provided UdpEncapsulationSocket
- * @param ikeSession the IkeSessionStateMachine that is requesting an IkeSocket.
- * @return an IkeSocket instance
+ * @return an IkSocket instance
*/
- public static IkeSocket getIkeSocket(
- UdpEncapsulationSocket udpEncapSocket, IkeSessionStateMachine ikeSession)
+ public static IkeSocket getIkeSocket(UdpEncapsulationSocket udpEncapSocket)
throws ErrnoException {
FileDescriptor fd = udpEncapSocket.getFileDescriptor();
// All created IkeSocket has modified its FileDescriptor to non-blocking type for handling
// read events in a non-blocking way.
Os.fcntlInt(fd, F_SETFL, SOCK_DGRAM | SOCK_NONBLOCK);
- IkeSocket ikeSocket = null;
if (sFdToIkeSocketMap.containsKey(udpEncapSocket)) {
- ikeSocket = sFdToIkeSocketMap.get(udpEncapSocket);
-
+ IkeSocket ikeSocket = sFdToIkeSocketMap.get(udpEncapSocket);
+ ikeSocket.mRefCount++;
+ return ikeSocket;
} else {
- ikeSocket = new IkeSocket(udpEncapSocket, new Handler());
+ IkeSocket ikeSocket = new IkeSocket(udpEncapSocket, new Handler());
// Create and register FileDescriptor for receiving IKE packet on current thread.
ikeSocket.start();
sFdToIkeSocketMap.put(udpEncapSocket, ikeSocket);
+ return ikeSocket;
}
-
- ikeSocket.mAliveIkeSessions.add(ikeSession);
- return ikeSocket;
}
/**
@@ -155,6 +151,10 @@ public final class IkeSocket extends PacketReader implements AutoCloseable {
static final class PacketReceiver implements IPacketReceiver {
public void handlePacket(
byte[] recvbuf, LongSparseArray<IkeSessionStateMachine> spiToIkeSession) {
+ // TODO: b/129708574 Consider only logging the error some % of the time it happens, or
+ // only logging the error the first time it happens and then keep a count to prevent
+ // logspam.
+
ByteBuffer byteBuffer = ByteBuffer.wrap(recvbuf);
// Check the existence of the Non-ESP Marker. A received packet can be either an IKE
@@ -164,7 +164,7 @@ public final class IkeSocket extends PacketReader implements AutoCloseable {
byteBuffer.get(espMarker);
if (!Arrays.equals(NON_ESP_MARKER, espMarker)) {
// Drop the received ESP packet.
- getIkeLog().e(TAG, "Receive an ESP packet.");
+ Log.e(TAG, "Receive an ESP packet.");
return;
}
@@ -173,11 +173,6 @@ public final class IkeSocket extends PacketReader implements AutoCloseable {
// IKE SPI.
byte[] ikePacketBytes = new byte[byteBuffer.remaining()];
byteBuffer.get(ikePacketBytes);
-
- // TODO: Retrieve and log the source address
- getIkeLog().d(TAG, "Receive packet of " + ikePacketBytes.length + " bytes)");
- getIkeLog().d(TAG, getIkeLog().pii(ikePacketBytes));
-
IkeHeader ikeHeader = new IkeHeader(ikePacketBytes);
long localGeneratedSpi =
@@ -187,14 +182,14 @@ public final class IkeSocket extends PacketReader implements AutoCloseable {
IkeSessionStateMachine ikeStateMachine = spiToIkeSession.get(localGeneratedSpi);
if (ikeStateMachine == null) {
- getIkeLog().w(TAG, "Unrecognized IKE SPI.");
+ Log.e(TAG, "Unrecognized IKE SPI.");
// TODO: Handle invalid IKE SPI error
} else {
ikeStateMachine.receiveIkePacket(ikeHeader, ikePacketBytes);
}
- } catch (IkeProtocolException e) {
+ } catch (IkeException e) {
// Handle invalid IKE header
- getIkeLog().i(TAG, "Can't parse malformed IKE packet header.");
+ Log.e(TAG, "Can't parse malformed IKE packet header.");
}
}
}
@@ -221,14 +216,6 @@ public final class IkeSocket extends PacketReader implements AutoCloseable {
* @param serverAddress IP address of remote server
*/
public void sendIkePacket(byte[] ikePacket, InetAddress serverAddress) {
- getIkeLog()
- .d(
- TAG,
- "Send packet to "
- + serverAddress.getHostAddress()
- + "( "
- + ikePacket.length
- + " bytes)");
try {
ByteBuffer buffer = ByteBuffer.allocate(NON_ESP_MARKER_LEN + ikePacket.length);
@@ -265,9 +252,9 @@ public final class IkeSocket extends PacketReader implements AutoCloseable {
}
/** Release reference of current IkeSocket when the IKE session is closed. */
- public void releaseReference(IkeSessionStateMachine ikeSession) {
- mAliveIkeSessions.remove(ikeSession);
- if (mAliveIkeSessions.isEmpty()) close();
+ public void releaseReference() {
+ mRefCount--;
+ if (mRefCount == 0) close();
}
/** Implement {@link AutoCloseable#close()} */
diff --git a/src/java/android/net/ipsec/ike/IkeTrafficSelector.java b/src/java/com/android/ike/ikev2/IkeTrafficSelector.java
index 65154b9d..baebe647 100644
--- a/src/java/android/net/ipsec/ike/IkeTrafficSelector.java
+++ b/src/java/com/android/ike/ikev2/IkeTrafficSelector.java
@@ -14,23 +14,21 @@
* limitations under the License.
*/
-package android.net.ipsec.ike;
+package com.android.ike.ikev2;
import android.annotation.IntDef;
import android.util.ArraySet;
+import com.android.ike.ikev2.exceptions.InvalidSyntaxException;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.net.ipsec.ike.exceptions.InvalidSyntaxException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.net.Inet4Address;
-import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.BufferOverflowException;
import java.nio.ByteBuffer;
-import java.util.Objects;
/**
* IkeTrafficSelector represents a Traffic Selector of a Child SA.
@@ -45,14 +43,14 @@ public final class IkeTrafficSelector {
// IpProtocolId consists of standard IP Protocol IDs.
@Retention(RetentionPolicy.SOURCE)
- @IntDef({IP_PROTOCOL_ID_UNSPEC, IP_PROTOCOL_ID_ICMP, IP_PROTOCOL_ID_TCP, IP_PROTOCOL_ID_UDP})
+ @IntDef({IP_PROTOCOL_ID_UNSPEC, IP_PROTOCOL_ID_ICMP, IP_PROTOCOL_ID_TCP, IP_PROTOCOL_ID_UCP})
public @interface IpProtocolId {}
// Zero value is re-defined by IKE to indicate that all IP protocols are acceptable.
@VisibleForTesting static final int IP_PROTOCOL_ID_UNSPEC = 0;
@VisibleForTesting static final int IP_PROTOCOL_ID_ICMP = 1;
@VisibleForTesting static final int IP_PROTOCOL_ID_TCP = 6;
- @VisibleForTesting static final int IP_PROTOCOL_ID_UDP = 17;
+ @VisibleForTesting static final int IP_PROTOCOL_ID_UCP = 17;
private static final ArraySet<Integer> IP_PROTOCOL_ID_SET = new ArraySet<>();
@@ -60,7 +58,7 @@ public final class IkeTrafficSelector {
IP_PROTOCOL_ID_SET.add(IP_PROTOCOL_ID_UNSPEC);
IP_PROTOCOL_ID_SET.add(IP_PROTOCOL_ID_ICMP);
IP_PROTOCOL_ID_SET.add(IP_PROTOCOL_ID_TCP);
- IP_PROTOCOL_ID_SET.add(IP_PROTOCOL_ID_UDP);
+ IP_PROTOCOL_ID_SET.add(IP_PROTOCOL_ID_UCP);
}
/**
@@ -77,9 +75,6 @@ public final class IkeTrafficSelector {
public static final int TRAFFIC_SELECTOR_TYPE_IPV4_ADDR_RANGE = 7;
public static final int TRAFFIC_SELECTOR_TYPE_IPV6_ADDR_RANGE = 8;
- public static final int PORT_NUMBER_MIN = 0;
- public static final int PORT_NUMBER_MAX = 65535;
-
// TODO: Consider defining these constants in a central place in Connectivity.
private static final int IPV4_ADDR_LEN = 4;
private static final int IPV6_ADDR_LEN = 16;
@@ -112,57 +107,7 @@ public final class IkeTrafficSelector {
this.endingAddress = endingAddress;
}
- /**
- * Construct an instance of IkeTrafficSelector for building an outbound IKE message.
- *
- * @param tsType the Traffic Selector type.
- * @param startPort the smallest port number allowed by this Traffic Selector.
- * @param endPort the largest port number allowed by this Traffic Selector.
- * @param startingAddress the smallest address included in this Traffic Selector.
- * @param endingAddress the largest address included in this Traffic Selector.
- */
- public IkeTrafficSelector(
- @TrafficSelectorType int tsType,
- int startPort,
- int endPort,
- InetAddress startingAddress,
- InetAddress endingAddress) {
-
- this.tsType = tsType;
- this.ipProtocolId = IP_PROTOCOL_ID_UNSPEC;
-
- switch (tsType) {
- case TRAFFIC_SELECTOR_TYPE_IPV4_ADDR_RANGE:
- this.selectorLength = TRAFFIC_SELECTOR_IPV4_LEN;
-
- if (!(startingAddress instanceof Inet4Address)
- || !(endingAddress instanceof Inet4Address)) {
- throw new IllegalArgumentException(
- "Invalid address range: TS_IPV4_ADDR_RANGE requires IPv4 addresses.");
- }
-
- break;
- case TRAFFIC_SELECTOR_TYPE_IPV6_ADDR_RANGE:
- throw new UnsupportedOperationException("Do not support IPv6 Traffic Selector.");
- // TODO: Support IPv6 Traffic Selector.
- default:
- throw new IllegalArgumentException("Unrecognized Traffic Selector type.");
- }
-
- if (compareInetAddressTo(startingAddress, endingAddress) > 0) {
- throw new IllegalArgumentException("Received invalid address range.");
- }
-
- if (!isPortRangeValid(startPort, endPort)) {
- throw new IllegalArgumentException(
- "Invalid port range. startPort: " + startPort + " endPort: " + endPort);
- }
-
- this.startPort = startPort;
- this.endPort = endPort;
- this.startingAddress = startingAddress;
- this.endingAddress = endingAddress;
- }
+ // TODO: Add a constructor for users to construct IkeTrafficSelector.
/**
* Decode IkeTrafficSelectors from inbound Traffic Selector Payload.
@@ -226,12 +171,8 @@ public final class IkeTrafficSelector {
// Decode and validate ports
int startPort = Short.toUnsignedInt(inputBuffer.getShort());
int endPort = Short.toUnsignedInt(inputBuffer.getShort());
- if (!isPortRangeValid(startPort, endPort)) {
- throw new InvalidSyntaxException(
- "Received invalid port range. startPort: "
- + startPort
- + " endPort: "
- + endPort);
+ if (startPort > endPort) {
+ throw new InvalidSyntaxException("Received invalid port range.");
}
// Decode and validate IPv4 addresses
@@ -245,7 +186,7 @@ public final class IkeTrafficSelector {
Inet4Address endAddress = (Inet4Address) (Inet4Address.getByAddress(endAddressBytes));
// Validate address range.
- if (compareInetAddressTo(startAddress, endAddress) > 0) {
+ if (!isInetAddressRangeValid(startAddress, endAddress)) {
throw new InvalidSyntaxException("Received invalid IPv4 address range.");
}
@@ -264,110 +205,27 @@ public final class IkeTrafficSelector {
// TODO: Add a method for decoding IPv6 traffic selector.
- // Validate port range.
- private static boolean isPortRangeValid(int startPort, int endPort) {
- return (startPort >= PORT_NUMBER_MIN
- && startPort <= PORT_NUMBER_MAX
- && endPort >= PORT_NUMBER_MIN
- && endPort <= PORT_NUMBER_MAX
- && startPort <= endPort);
- }
-
- // Compare two InetAddresses. Return -1 if the first input is smaller; 1 if the second input is
- // smaller; 0 if two addresses are equal.
- // TODO: Consider moving it to the platform code in the future./
- private static int compareInetAddressTo(InetAddress leftAddress, InetAddress rightAddress) {
- byte[] leftAddrBytes = leftAddress.getAddress();
- byte[] rightAddrBytes = rightAddress.getAddress();
+ // Validate address range. Caller must ensure two address are same types.
+ // TODO: Consider moving it to the platform code in the future.
+ private static boolean isInetAddressRangeValid(
+ InetAddress startAddress, InetAddress endAddress) {
+ byte[] startAddrBytes = startAddress.getAddress();
+ byte[] endAddrBytes = endAddress.getAddress();
- if (leftAddrBytes.length != rightAddrBytes.length) {
+ if (startAddrBytes.length != endAddrBytes.length) {
throw new IllegalArgumentException("Two addresses are different types.");
}
- for (int i = 0; i < leftAddrBytes.length; i++) {
- int unsignedByteLeft = Byte.toUnsignedInt(leftAddrBytes[i]);
- int unsignedByteRight = Byte.toUnsignedInt(rightAddrBytes[i]);
+ for (int i = 0; i < startAddrBytes.length; i++) {
+ int unsignedByteStart = Byte.toUnsignedInt(startAddrBytes[i]);
+ int unsignedByteEnd = Byte.toUnsignedInt(endAddrBytes[i]);
- int result = Integer.compare(unsignedByteLeft, unsignedByteRight);
- if (result != 0) return result;
- }
- return 0;
- }
-
- /**
- * Check if the input IkeTrafficSelector is a subset of this instance.
- *
- * @param ts the provided IkeTrafficSelector to check.
- * @return true if the input IkeTrafficSelector is a subset of this instance, otherwise false.
- */
- public boolean contains(IkeTrafficSelector ts) {
- if (tsType == ts.tsType
- && ipProtocolId == ts.ipProtocolId
- && startPort <= ts.startPort
- && endPort >= ts.endPort
- && compareInetAddressTo(startingAddress, ts.startingAddress) <= 0
- && compareInetAddressTo(endingAddress, ts.endingAddress) >= 0) {
- return true;
- }
- return false;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(
- tsType,
- ipProtocolId,
- selectorLength,
- startPort,
- endPort,
- startingAddress,
- endingAddress);
- }
-
- @Override
- public boolean equals(Object o) {
- if (!(o instanceof IkeTrafficSelector)) return false;
-
- IkeTrafficSelector other = (IkeTrafficSelector) o;
-
- if (tsType != other.tsType
- || ipProtocolId != other.ipProtocolId
- || startPort != other.startPort
- || endPort != other.endPort) {
- return false;
- }
-
- switch (tsType) {
- case TRAFFIC_SELECTOR_TYPE_IPV4_ADDR_RANGE:
- return (((Inet4Address) startingAddress)
- .equals((Inet4Address) other.startingAddress)
- && ((Inet4Address) endingAddress)
- .equals((Inet4Address) other.endingAddress));
- case TRAFFIC_SELECTOR_TYPE_IPV6_ADDR_RANGE:
- return (((Inet6Address) startingAddress)
- .equals((Inet6Address) other.startingAddress)
- && ((Inet6Address) endingAddress)
- .equals((Inet6Address) other.endingAddress));
- default:
- throw new UnsupportedOperationException("Unrecognized TS type");
+ if (unsignedByteStart < unsignedByteEnd) {
+ return true;
+ } else if (unsignedByteStart > unsignedByteEnd) {
+ return false;
+ }
}
- }
-
- /**
- * Encode traffic selector to ByteBuffer.
- *
- * <p>This method will be only called by IkeTsPayload for building an outbound IKE message.
- *
- * @param byteBuffer destination ByteBuffer that stores encoded traffic selector.
- */
- public void encodeToByteBuffer(ByteBuffer byteBuffer) {
- byteBuffer
- .put((byte) tsType)
- .put((byte) ipProtocolId)
- .putShort((short) selectorLength)
- .putShort((short) startPort)
- .putShort((short) endPort)
- .put(startingAddress.getAddress())
- .put(endingAddress.getAddress());
+ return true;
}
}
diff --git a/src/java/com/android/ike/ikev2/SaProposal.java b/src/java/com/android/ike/ikev2/SaProposal.java
new file mode 100644
index 00000000..53206cc9
--- /dev/null
+++ b/src/java/com/android/ike/ikev2/SaProposal.java
@@ -0,0 +1,597 @@
+/*
+ * Copyright (C) 2018 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.ike.ikev2;
+
+import android.annotation.IntDef;
+import android.util.ArraySet;
+
+import com.android.ike.ikev2.message.IkePayload;
+import com.android.ike.ikev2.message.IkeSaPayload.DhGroupTransform;
+import com.android.ike.ikev2.message.IkeSaPayload.EncryptionTransform;
+import com.android.ike.ikev2.message.IkeSaPayload.EsnTransform;
+import com.android.ike.ikev2.message.IkeSaPayload.IntegrityTransform;
+import com.android.ike.ikev2.message.IkeSaPayload.PrfTransform;
+import com.android.ike.ikev2.message.IkeSaPayload.Transform;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * SaProposal represents a user configured set contains cryptograhic algorithms and key generating
+ * materials for negotiating an IKE or Child SA.
+ *
+ * <p>User must provide at least a valid SaProposal when they are creating a new IKE SA or Child SA.
+ *
+ * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key Exchange
+ * Protocol Version 2 (IKEv2)</a>
+ */
+public final class SaProposal {
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({
+ ENCRYPTION_ALGORITHM_3DES,
+ ENCRYPTION_ALGORITHM_AES_CBC,
+ ENCRYPTION_ALGORITHM_AES_GCM_8,
+ ENCRYPTION_ALGORITHM_AES_GCM_12,
+ ENCRYPTION_ALGORITHM_AES_GCM_16
+ })
+ public @interface EncryptionAlgorithm {}
+
+ public static final int ENCRYPTION_ALGORITHM_3DES = 3;
+ public static final int ENCRYPTION_ALGORITHM_AES_CBC = 12;
+ public static final int ENCRYPTION_ALGORITHM_AES_GCM_8 = 18;
+ public static final int ENCRYPTION_ALGORITHM_AES_GCM_12 = 19;
+ public static final int ENCRYPTION_ALGORITHM_AES_GCM_16 = 20;
+
+ private static final Set<Integer> SUPPORTED_ENCRYPTION_ALGORITHM;
+
+ static {
+ SUPPORTED_ENCRYPTION_ALGORITHM = new ArraySet<>();
+ SUPPORTED_ENCRYPTION_ALGORITHM.add(ENCRYPTION_ALGORITHM_3DES);
+ SUPPORTED_ENCRYPTION_ALGORITHM.add(ENCRYPTION_ALGORITHM_AES_CBC);
+ SUPPORTED_ENCRYPTION_ALGORITHM.add(ENCRYPTION_ALGORITHM_AES_GCM_8);
+ SUPPORTED_ENCRYPTION_ALGORITHM.add(ENCRYPTION_ALGORITHM_AES_GCM_12);
+ SUPPORTED_ENCRYPTION_ALGORITHM.add(ENCRYPTION_ALGORITHM_AES_GCM_16);
+ }
+
+ public static final int KEY_LEN_AES_128 = 128;
+ public static final int KEY_LEN_AES_192 = 192;
+ public static final int KEY_LEN_AES_256 = 256;
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({PSEUDORANDOM_FUNCTION_HMAC_SHA1, PSEUDORANDOM_FUNCTION_AES128_XCBC})
+ public @interface PseudorandomFunction {}
+
+ public static final int PSEUDORANDOM_FUNCTION_HMAC_SHA1 = 2;
+ public static final int PSEUDORANDOM_FUNCTION_AES128_XCBC = 4;
+
+ private static final Set<Integer> SUPPORTED_PSEUDORANDOM_FUNCTION;
+
+ static {
+ SUPPORTED_PSEUDORANDOM_FUNCTION = new ArraySet<>();
+ SUPPORTED_PSEUDORANDOM_FUNCTION.add(PSEUDORANDOM_FUNCTION_HMAC_SHA1);
+ SUPPORTED_PSEUDORANDOM_FUNCTION.add(PSEUDORANDOM_FUNCTION_AES128_XCBC);
+ }
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({
+ INTEGRITY_ALGORITHM_NONE,
+ INTEGRITY_ALGORITHM_HMAC_SHA1_96,
+ INTEGRITY_ALGORITHM_AES_XCBC_96,
+ INTEGRITY_ALGORITHM_HMAC_SHA2_256_128,
+ INTEGRITY_ALGORITHM_HMAC_SHA2_384_192,
+ INTEGRITY_ALGORITHM_HMAC_SHA2_512_256
+ })
+ public @interface IntegrityAlgorithm {}
+
+ public static final int INTEGRITY_ALGORITHM_NONE = 0;
+ public static final int INTEGRITY_ALGORITHM_HMAC_SHA1_96 = 2;
+ public static final int INTEGRITY_ALGORITHM_AES_XCBC_96 = 5;
+ public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_256_128 = 12;
+ public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_384_192 = 13;
+ public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_512_256 = 14;
+
+ private static final Set<Integer> SUPPORTED_INTEGRITY_ALGORITHM;
+
+ static {
+ SUPPORTED_INTEGRITY_ALGORITHM = new ArraySet<>();
+ SUPPORTED_INTEGRITY_ALGORITHM.add(INTEGRITY_ALGORITHM_NONE);
+ SUPPORTED_INTEGRITY_ALGORITHM.add(INTEGRITY_ALGORITHM_HMAC_SHA1_96);
+ SUPPORTED_INTEGRITY_ALGORITHM.add(INTEGRITY_ALGORITHM_AES_XCBC_96);
+ SUPPORTED_INTEGRITY_ALGORITHM.add(INTEGRITY_ALGORITHM_HMAC_SHA2_256_128);
+ SUPPORTED_INTEGRITY_ALGORITHM.add(INTEGRITY_ALGORITHM_HMAC_SHA2_384_192);
+ SUPPORTED_INTEGRITY_ALGORITHM.add(INTEGRITY_ALGORITHM_HMAC_SHA2_512_256);
+ }
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({DH_GROUP_NONE, DH_GROUP_1024_BIT_MODP, DH_GROUP_2048_BIT_MODP})
+ public @interface DhGroup {}
+
+ public static final int DH_GROUP_NONE = 0;
+ public static final int DH_GROUP_1024_BIT_MODP = 2;
+ public static final int DH_GROUP_2048_BIT_MODP = 14;
+
+ private static final Set<Integer> SUPPORTED_DH_GROUP;
+
+ static {
+ SUPPORTED_DH_GROUP = new ArraySet<>();
+ SUPPORTED_DH_GROUP.add(DH_GROUP_NONE);
+ SUPPORTED_DH_GROUP.add(DH_GROUP_1024_BIT_MODP);
+ SUPPORTED_DH_GROUP.add(DH_GROUP_2048_BIT_MODP);
+ }
+
+ /** Package private */
+ @IkePayload.ProtocolId private final int mProtocolId;
+ /** Package private */
+ private final EncryptionTransform[] mEncryptionAlgorithms;
+ /** Package private */
+ private final PrfTransform[] mPseudorandomFunctions;
+ /** Package private */
+ private final IntegrityTransform[] mIntegrityAlgorithms;
+ /** Package private */
+ private final DhGroupTransform[] mDhGroups;
+ /** Package private */
+ private final EsnTransform[] mEsns;
+
+ private SaProposal(
+ @IkePayload.ProtocolId int protocol,
+ EncryptionTransform[] encryptionAlgos,
+ PrfTransform[] prfs,
+ IntegrityTransform[] integrityAlgos,
+ DhGroupTransform[] dhGroups) {
+ mProtocolId = protocol;
+ mEncryptionAlgorithms = encryptionAlgos;
+ mPseudorandomFunctions = prfs;
+ mIntegrityAlgorithms = integrityAlgos;
+ mDhGroups = dhGroups;
+
+ if (protocol == IkePayload.PROTOCOL_ID_IKE) {
+ // Do not negotiate ESN for IKE SA proposal
+ mEsns = new EsnTransform[0];
+ } else {
+ // Do not support negotiating Child SAs using extended sequence numbers.
+ mEsns = new EsnTransform[] {new EsnTransform()};
+ }
+ }
+
+ /**
+ * Construct SaProposal from a decoded inbound IKE packet, only called by IkeSaPayload.
+ *
+ * @param protocol IP protocol ID
+ * @param encryptionAlgos encryption algorithms decoded from inbound IKE packet.
+ * @param prfs pseudorandom functions decoded from inbound IKE packet.
+ * @param integrityAlgos integrity algorithms decoded from inbound IKE packet.
+ * @param dhGroups Dh groups decoded from inbound IKE packet.
+ * @param esns ESN policies decoded from IKE packet.
+ */
+ public SaProposal(
+ @IkePayload.ProtocolId int protocol,
+ EncryptionTransform[] encryptionAlgos,
+ PrfTransform[] prfs,
+ IntegrityTransform[] integrityAlgos,
+ DhGroupTransform[] dhGroups,
+ EsnTransform[] esns) {
+ mProtocolId = protocol;
+ mEncryptionAlgorithms = encryptionAlgos;
+ mPseudorandomFunctions = prfs;
+ mIntegrityAlgorithms = integrityAlgos;
+ mDhGroups = dhGroups;
+ mEsns = esns;
+ }
+
+ /**
+ * Check if the current SaProposal from the SA responder is consistent with the selected
+ * reqProposal from the SA initiator.
+ *
+ * @param reqProposal selected SaProposal from SA initiator
+ * @return if current SaProposal from SA responder is consistent with the selected reqProposal
+ * from SA initiator.
+ */
+ public boolean isNegotiatedFrom(SaProposal reqProposal) {
+ return isTransformSelectedFrom(mEncryptionAlgorithms, reqProposal.mEncryptionAlgorithms)
+ && isTransformSelectedFrom(
+ mPseudorandomFunctions, reqProposal.mPseudorandomFunctions)
+ && isTransformSelectedFrom(mIntegrityAlgorithms, reqProposal.mIntegrityAlgorithms)
+ && isTransformSelectedFrom(mDhGroups, reqProposal.mDhGroups)
+ && isTransformSelectedFrom(mEsns, reqProposal.mEsns);
+ }
+
+ /** Package private */
+ static boolean isTransformSelectedFrom(Transform[] selected, Transform[] selectFrom) {
+ // If the selected proposal has multiple transforms with the same type, the responder MUST
+ // choose a single one.
+ if ((selected.length > 1) || (selected.length == 0) != (selectFrom.length == 0)) {
+ return false;
+ }
+
+ if (selected.length == 0) return true;
+
+ return Arrays.asList(selectFrom).contains(selected[0]);
+ }
+
+ /*Package private*/
+ @IkePayload.ProtocolId
+ int getProtocolId() {
+ return mProtocolId;
+ }
+
+ /*Package private*/
+ EncryptionTransform[] getEncryptionTransforms() {
+ return mEncryptionAlgorithms;
+ }
+
+ /*Package private*/
+ PrfTransform[] getPrfTransforms() {
+ return mPseudorandomFunctions;
+ }
+
+ /*Package private*/
+ IntegrityTransform[] getIntegrityTransforms() {
+ return mIntegrityAlgorithms;
+ }
+
+ /*Package private*/
+ DhGroupTransform[] getDhGroupTransforms() {
+ return mDhGroups;
+ }
+
+ /*Package private*/
+ EsnTransform[] getEsnTransforms() {
+ return mEsns;
+ }
+
+ /**
+ * Return all SA Transforms in this SaProposal to be encoded for building an outbound IKE
+ * message.
+ *
+ * <p>This method can be called by only IKE library.
+ *
+ * @return Array of Transforms to be encoded.
+ */
+ public Transform[] getAllTransforms() {
+ int encodedNumTransforms =
+ mEncryptionAlgorithms.length
+ + mPseudorandomFunctions.length
+ + mIntegrityAlgorithms.length
+ + mDhGroups.length
+ + mEsns.length;
+
+ List<Transform> transformList = new ArrayList<Transform>(encodedNumTransforms);
+ transformList.addAll(Arrays.asList(mEncryptionAlgorithms));
+ transformList.addAll(Arrays.asList(mPseudorandomFunctions));
+ transformList.addAll(Arrays.asList(mIntegrityAlgorithms));
+ transformList.addAll(Arrays.asList(mDhGroups));
+ transformList.addAll(Arrays.asList(mEsns));
+
+ return transformList.toArray(new Transform[encodedNumTransforms]);
+ }
+
+ /**
+ * This class can be used to incrementally construct a SaProposal. SaProposal instances are
+ * immutable once built.
+ *
+ * <p>TODO: Support users to add algorithms from most preferred to least preferred.
+ */
+ public static final class Builder {
+ private static final String ERROR_TAG = "Invalid SA Proposal: ";
+
+ /** Indicate if Builder is for building IKE SA proposal or Child SA proposal. */
+ private final boolean mIsIkeProposal;
+ /**
+ * Indicate if Builder is for building first Child SA proposal or addtional Child SA
+ * proposal. Only valid if mIsIkeProposal is false.
+ */
+ private final boolean mIsFirstChild;
+
+ // Use set to avoid adding repeated algorithms.
+ private final Set<EncryptionTransform> mProposedEncryptAlgos = new ArraySet<>();
+ private final Set<PrfTransform> mProposedPrfs = new ArraySet<>();
+ private final Set<IntegrityTransform> mProposedIntegrityAlgos = new ArraySet<>();
+ private final Set<DhGroupTransform> mProposedDhGroups = new ArraySet<>();
+
+ private boolean mHasAead = false;
+
+ private Builder(boolean isIke, boolean isFirstChild) {
+ mIsIkeProposal = isIke;
+ mIsFirstChild = isFirstChild;
+ }
+
+ private static boolean isAead(@EncryptionAlgorithm int algorithm) {
+ switch (algorithm) {
+ case ENCRYPTION_ALGORITHM_3DES:
+ // Fall through
+ case ENCRYPTION_ALGORITHM_AES_CBC:
+ return false;
+ case ENCRYPTION_ALGORITHM_AES_GCM_8:
+ // Fall through
+ case ENCRYPTION_ALGORITHM_AES_GCM_12:
+ // Fall through
+ case ENCRYPTION_ALGORITHM_AES_GCM_16:
+ return true;
+ default:
+ // Won't hit here.
+ throw new IllegalArgumentException("Unsupported Encryption Algorithm.");
+ }
+ }
+
+ private EncryptionTransform[] buildEncryptAlgosOrThrow() {
+ if (mProposedEncryptAlgos.isEmpty()) {
+ throw new IllegalArgumentException(
+ ERROR_TAG + "Encryption algorithm must be proposed.");
+ }
+
+ return mProposedEncryptAlgos.toArray(
+ new EncryptionTransform[mProposedEncryptAlgos.size()]);
+ }
+
+ private PrfTransform[] buildPrfsOrThrow() {
+ if (mIsIkeProposal == mProposedPrfs.isEmpty()) {
+ throw new IllegalArgumentException(
+ ERROR_TAG + "Invalid PRF configuration for this SA Proposal.");
+ }
+
+ return mProposedPrfs.toArray(new PrfTransform[mProposedPrfs.size()]);
+ }
+
+ private IntegrityTransform[] buildIntegAlgosForIkeOrThrow() {
+ // When building IKE SA Proposal with normal-mode ciphers, mProposedIntegrityAlgos must
+ // not be empty and must not have INTEGRITY_ALGORITHM_NONE. When building IKE SA
+ // Proposal with combined-mode ciphers, mProposedIntegrityAlgos must be either empty or
+ // only have INTEGRITY_ALGORITHM_NONE.
+ if (mProposedIntegrityAlgos.isEmpty() && !mHasAead) {
+ throw new IllegalArgumentException(
+ ERROR_TAG
+ + "Integrity algorithm "
+ + "must be proposed with normal ciphers in IKE proposal.");
+ }
+
+ for (IntegrityTransform transform : mProposedIntegrityAlgos) {
+ if ((transform.id == INTEGRITY_ALGORITHM_NONE) != mHasAead) {
+ throw new IllegalArgumentException(
+ ERROR_TAG
+ + "Invalid integrity algorithm configuration"
+ + " for this SA Proposal");
+ }
+ }
+
+ return mProposedIntegrityAlgos.toArray(
+ new IntegrityTransform[mProposedIntegrityAlgos.size()]);
+ }
+
+ private IntegrityTransform[] buildIntegAlgosForChildOrThrow() {
+ // When building Child SA Proposal with normal-mode ciphers, there is no contraint on
+ // integrity algorithm. When building Child SA Proposal with combined-mode ciphers,
+ // mProposedIntegrityAlgos must be either empty or only have INTEGRITY_ALGORITHM_NONE.
+ for (IntegrityTransform transform : mProposedIntegrityAlgos) {
+ if (transform.id != INTEGRITY_ALGORITHM_NONE && mHasAead) {
+ throw new IllegalArgumentException(
+ ERROR_TAG
+ + "Only INTEGRITY_ALGORITHM_NONE can be"
+ + " proposed with combined-mode ciphers in any proposal.");
+ }
+ }
+
+ return mProposedIntegrityAlgos.toArray(
+ new IntegrityTransform[mProposedIntegrityAlgos.size()]);
+ }
+
+ private DhGroupTransform[] buildDhGroupsForIkeOrThrow() {
+ if (mProposedDhGroups.isEmpty()) {
+ throw new IllegalArgumentException(
+ ERROR_TAG + "DH group must be proposed in IKE SA proposal.");
+ }
+
+ for (DhGroupTransform transform : mProposedDhGroups) {
+ if (transform.id == DH_GROUP_NONE) {
+ throw new IllegalArgumentException(
+ ERROR_TAG
+ + "None-value DH group must not"
+ + " be proposed in IKE SA proposal");
+ }
+ }
+
+ return mProposedDhGroups.toArray(new DhGroupTransform[mProposedDhGroups.size()]);
+ }
+
+ private DhGroupTransform[] buildDhGroupsForChildOrThrow() {
+ for (DhGroupTransform transform : mProposedDhGroups) {
+ if (transform.id != DH_GROUP_NONE && mIsFirstChild) {
+ throw new IllegalArgumentException(
+ ERROR_TAG
+ + "Only DH_GROUP_NONE can be"
+ + " proposed in first Child SA proposal.");
+ }
+ }
+ return mProposedDhGroups.toArray(new DhGroupTransform[mProposedDhGroups.size()]);
+ }
+
+ /** Returns a new Builder for a IKE SA Proposal. */
+ public static Builder newIkeSaProposalBuilder() {
+ return new Builder(true, false);
+ }
+
+ /**
+ * Returns a new Builder for a Child SA Proposal.
+ *
+ * @param isFirstChildSaProposal indicates if this SA proposal for first Child SA.
+ * @return Builder for a Child SA Proposal.
+ */
+ public static Builder newChildSaProposalBuilder(boolean isFirstChildSaProposal) {
+ return new Builder(false, isFirstChildSaProposal);
+ }
+
+ /**
+ * Adds an encryption algorithm to SA proposal being built.
+ *
+ * @param algorithm encryption algorithm to add to SaProposal.
+ * @return Builder of SaProposal.
+ */
+ public Builder addEncryptionAlgorithm(@EncryptionAlgorithm int algorithm) {
+ // Construct EncryptionTransform and validate proposed algorithm during
+ // construction.
+ EncryptionTransform encryptionTransform = new EncryptionTransform(algorithm);
+
+ validateOnlyOneModeEncryptAlgoProposedOrThrow(algorithm);
+
+ mProposedEncryptAlgos.add(encryptionTransform);
+ return this;
+ }
+
+ /**
+ * Adds an encryption algorithm with specific key length to SA proposal being built.
+ *
+ * @param algorithm encryption algorithm to add to SaProposal.
+ * @param keyLength key length of algorithm.
+ * @return Builder of SaProposal.
+ * @throws IllegalArgumentException if AEAD and non-combined mode algorithms are mixed.
+ */
+ public Builder addEncryptionAlgorithm(@EncryptionAlgorithm int algorithm, int keyLength) {
+ // Construct EncryptionTransform and validate proposed algorithm during
+ // construction.
+ EncryptionTransform encryptionTransform = new EncryptionTransform(algorithm, keyLength);
+
+ validateOnlyOneModeEncryptAlgoProposedOrThrow(algorithm);
+
+ mProposedEncryptAlgos.add(encryptionTransform);
+ return this;
+ }
+
+ private void validateOnlyOneModeEncryptAlgoProposedOrThrow(
+ @EncryptionAlgorithm int algorithm) {
+ boolean isCurrentAead = isAead(algorithm);
+
+ if (!mProposedEncryptAlgos.isEmpty() && (mHasAead ^ isCurrentAead)) {
+ throw new IllegalArgumentException(
+ ERROR_TAG
+ + "Proposal cannot has both normal ciphers "
+ + "and combined-mode ciphers.");
+ }
+
+ if (isCurrentAead) mHasAead = true;
+ }
+
+ /**
+ * Adds a pseudorandom function to SA proposal being built.
+ *
+ * @param algorithm pseudorandom function to add to SaProposal.
+ * @return Builder of SaProposal.
+ */
+ public Builder addPseudorandomFunction(@PseudorandomFunction int algorithm) {
+ // Construct PrfTransform and validate proposed algorithm during
+ // construction.
+ mProposedPrfs.add(new PrfTransform(algorithm));
+ return this;
+ }
+
+ /**
+ * Adds an integrity algorithm to SA proposal being built.
+ *
+ * @param algorithm integrity algorithm to add to SaProposal.
+ * @return Builder of SaProposal.
+ */
+ public Builder addIntegrityAlgorithm(@IntegrityAlgorithm int algorithm) {
+ // Construct IntegrityTransform and validate proposed algorithm during
+ // construction.
+ mProposedIntegrityAlgos.add(new IntegrityTransform(algorithm));
+ return this;
+ }
+
+ /**
+ * Adds a Diffie-Hellman Group to SA proposal being built.
+ *
+ * @param dhGroup to add to SaProposal.
+ * @return Builder of SaProposal.
+ */
+ public Builder addDhGroup(@DhGroup int dhGroup) {
+ // Construct DhGroupTransform and validate proposed dhGroup during
+ // construction.
+ mProposedDhGroups.add(new DhGroupTransform(dhGroup));
+ return this;
+ }
+
+ /**
+ * Validates, builds and returns the SaProposal
+ *
+ * @return SaProposal the validated SaProposal.
+ * @throws IllegalArgumentException if SaProposal is invalid.
+ */
+ public SaProposal build() {
+ EncryptionTransform[] encryptionTransforms = buildEncryptAlgosOrThrow();
+ PrfTransform[] prfTransforms = buildPrfsOrThrow();
+ IntegrityTransform[] integrityTransforms =
+ mIsIkeProposal
+ ? buildIntegAlgosForIkeOrThrow()
+ : buildIntegAlgosForChildOrThrow();
+
+ DhGroupTransform[] dhGroupTransforms =
+ mIsIkeProposal ? buildDhGroupsForIkeOrThrow() : buildDhGroupsForChildOrThrow();
+ // IKE library only supports negotiating ESP Child SA.
+ int protocol = mIsIkeProposal ? IkePayload.PROTOCOL_ID_IKE : IkePayload.PROTOCOL_ID_ESP;
+
+ return new SaProposal(
+ protocol,
+ encryptionTransforms,
+ prfTransforms,
+ integrityTransforms,
+ dhGroupTransforms);
+ }
+ }
+
+ /**
+ * Check if the provided algorithm is a supported encryption algorithm.
+ *
+ * @param algorithm IKE standard encryption algorithm id.
+ * @return true if the provided algorithm is a supported encryption algorithm.
+ */
+ public static boolean isSupportedEncryptionAlgorithm(@EncryptionAlgorithm int algorithm) {
+ return SUPPORTED_ENCRYPTION_ALGORITHM.contains(algorithm);
+ }
+
+ /**
+ * Check if the provided algorithm is a supported pseudorandom function.
+ *
+ * @param algorithm IKE standard pseudorandom function id.
+ * @return true if the provided algorithm is a supported pseudorandom function.
+ */
+ public static boolean isSupportedPseudorandomFunction(@PseudorandomFunction int algorithm) {
+ return SUPPORTED_PSEUDORANDOM_FUNCTION.contains(algorithm);
+ }
+
+ /**
+ * Check if the provided algorithm is a supported integrity algorithm.
+ *
+ * @param algorithm IKE standard integrity algorithm id.
+ * @return true if the provided algorithm is a supported integrity algorithm.
+ */
+ public static boolean isSupportedIntegrityAlgorithm(@IntegrityAlgorithm int algorithm) {
+ return SUPPORTED_INTEGRITY_ALGORITHM.contains(algorithm);
+ }
+
+ /**
+ * Check if the provided group number is for a supported Diffie-Hellman Group.
+ *
+ * @param dhGroup IKE standard DH Group id.
+ * @return true if the provided number is for a supported Diffie-Hellman Group.
+ */
+ public static boolean isSupportedDhGroup(@DhGroup int dhGroup) {
+ return SUPPORTED_DH_GROUP.contains(dhGroup);
+ }
+}
diff --git a/src/java/com/android/ike/ikev2/SaRecord.java b/src/java/com/android/ike/ikev2/SaRecord.java
new file mode 100644
index 00000000..4dcddec4
--- /dev/null
+++ b/src/java/com/android/ike/ikev2/SaRecord.java
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2019 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.ike.ikev2;
+
+import com.android.ike.ikev2.message.IkeMessage;
+import com.android.ike.ikev2.message.IkePayload;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.nio.ByteBuffer;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.util.List;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+
+/**
+ * SaRecord represents common information of an IKE SA and a Child SA.
+ *
+ * <p>When doing rekey, there can be multiple SAs in the same IkeSessionStateMachine or
+ * ChildSessionStateMachine, where they use same cryptographic algorithms but with different keys.
+ * We store cryptographic algorithms and unchanged SA configurations in IkeSessionOptions or
+ * ChildSessionOptions and store changed information including keys, SPIs, and nonces in SaRecord.
+ */
+public abstract class SaRecord {
+
+ private static ISaRecordHelper sSaRecordHelper = new SaRecordHelper();
+
+ public final byte[] nonceInitiator;
+ public final byte[] nonceResponder;
+
+ /** Package private */
+ SaRecord(byte[] nonceInit, byte[] nonceResp) {
+ nonceInitiator = nonceInit;
+ nonceResponder = nonceResp;
+ }
+
+ /**
+ * SaRecordHelper implements methods for constructing SaRecord.
+ *
+ * <p>Package private
+ */
+ static class SaRecordHelper implements ISaRecordHelper {
+ @Override
+ public IkeSaRecord makeFirstIkeSaRecord(IkeMessage initRequest, IkeMessage initResponse) {
+ // TODO: Generate keying materials
+ return null;
+ }
+
+ @Override
+ public IkeSaRecord makeNewIkeSaRecord(
+ IkeSaRecord oldSaRecord, IkeMessage rekeyRequest, IkeMessage rekeyResponse) {
+ // TODO: Generate keying materials based on old SK_d
+ return null;
+ }
+
+ @Override
+ public ChildSaRecord makeChildSaRecord(
+ List<IkePayload> reqPayloads, List<IkePayload> respPayloads) {
+ // TODO: Calculate keys and build IpSecTransform.
+ return null;
+ }
+ }
+
+ /** Package private */
+ static void setSaRecordHelper(ISaRecordHelper helper) {
+ sSaRecordHelper = helper;
+ }
+
+ /** IkeSaRecord represents an IKE SA. */
+ public static class IkeSaRecord extends SaRecord implements Comparable<IkeSaRecord> {
+
+ /** SPI of IKE SA initiator */
+ public final long initiatorSpi;
+ /** SPI of IKE SA responder */
+ public final long responderSpi;
+ /** Flag indicates if this IKE SA is locally initiated */
+ public final boolean isLocalInit;
+
+ /** Package private */
+ IkeSaRecord(
+ long initSpi, long respSpi, boolean localInit, byte[] nonceInit, byte[] nonceResp) {
+ super(nonceInit, nonceResp);
+ initiatorSpi = initSpi;
+ responderSpi = respSpi;
+ isLocalInit = localInit;
+ // TODO: Impement constructor. There will be more input parameters.
+ }
+
+ /** Package private */
+ static IkeSaRecord makeFirstIkeSaRecord(IkeMessage initRequest, IkeMessage initResponse) {
+ return sSaRecordHelper.makeFirstIkeSaRecord(initRequest, initResponse);
+ }
+
+ /** Package private */
+ static IkeSaRecord makeNewIkeSaRecord(
+ IkeSaRecord oldSaRecord, IkeMessage rekeyRequest, IkeMessage rekeyResponse) {
+ return sSaRecordHelper.makeNewIkeSaRecord(oldSaRecord, rekeyRequest, rekeyResponse);
+ }
+
+ /** Package private */
+ long getRemoteSpi() {
+ if (isLocalInit) {
+ return responderSpi;
+ } else {
+ return initiatorSpi;
+ }
+ }
+
+ /**
+ * Compare with a specific IkeSaRecord
+ *
+ * @param record IkeSaRecord to be compared.
+ * @return a negative integer if input IkeSaRecord contains lowest nonce; a positive integer
+ * if this IkeSaRecord has lowest nonce; return zero if lowest nonces of two
+ * IkeSaRecords match.
+ */
+ public int compareTo(IkeSaRecord record) {
+ // TODO: Implement it b/122924815.
+ return 1;
+ }
+ }
+
+ /** ChildSaRecord represents an Child SA. */
+ public static class ChildSaRecord extends SaRecord implements Comparable<ChildSaRecord> {
+
+ /** Locally generated SPI for receiving IPsec Packet. */
+ public final int inboundSpi;
+ /** Remotely generated SPI for sending IPsec Packet. */
+ public final int outboundSpi;
+
+ /** Package private */
+ ChildSaRecord(int inSpi, int outSpi, byte[] nonceInit, byte[] nonceResp) {
+ super(nonceInit, nonceResp);
+ inboundSpi = inSpi;
+ outboundSpi = outSpi;
+ // TODO: Impement constructor. Will be more input parameters.
+ }
+
+ /** Package private */
+ static ChildSaRecord makeChildSaRecord(
+ List<IkePayload> reqPayloads, List<IkePayload> respPayloads) {
+ return sSaRecordHelper.makeChildSaRecord(reqPayloads, respPayloads);
+ }
+
+ /**
+ * Compare with a specific ChildSaRecord
+ *
+ * @param record ChildSaRecord to be compared.
+ * @return a negative integer if input ChildSaRecord contains lowest nonce; a positive
+ * integer if this ChildSaRecord has lowest nonce; return zero if lowest nonces of two
+ * ChildSaRecord match.
+ */
+ public int compareTo(ChildSaRecord record) {
+ // TODO: Implement it b/122924815
+ return 1;
+ }
+ }
+
+ /**
+ * ISaRecordHelper provides a package private interface for constructing SaRecord.
+ *
+ * <p>ISaRecordHelper exists so that the interface is injectable for testing.
+ */
+ interface ISaRecordHelper {
+ /**
+ * Construct IkeSaRecord as results of IKE initial exchange.
+ *
+ * @param initRequest IKE_INIT request.
+ * @param initResponse IKE_INIT request.
+ * @return ikeSaRecord for initial IKE SA.
+ */
+ IkeSaRecord makeFirstIkeSaRecord(IkeMessage initRequest, IkeMessage initResponse);
+
+ /**
+ * Construct new IkeSaRecord when doing rekey.
+ *
+ * @param oldSaRecord old IKE SA
+ * @param rekeyRequest Rekey IKE request.
+ * @param rekeyResponse Rekey IKE response.
+ * @return ikeSaRecord for new IKE SA.
+ */
+ IkeSaRecord makeNewIkeSaRecord(
+ IkeSaRecord oldSaRecord, IkeMessage rekeyRequest, IkeMessage rekeyResponse);
+
+ /**
+ * Construct ChildSaRecord and generate IpSecTransform pairs.
+ *
+ * @param reqPayloads payload list in request.
+ * @param respPayloads payload list in response.
+ * @return new Child SA.
+ */
+ ChildSaRecord makeChildSaRecord(
+ List<IkePayload> reqPayloads, List<IkePayload> respPayloads);
+ }
+
+ /** Generate SKEYSEED using negotiated PRF. */
+ @VisibleForTesting
+ static byte[] generateSKeySeed(
+ String prfAlgorithm, byte[] nonceInit, byte[] nonceResp, byte[] sharedDhKey) {
+ try {
+ ByteBuffer keyBuffer = ByteBuffer.allocate(nonceInit.length + nonceResp.length);
+ keyBuffer.put(nonceInit).put(nonceResp);
+ SecretKeySpec prfKeySpec = new SecretKeySpec(keyBuffer.array(), prfAlgorithm);
+
+ Mac prfMac = Mac.getInstance(prfAlgorithm, IkeMessage.getSecurityProvider());
+ prfMac.init(prfKeySpec);
+
+ ByteBuffer sharedKeyBuffer = ByteBuffer.wrap(sharedDhKey);
+ prfMac.update(sharedKeyBuffer);
+
+ return prfMac.doFinal();
+ } catch (InvalidKeyException | NoSuchAlgorithmException e) {
+ throw new IllegalArgumentException("Failed to generate SKEYSEED", e);
+ }
+ }
+
+ /**
+ * Derives key materials using negotiated PRF.
+ *
+ * <p>prf+(K, S) outputs a pseudorandom stream by using negotiated PRF iteratively. In this way
+ * it can generate long enough keying material containing all the keys for this IKE/Child SA.
+ *
+ * @see <a href="https://tools.ietf.org/html/rfc7296#section-2.13">RFC 7296 nternet Key Exchange
+ * Protocol Version 2 (IKEv2) 2.13. Generating Keying Material </a>
+ */
+ @VisibleForTesting
+ static byte[] generateKeyMat(
+ String prfAlgorithm, byte[] prfKey, byte[] dataToSign, int keyMaterialLen)
+ throws InvalidKeyException {
+ try {
+ SecretKeySpec prfKeySpec = new SecretKeySpec(prfKey, prfAlgorithm);
+ Mac prfMac = Mac.getInstance(prfAlgorithm, IkeMessage.getSecurityProvider());
+
+ ByteBuffer keyMatBuffer = ByteBuffer.allocate(keyMaterialLen);
+
+ byte[] previousMac = new byte[0];
+ final int padLen = 1;
+ byte padValue = 1;
+
+ while (keyMatBuffer.remaining() > 0) {
+ prfMac.init(prfKeySpec);
+
+ ByteBuffer dataToSignBuffer =
+ ByteBuffer.allocate(previousMac.length + dataToSign.length + padLen);
+ dataToSignBuffer.put(previousMac).put(dataToSign).put(padValue);
+ dataToSignBuffer.rewind();
+
+ prfMac.update(dataToSignBuffer);
+
+ previousMac = prfMac.doFinal();
+ keyMatBuffer.put(
+ previousMac, 0, Math.min(previousMac.length, keyMatBuffer.remaining()));
+
+ padValue++;
+ }
+
+ return keyMatBuffer.array();
+ } catch (InvalidKeyException | NoSuchAlgorithmException e) {
+ throw new IllegalArgumentException("Failed to generate keying material", e);
+ }
+ }
+}
diff --git a/src/java/com/android/internal/net/ipsec/ike/exceptions/AuthenticationFailedException.java b/src/java/com/android/ike/ikev2/exceptions/AuthenticationFailedException.java
index e5873648..8a5433b9 100644
--- a/src/java/com/android/internal/net/ipsec/ike/exceptions/AuthenticationFailedException.java
+++ b/src/java/com/android/ike/ikev2/exceptions/AuthenticationFailedException.java
@@ -13,11 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.internal.net.ipsec.ike.exceptions;
+package com.android.ike.ikev2.exceptions;
-import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_AUTHENTICATION_FAILED;
-
-import android.net.ipsec.ike.exceptions.IkeProtocolException;
+import com.android.ike.ikev2.message.IkeNotifyPayload;
/**
* This exception is thrown when IKE authentication fails.
@@ -27,16 +25,14 @@ import android.net.ipsec.ike.exceptions.IkeProtocolException;
* @see <a href="https://tools.ietf.org/html/rfc7296#section-2.21.2">RFC 7296, Internet Key Exchange
* Protocol Version 2 (IKEv2)</a>
*/
-public final class AuthenticationFailedException extends IkeProtocolException {
- private static final int EXPECTED_ERROR_DATA_LEN = 0;
-
+public final class AuthenticationFailedException extends IkeException {
/**
* Construct a instance of AuthenticationFailedException.
*
* @param message the detail message.
*/
public AuthenticationFailedException(String message) {
- super(ERROR_TYPE_AUTHENTICATION_FAILED, message);
+ super(IkeNotifyPayload.NOTIFY_TYPE_AUTHENTICATION_FAILED, message);
}
/**
@@ -45,20 +41,6 @@ public final class AuthenticationFailedException extends IkeProtocolException {
* @param cause the cause.
*/
public AuthenticationFailedException(Throwable cause) {
- super(ERROR_TYPE_AUTHENTICATION_FAILED, cause);
- }
-
- /**
- * Construct a instance of AuthenticationFailedExcepion from a notify payload.
- *
- * @param notifyData the notify data included in the payload.
- */
- public AuthenticationFailedException(byte[] notifyData) {
- super(ERROR_TYPE_AUTHENTICATION_FAILED, notifyData);
- }
-
- @Override
- protected boolean isValidDataLength(int dataLen) {
- return EXPECTED_ERROR_DATA_LEN == dataLen;
+ super(IkeNotifyPayload.NOTIFY_TYPE_AUTHENTICATION_FAILED, cause);
}
}
diff --git a/src/java/com/android/ike/ikev2/exceptions/IkeException.java b/src/java/com/android/ike/ikev2/exceptions/IkeException.java
new file mode 100644
index 00000000..532b6343
--- /dev/null
+++ b/src/java/com/android/ike/ikev2/exceptions/IkeException.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2018 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.ike.ikev2.exceptions;
+
+import com.android.ike.ikev2.message.IkeNotifyPayload;
+
+/**
+ * IkeException is an abstract class that represents the common information for all IKE protocol
+ * errors.
+ *
+ * <p>Each types of IKE error should implement its own subclass
+ *
+ * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.10.1">RFC 7296, Internet Key Exchange
+ * Protocol Version 2 (IKEv2)</a>
+ */
+public abstract class IkeException extends Exception {
+ @IkeNotifyPayload.NotifyType public final int errorCode;
+
+ /**
+ * Construct an instance of IkeException.
+ *
+ * @param code the protocol error code.
+ */
+ public IkeException(@IkeNotifyPayload.NotifyType int code) {
+ super();
+ errorCode = code;
+ }
+
+ /**
+ * Construct an instance of IkeException with specified detail message.
+ *
+ * @param code the protocol error code.
+ * @param message the detail message.
+ */
+ public IkeException(@IkeNotifyPayload.NotifyType int code, String message) {
+ super(message);
+ errorCode = code;
+ }
+
+ /**
+ * Construct an instance of IkeException with specified cause.
+ *
+ * @param code the protocol error code.
+ * @param cause the cause.
+ */
+ public IkeException(@IkeNotifyPayload.NotifyType int code, Throwable cause) {
+ super(cause);
+ errorCode = code;
+ }
+}
diff --git a/src/java/com/android/internal/net/ipsec/ike/exceptions/InvalidMajorVersionException.java b/src/java/com/android/ike/ikev2/exceptions/InvalidMajorVersionException.java
index dc0357ee..d23d0e3c 100644
--- a/src/java/com/android/internal/net/ipsec/ike/exceptions/InvalidMajorVersionException.java
+++ b/src/java/com/android/ike/ikev2/exceptions/InvalidMajorVersionException.java
@@ -13,11 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.internal.net.ipsec.ike.exceptions;
+package com.android.ike.ikev2.exceptions;
-import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_INVALID_MAJOR_VERSION;
-
-import android.net.ipsec.ike.exceptions.IkeProtocolException;
+import com.android.ike.ikev2.message.IkeNotifyPayload;
/**
* This exception is thrown when major version is higher than 2.
@@ -28,8 +26,8 @@ import android.net.ipsec.ike.exceptions.IkeProtocolException;
* @see <a href="https://tools.ietf.org/html/rfc7296#section-2.5">RFC 7296, Internet Key Exchange
* Protocol Version 2 (IKEv2)</a>
*/
-public final class InvalidMajorVersionException extends IkeProtocolException {
- private static final int EXPECTED_ERROR_DATA_LEN = 1;
+public final class InvalidMajorVersionException extends IkeException {
+ public final byte receivedMajorVersion;
/**
* Construct a instance of InvalidMajorVersionException
@@ -37,29 +35,7 @@ public final class InvalidMajorVersionException extends IkeProtocolException {
* @param version the major version in received packet
*/
public InvalidMajorVersionException(byte version) {
- super(ERROR_TYPE_INVALID_MAJOR_VERSION, new byte[] {version});
- }
-
- /**
- * Construct a instance of InvalidMajorVersionException from a notify payload.
- *
- * @param notifyData the notify data included in the payload.
- */
- public InvalidMajorVersionException(byte[] notifyData) {
- super(ERROR_TYPE_INVALID_MAJOR_VERSION, notifyData);
- }
-
- /**
- * Return the major verion included in this exception.
- *
- * @return the major verion
- */
- public int getMajorVerion() {
- return byteArrayToInteger(getErrorData());
- }
-
- @Override
- protected boolean isValidDataLength(int dataLen) {
- return EXPECTED_ERROR_DATA_LEN == dataLen;
+ super(IkeNotifyPayload.NOTIFY_TYPE_INVALID_MAJOR_VERSION);
+ receivedMajorVersion = version;
}
}
diff --git a/src/java/com/android/internal/net/ipsec/ike/exceptions/InvalidSyntaxException.java b/src/java/com/android/ike/ikev2/exceptions/InvalidSyntaxException.java
index fd73f2f1..489eeff8 100644
--- a/src/java/com/android/internal/net/ipsec/ike/exceptions/InvalidSyntaxException.java
+++ b/src/java/com/android/ike/ikev2/exceptions/InvalidSyntaxException.java
@@ -13,9 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.internal.net.ipsec.ike.exceptions;
+package com.android.ike.ikev2.exceptions;
-import android.net.ipsec.ike.exceptions.IkeProtocolException;
+import com.android.ike.ikev2.message.IkeNotifyPayload;
/**
* This exception is thrown if any IKE message field is invalid.
@@ -26,16 +26,14 @@ import android.net.ipsec.ike.exceptions.IkeProtocolException;
* @see <a href="https://tools.ietf.org/html/rfc7296#section-3.10.1">RFC 7296, Internet Key Exchange
* Protocol Version 2 (IKEv2)</a>
*/
-public final class InvalidSyntaxException extends IkeProtocolException {
- private static final int EXPECTED_ERROR_DATA_LEN = 0;
-
+public final class InvalidSyntaxException extends IkeException {
/**
* Construct an instance of InvalidSyntaxException.
*
* @param message the descriptive message.
*/
public InvalidSyntaxException(String message) {
- super(ERROR_TYPE_INVALID_SYNTAX, message);
+ super(IkeNotifyPayload.NOTIFY_TYPE_INVALID_SYNTAX);
}
/**
@@ -44,30 +42,6 @@ public final class InvalidSyntaxException extends IkeProtocolException {
* @param cause the reason of exception.
*/
public InvalidSyntaxException(Throwable cause) {
- super(ERROR_TYPE_INVALID_SYNTAX, cause);
- }
-
- /**
- * Construct a instance of InvalidSyntaxException.
- *
- * @param message the descriptive message.
- * @param cause the reason of exception.
- */
- public InvalidSyntaxException(String message, Throwable cause) {
- super(ERROR_TYPE_INVALID_SYNTAX, message, cause);
- }
-
- /**
- * Construct a instance of InvalidSyntaxException from a notify payload.
- *
- * @param notifyData the notify data included in the payload.
- */
- public InvalidSyntaxException(byte[] notifyData) {
- super(ERROR_TYPE_INVALID_SYNTAX, notifyData);
- }
-
- @Override
- protected boolean isValidDataLength(int dataLen) {
- return EXPECTED_ERROR_DATA_LEN == dataLen;
+ super(IkeNotifyPayload.NOTIFY_TYPE_INVALID_SYNTAX, cause);
}
}
diff --git a/src/java/com/android/internal/net/ipsec/ike/exceptions/NoValidProposalChosenException.java b/src/java/com/android/ike/ikev2/exceptions/NoValidProposalChosenException.java
index 4514c65a..8aac8724 100644
--- a/src/java/com/android/internal/net/ipsec/ike/exceptions/NoValidProposalChosenException.java
+++ b/src/java/com/android/ike/ikev2/exceptions/NoValidProposalChosenException.java
@@ -13,11 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.internal.net.ipsec.ike.exceptions;
+package com.android.ike.ikev2.exceptions;
-import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_NO_PROPOSAL_CHOSEN;
-
-import android.net.ipsec.ike.exceptions.IkeProtocolException;
+import com.android.ike.ikev2.message.IkeNotifyPayload;
/**
* This exception is thrown if either none of SA proposals from SA initiator is acceptable or the
@@ -29,39 +27,13 @@ import android.net.ipsec.ike.exceptions.IkeProtocolException;
* @see <a href="https://tools.ietf.org/html/rfc7296#section-2.7">RFC 7296, Internet Key Exchange
* Protocol Version 2 (IKEv2)</a>
*/
-public final class NoValidProposalChosenException extends IkeProtocolException {
- private static final int EXPECTED_ERROR_DATA_LEN = 0;
-
+public final class NoValidProposalChosenException extends IkeException {
/**
* Construct an instance of NoValidProposalChosenException.
*
* @param message the descriptive message.
*/
public NoValidProposalChosenException(String message) {
- super(ERROR_TYPE_NO_PROPOSAL_CHOSEN, message);
- }
-
- /**
- * Construct an instance of NoValidProposalChosenException.
- *
- * @param message the descriptive message.
- * @param cause the reason of exception.
- */
- public NoValidProposalChosenException(String message, Throwable cause) {
- super(ERROR_TYPE_NO_PROPOSAL_CHOSEN, cause);
- }
-
- /**
- * Construct a instance of NoValidProposalChosenException from a notify payload.
- *
- * @param notifyData the notify data included in the payload.
- */
- public NoValidProposalChosenException(byte[] notifyData) {
- super(ERROR_TYPE_NO_PROPOSAL_CHOSEN, notifyData);
- }
-
- @Override
- protected boolean isValidDataLength(int dataLen) {
- return EXPECTED_ERROR_DATA_LEN == dataLen;
+ super(IkeNotifyPayload.NOTIFY_TYPE_NO_PROPOSAL_CHOSEN, message);
}
}
diff --git a/src/java/com/android/ike/ikev2/exceptions/UnsupportedCriticalPayloadException.java b/src/java/com/android/ike/ikev2/exceptions/UnsupportedCriticalPayloadException.java
new file mode 100644
index 00000000..1bfde971
--- /dev/null
+++ b/src/java/com/android/ike/ikev2/exceptions/UnsupportedCriticalPayloadException.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2018 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.ike.ikev2.exceptions;
+
+import com.android.ike.ikev2.message.IkeNotifyPayload;
+
+import java.util.List;
+
+/**
+ * This exception is thrown when payload type is not supported and critical bit is set
+ *
+ * <p>Include UNSUPPORTED_CRITICAL_PAYLOAD Notify payload in a response message containing the
+ * payload type for each payload.
+ *
+ * @see <a href="https://tools.ietf.org/html/rfc7296#section-2.5">RFC 7296, Internet Key Exchange
+ * Protocol Version 2 (IKEv2)</a>
+ */
+public final class UnsupportedCriticalPayloadException extends IkeException {
+
+ public final List<Integer> payloadTypeList;
+
+ /**
+ * Construct an instance of UnsupportedCriticalPayloadException
+ *
+ * @param payloadList the list of all unsupported critical payload types
+ */
+ public UnsupportedCriticalPayloadException(List<Integer> payloadList) {
+ super(IkeNotifyPayload.NOTIFY_TYPE_UNSUPPORTED_CRITICAL_PAYLOAD);
+ payloadTypeList = payloadList;
+ }
+}
diff --git a/src/java/com/android/ike/ikev2/message/IkeAuthDigitalSignPayload.java b/src/java/com/android/ike/ikev2/message/IkeAuthDigitalSignPayload.java
new file mode 100644
index 00000000..9d7e0449
--- /dev/null
+++ b/src/java/com/android/ike/ikev2/message/IkeAuthDigitalSignPayload.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2019 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.ike.ikev2.message;
+
+import android.annotation.StringDef;
+
+import com.android.ike.ikev2.exceptions.AuthenticationFailedException;
+import com.android.ike.ikev2.exceptions.IkeException;
+import com.android.ike.ikev2.message.IkeAuthPayload.AuthMethod;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+
+/**
+ * IkeAuthDigitalSignPayload represents Authentication Payload using a specific or generic digital
+ * signature authentication method.
+ *
+ * <p>If AUTH_METHOD_RSA_DIGITAL_SIGN is used, then the hash algorithm is SHA1. If
+ * AUTH_METHOD_GENERIC_DIGITAL_SIGN is used, the signature algorihtm and hash algorithm are
+ * extracted from authentication data.
+ *
+ * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.8">RFC 7296, Internet Key Exchange
+ * Protocol Version 2 (IKEv2)</a>
+ * @see <a href="https://tools.ietf.org/html/rfc7427">RFC 7427, Signature Authentication in the
+ * Internet Key Exchange Version 2 (IKEv2)</a>
+ */
+public class IkeAuthDigitalSignPayload extends IkeAuthPayload {
+
+ // Byte arrays of DER encoded identifier ASN.1 objects that indicates the algorithm used to
+ // generate the signature, extracted from
+ // <a href="https://tools.ietf.org/html/rfc7427#appendix-A"> RFC 7427. There is no need to
+ // understand the encoding process. They are just constants to indicate the algorithm type.
+ private static final byte[] PKI_ALGO_ID_DER_BYTES_RSA_SHA1 = {
+ (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09,
+ (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86,
+ (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01,
+ (byte) 0x05, (byte) 0x05, (byte) 0x00
+ };
+ private static final byte[] PKI_ALGO_ID_DER_BYTES_RSA_SHA2_256 = {
+ (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09,
+ (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86,
+ (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01,
+ (byte) 0x0b, (byte) 0x05, (byte) 0x00
+ };
+ private static final byte[] PKI_ALGO_ID_DER_BYTES_RSA_SHA2_384 = {
+ (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09,
+ (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86,
+ (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01,
+ (byte) 0x0c, (byte) 0x05, (byte) 0x00
+ };
+ private static final byte[] PKI_ALGO_ID_DER_BYTES_RSA_SHA2_512 = {
+ (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09,
+ (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86,
+ (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01,
+ (byte) 0x0d, (byte) 0x05, (byte) 0x00
+ };
+
+ // Length of ASN.1 object length field.
+ private static final int SIGNATURE_ALGO_ASN1_LEN_LEN = 1;
+
+ // Currently we only support RSA for signature algorithm.
+ @Retention(RetentionPolicy.SOURCE)
+ @StringDef({
+ SIGNATURE_ALGO_RSA_SHA1,
+ SIGNATURE_ALGO_RSA_SHA2_256,
+ SIGNATURE_ALGO_RSA_SHA2_384,
+ SIGNATURE_ALGO_RSA_SHA2_512
+ })
+ public @interface SignatureAlgo {}
+
+ public static final String SIGNATURE_ALGO_RSA_SHA1 = "SHA1withRSA";
+ public static final String SIGNATURE_ALGO_RSA_SHA2_256 = "SHA256withRSA";
+ public static final String SIGNATURE_ALGO_RSA_SHA2_384 = "SHA384withRSA";
+ public static final String SIGNATURE_ALGO_RSA_SHA2_512 = "SHA512withRSA";
+ // TODO: Allow users to configure authentication method using @SignatureAlgo
+
+ public final String signatureAlgoAndHash;
+ public final byte[] signature;
+
+ protected IkeAuthDigitalSignPayload(
+ boolean critical, @AuthMethod int authMethod, byte[] authData) throws IkeException {
+ super(critical, authMethod);
+ switch (authMethod) {
+ case AUTH_METHOD_RSA_DIGITAL_SIGN:
+ signatureAlgoAndHash = SIGNATURE_ALGO_RSA_SHA1;
+ signature = authData;
+ break;
+ case AUTH_METHOD_GENERIC_DIGITAL_SIGN:
+ ByteBuffer inputBuffer = ByteBuffer.wrap(authData);
+
+ // Get signature algorithm.
+ int signAlgoLen = Byte.toUnsignedInt(inputBuffer.get());
+ byte[] signAlgoBytes = new byte[signAlgoLen];
+ inputBuffer.get(signAlgoBytes);
+ signatureAlgoAndHash = bytesToSignAlgoName(signAlgoBytes);
+
+ // Get signature.
+ signature = new byte[authData.length - SIGNATURE_ALGO_ASN1_LEN_LEN - signAlgoLen];
+ inputBuffer.get(signature);
+ break;
+ default:
+ // Won't hit here.
+ throw new IllegalArgumentException("Unrecognized authentication method.");
+ }
+ }
+
+ private String bytesToSignAlgoName(byte[] signAlgoBytes) throws AuthenticationFailedException {
+ if (Arrays.equals(PKI_ALGO_ID_DER_BYTES_RSA_SHA1, signAlgoBytes)) {
+ return SIGNATURE_ALGO_RSA_SHA1;
+ } else if (Arrays.equals(PKI_ALGO_ID_DER_BYTES_RSA_SHA2_256, signAlgoBytes)) {
+ return SIGNATURE_ALGO_RSA_SHA2_256;
+ } else if (Arrays.equals(PKI_ALGO_ID_DER_BYTES_RSA_SHA2_384, signAlgoBytes)) {
+ return SIGNATURE_ALGO_RSA_SHA2_384;
+ } else if (Arrays.equals(PKI_ALGO_ID_DER_BYTES_RSA_SHA2_512, signAlgoBytes)) {
+ return SIGNATURE_ALGO_RSA_SHA2_512;
+ } else {
+ throw new AuthenticationFailedException(
+ "Unrecognized ASN.1 objects for Signature algorithm and Hash");
+ }
+ }
+
+ // TODO: Add methods for generating and validating signature.
+
+ @Override
+ protected void encodeAuthDataToByteBuffer(ByteBuffer byteBuffer) {
+ // TODO: Implement it.
+ throw new UnsupportedOperationException(
+ "It is not supported to encode a " + getTypeString());
+ }
+
+ @Override
+ protected int getAuthDataLength() {
+ // TODO: Implement it.
+ throw new UnsupportedOperationException(
+ "It is not supported to get payload length of " + getTypeString());
+ }
+
+ @Override
+ public String getTypeString() {
+ return "Authentication-Digital-Signature Payload";
+ }
+}
diff --git a/src/java/com/android/internal/net/ipsec/ike/message/IkeAuthPayload.java b/src/java/com/android/ike/ikev2/message/IkeAuthPayload.java
index 53a3f65f..d6e2db06 100644
--- a/src/java/com/android/internal/net/ipsec/ike/message/IkeAuthPayload.java
+++ b/src/java/com/android/ike/ikev2/message/IkeAuthPayload.java
@@ -14,17 +14,19 @@
* limitations under the License.
*/
-package com.android.internal.net.ipsec.ike.message;
+package com.android.ike.ikev2.message;
import android.annotation.IntDef;
-import android.net.ipsec.ike.exceptions.IkeProtocolException;
-import com.android.internal.net.ipsec.ike.crypto.IkeMacPrf;
-import com.android.internal.net.ipsec.ike.exceptions.AuthenticationFailedException;
+import com.android.ike.ikev2.exceptions.IkeException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.nio.ByteBuffer;
+import java.security.InvalidKeyException;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
/**
* IkeAuthPayload is an abstract class that represents the common information for all Authentication
@@ -65,7 +67,7 @@ public abstract class IkeAuthPayload extends IkePayload {
}
protected static IkeAuthPayload getIkeAuthPayload(boolean critical, byte[] payloadBody)
- throws IkeProtocolException {
+ throws IkeException {
ByteBuffer inputBuffer = ByteBuffer.wrap(payloadBody);
int authMethod = Byte.toUnsignedInt(inputBuffer.get());
@@ -76,6 +78,7 @@ public abstract class IkeAuthPayload extends IkePayload {
byte[] authData = new byte[payloadBody.length - AUTH_HEADER_LEN];
inputBuffer.get(authData);
switch (authMethod) {
+ // TODO: Handle RSA and generic signature-based authentication.
case AUTH_METHOD_PRE_SHARED_KEY:
return new IkeAuthPskPayload(critical, authData);
case AUTH_METHOD_RSA_DIGITAL_SIGN:
@@ -85,10 +88,26 @@ public abstract class IkeAuthPayload extends IkePayload {
return new IkeAuthDigitalSignPayload(
critical, AUTH_METHOD_GENERIC_DIGITAL_SIGN, authData);
default:
- throw new AuthenticationFailedException("Unsupported authentication method");
+ // TODO: Throw AuthenticationFailedException
+ throw new UnsupportedOperationException("Unsupported authentication method");
}
}
+ // Sign data with PRF when building outbound packet or verifying inbound packet. It is called
+ // for calculating signature over ID payload for all types of authentication and also for
+ // calculating signature over PSK for PSK authentication.
+ protected static byte[] signWithPrf(Mac prfMac, byte[] prfKeyBytes, byte[] dataToSign)
+ throws InvalidKeyException {
+ SecretKeySpec prfKey = new SecretKeySpec(prfKeyBytes, prfMac.getAlgorithm());
+ prfMac.init(prfKey);
+
+ ByteBuffer dataBuffer = ByteBuffer.wrap(dataToSign);
+
+ // Calculate MAC.
+ prfMac.update(dataBuffer);
+ return prfMac.doFinal();
+ }
+
// When not using EAP, the peers are authenticated by having each sign a block of data named as
// SignedOctets. IKE initiator's SignedOctets are the concatenation of the IKE_INIT request
// message, the Nonce of IKE responder and the signed ID-Initiator payload body. Similarly, IKE
@@ -98,9 +117,10 @@ public abstract class IkeAuthPayload extends IkePayload {
byte[] ikeInitBytes,
byte[] nonce,
byte[] idPayloadBodyBytes,
- IkeMacPrf ikePrf,
- byte[] prfKeyBytes) {
- byte[] signedidPayloadBodyBytes = ikePrf.signBytes(prfKeyBytes, idPayloadBodyBytes);
+ Mac prfMac,
+ byte[] prfKeyBytes)
+ throws InvalidKeyException {
+ byte[] signedidPayloadBodyBytes = signWithPrf(prfMac, prfKeyBytes, idPayloadBodyBytes);
ByteBuffer buffer =
ByteBuffer.allocate(
@@ -122,6 +142,11 @@ public abstract class IkeAuthPayload extends IkePayload {
return GENERIC_HEADER_LENGTH + AUTH_HEADER_LEN + getAuthDataLength();
}
+ @Override
+ public String getTypeString() {
+ return "Authentication Payload";
+ }
+
protected abstract void encodeAuthDataToByteBuffer(ByteBuffer byteBuffer);
protected abstract int getAuthDataLength();
diff --git a/src/java/com/android/internal/net/ipsec/ike/message/IkeAuthPskPayload.java b/src/java/com/android/ike/ikev2/message/IkeAuthPskPayload.java
index 93bef170..182df8a8 100644
--- a/src/java/com/android/internal/net/ipsec/ike/message/IkeAuthPskPayload.java
+++ b/src/java/com/android/ike/ikev2/message/IkeAuthPskPayload.java
@@ -14,14 +14,16 @@
* limitations under the License.
*/
-package com.android.internal.net.ipsec.ike.message;
+package com.android.ike.ikev2.message;
-import com.android.internal.net.ipsec.ike.crypto.IkeMacPrf;
-import com.android.internal.net.ipsec.ike.exceptions.AuthenticationFailedException;
+import com.android.ike.ikev2.exceptions.AuthenticationFailedException;
import java.nio.ByteBuffer;
+import java.security.InvalidKeyException;
import java.util.Arrays;
+import javax.crypto.Mac;
+
/**
* IkeAuthPskPayload represents an Authentication Payload using Pre-Shared Key to do authentication.
*
@@ -61,20 +63,20 @@ public final class IkeAuthPskPayload extends IkeAuthPayload {
* @param nonce nonce of IKE responder for calculating IKE initiator's SignedOctets.
* @param idPayloadBodyBytes ID-Initiator payload body for calculating IKE initiator's
* SignedOctets.
- * @param ikePrf the negotiated PRF.
- * @param prfKeyBytes the negotiated PRF key.
+ * @param prfMac locally stored PRF
+ * @param prfKeyBytes locally stored PRF keys
*/
public IkeAuthPskPayload(
byte[] psk,
byte[] ikeInitBytes,
byte[] nonce,
byte[] idPayloadBodyBytes,
- IkeMacPrf ikePrf,
+ Mac prfMac,
byte[] prfKeyBytes) {
super(false, IkeAuthPayload.AUTH_METHOD_PRE_SHARED_KEY);
signature =
calculatePskSignature(
- psk, ikeInitBytes, nonce, idPayloadBodyBytes, ikePrf, prfKeyBytes);
+ psk, ikeInitBytes, nonce, idPayloadBodyBytes, prfMac, prfKeyBytes);
}
private static byte[] calculatePskSignature(
@@ -82,13 +84,16 @@ public final class IkeAuthPskPayload extends IkeAuthPayload {
byte[] ikeInitBytes,
byte[] nonce,
byte[] idPayloadBodyBytes,
- IkeMacPrf ikePrf,
+ Mac prfMac,
byte[] prfKeyBytes) {
- byte[] signingKeyBytes = ikePrf.signBytes(psk, IKE_KEY_PAD_STRING_ASCII_HEX_BYTES);
- byte[] dataToSignBytes =
- getSignedOctets(ikeInitBytes, nonce, idPayloadBodyBytes, ikePrf, prfKeyBytes);
-
- return ikePrf.signBytes(signingKeyBytes, dataToSignBytes);
+ try {
+ byte[] signingKeyBytes = signWithPrf(prfMac, psk, IKE_KEY_PAD_STRING_ASCII_HEX_BYTES);
+ byte[] dataToSignBytes =
+ getSignedOctets(ikeInitBytes, nonce, idPayloadBodyBytes, prfMac, prfKeyBytes);
+ return signWithPrf(prfMac, signingKeyBytes, dataToSignBytes);
+ } catch (InvalidKeyException e) {
+ throw new IllegalArgumentException("Locally stored PRF key is invalid: ", e);
+ }
}
/**
@@ -103,8 +108,8 @@ public final class IkeAuthPskPayload extends IkeAuthPayload {
* @param nonce nonce of IKE initiator for calculating IKE responder's SignedOctets.
* @param idPayloadBodyBytes ID-Responder payload body for calculating IKE responder's
* SignedOctets.
- * @param ikePrf the negotiated PRF.
- * @param prfKeyBytes the negotiated PRF key.
+ * @param prfMac locally stored PRF
+ * @param prfKeyBytes locally stored PRF keys
* @throws AuthenticationFailedException if received signature is not equal to calculated
* signature.
*/
@@ -113,12 +118,12 @@ public final class IkeAuthPskPayload extends IkeAuthPayload {
byte[] ikeInitBytes,
byte[] nonce,
byte[] idPayloadBodyBytes,
- IkeMacPrf ikePrf,
+ Mac prfMac,
byte[] prfKeyBytes)
throws AuthenticationFailedException {
byte[] calculatedSignature =
calculatePskSignature(
- psk, ikeInitBytes, nonce, idPayloadBodyBytes, ikePrf, prfKeyBytes);
+ psk, ikeInitBytes, nonce, idPayloadBodyBytes, prfMac, prfKeyBytes);
if (!Arrays.equals(signature, calculatedSignature)) {
throw new AuthenticationFailedException("Signature verification failed.");
}
@@ -136,6 +141,6 @@ public final class IkeAuthPskPayload extends IkeAuthPayload {
@Override
public String getTypeString() {
- return "Auth(PSK)";
+ return "Authentication-PSK Payload";
}
}
diff --git a/src/java/com/android/ike/ikev2/message/IkeCertPayload.java b/src/java/com/android/ike/ikev2/message/IkeCertPayload.java
new file mode 100644
index 00000000..bd54ee23
--- /dev/null
+++ b/src/java/com/android/ike/ikev2/message/IkeCertPayload.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2018 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.ike.ikev2.message;
+
+import android.annotation.IntDef;
+
+import com.android.ike.ikev2.exceptions.AuthenticationFailedException;
+import com.android.ike.ikev2.exceptions.IkeException;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.nio.ByteBuffer;
+
+/**
+ * IkeCertPayload is an abstract class that represents the common information for all Certificate
+ * Payload carrying different types of certifciate-related data and static methods related to
+ * certificate validation.
+ *
+ * <p>Certificate Payload is only sent in IKE_AUTH exchange.
+ *
+ * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.6">RFC 7296, Internet Key Exchange
+ * Protocol Version 2 (IKEv2)</a>
+ */
+public abstract class IkeCertPayload extends IkePayload {
+ // Length of certificate encoding type field in octets.
+ private static final int CERT_ENCODING_LEN = 1;
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({
+ CERTIFICATE_ENCODING_X509_CERT_SIGNATURE,
+ CERTIFICATE_ENCODING_CRL,
+ CERTIFICATE_ENCODING_X509_CERT_HASH_URL,
+ })
+ public @interface CertificateEncoding {}
+
+ public static final int CERTIFICATE_ENCODING_X509_CERT_SIGNATURE = 4;
+ public static final int CERTIFICATE_ENCODING_CRL = 7;
+ public static final int CERTIFICATE_ENCODING_X509_CERT_HASH_URL = 12;
+
+ @CertificateEncoding public final int certEncodingType;
+
+ protected IkeCertPayload(boolean critical, @CertificateEncoding int encodingType) {
+ super(PAYLOAD_TYPE_CERT, critical);
+ certEncodingType = encodingType;
+ }
+
+ protected static IkeCertPayload getIkeCertPayload(boolean critical, byte[] payloadBody)
+ throws IkeException {
+ ByteBuffer inputBuffer = ByteBuffer.wrap(payloadBody);
+
+ int certEncodingType = Byte.toUnsignedInt(inputBuffer.get());
+ byte[] certData = new byte[payloadBody.length - CERT_ENCODING_LEN];
+ inputBuffer.get(certData);
+ switch (certEncodingType) {
+ case CERTIFICATE_ENCODING_X509_CERT_SIGNATURE:
+ return new IkeCertX509CertPayload(critical, certData);
+ // TODO: Support decoding CRL and "Hash and URL".
+ case CERTIFICATE_ENCODING_CRL:
+ throw new AuthenticationFailedException(
+ "CERTIFICATE_ENCODING_CRL decoding is unsupported.");
+ case CERTIFICATE_ENCODING_X509_CERT_HASH_URL:
+ throw new AuthenticationFailedException(
+ "CERTIFICATE_ENCODING_X509_CERT_HASH_URL decoding is unsupported");
+ default:
+ throw new AuthenticationFailedException("Unrecognized certificate encoding type.");
+ }
+ }
+}
diff --git a/src/java/com/android/internal/net/ipsec/ike/message/IkeCertX509CertPayload.java b/src/java/com/android/ike/ikev2/message/IkeCertX509CertPayload.java
index 1804b9b9..76fab4f2 100644
--- a/src/java/com/android/internal/net/ipsec/ike/message/IkeCertX509CertPayload.java
+++ b/src/java/com/android/ike/ikev2/message/IkeCertX509CertPayload.java
@@ -14,11 +14,10 @@
* limitations under the License.
*/
-package com.android.internal.net.ipsec.ike.message;
+package com.android.ike.ikev2.message;
-import android.net.ipsec.ike.exceptions.IkeProtocolException;
-
-import com.android.internal.net.ipsec.ike.exceptions.AuthenticationFailedException;
+import com.android.ike.ikev2.exceptions.AuthenticationFailedException;
+import com.android.ike.ikev2.exceptions.IkeException;
import java.io.ByteArrayInputStream;
import java.nio.ByteBuffer;
@@ -40,14 +39,7 @@ import java.security.cert.X509Certificate;
public final class IkeCertX509CertPayload extends IkeCertPayload {
public final X509Certificate certificate;
- /** Construct IkeCertX509CertPayload for an outbound packet. */
- public IkeCertX509CertPayload(X509Certificate x509Certificate) {
- super(CERTIFICATE_ENCODING_X509_CERT_SIGNATURE);
- certificate = x509Certificate;
- }
-
- protected IkeCertX509CertPayload(boolean critical, byte[] certData)
- throws IkeProtocolException {
+ protected IkeCertX509CertPayload(boolean critical, byte[] certData) throws IkeException {
super(critical, CERTIFICATE_ENCODING_X509_CERT_SIGNATURE);
try {
CertificateFactory factory =
@@ -100,6 +92,6 @@ public final class IkeCertX509CertPayload extends IkeCertPayload {
*/
@Override
public String getTypeString() {
- return "Cert(X509)";
+ return "Certificate Payload Carrying X.509 Certificate";
}
}
diff --git a/src/java/com/android/internal/net/ipsec/ike/message/IkeDeletePayload.java b/src/java/com/android/ike/ikev2/message/IkeDeletePayload.java
index f629f506..fd4f3644 100644
--- a/src/java/com/android/internal/net/ipsec/ike/message/IkeDeletePayload.java
+++ b/src/java/com/android/ike/ikev2/message/IkeDeletePayload.java
@@ -14,11 +14,10 @@
* limitations under the License.
*/
-package com.android.internal.net.ipsec.ike.message;
+package com.android.ike.ikev2.message;
-import android.net.ipsec.ike.exceptions.IkeProtocolException;
-
-import com.android.internal.net.ipsec.ike.exceptions.InvalidSyntaxException;
+import com.android.ike.ikev2.exceptions.IkeException;
+import com.android.ike.ikev2.exceptions.InvalidSyntaxException;
import java.nio.ByteBuffer;
@@ -30,30 +29,10 @@ import java.nio.ByteBuffer;
* packets. Since IKE library only supports negotiating Child SA using ESP, only the protocol ID of
* 3 (ESP) is used for deleting Child SA.
*
- * The possible request/response pairs for deletion are as follows:
- * - IKE SA deletion:
- * Incoming: INFORMATIONAL(DELETE(PROTO_IKE))
- * Outgoing: INFORMATIONAL()
- *
- * - ESP SA deletion:
- * Incoming: INFORMATIONAL(DELETE(PROTO_ESP, SPI_A_OUT))
- * Outgoing: INFORMATIONAL(DELETE(PROTO_ESP, SPI_A_IN))
- *
- * - ESP SA simultaneous deletion:
- * Outgoing: INFORMATIONAL(DELETE(PROTO_ESP, SPI_A_IN))
- * Incoming: INFORMATIONAL(DELETE(PROTO_ESP, SPI_A_OUT))
- * Outgoing: INFORMATIONAL() // Notice DELETE payload omitted
- *
- * - ESP SA simultaneous multi-deletion:
- * Outgoing: INFORMATIONAL(DELETE(PROTO_ESP, SPI_A_IN))
- * Incoming: INFORMATIONAL(DELETE(PROTO_ESP, SPI_A_OUT, SPI_B_OUT))
- * Outgoing: INFORMATIONAL(DELETE(PROTO_ESP, SPI_B_IN)) // Notice SPI_A_OUT omitted
- *
* @see <a href="https://tools.ietf.org/html/rfc7296#section-3.11">RFC 7296, Internet Key Exchange
* Protocol Version 2 (IKEv2)</a>
*/
-public final class IkeDeletePayload extends IkeInformationalPayload {
- private static final int DELETE_HEADER_LEN = 4;
+public final class IkeDeletePayload extends IkePayload {
@ProtocolId public final int protocolId;
public final byte spiSize;
@@ -69,9 +48,9 @@ public final class IkeDeletePayload extends IkeInformationalPayload {
* @param critical indicates if this payload is critical. Ignored in supported payload as
* instructed by the RFC 7296.
* @param payloadBody payload body in byte array
- * @throws IkeProtocolException if there is any error
+ * @throws IkeException if there is any error
*/
- IkeDeletePayload(boolean critical, byte[] payloadBody) throws IkeProtocolException {
+ IkeDeletePayload(boolean critical, byte[] payloadBody) throws IkeException {
super(PAYLOAD_TYPE_DELETE, critical);
ByteBuffer inputBuffer = ByteBuffer.wrap(payloadBody);
@@ -107,37 +86,7 @@ public final class IkeDeletePayload extends IkeInformationalPayload {
}
}
- /**
- * Constructor for an outbound IKE SA deletion payload.
- *
- * <p>This constructor takes no SPI, as IKE SAs are deleted by sending a delete payload within
- * the negotiated session. As such, the SPIs are shared state that does not need to be sent.
- */
- public IkeDeletePayload() {
- super(PAYLOAD_TYPE_DELETE, false);
- protocolId = PROTOCOL_ID_IKE;
- spiSize = SPI_LEN_NOT_INCLUDED;
- numSpi = 0;
- spisToDelete = new int[0];
- }
-
- /**
- * Constructor for an outbound Child SA deletion payload.
- *
- * @param spis array of SPIs of Child SAs to delete. Must contain at least one SPI.
- */
- public IkeDeletePayload(int[] spis) {
- super(PAYLOAD_TYPE_DELETE, false);
-
- if (spis == null || spis.length < 1) {
- throw new IllegalArgumentException("No SPIs provided");
- }
-
- protocolId = PROTOCOL_ID_ESP;
- spiSize = SPI_LEN_IPSEC;
- numSpi = spis.length;
- spisToDelete = spis;
- }
+ // TODO: Add a constructor for building outbound IKE message.
/**
* Encode Delete Payload to ByteBuffer.
@@ -147,12 +96,8 @@ public final class IkeDeletePayload extends IkeInformationalPayload {
*/
@Override
protected void encodeToByteBuffer(@PayloadType int nextPayload, ByteBuffer byteBuffer) {
- encodePayloadHeaderToByteBuffer(nextPayload, getPayloadLength(), byteBuffer);
- byteBuffer.put((byte) protocolId).put(spiSize).putShort((short) numSpi);
-
- for (int toDelete : spisToDelete) {
- byteBuffer.putInt(toDelete);
- }
+ throw new UnsupportedOperationException("Operation not supported.");
+ // TODO: Implement it.
}
/**
@@ -162,7 +107,8 @@ public final class IkeDeletePayload extends IkeInformationalPayload {
*/
@Override
protected int getPayloadLength() {
- return GENERIC_HEADER_LENGTH + DELETE_HEADER_LEN + spisToDelete.length * spiSize;
+ throw new UnsupportedOperationException("Operation not supported.");
+ // TODO: Implement it.
}
/**
@@ -172,6 +118,6 @@ public final class IkeDeletePayload extends IkeInformationalPayload {
*/
@Override
public String getTypeString() {
- return "Del";
+ return "Delete Payload";
}
}
diff --git a/src/java/com/android/ike/ikev2/message/IkeEncryptedPayloadBody.java b/src/java/com/android/ike/ikev2/message/IkeEncryptedPayloadBody.java
new file mode 100644
index 00000000..a41d8555
--- /dev/null
+++ b/src/java/com/android/ike/ikev2/message/IkeEncryptedPayloadBody.java
@@ -0,0 +1,266 @@
+/*
+ * Copyright (C) 2019 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.ike.ikev2.message;
+
+import com.android.ike.ikev2.exceptions.IkeException;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.nio.ByteBuffer;
+import java.security.GeneralSecurityException;
+import java.security.SecureRandom;
+import java.util.Arrays;
+
+import javax.crypto.Cipher;
+import javax.crypto.Mac;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.IvParameterSpec;
+
+/**
+ * IkeEncryptedPayloadBody is a package private class that represents an IKE payload substructure
+ * that contains initialization vector, encrypted content, padding, pad length and integrity
+ * checksum.
+ *
+ * <p>Both an Encrypted Payload (IkeSkPayload) and an EncryptedFragmentPayload (IkeSkfPayload)
+ * consists of an IkeEncryptedPayloadBody instance.
+ *
+ * @see <a href="https://tools.ietf.org/html/rfc7296#page-105">RFC 7296, Internet Key Exchange
+ * Protocol Version 2 (IKEv2)</a>
+ * @see <a href="https://tools.ietf.org/html/rfc7383#page-6">RFC 7383, Internet Key Exchange
+ * Protocol Version 2 (IKEv2) Message Fragmentation</a>
+ */
+final class IkeEncryptedPayloadBody {
+ // Length of pad length field.
+ private static final int PAD_LEN_LEN = 1;
+
+ private final byte[] mUnencryptedData;
+ private final byte[] mEncryptedAndPaddedData;
+ private final byte[] mIv;
+ private final byte[] mIntegrityChecksum;
+
+ /**
+ * Package private constructor for constructing an instance of IkeEncryptedPayloadBody from
+ * decrypting an incoming packet.
+ */
+ IkeEncryptedPayloadBody(
+ byte[] message, Mac integrityMac, int checksumLen, Cipher decryptCipher, SecretKey dKey)
+ throws IkeException, GeneralSecurityException {
+ ByteBuffer inputBuffer = ByteBuffer.wrap(message);
+
+ // Skip IKE header and SK payload header
+ byte[] tempArray = new byte[IkeHeader.IKE_HEADER_LENGTH + IkePayload.GENERIC_HEADER_LENGTH];
+ inputBuffer.get(tempArray);
+
+ // Extract bytes for authentication and decryption.
+ int expectedIvLen = decryptCipher.getBlockSize();
+ mIv = new byte[expectedIvLen];
+
+ int encryptedDataLen =
+ message.length
+ - (IkeHeader.IKE_HEADER_LENGTH
+ + IkePayload.GENERIC_HEADER_LENGTH
+ + expectedIvLen
+ + checksumLen);
+ // IkeMessage will catch exception if encryptedDataLen is negative.
+ mEncryptedAndPaddedData = new byte[encryptedDataLen];
+
+ mIntegrityChecksum = new byte[checksumLen];
+ inputBuffer.get(mIv).get(mEncryptedAndPaddedData).get(mIntegrityChecksum);
+
+ // Authenticate and decrypt.
+ byte[] dataToAuthenticate = Arrays.copyOfRange(message, 0, message.length - checksumLen);
+ validateChecksumOrThrow(dataToAuthenticate, integrityMac, mIntegrityChecksum);
+ mUnencryptedData = decrypt(mEncryptedAndPaddedData, decryptCipher, dKey, mIv);
+ }
+
+ /**
+ * Package private constructor for constructing an instance of IkeEncryptedPayloadBody for
+ * building an outbound packet.
+ */
+ IkeEncryptedPayloadBody(
+ IkeHeader ikeHeader,
+ @IkePayload.PayloadType int firstPayloadType,
+ byte[] unencryptedPayloads,
+ Mac integrityMac,
+ int checksumLen,
+ Cipher encryptCipher,
+ SecretKey eKey) {
+ this(
+ ikeHeader,
+ firstPayloadType,
+ unencryptedPayloads,
+ integrityMac,
+ checksumLen,
+ encryptCipher,
+ eKey,
+ encryptCipher.getIV(),
+ calculatePadding(unencryptedPayloads.length, encryptCipher.getBlockSize()));
+ }
+
+ /** Package private constructor only for testing. */
+ @VisibleForTesting
+ IkeEncryptedPayloadBody(
+ IkeHeader ikeHeader,
+ @IkePayload.PayloadType int firstPayloadType,
+ byte[] unencryptedPayloads,
+ Mac integrityMac,
+ int checksumLen,
+ Cipher encryptCipher,
+ SecretKey eKey,
+ byte[] iv,
+ byte[] padding) {
+ mUnencryptedData = unencryptedPayloads;
+
+ // Encrypt data
+ mIv = iv;
+ mEncryptedAndPaddedData = encrypt(unencryptedPayloads, encryptCipher, eKey, iv, padding);
+
+ // Build authenticated section using ByteBuffer. Authenticated section includes bytes from
+ // beginning of IKE header to the pad length, which are concatenation of IKE header, current
+ // payload header, iv and encrypted and padded data.
+ int dataToAuthenticateLength =
+ IkeHeader.IKE_HEADER_LENGTH
+ + IkePayload.GENERIC_HEADER_LENGTH
+ + iv.length
+ + mEncryptedAndPaddedData.length;
+ ByteBuffer authenticatedSectionBuffer = ByteBuffer.allocate(dataToAuthenticateLength);
+
+ // Encode IKE header
+ int encryptedPayloadLength =
+ IkePayload.GENERIC_HEADER_LENGTH
+ + iv.length
+ + mEncryptedAndPaddedData.length
+ + checksumLen;
+ ikeHeader.encodeToByteBuffer(authenticatedSectionBuffer, encryptedPayloadLength);
+
+ // Encode payload header. The next payload type field indicates the first payload nested in
+ // this SkPayload/SkfPayload.
+ int payloadLength =
+ IkePayload.GENERIC_HEADER_LENGTH
+ + iv.length
+ + mEncryptedAndPaddedData.length
+ + checksumLen;
+ IkePayload.encodePayloadHeaderToByteBuffer(
+ firstPayloadType, payloadLength, authenticatedSectionBuffer);
+
+ // Encode iv and padded encrypted data.
+ authenticatedSectionBuffer.put(iv).put(mEncryptedAndPaddedData);
+
+ // Calculate checksum
+ mIntegrityChecksum =
+ calculateChecksum(authenticatedSectionBuffer.array(), integrityMac, checksumLen);
+ }
+
+ // TODO: Add another constructor for AEAD protected payload.
+
+ // TODO: Add constructors that initiate IkeEncryptedPayloadBody for an outbound packet
+
+ /** Package private for testing */
+ @VisibleForTesting
+ static byte[] calculateChecksum(byte[] dataToAuthenticate, Mac integrityMac, int checksumLen) {
+ ByteBuffer inputBuffer = ByteBuffer.wrap(dataToAuthenticate);
+ integrityMac.update(inputBuffer);
+ byte[] calculatedChecksum = Arrays.copyOfRange(integrityMac.doFinal(), 0, checksumLen);
+ return calculatedChecksum;
+ }
+
+ /** Package private for testing */
+ @VisibleForTesting
+ static void validateChecksumOrThrow(
+ byte[] dataToAuthenticate, Mac integrityMac, byte[] integrityChecksum)
+ throws GeneralSecurityException {
+ // TODO: Make it package private and add test.
+ int checkSumLen = integrityChecksum.length;
+ byte[] calculatedChecksum =
+ calculateChecksum(dataToAuthenticate, integrityMac, checkSumLen);
+
+ if (!Arrays.equals(integrityChecksum, calculatedChecksum)) {
+ throw new GeneralSecurityException("Message authentication failed.");
+ }
+ }
+
+ /** Package private for testing */
+ @VisibleForTesting
+ static byte[] encrypt(
+ byte[] dataToEncrypt, Cipher encryptCipher, SecretKey eKey, byte[] iv, byte[] padding) {
+ int padLength = padding.length;
+ int paddedDataLength = dataToEncrypt.length + padLength + PAD_LEN_LEN;
+ ByteBuffer inputBuffer = ByteBuffer.allocate(paddedDataLength);
+ inputBuffer.put(dataToEncrypt).put(padding).put((byte) padLength);
+ inputBuffer.rewind();
+
+ try {
+ // Encrypt data.
+ ByteBuffer outputBuffer = ByteBuffer.allocate(paddedDataLength);
+ encryptCipher.init(Cipher.ENCRYPT_MODE, eKey, new IvParameterSpec(iv));
+ encryptCipher.doFinal(inputBuffer, outputBuffer);
+ return outputBuffer.array();
+ } catch (GeneralSecurityException e) {
+ throw new IllegalArgumentException("Fail to encrypt IKE message. ", e);
+ }
+ }
+
+ /** Package private for testing */
+ @VisibleForTesting
+ static byte[] decrypt(byte[] encryptedData, Cipher decryptCipher, SecretKey dKey, byte[] iv)
+ throws GeneralSecurityException {
+ // TODO: Make it package private and add test.
+ decryptCipher.init(Cipher.DECRYPT_MODE, dKey, new IvParameterSpec(iv));
+
+ ByteBuffer inputBuffer = ByteBuffer.wrap(encryptedData);
+ ByteBuffer outputBuffer = ByteBuffer.allocate(encryptedData.length);
+ decryptCipher.doFinal(inputBuffer, outputBuffer);
+
+ // Remove padding
+ outputBuffer.rewind();
+ int padLength = Byte.toUnsignedInt(outputBuffer.get(encryptedData.length - PAD_LEN_LEN));
+ byte[] decryptedData = new byte[encryptedData.length - padLength - PAD_LEN_LEN];
+
+ outputBuffer.get(decryptedData);
+ return decryptedData;
+ }
+
+ /** Package private for testing */
+ @VisibleForTesting
+ static byte[] calculatePadding(int dataToEncryptLength, int blockSize) {
+ // Sum of dataToEncryptLength, PAD_LEN_LEN and padLength should be aligned with block size.
+ int unpaddedLen = dataToEncryptLength + PAD_LEN_LEN;
+ int padLength = (unpaddedLen + blockSize - 1) / blockSize * blockSize - unpaddedLen;
+ byte[] padding = new byte[padLength];
+
+ // According to RFC 7296, "Padding MAY contain any value".
+ new SecureRandom().nextBytes(padding);
+
+ return padding;
+ }
+
+ /** Package private */
+ byte[] getUnencryptedData() {
+ return mUnencryptedData;
+ }
+
+ /** Package private */
+ int getLength() {
+ return (mIv.length + mEncryptedAndPaddedData.length + mIntegrityChecksum.length);
+ }
+
+ /** Package private */
+ byte[] encode() {
+ ByteBuffer buffer = ByteBuffer.allocate(getLength());
+ buffer.put(mIv).put(mEncryptedAndPaddedData).put(mIntegrityChecksum);
+ return buffer.array();
+ }
+}
diff --git a/src/java/com/android/internal/net/ipsec/ike/message/IkeHeader.java b/src/java/com/android/ike/ikev2/message/IkeHeader.java
index 7aa4fbc8..c4f215ca 100644
--- a/src/java/com/android/internal/net/ipsec/ike/message/IkeHeader.java
+++ b/src/java/com/android/ike/ikev2/message/IkeHeader.java
@@ -14,17 +14,16 @@
* limitations under the License.
*/
-package com.android.internal.net.ipsec.ike.message;
+package com.android.ike.ikev2.message;
-import static com.android.internal.net.ipsec.ike.message.IkePayload.PayloadType;
+import static com.android.ike.ikev2.message.IkePayload.PayloadType;
import android.annotation.IntDef;
-import android.net.ipsec.ike.exceptions.IkeProtocolException;
-import android.util.SparseArray;
+import com.android.ike.ikev2.exceptions.IkeException;
+import com.android.ike.ikev2.exceptions.InvalidMajorVersionException;
+import com.android.ike.ikev2.exceptions.InvalidSyntaxException;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.net.ipsec.ike.exceptions.InvalidMajorVersionException;
-import com.android.internal.net.ipsec.ike.exceptions.InvalidSyntaxException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -46,8 +45,6 @@ public final class IkeHeader {
// Indicate whether this message is sent from the original IKE initiator
private static final byte IKE_HEADER_FLAG_FROM_IKE_INITIATOR = (byte) 0x08;
- private static final SparseArray<String> EXCHANGE_TYPE_TO_STRING;
-
public static final int IKE_HEADER_LENGTH = 28;
@Retention(RetentionPolicy.SOURCE)
@@ -64,14 +61,6 @@ public final class IkeHeader {
public static final int EXCHANGE_TYPE_CREATE_CHILD_SA = 36;
public static final int EXCHANGE_TYPE_INFORMATIONAL = 37;
- static {
- EXCHANGE_TYPE_TO_STRING = new SparseArray<>();
- EXCHANGE_TYPE_TO_STRING.put(EXCHANGE_TYPE_IKE_SA_INIT, "IKE INIT");
- EXCHANGE_TYPE_TO_STRING.put(EXCHANGE_TYPE_IKE_AUTH, "IKE AUTH");
- EXCHANGE_TYPE_TO_STRING.put(EXCHANGE_TYPE_CREATE_CHILD_SA, "Create Child");
- EXCHANGE_TYPE_TO_STRING.put(EXCHANGE_TYPE_INFORMATIONAL, "Informational");
- }
-
public final long ikeInitiatorSpi;
public final long ikeResponderSpi;
@PayloadType public final int nextPayloadType;
@@ -131,7 +120,7 @@ public final class IkeHeader {
*
* @param packet the raw byte array of the whole IKE message
*/
- public IkeHeader(byte[] packet) throws IkeProtocolException {
+ public IkeHeader(byte[] packet) throws IkeException {
if (packet.length <= IKE_HEADER_LENGTH) {
throw new InvalidSyntaxException("IKE message is too short to contain a header");
}
@@ -156,21 +145,6 @@ public final class IkeHeader {
mEncodedMessageLength = buffer.getInt();
}
- /** Packet private method to build header of an IKE fragemnt from current IKE header. */
- IkeHeader makeSkfHeaderFromSkHeader() {
- if (nextPayloadType != IkePayload.PAYLOAD_TYPE_SK) {
- throw new IllegalArgumentException("Next payload type is not SK.");
- }
- return new IkeHeader(
- ikeInitiatorSpi,
- ikeResponderSpi,
- IkePayload.PAYLOAD_TYPE_SKF,
- exchangeType,
- isResponseMsg,
- fromIkeInitiator,
- messageId);
- }
-
/*Package private*/
@VisibleForTesting
int getInboundMessageLength() {
@@ -181,8 +155,8 @@ public final class IkeHeader {
return mEncodedMessageLength;
}
- /** Validate major version of inbound IKE header. */
- public void validateMajorVersion() throws IkeProtocolException {
+ /** Validate syntax and major version of inbound IKE header. */
+ public void checkInboundValidOrThrow(int packetLength) throws IkeException {
if (majorVersion > 2) {
// Receive higher version of protocol. Stop parsing.
throw new InvalidMajorVersionException(majorVersion);
@@ -194,15 +168,6 @@ public final class IkeHeader {
// 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.");
@@ -231,14 +196,4 @@ public final class IkeHeader {
byteBuffer.put(flag).putInt(messageId).putInt(IKE_HEADER_LENGTH + encodedMessageBodyLen);
}
-
- /** Returns basic information for logging. */
- public String getBasicInfoString() {
- String exchangeStr = EXCHANGE_TYPE_TO_STRING.get(exchangeType);
- if (exchangeStr == null) exchangeStr = "Unknown exchange (" + exchangeType + ")";
-
- String reqOrResp = isResponseMsg ? "response" : "request";
-
- return exchangeStr + " " + reqOrResp + " " + messageId;
- }
}
diff --git a/src/java/com/android/internal/net/ipsec/ike/message/IkeIdPayload.java b/src/java/com/android/ike/ikev2/message/IkeIdPayload.java
index 12cc14ab..49b88603 100644
--- a/src/java/com/android/internal/net/ipsec/ike/message/IkeIdPayload.java
+++ b/src/java/com/android/ike/ikev2/message/IkeIdPayload.java
@@ -14,18 +14,15 @@
* limitations under the License.
*/
-package com.android.internal.net.ipsec.ike.message;
+package com.android.ike.ikev2.message;
-import android.net.ipsec.ike.IkeFqdnIdentification;
-import android.net.ipsec.ike.IkeIdentification;
-import android.net.ipsec.ike.IkeIpv4AddrIdentification;
-import android.net.ipsec.ike.IkeIpv6AddrIdentification;
-import android.net.ipsec.ike.IkeKeyIdIdentification;
-import android.net.ipsec.ike.IkeRfc822AddrIdentification;
-import android.net.ipsec.ike.exceptions.IkeProtocolException;
-
-import com.android.internal.net.ipsec.ike.exceptions.AuthenticationFailedException;
-import com.android.internal.net.ipsec.ike.exceptions.InvalidSyntaxException;
+import com.android.ike.ikev2.IkeIdentification;
+import com.android.ike.ikev2.IkeIdentification.IkeIpv4AddrIdentification;
+import com.android.ike.ikev2.IkeIdentification.IkeIpv6AddrIdentification;
+import com.android.ike.ikev2.exceptions.AuthenticationFailedException;
+import com.android.ike.ikev2.exceptions.IkeException;
+import com.android.ike.ikev2.exceptions.InvalidSyntaxException;
+import com.android.ike.ikev2.message.IkePayload.PayloadType;
import java.nio.ByteBuffer;
@@ -54,10 +51,9 @@ public final class IkeIdPayload extends IkePayload {
* @param payloadBody payload body in byte array.
* @param isInitiator indicates whether this payload contains the ID of IKE initiator or IKE
* responder.
- * @throws IkeProtocolException for decoding error.
+ * @throws IkeException for decoding error.
*/
- IkeIdPayload(boolean critical, byte[] payloadBody, boolean isInitiator)
- throws IkeProtocolException {
+ IkeIdPayload(boolean critical, byte[] payloadBody, boolean isInitiator) throws IkeException {
super((isInitiator ? PAYLOAD_TYPE_ID_INITIATOR : PAYLOAD_TYPE_ID_RESPONDER), critical);
// TODO: b/119791832 Add helper method for checking payload body length in superclass.
if (payloadBody.length <= ID_HEADER_LEN) {
@@ -78,20 +74,18 @@ public final class IkeIdPayload extends IkePayload {
ikeId = new IkeIpv4AddrIdentification(idData);
return;
case IkeIdentification.ID_TYPE_FQDN:
- ikeId = new IkeFqdnIdentification(idData);
- return;
+ // Fall through
case IkeIdentification.ID_TYPE_RFC822_ADDR:
- ikeId = new IkeRfc822AddrIdentification(idData);
- return;
+ throw new UnsupportedOperationException("ID type is not supported currently.");
case IkeIdentification.ID_TYPE_IPV6_ADDR:
ikeId = new IkeIpv6AddrIdentification(idData);
return;
- case IkeIdentification.ID_TYPE_DER_ASN1_DN: // Fall through
+ case IkeIdentification.ID_TYPE_DER_ASN1_DN:
+ // Fall through
case IkeIdentification.ID_TYPE_DER_ASN1_GN:
- throw new UnsupportedOperationException("ID type is not supported currently.");
+ // Fall through
case IkeIdentification.ID_TYPE_KEY_ID:
- ikeId = new IkeKeyIdIdentification(idData);
- return;
+ throw new UnsupportedOperationException("ID type is not supported currently.");
default:
throw new AuthenticationFailedException("Unsupported ID type: " + idType);
}
@@ -110,21 +104,6 @@ public final class IkeIdPayload extends IkePayload {
}
/**
- * Get encoded ID payload body for building or validating an Auth Payload.
- *
- * @return the byte array of encoded ID payload body.
- */
- public byte[] getEncodedPayloadBody() {
- ByteBuffer byteBuffer = ByteBuffer.allocate(getPayloadLength() - GENERIC_HEADER_LENGTH);
-
- byteBuffer
- .put((byte) ikeId.idType)
- .put(new byte[ID_HEADER_RESERVED_LEN])
- .put(ikeId.getEncodedIdData());
- return byteBuffer.array();
- }
-
- /**
* Encode Identification Payload to ByteBuffer.
*
* @param nextPayload type of payload that follows this payload.
@@ -133,7 +112,10 @@ public final class IkeIdPayload extends IkePayload {
@Override
protected void encodeToByteBuffer(@PayloadType int nextPayload, ByteBuffer byteBuffer) {
encodePayloadHeaderToByteBuffer(nextPayload, getPayloadLength(), byteBuffer);
- byteBuffer.put(getEncodedPayloadBody());
+ byteBuffer
+ .put((byte) ikeId.idType)
+ .put(new byte[ID_HEADER_RESERVED_LEN])
+ .put(ikeId.getEncodedIdData());
}
/**
@@ -155,9 +137,9 @@ public final class IkeIdPayload extends IkePayload {
public String getTypeString() {
switch (payloadType) {
case PAYLOAD_TYPE_ID_INITIATOR:
- return "IDi";
+ return "Identification Initiator Payload";
case PAYLOAD_TYPE_ID_RESPONDER:
- return "IDr";
+ return "Identification Responder Payload";
default:
// Won't reach here.
throw new IllegalArgumentException(
diff --git a/src/java/com/android/internal/net/ipsec/ike/message/IkeKePayload.java b/src/java/com/android/ike/ikev2/message/IkeKePayload.java
index 7389bf8d..92e22381 100644
--- a/src/java/com/android/internal/net/ipsec/ike/message/IkeKePayload.java
+++ b/src/java/com/android/ike/ikev2/message/IkeKePayload.java
@@ -14,28 +14,26 @@
* limitations under the License.
*/
-package com.android.internal.net.ipsec.ike.message;
+package com.android.ike.ikev2.message;
import android.annotation.Nullable;
-import android.net.ipsec.ike.SaProposal;
-import android.net.ipsec.ike.exceptions.IkeProtocolException;
-import com.android.internal.net.ipsec.ike.IkeDhParams;
-import com.android.internal.net.ipsec.ike.exceptions.InvalidSyntaxException;
-import com.android.internal.net.utils.BigIntegerUtils;
+import com.android.ike.ikev2.IkeDhParams;
+import com.android.ike.ikev2.SaProposal;
+import com.android.ike.ikev2.exceptions.IkeException;
+import com.android.ike.ikev2.exceptions.InvalidSyntaxException;
+import com.android.ike.ikev2.utils.BigIntegerUtils;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.security.GeneralSecurityException;
import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.ProviderException;
import java.security.SecureRandom;
-import java.security.spec.InvalidKeySpecException;
import javax.crypto.KeyAgreement;
import javax.crypto.interfaces.DHPrivateKey;
@@ -77,8 +75,8 @@ public final class IkeKePayload extends IkePayload {
/**
* localPrivateKey caches the locally generated private key when building an outbound KE
- * payload. It will not be sent out. It is only used to calculate DH shared key when IKE library
- * receives a public key from the remote server.
+ * payload. It will not be sent out. It is only used to calculate DH shared
+ * key when IKE library receives a public key from the remote server.
*
* <p>localPrivateKey of a inbound payload will be set to null. Caller MUST ensure its an
* outbound payload before using localPrivateKey.
@@ -91,11 +89,11 @@ public final class IkeKePayload extends IkePayload {
* @param critical indicates if this payload is critical. Ignored in supported payload as
* instructed by the RFC 7296.
* @param payloadBody payload body in byte array
- * @throws IkeProtocolException if there is any error
+ * @throws IkeException if there is any error
* @see <a href="https://tools.ietf.org/html/rfc7296#page-76">RFC 7296, Internet Key Exchange
* Protocol Version 2 (IKEv2), Critical.
*/
- IkeKePayload(boolean critical, byte[] payloadBody) throws IkeProtocolException {
+ IkeKePayload(boolean critical, byte[] payloadBody) throws IkeException {
super(PAYLOAD_TYPE_KE, critical);
isOutbound = false;
@@ -225,38 +223,29 @@ public final class IkeKePayload extends IkePayload {
*
* @param privateKeySpec contains the local private key, DH prime and DH base generator.
* @param remotePublicKey the public key from remote server.
- * @throws GeneralSecurityException if the remote public key is invalid.
+ * @throws GeneralSecurityException for security-related exception.
*/
public static byte[] getSharedKey(DHPrivateKeySpec privateKeySpec, byte[] remotePublicKey)
throws GeneralSecurityException {
- KeyAgreement dhKeyAgreement;
- KeyFactory dhKeyFactory;
- try {
- // Apply local private key.
- dhKeyAgreement =
- KeyAgreement.getInstance(
- KEY_EXCHANGE_ALGORITHM, IkeMessage.getSecurityProvider());
- dhKeyFactory =
- KeyFactory.getInstance(
- KEY_EXCHANGE_ALGORITHM, IkeMessage.getSecurityProvider());
- DHPrivateKey privateKey = (DHPrivateKey) dhKeyFactory.generatePrivate(privateKeySpec);
- dhKeyAgreement.init(privateKey);
- } catch (NoSuchAlgorithmException | InvalidKeySpecException | InvalidKeyException e) {
- throw new IllegalArgumentException("Failed to generate DH private key", e);
- }
-
- // Build public key.
BigInteger publicKeyValue = BigIntegerUtils.unsignedByteArrayToBigInteger(remotePublicKey);
BigInteger primeValue = privateKeySpec.getP();
+ // TODO: Add recipient test of remotePublicKey, as instructed by RFC6989 section 2.1
+
BigInteger baseGenValue = privateKeySpec.getG();
+
DHPublicKeySpec publicKeySpec =
new DHPublicKeySpec(publicKeyValue, primeValue, baseGenValue);
-
- // Validate and apply public key. Validation includes range check as instructed by RFC6989
- // section 2.1
+ KeyFactory dhKeyFactory =
+ KeyFactory.getInstance(KEY_EXCHANGE_ALGORITHM, IkeMessage.getSecurityProvider());
DHPublicKey publicKey = (DHPublicKey) dhKeyFactory.generatePublic(publicKeySpec);
+ DHPrivateKey privateKey = (DHPrivateKey) dhKeyFactory.generatePrivate(privateKeySpec);
+
+ // Calculate shared secret
+ KeyAgreement dhKeyAgreement =
+ KeyAgreement.getInstance(KEY_EXCHANGE_ALGORITHM, IkeMessage.getSecurityProvider());
+ dhKeyAgreement.init(privateKey);
+ dhKeyAgreement.doPhase(publicKey, true/** Last phase */);
- dhKeyAgreement.doPhase(publicKey, true /* Last phase */);
return dhKeyAgreement.generateSecret();
}
@@ -267,6 +256,6 @@ public final class IkeKePayload extends IkePayload {
*/
@Override
public String getTypeString() {
- return "KE";
+ return "KE Payload";
}
}
diff --git a/src/java/com/android/ike/ikev2/message/IkeMessage.java b/src/java/com/android/ike/ikev2/message/IkeMessage.java
new file mode 100644
index 00000000..5b63ee7f
--- /dev/null
+++ b/src/java/com/android/ike/ikev2/message/IkeMessage.java
@@ -0,0 +1,443 @@
+/*
+ * Copyright (C) 2018 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.ike.ikev2.message;
+
+import static com.android.ike.ikev2.message.IkePayload.PayloadType;
+
+import android.annotation.IntDef;
+import android.util.Pair;
+
+import com.android.ike.ikev2.IkeSessionOptions;
+import com.android.ike.ikev2.SaRecord.IkeSaRecord;
+import com.android.ike.ikev2.exceptions.IkeException;
+import com.android.ike.ikev2.exceptions.InvalidSyntaxException;
+import com.android.ike.ikev2.exceptions.UnsupportedCriticalPayloadException;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.org.bouncycastle.jce.provider.BouncyCastleProvider;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.nio.BufferUnderflowException;
+import java.nio.ByteBuffer;
+import java.security.GeneralSecurityException;
+import java.security.Provider;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.crypto.Cipher;
+import javax.crypto.Mac;
+import javax.crypto.SecretKey;
+
+/**
+ * IkeMessage represents an IKE message.
+ *
+ * <p>It contains all attributes and provides methods for encoding, decoding, encrypting and
+ * decrypting.
+ *
+ * @see <a href="https://tools.ietf.org/html/rfc7296#section-3">RFC 7296, Internet Key Exchange
+ * Protocol Version 2 (IKEv2)</a>
+ */
+public final class IkeMessage {
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({
+ MESSAGE_TYPE_IKE_INIT_RESP,
+ MESSAGE_TYPE_IKE_AUTH_RESP,
+ MESSAGE_TYPE_DELETE_IKE_REQ,
+ MESSAGE_TYPE_DELETE_IKE_RESP,
+ MESSAGE_TYPE_REKEY_IKE_REQ,
+ MESSAGE_TYPE_REKEY_IKE_RESP,
+ MESSAGE_TYPE_UNSUPPORTED_CRITICAL_PAYLOAD,
+ MESSAGE_TYPE_INVALID_MAJOR_VERSION,
+ MESSAGE_TYPE_INVALID_SYNTAX
+ })
+ public @interface MessageType {}
+
+ // Message type for decoded IkeMessage.
+ public static final int PROCEDURE_TYPE_BASE = 0;
+
+ public static final int MESSAGE_TYPE_IKE_INIT_RESP = PROCEDURE_TYPE_BASE + 1;
+ public static final int MESSAGE_TYPE_IKE_AUTH_RESP = PROCEDURE_TYPE_BASE + 2;
+ public static final int MESSAGE_TYPE_DELETE_IKE_REQ = PROCEDURE_TYPE_BASE + 3;
+ public static final int MESSAGE_TYPE_DELETE_IKE_RESP = PROCEDURE_TYPE_BASE + 4;
+ public static final int MESSAGE_TYPE_REKEY_IKE_REQ = PROCEDURE_TYPE_BASE + 5;
+ public static final int MESSAGE_TYPE_REKEY_IKE_RESP = PROCEDURE_TYPE_BASE + 6;
+
+ public static final int NOTIFICATION_TYPE_BASE = PROCEDURE_TYPE_BASE + 100;
+ public static final int MESSAGE_TYPE_UNSUPPORTED_CRITICAL_PAYLOAD =
+ NOTIFICATION_TYPE_BASE + IkeNotifyPayload.NOTIFY_TYPE_UNSUPPORTED_CRITICAL_PAYLOAD;
+ public static final int MESSAGE_TYPE_INVALID_MAJOR_VERSION =
+ NOTIFICATION_TYPE_BASE + IkeNotifyPayload.NOTIFY_TYPE_INVALID_MAJOR_VERSION;
+ public static final int MESSAGE_TYPE_INVALID_SYNTAX =
+ NOTIFICATION_TYPE_BASE + IkeNotifyPayload.NOTIFY_TYPE_INVALID_SYNTAX;
+
+ private static IIkeMessageHelper sIkeMessageHelper = new IkeMessageHelper();
+ // Currently use Bouncy Castle as crypto security provider
+ static final Provider SECURITY_PROVIDER = new BouncyCastleProvider();
+
+ public final IkeHeader ikeHeader;
+ public final List<IkePayload> ikePayloadList;
+ /**
+ * Conctruct an instance of IkeMessage. It is called by decode or for building outbound message.
+ *
+ * @param header the header of this IKE message
+ * @param payloadList the list of decoded IKE payloads in this IKE message
+ */
+ public IkeMessage(IkeHeader header, List<IkePayload> payloadList) {
+ ikeHeader = header;
+ ikePayloadList = payloadList;
+ }
+
+ /**
+ * Get security provider for IKE library
+ *
+ * <p>Use BouncyCastleProvider as the default security provider.
+ *
+ * @return the security provider of IKE library.
+ */
+ public static Provider getSecurityProvider() {
+ // TODO: Move this getter out of IKE message package since not only this package uses it.
+ return SECURITY_PROVIDER;
+ }
+
+ /**
+ * Decode unencrypted IKE message body and create an instance of IkeMessage.
+ *
+ * <p>This method catches all RuntimeException during decoding incoming IKE packet.
+ *
+ * @param header the IKE header that is decoded but not validated.
+ * @param inputPacket the byte array contains the whole IKE message.
+ * @return the IkeMessage instance.
+ * @throws IkeException if there is any protocol error.
+ */
+ public static IkeMessage decode(IkeHeader header, byte[] inputPacket) throws IkeException {
+ return sIkeMessageHelper.decode(header, inputPacket);
+ }
+
+ /**
+ * Decrypt and decode encrypted IKE message body and create an instance of IkeMessage.
+ *
+ * @param ikeSessionOptions IkeSessionOptions that contains cryptographic algorithm set.
+ * @param ikeSaRecord ikeSaRecord where this packet is sent on.
+ * @param ikeHeader header of IKE packet.
+ * @param packet IKE packet as a byte array.
+ * @return decoded IKE message.
+ * @throws IkeException for decoding errors.
+ * @throws GeneralSecurityException if there is any error during integrity check or decryption.
+ */
+ public static IkeMessage decode(
+ IkeSessionOptions ikeSessionOptions,
+ IkeSaRecord ikeSaRecord,
+ IkeHeader ikeHeader,
+ byte[] packet)
+ throws IkeException, GeneralSecurityException {
+ return sIkeMessageHelper.decode(ikeSessionOptions, ikeSaRecord, ikeHeader, packet);
+ }
+
+ private static List<IkePayload> decodePayloadList(
+ @PayloadType int firstPayloadType, boolean isResp, byte[] unencryptedPayloads)
+ throws IkeException {
+ ByteBuffer inputBuffer = ByteBuffer.wrap(unencryptedPayloads);
+ int currentPayloadType = firstPayloadType;
+ // For supported payload
+ List<IkePayload> supportedPayloadList = new LinkedList<>();
+ // For unsupported critical payload
+ List<Integer> unsupportedCriticalPayloadList = new LinkedList<>();
+
+ while (currentPayloadType != IkePayload.PAYLOAD_TYPE_NO_NEXT) {
+ Pair<IkePayload, Integer> pair =
+ IkePayloadFactory.getIkePayload(currentPayloadType, isResp, inputBuffer);
+ IkePayload payload = pair.first;
+
+ if (!(payload instanceof IkeUnsupportedPayload)) {
+ supportedPayloadList.add(payload);
+ } else if (payload.isCritical) {
+ unsupportedCriticalPayloadList.add(payload.payloadType);
+ }
+ // Simply ignore unsupported uncritical payload.
+
+ currentPayloadType = pair.second;
+ }
+
+ if (inputBuffer.remaining() > 0) {
+ throw new InvalidSyntaxException(
+ "Malformed IKE Payload: Unexpected bytes at the end of packet.");
+ }
+
+ if (unsupportedCriticalPayloadList.size() > 0) {
+ throw new UnsupportedCriticalPayloadException(unsupportedCriticalPayloadList);
+ }
+ return supportedPayloadList;
+ }
+
+ /**
+ * Encode unencrypted IKE message.
+ *
+ * @return encoded IKE message in byte array.
+ */
+ public byte[] encode() {
+ return sIkeMessageHelper.encode(this);
+ }
+
+ /**
+ * Encrypt and encode packet.
+ *
+ * @param ikeSessionOptions IkeSessionOptions that contains cryptographic algorithm set.
+ * @param ikeSaRecord ikeSaRecord where this packet is sent on.
+ * @return encoded IKE message in byte array.
+ */
+ public byte[] encode(IkeSessionOptions ikeSessionOptions, IkeSaRecord ikeSaRecord) {
+ return sIkeMessageHelper.encode(ikeSessionOptions, ikeSaRecord, this);
+ }
+
+ /**
+ * Encode all payloads to a byte array.
+ *
+ * @return byte array contains all encoded payloads
+ */
+ private byte[] encodePayloads() {
+ if (ikePayloadList.isEmpty()) {
+ return new byte[0];
+ }
+
+ int payloadLengthSum = 0;
+ for (IkePayload payload : ikePayloadList) {
+ payloadLengthSum += payload.getPayloadLength();
+ }
+
+ ByteBuffer byteBuffer = ByteBuffer.allocate(payloadLengthSum);
+
+ for (int i = 0; i < ikePayloadList.size() - 1; i++) {
+ ikePayloadList
+ .get(i)
+ .encodeToByteBuffer(ikePayloadList.get(i + 1).payloadType, byteBuffer);
+ }
+ ikePayloadList
+ .get(ikePayloadList.size() - 1)
+ .encodeToByteBuffer(IkePayload.PAYLOAD_TYPE_NO_NEXT, byteBuffer);
+
+ return byteBuffer.array();
+ }
+
+ /** Package */
+ @VisibleForTesting
+ byte[] attachEncodedHeader(byte[] encodedIkeBody) {
+ ByteBuffer outputBuffer =
+ ByteBuffer.allocate(IkeHeader.IKE_HEADER_LENGTH + encodedIkeBody.length);
+ ikeHeader.encodeToByteBuffer(outputBuffer, encodedIkeBody.length);
+ outputBuffer.put(encodedIkeBody);
+ return outputBuffer.array();
+ }
+
+ @MessageType
+ public int getMessageType() {
+ return sIkeMessageHelper.getMessageType(this);
+ }
+
+ /**
+ * IIkeMessageHelper provides interface for decoding, encoding and processing IKE packet.
+ *
+ * <p>IkeMessageHelper exists so that the interface is injectable for testing.
+ */
+ @VisibleForTesting
+ public interface IIkeMessageHelper {
+ /**
+ * Check message type of decoded IKE message.
+ *
+ * @param ikeMessage IKE message to be checked.
+ * @return message type.
+ */
+ @MessageType
+ int getMessageType(IkeMessage ikeMessage);
+
+ /**
+ * Encode IKE message.
+ *
+ * @param ikeMessage message need to be encoded.
+ * @return encoded IKE message in byte array.
+ */
+ byte[] encode(IkeMessage ikeMessage);
+
+ /**
+ * Encrypt and encode IKE message.
+ *
+ * @param ikeSessionOptions ikeSessionOptions that contains cryptographic algorithm set.
+ * @param ikeSaRecord ikeSaRecord where this packet is sent on.
+ * @param ikeMessage message need to be encoded.
+ * @return encoded IKE message in byte array.
+ */
+ byte[] encode(
+ IkeSessionOptions ikeSessionOptions,
+ IkeSaRecord ikeSaRecord,
+ IkeMessage ikeMessage);
+
+ /**
+ * Decode unencrypted packet.
+ *
+ * @param ikeHeader header of IKE packet.
+ * @param packet IKE packet as a byte array.
+ * @return decoded IKE message.
+ * @throws IkeException for decoding errors.
+ */
+ IkeMessage decode(IkeHeader ikeHeader, byte[] packet) throws IkeException;
+
+ /**
+ * Decrypt and decode packet.
+ *
+ * @param ikeSessionOptions ikeSessionOptions that contains cryptographic algorithm set.
+ * @param ikeSaRecord ikeSaRecord where this packet is sent on.
+ * @param ikeHeader header of IKE packet.
+ * @param packet IKE packet as a byte array.
+ * @return decoded IKE message.
+ * @throws IkeException for decoding errors.
+ */
+ IkeMessage decode(
+ IkeSessionOptions ikeSessionOptions,
+ IkeSaRecord ikeSaRecord,
+ IkeHeader ikeHeader,
+ byte[] packet)
+ throws IkeException, GeneralSecurityException;
+ }
+
+ /** IkeMessageHelper provides methods for decoding, encoding and processing IKE packet. */
+ public static final class IkeMessageHelper implements IIkeMessageHelper {
+ @Override
+ public byte[] encode(IkeMessage ikeMessage) {
+ byte[] encodedIkeBody = ikeMessage.encodePayloads();
+ return ikeMessage.attachEncodedHeader(encodedIkeBody);
+ }
+
+ @Override
+ public byte[] encode(
+ IkeSessionOptions ikeSessionOptions,
+ IkeSaRecord ikeSaRecord,
+ IkeMessage ikeMessage) {
+ // TODO: Extract crypto attributes and call encrypt()
+ return null;
+ }
+
+ //TODO: Create and use a container class for crypto algorithms and keys.
+ private byte[] encryptAndEncode(
+ IkeHeader ikeHeader,
+ @PayloadType int firstPayload,
+ byte[] unencryptedPayloads,
+ Mac integrityMac,
+ int checksumLen,
+ Cipher encryptCipher,
+ SecretKey eKey) {
+ IkeSkPayload skPayload =
+ new IkeSkPayload(
+ ikeHeader,
+ firstPayload,
+ unencryptedPayloads,
+ integrityMac,
+ checksumLen,
+ encryptCipher,
+ eKey);
+
+ ByteBuffer outputBuffer =
+ ByteBuffer.allocate(IkeHeader.IKE_HEADER_LENGTH + skPayload.getPayloadLength());
+ ikeHeader.encodeToByteBuffer(outputBuffer, skPayload.getPayloadLength());
+ skPayload.encodeToByteBuffer(firstPayload, outputBuffer);
+
+ return outputBuffer.array();
+ }
+
+ @Override
+ public IkeMessage decode(IkeHeader header, byte[] inputPacket) throws IkeException {
+ header.checkInboundValidOrThrow(inputPacket.length);
+
+ byte[] unencryptedPayloads =
+ Arrays.copyOfRange(
+ inputPacket, IkeHeader.IKE_HEADER_LENGTH, inputPacket.length);
+
+ try {
+ List<IkePayload> supportedPayloadList =
+ decodePayloadList(
+ header.nextPayloadType, header.isResponseMsg, unencryptedPayloads);
+ return new IkeMessage(header, supportedPayloadList);
+ } catch (NegativeArraySizeException | BufferUnderflowException e) {
+ // Invalid length error when parsing payload bodies.
+ throw new InvalidSyntaxException("Malformed IKE Payload");
+ }
+ }
+
+ @Override
+ public IkeMessage decode(
+ IkeSessionOptions ikeSessionOptions,
+ IkeSaRecord ikeSaRecord,
+ IkeHeader ikeHeader,
+ byte[] packet)
+ throws IkeException, GeneralSecurityException {
+ // TODO: Extract crypto params and call private decode method.
+ return null;
+ }
+
+ private IkeMessage decode(
+ IkeHeader header,
+ byte[] inputPacket,
+ Mac integrityMac,
+ int checksumLen,
+ Cipher decryptCipher,
+ SecretKey dKey)
+ throws IkeException, GeneralSecurityException {
+
+ header.checkInboundValidOrThrow(inputPacket.length);
+
+ if (header.nextPayloadType != IkePayload.PAYLOAD_TYPE_SK) {
+ // TODO: b/123372339 Handle message containing unprotected payloads.
+ throw new UnsupportedOperationException("Message contains unprotected payloads");
+ }
+
+ try {
+ Pair<IkeSkPayload, Integer> pair =
+ IkePayloadFactory.getIkeSkPayload(
+ inputPacket, integrityMac, checksumLen, decryptCipher, dKey);
+ IkeSkPayload skPayload = pair.first;
+ int firstPayloadType = pair.second;
+
+ List<IkePayload> supportedPayloadList =
+ decodePayloadList(
+ firstPayloadType,
+ header.isResponseMsg,
+ skPayload.getUnencryptedPayloads());
+
+ return new IkeMessage(header, supportedPayloadList);
+ } catch (NegativeArraySizeException | BufferUnderflowException e) {
+ // Invalid length error when parsing payload bodies.
+ throw new InvalidSyntaxException("Malformed IKE Payload");
+ }
+ }
+
+ @Override
+ @MessageType
+ public int getMessageType(IkeMessage ikeMessage) {
+ // TODO: Implement it.
+ return 0;
+ }
+ }
+
+ /**
+ * For setting mocked IIkeMessageHelper for testing
+ *
+ * @param helper the mocked IIkeMessageHelper
+ */
+ public static void setIkeMessageHelper(IIkeMessageHelper helper) {
+ sIkeMessageHelper = helper;
+ }
+}
diff --git a/src/java/com/android/internal/net/ipsec/ike/message/IkeNoncePayload.java b/src/java/com/android/ike/ikev2/message/IkeNoncePayload.java
index 70fc824d..3792e938 100644
--- a/src/java/com/android/internal/net/ipsec/ike/message/IkeNoncePayload.java
+++ b/src/java/com/android/ike/ikev2/message/IkeNoncePayload.java
@@ -14,11 +14,10 @@
* limitations under the License.
*/
-package com.android.internal.net.ipsec.ike.message;
+package com.android.ike.ikev2.message;
-import android.net.ipsec.ike.exceptions.IkeProtocolException;
-
-import com.android.internal.net.ipsec.ike.exceptions.InvalidSyntaxException;
+import com.android.ike.ikev2.exceptions.IkeException;
+import com.android.ike.ikev2.exceptions.InvalidSyntaxException;
import java.nio.ByteBuffer;
import java.security.SecureRandom;
@@ -53,7 +52,7 @@ public final class IkeNoncePayload extends IkePayload {
* @param critical indicates if it is a critical payload.
* @param payloadBody the nonce data
*/
- IkeNoncePayload(boolean critical, byte[] payloadBody) throws IkeProtocolException {
+ IkeNoncePayload(boolean critical, byte[] payloadBody) throws IkeException {
super(PAYLOAD_TYPE_NONCE, critical);
if (payloadBody.length < MIN_NONCE_LEN || payloadBody.length > MAX_NONCE_LEN) {
throw new InvalidSyntaxException(
@@ -103,6 +102,6 @@ public final class IkeNoncePayload extends IkePayload {
*/
@Override
public String getTypeString() {
- return "Nonce";
+ return "Nonce Payload";
}
}
diff --git a/src/java/com/android/ike/ikev2/message/IkeNotifyPayload.java b/src/java/com/android/ike/ikev2/message/IkeNotifyPayload.java
new file mode 100644
index 00000000..ee6fe47a
--- /dev/null
+++ b/src/java/com/android/ike/ikev2/message/IkeNotifyPayload.java
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 2018 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.ike.ikev2.message;
+
+import android.annotation.IntDef;
+import android.util.ArraySet;
+
+import com.android.ike.ikev2.exceptions.IkeException;
+import com.android.ike.ikev2.exceptions.InvalidSyntaxException;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.net.InetAddress;
+import java.nio.ByteBuffer;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Set;
+
+/**
+ * IkeNotifyPayload represents a Notify Payload.
+ *
+ * <p>As instructed by RFC 7296, for IKE SA concerned Notify Payload, Protocol ID and SPI Size must
+ * be zero. Unrecognized notify message type must be ignored but should be logged.
+ *
+ * <p>Critical bit for this payload must be ignored in received packet and must not be set in
+ * outbound packet.
+ *
+ * @see <a href="https://tools.ietf.org/html/rfc7296">RFC 7296, Internet Key Exchange Protocol
+ * Version 2 (IKEv2)</a>
+ */
+public final class IkeNotifyPayload extends IkePayload {
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({
+ NOTIFY_TYPE_UNSUPPORTED_CRITICAL_PAYLOAD,
+ NOTIFY_TYPE_INVALID_MAJOR_VERSION,
+ NOTIFY_TYPE_INVALID_SYNTAX,
+ NOTIFY_TYPE_NO_PROPOSAL_CHOSEN,
+ NOTIFY_TYPE_INVALID_SELECTORS,
+ NOTIFY_TYPE_CHILD_SA_NOT_FOUND,
+ NOTIFY_TYPE_NAT_DETECTION_SOURCE_IP,
+ NOTIFY_TYPE_NAT_DETECTION_DESTINATION_IP,
+ NOTIFY_TYPE_REKEY_SA
+ })
+ public @interface NotifyType {}
+
+ public static final int NOTIFY_TYPE_UNSUPPORTED_CRITICAL_PAYLOAD = 1;
+ public static final int NOTIFY_TYPE_INVALID_MAJOR_VERSION = 5;
+ public static final int NOTIFY_TYPE_INVALID_SYNTAX = 7;
+ public static final int NOTIFY_TYPE_NO_PROPOSAL_CHOSEN = 14;
+ public static final int NOTIFY_TYPE_AUTHENTICATION_FAILED = 24;
+ public static final int NOTIFY_TYPE_INVALID_SELECTORS = 39;
+ public static final int NOTIFY_TYPE_CHILD_SA_NOT_FOUND = 44;
+
+ public static final int NOTIFY_TYPE_NAT_DETECTION_SOURCE_IP = 16388;
+ public static final int NOTIFY_TYPE_NAT_DETECTION_DESTINATION_IP = 16389;
+ public static final int NOTIFY_TYPE_REKEY_SA = 16393;
+ // TODO: List all supported notify types.
+
+ private static final int NOTIFY_HEADER_LEN = 4;
+
+ private static final String NAT_DETECTION_DIGEST_ALGORITHM = "SHA-1";
+
+ private static final Set<Integer> VALID_NOTIFY_TYPES_FOR_CHILD_SA;
+
+ static {
+ VALID_NOTIFY_TYPES_FOR_CHILD_SA = new ArraySet<>();
+ VALID_NOTIFY_TYPES_FOR_CHILD_SA.add(NOTIFY_TYPE_INVALID_SELECTORS);
+ VALID_NOTIFY_TYPES_FOR_CHILD_SA.add(NOTIFY_TYPE_CHILD_SA_NOT_FOUND);
+ VALID_NOTIFY_TYPES_FOR_CHILD_SA.add(NOTIFY_TYPE_REKEY_SA);
+ }
+
+ public final int protocolId;
+ public final byte spiSize;
+ public final int notifyType;
+ public final int spi;
+ public final byte[] notifyData;
+
+ /**
+ * Construct an instance of IkeNotifyPayload in the context of IkePayloadFactory
+ *
+ * @param critical indicates if this payload is critical. Ignored in supported payload as
+ * instructed by the RFC 7296.
+ * @param payloadBody payload body in byte array
+ * @throws IkeException if there is any error
+ */
+ IkeNotifyPayload(boolean isCritical, byte[] payloadBody) throws IkeException {
+ super(PAYLOAD_TYPE_NOTIFY, isCritical);
+
+ ByteBuffer inputBuffer = ByteBuffer.wrap(payloadBody);
+
+ protocolId = Byte.toUnsignedInt(inputBuffer.get());
+ spiSize = inputBuffer.get();
+ notifyType = Short.toUnsignedInt(inputBuffer.getShort());
+
+ // Validate syntax of spiSize, protocolId and notifyType.
+ // Reference: <https://tools.ietf.org/html/rfc7296#page-100>
+ if (spiSize == SPI_LEN_IPSEC) {
+ // For message concerning existing Child SA
+ validateNotifyPayloadForExistingChildSa();
+ spi = inputBuffer.getInt();
+
+ } else if (spiSize == SPI_LEN_NOT_INCLUDED) {
+ // For message concerning IKE SA or for new Child SA that to be negotiated.
+ validateNotifyPayloadForIkeAndNewChild();
+ spi = SPI_NOT_INCLUDED;
+
+ } else {
+ throw new InvalidSyntaxException("Invalid SPI Size: " + spiSize);
+ }
+
+ notifyData = new byte[payloadBody.length - NOTIFY_HEADER_LEN];
+ inputBuffer.get(notifyData);
+ }
+
+ private void validateNotifyPayloadForExistingChildSa() throws InvalidSyntaxException {
+ if (protocolId != PROTOCOL_ID_AH && protocolId != PROTOCOL_ID_ESP) {
+ throw new InvalidSyntaxException(
+ "Expected Procotol ID AH(2) or ESP(3): Protocol ID is " + protocolId);
+ }
+
+ if (!VALID_NOTIFY_TYPES_FOR_CHILD_SA.contains(notifyType)) {
+ throw new InvalidSyntaxException(
+ "Expected Notify Type for existing Child SA: Notify Type is " + notifyType);
+ }
+ }
+
+ private void validateNotifyPayloadForIkeAndNewChild() throws InvalidSyntaxException {
+ if (protocolId != PROTOCOL_ID_UNSET) {
+ throw new InvalidSyntaxException(
+ "Expected Procotol ID unset: Protocol ID is " + protocolId);
+ }
+
+ if (notifyType == NOTIFY_TYPE_INVALID_SELECTORS
+ || notifyType == NOTIFY_TYPE_CHILD_SA_NOT_FOUND) {
+ throw new InvalidSyntaxException(
+ "Expected Notify Type concerning IKE SA or new Child SA under negotiation"
+ + ": Notify Type is "
+ + notifyType);
+ }
+ }
+
+ /**
+ * Generate NAT DETECTION notification data.
+ *
+ * <p>This method calculates NAT DETECTION notification data which is a SHA-1 digest of the IKE
+ * initiator's SPI, IKE responder's SPI, IP address and port. Source address and port should be
+ * used for generating NAT_DETECTION_SOURCE_IP data. Destination address and port should be used
+ * for generating NAT_DETECTION_DESTINATION_IP data.
+ *
+ * @param initiatorIkeSpi the SPI of IKE initiator
+ * @param responderIkeSpi the SPI of IKE responder
+ * @param ipAddress the IP address
+ * @param port the port
+ * @return the generated NAT DETECTION notification data as a byte array.
+ * @throws NoSuchAlgorithmException when "SHA-1" is not supported by the security provider.
+ */
+ public static byte[] generateNatDetectionData(
+ long initiatorIkeSpi, long responderIkeSpi, InetAddress ipAddress, int port)
+ throws NoSuchAlgorithmException {
+ byte[] rawIpAddr = ipAddress.getAddress();
+
+ ByteBuffer byteBuffer =
+ ByteBuffer.allocate(2 * SPI_LEN_IKE + rawIpAddr.length + IP_PORT_LEN);
+ byteBuffer
+ .putLong(initiatorIkeSpi)
+ .putLong(responderIkeSpi)
+ .put(rawIpAddr)
+ .putShort((short) port);
+
+ MessageDigest natDetectionDataDigest =
+ MessageDigest.getInstance(
+ NAT_DETECTION_DIGEST_ALGORITHM, IkeMessage.getSecurityProvider());
+ return natDetectionDataDigest.digest(byteBuffer.array());
+ }
+
+ /**
+ * Encode Notify payload to ByteBuffer.
+ *
+ * @param nextPayload type of payload that follows this payload.
+ * @param byteBuffer destination ByteBuffer that stores encoded payload.
+ */
+ @Override
+ protected void encodeToByteBuffer(@PayloadType int nextPayload, ByteBuffer byteBuffer) {
+ encodePayloadHeaderToByteBuffer(nextPayload, getPayloadLength(), byteBuffer);
+ byteBuffer.put((byte) protocolId).put(spiSize).putShort((short) notifyType);
+ if (spiSize == SPI_LEN_IPSEC) {
+ byteBuffer.putInt(spi);
+ }
+ byteBuffer.put(notifyData);
+ }
+
+ /**
+ * Get entire payload length.
+ *
+ * @return entire payload length.
+ */
+ @Override
+ protected int getPayloadLength() {
+ return GENERIC_HEADER_LENGTH + NOTIFY_HEADER_LEN + spiSize + notifyData.length;
+ }
+
+ protected IkeNotifyPayload(
+ @ProtocolId int protocolId,
+ byte spiSize,
+ int spi,
+ @NotifyType int notifyType,
+ byte[] notifyData) {
+ super(PAYLOAD_TYPE_NOTIFY, false);
+ this.protocolId = protocolId;
+ this.spiSize = spiSize;
+ this.spi = spi;
+ this.notifyType = notifyType;
+ this.notifyData = notifyData;
+ }
+
+ /**
+ * Construct IkeNotifyPayload concerning either an IKE SA or Child SA that is going to be
+ * negotiated.
+ *
+ * @param notifyType the notify type concerning IKE SA
+ * @param notifytData status or error data transmitted. Values for this field are notify type
+ * specific.
+ */
+ public IkeNotifyPayload(@NotifyType int notifyType, byte[] notifyData) {
+ this(PROTOCOL_ID_UNSET, SPI_LEN_NOT_INCLUDED, SPI_NOT_INCLUDED, notifyType, notifyData);
+ try {
+ validateNotifyPayloadForIkeAndNewChild();
+ } catch (InvalidSyntaxException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ /**
+ * Construct IkeNotifyPayload concerning existing Child SA
+ *
+ * @param notifyType the notify type concerning Child SA
+ * @param notifytData status or error data transmitted. Values for this field are notify type
+ * specific.
+ */
+ public IkeNotifyPayload(
+ @ProtocolId int protocolId, int spi, @NotifyType int notifyType, byte[] notifyData) {
+ this(protocolId, SPI_LEN_IPSEC, spi, notifyType, notifyData);
+ try {
+ validateNotifyPayloadForExistingChildSa();
+ } catch (InvalidSyntaxException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ /**
+ * Return the payload type as a String.
+ *
+ * @return the payload type as a String.
+ */
+ @Override
+ public String getTypeString() {
+ return "Notify Payload";
+ }
+}
diff --git a/src/java/com/android/internal/net/ipsec/ike/message/IkePayload.java b/src/java/com/android/ike/ikev2/message/IkePayload.java
index 9ea54c14..2474bb64 100644
--- a/src/java/com/android/internal/net/ipsec/ike/message/IkePayload.java
+++ b/src/java/com/android/ike/ikev2/message/IkePayload.java
@@ -14,16 +14,13 @@
* limitations under the License.
*/
-package com.android.internal.net.ipsec.ike.message;
+package com.android.ike.ikev2.message;
import android.annotation.IntDef;
-import android.util.SparseArray;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.nio.ByteBuffer;
-import java.util.LinkedList;
-import java.util.List;
/**
* IkePayload is an abstract class that represents the common information for all IKE payload types.
@@ -51,7 +48,6 @@ public abstract class IkePayload {
PAYLOAD_TYPE_SA,
PAYLOAD_TYPE_KE,
PAYLOAD_TYPE_CERT,
- PAYLOAD_TYPE_CERT_REQUEST,
PAYLOAD_TYPE_AUTH,
PAYLOAD_TYPE_ID_INITIATOR,
PAYLOAD_TYPE_ID_RESPONDER,
@@ -61,10 +57,7 @@ public abstract class IkePayload {
PAYLOAD_TYPE_VENDOR,
PAYLOAD_TYPE_TS_INITIATOR,
PAYLOAD_TYPE_TS_RESPONDER,
- PAYLOAD_TYPE_SK,
- PAYLOAD_TYPE_CP,
- PAYLOAD_TYPE_EAP,
- PAYLOAD_TYPE_SKF
+ PAYLOAD_TYPE_SK
})
public @interface PayloadType {}
@@ -78,10 +71,8 @@ public abstract class IkePayload {
public static final int PAYLOAD_TYPE_ID_INITIATOR = 35;
/** Identification Payload for IKE SA Responder */
public static final int PAYLOAD_TYPE_ID_RESPONDER = 36;
- /** Certificate Payload */
+ /** Certification Payload */
public static final int PAYLOAD_TYPE_CERT = 37;
- /** Certificate Request Payload */
- public static final int PAYLOAD_TYPE_CERT_REQUEST = 38;
/** Authentication Payload */
public static final int PAYLOAD_TYPE_AUTH = 39;
/** Nonce Payload */
@@ -98,12 +89,6 @@ public abstract class IkePayload {
public static final int PAYLOAD_TYPE_TS_RESPONDER = 45;
/** Encrypted and Authenticated Payload */
public static final int PAYLOAD_TYPE_SK = 46;
- /** Configuration Payload */
- public static final int PAYLOAD_TYPE_CP = 47;
- /** EAP Payload */
- public static final int PAYLOAD_TYPE_EAP = 48;
- /** Encrypted and Authenticated Fragment */
- public static final int PAYLOAD_TYPE_SKF = 53;
// TODO: List all payload types.
@@ -121,16 +106,6 @@ public abstract class IkePayload {
public static final int PROTOCOL_ID_AH = 2;
public static final int PROTOCOL_ID_ESP = 3;
- private static final SparseArray<String> PROTOCOL_TO_STR;
-
- static {
- PROTOCOL_TO_STR = new SparseArray<>();
- PROTOCOL_TO_STR.put(PROTOCOL_ID_UNSET, "Protocol Unset");
- PROTOCOL_TO_STR.put(PROTOCOL_ID_IKE, "IKE");
- PROTOCOL_TO_STR.put(PROTOCOL_ID_AH, "AH");
- PROTOCOL_TO_STR.put(PROTOCOL_ID_ESP, "ESP");
- }
-
public static final byte SPI_LEN_NOT_INCLUDED = 0;
public static final byte SPI_LEN_IPSEC = 4;
public static final byte SPI_LEN_IKE = 8;
@@ -159,56 +134,6 @@ public abstract class IkePayload {
}
/**
- * A helper method to quickly obtain payloads with the input payload type in the provided
- * payload list.
- *
- * <p>This method will not check if this payload type can be repeatable in an IKE message
- * because it does not know the context of the provided payload list. Caller should call this
- * method if they are expecting more than one payloads in the list.
- *
- * @param payloadType the payloadType to look for.
- * @param payloadClass the class of the desired payload.
- * @param searchList the payload list to do the search.
- * @return a list of IkePayloads with the payloadType.
- */
- public static <T extends IkePayload> List<T> getPayloadListForTypeInProvidedList(
- @IkePayload.PayloadType int payloadType,
- Class<T> payloadClass,
- List<IkePayload> searchList) {
- List<T> payloadList = new LinkedList<>();
-
- for (IkePayload payload : searchList) {
- if (payloadType == payload.payloadType) {
- payloadList.add(payloadClass.cast(payload));
- }
- }
-
- return payloadList;
- }
-
- /**
- * A helper method to quickly obtain the payload with the input payload type in the provided
- * payload list.
- *
- * <p>This method will not check if this payload type can be repeatable in an IKE message
- * because it does not know the context of the provided payload list. Caller should call this
- * method if they are expecting no more than one payloads in the list.
- *
- * @param payloadType the payloadType to look for.
- * @param payloadClass the class of the desired payload.
- * @param searchList the payload list to do the search.
- * @return the IkePayload with the payloadType.
- */
- public static <T extends IkePayload> T getPayloadForTypeInProvidedList(
- @IkePayload.PayloadType int payloadType,
- Class<T> payloadClass,
- List<IkePayload> searchList) {
- List<T> payloadList =
- getPayloadListForTypeInProvidedList(payloadType, payloadClass, searchList);
- return payloadList.isEmpty() ? null : payloadList.get(0);
- }
-
- /**
* Encode generic payload header to ByteBuffer.
*
* @param nextPayload type of payload that follows this payload.
@@ -223,11 +148,6 @@ public abstract class IkePayload {
.putShort((short) payloadLength);
}
- /** Retuns protocol type as String. */
- public static String getProtocolTypeString(@ProtocolId int protocol) {
- return PROTOCOL_TO_STR.get(protocol);
- }
-
/**
* Encode payload to ByteBuffer.
*
diff --git a/src/java/com/android/internal/net/ipsec/ike/message/IkePayloadFactory.java b/src/java/com/android/ike/ikev2/message/IkePayloadFactory.java
index 2f191d4e..bea87cad 100644
--- a/src/java/com/android/internal/net/ipsec/ike/message/IkePayloadFactory.java
+++ b/src/java/com/android/ike/ikev2/message/IkePayloadFactory.java
@@ -14,20 +14,21 @@
* limitations under the License.
*/
-package com.android.internal.net.ipsec.ike.message;
+package com.android.ike.ikev2.message;
-import android.annotation.Nullable;
-import android.net.ipsec.ike.exceptions.IkeProtocolException;
import android.util.Pair;
+import com.android.ike.ikev2.exceptions.IkeException;
+import com.android.ike.ikev2.exceptions.InvalidSyntaxException;
import com.android.internal.annotations.VisibleForTesting;
-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.exceptions.InvalidSyntaxException;
import java.nio.ByteBuffer;
import java.security.GeneralSecurityException;
+import javax.crypto.Cipher;
+import javax.crypto.Mac;
+import javax.crypto.SecretKey;
+
/**
* IkePayloadFactory is used for creating IkePayload according to is type.
*
@@ -58,7 +59,7 @@ final class IkePayloadFactory {
@Override
public IkePayload decodeIkePayload(
int payloadType, boolean isCritical, boolean isResp, byte[] payloadBody)
- throws IkeProtocolException {
+ throws IkeException {
switch (payloadType) {
// TODO: Add cases for creating supported payloads.
case IkePayload.PAYLOAD_TYPE_SA:
@@ -85,43 +86,10 @@ final class IkePayloadFactory {
return new IkeTsPayload(isCritical, payloadBody, true);
case IkePayload.PAYLOAD_TYPE_TS_RESPONDER:
return new IkeTsPayload(isCritical, payloadBody, false);
- case IkePayload.PAYLOAD_TYPE_CP:
- return new IkeConfigPayload(isCritical, payloadBody);
- case IkePayload.PAYLOAD_TYPE_EAP:
- return new IkeEapPayload(isCritical, payloadBody);
default:
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 +102,7 @@ final class IkePayloadFactory {
* @return a Pair including IkePayload and next payload type.
*/
protected static Pair<IkePayload, Integer> getIkePayload(
- int payloadType, boolean isResp, ByteBuffer input) throws IkeProtocolException {
+ int payloadType, boolean isResp, ByteBuffer input) throws IkeException {
int nextPayloadType = (int) input.get();
// read critical bit
boolean isCritical = isCriticalPayload(input.get());
@@ -161,24 +129,22 @@ final class IkePayloadFactory {
/**
* Construct an instance of IkeSkPayload by decrypting the received message.
*
- * @param isSkf indicates if this is a SKF Payload.
* @param message the byte array contains the whole IKE message.
- * @param integrityMac the negotiated integrity algorithm.
- * @param decryptCipher the negotiated encryption algorithm.
- * @param integrityKey the negotiated integrity algorithm key.
- * @param decryptionKey the negotiated decryption key.
+ * @param integrityMac the initialized Mac for integrity check.
+ * @param checksumLen the checksum length of negotiated integrity algorithm.
+ * @param decryptCipher the uninitialized Cipher for doing decryption.
+ * @param dKey the decryption key.
* @return a pair including IkePayload and next payload type.
- * @throws IkeProtocolException for decoding errors.
+ * @throws IkeException for decoding errors.
* @throws GeneralSecurityException if there is any error during integrity check or decryption.
*/
protected static Pair<IkeSkPayload, Integer> getIkeSkPayload(
- boolean isSkf,
byte[] message,
- IkeMacIntegrity integrityMac,
- IkeCipher decryptCipher,
- byte[] integrityKey,
- byte[] decryptionKey)
- throws IkeProtocolException, GeneralSecurityException {
+ Mac integrityMac,
+ int checksumLen,
+ Cipher decryptCipher,
+ SecretKey dKey)
+ throws IkeException, GeneralSecurityException {
ByteBuffer input =
ByteBuffer.wrap(
message,
@@ -207,15 +173,13 @@ final class IkePayloadFactory {
}
IkeSkPayload payload =
- sDecoderInstance.decodeIkeSkPayload(
- isSkf,
+ new IkeSkPayload(
isCritical,
message,
integrityMac,
+ checksumLen,
decryptCipher,
- integrityKey,
- decryptionKey);
-
+ dKey);
return new Pair(payload, nextPayloadType);
}
@@ -229,16 +193,6 @@ final class IkePayloadFactory {
interface IIkePayloadDecoder {
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;
+ throws IkeException;
}
}
diff --git a/src/java/com/android/internal/net/ipsec/ike/message/IkeSaPayload.java b/src/java/com/android/ike/ikev2/message/IkeSaPayload.java
index 3cce6255..c0651ae0 100644
--- a/src/java/com/android/internal/net/ipsec/ike/message/IkeSaPayload.java
+++ b/src/java/com/android/ike/ikev2/message/IkeSaPayload.java
@@ -14,36 +14,25 @@
* limitations under the License.
*/
-package com.android.internal.net.ipsec.ike.message;
+package com.android.ike.ikev2.message;
-import static android.net.ipsec.ike.IkeManager.getIkeLog;
-import static android.net.ipsec.ike.SaProposal.DhGroup;
-import static android.net.ipsec.ike.SaProposal.EncryptionAlgorithm;
-import static android.net.ipsec.ike.SaProposal.IntegrityAlgorithm;
-import static android.net.ipsec.ike.SaProposal.PseudorandomFunction;
+import static com.android.ike.ikev2.SaProposal.DhGroup;
+import static com.android.ike.ikev2.SaProposal.EncryptionAlgorithm;
+import static com.android.ike.ikev2.SaProposal.IntegrityAlgorithm;
+import static com.android.ike.ikev2.SaProposal.PseudorandomFunction;
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;
-import android.net.ipsec.ike.ChildSaProposal;
-import android.net.ipsec.ike.IkeSaProposal;
-import android.net.ipsec.ike.SaProposal;
-import android.net.ipsec.ike.exceptions.IkeProtocolException;
import android.util.ArraySet;
import android.util.Pair;
+import com.android.ike.ikev2.SaProposal;
+import com.android.ike.ikev2.exceptions.IkeException;
+import com.android.ike.ikev2.exceptions.InvalidSyntaxException;
+import com.android.ike.ikev2.exceptions.NoValidProposalChosenException;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.net.ipsec.ike.IkeSessionStateMachine.IkeSecurityParameterIndex;
-import com.android.internal.net.ipsec.ike.exceptions.InvalidSyntaxException;
-import com.android.internal.net.ipsec.ike.exceptions.NoValidProposalChosenException;
-import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import java.net.InetAddress;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.LinkedList;
@@ -58,8 +47,6 @@ import java.util.Set;
* Protocol Version 2 (IKEv2)</a>
*/
public final class IkeSaPayload extends IkePayload {
- private static final String TAG = "IkeSaPayload";
-
public final boolean isSaResponse;
public final List<Proposal> proposalList;
/**
@@ -70,7 +57,7 @@ public final class IkeSaPayload extends IkePayload {
* @param isResp indicates if this payload is in a response message.
* @param payloadBody the encoded payload body in byte array.
*/
- IkeSaPayload(boolean critical, boolean isResp, byte[] payloadBody) throws IkeProtocolException {
+ IkeSaPayload(boolean critical, boolean isResp, byte[] payloadBody) throws IkeException {
super(IkePayload.PAYLOAD_TYPE_SA, critical);
ByteBuffer inputBuffer = ByteBuffer.wrap(payloadBody);
@@ -80,10 +67,6 @@ public final class IkeSaPayload extends IkePayload {
proposalList.add(proposal);
}
- if (proposalList.isEmpty()) {
- throw new InvalidSyntaxException("Found no SA Proposal in this SA Payload.");
- }
-
// An SA response must have exactly one SA proposal.
if (isResp && proposalList.size() != 1) {
throw new InvalidSyntaxException(
@@ -91,393 +74,113 @@ public final class IkeSaPayload extends IkePayload {
+ "Multiple negotiated proposals found.");
}
isSaResponse = isResp;
-
- boolean firstIsIkeProposal = (proposalList.get(0).protocolId == PROTOCOL_ID_IKE);
- for (int i = 1; i < proposalList.size(); i++) {
- boolean isIkeProposal = (proposalList.get(i).protocolId == PROTOCOL_ID_IKE);
- if (firstIsIkeProposal != isIkeProposal) {
- getIkeLog()
- .w(TAG, "Found both IKE proposals and Child proposals in this SA Payload.");
- break;
- }
- }
-
- getIkeLog().d(TAG, "Receive " + toString());
- }
-
- /** Package private constructor for building a request for IKE SA initial creation or rekey */
- @VisibleForTesting
- IkeSaPayload(
- boolean isResp, byte spiSize, IkeSaProposal[] saProposals, InetAddress localAddress)
- throws IOException {
- this(isResp, spiSize, localAddress);
-
- if (saProposals.length < 1 || isResp && (saProposals.length > 1)) {
- throw new IllegalArgumentException("Invalid SA payload.");
- }
-
- for (int i = 0; i < saProposals.length; i++) {
- // Proposal number must start from 1.
- proposalList.add(
- IkeProposal.createIkeProposal(
- (byte) (i + 1) /*number*/, spiSize, saProposals[i], localAddress));
- }
-
- getIkeLog().d(TAG, "Generate " + toString());
- }
-
- /** Package private constructor for building an response SA Payload for IKE SA rekeys. */
- @VisibleForTesting
- IkeSaPayload(
- boolean isResp,
- byte spiSize,
- byte proposalNumber,
- IkeSaProposal saProposal,
- InetAddress localAddress)
- throws IOException {
- this(isResp, spiSize, localAddress);
-
- proposalList.add(
- IkeProposal.createIkeProposal(
- proposalNumber /*number*/, spiSize, saProposal, localAddress));
-
- getIkeLog().d(TAG, "Generate " + toString());
- }
-
- private IkeSaPayload(boolean isResp, byte spiSize, InetAddress localAddress)
- throws IOException {
- super(IkePayload.PAYLOAD_TYPE_SA, false);
-
- // TODO: Check that proposals.length <= 255 in IkeSessionOptions and ChildSessionOptions
- isSaResponse = isResp;
-
- // TODO: Allocate IKE SPI and pass to IkeProposal.createIkeProposal()
-
- // ProposalList populated in other constructors
- proposalList = new ArrayList<Proposal>();
}
/**
- * Package private constructor for building an outbound request SA Payload for Child SA
- * negotiation.
+ * Construct an instance of IkeSaPayload for building outbound packet.
+ *
+ * <p>The length of spis must be the same as saProposals.
+ *
+ * @param isResp indicates if this payload is in a response message.
+ * @param isIkeSa indicates if this payload is for IKE SA or Child SA
+ * @param spiSize the size of attached SPIs.
+ * @param spis the array of all attached SPIs.
+ * @param saProposals the array of all SA Proposals.
*/
- @VisibleForTesting
- IkeSaPayload(ChildSaProposal[] saProposals, IpSecManager ipSecManager, InetAddress localAddress)
- throws ResourceUnavailableException {
- this(false /*isResp*/, ipSecManager, localAddress);
+ public IkeSaPayload(
+ boolean isResp, boolean isIkeSa, byte spiSize, long[] spis, SaProposal[] saProposals) {
+ super(IkePayload.PAYLOAD_TYPE_SA, false);
- if (saProposals.length < 1) {
+ if (saProposals.length < 1
+ || isResp && (saProposals.length > 1)
+ || saProposals.length != spis.length) {
throw new IllegalArgumentException("Invalid SA payload.");
}
// TODO: Check that saProposals.length <= 255 in IkeSessionOptions and ChildSessionOptions
+ isSaResponse = isResp;
+ proposalList = new ArrayList<Proposal>(saProposals.length);
+ int protocolId = isIkeSa ? PROTOCOL_ID_IKE : PROTOCOL_ID_ESP;
for (int i = 0; i < saProposals.length; i++) {
// Proposal number must start from 1.
- proposalList.add(
- ChildProposal.createChildProposal(
- (byte) (i + 1) /*number*/, saProposals[i], ipSecManager, localAddress));
+ Proposal proposal =
+ new Proposal(
+ (byte) (i + 1) /*proposal number*/,
+ protocolId,
+ spiSize,
+ spis[i],
+ saProposals[i],
+ false /*does not have unrecognized Transform*/);
+ proposalList.add(proposal);
}
-
- getIkeLog().d(TAG, "Generate " + toString());
}
/**
- * Package private constructor for building an outbound response SA Payload for Child SA
- * negotiation.
- */
- @VisibleForTesting
- IkeSaPayload(
- byte proposalNumber,
- ChildSaProposal saProposal,
- IpSecManager ipSecManager,
- InetAddress localAddress)
- throws ResourceUnavailableException {
- this(true /*isResp*/, ipSecManager, localAddress);
-
- proposalList.add(
- ChildProposal.createChildProposal(
- proposalNumber /*number*/, saProposal, ipSecManager, 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) {
- super(IkePayload.PAYLOAD_TYPE_SA, false);
-
- isSaResponse = isResp;
-
- // TODO: Allocate Child SPI and pass to ChildProposal.createChildProposal()
-
- // ProposalList populated in other constructors
- proposalList = new ArrayList<Proposal>();
- }
-
- /**
- * Construct an instance of IkeSaPayload for building an outbound IKE initial setup request.
+ * Construct an instance of IkeSaPayload for building outbound IKE initial setup request.
*
* <p>According to RFC 7296, for an initial IKE SA negotiation, no SPI is included in SA
* Proposal. IKE library, as a client, only supports requesting this initial negotiation.
*
* @param saProposals the array of all SA Proposals.
*/
- public static IkeSaPayload createInitialIkeSaPayload(IkeSaProposal[] saProposals)
- throws IOException {
- return new IkeSaPayload(false /*isResp*/, SPI_LEN_NOT_INCLUDED, saProposals, null);
+ public IkeSaPayload(SaProposal[] saProposals) {
+ this(
+ false /*is request*/,
+ true /*is IKE SA*/,
+ (byte) 0,
+ new long[saProposals.length],
+ saProposals);
}
/**
- * Construct an instance of IkeSaPayload for building an outbound request for Rekey IKE.
+ * Validate and return the negotiated SA proposal from the received SA payload.
*
- * @param saProposals the array of all IKE SA Proposals.
- * @param localAddress the local address assigned on-device.
+ * @param reqSaPayload SA payload from SA initiator to validate against.
+ * @return the validated negotiated SA proposal.
+ * @throws NoValidProposalChosenException if received SA proposal is invalid.
*/
- public static IkeSaPayload createRekeyIkeSaRequestPayload(
- IkeSaProposal[] saProposals, InetAddress localAddress) throws IOException {
- return new IkeSaPayload(false /*isResp*/, SPI_LEN_IKE, saProposals, localAddress);
- }
-
- /**
- * Construct an instance of IkeSaPayload for building an outbound response for Rekey IKE.
- *
- * @param respProposalNumber the selected proposal's number.
- * @param saProposal the expected selected IKE SA Proposal.
- * @param localAddress the local address assigned on-device.
- */
- public static IkeSaPayload createRekeyIkeSaResponsePayload(
- byte respProposalNumber, IkeSaProposal saProposal, InetAddress localAddress)
- throws IOException {
- return new IkeSaPayload(
- true /*isResp*/, SPI_LEN_IKE, respProposalNumber, saProposal, localAddress);
- }
-
- /**
- * Construct an instance of IkeSaPayload for building an outbound request for Child SA
- * negotiation.
- *
- * @param saProposals the array of all Child SA Proposals.
- * @param ipSecManager the IpSecManager for generating IPsec SPIs.
- * @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 {
-
- return new IkeSaPayload(saProposals, ipSecManager, localAddress);
- }
-
- /**
- * Construct an instance of IkeSaPayload for building an outbound response for Child SA
- * negotiation.
- *
- * @param respProposalNumber the selected proposal's number.
- * @param saProposal the expected selected Child SA Proposal.
- * @param ipSecManager the IpSecManager for generating IPsec SPIs.
- * @param localAddress the local address assigned on-device.
- */
- public static IkeSaPayload createChildSaResponsePayload(
- byte respProposalNumber,
- ChildSaProposal saProposal,
- IpSecManager ipSecManager,
- InetAddress localAddress)
- throws ResourceUnavailableException {
- return new IkeSaPayload(respProposalNumber, saProposal, ipSecManager, localAddress);
- }
-
- /**
- * Finds the proposal in this (request) payload that matches the response proposal.
- *
- * @param respProposal the Proposal to match against.
- * @return the byte-value proposal number of the selected proposal
- * @throws NoValidProposalChosenException if no matching proposal was found.
- */
- public byte getNegotiatedProposalNumber(SaProposal respProposal)
+ public SaProposal getVerifiedNegotiatedProposal(IkeSaPayload reqSaPayload)
throws NoValidProposalChosenException {
- for (int i = 0; i < proposalList.size(); i++) {
- Proposal reqProposal = proposalList.get(i);
- if (respProposal.isNegotiatedFrom(reqProposal.getSaProposal())
- && reqProposal.getSaProposal().getProtocolId()
- == respProposal.getProtocolId()) {
- return reqProposal.number;
- }
+ if (!isSaResponse) {
+ throw new UnsupportedOperationException(
+ "Cannot get negotiated SA proposal from a request message.");
}
- throw new NoValidProposalChosenException("No remotely proposed protocol acceptable");
- }
-
- /**
- * Validate the IKE SA Payload pair (request/response) and return the IKE SA negotiation result.
- *
- * <p>Caller is able to extract the negotiated IKE SA Proposal from the response Proposal and
- * the IKE SPI pair generated by both sides.
- *
- * <p>In a locally-initiated case all IKE SA proposals (from users in initial creation or from
- * previously negotiated proposal in rekey creation) in the locally generated reqSaPayload have
- * been validated during building and are unmodified. All Transform combinations in these SA
- * proposals are valid for IKE SA negotiation. It means each IKE SA request proposal MUST have
- * Encryption algorithms, DH group configurations and PRFs. Integrity algorithms can only be
- * omitted when AEAD is used.
- *
- * <p>In a remotely-initiated case the locally generated respSaPayload has exactly one SA
- * proposal. It is validated during building and are unmodified. This proposal has a valid
- * Transform combination for an IKE SA and has at most one value for each Transform type.
- *
- * <p>The response IKE SA proposal is validated against one of the request IKE SA proposals. It
- * is guaranteed that for each Transform type that the request proposal has provided options,
- * the response proposal has exact one Transform value.
- *
- * @param reqSaPayload the request payload.
- * @param respSaPayload the response payload.
- * @param remoteAddress the address of the remote IKE peer.
- * @return the Pair of selected IkeProposal in request and the IkeProposal in response.
- * @throws NoValidProposalChosenException if the response SA Payload cannot be negotiated from
- * the request SA Payload.
- */
- public static Pair<IkeProposal, IkeProposal> getVerifiedNegotiatedIkeProposalPair(
- IkeSaPayload reqSaPayload, IkeSaPayload respSaPayload, InetAddress remoteAddress)
- throws NoValidProposalChosenException, IOException {
- Pair<Proposal, Proposal> proposalPair =
- getVerifiedNegotiatedProposalPair(reqSaPayload, respSaPayload);
- IkeProposal reqProposal = (IkeProposal) proposalPair.first;
- IkeProposal respProposal = (IkeProposal) proposalPair.second;
-
- try {
- // 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);
- }
- // 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);
- }
- return new Pair(reqProposal, respProposal);
- } catch (Exception e) {
- reqProposal.releaseSpiResourceIfExists();
- respProposal.releaseSpiResourceIfExists();
- throw e;
+ // If negotiated proposal has an unrecognized Transform, throw an exception.
+ Proposal respProposal = proposalList.get(0);
+ if (respProposal.hasUnrecognizedTransform) {
+ throw new NoValidProposalChosenException(
+ "Negotiated proposal has unrecognized Transform.");
}
- }
-
- /**
- * Validate the SA Payload pair (request/response) and return the Child SA negotiation result.
- *
- * <p>Caller is able to extract the negotiated SA Proposal from the response Proposal and the
- * IPsec SPI pair generated by both sides.
- *
- * <p>In a locally-initiated case all Child SA proposals (from users in initial creation or from
- * previously negotiated proposal in rekey creation) in the locally generated reqSaPayload have
- * been validated during building and are unmodified. All Transform combinations in these SA
- * proposals are valid for Child SA negotiation. It means each request SA proposal MUST have
- * Encryption algorithms and ESN configurations.
- *
- * <p>In a remotely-initiated case the locally generated respSapayload has exactly one SA
- * proposal. It is validated during building and are unmodified. This proposal has a valid
- * Transform combination for an Child SA and has at most one value for each Transform type.
- *
- * <p>The response Child SA proposal is validated against one of the request SA proposals. It is
- * guaranteed that for each Transform type that the request proposal has provided options, the
- * response proposal has exact one Transform value.
- *
- * @param reqSaPayload the request payload.
- * @param respSaPayload the response payload.
- * @param ipSecManager the IpSecManager 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
- * ChildProposal in this response.
- * @throws NoValidProposalChosenException if the response SA Payload cannot be negotiated from
- * the request SA Payload.
- * @throws ResourceUnavailableException if too many SPIs are currently allocated for this user.
- * @throws SpiUnavailableException if the remotely generated SPI is in use.
- */
- public static Pair<ChildProposal, ChildProposal> getVerifiedNegotiatedChildProposalPair(
- IkeSaPayload reqSaPayload,
- IkeSaPayload respSaPayload,
- IpSecManager ipSecManager,
- InetAddress remoteAddress)
- throws NoValidProposalChosenException, ResourceUnavailableException,
- SpiUnavailableException {
- Pair<Proposal, Proposal> proposalPair =
- getVerifiedNegotiatedProposalPair(reqSaPayload, respSaPayload);
- ChildProposal reqProposal = (ChildProposal) proposalPair.first;
- ChildProposal respProposal = (ChildProposal) proposalPair.second;
-
- try {
- // Allocate initiator's inbound SPI as needed for remotely initiated Child SA creation
- if (reqProposal.getChildSpiResource() == null) {
- reqProposal.allocateResourceForRemoteChildSpi(ipSecManager, remoteAddress);
- }
- // Allocate responder's inbound SPI as needed for locally initiated Child SA creation
- if (respProposal.getChildSpiResource() == null) {
- respProposal.allocateResourceForRemoteChildSpi(ipSecManager, remoteAddress);
- }
- return new Pair(reqProposal, respProposal);
- } catch (Exception e) {
- reqProposal.releaseSpiResourceIfExists();
- respProposal.releaseSpiResourceIfExists();
- throw e;
+ // In SA request payload, the first proposal MUST be 1, and subsequent proposals MUST be one
+ // more than the previous proposal. In SA response payload, the negotiated proposal number
+ // MUST match the selected proposal number in SA request Payload.
+ int negotiatedProposalNum = respProposal.number;
+ List<Proposal> reqProposalList = reqSaPayload.proposalList;
+ if (negotiatedProposalNum < 1 || negotiatedProposalNum > reqProposalList.size()) {
+ throw new NoValidProposalChosenException(
+ "Negotiated proposal has invalid proposal number.");
}
- }
- private static Pair<Proposal, Proposal> getVerifiedNegotiatedProposalPair(
- IkeSaPayload reqSaPayload, IkeSaPayload respSaPayload)
- throws NoValidProposalChosenException {
- try {
- // If negotiated proposal has an unrecognized Transform, throw an exception.
- Proposal respProposal = respSaPayload.proposalList.get(0);
- if (respProposal.hasUnrecognizedTransform) {
- throw new NoValidProposalChosenException(
- "Negotiated proposal has unrecognized Transform.");
- }
-
- // In SA request payload, the first proposal MUST be 1, and subsequent proposals MUST be
- // one more than the previous proposal. In SA response payload, the negotiated proposal
- // number MUST match the selected proposal number in SA request Payload.
- int negotiatedProposalNum = respProposal.number;
- List<Proposal> reqProposalList = reqSaPayload.proposalList;
- if (negotiatedProposalNum < 1 || negotiatedProposalNum > reqProposalList.size()) {
- throw new NoValidProposalChosenException(
- "Negotiated proposal has invalid proposal number.");
- }
-
- Proposal reqProposal = reqProposalList.get(negotiatedProposalNum - 1);
- if (!respProposal.isNegotiatedFrom(reqProposal)) {
- throw new NoValidProposalChosenException("Invalid negotiated proposal.");
- }
-
- // In a locally-initiated creation, release locally generated SPIs in unselected request
- // Proposals. In remotely-initiated SA creation, unused proposals do not have SPIs, and
- // will silently succeed.
- for (Proposal p : reqProposalList) {
- if (reqProposal != p) p.releaseSpiResourceIfExists();
- }
-
- return new Pair<Proposal, Proposal>(reqProposal, respProposal);
- } catch (Exception e) {
- // In a locally-initiated case, release all locally generated SPIs in the SA request
- // payload.
- for (Proposal p : reqSaPayload.proposalList) p.releaseSpiResourceIfExists();
- throw e;
+ Proposal reqProposal = reqProposalList.get(negotiatedProposalNum - 1);
+ if (!respProposal.isNegotiatedFrom(reqProposal)) {
+ throw new NoValidProposalChosenException("Invalid negotiated proposal.");
}
+ return respProposal.saProposal;
}
@VisibleForTesting
interface TransformDecoder {
- Transform[] decodeTransforms(int count, ByteBuffer inputBuffer) throws IkeProtocolException;
+ Transform[] decodeTransforms(int count, ByteBuffer inputBuffer) throws IkeException;
}
// TODO: Add another constructor for building outbound message.
/**
- * This class represents the common information of an IKE Proposal and a Child Proposal.
- *
- * <p>Proposal represents a set contains cryptographic algorithms and key generating materials.
- * It contains multiple {@link Transform}.
+ * Proposal represents a set contains cryptographic algorithms and key generating materials. It
+ * contains multiple {@link Transform}.
*
* @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3.1">RFC 7296, Internet Key
* Exchange Protocol Version 2 (IKEv2)</a>
@@ -485,7 +188,7 @@ public final class IkeSaPayload extends IkePayload {
* or lacking a necessary Transform Type shall be ignored when processing a received SA
* Payload.
*/
- public abstract static class Proposal {
+ public static final class Proposal {
private static final byte LAST_PROPOSAL = 0;
private static final byte NOT_LAST_PROPOSAL = 2;
@@ -497,7 +200,7 @@ public final class IkeSaPayload extends IkePayload {
new TransformDecoder() {
@Override
public Transform[] decodeTransforms(int count, ByteBuffer inputBuffer)
- throws IkeProtocolException {
+ throws IkeException {
Transform[] transformArray = new Transform[count];
for (int i = 0; i < count; i++) {
Transform transform = Transform.readFrom(inputBuffer);
@@ -516,24 +219,30 @@ public final class IkeSaPayload extends IkePayload {
public final byte spiSize;
public final long spi;
+ public final SaProposal saProposal;
+
public final boolean hasUnrecognizedTransform;
+ // TODO: Validate this proposal
+
@VisibleForTesting
Proposal(
byte number,
int protocolId,
byte spiSize,
long spi,
+ SaProposal saProposal,
boolean hasUnrecognizedTransform) {
this.number = number;
this.protocolId = protocolId;
this.spiSize = spiSize;
this.spi = spi;
+ this.saProposal = saProposal;
this.hasUnrecognizedTransform = hasUnrecognizedTransform;
}
@VisibleForTesting
- static Proposal readFrom(ByteBuffer inputBuffer) throws IkeProtocolException {
+ static Proposal readFrom(ByteBuffer inputBuffer) throws IkeException {
byte isLast = inputBuffer.get();
if (isLast != LAST_PROPOSAL && isLast != NOT_LAST_PROPOSAL) {
throw new InvalidSyntaxException(
@@ -602,37 +311,31 @@ public final class IkeSaPayload extends IkePayload {
}
}
- if (protocolId == PROTOCOL_ID_IKE) {
- IkeSaProposal saProposal =
- new IkeSaProposal(
- encryptAlgoList.toArray(
- new EncryptionTransform[encryptAlgoList.size()]),
- prfList.toArray(new PrfTransform[prfList.size()]),
- integAlgoList.toArray(new IntegrityTransform[integAlgoList.size()]),
- dhGroupList.toArray(new DhGroupTransform[dhGroupList.size()]));
- return new IkeProposal(number, spiSize, spi, saProposal, hasUnrecognizedTransform);
- } else {
- ChildSaProposal saProposal =
- new ChildSaProposal(
- encryptAlgoList.toArray(
- new EncryptionTransform[encryptAlgoList.size()]),
- integAlgoList.toArray(new IntegrityTransform[integAlgoList.size()]),
- dhGroupList.toArray(new DhGroupTransform[dhGroupList.size()]),
- esnList.toArray(new EsnTransform[esnList.size()]));
- return new ChildProposal(number, spi, saProposal, hasUnrecognizedTransform);
- }
+ SaProposal saProposal =
+ new SaProposal(
+ protocolId,
+ encryptAlgoList.toArray(
+ new EncryptionTransform[encryptAlgoList.size()]),
+ prfList.toArray(new PrfTransform[prfList.size()]),
+ integAlgoList.toArray(new IntegrityTransform[integAlgoList.size()]),
+ dhGroupList.toArray(new DhGroupTransform[dhGroupList.size()]),
+ esnList.toArray(new EsnTransform[esnList.size()]));
+
+ return new Proposal(
+ number, protocolId, spiSize, spi, saProposal, hasUnrecognizedTransform);
}
+ // TODO: Add another contructor for encoding.
/** Package private */
boolean isNegotiatedFrom(Proposal reqProposal) {
if (protocolId != reqProposal.protocolId || number != reqProposal.number) {
return false;
}
- return getSaProposal().isNegotiatedFrom(reqProposal.getSaProposal());
+ return saProposal.isNegotiatedFrom(reqProposal.saProposal);
}
protected void encodeToByteBuffer(boolean isLast, ByteBuffer byteBuffer) {
- Transform[] allTransforms = getSaProposal().getAllTransforms();
+ Transform[] allTransforms = saProposal.getAllTransforms();
byte isLastIndicator = isLast ? LAST_PROPOSAL : NOT_LAST_PROPOSAL;
byteBuffer
@@ -669,202 +372,15 @@ public final class IkeSaPayload extends IkePayload {
protected int getProposalLength() {
int len = PROPOSAL_HEADER_LEN + spiSize;
- Transform[] allTransforms = getSaProposal().getAllTransforms();
+ Transform[] allTransforms = saProposal.getAllTransforms();
for (Transform t : allTransforms) len += t.getTransformLength();
return len;
}
-
- @Override
- @NonNull
- public String toString() {
- return "Proposal(" + number + ") " + getSaProposal().toString();
- }
-
- /** Package private method for releasing SPI resource in this unselected Proposal. */
- abstract void releaseSpiResourceIfExists();
-
- /** Package private method for getting SaProposal */
- abstract SaProposal getSaProposal();
- }
-
- /** This class represents a Proposal for IKE SA negotiation. */
- public static final class IkeProposal extends Proposal {
- private IkeSecurityParameterIndex mIkeSpiResource;
-
- public final IkeSaProposal saProposal;
-
- /**
- * Construct IkeProposal from a decoded inbound message for IKE negotiation.
- *
- * <p>Package private
- */
- IkeProposal(
- byte number,
- byte spiSize,
- long spi,
- IkeSaProposal saProposal,
- boolean hasUnrecognizedTransform) {
- super(number, PROTOCOL_ID_IKE, spiSize, spi, hasUnrecognizedTransform);
- this.saProposal = saProposal;
- }
-
- /** Construct IkeProposal for an outbound message for IKE negotiation. */
- private IkeProposal(
- byte number,
- byte spiSize,
- IkeSecurityParameterIndex ikeSpiResource,
- IkeSaProposal saProposal) {
- super(
- number,
- PROTOCOL_ID_IKE,
- spiSize,
- ikeSpiResource == null ? SPI_NOT_INCLUDED : ikeSpiResource.getSpi(),
- false /*hasUnrecognizedTransform*/);
- mIkeSpiResource = ikeSpiResource;
- this.saProposal = saProposal;
- }
-
- /**
- * Construct IkeProposal for an outbound message for IKE negotiation.
- *
- * <p>Package private
- */
- @VisibleForTesting
- static IkeProposal createIkeProposal(
- byte number, byte spiSize, IkeSaProposal saProposal, 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));
- return new IkeProposal(number, spiSize, spiResource, saProposal);
- }
-
- /** Package private method for releasing SPI resource in this unselected Proposal. */
- void releaseSpiResourceIfExists() {
- // mIkeSpiResource is null when doing IKE initial exchanges.
- if (mIkeSpiResource == null) return;
- mIkeSpiResource.close();
- mIkeSpiResource = null;
- }
-
- /**
- * 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);
- }
-
- @Override
- public SaProposal getSaProposal() {
- return saProposal;
- }
-
- /**
- * Get the IKE SPI resource.
- *
- * @return the IKE SPI resource or null for IKE initial exchanges.
- */
- public IkeSecurityParameterIndex getIkeSpiResource() {
- return mIkeSpiResource;
- }
- }
-
- /** This class represents a Proposal for Child SA negotiation. */
- public static final class ChildProposal extends Proposal {
- private SecurityParameterIndex mChildSpiResource;
-
- public final ChildSaProposal saProposal;
-
- /**
- * Construct ChildProposal from a decoded inbound message for Child SA negotiation.
- *
- * <p>Package private
- */
- ChildProposal(
- byte number,
- long spi,
- ChildSaProposal saProposal,
- boolean hasUnrecognizedTransform) {
- super(
- number,
- PROTOCOL_ID_ESP,
- SPI_LEN_IPSEC,
- spi,
- hasUnrecognizedTransform);
- this.saProposal = saProposal;
- }
-
- /** Construct ChildProposal for an outbound message for Child SA negotiation. */
- private ChildProposal(
- byte number, SecurityParameterIndex childSpiResource, ChildSaProposal saProposal) {
- super(
- number,
- PROTOCOL_ID_ESP,
- SPI_LEN_IPSEC,
- (long) childSpiResource.getSpi(),
- false /*hasUnrecognizedTransform*/);
- mChildSpiResource = childSpiResource;
- this.saProposal = saProposal;
- }
-
- /**
- * Construct ChildProposal for an outbound message for Child SA negotiation.
- *
- * <p>Package private
- */
- @VisibleForTesting
- static ChildProposal createChildProposal(
- byte number,
- ChildSaProposal saProposal,
- IpSecManager ipSecManager,
- InetAddress localAddress)
- throws ResourceUnavailableException {
- return new ChildProposal(
- number, ipSecManager.allocateSecurityParameterIndex(localAddress), saProposal);
- }
-
- /** Package private method for releasing SPI resource in this unselected Proposal. */
- void releaseSpiResourceIfExists() {
- if (mChildSpiResource == null) return;
-
- mChildSpiResource.close();
- mChildSpiResource = null;
- }
-
- /**
- * Package private method for allocating SPI resource for a validated remotely generated
- * Child SA proposal.
- */
- void allocateResourceForRemoteChildSpi(IpSecManager ipSecManager, InetAddress remoteAddress)
- throws ResourceUnavailableException, SpiUnavailableException {
- mChildSpiResource =
- ipSecManager.allocateSecurityParameterIndex(remoteAddress, (int) spi);
- }
-
- @Override
- public SaProposal getSaProposal() {
- return saProposal;
- }
-
- /**
- * Get the IPsec SPI resource.
- *
- * @return the IPsec SPI resource.
- */
- public SecurityParameterIndex getChildSpiResource() {
- return mChildSpiResource;
- }
}
@VisibleForTesting
interface AttributeDecoder {
- List<Attribute> decodeAttributes(int length, ByteBuffer inputBuffer)
- throws IkeProtocolException;
+ List<Attribute> decodeAttributes(int length, ByteBuffer inputBuffer) throws IkeException;
}
/**
@@ -909,7 +425,7 @@ public final class IkeSaPayload extends IkePayload {
static AttributeDecoder sAttributeDecoder =
new AttributeDecoder() {
public List<Attribute> decodeAttributes(int length, ByteBuffer inputBuffer)
- throws IkeProtocolException {
+ throws IkeException {
List<Attribute> list = new LinkedList<>();
int parsedLength = BASIC_TRANSFORM_LEN;
while (parsedLength < length) {
@@ -947,7 +463,7 @@ public final class IkeSaPayload extends IkePayload {
}
@VisibleForTesting
- static Transform readFrom(ByteBuffer inputBuffer) throws IkeProtocolException {
+ static Transform readFrom(ByteBuffer inputBuffer) throws IkeException {
byte isLast = inputBuffer.get();
if (isLast != LAST_TRANSFORM && isLast != NOT_LAST_TRANSFORM) {
throw new InvalidSyntaxException(
@@ -988,7 +504,7 @@ public final class IkeSaPayload extends IkePayload {
// Throw InvalidSyntaxException if there are multiple Attributes of the same type
private static void validateAttributeUniqueness(List<Attribute> attributeList)
- throws IkeProtocolException {
+ throws IkeException {
Set<Integer> foundTypes = new ArraySet<>();
for (Attribute attr : attributeList) {
if (!foundTypes.add(attr.type)) {
@@ -1039,7 +555,7 @@ public final class IkeSaPayload extends IkePayload {
* Exchange Protocol Version 2 (IKEv2)</a>
*/
public static final class EncryptionTransform extends Transform {
- public static final int KEY_LEN_UNSPECIFIED = 0;
+ private static final int KEY_LEN_UNSPECIFIED = 0;
// When using encryption algorithm with variable-length keys, mSpecifiedKeyLength MUST be
// set and a KeyLengthAttribute MUST be attached. Otherwise, mSpecifiedKeyLength MUST NOT be
@@ -1097,15 +613,6 @@ public final class IkeSaPayload extends IkePayload {
}
}
- /**
- * Get the specified key length.
- *
- * @return the specified key length.
- */
- public int getSpecifiedKeyLength() {
- return mSpecifiedKeyLength;
- }
-
@Override
public int hashCode() {
return Objects.hash(type, id, mSpecifiedKeyLength);
@@ -1211,15 +718,6 @@ public final class IkeSaPayload extends IkePayload {
public String getTransformTypeString() {
return "Encryption Algorithm";
}
-
- @Override
- @NonNull
- public String toString() {
- return SaProposal.getEncryptionAlgorithmString(id)
- + "("
- + getSpecifiedKeyLength()
- + ")";
- }
}
/**
@@ -1287,12 +785,6 @@ public final class IkeSaPayload extends IkePayload {
public String getTransformTypeString() {
return "Pseudorandom Function";
}
-
- @Override
- @NonNull
- public String toString() {
- return SaProposal.getPseudorandomFunctionString(id);
- }
}
/**
@@ -1364,12 +856,6 @@ public final class IkeSaPayload extends IkePayload {
public String getTransformTypeString() {
return "Integrity Algorithm";
}
-
- @Override
- @NonNull
- public String toString() {
- return SaProposal.getIntegrityAlgorithmString(id);
- }
}
/**
@@ -1441,12 +927,6 @@ public final class IkeSaPayload extends IkePayload {
public String getTransformTypeString() {
return "Diffie-Hellman Group";
}
-
- @Override
- @NonNull
- public String toString() {
- return SaProposal.getDhGroupString(id);
- }
}
/**
@@ -1524,15 +1004,6 @@ public final class IkeSaPayload extends IkePayload {
public String getTransformTypeString() {
return "Extended Sequence Numbers";
}
-
- @Override
- @NonNull
- public String toString() {
- if (id == ESN_POLICY_NO_EXTENDED) {
- return "ESN_No_Extended";
- }
- return "ESN_Extended";
- }
}
/**
@@ -1622,8 +1093,7 @@ public final class IkeSaPayload extends IkePayload {
}
@VisibleForTesting
- static Pair<Attribute, Integer> readFrom(ByteBuffer inputBuffer)
- throws IkeProtocolException {
+ static Pair<Attribute, Integer> readFrom(ByteBuffer inputBuffer) throws IkeException {
short formatAndType = inputBuffer.getShort();
int format = formatAndType & ATTRIBUTE_FORMAT_MASK;
int type = formatAndType & ATTRIBUTE_TYPE_MASK;
@@ -1749,25 +1219,6 @@ public final class IkeSaPayload extends IkePayload {
*/
@Override
public String getTypeString() {
- return "SA";
- }
-
- @Override
- @NonNull
- public String toString() {
- StringBuilder sb = new StringBuilder();
- if (isSaResponse) {
- sb.append("SA Response: ");
- } else {
- sb.append("SA Request: ");
- }
-
- int len = proposalList.size();
- for (int i = 0; i < len; i++) {
- sb.append(proposalList.get(i).toString());
- if (i < len - 1) sb.append(", ");
- }
-
- return sb.toString();
+ return "SA Payload";
}
}
diff --git a/src/java/com/android/ike/ikev2/message/IkeSkPayload.java b/src/java/com/android/ike/ikev2/message/IkeSkPayload.java
new file mode 100644
index 00000000..d753ee83
--- /dev/null
+++ b/src/java/com/android/ike/ikev2/message/IkeSkPayload.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2018 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.ike.ikev2.message;
+
+import com.android.ike.ikev2.exceptions.IkeException;
+
+import java.nio.ByteBuffer;
+import java.security.GeneralSecurityException;
+
+import javax.crypto.Cipher;
+import javax.crypto.Mac;
+import javax.crypto.SecretKey;
+
+/**
+ * IkeSkPayload represents a Encrypted Payload.
+ *
+ * <p>It contains other payloads in encrypted form. It is must be the last payload in the message.
+ * It should be the only payload in this implementation.
+ *
+ * <p>Critical bit must be ignored when doing decoding.
+ *
+ * @see <a href="https://tools.ietf.org/html/rfc7296#page-105">RFC 7296, Internet Key Exchange
+ * Protocol Version 2 (IKEv2)</a>
+ */
+public final class IkeSkPayload extends IkePayload {
+
+ private final IkeEncryptedPayloadBody mIkeEncryptedPayloadBody;
+
+ /**
+ * Construct an instance of IkeSkPayload from decrypting an incoming packet.
+ *
+ * @param critical indicates if it is a critical payload.
+ * @param message the byte array contains the whole IKE message.
+ * @param integrityMac the initialized Mac for integrity check.
+ * @param checksumLen the checksum length of negotiated integrity algorithm.
+ * @param decryptCipher the uninitialized Cipher for doing decryption.
+ * @param dKey the decryption key.
+ */
+ IkeSkPayload(
+ boolean critical,
+ byte[] message,
+ Mac integrityMac,
+ int checksumLen,
+ Cipher decryptCipher,
+ SecretKey dKey)
+ throws IkeException, GeneralSecurityException {
+ super(PAYLOAD_TYPE_SK, critical);
+
+ mIkeEncryptedPayloadBody =
+ new IkeEncryptedPayloadBody(
+ message, integrityMac, checksumLen, decryptCipher, dKey);
+ }
+
+ /**
+ * Construct an instance of IkeSkPayload for building outbound packet.
+ *
+ * @param ikeHeader the IKE header.
+ * @param firstPayloadType the type of first payload nested in SkPayload.
+ * @param unencryptedPayloads the encoded payload list to protect.
+ * @param integrityMac the initialized Mac for calculating integrity checksum
+ * @param checksumLen the checksum length of negotiated integrity algorithm.
+ * @param encryptCipher the uninitialized Cipher for doing encryption.
+ * @param eKey the encryption key.
+ */
+ IkeSkPayload(
+ IkeHeader ikeHeader,
+ @PayloadType int firstPayloadType,
+ byte[] unencryptedPayloads,
+ Mac integrityMac,
+ int checksumLen,
+ Cipher encryptCipher,
+ SecretKey eKey) {
+ super(PAYLOAD_TYPE_SK, false);
+
+ mIkeEncryptedPayloadBody =
+ new IkeEncryptedPayloadBody(
+ ikeHeader,
+ firstPayloadType,
+ unencryptedPayloads,
+ integrityMac,
+ checksumLen,
+ encryptCipher,
+ eKey);
+ }
+
+ /**
+ * Return unencrypted payload list
+ *
+ * @return unencrypted payload list in a byte array.
+ */
+ public byte[] getUnencryptedPayloads() {
+ return mIkeEncryptedPayloadBody.getUnencryptedData();
+ }
+
+ // TODO: Add another constructor for AEAD protected payload.
+
+ /**
+ * Encode this payload to a ByteBuffer.
+ *
+ * @param nextPayload type of payload that follows this payload.
+ * @param byteBuffer destination ByteBuffer that stores encoded payload.
+ */
+ @Override
+ protected void encodeToByteBuffer(@PayloadType int nextPayload, ByteBuffer byteBuffer) {
+ encodePayloadHeaderToByteBuffer(nextPayload, getPayloadLength(), byteBuffer);
+ byteBuffer.put(mIkeEncryptedPayloadBody.encode());
+ }
+
+ /**
+ * Get entire payload length.
+ *
+ * @return entire payload length.
+ */
+ @Override
+ protected int getPayloadLength() {
+ return GENERIC_HEADER_LENGTH + mIkeEncryptedPayloadBody.getLength();
+ }
+
+ /**
+ * Return the payload type as a String.
+ *
+ * @return the payload type as a String.
+ */
+ @Override
+ public String getTypeString() {
+ return "Encrypted and Authenticated Payload";
+ }
+}
diff --git a/src/java/com/android/ike/ikev2/message/IkeTsPayload.java b/src/java/com/android/ike/ikev2/message/IkeTsPayload.java
new file mode 100644
index 00000000..8231e29c
--- /dev/null
+++ b/src/java/com/android/ike/ikev2/message/IkeTsPayload.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2019 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.ike.ikev2.message;
+
+import com.android.ike.ikev2.IkeTrafficSelector;
+import com.android.ike.ikev2.exceptions.IkeException;
+
+import java.nio.ByteBuffer;
+
+/**
+ * IkeTsPayload represents an Traffic Selector Initiator Payload or an Traffic Selector Responder
+ * Payload.
+ *
+ * <p>Traffic Selector Initiator Payload and Traffic Selector Responder Payload have same format but
+ * different payload types. They describe the address ranges and port ranges of Child SA initiator
+ * and Child SA responder.
+ *
+ * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.13">RFC 7296, Internet Key Exchange
+ * Protocol Version 2 (IKEv2)</a>
+ */
+public final class IkeTsPayload extends IkePayload {
+ // Length of reserved field in octets.
+ private static final int TS_HEADER_RESERVED_LEN = 3;
+
+ /** Number of Traffic Selectors */
+ public final int numTs;
+ public final IkeTrafficSelector[] trafficSelectors;
+
+ IkeTsPayload(boolean critical, byte[] payloadBody, boolean isInitiator) throws IkeException {
+ super((isInitiator ? PAYLOAD_TYPE_TS_INITIATOR : PAYLOAD_TYPE_TS_RESPONDER), critical);
+
+ ByteBuffer inputBuffer = ByteBuffer.wrap(payloadBody);
+ numTs = Byte.toUnsignedInt(inputBuffer.get());
+ // Skip RESERVED byte
+ inputBuffer.get(new byte[TS_HEADER_RESERVED_LEN]);
+
+ // Decode Traffic Selectors
+ byte[] tsBytes = new byte[inputBuffer.remaining()];
+ inputBuffer.get(tsBytes);
+ trafficSelectors = IkeTrafficSelector.decodeIkeTrafficSelectors(numTs, tsBytes);
+ }
+
+ /**
+ * Encode Traffic Selector Payload to ByteBuffer.
+ *
+ * @param nextPayload type of payload that follows this payload.
+ * @param byteBuffer destination ByteBuffer that stores encoded payload.
+ */
+ @Override
+ protected void encodeToByteBuffer(@PayloadType int nextPayload, ByteBuffer byteBuffer) {
+ throw new UnsupportedOperationException(
+ "It is not supported to encode a " + getTypeString());
+ //TODO: Implement it.
+ }
+
+ /**
+ * Get entire payload length.
+ *
+ * @return entire payload length.
+ */
+ @Override
+ protected int getPayloadLength() {
+ throw new UnsupportedOperationException(
+ "It is not supported to get payload length of " + getTypeString());
+ //TODO: Implement it.
+ }
+
+ /**
+ * Return the payload type as a String.
+ *
+ * @return the payload type as a String.
+ */
+ @Override
+ public String getTypeString() {
+ switch (payloadType) {
+ case PAYLOAD_TYPE_ID_INITIATOR:
+ return "Traffic Selector Initiator Payload";
+ case PAYLOAD_TYPE_ID_RESPONDER:
+ return "Traffic Selector Responder Payload";
+ default:
+ // Won't reach here.
+ throw new IllegalArgumentException(
+ "Invalid Payload Type for Traffic Selector Payload.");
+ }
+ }
+}
diff --git a/src/java/com/android/internal/net/ipsec/ike/message/IkeUnsupportedPayload.java b/src/java/com/android/ike/ikev2/message/IkeUnsupportedPayload.java
index ecfe1e9c..4506621a 100644
--- a/src/java/com/android/internal/net/ipsec/ike/message/IkeUnsupportedPayload.java
+++ b/src/java/com/android/ike/ikev2/message/IkeUnsupportedPayload.java
@@ -14,10 +14,9 @@
* limitations under the License.
*/
-package com.android.internal.net.ipsec.ike.message;
+package com.android.ike.ikev2.message;
import java.nio.ByteBuffer;
-
/**
* IkeUnsupportedPayload represents anunsupported payload.
*
@@ -66,6 +65,6 @@ final class IkeUnsupportedPayload extends IkePayload {
*/
@Override
public String getTypeString() {
- return String.valueOf(payloadType);
+ return "Unsupported Payload";
}
}
diff --git a/src/java/com/android/internal/net/ipsec/ike/message/IkeVendorPayload.java b/src/java/com/android/ike/ikev2/message/IkeVendorPayload.java
index d3464071..85996535 100644
--- a/src/java/com/android/internal/net/ipsec/ike/message/IkeVendorPayload.java
+++ b/src/java/com/android/ike/ikev2/message/IkeVendorPayload.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.internal.net.ipsec.ike.message;
+package com.android.ike.ikev2.message;
import java.nio.ByteBuffer;
@@ -71,6 +71,6 @@ public final class IkeVendorPayload extends IkePayload {
*/
@Override
public String getTypeString() {
- return "Vendor";
+ return "Vendor ID Payload";
}
}
diff --git a/src/java/com/android/internal/net/utils/BigIntegerUtils.java b/src/java/com/android/ike/ikev2/utils/BigIntegerUtils.java
index 09dad74b..6104834c 100644
--- a/src/java/com/android/internal/net/utils/BigIntegerUtils.java
+++ b/src/java/com/android/ike/ikev2/utils/BigIntegerUtils.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.internal.net.utils;
+package com.android.ike.ikev2.utils;
import java.math.BigInteger;
diff --git a/src/java/com/android/internal/net/crypto/KeyGenerationUtils.java b/src/java/com/android/internal/net/crypto/KeyGenerationUtils.java
deleted file mode 100644
index c9ade7d5..00000000
--- a/src/java/com/android/internal/net/crypto/KeyGenerationUtils.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2019 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.crypto;
-
-import java.nio.ByteBuffer;
-
-/**
- * KeyGenerationUtils is a util class that contains utils for key generation needed by IKEv2 and
- * EAP.
- */
-public class KeyGenerationUtils {
- /**
- * Returns the derived pseudorandom number with the specified length by iteratively applying a
- * PRF.
- *
- * <p>prf+(K, S) outputs a pseudorandom stream by using the PRF iteratively. In this way it can
- * generate long enough keying material containing all the keys.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#section-2.13">RFC 7296 Internet Key
- * Exchange Protocol Version 2 (IKEv2) 2.13. Generating Keying Material </a>
- * @param byteSigner the PRF used to sign the given data using the given key.
- * @param keyBytes the key to sign data.
- * @param dataToSign the data to be signed.
- * @param keyMaterialLen the length of keying materials to be generated.
- * @return the byte array of keying materials
- */
- public static byte[] prfPlus(
- ByteSigner byteSigner, byte[] keyBytes, byte[] dataToSign, int keyMaterialLen) {
- ByteBuffer keyMatBuffer = ByteBuffer.allocate(keyMaterialLen);
-
- byte[] previousMac = new byte[0];
- final int padLen = 1;
- byte padValue = 1;
-
- while (keyMatBuffer.remaining() > 0) {
- ByteBuffer dataToSignBuffer =
- ByteBuffer.allocate(previousMac.length + dataToSign.length + padLen);
- dataToSignBuffer.put(previousMac).put(dataToSign).put(padValue);
-
- previousMac = byteSigner.signBytes(keyBytes, dataToSignBuffer.array());
-
- keyMatBuffer.put(
- previousMac, 0, Math.min(previousMac.length, keyMatBuffer.remaining()));
-
- padValue++;
- }
-
- return keyMatBuffer.array();
- }
-
- /**
- * ByteSigner is an interface to be used for implementing the byte-signing for generating keys
- * using {@link KeyGenerationUtils#prfPlus(ByteSigner, byte[], byte[], int)}.
- */
- public interface ByteSigner {
- /**
- * Signs the given data using the key given.
- *
- * <p>Caller is responsible for providing a valid key according to their use cases.
- *
- * @param keyBytes the key to sign data.
- * @param dataToSign the data to be signed.
- * @return the signed value.
- */
- byte[] signBytes(byte[] keyBytes, byte[] dataToSign);
- }
-}
diff --git a/src/java/com/android/internal/net/eap/EapAuthenticator.java b/src/java/com/android/internal/net/eap/EapAuthenticator.java
deleted file mode 100644
index a6869d7d..00000000
--- a/src/java/com/android/internal/net/eap/EapAuthenticator.java
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap;
-
-import android.content.Context;
-import android.net.eap.EapSessionConfig;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.net.eap.EapResult.EapError;
-import com.android.internal.net.eap.EapResult.EapResponse;
-import com.android.internal.net.eap.EapResult.EapSuccess;
-import com.android.internal.net.eap.statemachine.EapStateMachine;
-import com.android.internal.net.utils.Log;
-
-import java.security.SecureRandom;
-import java.util.concurrent.Executor;
-import java.util.concurrent.Executors;
-import java.util.concurrent.TimeoutException;
-
-/**
- * EapAuthenticator represents an EAP peer implementation.
- *
- * @see <a href="https://tools.ietf.org/html/rfc3748#section-4">RFC 3748, Extensible Authentication
- * Protocol (EAP)</a>
- */
-public class EapAuthenticator extends Handler {
- private static final String EAP_TAG = "EAP";
- private static final boolean LOG_SENSITIVE = false;
- public static final Log LOG = new Log(EAP_TAG, LOG_SENSITIVE);
-
- private static final String TAG = EapAuthenticator.class.getSimpleName();
- private static final long DEFAULT_TIMEOUT_MILLIS = 7000L;
-
- private final Executor mWorkerPool;
- private final EapStateMachine mStateMachine;
- private final IEapCallback mCb;
- private final long mTimeoutMillis;
- private boolean mCallbackFired = false;
-
- /**
- * Constructor for EapAuthenticator
- *
- * @param looper Looper for running a message loop
- * @param cb IEapCallback for callbacks to the client
- * @param context Context for this EapAuthenticator
- * @param eapSessionConfig Configuration for an EapAuthenticator
- */
- public EapAuthenticator(
- Looper looper,
- IEapCallback cb,
- Context context,
- EapSessionConfig eapSessionConfig) {
- this(
- looper,
- cb,
- new EapStateMachine(context, eapSessionConfig, new SecureRandom()),
- Executors.newSingleThreadExecutor(),
- DEFAULT_TIMEOUT_MILLIS);
- }
-
- @VisibleForTesting
- EapAuthenticator(
- Looper looper,
- IEapCallback cb,
- EapStateMachine eapStateMachine,
- Executor executor,
- long timeoutMillis) {
- super(looper);
-
- mCb = cb;
- mStateMachine = eapStateMachine;
- mWorkerPool = executor;
- mTimeoutMillis = timeoutMillis;
- }
-
- @Override
- public void handleMessage(Message msg) {
- // No messages processed here. Only runnables. Drop all messages.
- }
-
- /**
- * Processes the given msgBytes within the context of the current EAP Session.
- *
- * <p>If the given message is successfully processed, the relevant {@link IEapCallback} function
- * is used. Otherwise, {@link IEapCallback#onError(Throwable)} is called.
- *
- * @param msgBytes the byte-array encoded EAP message to be processed
- */
- public void processEapMessage(byte[] msgBytes) {
- // reset
- mCallbackFired = false;
-
- postDelayed(
- () -> {
- if (!mCallbackFired) {
- // Fire failed callback
- mCallbackFired = true;
- LOG.e(TAG, "Timeout occurred in EapStateMachine");
- mCb.onError(new TimeoutException("Timeout while processing message"));
- }
- },
- EapAuthenticator.this,
- mTimeoutMillis);
-
- // proxy to worker thread for async processing
- mWorkerPool.execute(
- () -> {
- // Any unhandled exceptions within the state machine are caught here to make
- // sure that the caller does not wait for the full timeout duration before being
- // notified of a failure.
- EapResult processResponse;
- try {
- processResponse = mStateMachine.process(msgBytes);
- } catch (Exception ex) {
- LOG.e(TAG, "Exception thrown while processing message", ex);
- processResponse = new EapError(ex);
- }
-
- final EapResult finalProcessResponse = processResponse;
- EapAuthenticator.this.post(
- () -> {
- // No synchronization needed, since Handler serializes
- if (!mCallbackFired) {
- LOG.i(
- TAG,
- "EapStateMachine returned "
- + finalProcessResponse
- .getClass()
- .getSimpleName());
-
- if (finalProcessResponse instanceof EapResponse) {
- mCb.onResponse(((EapResponse) finalProcessResponse).packet);
- } else if (finalProcessResponse instanceof EapError) {
- EapError eapError = (EapError) finalProcessResponse;
- LOG.e(
- TAG,
- "EapError returned with cause=" + eapError.cause);
- mCb.onError(eapError.cause);
- } else if (finalProcessResponse instanceof EapSuccess) {
- EapSuccess eapSuccess = (EapSuccess) finalProcessResponse;
- LOG.d(
- TAG,
- "EapSuccess with"
- + " MSK=" + LOG.pii(eapSuccess.msk)
- + " EMSK=" + LOG.pii(eapSuccess.msk));
- mCb.onSuccess(eapSuccess.msk, eapSuccess.emsk);
- } else { // finalProcessResponse instanceof EapFailure
- mCb.onFail();
- }
-
- mCallbackFired = true;
-
- // Ensure delayed timeout runnable does not fire
- EapAuthenticator.this.removeCallbacksAndMessages(
- EapAuthenticator.this);
- }
- });
- });
- }
-}
diff --git a/src/java/com/android/internal/net/eap/EapResult.java b/src/java/com/android/internal/net/eap/EapResult.java
deleted file mode 100644
index 894dd475..00000000
--- a/src/java/com/android/internal/net/eap/EapResult.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap;
-
-import android.annotation.NonNull;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.net.eap.exceptions.InvalidEapResponseException;
-import com.android.internal.net.eap.message.EapMessage;
-
-/**
- * EapResult represents the return type R for a process operation within the EapStateMachine.
- */
-public abstract class EapResult {
-
- /**
- * EapSuccess represents a success response from the EapStateMachine.
- *
- * @see <a href="https://tools.ietf.org/html/rfc3748">RFC 3748, Extensible Authentication
- * Protocol (EAP)</a>
- */
- public static class EapSuccess extends EapResult {
- public final byte[] msk;
- public final byte[] emsk;
-
- public EapSuccess(@NonNull byte[] msk, @NonNull byte[] emsk) {
- if (msk == null || emsk == null) {
- throw new IllegalArgumentException("msk and emsk must not be null");
- }
- this.msk = msk;
- this.emsk = emsk;
- }
- }
-
- /**
- * EapFailure represents a failure response from the EapStateMachine.
- *
- * @see <a href="https://tools.ietf.org/html/rfc3748">RFC 3748, Extensible Authentication
- * Protocol (EAP)</a>
- */
- public static class EapFailure extends EapResult {}
-
- /**
- * EapResponse represents an outgoing message from the EapStateMachine.
- *
- * @see <a href="https://tools.ietf.org/html/rfc3748">RFC 3748, Extensible Authentication
- * Protocol (EAP)</a>
- */
- public static class EapResponse extends EapResult {
- public final byte[] packet;
-
- @VisibleForTesting
- protected EapResponse(byte[] packet) {
- this.packet = packet;
- }
-
- /**
- * Constructs and returns an EapResult for the given EapMessage.
- *
- * <p>If the given EapMessage is not of type EAP-Response, an EapError object will be
- * returned.
- *
- * @param message the EapMessage to be encoded in the EapResponse instance.
- * @return an EapResponse instance for the given message. If message.eapCode != {@link
- * EapMessage#EAP_CODE_RESPONSE}, an EapError instance is returned.
- */
- public static EapResult getEapResponse(@NonNull EapMessage message) {
- if (message == null) {
- throw new IllegalArgumentException("EapMessage should not be null");
- } else if (message.eapCode != EapMessage.EAP_CODE_RESPONSE) {
- return new EapError(new InvalidEapResponseException(
- "Cannot construct an EapResult from a non-EAP-Response message"));
- }
-
- return new EapResponse(message.encode());
- }
- }
-
- /**
- * EapError represents an error that occurred in the EapStateMachine.
- *
- * @see <a href="https://tools.ietf.org/html/rfc3748">RFC 3748, Extensible Authentication
- * Protocol (EAP)</a>
- */
- public static class EapError extends EapResult {
- public final Exception cause;
-
- /**
- * Constructs an EapError instance for the given cause.
- *
- * @param cause the Exception that caused the EapError to be returned from the
- * EapStateMachine
- */
- public EapError(Exception cause) {
- this.cause = cause;
- }
- }
-}
diff --git a/src/java/com/android/internal/net/eap/IEapCallback.java b/src/java/com/android/internal/net/eap/IEapCallback.java
deleted file mode 100644
index fae3edf8..00000000
--- a/src/java/com/android/internal/net/eap/IEapCallback.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap;
-
-/**
- * IEapCallback represents a Callback interface to be implemented by clients of the
- * {@link EapAuthenticator}.
- *
- * <p>Exactly one of these callbacks will be called for each message processed by the
- * {@link EapAuthenticator}.
- *
- * @see <a href="https://tools.ietf.org/html/rfc3748#section-4">RFC 3748, Extensible Authentication
- * Protocol (EAP)</a>
- */
-public interface IEapCallback {
- /**
- * Callback used to indicate that the EAP Authentication session was successful.
- *
- * @param msk The Master Session Key (MSK) generated in the session
- * @param emsk The Extended Master Session Key (EMSK) generated in the session
- */
- void onSuccess(byte[] msk, byte[] emsk);
-
- /**
- * Callback used to indicate that the EAP Authentication Session was unsuccessful.
- */
- void onFail();
-
- /**
- * Callback used to return an EAP-Response message for the message being processed.
- *
- * @param eapMsg byte-array encoded EAP-Response message to be sent to the Authentication server
- */
- void onResponse(byte[] eapMsg);
-
- /**
- * Callback used to indicate that there was an error processing the current EAP message.
- *
- * @param cause The cause of the processing error
- */
- void onError(Throwable cause);
-}
diff --git a/src/java/com/android/internal/net/eap/crypto/Fips186_2Prf.java b/src/java/com/android/internal/net/eap/crypto/Fips186_2Prf.java
deleted file mode 100644
index fb1268c0..00000000
--- a/src/java/com/android/internal/net/eap/crypto/Fips186_2Prf.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.crypto;
-
-import static com.android.internal.net.utils.BigIntegerUtils.bigIntegerToUnsignedByteArray;
-import static com.android.internal.net.utils.BigIntegerUtils.unsignedByteArrayToBigInteger;
-
-import com.android.org.bouncycastle.crypto.digests.SHA1Digest;
-
-import java.math.BigInteger;
-import java.nio.ByteBuffer;
-
-/**
- * This class implements the Pseudo-Random Number Generator as specified by FIPS 186-2, change
- * notice 1, as required by EAP-SIM (RFC 4186) and EAP-AKA (RFC 4187).
- *
- * <p>Simplifying constraints allow for some parameters to be permanently fixed: The "b" parameter
- * is specified to always be 160 by RFC 4186. Likewise, the seed must be 20 bytes and therefore can
- * never exceed 2^b.
- */
-public class Fips186_2Prf {
- private static final int SEED_LEN_BYTES = 20;
- private static final int SHA_OUTPUT_LEN_BYTES = 40;
-
- /**
- * Gets the next random based on the PRF described in FIPS 186-2, Change Notice 1.
- *
- * @param seed the seed value
- * @param outputLenBytes the output byte count required. Will run multiple iterations as needed.
- * @return the byte-array random result
- */
- public byte[] getRandom(byte[] seed, int outputLenBytes) {
- if (seed.length != SEED_LEN_BYTES) {
- throw new IllegalArgumentException("Invalid seed length. Must be 160b (20B)");
- }
-
- BigInteger xkey = unsignedByteArrayToBigInteger(seed);
- BigInteger exp_b = new BigInteger("2").pow(SEED_LEN_BYTES * 8);
-
- ByteBuffer buffer = ByteBuffer.allocate(outputLenBytes);
-
- // RFC 4186, Appendix B, Step 3:
- // M is the number of generation runs, based on the desired output bytes (rounded up)
- // EAP SIM/AKA require at least 16 (K_ENCR) + 16 (K_AUTH) + 64 (MSK) + 64 (EMSK) bytes
- // (total 160 Bytes)
- int numIterations = (outputLenBytes + SHA_OUTPUT_LEN_BYTES - 1) / SHA_OUTPUT_LEN_BYTES;
- for (int j = 0; j < numIterations; j++) {
- for (int i = 0; i < 2; i++) {
- // RFC 4186, Appendix B, Step 3.1 XSEED_j = 0
- // (XSEED_j unused, omitted)
-
- // RFC 4186, Appendix B, Step 3.2a: XVAL = (XKEY + XSEED_j) mod 2^b
- // (XSEED_j unused, omitted)
- BigInteger xval = xkey.mod(exp_b);
-
- // RFC 4186, Appendix B, Step 3.2b:
- // w_i = G(t, XVAL)
- byte[] w_i = new byte[SEED_LEN_BYTES];
- Sha1_186_2_FunctionG digest = new Sha1_186_2_FunctionG();
- digest.update(
- bigIntegerToUnsignedByteArray(xval, SEED_LEN_BYTES), 0, SEED_LEN_BYTES);
- digest.doFinal(w_i, 0);
-
- // RFC 4186, Appendix B, Step 3.2c:
- // XKEY = (1 + XKEY + w_i) mod 2^b
- xkey = xkey.add(BigInteger.ONE).add(unsignedByteArrayToBigInteger(w_i));
- xkey = xkey.mod(exp_b);
-
- // RFC 4186, Appendix B, Step 3.3:
- // x_j = w_0|w_1
- buffer.put(w_i, 0, Math.min(buffer.remaining(), w_i.length));
- }
- }
-
- return buffer.array();
- }
-
- /**
- * This inner class represents the modifications to the SHA1 digest required for FIPS 186-2 PRFs
- *
- * <p>FIPS 186-2 requires the use of a hashing function with exactly the same transforms as
- * SHA1, but with a slightly different padding (all 0s instead of appending additional metadata
- * for entropy).
- *
- * <p>Specifically, this function extends BouncyCastle's SHA1Digest in order to override the
- * finish method, preventing the additional padding bytes from being appended (leaving them all
- * 0).
- */
- private static class Sha1_186_2_FunctionG extends SHA1Digest {
- // IV (t) specified by SHA-1; Use default.
-
- @Override
- public void finish() {
- // Don't do any other processing. We only care about the processBlock() functionality.
- processBlock();
- }
- }
-}
diff --git a/src/java/com/android/internal/net/eap/crypto/HmacSha256ByteSigner.java b/src/java/com/android/internal/net/eap/crypto/HmacSha256ByteSigner.java
deleted file mode 100644
index db6e4b30..00000000
--- a/src/java/com/android/internal/net/eap/crypto/HmacSha256ByteSigner.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.crypto;
-
-import com.android.internal.net.crypto.KeyGenerationUtils;
-import com.android.internal.net.crypto.KeyGenerationUtils.ByteSigner;
-
-import java.security.InvalidKeyException;
-import java.security.NoSuchAlgorithmException;
-
-import javax.crypto.Mac;
-import javax.crypto.spec.SecretKeySpec;
-
-/**
- * HmacSha256ByteSigner is a {@link ByteSigner} to be used for computing HMAC-SHA-256 values for
- * specific keys and data.
- */
-public class HmacSha256ByteSigner implements KeyGenerationUtils.ByteSigner {
- private static final String TAG = HmacSha256ByteSigner.class.getSimpleName();
- private static final String MAC_ALGORITHM_STRING = "HmacSHA256";
- private static final HmacSha256ByteSigner sInstance = new HmacSha256ByteSigner();
-
- /**
- * Gets instance of HmacSha256ByteSigner.
- *
- * @return HmacSha256ByteSigner instance.
- */
- public static HmacSha256ByteSigner getInstance() {
- return sInstance;
- }
-
- @Override
- public byte[] signBytes(byte[] keyBytes, byte[] dataToSign) {
- try {
- Mac mac = Mac.getInstance(MAC_ALGORITHM_STRING);
- mac.init(new SecretKeySpec(keyBytes, MAC_ALGORITHM_STRING));
- return mac.doFinal(dataToSign);
- } catch (NoSuchAlgorithmException | InvalidKeyException ex) {
- throw new IllegalArgumentException(ex);
- }
- }
-}
diff --git a/src/java/com/android/internal/net/eap/crypto/ParityBitUtil.java b/src/java/com/android/internal/net/eap/crypto/ParityBitUtil.java
deleted file mode 100644
index 6413aded..00000000
--- a/src/java/com/android/internal/net/eap/crypto/ParityBitUtil.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.crypto;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-/**
- * This class sets parity-bits for a given byte-array as specified by the MSCHAPv2 standard.
- *
- * @see <a href="https://tools.ietf.org/html/rfc2759">RFC 2759, Microsoft PPP CHAP Extensions,
- * Version 2 (MSCHAPv2)</a>
- */
-public class ParityBitUtil {
- private static final int INPUT_LENGTH = 7;
- private static final int OUTPUT_LENGTH = 8;
- private static final int BITS_PER_BYTE = 8;
- private static final int BITS_PER_PARITY_BIT = 7;
- private static final byte MASK = (byte) 0xFE;
-
- /**
- * Computes and returns a byte[] with the odd-parity bits set.
- *
- * <p>Parity bits are set for the 8th, 16th, 24th, etc. bits as the LSB for each byte.
- *
- * @param input byte[] the input data requiring parity bits
- * @return byte[] the input byte[] with its parity-bits set
- * @throws IllegalArgumentException iff the given data array does not contain 7 bytes
- */
- public static byte[] addParityBits(byte[] input) {
- if (input.length != INPUT_LENGTH) {
- throw new IllegalArgumentException("Data must be 7B long");
- }
- byte[] output = new byte[OUTPUT_LENGTH];
-
- long allBits = byteArrayToLong(input) << 1; // make room for parity bit
-
- // allBits stores input bits as [b56, ..., b1, 0]. Consuming allBits in reverse populates
- // output with a right shift
- for (int i = output.length - 1; i >= 0; i--) {
- output[i] = getByteWithParityBit((byte) allBits);
- allBits >>= BITS_PER_PARITY_BIT;
- }
-
- return output;
- }
-
- @VisibleForTesting
- static byte getByteWithParityBit(byte b) {
- // Parity bits per RFC 2759#8.6
- byte parity =
- (byte) ((b >> 7) ^ (b >> 6) ^ (b >> 5) ^ (b >> 4) ^ (b >> 3) ^ (b >> 2) ^ (b >> 1));
-
- // If we have an odd number of bits, b1 should be 0.
- // If we have an even number of bits, b1 should be 1.
- byte parityBit = (byte) (~parity & 1);
- return (byte) ((b & MASK) | parityBit);
- }
-
- @VisibleForTesting
- static long byteArrayToLong(byte[] input) {
- long result = 0;
- for (int i = 0; i < input.length; i++) {
- result = (result << BITS_PER_BYTE) | Byte.toUnsignedInt(input[i]);
- }
- return result;
- }
-}
diff --git a/src/java/com/android/internal/net/eap/exceptions/EapInvalidPacketLengthException.java b/src/java/com/android/internal/net/eap/exceptions/EapInvalidPacketLengthException.java
deleted file mode 100644
index ca6d4da4..00000000
--- a/src/java/com/android/internal/net/eap/exceptions/EapInvalidPacketLengthException.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.exceptions;
-
-import com.android.internal.net.eap.message.EapMessage;
-
-/**
- * This exception is thrown when the Packet Length for an {@link EapMessage} is invalid.
- *
- * @see <a href="https://tools.ietf.org/html/rfc3748#section-4">RFC 3748, Extensible Authentication
- * Protocol (EAP)</a>
- */
-public class EapInvalidPacketLengthException extends EapSilentException {
- /**
- * Construct an instance of EapInvalidPacketLengthException with the specified detail message.
- *
- * @param message the detail message.
- */
- public EapInvalidPacketLengthException(String message) {
- super(message);
- }
-
- /**
- * Construct an instance of EapInvalidPacketLengthException with the specified message and
- * cause.
- *
- * @param message the detail message.
- * @param cause the cause.
- */
- public EapInvalidPacketLengthException(String message, Throwable cause) {
- super(message, cause);
- }
-}
diff --git a/src/java/com/android/internal/net/eap/exceptions/EapInvalidRequestException.java b/src/java/com/android/internal/net/eap/exceptions/EapInvalidRequestException.java
deleted file mode 100644
index 8dee31ae..00000000
--- a/src/java/com/android/internal/net/eap/exceptions/EapInvalidRequestException.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.exceptions;
-
-import com.android.internal.net.eap.statemachine.EapStateMachine;
-
-/**
- * EapInvalidRequestException is thrown when invalid EapMessages are attempted to be processed by
- * the {@link EapStateMachine}.
- */
-public class EapInvalidRequestException extends Exception {
- /**
- * Construct an instance of EapInvalidRequestException with the specified detail message.
- *
- * @param message the detail message.
- */
- public EapInvalidRequestException(String message) {
- super(message);
- }
-
- /**
- * Construct an instance of EapInvalidRequestException with the specified message and cause.
- *
- * @param message the detail message.
- * @param cause the cause.
- */
- public EapInvalidRequestException(String message, Throwable cause) {
- super(message, cause);
- }
-}
diff --git a/src/java/com/android/internal/net/eap/exceptions/EapSilentException.java b/src/java/com/android/internal/net/eap/exceptions/EapSilentException.java
deleted file mode 100644
index 3cb9211d..00000000
--- a/src/java/com/android/internal/net/eap/exceptions/EapSilentException.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.exceptions;
-
-/**
- * EapSilentException represents a category of EAP errors that should be silently discarded by
- * authenticators and peers.
- *
- * <p>EapSilentException is so-named due to its role in the EAP standard. RFC 3748 requires that
- * several error cases be "silently discarded". In these cases, no EAP-Response message will be sent
- * to the Authenticator. However, when thrown SilentExceptions will still signal an EAP failure to
- * the IKE library calling it, resulting in an Authentication failure.
- *
- * Each type of silent error should implement its own subclass.
- */
-public abstract class EapSilentException extends Exception {
- /**
- * Construct an instance of EapSilentException with the specified detail message.
- *
- * @param message the detail message.
- */
- public EapSilentException(String message) {
- super(message);
- }
-
- /**
- * Construct an instance of EapSilentException with the specified message and cause.
- *
- * @param message the detail message.
- * @param cause the cause.
- */
- public EapSilentException(String message, Throwable cause) {
- super(message, cause);
- }
-}
diff --git a/src/java/com/android/internal/net/eap/exceptions/InvalidEapCodeException.java b/src/java/com/android/internal/net/eap/exceptions/InvalidEapCodeException.java
deleted file mode 100644
index 17a0c4df..00000000
--- a/src/java/com/android/internal/net/eap/exceptions/InvalidEapCodeException.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.exceptions;
-
-import com.android.internal.net.eap.message.EapMessage;
-
-/**
- * This exception is thrown when the EAP Code for an {@link EapMessage} is invalid.
- *
- * @see <a href="https://tools.ietf.org/html/rfc3748#section-4">RFC 3748, Extensible Authentication
- * Protocol (EAP)</a>
- */
-public class InvalidEapCodeException extends EapSilentException {
- /**
- * Construct an instance of InvalidEapCodeException with the specified code.
- *
- * @param code The invalid code type
- */
- public InvalidEapCodeException(int code) {
- super("Invalid Code included in EapMessage: " + code);
- }
-}
diff --git a/src/java/com/android/internal/net/eap/exceptions/InvalidEapResponseException.java b/src/java/com/android/internal/net/eap/exceptions/InvalidEapResponseException.java
deleted file mode 100644
index c0a12e2c..00000000
--- a/src/java/com/android/internal/net/eap/exceptions/InvalidEapResponseException.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.exceptions;
-
-/**
- * InvalidEapResponseException is thrown when an invalid EapResponse is attempted to be constructed.
- *
- * <p>EapResponses can only be constructed from EapMessages with the EAP Code for Responses (2).
- */
-public class InvalidEapResponseException extends Exception {
-
- /**
- * Construct an instance of InvalidEapResponseException with the specified detail message.
- *
- * @param message the detail message.
- */
- public InvalidEapResponseException(String message) {
- super(message);
- }
-}
diff --git a/src/java/com/android/internal/net/eap/exceptions/UnsupportedEapTypeException.java b/src/java/com/android/internal/net/eap/exceptions/UnsupportedEapTypeException.java
deleted file mode 100644
index f128385b..00000000
--- a/src/java/com/android/internal/net/eap/exceptions/UnsupportedEapTypeException.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.exceptions;
-
-import com.android.internal.net.eap.message.EapData.EapType;
-import com.android.internal.net.eap.message.EapMessage;
-
-/**
- * UnsupportedEapTypeException is thrown when an {@link EapMessage} is constructed with an
- * unsupported {@link EapType} value.
- */
-public class UnsupportedEapTypeException extends EapSilentException {
- public final int eapIdentifier;
-
- /**
- * Construct an instance of UnsupportedEapTypeException with the specified detail message.
- *
- * @param eapIdentifier the EAP Identifier for the message that contained the unsupported
- * EapType
- * @param message the detail message.
- */
- public UnsupportedEapTypeException(int eapIdentifier, String message) {
- super(message);
- this.eapIdentifier = eapIdentifier;
- }
-
- /**
- * Construct an instance of UnsupportedEapTypeException with the specified message and cause.
- *
- * @param eapIdentifier the EAP Identifier for the message that contained the unsupported
- * EapType
- * @param message the detail message.
- * @param cause the cause.
- */
- public UnsupportedEapTypeException(int eapIdentifier, String message, Throwable cause) {
- super(message, cause);
- this.eapIdentifier = eapIdentifier;
- }
-}
diff --git a/src/java/com/android/internal/net/eap/exceptions/mschapv2/EapMsChapV2ParsingException.java b/src/java/com/android/internal/net/eap/exceptions/mschapv2/EapMsChapV2ParsingException.java
deleted file mode 100644
index 09f1faea..00000000
--- a/src/java/com/android/internal/net/eap/exceptions/mschapv2/EapMsChapV2ParsingException.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.exceptions.mschapv2;
-
-/**
- * EapMsChapV2ParsingException is thrown when an invalid MS-CHAPv2 Type Data is attempted to be
- * processed.
- */
-public class EapMsChapV2ParsingException extends Exception {
- /**
- * Construct an instance of EapMsChapV2ParsingException with the specified detail message.
- *
- * @param message the detail message.
- */
- public EapMsChapV2ParsingException(String message) {
- super(message);
- }
-
- /**
- * Construct an instance of EapMsChapV2ParsingException with the specified message and cause.
- *
- * @param message the detail message.
- * @param cause the cause.
- */
- public EapMsChapV2ParsingException(String message, Throwable cause) {
- super(message, cause);
- }
-}
diff --git a/src/java/com/android/internal/net/eap/exceptions/simaka/EapAkaInvalidAuthenticationResponse.java b/src/java/com/android/internal/net/eap/exceptions/simaka/EapAkaInvalidAuthenticationResponse.java
deleted file mode 100644
index 7310d787..00000000
--- a/src/java/com/android/internal/net/eap/exceptions/simaka/EapAkaInvalidAuthenticationResponse.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.exceptions.simaka;
-
-/**
- * EapAkaInvalidAuthenticationResponse is thrown when a UICC Challenge is processed during an
- * EAP-AKA session and an invalid response format is returned.
- */
-public class EapAkaInvalidAuthenticationResponse extends EapSimAkaAuthenticationFailureException {
- /**
- * Construct an instance of EapAkaInvalidAuthenticationResponse with the specified detail
- * message.
- *
- * @param message the detail message.
- */
- public EapAkaInvalidAuthenticationResponse(String message) {
- super(message);
- }
-
- /**
- * Construct an instance of EapAkaInvalidAuthenticationResponse with the specified message and
- * cause.
- *
- * @param message the detail message.
- * @param cause the cause.
- */
- public EapAkaInvalidAuthenticationResponse(String message, Throwable cause) {
- super(message, cause);
- }
-}
diff --git a/src/java/com/android/internal/net/eap/exceptions/simaka/EapSimAkaAuthenticationFailureException.java b/src/java/com/android/internal/net/eap/exceptions/simaka/EapSimAkaAuthenticationFailureException.java
deleted file mode 100644
index 699f22e4..00000000
--- a/src/java/com/android/internal/net/eap/exceptions/simaka/EapSimAkaAuthenticationFailureException.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.exceptions.simaka;
-
-/**
- * EapSimAkaAuthenticationFailureException is thrown when an invalid Uicc Challenge is processed
- * during an EAP-SIM or EAP-AKA session.
- */
-public class EapSimAkaAuthenticationFailureException extends Exception {
- /**
- * Construct an instance of EapSimAkaAuthenticationFailureException with the specified detail
- * message.
- *
- * @param message the detail message.
- */
- public EapSimAkaAuthenticationFailureException(String message) {
- super(message);
- }
-
- /**
- * Construct an instance of EapSimAkaAuthenticationFailureException with the specified message
- * and cause.
- *
- * @param message the detail message.
- * @param cause the cause.
- */
- public EapSimAkaAuthenticationFailureException(String message, Throwable cause) {
- super(message, cause);
- }
-}
diff --git a/src/java/com/android/internal/net/eap/exceptions/simaka/EapSimAkaIdentityUnavailableException.java b/src/java/com/android/internal/net/eap/exceptions/simaka/EapSimAkaIdentityUnavailableException.java
deleted file mode 100644
index 6a421719..00000000
--- a/src/java/com/android/internal/net/eap/exceptions/simaka/EapSimAkaIdentityUnavailableException.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.exceptions.simaka;
-
-import android.telephony.TelephonyManager;
-
-/**
- * EapSimAkaIdentityUnavailableException is thrown when the client's IMSI is unavailable from
- * {@link TelephonyManager#getSubscriberId()}.
- */
-public class EapSimAkaIdentityUnavailableException extends Exception {
- /**
- * Construct an instance of EapSimAkaIdentityUnavailableException with the specified detail
- * message.
- *
- * @param message the detail message.
- */
- public EapSimAkaIdentityUnavailableException(String message) {
- super(message);
- }
-
- /**
- * Construct an instance of EapSimAkaIdentityUnavailableException with the specified message and
- * cause.
- *
- * @param message the detail message.
- * @param cause the cause.
- */
- public EapSimAkaIdentityUnavailableException(String message, Throwable cause) {
- super(message, cause);
- }
-}
diff --git a/src/java/com/android/internal/net/eap/exceptions/simaka/EapSimAkaInvalidAtPaddingException.java b/src/java/com/android/internal/net/eap/exceptions/simaka/EapSimAkaInvalidAtPaddingException.java
deleted file mode 100644
index 34a8f046..00000000
--- a/src/java/com/android/internal/net/eap/exceptions/simaka/EapSimAkaInvalidAtPaddingException.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.exceptions.simaka;
-
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtPadding;
-
-/**
- * EapSimAkaInvalidAtPaddingException is thrown when an {@link AtPadding} with invalid padding is
- * parsed. Per RFC 4186#10.12 and RFC 4187#10.12, all padding bytes must be 0x00.
- *
- * @see <a href="https://tools.ietf.org/html/rfc4186#section-10.12">RFC 4186, EAP-SIM, Section
- * 10.12</a>
- * @see <a href="https://tools.ietf.org/html/rfc4187#section-10.12">RFC 4187, EAP-AKA, Section
- * 10.12</a>
- */
-public class EapSimAkaInvalidAtPaddingException extends EapSimAkaInvalidAttributeException {
- /**
- * Construct an instance of EapSimAkaInvalidAtPaddingException with the specified detail
- * message.
- *
- * @param message the detail message.
- */
- public EapSimAkaInvalidAtPaddingException(String message) {
- super(message);
- }
-
- /**
- * Construct an instance of EapSimAkaInvalidAtPaddingException with the specified message and
- * cause.
- *
- * @param message the detail message.
- * @param cause the cause.
- */
- public EapSimAkaInvalidAtPaddingException(String message, Throwable cause) {
- super(message, cause);
- }
-}
diff --git a/src/java/com/android/internal/net/eap/exceptions/simaka/EapSimAkaInvalidAttributeException.java b/src/java/com/android/internal/net/eap/exceptions/simaka/EapSimAkaInvalidAttributeException.java
deleted file mode 100644
index eff0c0c2..00000000
--- a/src/java/com/android/internal/net/eap/exceptions/simaka/EapSimAkaInvalidAttributeException.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.exceptions.simaka;
-
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute;
-
-/**
- * EapSimAkaInvalidAttributeException is thrown when an invalid {@link EapSimAkaAttribute} is
- * attempted to be parsed.
- */
-public class EapSimAkaInvalidAttributeException extends Exception {
- /**
- * Construct an instance of EapSimAkaInvalidAttributeException with the specified detail
- * message.
- *
- * @param message the detail message.
- */
- public EapSimAkaInvalidAttributeException(String message) {
- super(message);
- }
-
- /**
- * Construct an instance of EapSimAkaInvalidAttributeException with the specified message and
- * cause.
- *
- * @param message the detail message.
- * @param cause the cause.
- */
- public EapSimAkaInvalidAttributeException(String message, Throwable cause) {
- super(message, cause);
- }
-}
diff --git a/src/java/com/android/internal/net/eap/exceptions/simaka/EapSimAkaInvalidLengthException.java b/src/java/com/android/internal/net/eap/exceptions/simaka/EapSimAkaInvalidLengthException.java
deleted file mode 100644
index c484b112..00000000
--- a/src/java/com/android/internal/net/eap/exceptions/simaka/EapSimAkaInvalidLengthException.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.exceptions.simaka;
-
-import android.telephony.TelephonyManager;
-
-/**
- * EapSimAkaInvalidLengthException is thrown when
- * {@link TelephonyManager#getIccAuthentication(int, int, String)} returns responses with the wrong
- * lengths.
- */
-public class EapSimAkaInvalidLengthException extends Exception {
- /**
- * Construct an instance of EapSimAkaInvalidLengthException with the specified detail message.
- *
- * @param message the detail message.
- */
- public EapSimAkaInvalidLengthException(String message) {
- super(message);
- }
-
- /**
- * Construct an instance of EapSimAkaInvalidLengthException with the specified message and
- * cause.
- *
- * @param message the detail message.
- * @param cause the cause.
- */
- public EapSimAkaInvalidLengthException(String message, Throwable cause) {
- super(message, cause);
- }
-}
diff --git a/src/java/com/android/internal/net/eap/exceptions/simaka/EapSimAkaUnsupportedAttributeException.java b/src/java/com/android/internal/net/eap/exceptions/simaka/EapSimAkaUnsupportedAttributeException.java
deleted file mode 100644
index 11289175..00000000
--- a/src/java/com/android/internal/net/eap/exceptions/simaka/EapSimAkaUnsupportedAttributeException.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.exceptions.simaka;
-
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtVersionList;
-
-/**
- * EapSimAkaUnsupportedAttributeException is thrown when an unsupported {@link EapSimAkaAttribute}
- * is attempted to be decoded.
- *
- * <p>Attributes are supported or not supported per the EAP method being used. For example, an
- * {@link AtVersionList} attribute would be considered "supported" when decoded from an EAP-SIM
- * context, but would be considered "unsupported" from an EAP-AKA context.
- */
-public class EapSimAkaUnsupportedAttributeException extends Exception {
- /**
- * Construct an instance of EapSimAkaUnsupportedAttributeException with the specified detail
- * message.
- *
- * @param message the detail message.
- */
- public EapSimAkaUnsupportedAttributeException(String message) {
- super(message);
- }
-
- /**
- * Construct an instance of EapSimAkaUnsupportedAttributeException with the specified message
- * and cause.
- *
- * @param message the detail message.
- * @param cause the cause.
- */
- public EapSimAkaUnsupportedAttributeException(String message, Throwable cause) {
- super(message, cause);
- }
-}
diff --git a/src/java/com/android/internal/net/eap/exceptions/simaka/EapSimInvalidAtRandException.java b/src/java/com/android/internal/net/eap/exceptions/simaka/EapSimInvalidAtRandException.java
deleted file mode 100644
index c1b92004..00000000
--- a/src/java/com/android/internal/net/eap/exceptions/simaka/EapSimInvalidAtRandException.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.exceptions.simaka;
-
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtRandSim;
-
-/**
- * EapSimInvalidAtRandException is thrown when an {@link AtRandSim} with an invalid number of RAND
- * values is parsed. When this error is encountered, an EAP-Response/SIM/Client-Error response must
- * be used. Note that there MUST BE 2 or 3 RAND values for the AtRandSim to be considered valid.
- *
- * @see <a href="https://tools.ietf.org/html/rfc4186#section-10.9">RFC 4186, EAP-SIM, Section
- * 10.9</a>
- */
-public class EapSimInvalidAtRandException extends EapSimAkaInvalidAttributeException {
- /**
- * Construct an instance of EapSimInvalidAtRandException with the specified detail message.
- *
- * @param message the detail message.
- */
- public EapSimInvalidAtRandException(String message) {
- super(message);
- }
-
- /**
- * Construct an instance of EapSimInvalidAtRandException with the specified message and
- * cause.
- *
- * @param message the detail message.
- * @param cause the cause.
- */
- public EapSimInvalidAtRandException(String message, Throwable cause) {
- super(message, cause);
- }
-}
diff --git a/src/java/com/android/internal/net/eap/exceptions/simaka/EapSimInvalidTypeDataException.java b/src/java/com/android/internal/net/eap/exceptions/simaka/EapSimInvalidTypeDataException.java
deleted file mode 100644
index a6a2d457..00000000
--- a/src/java/com/android/internal/net/eap/exceptions/simaka/EapSimInvalidTypeDataException.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.exceptions.simaka;
-
-import com.android.internal.net.eap.message.simaka.EapSimTypeData;
-
-/**
- * EapSimInvalidTypeDataException is thrown when invalid {@link EapSimTypeData} are attempted to be
- * parsed.
- */
-public class EapSimInvalidTypeDataException extends Exception {
- /**
- * Construct an instance of EapSimInvalidTypeDataException with the specified detail message.
- *
- * @param message the detail message.
- */
- public EapSimInvalidTypeDataException(String message) {
- super(message);
- }
-
- /**
- * Construct an instance of EapSimInvalidTypeDataException with the specified message and cause.
- *
- * @param message the detail message.
- * @param cause the cause.
- */
- public EapSimInvalidTypeDataException(String message, Throwable cause) {
- super(message, cause);
- }
-}
diff --git a/src/java/com/android/internal/net/eap/message/EapData.java b/src/java/com/android/internal/net/eap/message/EapData.java
deleted file mode 100644
index 86dc43b2..00000000
--- a/src/java/com/android/internal/net/eap/message/EapData.java
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.message;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.nio.ByteBuffer;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-
-/**
- * EapData represents the data-bytes of an EAP-Packet.
- *
- * <p>EapData objects will always have a Type-value and the Type-Data bytes that follow.
- *
- * EapData objects should be parsed from the Type and Type-Data sections of an EAP Packet, as shown
- * below:
- *
- * +-----------------+-----------------+----------------------------------+
- * | Code (1B) | Identifier (1B) | Length (2B) |
- * +-----------------+-----------------+----------------------------------+
- * | Type (1B) | Type-Data ...
- * +-----------------+-----
- *
- * @see <a href="https://tools.ietf.org/html/rfc3748#section-4">RFC 3748, Extensible Authentication
- * Protocol (EAP)</a>
- */
-public class EapData {
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({
- EAP_IDENTITY,
- EAP_NOTIFICATION,
- EAP_NAK,
- EAP_TYPE_SIM,
- EAP_TYPE_AKA,
- EAP_TYPE_MSCHAP_V2,
- EAP_TYPE_AKA_PRIME
- })
- public @interface EapType {}
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({
- EAP_TYPE_SIM,
- EAP_TYPE_AKA,
- EAP_TYPE_MSCHAP_V2,
- EAP_TYPE_AKA_PRIME
- })
- public @interface EapMethod {}
-
- // EAP Type values defined by IANA
- // https://www.iana.org/assignments/eap-numbers/eap-numbers.xhtml
- public static final int EAP_IDENTITY = 1;
- public static final int EAP_NOTIFICATION = 2;
- public static final int EAP_NAK = 3;
- // EAP_MD5_CHALLENGE unsupported, allowable based on RFC 3748, Section 5.4
- public static final int EAP_TYPE_SIM = 18;
- public static final int EAP_TYPE_AKA = 23;
- public static final int EAP_TYPE_MSCHAP_V2 = 26;
- public static final int EAP_TYPE_AKA_PRIME = 50;
-
- public static final Map<Integer, String> EAP_TYPE_STRING = new HashMap<>();
- static {
- EAP_TYPE_STRING.put(EAP_IDENTITY, "Identity");
- EAP_TYPE_STRING.put(EAP_NOTIFICATION, "Notification");
- EAP_TYPE_STRING.put(EAP_NAK, "Nak");
- EAP_TYPE_STRING.put(EAP_TYPE_SIM, "EAP-SIM");
- EAP_TYPE_STRING.put(EAP_TYPE_AKA, "EAP-AKA");
- EAP_TYPE_STRING.put(EAP_TYPE_MSCHAP_V2, "EAP-MSCHAP-V2");
- EAP_TYPE_STRING.put(EAP_TYPE_AKA_PRIME, "EAP-AKA-PRIME");
- }
-
- private static final Set<Integer> SUPPORTED_TYPES = new HashSet<>();
- static {
- SUPPORTED_TYPES.add(EAP_IDENTITY);
- SUPPORTED_TYPES.add(EAP_NOTIFICATION);
- SUPPORTED_TYPES.add(EAP_NAK);
-
- // supported EAP Method types
- SUPPORTED_TYPES.add(EAP_TYPE_SIM);
- SUPPORTED_TYPES.add(EAP_TYPE_AKA);
- SUPPORTED_TYPES.add(EAP_TYPE_MSCHAP_V2);
- SUPPORTED_TYPES.add(EAP_TYPE_AKA_PRIME);
- }
-
- @EapType public final int eapType;
- public final byte[] eapTypeData;
-
- public static final EapData NOTIFICATION_DATA = new EapData(EAP_NOTIFICATION, new byte[0]);
-
- /**
- * Constructs a new EapData instance.
- *
- * @param eapType the {@link EapType} for this EapData instance
- * @param eapTypeData the Type-Data for this EapData instance
- * @throws IllegalArgumentException if eapTypeData is null or if
- * {@link EapData#isSupportedEapType} is false for the given eapType
- */
- public EapData(@EapType int eapType, @NonNull byte[] eapTypeData) {
- this.eapType = eapType;
- this.eapTypeData = eapTypeData;
-
- validate();
- }
-
- /**
- * Gets the length of this EapData object.
- *
- * @return int for the number of bytes this EapData object represents
- */
- public int getLength() {
- // length of byte-array + 1 (for 1B type field)
- return eapTypeData.length + 1;
- }
-
- /**
- * Returns whether this instance is equal to the given Object o.
- *
- * @param o the Object to be tested for equality
- * @return true iff this instance is equal to the given o
- */
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || !(o instanceof EapData)) {
- return false;
- }
- EapData eapData = (EapData) o;
- return eapType == eapData.eapType
- && Arrays.equals(eapTypeData, eapData.eapTypeData);
- }
-
- /**
- * Returns the hashCode value for this instance.
- *
- * @return the hashCode value for this instance
- */
- @Override
- public int hashCode() {
- return Objects.hash(eapType, Arrays.hashCode(eapTypeData));
- }
-
- /**
- * Puts the byte-encoding for this EapData instance into the given ByteBuffer.
- *
- * @param b the ByteBuffer to write this EapData instance to
- */
- public void encodeToByteBuffer(ByteBuffer b) {
- b.put((byte) eapType);
- b.put(eapTypeData);
- }
-
- /**
- * Returns whether the given eapType is a supported {@link EapType} value.
- *
- * @param eapType the value to be checked
- * @return true iff the given eapType is a supported EAP Type
- */
- public static boolean isSupportedEapType(int eapType) {
- return SUPPORTED_TYPES.contains(eapType);
- }
-
- private void validate() {
- if (this.eapTypeData == null) {
- throw new IllegalArgumentException("EapTypeData byte[] must be non-null");
- }
- if (!isSupportedEapType(this.eapType)) {
- throw new IllegalArgumentException("eapType must be be a valid @EapType value");
- }
- }
-}
diff --git a/src/java/com/android/internal/net/eap/message/EapMessage.java b/src/java/com/android/internal/net/eap/message/EapMessage.java
deleted file mode 100644
index bb1c6329..00000000
--- a/src/java/com/android/internal/net/eap/message/EapMessage.java
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.message;
-
-import static com.android.internal.net.eap.EapAuthenticator.LOG;
-import static com.android.internal.net.eap.message.EapData.EAP_NAK;
-import static com.android.internal.net.eap.message.EapData.NOTIFICATION_DATA;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-
-import com.android.internal.net.eap.EapResult;
-import com.android.internal.net.eap.EapResult.EapError;
-import com.android.internal.net.eap.EapResult.EapResponse;
-import com.android.internal.net.eap.exceptions.EapInvalidPacketLengthException;
-import com.android.internal.net.eap.exceptions.EapSilentException;
-import com.android.internal.net.eap.exceptions.InvalidEapCodeException;
-import com.android.internal.net.eap.exceptions.UnsupportedEapTypeException;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.nio.BufferUnderflowException;
-import java.nio.ByteBuffer;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * EapMessage represents an EAP Message.
- *
- * <p>EapMessages will be of type:
- * <ul>
- * <li>@{link EAP_CODE_REQUEST}</li>
- * <li>@{link EAP_CODE_RESPONSE}</li>
- * <li>@{link EAP_CODE_SUCCESS}</li>
- * <li>@{link EAP_CODE_FAILURE}</li>
- * </ul>
- *
- * Per RFC 3748 Section 4, EAP-Request and EAP-Response packets should be in the format:
- *
- * +-----------------+-----------------+----------------------------------+
- * | Code (1B) | Identifier (1B) | Length (2B) |
- * +-----------------+-----------------+----------------------------------+
- * | Type (1B) | Type-Data ...
- * +-----------------+-----
- *
- * EAP-Success and EAP-Failure packets should be in the format:
- *
- * +-----------------+-----------------+----------------------------------+
- * | Code (1B) | Identifier (1B) | Length (2B) = '0004' |
- * +-----------------+-----------------+----------------------------------+
- *
- * Note that Length includes the EAP Header bytes.
- *
- * @see <a href="https://tools.ietf.org/html/rfc3748#section-4">RFC 3748, Extensible Authentication
- * Protocol (EAP)</a>
- */
-public class EapMessage {
- private static final String TAG = EapMessage.class.getSimpleName();
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({
- EAP_CODE_REQUEST,
- EAP_CODE_RESPONSE,
- EAP_CODE_SUCCESS,
- EAP_CODE_FAILURE
- })
- public @interface EapCode {}
-
- public static final int EAP_CODE_REQUEST = 1;
- public static final int EAP_CODE_RESPONSE = 2;
- public static final int EAP_CODE_SUCCESS = 3;
- public static final int EAP_CODE_FAILURE = 4;
-
- public static final Map<Integer, String> EAP_CODE_STRING = new HashMap<>();
- static {
- EAP_CODE_STRING.put(EAP_CODE_REQUEST, "REQUEST");
- EAP_CODE_STRING.put(EAP_CODE_RESPONSE, "RESPONSE");
- EAP_CODE_STRING.put(EAP_CODE_SUCCESS, "SUCCESS");
- EAP_CODE_STRING.put(EAP_CODE_FAILURE, "FAILURE");
- }
-
- public static final int EAP_HEADER_LENGTH = 4;
-
- @EapCode public final int eapCode;
- public final int eapIdentifier;
- public final int eapLength;
- public final EapData eapData;
-
- public EapMessage(@EapCode int eapCode, int eapIdentifier, @Nullable EapData eapData)
- throws EapSilentException {
- this.eapCode = eapCode;
- this.eapIdentifier = eapIdentifier;
- this.eapLength = EAP_HEADER_LENGTH + ((eapData == null) ? 0 : eapData.getLength());
- this.eapData = eapData;
-
- validate();
- }
-
- /**
- * Decodes and returns an EapMessage from the given byte array.
- *
- * @param packet byte array containing a byte-encoded EapMessage
- * @return the EapMessage instance representing the given {@param packet}
- * @throws EapSilentException for decoding errors that must be discarded silently
- */
- public static EapMessage decode(@NonNull byte[] packet) throws EapSilentException {
- ByteBuffer buffer = ByteBuffer.wrap(packet);
- int eapCode;
- int eapIdentifier;
- int eapLength;
- EapData eapData;
- try {
- eapCode = Byte.toUnsignedInt(buffer.get());
- eapIdentifier = Byte.toUnsignedInt(buffer.get());
- eapLength = Short.toUnsignedInt(buffer.getShort());
-
- if (eapCode == EAP_CODE_REQUEST || eapCode == EAP_CODE_RESPONSE) {
- int eapType = Byte.toUnsignedInt(buffer.get());
- if (!EapData.isSupportedEapType(eapType)) {
- LOG.e(TAG, "Decoding EAP packet with unsupported EAP-Type: " + eapType);
- throw new UnsupportedEapTypeException(eapIdentifier,
- "Unsupported eapType=" + eapType);
- }
-
- byte[] eapDataBytes = new byte[buffer.remaining()];
- buffer.get(eapDataBytes);
- eapData = new EapData(eapType, eapDataBytes);
- } else {
- eapData = null;
- }
- } catch (BufferUnderflowException ex) {
- String msg = "EAP packet is missing required values";
- LOG.e(TAG, msg, ex);
- throw new EapInvalidPacketLengthException(msg, ex);
- }
-
- int eapDataLength = (eapData == null) ? 0 : eapData.getLength();
- if (eapLength > EAP_HEADER_LENGTH + eapDataLength) {
- String msg = "Packet is shorter than specified length";
- LOG.e(TAG, msg);
- throw new EapInvalidPacketLengthException(msg);
- }
-
- return new EapMessage(eapCode, eapIdentifier, eapData);
- }
-
- /**
- * Converts this EapMessage instance to its byte-encoded representation.
- *
- * @return byte[] representing the byte-encoded EapMessage
- */
- public byte[] encode() {
- ByteBuffer byteBuffer = ByteBuffer.allocate(eapLength);
- byteBuffer.put((byte) eapCode);
- byteBuffer.put((byte) eapIdentifier);
- byteBuffer.putShort((short) eapLength);
-
- if (eapData != null) {
- eapData.encodeToByteBuffer(byteBuffer);
- }
-
- return byteBuffer.array();
- }
-
- /**
- * Creates and returns an EAP-Response/Notification message for the given EAP Identifier wrapped
- * in an EapResponse object.
- *
- * @param eapIdentifier the identifier for the message being responded to
- * @return an EapResponse object containing an EAP-Response/Notification message with an
- * identifier matching the given identifier, or an EapError if an exception was thrown
- */
- public static EapResult getNotificationResponse(int eapIdentifier) {
- try {
- return EapResponse.getEapResponse(
- new EapMessage(EAP_CODE_RESPONSE, eapIdentifier, NOTIFICATION_DATA));
- } catch (EapSilentException ex) {
- // this should never happen - the only variable value is the identifier
- LOG.wtf(TAG, "Failed to create Notification Response for message with identifier="
- + eapIdentifier);
- return new EapError(ex);
- }
- }
-
- /**
- * Creates and returns an EAP-Response/Nak message for the given EAP Identifier wrapped in an
- * EapResponse object.
- *
- * @param eapIdentifier the identifier for the message being responded to
- * @param supportedEapTypes Collection of EAP Method types supported by the EAP Session
- * @return an EapResponse object containing an EAP-Response/Nak message with an identifier
- * matching the given identifier, or an EapError if an exception was thrown
- */
- public static EapResult getNakResponse(
- int eapIdentifier,
- Collection<Integer> supportedEapTypes) {
- try {
- ByteBuffer buffer = ByteBuffer.allocate(supportedEapTypes.size());
- for (int eapMethodType : supportedEapTypes) {
- buffer.put((byte) eapMethodType);
- }
- EapData nakData = new EapData(EAP_NAK, buffer.array());
-
- return EapResponse.getEapResponse(
- new EapMessage(EAP_CODE_RESPONSE, eapIdentifier, nakData));
- } catch (EapSilentException ex) {
- // this should never happen - the only variable value is the identifier
- LOG.wtf(TAG, "Failed to create Nak for message with identifier="
- + eapIdentifier);
- return new EapError(ex);
- }
- }
-
- private void validate() throws EapSilentException {
- if (eapCode != EAP_CODE_REQUEST
- && eapCode != EAP_CODE_RESPONSE
- && eapCode != EAP_CODE_SUCCESS
- && eapCode != EAP_CODE_FAILURE) {
- LOG.e(TAG, "Invalid EAP Code: " + eapCode);
- throw new InvalidEapCodeException(eapCode);
- }
-
- if ((eapCode == EAP_CODE_SUCCESS || eapCode == EAP_CODE_FAILURE)
- && eapLength != EAP_HEADER_LENGTH) {
- LOG.e(TAG, "Invalid length for EAP-Success/EAP-Failure. Length: " + eapLength);
- throw new EapInvalidPacketLengthException(
- "EAP Success/Failure packets must be length 4");
- }
-
- if ((eapCode == EAP_CODE_REQUEST || eapCode == EAP_CODE_RESPONSE) && eapData == null) {
- LOG.e(TAG, "No Type value included for EAP-Request/EAP-Response");
- throw new EapInvalidPacketLengthException(
- "EAP Request/Response packets must include a Type value");
- }
- }
-}
diff --git a/src/java/com/android/internal/net/eap/message/mschapv2/EapMsChapV2TypeData.java b/src/java/com/android/internal/net/eap/message/mschapv2/EapMsChapV2TypeData.java
deleted file mode 100644
index 985e0dac..00000000
--- a/src/java/com/android/internal/net/eap/message/mschapv2/EapMsChapV2TypeData.java
+++ /dev/null
@@ -1,600 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.message.mschapv2;
-
-import static com.android.internal.net.eap.EapAuthenticator.LOG;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.net.eap.EapResult.EapError;
-import com.android.internal.net.eap.exceptions.mschapv2.EapMsChapV2ParsingException;
-import com.android.internal.net.eap.message.EapMessage;
-
-import java.nio.BufferUnderflowException;
-import java.nio.ByteBuffer;
-import java.nio.charset.Charset;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * EapMsChapV2TypeData represents the Type Data for an {@link EapMessage} during an EAP MSCHAPv2
- * session.
- */
-public class EapMsChapV2TypeData {
- private static final int LABEL_VALUE_LENGTH = 2;
- private static final String ASCII_CHARSET_NAME = "US-ASCII";
- private static final String MESSAGE_PREFIX = "M=";
- private static final String MESSAGE_LABEL = "M";
-
- // EAP MSCHAPv2 OpCode values (EAP MSCHAPv2#2)
- public static final int EAP_MSCHAP_V2_CHALLENGE = 1;
- public static final int EAP_MSCHAP_V2_RESPONSE = 2;
- public static final int EAP_MSCHAP_V2_SUCCESS = 3;
- public static final int EAP_MSCHAP_V2_FAILURE = 4;
- public static final int EAP_MSCHAP_V2_CHANGE_PASSWORD = 7;
-
- public static final Map<Integer, String> EAP_OP_CODE_STRING = new HashMap<>();
- static {
- EAP_OP_CODE_STRING.put(EAP_MSCHAP_V2_CHALLENGE, "Challenge");
- EAP_OP_CODE_STRING.put(EAP_MSCHAP_V2_RESPONSE, "Response");
- EAP_OP_CODE_STRING.put(EAP_MSCHAP_V2_SUCCESS, "Success");
- EAP_OP_CODE_STRING.put(EAP_MSCHAP_V2_FAILURE, "Failure");
- EAP_OP_CODE_STRING.put(EAP_MSCHAP_V2_CHANGE_PASSWORD, "Change-Password");
- }
-
- private static final Set<Integer> SUPPORTED_OP_CODES = new HashSet<>();
- static {
- SUPPORTED_OP_CODES.add(EAP_MSCHAP_V2_CHALLENGE);
- SUPPORTED_OP_CODES.add(EAP_MSCHAP_V2_RESPONSE);
- SUPPORTED_OP_CODES.add(EAP_MSCHAP_V2_SUCCESS);
- SUPPORTED_OP_CODES.add(EAP_MSCHAP_V2_FAILURE);
- }
-
- public final int opCode;
-
- EapMsChapV2TypeData(int opCode) throws EapMsChapV2ParsingException {
- this.opCode = opCode;
-
- if (!SUPPORTED_OP_CODES.contains(opCode)) {
- throw new EapMsChapV2ParsingException("Unsupported opCode provided: " + opCode);
- }
- }
-
- /**
- * Encodes this EapMsChapV2TypeData instance as a byte[].
- *
- * @return byte[] representing the encoded value of this EapMsChapV2TypeData instance.
- */
- public byte[] encode() {
- throw new UnsupportedOperationException(
- "encode() not supported by " + this.getClass().getSimpleName());
- }
-
- abstract static class EapMsChapV2VariableTypeData extends EapMsChapV2TypeData {
- public final int msChapV2Id;
- public final int msLength;
-
- EapMsChapV2VariableTypeData(int opCode, int msChapV2Id, int msLength)
- throws EapMsChapV2ParsingException {
- super(opCode);
-
- this.msChapV2Id = msChapV2Id;
- this.msLength = msLength;
- }
- }
-
- /**
- * EapMsChapV2ChallengeRequest represents the EAP MSCHAPv2 Challenge Packet (EAP MSCHAPv2#2.1).
- */
- public static class EapMsChapV2ChallengeRequest extends EapMsChapV2VariableTypeData {
- public static final int VALUE_SIZE = 16;
- public static final int TYPE_DATA_HEADER_SIZE = 5;
-
- public final byte[] challenge = new byte[VALUE_SIZE];
- public final byte[] name;
-
- EapMsChapV2ChallengeRequest(ByteBuffer buffer) throws EapMsChapV2ParsingException {
- super(
- EAP_MSCHAP_V2_CHALLENGE,
- Byte.toUnsignedInt(buffer.get()),
- Short.toUnsignedInt(buffer.getShort()));
-
- int valueSize = Byte.toUnsignedInt(buffer.get());
- if (valueSize != VALUE_SIZE) {
- throw new EapMsChapV2ParsingException("Challenge Value-Size must be 16");
- }
- buffer.get(challenge);
-
- int nameLenBytes = msLength - VALUE_SIZE - TYPE_DATA_HEADER_SIZE;
- if (nameLenBytes < 0) {
- throw new EapMsChapV2ParsingException("Invalid MS-Length specified");
- }
-
- name = new byte[nameLenBytes];
- buffer.get(name);
- }
-
- @VisibleForTesting
- public EapMsChapV2ChallengeRequest(
- int msChapV2Id, int msLength, byte[] challenge, byte[] name)
- throws EapMsChapV2ParsingException {
- super(EAP_MSCHAP_V2_CHALLENGE, msChapV2Id, msLength);
-
- if (challenge.length != VALUE_SIZE) {
- throw new EapMsChapV2ParsingException("Challenge length must be 16");
- }
-
- System.arraycopy(challenge, 0, this.challenge, 0, VALUE_SIZE);
- this.name = name;
- }
- }
-
- /**
- * EapMsChapV2ChallengeResponse represents the EAP MSCHAPv2 Response Packet (EAP MSCHAPv2#2.2).
- */
- public static class EapMsChapV2ChallengeResponse extends EapMsChapV2VariableTypeData {
- public static final int VALUE_SIZE = 49;
- public static final int PEER_CHALLENGE_SIZE = 16;
- public static final int RESERVED_BYTES = 8;
- public static final int NT_RESPONSE_SIZE = 24;
- public static final int TYPE_DATA_HEADER_SIZE = 5;
-
- public final byte[] peerChallenge = new byte[PEER_CHALLENGE_SIZE];
- public final byte[] ntResponse = new byte[NT_RESPONSE_SIZE];
- public final int flags;
- public final byte[] name;
-
- public EapMsChapV2ChallengeResponse(
- int msChapV2Id, byte[] peerChallenge, byte[] ntResponse, int flags, byte[] name)
- throws EapMsChapV2ParsingException {
- super(
- EAP_MSCHAP_V2_RESPONSE,
- msChapV2Id,
- TYPE_DATA_HEADER_SIZE + VALUE_SIZE + name.length);
-
- if (peerChallenge.length != PEER_CHALLENGE_SIZE) {
- throw new EapMsChapV2ParsingException("Peer-Challenge must be 16B");
- } else if (ntResponse.length != NT_RESPONSE_SIZE) {
- throw new EapMsChapV2ParsingException("NT-Response must be 24B");
- } else if (flags != 0) {
- throw new EapMsChapV2ParsingException("Flags must be 0x00");
- }
-
- System.arraycopy(peerChallenge, 0, this.peerChallenge, 0, PEER_CHALLENGE_SIZE);
- System.arraycopy(ntResponse, 0, this.ntResponse, 0, NT_RESPONSE_SIZE);
- this.flags = flags;
- this.name = name;
- }
-
- @Override
- public byte[] encode() {
- ByteBuffer buffer = ByteBuffer.allocate(msLength);
- buffer.put((byte) EAP_MSCHAP_V2_RESPONSE);
- buffer.put((byte) msChapV2Id);
- buffer.putShort((short) msLength);
- buffer.put((byte) VALUE_SIZE);
- buffer.put(peerChallenge);
- buffer.put(new byte[RESERVED_BYTES]);
- buffer.put(ntResponse);
- buffer.put((byte) flags);
- buffer.put(name);
-
- return buffer.array();
- }
- }
-
- /**
- * EapMsChapV2SuccessRequest represents the EAP MSCHAPv2 Success Request Packet
- * (EAP MSCHAPv2#2.3).
- */
- public static class EapMsChapV2SuccessRequest extends EapMsChapV2VariableTypeData {
- private static final int AUTH_STRING_LEN_HEX = 40;
- private static final int AUTH_STRING_LEN_BYTES = 20;
- private static final int NUM_REQUIRED_ATTRIBUTES = 2;
- private static final String AUTH_STRING_LABEL = "S";
-
- public final byte[] authBytes = new byte[AUTH_STRING_LEN_BYTES];
- public final String message;
-
- EapMsChapV2SuccessRequest(ByteBuffer buffer) throws EapMsChapV2ParsingException {
- super(
- EAP_MSCHAP_V2_SUCCESS,
- Byte.toUnsignedInt(buffer.get()),
- Short.toUnsignedInt(buffer.getShort()));
-
- byte[] message = new byte[buffer.remaining()];
- buffer.get(message);
-
- // message formatting: "S=<auth_string> M=<message>"
- Map<String, String> mappings =
- getMessageMappings(new String(message, Charset.forName(ASCII_CHARSET_NAME)));
-
- if (!mappings.containsKey(AUTH_STRING_LABEL)
- || mappings.size() != NUM_REQUIRED_ATTRIBUTES) {
- throw new EapMsChapV2ParsingException(
- "Auth message must be in the format: 'S=<auth_string> M=<message>'");
- }
-
- String authStringHex = mappings.get(AUTH_STRING_LABEL);
- if (authStringHex.length() != AUTH_STRING_LEN_HEX) {
- throw new EapMsChapV2ParsingException("Auth String must be 40 hex chars (20B)");
- }
- byte[] authBytes = hexStringToByteArray(authStringHex);
- System.arraycopy(authBytes, 0, this.authBytes, 0, AUTH_STRING_LEN_BYTES);
-
- this.message = mappings.get(MESSAGE_LABEL);
- }
-
- @VisibleForTesting
- public EapMsChapV2SuccessRequest(
- int msChapV2Id, int msLength, byte[] authBytes, String message)
- throws EapMsChapV2ParsingException {
- super(EAP_MSCHAP_V2_SUCCESS, msChapV2Id, msLength);
-
- if (authBytes.length != AUTH_STRING_LEN_BYTES) {
- throw new EapMsChapV2ParsingException("Auth String must be 20B");
- }
-
- System.arraycopy(authBytes, 0, this.authBytes, 0, AUTH_STRING_LEN_BYTES);
- this.message = message;
- }
- }
-
- /**
- * EapMsChapV2SuccessResponse represents the EAP MSCHAPv2 Success Response Packet
- * (EAP MSCHAPv2#2.4).
- */
- public static class EapMsChapV2SuccessResponse extends EapMsChapV2TypeData {
- private EapMsChapV2SuccessResponse() throws EapMsChapV2ParsingException {
- super(EAP_MSCHAP_V2_SUCCESS);
- }
-
- /**
- * Constructs and returns a new EAP MSCHAPv2 Success Response type data.
- *
- * @return a new EapMsChapV2SuccessResponse instance
- */
- public static EapMsChapV2SuccessResponse getEapMsChapV2SuccessResponse() {
- try {
- return new EapMsChapV2SuccessResponse();
- } catch (EapMsChapV2ParsingException ex) {
- // This should never happen
- LOG.wtf(
- EapMsChapV2SuccessResponse.class.getSimpleName(),
- "ParsingException thrown while creating EapMsChapV2SuccessResponse",
- ex);
- return null;
- }
- }
-
- @Override
- public byte[] encode() {
- return new byte[] {(byte) EAP_MSCHAP_V2_SUCCESS};
- }
- }
-
- /**
- * EapMsChapV2FailureRequest represents the EAP MSCHAPv2 Failure Request Packet
- * (EAP MSCHAPv2#2.5).
- */
- public static class EapMsChapV2FailureRequest extends EapMsChapV2VariableTypeData {
- private static final int NUM_REQUIRED_ATTRIBUTES = 5;
- private static final int CHALLENGE_LENGTH = 16;
- private static final String ERROR_LABEL = "E";
- private static final String RETRY_LABEL = "R";
- private static final String IS_RETRYABLE_FLAG = "1";
- private static final String CHALLENGE_LABEL = "C";
- private static final String PASSWORD_CHANGE_PROTOCOL_LABEL = "V";
-
- // Error codes defined in EAP MSCHAPv2#2.5
- public static final Map<Integer, String> EAP_ERROR_CODE_STRING = new HashMap<>();
- static {
- EAP_ERROR_CODE_STRING.put(646, "ERROR_RESTRICTED_LOGON_HOURS");
- EAP_ERROR_CODE_STRING.put(647, "ERROR_ACCT_DISABLED");
- EAP_ERROR_CODE_STRING.put(648, "ERROR_PASSWD_EXPIRED");
- EAP_ERROR_CODE_STRING.put(649, "ERROR_NO_DIALIN_PERMISSION");
- EAP_ERROR_CODE_STRING.put(691, "ERROR_AUTHENTICATION_FAILURE");
- EAP_ERROR_CODE_STRING.put(709, "ERROR_CHANGING_PASSWORD");
- }
-
- public final int errorCode;
- public final boolean isRetryable;
- public final byte[] challenge;
- public final int passwordChangeProtocol;
- public final String message;
-
- EapMsChapV2FailureRequest(ByteBuffer buffer)
- throws EapMsChapV2ParsingException, NumberFormatException {
- super(
- EAP_MSCHAP_V2_FAILURE,
- Byte.toUnsignedInt(buffer.get()),
- Short.toUnsignedInt(buffer.getShort()));
-
- byte[] message = new byte[buffer.remaining()];
- buffer.get(message);
-
- // message formatting:
- // "E=<error_code> R=<retry bit> C=<challenge> V=<password_change_protocol> M=<message>"
- Map<String, String> mappings =
- getMessageMappings(new String(message, Charset.forName(ASCII_CHARSET_NAME)));
- if (!mappings.containsKey(ERROR_LABEL)
- || !mappings.containsKey(RETRY_LABEL)
- || !mappings.containsKey(CHALLENGE_LABEL)
- || !mappings.containsKey(PASSWORD_CHANGE_PROTOCOL_LABEL)
- || mappings.size() != NUM_REQUIRED_ATTRIBUTES) {
- throw new EapMsChapV2ParsingException(
- "Message must be formatted as: E=<error_code> R=<retry bit> C=<challenge>"
- + " V=<password_change_protocol> M=<message>");
- }
-
- this.errorCode = Integer.parseInt(mappings.get(ERROR_LABEL));
- this.isRetryable = IS_RETRYABLE_FLAG.equals(mappings.get(RETRY_LABEL));
- this.challenge = hexStringToByteArray(mappings.get(CHALLENGE_LABEL));
- this.passwordChangeProtocol = Integer.parseInt(mappings.get(
- PASSWORD_CHANGE_PROTOCOL_LABEL));
- this.message = mappings.get("M");
-
- if (challenge.length != CHALLENGE_LENGTH) {
- throw new EapMsChapV2ParsingException("Challenge must be 16B long");
- }
- }
-
- @VisibleForTesting
- public EapMsChapV2FailureRequest(
- int msChapV2Id,
- int msLength,
- int errorCode,
- boolean isRetryable,
- byte[] challenge,
- int passwordChangeProtocol,
- String message)
- throws EapMsChapV2ParsingException {
- super(EAP_MSCHAP_V2_FAILURE, msChapV2Id, msLength);
-
- this.errorCode = errorCode;
- this.isRetryable = isRetryable;
- this.challenge = challenge;
- this.passwordChangeProtocol = passwordChangeProtocol;
- this.message = message;
-
- if (challenge.length != CHALLENGE_LENGTH) {
- throw new EapMsChapV2ParsingException("Challenge length must be 16B");
- }
- }
- }
-
- /**
- * EapMsChapV2FailureResponse represents the EAP MSCHAPv2 Failure Response Packet
- * (EAP MSCHAPv2#2.6).
- */
- public static class EapMsChapV2FailureResponse extends EapMsChapV2TypeData {
- private EapMsChapV2FailureResponse() throws EapMsChapV2ParsingException {
- super(EAP_MSCHAP_V2_FAILURE);
- }
-
- /**
- * Constructs and returns a new EAP MSCHAPv2 Failure Response type data.
- *
- * @return a new EapMsChapV2FailureResponse instance
- */
- public static EapMsChapV2FailureResponse getEapMsChapV2FailureResponse() {
- try {
- return new EapMsChapV2FailureResponse();
- } catch (EapMsChapV2ParsingException ex) {
- // This should never happen
- LOG.wtf(
- EapMsChapV2SuccessResponse.class.getSimpleName(),
- "ParsingException thrown while creating EapMsChapV2FailureResponse",
- ex);
- return null;
- }
- }
-
- @Override
- public byte[] encode() {
- return new byte[] {(byte) EAP_MSCHAP_V2_FAILURE};
- }
- }
-
- @VisibleForTesting
- static Map<String, String> getMessageMappings(String message)
- throws EapMsChapV2ParsingException {
- Map<String, String> messageMappings = new HashMap<>();
- int mPos = message.indexOf(MESSAGE_PREFIX);
-
- String preMString;
- if (mPos == -1) {
- preMString = message;
- messageMappings.put(MESSAGE_LABEL, "<omitted by authenticator>");
- } else {
- preMString = message.substring(0, mPos);
- messageMappings.put(MESSAGE_LABEL, message.substring(mPos + MESSAGE_PREFIX.length()));
- }
-
- // preMString: "S=<auth string> " or "E=<error> R=r C=<challenge> V=<version> "
- for (String value : preMString.split(" ")) {
- String[] keyValue = value.split("=");
- if (keyValue.length != LABEL_VALUE_LENGTH) {
- throw new EapMsChapV2ParsingException(
- "Message must be formatted <label character>=<value>");
- } else if (messageMappings.containsKey(keyValue[0])) {
- throw new EapMsChapV2ParsingException(
- "Duplicated key-value pair in message: " + LOG.pii(message));
- }
- messageMappings.put(keyValue[0], keyValue[1]);
- }
-
- return messageMappings;
- }
-
- @VisibleForTesting
- static byte[] hexStringToByteArray(String hexString)
- throws EapMsChapV2ParsingException, NumberFormatException {
- if (hexString.length() % 2 != 0) {
- throw new EapMsChapV2ParsingException(
- "Hex string must contain an even number of characters");
- }
-
- byte[] dataBytes = new byte[hexString.length() / 2];
- for (int i = 0; i < hexString.length(); i += 2) {
- dataBytes[i / 2] = (byte) Integer.parseInt(hexString.substring(i, i + 2), 16);
- }
- return dataBytes;
- }
-
- /** Class for decoding EAP MSCHAPv2 type data. */
- public static class EapMsChapV2TypeDataDecoder {
- /**
- * Returns the EAP MSCHAPv2 Op Code for the given EAP type data.
- *
- * @param eapTypeData byte[] type data to read the Op Code from
- * @return the EAP MSCHAPv2 Op Code for the current type data
- * @throws BufferUnderflowException iff eapTypeData.length == 0
- */
- public int getOpCode(byte[] eapTypeData) throws BufferUnderflowException {
- return Byte.toUnsignedInt(ByteBuffer.wrap(eapTypeData).get());
- }
-
- /**
- * Decodes and returns an EapMsChapV2ChallengeRequest for the specified eapTypeData.
- *
- * @param tag String for logging tag
- * @param eapTypeData byte[] to be decoded as an EapMsChapV2ChallengeRequest instance
- * @return DecodeResult wrapping an EapMsChapV2ChallengeRequest instance for the given
- * eapTypeData iff the eapTypeData is formatted correctly. Otherwise, the DecodeResult
- * wraps the appropriate EapError.
- */
- public DecodeResult<EapMsChapV2ChallengeRequest> decodeChallengeRequest(
- String tag, byte[] eapTypeData) {
- try {
- ByteBuffer buffer = ByteBuffer.wrap(eapTypeData);
- int opCode = Byte.toUnsignedInt(buffer.get());
-
- if (opCode != EAP_MSCHAP_V2_CHALLENGE) {
- return new DecodeResult<>(
- new EapError(
- new EapMsChapV2ParsingException(
- "Received type data with invalid opCode: "
- + EAP_OP_CODE_STRING.getOrDefault(
- opCode, "Unknown (" + opCode + ")"))));
- }
-
- return new DecodeResult<>(new EapMsChapV2ChallengeRequest(buffer));
- } catch (BufferUnderflowException | EapMsChapV2ParsingException ex) {
- LOG.e(tag, "Error parsing EAP MSCHAPv2 Challenge Request type data", ex);
- return new DecodeResult<>(new EapError(ex));
- }
- }
-
- /**
- * Decodes and returns an EapMsChapV2SuccessRequest for the specified eapTypeData.
- *
- * @param tag String for logging tag
- * @param eapTypeData byte[] to be decoded as an EapMsChapV2SuccessRequest instance
- * @return DecodeResult wrapping an EapMsChapV2SuccessRequest instance for the given
- * eapTypeData iff the eapTypeData is formatted correctly. Otherwise, the DecodeResult
- * wraps the appropriate EapError.
- */
- public DecodeResult<EapMsChapV2SuccessRequest> decodeSuccessRequest(
- String tag, byte[] eapTypeData) {
- try {
- ByteBuffer buffer = ByteBuffer.wrap(eapTypeData);
- int opCode = Byte.toUnsignedInt(buffer.get());
-
- if (opCode != EAP_MSCHAP_V2_SUCCESS) {
- return new DecodeResult<>(
- new EapError(
- new EapMsChapV2ParsingException(
- "Received type data with invalid opCode: "
- + EAP_OP_CODE_STRING.getOrDefault(
- opCode, "Unknown (" + opCode + ")"))));
- }
-
- return new DecodeResult<>(new EapMsChapV2SuccessRequest(buffer));
- } catch (BufferUnderflowException
- | NumberFormatException
- | EapMsChapV2ParsingException ex) {
- LOG.e(tag, "Error parsing EAP MSCHAPv2 Success Request type data", ex);
- return new DecodeResult<>(new EapError(ex));
- }
- }
-
- /**
- * Decodes and returns an EapMsChapV2FailureRequest for the specified eapTypeData.
- *
- * @param tag String for logging tag
- * @param eapTypeData byte[] to be decoded as an EapMsChapV2FailureRequest instance
- * @return DecodeResult wrapping an EapMsChapV2FailureRequest instance for the given
- * eapTypeData iff the eapTypeData is formatted correctly. Otherwise, the DecodeResult
- * wraps the appropriate EapError.
- */
- public DecodeResult<EapMsChapV2FailureRequest> decodeFailureRequest(
- String tag, byte[] eapTypeData) {
- try {
- ByteBuffer buffer = ByteBuffer.wrap(eapTypeData);
- int opCode = Byte.toUnsignedInt(buffer.get());
-
- if (opCode != EAP_MSCHAP_V2_FAILURE) {
- return new DecodeResult<>(
- new EapError(
- new EapMsChapV2ParsingException(
- "Received type data with invalid opCode: "
- + EAP_OP_CODE_STRING.getOrDefault(
- opCode, "Unknown (" + opCode + ")"))));
- }
-
- return new DecodeResult<>(new EapMsChapV2FailureRequest(buffer));
- } catch (BufferUnderflowException
- | NumberFormatException
- | EapMsChapV2ParsingException ex) {
- LOG.e(tag, "Error parsing EAP MSCHAPv2 Failure Request type data", ex);
- return new DecodeResult<>(new EapError(ex));
- }
- }
-
- /**
- * DecodeResult represents the result from calling a decode method within
- * EapMsChapV2TypeDataDecoder. It will contain either an EapMsChapV2TypeData or an EapError.
- *
- * @param <T> The EapMsChapV2TypeData type that is wrapped in this DecodeResult
- */
- public static class DecodeResult<T extends EapMsChapV2TypeData> {
- public final T eapTypeData;
- public final EapError eapError;
-
- public DecodeResult(T eapTypeData) {
- this.eapTypeData = eapTypeData;
- this.eapError = null;
- }
-
- public DecodeResult(EapError eapError) {
- this.eapTypeData = null;
- this.eapError = eapError;
- }
-
- /**
- * Checks whether this instance represents a successful decode operation.
- *
- * @return true iff this DecodeResult represents a successfully decoded Type Data
- */
- public boolean isSuccessfulDecode() {
- return eapTypeData != null;
- }
- }
- }
-}
diff --git a/src/java/com/android/internal/net/eap/message/simaka/EapAkaAttributeFactory.java b/src/java/com/android/internal/net/eap/message/simaka/EapAkaAttributeFactory.java
deleted file mode 100644
index 5b687818..00000000
--- a/src/java/com/android/internal/net/eap/message/simaka/EapAkaAttributeFactory.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.message.simaka;
-
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_AUTN;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_AUTS;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_BIDDING;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_RAND;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_RES;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.LENGTH_SCALING;
-
-import com.android.internal.net.eap.exceptions.simaka.EapSimAkaInvalidAttributeException;
-import com.android.internal.net.eap.exceptions.simaka.EapSimAkaUnsupportedAttributeException;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtAutn;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtAuts;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtBidding;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtRandAka;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtRes;
-
-import java.nio.ByteBuffer;
-
-/**
- * EapAkaAttributeFactory is used for creating EAP-AKA attributes according to their type.
- *
- * @see <a href="https://tools.ietf.org/html/rfc4187">RFC 4187, Extensible Authentication
- * Protocol for Authentication and Key Agreement (EAP-AKA)</a>
- * @see <a href="https://www.iana.org/assignments/eap-numbers/eap-numbers.xhtml">EAP SIM/AKA
- * Attributes</a>
- */
-public class EapAkaAttributeFactory extends EapSimAkaAttributeFactory {
- private static EapAkaAttributeFactory sInstance = new EapAkaAttributeFactory();
-
- protected EapAkaAttributeFactory() {}
-
- public static EapAkaAttributeFactory getInstance() {
- return sInstance;
- }
-
- /**
- * Decodes a single EapSimAkaAttribute object from the given ByteBuffer.
- *
- * <p>Decoding logic is based on Attribute definitions in RFC 4187#10.
- *
- * @param byteBuffer The ByteBuffer to parse the current attribute from
- * @return The current EapSimAkaAttribute to be parsed, or EapSimAkaUnsupportedAttribute if the
- * given attributeType is skippable and unsupported
- * @throws EapSimAkaInvalidAttributeException when a malformatted attribute is attempted to be
- * decoded
- * @throws EapSimAkaUnsupportedAttributeException when an unsupported, unskippable Attribute is
- * attempted to be decoded
- */
- public EapSimAkaAttribute getAttribute(ByteBuffer byteBuffer)
- throws EapSimAkaInvalidAttributeException, EapSimAkaUnsupportedAttributeException {
- int attributeType = Byte.toUnsignedInt(byteBuffer.get());
-
- // Length is given as a multiple of 4x bytes (RFC 4187#8.1)
- int lengthInBytes = Byte.toUnsignedInt(byteBuffer.get()) * LENGTH_SCALING;
-
- return getAttribute(attributeType, lengthInBytes, byteBuffer);
- }
-
- @Override
- protected EapSimAkaAttribute getAttribute(
- int attributeType, int lengthInBytes, ByteBuffer byteBuffer)
- throws EapSimAkaInvalidAttributeException, EapSimAkaUnsupportedAttributeException {
- switch (attributeType) {
- case EAP_AT_RAND:
- return new AtRandAka(lengthInBytes, byteBuffer);
- case EAP_AT_AUTN:
- return new AtAutn(lengthInBytes, byteBuffer);
- case EAP_AT_RES:
- return new AtRes(lengthInBytes, byteBuffer);
- case EAP_AT_AUTS:
- return new AtAuts(lengthInBytes, byteBuffer);
- case EAP_AT_BIDDING:
- return new AtBidding(lengthInBytes, byteBuffer);
- default:
- return super.getAttribute(attributeType, lengthInBytes, byteBuffer);
- }
- }
-}
diff --git a/src/java/com/android/internal/net/eap/message/simaka/EapAkaPrimeAttributeFactory.java b/src/java/com/android/internal/net/eap/message/simaka/EapAkaPrimeAttributeFactory.java
deleted file mode 100644
index 46f97e53..00000000
--- a/src/java/com/android/internal/net/eap/message/simaka/EapAkaPrimeAttributeFactory.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.message.simaka;
-
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_KDF;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_KDF_INPUT;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.LENGTH_SCALING;
-
-import com.android.internal.net.eap.exceptions.simaka.EapSimAkaInvalidAttributeException;
-import com.android.internal.net.eap.exceptions.simaka.EapSimAkaUnsupportedAttributeException;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtKdf;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtKdfInput;
-
-import java.nio.ByteBuffer;
-
-/**
- * EapAkaPrimeAttributeFactory is used for creating EAP-AKA' attributes according to their type.
- *
- * @see <a href="https://tools.ietf.org/html/rfc5448">RFC 5448, Improved Extensible Authentication
- * Protocol Method for 3rd Generation Authentication and Key Agreement (EAP-AKA')</a>
- * @see <a href="https://www.iana.org/assignments/eap-numbers/eap-numbers.xhtml">EAP SIM/AKA
- * Attributes</a>
- */
-public class EapAkaPrimeAttributeFactory extends EapAkaAttributeFactory {
- private static EapAkaPrimeAttributeFactory sInstance = new EapAkaPrimeAttributeFactory();
-
- private EapAkaPrimeAttributeFactory() {}
-
- public static EapAkaPrimeAttributeFactory getInstance() {
- return sInstance;
- }
-
- /**
- * Decodes a single EapSimAkaAttribute object from the given ByteBuffer.
- *
- * <p>Decoding logic is based on Attribute definitions in RFC 5448#10.
- *
- * @param byteBuffer The ByteBuffer to parse the current attribute from
- * @return The current EapSimAkaAttribute to be parsed, or EapSimAkaUnsupportedAttribute if the
- * given attributeType is skippable and unsupported
- * @throws EapSimAkaInvalidAttributeException when a malformatted attribute is attempted to be
- * decoded
- * @throws EapSimAkaUnsupportedAttributeException when an unsupported, unskippable Attribute is
- * attempted to be decoded
- */
- @Override
- public EapSimAkaAttribute getAttribute(ByteBuffer byteBuffer)
- throws EapSimAkaInvalidAttributeException, EapSimAkaUnsupportedAttributeException {
- int attributeType = Byte.toUnsignedInt(byteBuffer.get());
-
- // Length is given as a multiple of 4x bytes (RFC 4187#8.1)
- int lengthInBytes = Byte.toUnsignedInt(byteBuffer.get()) * LENGTH_SCALING;
-
- switch (attributeType) {
- case EAP_AT_KDF_INPUT:
- return new AtKdfInput(lengthInBytes, byteBuffer);
- case EAP_AT_KDF:
- return new AtKdf(lengthInBytes, byteBuffer);
- default:
- return super.getAttribute(attributeType, lengthInBytes, byteBuffer);
- }
- }
-}
diff --git a/src/java/com/android/internal/net/eap/message/simaka/EapAkaPrimeTypeData.java b/src/java/com/android/internal/net/eap/message/simaka/EapAkaPrimeTypeData.java
deleted file mode 100644
index 23dcd024..00000000
--- a/src/java/com/android/internal/net/eap/message/simaka/EapAkaPrimeTypeData.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.message.simaka;
-
-import android.annotation.NonNull;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.net.eap.message.EapMessage;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtClientErrorCode;
-
-import java.util.LinkedHashMap;
-import java.util.List;
-
-/**
- * EapAkaPrimeTypeData represents the Type Data for an {@link EapMessage} during an EAP-AKA'
- * session.
- */
-public class EapAkaPrimeTypeData extends EapAkaTypeData {
- private static final EapAkaPrimeTypeDataDecoder sTypeDataDecoder =
- new EapAkaPrimeTypeDataDecoder();
-
- @VisibleForTesting
- EapAkaPrimeTypeData(
- int eapSubType, LinkedHashMap<Integer, EapSimAkaAttribute> attributeMap) {
- super(eapSubType, attributeMap);
- }
-
- /**
- * Creates and returns an EapAkaPrimeTypeData instance with the given subtype and attributes.
- *
- * @param eapSubtype the subtype for the EAP-AKA type data
- * @param attributes the List of EapSimAkaAttributes to be included in this type data
- */
- public EapAkaPrimeTypeData(int eapSubtype, List<EapSimAkaAttribute> attributes) {
- super(eapSubtype, attributes);
- }
-
- public static EapAkaPrimeTypeDataDecoder getEapAkaPrimeTypeDataDecoder() {
- return sTypeDataDecoder;
- }
-
- /**
- * EapAkaTypeDataDecoder will be used for decoding {@link EapAkaPrimeTypeData} objects.
- */
- public static class EapAkaPrimeTypeDataDecoder
- extends EapSimAkaTypeDataDecoder<EapAkaTypeData> {
- private static final String TAG = EapAkaPrimeTypeDataDecoder.class.getSimpleName();
- private static final String EAP_METHOD = "EAP-AKA'";
-
- protected EapAkaPrimeTypeDataDecoder() {
- super(
- TAG,
- EAP_METHOD,
- SUPPORTED_SUBTYPES,
- EapAkaPrimeAttributeFactory.getInstance(),
- EAP_AKA_SUBTYPE_STRING);
- }
-
- /**
- * Decodes the given byte-array into a DecodeResult object.
- *
- * <p>Note that <b>only 1 KDF value</b> is allowed. If multiple AT_KDF attributes are
- * supplied, a {@link DecodeResult} wrapping a {@link AtClientErrorCode#UNABLE_TO_PROCESS}
- * will be returned.
- *
- * @param typeData the byte-encoding of the EapAkaPrimeTypeData to be parsed
- * @return a DecodeResult object. If the decoding is successful, this will encapsulate an
- * EapAkaPrimeTypeData instance representing the data stored in typeData. Otherwise, it
- * will contain the relevant AtClientErrorCode for the decoding error.
- */
- public DecodeResult<EapAkaTypeData> decode(@NonNull byte[] typeData) {
- return super.decode(typeData);
- }
-
- @Override
- protected EapAkaPrimeTypeData getInstance(
- int eapSubtype, LinkedHashMap<Integer, EapSimAkaAttribute> attributeMap) {
- return new EapAkaPrimeTypeData(eapSubtype, attributeMap);
- }
- }
-}
diff --git a/src/java/com/android/internal/net/eap/message/simaka/EapAkaTypeData.java b/src/java/com/android/internal/net/eap/message/simaka/EapAkaTypeData.java
deleted file mode 100644
index e3ce817e..00000000
--- a/src/java/com/android/internal/net/eap/message/simaka/EapAkaTypeData.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.message.simaka;
-
-import android.annotation.NonNull;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.net.eap.message.EapMessage;
-
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * EapAkaTypeData represents the Type Data for an {@link EapMessage} during an EAP-AKA session.
- */
-public class EapAkaTypeData extends EapSimAkaTypeData {
- private static final String TAG = EapAkaTypeData.class.getSimpleName();
-
- // EAP-AKA Subtype values defined by IANA
- // https://www.iana.org/assignments/eapsimaka-numbers/eapsimaka-numbers.xhtml
- public static final int EAP_AKA_CHALLENGE = 1;
- public static final int EAP_AKA_AUTHENTICATION_REJECT = 2;
- public static final int EAP_AKA_SYNCHRONIZATION_FAILURE = 4;
- public static final int EAP_AKA_IDENTITY = 5;
- public static final int EAP_AKA_NOTIFICATION = 12;
- public static final int EAP_AKA_REAUTHENTICATION = 13;
- public static final int EAP_AKA_CLIENT_ERROR = 14;
-
- public static final Map<Integer, String> EAP_AKA_SUBTYPE_STRING = new HashMap<>();
- static {
- EAP_AKA_SUBTYPE_STRING.put(EAP_AKA_CHALLENGE, "Challenge");
- EAP_AKA_SUBTYPE_STRING.put(EAP_AKA_AUTHENTICATION_REJECT, "Authentication-Reject");
- EAP_AKA_SUBTYPE_STRING.put(EAP_AKA_SYNCHRONIZATION_FAILURE, "Synchronization-Failure");
- EAP_AKA_SUBTYPE_STRING.put(EAP_AKA_IDENTITY, "Identity");
- EAP_AKA_SUBTYPE_STRING.put(EAP_AKA_NOTIFICATION, "Notification");
- EAP_AKA_SUBTYPE_STRING.put(EAP_AKA_REAUTHENTICATION, "Re-authentication");
- EAP_AKA_SUBTYPE_STRING.put(EAP_AKA_CLIENT_ERROR, "Client-Error");
- }
-
- protected static final Set<Integer> SUPPORTED_SUBTYPES = new HashSet<>();
- static {
- SUPPORTED_SUBTYPES.add(EAP_AKA_CHALLENGE);
- SUPPORTED_SUBTYPES.add(EAP_AKA_AUTHENTICATION_REJECT);
- SUPPORTED_SUBTYPES.add(EAP_AKA_SYNCHRONIZATION_FAILURE);
- SUPPORTED_SUBTYPES.add(EAP_AKA_IDENTITY);
- SUPPORTED_SUBTYPES.add(EAP_AKA_NOTIFICATION);
- SUPPORTED_SUBTYPES.add(EAP_AKA_REAUTHENTICATION);
- SUPPORTED_SUBTYPES.add(EAP_AKA_CLIENT_ERROR);
- }
-
- private static final EapAkaTypeDataDecoder sTypeDataDecoder = new EapAkaTypeDataDecoder();
-
- @VisibleForTesting
- public EapAkaTypeData(int eapSubType, LinkedHashMap<Integer, EapSimAkaAttribute> attributeMap) {
- super(eapSubType, attributeMap);
- }
-
- /**
- * Creates and returns an EapAkaTypeData instance with the given subtype and attributes.
- *
- * @param eapSubtype the subtype for the EAP-AKA type data
- * @param attributes the List of EapSimAkaAttributes to be included in this type data
- */
- public EapAkaTypeData(int eapSubtype, List<EapSimAkaAttribute> attributes) {
- super(eapSubtype, new LinkedHashMap<>());
-
- if (!SUPPORTED_SUBTYPES.contains(eapSubtype)) {
- throw new IllegalArgumentException("Invalid subtype for EAP-AKA: " + eapSubtype);
- }
-
- for (EapSimAkaAttribute attribute : attributes) {
- if (attributeMap.containsKey(attribute.attributeType)) {
- throw new IllegalArgumentException(
- "Duplicate attribute in attributes: " + attribute.attributeType);
- }
- attributeMap.put(attribute.attributeType, attribute);
- }
- }
-
- public static EapAkaTypeDataDecoder getEapAkaTypeDataDecoder() {
- return sTypeDataDecoder;
- }
-
- /**
- * EapAkaTypeDataDecoder will be used for decoding {@link EapAkaTypeData} objects.
- */
- public static class EapAkaTypeDataDecoder extends EapSimAkaTypeDataDecoder<EapAkaTypeData> {
- private static final String TAG = EapAkaTypeDataDecoder.class.getSimpleName();
- private static final String EAP_METHOD = "EAP-AKA";
-
- protected EapAkaTypeDataDecoder() {
- super(
- TAG,
- EAP_METHOD,
- SUPPORTED_SUBTYPES,
- EapAkaAttributeFactory.getInstance(),
- EAP_AKA_SUBTYPE_STRING);
- }
-
- /**
- * Decodes the given byte-array into a DecodeResult object.
- *
- * @param typeData the byte-encoding of the EapAkaTypeData to be parsed
- * @return a DecodeResult object. If the decoding is successful, this will encapsulate an
- * EapAkaTypeData instance representing the data stored in typeData. Otherwise, it
- * will contain the relevant AtClientErrorCode for the decoding error.
- */
- public DecodeResult<EapAkaTypeData> decode(@NonNull byte[] typeData) {
- return super.decode(typeData);
- }
-
- @Override
- protected EapAkaTypeData getInstance(
- int eapSubtype,
- LinkedHashMap<Integer, EapSimAkaAttribute> attributeMap) {
- return new EapAkaTypeData(eapSubtype, attributeMap);
- }
- }
-}
diff --git a/src/java/com/android/internal/net/eap/message/simaka/EapSimAkaAttribute.java b/src/java/com/android/internal/net/eap/message/simaka/EapSimAkaAttribute.java
deleted file mode 100644
index 73d6752d..00000000
--- a/src/java/com/android/internal/net/eap/message/simaka/EapSimAkaAttribute.java
+++ /dev/null
@@ -1,1162 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.message.simaka;
-
-import static com.android.internal.net.eap.EapAuthenticator.LOG;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.net.eap.exceptions.simaka.EapSimAkaInvalidAtPaddingException;
-import com.android.internal.net.eap.exceptions.simaka.EapSimAkaInvalidAttributeException;
-import com.android.internal.net.eap.exceptions.simaka.EapSimInvalidAtRandException;
-
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * EapSimAkaAttribute represents a single EAP SIM/AKA Attribute.
- *
- * @see <a href="https://tools.ietf.org/html/rfc4186">RFC 4186, Extensible Authentication
- * Protocol for Subscriber Identity Modules (EAP-SIM)</a>
- * @see <a href="https://tools.ietf.org/html/rfc4187">RFC 4187, Extensible Authentication
- * Protocol for Authentication and Key Agreement (EAP-AKA)</a>
- * @see <a href="https://www.iana.org/assignments/eap-numbers/eap-numbers.xhtml">EAP SIM/AKA
- * Attributes</a>
- */
-public abstract class EapSimAkaAttribute {
- static final int LENGTH_SCALING = 4;
-
- private static final int MIN_ATTR_LENGTH = 4;
-
- public static final int SKIPPABLE_ATTRIBUTE_RANGE_START = 128;
-
- // EAP non-Skippable Attribute values defined by IANA
- // https://www.iana.org/assignments/eapsimaka-numbers/eapsimaka-numbers.xhtml
- public static final int EAP_AT_RAND = 1;
- public static final int EAP_AT_AUTN = 2;
- public static final int EAP_AT_RES = 3;
- public static final int EAP_AT_AUTS = 4;
- public static final int EAP_AT_PADDING = 6;
- public static final int EAP_AT_NONCE_MT = 7;
- public static final int EAP_AT_PERMANENT_ID_REQ = 10;
- public static final int EAP_AT_MAC = 11;
- public static final int EAP_AT_NOTIFICATION = 12;
- public static final int EAP_AT_ANY_ID_REQ = 13;
- public static final int EAP_AT_IDENTITY = 14;
- public static final int EAP_AT_VERSION_LIST = 15;
- public static final int EAP_AT_SELECTED_VERSION = 16;
- public static final int EAP_AT_FULLAUTH_ID_REQ = 17;
- public static final int EAP_AT_COUNTER = 19;
- public static final int EAP_AT_COUNTER_TOO_SMALL = 20;
- public static final int EAP_AT_NONCE_S = 21;
- public static final int EAP_AT_CLIENT_ERROR_CODE = 22;
- public static final int EAP_AT_KDF_INPUT = 23;
- public static final int EAP_AT_KDF = 24;
-
- // EAP Skippable Attribute values defined by IANA
- // https://www.iana.org/assignments/eapsimaka-numbers/eapsimaka-numbers.xhtml
- public static final int EAP_AT_IV = 129;
- public static final int EAP_AT_ENCR_DATA = 130;
- public static final int EAP_AT_NEXT_PSEUDONYM = 132;
- public static final int EAP_AT_NEXT_REAUTH_ID = 133;
- public static final int EAP_AT_CHECKCODE = 134;
- public static final int EAP_AT_RESULT_IND = 135;
- public static final int EAP_AT_BIDDING = 136;
-
- public static final Map<Integer, String> EAP_ATTRIBUTE_STRING = new HashMap<>();
- static {
- EAP_ATTRIBUTE_STRING.put(EAP_AT_RAND, "AT_RAND");
- EAP_ATTRIBUTE_STRING.put(EAP_AT_AUTN, "AT_AUTN");
- EAP_ATTRIBUTE_STRING.put(EAP_AT_RES, "AT_RES");
- EAP_ATTRIBUTE_STRING.put(EAP_AT_AUTS, "AT_AUTS");
- EAP_ATTRIBUTE_STRING.put(EAP_AT_PADDING, "AT_PADDING");
- EAP_ATTRIBUTE_STRING.put(EAP_AT_NONCE_MT, "AT_NONCE_MT");
- EAP_ATTRIBUTE_STRING.put(EAP_AT_PERMANENT_ID_REQ, "AT_PERMANENT_ID_REQ");
- EAP_ATTRIBUTE_STRING.put(EAP_AT_MAC, "AT_MAC");
- EAP_ATTRIBUTE_STRING.put(EAP_AT_NOTIFICATION, "AT_NOTIFICATION");
- EAP_ATTRIBUTE_STRING.put(EAP_AT_ANY_ID_REQ, "AT_ANY_ID_REQ");
- EAP_ATTRIBUTE_STRING.put(EAP_AT_IDENTITY, "AT_IDENTITY");
- EAP_ATTRIBUTE_STRING.put(EAP_AT_VERSION_LIST, "AT_VERSION_LIST");
- EAP_ATTRIBUTE_STRING.put(EAP_AT_SELECTED_VERSION, "AT_SELECTED_VERSION");
- EAP_ATTRIBUTE_STRING.put(EAP_AT_FULLAUTH_ID_REQ, "AT_FULLAUTH_ID_REQ");
- EAP_ATTRIBUTE_STRING.put(EAP_AT_COUNTER, "AT_COUNTER");
- EAP_ATTRIBUTE_STRING.put(EAP_AT_COUNTER_TOO_SMALL, "AT_COUNTER_TOO_SMALL");
- EAP_ATTRIBUTE_STRING.put(EAP_AT_NONCE_S, "AT_NONCE_S");
- EAP_ATTRIBUTE_STRING.put(EAP_AT_CLIENT_ERROR_CODE, "AT_CLIENT_ERROR_CODE");
- EAP_ATTRIBUTE_STRING.put(EAP_AT_KDF_INPUT, "AT_KDF_INPUT");
- EAP_ATTRIBUTE_STRING.put(EAP_AT_KDF, "AT_KDF");
-
- EAP_ATTRIBUTE_STRING.put(EAP_AT_IV, "AT_IV");
- EAP_ATTRIBUTE_STRING.put(EAP_AT_ENCR_DATA, "AT_ENCR_DATA");
- EAP_ATTRIBUTE_STRING.put(EAP_AT_NEXT_PSEUDONYM, "AT_NEXT_PSEUDONYM");
- EAP_ATTRIBUTE_STRING.put(EAP_AT_NEXT_REAUTH_ID, "AT_NEXT_REAUTH_ID");
- EAP_ATTRIBUTE_STRING.put(EAP_AT_CHECKCODE, "AT_CHECKCODE");
- EAP_ATTRIBUTE_STRING.put(EAP_AT_RESULT_IND, "AT_RESULT_IND");
- EAP_ATTRIBUTE_STRING.put(EAP_AT_BIDDING, "AT_BIDDING");
- }
-
- public final int attributeType;
- public final int lengthInBytes;
-
- protected EapSimAkaAttribute(int attributeType, int lengthInBytes)
- throws EapSimAkaInvalidAttributeException {
- this.attributeType = attributeType;
- this.lengthInBytes = lengthInBytes;
-
- if (lengthInBytes % LENGTH_SCALING != 0) {
- throw new EapSimAkaInvalidAttributeException("Attribute length must be multiple of 4");
- }
- }
-
- /**
- * Encodes this EapSimAkaAttribute into the given ByteBuffer
- *
- * @param byteBuffer the ByteBuffer that this instance will be written to
- */
- public abstract void encode(ByteBuffer byteBuffer);
-
- protected void encodeAttributeHeader(ByteBuffer byteBuffer) {
- byteBuffer.put((byte) attributeType);
- byteBuffer.put((byte) (lengthInBytes / LENGTH_SCALING));
- }
-
- void consumePadding(int bytesUsed, ByteBuffer byteBuffer) {
- int paddingRemaining = lengthInBytes - bytesUsed;
- byteBuffer.get(new byte[paddingRemaining]);
- }
-
- void addPadding(int bytesUsed, ByteBuffer byteBuffer) {
- int paddingNeeded = lengthInBytes - bytesUsed;
- byteBuffer.put(new byte[paddingNeeded]);
- }
-
- /**
- * EapSimAkaUnsupportedAttribute represents any unsupported, skippable EAP-SIM attribute.
- */
- public static class EapSimAkaUnsupportedAttribute extends EapSimAkaAttribute {
- // Attribute Type (1B) + Attribute Length (1B) = 2B Header
- private static final int HEADER_BYTES = 2;
-
- public final byte[] data;
-
- public EapSimAkaUnsupportedAttribute(
- int attributeType,
- int lengthInBytes,
- ByteBuffer byteBuffer) throws EapSimAkaInvalidAttributeException {
- super(attributeType, lengthInBytes);
-
- // Attribute not supported, but remaining attribute still needs to be saved
- int remainingBytes = lengthInBytes - HEADER_BYTES;
- data = new byte[remainingBytes];
- byteBuffer.get(data);
- }
-
- @VisibleForTesting
- public EapSimAkaUnsupportedAttribute(int attributeType, int lengthInBytes, byte[] data)
- throws EapSimAkaInvalidAttributeException {
- super(attributeType, lengthInBytes);
- this.data = data;
- }
-
- @Override
- public void encode(ByteBuffer byteBuffer) {
- encodeAttributeHeader(byteBuffer);
- byteBuffer.put(data);
- }
- }
-
- /**
- * AtVersionList represents the AT_VERSION_LIST attribute defined in RFC 4186#10.2
- */
- public static class AtVersionList extends EapSimAkaAttribute {
- private static final int BYTES_PER_VERSION = 2;
-
- public final List<Integer> versions = new ArrayList<>();
-
- public AtVersionList(int lengthInBytes, ByteBuffer byteBuffer)
- throws EapSimAkaInvalidAttributeException {
- super(EAP_AT_VERSION_LIST, lengthInBytes);
-
- // number of bytes used to represent list (RFC 4186 Section 10.2)
- int bytesInList = Short.toUnsignedInt(byteBuffer.getShort());
- if (bytesInList % BYTES_PER_VERSION != 0) {
- throw new EapSimAkaInvalidAttributeException(
- "Actual Version List Length must be multiple of 2");
- }
-
- int numVersions = bytesInList / BYTES_PER_VERSION;
- for (int i = 0; i < numVersions; i++) {
- versions.add(Short.toUnsignedInt(byteBuffer.getShort()));
- }
-
- int bytesUsed = MIN_ATTR_LENGTH + (BYTES_PER_VERSION * versions.size());
- consumePadding(bytesUsed, byteBuffer);
- }
-
- @VisibleForTesting
- public AtVersionList(int lengthInBytes, int... versions)
- throws EapSimAkaInvalidAttributeException {
- super(EAP_AT_VERSION_LIST, lengthInBytes);
- for (int version : versions) {
- this.versions.add(version);
- }
- }
-
- @Override
- public void encode(ByteBuffer byteBuffer) {
- encodeAttributeHeader(byteBuffer);
-
- byteBuffer.putShort((short) (versions.size() * BYTES_PER_VERSION));
- for (int i : versions) {
- byteBuffer.putShort((short) i);
- }
-
- int bytesUsed = MIN_ATTR_LENGTH + (BYTES_PER_VERSION * versions.size());
- addPadding(bytesUsed, byteBuffer);
- }
- }
-
- /**
- * AtSelectedVersion represents the AT_SELECTED_VERSION attribute defined in RFC 4186#10.3
- */
- public static class AtSelectedVersion extends EapSimAkaAttribute {
- private static final String TAG = AtSelectedVersion.class.getSimpleName();
- private static final int LENGTH = LENGTH_SCALING;
-
- public static final int SUPPORTED_VERSION = 1;
-
- public final int selectedVersion;
-
- public AtSelectedVersion(int lengthInBytes, int selectedVersion)
- throws EapSimAkaInvalidAttributeException {
- super(EAP_AT_SELECTED_VERSION, LENGTH);
- this.selectedVersion = selectedVersion;
-
- if (lengthInBytes != LENGTH) {
- throw new EapSimAkaInvalidAttributeException("Invalid Length specified");
- }
- }
-
- @VisibleForTesting
- public AtSelectedVersion(int selectedVersion) throws EapSimAkaInvalidAttributeException {
- super(EAP_AT_SELECTED_VERSION, LENGTH);
- this.selectedVersion = selectedVersion;
- }
-
- @Override
- public void encode(ByteBuffer byteBuffer) {
- encodeAttributeHeader(byteBuffer);
- byteBuffer.putShort((short) selectedVersion);
- }
-
- /**
- * Constructs and returns an AtSelectedVersion for the only supported version of EAP-SIM
- *
- * @return an AtSelectedVersion for the supported version (1) of EAP-SIM
- */
- public static AtSelectedVersion getSelectedVersion() {
- try {
- return new AtSelectedVersion(LENGTH, SUPPORTED_VERSION);
- } catch (EapSimAkaInvalidAttributeException ex) {
- // this should never happen
- LOG.wtf(TAG,
- "Error thrown while creating AtSelectedVersion with correct length", ex);
- throw new AssertionError("Impossible exception encountered", ex);
- }
- }
- }
-
- /**
- * AtNonceMt represents the AT_NONCE_MT attribute defined in RFC 4186#10.4
- */
- public static class AtNonceMt extends EapSimAkaAttribute {
- private static final int LENGTH = 5 * LENGTH_SCALING;
- private static final int RESERVED_BYTES = 2;
-
- public static final int NONCE_MT_LENGTH = 16;
-
- public final byte[] nonceMt = new byte[NONCE_MT_LENGTH];
-
- public AtNonceMt(int lengthInBytes, ByteBuffer byteBuffer)
- throws EapSimAkaInvalidAttributeException {
- super(EAP_AT_NONCE_MT, LENGTH);
- if (lengthInBytes != LENGTH) {
- throw new EapSimAkaInvalidAttributeException("Invalid Length specified");
- }
-
- // next two bytes are reserved (RFC 4186 Section 10.4)
- byteBuffer.get(new byte[RESERVED_BYTES]);
- byteBuffer.get(nonceMt);
- }
-
- @VisibleForTesting
- public AtNonceMt(byte[] nonceMt) throws EapSimAkaInvalidAttributeException {
- super(EAP_AT_NONCE_MT, LENGTH);
-
- if (nonceMt.length != NONCE_MT_LENGTH) {
- throw new EapSimAkaInvalidAttributeException("NonceMt length must be 16B");
- }
- System.arraycopy(nonceMt, 0, this.nonceMt, 0, NONCE_MT_LENGTH);
- }
-
- @Override
- public void encode(ByteBuffer byteBuffer) {
- encodeAttributeHeader(byteBuffer);
- byteBuffer.put(new byte[RESERVED_BYTES]);
- byteBuffer.put(nonceMt);
- }
- }
-
- private abstract static class AtIdReq extends EapSimAkaAttribute {
- private static final int ATTR_LENGTH = LENGTH_SCALING;
- private static final int RESERVED_BYTES = 2;
-
- protected AtIdReq(int lengthInBytes, int attributeType, ByteBuffer byteBuffer)
- throws EapSimAkaInvalidAttributeException {
- super(attributeType, ATTR_LENGTH);
-
- if (lengthInBytes != ATTR_LENGTH) {
- throw new EapSimAkaInvalidAttributeException("Invalid Length specified");
- }
-
- // next two bytes are reserved (RFC 4186 Section 10.5-10.7)
- byteBuffer.get(new byte[RESERVED_BYTES]);
- }
-
- @VisibleForTesting
- protected AtIdReq(int attributeType) throws EapSimAkaInvalidAttributeException {
- super(attributeType, ATTR_LENGTH);
- }
-
- @Override
- public void encode(ByteBuffer byteBuffer) {
- encodeAttributeHeader(byteBuffer);
- byteBuffer.put(new byte[RESERVED_BYTES]);
- }
- }
-
- /**
- * AtPermanentIdReq represents the AT_PERMANENT_ID_REQ attribute defined in RFC 4186#10.5 and
- * RFC 4187#10.2
- */
- public static class AtPermanentIdReq extends AtIdReq {
- public AtPermanentIdReq(int lengthInBytes, ByteBuffer byteBuffer)
- throws EapSimAkaInvalidAttributeException {
- super(lengthInBytes, EAP_AT_PERMANENT_ID_REQ, byteBuffer);
- }
-
- @VisibleForTesting
- public AtPermanentIdReq() throws EapSimAkaInvalidAttributeException {
- super(EAP_AT_PERMANENT_ID_REQ);
- }
- }
-
- /**
- * AtAnyIdReq represents the AT_ANY_ID_REQ attribute defined in RFC 4186#10.6 and RFC 4187#10.3
- */
- public static class AtAnyIdReq extends AtIdReq {
- public AtAnyIdReq(int lengthInBytes, ByteBuffer byteBuffer)
- throws EapSimAkaInvalidAttributeException {
- super(lengthInBytes, EAP_AT_ANY_ID_REQ, byteBuffer);
- }
-
- @VisibleForTesting
- public AtAnyIdReq() throws EapSimAkaInvalidAttributeException {
- super(EAP_AT_ANY_ID_REQ);
- }
- }
-
- /**
- * AtFullauthIdReq represents the AT_FULLAUTH_ID_REQ attribute defined in RFC 4186#10.7 and RFC
- * 4187#10.4
- */
- public static class AtFullauthIdReq extends AtIdReq {
- public AtFullauthIdReq(int lengthInBytes, ByteBuffer byteBuffer)
- throws EapSimAkaInvalidAttributeException {
- super(lengthInBytes, EAP_AT_FULLAUTH_ID_REQ, byteBuffer);
- }
-
- @VisibleForTesting
- public AtFullauthIdReq() throws EapSimAkaInvalidAttributeException {
- super(EAP_AT_FULLAUTH_ID_REQ);
- }
- }
-
- /**
- * AtIdentity represents the AT_IDENTITY attribute defined in RFC 4186#10.8 and RFC 4187#10.5
- */
- public static class AtIdentity extends EapSimAkaAttribute {
- public final byte[] identity;
-
- public AtIdentity(int lengthInBytes, ByteBuffer byteBuffer)
- throws EapSimAkaInvalidAttributeException {
- super(EAP_AT_IDENTITY, lengthInBytes);
-
- int identityLength = Short.toUnsignedInt(byteBuffer.getShort());
- identity = new byte[identityLength];
- byteBuffer.get(identity);
-
- int bytesUsed = MIN_ATTR_LENGTH + identityLength;
- consumePadding(bytesUsed, byteBuffer);
- }
-
- @VisibleForTesting
- public AtIdentity(int lengthInBytes, byte[] identity)
- throws EapSimAkaInvalidAttributeException {
- super(EAP_AT_IDENTITY, lengthInBytes);
- this.identity = identity;
- }
-
- @Override
- public void encode(ByteBuffer byteBuffer) {
- encodeAttributeHeader(byteBuffer);
- byteBuffer.putShort((short) identity.length);
- byteBuffer.put(identity);
-
- int bytesUsed = MIN_ATTR_LENGTH + identity.length;
- addPadding(bytesUsed, byteBuffer);
- }
-
- /**
- * Creates and returns an AtIdentity instance for the given identity.
- *
- * @param identity byte-array representing the identity for the AtIdentity
- * @return AtIdentity instance for the given identity byte-array
- */
- public static AtIdentity getAtIdentity(byte[] identity)
- throws EapSimAkaInvalidAttributeException {
- int lengthInBytes = MIN_ATTR_LENGTH + identity.length;
- if (lengthInBytes % LENGTH_SCALING != 0) {
- lengthInBytes += LENGTH_SCALING - (lengthInBytes % LENGTH_SCALING);
- }
-
- return new AtIdentity(lengthInBytes, identity);
- }
- }
-
- /**
- * AtRandSim represents the AT_RAND attribute for EAP-SIM defined in RFC 4186#10.9
- */
- public static class AtRandSim extends EapSimAkaAttribute {
- private static final int RAND_LENGTH = 16;
- private static final int RESERVED_BYTES = 2;
- private static final int MIN_RANDS = 2;
- private static final int MAX_RANDS = 3;
-
- public final List<byte[]> rands = new ArrayList<>(MAX_RANDS);
-
- public AtRandSim(int lengthInBytes, ByteBuffer byteBuffer)
- throws EapSimAkaInvalidAttributeException {
- super(EAP_AT_RAND, lengthInBytes);
-
- // next two bytes are reserved (RFC 4186 Section 10.9)
- byteBuffer.get(new byte[RESERVED_BYTES]);
-
- int numRands = (lengthInBytes - MIN_ATTR_LENGTH) / RAND_LENGTH;
- if (!isValidNumRands(numRands)) {
- throw new EapSimInvalidAtRandException("Unexpected number of rands: " + numRands);
- }
-
- for (int i = 0; i < numRands; i++) {
- byte[] rand = new byte[RAND_LENGTH];
- byteBuffer.get(rand);
-
- // check for rand being unique (RFC 4186 Section 10.9)
- for (int j = 0; j < i; j++) {
- byte[] otherRand = rands.get(j);
- if (Arrays.equals(rand, otherRand)) {
- throw new EapSimAkaInvalidAttributeException("Received identical RANDs");
- }
- }
- rands.add(rand);
- }
- }
-
- @VisibleForTesting
- public AtRandSim(int lengthInBytes, byte[]... rands)
- throws EapSimAkaInvalidAttributeException {
- super(EAP_AT_RAND, lengthInBytes);
-
- if (!isValidNumRands(rands.length)) {
- throw new EapSimInvalidAtRandException("Unexpected number of rands: "
- + rands.length);
- }
- for (byte[] rand : rands) {
- this.rands.add(rand);
- }
- }
-
- private boolean isValidNumRands(int numRands) {
- // numRands is valid iff 2 <= numRands <= 3
- return MIN_RANDS <= numRands && numRands <= MAX_RANDS;
- }
-
- @Override
- public void encode(ByteBuffer byteBuffer) {
- encodeAttributeHeader(byteBuffer);
- byteBuffer.put(new byte[RESERVED_BYTES]);
-
- for (byte[] rand : rands) {
- byteBuffer.put(rand);
- }
- }
- }
-
- /**
- * AtRandAka represents the AT_RAND attribute for EAP-AKA defined in RFC 4187#10.6
- */
- public static class AtRandAka extends EapSimAkaAttribute {
- private static final int ATTR_LENGTH = 5 * LENGTH_SCALING;
- private static final int RAND_LENGTH = 16;
- private static final int RESERVED_BYTES = 2;
-
- public final byte[] rand = new byte[RAND_LENGTH];
-
- public AtRandAka(int lengthInBytes, ByteBuffer byteBuffer)
- throws EapSimAkaInvalidAttributeException {
- super(EAP_AT_RAND, lengthInBytes);
-
- if (lengthInBytes != ATTR_LENGTH) {
- throw new EapSimAkaInvalidAttributeException("Length must be 20B");
- }
-
- // next two bytes are reserved (RFC 4187#10.6)
- byteBuffer.get(new byte[RESERVED_BYTES]);
-
- byteBuffer.get(rand);
- }
-
- @VisibleForTesting
- public AtRandAka(byte[] rand)
- throws EapSimAkaInvalidAttributeException {
- super(EAP_AT_RAND, ATTR_LENGTH);
-
- if (rand.length != RAND_LENGTH) {
- throw new EapSimAkaInvalidAttributeException("Rand must be 16B");
- }
-
- System.arraycopy(rand, 0, this.rand, 0, RAND_LENGTH);
- }
-
- @Override
- public void encode(ByteBuffer byteBuffer) {
- encodeAttributeHeader(byteBuffer);
- byteBuffer.put(new byte[RESERVED_BYTES]);
- byteBuffer.put(rand);
- }
- }
-
- /**
- * AtPadding represents the AT_PADDING attribute defined in RFC 4186#10.12 and RFC 4187#10.12
- */
- public static class AtPadding extends EapSimAkaAttribute {
- private static final int ATTR_HEADER = 2;
-
- public AtPadding(int lengthInBytes, ByteBuffer byteBuffer)
- throws EapSimAkaInvalidAttributeException {
- super(EAP_AT_PADDING, lengthInBytes);
-
- int remainingBytes = lengthInBytes - ATTR_HEADER;
- for (int i = 0; i < remainingBytes; i++) {
- // Padding must be checked to all be 0x00 bytes (RFC 4186 Section 10.12)
- if (byteBuffer.get() != 0) {
- throw new EapSimAkaInvalidAtPaddingException("Padding bytes must all be 0x00");
- }
- }
- }
-
- @VisibleForTesting
- public AtPadding(int lengthInBytes) throws EapSimAkaInvalidAttributeException {
- super(EAP_AT_PADDING, lengthInBytes);
- }
-
- @Override
- public void encode(ByteBuffer byteBuffer) {
- encodeAttributeHeader(byteBuffer);
-
- addPadding(ATTR_HEADER, byteBuffer);
- }
- }
-
- /**
- * AtMac represents the AT_MAC attribute defined in RFC 4186#10.14 and RFC 4187#10.15
- */
- public static class AtMac extends EapSimAkaAttribute {
- private static final int ATTR_LENGTH = 5 * LENGTH_SCALING;
- private static final int RESERVED_BYTES = 2;
-
- public static final int MAC_LENGTH = 4 * LENGTH_SCALING;
-
- public final byte[] mac;
-
- public AtMac(int lengthInBytes, ByteBuffer byteBuffer)
- throws EapSimAkaInvalidAttributeException {
- super(EAP_AT_MAC, lengthInBytes);
-
- if (lengthInBytes != ATTR_LENGTH) {
- throw new EapSimAkaInvalidAttributeException("Invalid Length specified");
- }
-
- // next two bytes are reserved (RFC 4186 Section 10.14)
- byteBuffer.get(new byte[RESERVED_BYTES]);
-
- mac = new byte[MAC_LENGTH];
- byteBuffer.get(mac);
- }
-
- // Used for calculating MACs. Per RFC 4186 Section 10.14, the MAC should be calculated over
- // the entire packet, with the value field of the MAC attribute set to zero.
- public AtMac() throws EapSimAkaInvalidAttributeException {
- super(EAP_AT_MAC, ATTR_LENGTH);
- mac = new byte[MAC_LENGTH];
- }
-
- public AtMac(byte[] mac) throws EapSimAkaInvalidAttributeException {
- super(EAP_AT_MAC, ATTR_LENGTH);
- this.mac = mac;
-
- if (mac.length != MAC_LENGTH) {
- throw new EapSimAkaInvalidAttributeException("Invalid length for MAC");
- }
- }
-
- @Override
- public void encode(ByteBuffer byteBuffer) {
- encodeAttributeHeader(byteBuffer);
- byteBuffer.put(new byte[RESERVED_BYTES]);
- byteBuffer.put(mac);
- }
- }
-
- /**
- * AtCounter represents the AT_COUNTER attribute defined in RFC 4186#10.15 and RFC 4187#10.16
- */
- public static class AtCounter extends EapSimAkaAttribute {
- private static final int ATTR_LENGTH = LENGTH_SCALING;
-
- public final int counter;
-
- public AtCounter(int lengthInBytes, ByteBuffer byteBuffer)
- throws EapSimAkaInvalidAttributeException {
- super(EAP_AT_COUNTER, lengthInBytes);
-
- if (lengthInBytes != ATTR_LENGTH) {
- throw new EapSimAkaInvalidAttributeException("Invalid Length specified");
- }
-
- this.counter = Short.toUnsignedInt(byteBuffer.getShort());
- }
-
- @VisibleForTesting
- public AtCounter(int counter) throws EapSimAkaInvalidAttributeException {
- super(EAP_AT_COUNTER, ATTR_LENGTH);
- this.counter = counter;
- }
-
- @Override
- public void encode(ByteBuffer byteBuffer) {
- encodeAttributeHeader(byteBuffer);
- byteBuffer.putShort((short) counter);
- }
- }
-
-
- /**
- * AtCounterTooSmall represents the AT_COUNTER_TOO_SMALL attribute defined in RFC 4186#10.16 and
- * RFC 4187#10.17
- */
- public static class AtCounterTooSmall extends EapSimAkaAttribute {
- private static final int ATTR_LENGTH = LENGTH_SCALING;
- private static final int ATTR_HEADER = 2;
-
- public AtCounterTooSmall(int lengthInBytes, ByteBuffer byteBuffer)
- throws EapSimAkaInvalidAttributeException {
- super(EAP_AT_COUNTER_TOO_SMALL, lengthInBytes);
-
- if (lengthInBytes != ATTR_LENGTH) {
- throw new EapSimAkaInvalidAttributeException("Invalid Length specified");
- }
- consumePadding(ATTR_HEADER, byteBuffer);
- }
-
- public AtCounterTooSmall() throws EapSimAkaInvalidAttributeException {
- super(EAP_AT_COUNTER_TOO_SMALL, ATTR_LENGTH);
- }
-
- @Override
- public void encode(ByteBuffer byteBuffer) {
- encodeAttributeHeader(byteBuffer);
- addPadding(ATTR_HEADER, byteBuffer);
- }
- }
-
- /**
- * AtNonceS represents the AT_NONCE_S attribute defined in RFC 4186#10.17 and RFC 4187#10.18
- *
- * <p>This Nonce is generated by the server and used for fast re-authentication only.
- */
- public static class AtNonceS extends EapSimAkaAttribute {
- private static final int ATTR_LENGTH = 5 * LENGTH_SCALING;
- private static final int NONCE_S_LENGTH = 4 * LENGTH_SCALING;
- private static final int RESERVED_BYTES = 2;
-
- public final byte[] nonceS = new byte[NONCE_S_LENGTH];
-
- public AtNonceS(int lengthInBytes, ByteBuffer byteBuffer)
- throws EapSimAkaInvalidAttributeException {
- super(EAP_AT_NONCE_S, lengthInBytes);
-
- if (lengthInBytes != ATTR_LENGTH) {
- throw new EapSimAkaInvalidAttributeException("Invalid Length specified");
- }
-
- // next two bytes are reserved (RFC 4186 Section 10.17)
- byteBuffer.get(new byte[RESERVED_BYTES]);
- byteBuffer.get(nonceS);
- }
-
- @VisibleForTesting
- public AtNonceS(byte[] nonceS) throws EapSimAkaInvalidAttributeException {
- super(EAP_AT_NONCE_S, ATTR_LENGTH);
-
- if (nonceS.length != NONCE_S_LENGTH) {
- throw new EapSimAkaInvalidAttributeException("NonceS length must be 16B");
- }
-
- System.arraycopy(nonceS, 0, this.nonceS, 0, NONCE_S_LENGTH);
- }
-
- @Override
- public void encode(ByteBuffer byteBuffer) {
- encodeAttributeHeader(byteBuffer);
- byteBuffer.put(new byte[RESERVED_BYTES]);
- byteBuffer.put(nonceS);
- }
- }
-
- /**
- * AtNotification represents the AT_NOTIFICATION attribute defined in RFC 4186#10.18 and RFC
- * 4187#10.19
- */
- public static class AtNotification extends EapSimAkaAttribute {
- private static final int ATTR_LENGTH = 4;
- private static final int SUCCESS_MASK = 0x8000;
- private static final int PRE_SUCCESSFUL_CHALLENGE_MASK = 0x4000;
-
- // Notification codes defined in RFC 4186 Section 10.18
- public static final int GENERAL_FAILURE_POST_CHALLENGE = 0;
- public static final int GENERAL_FAILURE_PRE_CHALLENGE = 16384; // 0x4000
- public static final int SUCCESS = 32768; // 0x8000
- public static final int DENIED_ACCESS_POST_CHALLENGE = 1026;
- public static final int USER_NOT_SUBSCRIBED_POST_CHALLENGE = 1031;
-
- private static final Map<Integer, String> CODE_DEFS = loadCodeDefs();
-
- public final boolean isSuccessCode;
- public final boolean isPreSuccessfulChallenge;
- public final int notificationCode;
-
- public AtNotification(int lengthInBytes, ByteBuffer byteBuffer)
- throws EapSimAkaInvalidAttributeException {
- super(EAP_AT_NOTIFICATION, lengthInBytes);
-
- if (lengthInBytes != ATTR_LENGTH) {
- throw new EapSimAkaInvalidAttributeException("Invalid Length specified");
- }
-
- notificationCode = Short.toUnsignedInt(byteBuffer.getShort());
-
- // If Success bit == 0, failure is implied
- isSuccessCode = (notificationCode & SUCCESS_MASK) != 0;
-
- // if Phase bit == 0, notification code can only be used after a successful
- isPreSuccessfulChallenge = (notificationCode & PRE_SUCCESSFUL_CHALLENGE_MASK) != 0;
-
- if (isSuccessCode && isPreSuccessfulChallenge) {
- throw new EapSimAkaInvalidAttributeException("Invalid state specified");
- }
- }
-
- @VisibleForTesting
- public AtNotification(int notificationCode) throws EapSimAkaInvalidAttributeException {
- super(EAP_AT_NOTIFICATION, ATTR_LENGTH);
- this.notificationCode = notificationCode;
-
- // If Success bit == 0, failure is implied
- isSuccessCode = (notificationCode & SUCCESS_MASK) != 0;
-
- // if Phase bit == 0, notification code can only be used after a successful challenge
- isPreSuccessfulChallenge = (notificationCode & PRE_SUCCESSFUL_CHALLENGE_MASK) != 0;
-
- if (isSuccessCode && isPreSuccessfulChallenge) {
- throw new EapSimAkaInvalidAttributeException("Invalid state specified");
- }
- }
-
- @Override
- public void encode(ByteBuffer byteBuffer) {
- encodeAttributeHeader(byteBuffer);
- byteBuffer.putShort((short) notificationCode);
- }
-
- @Override
- public String toString() {
- String description = CODE_DEFS.getOrDefault(notificationCode, "Code not recognized");
- return "{Notification Code=" + notificationCode + ", descr=" + description + "}";
- }
-
- private static Map<Integer, String> loadCodeDefs() {
- Map<Integer, String> defs = new HashMap<>();
- defs.put(GENERAL_FAILURE_POST_CHALLENGE,
- "General failure after authentication. (Implies failure, used after successful"
- + " authentication.)");
- defs.put(GENERAL_FAILURE_PRE_CHALLENGE,
- "General failure. (Implies failure, used before authentication.)");
- defs.put(SUCCESS,
- "Success. User has been successfully authenticated. (Does not imply failure,"
- + " used after successful authentication).");
- defs.put(DENIED_ACCESS_POST_CHALLENGE,
- "User has been temporarily denied access to the requested service. (Implies"
- + " failure, used after successful authentication.)");
- defs.put(USER_NOT_SUBSCRIBED_POST_CHALLENGE,
- "User has not subscribed to the requested service. (Implies failure, used"
- + " after successful authentication.)");
- return defs;
- }
- }
-
- /**
- * AtClientErrorCode represents the AT_CLIENT_ERROR_CODE attribute defined in RFC 4186#10.19 and
- * RFC 4187#10.20
- */
- public static class AtClientErrorCode extends EapSimAkaAttribute {
- private static final String TAG = AtClientErrorCode.class.getSimpleName();
- private static final int ATTR_LENGTH = 4;
-
- // Error codes defined in RFC 4186 Section 10.19
- public static final AtClientErrorCode UNABLE_TO_PROCESS = getClientErrorCode(0);
- public static final AtClientErrorCode UNSUPPORTED_VERSION = getClientErrorCode(1);
- public static final AtClientErrorCode INSUFFICIENT_CHALLENGES = getClientErrorCode(2);
- public static final AtClientErrorCode STALE_RANDS = getClientErrorCode(3);
-
- public final int errorCode;
-
- public AtClientErrorCode(int lengthInBytes, int errorCode)
- throws EapSimAkaInvalidAttributeException {
- super(EAP_AT_CLIENT_ERROR_CODE, lengthInBytes);
-
- if (lengthInBytes != ATTR_LENGTH) {
- throw new EapSimAkaInvalidAttributeException("Invalid Length specified");
- }
-
- this.errorCode = errorCode;
- }
-
- @Override
- public void encode(ByteBuffer byteBuffer) {
- encodeAttributeHeader(byteBuffer);
- byteBuffer.putShort((short) errorCode);
- }
-
- private static AtClientErrorCode getClientErrorCode(int errorCode) {
- try {
- return new AtClientErrorCode(ATTR_LENGTH, errorCode);
- } catch (EapSimAkaInvalidAttributeException exception) {
- LOG.wtf(TAG, "Exception thrown while making AtClientErrorCodeConstants");
- return null;
- }
- }
- }
-
- /**
- * AtAutn represents the AT_AUTN attribute defined in RFC 4187#10.7
- */
- public static class AtAutn extends EapSimAkaAttribute {
- private static final int ATTR_LENGTH = 5 * LENGTH_SCALING;
- private static final int AUTN_LENGTH = 16;
- private static final int RESERVED_BYTES = 2;
-
- public final byte[] autn = new byte[AUTN_LENGTH];
-
- public AtAutn(int lengthInBytes, ByteBuffer byteBuffer)
- throws EapSimAkaInvalidAttributeException {
- super(EAP_AT_AUTN, lengthInBytes);
-
- if (lengthInBytes != ATTR_LENGTH) {
- throw new EapSimAkaInvalidAttributeException("Length must be 20B");
- }
-
- // next two bytes are reserved (RFC 4187#10.7)
- byteBuffer.get(new byte[RESERVED_BYTES]);
-
- byteBuffer.get(autn);
- }
-
- @VisibleForTesting
- public AtAutn(byte[] autn) throws EapSimAkaInvalidAttributeException {
- super(EAP_AT_AUTN, ATTR_LENGTH);
-
- if (autn.length != AUTN_LENGTH) {
- throw new EapSimAkaInvalidAttributeException("Autn must be 16B");
- }
-
- System.arraycopy(autn, 0, this.autn, 0, AUTN_LENGTH);
- }
-
- @Override
- public void encode(ByteBuffer byteBuffer) {
- encodeAttributeHeader(byteBuffer);
- byteBuffer.put(new byte[RESERVED_BYTES]);
- byteBuffer.put(autn);
- }
- }
-
- /**
- * AtRes respresents the AT_RES attribute defined in RFC 4187#10.8
- */
- public static class AtRes extends EapSimAkaAttribute {
- private static final int BITS_PER_BYTE = 8;
- private static final int MIN_RES_LEN_BYTES = 4;
- private static final int MAX_RES_LEN_BYTES = 16;
-
- public final byte[] res;
-
- public AtRes(int lengthInBytes, ByteBuffer byteBuffer)
- throws EapSimAkaInvalidAttributeException {
- super(EAP_AT_RES, lengthInBytes);
-
- // RES length is in bits (RFC 4187#10.8).
- // RES length should be a multiple of 8 bits (TS 133 105#5.1.7.8)
- int resLength = Short.toUnsignedInt(byteBuffer.getShort());
- if (resLength % BITS_PER_BYTE != 0) {
- throw new EapSimAkaInvalidAttributeException("RES length must be multiple of 8");
- }
- int resLengthBytes = resLength / BITS_PER_BYTE;
- if (resLengthBytes < MIN_RES_LEN_BYTES || resLengthBytes > MAX_RES_LEN_BYTES) {
- throw new EapSimAkaInvalidAttributeException(
- "RES length must be: 4B <= len <= 16B");
- }
-
- res = new byte[resLengthBytes];
- byteBuffer.get(res);
-
- int bytesUsed = MIN_ATTR_LENGTH + resLengthBytes;
- consumePadding(bytesUsed, byteBuffer);
- }
-
- @VisibleForTesting
- public AtRes(int lengthInBytes, byte[] res) throws EapSimAkaInvalidAttributeException {
- super(EAP_AT_RES, lengthInBytes);
-
- if (res.length < MIN_RES_LEN_BYTES || res.length > MAX_RES_LEN_BYTES) {
- throw new EapSimAkaInvalidAttributeException(
- "RES length must be: 4B <= len <= 16B");
- }
-
- this.res = res;
- }
-
- @Override
- public void encode(ByteBuffer byteBuffer) {
- encodeAttributeHeader(byteBuffer);
-
- int resLenBits = res.length * BITS_PER_BYTE;
- byteBuffer.putShort((short) resLenBits);
- byteBuffer.put(res);
-
- int bytesUsed = MIN_ATTR_LENGTH + res.length;
- addPadding(bytesUsed, byteBuffer);
- }
-
- /**
- * Creates and returns an AtRes instance with the given res value.
- *
- * @param res byte-array RES value to be used for this
- * @return AtRes instance for the given RES value
- * @throws EapSimAkaInvalidAttributeException if the given res value has an invalid length
- */
- public static AtRes getAtRes(byte[] res) throws EapSimAkaInvalidAttributeException {
- // Attributes must be 4B-aligned, so there can be 0 to 3 padding bytes added
- int resLenBytes = MIN_ATTR_LENGTH + res.length;
- if (resLenBytes % LENGTH_SCALING != 0) {
- resLenBytes += LENGTH_SCALING - (resLenBytes % LENGTH_SCALING);
- }
-
- return new AtRes(resLenBytes, res);
- }
-
- /**
- * Checks whether the given RES length is valid.
- *
- * @param resLenBytes the RES length to be checked
- * @return true iff the given resLen is valid
- */
- public static boolean isValidResLen(int resLenBytes) {
- return resLenBytes >= MIN_RES_LEN_BYTES && resLenBytes <= MAX_RES_LEN_BYTES;
- }
- }
-
- /**
- * AtAuts represents the AT_AUTS attribute defined in RFC 4187#10.9
- */
- public static class AtAuts extends EapSimAkaAttribute {
- private static final int ATTR_LENGTH = 4 * LENGTH_SCALING;
- public static final int AUTS_LENGTH = 14;
-
- public final byte[] auts = new byte[AUTS_LENGTH];
-
- public AtAuts(int lengthInBytes, ByteBuffer byteBuffer)
- throws EapSimAkaInvalidAttributeException {
- super(EAP_AT_AUTS, lengthInBytes);
-
- if (lengthInBytes != ATTR_LENGTH) {
- throw new EapSimAkaInvalidAttributeException("Length must be 16B");
- }
-
- byteBuffer.get(auts);
- }
-
- public AtAuts(byte[] auts) throws EapSimAkaInvalidAttributeException {
- super(EAP_AT_AUTS, ATTR_LENGTH);
-
- if (auts.length != AUTS_LENGTH) {
- throw new EapSimAkaInvalidAttributeException("Auts must be 14B");
- }
-
- System.arraycopy(auts, 0, this.auts, 0, AUTS_LENGTH);
- }
-
- @Override
- public void encode(ByteBuffer byteBuffer) {
- encodeAttributeHeader(byteBuffer);
-
- byteBuffer.put(auts);
- }
- }
-
- /**
- * AtKdfInput represents the AT_KDF_INPUT attribute defined in RFC 5448#3.1
- */
- public static class AtKdfInput extends EapSimAkaAttribute {
- public final byte[] networkName;
-
- public AtKdfInput(int lengthInBytes, ByteBuffer byteBuffer)
- throws EapSimAkaInvalidAttributeException {
- super(EAP_AT_KDF_INPUT, lengthInBytes);
-
- int networkNameLength = Short.toUnsignedInt(byteBuffer.getShort());
- networkName = new byte[networkNameLength];
- byteBuffer.get(networkName);
-
- int bytesUsed = MIN_ATTR_LENGTH + networkNameLength;
- consumePadding(bytesUsed, byteBuffer);
- }
-
- @VisibleForTesting
- public AtKdfInput(int lengthInbytes, byte[] networkName)
- throws EapSimAkaInvalidAttributeException {
- super(EAP_AT_KDF_INPUT, lengthInbytes);
-
- this.networkName = networkName;
- }
-
- @Override
- public void encode(ByteBuffer byteBuffer) {
- encodeAttributeHeader(byteBuffer);
- byteBuffer.putShort((short) networkName.length);
- byteBuffer.put(networkName);
-
- int bytesUsed = MIN_ATTR_LENGTH + networkName.length;
- addPadding(bytesUsed, byteBuffer);
- }
- }
-
- /**
- * AdKdf represents the AT_KDF attribute defined in RFC 5448#3.2
- */
- public static class AtKdf extends EapSimAkaAttribute {
- private static final int ATTR_LENGTH = MIN_ATTR_LENGTH;
-
- public final int kdf;
-
- public AtKdf(int lengthInBytes, ByteBuffer buffer)
- throws EapSimAkaInvalidAttributeException {
- super(EAP_AT_KDF, lengthInBytes);
-
- if (lengthInBytes != ATTR_LENGTH) {
- throw new EapSimAkaInvalidAttributeException("AtKdf length must be 4B");
- }
-
- kdf = Short.toUnsignedInt(buffer.getShort());
- }
-
- @VisibleForTesting
- public AtKdf(int kdf) throws EapSimAkaInvalidAttributeException {
- super(EAP_AT_KDF, ATTR_LENGTH);
-
- this.kdf = kdf;
- }
-
- @Override
- public void encode(ByteBuffer byteBuffer) {
- encodeAttributeHeader(byteBuffer);
-
- byteBuffer.putShort((short) kdf);
- }
- }
-
- /**
- * AtBidding represents the AT_BIDDING attribute defined in RFC 5448#4
- */
- public static class AtBidding extends EapSimAkaAttribute {
- private static final int ATTR_LENGTH = MIN_ATTR_LENGTH;
- private static final int SUPPORTS_EAP_AKA_PRIME_MASK = 0x8000;
-
- public final boolean doesServerSupportEapAkaPrime;
-
- public AtBidding(int lengthInBytes, ByteBuffer buffer)
- throws EapSimAkaInvalidAttributeException {
- super(EAP_AT_BIDDING, lengthInBytes);
-
- if (lengthInBytes != ATTR_LENGTH) {
- throw new EapSimAkaInvalidAttributeException("AtBidding length must be 4B");
- }
-
- int serverFlag = Short.toUnsignedInt(buffer.getShort());
- doesServerSupportEapAkaPrime = (serverFlag & SUPPORTS_EAP_AKA_PRIME_MASK) != 0;
- }
-
- @VisibleForTesting
- public AtBidding(boolean doesServerSupportEapAkaPrime)
- throws EapSimAkaInvalidAttributeException {
- super(EAP_AT_BIDDING, ATTR_LENGTH);
-
- this.doesServerSupportEapAkaPrime = doesServerSupportEapAkaPrime;
- }
-
- @Override
- public void encode(ByteBuffer byteBuffer) {
- encodeAttributeHeader(byteBuffer);
-
- int flagToWrite = doesServerSupportEapAkaPrime ? SUPPORTS_EAP_AKA_PRIME_MASK : 0;
- byteBuffer.putShort((short) flagToWrite);
- }
- }
-}
diff --git a/src/java/com/android/internal/net/eap/message/simaka/EapSimAkaAttributeFactory.java b/src/java/com/android/internal/net/eap/message/simaka/EapSimAkaAttributeFactory.java
deleted file mode 100644
index df79a25e..00000000
--- a/src/java/com/android/internal/net/eap/message/simaka/EapSimAkaAttributeFactory.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.message.simaka;
-
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_ANY_ID_REQ;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_CLIENT_ERROR_CODE;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_COUNTER;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_COUNTER_TOO_SMALL;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_FULLAUTH_ID_REQ;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_IDENTITY;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_MAC;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_NONCE_S;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_NOTIFICATION;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_PADDING;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_PERMANENT_ID_REQ;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.LENGTH_SCALING;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.SKIPPABLE_ATTRIBUTE_RANGE_START;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.net.eap.exceptions.simaka.EapSimAkaInvalidAttributeException;
-import com.android.internal.net.eap.exceptions.simaka.EapSimAkaUnsupportedAttributeException;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtAnyIdReq;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtClientErrorCode;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtCounter;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtCounterTooSmall;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtFullauthIdReq;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtIdentity;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtMac;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtNonceS;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtNotification;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtPadding;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtPermanentIdReq;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EapSimAkaUnsupportedAttribute;
-
-import java.nio.ByteBuffer;
-
-/**
- * EapSimAkaAttributeFactory is used for creating EapSimAkaAttributes according to their type.
- *
- * @see <a href="https://tools.ietf.org/html/rfc4186">RFC 4186, Extensible Authentication
- * Protocol for Subscriber Identity Modules (EAP-SIM)</a>
- * @see <a href="https://tools.ietf.org/html/rfc4187">RFC 4187, Extensible Authentication
- * Protocol for Authentication and Key Agreement (EAP-AKA)</a>
- * @see <a href="https://www.iana.org/assignments/eap-numbers/eap-numbers.xhtml">EAP SIM/AKA
- * Attributes</a>
- */
-public abstract class EapSimAkaAttributeFactory {
- /**
- * Decodes a single EapSimAkaAttribute object from the given ByteBuffer.
- *
- * <p>Decoding logic is based on Attribute definitions in RFC 4186#10 and RFC 4187#10.
- *
- * @param attributeType the attribute type to be decoded
- * @param lengthInBytes the length in bytes of the attribute to be decoded
- * @param byteBuffer The ByteBuffer to parse the current attribute from
- * @return The current EapSimAkaAttribute to be parsed, or EapSimAkaUnsupportedAttribute if the
- * given attributeType is skippable and unsupported
- * @throws EapSimAkaInvalidAttributeException when a malformatted attribute is attempted to be
- * decoded
- * @throws EapSimAkaUnsupportedAttributeException when an unsupported, unskippable Attribute is
- * attempted to be decoded
- */
- EapSimAkaAttribute getAttribute(int attributeType, int lengthInBytes, ByteBuffer byteBuffer)
- throws EapSimAkaInvalidAttributeException, EapSimAkaUnsupportedAttributeException {
- switch (attributeType) {
- // TODO(b/139482157): define optional shared attributes
- case EAP_AT_PERMANENT_ID_REQ:
- return new AtPermanentIdReq(lengthInBytes, byteBuffer);
- case EAP_AT_ANY_ID_REQ:
- return new AtAnyIdReq(lengthInBytes, byteBuffer);
- case EAP_AT_FULLAUTH_ID_REQ:
- return new AtFullauthIdReq(lengthInBytes, byteBuffer);
- case EAP_AT_IDENTITY:
- return new AtIdentity(lengthInBytes, byteBuffer);
- case EAP_AT_PADDING:
- return new AtPadding(lengthInBytes, byteBuffer);
- case EAP_AT_MAC:
- return new AtMac(lengthInBytes, byteBuffer);
- case EAP_AT_COUNTER:
- return new AtCounter(lengthInBytes, byteBuffer);
- case EAP_AT_COUNTER_TOO_SMALL:
- return new AtCounterTooSmall(lengthInBytes, byteBuffer);
- case EAP_AT_NONCE_S:
- return new AtNonceS(lengthInBytes, byteBuffer);
- case EAP_AT_NOTIFICATION:
- return new AtNotification(lengthInBytes, byteBuffer);
- case EAP_AT_CLIENT_ERROR_CODE:
- int errorCode = Short.toUnsignedInt(byteBuffer.getShort());
- return new AtClientErrorCode(lengthInBytes, errorCode);
- default:
- if (attributeType >= SKIPPABLE_ATTRIBUTE_RANGE_START) {
- return new EapSimAkaUnsupportedAttribute(
- attributeType, lengthInBytes, byteBuffer);
- }
-
- throw new EapSimAkaUnsupportedAttributeException(
- "Unexpected EAP Attribute=" + attributeType);
- }
- }
-
- /**
- * This method exists only for testing.
- *
- * <p>It follows the attributeFactory.getAttribute(ByteBuffer) pattern used by
- * EapSimAttributeFactory and EapAkaAttributeFactory.
- */
- @VisibleForTesting
- public EapSimAkaAttribute getAttribute(ByteBuffer byteBuffer)
- throws EapSimAkaInvalidAttributeException, EapSimAkaUnsupportedAttributeException {
- int attributeType = Byte.toUnsignedInt(byteBuffer.get());
-
- // Length is given as a multiple of 4x bytes (RFC 4186 Section 8.1)
- int lengthInBytes = Byte.toUnsignedInt(byteBuffer.get()) * LENGTH_SCALING;
- return getAttribute(attributeType, lengthInBytes, byteBuffer);
- }
-}
diff --git a/src/java/com/android/internal/net/eap/message/simaka/EapSimAkaTypeData.java b/src/java/com/android/internal/net/eap/message/simaka/EapSimAkaTypeData.java
deleted file mode 100644
index c84fdf4b..00000000
--- a/src/java/com/android/internal/net/eap/message/simaka/EapSimAkaTypeData.java
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.message.simaka;
-
-import static com.android.internal.net.eap.EapAuthenticator.LOG;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_ATTRIBUTE_STRING;
-
-import android.annotation.NonNull;
-
-import com.android.internal.net.eap.exceptions.simaka.EapSimAkaInvalidAttributeException;
-import com.android.internal.net.eap.exceptions.simaka.EapSimAkaUnsupportedAttributeException;
-import com.android.internal.net.eap.exceptions.simaka.EapSimInvalidAtRandException;
-import com.android.internal.net.eap.message.EapMessage;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtClientErrorCode;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EapSimAkaUnsupportedAttribute;
-
-import java.nio.BufferUnderflowException;
-import java.nio.ByteBuffer;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * EapSimTypeData represents the Type Data for an {@link EapMessage} during an EAP-SIM session.
- */
-public abstract class EapSimAkaTypeData {
- private static final int MIN_LEN_BYTES = 3; // subtype (1B) + reserved bytes (2B)
- private static final int RESERVED_BYTES = 2; // RFC 4186#8.1, RFC 4187#8.1
-
- public final int eapSubtype;
-
- // LinkedHashMap used to preserve encoded ordering of attributes. This is necessary for checking
- // the MAC value for the message
- public final LinkedHashMap<Integer, EapSimAkaAttribute> attributeMap;
-
- public EapSimAkaTypeData(
- int eapSubType,
- LinkedHashMap<Integer, EapSimAkaAttribute> attributeMap) {
- this.eapSubtype = eapSubType;
- this.attributeMap = attributeMap;
- }
-
- /**
- * Creates and returns the byte-array encoding of this EapSimTypeData instance.
- *
- * @return byte[] representing the byte-encoding of this EapSimTypeData instance.
- */
- public byte[] encode() {
- int lengthInBytes = MIN_LEN_BYTES;
- for (EapSimAkaAttribute attribute : attributeMap.values()) {
- lengthInBytes += attribute.lengthInBytes;
- }
-
- ByteBuffer output = ByteBuffer.allocate(lengthInBytes);
- output.put((byte) eapSubtype);
-
- // two reserved bytes (RFC 4186#8.1, RFC 4187#8.1)
- output.put(new byte[RESERVED_BYTES]);
-
- for (EapSimAkaAttribute attribute : attributeMap.values()) {
- attribute.encode(output);
- }
-
- return output.array();
- }
-
- /**
- * Class for decoding EAP-SIM and EAP-AKA type-datas.
- *
- * @param <T> The EapSimAkaTypeData type that the EapSimAkaTypeDataDecoder will be decoding
- */
- public abstract static class EapSimAkaTypeDataDecoder<T extends EapSimAkaTypeData> {
- private final String mTAG;
- private final String mEapMethod;
- private final Set<Integer> mSupportedSubtypes;
- private final EapSimAkaAttributeFactory mAttributeFactory;
- private final Map<Integer, String> mEapSubtypeStrings;
-
- EapSimAkaTypeDataDecoder(
- String tag,
- String eapMethod,
- Set<Integer> supportedSubtypes,
- EapSimAkaAttributeFactory eapSimAkaAttributeFactory,
- Map<Integer, String> eapSubtypeStrings) {
- this.mTAG = tag;
- this.mEapMethod = eapMethod;
- this.mSupportedSubtypes = supportedSubtypes;
- this.mAttributeFactory = eapSimAkaAttributeFactory;
- this.mEapSubtypeStrings = eapSubtypeStrings;
- }
-
- protected DecodeResult<T> decode(@NonNull byte[] typeData) {
- if (typeData == null) {
- LOG.d(mTAG, "Invalid EAP Type-Data");
- return new DecodeResult<>(AtClientErrorCode.UNABLE_TO_PROCESS);
- }
-
- ByteBuffer byteBuffer = ByteBuffer.wrap(typeData);
- try {
- int eapSubType = Byte.toUnsignedInt(byteBuffer.get());
- if (!mSupportedSubtypes.contains(eapSubType)) {
- LOG.d(mTAG, "Invalid EAP Type-Data");
- return new DecodeResult<>(AtClientErrorCode.UNABLE_TO_PROCESS);
- }
-
- // next two bytes are reserved (RFC 4186#8.1, RFC 4187#8.1)
- byteBuffer.get(new byte[RESERVED_BYTES]);
-
- // read attributes
- LinkedHashMap<Integer, EapSimAkaAttribute> attributeMap = new LinkedHashMap<>();
- while (byteBuffer.hasRemaining()) {
- EapSimAkaAttribute attribute = mAttributeFactory.getAttribute(byteBuffer);
-
- if (attributeMap.containsKey(attribute.attributeType)) {
- // Duplicate attributes are not allowed (RFC 4186#6.3.1, RFC 4187#6.3.1)
- LOG.e(mTAG, "Duplicate attribute in parsed EAP-Message");
- return new DecodeResult<>(AtClientErrorCode.UNABLE_TO_PROCESS);
- }
-
- if (attribute instanceof EapSimAkaUnsupportedAttribute) {
- LOG.d(mTAG, "Unsupported EAP-SIM attribute during decoding: "
- + attribute.attributeType);
- }
- attributeMap.put(attribute.attributeType, attribute);
- }
-
- T eapSimAkaTypeData = getInstance(eapSubType, attributeMap);
-
- logDecodedEapSimTypeData(eapSimAkaTypeData);
-
- return new DecodeResult<>(eapSimAkaTypeData);
- } catch (EapSimInvalidAtRandException ex) {
- LOG.e(mTAG, "Invalid AtRand attribute", ex);
- return new DecodeResult<>(AtClientErrorCode.INSUFFICIENT_CHALLENGES);
- } catch (EapSimAkaInvalidAttributeException | BufferUnderflowException ex) {
- LOG.e(mTAG, "Incorrectly formatted attribute", ex);
- return new DecodeResult<>(AtClientErrorCode.UNABLE_TO_PROCESS);
- } catch (EapSimAkaUnsupportedAttributeException ex) {
- LOG.e(mTAG, "Unrecognized, non-skippable attribute encountered", ex);
- return new DecodeResult<>(AtClientErrorCode.UNABLE_TO_PROCESS);
- }
- }
-
- protected abstract T getInstance(
- int eapSubType,
- LinkedHashMap<Integer, EapSimAkaAttribute> attributeMap);
-
- private void logDecodedEapSimTypeData(EapSimAkaTypeData eapSimAkaTypeData) {
- StringBuilder msg = new StringBuilder();
- msg.append("Decoded ");
- msg.append(mEapMethod);
- msg.append(" type data: ");
-
- msg.append(mEapSubtypeStrings.getOrDefault(eapSimAkaTypeData.eapSubtype, "Unknown"));
- msg.append(" attributes=[ ");
- for (int attributeType : eapSimAkaTypeData.attributeMap.keySet()) {
- msg.append(
- EAP_ATTRIBUTE_STRING.getOrDefault(attributeType,
- "Unknown(" + attributeType + ")"));
- msg.append(" ");
- }
- msg.append("]");
- LOG.i(mTAG, msg.toString());
- }
- }
-
- /**
- * DecodeResult represents the result from calling EapSimTypeDataDecoder.decode(). It will
- * contain either a decoded EapSimTypeData or the relevant AtClientErrorCode.
- *
- * @param <T> The EapSimAkaTypeData type that is wrapped in this DecodeResult
- */
- public static class DecodeResult<T extends EapSimAkaTypeData> {
- public final T eapTypeData;
- public final EapSimAkaAttribute.AtClientErrorCode atClientErrorCode;
-
- public DecodeResult(T eapTypeData) {
- this.eapTypeData = eapTypeData;
- this.atClientErrorCode = null;
- }
-
- public DecodeResult(EapSimAkaAttribute.AtClientErrorCode atClientErrorCode) {
- this.atClientErrorCode = atClientErrorCode;
- eapTypeData = null;
- }
-
- public boolean isSuccessfulDecode() {
- return eapTypeData != null;
- }
- }
-}
diff --git a/src/java/com/android/internal/net/eap/message/simaka/EapSimAttributeFactory.java b/src/java/com/android/internal/net/eap/message/simaka/EapSimAttributeFactory.java
deleted file mode 100644
index 8be348eb..00000000
--- a/src/java/com/android/internal/net/eap/message/simaka/EapSimAttributeFactory.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.message.simaka;
-
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_NONCE_MT;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_RAND;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_SELECTED_VERSION;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_VERSION_LIST;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.LENGTH_SCALING;
-
-import com.android.internal.net.eap.exceptions.simaka.EapSimAkaInvalidAttributeException;
-import com.android.internal.net.eap.exceptions.simaka.EapSimAkaUnsupportedAttributeException;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtNonceMt;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtRandSim;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtSelectedVersion;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtVersionList;
-
-import java.nio.ByteBuffer;
-
-/**
- * EapSimAttributeFactory is used for creating EAP-SIM attributes according to their type.
- *
- * @see <a href="https://tools.ietf.org/html/rfc4186">RFC 4186, Extensible Authentication
- * Protocol for Subscriber Identity Modules (EAP-SIM)</a>
- * @see <a href="https://www.iana.org/assignments/eap-numbers/eap-numbers.xhtml">EAP SIM/AKA
- * Attributes</a>
- */
-public class EapSimAttributeFactory extends EapSimAkaAttributeFactory {
- private static EapSimAttributeFactory sInstance = new EapSimAttributeFactory();
-
- private EapSimAttributeFactory() {
- }
-
- public static EapSimAttributeFactory getInstance() {
- return sInstance;
- }
-
- /**
- * Decodes a single EapSimAkaAttribute object from the given ByteBuffer.
- *
- * <p>Decoding logic is based on Attribute definitions in RFC 4186#10.
- *
- * @param byteBuffer The ByteBuffer to parse the current attribute from
- * @return The current EapSimAkaAttribute to be parsed, or EapSimAkaUnsupportedAttribute if the
- * given attributeType is skippable and unsupported
- * @throws EapSimAkaInvalidAttributeException when a malformatted attribute is attempted to be
- * decoded
- * @throws EapSimAkaUnsupportedAttributeException when an unsupported, unskippable Attribute is
- * attempted to be decoded
- */
- public EapSimAkaAttribute getAttribute(ByteBuffer byteBuffer) throws
- EapSimAkaInvalidAttributeException, EapSimAkaUnsupportedAttributeException {
- int attributeType = Byte.toUnsignedInt(byteBuffer.get());
-
- // Length is given as a multiple of 4x bytes (RFC 4186 Section 8.1)
- int lengthInBytes = Byte.toUnsignedInt(byteBuffer.get()) * LENGTH_SCALING;
-
- switch (attributeType) {
- // TODO(b/134670528): add case statements for all EAP-SIM attributes
- case EAP_AT_VERSION_LIST:
- return new AtVersionList(lengthInBytes, byteBuffer);
- case EAP_AT_SELECTED_VERSION:
- int selectedVersion = Short.toUnsignedInt(byteBuffer.getShort());
- return new AtSelectedVersion(lengthInBytes, selectedVersion);
- case EAP_AT_NONCE_MT:
- return new AtNonceMt(lengthInBytes, byteBuffer);
- case EAP_AT_RAND:
- return new AtRandSim(lengthInBytes, byteBuffer);
- default:
- return super.getAttribute(attributeType, lengthInBytes, byteBuffer);
- }
- }
-}
diff --git a/src/java/com/android/internal/net/eap/message/simaka/EapSimTypeData.java b/src/java/com/android/internal/net/eap/message/simaka/EapSimTypeData.java
deleted file mode 100644
index ff1be603..00000000
--- a/src/java/com/android/internal/net/eap/message/simaka/EapSimTypeData.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.message.simaka;
-
-import android.annotation.NonNull;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.net.eap.message.EapMessage;
-
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * EapSimTypeData represents the Type Data for an {@link EapMessage} during an EAP-SIM session.
- */
-public class EapSimTypeData extends EapSimAkaTypeData {
- private static final String TAG = EapSimTypeData.class.getSimpleName();
-
- // EAP-SIM Subtype values defined by IANA
- // https://www.iana.org/assignments/eapsimaka-numbers/eapsimaka-numbers.xhtml
- public static final int EAP_SIM_START = 10;
- public static final int EAP_SIM_CHALLENGE = 11;
- public static final int EAP_SIM_NOTIFICATION = 12;
- public static final int EAP_SIM_REAUTHENTICATION = 13;
- public static final int EAP_SIM_CLIENT_ERROR = 14;
-
- public static final Map<Integer, String> EAP_SIM_SUBTYPE_STRING = new HashMap<>();
- static {
- EAP_SIM_SUBTYPE_STRING.put(EAP_SIM_START, "Start");
- EAP_SIM_SUBTYPE_STRING.put(EAP_SIM_CHALLENGE, "Challenge");
- EAP_SIM_SUBTYPE_STRING.put(EAP_SIM_NOTIFICATION, "Notification");
- EAP_SIM_SUBTYPE_STRING.put(EAP_SIM_REAUTHENTICATION, "Re-authentication");
- EAP_SIM_SUBTYPE_STRING.put(EAP_SIM_CLIENT_ERROR, "Client-Error");
- }
-
- private static final Set<Integer> SUPPORTED_SUBTYPES = new HashSet<>();
- static {
- SUPPORTED_SUBTYPES.add(EAP_SIM_START);
- SUPPORTED_SUBTYPES.add(EAP_SIM_CHALLENGE);
- SUPPORTED_SUBTYPES.add(EAP_SIM_NOTIFICATION);
- SUPPORTED_SUBTYPES.add(EAP_SIM_REAUTHENTICATION);
- SUPPORTED_SUBTYPES.add(EAP_SIM_CLIENT_ERROR);
- }
-
- private static final EapSimTypeDataDecoder sTypeDataDecoder = new EapSimTypeDataDecoder();
-
- @VisibleForTesting
- public EapSimTypeData(int eapSubType, LinkedHashMap<Integer, EapSimAkaAttribute> attributeMap) {
- super(eapSubType, attributeMap);
- }
-
- public EapSimTypeData(int eapSubtype, List<EapSimAkaAttribute> attributes) {
- super(eapSubtype, new LinkedHashMap<>());
-
- if (!SUPPORTED_SUBTYPES.contains(eapSubtype)) {
- throw new IllegalArgumentException("Invalid subtype for EAP-SIM: " + eapSubtype);
- }
-
- for (EapSimAkaAttribute attribute : attributes) {
- if (attributeMap.containsKey(attribute.attributeType)) {
- throw new IllegalArgumentException(
- "Duplicate attribute in attributes: " + attribute.attributeType);
- }
- attributeMap.put(attribute.attributeType, attribute);
- }
- }
-
- public static EapSimTypeDataDecoder getEapSimTypeDataDecoder() {
- return sTypeDataDecoder;
- }
-
- /**
- * EapSimTypeDataDecoder will be used for decoding {@link EapSimTypeData} objects.
- */
- public static class EapSimTypeDataDecoder extends EapSimAkaTypeDataDecoder<EapSimTypeData> {
- private static final String TAG = EapSimTypeDataDecoder.class.getSimpleName();
- private static final String EAP_METHOD = "EAP-SIM";
-
- protected EapSimTypeDataDecoder() {
- super(
- TAG,
- EAP_METHOD,
- SUPPORTED_SUBTYPES,
- EapSimAttributeFactory.getInstance(),
- EAP_SIM_SUBTYPE_STRING);
- }
-
- /**
- * Decodes the given byte-array into a DecodeResult object.
- *
- * @param typeData the byte-encoding of the EapSimTypeData to be parsed
- * @return a DecodeResult object. If the decoding is successful, this will encapsulate an
- * EapSimTypeData instance representing the data stored in typeData. Otherwise, it
- * will contain the relevant AtClientErrorCode for the decoding error.
- */
- public DecodeResult<EapSimTypeData> decode(@NonNull byte[] typeData) {
- return super.decode(typeData);
- }
-
- @Override
- protected EapSimTypeData getInstance(
- int eapSubtype,
- LinkedHashMap<Integer, EapSimAkaAttribute> attributeMap) {
- return new EapSimTypeData(eapSubtype, attributeMap);
- }
- }
-}
diff --git a/src/java/com/android/internal/net/eap/statemachine/EapAkaMethodStateMachine.java b/src/java/com/android/internal/net/eap/statemachine/EapAkaMethodStateMachine.java
deleted file mode 100644
index b26c8e95..00000000
--- a/src/java/com/android/internal/net/eap/statemachine/EapAkaMethodStateMachine.java
+++ /dev/null
@@ -1,612 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.statemachine;
-
-import static com.android.internal.net.eap.EapAuthenticator.LOG;
-import static com.android.internal.net.eap.message.EapData.EAP_NOTIFICATION;
-import static com.android.internal.net.eap.message.EapData.EAP_TYPE_AKA;
-import static com.android.internal.net.eap.message.EapMessage.EAP_CODE_FAILURE;
-import static com.android.internal.net.eap.message.EapMessage.EAP_CODE_SUCCESS;
-import static com.android.internal.net.eap.message.simaka.EapAkaTypeData.EAP_AKA_AUTHENTICATION_REJECT;
-import static com.android.internal.net.eap.message.simaka.EapAkaTypeData.EAP_AKA_CHALLENGE;
-import static com.android.internal.net.eap.message.simaka.EapAkaTypeData.EAP_AKA_CLIENT_ERROR;
-import static com.android.internal.net.eap.message.simaka.EapAkaTypeData.EAP_AKA_IDENTITY;
-import static com.android.internal.net.eap.message.simaka.EapAkaTypeData.EAP_AKA_NOTIFICATION;
-import static com.android.internal.net.eap.message.simaka.EapAkaTypeData.EAP_AKA_SYNCHRONIZATION_FAILURE;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_ANY_ID_REQ;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_AUTN;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_BIDDING;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_ENCR_DATA;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_FULLAUTH_ID_REQ;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_IV;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_MAC;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_PERMANENT_ID_REQ;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_RAND;
-
-import android.annotation.Nullable;
-import android.content.Context;
-import android.net.eap.EapSessionConfig.EapAkaConfig;
-import android.telephony.TelephonyManager;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.net.eap.EapResult;
-import com.android.internal.net.eap.EapResult.EapError;
-import com.android.internal.net.eap.EapResult.EapFailure;
-import com.android.internal.net.eap.EapResult.EapSuccess;
-import com.android.internal.net.eap.crypto.Fips186_2Prf;
-import com.android.internal.net.eap.exceptions.EapInvalidRequestException;
-import com.android.internal.net.eap.exceptions.EapSilentException;
-import com.android.internal.net.eap.exceptions.simaka.EapAkaInvalidAuthenticationResponse;
-import com.android.internal.net.eap.exceptions.simaka.EapSimAkaAuthenticationFailureException;
-import com.android.internal.net.eap.exceptions.simaka.EapSimAkaIdentityUnavailableException;
-import com.android.internal.net.eap.exceptions.simaka.EapSimAkaInvalidAttributeException;
-import com.android.internal.net.eap.exceptions.simaka.EapSimAkaInvalidLengthException;
-import com.android.internal.net.eap.message.EapData.EapMethod;
-import com.android.internal.net.eap.message.EapMessage;
-import com.android.internal.net.eap.message.simaka.EapAkaTypeData;
-import com.android.internal.net.eap.message.simaka.EapAkaTypeData.EapAkaTypeDataDecoder;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtAutn;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtAuts;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtBidding;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtClientErrorCode;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtIdentity;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtRandAka;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtRes;
-import com.android.internal.net.eap.message.simaka.EapSimAkaTypeData.DecodeResult;
-
-import java.nio.BufferUnderflowException;
-import java.nio.ByteBuffer;
-import java.nio.charset.StandardCharsets;
-import java.security.GeneralSecurityException;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Set;
-
-/**
- * EapAkaMethodStateMachine represents the valid paths possible for the EAP-AKA protocol.
- *
- * <p>EAP-AKA sessions will always follow the path:
- *
- * Created --+--> Identity --+--> Challenge --> Final
- * | |
- * +---------------+
- *
- * Note: If the EAP-Request/AKA-Challenge message contains an AUTN with an invalid sequence number,
- * the peer will indicate a synchronization failure to the server and a new challenge will be
- * attempted.
- *
- * Note: EAP-Request/Notification messages can be received at any point in the above state machine
- * At most one EAP-AKA/Notification message is allowed per EAP-AKA session.
- *
- * @see <a href="https://tools.ietf.org/html/rfc4187">RFC 4187, Extensible Authentication
- * Protocol for Authentication and Key Agreement (EAP-AKA)</a>
- */
-class EapAkaMethodStateMachine extends EapSimAkaMethodStateMachine {
- private static final String TAG = EapAkaMethodStateMachine.class.getSimpleName();
-
- // EAP-AKA identity prefix (RFC 4187#4.1.1.6)
- private static final String AKA_IDENTITY_PREFIX = "0";
-
- private final EapAkaTypeDataDecoder mEapAkaTypeDataDecoder;
- private final boolean mSupportsEapAkaPrime;
-
- protected EapAkaMethodStateMachine(
- Context context, byte[] eapIdentity, EapAkaConfig eapAkaConfig) {
- this(context, eapIdentity, eapAkaConfig, false);
- }
-
- EapAkaMethodStateMachine(
- Context context,
- byte[] eapIdentity,
- EapAkaConfig eapAkaConfig,
- boolean supportsEapAkaPrime) {
- this(
- (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE),
- eapIdentity,
- eapAkaConfig,
- EapAkaTypeData.getEapAkaTypeDataDecoder(),
- supportsEapAkaPrime);
- }
-
- @VisibleForTesting
- protected EapAkaMethodStateMachine(
- TelephonyManager telephonyManager,
- byte[] eapIdentity,
- EapAkaConfig eapAkaConfig,
- EapAkaTypeDataDecoder eapAkaTypeDataDecoder,
- boolean supportsEapAkaPrime) {
- super(
- telephonyManager.createForSubscriptionId(eapAkaConfig.subId),
- eapIdentity,
- eapAkaConfig);
- mEapAkaTypeDataDecoder = eapAkaTypeDataDecoder;
- mSupportsEapAkaPrime = supportsEapAkaPrime;
-
- transitionTo(new CreatedState());
- }
-
- @Override
- @EapMethod
- int getEapMethod() {
- return EAP_TYPE_AKA;
- }
-
- protected DecodeResult<EapAkaTypeData> decode(byte[] typeData) {
- return mEapAkaTypeDataDecoder.decode(typeData);
- }
-
- /**
- * This exists so we can override the identity prefix in the EapAkaPrimeMethodStateMachine.
- *
- * @return the Identity prefix for this EAP method
- */
- protected String getIdentityPrefix() {
- return AKA_IDENTITY_PREFIX;
- }
-
- protected ChallengeState buildChallengeState() {
- return new ChallengeState();
- }
-
- protected ChallengeState buildChallengeState(byte[] identity) {
- return new ChallengeState(identity);
- }
-
- protected class CreatedState extends EapMethodState {
- private final String mTAG = CreatedState.class.getSimpleName();
-
- public EapResult process(EapMessage message) {
- EapResult result = handleEapSuccessFailureNotification(mTAG, message);
- if (result != null) {
- return result;
- }
-
- DecodeResult<? extends EapAkaTypeData> decodeResult =
- decode(message.eapData.eapTypeData);
- if (!decodeResult.isSuccessfulDecode()) {
- return buildClientErrorResponse(
- message.eapIdentifier, getEapMethod(), decodeResult.atClientErrorCode);
- }
-
- EapAkaTypeData eapAkaTypeData = decodeResult.eapTypeData;
- switch (eapAkaTypeData.eapSubtype) {
- case EAP_AKA_IDENTITY:
- return transitionAndProcess(new IdentityState(), message);
- case EAP_AKA_CHALLENGE:
- return transitionAndProcess(buildChallengeState(), message);
- case EAP_AKA_NOTIFICATION:
- return handleEapSimAkaNotification(
- mTAG,
- true, // isPreChallengeState
- message.eapIdentifier,
- eapAkaTypeData);
- default:
- return buildClientErrorResponse(
- message.eapIdentifier,
- getEapMethod(),
- AtClientErrorCode.UNABLE_TO_PROCESS);
- }
- }
- }
-
- protected class IdentityState extends EapMethodState {
- private final String mTAG = IdentityState.class.getSimpleName();
-
- private byte[] mIdentity;
-
- public EapResult process(EapMessage message) {
- EapResult result = handleEapSuccessFailureNotification(mTAG, message);
- if (result != null) {
- return result;
- }
-
- DecodeResult<? extends EapAkaTypeData> decodeResult =
- decode(message.eapData.eapTypeData);
- if (!decodeResult.isSuccessfulDecode()) {
- return buildClientErrorResponse(
- message.eapIdentifier, getEapMethod(), decodeResult.atClientErrorCode);
- }
-
- EapAkaTypeData eapAkaTypeData = decodeResult.eapTypeData;
- switch (eapAkaTypeData.eapSubtype) {
- case EAP_AKA_IDENTITY:
- break;
- case EAP_AKA_CHALLENGE:
- return transitionAndProcess(buildChallengeState(mIdentity), message);
- case EAP_AKA_NOTIFICATION:
- return handleEapSimAkaNotification(
- mTAG,
- true, // isPreChallengeState
- message.eapIdentifier,
- eapAkaTypeData);
- default:
- return buildClientErrorResponse(
- message.eapIdentifier,
- getEapMethod(),
- AtClientErrorCode.UNABLE_TO_PROCESS);
- }
-
- if (!isValidIdentityAttributes(eapAkaTypeData)) {
- LOG.e(mTAG, "Invalid attributes: " + eapAkaTypeData.attributeMap.keySet());
- return buildClientErrorResponse(
- message.eapIdentifier,
- EAP_TYPE_AKA,
- AtClientErrorCode.UNABLE_TO_PROCESS);
- }
-
- String imsi = mTelephonyManager.getSubscriberId();
- if (imsi == null) {
- LOG.e(mTAG, "Unable to get IMSI for subId=" + mEapUiccConfig.subId);
- return new EapError(
- new EapSimAkaIdentityUnavailableException(
- "IMSI for subId (" + mEapUiccConfig.subId + ") not available"));
- }
- String identityString = getIdentityPrefix() + imsi;
- mIdentity = identityString.getBytes(StandardCharsets.US_ASCII);
- LOG.d(mTAG, "EAP-AKA/Identity=" + LOG.pii(identityString));
-
- AtIdentity atIdentity;
- try {
- atIdentity = AtIdentity.getAtIdentity(mIdentity);
- } catch (EapSimAkaInvalidAttributeException ex) {
- LOG.wtf(mTAG, "Exception thrown while making AtIdentity attribute", ex);
- return new EapError(ex);
- }
-
- return buildResponseMessage(
- getEapMethod(),
- EAP_AKA_IDENTITY,
- message.eapIdentifier,
- Arrays.asList(atIdentity));
- }
-
- private boolean isValidIdentityAttributes(EapAkaTypeData eapAkaTypeData) {
- Set<Integer> attrs = eapAkaTypeData.attributeMap.keySet();
-
- // exactly one ID request type required
- int idRequests = 0;
- idRequests += attrs.contains(EAP_AT_PERMANENT_ID_REQ) ? 1 : 0;
- idRequests += attrs.contains(EAP_AT_ANY_ID_REQ) ? 1 : 0;
- idRequests += attrs.contains(EAP_AT_FULLAUTH_ID_REQ) ? 1 : 0;
-
- if (idRequests != 1) {
- return false;
- }
-
- // can't contain mac, iv, encr data
- if (attrs.contains(EAP_AT_MAC)
- || attrs.contains(EAP_AT_IV)
- || attrs.contains(EAP_AT_ENCR_DATA)) {
- return false;
- }
- return true;
- }
- }
-
- protected class ChallengeState extends EapMethodState {
- private final String mTAG = ChallengeState.class.getSimpleName();
-
- @VisibleForTesting boolean mHadSuccessfulChallenge = false;
- @VisibleForTesting protected final byte[] mIdentity;
-
- // IK and CK lengths defined as 16B (RFC 4187#1)
- private final int mIkLenBytes = 16;
- private final int mCkLenBytes = 16;
-
- // Tags for Successful and Synchronization responses
- private final byte mSuccess = (byte) 0xDB;
- private final byte mSynchronization = (byte) 0xDC;
-
- ChallengeState() {
- // use the EAP-Identity for the default value (RFC 4187#7)
- this(mEapIdentity);
- }
-
- ChallengeState(byte[] identity) {
- this.mIdentity = identity;
- }
-
- public EapResult process(EapMessage message) {
- if (message.eapCode == EAP_CODE_SUCCESS) {
- if (!mHadSuccessfulChallenge) {
- LOG.e(mTAG, "Received unexpected EAP-Success");
- return new EapError(
- new EapInvalidRequestException(
- "Received an EAP-Success in the ChallengeState"));
- }
- transitionTo(new FinalState());
- return new EapSuccess(mMsk, mEmsk);
- } else if (message.eapCode == EAP_CODE_FAILURE) {
- transitionTo(new FinalState());
- return new EapFailure();
- } else if (message.eapData.eapType == EAP_NOTIFICATION) {
- return handleEapNotification(mTAG, message);
- }
-
- if (message.eapData.eapType != getEapMethod()) {
- return new EapError(new EapInvalidRequestException(
- "Expected EAP Type " + getEapMethod()
- + ", received " + message.eapData.eapType));
- }
-
- DecodeResult<? extends EapAkaTypeData> decodeResult =
- decode(message.eapData.eapTypeData);
- if (!decodeResult.isSuccessfulDecode()) {
- return buildClientErrorResponse(
- message.eapIdentifier, getEapMethod(), decodeResult.atClientErrorCode);
- }
-
- EapAkaTypeData eapAkaTypeData = decodeResult.eapTypeData;
- switch (eapAkaTypeData.eapSubtype) {
- case EAP_AKA_CHALLENGE:
- break;
- case EAP_AKA_NOTIFICATION:
- return handleEapSimAkaNotification(
- mTAG,
- false, // isPreChallengeState
- message.eapIdentifier,
- eapAkaTypeData);
- default:
- return buildClientErrorResponse(
- message.eapIdentifier,
- getEapMethod(),
- AtClientErrorCode.UNABLE_TO_PROCESS);
- }
-
- if (!isValidChallengeAttributes(eapAkaTypeData)) {
- LOG.e(mTAG, "Invalid attributes: " + eapAkaTypeData.attributeMap.keySet());
- return buildClientErrorResponse(
- message.eapIdentifier, getEapMethod(), AtClientErrorCode.UNABLE_TO_PROCESS);
- }
-
- return handleChallengeAuthentication(message, eapAkaTypeData);
- }
-
- protected EapResult handleChallengeAuthentication(
- EapMessage message, EapAkaTypeData eapAkaTypeData) {
- RandChallengeResult result;
- try {
- result = getRandChallengeResult(eapAkaTypeData);
- } catch (EapAkaInvalidAuthenticationResponse ex) {
- return new EapError(ex);
- } catch (EapSimAkaInvalidLengthException | BufferUnderflowException ex) {
- LOG.e(mTAG, "Invalid response returned from SIM", ex);
- return buildClientErrorResponse(
- message.eapIdentifier, getEapMethod(), AtClientErrorCode.UNABLE_TO_PROCESS);
- } catch (EapSimAkaAuthenticationFailureException ex) {
- // Return EAP-Response/AKA-Authentication-Reject when the AUTN is rejected
- // (RFC 4187#6.3.1)
- return buildAuthenticationRejectMessage(message.eapIdentifier);
- }
-
- if (!result.isSuccessfulResult()) {
- try {
- return buildResponseMessage(
- getEapMethod(),
- EAP_AKA_SYNCHRONIZATION_FAILURE,
- message.eapIdentifier,
- Arrays.asList(new AtAuts(result.auts)));
- } catch (EapSimAkaInvalidAttributeException ex) {
- LOG.wtf(mTAG, "Error creating an AtAuts attr", ex);
- return new EapError(ex);
- }
- }
-
- EapResult eapResult =
- generateAndPersistEapAkaKeys(result, message.eapIdentifier, eapAkaTypeData);
- if (eapResult != null) {
- return eapResult;
- }
-
- try {
- if (!isValidMac(mTAG, message, eapAkaTypeData, new byte[0])) {
- return buildClientErrorResponse(
- message.eapIdentifier,
- getEapMethod(),
- AtClientErrorCode.UNABLE_TO_PROCESS);
- }
- } catch (GeneralSecurityException
- | EapSilentException
- | EapSimAkaInvalidAttributeException ex) {
- // if the MAC can't be generated, we can't continue
- LOG.e(mTAG, "Error computing MAC for EapMessage", ex);
- return new EapError(ex);
- }
-
- // before sending a response, check for bidding-down attacks (RFC 5448#4)
- if (mSupportsEapAkaPrime) {
- AtBidding atBidding = (AtBidding) eapAkaTypeData.attributeMap.get(EAP_AT_BIDDING);
- if (atBidding != null && atBidding.doesServerSupportEapAkaPrime) {
- LOG.w(
- mTAG,
- "Potential bidding down attack. AT_BIDDING attr included and EAP-AKA'"
- + " is supported");
- return buildAuthenticationRejectMessage(message.eapIdentifier);
- }
- }
-
- // server has been authenticated, so we can send a response
- try {
- mHadSuccessfulChallenge = true;
- return buildResponseMessageWithMac(
- message.eapIdentifier,
- EAP_AKA_CHALLENGE,
- new byte[0],
- Arrays.asList(AtRes.getAtRes(result.res)));
- } catch (EapSimAkaInvalidAttributeException ex) {
- LOG.wtf(mTAG, "Error creating AtRes value", ex);
- return new EapError(ex);
- }
- }
-
- @VisibleForTesting
- class RandChallengeResult {
- public final byte[] res;
- public final byte[] ik;
- public final byte[] ck;
- public final byte[] auts;
-
- RandChallengeResult(byte[] res, byte[] ik, byte[] ck)
- throws EapSimAkaInvalidLengthException {
- if (!AtRes.isValidResLen(res.length)) {
- throw new EapSimAkaInvalidLengthException("Invalid RES length");
- } else if (ik.length != mIkLenBytes) {
- throw new EapSimAkaInvalidLengthException("Invalid IK length");
- } else if (ck.length != mCkLenBytes) {
- throw new EapSimAkaInvalidLengthException("Invalid CK length");
- }
-
- this.res = res;
- this.ik = ik;
- this.ck = ck;
- this.auts = null;
- }
-
- RandChallengeResult(byte[] auts) throws EapSimAkaInvalidLengthException {
- if (auts.length != AtAuts.AUTS_LENGTH) {
- throw new EapSimAkaInvalidLengthException("Invalid AUTS length");
- }
-
- this.res = null;
- this.ik = null;
- this.ck = null;
- this.auts = auts;
- }
-
- private boolean isSuccessfulResult() {
- return res != null && ik != null && ck != null;
- }
- }
-
- private boolean isValidChallengeAttributes(EapAkaTypeData eapAkaTypeData) {
- Set<Integer> attrs = eapAkaTypeData.attributeMap.keySet();
-
- // must contain: AT_RAND, AT_AUTN, AT_MAC
- return attrs.contains(EAP_AT_RAND)
- && attrs.contains(EAP_AT_AUTN)
- && attrs.contains(EAP_AT_MAC);
- }
-
- private RandChallengeResult getRandChallengeResult(EapAkaTypeData eapAkaTypeData)
- throws EapSimAkaAuthenticationFailureException, EapSimAkaInvalidLengthException {
- AtRandAka atRandAka = (AtRandAka) eapAkaTypeData.attributeMap.get(EAP_AT_RAND);
- AtAutn atAutn = (AtAutn) eapAkaTypeData.attributeMap.get(EAP_AT_AUTN);
-
- // pre-Base64 formatting needs to be: [Length][RAND][Length][AUTN]
- int randLen = atRandAka.rand.length;
- int autnLen = atAutn.autn.length;
- ByteBuffer formattedChallenge = ByteBuffer.allocate(1 + randLen + 1 + autnLen);
- formattedChallenge.put((byte) randLen);
- formattedChallenge.put(atRandAka.rand);
- formattedChallenge.put((byte) autnLen);
- formattedChallenge.put(atAutn.autn);
-
- byte[] challengeResponse =
- processUiccAuthentication(
- mTAG,
- TelephonyManager.AUTHTYPE_EAP_AKA,
- formattedChallenge.array());
- ByteBuffer buffer = ByteBuffer.wrap(challengeResponse);
- byte tag = buffer.get();
-
- switch (tag) {
- case mSuccess:
- // response format: [tag][RES length][RES][IK length][IK][CK length][CK]
- break;
- case mSynchronization:
- // response format: [tag][AUTS length][AUTS]
- byte[] auts = new byte[Byte.toUnsignedInt(buffer.get())];
- buffer.get(auts);
-
- LOG.i(mTAG, "Synchronization Failure");
- LOG.d(
- mTAG,
- "RAND=" + LOG.pii(atRandAka.rand)
- + " AUTN=" + LOG.pii(atAutn.autn)
- + " AUTS=" + LOG.pii(auts));
-
- return new RandChallengeResult(auts);
- default:
- throw new EapAkaInvalidAuthenticationResponse(
- "Invalid tag for UICC response: " + String.format("%02X", tag));
- }
-
- byte[] res = new byte[Byte.toUnsignedInt(buffer.get())];
- buffer.get(res);
-
- byte[] ik = new byte[Byte.toUnsignedInt(buffer.get())];
- buffer.get(ik);
-
- byte[] ck = new byte[Byte.toUnsignedInt(buffer.get())];
- buffer.get(ck);
-
- LOG.d(
- mTAG,
- "RAND=" + LOG.pii(atRandAka.rand)
- + " AUTN=" + LOG.pii(atAutn.autn)
- + " RES=" + LOG.pii(res)
- + " IK=" + LOG.pii(ik)
- + " CK=" + LOG.pii(ck));
-
- return new RandChallengeResult(res, ik, ck);
- }
-
- protected EapResult buildAuthenticationRejectMessage(int eapIdentifier) {
- return buildResponseMessage(
- getEapMethod(),
- EAP_AKA_AUTHENTICATION_REJECT,
- eapIdentifier,
- new ArrayList<>());
- }
-
- @Nullable
- protected EapResult generateAndPersistEapAkaKeys(
- RandChallengeResult result, int eapIdentifier, EapAkaTypeData eapAkaTypeData) {
- try {
- MessageDigest sha1 = MessageDigest.getInstance(MASTER_KEY_GENERATION_ALG);
- byte[] mkInputData = getMkInputData(result);
- generateAndPersistKeys(mTAG, sha1, new Fips186_2Prf(), mkInputData);
- return null;
- } catch (NoSuchAlgorithmException | BufferUnderflowException ex) {
- LOG.e(mTAG, "Error while creating keys", ex);
- return buildClientErrorResponse(
- eapIdentifier, EAP_TYPE_AKA, AtClientErrorCode.UNABLE_TO_PROCESS);
- }
- }
-
- private byte[] getMkInputData(RandChallengeResult result) {
- int numInputBytes = mIdentity.length + result.ik.length + result.ck.length;
- ByteBuffer buffer = ByteBuffer.allocate(numInputBytes);
- buffer.put(mIdentity);
- buffer.put(result.ik);
- buffer.put(result.ck);
- return buffer.array();
- }
- }
-
- EapAkaTypeData getEapSimAkaTypeData(AtClientErrorCode clientErrorCode) {
- return new EapAkaTypeData(EAP_AKA_CLIENT_ERROR, Arrays.asList(clientErrorCode));
- }
-
- EapAkaTypeData getEapSimAkaTypeData(int eapSubtype, List<EapSimAkaAttribute> attributes) {
- return new EapAkaTypeData(eapSubtype, attributes);
- }
-}
diff --git a/src/java/com/android/internal/net/eap/statemachine/EapAkaPrimeMethodStateMachine.java b/src/java/com/android/internal/net/eap/statemachine/EapAkaPrimeMethodStateMachine.java
deleted file mode 100644
index d2e8ba25..00000000
--- a/src/java/com/android/internal/net/eap/statemachine/EapAkaPrimeMethodStateMachine.java
+++ /dev/null
@@ -1,336 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.statemachine;
-
-import static com.android.internal.net.eap.EapAuthenticator.LOG;
-import static com.android.internal.net.eap.message.EapData.EAP_TYPE_AKA_PRIME;
-import static com.android.internal.net.eap.message.simaka.EapAkaTypeData.EAP_AKA_CLIENT_ERROR;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_AUTN;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_KDF;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_KDF_INPUT;
-
-import android.annotation.Nullable;
-import android.content.Context;
-import android.net.eap.EapSessionConfig.EapAkaPrimeConfig;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.net.crypto.KeyGenerationUtils;
-import com.android.internal.net.eap.EapResult;
-import com.android.internal.net.eap.crypto.HmacSha256ByteSigner;
-import com.android.internal.net.eap.message.EapData.EapMethod;
-import com.android.internal.net.eap.message.EapMessage;
-import com.android.internal.net.eap.message.simaka.EapAkaPrimeTypeData;
-import com.android.internal.net.eap.message.simaka.EapAkaPrimeTypeData.EapAkaPrimeTypeDataDecoder;
-import com.android.internal.net.eap.message.simaka.EapAkaTypeData;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtAutn;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtClientErrorCode;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtKdf;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtKdfInput;
-import com.android.internal.net.eap.message.simaka.EapSimAkaTypeData.DecodeResult;
-
-import java.nio.BufferOverflowException;
-import java.nio.BufferUnderflowException;
-import java.nio.ByteBuffer;
-import java.nio.charset.StandardCharsets;
-import java.security.GeneralSecurityException;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-
-import javax.crypto.Mac;
-import javax.crypto.spec.SecretKeySpec;
-
-/**
- * EapAkaPrimeMethodStateMachine represents the valid paths possible for the EAP-AKA' protocol.
- *
- * <p>EAP-AKA' sessions will always follow the path:
- *
- * Created --+--> Identity --+--> Challenge --> Final
- * | |
- * +---------------+
- *
- * <p>Note: If the EAP-Request/AKA'-Challenge message contains an AUTN with an invalid sequence
- * number, the peer will indicate a synchronization failure to the server and a new challenge will
- * be attempted.
- *
- * <p>Note: EAP-Request/Notification messages can be received at any point in the above state
- * machine At most one EAP-AKA'/Notification message is allowed per EAP-AKA' session.
- *
- * @see <a href="https://tools.ietf.org/html/rfc4187">RFC 4187, Extensible Authentication Protocol
- * for Authentication and Key Agreement (EAP-AKA)</a>
- * @see <a href="https://tools.ietf.org/html/rfc5448">RFC 5448, Improved Extensible Authentication
- * 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;
-
- EapAkaPrimeMethodStateMachine(
- Context context, byte[] eapIdentity, EapAkaPrimeConfig eapAkaPrimeConfig) {
- this(
- context,
- eapIdentity,
- eapAkaPrimeConfig,
- EapAkaPrimeTypeData.getEapAkaPrimeTypeDataDecoder());
- }
-
- @VisibleForTesting
- protected EapAkaPrimeMethodStateMachine(
- Context context,
- byte[] eapIdentity,
- EapAkaPrimeConfig eapAkaPrimeConfig,
- EapAkaPrimeTypeDataDecoder eapAkaPrimeTypeDataDecoder) {
- super(context, eapIdentity, eapAkaPrimeConfig);
- mEapAkaPrimeConfig = eapAkaPrimeConfig;
- mEapAkaPrimeTypeDataDecoder = eapAkaPrimeTypeDataDecoder;
-
- transitionTo(new CreatedState());
- }
-
- @Override
- @EapMethod
- int getEapMethod() {
- return EAP_TYPE_AKA_PRIME;
- }
-
- @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);
- }
-
- @Override
- protected String getIdentityPrefix() {
- return AKA_PRIME_IDENTITY_PREFIX;
- }
-
- @Override
- protected ChallengeState buildChallengeState() {
- return new ChallengeState();
- }
-
- @Override
- protected ChallengeState buildChallengeState(byte[] identity) {
- return new ChallengeState(identity);
- }
-
- @Override
- protected String getMacAlgorithm() {
- return MAC_ALGORITHM_STRING;
- }
-
- protected class ChallengeState extends EapAkaMethodStateMachine.ChallengeState {
- private final String mTAG = ChallengeState.class.getSimpleName();
-
- ChallengeState() {
- super();
- }
-
- ChallengeState(byte[] identity) {
- super(identity);
- }
-
- @Override
- protected EapResult handleChallengeAuthentication(
- EapMessage message, EapAkaTypeData eapAkaTypeData) {
- EapAkaPrimeTypeData eapAkaPrimeTypeData = (EapAkaPrimeTypeData) eapAkaTypeData;
-
- if (!isValidChallengeAttributes(eapAkaPrimeTypeData)) {
- return buildAuthenticationRejectMessage(message.eapIdentifier);
- }
- return super.handleChallengeAuthentication(message, eapAkaPrimeTypeData);
- }
-
- @VisibleForTesting
- boolean isValidChallengeAttributes(EapAkaPrimeTypeData eapAkaPrimeTypeData) {
- Map<Integer, EapSimAkaAttribute> attrs = eapAkaPrimeTypeData.attributeMap;
-
- if (!attrs.containsKey(EAP_AT_KDF) || !attrs.containsKey(EAP_AT_KDF_INPUT)) {
- return false;
- }
-
- // TODO(b/143073851): implement KDF resolution specified in RFC 5448#3.2
- // This is safe, as there only exists one defined KDF.
- AtKdf atKdf = (AtKdf) attrs.get(EAP_AT_KDF);
- if (atKdf.kdf != SUPPORTED_KDF) {
- return false;
- }
-
- AtKdfInput atKdfInput = (AtKdfInput) attrs.get(EAP_AT_KDF_INPUT);
- if (atKdfInput.networkName.length == 0) {
- return false;
- }
-
- boolean hasMatchingNetworkNames =
- hasMatchingNetworkNames(
- mEapAkaPrimeConfig.networkName,
- new String(atKdfInput.networkName, StandardCharsets.UTF_8));
- return mEapAkaPrimeConfig.allowMismatchedNetworkNames || hasMatchingNetworkNames;
- }
-
- /**
- * Compares the peer's network name against the server's network name.
- *
- * <p>RFC 5448#3.1 describes how the network names are to be compared: "each name is broken
- * down to the fields separated by colons. If one of the names has more colons and fields
- * than the other one, the additional fields are ignored. The remaining sequences of fields
- * are compared. This algorithm allows a prefix match".
- *
- * @return true iff one network name matches the other, as defined by RC 5448#3.1
- */
- @VisibleForTesting
- boolean hasMatchingNetworkNames(String peerNetworkName, String serverNetworkName) {
- // compare network names according to RFC 5448#3.1
- if (peerNetworkName.isEmpty() || serverNetworkName.isEmpty()) {
- return true;
- }
-
- String[] peerNetworkNameFields = peerNetworkName.split(":");
- String[] serverNetworkNameFields = serverNetworkName.split(":");
- int numFieldsToCompare =
- Math.min(peerNetworkNameFields.length, serverNetworkNameFields.length);
- for (int i = 0; i < numFieldsToCompare; i++) {
- if (!peerNetworkNameFields[i].equals(serverNetworkNameFields[i])) {
- LOG.i(
- mTAG,
- "EAP-AKA' network names don't match."
- + " Peer: " + LOG.pii(peerNetworkName)
- + ", Server: " + LOG.pii(serverNetworkName));
- return false;
- }
- }
-
- 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
- *
- * <p>CK' and IK' generation is specified in TS 133 402 Annex A.2, which relies on the key
- * derivation function KDF specified in TS 133 220 Annex B.2.
- */
- @VisibleForTesting
- byte[] deriveCkIkPrime(
- RandChallengeResult randChallengeResult, AtKdfInput atKdfInput, AtAutn atAutn)
- throws GeneralSecurityException {
- final int fcLen = 1;
- int lengthFieldLen = 2;
-
- // SQN ^ AK is the first 6B of the AUTN value
- byte[] sqnXorAk = Arrays.copyOf(atAutn.autn, SQN_XOR_AK_LEN);
- int sLength =
- fcLen
- + atKdfInput.networkName.length + lengthFieldLen
- + SQN_XOR_AK_LEN + lengthFieldLen;
-
- ByteBuffer dataToSign = ByteBuffer.allocate(sLength);
- dataToSign.put((byte) FC);
- dataToSign.put(atKdfInput.networkName);
- dataToSign.putShort((short) atKdfInput.networkName.length);
- dataToSign.put(sqnXorAk);
- dataToSign.putShort((short) SQN_XOR_AK_LEN);
-
- int keyLen = randChallengeResult.ck.length + randChallengeResult.ik.length;
- ByteBuffer key = ByteBuffer.allocate(keyLen);
- key.put(randChallengeResult.ck);
- key.put(randChallengeResult.ik);
-
- Mac mac = Mac.getInstance(MAC_ALGORITHM_STRING);
- mac.init(new SecretKeySpec(key.array(), MAC_ALGORITHM_STRING));
- return mac.doFinal(dataToSign.array());
- }
- }
-
- EapAkaPrimeTypeData getEapSimAkaTypeData(AtClientErrorCode clientErrorCode) {
- return new EapAkaPrimeTypeData(EAP_AKA_CLIENT_ERROR, Arrays.asList(clientErrorCode));
- }
-
- EapAkaPrimeTypeData getEapSimAkaTypeData(int eapSubtype, List<EapSimAkaAttribute> attributes) {
- return new EapAkaPrimeTypeData(eapSubtype, attributes);
- }
-}
diff --git a/src/java/com/android/internal/net/eap/statemachine/EapMethodStateMachine.java b/src/java/com/android/internal/net/eap/statemachine/EapMethodStateMachine.java
deleted file mode 100644
index bab182b9..00000000
--- a/src/java/com/android/internal/net/eap/statemachine/EapMethodStateMachine.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.statemachine;
-
-import static com.android.internal.net.eap.EapAuthenticator.LOG;
-import static com.android.internal.net.eap.message.EapData.EAP_NOTIFICATION;
-import static com.android.internal.net.eap.message.EapMessage.EAP_CODE_FAILURE;
-import static com.android.internal.net.eap.message.EapMessage.EAP_CODE_SUCCESS;
-
-import android.annotation.Nullable;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.net.eap.EapResult;
-import com.android.internal.net.eap.EapResult.EapError;
-import com.android.internal.net.eap.EapResult.EapFailure;
-import com.android.internal.net.eap.exceptions.EapInvalidRequestException;
-import com.android.internal.net.eap.message.EapData.EapMethod;
-import com.android.internal.net.eap.message.EapMessage;
-import com.android.internal.net.utils.SimpleStateMachine;
-
-/**
- * EapMethodStateMachine is an abstract class representing a state machine for EAP Method
- * implementations.
- */
-public abstract class EapMethodStateMachine extends SimpleStateMachine<EapMessage, EapResult> {
- /**
- * Returns the EAP Method type for this EapMethodStateMachine implementation.
- *
- * @return the IANA value for the EAP Method represented by this EapMethodStateMachine
- */
- @EapMethod
- abstract int getEapMethod();
-
- @VisibleForTesting
- protected SimpleState getState() {
- return mState;
- }
-
- @VisibleForTesting
- protected void transitionTo(EapMethodState newState) {
- LOG.d(
- this.getClass().getSimpleName(),
- "Transitioning from " + mState.getClass().getSimpleName()
- + " to " + newState.getClass().getSimpleName());
- super.transitionTo(newState);
- }
-
- abstract EapResult handleEapNotification(String tag, EapMessage message);
-
- protected abstract class EapMethodState extends SimpleState {
- /**
- * Handles premature EAP-Success and EAP-Failure messages, as well as EAP-Notification
- * messages.
- *
- * @param tag the String logging tag to be used while handing message
- * @param message the EapMessage to be checked for early Success/Failure/Notification
- * messages
- * @return the EapResult generated from handling the give EapMessage, or null if the message
- * Type matches that of the current EAP method
- */
- @Nullable
- EapResult handleEapSuccessFailureNotification(String tag, EapMessage message) {
- if (message.eapCode == EAP_CODE_SUCCESS) {
- // EAP-SUCCESS is required to be the last EAP message sent during the EAP protocol,
- // so receiving a premature SUCCESS message is an unrecoverable error.
- return new EapError(
- new EapInvalidRequestException(
- "Received an EAP-Success in the " + tag));
- } else if (message.eapCode == EAP_CODE_FAILURE) {
- transitionTo(new EapAkaMethodStateMachine.FinalState());
- return new EapFailure();
- } else if (message.eapData.eapType == EAP_NOTIFICATION) {
- return handleEapNotification(tag, message);
- } else if (message.eapData.eapType != getEapMethod()) {
- return new EapError(new EapInvalidRequestException(
- "Expected EAP Type " + getEapMethod()
- + ", received " + message.eapData.eapType));
- }
-
- return null;
- }
- }
-
- protected class FinalState extends EapMethodState {
- @Override
- public EapResult process(EapMessage msg) {
- return new EapError(
- new IllegalStateException("Attempting to process from a FinalState"));
- }
- }
-}
diff --git a/src/java/com/android/internal/net/eap/statemachine/EapMsChapV2MethodStateMachine.java b/src/java/com/android/internal/net/eap/statemachine/EapMsChapV2MethodStateMachine.java
deleted file mode 100644
index 490b8ba1..00000000
--- a/src/java/com/android/internal/net/eap/statemachine/EapMsChapV2MethodStateMachine.java
+++ /dev/null
@@ -1,673 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.statemachine;
-
-import static com.android.internal.net.eap.EapAuthenticator.LOG;
-import static com.android.internal.net.eap.message.EapData.EAP_NOTIFICATION;
-import static com.android.internal.net.eap.message.EapData.EAP_TYPE_MSCHAP_V2;
-import static com.android.internal.net.eap.message.EapData.EAP_TYPE_STRING;
-import static com.android.internal.net.eap.message.EapMessage.EAP_CODE_FAILURE;
-import static com.android.internal.net.eap.message.EapMessage.EAP_CODE_RESPONSE;
-import static com.android.internal.net.eap.message.EapMessage.EAP_CODE_SUCCESS;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2TypeData.EAP_MSCHAP_V2_FAILURE;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2TypeData.EAP_MSCHAP_V2_SUCCESS;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2TypeData.EAP_OP_CODE_STRING;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2TypeData.EapMsChapV2FailureRequest.EAP_ERROR_CODE_STRING;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2TypeData.EapMsChapV2FailureResponse.getEapMsChapV2FailureResponse;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2TypeData.EapMsChapV2SuccessResponse.getEapMsChapV2SuccessResponse;
-
-import android.net.eap.EapSessionConfig.EapMsChapV2Config;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.net.eap.EapResult;
-import com.android.internal.net.eap.EapResult.EapError;
-import com.android.internal.net.eap.EapResult.EapFailure;
-import com.android.internal.net.eap.EapResult.EapResponse;
-import com.android.internal.net.eap.EapResult.EapSuccess;
-import com.android.internal.net.eap.crypto.ParityBitUtil;
-import com.android.internal.net.eap.exceptions.EapInvalidRequestException;
-import com.android.internal.net.eap.exceptions.EapSilentException;
-import com.android.internal.net.eap.exceptions.mschapv2.EapMsChapV2ParsingException;
-import com.android.internal.net.eap.message.EapData;
-import com.android.internal.net.eap.message.EapData.EapMethod;
-import com.android.internal.net.eap.message.EapMessage;
-import com.android.internal.net.eap.message.mschapv2.EapMsChapV2TypeData;
-import com.android.internal.net.eap.message.mschapv2.EapMsChapV2TypeData.EapMsChapV2ChallengeRequest;
-import com.android.internal.net.eap.message.mschapv2.EapMsChapV2TypeData.EapMsChapV2ChallengeResponse;
-import com.android.internal.net.eap.message.mschapv2.EapMsChapV2TypeData.EapMsChapV2FailureRequest;
-import com.android.internal.net.eap.message.mschapv2.EapMsChapV2TypeData.EapMsChapV2SuccessRequest;
-import com.android.internal.net.eap.message.mschapv2.EapMsChapV2TypeData.EapMsChapV2TypeDataDecoder;
-import com.android.internal.net.eap.message.mschapv2.EapMsChapV2TypeData.EapMsChapV2TypeDataDecoder.DecodeResult;
-import com.android.internal.net.utils.Log;
-import com.android.org.bouncycastle.crypto.digests.MD4Digest;
-
-import java.io.UnsupportedEncodingException;
-import java.nio.BufferUnderflowException;
-import java.nio.ByteBuffer;
-import java.nio.charset.StandardCharsets;
-import java.security.GeneralSecurityException;
-import java.security.MessageDigest;
-import java.security.SecureRandom;
-import java.util.Arrays;
-
-import javax.crypto.Cipher;
-import javax.crypto.SecretKey;
-import javax.crypto.SecretKeyFactory;
-import javax.crypto.spec.DESKeySpec;
-
-/**
- * EapMsChapV2MethodStateMachine represents the valid paths possible for the EAP MSCHAPv2 protocol.
- *
- * <p>EAP MSCHAPv2 sessions will always follow the path:
- *
- * <p>CreatedState
- * |
- * +--> ChallengeState
- * |
- * +--> ValidateAuthenticatorState --+--> AwaitingEapSuccessState --> FinalState
- * |
- * +--> AwaitingEapFailureState --> FinalState
- *
- * <p>Note: All Failure-Request messages received in the PostChallenge state will be responded to
- * with Failure-Response messages. That is, retryable failures <i>will not</i> be retried.
- *
- * <p>Note: The EAP standard states that EAP methods may disallow EAP Notification messages for the
- * duration of the method (RFC 3748#5.2). EAP MSCHAPv2 does not explicitly ban these packets, so
- * they are allowed at any time (except once a terminal state is reached).
- *
- * @see <a href="https://tools.ietf.org/html/draft-kamath-pppext-eap-mschapv2-02">Microsoft EAP CHAP
- * Extensions Draft (EAP MSCHAPv2)</a>
- * @see <a href="https://tools.ietf.org/html/rfc2759">RFC 2759, Microsoft PPP CHAP Extensions,
- * Version 2 (MSCHAPv2)</a>
- * @see <a href="https://tools.ietf.org/html/rfc3079">RFC 3079, Deriving Keys for use with Microsoft
- * Point-to-Point Encryption (MPPE)</a>
- */
-public class EapMsChapV2MethodStateMachine extends EapMethodStateMachine {
- private static final String SHA_ALG = "SHA-1";
- private static final String DES_ALG = "DES/ECB/NoPadding";
- private static final String DES_KEY_FACTORY = "DES";
- private static final int PEER_CHALLENGE_SIZE = 16;
- private static final int CHALLENGE_HASH_LEN = 8;
- private static final int PASSWORD_HASH_LEN = 16;
- private static final int PASSWORD_HASH_HASH_LEN = 16;
- private static final int RESPONSE_LEN = 24;
- private static final int Z_PASSWORD_HASH_LEN = 21;
- private static final int Z_PASSWORD_SECTION_LEN = 7;
- private static final int RESPONSE_SECTION_LEN = 8;
- private static final int SHS_PAD_LEN = 40;
- private static final int MASTER_KEY_LEN = 16;
- private static final int SESSION_KEY_LEN = 16;
- private static final int MASTER_SESSION_KEY_LEN = 2 * SESSION_KEY_LEN;
-
- // Reserved for future use and must be 0 (EAP MSCHAPv2#2.2)
- private static final int FLAGS = 0;
-
- // we all need a little magic in our lives
- // Defined in RFC 2759#8.7. Constants used for Success response generation.
- private static final byte[] CHALLENGE_MAGIC_1 = {
- (byte) 0x4D, (byte) 0x61, (byte) 0x67, (byte) 0x69, (byte) 0x63, (byte) 0x20, (byte) 0x73,
- (byte) 0x65, (byte) 0x72, (byte) 0x76, (byte) 0x65, (byte) 0x72, (byte) 0x20, (byte) 0x74,
- (byte) 0x6F, (byte) 0x20, (byte) 0x63, (byte) 0x6C, (byte) 0x69, (byte) 0x65, (byte) 0x6E,
- (byte) 0x74, (byte) 0x20, (byte) 0x73, (byte) 0x69, (byte) 0x67, (byte) 0x6E, (byte) 0x69,
- (byte) 0x6E, (byte) 0x67, (byte) 0x20, (byte) 0x63, (byte) 0x6F, (byte) 0x6E, (byte) 0x73,
- (byte) 0x74, (byte) 0x61, (byte) 0x6E, (byte) 0x74
- };
- private static final byte[] CHALLENGE_MAGIC_2 = {
- (byte) 0x50, (byte) 0x61, (byte) 0x64, (byte) 0x20, (byte) 0x74, (byte) 0x6F, (byte) 0x20,
- (byte) 0x6D, (byte) 0x61, (byte) 0x6B, (byte) 0x65, (byte) 0x20, (byte) 0x69, (byte) 0x74,
- (byte) 0x20, (byte) 0x64, (byte) 0x6F, (byte) 0x20, (byte) 0x6D, (byte) 0x6F, (byte) 0x72,
- (byte) 0x65, (byte) 0x20, (byte) 0x74, (byte) 0x68, (byte) 0x61, (byte) 0x6E, (byte) 0x20,
- (byte) 0x6F, (byte) 0x6E, (byte) 0x65, (byte) 0x20, (byte) 0x69, (byte) 0x74, (byte) 0x65,
- (byte) 0x72, (byte) 0x61, (byte) 0x74, (byte) 0x69, (byte) 0x6F, (byte) 0x6E
- };
-
- // Defined in RFC 3079#3.4. Constants used for Master Session Key (MSK) generation
- private static final byte[] SHS_PAD_1 = new byte[SHS_PAD_LEN];
- private static final byte[] SHS_PAD_2 = new byte[SHS_PAD_LEN];
-
- static {
- Arrays.fill(SHS_PAD_2, (byte) 0xF2);
- }
-
- private static final byte[] MSK_MAGIC_1 = {
- (byte) 0x54, (byte) 0x68, (byte) 0x69, (byte) 0x73, (byte) 0x20, (byte) 0x69,
- (byte) 0x73, (byte) 0x20, (byte) 0x74, (byte) 0x68, (byte) 0x65, (byte) 0x20,
- (byte) 0x4D, (byte) 0x50, (byte) 0x50, (byte) 0x45, (byte) 0x20, (byte) 0x4D,
- (byte) 0x61, (byte) 0x73, (byte) 0x74, (byte) 0x65, (byte) 0x72, (byte) 0x20,
- (byte) 0x4B, (byte) 0x65, (byte) 0x79
- };
- private static final byte[] MSK_MAGIC_2 = {
- (byte) 0x4F, (byte) 0x6E, (byte) 0x20, (byte) 0x74, (byte) 0x68, (byte) 0x65,
- (byte) 0x20, (byte) 0x63, (byte) 0x6C, (byte) 0x69, (byte) 0x65, (byte) 0x6E,
- (byte) 0x74, (byte) 0x20, (byte) 0x73, (byte) 0x69, (byte) 0x64, (byte) 0x65,
- (byte) 0x2C, (byte) 0x20, (byte) 0x74, (byte) 0x68, (byte) 0x69, (byte) 0x73,
- (byte) 0x20, (byte) 0x69, (byte) 0x73, (byte) 0x20, (byte) 0x74, (byte) 0x68,
- (byte) 0x65, (byte) 0x20, (byte) 0x73, (byte) 0x65, (byte) 0x6E, (byte) 0x64,
- (byte) 0x20, (byte) 0x6B, (byte) 0x65, (byte) 0x79, (byte) 0x3B, (byte) 0x20,
- (byte) 0x6F, (byte) 0x6E, (byte) 0x20, (byte) 0x74, (byte) 0x68, (byte) 0x65,
- (byte) 0x20, (byte) 0x73, (byte) 0x65, (byte) 0x72, (byte) 0x76, (byte) 0x65,
- (byte) 0x72, (byte) 0x20, (byte) 0x73, (byte) 0x69, (byte) 0x64, (byte) 0x65,
- (byte) 0x2C, (byte) 0x20, (byte) 0x69, (byte) 0x74, (byte) 0x20, (byte) 0x69,
- (byte) 0x73, (byte) 0x20, (byte) 0x74, (byte) 0x68, (byte) 0x65, (byte) 0x20,
- (byte) 0x72, (byte) 0x65, (byte) 0x63, (byte) 0x65, (byte) 0x69, (byte) 0x76,
- (byte) 0x65, (byte) 0x20, (byte) 0x6B, (byte) 0x65, (byte) 0x79, (byte) 0x2E
- };
- private static final byte[] MSK_MAGIC_3 = {
- (byte) 0x4F, (byte) 0x6E, (byte) 0x20, (byte) 0x74, (byte) 0x68, (byte) 0x65,
- (byte) 0x20, (byte) 0x63, (byte) 0x6C, (byte) 0x69, (byte) 0x65, (byte) 0x6E,
- (byte) 0x74, (byte) 0x20, (byte) 0x73, (byte) 0x69, (byte) 0x64, (byte) 0x65,
- (byte) 0x2C, (byte) 0x20, (byte) 0x74, (byte) 0x68, (byte) 0x69, (byte) 0x73,
- (byte) 0x20, (byte) 0x69, (byte) 0x73, (byte) 0x20, (byte) 0x74, (byte) 0x68,
- (byte) 0x65, (byte) 0x20, (byte) 0x72, (byte) 0x65, (byte) 0x63, (byte) 0x65,
- (byte) 0x69, (byte) 0x76, (byte) 0x65, (byte) 0x20, (byte) 0x6B, (byte) 0x65,
- (byte) 0x79, (byte) 0x3B, (byte) 0x20, (byte) 0x6F, (byte) 0x6E, (byte) 0x20,
- (byte) 0x74, (byte) 0x68, (byte) 0x65, (byte) 0x20, (byte) 0x73, (byte) 0x65,
- (byte) 0x72, (byte) 0x76, (byte) 0x65, (byte) 0x72, (byte) 0x20, (byte) 0x73,
- (byte) 0x69, (byte) 0x64, (byte) 0x65, (byte) 0x2C, (byte) 0x20, (byte) 0x69,
- (byte) 0x74, (byte) 0x20, (byte) 0x69, (byte) 0x73, (byte) 0x20, (byte) 0x74,
- (byte) 0x68, (byte) 0x65, (byte) 0x20, (byte) 0x73, (byte) 0x65, (byte) 0x6E,
- (byte) 0x64, (byte) 0x20, (byte) 0x6B, (byte) 0x65, (byte) 0x79, (byte) 0x2E
- };
-
- private final EapMsChapV2Config mEapMsChapV2Config;
- private final SecureRandom mSecureRandom;
- private final EapMsChapV2TypeDataDecoder mTypeDataDecoder;
-
- public EapMsChapV2MethodStateMachine(
- EapMsChapV2Config eapMsChapV2Config, SecureRandom secureRandom) {
- this(eapMsChapV2Config, secureRandom, new EapMsChapV2TypeDataDecoder());
- }
-
- @VisibleForTesting
- EapMsChapV2MethodStateMachine(
- EapMsChapV2Config eapMsChapV2Config,
- SecureRandom secureRandom,
- EapMsChapV2TypeDataDecoder eapMsChapV2TypeDataDecoder) {
- this.mEapMsChapV2Config = eapMsChapV2Config;
- this.mSecureRandom = secureRandom;
- this.mTypeDataDecoder = eapMsChapV2TypeDataDecoder;
-
- transitionTo(new CreatedState());
- }
-
- @Override
- @EapMethod
- int getEapMethod() {
- return EAP_TYPE_MSCHAP_V2;
- }
-
- @Override
- EapResult handleEapNotification(String tag, EapMessage message) {
- return EapStateMachine.handleNotification(tag, message);
- }
-
- protected class CreatedState extends EapMethodState {
- private final String mTAG = this.getClass().getSimpleName();
-
- @Override
- public EapResult process(EapMessage message) {
- EapResult result = handleEapSuccessFailureNotification(mTAG, message);
- if (result != null) {
- return result;
- }
-
- DecodeResult<EapMsChapV2ChallengeRequest> decodeResult =
- mTypeDataDecoder.decodeChallengeRequest(mTAG, message.eapData.eapTypeData);
- if (!decodeResult.isSuccessfulDecode()) {
- return decodeResult.eapError;
- }
-
- return transitionAndProcess(new ChallengeState(), message);
- }
- }
-
- protected class ChallengeState extends EapMethodState {
- private final String mTAG = this.getClass().getSimpleName();
-
- @Override
- public EapResult process(EapMessage message) {
- EapResult result = handleEapSuccessFailureNotification(mTAG, message);
- if (result != null) {
- return result;
- }
-
- DecodeResult<EapMsChapV2ChallengeRequest> decodeResult =
- mTypeDataDecoder.decodeChallengeRequest(mTAG, message.eapData.eapTypeData);
- if (!decodeResult.isSuccessfulDecode()) {
- return decodeResult.eapError;
- }
-
- EapMsChapV2ChallengeRequest challengeRequest = decodeResult.eapTypeData;
- LOG.d(
- mTAG,
- "Received Challenge Request:"
- + " Challenge=" + LOG.pii(challengeRequest.challenge)
- + " Server-Name=" + Log.byteArrayToHexString(challengeRequest.name));
-
- byte[] peerChallenge = new byte[PEER_CHALLENGE_SIZE];
- mSecureRandom.nextBytes(peerChallenge);
-
- byte[] ntResponse;
- try {
- ntResponse =
- generateNtResponse(
- challengeRequest.challenge,
- peerChallenge,
- mEapMsChapV2Config.username,
- mEapMsChapV2Config.password);
- } catch (GeneralSecurityException ex) {
- LOG.e(mTAG, "Error generating EAP MSCHAPv2 Challenge response", ex);
- return new EapError(ex);
- }
-
- LOG.d(
- mTAG,
- "Generating Challenge Response:"
- + " Username=" + LOG.pii(mEapMsChapV2Config.username)
- + " Peer-Challenge=" + LOG.pii(peerChallenge)
- + " NT-Response=" + LOG.pii(ntResponse));
-
- try {
- EapMsChapV2ChallengeResponse challengeResponse =
- new EapMsChapV2ChallengeResponse(
- challengeRequest.msChapV2Id,
- peerChallenge,
- ntResponse,
- FLAGS,
- usernameToBytes(mEapMsChapV2Config.username));
- transitionTo(
- new ValidateAuthenticatorState(
- challengeRequest.challenge, peerChallenge, ntResponse));
-
- return buildEapMessageResponse(mTAG, message.eapIdentifier, challengeResponse);
- } catch (EapMsChapV2ParsingException ex) {
- LOG.e(mTAG, "Error building response type data", ex);
- return new EapError(ex);
- }
- }
- }
-
- protected class ValidateAuthenticatorState extends EapMethodState {
- private final String mTAG = this.getClass().getSimpleName();
-
- private final byte[] mAuthenticatorChallenge;
- private final byte[] mPeerChallenge;
- private final byte[] mNtResponse;
-
- @VisibleForTesting
- ValidateAuthenticatorState(
- byte[] authenticatorChallenge, byte[] peerChallenge, byte[] ntResponse) {
- this.mAuthenticatorChallenge = authenticatorChallenge;
- this.mPeerChallenge = peerChallenge;
- this.mNtResponse = ntResponse;
- }
-
- @Override
- public EapResult process(EapMessage message) {
- EapResult result = handleEapSuccessFailureNotification(mTAG, message);
- if (result != null) {
- return result;
- }
-
- int opCode;
- try {
- opCode = mTypeDataDecoder.getOpCode(message.eapData.eapTypeData);
- } catch (BufferUnderflowException ex) {
- LOG.e(mTAG, "Empty type data received in ValidateAuthenticatorState", ex);
- return new EapError(ex);
- }
-
- LOG.d(
- mTAG,
- "Received Op Code: "
- + EAP_OP_CODE_STRING.getOrDefault(opCode, "Unknown")
- + " (" + opCode + ")");
-
- switch (opCode) {
- case EAP_MSCHAP_V2_SUCCESS:
- DecodeResult<EapMsChapV2SuccessRequest> successDecodeResult =
- mTypeDataDecoder.decodeSuccessRequest(
- mTAG, message.eapData.eapTypeData);
- if (!successDecodeResult.isSuccessfulDecode()) {
- return successDecodeResult.eapError;
- }
-
- EapMsChapV2SuccessRequest successRequest = successDecodeResult.eapTypeData;
- LOG.d(
- mTAG,
- "Received SuccessRequest:"
- + " Auth-String=" + LOG.pii(successRequest.authBytes)
- + " Message=" + successRequest.message);
-
- boolean isSuccessfulAuth;
- try {
- isSuccessfulAuth =
- checkAuthenticatorResponse(
- mEapMsChapV2Config.password,
- mNtResponse,
- mPeerChallenge,
- mAuthenticatorChallenge,
- mEapMsChapV2Config.username,
- successRequest.authBytes);
- } catch (GeneralSecurityException | UnsupportedEncodingException ex) {
- LOG.e(mTAG, "Error validating MSCHAPv2 Authenticator Response", ex);
- return new EapError(ex);
- }
-
- if (!isSuccessfulAuth) {
- LOG.e(
- mTAG,
- "Authenticator Response does not match expected response value");
- transitionTo(new FinalState());
- return new EapFailure();
- }
-
- transitionTo(new AwaitingEapSuccessState(mNtResponse));
- return buildEapMessageResponse(
- mTAG, message.eapIdentifier, getEapMsChapV2SuccessResponse());
-
- case EAP_MSCHAP_V2_FAILURE:
- DecodeResult<EapMsChapV2FailureRequest> failureDecodeResult =
- mTypeDataDecoder.decodeFailureRequest(
- mTAG, message.eapData.eapTypeData);
- if (!failureDecodeResult.isSuccessfulDecode()) {
- return failureDecodeResult.eapError;
- }
-
- EapMsChapV2FailureRequest failureRequest = failureDecodeResult.eapTypeData;
- int errorCode = failureRequest.errorCode;
- LOG.e(
- mTAG,
- String.format(
- "Received MSCHAPv2 Failure-Request: E=%s (%d) R=%b V=%d M=%s",
- EAP_ERROR_CODE_STRING.getOrDefault(errorCode, "UNKNOWN"),
- errorCode,
- failureRequest.isRetryable,
- failureRequest.passwordChangeProtocol,
- failureRequest.message));
- transitionTo(new AwaitingEapFailureState());
- return buildEapMessageResponse(
- mTAG, message.eapIdentifier, getEapMsChapV2FailureResponse());
-
- default:
- LOG.e(mTAG, "Invalid OpCode: " + opCode);
- return new EapError(
- new EapInvalidRequestException(
- "Unexpected request received in EAP MSCHAPv2"));
- }
- }
- }
-
- protected class AwaitingEapSuccessState extends EapMethodState {
- private final String mTAG = this.getClass().getSimpleName();
-
- private final byte[] mNtResponse;
-
- AwaitingEapSuccessState(byte[] ntResponse) {
- this.mNtResponse = ntResponse;
- }
-
- @Override
- public EapResult process(EapMessage message) {
- if (message.eapCode == EAP_CODE_FAILURE) {
- LOG.e(mTAG, "Received EAP-Failure in PreSuccessState");
- transitionTo(new FinalState());
- return new EapFailure();
- } else if (message.eapCode != EAP_CODE_SUCCESS) {
- int eapType = message.eapData.eapType;
- if (eapType == EAP_NOTIFICATION) {
- return handleEapNotification(mTAG, message);
- } else {
- LOG.e(
- mTAG,
- "Received unexpected EAP message. Type="
- + EAP_TYPE_STRING.getOrDefault(
- eapType, "UNKNOWN (" + eapType + ")"));
- return new EapError(
- new EapInvalidRequestException(
- "Expected EAP Type "
- + getEapMethod()
- + ", received "
- + eapType));
- }
- }
-
- try {
- byte[] msk = generateMsk(mEapMsChapV2Config.password, mNtResponse);
- transitionTo(new FinalState());
- return new EapSuccess(msk, new byte[0]);
- } catch (GeneralSecurityException | UnsupportedEncodingException ex) {
- LOG.e(mTAG, "Error generating MSK for EAP MSCHAPv2", ex);
- return new EapError(ex);
- }
- }
- }
-
- protected class AwaitingEapFailureState extends EapMethodState {
- private final String mTAG = this.getClass().getSimpleName();
-
- @Override
- public EapResult process(EapMessage message) {
- EapResult result = handleEapSuccessFailureNotification(mTAG, message);
- if (result != null) {
- return result;
- }
- int eapType = message.eapData.eapType;
- LOG.e(
- mTAG,
- "Received unexpected EAP message. Type="
- + EAP_TYPE_STRING.getOrDefault(eapType, "UNKNOWN (" + eapType + ")"));
- return new EapError(
- new EapInvalidRequestException(
- "Expected EAP Type " + getEapMethod() + ", received " + eapType));
- }
- }
-
- private EapResult buildEapMessageResponse(
- String tag, int eapIdentifier, EapMsChapV2TypeData typeData) {
- try {
- EapData eapData = new EapData(getEapMethod(), typeData.encode());
- EapMessage eapMessage = new EapMessage(EAP_CODE_RESPONSE, eapIdentifier, eapData);
- return EapResponse.getEapResponse(eapMessage);
- } catch (EapSilentException ex) {
- LOG.e(tag, "Error building response EapMessage", ex);
- return new EapError(ex);
- }
- }
-
- /** Util for converting String username to "0-to-256 char username", as used in RFC 2759#8. */
- @VisibleForTesting
- static byte[] usernameToBytes(String username) {
- return username.getBytes(StandardCharsets.US_ASCII);
- }
-
- /**
- * Util for converting String password to "0-to-256-unicode-char password", as used in
- * RFC 2759#8.
- */
- @VisibleForTesting
- static byte[] passwordToBytes(String password) {
- return password.getBytes(StandardCharsets.UTF_16LE);
- }
-
- /* Implementation of RFC 2759#8.1: GenerateNTResponse() */
- @VisibleForTesting
- static byte[] generateNtResponse(
- byte[] authenticatorChallenge, byte[] peerChallenge, String username, String password)
- throws GeneralSecurityException {
- byte[] challenge = challengeHash(peerChallenge, authenticatorChallenge, username);
- byte[] passwordHash = ntPasswordHash(password);
- return challengeResponse(challenge, passwordHash);
- }
-
- /* Implementation of RFC 2759#8.2: ChallengeHash() */
- @VisibleForTesting
- static byte[] challengeHash(
- byte[] peerChallenge, byte[] authenticatorChallenge, String username)
- throws GeneralSecurityException {
- MessageDigest sha1 = MessageDigest.getInstance(SHA_ALG);
- sha1.update(peerChallenge);
- sha1.update(authenticatorChallenge);
- sha1.update(usernameToBytes(username));
- return Arrays.copyOf(sha1.digest(), CHALLENGE_HASH_LEN);
- }
-
- /* Implementation of RFC 2759#8.3: NtPasswordHash() */
- @VisibleForTesting
- static byte[] ntPasswordHash(String password) {
- MD4Digest md4 = new MD4Digest();
- byte[] passwordBytes = passwordToBytes(password);
- md4.update(passwordBytes, 0, passwordBytes.length);
-
- byte[] passwordHash = new byte[PASSWORD_HASH_LEN];
- md4.doFinal(passwordHash, 0);
- return passwordHash;
- }
-
- /* Implementation of RFC 2759#8.4: HashNtPasswordHash() */
- @VisibleForTesting
- static byte[] hashNtPasswordHash(byte[] passwordHash) {
- MD4Digest md4 = new MD4Digest();
- md4.update(passwordHash, 0, passwordHash.length);
-
- byte[] passwordHashHash = new byte[PASSWORD_HASH_HASH_LEN];
- md4.doFinal(passwordHashHash, 0);
- return passwordHashHash;
- }
-
- /* Implementation of RFC 2759#8.5: ChallengeResponse() */
- @VisibleForTesting
- static byte[] challengeResponse(byte[] challenge, byte[] passwordHash)
- throws GeneralSecurityException {
- byte[] zPasswordHash = Arrays.copyOf(passwordHash, Z_PASSWORD_HASH_LEN);
-
- ByteBuffer response = ByteBuffer.allocate(RESPONSE_LEN);
- for (int i = 0; i < 3; i++) {
- int from = i * Z_PASSWORD_SECTION_LEN;
- int to = from + Z_PASSWORD_SECTION_LEN;
- byte[] zPasswordSection = Arrays.copyOfRange(zPasswordHash, from, to);
- response.put(desEncrypt(challenge, zPasswordSection));
- }
- return response.array();
- }
-
- /* Implementation of RFC 2759#8.6: DesEncrypt() */
- @VisibleForTesting
- static byte[] desEncrypt(byte[] clear, byte[] key) throws GeneralSecurityException {
- if (key.length != Z_PASSWORD_SECTION_LEN) {
- throw new IllegalArgumentException("DES Key must be 7B before parity-bits are added");
- }
-
- key = ParityBitUtil.addParityBits(key);
- SecretKey secretKey =
- SecretKeyFactory.getInstance(DES_KEY_FACTORY).generateSecret(new DESKeySpec(key));
-
- Cipher des = Cipher.getInstance(DES_ALG);
- des.init(Cipher.ENCRYPT_MODE, secretKey);
- byte[] output = des.doFinal(clear);
-
- // RFC 2759#8.6 specifies 8B outputs for DesEncrypt()
- return Arrays.copyOf(output, RESPONSE_SECTION_LEN);
- }
-
- /**
- * Implementation of RFC 2759#8.7: GenerateAuthenticatorResponse()
- *
- * <p>Keep response as byte[] so checkAuthenticatorResponse() can easily compare byte[]'s
- */
- @VisibleForTesting
- static byte[] generateAuthenticatorResponse(
- String password,
- byte[] ntResponse,
- byte[] peerChallenge,
- byte[] authenticatorChallenge,
- String username)
- throws GeneralSecurityException, UnsupportedEncodingException {
- byte[] passwordHash = ntPasswordHash(password);
- byte[] passwordHashHash = hashNtPasswordHash(passwordHash);
-
- MessageDigest sha1 = MessageDigest.getInstance(SHA_ALG);
- sha1.update(passwordHashHash);
- sha1.update(ntResponse);
- sha1.update(CHALLENGE_MAGIC_1); // add just a dash of magic
- byte[] digest = sha1.digest();
-
- byte[] challenge = challengeHash(peerChallenge, authenticatorChallenge, username);
-
- sha1.update(digest);
- sha1.update(challenge);
- sha1.update(CHALLENGE_MAGIC_2);
-
- return sha1.digest();
- }
-
- /* Implementation of RFC 2759#8.8: CheckAuthenticatorResponse() */
- @VisibleForTesting
- static boolean checkAuthenticatorResponse(
- String password,
- byte[] ntResponse,
- byte[] peerChallenge,
- byte[] authenticatorChallenge,
- String userName,
- byte[] receivedResponse)
- throws GeneralSecurityException, UnsupportedEncodingException {
- byte[] myResponse =
- generateAuthenticatorResponse(
- password, ntResponse, peerChallenge, authenticatorChallenge, userName);
- return Arrays.equals(myResponse, receivedResponse);
- }
-
- /* Implementation of RFC 3079#3.4: GetMasterKey() */
- @VisibleForTesting
- static byte[] getMasterKey(byte[] passwordHashHash, byte[] ntResponse)
- throws GeneralSecurityException {
- MessageDigest sha1 = MessageDigest.getInstance(SHA_ALG);
- sha1.update(passwordHashHash);
- sha1.update(ntResponse);
- sha1.update(MSK_MAGIC_1);
- return Arrays.copyOf(sha1.digest(), MASTER_KEY_LEN);
- }
-
- /* Implementation of RFC 3079#3.4: GetAsymmetricStartKey() */
- @VisibleForTesting
- static byte[] getAsymmetricStartKey(byte[] masterKey, boolean isSend)
- throws GeneralSecurityException {
- // salt: referred to as 's' in RFC 3079#3.4 GetAsymmetricStartKey()
- byte[] salt = isSend ? MSK_MAGIC_2 : MSK_MAGIC_3;
- MessageDigest sha1 = MessageDigest.getInstance(SHA_ALG);
- sha1.update(masterKey);
- sha1.update(SHS_PAD_1);
- sha1.update(salt);
- sha1.update(SHS_PAD_2);
- return Arrays.copyOf(sha1.digest(), SESSION_KEY_LEN);
- }
-
- @VisibleForTesting
- static byte[] generateMsk(String password, byte[] ntResponse)
- throws GeneralSecurityException, UnsupportedEncodingException {
- byte[] passwordHash = ntPasswordHash(password);
- byte[] passwordHashHash = hashNtPasswordHash(passwordHash);
- byte[] masterKey = getMasterKey(passwordHashHash, ntResponse);
-
- // MSK: SendKey + ReceiveKey
- ByteBuffer msk = ByteBuffer.allocate(MASTER_SESSION_KEY_LEN);
- msk.put(getAsymmetricStartKey(masterKey, true /* isSend */));
- msk.put(getAsymmetricStartKey(masterKey, false /* isSend */));
-
- return msk.array();
- }
-}
diff --git a/src/java/com/android/internal/net/eap/statemachine/EapSimAkaMethodStateMachine.java b/src/java/com/android/internal/net/eap/statemachine/EapSimAkaMethodStateMachine.java
deleted file mode 100644
index dfd16276..00000000
--- a/src/java/com/android/internal/net/eap/statemachine/EapSimAkaMethodStateMachine.java
+++ /dev/null
@@ -1,355 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.statemachine;
-
-import static com.android.internal.net.eap.EapAuthenticator.LOG;
-import static com.android.internal.net.eap.message.EapMessage.EAP_CODE_REQUEST;
-import static com.android.internal.net.eap.message.EapMessage.EAP_CODE_RESPONSE;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_MAC;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_NOTIFICATION;
-
-import android.net.eap.EapSessionConfig.EapUiccConfig;
-import android.telephony.TelephonyManager;
-import android.util.Base64;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.net.eap.EapResult;
-import com.android.internal.net.eap.EapResult.EapError;
-import com.android.internal.net.eap.EapResult.EapResponse;
-import com.android.internal.net.eap.crypto.Fips186_2Prf;
-import com.android.internal.net.eap.exceptions.EapInvalidRequestException;
-import com.android.internal.net.eap.exceptions.EapSilentException;
-import com.android.internal.net.eap.exceptions.simaka.EapSimAkaAuthenticationFailureException;
-import com.android.internal.net.eap.exceptions.simaka.EapSimAkaInvalidAttributeException;
-import com.android.internal.net.eap.message.EapData;
-import com.android.internal.net.eap.message.EapMessage;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtClientErrorCode;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtMac;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtNotification;
-import com.android.internal.net.eap.message.simaka.EapSimAkaTypeData;
-import com.android.internal.net.utils.Log;
-
-import java.nio.ByteBuffer;
-import java.security.GeneralSecurityException;
-import java.security.MessageDigest;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-import javax.crypto.Mac;
-import javax.crypto.spec.SecretKeySpec;
-
-/**
- * EapSimAkaMethodStateMachine represents an abstract state machine for managing EAP-SIM and EAP-AKA
- * sessions.
- *
- * @see <a href="https://tools.ietf.org/html/rfc4186">RFC 4186, Extensible Authentication
- * Protocol for Subscriber Identity Modules (EAP-SIM)</a>
- * @see <a href="https://tools.ietf.org/html/rfc4187">RFC 4187, Extensible Authentication
- * Protocol for Authentication and Key Agreement (EAP-AKA)</a>
- */
-public abstract class EapSimAkaMethodStateMachine extends EapMethodStateMachine {
- public static final String MASTER_KEY_GENERATION_ALG = "SHA-1";
- public static final String MAC_ALGORITHM_STRING = "HmacSHA1";
-
- // K_encr and K_aut lengths are 16 bytes (RFC 4186#7, RFC 4187#7)
- public static final int KEY_LEN = 16;
-
- // Session Key lengths are 64 bytes (RFC 4186#7, RFC 4187#7)
- public static final int SESSION_KEY_LENGTH = 64;
-
- public final byte[] mKEncr = new byte[getKEncrLength()];
- public final byte[] mKAut = new byte[getKAutLength()];
- public final byte[] mMsk = new byte[getMskLength()];
- public final byte[] mEmsk = new byte[getEmskLength()];
-
- @VisibleForTesting boolean mHasReceivedSimAkaNotification = false;
-
- final TelephonyManager mTelephonyManager;
- final byte[] mEapIdentity;
- final EapUiccConfig mEapUiccConfig;
-
- @VisibleForTesting Mac mMacAlgorithm;
-
- EapSimAkaMethodStateMachine(
- TelephonyManager telephonyManager, byte[] eapIdentity, EapUiccConfig eapUiccConfig) {
- if (telephonyManager == null) {
- throw new IllegalArgumentException("TelephonyManager must be non-null");
- } else if (eapIdentity == null) {
- throw new IllegalArgumentException("EapIdentity must be non-null");
- } else if (eapUiccConfig == null) {
- throw new IllegalArgumentException("EapUiccConfig must be non-null");
- }
- this.mTelephonyManager = telephonyManager;
- this.mEapIdentity = eapIdentity;
- this.mEapUiccConfig = eapUiccConfig;
-
- LOG.d(
- this.getClass().getSimpleName(),
- mEapUiccConfig.getClass().getSimpleName() + ":"
- + " subId=" + mEapUiccConfig.subId
- + " apptype=" + mEapUiccConfig.apptype);
- }
-
- protected int getKEncrLength() {
- return KEY_LEN;
- }
-
- protected int getKAutLength() {
- return KEY_LEN;
- }
-
- protected int getMskLength() {
- return SESSION_KEY_LENGTH;
- }
-
- protected int getEmskLength() {
- return SESSION_KEY_LENGTH;
- }
-
- @Override
- EapResult handleEapNotification(String tag, EapMessage message) {
- return EapStateMachine.handleNotification(tag, message);
- }
-
- protected String getMacAlgorithm() {
- return MAC_ALGORITHM_STRING;
- }
-
- @VisibleForTesting
- EapResult buildClientErrorResponse(
- int eapIdentifier,
- int eapMethodType,
- AtClientErrorCode clientErrorCode) {
- EapSimAkaTypeData eapSimAkaTypeData = getEapSimAkaTypeData(clientErrorCode);
- byte[] encodedTypeData = eapSimAkaTypeData.encode();
-
- EapData eapData = new EapData(eapMethodType, encodedTypeData);
- try {
- EapMessage response = new EapMessage(EAP_CODE_RESPONSE, eapIdentifier, eapData);
- return EapResult.EapResponse.getEapResponse(response);
- } catch (EapSilentException ex) {
- return new EapResult.EapError(ex);
- }
- }
-
- @VisibleForTesting
- EapResult buildResponseMessage(
- int eapType,
- int eapSubtype,
- int identifier,
- List<EapSimAkaAttribute> attributes) {
- EapSimAkaTypeData eapSimTypeData = getEapSimAkaTypeData(eapSubtype, attributes);
- EapData eapData = new EapData(eapType, eapSimTypeData.encode());
-
- try {
- EapMessage eapMessage = new EapMessage(EAP_CODE_RESPONSE, identifier, eapData);
- return EapResult.EapResponse.getEapResponse(eapMessage);
- } catch (EapSilentException ex) {
- return new EapResult.EapError(ex);
- }
- }
-
- @VisibleForTesting
- protected void generateAndPersistKeys(
- String tag, MessageDigest sha1, Fips186_2Prf prf, byte[] mkInput) {
- byte[] mk = sha1.digest(mkInput);
-
- // run mk through FIPS 186-2
- int outputBytes = mKEncr.length + mKAut.length + mMsk.length + mEmsk.length;
- byte[] prfResult = prf.getRandom(mk, outputBytes);
-
- ByteBuffer prfResultBuffer = ByteBuffer.wrap(prfResult);
- prfResultBuffer.get(mKEncr);
- prfResultBuffer.get(mKAut);
- prfResultBuffer.get(mMsk);
- prfResultBuffer.get(mEmsk);
-
- // Log as hash unless PII debug mode enabled
- LOG.d(tag, "K_encr=" + LOG.pii(mKEncr));
- LOG.d(tag, "K_aut=" + LOG.pii(mKAut));
- LOG.d(tag, "MSK=" + LOG.pii(mMsk));
- LOG.d(tag, "EMSK=" + LOG.pii(mEmsk));
- }
-
- @VisibleForTesting
- byte[] processUiccAuthentication(String tag, int authType, byte[] formattedChallenge) throws
- EapSimAkaAuthenticationFailureException {
- String base64Challenge = Base64.encodeToString(formattedChallenge, Base64.NO_WRAP);
- String base64Response =
- mTelephonyManager.getIccAuthentication(
- mEapUiccConfig.apptype,
- authType,
- base64Challenge);
-
- if (base64Response == null) {
- String msg = "UICC authentication failed. Input: " + LOG.pii(formattedChallenge);
- LOG.e(tag, msg);
- throw new EapSimAkaAuthenticationFailureException(msg);
- }
-
- return Base64.decode(base64Response, Base64.DEFAULT);
- }
-
- @VisibleForTesting
- boolean isValidMac(String tag, EapMessage message, EapSimAkaTypeData typeData, byte[] extraData)
- throws GeneralSecurityException, EapSimAkaInvalidAttributeException,
- EapSilentException {
- mMacAlgorithm = Mac.getInstance(getMacAlgorithm());
- mMacAlgorithm.init(new SecretKeySpec(mKAut, getMacAlgorithm()));
-
- byte[] mac = getMac(message.eapCode, message.eapIdentifier, typeData, extraData);
- // attributes are 'valid', so must have AtMac
- AtMac atMac = (AtMac) typeData.attributeMap.get(EAP_AT_MAC);
-
- boolean isValidMac = Arrays.equals(mac, atMac.mac);
- if (!isValidMac) {
- // MAC in message != calculated mac
- LOG.e(
- tag,
- "Received message with invalid Mac."
- + " received=" + Log.byteArrayToHexString(atMac.mac)
- + ", computed=" + Log.byteArrayToHexString(mac));
- }
-
- return isValidMac;
- }
-
- @VisibleForTesting
- byte[] getMac(int eapCode, int eapIdentifier, EapSimAkaTypeData typeData, byte[] extraData)
- throws EapSimAkaInvalidAttributeException, EapSilentException {
- if (mMacAlgorithm == null) {
- throw new IllegalStateException(
- "Can't calculate MAC before mMacAlgorithm is set in ChallengeState");
- }
-
- // cache original Mac so it can be restored after calculating the Mac
- AtMac originalMac = (AtMac) typeData.attributeMap.get(EAP_AT_MAC);
- typeData.attributeMap.put(EAP_AT_MAC, new AtMac());
-
- byte[] typeDataWithEmptyMac = typeData.encode();
- EapData eapData = new EapData(getEapMethod(), typeDataWithEmptyMac);
- EapMessage messageForMac = new EapMessage(eapCode, eapIdentifier, eapData);
-
- ByteBuffer buffer = ByteBuffer.allocate(messageForMac.eapLength + extraData.length);
- buffer.put(messageForMac.encode());
- buffer.put(extraData);
- byte[] mac = mMacAlgorithm.doFinal(buffer.array());
-
- typeData.attributeMap.put(EAP_AT_MAC, originalMac);
-
- // need HMAC-SHA1-128 - first 16 bytes of SHA1 (RFC 4186#10.14, RFC 4187#10.15)
- return Arrays.copyOfRange(mac, 0, AtMac.MAC_LENGTH);
- }
-
- @VisibleForTesting
- EapResult buildResponseMessageWithMac(int identifier, int eapSubtype, byte[] extraData) {
- // capacity of 1 for AtMac to be added
- return buildResponseMessageWithMac(identifier, eapSubtype, extraData, new ArrayList<>(1));
- }
-
- @VisibleForTesting
- EapResult buildResponseMessageWithMac(
- int identifier, int eapSubtype, byte[] extraData, List<EapSimAkaAttribute> attributes) {
- try {
- attributes = new ArrayList<>(attributes);
- attributes.add(new AtMac());
- EapSimAkaTypeData eapSimAkaTypeData = getEapSimAkaTypeData(eapSubtype, attributes);
-
- byte[] mac = getMac(EAP_CODE_RESPONSE, identifier, eapSimAkaTypeData, extraData);
-
- eapSimAkaTypeData.attributeMap.put(EAP_AT_MAC, new AtMac(mac));
- EapData eapData = new EapData(getEapMethod(), eapSimAkaTypeData.encode());
- EapMessage eapMessage = new EapMessage(EAP_CODE_RESPONSE, identifier, eapData);
- return EapResponse.getEapResponse(eapMessage);
- } catch (EapSimAkaInvalidAttributeException | EapSilentException ex) {
- // this should never happen
- return new EapError(ex);
- }
- }
-
- @VisibleForTesting
- EapResult handleEapSimAkaNotification(
- String tag,
- boolean isPreChallengeState,
- int identifier,
- EapSimAkaTypeData eapSimAkaTypeData) {
- // EAP-SIM exchanges must not include more than one EAP-SIM notification round
- // (RFC 4186#6.1, RFC 4187#6.1)
- if (mHasReceivedSimAkaNotification) {
- return new EapError(
- new EapInvalidRequestException("Received multiple EAP-SIM notifications"));
- }
-
- mHasReceivedSimAkaNotification = true;
- AtNotification atNotification =
- (AtNotification) eapSimAkaTypeData.attributeMap.get(EAP_AT_NOTIFICATION);
-
- LOG.d(
- tag,
- "Received AtNotification:"
- + " S=" + (atNotification.isSuccessCode ? "1" : "0")
- + " P=" + (atNotification.isPreSuccessfulChallenge ? "1" : "0")
- + " Code=" + atNotification.notificationCode);
-
- // P bit of notification code is only allowed after a successful challenge round. This is
- // only possible in the ChallengeState (RFC 4186#6.1, RFC 4187#6.1)
- if (isPreChallengeState && !atNotification.isPreSuccessfulChallenge) {
- return buildClientErrorResponse(
- identifier, getEapMethod(), AtClientErrorCode.UNABLE_TO_PROCESS);
- }
-
- if (atNotification.isPreSuccessfulChallenge) {
- // AT_MAC attribute must not be included when the P bit is set (RFC 4186#9.8,
- // RFC 4187#9.10)
- if (eapSimAkaTypeData.attributeMap.containsKey(EAP_AT_MAC)) {
- return buildClientErrorResponse(
- identifier, getEapMethod(), AtClientErrorCode.UNABLE_TO_PROCESS);
- }
-
- return buildResponseMessage(
- getEapMethod(), eapSimAkaTypeData.eapSubtype, identifier, Arrays.asList());
- } else if (!eapSimAkaTypeData.attributeMap.containsKey(EAP_AT_MAC)) {
- // MAC must be included for messages with their P bit not set (RFC 4186#9.8,
- // RFC 4187#9.10)
- return buildClientErrorResponse(
- identifier, getEapMethod(), AtClientErrorCode.UNABLE_TO_PROCESS);
- }
-
- try {
- byte[] mac = getMac(EAP_CODE_REQUEST, identifier, eapSimAkaTypeData, new byte[0]);
-
- AtMac atMac = (AtMac) eapSimAkaTypeData.attributeMap.get(EAP_AT_MAC);
- if (!Arrays.equals(mac, atMac.mac)) {
- // MAC in message != calculated mac
- return buildClientErrorResponse(
- identifier, getEapMethod(), AtClientErrorCode.UNABLE_TO_PROCESS);
- }
- } catch (EapSilentException | EapSimAkaInvalidAttributeException ex) {
- // We can't continue if the MAC can't be generated
- return new EapError(ex);
- }
-
- // server has been authenticated, so we can send a response
- return buildResponseMessageWithMac(identifier, eapSimAkaTypeData.eapSubtype, new byte[0]);
- }
-
- abstract EapSimAkaTypeData getEapSimAkaTypeData(AtClientErrorCode clientErrorCode);
- abstract EapSimAkaTypeData getEapSimAkaTypeData(
- int eapSubtype, List<EapSimAkaAttribute> attributes);
-}
diff --git a/src/java/com/android/internal/net/eap/statemachine/EapSimMethodStateMachine.java b/src/java/com/android/internal/net/eap/statemachine/EapSimMethodStateMachine.java
deleted file mode 100644
index 005cfb96..00000000
--- a/src/java/com/android/internal/net/eap/statemachine/EapSimMethodStateMachine.java
+++ /dev/null
@@ -1,604 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.statemachine;
-
-import static com.android.internal.net.eap.EapAuthenticator.LOG;
-import static com.android.internal.net.eap.message.EapData.EAP_NOTIFICATION;
-import static com.android.internal.net.eap.message.EapData.EAP_TYPE_SIM;
-import static com.android.internal.net.eap.message.EapMessage.EAP_CODE_FAILURE;
-import static com.android.internal.net.eap.message.EapMessage.EAP_CODE_SUCCESS;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_ANY_ID_REQ;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_ENCR_DATA;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_FULLAUTH_ID_REQ;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_IV;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_MAC;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_PERMANENT_ID_REQ;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_RAND;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_VERSION_LIST;
-import static com.android.internal.net.eap.message.simaka.EapSimTypeData.EAP_SIM_CHALLENGE;
-import static com.android.internal.net.eap.message.simaka.EapSimTypeData.EAP_SIM_CLIENT_ERROR;
-import static com.android.internal.net.eap.message.simaka.EapSimTypeData.EAP_SIM_NOTIFICATION;
-import static com.android.internal.net.eap.message.simaka.EapSimTypeData.EAP_SIM_START;
-
-import android.annotation.Nullable;
-import android.content.Context;
-import android.net.eap.EapSessionConfig.EapSimConfig;
-import android.telephony.TelephonyManager;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.net.eap.EapResult;
-import com.android.internal.net.eap.EapResult.EapError;
-import com.android.internal.net.eap.EapResult.EapFailure;
-import com.android.internal.net.eap.EapResult.EapSuccess;
-import com.android.internal.net.eap.crypto.Fips186_2Prf;
-import com.android.internal.net.eap.exceptions.EapInvalidRequestException;
-import com.android.internal.net.eap.exceptions.EapSilentException;
-import com.android.internal.net.eap.exceptions.simaka.EapSimAkaAuthenticationFailureException;
-import com.android.internal.net.eap.exceptions.simaka.EapSimAkaIdentityUnavailableException;
-import com.android.internal.net.eap.exceptions.simaka.EapSimAkaInvalidAttributeException;
-import com.android.internal.net.eap.exceptions.simaka.EapSimAkaInvalidLengthException;
-import com.android.internal.net.eap.message.EapData.EapMethod;
-import com.android.internal.net.eap.message.EapMessage;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtClientErrorCode;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtIdentity;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtNonceMt;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtRandSim;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtSelectedVersion;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtVersionList;
-import com.android.internal.net.eap.message.simaka.EapSimAkaTypeData.DecodeResult;
-import com.android.internal.net.eap.message.simaka.EapSimTypeData;
-import com.android.internal.net.eap.message.simaka.EapSimTypeData.EapSimTypeDataDecoder;
-
-import java.nio.BufferUnderflowException;
-import java.nio.ByteBuffer;
-import java.nio.charset.StandardCharsets;
-import java.security.GeneralSecurityException;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.security.SecureRandom;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Set;
-
-/**
- * EapSimMethodStateMachine represents the valid paths possible for the EAP-SIM protocol.
- *
- * <p>EAP-SIM procedures will always follow the path:
- *
- * Created ---> Start --+--> Challenge --+--> null
- * | |
- * +--> failed >--+
- *
- * Note that EAP-SIM/Notification messages can be received at any point in the above state machine.
- * At most one EAP-SIM/Notification message is allowed per EAP-SIM session.
- *
- * @see <a href="https://tools.ietf.org/html/rfc4186">RFC 4186, Extensible Authentication Protocol
- * Method for Subscriber Identity Modules (EAP-SIM)</a>
- */
-class EapSimMethodStateMachine extends EapSimAkaMethodStateMachine {
- private final SecureRandom mSecureRandom;
- private final EapSimTypeDataDecoder mEapSimTypeDataDecoder;
-
- EapSimMethodStateMachine(
- Context context,
- byte[] eapIdentity,
- EapSimConfig eapSimConfig,
- SecureRandom secureRandom) {
- this(
- (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE),
- eapIdentity,
- eapSimConfig,
- secureRandom,
- EapSimTypeData.getEapSimTypeDataDecoder());
- }
-
- @VisibleForTesting
- EapSimMethodStateMachine(
- TelephonyManager telephonyManager,
- byte[] eapIdentity,
- EapSimConfig eapSimConfig,
- SecureRandom secureRandom,
- EapSimTypeDataDecoder eapSimTypeDataDecoder) {
- super(
- telephonyManager.createForSubscriptionId(eapSimConfig.subId),
- eapIdentity,
- eapSimConfig);
-
- if (eapSimTypeDataDecoder == null) {
- throw new IllegalArgumentException("EapSimTypeDataDecoder must be non-null");
- }
-
- this.mSecureRandom = secureRandom;
- this.mEapSimTypeDataDecoder = eapSimTypeDataDecoder;
- transitionTo(new CreatedState());
- }
-
- @Override
- @EapMethod
- int getEapMethod() {
- return EAP_TYPE_SIM;
- }
-
- protected class CreatedState extends EapMethodState {
- private final String mTAG = CreatedState.class.getSimpleName();
-
- public EapResult process(EapMessage message) {
- EapResult result = handleEapSuccessFailureNotification(mTAG, message);
- if (result != null) {
- return result;
- }
-
- DecodeResult<EapSimTypeData> decodeResult =
- mEapSimTypeDataDecoder.decode(message.eapData.eapTypeData);
- if (!decodeResult.isSuccessfulDecode()) {
- return buildClientErrorResponse(
- message.eapIdentifier,
- EAP_TYPE_SIM,
- decodeResult.atClientErrorCode);
- }
-
- EapSimTypeData eapSimTypeData = decodeResult.eapTypeData;
- switch (eapSimTypeData.eapSubtype) {
- case EAP_SIM_START:
- break;
- case EAP_SIM_NOTIFICATION:
- return handleEapSimAkaNotification(
- mTAG,
- true, // isPreChallengeState
- message.eapIdentifier,
- eapSimTypeData);
- default:
- return buildClientErrorResponse(
- message.eapIdentifier,
- EAP_TYPE_SIM,
- AtClientErrorCode.UNABLE_TO_PROCESS);
- }
-
- byte[] nonce = new byte[AtNonceMt.NONCE_MT_LENGTH];
- mSecureRandom.nextBytes(nonce);
- AtNonceMt atNonceMt;
- try {
- atNonceMt = new AtNonceMt(nonce);
- } catch (EapSimAkaInvalidAttributeException ex) {
- LOG.wtf(mTAG, "Exception thrown while creating AtNonceMt", ex);
- return new EapError(ex);
- }
- return transitionAndProcess(new StartState(atNonceMt), message);
- }
- }
-
- protected class StartState extends EapMethodState {
- private final String mTAG = StartState.class.getSimpleName();
- private final AtNonceMt mAtNonceMt;
-
- private List<Integer> mVersions;
-
- // use the EAP-Identity for the default value (RFC 4186#7)
- @VisibleForTesting byte[] mIdentity = mEapIdentity;
-
- protected StartState(AtNonceMt atNonceMt) {
- this.mAtNonceMt = atNonceMt;
- }
-
- public EapResult process(EapMessage message) {
- EapResult result = handleEapSuccessFailureNotification(mTAG, message);
- if (result != null) {
- return result;
- }
-
- DecodeResult<EapSimTypeData> decodeResult =
- mEapSimTypeDataDecoder.decode(message.eapData.eapTypeData);
- if (!decodeResult.isSuccessfulDecode()) {
- return buildClientErrorResponse(
- message.eapIdentifier,
- EAP_TYPE_SIM,
- decodeResult.atClientErrorCode);
- }
-
- EapSimTypeData eapSimTypeData = decodeResult.eapTypeData;
- switch (eapSimTypeData.eapSubtype) {
- case EAP_SIM_START:
- break;
- case EAP_SIM_NOTIFICATION:
- return handleEapSimAkaNotification(
- mTAG,
- true, // isPreChallengeState
- message.eapIdentifier,
- eapSimTypeData);
- case EAP_SIM_CHALLENGE:
- // By virtue of being in the StartState, we have received (and processed) the
- // EAP-SIM/Start request. Receipt of an EAP-SIM/Challenge request indicates that
- // the server has accepted our EAP-SIM/Start response, including our identity
- // (if any).
- return transitionAndProcess(
- new ChallengeState(mVersions, mAtNonceMt, mIdentity), message);
- default:
- return buildClientErrorResponse(
- message.eapIdentifier,
- EAP_TYPE_SIM,
- AtClientErrorCode.UNABLE_TO_PROCESS);
- }
-
- if (!isValidStartAttributes(eapSimTypeData)) {
- LOG.e(mTAG, "Invalid attributes: " + eapSimTypeData.attributeMap.keySet());
- return buildClientErrorResponse(
- message.eapIdentifier,
- EAP_TYPE_SIM,
- AtClientErrorCode.UNABLE_TO_PROCESS);
- }
-
- List<EapSimAkaAttribute> responseAttributes = new ArrayList<>();
- responseAttributes.add(mAtNonceMt);
-
- // choose EAP-SIM version
- AtVersionList atVersionList = (AtVersionList)
- eapSimTypeData.attributeMap.get(EAP_AT_VERSION_LIST);
- mVersions = atVersionList.versions;
- if (!mVersions.contains(AtSelectedVersion.SUPPORTED_VERSION)) {
- return buildClientErrorResponse(
- message.eapIdentifier,
- EAP_TYPE_SIM,
- AtClientErrorCode.UNSUPPORTED_VERSION);
- }
- responseAttributes.add(AtSelectedVersion.getSelectedVersion());
-
- try {
- AtIdentity atIdentity = getIdentityResponse(eapSimTypeData);
- if (atIdentity != null) {
- responseAttributes.add(atIdentity);
- }
- } catch (EapSimAkaInvalidAttributeException ex) {
- LOG.wtf(mTAG, "Exception thrown while making AtIdentity attribute", ex);
- return new EapError(ex);
- } catch (EapSimAkaIdentityUnavailableException ex) {
- LOG.e(mTAG, "Unable to get IMSI for subId=" + mEapUiccConfig.subId);
- return new EapError(ex);
- }
-
- return buildResponseMessage(
- EAP_TYPE_SIM,
- EAP_SIM_START,
- message.eapIdentifier,
- responseAttributes);
- }
-
- /**
- * Returns true iff the given EapSimTypeData meets the following conditions:
- * - contains an AT_VERSION_LIST attribute
- * - contains at most one of AT_PERMANENT_ID_REQ, AT_ANY_ID_REQ, or AT_FULLAUTH_D_REQ
- * attributes
- * - does not contain AT_MAC, AT_IV, or AT_ENCR_DATA attributes
- */
- @VisibleForTesting
- boolean isValidStartAttributes(EapSimTypeData eapSimTypeData) {
- // must contain: version list
- Set<Integer> attrs = eapSimTypeData.attributeMap.keySet();
- if (!attrs.contains(EAP_AT_VERSION_LIST)) {
- return false;
- }
-
- // may contain: ID request (but only 1)
- int idRequests = 0;
- if (attrs.contains(EAP_AT_PERMANENT_ID_REQ)) {
- idRequests++;
- }
- if (attrs.contains(EAP_AT_ANY_ID_REQ)) {
- idRequests++;
- }
- if (attrs.contains(EAP_AT_FULLAUTH_ID_REQ)) {
- idRequests++;
- }
- if (idRequests > 1) {
- return false;
- }
-
- // can't contain mac, iv, encr data
- if (attrs.contains(EAP_AT_MAC)
- || attrs.contains(EAP_AT_IV)
- || attrs.contains(EAP_AT_ENCR_DATA)) {
- return false;
- }
- return true;
- }
-
- @VisibleForTesting
- @Nullable
- AtIdentity getIdentityResponse(EapSimTypeData eapSimTypeData)
- throws EapSimAkaInvalidAttributeException, EapSimAkaIdentityUnavailableException {
- Set<Integer> attributes = eapSimTypeData.attributeMap.keySet();
-
- // TODO(b/136180022): process separate ID requests differently (pseudonym vs permanent)
- if (attributes.contains(EAP_AT_PERMANENT_ID_REQ)
- || attributes.contains(EAP_AT_FULLAUTH_ID_REQ)
- || attributes.contains(EAP_AT_ANY_ID_REQ)) {
- String imsi = mTelephonyManager.getSubscriberId();
- if (imsi == null) {
- throw new EapSimAkaIdentityUnavailableException(
- "IMSI for subId (" + mEapUiccConfig.subId + ") not available");
- }
-
- // Permanent Identity is "1" + IMSI (RFC 4186 Section 4.1.2.6)
- String identity = "1" + imsi;
- mIdentity = identity.getBytes(StandardCharsets.US_ASCII);
- LOG.d(mTAG, "EAP-SIM/Identity=" + LOG.pii(identity));
-
- return AtIdentity.getAtIdentity(mIdentity);
- }
-
- return null;
- }
- }
-
- protected class ChallengeState extends EapMethodState {
- private final String mTAG = ChallengeState.class.getSimpleName();
- private final int mBytesPerShort = 2;
- private final int mVersionLenBytes = 2;
-
- // Lengths defined by TS 31.102 Section 7.1.2.1 (case 3)
- // SRES stands for "SIM response"
- // Kc stands for "cipher key"
- private final int mSresLenBytes = 4;
- private final int mKcLenBytes = 8;
-
- private final List<Integer> mVersions;
- private final byte[] mNonce;
- @VisibleForTesting final byte[] mIdentity;
-
- protected ChallengeState(List<Integer> versions, AtNonceMt atNonceMt, byte[] identity) {
- mVersions = versions;
- mNonce = atNonceMt.nonceMt;
- mIdentity = identity;
- }
-
- public EapResult process(EapMessage message) {
- if (message.eapCode == EAP_CODE_SUCCESS) {
- transitionTo(new FinalState());
- return new EapSuccess(mMsk, mEmsk);
- } else if (message.eapCode == EAP_CODE_FAILURE) {
- transitionTo(new FinalState());
- return new EapFailure();
- } else if (message.eapData.eapType == EAP_NOTIFICATION) {
- return handleEapNotification(mTAG, message);
- }
-
- if (message.eapData.eapType != getEapMethod()) {
- return new EapError(new EapInvalidRequestException(
- "Expected EAP Type " + getEapMethod()
- + ", received " + message.eapData.eapType));
- }
-
- DecodeResult<EapSimTypeData> decodeResult =
- mEapSimTypeDataDecoder.decode(message.eapData.eapTypeData);
- if (!decodeResult.isSuccessfulDecode()) {
- return buildClientErrorResponse(
- message.eapIdentifier,
- EAP_TYPE_SIM,
- decodeResult.atClientErrorCode);
- }
-
- EapSimTypeData eapSimTypeData = decodeResult.eapTypeData;
- switch (eapSimTypeData.eapSubtype) {
- case EAP_SIM_NOTIFICATION:
- return handleEapSimAkaNotification(
- mTAG,
- false, // isPreChallengeState
- message.eapIdentifier,
- eapSimTypeData);
- case EAP_SIM_CHALLENGE:
- break;
- default:
- return buildClientErrorResponse(
- message.eapIdentifier,
- EAP_TYPE_SIM,
- AtClientErrorCode.UNABLE_TO_PROCESS);
- }
-
- if (!isValidChallengeAttributes(eapSimTypeData)) {
- LOG.e(mTAG, "Invalid attributes: " + eapSimTypeData.attributeMap.keySet());
- return buildClientErrorResponse(
- message.eapIdentifier,
- EAP_TYPE_SIM,
- AtClientErrorCode.UNABLE_TO_PROCESS);
- }
-
- List<RandChallengeResult> randChallengeResults;
- try {
- randChallengeResults = getRandChallengeResults(eapSimTypeData);
- } catch (EapSimAkaInvalidLengthException | BufferUnderflowException ex) {
- LOG.e(mTAG, "Invalid SRES/Kc tuple returned from SIM", ex);
- return buildClientErrorResponse(
- message.eapIdentifier,
- EAP_TYPE_SIM,
- AtClientErrorCode.UNABLE_TO_PROCESS);
- } catch (EapSimAkaAuthenticationFailureException ex) {
- return new EapError(ex);
- }
-
- try {
- MessageDigest sha1 = MessageDigest.getInstance(MASTER_KEY_GENERATION_ALG);
- byte[] mkInputData = getMkInputData(randChallengeResults);
- generateAndPersistKeys(mTAG, sha1, new Fips186_2Prf(), mkInputData);
- } catch (NoSuchAlgorithmException | BufferUnderflowException ex) {
- LOG.e(mTAG, "Error while creating keys", ex);
- return buildClientErrorResponse(
- message.eapIdentifier,
- EAP_TYPE_SIM,
- AtClientErrorCode.UNABLE_TO_PROCESS);
- }
-
- try {
- if (!isValidMac(mTAG, message, eapSimTypeData, mNonce)) {
- return buildClientErrorResponse(
- message.eapIdentifier,
- EAP_TYPE_SIM,
- AtClientErrorCode.UNABLE_TO_PROCESS);
- }
- } catch (GeneralSecurityException | EapSilentException
- | EapSimAkaInvalidAttributeException ex) {
- // if the MAC can't be generated, we can't continue
- LOG.e(mTAG, "Error computing MAC for EapMessage", ex);
- return new EapError(ex);
- }
-
- ByteBuffer sresValues =
- ByteBuffer.allocate(randChallengeResults.size() * mSresLenBytes);
- for (RandChallengeResult result : randChallengeResults) {
- sresValues.put(result.sres);
- }
-
- // server has been authenticated, so we can send a response
- return buildResponseMessageWithMac(
- message.eapIdentifier,
- EAP_SIM_CHALLENGE,
- sresValues.array());
- }
-
- /**
- * Returns true iff the given EapSimTypeData contains both AT_RAND and AT_MAC attributes.
- */
- @VisibleForTesting
- boolean isValidChallengeAttributes(EapSimTypeData eapSimTypeData) {
- Set<Integer> attrs = eapSimTypeData.attributeMap.keySet();
- return attrs.contains(EAP_AT_RAND) && attrs.contains(EAP_AT_MAC);
- }
-
- @VisibleForTesting
- List<RandChallengeResult> getRandChallengeResults(EapSimTypeData eapSimTypeData)
- throws EapSimAkaInvalidLengthException, EapSimAkaAuthenticationFailureException {
- AtRandSim atRand = (AtRandSim) eapSimTypeData.attributeMap.get(EAP_AT_RAND);
- List<byte[]> randList = atRand.rands;
- List<RandChallengeResult> challengeResults = new ArrayList<>();
-
- for (byte[] rand : randList) {
- // Rand (pre-Base64 formatting) needs to be formatted as [length][rand data]
- ByteBuffer formattedRand = ByteBuffer.allocate(rand.length + 1);
- formattedRand.put((byte) rand.length);
- formattedRand.put(rand);
-
- byte[] challengeResponseBytes =
- processUiccAuthentication(
- mTAG,
- TelephonyManager.AUTHTYPE_EAP_SIM,
- formattedRand.array());
-
- RandChallengeResult randChallengeResult =
- getRandChallengeResultFromResponse(challengeResponseBytes);
- challengeResults.add(randChallengeResult);
-
- // Log rand/challenge as PII
- LOG.d(
- mTAG,
- "RAND=" + LOG.pii(rand)
- + " SRES=" + LOG.pii(randChallengeResult.sres)
- + " Kc=" + LOG.pii(randChallengeResult.kc));
- }
-
- return challengeResults;
- }
-
- /**
- * Parses the SRES and Kc values from the given challengeResponse. The values are returned
- * in a Pair<byte[], byte[]>, where SRES and Kc are the first and second values,
- * respectively.
- */
- @VisibleForTesting
- RandChallengeResult getRandChallengeResultFromResponse(byte[] challengeResponse)
- throws EapSimAkaInvalidLengthException {
- ByteBuffer buffer = ByteBuffer.wrap(challengeResponse);
- int lenSres = Byte.toUnsignedInt(buffer.get());
- if (lenSres != mSresLenBytes) {
- throw new EapSimAkaInvalidLengthException("Invalid SRES length specified");
- }
- byte[] sres = new byte[mSresLenBytes];
- buffer.get(sres);
-
- int lenKc = Byte.toUnsignedInt(buffer.get());
- if (lenKc != mKcLenBytes) {
- throw new EapSimAkaInvalidLengthException("Invalid Kc length specified");
- }
- byte[] kc = new byte[mKcLenBytes];
- buffer.get(kc);
-
- return new RandChallengeResult(sres, kc);
- }
-
- @VisibleForTesting
- class RandChallengeResult {
- public final byte[] sres;
- public final byte[] kc;
-
- RandChallengeResult(byte[] sres, byte[] kc) throws EapSimAkaInvalidLengthException {
- this.sres = sres;
- this.kc = kc;
-
- if (sres.length != mSresLenBytes) {
- throw new EapSimAkaInvalidLengthException("Invalid SRES length");
- }
- if (kc.length != mKcLenBytes) {
- throw new EapSimAkaInvalidLengthException("Invalid Kc length");
- }
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (!(o instanceof RandChallengeResult)) return false;
- RandChallengeResult that = (RandChallengeResult) o;
- return Arrays.equals(sres, that.sres)
- && Arrays.equals(kc, that.kc);
- }
-
- @Override
- public int hashCode() {
- int result = Arrays.hashCode(sres);
- result = 31 * result + Arrays.hashCode(kc);
- return result;
- }
- }
-
- private byte[] getMkInputData(List<RandChallengeResult> randChallengeResults) {
- int numInputBytes =
- mIdentity.length
- + (randChallengeResults.size() * mKcLenBytes)
- + mNonce.length
- + (mVersions.size() * mBytesPerShort) // 2B per version
- + mVersionLenBytes;
-
- ByteBuffer mkInputBuffer = ByteBuffer.allocate(numInputBytes);
- mkInputBuffer.put(mIdentity);
- for (RandChallengeResult randChallengeResult : randChallengeResults) {
- mkInputBuffer.put(randChallengeResult.kc);
- }
- mkInputBuffer.put(mNonce);
- for (int i : mVersions) {
- mkInputBuffer.putShort((short) i);
- }
- mkInputBuffer.putShort((short) AtSelectedVersion.SUPPORTED_VERSION);
- return mkInputBuffer.array();
- }
- }
-
- EapSimTypeData getEapSimAkaTypeData(AtClientErrorCode clientErrorCode) {
- return new EapSimTypeData(EAP_SIM_CLIENT_ERROR, Arrays.asList(clientErrorCode));
- }
-
- EapSimTypeData getEapSimAkaTypeData(int eapSubtype, List<EapSimAkaAttribute> attributes) {
- return new EapSimTypeData(eapSubtype, attributes);
- }
-}
diff --git a/src/java/com/android/internal/net/eap/statemachine/EapStateMachine.java b/src/java/com/android/internal/net/eap/statemachine/EapStateMachine.java
deleted file mode 100644
index f3e933e2..00000000
--- a/src/java/com/android/internal/net/eap/statemachine/EapStateMachine.java
+++ /dev/null
@@ -1,371 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.statemachine;
-
-import static com.android.internal.net.eap.EapAuthenticator.LOG;
-import static com.android.internal.net.eap.message.EapData.EAP_IDENTITY;
-import static com.android.internal.net.eap.message.EapData.EAP_NAK;
-import static com.android.internal.net.eap.message.EapData.EAP_NOTIFICATION;
-import static com.android.internal.net.eap.message.EapData.EAP_TYPE_AKA;
-import static com.android.internal.net.eap.message.EapData.EAP_TYPE_AKA_PRIME;
-import static com.android.internal.net.eap.message.EapData.EAP_TYPE_MSCHAP_V2;
-import static com.android.internal.net.eap.message.EapData.EAP_TYPE_SIM;
-import static com.android.internal.net.eap.message.EapData.EAP_TYPE_STRING;
-import static com.android.internal.net.eap.message.EapMessage.EAP_CODE_FAILURE;
-import static com.android.internal.net.eap.message.EapMessage.EAP_CODE_REQUEST;
-import static com.android.internal.net.eap.message.EapMessage.EAP_CODE_RESPONSE;
-import static com.android.internal.net.eap.message.EapMessage.EAP_CODE_STRING;
-import static com.android.internal.net.eap.message.EapMessage.EAP_CODE_SUCCESS;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.Context;
-import android.net.eap.EapSessionConfig;
-import android.net.eap.EapSessionConfig.EapAkaConfig;
-import android.net.eap.EapSessionConfig.EapAkaPrimeConfig;
-import android.net.eap.EapSessionConfig.EapMethodConfig;
-import android.net.eap.EapSessionConfig.EapMsChapV2Config;
-import android.net.eap.EapSessionConfig.EapSimConfig;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.net.eap.EapResult;
-import com.android.internal.net.eap.EapResult.EapError;
-import com.android.internal.net.eap.EapResult.EapFailure;
-import com.android.internal.net.eap.EapResult.EapResponse;
-import com.android.internal.net.eap.EapResult.EapSuccess;
-import com.android.internal.net.eap.exceptions.EapInvalidRequestException;
-import com.android.internal.net.eap.exceptions.EapSilentException;
-import com.android.internal.net.eap.exceptions.UnsupportedEapTypeException;
-import com.android.internal.net.eap.message.EapData;
-import com.android.internal.net.eap.message.EapData.EapMethod;
-import com.android.internal.net.eap.message.EapMessage;
-import com.android.internal.net.utils.SimpleStateMachine;
-
-import java.nio.charset.StandardCharsets;
-import java.security.SecureRandom;
-
-/**
- * EapStateMachine represents the valid paths for a single EAP Authentication procedure.
- *
- * <p>EAP Authentication procedures will always follow the path:
- *
- * CreatedState --> IdentityState --> Method State --+--> SuccessState
- * | ^ |
- * +---------------------------------+ +--> FailureState
- *
- */
-public class EapStateMachine extends SimpleStateMachine<byte[], EapResult> {
- private static final String TAG = EapStateMachine.class.getSimpleName();
-
- private final Context mContext;
- private final EapSessionConfig mEapSessionConfig;
- private final SecureRandom mSecureRandom;
-
- public EapStateMachine(
- @NonNull Context context,
- @NonNull EapSessionConfig eapSessionConfig,
- @NonNull SecureRandom secureRandom) {
- this.mContext = context;
- this.mEapSessionConfig = eapSessionConfig;
- this.mSecureRandom = secureRandom;
-
- LOG.d(
- TAG,
- "Starting EapStateMachine with EAP-Identity="
- + LOG.pii(eapSessionConfig.eapIdentity)
- + " and configs=" + eapSessionConfig.eapConfigs.keySet());
-
- transitionTo(new CreatedState());
- }
-
- @VisibleForTesting
- protected SimpleStateMachine.SimpleState getState() {
- return mState;
- }
-
- @VisibleForTesting
- protected void transitionTo(EapState newState) {
- LOG.d(
- TAG,
- "Transitioning from " + mState.getClass().getSimpleName()
- + " to " + newState.getClass().getSimpleName());
- super.transitionTo(newState);
- }
-
- @VisibleForTesting
- protected EapResult transitionAndProcess(EapState newState, byte[] packet) {
- return super.transitionAndProcess(newState, packet);
- }
-
- protected abstract class EapState extends SimpleState {
- protected DecodeResult decode(@NonNull byte[] packet) {
- LOG.d(getClass().getSimpleName(),
- "Received packet=[" + LOG.pii(packet) + "]");
-
- if (packet == null) {
- return new DecodeResult(new EapError(
- new IllegalArgumentException("Attempting to decode null packet")));
- }
-
- try {
- EapMessage eapMessage = EapMessage.decode(packet);
-
- // Log inbound message in the format "EAP-<Code>/<Type>"
- String eapDataString =
- (eapMessage.eapData == null)
- ? ""
- : "/" + EAP_TYPE_STRING.getOrDefault(
- eapMessage.eapData.eapType,
- "UNKNOWN (" + eapMessage.eapData.eapType + ")");
- String msg = "Decoded message: EAP-"
- + EAP_CODE_STRING.getOrDefault(eapMessage.eapCode, "UNKNOWN")
- + eapDataString;
- LOG.i(getClass().getSimpleName(), msg);
-
- if (eapMessage.eapCode == EAP_CODE_RESPONSE) {
- EapInvalidRequestException cause =
- new EapInvalidRequestException("Received an EAP-Response message");
- return new DecodeResult(new EapError(cause));
- } else if (eapMessage.eapCode == EAP_CODE_REQUEST
- && eapMessage.eapData.eapType == EAP_NAK) {
- // RFC 3748 Section 5.3.1 states that Nak type is only valid in responses
- EapInvalidRequestException cause =
- new EapInvalidRequestException("Received an EAP-Request of type Nak");
- return new DecodeResult(new EapError(cause));
- }
-
- return new DecodeResult(eapMessage);
- } catch (UnsupportedEapTypeException ex) {
- return new DecodeResult(
- EapMessage.getNakResponse(
- ex.eapIdentifier,
- mEapSessionConfig.eapConfigs.keySet()));
- } catch (EapSilentException ex) {
- return new DecodeResult(new EapError(ex));
- }
- }
-
- protected final class DecodeResult {
- public final EapMessage eapMessage;
- public final EapResult eapResult;
-
- public DecodeResult(EapMessage eapMessage) {
- this.eapMessage = eapMessage;
- this.eapResult = null;
- }
-
- public DecodeResult(EapResult eapResult) {
- this.eapMessage = null;
- this.eapResult = eapResult;
- }
-
- public boolean isValidEapMessage() {
- return eapMessage != null;
- }
- }
- }
-
- protected class CreatedState extends EapState {
- private final String mTAG = CreatedState.class.getSimpleName();
-
- public EapResult process(@NonNull byte[] packet) {
- DecodeResult decodeResult = decode(packet);
- if (!decodeResult.isValidEapMessage()) {
- return decodeResult.eapResult;
- }
- EapMessage message = decodeResult.eapMessage;
-
- if (message.eapCode != EAP_CODE_REQUEST) {
- return new EapError(
- new EapInvalidRequestException("Received non EAP-Request in CreatedState"));
- }
-
- // EapMessage#validate verifies that all EapMessage objects representing
- // EAP-Request packets have a Type value
- switch (message.eapData.eapType) {
- case EAP_NOTIFICATION:
- return handleNotification(mTAG, message);
-
- case EAP_IDENTITY:
- return transitionAndProcess(new IdentityState(), packet);
-
- // all EAP methods should be handled by MethodState
- default:
- return transitionAndProcess(new MethodState(), packet);
- }
- }
- }
-
- protected class IdentityState extends EapState {
- private final String mTAG = IdentityState.class.getSimpleName();
-
- public EapResult process(@NonNull byte[] packet) {
- DecodeResult decodeResult = decode(packet);
- if (!decodeResult.isValidEapMessage()) {
- return decodeResult.eapResult;
- }
- EapMessage message = decodeResult.eapMessage;
-
- if (message.eapCode != EAP_CODE_REQUEST) {
- return new EapError(new EapInvalidRequestException(
- "Received non EAP-Request in IdentityState"));
- }
-
- // EapMessage#validate verifies that all EapMessage objects representing
- // EAP-Request packets have a Type value
- switch (message.eapData.eapType) {
- case EAP_NOTIFICATION:
- return handleNotification(mTAG, message);
-
- case EAP_IDENTITY:
- return getIdentityResponse(message.eapIdentifier);
-
- // all EAP methods should be handled by MethodState
- default:
- return transitionAndProcess(new MethodState(), packet);
- }
- }
-
- @VisibleForTesting
- EapResult getIdentityResponse(int eapIdentifier) {
- try {
- LOG.d(mTAG, "Returning EAP-Identity: " + LOG.pii(mEapSessionConfig.eapIdentity));
- EapData identityData = new EapData(EAP_IDENTITY, mEapSessionConfig.eapIdentity);
- return EapResponse.getEapResponse(
- new EapMessage(EAP_CODE_RESPONSE, eapIdentifier, identityData));
- } catch (EapSilentException ex) {
- // this should never happen - only identifier and identity bytes are variable
- LOG.wtf(mTAG, "Failed to create Identity response for message with identifier="
- + LOG.pii(eapIdentifier));
- return new EapError(ex);
- }
- }
- }
-
- protected class MethodState extends EapState {
- private final String mTAG = MethodState.class.getSimpleName();
-
- @VisibleForTesting
- EapMethodStateMachine mEapMethodStateMachine;
-
- // Not all EAP Method implementations may support EAP-Notifications, so allow the EAP-Method
- // to handle any EAP-REQUEST/Notification messages (RFC 3748 Section 5.2)
- public EapResult process(@NonNull byte[] packet) {
- DecodeResult decodeResult = decode(packet);
- if (!decodeResult.isValidEapMessage()) {
- return decodeResult.eapResult;
- }
- EapMessage eapMessage = decodeResult.eapMessage;
-
- if (mEapMethodStateMachine == null) {
- if (eapMessage.eapCode == EAP_CODE_SUCCESS) {
- // EAP-SUCCESS is required to be the last EAP message sent during the EAP
- // protocol, so receiving a premature SUCCESS message is an unrecoverable error
- return new EapError(
- new EapInvalidRequestException(
- "Received an EAP-Success in the MethodState"));
- } else if (eapMessage.eapCode == EAP_CODE_FAILURE) {
- transitionTo(new FailureState());
- return new EapFailure();
- } else if (eapMessage.eapData.eapType == EAP_NOTIFICATION) {
- // if no EapMethodStateMachine has been assigned and we receive an
- // EAP-Notification, we should log it and respond
- return handleNotification(mTAG, eapMessage);
- }
-
- int eapType = eapMessage.eapData.eapType;
- mEapMethodStateMachine = buildEapMethodStateMachine(eapType);
-
- if (mEapMethodStateMachine == null) {
- return EapMessage.getNakResponse(
- eapMessage.eapIdentifier,
- mEapSessionConfig.eapConfigs.keySet());
- }
- }
-
- EapResult result = mEapMethodStateMachine.process(decodeResult.eapMessage);
- if (result instanceof EapSuccess) {
- transitionTo(new SuccessState());
- } else if (result instanceof EapFailure) {
- transitionTo(new FailureState());
- }
- return result;
- }
-
- @Nullable
- private EapMethodStateMachine buildEapMethodStateMachine(@EapMethod int eapType) {
- EapMethodConfig eapMethodConfig = mEapSessionConfig.eapConfigs.get(eapType);
- if (eapMethodConfig == null) {
- LOG.e(
- mTAG,
- "No configs provided for method: "
- + EAP_TYPE_STRING.getOrDefault(
- eapType, "Unknown (" + eapType + ")"));
- return null;
- }
-
- switch (eapType) {
- case EAP_TYPE_SIM:
- EapSimConfig eapSimConfig = (EapSimConfig) eapMethodConfig;
- return new EapSimMethodStateMachine(
- mContext, mEapSessionConfig.eapIdentity, eapSimConfig, mSecureRandom);
- case EAP_TYPE_AKA:
- EapAkaConfig eapAkaConfig = (EapAkaConfig) eapMethodConfig;
- boolean supportsEapAkaPrime =
- mEapSessionConfig.eapConfigs.containsKey(EAP_TYPE_AKA_PRIME);
- return new EapAkaMethodStateMachine(
- mContext,
- mEapSessionConfig.eapIdentity,
- eapAkaConfig,
- supportsEapAkaPrime);
- case EAP_TYPE_AKA_PRIME:
- EapAkaPrimeConfig eapAkaPrimeConfig = (EapAkaPrimeConfig) eapMethodConfig;
- return new EapAkaPrimeMethodStateMachine(
- mContext, mEapSessionConfig.eapIdentity, eapAkaPrimeConfig);
- case EAP_TYPE_MSCHAP_V2:
- EapMsChapV2Config eapMsChapV2Config = (EapMsChapV2Config) eapMethodConfig;
- return new EapMsChapV2MethodStateMachine(eapMsChapV2Config, mSecureRandom);
- default:
- // received unsupported EAP Type. This should never happen.
- LOG.e(mTAG, "Received unsupported EAP Type=" + eapType);
- throw new IllegalArgumentException(
- "Received unsupported EAP Type in MethodState constructor");
- }
- }
- }
-
- protected class SuccessState extends EapState {
- public EapResult process(byte[] packet) {
- return new EapError(new EapInvalidRequestException(
- "Not possible to process messages in Success State"));
- }
- }
-
- protected class FailureState extends EapState {
- public EapResult process(byte[] message) {
- return new EapError(new EapInvalidRequestException(
- "Not possible to process messages in Failure State"));
- }
- }
-
- protected static EapResult handleNotification(String tag, EapMessage message) {
- // Type-Data will be UTF-8 encoded ISO 10646 characters (RFC 3748 Section 5.2)
- String content = new String(message.eapData.eapTypeData, StandardCharsets.UTF_8);
- LOG.i(tag, "Received EAP-Request/Notification: [" + content + "]");
- return EapMessage.getNotificationResponse(message.eapIdentifier);
- }
-}
diff --git a/src/java/com/android/internal/net/ipsec/ike/AbstractSessionStateMachine.java b/src/java/com/android/internal/net/ipsec/ike/AbstractSessionStateMachine.java
deleted file mode 100644
index 82122847..00000000
--- a/src/java/com/android/internal/net/ipsec/ike/AbstractSessionStateMachine.java
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * Copyright (C) 2019 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;
-
-import static android.net.ipsec.ike.IkeManager.getIkeLog;
-
-import android.os.Looper;
-import android.os.Message;
-import android.util.SparseArray;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.State;
-import com.android.internal.util.StateMachine;
-
-import java.util.concurrent.TimeUnit;
-
-/**
- * This class represents the common information of both IkeSessionStateMachine and
- * ChildSessionStateMachine
- */
-abstract class AbstractSessionStateMachine extends StateMachine {
- private static final int CMD_SHARED_BASE = 0;
- protected static final int CMD_CATEGORY_SIZE = 100;
-
- /**
- * Commands of Child local request that will be used in both IkeSessionStateMachine and
- * ChildSessionStateMachine.
- */
- protected static final int CMD_CHILD_LOCAL_REQUEST_BASE = CMD_SHARED_BASE;
-
- @VisibleForTesting
- static final int CMD_LOCAL_REQUEST_CREATE_CHILD = CMD_CHILD_LOCAL_REQUEST_BASE + 1;
-
- @VisibleForTesting
- static final int CMD_LOCAL_REQUEST_DELETE_CHILD = CMD_CHILD_LOCAL_REQUEST_BASE + 2;
-
- @VisibleForTesting
- static final int CMD_LOCAL_REQUEST_REKEY_CHILD = CMD_CHILD_LOCAL_REQUEST_BASE + 3;
-
- /** Timeout commands. */
- protected static final int CMD_TIMEOUT_BASE = CMD_SHARED_BASE + CMD_CATEGORY_SIZE;
- /** Timeout when the remote side fails to send a Rekey-Delete request. */
- @VisibleForTesting static final int TIMEOUT_REKEY_REMOTE_DELETE = CMD_TIMEOUT_BASE + 1;
-
- /** Commands for testing only */
- protected static final int CMD_TEST_BASE = CMD_SHARED_BASE + 2 * CMD_CATEGORY_SIZE;
- /** Force state machine to a target state for testing purposes. */
- @VisibleForTesting static final int CMD_FORCE_TRANSITION = CMD_TEST_BASE + 1;
-
- /** Private commands for subclasses */
- protected static final int CMD_PRIVATE_BASE = CMD_SHARED_BASE + 3 * CMD_CATEGORY_SIZE;
-
- protected static final SparseArray<String> SHARED_CMD_TO_STR;
-
- static {
- SHARED_CMD_TO_STR = new SparseArray<>();
- SHARED_CMD_TO_STR.put(CMD_LOCAL_REQUEST_CREATE_CHILD, "Create Child");
- SHARED_CMD_TO_STR.put(CMD_LOCAL_REQUEST_DELETE_CHILD, "Delete Child");
- SHARED_CMD_TO_STR.put(CMD_LOCAL_REQUEST_REKEY_CHILD, "Rekey Child");
- SHARED_CMD_TO_STR.put(TIMEOUT_REKEY_REMOTE_DELETE, "Timout rekey remote delete");
- SHARED_CMD_TO_STR.put(CMD_FORCE_TRANSITION, "Force transition");
- }
-
- // Use a value greater than the retransmit-failure timeout.
- static final long REKEY_DELETE_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(180L);
-
- private final String mLogTag;
-
- protected AbstractSessionStateMachine(String name, Looper looper) {
- super(name, looper);
- mLogTag = name;
- }
-
- /**
- * Top level state for handling uncaught exceptions for all subclasses.
- *
- * <p>All other state in SessionStateMachine MUST extend this state.
- *
- * <p>Only errors this state should catch are unexpected internal failures. Since this may be
- * run in critical processes, it must never take down the process if it fails
- */
- protected abstract class ExceptionHandlerBase extends State {
- @Override
- public final void enter() {
- try {
- enterState();
- } catch (RuntimeException e) {
- cleanUpAndQuit(e);
- }
- }
-
- @Override
- public final boolean processMessage(Message message) {
- try {
- String cmdName = SHARED_CMD_TO_STR.get(message.what);
- if (cmdName == null) {
- cmdName = getCmdString(message.what);
- }
-
- // Unrecognized message will be logged by super class(Android StateMachine)
- if (cmdName != null) logd("processStateMessage: " + cmdName);
-
- return processStateMessage(message);
- } catch (RuntimeException e) {
- cleanUpAndQuit(e);
- return HANDLED;
- }
- }
-
- @Override
- public final void exit() {
- try {
- exitState();
- } catch (RuntimeException e) {
- cleanUpAndQuit(e);
- }
- }
-
- protected void enterState() {
- // Do nothing. Subclasses MUST override it if they care.
- }
-
- protected boolean processStateMessage(Message message) {
- return NOT_HANDLED;
- }
-
- protected void exitState() {
- // Do nothing. Subclasses MUST override it if they care.
- }
-
- protected abstract void cleanUpAndQuit(RuntimeException e);
-
- protected abstract String getCmdString(int cmd);
- }
-
- @Override
- protected void log(String s) {
- getIkeLog().d(mLogTag, s);
- }
-
- @Override
- protected void logd(String s) {
- getIkeLog().d(mLogTag, s);
- }
-
- protected void logd(String s, Throwable e) {
- getIkeLog().d(mLogTag, s, e);
- }
-
- @Override
- protected void logv(String s) {
- getIkeLog().v(mLogTag, s);
- }
-
- @Override
- protected void logi(String s) {
- getIkeLog().i(mLogTag, s);
- }
-
- protected void logi(String s, Throwable cause) {
- getIkeLog().i(mLogTag, s, cause);
- }
-
- @Override
- protected void logw(String s) {
- getIkeLog().w(mLogTag, s);
- }
-
- @Override
- protected void loge(String s) {
- getIkeLog().e(mLogTag, s);
- }
-
- @Override
- protected void loge(String s, Throwable e) {
- getIkeLog().e(mLogTag, s, e);
- }
-
- protected void logWtf(String s) {
- getIkeLog().wtf(mLogTag, s);
- }
-
- protected void logWtf(String s, Throwable e) {
- getIkeLog().wtf(mLogTag, s, e);
- }
-}
diff --git a/src/java/com/android/internal/net/ipsec/ike/ChildSessionStateMachine.java b/src/java/com/android/internal/net/ipsec/ike/ChildSessionStateMachine.java
deleted file mode 100644
index 889d8c12..00000000
--- a/src/java/com/android/internal/net/ipsec/ike/ChildSessionStateMachine.java
+++ /dev/null
@@ -1,2268 +0,0 @@
-/*
- * Copyright (C) 2019 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;
-
-import static android.net.ipsec.ike.IkeManager.getIkeLog;
-import static android.net.ipsec.ike.SaProposal.DH_GROUP_NONE;
-import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_TEMPORARY_FAILURE;
-
-import static com.android.internal.net.ipsec.ike.IkeSessionStateMachine.IKE_EXCHANGE_SUBTYPE_DELETE_CHILD;
-import static com.android.internal.net.ipsec.ike.IkeSessionStateMachine.IKE_EXCHANGE_SUBTYPE_REKEY_CHILD;
-import static com.android.internal.net.ipsec.ike.message.IkeHeader.EXCHANGE_TYPE_CREATE_CHILD_SA;
-import static com.android.internal.net.ipsec.ike.message.IkeHeader.EXCHANGE_TYPE_IKE_AUTH;
-import static com.android.internal.net.ipsec.ike.message.IkeHeader.EXCHANGE_TYPE_INFORMATIONAL;
-import static com.android.internal.net.ipsec.ike.message.IkeHeader.ExchangeType;
-import static com.android.internal.net.ipsec.ike.message.IkeNotifyPayload.NOTIFY_TYPE_REKEY_SA;
-import static com.android.internal.net.ipsec.ike.message.IkeNotifyPayload.NOTIFY_TYPE_USE_TRANSPORT_MODE;
-import static com.android.internal.net.ipsec.ike.message.IkePayload.PAYLOAD_TYPE_CP;
-import static com.android.internal.net.ipsec.ike.message.IkePayload.PAYLOAD_TYPE_DELETE;
-import static com.android.internal.net.ipsec.ike.message.IkePayload.PAYLOAD_TYPE_KE;
-import static com.android.internal.net.ipsec.ike.message.IkePayload.PAYLOAD_TYPE_NONCE;
-import static com.android.internal.net.ipsec.ike.message.IkePayload.PAYLOAD_TYPE_NOTIFY;
-import static com.android.internal.net.ipsec.ike.message.IkePayload.PAYLOAD_TYPE_SA;
-import static com.android.internal.net.ipsec.ike.message.IkePayload.PAYLOAD_TYPE_TS_INITIATOR;
-import static com.android.internal.net.ipsec.ike.message.IkePayload.PAYLOAD_TYPE_TS_RESPONDER;
-import static com.android.internal.net.ipsec.ike.message.IkePayload.PROTOCOL_ID_ESP;
-
-import android.annotation.IntDef;
-import android.annotation.Nullable;
-import android.content.Context;
-import android.net.IpSecManager;
-import android.net.IpSecManager.ResourceUnavailableException;
-import android.net.IpSecManager.SecurityParameterIndex;
-import android.net.IpSecManager.SpiUnavailableException;
-import android.net.IpSecManager.UdpEncapsulationSocket;
-import android.net.ipsec.ike.ChildSaProposal;
-import android.net.ipsec.ike.ChildSessionCallback;
-import android.net.ipsec.ike.ChildSessionConfiguration;
-import android.net.ipsec.ike.ChildSessionOptions;
-import android.net.ipsec.ike.IkeTrafficSelector;
-import android.net.ipsec.ike.SaProposal;
-import android.net.ipsec.ike.TunnelModeChildSessionOptions;
-import android.net.ipsec.ike.exceptions.IkeException;
-import android.net.ipsec.ike.exceptions.IkeInternalException;
-import android.net.ipsec.ike.exceptions.IkeProtocolException;
-import android.os.Looper;
-import android.os.Message;
-import android.util.Pair;
-import android.util.SparseArray;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.net.ipsec.ike.IkeLocalRequestScheduler.ChildLocalRequest;
-import com.android.internal.net.ipsec.ike.IkeSessionStateMachine.IkeExchangeSubType;
-import com.android.internal.net.ipsec.ike.SaRecord.ChildSaRecord;
-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;
-import com.android.internal.net.ipsec.ike.exceptions.InvalidKeException;
-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.exceptions.TemporaryFailureException;
-import com.android.internal.net.ipsec.ike.exceptions.TsUnacceptableException;
-import com.android.internal.net.ipsec.ike.message.IkeConfigPayload;
-import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttribute;
-import com.android.internal.net.ipsec.ike.message.IkeDeletePayload;
-import com.android.internal.net.ipsec.ike.message.IkeKePayload;
-import com.android.internal.net.ipsec.ike.message.IkeMessage;
-import com.android.internal.net.ipsec.ike.message.IkeNoncePayload;
-import com.android.internal.net.ipsec.ike.message.IkeNotifyPayload;
-import com.android.internal.net.ipsec.ike.message.IkeNotifyPayload.NotifyType;
-import com.android.internal.net.ipsec.ike.message.IkePayload;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload;
-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.util.State;
-
-import java.io.IOException;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.net.InetAddress;
-import java.security.GeneralSecurityException;
-import java.security.Provider;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.concurrent.Executor;
-import java.util.concurrent.TimeUnit;
-
-/**
- * ChildSessionStateMachine tracks states and manages exchanges of this Child Session.
- *
- * <p>ChildSessionStateMachine has two types of states. One type are states where there is no
- * ongoing procedure affecting Child Session (non-procedure state), including Initial, Idle and
- * Receiving. All other states are "procedure" states which are named as follows:
- *
- * <pre>
- * State Name = [Procedure Type] + [Exchange Initiator] + [Exchange Type].
- * - An IKE procedure consists of one or two IKE exchanges:
- * Procedure Type = {CreateChild | DeleteChild | Info | RekeyChild | SimulRekeyChild}.
- * - Exchange Initiator indicates whether local or remote peer is the exchange initiator:
- * Exchange Initiator = {Local | Remote}
- * - Exchange type defines the function of this exchange.
- * Exchange Type = {Create | Delete}
- * </pre>
- */
-public class ChildSessionStateMachine extends AbstractSessionStateMachine {
- private static final String TAG = "ChildSessionStateMachine";
-
- private static final int SPI_NOT_REGISTERED = 0;
-
- // Time after which Child SA needs to be rekeyed
- @VisibleForTesting static final long SA_SOFT_LIFETIME_MS = TimeUnit.HOURS.toMillis(2L);
-
- private static final int CMD_GENERAL_BASE = CMD_PRIVATE_BASE;
-
- /** Receive request for negotiating first Child SA. */
- private static final int CMD_HANDLE_FIRST_CHILD_EXCHANGE = CMD_GENERAL_BASE + 1;
- /** Receive a request from the remote. */
- private static final int CMD_HANDLE_RECEIVED_REQUEST = CMD_GENERAL_BASE + 2;
- /** Receive a reponse from the remote. */
- private static final int CMD_HANDLE_RECEIVED_RESPONSE = CMD_GENERAL_BASE + 3;
- /** Kill Session and close all alive Child SAs immediately. */
- private static final int CMD_KILL_SESSION = CMD_GENERAL_BASE + 4;
-
- private static final SparseArray<String> CMD_TO_STR;
-
- static {
- CMD_TO_STR = new SparseArray<>();
- CMD_TO_STR.put(CMD_HANDLE_FIRST_CHILD_EXCHANGE, "Handle First Child");
- CMD_TO_STR.put(CMD_HANDLE_RECEIVED_REQUEST, "Rcv request");
- CMD_TO_STR.put(CMD_HANDLE_RECEIVED_RESPONSE, "Rcv response");
- CMD_TO_STR.put(CMD_KILL_SESSION, "Kill session");
- }
-
- private final Context mContext;
- private final IpSecManager mIpSecManager;
-
- /** User provided configurations. */
- private final ChildSessionOptions mChildSessionOptions;
-
- private final Executor mUserCbExecutor;
- private final ChildSessionCallback mUserCallback;
-
- /** Callback to notify IKE Session the state changes. */
- private final IChildSessionSmCallback mChildSmCallback;
-
- // TODO: Also store ChildSessionCallback for notifying users.
-
- /** Local address assigned on device. */
- @VisibleForTesting InetAddress mLocalAddress;
- /** Remote address configured by users. */
- @VisibleForTesting InetAddress mRemoteAddress;
-
- /**
- * UDP-Encapsulated socket that allows IPsec traffic to pass through a NAT. Null if UDP
- * encapsulation is not needed.
- */
- @VisibleForTesting @Nullable UdpEncapsulationSocket mUdpEncapSocket;
-
- /** Crypto parameters. Updated upon initial negotiation or IKE SA rekey. */
- @VisibleForTesting IkeMacPrf mIkePrf;
-
- @VisibleForTesting byte[] mSkD;
-
- /** Package private ChildSaProposal that represents the negotiated Child SA proposal. */
- @VisibleForTesting ChildSaProposal mSaProposal;
-
- /** Negotiated local Traffic Selector. */
- @VisibleForTesting IkeTrafficSelector[] mLocalTs;
- /** Negotiated remote Traffic Selector. */
- @VisibleForTesting IkeTrafficSelector[] mRemoteTs;
-
- @VisibleForTesting IkeCipher mChildCipher;
- @VisibleForTesting IkeMacIntegrity mChildIntegrity;
-
- /** Package private */
- @VisibleForTesting ChildSaRecord mCurrentChildSaRecord;
- /** Package private */
- @VisibleForTesting ChildSaRecord mLocalInitNewChildSaRecord;
- /** Package private */
- @VisibleForTesting ChildSaRecord mRemoteInitNewChildSaRecord;
-
- /** Package private */
- @VisibleForTesting ChildSaRecord mChildSaRecordSurviving;
-
- @VisibleForTesting final State mKillChildSessionParent = new KillChildSessionParent();
-
- @VisibleForTesting final State mInitial = new Initial();
- @VisibleForTesting final State mCreateChildLocalCreate = new CreateChildLocalCreate();
- @VisibleForTesting final State mIdle = new Idle();
- @VisibleForTesting final State mDeleteChildLocalDelete = new DeleteChildLocalDelete();
- @VisibleForTesting final State mDeleteChildRemoteDelete = new DeleteChildRemoteDelete();
- @VisibleForTesting final State mRekeyChildLocalCreate = new RekeyChildLocalCreate();
- @VisibleForTesting final State mRekeyChildRemoteCreate = new RekeyChildRemoteCreate();
- @VisibleForTesting final State mRekeyChildLocalDelete = new RekeyChildLocalDelete();
- @VisibleForTesting final State mRekeyChildRemoteDelete = new RekeyChildRemoteDelete();
-
- /**
- * Builds a new uninitialized ChildSessionStateMachine
- *
- * <p>Upon creation, this state machine will await either the handleFirstChildExchange
- * (IKE_AUTH), or the createChildSession (Additional child creation beyond the first child) to
- * be called, both of which must pass keying and SA information.
- *
- * <p>This two-stage initialization is required to allow race-free user interaction with the IKE
- * Session keyed on the child state machine callbacks.
- *
- * <p>Package private
- */
- ChildSessionStateMachine(
- Looper looper,
- Context context,
- IpSecManager ipSecManager,
- ChildSessionOptions sessionOptions,
- Executor userCbExecutor,
- ChildSessionCallback userCallback,
- IChildSessionSmCallback childSmCallback) {
- super(TAG, looper);
-
- mContext = context;
- mIpSecManager = ipSecManager;
- mChildSessionOptions = sessionOptions;
-
- mUserCbExecutor = userCbExecutor;
- mUserCallback = userCallback;
- mChildSmCallback = childSmCallback;
-
- addState(mKillChildSessionParent);
-
- addState(mInitial, mKillChildSessionParent);
- addState(mCreateChildLocalCreate, mKillChildSessionParent);
- addState(mIdle, mKillChildSessionParent);
- addState(mDeleteChildLocalDelete, mKillChildSessionParent);
- addState(mDeleteChildRemoteDelete, mKillChildSessionParent);
- addState(mRekeyChildLocalCreate, mKillChildSessionParent);
- addState(mRekeyChildRemoteCreate, mKillChildSessionParent);
- addState(mRekeyChildLocalDelete, mKillChildSessionParent);
- addState(mRekeyChildRemoteDelete, mKillChildSessionParent);
-
- setInitialState(mInitial);
- }
-
- /**
- * Interface for ChildSessionStateMachine to notify IkeSessionStateMachine of state changes.
- *
- * <p>Child Session may encounter an IKE Session fatal error in three cases with different
- * handling rules:
- *
- * <pre>
- * - When there is a fatal error in an inbound request, onOutboundPayloadsReady will be
- * called first to send out an error notification and then onFatalIkeSessionError(false)
- * will be called to locally close the IKE Session.
- * - When there is a fatal error in an inbound response, only onFatalIkeSessionError(true)
- * will be called to notify the remote with a Delete request and then close the IKE Session.
- * - When there is an fatal error notification in an inbound response, only
- * onFatalIkeSessionError(false) is called to close the IKE Session locally.
- * </pre>
- *
- * <p>Package private.
- */
- interface IChildSessionSmCallback {
- /** Notify that new Child SA is created. */
- void onChildSaCreated(int remoteSpi, ChildSessionStateMachine childSession);
-
- /** Notify that a Child SA is deleted. */
- void onChildSaDeleted(int remoteSpi);
-
- /** Schedule a future Child Rekey Request on the LocalRequestScheduler. */
- void scheduleLocalRequest(ChildLocalRequest futureRequest, long delayedTime);
-
- /** Schedule retry for a Child Rekey Request on the LocalRequestScheduler. */
- void scheduleRetryLocalRequest(ChildLocalRequest futureRequest);
-
- /** Notify the IKE Session to send out IKE message for this Child Session. */
- void onOutboundPayloadsReady(
- @ExchangeType int exchangeType,
- boolean isResp,
- List<IkePayload> payloadList,
- ChildSessionStateMachine childSession);
-
- /** Notify that a Child procedure has been finished. */
- void onProcedureFinished(ChildSessionStateMachine childSession);
-
- /**
- * Notify the IKE Session State Machine that this Child has been fully shut down.
- *
- * <p>This method MUST be called after the user callbacks have been fired, and MUST always
- * be called before the state machine can shut down.
- */
- void onChildSessionClosed(ChildSessionCallback userCallbacks);
-
- /**
- * Notify that a Child procedure has been finished and the IKE Session should close itself
- * because of a fatal error.
- *
- * <p>The IKE Session should send a Delete IKE request before closing when needsNotifyRemote
- * is true.
- */
- void onFatalIkeSessionError(boolean needsNotifyRemote);
- }
-
- /**
- * Receive requesting and responding payloads for negotiating first Child SA.
- *
- * <p>This method is called synchronously from IkeStateMachine. It proxies the synchronous call
- * as an asynchronous job to the ChildStateMachine handler.
- *
- * @param reqPayloads SA negotiation related payloads in IKE_AUTH request.
- * @param respPayloads SA negotiation related payloads in IKE_AUTH response.
- * @param localAddress The local (outer) address of the Child Session.
- * @param remoteAddress The remote (outer) address of the Child Session.
- * @param udpEncapSocket The socket to use for UDP encapsulation, or NULL if no encap needed.
- * @param ikePrf The pseudo-random function to use for key derivation
- * @param skD The key for which to derive new keying information from.
- */
- public void handleFirstChildExchange(
- List<IkePayload> reqPayloads,
- List<IkePayload> respPayloads,
- InetAddress localAddress,
- InetAddress remoteAddress,
- UdpEncapsulationSocket udpEncapSocket,
- IkeMacPrf ikePrf,
- byte[] skD) {
-
- this.mLocalAddress = localAddress;
- this.mRemoteAddress = remoteAddress;
- this.mUdpEncapSocket = udpEncapSocket;
- this.mIkePrf = ikePrf;
- this.mSkD = skD;
-
- int spi = registerProvisionalChildAndGetSpi(respPayloads);
- sendMessage(
- CMD_HANDLE_FIRST_CHILD_EXCHANGE,
- new FirstChildNegotiationData(reqPayloads, respPayloads, spi));
- }
-
- /**
- * Initiate Create Child procedure.
- *
- * <p>This method is called synchronously from IkeStateMachine. It proxies the synchronous call
- * as an asynchronous job to the ChildStateMachine handler.
- *
- * @param localAddress The local (outer) address from which traffic will originate.
- * @param remoteAddress The remote (outer) address to which traffic will be sent.
- * @param udpEncapSocket The socket to use for UDP encapsulation, or NULL if no encap needed.
- * @param ikePrf The pseudo-random function to use for key derivation
- * @param skD The key for which to derive new keying information from.
- */
- public void createChildSession(
- InetAddress localAddress,
- InetAddress remoteAddress,
- UdpEncapsulationSocket udpEncapSocket,
- IkeMacPrf ikePrf,
- byte[] skD) {
- this.mLocalAddress = localAddress;
- this.mRemoteAddress = remoteAddress;
- this.mUdpEncapSocket = udpEncapSocket;
- this.mIkePrf = ikePrf;
- this.mSkD = skD;
-
- sendMessage(CMD_LOCAL_REQUEST_CREATE_CHILD);
- }
-
- /**
- * Initiate Delete Child procedure.
- *
- * <p>This method is called synchronously from IkeStateMachine. It proxies the synchronous call
- * as an asynchronous job to the ChildStateMachine handler.
- */
- public void deleteChildSession() {
- sendMessage(CMD_LOCAL_REQUEST_DELETE_CHILD);
- }
-
- /**
- * Initiate Rekey Child procedure.
- *
- * <p>This method is called synchronously from IkeStateMachine. It proxies the synchronous call
- * as an asynchronous job to the ChildStateMachine handler.
- */
- public void rekeyChildSession() {
- sendMessage(CMD_LOCAL_REQUEST_REKEY_CHILD);
- }
-
- /**
- * Kill Child Session and all alive Child SAs without doing IKE exchange.
- *
- * <p>It is usually called when IKE Session is being closed.
- */
- public void killSession() {
- sendMessage(CMD_KILL_SESSION);
- }
-
- private ChildLocalRequest makeRekeyLocalRequest() {
- return new ChildLocalRequest(
- CMD_LOCAL_REQUEST_REKEY_CHILD, mUserCallback, null /*childOptions*/);
- }
-
- private long getRekeyTimeout() {
- // TODO: Make rekey timout fuzzy
- return SA_SOFT_LIFETIME_MS;
- }
-
- /**
- * Receive a request
- *
- * <p>This method is called synchronously from IkeStateMachine. It proxies the synchronous call
- * as an asynchronous job to the ChildStateMachine handler.
- *
- * @param exchangeSubtype the exchange subtype of this inbound request.
- * @param exchangeType the exchange type in the request message.
- * @param payloadList the Child-procedure-related payload list in the request message that needs
- * validation.
- */
- public void receiveRequest(
- @IkeExchangeSubType int exchangeSubtype,
- @ExchangeType int exchangeType,
- List<IkePayload> payloadList) {
- sendMessage(
- CMD_HANDLE_RECEIVED_REQUEST,
- new ReceivedRequest(exchangeSubtype, exchangeType, payloadList));
- }
-
- /**
- * Receive a response.
- *
- * <p>This method is called synchronously from IkeStateMachine. It proxies the synchronous call
- * as an asynchronous job to the ChildStateMachine handler.
- *
- * @param exchangeType the exchange type in the response message that needs validation.
- * @param payloadList the Child-procedure-related payload list in the response message that
- * needs validation.
- */
- public void receiveResponse(@ExchangeType int exchangeType, List<IkePayload> payloadList) {
- if (!isAwaitingCreateResp()) {
- sendMessage(
- CMD_HANDLE_RECEIVED_RESPONSE, new ReceivedResponse(exchangeType, payloadList));
- }
-
- // If we are waiting for a Create/RekeyCreate response and the received message contains SA
- // payload we need to register for this provisional Child.
- int spi = registerProvisionalChildAndGetSpi(payloadList);
- sendMessage(
- CMD_HANDLE_RECEIVED_RESPONSE,
- new ReceivedCreateResponse(exchangeType, payloadList, spi));
- }
-
- private boolean isAwaitingCreateResp() {
- return (getCurrentState() == mCreateChildLocalCreate
- || getCurrentState() == mRekeyChildLocalCreate);
- }
-
- /**
- * Update SK_d with provided value when IKE SA is rekeyed.
- *
- * <p>It MUST be only called at the end of Rekey IKE procedure, which guarantees this Child
- * Session is not in Create Child or Rekey Child procedure.
- *
- * @param skD the new skD in byte array.
- */
- public void setSkD(byte[] skD) {
- mSkD = skD;
- }
-
- /**
- * Register provisioning ChildSessionStateMachine in IChildSessionSmCallback
- *
- * <p>This method is for avoiding CHILD_SA_NOT_FOUND error in IkeSessionStateMachine when remote
- * peer sends request for delete/rekey this Child SA before ChildSessionStateMachine sends
- * FirstChildNegotiationData or Create response to itself.
- */
- private int registerProvisionalChildAndGetSpi(List<IkePayload> respPayloads) {
- IkeSaPayload saPayload =
- IkePayload.getPayloadForTypeInProvidedList(
- PAYLOAD_TYPE_SA, IkeSaPayload.class, respPayloads);
-
- if (saPayload == null) return SPI_NOT_REGISTERED;
-
- // IkeSaPayload.Proposal stores SPI in long type so as to be applied to both 8-byte IKE SPI
- // and 4-byte Child SPI. Here we cast the stored SPI to int to represent a Child SPI.
- int remoteGenSpi = (int) (saPayload.proposalList.get(0).spi);
- mChildSmCallback.onChildSaCreated(remoteGenSpi, this);
- return remoteGenSpi;
- }
-
- private void replyErrorNotification(@NotifyType int notifyType) {
- replyErrorNotification(notifyType, new byte[0]);
- }
-
- private void replyErrorNotification(@NotifyType int notifyType, byte[] notifyData) {
- List<IkePayload> outPayloads = new ArrayList<>(1);
- IkeNotifyPayload notifyPayload = new IkeNotifyPayload(notifyType, notifyData);
- outPayloads.add(notifyPayload);
-
- mChildSmCallback.onOutboundPayloadsReady(
- EXCHANGE_TYPE_INFORMATIONAL, true /*isResp*/, outPayloads, this);
- }
-
- /** Notify users the deletion of a Child SA. MUST be called through mUserCbExecutor */
- private void onIpSecTransformPairDeleted(ChildSaRecord childSaRecord) {
- mUserCallback.onIpSecTransformDeleted(
- childSaRecord.getOutboundIpSecTransform(), IpSecManager.DIRECTION_OUT);
- mUserCallback.onIpSecTransformDeleted(
- childSaRecord.getInboundIpSecTransform(), IpSecManager.DIRECTION_IN);
- }
-
- /**
- * ReceivedRequest contains exchange subtype and payloads that are extracted from a request
- * message to the current Child procedure.
- */
- private static class ReceivedRequest {
- @IkeExchangeSubType public final int exchangeSubtype;
- @ExchangeType public final int exchangeType;
- public final List<IkePayload> requestPayloads;
-
- ReceivedRequest(
- @IkeExchangeSubType int eSubtype,
- @ExchangeType int eType,
- List<IkePayload> reqPayloads) {
- exchangeSubtype = eSubtype;
- exchangeType = eType;
- requestPayloads = reqPayloads;
- }
- }
-
- /**
- * ReceivedResponse contains exchange type and payloads that are extracted from a response
- * message to the current Child procedure.
- */
- private static class ReceivedResponse {
- @ExchangeType public final int exchangeType;
- public final List<IkePayload> responsePayloads;
-
- ReceivedResponse(@ExchangeType int eType, List<IkePayload> respPayloads) {
- exchangeType = eType;
- responsePayloads = respPayloads;
- }
- }
-
- private static class ReceivedCreateResponse extends ReceivedResponse {
- public final int registeredSpi;
-
- ReceivedCreateResponse(@ExchangeType int eType, List<IkePayload> respPayloads, int spi) {
- super(eType, respPayloads);
- registeredSpi = spi;
- }
- }
-
- /**
- * FirstChildNegotiationData contains payloads for negotiating first Child SA in IKE_AUTH
- * request and IKE_AUTH response and callback to notify IkeSessionStateMachine the SA
- * negotiation result.
- */
- private static class FirstChildNegotiationData extends ReceivedCreateResponse {
- public final List<IkePayload> requestPayloads;
-
- FirstChildNegotiationData(
- List<IkePayload> reqPayloads, List<IkePayload> respPayloads, int spi) {
- super(EXCHANGE_TYPE_IKE_AUTH, respPayloads, spi);
- requestPayloads = reqPayloads;
- }
- }
-
- /** Top level state for handling uncaught exceptions for all subclasses. */
- abstract class ExceptionHandler extends ExceptionHandlerBase {
- @Override
- protected void cleanUpAndQuit(RuntimeException e) {
- // TODO: b/140123526 Send a response if exception was caught when processing a request.
-
- // Clean up all SaRecords.
- closeAllSaRecords(false /*expectSaClosed*/);
-
- mUserCbExecutor.execute(
- () -> {
- mUserCallback.onClosedExceptionally(new IkeInternalException(e));
- });
- logWtf("Unexpected exception in " + getCurrentState().getName(), e);
- quitNow();
- }
-
- @Override
- protected String getCmdString(int cmd) {
- return CMD_TO_STR.get(cmd);
- }
- }
-
- /** Called when this StateMachine quits. */
- @Override
- protected void onQuitting() {
- // Clean up all SaRecords.
- closeAllSaRecords(true /*expectSaClosed*/);
-
- mChildSmCallback.onProcedureFinished(this);
- mChildSmCallback.onChildSessionClosed(mUserCallback);
- }
-
- private void closeAllSaRecords(boolean expectSaClosed) {
- closeChildSaRecord(mCurrentChildSaRecord, expectSaClosed);
- closeChildSaRecord(mLocalInitNewChildSaRecord, expectSaClosed);
- closeChildSaRecord(mRemoteInitNewChildSaRecord, expectSaClosed);
-
- mCurrentChildSaRecord = null;
- mLocalInitNewChildSaRecord = null;
- mRemoteInitNewChildSaRecord = null;
- }
-
- private void closeChildSaRecord(ChildSaRecord childSaRecord, boolean expectSaClosed) {
- if (childSaRecord == null) return;
-
- mUserCbExecutor.execute(
- () -> {
- onIpSecTransformPairDeleted(childSaRecord);
- });
-
- mChildSmCallback.onChildSaDeleted(childSaRecord.getRemoteSpi());
- childSaRecord.close();
-
- if (!expectSaClosed) return;
-
- logWtf(
- "ChildSaRecord with local SPI: "
- + childSaRecord.getLocalSpi()
- + " is not correctly closed.");
- }
-
- private void handleChildFatalError(Exception error) {
- IkeException ikeException =
- error instanceof IkeException
- ? (IkeException) error
- : new IkeInternalException(error);
-
- mUserCbExecutor.execute(
- () -> {
- mUserCallback.onClosedExceptionally(ikeException);
- });
- loge("Child Session fatal error", ikeException);
-
- // Clean up all SaRecords and quit
- closeAllSaRecords(false /*expectSaClosed*/);
- quitNow();
- }
-
- /**
- * This state handles the request to close Child Session immediately without initiating any
- * exchange.
- *
- * <p>Request for closing Child Session immediately is usually caused by the closing of IKE
- * Session. All states MUST be a child state of KillChildSessionParent to handle the closing
- * request.
- */
- private class KillChildSessionParent extends ExceptionHandler {
- @Override
- public boolean processStateMessage(Message message) {
- switch (message.what) {
- case CMD_KILL_SESSION:
- mUserCbExecutor.execute(
- () -> {
- mUserCallback.onClosed();
- });
-
- closeAllSaRecords(false /*expectSaClosed*/);
-
- quitNow();
- return HANDLED;
- default:
- return NOT_HANDLED;
- }
- }
- }
-
- /**
- * CreateChildLocalCreateBase represents the common information for a locally-initiated initial
- * Child SA negotiation for setting up this Child Session.
- */
- private abstract class CreateChildLocalCreateBase extends ExceptionHandler {
- protected void validateAndBuildChild(
- List<IkePayload> reqPayloads,
- List<IkePayload> respPayloads,
- @ExchangeType int exchangeType,
- @ExchangeType int expectedExchangeType,
- int registeredSpi) {
- CreateChildResult createChildResult =
- CreateChildSaHelper.validateAndNegotiateInitChild(
- reqPayloads,
- respPayloads,
- exchangeType,
- expectedExchangeType,
- mChildSessionOptions.isTransportMode(),
- mIpSecManager,
- mRemoteAddress);
- switch (createChildResult.status) {
- case CREATE_STATUS_OK:
- try {
- setUpNegotiatedResult(createChildResult);
-
- ChildLocalRequest rekeyLocalRequest = makeRekeyLocalRequest();
-
- mCurrentChildSaRecord =
- ChildSaRecord.makeChildSaRecord(
- mContext,
- reqPayloads,
- respPayloads,
- createChildResult.initSpi,
- createChildResult.respSpi,
- mLocalAddress,
- mRemoteAddress,
- mUdpEncapSocket,
- mIkePrf,
- mChildIntegrity,
- mChildCipher,
- mSkD,
- mChildSessionOptions.isTransportMode(),
- true /*isLocalInit*/,
- rekeyLocalRequest);
-
- mChildSmCallback.scheduleLocalRequest(rekeyLocalRequest, getRekeyTimeout());
-
- ChildSessionConfiguration sessionConfig =
- buildChildSessionConfigFromResp(createChildResult, respPayloads);
- mUserCbExecutor.execute(
- () -> {
- mUserCallback.onIpSecTransformCreated(
- mCurrentChildSaRecord.getInboundIpSecTransform(),
- IpSecManager.DIRECTION_IN);
- mUserCallback.onIpSecTransformCreated(
- mCurrentChildSaRecord.getOutboundIpSecTransform(),
- IpSecManager.DIRECTION_OUT);
- mUserCallback.onOpened(sessionConfig);
- });
-
- transitionTo(mIdle);
- } catch (GeneralSecurityException
- | ResourceUnavailableException
- | SpiUnavailableException
- | IOException e) {
- // #makeChildSaRecord failed.
-
- // TODO: Initiate deletion
- mChildSmCallback.onChildSaDeleted(createChildResult.respSpi.getSpi());
- createChildResult.initSpi.close();
- createChildResult.respSpi.close();
- handleChildFatalError(e);
- }
- break;
- case CREATE_STATUS_CHILD_ERROR_INVALID_MSG:
- // TODO: Initiate deletion
- handleCreationFailAndQuit(registeredSpi, createChildResult.exception);
- break;
- case CREATE_STATUS_CHILD_ERROR_RCV_NOTIFY:
- handleCreationFailAndQuit(registeredSpi, createChildResult.exception);
- break;
- default:
- cleanUpAndQuit(
- new IllegalStateException(
- "Unrecognized status: " + createChildResult.status));
- }
- }
-
- private void setUpNegotiatedResult(CreateChildResult createChildResult) {
- // Build crypto tools using negotiated ChildSaProposal. It is ensured by {@link
- // IkeSaPayload#getVerifiedNegotiatedChildProposalPair} that the negotiated
- // ChildSaProposal is valid. The negotiated ChildSaProposal has exactly one encryption
- // algorithm. When it has a combined-mode encryption algorithm, it either does not have
- // integrity algorithm or only has one NONE value integrity algorithm. When the
- // negotiated ChildSaProposal has a normal encryption algorithm, it either does not have
- // integrity algorithm or has one integrity algorithm with any supported value.
-
- mSaProposal = createChildResult.negotiatedProposal;
- Provider provider = IkeMessage.getSecurityProvider();
- mChildCipher = IkeCipher.create(mSaProposal.getEncryptionTransforms()[0], provider);
- if (mSaProposal.getIntegrityTransforms().length != 0
- && mSaProposal.getIntegrityTransforms()[0].id
- != SaProposal.INTEGRITY_ALGORITHM_NONE) {
- mChildIntegrity =
- IkeMacIntegrity.create(mSaProposal.getIntegrityTransforms()[0], provider);
- }
-
- mLocalTs = createChildResult.initTs;
- mRemoteTs = createChildResult.respTs;
- }
-
- private ChildSessionConfiguration buildChildSessionConfigFromResp(
- CreateChildResult createChildResult, List<IkePayload> respPayloads) {
- IkeConfigPayload configPayload =
- IkePayload.getPayloadForTypeInProvidedList(
- PAYLOAD_TYPE_CP, IkeConfigPayload.class, respPayloads);
-
- if (mChildSessionOptions.isTransportMode()
- || configPayload == null
- || configPayload.configType != IkeConfigPayload.CONFIG_TYPE_REPLY) {
- if (configPayload != null) {
- logw("Unexpected config payload. Config Type: " + configPayload.configType);
- }
-
- return new ChildSessionConfiguration(
- Arrays.asList(createChildResult.initTs),
- Arrays.asList(createChildResult.respTs));
- } else {
- return new ChildSessionConfiguration(
- Arrays.asList(createChildResult.initTs),
- Arrays.asList(createChildResult.respTs),
- configPayload);
- }
- }
-
- private void handleCreationFailAndQuit(int registeredSpi, IkeException exception) {
- if (registeredSpi != SPI_NOT_REGISTERED) {
- mChildSmCallback.onChildSaDeleted(registeredSpi);
- }
- handleChildFatalError(exception);
- }
- }
-
- /** Initial state of ChildSessionStateMachine. */
- class Initial extends CreateChildLocalCreateBase {
- @Override
- public boolean processStateMessage(Message message) {
- switch (message.what) {
- case CMD_HANDLE_FIRST_CHILD_EXCHANGE:
- FirstChildNegotiationData childNegotiationData =
- (FirstChildNegotiationData) message.obj;
- List<IkePayload> reqPayloads = childNegotiationData.requestPayloads;
- List<IkePayload> respPayloads = childNegotiationData.responsePayloads;
-
- // Negotiate Child SA. The exchangeType has been validated in
- // IkeSessionStateMachine. Won't validate it again here.
- validateAndBuildChild(
- reqPayloads,
- respPayloads,
- EXCHANGE_TYPE_IKE_AUTH,
- EXCHANGE_TYPE_IKE_AUTH,
- childNegotiationData.registeredSpi);
-
- return HANDLED;
- case CMD_LOCAL_REQUEST_CREATE_CHILD:
- transitionTo(mCreateChildLocalCreate);
- return HANDLED;
- case CMD_LOCAL_REQUEST_DELETE_CHILD:
- // This may happen when creation has been rescheduled to be after deletion.
- mUserCbExecutor.execute(
- () -> {
- mUserCallback.onClosed();
- });
- quitNow();
- return HANDLED;
- case CMD_FORCE_TRANSITION:
- transitionTo((State) message.obj);
- return HANDLED;
- default:
- return NOT_HANDLED;
- }
- }
- }
-
- /**
- * CreateChildLocalCreate represents the state where Child Session initiates the Create Child
- * exchange.
- */
- class CreateChildLocalCreate extends CreateChildLocalCreateBase {
- private List<IkePayload> mRequestPayloads;
-
- @Override
- public void enterState() {
- try {
- mRequestPayloads =
- CreateChildSaHelper.getInitChildCreateReqPayloads(
- mIpSecManager,
- mLocalAddress,
- mChildSessionOptions,
- false /*isFirstChild*/);
- mChildSmCallback.onOutboundPayloadsReady(
- EXCHANGE_TYPE_CREATE_CHILD_SA,
- false /*isResp*/,
- mRequestPayloads,
- ChildSessionStateMachine.this);
- } catch (ResourceUnavailableException e) {
- // Fail to assign SPI
- handleChildFatalError(e);
- }
- }
-
- @Override
- public boolean processStateMessage(Message message) {
- switch (message.what) {
- case CMD_HANDLE_RECEIVED_RESPONSE:
- ReceivedCreateResponse rcvResp = (ReceivedCreateResponse) message.obj;
- validateAndBuildChild(
- mRequestPayloads,
- rcvResp.responsePayloads,
- rcvResp.exchangeType,
- EXCHANGE_TYPE_CREATE_CHILD_SA,
- rcvResp.registeredSpi);
- return HANDLED;
- default:
- return NOT_HANDLED;
- }
- }
- }
-
- /**
- * Idle represents a state when there is no ongoing IKE exchange affecting established Child SA.
- */
- class Idle extends ExceptionHandler {
- @Override
- public void enterState() {
- mChildSmCallback.onProcedureFinished(ChildSessionStateMachine.this);
- }
-
- @Override
- public boolean processStateMessage(Message message) {
- switch (message.what) {
- case CMD_LOCAL_REQUEST_DELETE_CHILD:
- transitionTo(mDeleteChildLocalDelete);
- return HANDLED;
- case CMD_LOCAL_REQUEST_REKEY_CHILD:
- transitionTo(mRekeyChildLocalCreate);
- return HANDLED;
- case CMD_HANDLE_RECEIVED_REQUEST:
- ReceivedRequest req = (ReceivedRequest) message.obj;
- switch (req.exchangeSubtype) {
- case IKE_EXCHANGE_SUBTYPE_DELETE_CHILD:
- deferMessage(message);
- transitionTo(mDeleteChildRemoteDelete);
- return HANDLED;
- case IKE_EXCHANGE_SUBTYPE_REKEY_CHILD:
- deferMessage(message);
- transitionTo(mRekeyChildRemoteCreate);
- return HANDLED;
- default:
- return NOT_HANDLED;
- }
- case CMD_FORCE_TRANSITION: // Testing command
- transitionTo((State) message.obj);
- return HANDLED;
- default:
- return NOT_HANDLED;
- }
- }
- }
-
- /**
- * DeleteResponderBase represents all states after Child Session is established
- *
- * <p>All post-init states share common functionality of being able to respond to Delete Child
- * requests.
- */
- private abstract class DeleteResponderBase extends ExceptionHandler {
- /**
- * Check if the payload list has a Delete Payload that includes the remote SPI of the input
- * ChildSaRecord.
- */
- protected boolean hasRemoteChildSpiForDelete(
- List<IkePayload> payloads, ChildSaRecord expectedRecord) {
- List<IkeDeletePayload> delPayloads =
- IkePayload.getPayloadListForTypeInProvidedList(
- PAYLOAD_TYPE_DELETE, IkeDeletePayload.class, payloads);
-
- for (IkeDeletePayload delPayload : delPayloads) {
- for (int spi : delPayload.spisToDelete) {
- if (spi == expectedRecord.getRemoteSpi()) return true;
- }
- }
- return false;
- }
-
- /**
- * Build and send payload list that has a Delete Payload that includes the local SPI of the
- * input ChildSaRecord.
- */
- protected void sendDeleteChild(ChildSaRecord childSaRecord, boolean isResp) {
- List<IkePayload> outIkePayloads = new ArrayList<>(1);
- outIkePayloads.add(new IkeDeletePayload(new int[] {childSaRecord.getLocalSpi()}));
-
- mChildSmCallback.onOutboundPayloadsReady(
- EXCHANGE_TYPE_INFORMATIONAL,
- isResp,
- outIkePayloads,
- ChildSessionStateMachine.this);
- }
-
- /**
- * Helper method for responding to a session deletion request
- *
- * <p>Note that this method expects that the session is keyed on the mCurrentChildSaRecord
- * and closing this Child SA indicates that the remote wishes to end the session as a whole.
- * As such, this should not be used in rekey cases where there is any ambiguity as to which
- * Child SA the session is reliant upon.
- *
- * <p>Note that this method will also quit the state machine
- */
- protected void handleDeleteSessionRequest(List<IkePayload> payloads) {
- if (!hasRemoteChildSpiForDelete(payloads, mCurrentChildSaRecord)) {
- cleanUpAndQuit(
- new IllegalStateException(
- "Found no remote SPI for mCurrentChildSaRecord in a Delete Child"
- + " request."));
- } else {
-
- mUserCbExecutor.execute(
- () -> {
- mUserCallback.onClosed();
- onIpSecTransformPairDeleted(mCurrentChildSaRecord);
- });
-
- sendDeleteChild(mCurrentChildSaRecord, true /*isResp*/);
-
- mChildSmCallback.onChildSaDeleted(mCurrentChildSaRecord.getRemoteSpi());
- mCurrentChildSaRecord.close();
- mCurrentChildSaRecord = null;
-
- quitNow();
- }
- }
- }
-
- /**
- * DeleteBase abstracts deletion handling for all states initiating and responding to a Delete
- * Child exchange
- *
- * <p>All subclasses of this state share common functionality that a deletion request is sent,
- * and the response is received.
- */
- private abstract class DeleteBase extends DeleteResponderBase {
- /** Validate payload types in Delete Child response. */
- protected void validateDeleteRespPayloadAndExchangeType(
- List<IkePayload> respPayloads, @ExchangeType int exchangeType)
- throws IkeProtocolException {
-
- if (exchangeType != EXCHANGE_TYPE_INFORMATIONAL) {
- throw new InvalidSyntaxException(
- "Unexpected exchange type in Delete Child response: " + exchangeType);
- }
-
- for (IkePayload payload : respPayloads) {
- handlePayload:
- switch (payload.payloadType) {
- case PAYLOAD_TYPE_DELETE:
- // A Delete Payload is only required when it is not simultaneous deletion.
- // Included Child SPIs are verified in the subclass to make sure the remote
- // side is deleting the right SAs.
- break handlePayload;
- case PAYLOAD_TYPE_NOTIFY:
- IkeNotifyPayload notify = (IkeNotifyPayload) payload;
- if (!notify.isErrorNotify()) {
- logw(
- "Unexpected or unknown status notification in Delete Child"
- + " response: "
- + notify.notifyType);
- break handlePayload;
- }
-
- throw notify.validateAndBuildIkeException();
- default:
- logw(
- "Unexpected payload type in Delete Child response: "
- + payload.payloadType);
- }
- }
- }
- }
-
- /**
- * DeleteChildLocalDelete represents the state where Child Session initiates the Delete Child
- * exchange.
- */
- class DeleteChildLocalDelete extends DeleteBase {
- private boolean mSimulDeleteDetected = false;
-
- @Override
- public void enterState() {
- mSimulDeleteDetected = false;
- sendDeleteChild(mCurrentChildSaRecord, false /*isResp*/);
- }
-
- @Override
- public boolean processStateMessage(Message message) {
- switch (message.what) {
- case CMD_HANDLE_RECEIVED_RESPONSE:
- try {
- ReceivedResponse resp = (ReceivedResponse) message.obj;
- validateDeleteRespPayloadAndExchangeType(
- resp.responsePayloads, resp.exchangeType);
-
- boolean currentSaSpiFound =
- hasRemoteChildSpiForDelete(
- resp.responsePayloads, mCurrentChildSaRecord);
- if (!currentSaSpiFound && !mSimulDeleteDetected) {
- throw new InvalidSyntaxException(
- "Found no remote SPI in received Delete response.");
- } else if (currentSaSpiFound && mSimulDeleteDetected) {
- // As required by the RFC 7296, in simultaneous delete case, the remote
- // side MUST NOT include SPI of mCurrentChildSaRecord. However, to
- // provide better interoperatibility, IKE library will keep IKE Session
- // alive and continue the deleting process.
- logw(
- "Found remote SPI in the Delete response in a simultaneous"
- + " deletion case");
- }
-
- mUserCbExecutor.execute(
- () -> {
- mUserCallback.onClosed();
- onIpSecTransformPairDeleted(mCurrentChildSaRecord);
- });
-
- mChildSmCallback.onChildSaDeleted(mCurrentChildSaRecord.getRemoteSpi());
- mCurrentChildSaRecord.close();
- mCurrentChildSaRecord = null;
-
- quitNow();
- } catch (IkeProtocolException e) {
- // Shut down Child Session and notify users the error.
- handleChildFatalError(e);
- }
- return HANDLED;
- case CMD_HANDLE_RECEIVED_REQUEST:
- ReceivedRequest req = (ReceivedRequest) message.obj;
- switch (req.exchangeSubtype) {
- case IKE_EXCHANGE_SUBTYPE_DELETE_CHILD:
- // It has been verified in IkeSessionStateMachine that the incoming
- // request can be ONLY for mCurrentChildSaRecord at this point.
- if (!hasRemoteChildSpiForDelete(
- req.requestPayloads, mCurrentChildSaRecord)) {
- // Program error
- cleanUpAndQuit(
- new IllegalStateException(
- "Found no remote SPI for mCurrentChildSaRecord in"
- + " a Delete request"));
-
- } else {
- mChildSmCallback.onOutboundPayloadsReady(
- EXCHANGE_TYPE_INFORMATIONAL,
- true /*isResp*/,
- new LinkedList<>(),
- ChildSessionStateMachine.this);
- mSimulDeleteDetected = true;
- }
- return HANDLED;
- case IKE_EXCHANGE_SUBTYPE_REKEY_CHILD:
- replyErrorNotification(ERROR_TYPE_TEMPORARY_FAILURE);
- return HANDLED;
- default:
- cleanUpAndQuit(
- new IllegalStateException(
- "Invalid exchange subtype for Child Session: "
- + req.exchangeSubtype));
- return HANDLED;
- }
- default:
- return NOT_HANDLED;
- }
- }
- }
-
- /**
- * DeleteChildRemoteDelete represents the state where Child Session receives the Delete Child
- * request.
- */
- class DeleteChildRemoteDelete extends DeleteResponderBase {
- @Override
- public boolean processStateMessage(Message message) {
- switch (message.what) {
- case CMD_HANDLE_RECEIVED_REQUEST:
- ReceivedRequest req = (ReceivedRequest) message.obj;
- if (req.exchangeSubtype == IKE_EXCHANGE_SUBTYPE_DELETE_CHILD) {
- handleDeleteSessionRequest(req.requestPayloads);
- return HANDLED;
- }
- return NOT_HANDLED;
- default:
- return NOT_HANDLED;
- }
- }
- }
-
- /**
- * RekeyChildLocalCreate represents the state where Child Session initiates the Rekey Child
- * exchange.
- *
- * <p>As indicated in RFC 7296 section 2.8, "when rekeying, the new Child SA SHOULD NOT have
- * different Traffic Selectors and algorithms than the old one."
- */
- class RekeyChildLocalCreate extends DeleteResponderBase {
- private List<IkePayload> mRequestPayloads;
-
- @Override
- public void enterState() {
- try {
- // Build request with negotiated proposal and TS.
- mRequestPayloads =
- CreateChildSaHelper.getRekeyChildCreateReqPayloads(
- mIpSecManager,
- mLocalAddress,
- mSaProposal,
- mLocalTs,
- mRemoteTs,
- mCurrentChildSaRecord.getLocalSpi(),
- mChildSessionOptions.isTransportMode());
- mChildSmCallback.onOutboundPayloadsReady(
- EXCHANGE_TYPE_CREATE_CHILD_SA,
- false /*isResp*/,
- mRequestPayloads,
- ChildSessionStateMachine.this);
- } catch (ResourceUnavailableException e) {
- loge("Fail to assign Child SPI. Schedule a retry for rekey Child");
- mChildSmCallback.scheduleRetryLocalRequest(
- (ChildLocalRequest) mCurrentChildSaRecord.getFutureRekeyEvent());
- transitionTo(mIdle);
- }
- }
-
- @Override
- public boolean processStateMessage(Message message) {
- switch (message.what) {
- case CMD_HANDLE_RECEIVED_RESPONSE:
- ReceivedCreateResponse resp = (ReceivedCreateResponse) message.obj;
- CreateChildResult createChildResult =
- CreateChildSaHelper.validateAndNegotiateRekeyChildResp(
- mRequestPayloads,
- resp.responsePayloads,
- resp.exchangeType,
- EXCHANGE_TYPE_CREATE_CHILD_SA,
- mChildSessionOptions.isTransportMode(),
- mCurrentChildSaRecord,
- mIpSecManager,
- mRemoteAddress);
-
- switch (createChildResult.status) {
- case CREATE_STATUS_OK:
- try {
- // Do not need to update the negotiated proposal and TS because they
- // are not changed.
-
- ChildLocalRequest rekeyLocalRequest = makeRekeyLocalRequest();
-
- mLocalInitNewChildSaRecord =
- ChildSaRecord.makeChildSaRecord(
- mContext,
- mRequestPayloads,
- resp.responsePayloads,
- createChildResult.initSpi,
- createChildResult.respSpi,
- mLocalAddress,
- mRemoteAddress,
- mUdpEncapSocket,
- mIkePrf,
- mChildIntegrity,
- mChildCipher,
- mSkD,
- mChildSessionOptions.isTransportMode(),
- true /*isLocalInit*/,
- rekeyLocalRequest);
-
- mChildSmCallback.scheduleLocalRequest(
- rekeyLocalRequest, getRekeyTimeout());
-
- mUserCbExecutor.execute(
- () -> {
- mUserCallback.onIpSecTransformCreated(
- mLocalInitNewChildSaRecord
- .getInboundIpSecTransform(),
- IpSecManager.DIRECTION_IN);
- mUserCallback.onIpSecTransformCreated(
- mLocalInitNewChildSaRecord
- .getOutboundIpSecTransform(),
- IpSecManager.DIRECTION_OUT);
- });
-
- transitionTo(mRekeyChildLocalDelete);
- } catch (GeneralSecurityException
- | ResourceUnavailableException
- | SpiUnavailableException
- | IOException e) {
- // #makeChildSaRecord failed
- handleProcessRespOrSaCreationFailAndQuit(resp.registeredSpi, e);
- createChildResult.initSpi.close();
- createChildResult.respSpi.close();
- }
- break;
- case CREATE_STATUS_CHILD_ERROR_INVALID_MSG:
- handleProcessRespOrSaCreationFailAndQuit(
- resp.registeredSpi, createChildResult.exception);
- break;
- case CREATE_STATUS_CHILD_ERROR_RCV_NOTIFY:
- if (createChildResult.exception instanceof TemporaryFailureException) {
- loge(
- "Received TEMPORARY_FAILURE for rekey Child. Retry has"
- + "already been scheduled by IKE Session.");
- } else {
- loge(
- "Received error notification for rekey Child. Schedule a"
- + " retry");
- mChildSmCallback.scheduleRetryLocalRequest(
- (ChildLocalRequest)
- mCurrentChildSaRecord.getFutureRekeyEvent());
- }
-
- transitionTo(mIdle);
- break;
- default:
- cleanUpAndQuit(
- new IllegalStateException(
- "Unrecognized status: " + createChildResult.status));
- }
- return HANDLED;
- default:
- // TODO: Handle rekey and delete request
- return NOT_HANDLED;
- }
- }
-
- private void handleProcessRespOrSaCreationFailAndQuit(
- int registeredSpi, Exception exception) {
- // We don't retry rekey if failure was caused by invalid response or SA creation error.
- // Reason is there is no way to notify the remote side the old SA is still alive but the
- // new one has failed. Sending delete request for new SA indicates the rekey has
- // finished and the new SA has died.
-
- // TODO: Initiate deletion on newly created SA
- if (registeredSpi != SPI_NOT_REGISTERED) {
- mChildSmCallback.onChildSaDeleted(registeredSpi);
- }
- handleChildFatalError(exception);
- }
- }
-
- /**
- * RekeyChildRemoteCreate represents the state where Child Session receives a Rekey Child
- * request.
- *
- * <p>As indicated in RFC 7296 section 2.8, "when rekeying, the new Child SA SHOULD NOT have
- * different Traffic Selectors and algorithms than the old one."
- *
- * <p>Errors in this exchange with no specific protocol error code will all be classified to use
- * NO_PROPOSAL_CHOSEN. The reason that we don't use NO_ADDITIONAL_SAS is because it indicates
- * "responder is unwilling to accept any more Child SAs on this IKE SA.", according to RFC 7296.
- * Sending this error may mislead the remote peer.
- */
- class RekeyChildRemoteCreate extends ExceptionHandler {
- @Override
- public boolean processStateMessage(Message message) {
- switch (message.what) {
- case CMD_HANDLE_RECEIVED_REQUEST:
- ReceivedRequest req = (ReceivedRequest) message.obj;
-
- if (req.exchangeSubtype == IKE_EXCHANGE_SUBTYPE_REKEY_CHILD) {
- handleCreateChildRequest(req);
- return HANDLED;
- }
-
- return NOT_HANDLED;
- default:
- return NOT_HANDLED;
- }
- }
-
- private void handleCreateChildRequest(ReceivedRequest req) {
- List<IkePayload> reqPayloads = null;
- List<IkePayload> respPayloads = null;
- try {
- reqPayloads = req.requestPayloads;
-
- // Build a rekey response payload list with our previously selected proposal,
- // against which we will validate the received request. It is guaranteed in
- // IkeSessionStateMachine#getIkeExchangeSubType that a SA Payload is included in the
- // inbound request payload list.
- IkeSaPayload reqSaPayload =
- IkePayload.getPayloadForTypeInProvidedList(
- PAYLOAD_TYPE_SA, IkeSaPayload.class, reqPayloads);
- byte respProposalNumber = reqSaPayload.getNegotiatedProposalNumber(mSaProposal);
-
- respPayloads =
- CreateChildSaHelper.getRekeyChildCreateRespPayloads(
- mIpSecManager,
- mLocalAddress,
- respProposalNumber,
- mSaProposal,
- mLocalTs,
- mRemoteTs,
- mCurrentChildSaRecord.getLocalSpi(),
- mChildSessionOptions.isTransportMode());
- } catch (NoValidProposalChosenException e) {
- handleCreationFailureAndBackToIdle(e);
- return;
- } catch (ResourceUnavailableException e) {
- handleCreationFailureAndBackToIdle(
- new NoValidProposalChosenException("Fail to assign inbound SPI", e));
- return;
- }
-
- CreateChildResult createChildResult =
- CreateChildSaHelper.validateAndNegotiateRekeyChildRequest(
- reqPayloads,
- respPayloads,
- req.exchangeType /*exchangeType*/,
- EXCHANGE_TYPE_CREATE_CHILD_SA /*expectedExchangeType*/,
- mChildSessionOptions.isTransportMode(),
- mIpSecManager,
- mRemoteAddress);
-
- switch (createChildResult.status) {
- case CREATE_STATUS_OK:
- try {
- // Do not need to update the negotiated proposal and TS
- // because they are not changed.
-
- ChildLocalRequest rekeyLocalRequest = makeRekeyLocalRequest();
-
- mRemoteInitNewChildSaRecord =
- ChildSaRecord.makeChildSaRecord(
- mContext,
- reqPayloads,
- respPayloads,
- createChildResult.initSpi,
- createChildResult.respSpi,
- mLocalAddress,
- mRemoteAddress,
- mUdpEncapSocket,
- mIkePrf,
- mChildIntegrity,
- mChildCipher,
- mSkD,
- mChildSessionOptions.isTransportMode(),
- false /*isLocalInit*/,
- rekeyLocalRequest);
-
- mChildSmCallback.scheduleLocalRequest(rekeyLocalRequest, getRekeyTimeout());
-
- mChildSmCallback.onChildSaCreated(
- mRemoteInitNewChildSaRecord.getRemoteSpi(),
- ChildSessionStateMachine.this);
-
- // To avoid traffic loss, outbound transform should only be applied once
- // the remote has (implicitly) acknowledged our response via the
- // delete-old-SA request. This will be performed in the finishRekey()
- // method.
- mUserCbExecutor.execute(
- () -> {
- mUserCallback.onIpSecTransformCreated(
- mRemoteInitNewChildSaRecord.getInboundIpSecTransform(),
- IpSecManager.DIRECTION_IN);
- });
-
- mChildSmCallback.onOutboundPayloadsReady(
- EXCHANGE_TYPE_CREATE_CHILD_SA,
- true /*isResp*/,
- respPayloads,
- ChildSessionStateMachine.this);
-
- transitionTo(mRekeyChildRemoteDelete);
- } catch (GeneralSecurityException
- | ResourceUnavailableException
- | SpiUnavailableException
- | IOException e) {
- // #makeChildSaRecord failed.
- createChildResult.initSpi.close();
- createChildResult.respSpi.close();
-
- handleCreationFailureAndBackToIdle(
- new NoValidProposalChosenException(
- "Error in Child SA creation", e));
- }
- break;
- case CREATE_STATUS_CHILD_ERROR_INVALID_MSG:
- IkeException error = createChildResult.exception;
- if (error instanceof IkeProtocolException) {
- handleCreationFailureAndBackToIdle((IkeProtocolException) error);
- } else {
- handleCreationFailureAndBackToIdle(
- new NoValidProposalChosenException(
- "Error in validating Create Child request", error));
- }
- break;
- case CREATE_STATUS_CHILD_ERROR_RCV_NOTIFY:
- cleanUpAndQuit(
- new IllegalStateException(
- "Unexpected processing status in Create Child request: "
- + createChildResult.status));
- break;
- default:
- cleanUpAndQuit(
- new IllegalStateException(
- "Unrecognized status: " + createChildResult.status));
- }
- }
-
- private void handleCreationFailureAndBackToIdle(IkeProtocolException e) {
- loge("Received invalid Rekey Child request. Reject with error notification", e);
-
- ArrayList<IkePayload> payloads = new ArrayList<>(1);
- payloads.add(e.buildNotifyPayload());
- mChildSmCallback.onOutboundPayloadsReady(
- EXCHANGE_TYPE_CREATE_CHILD_SA,
- true /*isResp*/,
- payloads,
- ChildSessionStateMachine.this);
-
- transitionTo(mIdle);
- }
- }
-
- /**
- * RekeyChildDeleteBase represents common behaviours of deleting stage during rekeying Child SA.
- */
- abstract class RekeyChildDeleteBase extends DeleteBase {
- @Override
- public boolean processStateMessage(Message message) {
- switch (message.what) {
- case CMD_HANDLE_RECEIVED_REQUEST:
- try {
- if (isOnNewSa((ReceivedRequest) message.obj)) {
- finishRekey();
- deferMessage(message);
- transitionTo(mIdle);
- return HANDLED;
- }
- return NOT_HANDLED;
- } catch (IllegalStateException e) {
- cleanUpAndQuit(e);
- return HANDLED;
- }
- default:
- return NOT_HANDLED;
- }
- }
-
- private boolean isOnNewSa(ReceivedRequest req) {
- switch (req.exchangeSubtype) {
- case IKE_EXCHANGE_SUBTYPE_DELETE_CHILD:
- return hasRemoteChildSpiForDelete(req.requestPayloads, mChildSaRecordSurviving);
- case IKE_EXCHANGE_SUBTYPE_REKEY_CHILD:
- return CreateChildSaHelper.hasRemoteChildSpiForRekey(
- req.requestPayloads, mChildSaRecordSurviving);
- default:
- throw new IllegalStateException(
- "Invalid exchange subtype for Child Session: " + req.exchangeSubtype);
- }
- }
-
- // Rekey timer for old SA will be cancelled as part of the closing of the SA.
- protected void finishRekey() {
- mUserCbExecutor.execute(
- () -> {
- onIpSecTransformPairDeleted(mCurrentChildSaRecord);
- });
-
- mChildSmCallback.onChildSaDeleted(mCurrentChildSaRecord.getRemoteSpi());
- mCurrentChildSaRecord.close();
-
- mCurrentChildSaRecord = mChildSaRecordSurviving;
-
- mLocalInitNewChildSaRecord = null;
- mRemoteInitNewChildSaRecord = null;
- mChildSaRecordSurviving = null;
- }
- }
-
- /**
- * RekeyChildLocalDelete represents the deleting stage of a locally-initiated Rekey Child
- * procedure.
- */
- class RekeyChildLocalDelete extends RekeyChildDeleteBase {
- @Override
- public void enterState() {
- mChildSaRecordSurviving = mLocalInitNewChildSaRecord;
- sendDeleteChild(mCurrentChildSaRecord, false /*isResp*/);
- }
-
- @Override
- public boolean processStateMessage(Message message) {
- if (super.processStateMessage(message) == HANDLED) {
- return HANDLED;
- }
-
- switch (message.what) {
- case CMD_HANDLE_RECEIVED_RESPONSE:
- try {
- ReceivedResponse resp = (ReceivedResponse) message.obj;
- validateDeleteRespPayloadAndExchangeType(
- resp.responsePayloads, resp.exchangeType);
-
- boolean currentSaSpiFound =
- hasRemoteChildSpiForDelete(
- resp.responsePayloads, mCurrentChildSaRecord);
- if (!currentSaSpiFound) {
- loge(
- "Found no remote SPI for current SA in received Delete"
- + " response. Shutting down old SA and finishing rekey.");
- }
- } catch (IkeProtocolException e) {
- loge(
- "Received Delete response with invalid syntax or error"
- + " notifications. Shutting down old SA and finishing rekey.",
- e);
- }
- finishRekey();
- transitionTo(mIdle);
- return HANDLED;
- default:
- // TODO: Handle requests on mCurrentChildSaRecord: Reply TEMPORARY_FAILURE to
- // a rekey request and reply empty INFORMATIONAL message to a delete request.
- return NOT_HANDLED;
- }
- }
- }
-
- /**
- * RekeyChildRemoteDelete represents the deleting stage of a remotely-initiated Rekey Child
- * procedure.
- */
- class RekeyChildRemoteDelete extends RekeyChildDeleteBase {
- @Override
- public void enterState() {
- mChildSaRecordSurviving = mRemoteInitNewChildSaRecord;
- sendMessageDelayed(TIMEOUT_REKEY_REMOTE_DELETE, REKEY_DELETE_TIMEOUT_MS);
- }
-
- @Override
- public boolean processStateMessage(Message message) {
- if (super.processStateMessage(message) == HANDLED) {
- return HANDLED;
- }
-
- switch (message.what) {
- case CMD_HANDLE_RECEIVED_REQUEST:
- ReceivedRequest req = (ReceivedRequest) message.obj;
-
- if (req.exchangeSubtype == IKE_EXCHANGE_SUBTYPE_DELETE_CHILD) {
- handleDeleteRequest(req.requestPayloads);
-
- } else {
- replyErrorNotification(ERROR_TYPE_TEMPORARY_FAILURE);
- }
- return HANDLED;
- case TIMEOUT_REKEY_REMOTE_DELETE:
- // Receiving this signal means the remote side has received the outbound
- // Rekey-Create response since no retransmissions were received during the
- // waiting time. IKE library will assume the remote side has set up the new
- // Child SA and finish the rekey procedure. Users should be warned there is
- // a risk that the remote side failed to set up the new Child SA and all
- // outbound IPsec traffic protected by new Child SA will be dropped.
-
- // TODO:Consider finishing rekey procedure if the IKE Session receives a new
- // request. Since window size is one, receiving a new request indicates the
- // remote side has received the outbound Rekey-Create response
-
- finishRekey();
- transitionTo(mIdle);
- return HANDLED;
- default:
- return NOT_HANDLED;
- }
- }
-
- private void handleDeleteRequest(List<IkePayload> payloads) {
- if (!hasRemoteChildSpiForDelete(payloads, mCurrentChildSaRecord)) {
- // Request received on incorrect SA
- cleanUpAndQuit(
- new IllegalStateException(
- "Found no remote SPI for current SA in received Delete"
- + " response."));
- } else {
- sendDeleteChild(mCurrentChildSaRecord, true /*isResp*/);
- finishRekey();
- transitionTo(mIdle);
- }
- }
-
- @Override
- protected void finishRekey() {
- mUserCbExecutor.execute(
- () -> {
- mUserCallback.onIpSecTransformCreated(
- mRemoteInitNewChildSaRecord.getOutboundIpSecTransform(),
- IpSecManager.DIRECTION_OUT);
- });
-
- super.finishRekey();
- }
-
- @Override
- public void exitState() {
- removeMessages(TIMEOUT_REKEY_REMOTE_DELETE);
- }
- }
-
- /**
- * Package private helper class to generate IKE SA creation payloads, in both request and
- * response directions.
- */
- static class CreateChildSaHelper {
- /** Create payload list for creating the initial Child SA for this Child Session. */
- public static List<IkePayload> getInitChildCreateReqPayloads(
- IpSecManager ipSecManager,
- InetAddress localAddress,
- ChildSessionOptions childSessionOptions,
- boolean isFirstChild)
- throws ResourceUnavailableException {
-
- ChildSaProposal[] saProposals = childSessionOptions.getSaProposals();
-
- if (isFirstChild) {
- for (int i = 0; i < saProposals.length; i++) {
- saProposals[i] =
- childSessionOptions.getSaProposals()[i].getCopyWithoutDhTransform();
- }
- }
-
- List<IkePayload> payloadList =
- getChildCreatePayloads(
- IkeSaPayload.createChildSaRequestPayload(
- saProposals, ipSecManager, localAddress),
- childSessionOptions.getLocalTrafficSelectors(),
- childSessionOptions.getRemoteTrafficSelectors(),
- childSessionOptions.isTransportMode());
-
- if (!childSessionOptions.isTransportMode()) {
- ConfigAttribute[] attributes =
- ((TunnelModeChildSessionOptions) childSessionOptions)
- .getConfigurationRequests();
- IkeConfigPayload configPayload =
- new IkeConfigPayload(false /*isReply*/, Arrays.asList(attributes));
- payloadList.add(configPayload);
- }
-
- return payloadList;
- }
-
- /** Create payload list as a rekey Child Session request. */
- public static List<IkePayload> getRekeyChildCreateReqPayloads(
- IpSecManager ipSecManager,
- InetAddress localAddress,
- ChildSaProposal currentProposal,
- IkeTrafficSelector[] currentLocalTs,
- IkeTrafficSelector[] currentRemoteTs,
- int localSpi,
- boolean isTransport)
- throws ResourceUnavailableException {
- List<IkePayload> payloads =
- getChildCreatePayloads(
- IkeSaPayload.createChildSaRequestPayload(
- new ChildSaProposal[] {currentProposal},
- ipSecManager,
- localAddress),
- currentLocalTs,
- currentRemoteTs,
- isTransport);
-
- payloads.add(
- new IkeNotifyPayload(
- PROTOCOL_ID_ESP, localSpi, NOTIFY_TYPE_REKEY_SA, new byte[0]));
- return payloads;
- }
-
- /** Create payload list as a rekey Child Session response. */
- public static List<IkePayload> getRekeyChildCreateRespPayloads(
- IpSecManager ipSecManager,
- InetAddress localAddress,
- byte proposalNumber,
- ChildSaProposal currentProposal,
- IkeTrafficSelector[] currentLocalTs,
- IkeTrafficSelector[] currentRemoteTs,
- int localSpi,
- boolean isTransport)
- throws ResourceUnavailableException {
- List<IkePayload> payloads =
- getChildCreatePayloads(
- IkeSaPayload.createChildSaResponsePayload(
- proposalNumber, currentProposal, ipSecManager, localAddress),
- currentRemoteTs /*initTs*/,
- currentLocalTs /*respTs*/,
- isTransport);
-
- payloads.add(
- new IkeNotifyPayload(
- PROTOCOL_ID_ESP, localSpi, NOTIFY_TYPE_REKEY_SA, new byte[0]));
- return payloads;
- }
-
- /** Create payload list for creating a new Child SA. */
- private static List<IkePayload> getChildCreatePayloads(
- IkeSaPayload saPayload,
- IkeTrafficSelector[] initTs,
- IkeTrafficSelector[] respTs,
- boolean isTransport)
- throws ResourceUnavailableException {
- List<IkePayload> payloadList = new ArrayList<>(5);
-
- payloadList.add(saPayload);
- payloadList.add(new IkeTsPayload(true /*isInitiator*/, initTs));
- payloadList.add(new IkeTsPayload(false /*isInitiator*/, respTs));
- payloadList.add(new IkeNoncePayload());
-
- DhGroupTransform[] dhGroups =
- ((ChildProposal) saPayload.proposalList.get(0))
- .saProposal.getDhGroupTransforms();
- if (dhGroups.length != 0 && dhGroups[0].id != DH_GROUP_NONE) {
- payloadList.add(new IkeKePayload(dhGroups[0].id));
- }
-
- if (isTransport) payloadList.add(new IkeNotifyPayload(NOTIFY_TYPE_USE_TRANSPORT_MODE));
-
- return payloadList;
- }
-
- /**
- * Validate the received response of initial Create Child SA exchange and return the
- * negotiation result.
- */
- public static CreateChildResult validateAndNegotiateInitChild(
- List<IkePayload> reqPayloads,
- List<IkePayload> respPayloads,
- @ExchangeType int exchangeType,
- @ExchangeType int expectedExchangeType,
- boolean expectTransport,
- IpSecManager ipSecManager,
- InetAddress remoteAddress) {
-
- return validateAndNegotiateChild(
- reqPayloads,
- respPayloads,
- exchangeType,
- expectedExchangeType,
- true /*isLocalInit*/,
- expectTransport,
- ipSecManager,
- remoteAddress);
- }
-
- /**
- * Validate the received rekey-create request against locally built response (based on
- * previously negotiated Child SA) and return the negotiation result.
- */
- public static CreateChildResult validateAndNegotiateRekeyChildRequest(
- List<IkePayload> reqPayloads,
- List<IkePayload> respPayloads,
- @ExchangeType int exchangeType,
- @ExchangeType int expectedExchangeType,
- boolean expectTransport,
- IpSecManager ipSecManager,
- InetAddress remoteAddress) {
-
- // It is guaranteed that a Rekey-Notify Payload with remote SPI of current Child SA is
- // included in the reqPayloads. So we won't validate it again here.
- return validateAndNegotiateChild(
- reqPayloads,
- respPayloads,
- exchangeType,
- expectedExchangeType,
- false /*isLocalInit*/,
- expectTransport,
- ipSecManager,
- remoteAddress);
- }
-
- /**
- * Validate the received rekey-create response against locally built request and previously
- * negotiated Child SA, and return the negotiation result.
- */
- public static CreateChildResult validateAndNegotiateRekeyChildResp(
- List<IkePayload> reqPayloads,
- List<IkePayload> respPayloads,
- @ExchangeType int exchangeType,
- @ExchangeType int expectedExchangeType,
- boolean expectTransport,
- ChildSaRecord expectedChildRecord,
- IpSecManager ipSecManager,
- InetAddress remoteAddress) {
- // Validate rest of payloads and negotiate Child SA.
- CreateChildResult childResult =
- validateAndNegotiateChild(
- reqPayloads,
- respPayloads,
- exchangeType,
- expectedExchangeType,
- true /*isLocalInit*/,
- expectTransport,
- ipSecManager,
- remoteAddress);
-
- // TODO: Validate new Child SA does not have different Traffic Selectors
-
- return childResult;
- }
-
- /**
- * Check if SPI of Child SA that is expected to be rekeyed is included in the provided
- * payload list.
- */
- public static boolean hasRemoteChildSpiForRekey(
- List<IkePayload> payloads, ChildSaRecord expectedRecord) {
- List<IkeNotifyPayload> notifyPayloads =
- IkePayload.getPayloadListForTypeInProvidedList(
- IkePayload.PAYLOAD_TYPE_NOTIFY, IkeNotifyPayload.class, payloads);
-
- boolean hasExpectedRekeyNotify = false;
- for (IkeNotifyPayload notifyPayload : notifyPayloads) {
- if (notifyPayload.notifyType == NOTIFY_TYPE_REKEY_SA
- && notifyPayload.spi == expectedRecord.getRemoteSpi()) {
- hasExpectedRekeyNotify = true;
- break;
- }
- }
-
- return hasExpectedRekeyNotify;
- }
-
- /** Validate the received payload list and negotiate Child SA. */
- private static CreateChildResult validateAndNegotiateChild(
- List<IkePayload> reqPayloads,
- List<IkePayload> respPayloads,
- @ExchangeType int exchangeType,
- @ExchangeType int expectedExchangeType,
- boolean isLocalInit,
- boolean expectTransport,
- IpSecManager ipSecManager,
- InetAddress remoteAddress) {
- List<IkePayload> inboundPayloads = isLocalInit ? respPayloads : reqPayloads;
-
- try {
- validatePayloadAndExchangeType(
- inboundPayloads,
- isLocalInit /*isResp*/,
- exchangeType,
- expectedExchangeType);
- } catch (InvalidSyntaxException e) {
- return new CreateChildResult(CREATE_STATUS_CHILD_ERROR_INVALID_MSG, e);
- }
-
- List<IkeNotifyPayload> notifyPayloads =
- IkePayload.getPayloadListForTypeInProvidedList(
- IkePayload.PAYLOAD_TYPE_NOTIFY,
- IkeNotifyPayload.class,
- inboundPayloads);
-
- boolean hasTransportNotify = false;
- for (IkeNotifyPayload notify : notifyPayloads) {
- if (notify.isErrorNotify()) {
- try {
- IkeProtocolException exception = notify.validateAndBuildIkeException();
- if (isLocalInit) {
- return new CreateChildResult(
- CREATE_STATUS_CHILD_ERROR_RCV_NOTIFY, exception);
- } else {
- logw("Received unexpected error notification: " + notify.notifyType);
- }
- } catch (InvalidSyntaxException e) {
- return new CreateChildResult(CREATE_STATUS_CHILD_ERROR_INVALID_MSG, e);
- }
- }
-
- switch (notify.notifyType) {
- case IkeNotifyPayload.NOTIFY_TYPE_ADDITIONAL_TS_POSSIBLE:
- // TODO: Store it as part of negotiation results that can be retrieved
- // by users.
- break;
- case IkeNotifyPayload.NOTIFY_TYPE_IPCOMP_SUPPORTED:
- // Ignore
- break;
- case IkeNotifyPayload.NOTIFY_TYPE_USE_TRANSPORT_MODE:
- hasTransportNotify = true;
- break;
- case IkeNotifyPayload.NOTIFY_TYPE_ESP_TFC_PADDING_NOT_SUPPORTED:
- // Ignore
- break;
- default:
- // Unknown and unexpected status notifications are ignored as per RFC7296.
- logw(
- "Received unknown or unexpected status notifications with notify"
- + " type: "
- + notify.notifyType);
- }
- }
-
- Pair<ChildProposal, ChildProposal> childProposalPair = null;
- try {
- IkeSaPayload reqSaPayload =
- IkePayload.getPayloadForTypeInProvidedList(
- IkePayload.PAYLOAD_TYPE_SA, IkeSaPayload.class, reqPayloads);
- IkeSaPayload respSaPayload =
- IkePayload.getPayloadForTypeInProvidedList(
- IkePayload.PAYLOAD_TYPE_SA, IkeSaPayload.class, respPayloads);
-
- // This method either throws exception or returns non-null pair that contains two
- // valid {@link ChildProposal} both with a {@link SecurityParameterIndex} allocated
- // inside.
- childProposalPair =
- IkeSaPayload.getVerifiedNegotiatedChildProposalPair(
- reqSaPayload, respSaPayload, ipSecManager, remoteAddress);
- ChildSaProposal saProposal = childProposalPair.second.saProposal;
-
- validateKePayloads(inboundPayloads, isLocalInit /*isResp*/, saProposal);
-
- if (expectTransport != hasTransportNotify) {
- throw new NoValidProposalChosenException(
- "Failed the negotiation on Child SA mode (conflicting modes chosen).");
- }
-
- Pair<IkeTrafficSelector[], IkeTrafficSelector[]> tsPair =
- validateAndGetNegotiatedTsPair(reqPayloads, respPayloads);
-
- return new CreateChildResult(
- childProposalPair.first.getChildSpiResource(),
- childProposalPair.second.getChildSpiResource(),
- saProposal,
- tsPair.first,
- tsPair.second);
- } catch (IkeProtocolException
- | ResourceUnavailableException
- | SpiUnavailableException e) {
- if (childProposalPair != null) {
- childProposalPair.first.getChildSpiResource().close();
- childProposalPair.second.getChildSpiResource().close();
- }
-
- if (e instanceof InvalidSyntaxException) {
- return new CreateChildResult(
- CREATE_STATUS_CHILD_ERROR_INVALID_MSG, (InvalidSyntaxException) e);
- } else if (e instanceof IkeProtocolException) {
- return new CreateChildResult(
- CREATE_STATUS_CHILD_ERROR_INVALID_MSG,
- new InvalidSyntaxException(
- "Processing error in received Create Child response", e));
- } else {
- return new CreateChildResult(
- CREATE_STATUS_CHILD_ERROR_INVALID_MSG, new IkeInternalException(e));
- }
- }
- }
-
- // Validate syntax to make sure all necessary payloads exist and exchange type is correct.
- private static void validatePayloadAndExchangeType(
- List<IkePayload> inboundPayloads,
- boolean isResp,
- @ExchangeType int exchangeType,
- @ExchangeType int expectedExchangeType)
- throws InvalidSyntaxException {
- boolean hasSaPayload = false;
- boolean hasKePayload = false;
- boolean hasNoncePayload = false;
- boolean hasTsInitPayload = false;
- boolean hasTsRespPayload = false;
- boolean hasErrorNotify = false;
-
- for (IkePayload payload : inboundPayloads) {
- switch (payload.payloadType) {
- case PAYLOAD_TYPE_SA:
- hasSaPayload = true;
- break;
- case PAYLOAD_TYPE_KE:
- // Could not decide if KE Payload MUST or MUST NOT be included until SA
- // negotiation is done.
- hasKePayload = true;
- break;
- case PAYLOAD_TYPE_NONCE:
- hasNoncePayload = true;
- break;
- case PAYLOAD_TYPE_TS_INITIATOR:
- hasTsInitPayload = true;
- break;
- case PAYLOAD_TYPE_TS_RESPONDER:
- hasTsRespPayload = true;
- break;
- case PAYLOAD_TYPE_NOTIFY:
- if (((IkeNotifyPayload) payload).isErrorNotify()) hasErrorNotify = true;
- // Do not have enough context to handle all notifications. Handle them
- // together in higher layer.
- break;
- case PAYLOAD_TYPE_CP:
- // Handled in child creation state. Note Child Session can only handle
- // Config Payload in initial creation and can only handle a Config Reply.
- // For interoperability, Config Payloads received in rekey creation
- // or with other config types will be ignored.
- break;
- default:
- logw(
- "Received unexpected payload in Create Child SA message. Payload"
- + " type: "
- + payload.payloadType);
- }
- }
-
- // Do not need to check exchange type of a request because it has been already verified
- // in IkeSessionStateMachine
- if (isResp
- && exchangeType != expectedExchangeType
- && exchangeType != EXCHANGE_TYPE_INFORMATIONAL) {
- throw new InvalidSyntaxException("Received invalid exchange type: " + exchangeType);
- }
-
- if (exchangeType == EXCHANGE_TYPE_INFORMATIONAL
- && (hasSaPayload
- || hasKePayload
- || hasNoncePayload
- || hasTsInitPayload
- || hasTsRespPayload)) {
- logw(
- "Unexpected payload found in an INFORMATIONAL message: SA, KE, Nonce,"
- + " TS-Initiator or TS-Responder");
- }
-
- if (isResp
- && !hasErrorNotify
- && (!hasSaPayload
- || !hasNoncePayload
- || !hasTsInitPayload
- || !hasTsRespPayload)) {
- throw new InvalidSyntaxException(
- "SA, Nonce, TS-Initiator or TS-Responder missing.");
- }
- }
-
- private static Pair<IkeTrafficSelector[], IkeTrafficSelector[]>
- validateAndGetNegotiatedTsPair(
- List<IkePayload> reqPayloads, List<IkePayload> respPayloads)
- throws TsUnacceptableException {
- IkeTrafficSelector[] initTs =
- validateAndGetNegotiatedTs(reqPayloads, respPayloads, true /*isInitTs*/);
- IkeTrafficSelector[] respTs =
- validateAndGetNegotiatedTs(reqPayloads, respPayloads, false /*isInitTs*/);
-
- return new Pair<IkeTrafficSelector[], IkeTrafficSelector[]>(initTs, respTs);
- }
-
- private static IkeTrafficSelector[] validateAndGetNegotiatedTs(
- List<IkePayload> reqPayloads, List<IkePayload> respPayloads, boolean isInitTs)
- throws TsUnacceptableException {
- int tsType = isInitTs ? PAYLOAD_TYPE_TS_INITIATOR : PAYLOAD_TYPE_TS_RESPONDER;
- IkeTsPayload reqPayload =
- IkePayload.getPayloadForTypeInProvidedList(
- tsType, IkeTsPayload.class, reqPayloads);
- IkeTsPayload respPayload =
- IkePayload.getPayloadForTypeInProvidedList(
- tsType, IkeTsPayload.class, respPayloads);
-
- if (!reqPayload.contains(respPayload)) {
- throw new TsUnacceptableException();
- }
-
- // It is guaranteed by decoding inbound TS Payload and constructing outbound TS Payload
- // that each TS Payload has at least one IkeTrafficSelector.
- return respPayload.trafficSelectors;
- }
-
- @VisibleForTesting
- static void validateKePayloads(
- List<IkePayload> inboundPayloads,
- boolean isResp,
- ChildSaProposal negotiatedProposal)
- throws IkeProtocolException {
- DhGroupTransform[] dhTransforms = negotiatedProposal.getDhGroupTransforms();
-
- if (dhTransforms.length > 1) {
- throw new IllegalArgumentException(
- "Found multiple DH Group Transforms in the negotiated SA proposal");
- }
- boolean expectKePayload =
- dhTransforms.length == 1 && dhTransforms[0].id != DH_GROUP_NONE;
-
- IkeKePayload kePayload =
- IkePayload.getPayloadForTypeInProvidedList(
- PAYLOAD_TYPE_KE, IkeKePayload.class, inboundPayloads);
-
- if (expectKePayload && (kePayload == null || dhTransforms[0].id != kePayload.dhGroup)) {
- if (isResp) {
- throw new InvalidSyntaxException(
- "KE Payload missing or has mismatched DH Group with the negotiated"
- + " proposal.");
- } else {
- throw new InvalidKeException(dhTransforms[0].id);
- }
-
- } else if (!expectKePayload && kePayload != null && isResp) {
- // It is valid when the remote request proposed multiple DH Groups with a KE
- // payload, and the responder chose DH_GROUP_NONE.
- throw new InvalidSyntaxException("Received unexpected KE Payload.");
- }
- }
-
- private static void logw(String s) {
- getIkeLog().w(TAG, s);
- }
- }
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({
- CREATE_STATUS_OK,
- CREATE_STATUS_CHILD_ERROR_INVALID_MSG,
- CREATE_STATUS_CHILD_ERROR_RCV_NOTIFY
- })
- @interface CreateStatus {}
-
- /** The Child SA negotiation succeeds. */
- private static final int CREATE_STATUS_OK = 0;
- /** The inbound message is invalid in Child negotiation but is non-fatal for IKE Session. */
- private static final int CREATE_STATUS_CHILD_ERROR_INVALID_MSG = 1;
- /** The inbound message includes error notification that failed the Child negotiation. */
- private static final int CREATE_STATUS_CHILD_ERROR_RCV_NOTIFY = 2;
-
- private static class CreateChildResult {
- @CreateStatus public final int status;
- public final SecurityParameterIndex initSpi;
- public final SecurityParameterIndex respSpi;
- public final ChildSaProposal negotiatedProposal;
- public final IkeTrafficSelector[] initTs;
- public final IkeTrafficSelector[] respTs;
- public final IkeException exception;
-
- private CreateChildResult(
- @CreateStatus int status,
- SecurityParameterIndex initSpi,
- SecurityParameterIndex respSpi,
- ChildSaProposal negotiatedProposal,
- IkeTrafficSelector[] initTs,
- IkeTrafficSelector[] respTs,
- IkeException exception) {
- this.status = status;
- this.initSpi = initSpi;
- this.respSpi = respSpi;
- this.negotiatedProposal = negotiatedProposal;
- this.initTs = initTs;
- this.respTs = respTs;
- this.exception = exception;
- }
-
- /* Construct a CreateChildResult instance for a successful case. */
- CreateChildResult(
- SecurityParameterIndex initSpi,
- SecurityParameterIndex respSpi,
- ChildSaProposal negotiatedProposal,
- IkeTrafficSelector[] initTs,
- IkeTrafficSelector[] respTs) {
- this(
- CREATE_STATUS_OK,
- initSpi,
- respSpi,
- negotiatedProposal,
- initTs,
- respTs,
- null /*exception*/);
- }
-
- /** Construct a CreateChildResult instance for an error case. */
- CreateChildResult(@CreateStatus int status, IkeException exception) {
- this(
- status,
- null /*initSpi*/,
- null /*respSpi*/,
- null /*negotiatedProposal*/,
- null /*initTs*/,
- null /*respTs*/,
- exception);
- }
- }
-}
diff --git a/src/java/com/android/internal/net/ipsec/ike/IkeEapAuthenticatorFactory.java b/src/java/com/android/internal/net/ipsec/ike/IkeEapAuthenticatorFactory.java
deleted file mode 100644
index b0d6f127..00000000
--- a/src/java/com/android/internal/net/ipsec/ike/IkeEapAuthenticatorFactory.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2019 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;
-
-import android.content.Context;
-import android.net.eap.EapSessionConfig;
-import android.os.Looper;
-
-import com.android.internal.net.eap.EapAuthenticator;
-import com.android.internal.net.eap.IEapCallback;
-
-/** Package private factory for building EapAuthenticator instances. */
-final class IkeEapAuthenticatorFactory {
- /**
- * Builds and returns a new EapAuthenticator
- *
- * @param looper Looper for running a message loop
- * @param cbHandler Handler for posting callbacks to the given IEapCallback
- * @param cb IEapCallback for callbacks to the client
- * @param context Context for the EapAuthenticator
- */
- public EapAuthenticator newEapAuthenticator(
- Looper looper, IEapCallback cb, Context context, EapSessionConfig eapSessionConfig) {
- return new EapAuthenticator(looper, cb, context, eapSessionConfig);
- }
-}
diff --git a/src/java/com/android/internal/net/ipsec/ike/IkeLocalRequestScheduler.java b/src/java/com/android/internal/net/ipsec/ike/IkeLocalRequestScheduler.java
deleted file mode 100644
index b7bf8701..00000000
--- a/src/java/com/android/internal/net/ipsec/ike/IkeLocalRequestScheduler.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2019 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;
-
-import android.net.ipsec.ike.ChildSessionCallback;
-import android.net.ipsec.ike.ChildSessionOptions;
-
-import java.util.LinkedList;
-
-/**
- * IkeLocalRequestScheduler caches all local requests scheduled by an IKE Session and notify the IKE
- * Session to process the request when it is allowed.
- *
- * <p>LocalRequestScheduler is running on the IkeSessionStateMachine thread.
- */
-public final class IkeLocalRequestScheduler {
- private final LinkedList<LocalRequest> mRequestQueue = new LinkedList<>();
-
- private final IProcedureConsumer mConsumer;
-
- private boolean mLocalProcedureOngoing;
- private boolean mRemoteProcedureOngoing;
-
- /**
- * Construct an instance of IkeLocalRequestScheduler
- *
- * @param consumer the interface to initiate new procedure.
- */
- public IkeLocalRequestScheduler(IProcedureConsumer consumer) {
- mConsumer = consumer;
- }
-
- /** Add a new local request to the queue. */
- public void addRequest(LocalRequest request) {
- mRequestQueue.offer(request);
- }
-
- /** Add a new local request to the front of the queue. */
- public void addRequestAtFront(LocalRequest request) {
- mRequestQueue.offerFirst(request);
- }
-
- /**
- * Notifies the scheduler that the caller is ready for a new procedure
- *
- * <p>Synchronously triggers the call to onNewProcedureReady.
- */
- public void readyForNextProcedure() {
- while (!mRequestQueue.isEmpty()) {
- LocalRequest request = mRequestQueue.poll();
- if (!request.isCancelled()) {
- mConsumer.onNewProcedureReady(request);
- return;
- }
- }
- }
-
- /**
- * This class represents a user requested or internally scheduled IKE procedure that will be
- * initiated locally.
- */
- public static class LocalRequest {
- public final int procedureType;
- // TODO: Also store specific payloads for INFO exchange.
- private boolean mIsCancelled;
-
- LocalRequest(int type) {
- procedureType = type;
- mIsCancelled = false;
- }
-
- boolean isCancelled() {
- return mIsCancelled;
- }
-
- void cancel() {
- mIsCancelled = true;
- }
- }
-
- /**
- * This class represents a user requested or internally scheduled Child procedure that will be
- * initiated locally.
- */
- public static class ChildLocalRequest extends LocalRequest {
- public final ChildSessionCallback childSessionCallback;
- public final ChildSessionOptions childSessionOptions;
-
- ChildLocalRequest(
- int type, ChildSessionCallback childCallback, ChildSessionOptions childOptions) {
- super(type);
- childSessionOptions = childOptions;
- childSessionCallback = childCallback;
- }
- }
-
- /** Interface to initiate a new IKE procedure */
- public interface IProcedureConsumer {
- /**
- * Called when a new IKE procedure can be initiated.
- *
- * @param localRequest the request to be initiated.
- */
- void onNewProcedureReady(LocalRequest localRequest);
- }
-}
diff --git a/src/java/com/android/internal/net/ipsec/ike/IkeSessionStateMachine.java b/src/java/com/android/internal/net/ipsec/ike/IkeSessionStateMachine.java
deleted file mode 100644
index 03c419db..00000000
--- a/src/java/com/android/internal/net/ipsec/ike/IkeSessionStateMachine.java
+++ /dev/null
@@ -1,4235 +0,0 @@
-/*
- * Copyright (C) 2019 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;
-
-import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_CHILD_SA_NOT_FOUND;
-import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_INVALID_SYNTAX;
-import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_NO_ADDITIONAL_SAS;
-import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_TEMPORARY_FAILURE;
-import static android.net.ipsec.ike.exceptions.IkeProtocolException.ErrorType;
-
-import static com.android.internal.net.ipsec.ike.message.IkeHeader.EXCHANGE_TYPE_INFORMATIONAL;
-import static com.android.internal.net.ipsec.ike.message.IkeMessage.DECODE_STATUS_OK;
-import static com.android.internal.net.ipsec.ike.message.IkeMessage.DECODE_STATUS_PARTIAL;
-import static com.android.internal.net.ipsec.ike.message.IkeMessage.DECODE_STATUS_PROTECTED_ERROR;
-import static com.android.internal.net.ipsec.ike.message.IkeMessage.DECODE_STATUS_UNPROTECTED_ERROR;
-import static com.android.internal.net.ipsec.ike.message.IkeNotifyPayload.NOTIFY_TYPE_IKEV2_FRAGMENTATION_SUPPORTED;
-import static com.android.internal.net.ipsec.ike.message.IkeNotifyPayload.NOTIFY_TYPE_NAT_DETECTION_DESTINATION_IP;
-import static com.android.internal.net.ipsec.ike.message.IkeNotifyPayload.NOTIFY_TYPE_NAT_DETECTION_SOURCE_IP;
-import static com.android.internal.net.ipsec.ike.message.IkeNotifyPayload.NOTIFY_TYPE_REKEY_SA;
-import static com.android.internal.net.ipsec.ike.message.IkePayload.PAYLOAD_TYPE_CP;
-import static com.android.internal.net.ipsec.ike.message.IkePayload.PAYLOAD_TYPE_DELETE;
-import static com.android.internal.net.ipsec.ike.message.IkePayload.PAYLOAD_TYPE_NOTIFY;
-import static com.android.internal.net.ipsec.ike.message.IkePayload.PAYLOAD_TYPE_VENDOR;
-
-import android.annotation.IntDef;
-import android.content.Context;
-import android.net.IpSecManager;
-import android.net.IpSecManager.ResourceUnavailableException;
-import android.net.IpSecManager.UdpEncapsulationSocket;
-import android.net.ipsec.ike.ChildSessionCallback;
-import android.net.ipsec.ike.ChildSessionOptions;
-import android.net.ipsec.ike.IkeSaProposal;
-import android.net.ipsec.ike.IkeSessionCallback;
-import android.net.ipsec.ike.IkeSessionOptions;
-import android.net.ipsec.ike.IkeSessionOptions.IkeAuthConfig;
-import android.net.ipsec.ike.IkeSessionOptions.IkeAuthDigitalSignRemoteConfig;
-import android.net.ipsec.ike.IkeSessionOptions.IkeAuthPskConfig;
-import android.net.ipsec.ike.exceptions.IkeException;
-import android.net.ipsec.ike.exceptions.IkeInternalException;
-import android.net.ipsec.ike.exceptions.IkeProtocolException;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.system.ErrnoException;
-import android.system.Os;
-import android.system.OsConstants;
-import android.util.LongSparseArray;
-import android.util.Pair;
-import android.util.SparseArray;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.net.eap.EapAuthenticator;
-import com.android.internal.net.eap.IEapCallback;
-import com.android.internal.net.ipsec.ike.ChildSessionStateMachine.CreateChildSaHelper;
-import com.android.internal.net.ipsec.ike.IkeLocalRequestScheduler.ChildLocalRequest;
-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.crypto.IkeCipher;
-import com.android.internal.net.ipsec.ike.crypto.IkeMacIntegrity;
-import com.android.internal.net.ipsec.ike.crypto.IkeMacPrf;
-import com.android.internal.net.ipsec.ike.exceptions.AuthenticationFailedException;
-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.message.IkeAuthDigitalSignPayload;
-import com.android.internal.net.ipsec.ike.message.IkeAuthPayload;
-import com.android.internal.net.ipsec.ike.message.IkeAuthPskPayload;
-import com.android.internal.net.ipsec.ike.message.IkeCertPayload;
-import com.android.internal.net.ipsec.ike.message.IkeCertX509CertPayload;
-import com.android.internal.net.ipsec.ike.message.IkeDeletePayload;
-import com.android.internal.net.ipsec.ike.message.IkeEapPayload;
-import com.android.internal.net.ipsec.ike.message.IkeHeader;
-import com.android.internal.net.ipsec.ike.message.IkeHeader.ExchangeType;
-import com.android.internal.net.ipsec.ike.message.IkeIdPayload;
-import com.android.internal.net.ipsec.ike.message.IkeInformationalPayload;
-import com.android.internal.net.ipsec.ike.message.IkeKePayload;
-import com.android.internal.net.ipsec.ike.message.IkeMessage;
-import com.android.internal.net.ipsec.ike.message.IkeMessage.DecodeResult;
-import com.android.internal.net.ipsec.ike.message.IkeMessage.DecodeResultError;
-import com.android.internal.net.ipsec.ike.message.IkeMessage.DecodeResultOk;
-import com.android.internal.net.ipsec.ike.message.IkeMessage.DecodeResultPartial;
-import com.android.internal.net.ipsec.ike.message.IkeMessage.DecodeResultProtectedError;
-import com.android.internal.net.ipsec.ike.message.IkeNoncePayload;
-import com.android.internal.net.ipsec.ike.message.IkeNotifyPayload;
-import com.android.internal.net.ipsec.ike.message.IkePayload;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload.DhGroupTransform;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload.IkeProposal;
-import com.android.internal.net.ipsec.ike.message.IkeTsPayload;
-import com.android.internal.net.ipsec.ike.utils.Retransmitter;
-import com.android.internal.util.State;
-
-import dalvik.system.CloseGuard;
-
-import java.io.FileDescriptor;
-import java.io.IOException;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.net.Inet4Address;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.SocketException;
-import java.security.GeneralSecurityException;
-import java.security.Provider;
-import java.security.SecureRandom;
-import java.security.cert.TrustAnchor;
-import java.security.cert.X509Certificate;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.Executor;
-import java.util.concurrent.TimeUnit;
-
-/**
- * IkeSessionStateMachine tracks states and manages exchanges of this IKE session.
- *
- * <p>IkeSessionStateMachine has two types of states. One type are states where there is no ongoing
- * procedure affecting IKE session (non-procedure state), including Initial, Idle and Receiving. All
- * other states are "procedure" states which are named as follows:
- *
- * <pre>
- * State Name = [Procedure Type] + [Exchange Initiator] + [Exchange Type].
- * - An IKE procedure consists of one or two IKE exchanges:
- * Procedure Type = {CreateIke | DeleteIke | Info | RekeyIke | SimulRekeyIke}.
- * - Exchange Initiator indicates whether local or remote peer is the exchange initiator:
- * Exchange Initiator = {Local | Remote}
- * - Exchange type defines the function of this exchange. To make it more descriptive, we separate
- * Delete Exchange from generic Informational Exchange:
- * Exchange Type = {IkeInit | IkeAuth | Create | Delete | Info}
- * </pre>
- */
-public class IkeSessionStateMachine extends AbstractSessionStateMachine {
-
- private static final String TAG = "IkeSessionStateMachine";
-
- // TODO: b/140579254 Allow users to configure fragment size.
-
- // Default fragment size in bytes.
- @VisibleForTesting static final int DEFAULT_FRAGMENT_SIZE = 1280;
-
- // TODO: Add SA_HARD_LIFETIME_MS
-
- // Time after which IKE SA needs to be rekeyed
- @VisibleForTesting static final long SA_SOFT_LIFETIME_MS = TimeUnit.HOURS.toMillis(3L);
-
- // Default delay time for retrying a request
- @VisibleForTesting static final long RETRY_INTERVAL_MS = TimeUnit.SECONDS.toMillis(15L);
-
- // Close IKE Session when all responses during this time were TEMPORARY_FAILURE(s). This
- // indicates that something has gone wrong, and we are out of sync.
- @VisibleForTesting
- static final long TEMP_FAILURE_RETRY_TIMEOUT_MS = TimeUnit.MINUTES.toMillis(5L);
-
- // TODO: Allow users to configure IKE lifetime
-
- // Package private IKE exchange subtypes describe the specific function of a IKE
- // request/response exchange. It helps IkeSessionStateMachine to do message validation according
- // to the subtype specific rules.
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({
- IKE_EXCHANGE_SUBTYPE_INVALID,
- IKE_EXCHANGE_SUBTYPE_IKE_INIT,
- IKE_EXCHANGE_SUBTYPE_IKE_AUTH,
- IKE_EXCHANGE_SUBTYPE_DELETE_IKE,
- IKE_EXCHANGE_SUBTYPE_DELETE_CHILD,
- IKE_EXCHANGE_SUBTYPE_REKEY_IKE,
- IKE_EXCHANGE_SUBTYPE_REKEY_CHILD,
- IKE_EXCHANGE_SUBTYPE_GENERIC_INFO
- })
- @interface IkeExchangeSubType {}
-
- static final int IKE_EXCHANGE_SUBTYPE_INVALID = 0;
- static final int IKE_EXCHANGE_SUBTYPE_IKE_INIT = 1;
- static final int IKE_EXCHANGE_SUBTYPE_IKE_AUTH = 2;
- static final int IKE_EXCHANGE_SUBTYPE_CREATE_CHILD = 3;
- static final int IKE_EXCHANGE_SUBTYPE_DELETE_IKE = 4;
- static final int IKE_EXCHANGE_SUBTYPE_DELETE_CHILD = 5;
- static final int IKE_EXCHANGE_SUBTYPE_REKEY_IKE = 6;
- static final int IKE_EXCHANGE_SUBTYPE_REKEY_CHILD = 7;
- static final int IKE_EXCHANGE_SUBTYPE_GENERIC_INFO = 8;
-
- private static final SparseArray<String> EXCHANGE_SUBTYPE_TO_STRING;
-
- static {
- EXCHANGE_SUBTYPE_TO_STRING = new SparseArray<>();
- EXCHANGE_SUBTYPE_TO_STRING.put(IKE_EXCHANGE_SUBTYPE_INVALID, "Invalid");
- EXCHANGE_SUBTYPE_TO_STRING.put(IKE_EXCHANGE_SUBTYPE_IKE_INIT, "IKE INIT");
- EXCHANGE_SUBTYPE_TO_STRING.put(IKE_EXCHANGE_SUBTYPE_IKE_AUTH, "IKE AUTH");
- EXCHANGE_SUBTYPE_TO_STRING.put(IKE_EXCHANGE_SUBTYPE_CREATE_CHILD, "Create Child");
- EXCHANGE_SUBTYPE_TO_STRING.put(IKE_EXCHANGE_SUBTYPE_DELETE_IKE, "Delete IKE");
- EXCHANGE_SUBTYPE_TO_STRING.put(IKE_EXCHANGE_SUBTYPE_DELETE_CHILD, "Delete Child");
- EXCHANGE_SUBTYPE_TO_STRING.put(IKE_EXCHANGE_SUBTYPE_REKEY_IKE, "Rekey IKE");
- EXCHANGE_SUBTYPE_TO_STRING.put(IKE_EXCHANGE_SUBTYPE_REKEY_CHILD, "Rekey Child");
- EXCHANGE_SUBTYPE_TO_STRING.put(IKE_EXCHANGE_SUBTYPE_GENERIC_INFO, "Generic Info");
- }
-
- /** Package private signals accessible for testing code. */
- private static final int CMD_GENERAL_BASE = CMD_PRIVATE_BASE;
-
- /** Receive encoded IKE packet on IkeSessionStateMachine. */
- static final int CMD_RECEIVE_IKE_PACKET = CMD_GENERAL_BASE + 1;
- /** Receive encoded IKE packet with unrecognized IKE SPI on IkeSessionStateMachine. */
- static final int CMD_RECEIVE_PACKET_INVALID_IKE_SPI = CMD_GENERAL_BASE + 2;
- /** Receive an remote request for a Child procedure. */
- static final int CMD_RECEIVE_REQUEST_FOR_CHILD = CMD_GENERAL_BASE + 3;
- /** Receive payloads from Child Session for building an outbound IKE message. */
- static final int CMD_OUTBOUND_CHILD_PAYLOADS_READY = CMD_GENERAL_BASE + 4;
- /** A Child Session has finished its procedure. */
- static final int CMD_CHILD_PROCEDURE_FINISHED = CMD_GENERAL_BASE + 5;
- /** Send request/response payloads to ChildSessionStateMachine for further processing. */
- static final int CMD_HANDLE_FIRST_CHILD_NEGOTIATION = CMD_GENERAL_BASE + 6;
- /** Receive a local request to execute from the scheduler */
- static final int CMD_EXECUTE_LOCAL_REQ = CMD_GENERAL_BASE + 7;
- /** Trigger a retransmission. */
- public static final int CMD_RETRANSMIT = CMD_GENERAL_BASE + 8;
- /** Send EAP request payloads to EapAuthenticator for further processing. */
- static final int CMD_EAP_START_EAP_AUTH = CMD_GENERAL_BASE + 9;
- /** Send the outbound IKE-wrapped EAP-Response message. */
- static final int CMD_EAP_OUTBOUND_MSG_READY = CMD_GENERAL_BASE + 10;
- /** Proxy to IkeSessionStateMachine handler to notify of errors */
- static final int CMD_EAP_ERRORED = CMD_GENERAL_BASE + 11;
- /** Proxy to IkeSessionStateMachine handler to notify of failures */
- static final int CMD_EAP_FAILED = CMD_GENERAL_BASE + 12;
- /** Proxy to IkeSessionStateMachine handler to notify of success, to continue to post-auth */
- static final int CMD_EAP_FINISH_EAP_AUTH = CMD_GENERAL_BASE + 14;
- /** Force state machine to a target state for testing purposes. */
- static final int CMD_FORCE_TRANSITION = CMD_GENERAL_BASE + 99;
-
- static final int CMD_IKE_LOCAL_REQUEST_BASE = CMD_GENERAL_BASE + CMD_CATEGORY_SIZE;
- static final int CMD_LOCAL_REQUEST_CREATE_IKE = CMD_IKE_LOCAL_REQUEST_BASE + 1;
- static final int CMD_LOCAL_REQUEST_DELETE_IKE = CMD_IKE_LOCAL_REQUEST_BASE + 2;
- static final int CMD_LOCAL_REQUEST_REKEY_IKE = CMD_IKE_LOCAL_REQUEST_BASE + 3;
- static final int CMD_LOCAL_REQUEST_INFO = CMD_IKE_LOCAL_REQUEST_BASE + 4;
-
- private static final SparseArray<String> CMD_TO_STR;
-
- static {
- CMD_TO_STR = new SparseArray<>();
- CMD_TO_STR.put(CMD_RECEIVE_IKE_PACKET, "Rcv packet");
- CMD_TO_STR.put(CMD_RECEIVE_PACKET_INVALID_IKE_SPI, "Rcv invalid IKE SPI");
- CMD_TO_STR.put(CMD_RECEIVE_REQUEST_FOR_CHILD, "Rcv Child request");
- CMD_TO_STR.put(CMD_OUTBOUND_CHILD_PAYLOADS_READY, "Out child payloads ready");
- CMD_TO_STR.put(CMD_CHILD_PROCEDURE_FINISHED, "Child procedure finished");
- CMD_TO_STR.put(CMD_HANDLE_FIRST_CHILD_NEGOTIATION, "Negotiate first Child");
- CMD_TO_STR.put(CMD_EXECUTE_LOCAL_REQ, "Execute local request");
- CMD_TO_STR.put(CMD_RETRANSMIT, "Retransmit");
- CMD_TO_STR.put(CMD_EAP_START_EAP_AUTH, "Start EAP");
- CMD_TO_STR.put(CMD_EAP_OUTBOUND_MSG_READY, "EAP outbound msg ready");
- CMD_TO_STR.put(CMD_EAP_ERRORED, "EAP errored");
- CMD_TO_STR.put(CMD_EAP_FAILED, "EAP failed");
- CMD_TO_STR.put(CMD_EAP_FINISH_EAP_AUTH, "Finish EAP");
- CMD_TO_STR.put(CMD_LOCAL_REQUEST_CREATE_IKE, "Create IKE");
- CMD_TO_STR.put(CMD_LOCAL_REQUEST_DELETE_IKE, "Delete IKE");
- CMD_TO_STR.put(CMD_LOCAL_REQUEST_REKEY_IKE, "Rekey IKE");
- CMD_TO_STR.put(CMD_LOCAL_REQUEST_INFO, "Info");
- }
-
- private final IkeSessionOptions mIkeSessionOptions;
-
- /** Map that stores all IkeSaRecords, keyed by locally generated IKE SPI. */
- private final LongSparseArray<IkeSaRecord> mLocalSpiToIkeSaRecordMap;
- /**
- * Map that stores all ChildSessionStateMachines, keyed by remotely generated Child SPI for
- * sending IPsec packet. Different SPIs may point to the same ChildSessionStateMachine if this
- * Child Session is doing Rekey.
- */
- private final SparseArray<ChildSessionStateMachine> mRemoteSpiToChildSessionMap;
-
- private final Context mContext;
- private final IpSecManager mIpSecManager;
- private final IkeLocalRequestScheduler mScheduler;
- private final Executor mUserCbExecutor;
- private final IkeSessionCallback mIkeSessionCallback;
- private final IkeEapAuthenticatorFactory mEapAuthenticatorFactory;
- private final TempFailureHandler mTempFailHandler;
-
- @VisibleForTesting
- @GuardedBy("mChildCbToSessions")
- final HashMap<ChildSessionCallback, ChildSessionStateMachine> mChildCbToSessions =
- new HashMap<>();
-
- /**
- * Package private socket that sends and receives encoded IKE message. Initialized in Initial
- * State.
- */
- @VisibleForTesting IkeSocket mIkeSocket;
-
- /** Local address assigned on device. Initialized in Initial State. */
- @VisibleForTesting InetAddress mLocalAddress;
- /** Remote address configured by users. Initialized in Initial State. */
- @VisibleForTesting InetAddress mRemoteAddress;
- /** Local port assigned on device. Initialized in Initial State. */
- @VisibleForTesting int mLocalPort;
-
- /** Indicates if local node is behind a NAT. */
- @VisibleForTesting boolean mIsLocalBehindNat;
- /** Indicates if remote node is behind a NAT. */
- @VisibleForTesting boolean mIsRemoteBehindNat;
-
- /** Indicates if both sides support fragmentation. Set in IKE INIT */
- @VisibleForTesting boolean mSupportFragment;
-
- /** Package private IkeSaProposal that represents the negotiated IKE SA proposal. */
- @VisibleForTesting IkeSaProposal mSaProposal;
-
- @VisibleForTesting IkeCipher mIkeCipher;
- @VisibleForTesting IkeMacIntegrity mIkeIntegrity;
- @VisibleForTesting IkeMacPrf mIkePrf;
-
- // FIXME: b/131265898 Pass these parameters from CreateIkeLocalIkeInit to CreateIkeLocalIkeAuth
- // as entry data when Android StateMachine can support that.
- @VisibleForTesting byte[] mIkeInitRequestBytes;
- @VisibleForTesting byte[] mIkeInitResponseBytes;
- @VisibleForTesting IkeNoncePayload mIkeInitNoncePayload;
- @VisibleForTesting IkeNoncePayload mIkeRespNoncePayload;
-
- // FIXME: b/131265898 Pass these parameters from CreateIkeLocalIkeAuth through to
- // CreateIkeLocalIkeAuthPostEap as entry data when Android StateMachine can support that.
- @VisibleForTesting IkeIdPayload mInitIdPayload;
- @VisibleForTesting IkeIdPayload mRespIdPayload;
- @VisibleForTesting List<IkePayload> mFirstChildReqList;
-
- // FIXME: b/131265898 Move into CreateIkeLocalIkeAuth, and pass through to
- // CreateIkeLocalIkeAuthPostEap once passing entry data is supported
- private ChildSessionOptions mFirstChildSessionOptions;
- private ChildSessionCallback mFirstChildCallbacks;
-
- /** Package */
- @VisibleForTesting IkeSaRecord mCurrentIkeSaRecord;
- /** Package */
- @VisibleForTesting IkeSaRecord mLocalInitNewIkeSaRecord;
- /** Package */
- @VisibleForTesting IkeSaRecord mRemoteInitNewIkeSaRecord;
-
- /** Package */
- @VisibleForTesting IkeSaRecord mIkeSaRecordSurviving;
- /** Package */
- @VisibleForTesting IkeSaRecord mIkeSaRecordAwaitingLocalDel;
- /** Package */
- @VisibleForTesting IkeSaRecord mIkeSaRecordAwaitingRemoteDel;
-
- // States
- @VisibleForTesting final State mInitial = new Initial();
- @VisibleForTesting final State mIdle = new Idle();
- @VisibleForTesting final State mChildProcedureOngoing = new ChildProcedureOngoing();
- @VisibleForTesting final State mReceiving = new Receiving();
- @VisibleForTesting final State mCreateIkeLocalIkeInit = new CreateIkeLocalIkeInit();
- @VisibleForTesting final State mCreateIkeLocalIkeAuth = new CreateIkeLocalIkeAuth();
- @VisibleForTesting final State mCreateIkeLocalIkeAuthInEap = new CreateIkeLocalIkeAuthInEap();
-
- @VisibleForTesting
- final State mCreateIkeLocalIkeAuthPostEap = new CreateIkeLocalIkeAuthPostEap();
-
- @VisibleForTesting final State mRekeyIkeLocalCreate = new RekeyIkeLocalCreate();
- @VisibleForTesting final State mSimulRekeyIkeLocalCreate = new SimulRekeyIkeLocalCreate();
-
- @VisibleForTesting
- final State mSimulRekeyIkeLocalDeleteRemoteDelete = new SimulRekeyIkeLocalDeleteRemoteDelete();
-
- @VisibleForTesting final State mSimulRekeyIkeLocalDelete = new SimulRekeyIkeLocalDelete();
- @VisibleForTesting final State mSimulRekeyIkeRemoteDelete = new SimulRekeyIkeRemoteDelete();
- @VisibleForTesting final State mRekeyIkeLocalDelete = new RekeyIkeLocalDelete();
- @VisibleForTesting final State mRekeyIkeRemoteDelete = new RekeyIkeRemoteDelete();
- @VisibleForTesting final State mDeleteIkeLocalDelete = new DeleteIkeLocalDelete();
- // TODO: Add InfoLocal.
-
- /** Constructor for testing. */
- @VisibleForTesting
- public IkeSessionStateMachine(
- Looper looper,
- Context context,
- IpSecManager ipSecManager,
- IkeSessionOptions ikeOptions,
- ChildSessionOptions firstChildOptions,
- Executor userCbExecutor,
- IkeSessionCallback ikeSessionCallback,
- ChildSessionCallback firstChildSessionCallback,
- IkeEapAuthenticatorFactory eapAuthenticatorFactory) {
- super(TAG, looper);
-
- mIkeSessionOptions = ikeOptions;
- mEapAuthenticatorFactory = eapAuthenticatorFactory;
-
- mTempFailHandler = new TempFailureHandler(looper);
-
- // There are at most three IkeSaRecords co-existing during simultaneous rekeying.
- mLocalSpiToIkeSaRecordMap = new LongSparseArray<>(3);
- mRemoteSpiToChildSessionMap = new SparseArray<>();
-
- mContext = context;
- mIpSecManager = ipSecManager;
-
- mUserCbExecutor = userCbExecutor;
- mIkeSessionCallback = ikeSessionCallback;
-
- mFirstChildSessionOptions = firstChildOptions;
- mFirstChildCallbacks = firstChildSessionCallback;
- registerChildSessionCallback(firstChildOptions, firstChildSessionCallback, true);
-
- addState(mInitial);
- addState(mCreateIkeLocalIkeInit);
- addState(mCreateIkeLocalIkeAuth);
- addState(mCreateIkeLocalIkeAuthInEap);
- addState(mCreateIkeLocalIkeAuthPostEap);
- addState(mIdle);
- addState(mChildProcedureOngoing);
- addState(mReceiving);
- addState(mRekeyIkeLocalCreate);
- addState(mSimulRekeyIkeLocalCreate, mRekeyIkeLocalCreate);
- addState(mSimulRekeyIkeLocalDeleteRemoteDelete);
- addState(mSimulRekeyIkeLocalDelete, mSimulRekeyIkeLocalDeleteRemoteDelete);
- addState(mSimulRekeyIkeRemoteDelete, mSimulRekeyIkeLocalDeleteRemoteDelete);
- addState(mRekeyIkeLocalDelete);
- addState(mRekeyIkeRemoteDelete);
- addState(mDeleteIkeLocalDelete);
-
- setInitialState(mInitial);
- mScheduler =
- new IkeLocalRequestScheduler(
- localReq -> {
- sendMessageAtFrontOfQueue(CMD_EXECUTE_LOCAL_REQ, localReq);
- });
-
- start();
- }
-
- /** Construct an instance of IkeSessionStateMachine. */
- public IkeSessionStateMachine(
- Looper looper,
- Context context,
- IpSecManager ipSecManager,
- IkeSessionOptions ikeOptions,
- ChildSessionOptions firstChildOptions,
- Executor userCbExecutor,
- IkeSessionCallback ikeSessionCallback,
- ChildSessionCallback firstChildSessionCallback) {
- this(
- looper,
- context,
- ipSecManager,
- ikeOptions,
- firstChildOptions,
- userCbExecutor,
- ikeSessionCallback,
- firstChildSessionCallback,
- new IkeEapAuthenticatorFactory());
- }
-
- private boolean hasChildSessionCallback(ChildSessionCallback callback) {
- synchronized (mChildCbToSessions) {
- return mChildCbToSessions.containsKey(callback);
- }
- }
-
- /**
- * Synchronously builds and registers a child session.
- *
- * <p>Setup of the child state machines MUST be done in two stages to ensure that if an external
- * caller calls openChildSession and then calls closeChildSession before the state machine has
- * gotten a chance to negotiate the sessions, a valid callback mapping exists (and does not
- * throw an exception that the callback was not found).
- *
- * <p>In the edge case where a child creation fails, and deletes itself, all pending requests
- * will no longer find the session in the map. Assume it has errored/failed, and skip/ignore.
- * This is safe, as closeChildSession() (previously) validated that the callback was registered.
- */
- @VisibleForTesting
- void registerChildSessionCallback(
- ChildSessionOptions childOptions,
- ChildSessionCallback callbacks,
- boolean isFirstChild) {
- synchronized (mChildCbToSessions) {
- if (!isFirstChild && getCurrentState() == null) {
- throw new IllegalStateException(
- "Request rejected because IKE Session is being closed. ");
- }
-
- mChildCbToSessions.put(
- callbacks,
- ChildSessionStateMachineFactory.makeChildSessionStateMachine(
- getHandler().getLooper(),
- mContext,
- childOptions,
- mUserCbExecutor,
- callbacks,
- new ChildSessionSmCallback()));
- }
- }
-
- /** Initiates IKE setup procedure. */
- public void openSession() {
- sendMessage(CMD_LOCAL_REQUEST_CREATE_IKE, new LocalRequest(CMD_LOCAL_REQUEST_CREATE_IKE));
- }
-
- /** Schedules a Create Child procedure. */
- public void openChildSession(
- ChildSessionOptions childSessionOptions, ChildSessionCallback childSessionCallback) {
- if (childSessionCallback == null) {
- throw new IllegalArgumentException("Child Session Callback must be provided");
- }
-
- if (hasChildSessionCallback(childSessionCallback)) {
- throw new IllegalArgumentException("Child Session Callback handle already registered");
- }
-
- registerChildSessionCallback(
- childSessionOptions, childSessionCallback, false /*isFirstChild*/);
- sendMessage(
- CMD_LOCAL_REQUEST_CREATE_CHILD,
- new ChildLocalRequest(
- CMD_LOCAL_REQUEST_CREATE_CHILD, childSessionCallback, childSessionOptions));
- }
-
- /** Schedules a Delete Child procedure. */
- public void closeChildSession(ChildSessionCallback childSessionCallback) {
- if (childSessionCallback == null) {
- throw new IllegalArgumentException("Child Session Callback must be provided");
- }
-
- if (!hasChildSessionCallback(childSessionCallback)) {
- throw new IllegalArgumentException("Child Session Callback handle not registered");
- }
-
- sendMessage(
- CMD_LOCAL_REQUEST_DELETE_CHILD,
- new ChildLocalRequest(CMD_LOCAL_REQUEST_DELETE_CHILD, childSessionCallback, null));
- }
-
- /** Initiates Delete IKE procedure. */
- public void closeSession() {
- sendMessage(CMD_LOCAL_REQUEST_DELETE_IKE, new LocalRequest(CMD_LOCAL_REQUEST_DELETE_IKE));
- }
-
- /** Forcibly close IKE Session. */
- public void killSession() {
- // TODO: b/142977160 Support closing IKE Sesison immediately.
- }
-
- private void scheduleRekeySession(LocalRequest rekeyRequest) {
- // TODO: Make rekey timeout fuzzy
- sendMessageDelayed(CMD_LOCAL_REQUEST_REKEY_IKE, rekeyRequest, SA_SOFT_LIFETIME_MS);
- }
-
- private void scheduleRetry(LocalRequest localRequest) {
- sendMessageDelayed(localRequest.procedureType, localRequest, RETRY_INTERVAL_MS);
- }
-
- // TODO: Support initiating Delete IKE exchange when IKE SA expires
-
- // TODO: Add interfaces to initiate IKE exchanges.
-
- /**
- * This class is for handling temporary failure.
- *
- * <p>Receiving a TEMPORARY_FAILURE is caused by a temporary condition. IKE Session should be
- * closed if it continues to receive this error after several minutes.
- */
- @VisibleForTesting
- class TempFailureHandler extends Handler {
- private static final int TEMP_FAILURE_RETRY_TIMEOUT = 1;
-
- private boolean mTempFailureReceived = false;
-
- TempFailureHandler(Looper looper) {
- super(looper);
- }
-
- @Override
- public void handleMessage(Message msg) {
- if (msg.what == TEMP_FAILURE_RETRY_TIMEOUT) {
- IOException error =
- new IOException(
- "Kept receiving TEMPORARY_FAILURE error. State information is out"
- + " of sync.");
- mUserCbExecutor.execute(
- () -> {
- mIkeSessionCallback.onClosedExceptionally(
- new IkeInternalException(error));
- });
- loge("Fatal error", error);
-
- closeAllSaRecords(false /*expectSaClosed*/);
- quitNow();
- } else {
- logWtf("Unknown message.what: " + msg.what);
- }
- }
-
- /** Schedule retry when a request got rejected by TEMPORARY_FAILURE. */
- public void handleTempFailure(LocalRequest localRequest) {
- logd(
- "TempFailureHandler: Receive TEMPORARY FAILURE. Reschedule request: "
- + localRequest.procedureType);
-
- // TODO: Support customized delay time when this is a rekey request and SA is going to
- // expire soon.
- scheduleRetry(localRequest);
-
- if (!mTempFailureReceived) {
- sendEmptyMessageDelayed(TEMP_FAILURE_RETRY_TIMEOUT, TEMP_FAILURE_RETRY_TIMEOUT_MS);
- mTempFailureReceived = true;
- }
- }
-
- /** Stop tracking temporary condition when request was not rejected by TEMPORARY_FAILURE. */
- public void reset() {
- logd("TempFailureHandler: Reset Temporary failure retry timeout");
- removeMessages(TEMP_FAILURE_RETRY_TIMEOUT);
- mTempFailureReceived = false;
- }
- }
- /**
- * This class represents a reserved IKE SPI.
- *
- * <p>This class is created to avoid assigning same SPI to the same address.
- *
- * <p>Objects of this type are used to track reserved IKE SPI to avoid SPI collision. They can
- * be obtained by calling {@link #allocateSecurityParameterIndex()} and must be released by
- * calling {@link #close()} when they are no longer needed.
- *
- * <p>This class follows the pattern of {@link IpSecManager.SecurityParameterIndex}.
- *
- * <p>TODO: Move this class to a central place, like IkeManager.
- */
- public static 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();
-
- private final InetAddress mSourceAddress;
- private final long mSpi;
- private final CloseGuard mCloseGuard = CloseGuard.get();
-
- private 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.
- */
- public long getSpi() {
- return mSpi;
- }
-
- /** Release an SPI that was previously reserved. */
- @Override
- public void close() {
- sAssignedIkeSpis.remove(new Pair<InetAddress, Long>(mSourceAddress, mSpi));
- mCloseGuard.close();
- }
-
- /** Check that the IkeSecurityParameterIndex was closed properly. */
- @Override
- protected void finalize() throws Throwable {
- if (mCloseGuard != null) {
- mCloseGuard.warnIfOpen();
- }
- close();
- }
- }
-
- // TODO: Add methods for building and validating general Informational packet.
-
- @VisibleForTesting
- void addIkeSaRecord(IkeSaRecord record) {
- mLocalSpiToIkeSaRecordMap.put(record.getLocalSpi(), record);
-
- // In IKE_INIT exchange, local SPI was registered with this IkeSessionStateMachine before
- // IkeSaRecord is created. Calling this method at the end of exchange will double-register
- // the SPI but it is safe because the key and value are not changed.
- mIkeSocket.registerIke(record.getLocalSpi(), this);
-
- scheduleRekeySession(record.getFutureRekeyEvent());
- }
-
- @VisibleForTesting
- void removeIkeSaRecord(IkeSaRecord record) {
- mIkeSocket.unregisterIke(record.getLocalSpi());
- mLocalSpiToIkeSaRecordMap.remove(record.getLocalSpi());
- }
-
- /**
- * Receive IKE packet from remote server.
- *
- * <p>This method is called synchronously from IkeSocket. It proxies the synchronous call as an
- * asynchronous job to the IkeSessionStateMachine handler.
- *
- * @param ikeHeader the decoded IKE header.
- * @param ikePacketBytes the byte array of the entire received IKE packet.
- */
- public void receiveIkePacket(IkeHeader ikeHeader, byte[] ikePacketBytes) {
- sendMessage(CMD_RECEIVE_IKE_PACKET, new ReceivedIkePacket(ikeHeader, ikePacketBytes));
- }
-
- /**
- * ReceivedIkePacket is a package private data container consists of decoded IkeHeader and
- * encoded IKE packet in a byte array.
- */
- static class ReceivedIkePacket {
- /** Decoded IKE header */
- public final IkeHeader ikeHeader;
- /** Entire encoded IKE message including IKE header */
- public final byte[] ikePacketBytes;
-
- ReceivedIkePacket(IkeHeader ikeHeader, byte[] ikePacketBytes) {
- this.ikeHeader = ikeHeader;
- this.ikePacketBytes = ikePacketBytes;
- }
- }
-
- /** Class to group parameters for negotiating the first Child SA. */
- private static class FirstChildNegotiationData {
- public final ChildSessionOptions childSessionOptions;
- public final ChildSessionCallback childSessionCallback;
- public final List<IkePayload> reqPayloads;
- public final List<IkePayload> respPayloads;
-
- FirstChildNegotiationData(
- ChildSessionOptions childSessionOptions,
- ChildSessionCallback childSessionCallback,
- List<IkePayload> reqPayloads,
- List<IkePayload> respPayloads) {
- this.childSessionOptions = childSessionOptions;
- this.childSessionCallback = childSessionCallback;
- this.reqPayloads = reqPayloads;
- this.respPayloads = respPayloads;
- }
- }
-
- /** Class to group parameters for building an outbound message for ChildSessions. */
- private static class ChildOutboundData {
- @ExchangeType public final int exchangeType;
- public final boolean isResp;
- public final List<IkePayload> payloadList;
- public final ChildSessionStateMachine childSession;
-
- ChildOutboundData(
- @ExchangeType int exchangeType,
- boolean isResp,
- List<IkePayload> payloadList,
- ChildSessionStateMachine childSession) {
- this.exchangeType = exchangeType;
- this.isResp = isResp;
- this.payloadList = payloadList;
- this.childSession = childSession;
- }
- }
-
- /** Callback for ChildSessionStateMachine to notify IkeSessionStateMachine. */
- @VisibleForTesting
- class ChildSessionSmCallback implements ChildSessionStateMachine.IChildSessionSmCallback {
- @Override
- public void onChildSaCreated(int remoteSpi, ChildSessionStateMachine childSession) {
- mRemoteSpiToChildSessionMap.put(remoteSpi, childSession);
- }
-
- @Override
- public void onChildSaDeleted(int remoteSpi) {
- mRemoteSpiToChildSessionMap.remove(remoteSpi);
- }
-
- @Override
- public void scheduleLocalRequest(ChildLocalRequest futureRequest, long delayedTime) {
- sendMessageDelayed(futureRequest.procedureType, futureRequest, delayedTime);
- }
-
- @Override
- public void scheduleRetryLocalRequest(ChildLocalRequest childRequest) {
- scheduleRetry(childRequest);
- }
-
- @Override
- public void onOutboundPayloadsReady(
- @ExchangeType int exchangeType,
- boolean isResp,
- List<IkePayload> payloadList,
- ChildSessionStateMachine childSession) {
- sendMessage(
- CMD_OUTBOUND_CHILD_PAYLOADS_READY,
- new ChildOutboundData(exchangeType, isResp, payloadList, childSession));
- }
-
- @Override
- public void onProcedureFinished(ChildSessionStateMachine childSession) {
- if (getHandler() == null) {
- // If the state machine has quit (because IKE Session is being closed), do not send
- // any message.
- return;
- }
-
- sendMessage(CMD_CHILD_PROCEDURE_FINISHED, childSession);
- }
-
- @Override
- public void onChildSessionClosed(ChildSessionCallback userCallbacks) {
- synchronized (mChildCbToSessions) {
- mChildCbToSessions.remove(userCallbacks);
- }
- }
-
- @Override
- public void onFatalIkeSessionError(boolean needsNotifyRemote) {
- // TODO: If needsNotifyRemote is true, send a Delete IKE request and then kill the IKE
- // Session. Otherwise, directly kill the IKE Session.
- }
- }
-
- /** Top level state for handling uncaught exceptions for all subclasses. */
- abstract class ExceptionHandler extends ExceptionHandlerBase {
- @Override
- protected void cleanUpAndQuit(RuntimeException e) {
- // Clean up all SaRecords.
- closeAllSaRecords(false /*expectSaClosed*/);
-
- mUserCbExecutor.execute(
- () -> {
- mIkeSessionCallback.onClosedExceptionally(new IkeInternalException(e));
- });
- logWtf("Unexpected exception in " + getCurrentState().getName(), e);
- quitNow();
- }
-
- @Override
- protected String getCmdString(int cmd) {
- return CMD_TO_STR.get(cmd);
- }
- }
-
- /** Called when this StateMachine quits. */
- @Override
- protected void onQuitting() {
- // Clean up all SaRecords.
- closeAllSaRecords(true /*expectSaClosed*/);
-
- synchronized (mChildCbToSessions) {
- for (ChildSessionStateMachine child : mChildCbToSessions.values()) {
- // Fire asynchronous call for Child Sessions to do cleanup and remove itself
- // from the map.
- child.killSession();
- }
- }
-
- if (mIkeSocket == null) return;
- mIkeSocket.releaseReference(this);
- }
-
- private void closeAllSaRecords(boolean expectSaClosed) {
- closeIkeSaRecord(mCurrentIkeSaRecord, expectSaClosed);
- closeIkeSaRecord(mLocalInitNewIkeSaRecord, expectSaClosed);
- closeIkeSaRecord(mRemoteInitNewIkeSaRecord, expectSaClosed);
-
- mCurrentIkeSaRecord = null;
- mLocalInitNewIkeSaRecord = null;
- mRemoteInitNewIkeSaRecord = null;
- }
-
- private void closeIkeSaRecord(IkeSaRecord ikeSaRecord, boolean expectSaClosed) {
- if (ikeSaRecord == null) return;
-
- removeIkeSaRecord(ikeSaRecord);
- ikeSaRecord.close();
-
- if (!expectSaClosed) return;
-
- logWtf(
- "IkeSaRecord with local SPI: "
- + ikeSaRecord.getLocalSpi()
- + " is not correctly closed.");
- }
-
- private void handleIkeFatalError(Exception error) {
- IkeException ikeException =
- error instanceof IkeException
- ? (IkeException) error
- : new IkeInternalException(error);
-
- // Clean up all SaRecords.
- closeAllSaRecords(false /*expectSaClosed*/);
- mUserCbExecutor.execute(
- () -> {
- mIkeSessionCallback.onClosedExceptionally(ikeException);
- });
- loge("IKE Session fatal error in " + getCurrentState().getName(), ikeException);
-
- quitNow();
- }
-
- /** Initial state of IkeSessionStateMachine. */
- class Initial extends ExceptionHandler {
- @Override
- public void enterState() {
- try {
- mRemoteAddress = mIkeSessionOptions.getServerAddress();
-
- boolean isIpv4 = mRemoteAddress instanceof Inet4Address;
- FileDescriptor sock =
- Os.socket(
- isIpv4 ? OsConstants.AF_INET : OsConstants.AF_INET6,
- OsConstants.SOCK_DGRAM,
- OsConstants.IPPROTO_UDP);
- Os.connect(sock, mRemoteAddress, IkeSocket.IKE_SERVER_PORT);
- InetSocketAddress localAddr = (InetSocketAddress) Os.getsockname(sock);
- mLocalAddress = localAddr.getAddress();
- mLocalPort = localAddr.getPort();
- Os.close(sock);
-
- mIkeSocket =
- IkeSocket.getIkeSocket(
- mIkeSessionOptions.getUdpEncapsulationSocket(),
- IkeSessionStateMachine.this);
- } catch (ErrnoException | SocketException e) {
- handleIkeFatalError(e);
- }
- }
-
- @Override
- public boolean processStateMessage(Message message) {
- switch (message.what) {
- case CMD_LOCAL_REQUEST_CREATE_IKE:
- transitionTo(mCreateIkeLocalIkeInit);
- return HANDLED;
- case CMD_FORCE_TRANSITION:
- transitionTo((State) message.obj);
- return HANDLED;
- default:
- return NOT_HANDLED;
- }
- }
- }
-
- /**
- * Idle represents a state when there is no ongoing IKE exchange affecting established IKE SA.
- */
- class Idle extends LocalRequestQueuer {
- @Override
- public void enterState() {
- mScheduler.readyForNextProcedure();
- }
-
- @Override
- public boolean processStateMessage(Message message) {
- switch (message.what) {
- case CMD_RECEIVE_IKE_PACKET:
- deferMessage(message);
- transitionTo(mReceiving);
- return HANDLED;
-
- case CMD_FORCE_TRANSITION: // Testing command
- transitionTo((State) message.obj);
- return HANDLED;
-
- case CMD_EXECUTE_LOCAL_REQ:
- executeLocalRequest((LocalRequest) message.obj, message);
- return HANDLED;
-
- default:
- // Queue local requests, and trigger next procedure
- if (isLocalRequest(message.what)) {
- handleLocalRequest(message.what, (LocalRequest) message.obj);
-
- // Synchronously calls through to the scheduler callback, which will
- // post the CMD_EXECUTE_LOCAL_REQ to the front of the queue, ensuring
- // it is always the next request processed.
- mScheduler.readyForNextProcedure();
- return HANDLED;
- }
- return NOT_HANDLED;
- }
- }
-
- private void executeLocalRequest(LocalRequest req, Message message) {
- switch (req.procedureType) {
- case CMD_LOCAL_REQUEST_REKEY_IKE:
- transitionTo(mRekeyIkeLocalCreate);
- break;
- case CMD_LOCAL_REQUEST_DELETE_IKE:
- transitionTo(mDeleteIkeLocalDelete);
- break;
- case CMD_LOCAL_REQUEST_CREATE_CHILD: // fallthrough
- case CMD_LOCAL_REQUEST_REKEY_CHILD: // fallthrough
- case CMD_LOCAL_REQUEST_DELETE_CHILD:
- deferMessage(message);
- transitionTo(mChildProcedureOngoing);
- break;
- default:
- cleanUpAndQuit(
- new IllegalStateException(
- "Invalid local request procedure type: " + req.procedureType));
- }
- }
- }
-
- /**
- * Gets IKE exchange subtype of a inbound IKE request message.
- *
- * <p>Knowing IKE exchange subtype of a inbound IKE request message helps IkeSessionStateMachine
- * to validate this request using the specific rule.
- *
- * <p>It is not allowed to obtain exchange subtype from a inbound response message for two
- * reasons. Firstly, the exchange subtype of a response message is the same with its
- * corresponding request message. Secondly, trying to get the exchange subtype from a response
- * message will easily fail when the response message contains only error notification payloads.
- *
- * @param ikeMessage inbound request IKE message to check.
- * @return IKE exchange subtype.
- */
- @IkeExchangeSubType
- private static int getIkeExchangeSubType(IkeMessage ikeMessage) {
- IkeHeader ikeHeader = ikeMessage.ikeHeader;
- if (ikeHeader.isResponseMsg) {
- throw new IllegalStateException("IKE Exchange subtype invalid for response messages.");
- }
-
- switch (ikeHeader.exchangeType) {
- // DPD omitted - should never be handled via handleRequestIkeMessage()
- case IkeHeader.EXCHANGE_TYPE_IKE_SA_INIT:
- return IKE_EXCHANGE_SUBTYPE_IKE_INIT;
- case IkeHeader.EXCHANGE_TYPE_IKE_AUTH:
- return IKE_EXCHANGE_SUBTYPE_IKE_AUTH;
- case IkeHeader.EXCHANGE_TYPE_CREATE_CHILD_SA:
- // It is guaranteed in the decoding process that SA Payload has at least one SA
- // Proposal. Since Rekey IKE and Create Child (both initial creation and rekey
- // creation) will cause a collision, although the RFC 7296 does not prohibit one SA
- // Payload to contain both IKE proposals and Child proposals, containing two types
- // does not make sense. IKE libary will reply according to the first SA Proposal
- // type and ignore the other type.
- IkeSaPayload saPayload =
- ikeMessage.getPayloadForType(
- IkePayload.PAYLOAD_TYPE_SA, IkeSaPayload.class);
- if (saPayload == null) {
- return IKE_EXCHANGE_SUBTYPE_INVALID;
- }
-
- // If the received message has both SA(IKE) Payload and Notify-Rekey Payload, IKE
- // library will treat it as a Rekey IKE request and ignore the Notify-Rekey
- // Payload to provide better interoperability.
- if (saPayload.proposalList.get(0).protocolId == IkePayload.PROTOCOL_ID_IKE) {
- return IKE_EXCHANGE_SUBTYPE_REKEY_IKE;
- }
-
- // If a Notify-Rekey Payload is found, this message is for rekeying a Child SA.
- List<IkeNotifyPayload> notifyPayloads =
- ikeMessage.getPayloadListForType(
- IkePayload.PAYLOAD_TYPE_NOTIFY, IkeNotifyPayload.class);
-
- // It is checked during decoding that there is at most one Rekey notification
- // payload.
- for (IkeNotifyPayload notifyPayload : notifyPayloads) {
- if (notifyPayload.notifyType == IkeNotifyPayload.NOTIFY_TYPE_REKEY_SA) {
- return IKE_EXCHANGE_SUBTYPE_REKEY_CHILD;
- }
- }
-
- return IKE_EXCHANGE_SUBTYPE_CREATE_CHILD;
- case IkeHeader.EXCHANGE_TYPE_INFORMATIONAL:
- List<IkeDeletePayload> deletePayloads =
- ikeMessage.getPayloadListForType(
- IkePayload.PAYLOAD_TYPE_DELETE, IkeDeletePayload.class);
-
- // If no Delete payload was found, this request is a generic informational request.
- if (deletePayloads.isEmpty()) return IKE_EXCHANGE_SUBTYPE_GENERIC_INFO;
-
- // IKEv2 protocol does not clearly disallow to have both a Delete IKE payload and a
- // Delete Child payload in one IKE message. In this case, IKE library will only
- // respond to the Delete IKE payload.
- for (IkeDeletePayload deletePayload : deletePayloads) {
- if (deletePayload.protocolId == IkePayload.PROTOCOL_ID_IKE) {
- return IKE_EXCHANGE_SUBTYPE_DELETE_IKE;
- }
- }
- return IKE_EXCHANGE_SUBTYPE_DELETE_CHILD;
- default:
- throw new IllegalStateException(
- "Unrecognized exchange type in the validated IKE header: "
- + ikeHeader.exchangeType);
- }
- }
-
- // Sends the provided IkeMessage using the current IKE SA record
- @VisibleForTesting
- void sendEncryptedIkeMessage(IkeMessage msg) {
- sendEncryptedIkeMessage(mCurrentIkeSaRecord, msg);
- }
-
- // Sends the provided IkeMessage using the provided IKE SA record
- @VisibleForTesting
- void sendEncryptedIkeMessage(IkeSaRecord ikeSaRecord, IkeMessage msg) {
- byte[][] packetList =
- msg.encryptAndEncode(
- mIkeIntegrity,
- mIkeCipher,
- ikeSaRecord,
- mSupportFragment,
- DEFAULT_FRAGMENT_SIZE);
- for (byte[] packet : packetList) {
- mIkeSocket.sendIkePacket(packet, mRemoteAddress);
- }
- if (msg.ikeHeader.isResponseMsg) {
- ikeSaRecord.updateLastSentRespAllPackets(Arrays.asList(packetList));
- }
- }
-
- // Builds and sends IKE-level error notification response on the provided IKE SA record
- @VisibleForTesting
- void buildAndSendErrorNotificationResponse(
- IkeSaRecord ikeSaRecord, int messageId, @ErrorType int errorType) {
- IkeNotifyPayload error = new IkeNotifyPayload(errorType);
- buildAndSendNotificationResponse(ikeSaRecord, messageId, error);
- }
-
- // Builds and sends error notification response on the provided IKE SA record
- @VisibleForTesting
- void buildAndSendNotificationResponse(
- IkeSaRecord ikeSaRecord, int messageId, IkeNotifyPayload notifyPayload) {
- IkeMessage msg =
- buildEncryptedNotificationMessage(
- ikeSaRecord,
- new IkeInformationalPayload[] {notifyPayload},
- EXCHANGE_TYPE_INFORMATIONAL,
- true /*isResponse*/,
- messageId);
-
- sendEncryptedIkeMessage(ikeSaRecord, msg);
- }
-
- // Builds an Encrypted IKE Informational Message for the given IkeInformationalPayload using the
- // current IKE SA record.
- @VisibleForTesting
- IkeMessage buildEncryptedInformationalMessage(
- IkeInformationalPayload[] payloads, boolean isResponse, int messageId) {
- return buildEncryptedInformationalMessage(
- mCurrentIkeSaRecord, payloads, isResponse, messageId);
- }
-
- // Builds an Encrypted IKE Informational Message for the given IkeInformationalPayload using the
- // provided IKE SA record.
- @VisibleForTesting
- IkeMessage buildEncryptedInformationalMessage(
- IkeSaRecord saRecord,
- IkeInformationalPayload[] payloads,
- boolean isResponse,
- int messageId) {
- return buildEncryptedNotificationMessage(
- saRecord, payloads, IkeHeader.EXCHANGE_TYPE_INFORMATIONAL, isResponse, messageId);
- }
-
- // Builds an Encrypted IKE Message for the given IkeInformationalPayload using the provided IKE
- // SA record and exchange type.
- @VisibleForTesting
- IkeMessage buildEncryptedNotificationMessage(
- IkeSaRecord saRecord,
- IkeInformationalPayload[] payloads,
- @ExchangeType int exchangeType,
- boolean isResponse,
- int messageId) {
- IkeHeader header =
- new IkeHeader(
- saRecord.getInitiatorSpi(),
- saRecord.getResponderSpi(),
- IkePayload.PAYLOAD_TYPE_SK,
- exchangeType,
- isResponse /*isResponseMsg*/,
- saRecord.isLocalInit /*fromIkeInitiator*/,
- messageId);
-
- return new IkeMessage(header, Arrays.asList(payloads));
- }
-
- private abstract class LocalRequestQueuer extends ExceptionHandler {
- /**
- * Reroutes all local requests to the scheduler
- *
- * @param requestVal The command value of the request
- * @param req The instance of the LocalRequest to be queued.
- */
- protected void handleLocalRequest(int requestVal, LocalRequest req) {
- if (req.isCancelled()) return;
-
- switch (requestVal) {
- case CMD_LOCAL_REQUEST_DELETE_IKE:
- mScheduler.addRequestAtFront(req);
- return;
-
- case CMD_LOCAL_REQUEST_REKEY_IKE: // Fallthrough
- case CMD_LOCAL_REQUEST_INFO:
- mScheduler.addRequest(req);
- return;
-
- case CMD_LOCAL_REQUEST_CREATE_CHILD: // Fallthrough
- case CMD_LOCAL_REQUEST_REKEY_CHILD: // Fallthrough
- case CMD_LOCAL_REQUEST_DELETE_CHILD:
- ChildLocalRequest childReq = (ChildLocalRequest) req;
- if (childReq.procedureType != requestVal) {
- cleanUpAndQuit(
- new IllegalArgumentException(
- "ChildLocalRequest procedure type was invalid"));
- }
- mScheduler.addRequest(childReq);
- return;
-
- default:
- cleanUpAndQuit(
- new IllegalStateException(
- "Unknown local request passed to handleLocalRequest"));
- }
- }
-
- /** Check if received signal is a local request. */
- protected boolean isLocalRequest(int msgWhat) {
- if ((msgWhat >= CMD_IKE_LOCAL_REQUEST_BASE
- && msgWhat < CMD_IKE_LOCAL_REQUEST_BASE + CMD_CATEGORY_SIZE)
- || (msgWhat >= CMD_CHILD_LOCAL_REQUEST_BASE
- && msgWhat < CMD_CHILD_LOCAL_REQUEST_BASE + CMD_CATEGORY_SIZE)) {
- return true;
- }
- return false;
- }
- }
-
- /**
- * Base state defines common behaviours when receiving an IKE packet.
- *
- * <p>State that represents an ongoing IKE procedure MUST extend BusyState to handle received
- * IKE packet. Idle state will defer the received packet to a BusyState to process it.
- */
- private abstract class BusyState extends LocalRequestQueuer {
- @Override
- public boolean processStateMessage(Message message) {
- switch (message.what) {
- case CMD_RECEIVE_IKE_PACKET:
- handleReceivedIkePacket(message);
- return HANDLED;
-
- case CMD_FORCE_TRANSITION:
- transitionTo((State) message.obj);
- return HANDLED;
-
- case CMD_EXECUTE_LOCAL_REQ:
- logWtf("Invalid execute local request command in non-idle state");
- return NOT_HANDLED;
-
- case CMD_RETRANSMIT:
- triggerRetransmit();
- return HANDLED;
-
- default:
- // Queue local requests, and trigger next procedure
- if (isLocalRequest(message.what)) {
- handleLocalRequest(message.what, (LocalRequest) message.obj);
- return HANDLED;
- }
- return NOT_HANDLED;
- }
- }
-
- /**
- * Handler for retransmission timer firing
- *
- * <p>By default, the trigger is logged and dropped. States that have a retransmitter should
- * override this function, and proxy the call to Retransmitter.retransmit()
- */
- protected void triggerRetransmit() {
- logWtf("Retransmission trigger dropped in state: " + this.getClass().getSimpleName());
- }
-
- protected IkeSaRecord getIkeSaRecordForPacket(IkeHeader ikeHeader) {
- if (ikeHeader.fromIkeInitiator) {
- return mLocalSpiToIkeSaRecordMap.get(ikeHeader.ikeResponderSpi);
- } else {
- return mLocalSpiToIkeSaRecordMap.get(ikeHeader.ikeInitiatorSpi);
- }
- }
-
- protected void handleReceivedIkePacket(Message message) {
- // TODO: b/138411550 Notify subclasses when discarding a received packet. Receiving MUST
- // go back to Idle state in this case.
-
- String methodTag = "handleReceivedIkePacket: ";
-
- ReceivedIkePacket receivedIkePacket = (ReceivedIkePacket) message.obj;
- IkeHeader ikeHeader = receivedIkePacket.ikeHeader;
- byte[] ikePacketBytes = receivedIkePacket.ikePacketBytes;
- IkeSaRecord ikeSaRecord = getIkeSaRecordForPacket(ikeHeader);
-
- String msgDirection = ikeHeader.isResponseMsg ? "response" : "request";
-
- // Drop packets that we don't have an SA for:
- if (ikeSaRecord == null) {
- // TODO: Print a summary of the IKE message (perhaps the IKE header)
- cleanUpAndQuit(
- new IllegalStateException(
- "Received an IKE "
- + msgDirection
- + "but found no matching SA for it"));
- return;
- }
-
- logd(
- methodTag
- + "Received an "
- + ikeHeader.getBasicInfoString()
- + " on IKE SA with local SPI: "
- + ikeSaRecord.getLocalSpi()
- + ". Packet size: "
- + ikePacketBytes.length);
-
- if (ikeHeader.isResponseMsg) {
- int expectedMsgId = ikeSaRecord.getLocalRequestMessageId();
- if (expectedMsgId - 1 == ikeHeader.messageId) {
- logd(methodTag + "Received re-transmitted response. Discard it.");
- return;
- }
-
- DecodeResult decodeResult =
- IkeMessage.decode(
- expectedMsgId,
- mIkeIntegrity,
- mIkeCipher,
- ikeSaRecord,
- ikeHeader,
- ikePacketBytes,
- ikeSaRecord.getCollectedFragments(true /*isResp*/));
- switch (decodeResult.status) {
- case DECODE_STATUS_OK:
- ikeSaRecord.incrementLocalRequestMessageId();
- ikeSaRecord.resetCollectedFragments(true /*isResp*/);
-
- DecodeResultOk resultOk = (DecodeResultOk) decodeResult;
- if (isTempFailure(resultOk.ikeMessage)) {
- handleTempFailure();
- } else {
- mTempFailHandler.reset();
- }
-
- handleResponseIkeMessage(resultOk.ikeMessage);
- break;
- case DECODE_STATUS_PARTIAL:
- ikeSaRecord.updateCollectedFragments(
- (DecodeResultPartial) decodeResult, true /*isResp*/);
- break;
- case DECODE_STATUS_PROTECTED_ERROR:
- IkeException ikeException = ((DecodeResultError) decodeResult).ikeException;
- logi(methodTag + "Protected error", ikeException);
-
- ikeSaRecord.incrementLocalRequestMessageId();
- ikeSaRecord.resetCollectedFragments(true /*isResp*/);
-
- handleResponseGenericProcessError(
- ikeSaRecord,
- new InvalidSyntaxException(
- "Generic processing error in the received response",
- ikeException));
- break;
- case DECODE_STATUS_UNPROTECTED_ERROR:
- logi(
- methodTag
- + "Message authentication or decryption failed on received"
- + " response. Discard it",
- ((DecodeResultError) decodeResult).ikeException);
- break;
- default:
- cleanUpAndQuit(
- new IllegalStateException(
- "Unrecognized decoding status: " + decodeResult.status));
- }
-
- } else {
- int expectedMsgId = ikeSaRecord.getRemoteRequestMessageId();
- if (expectedMsgId - 1 == ikeHeader.messageId) {
-
- if (ikeSaRecord.isRetransmittedRequest(ikePacketBytes)) {
- logd("Received re-transmitted request. Retransmitting response");
-
- for (byte[] packet : ikeSaRecord.getLastSentRespAllPackets()) {
- mIkeSocket.sendIkePacket(packet, mRemoteAddress);
- }
-
- // TODO:Support resetting remote rekey delete timer.
- } else {
- logi(methodTag + "Received response with invalid message ID. Discard it.");
- }
- } else {
- DecodeResult decodeResult =
- IkeMessage.decode(
- expectedMsgId,
- mIkeIntegrity,
- mIkeCipher,
- ikeSaRecord,
- ikeHeader,
- ikePacketBytes,
- ikeSaRecord.getCollectedFragments(false /*isResp*/));
- switch (decodeResult.status) {
- case DECODE_STATUS_OK:
- ikeSaRecord.incrementRemoteRequestMessageId();
- ikeSaRecord.resetCollectedFragments(false /*isResp*/);
-
- DecodeResultOk resultOk = (DecodeResultOk) decodeResult;
- IkeMessage ikeMessage = resultOk.ikeMessage;
- ikeSaRecord.updateLastReceivedReqFirstPacket(resultOk.firstPacket);
-
- // Handle DPD here.
- if (ikeMessage.isDpdRequest()) {
- logd(methodTag + "Received DPD request");
- IkeMessage dpdResponse =
- buildEncryptedInformationalMessage(
- ikeSaRecord,
- new IkeInformationalPayload[] {},
- true,
- ikeHeader.messageId);
- sendEncryptedIkeMessage(ikeSaRecord, dpdResponse);
- break;
- }
-
- int ikeExchangeSubType = getIkeExchangeSubType(ikeMessage);
- logd(
- methodTag
- + "Request exchange subtype: "
- + EXCHANGE_SUBTYPE_TO_STRING.get(ikeExchangeSubType));
-
- if (ikeExchangeSubType == IKE_EXCHANGE_SUBTYPE_INVALID
- || ikeExchangeSubType == IKE_EXCHANGE_SUBTYPE_IKE_INIT
- || ikeExchangeSubType == IKE_EXCHANGE_SUBTYPE_IKE_AUTH) {
-
- // Reply with INVALID_SYNTAX and close IKE Session.
- buildAndSendErrorNotificationResponse(
- mCurrentIkeSaRecord,
- ikeHeader.messageId,
- ERROR_TYPE_INVALID_SYNTAX);
- handleIkeFatalError(
- new InvalidSyntaxException(
- "Cannot handle message with invalid or unexpected"
- + " IkeExchangeSubType: "
- + ikeExchangeSubType));
- return;
- }
- handleRequestIkeMessage(ikeMessage, ikeExchangeSubType, message);
- break;
- case DECODE_STATUS_PARTIAL:
- ikeSaRecord.updateCollectedFragments(
- (DecodeResultPartial) decodeResult, false /*isResp*/);
- break;
- case DECODE_STATUS_PROTECTED_ERROR:
- DecodeResultProtectedError resultError =
- (DecodeResultProtectedError) decodeResult;
-
- IkeException ikeException = resultError.ikeException;
- logi(methodTag + "Protected error", resultError.ikeException);
-
- ikeSaRecord.incrementRemoteRequestMessageId();
- ikeSaRecord.resetCollectedFragments(false /*isResp*/);
-
- ikeSaRecord.updateLastReceivedReqFirstPacket(resultError.firstPacket);
-
- // IkeException MUST be already wrapped into an IkeProtocolException
- handleRequestGenericProcessError(
- ikeSaRecord,
- ikeHeader.messageId,
- (IkeProtocolException) ikeException);
- break;
- case DECODE_STATUS_UNPROTECTED_ERROR:
- logi(
- methodTag
- + "Message authentication or decryption failed on"
- + " received request. Discard it",
- ((DecodeResultError) decodeResult).ikeException);
- break;
- default:
- cleanUpAndQuit(
- new IllegalStateException(
- "Unrecognized decoding status: "
- + decodeResult.status));
- }
- }
- }
- }
-
- private boolean isTempFailure(IkeMessage message) {
- List<IkeNotifyPayload> notifyPayloads =
- message.getPayloadListForType(PAYLOAD_TYPE_NOTIFY, IkeNotifyPayload.class);
-
- for (IkeNotifyPayload notify : notifyPayloads) {
- if (notify.notifyType == ERROR_TYPE_TEMPORARY_FAILURE) {
- return true;
- }
- }
- return false;
- }
-
- protected void handleTempFailure() {
- // Log and close IKE Session due to unexpected TEMPORARY_FAILURE. This error should
- // only occur during CREATE_CHILD_SA exchange.
- handleIkeFatalError(
- new InvalidSyntaxException("Received unexpected TEMPORARY_FAILURE"));
-
- // States that accept a TEMPORARY MUST override this method to schedule a retry.
- }
-
- protected void handleRequestIkeMessage(
- IkeMessage ikeMessage, int ikeExchangeSubType, Message message) {
- // Subclasses MUST override it if they care
- cleanUpAndQuit(
- new IllegalStateException(
- "Do not support handling an encrypted request: " + ikeExchangeSubType));
- }
-
- protected void handleResponseIkeMessage(IkeMessage ikeMessage) {
- // Subclasses MUST override it if they care
- cleanUpAndQuit(
- new IllegalStateException("Do not support handling an encrypted response"));
- }
-
- /**
- * Method for handling generic processing error of a request.
- *
- * <p>A generic processing error is usally syntax error, unsupported critical payload error
- * and major version error. IKE SA that should reply with corresponding error notifications
- */
- protected void handleRequestGenericProcessError(
- IkeSaRecord ikeSaRecord, int messageId, IkeProtocolException exception) {
- IkeNotifyPayload errNotify = exception.buildNotifyPayload();
- sendEncryptedIkeMessage(
- ikeSaRecord,
- buildEncryptedInformationalMessage(
- ikeSaRecord,
- new IkeInformationalPayload[] {errNotify},
- true /*isResponse*/,
- messageId));
-
- // Receiver of INVALID_SYNTAX error notification should delete the IKE SA
- if (exception.getErrorType() == ERROR_TYPE_INVALID_SYNTAX) {
- handleIkeFatalError(exception);
- }
- }
-
- /**
- * Method for handling generic processing error of a response.
- *
- * <p>Detailed error is wrapped in the InvalidSyntaxException, which is usally syntax error,
- * unsupported critical payload error and major version error. IKE SA that receives a
- * response with these errors should be closed.
- */
- protected void handleResponseGenericProcessError(
- IkeSaRecord ikeSaRecord, InvalidSyntaxException ikeException) {
- // Subclasses MUST override it if they care
- cleanUpAndQuit(
- new IllegalStateException(
- "Do not support handling generic processing error of encrypted"
- + " response"));
- }
- }
-
- /**
- * Retransmitter represents a RAII class to send the initial request, and retransmit as needed.
- *
- * <p>The Retransmitter class will automatically start transmission upon creation.
- */
- @VisibleForTesting
- class EncryptedRetransmitter extends Retransmitter {
- private final IkeSaRecord mIkeSaRecord;
-
- @VisibleForTesting
- EncryptedRetransmitter(IkeMessage msg) {
- this(mCurrentIkeSaRecord, msg);
- }
-
- private EncryptedRetransmitter(IkeSaRecord ikeSaRecord, IkeMessage msg) {
- super(getHandler(), msg);
-
- mIkeSaRecord = ikeSaRecord;
-
- retransmit();
- }
-
- @Override
- public void send(IkeMessage msg) {
- sendEncryptedIkeMessage(mIkeSaRecord, msg);
- }
-
- @Override
- public void handleRetransmissionFailure() {
- handleIkeFatalError(new IOException("Retransmitting failure"));
- }
- }
-
- /**
- * DeleteResponderBase represents all states after IKE_INIT and IKE_AUTH.
- *
- * <p>All post-init states share common functionality of being able to respond to IKE_DELETE
- * requests.
- */
- private abstract class DeleteResponderBase extends BusyState {
- /** Builds a IKE Delete Response for the given IKE SA and request. */
- protected IkeMessage buildIkeDeleteResp(IkeMessage req, IkeSaRecord ikeSaRecord) {
- IkeInformationalPayload[] payloads = new IkeInformationalPayload[] {};
- return buildEncryptedInformationalMessage(
- ikeSaRecord, payloads, true /* isResp */, req.ikeHeader.messageId);
- }
-
- /**
- * Validates that the delete request is acceptable.
- *
- * <p>The request message must be guaranteed by previous checks to be of SUBTYPE_DELETE_IKE,
- * and therefore contains an IkeDeletePayload. This is checked in getIkeExchangeSubType.
- */
- protected void validateIkeDeleteReq(IkeMessage req, IkeSaRecord expectedRecord)
- throws InvalidSyntaxException {
- if (expectedRecord != getIkeSaRecordForPacket(req.ikeHeader)) {
- throw new InvalidSyntaxException("Delete request received in wrong SA");
- }
- }
-
- /**
- * Helper method for responding to a session deletion request
- *
- * <p>Note that this method expects that the session is keyed on the current IKE SA session,
- * and closing the IKE SA indicates that the remote wishes to end the session as a whole. As
- * such, this should not be used in rekey cases where there is any ambiguity as to which IKE
- * SA the session is reliant upon.
- *
- * <p>Note that this method will also quit the state machine.
- *
- * @param ikeMessage The received session deletion request
- */
- protected void handleDeleteSessionRequest(IkeMessage ikeMessage) {
- try {
- validateIkeDeleteReq(ikeMessage, mCurrentIkeSaRecord);
- IkeMessage resp = buildIkeDeleteResp(ikeMessage, mCurrentIkeSaRecord);
-
- mUserCbExecutor.execute(
- () -> {
- mIkeSessionCallback.onClosed();
- });
-
- sendEncryptedIkeMessage(mCurrentIkeSaRecord, resp);
-
- removeIkeSaRecord(mCurrentIkeSaRecord);
- mCurrentIkeSaRecord.close();
- mCurrentIkeSaRecord = null;
-
- quitNow();
- } catch (InvalidSyntaxException e) {
- // Got deletion of a non-Current IKE SA. Program error.
- cleanUpAndQuit(new IllegalStateException(e));
- }
- }
- }
-
- /**
- * DeleteBase abstracts deletion handling for all states initiating a delete exchange
- *
- * <p>All subclasses of this state share common functionality that a deletion request is sent,
- * and the response is received.
- */
- private abstract class DeleteBase extends DeleteResponderBase {
- /** Builds a IKE Delete Request for the given IKE SA. */
- protected IkeMessage buildIkeDeleteReq(IkeSaRecord ikeSaRecord) {
- IkeInformationalPayload[] payloads =
- new IkeInformationalPayload[] {new IkeDeletePayload()};
- return buildEncryptedInformationalMessage(
- ikeSaRecord,
- payloads,
- false /* isResp */,
- ikeSaRecord.getLocalRequestMessageId());
- }
-
- protected void validateIkeDeleteResp(IkeMessage resp, IkeSaRecord expectedSaRecord)
- throws InvalidSyntaxException {
- if (expectedSaRecord != getIkeSaRecordForPacket(resp.ikeHeader)) {
- throw new IllegalStateException("Response received on incorrect SA");
- }
-
- if (resp.ikeHeader.exchangeType != IkeHeader.EXCHANGE_TYPE_INFORMATIONAL) {
- throw new InvalidSyntaxException(
- "Invalid exchange type; expected INFORMATIONAL, but got: "
- + resp.ikeHeader.exchangeType);
- }
-
- if (!resp.ikePayloadList.isEmpty()) {
- throw new InvalidSyntaxException(
- "Unexpected payloads - IKE Delete response should be empty.");
- }
- }
- }
-
- /**
- * Receiving represents a state when idle IkeSessionStateMachine receives an incoming packet.
- *
- * <p>If this incoming packet is fully handled by Receiving state and does not trigger any
- * further state transition or deletion of whole IKE Session, IkeSessionStateMachine MUST
- * transition back to Idle.
- */
- class Receiving extends RekeyIkeHandlerBase {
- private boolean mProcedureFinished = true;
-
- @Override
- public void enterState() {
- mProcedureFinished = true;
- }
-
- @Override
- protected void handleReceivedIkePacket(Message message) {
- super.handleReceivedIkePacket(message);
-
- // If the received packet does not trigger a state transition or the packet causes this
- // state machine to quit, transition back to Idle State. In the second case, state
- // machine will first go back to Idle and then quit.
- if (mProcedureFinished) transitionTo(mIdle);
- }
-
- @Override
- protected void handleRequestIkeMessage(
- IkeMessage ikeMessage, int ikeExchangeSubType, Message message) {
- switch (ikeExchangeSubType) {
- case IKE_EXCHANGE_SUBTYPE_REKEY_IKE:
- // Errors in this exchange with no specific protocol error code will all be
- // classified to use NO_PROPOSAL_CHOSEN. The reason that we don't use
- // NO_ADDITIONAL_SAS is because it indicates "responder is unwilling to accept
- // any more Child SAs on this IKE SA.", according to RFC 7296. Sending this
- // error may mislead the remote peer.
- try {
- validateIkeRekeyReq(ikeMessage);
-
- // TODO: Add support for limited re-negotiation of parameters
-
- // Build a rekey response payload with our previously selected proposal,
- // against which we will validate the received proposals.
- IkeSaPayload reqSaPayload =
- ikeMessage.getPayloadForType(
- IkePayload.PAYLOAD_TYPE_SA, IkeSaPayload.class);
- byte respProposalNumber =
- reqSaPayload.getNegotiatedProposalNumber(mSaProposal);
-
- List<IkePayload> payloadList =
- CreateIkeSaHelper.getRekeyIkeSaResponsePayloads(
- respProposalNumber, mSaProposal, mLocalAddress);
-
- // Build IKE header
- IkeHeader ikeHeader =
- new IkeHeader(
- mCurrentIkeSaRecord.getInitiatorSpi(),
- mCurrentIkeSaRecord.getResponderSpi(),
- IkePayload.PAYLOAD_TYPE_SK,
- IkeHeader.EXCHANGE_TYPE_CREATE_CHILD_SA,
- true /*isResponseMsg*/,
- mCurrentIkeSaRecord.isLocalInit,
- ikeMessage.ikeHeader.messageId);
-
- IkeMessage responseIkeMessage = new IkeMessage(ikeHeader, payloadList);
-
- // Build new SA first to ensure that we can find a valid proposal.
- mRemoteInitNewIkeSaRecord =
- validateAndBuildIkeSa(
- ikeMessage, responseIkeMessage, false /*isLocalInit*/);
-
- sendEncryptedIkeMessage(responseIkeMessage);
-
- transitionTo(mRekeyIkeRemoteDelete);
- mProcedureFinished = false;
- } catch (IkeProtocolException e) {
- handleRekeyCreationFailure(ikeMessage.ikeHeader.messageId, e);
- } catch (GeneralSecurityException e) {
- handleRekeyCreationFailure(
- ikeMessage.ikeHeader.messageId,
- new NoValidProposalChosenException(
- "Error in building new IKE SA", e));
- } catch (IOException e) {
- handleRekeyCreationFailure(
- ikeMessage.ikeHeader.messageId,
- new NoValidProposalChosenException(
- "IKE SPI allocation collided - they reused an SPI.", e));
- }
- return;
- case IKE_EXCHANGE_SUBTYPE_DELETE_IKE:
- handleDeleteSessionRequest(ikeMessage);
- return;
- case IKE_EXCHANGE_SUBTYPE_CREATE_CHILD: // Fall through
- case IKE_EXCHANGE_SUBTYPE_DELETE_CHILD: // Fall through
- case IKE_EXCHANGE_SUBTYPE_REKEY_CHILD:
- deferMessage(
- obtainMessage(
- CMD_RECEIVE_REQUEST_FOR_CHILD,
- ikeExchangeSubType,
- 0 /*placeHolder*/,
- ikeMessage));
- transitionTo(mChildProcedureOngoing);
- mProcedureFinished = false;
- return;
- default:
- // TODO: Add support for generic INFORMATIONAL request
- }
- }
-
- private void handleRekeyCreationFailure(int messageId, IkeProtocolException e) {
- loge("Received invalid Rekey IKE request. Reject with error notification", e);
-
- buildAndSendNotificationResponse(
- mCurrentIkeSaRecord, messageId, e.buildNotifyPayload());
- }
- }
-
- /**
- * This class represents a state when there is at least one ongoing Child procedure
- * (Create/Rekey/Delete Child)
- *
- * <p>For a locally initiated Child procedure, this state is responsible for notifying Child
- * Session to initiate the exchange, building outbound request IkeMessage with Child Session
- * provided payload list and redirecting the inbound response to Child Session for validation.
- *
- * <p>For a remotely initiated Child procedure, this state is responsible for redirecting the
- * inbound request to Child Session(s) and building outbound response IkeMessage with Child
- * Session provided payload list. Exchange collision on a Child Session will be resolved inside
- * the Child Session.
- *
- * <p>For a remotely initiated IKE procedure, this state will only accept a Delete IKE request
- * and reject other types with TEMPORARY_FAILURE, since it causes conflict with the ongoing
- * Child procedure.
- *
- * <p>For most inbound request/response, this state will first pick out and handle IKE related
- * payloads and then send the rest of the payloads to Child Session for further validation. It
- * is the Child Session's responsibility to check required payloads (and verify the exchange
- * type) according to its procedure type. Only when receiving an inbound delete Child request,
- * as the only case where multiple Child Sessions will be affected by one IkeMessage, this state
- * will only send Delete Payload(s) to Child Session.
- */
- class ChildProcedureOngoing extends DeleteBase {
- // It is possible that mChildInLocalProcedure is also in mChildInRemoteProcedures when both
- // sides initiated exchange for the same Child Session.
- private ChildSessionStateMachine mChildInLocalProcedure;
- private Set<ChildSessionStateMachine> mChildInRemoteProcedures;
-
- private ChildLocalRequest mLocalRequestOngoing;
-
- private int mLastInboundRequestMsgId;
- private List<IkePayload> mOutboundRespPayloads;
- private Set<ChildSessionStateMachine> mAwaitingChildResponse;
-
- private EncryptedRetransmitter mRetransmitter;
-
- @Override
- public void enterState() {
- mChildInLocalProcedure = null;
- mChildInRemoteProcedures = new HashSet<>();
-
- mLocalRequestOngoing = null;
-
- mLastInboundRequestMsgId = 0;
- mOutboundRespPayloads = new LinkedList<>();
- mAwaitingChildResponse = new HashSet<>();
- }
-
- @Override
- protected void triggerRetransmit() {
- mRetransmitter.retransmit();
- }
-
- @Override
- public boolean processStateMessage(Message message) {
- switch (message.what) {
- case CMD_RECEIVE_REQUEST_FOR_CHILD:
- // Handle remote request (and do state transition)
- handleRequestIkeMessage(
- (IkeMessage) message.obj,
- message.arg1 /*ikeExchangeSubType*/,
- null /*ReceivedIkePacket*/);
- return HANDLED;
- case CMD_OUTBOUND_CHILD_PAYLOADS_READY:
- ChildOutboundData outboundData = (ChildOutboundData) message.obj;
- int exchangeType = outboundData.exchangeType;
- List<IkePayload> outboundPayloads = outboundData.payloadList;
-
- if (outboundData.isResp) {
- handleOutboundResponse(
- exchangeType, outboundPayloads, outboundData.childSession);
- } else {
- handleOutboundRequest(exchangeType, outboundPayloads);
- }
-
- return HANDLED;
- case CMD_CHILD_PROCEDURE_FINISHED:
- ChildSessionStateMachine childSession = (ChildSessionStateMachine) message.obj;
-
- if (mChildInLocalProcedure == childSession) {
- mChildInLocalProcedure = null;
- mLocalRequestOngoing = null;
- }
- mChildInRemoteProcedures.remove(childSession);
-
- transitionToIdleIfAllProceduresDone();
- return HANDLED;
- case CMD_HANDLE_FIRST_CHILD_NEGOTIATION:
- FirstChildNegotiationData childData = (FirstChildNegotiationData) message.obj;
-
- mChildInLocalProcedure = getChildSession(childData.childSessionCallback);
- if (mChildInLocalProcedure == null) {
- cleanUpAndQuit(new IllegalStateException("First child not found."));
- return HANDLED;
- }
-
- mChildInLocalProcedure.handleFirstChildExchange(
- childData.reqPayloads,
- childData.respPayloads,
- mLocalAddress,
- mRemoteAddress,
- getEncapSocketIfNeeded(),
- mIkePrf,
- mCurrentIkeSaRecord.getSkD());
- return HANDLED;
- case CMD_EXECUTE_LOCAL_REQ:
- executeLocalRequest((ChildLocalRequest) message.obj);
- return HANDLED;
- default:
- return super.processStateMessage(message);
- }
- }
-
- @Override
- protected void handleTempFailure() {
- mTempFailHandler.handleTempFailure(mLocalRequestOngoing);
- }
-
- private void transitionToIdleIfAllProceduresDone() {
- if (mChildInLocalProcedure == null && mChildInRemoteProcedures.isEmpty()) {
- transitionTo(mIdle);
- }
- }
-
- private ChildSessionStateMachine getChildSession(ChildSessionCallback callbacks) {
- synchronized (mChildCbToSessions) {
- return mChildCbToSessions.get(callbacks);
- }
- }
-
- private UdpEncapsulationSocket getEncapSocketIfNeeded() {
- boolean isNatDetected = mIsLocalBehindNat || mIsRemoteBehindNat;
-
- return (isNatDetected ? mIkeSessionOptions.getUdpEncapsulationSocket() : null);
- }
-
- private void executeLocalRequest(ChildLocalRequest req) {
- mChildInLocalProcedure = getChildSession(req.childSessionCallback);
- mLocalRequestOngoing = req;
-
- if (mChildInLocalProcedure == null) {
- // This request has been validated to have a recognized target Child Session when
- // it was sent to IKE Session at the begginnig. Failing to find this Child Session
- // now means the Child creation has failed.
- logd(
- "Child state machine not found for local request: "
- + req.procedureType
- + " Creation of Child Session may have been failed.");
-
- transitionToIdleIfAllProceduresDone();
- return;
- }
- switch (req.procedureType) {
- case CMD_LOCAL_REQUEST_CREATE_CHILD:
- mChildInLocalProcedure.createChildSession(
- mLocalAddress,
- mRemoteAddress,
- getEncapSocketIfNeeded(),
- mIkePrf,
- mCurrentIkeSaRecord.getSkD());
- break;
- case CMD_LOCAL_REQUEST_REKEY_CHILD:
- mChildInLocalProcedure.rekeyChildSession();
- break;
- case CMD_LOCAL_REQUEST_DELETE_CHILD:
- mChildInLocalProcedure.deleteChildSession();
- break;
- default:
- cleanUpAndQuit(
- new IllegalStateException(
- "Invalid Child procedure type: " + req.procedureType));
- break;
- }
- }
-
- /**
- * This method is called when this state receives an inbound request or when mReceiving
- * received an inbound Child request and deferred it to this state.
- */
- @Override
- protected void handleRequestIkeMessage(
- IkeMessage ikeMessage, int ikeExchangeSubType, Message message) {
- // TODO: Grab a remote lock and hand payloads to the Child Session
-
- mLastInboundRequestMsgId = ikeMessage.ikeHeader.messageId;
- switch (ikeExchangeSubType) {
- case IKE_EXCHANGE_SUBTYPE_CREATE_CHILD:
- buildAndSendErrorNotificationResponse(
- mCurrentIkeSaRecord,
- ikeMessage.ikeHeader.messageId,
- ERROR_TYPE_NO_ADDITIONAL_SAS);
- break;
- case IKE_EXCHANGE_SUBTYPE_DELETE_IKE:
- // Send response and quit state machine
- handleDeleteSessionRequest(ikeMessage);
-
- // Return immediately to avoid transitioning to mIdle
- return;
- case IKE_EXCHANGE_SUBTYPE_DELETE_CHILD:
- handleInboundDeleteChildRequest(ikeMessage);
- break;
- case IKE_EXCHANGE_SUBTYPE_REKEY_IKE:
- buildAndSendErrorNotificationResponse(
- mCurrentIkeSaRecord,
- ikeMessage.ikeHeader.messageId,
- ERROR_TYPE_TEMPORARY_FAILURE);
- break;
- case IKE_EXCHANGE_SUBTYPE_REKEY_CHILD:
- handleInboundRekeyChildRequest(ikeMessage);
- break;
- case IKE_EXCHANGE_SUBTYPE_GENERIC_INFO:
- // TODO:b/139943757 Handle general informational request
- default:
- cleanUpAndQuit(
- new IllegalStateException(
- "Invalid IKE exchange subtype: " + ikeExchangeSubType));
- return;
- }
- transitionToIdleIfAllProceduresDone();
- }
-
- @Override
- protected void handleResponseIkeMessage(IkeMessage ikeMessage) {
- mRetransmitter.stopRetransmitting();
-
- List<IkePayload> handledPayloads = new LinkedList<>();
-
- for (IkePayload payload : ikeMessage.ikePayloadList) {
- switch (payload.payloadType) {
- case PAYLOAD_TYPE_NOTIFY:
- // TODO: Handle fatal IKE error notification and IKE status notification.
- break;
- case PAYLOAD_TYPE_VENDOR:
- // TODO: Handle Vendor ID Payload
- handledPayloads.add(payload);
- break;
- case PAYLOAD_TYPE_CP:
- // TODO: Handle IKE related configuration attributes and pass the payload to
- // Child to further handle internal IP address attributes.
- break;
- default:
- break;
- }
- }
-
- List<IkePayload> payloads = new LinkedList<>();
- payloads.addAll(ikeMessage.ikePayloadList);
- payloads.removeAll(handledPayloads);
-
- mChildInLocalProcedure.receiveResponse(ikeMessage.ikeHeader.exchangeType, payloads);
- }
-
- @Override
- protected void handleResponseGenericProcessError(
- IkeSaRecord ikeSaRecord, InvalidSyntaxException ikeException) {
- mRetransmitter.stopRetransmitting();
-
- sendEncryptedIkeMessage(buildIkeDeleteReq(mCurrentIkeSaRecord));
- handleIkeFatalError(ikeException);
- }
-
- private void handleInboundDeleteChildRequest(IkeMessage ikeMessage) {
- // It is guaranteed in #getIkeExchangeSubType that at least one Delete Child Payload
- // exists.
-
- HashMap<ChildSessionStateMachine, List<IkePayload>> childToDelPayloadsMap =
- new HashMap<>();
- Set<Integer> spiHandled = new HashSet<>();
-
- for (IkePayload payload : ikeMessage.ikePayloadList) {
- switch (payload.payloadType) {
- case PAYLOAD_TYPE_VENDOR:
- // TODO: Investigate if Vendor ID Payload can be in an INFORMATIONAL
- // message.
- break;
- case PAYLOAD_TYPE_NOTIFY:
- logw(
- "Unexpected or unknown notification: "
- + ((IkeNotifyPayload) payload).notifyType);
- break;
- case PAYLOAD_TYPE_DELETE:
- IkeDeletePayload delPayload = (IkeDeletePayload) payload;
-
- for (int spi : delPayload.spisToDelete) {
- ChildSessionStateMachine child = mRemoteSpiToChildSessionMap.get(spi);
- if (child == null) {
- // TODO: Investigate how other implementations handle that.
- logw("Child SA not found with received SPI: " + spi);
- } else if (!spiHandled.add(spi)) {
- logw("Received repeated Child SPI: " + spi);
- } else {
- // Store Delete Payload with its target ChildSession
- if (!childToDelPayloadsMap.containsKey(child)) {
- childToDelPayloadsMap.put(child, new LinkedList<>());
- }
- List<IkePayload> delPayloads = childToDelPayloadsMap.get(child);
-
- // Avoid storing repeated Delete Payload
- if (!delPayloads.contains(delPayload)) delPayloads.add(delPayload);
- }
- }
-
- break;
- case PAYLOAD_TYPE_CP:
- // TODO: Handle it
- break;
- default:
- logw("Unexpected payload types found: " + payload.payloadType);
- }
- }
-
- // If no Child SA is found, only reply with IKE related payloads or an empty
- // message
- if (childToDelPayloadsMap.isEmpty()) {
- logd("No Child SA is found for this request.");
- sendEncryptedIkeMessage(
- buildEncryptedInformationalMessage(
- new IkeInformationalPayload[0],
- true /*isResp*/,
- ikeMessage.ikeHeader.messageId));
- return;
- }
-
- // Send Delete Payloads to Child Sessions
- for (ChildSessionStateMachine child : childToDelPayloadsMap.keySet()) {
- child.receiveRequest(
- IKE_EXCHANGE_SUBTYPE_DELETE_CHILD,
- EXCHANGE_TYPE_INFORMATIONAL,
- childToDelPayloadsMap.get(child));
- mAwaitingChildResponse.add(child);
- mChildInRemoteProcedures.add(child);
- }
- }
-
- private void handleInboundRekeyChildRequest(IkeMessage ikeMessage) {
- // It is guaranteed in #getIkeExchangeSubType that at least one Notify-Rekey Child
- // Payload exists.
- List<IkePayload> handledPayloads = new LinkedList<>();
- ChildSessionStateMachine targetChild = null;
- Set<Integer> unrecognizedSpis = new HashSet<>();
-
- for (IkePayload payload : ikeMessage.ikePayloadList) {
- switch (payload.payloadType) {
- case PAYLOAD_TYPE_VENDOR:
- // TODO: Handle it.
- handledPayloads.add(payload);
- break;
- case PAYLOAD_TYPE_NOTIFY:
- IkeNotifyPayload notifyPayload = (IkeNotifyPayload) payload;
- if (NOTIFY_TYPE_REKEY_SA != notifyPayload.notifyType) break;
-
- int childSpi = notifyPayload.spi;
- ChildSessionStateMachine child = mRemoteSpiToChildSessionMap.get(childSpi);
-
- if (child == null) {
- // Remember unrecognized SPIs and reply error notification if no
- // recognized SPI found.
- unrecognizedSpis.add(childSpi);
- logw("Child SA not found with received SPI: " + childSpi);
- } else if (targetChild == null) {
- // Each message should have only one Notify-Rekey Payload. If there are
- // multiple of them, we only process the first valid one and ignore
- // others.
- targetChild = mRemoteSpiToChildSessionMap.get(childSpi);
- } else {
- logw("More than one Notify-Rekey Payload found with SPI: " + childSpi);
- handledPayloads.add(notifyPayload);
- }
- break;
- case PAYLOAD_TYPE_CP:
- // TODO: Handle IKE related configuration attributes and pass the payload to
- // Child to further handle internal IP address attributes.
- break;
- default:
- break;
- }
- }
-
- // Reject request with error notification.
- if (targetChild == null) {
- IkeInformationalPayload[] errorPayloads =
- new IkeInformationalPayload[unrecognizedSpis.size()];
- int i = 0;
- for (Integer spi : unrecognizedSpis) {
- errorPayloads[i++] =
- new IkeNotifyPayload(
- IkePayload.PROTOCOL_ID_ESP,
- spi,
- ERROR_TYPE_CHILD_SA_NOT_FOUND,
- new byte[0]);
- }
-
- IkeMessage msg =
- buildEncryptedNotificationMessage(
- mCurrentIkeSaRecord,
- errorPayloads,
- EXCHANGE_TYPE_INFORMATIONAL,
- true /*isResponse*/,
- ikeMessage.ikeHeader.messageId);
-
- sendEncryptedIkeMessage(mCurrentIkeSaRecord, msg);
- return;
- }
-
- // Normal path
- List<IkePayload> payloads = new LinkedList<>();
- payloads.addAll(ikeMessage.ikePayloadList);
- payloads.removeAll(handledPayloads);
-
- mAwaitingChildResponse.add(targetChild);
- mChildInRemoteProcedures.add(targetChild);
-
- targetChild.receiveRequest(
- IKE_EXCHANGE_SUBTYPE_REKEY_CHILD, ikeMessage.ikeHeader.exchangeType, payloads);
- }
-
- private void handleOutboundRequest(int exchangeType, List<IkePayload> outboundPayloads) {
- IkeHeader ikeHeader =
- new IkeHeader(
- mCurrentIkeSaRecord.getInitiatorSpi(),
- mCurrentIkeSaRecord.getResponderSpi(),
- IkePayload.PAYLOAD_TYPE_SK,
- exchangeType,
- false /*isResp*/,
- mCurrentIkeSaRecord.isLocalInit,
- mCurrentIkeSaRecord.getLocalRequestMessageId());
- IkeMessage ikeMessage = new IkeMessage(ikeHeader, outboundPayloads);
-
- mRetransmitter = new EncryptedRetransmitter(ikeMessage);
- }
-
- private void handleOutboundResponse(
- int exchangeType,
- List<IkePayload> outboundPayloads,
- ChildSessionStateMachine childSession) {
- // For each request IKE passed to Child, Child will send back to IKE a response. Even
- // if the Child Sesison is under simultaneous deletion, it will send back an empty
- // payload list.
- mOutboundRespPayloads.addAll(outboundPayloads);
- mAwaitingChildResponse.remove(childSession);
- if (!mAwaitingChildResponse.isEmpty()) return;
-
- IkeHeader ikeHeader =
- new IkeHeader(
- mCurrentIkeSaRecord.getInitiatorSpi(),
- mCurrentIkeSaRecord.getResponderSpi(),
- IkePayload.PAYLOAD_TYPE_SK,
- exchangeType,
- true /*isResp*/,
- mCurrentIkeSaRecord.isLocalInit,
- mLastInboundRequestMsgId);
- IkeMessage ikeMessage = new IkeMessage(ikeHeader, mOutboundRespPayloads);
- sendEncryptedIkeMessage(ikeMessage);
- }
- }
-
- /** CreateIkeLocalIkeInit represents state when IKE library initiates IKE_INIT exchange. */
- @VisibleForTesting
- public class CreateIkeLocalIkeInit extends BusyState {
- private IkeSecurityParameterIndex mLocalIkeSpiResource;
- private IkeSecurityParameterIndex mRemoteIkeSpiResource;
- private Retransmitter mRetransmitter;
-
- // TODO: Support negotiating IKE fragmentation
-
- @Override
- public void enterState() {
- try {
- IkeMessage request = buildIkeInitReq();
-
- // Register local SPI to receive the IKE INIT response.
- mIkeSocket.registerIke(
- request.ikeHeader.ikeInitiatorSpi, IkeSessionStateMachine.this);
-
- mIkeInitRequestBytes = request.encode();
- mIkeInitNoncePayload =
- request.getPayloadForType(
- IkePayload.PAYLOAD_TYPE_NONCE, IkeNoncePayload.class);
- mRetransmitter = new UnencryptedRetransmitter(request);
- } catch (IOException e) {
- // Fail to assign IKE SPI
- handleIkeFatalError(e);
- }
- }
-
- @Override
- protected void triggerRetransmit() {
- mRetransmitter.retransmit();
- }
-
- @Override
- public boolean processStateMessage(Message message) {
- switch (message.what) {
- case CMD_RECEIVE_IKE_PACKET:
- handleReceivedIkePacket(message);
- return HANDLED;
-
- default:
- return super.processStateMessage(message);
- }
- }
-
- protected void handleReceivedIkePacket(Message message) {
- String methodTag = "handleReceivedIkePacket: ";
-
- ReceivedIkePacket receivedIkePacket = (ReceivedIkePacket) message.obj;
- IkeHeader ikeHeader = receivedIkePacket.ikeHeader;
- byte[] ikePacketBytes = receivedIkePacket.ikePacketBytes;
-
- logd(
- methodTag
- + "Received an "
- + ikeHeader.getBasicInfoString()
- + ". Packet size: "
- + ikePacketBytes.length);
-
- if (ikeHeader.isResponseMsg) {
- DecodeResult decodeResult = IkeMessage.decode(0, ikeHeader, ikePacketBytes);
-
- switch (decodeResult.status) {
- case DECODE_STATUS_OK:
- handleResponseIkeMessage(((DecodeResultOk) decodeResult).ikeMessage);
- mIkeInitResponseBytes = ikePacketBytes;
-
- // SA negotiation failed
- if (mCurrentIkeSaRecord == null) break;
-
- mCurrentIkeSaRecord.incrementLocalRequestMessageId();
- break;
- case DECODE_STATUS_PARTIAL:
- // Fall through. We don't support IKE fragmentation here. We should never
- // get this status.
- case DECODE_STATUS_PROTECTED_ERROR:
- // IKE INIT response is not protected. So we should never get this status
- cleanUpAndQuit(
- new IllegalStateException(
- "Unexpected decoding status: " + decodeResult.status));
- break;
- case DECODE_STATUS_UNPROTECTED_ERROR:
- logi(
- "Discard unencrypted response with syntax error",
- ((DecodeResultError) decodeResult).ikeException);
- break;
- default:
- cleanUpAndQuit(
- new IllegalStateException(
- "Invalid decoding status: " + decodeResult.status));
- }
-
- } else {
- // TODO: Also prettyprint IKE header in the log.
- logi("Received a request while waiting for IKE_INIT response. Discard it.");
- }
- }
-
- @Override
- protected void handleResponseIkeMessage(IkeMessage ikeMessage) {
- boolean ikeInitSuccess = false;
- try {
- validateIkeInitResp(mRetransmitter.getMessage(), ikeMessage);
-
- mCurrentIkeSaRecord =
- IkeSaRecord.makeFirstIkeSaRecord(
- mRetransmitter.getMessage(),
- ikeMessage,
- mLocalIkeSpiResource,
- mRemoteIkeSpiResource,
- mIkePrf,
- mIkeIntegrity == null ? 0 : mIkeIntegrity.getKeyLength(),
- mIkeCipher.getKeyLength(),
- new LocalRequest(CMD_LOCAL_REQUEST_REKEY_IKE));
-
- addIkeSaRecord(mCurrentIkeSaRecord);
- ikeInitSuccess = true;
-
- transitionTo(mCreateIkeLocalIkeAuth);
- } catch (IkeProtocolException | GeneralSecurityException | IOException e) {
- // TODO: Try another DH group to buld KE Payload if receiving InvalidKeException
- handleIkeFatalError(e);
- } finally {
- if (!ikeInitSuccess) {
- if (mLocalIkeSpiResource != null) {
- mLocalIkeSpiResource.close();
- mLocalIkeSpiResource = null;
- }
- if (mRemoteIkeSpiResource != null) {
- mRemoteIkeSpiResource.close();
- mRemoteIkeSpiResource = null;
- }
- }
- }
- }
-
- private IkeMessage buildIkeInitReq() throws IOException {
- // Generate IKE SPI
- mLocalIkeSpiResource =
- IkeSecurityParameterIndex.allocateSecurityParameterIndex(mLocalAddress);
- long initSpi = mLocalIkeSpiResource.getSpi();
- long respSpi = 0;
-
- // It is validated in IkeSessionOptions.Builder to ensure IkeSessionOptions has at least
- // one IkeSaProposal and all SaProposals are valid for IKE SA negotiation.
- IkeSaProposal[] saProposals = mIkeSessionOptions.getSaProposals();
- List<IkePayload> payloadList =
- CreateIkeSaHelper.getIkeInitSaRequestPayloads(
- saProposals,
- initSpi,
- respSpi,
- mLocalAddress,
- mRemoteAddress,
- mLocalPort,
- IkeSocket.IKE_SERVER_PORT);
- payloadList.add(
- new IkeNotifyPayload(
- IkeNotifyPayload.NOTIFY_TYPE_IKEV2_FRAGMENTATION_SUPPORTED));
-
- // TODO: Add Notification Payloads according to user configurations.
-
- // Build IKE header
- IkeHeader ikeHeader =
- new IkeHeader(
- initSpi,
- respSpi,
- IkePayload.PAYLOAD_TYPE_SA,
- IkeHeader.EXCHANGE_TYPE_IKE_SA_INIT,
- false /*isResponseMsg*/,
- true /*fromIkeInitiator*/,
- 0 /*messageId*/);
-
- return new IkeMessage(ikeHeader, payloadList);
- }
-
- private void validateIkeInitResp(IkeMessage reqMsg, IkeMessage respMsg)
- throws IkeProtocolException, IOException {
- IkeHeader respIkeHeader = respMsg.ikeHeader;
- mRemoteIkeSpiResource =
- IkeSecurityParameterIndex.allocateSecurityParameterIndex(
- mIkeSessionOptions.getServerAddress(), respIkeHeader.ikeResponderSpi);
-
- int exchangeType = respIkeHeader.exchangeType;
- if (exchangeType != IkeHeader.EXCHANGE_TYPE_IKE_SA_INIT) {
- throw new InvalidSyntaxException(
- "Expected EXCHANGE_TYPE_IKE_SA_INIT but received: " + exchangeType);
- }
-
- IkeSaPayload respSaPayload = null;
- IkeKePayload respKePayload = null;
-
- /**
- * There MAY be multiple NAT_DETECTION_SOURCE_IP payloads in a message if the sender
- * does not know which of several network attachments will be used to send the packet.
- */
- List<IkeNotifyPayload> natSourcePayloads = new LinkedList<>();
- IkeNotifyPayload natDestPayload = null;
-
- boolean hasNoncePayload = false;
-
- for (IkePayload payload : respMsg.ikePayloadList) {
- switch (payload.payloadType) {
- case IkePayload.PAYLOAD_TYPE_SA:
- respSaPayload = (IkeSaPayload) payload;
- break;
- case IkePayload.PAYLOAD_TYPE_KE:
- respKePayload = (IkeKePayload) payload;
- break;
- case IkePayload.PAYLOAD_TYPE_CERT_REQUEST:
- throw new UnsupportedOperationException(
- "Do not support handling Cert Request Payload.");
- // TODO: Handle it when using certificate based authentication. Otherwise,
- // ignore it.
- case IkePayload.PAYLOAD_TYPE_NONCE:
- hasNoncePayload = true;
- mIkeRespNoncePayload = (IkeNoncePayload) payload;
- break;
- case IkePayload.PAYLOAD_TYPE_VENDOR:
- // Do not support any vendor defined protocol extensions. Ignore
- // all Vendor ID Payloads.
- break;
- case IkePayload.PAYLOAD_TYPE_NOTIFY:
- IkeNotifyPayload notifyPayload = (IkeNotifyPayload) payload;
-
- if (notifyPayload.isErrorNotify()) {
- throw notifyPayload.validateAndBuildIkeException();
- }
-
- switch (notifyPayload.notifyType) {
- case NOTIFY_TYPE_NAT_DETECTION_SOURCE_IP:
- natSourcePayloads.add(notifyPayload);
- break;
- case NOTIFY_TYPE_NAT_DETECTION_DESTINATION_IP:
- if (natDestPayload != null) {
- throw new InvalidSyntaxException(
- "More than one"
- + " NOTIFY_TYPE_NAT_DETECTION_DESTINATION_IP"
- + " found");
- }
- natDestPayload = notifyPayload;
- break;
- case NOTIFY_TYPE_IKEV2_FRAGMENTATION_SUPPORTED:
- mSupportFragment = true;
- break;
- default:
- // Unknown and unexpected status notifications are ignored as per
- // RFC7296.
- logw(
- "Received unknown or unexpected status notifications with"
- + " notify type: "
- + notifyPayload.notifyType);
- }
-
- break;
- default:
- logw(
- "Received unexpected payload in IKE INIT response. Payload type: "
- + payload.payloadType);
- }
- }
-
- if (respSaPayload == null
- || respKePayload == null
- || natSourcePayloads.isEmpty()
- || natDestPayload == null
- || !hasNoncePayload) {
- throw new InvalidSyntaxException(
- "SA, KE, Nonce, Notify-NAT-Detection-Source, or"
- + " Notify-NAT-Detection-Destination payload missing.");
- }
-
- IkeSaPayload reqSaPayload =
- reqMsg.getPayloadForType(IkePayload.PAYLOAD_TYPE_SA, IkeSaPayload.class);
- mSaProposal =
- IkeSaPayload.getVerifiedNegotiatedIkeProposalPair(
- reqSaPayload, respSaPayload, mRemoteAddress)
- .second
- .saProposal;
-
- // Build IKE crypto tools using mSaProposal. It is ensured that mSaProposal is valid and
- // has exactly one Transform for each Transform type. Only exception is when
- // combined-mode cipher is used, there will be either no integrity algorithm or an
- // INTEGRITY_ALGORITHM_NONE type algorithm.
- Provider provider = IkeMessage.getSecurityProvider();
- mIkeCipher = IkeCipher.create(mSaProposal.getEncryptionTransforms()[0], provider);
- if (!mIkeCipher.isAead()) {
- mIkeIntegrity =
- IkeMacIntegrity.create(mSaProposal.getIntegrityTransforms()[0], provider);
- }
- mIkePrf = IkeMacPrf.create(mSaProposal.getPrfTransforms()[0], provider);
-
- IkeKePayload reqKePayload =
- reqMsg.getPayloadForType(IkePayload.PAYLOAD_TYPE_KE, IkeKePayload.class);
- if (reqKePayload.dhGroup != respKePayload.dhGroup
- && respKePayload.dhGroup != mSaProposal.getDhGroupTransforms()[0].id) {
- throw new InvalidSyntaxException("Received KE payload with mismatched DH group.");
- }
-
- // NAT detection
- long initIkeSpi = respMsg.ikeHeader.ikeInitiatorSpi;
- long respIkeSpi = respMsg.ikeHeader.ikeResponderSpi;
- mIsLocalBehindNat = true;
- mIsRemoteBehindNat = true;
-
- // Check if local node is behind NAT
- byte[] expectedLocalNatData =
- IkeNotifyPayload.generateNatDetectionData(
- initIkeSpi, respIkeSpi, mLocalAddress, mLocalPort);
- mIsLocalBehindNat = !Arrays.equals(expectedLocalNatData, natDestPayload.notifyData);
-
- // Check if the remote node is behind NAT
- byte[] expectedRemoteNatData =
- IkeNotifyPayload.generateNatDetectionData(
- initIkeSpi, respIkeSpi, mRemoteAddress, IkeSocket.IKE_SERVER_PORT);
- for (IkeNotifyPayload natPayload : natSourcePayloads) {
- // If none of the received hash matches the expected value, the remote node is
- // behind NAT.
- if (Arrays.equals(expectedRemoteNatData, natPayload.notifyData)) {
- mIsRemoteBehindNat = false;
- }
- }
- }
-
- @Override
- public void exitState() {
- super.exitState();
- mRetransmitter.stopRetransmitting();
- }
-
- private class UnencryptedRetransmitter extends Retransmitter {
- private UnencryptedRetransmitter(IkeMessage msg) {
- super(getHandler(), msg);
-
- retransmit();
- }
-
- @Override
- public void send(IkeMessage msg) {
- // Sends unencrypted
- mIkeSocket.sendIkePacket(msg.encode(), mRemoteAddress);
- }
-
- @Override
- public void handleRetransmissionFailure() {
- handleIkeFatalError(new IOException("Retransmitting IKE INIT request failure"));
- }
- }
- }
-
- /**
- * CreateIkeLocalIkeAuthBase represents the common state and functionality required to perform
- * IKE AUTH exchanges in both the EAP and non-EAP flows.
- */
- abstract class CreateIkeLocalIkeAuthBase extends DeleteBase {
- protected Retransmitter mRetransmitter;
-
- @Override
- protected void triggerRetransmit() {
- mRetransmitter.retransmit();
- }
-
- // TODO: b/139482382 If receiving a remote request while waiting for the last IKE AUTH
- // response, defer it to next state.
-
- protected IkeMessage buildIkeAuthReqMessage(List<IkePayload> payloadList) {
- // Build IKE header
- IkeHeader ikeHeader =
- new IkeHeader(
- mCurrentIkeSaRecord.getInitiatorSpi(),
- mCurrentIkeSaRecord.getResponderSpi(),
- IkePayload.PAYLOAD_TYPE_SK,
- IkeHeader.EXCHANGE_TYPE_IKE_AUTH,
- false /*isResponseMsg*/,
- true /*fromIkeInitiator*/,
- mCurrentIkeSaRecord.getLocalRequestMessageId());
-
- return new IkeMessage(ikeHeader, payloadList);
- }
-
- protected void authenticatePsk(
- byte[] psk, IkeAuthPayload authPayload, IkeIdPayload respIdPayload)
- throws AuthenticationFailedException {
- if (authPayload.authMethod != IkeAuthPayload.AUTH_METHOD_PRE_SHARED_KEY) {
- throw new AuthenticationFailedException(
- "Expected the remote/server to use PSK-based authentication but"
- + " they used: "
- + authPayload.authMethod);
- }
-
- IkeAuthPskPayload pskPayload = (IkeAuthPskPayload) authPayload;
- pskPayload.verifyInboundSignature(
- psk,
- mIkeInitResponseBytes,
- mCurrentIkeSaRecord.nonceInitiator,
- respIdPayload.getEncodedPayloadBody(),
- mIkePrf,
- mCurrentIkeSaRecord.getSkPr());
- }
-
- protected List<IkePayload> extractChildPayloadsFromMessage(IkeMessage ikeMessage)
- throws InvalidSyntaxException {
- IkeSaPayload saPayload =
- ikeMessage.getPayloadForType(IkePayload.PAYLOAD_TYPE_SA, IkeSaPayload.class);
- IkeTsPayload tsInitPayload =
- ikeMessage.getPayloadForType(
- IkePayload.PAYLOAD_TYPE_TS_INITIATOR, IkeTsPayload.class);
- IkeTsPayload tsRespPayload =
- ikeMessage.getPayloadForType(
- IkePayload.PAYLOAD_TYPE_TS_RESPONDER, IkeTsPayload.class);
-
- List<IkeNotifyPayload> notifyPayloads =
- ikeMessage.getPayloadListForType(
- IkePayload.PAYLOAD_TYPE_NOTIFY, IkeNotifyPayload.class);
-
- boolean hasErrorNotify = false;
- List<IkePayload> list = new LinkedList<>();
- for (IkeNotifyPayload payload : notifyPayloads) {
- if (payload.isNewChildSaNotify()) {
- list.add(payload);
- if (payload.isErrorNotify()) {
- hasErrorNotify = true;
- }
- }
- }
-
- // If there is no error notification, SA, TS-initiator and TS-responder MUST all be
- // included in this message.
- if (!hasErrorNotify
- && (saPayload == null || tsInitPayload == null || tsRespPayload == null)) {
- throw new InvalidSyntaxException(
- "SA, TS-Initiator or TS-Responder payload is missing.");
- }
-
- list.add(saPayload);
- list.add(tsInitPayload);
- list.add(tsRespPayload);
- return list;
- }
-
- protected void performFirstChildNegotiation(
- List<IkePayload> childReqList, List<IkePayload> childRespList) {
- childReqList.add(mIkeInitNoncePayload);
- childRespList.add(mIkeRespNoncePayload);
-
- deferMessage(
- obtainMessage(
- CMD_HANDLE_FIRST_CHILD_NEGOTIATION,
- new FirstChildNegotiationData(
- mFirstChildSessionOptions,
- mFirstChildCallbacks,
- childReqList,
- childRespList)));
-
- mUserCbExecutor.execute(
- () -> {
- mIkeSessionCallback.onOpened(null /*sessionConfiguration*/);
- // TODO: Construct and pass a real IkeSessionConfiguration
- });
- transitionTo(mChildProcedureOngoing);
- }
- }
-
- /**
- * CreateIkeLocalIkeAuth represents state when IKE library initiates IKE_AUTH exchange.
- *
- * <p>If using EAP, CreateIkeLocalIkeAuth will transition to CreateIkeLocalIkeAuthInEap state
- * after validating the IKE AUTH response.
- */
- class CreateIkeLocalIkeAuth extends CreateIkeLocalIkeAuthBase {
- private boolean mUseEap;
-
- @Override
- public void enterState() {
- try {
- super.enterState();
- mRetransmitter = new EncryptedRetransmitter(buildIkeAuthReq());
- mUseEap =
- (IkeSessionOptions.IKE_AUTH_METHOD_EAP
- == mIkeSessionOptions.getLocalAuthConfig().mAuthMethod);
- } catch (ResourceUnavailableException e) {
- // Handle IPsec SPI assigning failure.
- handleIkeFatalError(e);
- }
- }
-
- @Override
- protected void handleResponseIkeMessage(IkeMessage ikeMessage) {
- try {
- int exchangeType = ikeMessage.ikeHeader.exchangeType;
- if (exchangeType != IkeHeader.EXCHANGE_TYPE_IKE_AUTH) {
- throw new InvalidSyntaxException(
- "Expected EXCHANGE_TYPE_IKE_AUTH but received: " + exchangeType);
- }
-
- List<IkePayload> childReqList =
- extractChildPayloadsFromMessage(mRetransmitter.getMessage());
-
- if (mUseEap) {
- validateIkeAuthRespWithEapPayload(ikeMessage);
-
- // childReqList needed after EAP completed, so persist to IkeSessionStateMachine
- // state.
- mFirstChildReqList = childReqList;
-
- IkeEapPayload ikeEapPayload =
- ikeMessage.getPayloadForType(
- IkePayload.PAYLOAD_TYPE_EAP, IkeEapPayload.class);
-
- deferMessage(obtainMessage(CMD_EAP_START_EAP_AUTH, ikeEapPayload));
- transitionTo(mCreateIkeLocalIkeAuthInEap);
- } else {
- validateIkeAuthRespWithChildPayloads(ikeMessage);
-
- performFirstChildNegotiation(
- childReqList, extractChildPayloadsFromMessage(ikeMessage));
- }
- } catch (IkeProtocolException e) {
- if (!mUseEap) {
- // Notify the remote because they may have set up the IKE SA.
- sendEncryptedIkeMessage(buildIkeDeleteReq(mCurrentIkeSaRecord));
- }
- handleIkeFatalError(e);
- }
- }
-
- @Override
- protected void handleResponseGenericProcessError(
- IkeSaRecord ikeSaRecord, InvalidSyntaxException ikeException) {
- mRetransmitter.stopRetransmitting();
-
- if (!mUseEap) {
- // Notify the remote because they may have set up the IKE SA.
- sendEncryptedIkeMessage(buildIkeDeleteReq(mCurrentIkeSaRecord));
- }
- handleIkeFatalError(ikeException);
- }
-
- private IkeMessage buildIkeAuthReq() throws ResourceUnavailableException {
- List<IkePayload> payloadList = new LinkedList<>();
-
- // Build Identification payloads
- mInitIdPayload =
- new IkeIdPayload(
- true /*isInitiator*/, mIkeSessionOptions.getLocalIdentification());
- IkeIdPayload respIdPayload =
- new IkeIdPayload(
- false /*isInitiator*/, mIkeSessionOptions.getRemoteIdentification());
- payloadList.add(mInitIdPayload);
- payloadList.add(respIdPayload);
-
- // Build Authentication payload
- IkeAuthConfig authConfig = mIkeSessionOptions.getLocalAuthConfig();
- switch (authConfig.mAuthMethod) {
- case IkeSessionOptions.IKE_AUTH_METHOD_PSK:
- IkeAuthPskPayload pskPayload =
- new IkeAuthPskPayload(
- ((IkeAuthPskConfig) authConfig).mPsk,
- mIkeInitRequestBytes,
- mCurrentIkeSaRecord.nonceResponder,
- mInitIdPayload.getEncodedPayloadBody(),
- mIkePrf,
- mCurrentIkeSaRecord.getSkPi());
- payloadList.add(pskPayload);
- break;
- case IkeSessionOptions.IKE_AUTH_METHOD_PUB_KEY_SIGNATURE:
- // TODO: Support authentication based on public key signature.
- throw new UnsupportedOperationException(
- "Do not support public-key based authentication.");
- case IkeSessionOptions.IKE_AUTH_METHOD_EAP:
- // Do not include AUTH payload when using EAP.
- break;
- default:
- cleanUpAndQuit(
- new IllegalArgumentException(
- "Unrecognized authentication method: "
- + authConfig.mAuthMethod));
- }
-
- payloadList.addAll(
- CreateChildSaHelper.getInitChildCreateReqPayloads(
- mIpSecManager,
- mLocalAddress,
- mFirstChildSessionOptions,
- true /*isFirstChild*/));
-
- return buildIkeAuthReqMessage(payloadList);
- }
-
- private void validateIkeAuthRespWithEapPayload(IkeMessage respMsg)
- throws IkeProtocolException {
- IkeEapPayload ikeEapPayload =
- respMsg.getPayloadForType(IkePayload.PAYLOAD_TYPE_EAP, IkeEapPayload.class);
- if (ikeEapPayload == null) {
- throw new AuthenticationFailedException("Missing EAP payload");
- }
-
- // TODO: check that we don't receive any ChildSaRespPayloads here
-
- List<IkePayload> nonEapPayloads = new LinkedList<>();
- nonEapPayloads.addAll(respMsg.ikePayloadList);
- nonEapPayloads.remove(ikeEapPayload);
- validateIkeAuthResp(nonEapPayloads);
- }
-
- private void validateIkeAuthRespWithChildPayloads(IkeMessage respMsg)
- throws IkeProtocolException {
- // Extract and validate existence of payloads for first Child SA setup.
- List<IkePayload> childSaRespPayloads = extractChildPayloadsFromMessage(respMsg);
-
- List<IkePayload> nonChildPayloads = new LinkedList<>();
- nonChildPayloads.addAll(respMsg.ikePayloadList);
- nonChildPayloads.removeAll(childSaRespPayloads);
-
- validateIkeAuthResp(nonChildPayloads);
- }
-
- private void validateIkeAuthResp(List<IkePayload> payloadList) throws IkeProtocolException {
- // Validate IKE Authentication
- IkeAuthPayload authPayload = null;
- List<IkeCertPayload> certPayloads = new LinkedList<>();
-
- for (IkePayload payload : payloadList) {
- switch (payload.payloadType) {
- case IkePayload.PAYLOAD_TYPE_ID_RESPONDER:
- mRespIdPayload = (IkeIdPayload) payload;
- if (!mIkeSessionOptions
- .getRemoteIdentification()
- .equals(mRespIdPayload.ikeId)) {
- throw new AuthenticationFailedException(
- "Unrecognized Responder Identification.");
- }
- break;
- case IkePayload.PAYLOAD_TYPE_AUTH:
- authPayload = (IkeAuthPayload) payload;
- break;
- case IkePayload.PAYLOAD_TYPE_CERT:
- certPayloads.add((IkeCertPayload) payload);
- break;
- case IkePayload.PAYLOAD_TYPE_NOTIFY:
- IkeNotifyPayload notifyPayload = (IkeNotifyPayload) payload;
- if (notifyPayload.isErrorNotify()) {
- throw notifyPayload.validateAndBuildIkeException();
- } else {
- // Unknown and unexpected status notifications are ignored as per
- // RFC7296.
- logw(
- "Received unknown or unexpected status notifications with"
- + " notify type: "
- + notifyPayload.notifyType);
- }
- break;
- default:
- logw(
- "Received unexpected payload in IKE AUTH response. Payload"
- + " type: "
- + payload.payloadType);
- }
- }
-
- // Verify existence of payloads
- if (mRespIdPayload == null || authPayload == null) {
- throw new AuthenticationFailedException("ID-Responder or Auth payload is missing.");
- }
-
- // Authenticate the remote peer.
- authenticate(authPayload, mRespIdPayload, certPayloads);
- }
-
- private void authenticate(
- IkeAuthPayload authPayload,
- IkeIdPayload respIdPayload,
- List<IkeCertPayload> certPayloads)
- throws AuthenticationFailedException {
- switch (mIkeSessionOptions.getRemoteAuthConfig().mAuthMethod) {
- case IkeSessionOptions.IKE_AUTH_METHOD_PSK:
- authenticatePsk(
- ((IkeAuthPskConfig) mIkeSessionOptions.getRemoteAuthConfig()).mPsk,
- authPayload,
- respIdPayload);
- break;
- case IkeSessionOptions.IKE_AUTH_METHOD_PUB_KEY_SIGNATURE:
- authenticateDigitalSignature(
- certPayloads,
- ((IkeAuthDigitalSignRemoteConfig)
- mIkeSessionOptions.getRemoteAuthConfig())
- .mTrustAnchor,
- authPayload,
- respIdPayload);
- break;
- default:
- cleanUpAndQuit(
- new IllegalArgumentException(
- "Unrecognized auth method: " + authPayload.authMethod));
- }
- }
-
- private void authenticateDigitalSignature(
- List<IkeCertPayload> certPayloads,
- TrustAnchor trustAnchor,
- IkeAuthPayload authPayload,
- IkeIdPayload respIdPayload)
- throws AuthenticationFailedException {
- if (authPayload.authMethod != IkeAuthPayload.AUTH_METHOD_RSA_DIGITAL_SIGN
- && authPayload.authMethod != IkeAuthPayload.AUTH_METHOD_GENERIC_DIGITAL_SIGN) {
- throw new AuthenticationFailedException(
- "Expected the remote/server to use digital-signature-based authentication"
- + " but they used: "
- + authPayload.authMethod);
- }
-
- X509Certificate endCert = null;
- List<X509Certificate> certList = new LinkedList<>();
-
- // TODO: b/122676944 Extract CRL from IkeCrlPayload when we support IkeCrlPayload
- for (IkeCertPayload certPayload : certPayloads) {
- X509Certificate cert = ((IkeCertX509CertPayload) certPayload).certificate;
-
- // The first certificate MUST be the end entity certificate.
- if (endCert == null) endCert = cert;
- certList.add(cert);
- }
-
- if (endCert == null) {
- throw new AuthenticationFailedException(
- "The remote/server failed to provide a end certificate");
- }
-
- Set<TrustAnchor> trustAnchorSet = new HashSet<>();
- trustAnchorSet.add(trustAnchor);
-
- IkeCertPayload.validateCertificates(
- endCert, certList, null /*crlList*/, trustAnchorSet);
-
- IkeAuthDigitalSignPayload signPayload = (IkeAuthDigitalSignPayload) authPayload;
- signPayload.verifyInboundSignature(
- endCert,
- mIkeInitResponseBytes,
- mCurrentIkeSaRecord.nonceInitiator,
- respIdPayload.getEncodedPayloadBody(),
- mIkePrf,
- mCurrentIkeSaRecord.getSkPr());
- }
-
- @Override
- public void exitState() {
- mRetransmitter.stopRetransmitting();
- }
- }
-
- /**
- * CreateIkeLocalIkeAuthInEap represents the state when the IKE library authenticates the client
- * with an EAP session.
- */
- class CreateIkeLocalIkeAuthInEap extends CreateIkeLocalIkeAuthBase {
- private EapAuthenticator mEapAuthenticator;
-
- @Override
- public void enterState() {
- IkeSessionOptions.IkeAuthEapConfig ikeAuthEapConfig =
- (IkeSessionOptions.IkeAuthEapConfig) mIkeSessionOptions.getLocalAuthConfig();
-
- mEapAuthenticator =
- mEapAuthenticatorFactory.newEapAuthenticator(
- getHandler().getLooper(),
- new IkeEapCallback(),
- mContext,
- ikeAuthEapConfig.mEapConfig);
- }
-
- @Override
- public boolean processStateMessage(Message msg) {
- switch (msg.what) {
- case CMD_EAP_START_EAP_AUTH:
- IkeEapPayload ikeEapPayload = (IkeEapPayload) msg.obj;
- mEapAuthenticator.processEapMessage(ikeEapPayload.eapMessage);
-
- return HANDLED;
- case CMD_EAP_OUTBOUND_MSG_READY:
- byte[] eapMsgBytes = (byte[]) msg.obj;
- IkeEapPayload eapPayload = new IkeEapPayload(eapMsgBytes);
-
- // Setup new retransmitter with EAP response
- mRetransmitter =
- new EncryptedRetransmitter(
- buildIkeAuthReqMessage(Arrays.asList(eapPayload)));
-
- return HANDLED;
- case CMD_EAP_ERRORED:
- handleIkeFatalError(new AuthenticationFailedException((Throwable) msg.obj));
- return HANDLED;
- case CMD_EAP_FAILED:
- AuthenticationFailedException exception =
- new AuthenticationFailedException("EAP Authentication Failed");
-
- handleIkeFatalError(exception);
- return HANDLED;
- case CMD_EAP_FINISH_EAP_AUTH:
- deferMessage(msg);
- transitionTo(mCreateIkeLocalIkeAuthPostEap);
-
- return HANDLED;
- default:
- return super.processStateMessage(msg);
- }
- }
-
- @Override
- protected void handleResponseIkeMessage(IkeMessage ikeMessage) {
- try {
- mRetransmitter.stopRetransmitting();
-
- int exchangeType = ikeMessage.ikeHeader.exchangeType;
- if (exchangeType != IkeHeader.EXCHANGE_TYPE_IKE_AUTH) {
- throw new InvalidSyntaxException(
- "Expected EXCHANGE_TYPE_IKE_AUTH but received: " + exchangeType);
- }
-
- IkeEapPayload eapPayload = null;
- for (IkePayload payload : ikeMessage.ikePayloadList) {
- switch (payload.payloadType) {
- case IkePayload.PAYLOAD_TYPE_EAP:
- eapPayload = (IkeEapPayload) payload;
- break;
- case IkePayload.PAYLOAD_TYPE_NOTIFY:
- IkeNotifyPayload notifyPayload = (IkeNotifyPayload) payload;
- if (notifyPayload.isErrorNotify()) {
- throw notifyPayload.validateAndBuildIkeException();
- } else {
- // Unknown and unexpected status notifications are ignored as per
- // RFC7296.
- logw(
- "Received unknown or unexpected status notifications with"
- + " notify type: "
- + notifyPayload.notifyType);
- }
- break;
- default:
- logw(
- "Received unexpected payload in IKE AUTH response. Payload"
- + " type: "
- + payload.payloadType);
- }
- }
-
- if (eapPayload == null) {
- throw new AuthenticationFailedException("EAP Payload is missing.");
- }
-
- mEapAuthenticator.processEapMessage(eapPayload.eapMessage);
- } catch (IkeProtocolException exception) {
- handleIkeFatalError(exception);
- }
- }
-
- @Override
- protected void handleResponseGenericProcessError(
- IkeSaRecord ikeSaRecord, InvalidSyntaxException ikeException) {
- mRetransmitter.stopRetransmitting();
- handleIkeFatalError(ikeException);
- }
-
- private class IkeEapCallback implements IEapCallback {
- @Override
- public void onSuccess(byte[] msk, byte[] emsk) {
- // Extended MSK not used in IKEv2, drop.
- sendMessage(CMD_EAP_FINISH_EAP_AUTH, msk);
- }
-
- @Override
- public void onFail() {
- sendMessage(CMD_EAP_FAILED);
- }
-
- @Override
- public void onResponse(byte[] eapMsg) {
- sendMessage(CMD_EAP_OUTBOUND_MSG_READY, eapMsg);
- }
-
- @Override
- public void onError(Throwable cause) {
- sendMessage(CMD_EAP_ERRORED, cause);
- }
- }
- }
-
- /**
- * CreateIkeLocalIkeAuthPostEap represents the state when the IKE library is performing the
- * post-EAP PSK-base authentication run.
- */
- class CreateIkeLocalIkeAuthPostEap extends CreateIkeLocalIkeAuthBase {
- private byte[] mEapMsk = new byte[0];
-
- @Override
- public boolean processStateMessage(Message msg) {
- switch (msg.what) {
- case CMD_EAP_FINISH_EAP_AUTH:
- mEapMsk = (byte[]) msg.obj;
-
- IkeAuthPskPayload pskPayload =
- new IkeAuthPskPayload(
- mEapMsk,
- mIkeInitRequestBytes,
- mCurrentIkeSaRecord.nonceResponder,
- mInitIdPayload.getEncodedPayloadBody(),
- mIkePrf,
- mCurrentIkeSaRecord.getSkPi());
- IkeMessage postEapAuthMsg = buildIkeAuthReqMessage(Arrays.asList(pskPayload));
- mRetransmitter = new EncryptedRetransmitter(postEapAuthMsg);
-
- return HANDLED;
- default:
- return super.processStateMessage(msg);
- }
- }
-
- @Override
- protected void handleResponseIkeMessage(IkeMessage ikeMessage) {
- try {
- int exchangeType = ikeMessage.ikeHeader.exchangeType;
- if (exchangeType != IkeHeader.EXCHANGE_TYPE_IKE_AUTH) {
- throw new InvalidSyntaxException(
- "Expected EXCHANGE_TYPE_IKE_AUTH but received: " + exchangeType);
- }
-
- // Extract and validate existence of payloads for first Child SA setup.
- List<IkePayload> childSaRespPayloads = extractChildPayloadsFromMessage(ikeMessage);
-
- List<IkePayload> nonChildPayloads = new LinkedList<>();
- nonChildPayloads.addAll(ikeMessage.ikePayloadList);
- nonChildPayloads.removeAll(childSaRespPayloads);
-
- validateIkeAuthRespPostEap(nonChildPayloads);
-
- performFirstChildNegotiation(mFirstChildReqList, childSaRespPayloads);
- } catch (IkeProtocolException e) {
- // Notify the remote because they may have set up the IKE SA.
- sendEncryptedIkeMessage(buildIkeDeleteReq(mCurrentIkeSaRecord));
- handleIkeFatalError(e);
- }
- }
-
- @Override
- protected void handleResponseGenericProcessError(
- IkeSaRecord ikeSaRecord, InvalidSyntaxException ikeException) {
- mRetransmitter.stopRetransmitting();
- // Notify the remote because they may have set up the IKE SA.
- sendEncryptedIkeMessage(buildIkeDeleteReq(mCurrentIkeSaRecord));
- handleIkeFatalError(ikeException);
- }
-
- private void validateIkeAuthRespPostEap(List<IkePayload> payloadList)
- throws IkeProtocolException {
- IkeAuthPayload authPayload = null;
-
- for (IkePayload payload : payloadList) {
- switch (payload.payloadType) {
- case IkePayload.PAYLOAD_TYPE_AUTH:
- authPayload = (IkeAuthPayload) payload;
- break;
- case IkePayload.PAYLOAD_TYPE_NOTIFY:
- IkeNotifyPayload notifyPayload = (IkeNotifyPayload) payload;
- if (notifyPayload.isErrorNotify()) {
- throw notifyPayload.validateAndBuildIkeException();
- } else {
- // Unknown and unexpected status notifications are ignored as per
- // RFC7296.
- logw(
- "Received unknown or unexpected status notifications with"
- + " notify type: "
- + notifyPayload.notifyType);
- }
- break;
- default:
- logw(
- "Received unexpected payload in IKE AUTH response. Payload"
- + " type: "
- + payload.payloadType);
- }
- }
-
- // Verify existence of payloads
- if (authPayload == null) {
- throw new AuthenticationFailedException("Post-EAP Auth payload missing.");
- }
-
- authenticatePsk(mEapMsk, authPayload, mRespIdPayload);
- }
-
- @Override
- public void exitState() {
- mRetransmitter.stopRetransmitting();
- }
- }
-
- private abstract class RekeyIkeHandlerBase extends DeleteBase {
- private void validateIkeRekeyCommon(IkeMessage ikeMessage) throws InvalidSyntaxException {
- boolean hasSaPayload = false;
- boolean hasKePayload = false;
- boolean hasNoncePayload = false;
- for (IkePayload payload : ikeMessage.ikePayloadList) {
- switch (payload.payloadType) {
- case IkePayload.PAYLOAD_TYPE_SA:
- hasSaPayload = true;
- break;
- case IkePayload.PAYLOAD_TYPE_KE:
- hasKePayload = true;
- break;
- case IkePayload.PAYLOAD_TYPE_NONCE:
- hasNoncePayload = true;
- break;
- case IkePayload.PAYLOAD_TYPE_VENDOR:
- // Vendor payloads allowed, but not verified
- break;
- case IkePayload.PAYLOAD_TYPE_NOTIFY:
- // Notification payloads allowed, but left to handler methods to process.
- break;
- default:
- logw(
- "Received unexpected payload in IKE REKEY request. Payload type: "
- + payload.payloadType);
- }
- }
-
- if (!hasSaPayload || !hasKePayload || !hasNoncePayload) {
- throw new InvalidSyntaxException("SA, KE or Nonce payload missing.");
- }
- }
-
- @VisibleForTesting
- void validateIkeRekeyReq(IkeMessage ikeMessage) throws InvalidSyntaxException {
- // Skip validation of exchange type since it has been done during decoding request.
-
- List<IkeNotifyPayload> notificationPayloads =
- ikeMessage.getPayloadListForType(
- IkePayload.PAYLOAD_TYPE_NOTIFY, IkeNotifyPayload.class);
- for (IkeNotifyPayload notifyPayload : notificationPayloads) {
- if (notifyPayload.isErrorNotify()) {
- logw("Error notifications invalid in request: " + notifyPayload.notifyType);
- }
- }
-
- validateIkeRekeyCommon(ikeMessage);
- }
-
- @VisibleForTesting
- void validateIkeRekeyResp(IkeMessage reqMsg, IkeMessage respMsg)
- throws InvalidSyntaxException {
- int exchangeType = respMsg.ikeHeader.exchangeType;
- if (exchangeType != IkeHeader.EXCHANGE_TYPE_CREATE_CHILD_SA
- && exchangeType != IkeHeader.EXCHANGE_TYPE_INFORMATIONAL) {
- throw new InvalidSyntaxException(
- "Expected Rekey response (CREATE_CHILD_SA or INFORMATIONAL) but received: "
- + exchangeType);
- }
-
- List<IkeNotifyPayload> notificationPayloads =
- respMsg.getPayloadListForType(
- IkePayload.PAYLOAD_TYPE_NOTIFY, IkeNotifyPayload.class);
- for (IkeNotifyPayload notifyPayload : notificationPayloads) {
- if (notifyPayload.isErrorNotify()) {
- // Error notifications found. Stop validation for SA negotiation.
- return;
- }
- }
-
- validateIkeRekeyCommon(respMsg);
-
- // Verify DH groups matching
- IkeKePayload reqKePayload =
- reqMsg.getPayloadForType(IkePayload.PAYLOAD_TYPE_KE, IkeKePayload.class);
- IkeKePayload respKePayload =
- respMsg.getPayloadForType(IkePayload.PAYLOAD_TYPE_KE, IkeKePayload.class);
- if (reqKePayload.dhGroup != respKePayload.dhGroup) {
- throw new InvalidSyntaxException("Received KE payload with mismatched DH group.");
- }
- }
-
- // It doesn't make sense to include multiple error notify payloads in one response. If it
- // happens, IKE Session will only handle the most severe one.
- protected boolean handleErrorNotifyIfExists(IkeMessage respMsg, boolean isSimulRekey) {
- IkeNotifyPayload invalidSyntaxNotifyPayload = null;
- IkeNotifyPayload tempFailureNotifyPayload = null;
- IkeNotifyPayload firstErrorNotifyPayload = null;
-
- List<IkeNotifyPayload> notificationPayloads =
- respMsg.getPayloadListForType(
- IkePayload.PAYLOAD_TYPE_NOTIFY, IkeNotifyPayload.class);
- for (IkeNotifyPayload notifyPayload : notificationPayloads) {
- if (!notifyPayload.isErrorNotify()) continue;
-
- if (firstErrorNotifyPayload == null) firstErrorNotifyPayload = notifyPayload;
-
- if (ERROR_TYPE_INVALID_SYNTAX == notifyPayload.notifyType) {
- invalidSyntaxNotifyPayload = notifyPayload;
- } else if (ERROR_TYPE_TEMPORARY_FAILURE == notifyPayload.notifyType) {
- tempFailureNotifyPayload = notifyPayload;
- }
- }
-
- // No error Notify Payload included in this response.
- if (firstErrorNotifyPayload == null) return NOT_HANDLED;
-
- // Handle Invalid Syntax if it exists
- if (invalidSyntaxNotifyPayload != null) {
- try {
- IkeProtocolException exception =
- invalidSyntaxNotifyPayload.validateAndBuildIkeException();
- handleIkeFatalError(exception);
- } catch (InvalidSyntaxException e) {
- // Error notify payload has invalid syntax
- handleIkeFatalError(e);
- }
- return HANDLED;
- }
-
- if (tempFailureNotifyPayload != null) {
- // Handle Temporary Failure if exists
- loge("Received TEMPORARY_FAILURE for rekey IKE. Already handled during decoding.");
- } else {
- // Handle other errors
- loge(
- "Received error notification: "
- + firstErrorNotifyPayload.notifyType
- + " for rekey IKE. Schedule a retry");
- if (!isSimulRekey) {
- scheduleRetry(mCurrentIkeSaRecord.getFutureRekeyEvent());
- }
- }
-
- if (isSimulRekey) {
- transitionTo(mRekeyIkeRemoteDelete);
- } else {
- transitionTo(mIdle);
- }
- return HANDLED;
- }
-
- protected IkeSaRecord validateAndBuildIkeSa(
- IkeMessage reqMsg, IkeMessage respMessage, boolean isLocalInit)
- throws IkeProtocolException, GeneralSecurityException, IOException {
- InetAddress initAddr = isLocalInit ? mLocalAddress : mRemoteAddress;
- InetAddress respAddr = isLocalInit ? mRemoteAddress : mLocalAddress;
-
- Pair<IkeProposal, IkeProposal> negotiatedProposals = null;
- try {
- IkeSaPayload reqSaPayload =
- reqMsg.getPayloadForType(IkePayload.PAYLOAD_TYPE_SA, IkeSaPayload.class);
- IkeSaPayload respSaPayload =
- respMessage.getPayloadForType(
- IkePayload.PAYLOAD_TYPE_SA, IkeSaPayload.class);
-
- // Throw exception or return valid negotiated proposal with allocated SPIs
- negotiatedProposals =
- IkeSaPayload.getVerifiedNegotiatedIkeProposalPair(
- reqSaPayload, respSaPayload, mRemoteAddress);
- IkeProposal reqProposal = negotiatedProposals.first;
- IkeProposal respProposal = negotiatedProposals.second;
-
- Provider provider = IkeMessage.getSecurityProvider();
- IkeMacPrf newPrf;
- IkeCipher newCipher;
- IkeMacIntegrity newIntegrity = null;
-
- newCipher =
- IkeCipher.create(
- respProposal.saProposal.getEncryptionTransforms()[0], provider);
- if (!newCipher.isAead()) {
- newIntegrity =
- IkeMacIntegrity.create(
- respProposal.saProposal.getIntegrityTransforms()[0], provider);
- }
- newPrf = IkeMacPrf.create(respProposal.saProposal.getPrfTransforms()[0], provider);
-
- // Build new SaRecord
- IkeSaRecord newSaRecord =
- IkeSaRecord.makeRekeyedIkeSaRecord(
- mCurrentIkeSaRecord,
- mIkePrf,
- reqMsg,
- respMessage,
- reqProposal.getIkeSpiResource(),
- respProposal.getIkeSpiResource(),
- newPrf,
- newIntegrity == null ? 0 : newIntegrity.getKeyLength(),
- newCipher.getKeyLength(),
- isLocalInit,
- new LocalRequest(CMD_LOCAL_REQUEST_REKEY_IKE));
-
- addIkeSaRecord(newSaRecord);
-
- mIkeCipher = newCipher;
- mIkePrf = newPrf;
- mIkeIntegrity = newIntegrity;
-
- return newSaRecord;
- } catch (IkeProtocolException | GeneralSecurityException | IOException e) {
- if (negotiatedProposals != null) {
- negotiatedProposals.first.getIkeSpiResource().close();
- negotiatedProposals.second.getIkeSpiResource().close();
- }
- throw e;
- }
- }
- }
-
- /** RekeyIkeLocalCreate represents state when IKE library initiates Rekey IKE exchange. */
- class RekeyIkeLocalCreate extends RekeyIkeHandlerBase {
- protected Retransmitter mRetransmitter;
-
- @Override
- public void enterState() {
- try {
- mRetransmitter = new EncryptedRetransmitter(buildIkeRekeyReq());
- } catch (IOException e) {
- loge("Fail to assign IKE SPI for rekey. Schedule a retry.", e);
- scheduleRetry(mCurrentIkeSaRecord.getFutureRekeyEvent());
- transitionTo(mIdle);
- }
- }
-
- @Override
- protected void triggerRetransmit() {
- mRetransmitter.retransmit();
- }
-
- @Override
- protected void handleTempFailure() {
- mTempFailHandler.handleTempFailure(mCurrentIkeSaRecord.getFutureRekeyEvent());
- }
-
- /**
- * Builds a IKE Rekey request, reusing the current proposal
- *
- * <p>As per RFC 7296, rekey messages are of format: { HDR { SK { SA, Ni, KEi } } }
- *
- * <p>This method currently reuses agreed upon proposal.
- */
- private IkeMessage buildIkeRekeyReq() throws IOException {
- // TODO: Evaluate if we need to support different proposals for rekeys
- IkeSaProposal[] saProposals = new IkeSaProposal[] {mSaProposal};
-
- // No need to allocate SPIs; they will be allocated as part of the
- // getRekeyIkeSaRequestPayloads
- List<IkePayload> payloadList =
- CreateIkeSaHelper.getRekeyIkeSaRequestPayloads(saProposals, mLocalAddress);
-
- // Build IKE header
- IkeHeader ikeHeader =
- new IkeHeader(
- mCurrentIkeSaRecord.getInitiatorSpi(),
- mCurrentIkeSaRecord.getResponderSpi(),
- IkePayload.PAYLOAD_TYPE_SK,
- IkeHeader.EXCHANGE_TYPE_CREATE_CHILD_SA,
- false /*isResponseMsg*/,
- mCurrentIkeSaRecord.isLocalInit,
- mCurrentIkeSaRecord.getLocalRequestMessageId());
-
- return new IkeMessage(ikeHeader, payloadList);
- }
-
- @Override
- protected void handleRequestIkeMessage(
- IkeMessage ikeMessage, int ikeExchangeSubType, Message message) {
- switch (ikeExchangeSubType) {
- case IKE_EXCHANGE_SUBTYPE_DELETE_IKE:
- handleDeleteSessionRequest(ikeMessage);
- break;
- default:
- // TODO: Implement simultaneous rekey
- buildAndSendErrorNotificationResponse(
- mCurrentIkeSaRecord,
- ikeMessage.ikeHeader.messageId,
- ERROR_TYPE_TEMPORARY_FAILURE);
- }
- }
-
- @Override
- protected void handleResponseIkeMessage(IkeMessage ikeMessage) {
- try {
- // Validate syntax
- validateIkeRekeyResp(mRetransmitter.getMessage(), ikeMessage);
-
- // Handle error notifications if they exist
- if (handleErrorNotifyIfExists(ikeMessage, false /*isSimulRekey*/) == NOT_HANDLED) {
- // No error notifications included. Negotiate new SA
- mLocalInitNewIkeSaRecord =
- validateAndBuildIkeSa(
- mRetransmitter.getMessage(), ikeMessage, true /*isLocalInit*/);
- transitionTo(mRekeyIkeLocalDelete);
- }
-
- // Stop retransmissions
- mRetransmitter.stopRetransmitting();
- } catch (IkeProtocolException e) {
- if (e instanceof InvalidSyntaxException) {
- handleProcessRespOrSaCreationFailureAndQuit(e);
- } else {
- handleProcessRespOrSaCreationFailureAndQuit(
- new InvalidSyntaxException(
- "Error in processing IKE Rekey-Create response", e));
- }
-
- } catch (GeneralSecurityException | IOException e) {
- handleProcessRespOrSaCreationFailureAndQuit(
- new IkeInternalException("Error in creating a new IKE SA during rekey", e));
- }
- }
-
- @Override
- protected void handleResponseGenericProcessError(
- IkeSaRecord ikeSaRecord, InvalidSyntaxException ikeException) {
- handleProcessRespOrSaCreationFailureAndQuit(ikeException);
- }
-
- private void handleProcessRespOrSaCreationFailureAndQuit(IkeException exception) {
- // We don't retry rekey if failure was caused by invalid response or SA creation error.
- // Reason is there is no way to notify the remote side the old SA is still alive but the
- // new one has failed.
-
- mRetransmitter.stopRetransmitting();
-
- sendEncryptedIkeMessage(buildIkeDeleteReq(mCurrentIkeSaRecord));
- handleIkeFatalError(exception);
- }
- }
-
- /**
- * SimulRekeyIkeLocalCreate represents the state where IKE library has replied to rekey request
- * sent from the remote and is waiting for a rekey response for a locally initiated rekey
- * request.
- *
- * <p>SimulRekeyIkeLocalCreate extends RekeyIkeLocalCreate so that it can call super class to
- * validate incoming rekey response against locally initiated rekey request.
- */
- class SimulRekeyIkeLocalCreate extends RekeyIkeLocalCreate {
- @Override
- public void enterState() {
- mRetransmitter = new EncryptedRetransmitter(null);
- // TODO: Populate super.mRetransmitter from state initialization data
- // Do not send request.
- }
-
- public IkeMessage buildRequest() {
- throw new UnsupportedOperationException(
- "Do not support sending request in " + getCurrentState().getName());
- }
-
- @Override
- public void exitState() {
- // Do nothing.
- }
-
- @Override
- public boolean processStateMessage(Message message) {
- switch (message.what) {
- case CMD_RECEIVE_IKE_PACKET:
- ReceivedIkePacket receivedIkePacket = (ReceivedIkePacket) message.obj;
- IkeHeader ikeHeader = receivedIkePacket.ikeHeader;
-
- if (mRemoteInitNewIkeSaRecord == getIkeSaRecordForPacket(ikeHeader)) {
- deferMessage(message);
- } else {
- handleReceivedIkePacket(message);
- }
- return HANDLED;
-
- default:
- return super.processStateMessage(message);
- }
- }
-
- @Override
- protected void handleRequestIkeMessage(
- IkeMessage ikeMessage, int ikeExchangeSubType, Message message) {
- switch (ikeExchangeSubType) {
- case IKE_EXCHANGE_SUBTYPE_DELETE_IKE:
- deferMessage(message);
- return;
- default:
- // TODO: Add more cases for other types of request.
- }
- }
-
- @Override
- protected void handleResponseIkeMessage(IkeMessage ikeMessage) {
- try {
- validateIkeRekeyResp(mRetransmitter.getMessage(), ikeMessage);
-
- // TODO: Check and handle error notifications before SA negotiation
-
- mLocalInitNewIkeSaRecord =
- validateAndBuildIkeSa(
- mRetransmitter.getMessage(), ikeMessage, true /*isLocalInit*/);
- transitionTo(mSimulRekeyIkeLocalDeleteRemoteDelete);
- } catch (IkeProtocolException e) {
- // TODO: Handle processing errors.
- } catch (GeneralSecurityException e) {
- // TODO: Fatal - kill session.
- } catch (IOException e) {
- // TODO: SPI allocation collided - delete new IKE SA, retry rekey.
- }
- }
- }
-
- /** RekeyIkeDeleteBase represents common behaviours of deleting stage during rekeying IKE SA. */
- private abstract class RekeyIkeDeleteBase extends DeleteBase {
- @Override
- public boolean processStateMessage(Message message) {
- switch (message.what) {
- case CMD_RECEIVE_IKE_PACKET:
- ReceivedIkePacket receivedIkePacket = (ReceivedIkePacket) message.obj;
- IkeHeader ikeHeader = receivedIkePacket.ikeHeader;
-
- // Verify that this message is correctly authenticated and encrypted:
- IkeSaRecord ikeSaRecord = getIkeSaRecordForPacket(ikeHeader);
- boolean isMessageOnNewSa = false;
- if (ikeSaRecord != null && mIkeSaRecordSurviving == ikeSaRecord) {
- DecodeResult decodeResult =
- IkeMessage.decode(
- ikeHeader.isResponseMsg
- ? ikeSaRecord.getLocalRequestMessageId()
- : ikeSaRecord.getRemoteRequestMessageId(),
- mIkeIntegrity,
- mIkeCipher,
- ikeSaRecord,
- ikeHeader,
- receivedIkePacket.ikePacketBytes,
- ikeSaRecord.getCollectedFragments(ikeHeader.isResponseMsg));
- isMessageOnNewSa =
- (decodeResult.status == DECODE_STATUS_PROTECTED_ERROR)
- || (decodeResult.status == DECODE_STATUS_OK)
- || (decodeResult.status == DECODE_STATUS_PARTIAL);
- }
-
- // Authenticated request received on the new/surviving SA; treat it as
- // an acknowledgement that the remote has successfully rekeyed.
- if (isMessageOnNewSa) {
- State nextState = mIdle;
-
- // This is the first IkeMessage seen on the new SA. It cannot be a response.
- // Likewise, if it a request, it must not be a retransmission. Verify msgId.
- // If either condition happens, consider rekey a success, but immediately
- // kill the session.
- if (ikeHeader.isResponseMsg
- || ikeSaRecord.getRemoteRequestMessageId() - ikeHeader.messageId
- != 0) {
- nextState = mDeleteIkeLocalDelete;
- } else {
- deferMessage(message);
- }
-
- // Locally close old (and losing) IKE SAs. As a result of not waiting for
- // delete responses, the old SA can be left in a state where the stored ID
- // is no longer correct. However, this finishRekey() call will remove that
- // SA, so it doesn't matter.
- finishRekey();
- transitionTo(nextState);
- } else {
- handleReceivedIkePacket(message);
- }
-
- return HANDLED;
- default:
- return super.processStateMessage(message);
- // TODO: Add more cases for other packet types.
- }
- }
-
- // Rekey timer for old (and losing) SAs will be cancelled as part of the closing of the SA.
- protected void finishRekey() {
- mCurrentIkeSaRecord = mIkeSaRecordSurviving;
- mLocalInitNewIkeSaRecord = null;
- mRemoteInitNewIkeSaRecord = null;
-
- mIkeSaRecordSurviving = null;
-
- if (mIkeSaRecordAwaitingLocalDel != null) {
- removeIkeSaRecord(mIkeSaRecordAwaitingLocalDel);
- mIkeSaRecordAwaitingLocalDel.close();
- mIkeSaRecordAwaitingLocalDel = null;
- }
-
- if (mIkeSaRecordAwaitingRemoteDel != null) {
- removeIkeSaRecord(mIkeSaRecordAwaitingRemoteDel);
- mIkeSaRecordAwaitingRemoteDel.close();
- mIkeSaRecordAwaitingRemoteDel = null;
- }
-
- synchronized (mChildCbToSessions) {
- for (ChildSessionStateMachine child : mChildCbToSessions.values()) {
- child.setSkD(mCurrentIkeSaRecord.getSkD());
- }
- }
-
- // TODO: Update prf of all child sessions
- }
- }
-
- /**
- * SimulRekeyIkeLocalDeleteRemoteDelete represents the deleting stage during simultaneous
- * rekeying when IKE library is waiting for both a Delete request and a Delete response.
- */
- class SimulRekeyIkeLocalDeleteRemoteDelete extends RekeyIkeDeleteBase {
- private Retransmitter mRetransmitter;
-
- @Override
- public void enterState() {
- // Detemine surviving IKE SA. According to RFC 7296: "The new IKE SA containing the
- // lowest nonce SHOULD be deleted by the node that created it, and the other surviving
- // new IKE SA MUST inherit all the Child SAs."
- if (mLocalInitNewIkeSaRecord.compareTo(mRemoteInitNewIkeSaRecord) > 0) {
- mIkeSaRecordSurviving = mLocalInitNewIkeSaRecord;
- mIkeSaRecordAwaitingLocalDel = mCurrentIkeSaRecord;
- mIkeSaRecordAwaitingRemoteDel = mRemoteInitNewIkeSaRecord;
- } else {
- mIkeSaRecordSurviving = mRemoteInitNewIkeSaRecord;
- mIkeSaRecordAwaitingLocalDel = mLocalInitNewIkeSaRecord;
- mIkeSaRecordAwaitingRemoteDel = mCurrentIkeSaRecord;
- }
- mRetransmitter =
- new EncryptedRetransmitter(
- mIkeSaRecordAwaitingLocalDel,
- buildIkeDeleteReq(mIkeSaRecordAwaitingLocalDel));
- // TODO: Set timer awaiting for delete request.
- }
-
- @Override
- protected void triggerRetransmit() {
- mRetransmitter.retransmit();
- }
-
- @Override
- protected void handleRequestIkeMessage(
- IkeMessage ikeMessage, int ikeExchangeSubType, Message message) {
- IkeSaRecord ikeSaRecordForPacket = getIkeSaRecordForPacket(ikeMessage.ikeHeader);
- switch (ikeExchangeSubType) {
- case IKE_EXCHANGE_SUBTYPE_DELETE_IKE:
- try {
- validateIkeDeleteReq(ikeMessage, mIkeSaRecordAwaitingRemoteDel);
- IkeMessage respMsg =
- buildIkeDeleteResp(ikeMessage, mIkeSaRecordAwaitingRemoteDel);
- removeIkeSaRecord(mIkeSaRecordAwaitingRemoteDel);
- // TODO: Encode and send response and close
- // mIkeSaRecordAwaitingRemoteDel.
- // TODO: Stop timer awating delete request.
- transitionTo(mSimulRekeyIkeLocalDelete);
- } catch (InvalidSyntaxException e) {
- logd("Validation failed for delete request", e);
- // TODO: Shutdown - fatal error
- }
- return;
- default:
- // TODO: Reply with TEMPORARY_FAILURE
- }
- }
-
- @Override
- protected void handleResponseIkeMessage(IkeMessage ikeMessage) {
- try {
- validateIkeDeleteResp(ikeMessage, mIkeSaRecordAwaitingLocalDel);
- finishDeleteIkeSaAwaitingLocalDel();
- } catch (InvalidSyntaxException e) {
- loge("Invalid syntax on IKE Delete response. Shutting down anyways", e);
- finishDeleteIkeSaAwaitingLocalDel();
- } catch (IllegalStateException e) {
- // Response received on incorrect SA
- cleanUpAndQuit(e);
- }
- }
-
- @Override
- protected void handleResponseGenericProcessError(
- IkeSaRecord ikeSaRecord, InvalidSyntaxException exception) {
- if (mIkeSaRecordAwaitingLocalDel == ikeSaRecord) {
- loge("Invalid syntax on IKE Delete response. Shutting down anyways", exception);
- finishDeleteIkeSaAwaitingLocalDel();
- } else {
- cleanUpAndQuit(
- new IllegalStateException("Delete response received on incorrect SA"));
- }
- }
-
- private void finishDeleteIkeSaAwaitingLocalDel() {
- mRetransmitter.stopRetransmitting();
-
- removeIkeSaRecord(mIkeSaRecordAwaitingLocalDel);
- mIkeSaRecordAwaitingLocalDel.close();
- mIkeSaRecordAwaitingLocalDel = null;
-
- transitionTo(mSimulRekeyIkeRemoteDelete);
- }
-
- @Override
- public void exitState() {
- finishRekey();
- mRetransmitter.stopRetransmitting();
- // TODO: Stop awaiting delete request timer.
- }
- }
-
- /**
- * SimulRekeyIkeLocalDelete represents the state when IKE library is waiting for a Delete
- * response during simultaneous rekeying.
- */
- class SimulRekeyIkeLocalDelete extends RekeyIkeDeleteBase {
- private Retransmitter mRetransmitter;
-
- @Override
- public void enterState() {
- mRetransmitter = new EncryptedRetransmitter(mIkeSaRecordAwaitingLocalDel, null);
- // TODO: Populate mRetransmitter from state initialization data.
- }
-
- @Override
- protected void triggerRetransmit() {
- mRetransmitter.retransmit();
- }
-
- @Override
- protected void handleRequestIkeMessage(
- IkeMessage ikeMessage, int ikeExchangeSubType, Message message) {
- // Always return a TEMPORARY_FAILURE. In no case should we accept a message on an SA
- // that is going away. All messages on the new SA is caught in RekeyIkeDeleteBase
- buildAndSendErrorNotificationResponse(
- mIkeSaRecordAwaitingLocalDel,
- ikeMessage.ikeHeader.messageId,
- ERROR_TYPE_TEMPORARY_FAILURE);
- }
-
- @Override
- protected void handleResponseIkeMessage(IkeMessage ikeMessage) {
- try {
- validateIkeDeleteResp(ikeMessage, mIkeSaRecordAwaitingLocalDel);
- finishRekey();
- transitionTo(mIdle);
- } catch (InvalidSyntaxException e) {
- loge(
- "Invalid syntax on IKE Delete response. Shutting down old IKE SA and"
- + " finishing rekey",
- e);
- finishRekey();
- transitionTo(mIdle);
- } catch (IllegalStateException e) {
- // Response received on incorrect SA
- cleanUpAndQuit(e);
- }
- }
-
- @Override
- protected void handleResponseGenericProcessError(
- IkeSaRecord ikeSaRecord, InvalidSyntaxException exception) {
- if (mIkeSaRecordAwaitingLocalDel == ikeSaRecord) {
- loge(
- "Invalid syntax on IKE Delete response. Shutting down old IKE SA and"
- + " finishing rekey",
- exception);
- finishRekey();
- transitionTo(mIdle);
- } else {
- cleanUpAndQuit(
- new IllegalStateException("Delete response received on incorrect SA"));
- }
- }
- }
-
- /**
- * SimulRekeyIkeRemoteDelete represents the state that waiting for a Delete request during
- * simultaneous rekeying.
- */
- class SimulRekeyIkeRemoteDelete extends RekeyIkeDeleteBase {
- @Override
- protected void handleRequestIkeMessage(
- IkeMessage ikeMessage, int ikeExchangeSubType, Message message) {
- // At this point, the incoming request can ONLY be on mIkeSaRecordAwaitingRemoteDel - if
- // it was on the surviving SA, it is deferred and the rekey is finished. It is likewise
- // impossible to have this on the local-deleted SA, since the delete has already been
- // acknowledged in the SimulRekeyIkeLocalDeleteRemoteDelete state.
- switch (ikeExchangeSubType) {
- case IKE_EXCHANGE_SUBTYPE_DELETE_IKE:
- try {
- validateIkeDeleteReq(ikeMessage, mIkeSaRecordAwaitingRemoteDel);
-
- IkeMessage respMsg =
- buildIkeDeleteResp(ikeMessage, mIkeSaRecordAwaitingRemoteDel);
- sendEncryptedIkeMessage(mIkeSaRecordAwaitingRemoteDel, respMsg);
-
- finishRekey();
- transitionTo(mIdle);
- } catch (InvalidSyntaxException e) {
- // Program error.
- cleanUpAndQuit(new IllegalStateException(e));
- }
- return;
- default:
- buildAndSendErrorNotificationResponse(
- mIkeSaRecordAwaitingRemoteDel,
- ikeMessage.ikeHeader.messageId,
- ERROR_TYPE_TEMPORARY_FAILURE);
- }
- }
- }
-
- /**
- * RekeyIkeLocalDelete represents the deleting stage when IKE library is initiating a Rekey
- * procedure.
- *
- * <p>RekeyIkeLocalDelete and SimulRekeyIkeLocalDelete have same behaviours in
- * processStateMessage(). While RekeyIkeLocalDelete overrides enterState() and exitState()
- * methods for initiating and finishing the deleting stage for IKE rekeying.
- */
- class RekeyIkeLocalDelete extends SimulRekeyIkeLocalDelete {
- private Retransmitter mRetransmitter;
-
- @Override
- public void enterState() {
- mIkeSaRecordSurviving = mLocalInitNewIkeSaRecord;
- mIkeSaRecordAwaitingLocalDel = mCurrentIkeSaRecord;
- mRetransmitter =
- new EncryptedRetransmitter(
- mIkeSaRecordAwaitingLocalDel,
- buildIkeDeleteReq(mIkeSaRecordAwaitingLocalDel));
- }
-
- @Override
- protected void triggerRetransmit() {
- mRetransmitter.retransmit();
- }
-
- @Override
- public void exitState() {
- mRetransmitter.stopRetransmitting();
- }
- }
-
- /**
- * RekeyIkeRemoteDelete represents the deleting stage when responding to a Rekey procedure.
- *
- * <p>RekeyIkeRemoteDelete and SimulRekeyIkeRemoteDelete have same behaviours in
- * processStateMessage(). While RekeyIkeLocalDelete overrides enterState() and exitState()
- * methods for waiting incoming delete request and for finishing the deleting stage for IKE
- * rekeying.
- */
- class RekeyIkeRemoteDelete extends SimulRekeyIkeRemoteDelete {
- @Override
- public void enterState() {
- mIkeSaRecordSurviving = mRemoteInitNewIkeSaRecord;
- mIkeSaRecordAwaitingRemoteDel = mCurrentIkeSaRecord;
-
- sendMessageDelayed(TIMEOUT_REKEY_REMOTE_DELETE, REKEY_DELETE_TIMEOUT_MS);
- }
-
- @Override
- public boolean processStateMessage(Message message) {
- // Intercept rekey delete timeout. Assume rekey succeeded since no retransmissions
- // were received.
- if (message.what == TIMEOUT_REKEY_REMOTE_DELETE) {
- finishRekey();
- transitionTo(mIdle);
-
- return HANDLED;
- } else {
- return super.processStateMessage(message);
- }
- }
-
- @Override
- public void exitState() {
- removeMessages(TIMEOUT_REKEY_REMOTE_DELETE);
- }
- }
-
- /** DeleteIkeLocalDelete initiates a deletion request of the current IKE Session. */
- class DeleteIkeLocalDelete extends DeleteBase {
- private Retransmitter mRetransmitter;
-
- @Override
- public void enterState() {
- mRetransmitter = new EncryptedRetransmitter(buildIkeDeleteReq(mCurrentIkeSaRecord));
- }
-
- @Override
- protected void triggerRetransmit() {
- mRetransmitter.retransmit();
- }
-
- @Override
- protected void handleRequestIkeMessage(
- IkeMessage ikeMessage, int ikeExchangeSubType, Message message) {
- switch (ikeExchangeSubType) {
- case IKE_EXCHANGE_SUBTYPE_DELETE_IKE:
- handleDeleteSessionRequest(ikeMessage);
- return;
- default:
- buildAndSendErrorNotificationResponse(
- mCurrentIkeSaRecord,
- ikeMessage.ikeHeader.messageId,
- ERROR_TYPE_TEMPORARY_FAILURE);
- }
- }
-
- @Override
- protected void handleResponseIkeMessage(IkeMessage ikeMessage) {
- try {
- validateIkeDeleteResp(ikeMessage, mCurrentIkeSaRecord);
- mUserCbExecutor.execute(
- () -> {
- mIkeSessionCallback.onClosed();
- });
-
- removeIkeSaRecord(mCurrentIkeSaRecord);
- mCurrentIkeSaRecord.close();
- mCurrentIkeSaRecord = null;
- quitNow();
- } catch (InvalidSyntaxException e) {
- handleResponseGenericProcessError(mCurrentIkeSaRecord, e);
- }
- }
-
- @Override
- protected void handleResponseGenericProcessError(
- IkeSaRecord ikeSaRecord, InvalidSyntaxException exception) {
- loge("Invalid syntax on IKE Delete response. Shutting down anyways", exception);
- handleIkeFatalError(exception);
- quitNow();
- }
-
- @Override
- public void exitState() {
- mRetransmitter.stopRetransmitting();
- }
- }
-
- /**
- * Helper class to generate IKE SA creation payloads, in both request and response directions.
- */
- private static class CreateIkeSaHelper {
- public static List<IkePayload> getIkeInitSaRequestPayloads(
- IkeSaProposal[] saProposals,
- long initIkeSpi,
- long respIkeSpi,
- InetAddress localAddr,
- InetAddress remoteAddr,
- int localPort,
- int remotePort)
- throws IOException {
- List<IkePayload> payloadList =
- getCreateIkeSaPayloads(IkeSaPayload.createInitialIkeSaPayload(saProposals));
-
- // Though RFC says Notify-NAT payload is "just after the Ni and Nr payloads (before the
- // optional CERTREQ payload)", it also says recipient MUST NOT reject " messages in
- // which the payloads were not in the "right" order" due to the lack of clarity of the
- // payload order.
- payloadList.add(
- new IkeNotifyPayload(
- NOTIFY_TYPE_NAT_DETECTION_SOURCE_IP,
- IkeNotifyPayload.generateNatDetectionData(
- initIkeSpi, respIkeSpi, localAddr, localPort)));
- payloadList.add(
- new IkeNotifyPayload(
- NOTIFY_TYPE_NAT_DETECTION_DESTINATION_IP,
- IkeNotifyPayload.generateNatDetectionData(
- initIkeSpi, respIkeSpi, remoteAddr, remotePort)));
- return payloadList;
- }
-
- public static List<IkePayload> getRekeyIkeSaRequestPayloads(
- IkeSaProposal[] saProposals, InetAddress localAddr) throws IOException {
- if (localAddr == null) {
- throw new IllegalArgumentException("Local address was null for rekey");
- }
-
- return getCreateIkeSaPayloads(
- IkeSaPayload.createRekeyIkeSaRequestPayload(saProposals, localAddr));
- }
-
- public static List<IkePayload> getRekeyIkeSaResponsePayloads(
- byte respProposalNumber, IkeSaProposal saProposal, InetAddress localAddr)
- throws IOException {
- if (localAddr == null) {
- throw new IllegalArgumentException("Local address was null for rekey");
- }
-
- return getCreateIkeSaPayloads(
- IkeSaPayload.createRekeyIkeSaResponsePayload(
- respProposalNumber, saProposal, localAddr));
- }
-
- /**
- * Builds the initial or rekey IKE creation payloads.
- *
- * <p>Will return a non-empty list of IkePayloads, the first of which WILL be the SA payload
- */
- private static List<IkePayload> getCreateIkeSaPayloads(IkeSaPayload saPayload)
- throws IOException {
- if (saPayload.proposalList.size() == 0) {
- throw new IllegalArgumentException("Invalid SA proposal list - was empty");
- }
-
- List<IkePayload> payloadList = new ArrayList<>(3);
-
- payloadList.add(saPayload);
- payloadList.add(new IkeNoncePayload());
-
- // SaPropoals.Builder guarantees that each SA proposal has at least one DH group.
- DhGroupTransform dhGroupTransform =
- ((IkeProposal) saPayload.proposalList.get(0))
- .saProposal
- .getDhGroupTransforms()[0];
- payloadList.add(new IkeKePayload(dhGroupTransform.id));
-
- return payloadList;
- }
- }
-}
diff --git a/src/java/com/android/internal/net/ipsec/ike/SaRecord.java b/src/java/com/android/internal/net/ipsec/ike/SaRecord.java
deleted file mode 100644
index 035af175..00000000
--- a/src/java/com/android/internal/net/ipsec/ike/SaRecord.java
+++ /dev/null
@@ -1,1098 +0,0 @@
-/*
- * Copyright (C) 2019 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;
-
-import static android.net.ipsec.ike.IkeManager.getIkeLog;
-
-import android.annotation.Nullable;
-import android.content.Context;
-import android.net.IpSecManager;
-import android.net.IpSecManager.ResourceUnavailableException;
-import android.net.IpSecManager.SecurityParameterIndex;
-import android.net.IpSecManager.SpiUnavailableException;
-import android.net.IpSecManager.UdpEncapsulationSocket;
-import android.net.IpSecTransform;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.net.ipsec.ike.IkeLocalRequestScheduler.ChildLocalRequest;
-import com.android.internal.net.ipsec.ike.IkeLocalRequestScheduler.LocalRequest;
-import com.android.internal.net.ipsec.ike.IkeSessionStateMachine.IkeSecurityParameterIndex;
-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;
-import com.android.internal.net.ipsec.ike.message.IkeKePayload;
-import com.android.internal.net.ipsec.ike.message.IkeMessage;
-import com.android.internal.net.ipsec.ike.message.IkeMessage.DecodeResultPartial;
-import com.android.internal.net.ipsec.ike.message.IkeNoncePayload;
-import com.android.internal.net.ipsec.ike.message.IkePayload;
-
-import dalvik.system.CloseGuard;
-
-import java.io.IOException;
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.nio.ByteBuffer;
-import java.security.GeneralSecurityException;
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * SaRecord represents common information of an IKE SA and a Child SA.
- *
- * <p>When doing rekey, there can be multiple SAs in the same IkeSessionStateMachine or
- * ChildSessionStateMachine, where they use same cryptographic algorithms but with different keys.
- * We store cryptographic algorithms and unchanged SA configurations in IkeSessionOptions or
- * ChildSessionOptions and store changed information including keys, SPIs, and nonces in SaRecord.
- *
- * <p>All keys are named by the key type plus the source of the traffic this key is protecting. For
- * example, "mSkAi" represents the integrity key that protects traffic from the SA initiator to the
- * SA responder.
- *
- * <p>Except for keys, all other paramters (SPIs, nonces and messages) are named by the creator. For
- * example, "initSPI" represents a SPI that is created by the SA initiator.
- */
-public abstract class SaRecord implements AutoCloseable {
- private static ISaRecordHelper sSaRecordHelper = new SaRecordHelper();
- private static IIpSecTransformHelper sIpSecTransformHelper = new IpSecTransformHelper();
-
- /** Flag indicates if this SA is locally initiated */
- public final boolean isLocalInit;
-
- public final byte[] nonceInitiator;
- public final byte[] nonceResponder;
-
- private final byte[] mSkAi;
- private final byte[] mSkAr;
- private final byte[] mSkEi;
- private final byte[] mSkEr;
-
- private final LocalRequest mFutureRekeyEvent;
-
- private final CloseGuard mCloseGuard = CloseGuard.get();
-
- /** Package private */
- SaRecord(
- boolean localInit,
- byte[] nonceInit,
- byte[] nonceResp,
- byte[] skAi,
- byte[] skAr,
- byte[] skEi,
- byte[] skEr,
- LocalRequest futureRekeyEvent) {
- isLocalInit = localInit;
- nonceInitiator = nonceInit;
- nonceResponder = nonceResp;
-
- mSkAi = skAi;
- mSkAr = skAr;
- mSkEi = skEi;
- mSkEr = skEr;
-
- logKey("SK_ai", skAi);
- logKey("SK_ar", skAr);
- logKey("SK_ei", skEi);
- logKey("SK_er", skEr);
-
- mFutureRekeyEvent = futureRekeyEvent;
-
- mCloseGuard.open("close");
- }
-
- private void logKey(String type, byte[] key) {
- getIkeLog().d(getTag(), type + ": " + getIkeLog().pii(key));
- }
-
- protected abstract String getTag();
-
- /**
- * Get the integrity key for calculate integrity checksum for an outbound packet.
- *
- * @return the integrity key in a byte array, which will be empty if integrity algorithm is not
- * used in this SA.
- */
- public byte[] getOutboundIntegrityKey() {
- return isLocalInit ? mSkAi : mSkAr;
- }
-
- /**
- * Get the integrity key to authenticate an inbound packet.
- *
- * @return the integrity key in a byte array, which will be empty if integrity algorithm is not
- * used in this SA.
- */
- public byte[] getInboundIntegrityKey() {
- return isLocalInit ? mSkAr : mSkAi;
- }
-
- /**
- * Get the encryption key for protecting an outbound packet.
- *
- * @return the encryption key in a byte array.
- */
- public byte[] getOutboundEncryptionKey() {
- return isLocalInit ? mSkEi : mSkEr;
- }
-
- /**
- * Get the decryption key for an inbound packet.
- *
- * @return the decryption key in a byte array.
- */
- public byte[] getInboundDecryptionKey() {
- return isLocalInit ? mSkEr : mSkEi;
- }
-
- /** Check that the SaRecord was closed properly. */
- @Override
- protected void finalize() throws Throwable {
- if (mCloseGuard != null) {
- mCloseGuard.warnIfOpen();
- }
- close();
- }
-
- @Override
- public void close() {
- mFutureRekeyEvent.cancel();
- }
-
- /** Package private */
- LocalRequest getFutureRekeyEvent() {
- return mFutureRekeyEvent;
- }
-
- /** Package private */
- @VisibleForTesting
- static void setSaRecordHelper(ISaRecordHelper helper) {
- sSaRecordHelper = helper;
- }
-
- /** Package private */
- @VisibleForTesting
- static void setIpSecTransformHelper(IIpSecTransformHelper helper) {
- sIpSecTransformHelper = helper;
- }
-
- /**
- * SaRecordHelper implements methods for constructing SaRecord.
- *
- * <p>Package private
- */
- static class SaRecordHelper implements ISaRecordHelper {
- @Override
- public IkeSaRecord makeFirstIkeSaRecord(
- IkeMessage initRequest,
- IkeMessage initResponse,
- IkeSaRecordConfig ikeSaRecordConfig)
- throws GeneralSecurityException {
- // Extract nonces
- byte[] nonceInit =
- initRequest.getPayloadForType(
- IkePayload.PAYLOAD_TYPE_NONCE, IkeNoncePayload.class)
- .nonceData;
- byte[] nonceResp =
- initResponse.getPayloadForType(
- IkePayload.PAYLOAD_TYPE_NONCE, IkeNoncePayload.class)
- .nonceData;
-
- // Get SKEYSEED
- byte[] sharedDhKey = getSharedKey(initRequest, initResponse);
- byte[] sKeySeed =
- ikeSaRecordConfig.prf.generateSKeySeed(nonceInit, nonceResp, sharedDhKey);
-
- return makeIkeSaRecord(sKeySeed, nonceInit, nonceResp, ikeSaRecordConfig);
- }
-
- @Override
- public IkeSaRecord makeRekeyedIkeSaRecord(
- IkeSaRecord oldSaRecord,
- IkeMacPrf oldPrf,
- IkeMessage rekeyRequest,
- IkeMessage rekeyResponse,
- IkeSaRecordConfig ikeSaRecordConfig)
- throws GeneralSecurityException {
- // Extract nonces
- byte[] nonceInit =
- rekeyRequest.getPayloadForType(
- IkePayload.PAYLOAD_TYPE_NONCE, IkeNoncePayload.class)
- .nonceData;
- byte[] nonceResp =
- rekeyResponse.getPayloadForType(
- IkePayload.PAYLOAD_TYPE_NONCE, IkeNoncePayload.class)
- .nonceData;
-
- // Get SKEYSEED
- IkeMessage localMsg = ikeSaRecordConfig.isLocalInit ? rekeyRequest : rekeyResponse;
- IkeMessage remoteMsg = ikeSaRecordConfig.isLocalInit ? rekeyResponse : rekeyRequest;
-
- byte[] sharedDhKey = getSharedKey(localMsg, remoteMsg);
- byte[] sKeySeed =
- oldPrf.generateRekeyedSKeySeed(
- oldSaRecord.mSkD, nonceInit, nonceResp, sharedDhKey);
-
- return makeIkeSaRecord(sKeySeed, nonceInit, nonceResp, ikeSaRecordConfig);
- }
-
- private byte[] getSharedKey(IkeMessage keLocalMessage, IkeMessage keRemoteMessage)
- throws GeneralSecurityException {
- IkeKePayload keLocalPayload =
- keLocalMessage.getPayloadForType(
- IkePayload.PAYLOAD_TYPE_KE, IkeKePayload.class);
- IkeKePayload keRemotePayload =
- keRemoteMessage.getPayloadForType(
- IkePayload.PAYLOAD_TYPE_KE, IkeKePayload.class);
-
- return IkeKePayload.getSharedKey(
- keLocalPayload.localPrivateKey, keRemotePayload.keyExchangeData);
- }
-
- /**
- * Package private method for calculating keys and construct IkeSaRecord.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#section-2.13">RFC 7296, Internet Key
- * Exchange Protocol Version 2 (IKEv2), Generating Keying Material</a>
- */
- @VisibleForTesting
- IkeSaRecord makeIkeSaRecord(
- byte[] sKeySeed,
- byte[] nonceInit,
- byte[] nonceResp,
- IkeSaRecordConfig ikeSaRecordConfig) {
- // Build data to sign for generating the keying material.
- ByteBuffer bufferToSign =
- ByteBuffer.allocate(
- nonceInit.length + nonceResp.length + 2 * IkePayload.SPI_LEN_IKE);
-
- IkeSecurityParameterIndex initSpi = ikeSaRecordConfig.initSpi;
- IkeSecurityParameterIndex respSpi = ikeSaRecordConfig.respSpi;
- IkeMacPrf prf = ikeSaRecordConfig.prf;
- int integrityKeyLength = ikeSaRecordConfig.integrityKeyLength;
- int encryptionKeyLength = ikeSaRecordConfig.encryptionKeyLength;
-
- bufferToSign
- .put(nonceInit)
- .put(nonceResp)
- .putLong(initSpi.getSpi())
- .putLong(respSpi.getSpi());
-
- // Get length of the keying material according to RFC 7296, 2.13 and 2.14. The length of
- // SK_D is always equal to the length of PRF key.
- int skDLength = prf.getKeyLength();
- int keyMaterialLen =
- skDLength
- + 2 * integrityKeyLength
- + 2 * encryptionKeyLength
- + 2 * prf.getKeyLength();
- byte[] keyMat = prf.generateKeyMat(sKeySeed, bufferToSign.array(), keyMaterialLen);
-
- // Extract keys.
- byte[] skD = new byte[skDLength];
- byte[] skAi = new byte[integrityKeyLength];
- byte[] skAr = new byte[integrityKeyLength];
- byte[] skEi = new byte[encryptionKeyLength];
- byte[] skEr = new byte[encryptionKeyLength];
- byte[] skPi = new byte[prf.getKeyLength()];
- byte[] skPr = new byte[prf.getKeyLength()];
-
- ByteBuffer keyMatBuffer = ByteBuffer.wrap(keyMat);
- keyMatBuffer.get(skD).get(skAi).get(skAr).get(skEi).get(skEr).get(skPi).get(skPr);
- return new IkeSaRecord(
- initSpi,
- respSpi,
- ikeSaRecordConfig.isLocalInit,
- nonceInit,
- nonceResp,
- skD,
- skAi,
- skAr,
- skEi,
- skEr,
- skPi,
- skPr,
- ikeSaRecordConfig.futureRekeyEvent);
- }
-
- @Override
- public ChildSaRecord makeChildSaRecord(
- List<IkePayload> reqPayloads,
- List<IkePayload> respPayloads,
- ChildSaRecordConfig childSaRecordConfig)
- throws GeneralSecurityException, ResourceUnavailableException,
- SpiUnavailableException, IOException {
- // Extract nonces. Encoding/Decoding of payload list guarantees that there is only one
- // nonce payload in the reqPayloads and respPayloads lists
- byte[] nonceInit =
- IkePayload.getPayloadForTypeInProvidedList(
- IkePayload.PAYLOAD_TYPE_NONCE,
- IkeNoncePayload.class,
- reqPayloads)
- .nonceData;
- byte[] nonceResp =
- IkePayload.getPayloadForTypeInProvidedList(
- IkePayload.PAYLOAD_TYPE_NONCE,
- IkeNoncePayload.class,
- respPayloads)
- .nonceData;
-
- // Check if KE Payload exists and get DH shared key. Encoding/Decoding of payload list
- // guarantees that there is either no KE payload in the reqPayloads and respPayloads
- // lists, or only one KE payload in each list.
- byte[] sharedDhKey = new byte[0];
- IkeKePayload keInitPayload =
- IkePayload.getPayloadForTypeInProvidedList(
- IkePayload.PAYLOAD_TYPE_KE, IkeKePayload.class, reqPayloads);
- if (keInitPayload != null) {
- IkeKePayload keRespPayload =
- IkePayload.getPayloadForTypeInProvidedList(
- IkePayload.PAYLOAD_TYPE_KE, IkeKePayload.class, respPayloads);
- sharedDhKey =
- IkeKePayload.getSharedKey(
- keInitPayload.localPrivateKey, keRespPayload.keyExchangeData);
- }
-
- return makeChildSaRecord(sharedDhKey, nonceInit, nonceResp, childSaRecordConfig);
- }
- /**
- * Package private method for calculating keys, build IpSecTransforms and construct
- * ChildSaRecord.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#section-2.17">RFC 7296, Internet Key
- * Exchange Protocol Version 2 (IKEv2), Generating Keying Material for Child SAs</a>
- */
- @VisibleForTesting
- ChildSaRecord makeChildSaRecord(
- byte[] sharedKey,
- byte[] nonceInit,
- byte[] nonceResp,
- ChildSaRecordConfig childSaRecordConfig)
- throws ResourceUnavailableException, SpiUnavailableException, IOException {
- // Build data to sign for generating the keying material.
- ByteBuffer bufferToSign =
- ByteBuffer.allocate(sharedKey.length + nonceInit.length + nonceResp.length);
- bufferToSign.put(sharedKey).put(nonceInit).put(nonceResp);
-
- // Get length of the keying material according to RFC 7296, 2.17.
- int encryptionKeyLength = childSaRecordConfig.encryptionAlgo.getKeyLength();
- int integrityKeyLength =
- childSaRecordConfig.hasIntegrityAlgo
- ? childSaRecordConfig.integrityAlgo.getKeyLength()
- : 0;
- int keyMaterialLen = 2 * encryptionKeyLength + 2 * integrityKeyLength;
- byte[] keyMat =
- childSaRecordConfig.ikePrf.generateKeyMat(
- childSaRecordConfig.skD, bufferToSign.array(), keyMaterialLen);
-
- // Extract keys according to the order that keys carrying data from initiator to
- // responder are taken before keys for the other direction and encryption keys are taken
- // before integrity keys.
- byte[] skEi = new byte[encryptionKeyLength];
- byte[] skAi = new byte[integrityKeyLength];
- byte[] skEr = new byte[encryptionKeyLength];
- byte[] skAr = new byte[integrityKeyLength];
-
- ByteBuffer keyMatBuffer = ByteBuffer.wrap(keyMat);
- keyMatBuffer.get(skEi).get(skAi).get(skEr).get(skAr);
-
- // IpSecTransform for traffic from the initiator
- IpSecTransform initTransform = null;
- // IpSecTransform for traffic from the responder
- IpSecTransform respTransform = null;
- try {
- // Build IpSecTransform
- initTransform =
- sIpSecTransformHelper.makeIpSecTransform(
- childSaRecordConfig.context,
- childSaRecordConfig.initAddress /*source address*/,
- childSaRecordConfig.udpEncapSocket,
- childSaRecordConfig.respSpi /*destination SPI*/,
- childSaRecordConfig.integrityAlgo,
- childSaRecordConfig.encryptionAlgo,
- skAi,
- skEi,
- childSaRecordConfig.isTransport);
- respTransform =
- sIpSecTransformHelper.makeIpSecTransform(
- childSaRecordConfig.context,
- childSaRecordConfig.respAddress /*source address*/,
- childSaRecordConfig.udpEncapSocket,
- childSaRecordConfig.initSpi /*destination SPI*/,
- childSaRecordConfig.integrityAlgo,
- childSaRecordConfig.encryptionAlgo,
- skAr,
- skEr,
- childSaRecordConfig.isTransport);
-
- int initSpi = childSaRecordConfig.initSpi.getSpi();
- int respSpi = childSaRecordConfig.respSpi.getSpi();
-
- boolean isLocalInit = childSaRecordConfig.isLocalInit;
- int inSpi = isLocalInit ? initSpi : respSpi;
- int outSpi = isLocalInit ? respSpi : initSpi;
- IpSecTransform inTransform = isLocalInit ? respTransform : initTransform;
- IpSecTransform outTransform = isLocalInit ? initTransform : respTransform;
-
- return new ChildSaRecord(
- inSpi,
- outSpi,
- isLocalInit,
- nonceInit,
- nonceResp,
- skAi,
- skAr,
- skEi,
- skEr,
- inTransform,
- outTransform,
- childSaRecordConfig.futureRekeyEvent);
-
- } catch (Exception e) {
- if (initTransform != null) initTransform.close();
- if (respTransform != null) respTransform.close();
- throw e;
- }
- }
- }
-
- /**
- * IpSecTransformHelper implements the IIpSecTransformHelper interface for constructing {@link
- * IpSecTransform}}.
- *
- * <p>Package private
- */
- static class IpSecTransformHelper implements IIpSecTransformHelper {
- private static final String TAG = "IpSecTransformHelper";
-
- @Override
- public IpSecTransform makeIpSecTransform(
- Context context,
- InetAddress sourceAddress,
- UdpEncapsulationSocket udpEncapSocket,
- IpSecManager.SecurityParameterIndex spi,
- @Nullable IkeMacIntegrity integrityAlgo,
- IkeCipher encryptionAlgo,
- byte[] integrityKey,
- byte[] encryptionKey,
- boolean isTransport)
- throws ResourceUnavailableException, SpiUnavailableException, IOException {
- IpSecTransform.Builder builder = new IpSecTransform.Builder(context);
-
- if (encryptionAlgo.isAead()) {
- builder.setAuthenticatedEncryption(
- encryptionAlgo.buildIpSecAlgorithmWithKey(encryptionKey));
- } else {
- builder.setEncryption(encryptionAlgo.buildIpSecAlgorithmWithKey(encryptionKey));
- builder.setAuthentication(integrityAlgo.buildIpSecAlgorithmWithKey(integrityKey));
- }
-
- if (udpEncapSocket != null && sourceAddress instanceof Inet6Address) {
- getIkeLog().wtf(TAG, "Kernel does not support UDP encapsulation for IPv6 SAs");
- }
- if (udpEncapSocket != null && sourceAddress instanceof Inet4Address) {
- builder.setIpv4Encapsulation(udpEncapSocket, IkeSocket.IKE_SERVER_PORT);
- }
-
- if (isTransport) {
- return builder.buildTransportModeTransform(sourceAddress, spi);
- } else {
- return builder.buildTunnelModeTransform(sourceAddress, spi);
- }
- }
- }
-
- /** Package private class to group parameters for building a ChildSaRecord. */
- @VisibleForTesting
- static final class ChildSaRecordConfig {
- public final Context context;
- public final SecurityParameterIndex initSpi;
- public final SecurityParameterIndex respSpi;
- public final InetAddress initAddress;
- public final InetAddress respAddress;
- @Nullable public final UdpEncapsulationSocket udpEncapSocket;
- public final IkeMacPrf ikePrf;
- @Nullable public final IkeMacIntegrity integrityAlgo;
- public final IkeCipher encryptionAlgo;
- public final byte[] skD;
- public final boolean isTransport;
- public final boolean isLocalInit;
- public final boolean hasIntegrityAlgo;
- public final ChildLocalRequest futureRekeyEvent;
-
- ChildSaRecordConfig(
- Context context,
- SecurityParameterIndex initSpi,
- SecurityParameterIndex respSpi,
- InetAddress localAddress,
- InetAddress remoteAddress,
- @Nullable UdpEncapsulationSocket udpEncapSocket,
- IkeMacPrf ikePrf,
- @Nullable IkeMacIntegrity integrityAlgo,
- IkeCipher encryptionAlgo,
- byte[] skD,
- boolean isTransport,
- boolean isLocalInit,
- ChildLocalRequest futureRekeyEvent) {
- this.context = context;
- this.initSpi = initSpi;
- this.respSpi = respSpi;
- this.initAddress = isLocalInit ? localAddress : remoteAddress;
- this.respAddress = isLocalInit ? remoteAddress : localAddress;
- this.udpEncapSocket = udpEncapSocket;
- this.ikePrf = ikePrf;
- this.integrityAlgo = integrityAlgo;
- this.encryptionAlgo = encryptionAlgo;
- this.skD = skD;
- this.isTransport = isTransport;
- this.isLocalInit = isLocalInit;
- hasIntegrityAlgo = (integrityAlgo != null);
- this.futureRekeyEvent = futureRekeyEvent;
- }
- }
-
- /** IkeSaRecord represents an IKE SA. */
- public static class IkeSaRecord extends SaRecord implements Comparable<IkeSaRecord> {
- private static final String TAG = "IkeSaRecord";
-
- /** SPI of IKE SA initiator */
- private final IkeSecurityParameterIndex mInitiatorSpiResource;
- /** SPI of IKE SA responder */
- private final IkeSecurityParameterIndex mResponderSpiResource;
-
- private final byte[] mSkD;
- private final byte[] mSkPi;
- private final byte[] mSkPr;
-
- private int mLocalRequestMessageId;
- private int mRemoteRequestMessageId;
-
- private DecodeResultPartial mCollectedReqFragments;
- private DecodeResultPartial mCollectedRespFragments;
-
- private byte[] mLastRecivedReqFirstPacket;
- private List<byte[]> mLastSentRespAllPackets;
-
- /** Package private */
- IkeSaRecord(
- IkeSecurityParameterIndex initSpi,
- IkeSecurityParameterIndex respSpi,
- boolean localInit,
- byte[] nonceInit,
- byte[] nonceResp,
- byte[] skD,
- byte[] skAi,
- byte[] skAr,
- byte[] skEi,
- byte[] skEr,
- byte[] skPi,
- byte[] skPr,
- LocalRequest futureRekeyEvent) {
- super(localInit, nonceInit, nonceResp, skAi, skAr, skEi, skEr, futureRekeyEvent);
-
- mInitiatorSpiResource = initSpi;
- mResponderSpiResource = respSpi;
-
- mSkD = skD;
- mSkPi = skPi;
- mSkPr = skPr;
-
- mLocalRequestMessageId = 0;
- mRemoteRequestMessageId = 0;
-
- mCollectedReqFragments = null;
- mCollectedRespFragments = null;
-
- logKey("SK_d", skD);
- logKey("SK_pi", skPi);
- logKey("SK_pr", skPr);
- }
-
- /**
- * Package private interface for IkeSessionStateMachien to construct an IkeSaRecord
- * instance.
- */
- static IkeSaRecord makeFirstIkeSaRecord(
- IkeMessage initRequest,
- IkeMessage initResponse,
- IkeSecurityParameterIndex initSpi,
- IkeSecurityParameterIndex respSpi,
- IkeMacPrf prf,
- int integrityKeyLength,
- int encryptionKeyLength,
- LocalRequest futureRekeyEvent)
- throws GeneralSecurityException {
- return sSaRecordHelper.makeFirstIkeSaRecord(
- initRequest,
- initResponse,
- new IkeSaRecordConfig(
- initSpi,
- respSpi,
- prf,
- integrityKeyLength,
- encryptionKeyLength,
- true /*isLocalInit*/,
- futureRekeyEvent));
- }
-
- /** Package private */
- static IkeSaRecord makeRekeyedIkeSaRecord(
- IkeSaRecord oldSaRecord,
- IkeMacPrf oldPrf,
- IkeMessage rekeyRequest,
- IkeMessage rekeyResponse,
- IkeSecurityParameterIndex initSpi,
- IkeSecurityParameterIndex respSpi,
- IkeMacPrf prf,
- int integrityKeyLength,
- int encryptionKeyLength,
- boolean isLocalInit,
- LocalRequest futureRekeyEvent)
- throws GeneralSecurityException {
- return sSaRecordHelper.makeRekeyedIkeSaRecord(
- oldSaRecord,
- oldPrf,
- rekeyRequest,
- rekeyResponse,
- new IkeSaRecordConfig(
- initSpi,
- respSpi,
- prf,
- integrityKeyLength,
- encryptionKeyLength,
- isLocalInit,
- futureRekeyEvent));
- }
-
- private void logKey(String type, byte[] key) {
- getIkeLog().d(TAG, type + ": " + getIkeLog().pii(key));
- }
-
- @Override
- protected String getTag() {
- return TAG;
- }
-
- /** Package private */
- long getInitiatorSpi() {
- return mInitiatorSpiResource.getSpi();
- }
-
- /** Package private */
- long getResponderSpi() {
- return mResponderSpiResource.getSpi();
- }
-
- /** Package private */
- long getLocalSpi() {
- return isLocalInit ? mInitiatorSpiResource.getSpi() : mResponderSpiResource.getSpi();
- }
-
- /** Package private */
- long getRemoteSpi() {
- return isLocalInit ? mResponderSpiResource.getSpi() : mInitiatorSpiResource.getSpi();
- }
-
- /** Package private */
- byte[] getSkD() {
- return mSkD;
- }
-
- /**
- * Get the PRF key of IKE initiator for building an outbound Auth Payload.
- *
- * @return the PRF key in a byte array.
- */
- public byte[] getSkPi() {
- return mSkPi;
- }
-
- /**
- * Get the PRF key of IKE responder for validating an inbound Auth Payload.
- *
- * @return the PRF key in a byte array.
- */
- public byte[] getSkPr() {
- return mSkPr;
- }
-
- /**
- * Compare with a specific IkeSaRecord
- *
- * @param record IkeSaRecord to be compared.
- * @return a negative integer if input IkeSaRecord contains lowest nonce; a positive integer
- * if this IkeSaRecord has lowest nonce; return zero if lowest nonces of two
- * IkeSaRecords match.
- */
- public int compareTo(IkeSaRecord record) {
- // TODO: Implement it b/122924815.
- return 1;
- }
-
- /**
- * Get current message ID for the local requesting window.
- *
- * <p>Called for building an outbound request or for validating the message ID of an inbound
- * response.
- *
- * @return the local request message ID.
- */
- public int getLocalRequestMessageId() {
- return mLocalRequestMessageId;
- }
-
- /**
- * Get current message ID for the remote requesting window.
- *
- * <p>Called for validating the message ID of an inbound request. If the message ID of the
- * inbound request is smaller than the current remote message ID by one, it means the
- * message is a retransmitted request.
- *
- * @return the remote request message ID
- */
- public int getRemoteRequestMessageId() {
- return mRemoteRequestMessageId;
- }
-
- /**
- * Increment the local request message ID by one.
- *
- * <p>It should be called when IKE library has received an authenticated and protected
- * response with the correct local request message ID.
- */
- public void incrementLocalRequestMessageId() {
- mLocalRequestMessageId++;
- }
-
- /**
- * Increment the remote request message ID by one.
- *
- * <p>It should be called when IKE library has received an authenticated and protected
- * request with the correct remote request message ID.
- */
- public void incrementRemoteRequestMessageId() {
- mRemoteRequestMessageId++;
- }
-
- /** Return all collected IKE fragments that have been collected. */
- public DecodeResultPartial getCollectedFragments(boolean isResp) {
- return isResp ? mCollectedRespFragments : mCollectedReqFragments;
- }
-
- /**
- * Update collected IKE fragments when receiving new IKE fragment.
- *
- * <p>TODO: b/140264067 Investigate if we need to support reassembling timeout. It is safe
- * to do not support it because as an initiator, we will re-transmit the request anyway. As
- * a responder, caching these fragments until getting a complete message won't affect
- * anything.
- */
- public void updateCollectedFragments(
- DecodeResultPartial updatedFragments, boolean isResp) {
- if (isResp) {
- mCollectedRespFragments = updatedFragments;
- } else {
- mCollectedReqFragments = updatedFragments;
- }
- }
-
- /** Reset collected IKE fragemnts */
- public void resetCollectedFragments(boolean isResp) {
- updateCollectedFragments(null, isResp);
- }
-
- /** Update first packet of last received request. */
- public void updateLastReceivedReqFirstPacket(byte[] reqPacket) {
- mLastRecivedReqFirstPacket = reqPacket;
- }
-
- /** Update all packets of last sent response. */
- public void updateLastSentRespAllPackets(List<byte[]> respPacketList) {
- mLastSentRespAllPackets = respPacketList;
- }
-
- /** Returns if received IKE packet is the first packet of a re-transmistted request. */
- public boolean isRetransmittedRequest(byte[] request) {
- return Arrays.equals(mLastRecivedReqFirstPacket, request);
- }
-
- /** Get all encoded packets of last sent response. */
- public List<byte[]> getLastSentRespAllPackets() {
- return mLastSentRespAllPackets;
- }
-
- /** Release IKE SPI resource. */
- @Override
- public void close() {
- super.close();
- mInitiatorSpiResource.close();
- mResponderSpiResource.close();
- }
- }
-
- /** Package private class that groups parameters to construct an IkeSaRecord instance. */
- @VisibleForTesting
- static class IkeSaRecordConfig {
- public final IkeSecurityParameterIndex initSpi;
- public final IkeSecurityParameterIndex respSpi;
- public final IkeMacPrf prf;
- public final int integrityKeyLength;
- public final int encryptionKeyLength;
- public final boolean isLocalInit;
- public final LocalRequest futureRekeyEvent;
-
- IkeSaRecordConfig(
- IkeSecurityParameterIndex initSpi,
- IkeSecurityParameterIndex respSpi,
- IkeMacPrf prf,
- int integrityKeyLength,
- int encryptionKeyLength,
- boolean isLocalInit,
- LocalRequest futureRekeyEvent) {
- this.initSpi = initSpi;
- this.respSpi = respSpi;
- this.prf = prf;
- this.integrityKeyLength = integrityKeyLength;
- this.encryptionKeyLength = encryptionKeyLength;
- this.isLocalInit = isLocalInit;
- this.futureRekeyEvent = futureRekeyEvent;
- }
- }
-
- /** ChildSaRecord represents an Child SA. */
- public static class ChildSaRecord extends SaRecord implements Comparable<ChildSaRecord> {
- private static final String TAG = "ChildSaRecord";
-
- /** Locally generated SPI for receiving IPsec Packet. */
- private final int mInboundSpi;
- /** Remotely generated SPI for sending IPsec Packet. */
- private final int mOutboundSpi;
-
- /** IPsec Transform applied to traffic towards the host. */
- private final IpSecTransform mInboundTransform;
- /** IPsec Transform applied to traffic from the host. */
- private final IpSecTransform mOutboundTransform;
-
- /** Package private */
- ChildSaRecord(
- int inSpi,
- int outSpi,
- boolean localInit,
- byte[] nonceInit,
- byte[] nonceResp,
- byte[] skAi,
- byte[] skAr,
- byte[] skEi,
- byte[] skEr,
- IpSecTransform inTransform,
- IpSecTransform outTransform,
- ChildLocalRequest futureRekeyEvent) {
- super(localInit, nonceInit, nonceResp, skAi, skAr, skEi, skEr, futureRekeyEvent);
-
- mInboundSpi = inSpi;
- mOutboundSpi = outSpi;
- mInboundTransform = inTransform;
- mOutboundTransform = outTransform;
- }
-
- /**
- * Package private interface for ChildSessionStateMachine to construct a ChildSaRecord
- * instance.
- */
- static ChildSaRecord makeChildSaRecord(
- Context context,
- List<IkePayload> reqPayloads,
- List<IkePayload> respPayloads,
- SecurityParameterIndex initSpi,
- SecurityParameterIndex respSpi,
- InetAddress localAddress,
- InetAddress remoteAddress,
- @Nullable UdpEncapsulationSocket udpEncapSocket,
- IkeMacPrf prf,
- @Nullable IkeMacIntegrity integrityAlgo,
- IkeCipher encryptionAlgo,
- byte[] skD,
- boolean isTransport,
- boolean isLocalInit,
- ChildLocalRequest futureRekeyEvent)
- throws GeneralSecurityException, ResourceUnavailableException,
- SpiUnavailableException, IOException {
- return sSaRecordHelper.makeChildSaRecord(
- reqPayloads,
- respPayloads,
- new ChildSaRecordConfig(
- context,
- initSpi,
- respSpi,
- localAddress,
- remoteAddress,
- udpEncapSocket,
- prf,
- integrityAlgo,
- encryptionAlgo,
- skD,
- isTransport,
- isLocalInit,
- futureRekeyEvent));
- }
-
- @Override
- protected String getTag() {
- return TAG;
- }
-
- /** Package private */
- int getLocalSpi() {
- return mInboundSpi;
- }
-
- /** Package private */
- int getRemoteSpi() {
- return mOutboundSpi;
- }
-
- /** Package private */
- IpSecTransform getInboundIpSecTransform() {
- return mInboundTransform;
- }
-
- /** Package private */
- IpSecTransform getOutboundIpSecTransform() {
- return mOutboundTransform;
- }
-
- /**
- * Compare with a specific ChildSaRecord
- *
- * @param record ChildSaRecord to be compared.
- * @return a negative integer if input ChildSaRecord contains lowest nonce; a positive
- * integer if this ChildSaRecord has lowest nonce; return zero if lowest nonces of two
- * ChildSaRecord match.
- */
- public int compareTo(ChildSaRecord record) {
- // TODO: Implement it b/122924815
- return 1;
- }
-
- /** Release IpSecTransform pair. */
- @Override
- public void close() {
- super.close();
- mInboundTransform.close();
- mOutboundTransform.close();
- }
- }
-
- /**
- * ISaRecordHelper provides a package private interface for constructing SaRecord.
- *
- * <p>ISaRecordHelper exists so that the interface is injectable for testing.
- */
- interface ISaRecordHelper {
- /**
- * Construct IkeSaRecord as results of IKE initial exchange.
- *
- * @param initRequest IKE_INIT request.
- * @param initResponse IKE_INIT request.
- * @param ikeSaRecordConfig that contains IKE SPI resources and negotiated algorithm
- * information for constructing an IkeSaRecord instance.
- * @return ikeSaRecord for initial IKE SA.
- * @throws GeneralSecurityException if the DH public key in the response is invalid.
- */
- IkeSaRecord makeFirstIkeSaRecord(
- IkeMessage initRequest,
- IkeMessage initResponse,
- IkeSaRecordConfig ikeSaRecordConfig)
- throws GeneralSecurityException;
-
- /**
- * Construct new IkeSaRecord when doing rekey.
- *
- * @param oldSaRecord old IKE SA
- * @param oldPrf the PRF function from the old SA
- * @param rekeyRequest Rekey IKE request.
- * @param rekeyResponse Rekey IKE response.
- * @param ikeSaRecordConfig that contains IKE SPI resources and negotiated algorithm
- * information for constructing an IkeSaRecord instance.
- * @return ikeSaRecord for new IKE SA.
- */
- IkeSaRecord makeRekeyedIkeSaRecord(
- IkeSaRecord oldSaRecord,
- IkeMacPrf oldPrf,
- IkeMessage rekeyRequest,
- IkeMessage rekeyResponse,
- IkeSaRecordConfig ikeSaRecordConfig)
- throws GeneralSecurityException;
-
- /**
- * Construct ChildSaRecord and generate IpSecTransform pairs.
- *
- * @param reqPayloads payload list in request.
- * @param respPayloads payload list in response.
- * @param childSaRecordConfig the grouped parameters for constructing ChildSaRecord.
- * @return new Child SA.
- */
- ChildSaRecord makeChildSaRecord(
- List<IkePayload> reqPayloads,
- List<IkePayload> respPayloads,
- ChildSaRecordConfig childSaRecordConfig)
- throws GeneralSecurityException, ResourceUnavailableException,
- SpiUnavailableException, IOException;
- }
-
- /**
- * IIpSecTransformHelper provides a package private interface to construct {@link
- * IpSecTransform}
- *
- * <p>IIpSecTransformHelper exists so that the interface is injectable for testing.
- */
- @VisibleForTesting
- interface IIpSecTransformHelper {
- /**
- * Construct an instance of {@link IpSecTransform}
- *
- * @param context current context
- * @param sourceAddress the source {@code InetAddress} of traffic on sockets of interfaces
- * that will use this transform
- * @param udpEncapSocket the UDP-Encap socket that allows IpSec traffic to pass through a
- * NAT. Null if no NAT exists.
- * @param spi a unique {@link IpSecManager.SecurityParameterIndex} to identify transformed
- * traffic
- * @param integrityAlgo specifying the authentication algorithm to be applied.
- * @param encryptionAlgo specifying the encryption algorithm or authenticated encryption
- * algorithm to be applied.
- * @param integrityKey the negotiated authentication key to be applied.
- * @param encryptionKey the negotiated encryption key to be applied.
- * @param isTransport the flag indicates if a transport or a tunnel mode transform will be
- * built.
- * @return an instance of {@link IpSecTransform}
- * @throws ResourceUnavailableException indicating that too many transforms are active
- * @throws SpiUnavailableException indicating the rare case where an SPI collides with an
- * existing transform
- * @throws IOException indicating other errors
- */
- IpSecTransform makeIpSecTransform(
- Context context,
- InetAddress sourceAddress,
- UdpEncapsulationSocket udpEncapSocket,
- IpSecManager.SecurityParameterIndex spi,
- @Nullable IkeMacIntegrity integrityAlgo,
- IkeCipher encryptionAlgo,
- byte[] integrityKey,
- byte[] encryptionKey,
- boolean isTransport)
- throws ResourceUnavailableException, SpiUnavailableException, IOException;
- }
-}
diff --git a/src/java/com/android/internal/net/ipsec/ike/crypto/IkeCipher.java b/src/java/com/android/internal/net/ipsec/ike/crypto/IkeCipher.java
deleted file mode 100644
index 33a8b37c..00000000
--- a/src/java/com/android/internal/net/ipsec/ike/crypto/IkeCipher.java
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * Copyright (C) 2019 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.crypto;
-
-import android.net.IpSecAlgorithm;
-import android.net.ipsec.ike.SaProposal;
-
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload.EncryptionTransform;
-
-import java.security.NoSuchAlgorithmException;
-import java.security.Provider;
-import java.security.SecureRandom;
-
-import javax.crypto.Cipher;
-import javax.crypto.NoSuchPaddingException;
-
-/**
- * IkeCipher contains common information of normal and combined mode encryption algorithms.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3.2">RFC 7296, Internet Key Exchange
- * Protocol Version 2 (IKEv2)</a>
- */
-public abstract class IkeCipher extends IkeCrypto {
- private static final int KEY_LEN_3DES = 24;
-
- private static final int IV_LEN_3DES = 8;
- private static final int IV_LEN_AES_CBC = 16;
- private static final int IV_LEN_AES_GCM = 8;
-
- private final boolean mIsAead;
- private final int mIvLen;
-
- protected final Cipher mCipher;
-
- protected IkeCipher(
- int algorithmId,
- int keyLength,
- int ivLength,
- String algorithmName,
- boolean isAead,
- Provider provider) {
- super(algorithmId, keyLength, algorithmName);
- mIvLen = ivLength;
- mIsAead = isAead;
-
- try {
- mCipher = Cipher.getInstance(getAlgorithmName(), provider);
- } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
- throw new IllegalArgumentException("Failed to construct " + getTypeString(), e);
- }
- }
-
- /**
- * Contruct an instance of IkeCipher.
- *
- * @param encryptionTransform the valid negotiated EncryptionTransform.
- * @param provider the security provider.
- * @return an instance of IkeCipher.
- */
- public static IkeCipher create(EncryptionTransform encryptionTransform, Provider provider) {
- int algorithmId = encryptionTransform.id;
-
- // Use specifiedKeyLength for algorithms with variable key length. Since
- // specifiedKeyLength are encoded in bits, it needs to be converted to bytes.
- switch (algorithmId) {
- case SaProposal.ENCRYPTION_ALGORITHM_3DES:
- return new IkeNormalModeCipher(
- algorithmId, KEY_LEN_3DES, IV_LEN_3DES, "DESede/CBC/NoPadding", provider);
- case SaProposal.ENCRYPTION_ALGORITHM_AES_CBC:
- return new IkeNormalModeCipher(
- algorithmId,
- encryptionTransform.getSpecifiedKeyLength() / 8,
- IV_LEN_AES_CBC,
- "AES/CBC/NoPadding",
- provider);
- case SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8:
- // Fall through
- case SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12:
- // Fall through
- case SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_16:
- // Fall through
- return new IkeCombinedModeCipher(
- algorithmId,
- encryptionTransform.getSpecifiedKeyLength() / 8,
- IV_LEN_AES_GCM,
- "AES/GCM/NoPadding",
- provider);
- default:
- throw new IllegalArgumentException(
- "Unrecognized Encryption Algorithm ID: " + algorithmId);
- }
- }
-
- /**
- * Check if this encryption algorithm is a combined-mode/AEAD algorithm.
- *
- * @return if this encryption algorithm is a combined-mode/AEAD algorithm.
- */
- public boolean isAead() {
- return mIsAead;
- }
-
- /**
- * Get the block size (in bytes).
- *
- * @return the block size (in bytes).
- */
- public int getBlockSize() {
- // Currently all supported encryption algorithms are block ciphers. So the return value will
- // not be zero.
- return mCipher.getBlockSize();
- }
-
- /**
- * Get initialization vector (IV) length.
- *
- * @return the IV length.
- */
- public int getIvLen() {
- return mIvLen;
- }
-
- /**
- * Generate initialization vector (IV).
- *
- * @return the initialization vector (IV).
- */
- public byte[] generateIv() {
- byte[] iv = new byte[getIvLen()];
- new SecureRandom().nextBytes(iv);
- return iv;
- }
-
- protected void validateKeyLenOrThrow(byte[] key) {
- if (key.length != getKeyLength()) {
- throw new IllegalArgumentException(
- "Expected key with length of : "
- + getKeyLength()
- + " Received key with length of : "
- + key.length);
- }
- }
-
- /**
- * Build IpSecAlgorithm from this IkeCipher.
- *
- * <p>Build IpSecAlgorithm that represents the same encryption algorithm with this IkeCipher
- * instance with provided encryption key.
- *
- * @param key the encryption key in byte array.
- * @return the IpSecAlgorithm.
- */
- public abstract IpSecAlgorithm buildIpSecAlgorithmWithKey(byte[] key);
-
- /**
- * Returns algorithm type as a String.
- *
- * @return the algorithm type as a String.
- */
- @Override
- public String getTypeString() {
- return "Encryption Algorithm";
- }
-}
diff --git a/src/java/com/android/internal/net/ipsec/ike/crypto/IkeCombinedModeCipher.java b/src/java/com/android/internal/net/ipsec/ike/crypto/IkeCombinedModeCipher.java
deleted file mode 100644
index 4bb1d34b..00000000
--- a/src/java/com/android/internal/net/ipsec/ike/crypto/IkeCombinedModeCipher.java
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * Copyright (C) 2019 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.crypto;
-
-import android.net.IpSecAlgorithm;
-import android.net.ipsec.ike.SaProposal;
-
-import java.nio.ByteBuffer;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidKeyException;
-import java.security.Provider;
-import java.security.spec.AlgorithmParameterSpec;
-import java.util.Arrays;
-
-import javax.crypto.AEADBadTagException;
-import javax.crypto.BadPaddingException;
-import javax.crypto.Cipher;
-import javax.crypto.IllegalBlockSizeException;
-import javax.crypto.ShortBufferException;
-import javax.crypto.spec.GCMParameterSpec;
-import javax.crypto.spec.SecretKeySpec;
-
-/**
- * IkeCipher represents a negotiated combined-mode cipher(AEAD) encryption algorithm.
- *
- * <p>Checksum mentioned in this class is also known as authentication tag or Integrity Checksum
- * Vector(ICV)
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3.2">RFC 7296, Internet Key Exchange
- * Protocol Version 2 (IKEv2)</a>
- * @see <a href="https://tools.ietf.org/html/rfc5282">RFC 5282,Using Authenticated Encryption
- * Algorithms with the Encrypted Payload of the Internet Key Exchange version 2 (IKEv2)
- * Protocol</a>
- */
-public final class IkeCombinedModeCipher extends IkeCipher {
- private static final int SALT_LEN_GCM = 4;
-
- private final int mChecksumLen;
- private final int mSaltLen;
-
- /** Package private */
- IkeCombinedModeCipher(
- int algorithmId, int keyLength, int ivLength, String algorithmName, Provider provider) {
- super(algorithmId, keyLength, ivLength, algorithmName, true /*isAead*/, provider);
- switch (algorithmId) {
- case SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8:
- mSaltLen = SALT_LEN_GCM;
- mChecksumLen = 8;
- break;
- case SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12:
- mSaltLen = SALT_LEN_GCM;
- mChecksumLen = 12;
- break;
- case SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_16:
- mSaltLen = SALT_LEN_GCM;
- mChecksumLen = 16;
- break;
- default:
- throw new IllegalArgumentException(
- "Unrecognized Encryption Algorithm ID: " + algorithmId);
- }
- }
-
- private byte[] doCipherAction(
- byte[] data, byte[] additionalAuthData, byte[] keyBytes, byte[] ivBytes, int opmode)
- throws AEADBadTagException {
- try {
- // Provided key consists of encryption/decryption key plus 4-byte salt. Salt is used
- // with IV to build the nonce.
- ByteBuffer secretKeyAndSaltBuffer = ByteBuffer.wrap(keyBytes);
- byte[] secretKeyBytes = new byte[keyBytes.length - mSaltLen];
- byte[] salt = new byte[mSaltLen];
- secretKeyAndSaltBuffer.get(secretKeyBytes);
- secretKeyAndSaltBuffer.get(salt);
-
- SecretKeySpec key = new SecretKeySpec(secretKeyBytes, getAlgorithmName());
-
- ByteBuffer nonceBuffer = ByteBuffer.allocate(mSaltLen + ivBytes.length);
- nonceBuffer.put(salt);
- nonceBuffer.put(ivBytes);
-
- mCipher.init(opmode, key, getParamSpec(nonceBuffer.array()));
- mCipher.updateAAD(additionalAuthData);
-
- ByteBuffer inputBuffer = ByteBuffer.wrap(data);
-
- int outputLen = data.length;
- if (opmode == Cipher.ENCRYPT_MODE) outputLen += mChecksumLen;
- ByteBuffer outputBuffer = ByteBuffer.allocate(outputLen);
-
- mCipher.doFinal(inputBuffer, outputBuffer);
- return outputBuffer.array();
- } catch (AEADBadTagException e) {
- // Checksum failed in decryption
- throw (AEADBadTagException) e;
- } catch (InvalidKeyException
- | InvalidAlgorithmParameterException
- | IllegalBlockSizeException
- | BadPaddingException
- | ShortBufferException e) {
- String errorMessage =
- Cipher.ENCRYPT_MODE == opmode
- ? "Failed to encrypt data: "
- : "Failed to decrypt data: ";
- throw new IllegalArgumentException(errorMessage, e);
- }
- }
-
- private AlgorithmParameterSpec getParamSpec(byte[] nonce) {
- switch (getAlgorithmId()) {
- case SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8:
- // Fall through
- case SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12:
- // Fall through
- case SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_16:
- return new GCMParameterSpec(mChecksumLen * 8, nonce);
- default:
- throw new IllegalArgumentException(
- "Unrecognized Encryption Algorithm ID: " + getAlgorithmId());
- }
- }
-
- /**
- * Encrypt padded data and calculate checksum for it.
- *
- * @param paddedData the padded data to encrypt.
- * @param additionalAuthData additional data to authenticate (also known as associated data).
- * @param keyBytes the encryption key.
- * @param ivBytes the initialization vector (IV).
- * @return the encrypted and padded data with checksum.
- */
- public byte[] encrypt(
- byte[] paddedData, byte[] additionalAuthData, byte[] keyBytes, byte[] ivBytes) {
- try {
- return doCipherAction(
- paddedData, additionalAuthData, keyBytes, ivBytes, Cipher.ENCRYPT_MODE);
- } catch (AEADBadTagException e) {
- throw new IllegalArgumentException("Failed to encrypt data: ", e);
- }
- }
-
- /**
- * Authenticate and decrypt the padded data with checksum.
- *
- * @param paddedDataWithChecksum the padded data with checksum.
- * @param additionalAuthData additional data to authenticate (also known as associated data).
- * @param keyBytes the decryption key.
- * @param ivBytes the initialization vector (IV).
- * @return the decrypted and padded data
- * @throws AEADBadTagException if authentication or decryption fails
- */
- public byte[] decrypt(
- byte[] paddedDataWithChecksum,
- byte[] additionalAuthData,
- byte[] keyBytes,
- byte[] ivBytes)
- throws AEADBadTagException {
-
- byte[] decryptPaddedDataAndAuthTag =
- doCipherAction(
- paddedDataWithChecksum,
- additionalAuthData,
- keyBytes,
- ivBytes,
- Cipher.DECRYPT_MODE);
-
- int decryptPaddedDataLen = decryptPaddedDataAndAuthTag.length - mChecksumLen;
- return Arrays.copyOf(decryptPaddedDataAndAuthTag, decryptPaddedDataLen);
- }
-
- /**
- * Gets key length of this algorithm (in bytes).
- *
- * @return the key length (in bytes).
- */
- @Override
- public int getKeyLength() {
- return super.getKeyLength() + mSaltLen;
- }
-
- /**
- * Returns length of checksum.
- *
- * @return the length of checksum in bytes.
- */
- public int getChecksumLen() {
- return mChecksumLen;
- }
-
- @Override
- public IpSecAlgorithm buildIpSecAlgorithmWithKey(byte[] key) {
- validateKeyLenOrThrow(key);
- return new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, key, mChecksumLen * 8);
- }
-}
diff --git a/src/java/com/android/internal/net/ipsec/ike/crypto/IkeCrypto.java b/src/java/com/android/internal/net/ipsec/ike/crypto/IkeCrypto.java
deleted file mode 100644
index 65a676b5..00000000
--- a/src/java/com/android/internal/net/ipsec/ike/crypto/IkeCrypto.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2019 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.crypto;
-
-/**
- * IkeCrypto is an abstract class that represents common information for all negotiated
- * cryptographic algorithms that are used to build IKE SA and protect IKE message.
- */
-abstract class IkeCrypto {
- private final int mAlgorithmId;
- private final int mKeyLength;
- private final String mAlgorithmName;
-
- protected IkeCrypto(int algorithmId, int keyLength, String algorithmName) {
- mAlgorithmId = algorithmId;
- mKeyLength = keyLength;
- mAlgorithmName = algorithmName;
- }
-
- protected int getAlgorithmId() {
- return mAlgorithmId;
- }
-
- protected String getAlgorithmName() {
- return mAlgorithmName;
- }
-
- /**
- * Gets key length of this algorithm (in bytes).
- *
- * @return the key length (in bytes).
- */
- public int getKeyLength() {
- return mKeyLength;
- }
-
- /**
- * Returns algorithm type as a String.
- *
- * @return the algorithm type as a String.
- */
- public abstract String getTypeString();
-}
diff --git a/src/java/com/android/internal/net/ipsec/ike/crypto/IkeMac.java b/src/java/com/android/internal/net/ipsec/ike/crypto/IkeMac.java
deleted file mode 100644
index ee45cc9e..00000000
--- a/src/java/com/android/internal/net/ipsec/ike/crypto/IkeMac.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2019 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.crypto;
-
-import com.android.internal.net.crypto.KeyGenerationUtils.ByteSigner;
-
-import java.nio.ByteBuffer;
-import java.security.InvalidKeyException;
-import java.security.NoSuchAlgorithmException;
-import java.security.Provider;
-
-import javax.crypto.Cipher;
-import javax.crypto.Mac;
-import javax.crypto.NoSuchPaddingException;
-import javax.crypto.spec.SecretKeySpec;
-
-/**
- * IkeMac is an abstract class that represents common information for all negotiated algorithms that
- * generates Message Authentication Code (MAC), e.g. PRF and integrity algorithm.
- */
-abstract class IkeMac extends IkeCrypto implements ByteSigner {
- // STOPSHIP: b/130190639 Catch unchecked exceptions, notify users and close the IKE session.
- private final boolean mIsEncryptAlgo;
- private final Mac mMac;
- private final Cipher mCipher;
-
- protected IkeMac(
- int algorithmId,
- int keyLength,
- String algorithmName,
- boolean isEncryptAlgo,
- Provider provider) {
- super(algorithmId, keyLength, algorithmName);
-
- mIsEncryptAlgo = isEncryptAlgo;
-
- try {
- if (mIsEncryptAlgo) {
- mMac = null;
- mCipher = Cipher.getInstance(getAlgorithmName(), provider);
- } else {
- mMac = Mac.getInstance(getAlgorithmName(), provider);
- mCipher = null;
- }
- } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
- throw new IllegalArgumentException("Failed to construct " + getTypeString(), e);
- }
- }
-
- /**
- * Signs the bytes to generate a Message Authentication Code (MAC).
- *
- * <p>Caller is responsible for providing valid key according to their use cases (e.g. PSK,
- * SK_p, SK_d ...).
- *
- * @param keyBytes the key to sign data.
- * @param dataToSign the data to be signed.
- * @return the calculated MAC.
- */
- @Override
- public byte[] signBytes(byte[] keyBytes, byte[] dataToSign) {
- try {
- SecretKeySpec secretKey = new SecretKeySpec(keyBytes, getAlgorithmName());
-
- if (mIsEncryptAlgo) {
- throw new UnsupportedOperationException(
- "Do not support " + getTypeString() + " using encryption algorithm.");
- } else {
- ByteBuffer inputBuffer = ByteBuffer.wrap(dataToSign);
- mMac.init(secretKey);
- mMac.update(inputBuffer);
-
- return mMac.doFinal();
- }
- } catch (InvalidKeyException | IllegalStateException e) {
- throw new IllegalArgumentException("Failed to generate MAC: ", e);
- }
- }
-}
diff --git a/src/java/com/android/internal/net/ipsec/ike/crypto/IkeMacIntegrity.java b/src/java/com/android/internal/net/ipsec/ike/crypto/IkeMacIntegrity.java
deleted file mode 100644
index 8f2173f6..00000000
--- a/src/java/com/android/internal/net/ipsec/ike/crypto/IkeMacIntegrity.java
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * Copyright (C) 2019 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.crypto;
-
-import android.net.IpSecAlgorithm;
-import android.net.ipsec.ike.SaProposal;
-
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload.IntegrityTransform;
-
-import java.security.Provider;
-import java.util.Arrays;
-
-import javax.crypto.Cipher;
-import javax.crypto.Mac;
-
-/**
- * IkeMacIntegrity represents a negotiated integrity algorithm.
- *
- * <p>For integrity algorithms based on encryption algorithm, all operations will be done by a
- * {@link Cipher}. Otherwise, all operations will be done by a {@link Mac}.
- *
- * <p>@see <a href="https://tools.ietf.org/html/rfc7296#section-3.3.2">RFC 7296, Internet Key
- * Exchange Protocol Version 2 (IKEv2)</a>
- */
-public class IkeMacIntegrity extends IkeMac {
- // STOPSHIP: b/130190639 Catch unchecked exceptions, notify users and close the IKE session.
- private final int mChecksumLength;
-
- private IkeMacIntegrity(
- @SaProposal.IntegrityAlgorithm int algorithmId,
- int keyLength,
- String algorithmName,
- boolean isEncryptAlgo,
- Provider provider,
- int checksumLength) {
- super(algorithmId, keyLength, algorithmName, isEncryptAlgo, provider);
- mChecksumLength = checksumLength;
- }
-
- /**
- * Construct an instance of IkeMacIntegrity.
- *
- * @param integrityTransform the valid negotiated IntegrityTransform.
- * @param provider the security provider.
- * @return an instance of IkeMacIntegrity.
- */
- public static IkeMacIntegrity create(IntegrityTransform integrityTransform, Provider provider) {
- int algorithmId = integrityTransform.id;
-
- int keyLength = 0;
- String algorithmName = "";
- boolean isEncryptAlgo = false;
- int checksumLength = 0;
-
- switch (algorithmId) {
- case SaProposal.INTEGRITY_ALGORITHM_NONE:
- throw new IllegalArgumentException("Integrity algorithm is not found.");
- case SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96:
- keyLength = 20;
- algorithmName = "HmacSHA1";
- checksumLength = 12;
- break;
- case SaProposal.INTEGRITY_ALGORITHM_AES_XCBC_96:
- keyLength = 16;
- isEncryptAlgo = true;
- checksumLength = 12;
-
- // TODO:Set mAlgorithmName
- throw new UnsupportedOperationException(
- "Do not support INTEGRITY_ALGORITHM_AES_XCBC_96.");
- case SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_256_128:
- keyLength = 32;
- algorithmName = "HmacSHA256";
- checksumLength = 16;
- break;
- case SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_384_192:
- keyLength = 48;
- algorithmName = "HmacSHA384";
- checksumLength = 24;
- break;
- case SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_512_256:
- keyLength = 64;
- algorithmName = "HmacSHA512";
- checksumLength = 32;
- break;
- default:
- throw new IllegalArgumentException(
- "Unrecognized Integrity Algorithm ID: " + algorithmId);
- }
-
- return new IkeMacIntegrity(
- algorithmId, keyLength, algorithmName, isEncryptAlgo, provider, checksumLength);
- }
-
- /**
- * Gets integrity checksum length (in bytes).
- *
- * <p>IKE defines a fixed truncation length for each integirty algorithm as its checksum length.
- *
- * @return the integrity checksum length (in bytes).
- */
- public int getChecksumLen() {
- return mChecksumLength;
- }
-
- /**
- * Signs the bytes to generate an integrity checksum.
- *
- * @param keyBytes the negotiated integrity key.
- * @param dataToAuthenticate the data to authenticate.
- * @return the integrity checksum.
- */
- public byte[] generateChecksum(byte[] keyBytes, byte[] dataToAuthenticate) {
- if (getKeyLength() != keyBytes.length) {
- throw new IllegalArgumentException(
- "Expected key length: "
- + getKeyLength()
- + " Received key length: "
- + keyBytes.length);
- }
-
- byte[] signedBytes = signBytes(keyBytes, dataToAuthenticate);
- return Arrays.copyOfRange(signedBytes, 0, mChecksumLength);
- }
-
- /**
- * Build IpSecAlgorithm from this IkeMacIntegrity.
- *
- * <p>Build IpSecAlgorithm that represents the same integrity algorithm with this
- * IkeMacIntegrity instance with provided integrity key.
- *
- * @param key the integrity key in byte array.
- * @return the IpSecAlgorithm.
- */
- public IpSecAlgorithm buildIpSecAlgorithmWithKey(byte[] key) {
- if (key.length != getKeyLength()) {
- throw new IllegalArgumentException(
- "Expected key with length of : "
- + getKeyLength()
- + " Received key with length of : "
- + key.length);
- }
-
- switch (getAlgorithmId()) {
- case SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96:
- return new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA1, key, mChecksumLength * 8);
- case SaProposal.INTEGRITY_ALGORITHM_AES_XCBC_96:
- // TODO:Consider supporting AES128_XCBC in IpSecTransform.
- throw new IllegalArgumentException(
- "Do not support IpSecAlgorithm with AES128_XCBC.");
- case SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_256_128:
- return new IpSecAlgorithm(
- IpSecAlgorithm.AUTH_HMAC_SHA256, key, mChecksumLength * 8);
- case SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_384_192:
- return new IpSecAlgorithm(
- IpSecAlgorithm.AUTH_HMAC_SHA384, key, mChecksumLength * 8);
- case SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_512_256:
- return new IpSecAlgorithm(
- IpSecAlgorithm.AUTH_HMAC_SHA512, key, mChecksumLength * 8);
- default:
- throw new IllegalArgumentException(
- "Unrecognized Integrity Algorithm ID: " + getAlgorithmId());
- }
- }
-
- /**
- * Returns algorithm type as a String.
- *
- * @return the algorithm type as a String.
- */
- @Override
- public String getTypeString() {
- return "Integrity Algorithm.";
- }
-}
diff --git a/src/java/com/android/internal/net/ipsec/ike/crypto/IkeMacPrf.java b/src/java/com/android/internal/net/ipsec/ike/crypto/IkeMacPrf.java
deleted file mode 100644
index 1d81aaed..00000000
--- a/src/java/com/android/internal/net/ipsec/ike/crypto/IkeMacPrf.java
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (C) 2019 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.crypto;
-
-import android.net.ipsec.ike.SaProposal;
-
-import com.android.internal.net.crypto.KeyGenerationUtils;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload.PrfTransform;
-
-import java.nio.ByteBuffer;
-import java.security.Provider;
-
-import javax.crypto.Cipher;
-import javax.crypto.Mac;
-
-/**
- * IkeMacPrf represents a negotiated pseudorandom function.
- *
- * <p>Pseudorandom function is usually used for IKE SA authentication and generating keying
- * materials.
- *
- * <p>For pseudorandom functions based on integrity algorithms, all operations will be done by a
- * {@link Mac}. For pseudorandom functions based on encryption algorithms, all operations will be
- * done by a {@link Cipher}.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3.2">RFC 7296, Internet Key Exchange
- * Protocol Version 2 (IKEv2)</a>
- */
-public class IkeMacPrf extends IkeMac {
- // STOPSHIP: b/130190639 Catch unchecked exceptions, notify users and close the IKE session.
-
- private IkeMacPrf(
- @SaProposal.PseudorandomFunction int algorithmId,
- int keyLength,
- String algorithmName,
- boolean isEncryptAlgo,
- Provider provider) {
- super(algorithmId, keyLength, algorithmName, isEncryptAlgo, provider);
- }
-
- /**
- * Construct an instance of IkeMacPrf.
- *
- * @param prfTransform the valid negotiated PrfTransform.
- * @param provider the security provider.
- * @return an instance of IkeMacPrf.
- */
- public static IkeMacPrf create(PrfTransform prfTransform, Provider provider) {
- int algorithmId = prfTransform.id;
-
- int keyLength = 0;
- String algorithmName = "";
- boolean isEncryptAlgo = false;
-
- switch (algorithmId) {
- case SaProposal.PSEUDORANDOM_FUNCTION_HMAC_SHA1:
- keyLength = 20;
- algorithmName = "HmacSHA1";
- break;
- case SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC:
- keyLength = 16;
- isEncryptAlgo = true;
-
- // TODO:Set mAlgorithmName
- throw new UnsupportedOperationException(
- "Do not support PSEUDORANDOM_FUNCTION_AES128_XCBC.");
- default:
- throw new IllegalArgumentException("Unrecognized PRF ID: " + algorithmId);
- }
-
- return new IkeMacPrf(algorithmId, keyLength, algorithmName, isEncryptAlgo, provider);
- }
-
- /**
- * Generates SKEYSEED based on the nonces and shared DH secret.
- *
- * @param nonceInit the IKE initiator nonce.
- * @param nonceResp the IKE responder nonce.
- * @param sharedDhKey the DH shared key.
- * @return the byte array of SKEYSEED.
- */
- public byte[] generateSKeySeed(byte[] nonceInit, byte[] nonceResp, byte[] sharedDhKey) {
- // TODO: If it is PSEUDORANDOM_FUNCTION_AES128_XCBC, only use first 8 bytes of each nonce.
-
- ByteBuffer keyBuffer = ByteBuffer.allocate(nonceInit.length + nonceResp.length);
- keyBuffer.put(nonceInit).put(nonceResp);
-
- return signBytes(keyBuffer.array(), sharedDhKey);
- }
-
- /**
- * Generates a rekey SKEYSEED based on the nonces and shared DH secret.
- *
- * @param skD the secret for deriving new keys
- * @param nonceInit the IKE initiator nonce.
- * @param nonceResp the IKE responder nonce.
- * @param sharedDhKey the DH shared key.
- * @return the byte array of SKEYSEED.
- */
- public byte[] generateRekeyedSKeySeed(
- byte[] skD, byte[] nonceInit, byte[] nonceResp, byte[] sharedDhKey) {
- // TODO: If it is PSEUDORANDOM_FUNCTION_AES128_XCBC, only use first 8 bytes of each nonce.
-
- ByteBuffer dataToSign =
- ByteBuffer.allocate(sharedDhKey.length + nonceInit.length + nonceResp.length);
- dataToSign.put(sharedDhKey).put(nonceInit).put(nonceResp);
-
- return signBytes(skD, dataToSign.array());
- }
-
- /**
- * Derives keying materials from IKE/Child SA negotiation.
- *
- * <p>prf+(K, S) outputs a pseudorandom stream by using negotiated PRF iteratively. In this way
- * it can generate long enough keying material containing all the keys for this IKE/Child SA.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#section-2.13">RFC 7296 Internet Key
- * Exchange Protocol Version 2 (IKEv2) 2.13. Generating Keying Material </a>
- * @param keyBytes the key to sign data. SKEYSEED is used for generating KEYMAT for IKE SA. SK_d
- * is used for generating KEYMAT for Child SA.
- * @param dataToSign the data to be signed.
- * @param keyMaterialLen the length of keying materials.
- * @return the byte array of keying materials
- */
- public byte[] generateKeyMat(byte[] keyBytes, byte[] dataToSign, int keyMaterialLen) {
- return KeyGenerationUtils.prfPlus(this, keyBytes, dataToSign, keyMaterialLen);
- }
-
- /**
- * Returns algorithm type as a String.
- *
- * @return the algorithm type as a String.
- */
- @Override
- public String getTypeString() {
- return "Pseudorandom Function";
- }
-}
diff --git a/src/java/com/android/internal/net/ipsec/ike/crypto/IkeNormalModeCipher.java b/src/java/com/android/internal/net/ipsec/ike/crypto/IkeNormalModeCipher.java
deleted file mode 100644
index e4904d4f..00000000
--- a/src/java/com/android/internal/net/ipsec/ike/crypto/IkeNormalModeCipher.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright (C) 2019 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.crypto;
-
-import android.net.IpSecAlgorithm;
-import android.net.ipsec.ike.SaProposal;
-
-import java.nio.ByteBuffer;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidKeyException;
-import java.security.Provider;
-
-import javax.crypto.BadPaddingException;
-import javax.crypto.Cipher;
-import javax.crypto.IllegalBlockSizeException;
-import javax.crypto.ShortBufferException;
-import javax.crypto.spec.IvParameterSpec;
-import javax.crypto.spec.SecretKeySpec;
-
-/**
- * IkeCipher represents a negotiated normal mode encryption algorithm.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3.2">RFC 7296, Internet Key Exchange
- * Protocol Version 2 (IKEv2)</a>
- */
-public final class IkeNormalModeCipher extends IkeCipher {
- /** Package private */
- IkeNormalModeCipher(
- int algorithmId, int keyLength, int ivLength, String algorithmName, Provider provider) {
- super(algorithmId, keyLength, ivLength, algorithmName, false /*isAead*/, provider);
- }
-
- private byte[] doCipherAction(byte[] data, byte[] keyBytes, byte[] ivBytes, int opmode)
- throws IllegalBlockSizeException {
- if (getKeyLength() != keyBytes.length) {
- throw new IllegalArgumentException(
- "Expected key length: "
- + getKeyLength()
- + " Received key length: "
- + keyBytes.length);
- }
- try {
- SecretKeySpec key = new SecretKeySpec(keyBytes, getAlgorithmName());
- IvParameterSpec iv = new IvParameterSpec(ivBytes);
- mCipher.init(opmode, key, iv);
-
- ByteBuffer inputBuffer = ByteBuffer.wrap(data);
- ByteBuffer outputBuffer = ByteBuffer.allocate(data.length);
-
- mCipher.doFinal(inputBuffer, outputBuffer);
- return outputBuffer.array();
- } catch (InvalidKeyException
- | InvalidAlgorithmParameterException
- | BadPaddingException
- | ShortBufferException e) {
- String errorMessage =
- Cipher.ENCRYPT_MODE == opmode
- ? "Failed to encrypt data: "
- : "Failed to decrypt data: ";
- throw new IllegalArgumentException(errorMessage, e);
- }
- }
-
- /**
- * Encrypt padded data.
- *
- * @param paddedData the padded data to encrypt.
- * @param keyBytes the encryption key.
- * @param ivBytes the initialization vector (IV).
- * @return the encrypted and padded data.
- */
- public byte[] encrypt(byte[] paddedData, byte[] keyBytes, byte[] ivBytes) {
- try {
- return doCipherAction(paddedData, keyBytes, ivBytes, Cipher.ENCRYPT_MODE);
- } catch (IllegalBlockSizeException e) {
- throw new IllegalArgumentException("Failed to encrypt data: ", e);
- }
- }
-
- /**
- * Decrypt the encrypted and padded data.
- *
- * @param encryptedData the encrypted and padded data.
- * @param keyBytes the decryption key.
- * @param ivBytes the initialization vector (IV).
- * @return the decrypted and padded data.
- * @throws IllegalBlockSizeException if the total encryptedData length is not a multiple of
- * block size.
- */
- public byte[] decrypt(byte[] encryptedData, byte[] keyBytes, byte[] ivBytes)
- throws IllegalBlockSizeException {
- return doCipherAction(encryptedData, keyBytes, ivBytes, Cipher.DECRYPT_MODE);
- }
-
- @Override
- public IpSecAlgorithm buildIpSecAlgorithmWithKey(byte[] key) {
- validateKeyLenOrThrow(key);
-
- switch (getAlgorithmId()) {
- case SaProposal.ENCRYPTION_ALGORITHM_3DES:
- // TODO: Consider supporting 3DES in IpSecTransform.
- throw new UnsupportedOperationException("Do not support 3Des encryption.");
- case SaProposal.ENCRYPTION_ALGORITHM_AES_CBC:
- return new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, key);
- default:
- throw new IllegalArgumentException(
- "Unrecognized Encryption Algorithm ID: " + getAlgorithmId());
- }
- }
-}
diff --git a/src/java/com/android/internal/net/ipsec/ike/exceptions/InvalidKeException.java b/src/java/com/android/internal/net/ipsec/ike/exceptions/InvalidKeException.java
deleted file mode 100644
index ae2330c7..00000000
--- a/src/java/com/android/internal/net/ipsec/ike/exceptions/InvalidKeException.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2019 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.exceptions;
-
-import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_INVALID_KE_PAYLOAD;
-
-import android.net.ipsec.ike.exceptions.IkeProtocolException;
-
-/**
- * This exception is thrown when the received KE payload in the request is different from accepted
- * Diffie-Hellman group.
- *
- * <p>Responder should include an INVALID_KE_PAYLOAD Notify payload in a response message for both
- * IKE INI exchange and other SA negotiation exchanges after IKE is setup..
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#section-1.3">RFC 7296, Internet Key Exchange
- * Protocol Version 2 (IKEv2)</a>
- */
-public final class InvalidKeException extends IkeProtocolException {
- private static final int EXPECTED_ERROR_DATA_LEN = 2;
-
- /**
- * Construct an instance of InvalidKeException
- *
- * @param dhGroup the expected DH group
- */
- public InvalidKeException(int dhGroup) {
- super(ERROR_TYPE_INVALID_KE_PAYLOAD, integerToByteArray(dhGroup, EXPECTED_ERROR_DATA_LEN));
- }
-
- /**
- * Construct a instance of InvalidKeException from a notify payload.
- *
- * @param notifyData the notify data included in the payload.
- */
- public InvalidKeException(byte[] notifyData) {
- super(ERROR_TYPE_INVALID_KE_PAYLOAD, notifyData);
- }
-
- /**
- * Return the expected DH Group included in this exception.
- *
- * @return the expected DH Group.
- */
- public int getDhGroup() {
- return byteArrayToInteger(getErrorData());
- }
-
- @Override
- protected boolean isValidDataLength(int dataLen) {
- return EXPECTED_ERROR_DATA_LEN == dataLen;
- }
-}
diff --git a/src/java/com/android/internal/net/ipsec/ike/exceptions/InvalidMessageIdException.java b/src/java/com/android/internal/net/ipsec/ike/exceptions/InvalidMessageIdException.java
deleted file mode 100644
index 9c5cffa3..00000000
--- a/src/java/com/android/internal/net/ipsec/ike/exceptions/InvalidMessageIdException.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2019 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.exceptions;
-
-import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_INVALID_MESSAGE_ID;
-
-import android.net.ipsec.ike.exceptions.IkeProtocolException;
-
-/**
- * This exception is thrown when the message ID is out of window size.
- *
- * <p>Notifications based on this exception contains the four-octet invalid message ID. It MUST only
- * ever be sent in an INFORMATIONAL request. Sending this notification is OPTIONAL, and
- * notifications of this type MUST be rate limited.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#section-2.3">RFC 7296, Internet Key Exchange
- * Protocol Version 2 (IKEv2)</a>
- */
-public final class InvalidMessageIdException extends IkeProtocolException {
- private static final int EXPECTED_ERROR_DATA_LEN = 4;
-
- /**
- * Construct a instance of InvalidMessageIdException
- *
- * @param messageId the invalid Message ID.
- */
- public InvalidMessageIdException(int messageId) {
- super(
- ERROR_TYPE_INVALID_MESSAGE_ID,
- integerToByteArray(messageId, EXPECTED_ERROR_DATA_LEN));
- }
-
- /**
- * Construct a instance of InvalidMessageIdException from a notify payload.
- *
- * @param notifyData the notify data included in the payload.
- */
- public InvalidMessageIdException(byte[] notifyData) {
- super(ERROR_TYPE_INVALID_MESSAGE_ID, notifyData);
- }
-
- /**
- * Return the invalid message ID included in this exception.
- *
- * @return the message ID.
- */
- public int getMessageId() {
- return byteArrayToInteger(getErrorData());
- }
-
- @Override
- protected boolean isValidDataLength(int dataLen) {
- return EXPECTED_ERROR_DATA_LEN == dataLen;
- }
-}
diff --git a/src/java/com/android/internal/net/ipsec/ike/exceptions/TemporaryFailureException.java b/src/java/com/android/internal/net/ipsec/ike/exceptions/TemporaryFailureException.java
deleted file mode 100644
index 57ef8cda..00000000
--- a/src/java/com/android/internal/net/ipsec/ike/exceptions/TemporaryFailureException.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2019 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.exceptions;
-
-import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_TEMPORARY_FAILURE;
-
-import android.net.ipsec.ike.exceptions.IkeProtocolException;
-
-/**
- * This exception is thrown when local node or remote peer receives a request that cannot be
- * completed due to a temporary condition such as a rekeying operation.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#section-2.7">RFC 7296, Internet Key Exchange
- * Protocol Version 2 (IKEv2)</a>
- */
-public final class TemporaryFailureException extends IkeProtocolException {
- private static final int EXPECTED_ERROR_DATA_LEN = 0;
-
- /**
- * Construct an instance of TemporaryFailureException.
- *
- * @param message the descriptive message.
- */
- public TemporaryFailureException(String message) {
- super(ERROR_TYPE_TEMPORARY_FAILURE, message);
- }
-
- /**
- * Construct a instance of TemporaryFailureException from a notify payload.
- *
- * @param notifyData the notify data included in the payload.
- */
- public TemporaryFailureException(byte[] notifyData) {
- super(ERROR_TYPE_TEMPORARY_FAILURE, notifyData);
- }
-
- @Override
- protected boolean isValidDataLength(int dataLen) {
- return EXPECTED_ERROR_DATA_LEN == dataLen;
- }
-}
diff --git a/src/java/com/android/internal/net/ipsec/ike/exceptions/TsUnacceptableException.java b/src/java/com/android/internal/net/ipsec/ike/exceptions/TsUnacceptableException.java
deleted file mode 100644
index ef1152a0..00000000
--- a/src/java/com/android/internal/net/ipsec/ike/exceptions/TsUnacceptableException.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2019 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.exceptions;
-
-import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_TS_UNACCEPTABLE;
-
-import android.net.ipsec.ike.exceptions.IkeProtocolException;
-
-/**
- * This exception is thrown if the remote sever proposed unacceptable TS.
- *
- * <p>If remote server is the exchange initiator, IKE library should respond with a TS_UNACCEPTABLE
- * Notify message. If the remote server is the exchange responder, IKE library should initiate a
- * Delete IKE exchange and close the IKE Session.
- */
-public final class TsUnacceptableException extends IkeProtocolException {
- private static final int EXPECTED_ERROR_DATA_LEN = 0;
-
- /** Construct an instance of TsUnacceptableException. */
- public TsUnacceptableException() {
- super(ERROR_TYPE_TS_UNACCEPTABLE);
- }
-
- /**
- * Construct a instance of TsUnacceptableException from a notify payload.
- *
- * @param notifyData the notify data included in the payload.
- */
- public TsUnacceptableException(byte[] notifyData) {
- super(ERROR_TYPE_TS_UNACCEPTABLE, notifyData);
- }
-
- @Override
- protected boolean isValidDataLength(int dataLen) {
- return EXPECTED_ERROR_DATA_LEN == dataLen;
- }
-}
diff --git a/src/java/com/android/internal/net/ipsec/ike/exceptions/UnrecognizedIkeProtocolException.java b/src/java/com/android/internal/net/ipsec/ike/exceptions/UnrecognizedIkeProtocolException.java
deleted file mode 100644
index 3d1d5087..00000000
--- a/src/java/com/android/internal/net/ipsec/ike/exceptions/UnrecognizedIkeProtocolException.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2019 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.exceptions;
-
-import android.net.ipsec.ike.exceptions.IkeProtocolException;
-
-/**
- * This exception represents an unrecognized error notification in a received response.
- *
- * <p>When receiving an unrecognized error notification in a response, IKE Session MUST assume that
- * the corresponding request has failed entirely. If it is in a request, IKE Session MUST ignore it.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.10.1">RFC 7296, Internet Key Exchange
- * Protocol Version 2 (IKEv2)</a>
- */
-public final class UnrecognizedIkeProtocolException extends IkeProtocolException {
- /** Constructs an instance of UnrecognizedIkeProtocolException */
- public UnrecognizedIkeProtocolException(int errorType, byte[] notifyData) {
- super(errorType, notifyData);
- }
-
- @Override
- protected boolean isValidDataLength(int dataLen) {
- // Unrecognized error does not have an expected error data length. Any non-negative length
- // is valid
- return dataLen >= 0;
- }
-}
diff --git a/src/java/com/android/internal/net/ipsec/ike/exceptions/UnsupportedCriticalPayloadException.java b/src/java/com/android/internal/net/ipsec/ike/exceptions/UnsupportedCriticalPayloadException.java
deleted file mode 100644
index ab1f75e4..00000000
--- a/src/java/com/android/internal/net/ipsec/ike/exceptions/UnsupportedCriticalPayloadException.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2018 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.exceptions;
-
-import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_UNSUPPORTED_CRITICAL_PAYLOAD;
-
-import android.net.ipsec.ike.exceptions.IkeProtocolException;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * This exception is thrown when payload type is not supported and critical bit is set
- *
- * <p>Include UNSUPPORTED_CRITICAL_PAYLOAD Notify payloads in a response message. Each payload
- * contains only one payload type.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#section-2.5">RFC 7296, Internet Key Exchange
- * Protocol Version 2 (IKEv2)</a>
- */
-public final class UnsupportedCriticalPayloadException extends IkeProtocolException {
- private static final int EXPECTED_ERROR_DATA_LEN = 1;
-
- public final List<Integer> payloadTypeList;
-
- /**
- * Construct an instance of UnsupportedCriticalPayloadException.
- *
- * <p>To keep IkeProtocolException simpler, we only pass the first payload type to the
- * superclass which can be retrieved by users.
- *
- * @param payloadList the list of all unsupported critical payload types.
- */
- public UnsupportedCriticalPayloadException(List<Integer> payloadList) {
- super(
- ERROR_TYPE_UNSUPPORTED_CRITICAL_PAYLOAD,
- integerToByteArray(payloadList.get(0), EXPECTED_ERROR_DATA_LEN));
- payloadTypeList = payloadList;
- }
-
- /**
- * Construct a instance of UnsupportedCriticalPayloadException from a notify payload.
- *
- * @param notifyData the notify data included in the payload.
- */
- public UnsupportedCriticalPayloadException(byte[] notifyData) {
- super(ERROR_TYPE_UNSUPPORTED_CRITICAL_PAYLOAD, notifyData);
- payloadTypeList = new ArrayList<>(1);
- payloadTypeList.add(byteArrayToInteger(notifyData));
- }
-
- /**
- * Return the all the unsupported critical payloads included in this exception.
- *
- * @return the unsupported critical payload list.
- */
- public List<Integer> getUnsupportedCriticalPayloadList() {
- return payloadTypeList;
- }
-
- @Override
- protected boolean isValidDataLength(int dataLen) {
- return EXPECTED_ERROR_DATA_LEN == dataLen;
- }
-}
diff --git a/src/java/com/android/internal/net/ipsec/ike/message/IkeAuthDigitalSignPayload.java b/src/java/com/android/internal/net/ipsec/ike/message/IkeAuthDigitalSignPayload.java
deleted file mode 100644
index a4803af4..00000000
--- a/src/java/com/android/internal/net/ipsec/ike/message/IkeAuthDigitalSignPayload.java
+++ /dev/null
@@ -1,265 +0,0 @@
-/*
- * Copyright (C) 2019 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.message;
-
-import android.annotation.StringDef;
-import android.net.ipsec.ike.exceptions.IkeProtocolException;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.net.ipsec.ike.crypto.IkeMacPrf;
-import com.android.internal.net.ipsec.ike.exceptions.AuthenticationFailedException;
-import com.android.internal.net.ipsec.ike.message.IkeAuthPayload.AuthMethod;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.nio.ByteBuffer;
-import java.security.InvalidKeyException;
-import java.security.NoSuchAlgorithmException;
-import java.security.PrivateKey;
-import java.security.ProviderException;
-import java.security.Signature;
-import java.security.SignatureException;
-import java.security.cert.X509Certificate;
-import java.util.Arrays;
-
-/**
- * IkeAuthDigitalSignPayload represents Authentication Payload using a specific or generic digital
- * signature authentication method.
- *
- * <p>If AUTH_METHOD_RSA_DIGITAL_SIGN is used, then the hash algorithm is SHA1. If
- * AUTH_METHOD_GENERIC_DIGITAL_SIGN is used, the signature algorihtm and hash algorithm are
- * extracted from authentication data.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.8">RFC 7296, Internet Key Exchange
- * Protocol Version 2 (IKEv2)</a>
- * @see <a href="https://tools.ietf.org/html/rfc7427">RFC 7427, Signature Authentication in the
- * Internet Key Exchange Version 2 (IKEv2)</a>
- */
-public class IkeAuthDigitalSignPayload extends IkeAuthPayload {
- private static final String KEY_ALGO_NAME = "RSA";
-
- // Byte arrays of DER encoded identifier ASN.1 objects that indicates the algorithm used to
- // generate the signature, extracted from
- // <a href="https://tools.ietf.org/html/rfc7427#appendix-A"> RFC 7427. There is no need to
- // understand the encoding process. They are just constants to indicate the algorithm type.
- private static final byte[] PKI_ALGO_ID_DER_BYTES_RSA_SHA1 = {
- (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09,
- (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86,
- (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01,
- (byte) 0x05, (byte) 0x05, (byte) 0x00
- };
- private static final byte[] PKI_ALGO_ID_DER_BYTES_RSA_SHA2_256 = {
- (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09,
- (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86,
- (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01,
- (byte) 0x0b, (byte) 0x05, (byte) 0x00
- };
- private static final byte[] PKI_ALGO_ID_DER_BYTES_RSA_SHA2_384 = {
- (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09,
- (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86,
- (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01,
- (byte) 0x0c, (byte) 0x05, (byte) 0x00
- };
- private static final byte[] PKI_ALGO_ID_DER_BYTES_RSA_SHA2_512 = {
- (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09,
- (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86,
- (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01,
- (byte) 0x0d, (byte) 0x05, (byte) 0x00
- };
-
- // Length of ASN.1 object length field.
- private static final int SIGNATURE_ALGO_ASN1_LEN_LEN = 1;
-
- // Currently we only support RSA for signature algorithm.
- @Retention(RetentionPolicy.SOURCE)
- @StringDef({
- SIGNATURE_ALGO_RSA_SHA1,
- SIGNATURE_ALGO_RSA_SHA2_256,
- SIGNATURE_ALGO_RSA_SHA2_384,
- SIGNATURE_ALGO_RSA_SHA2_512
- })
- @VisibleForTesting
- @interface SignatureAlgo {}
-
- @VisibleForTesting static final String SIGNATURE_ALGO_RSA_SHA1 = "SHA1withRSA";
- @VisibleForTesting static final String SIGNATURE_ALGO_RSA_SHA2_256 = "SHA256withRSA";
- @VisibleForTesting static final String SIGNATURE_ALGO_RSA_SHA2_384 = "SHA384withRSA";
- @VisibleForTesting static final String SIGNATURE_ALGO_RSA_SHA2_512 = "SHA512withRSA";
-
- public final String signatureAlgoAndHash;
- public final byte[] signature;
-
- protected IkeAuthDigitalSignPayload(
- boolean critical, @AuthMethod int authMethod, byte[] authData)
- throws IkeProtocolException {
- super(critical, authMethod);
- switch (authMethod) {
- case AUTH_METHOD_RSA_DIGITAL_SIGN:
- signatureAlgoAndHash = SIGNATURE_ALGO_RSA_SHA1;
- signature = authData;
- break;
- case AUTH_METHOD_GENERIC_DIGITAL_SIGN:
- ByteBuffer inputBuffer = ByteBuffer.wrap(authData);
-
- // Get signature algorithm.
- int signAlgoLen = Byte.toUnsignedInt(inputBuffer.get());
- byte[] signAlgoBytes = new byte[signAlgoLen];
- inputBuffer.get(signAlgoBytes);
- signatureAlgoAndHash = bytesToJavaStandardSignAlgoName(signAlgoBytes);
-
- // Get signature.
- signature = new byte[authData.length - SIGNATURE_ALGO_ASN1_LEN_LEN - signAlgoLen];
- inputBuffer.get(signature);
- break;
- default:
- throw new IllegalArgumentException("Unrecognized authentication method.");
- }
- }
-
- /**
- * Construct IkeAuthDigitalSignPayload for an outbound IKE packet.
- *
- * <p>Since IKE library is always a client, outbound IkeAuthDigitalSignPayload always signs IKE
- * initiator's SignedOctets, which is concatenation of the IKE_INIT request message, the Nonce
- * of IKE responder and the signed ID-Initiator payload body.
- *
- * <p>Caller MUST validate that the signatureAlgoName is supported by IKE library.
- *
- * @param signatureAlgoName the name of the algorithm requested. See the Signature section in
- * the <a href= "{@docRoot}/../technotes/guides/security/StandardNames.html#Signature"> Java
- * Cryptography Architecture Standard Algorithm Name Documentation</a> for information about
- * standard algorithm names.
- * @param privateKey the private key of the identity whose signature is going to be generated.
- * @param ikeInitBytes IKE_INIT request for calculating IKE initiator's SignedOctets.
- * @param nonce nonce of IKE responder for calculating IKE initiator's SignedOctets.
- * @param idPayloadBodyBytes ID-Initiator payload body for calculating IKE initiator's
- * SignedOctets.
- * @param ikePrf the negotiated PRF.
- * @param prfKeyBytes the negotiated PRF initiator key.
- */
- public IkeAuthDigitalSignPayload(
- String signatureAlgoName,
- PrivateKey privateKey,
- byte[] ikeInitBytes,
- byte[] nonce,
- byte[] idPayloadBodyBytes,
- IkeMacPrf ikePrf,
- byte[] prfKeyBytes) {
- super(false, IkeAuthPayload.AUTH_METHOD_GENERIC_DIGITAL_SIGN);
- byte[] dataToSignBytes =
- getSignedOctets(ikeInitBytes, nonce, idPayloadBodyBytes, ikePrf, prfKeyBytes);
-
- try {
- Signature signGen =
- Signature.getInstance(signatureAlgoName, IkeMessage.getSecurityProvider());
- signGen.initSign(privateKey);
- signGen.update(dataToSignBytes);
-
- signature = signGen.sign();
- signatureAlgoAndHash = signatureAlgoName;
- } catch (SignatureException | InvalidKeyException e) {
- throw new IllegalArgumentException("Signature generation failed", e);
- } catch (NoSuchAlgorithmException e) {
- throw new ProviderException(
- "Security Provider does not support "
- + KEY_ALGO_NAME
- + " or "
- + signatureAlgoName);
- }
- }
-
- private String bytesToJavaStandardSignAlgoName(byte[] signAlgoBytes)
- throws AuthenticationFailedException {
- if (Arrays.equals(PKI_ALGO_ID_DER_BYTES_RSA_SHA1, signAlgoBytes)) {
- return SIGNATURE_ALGO_RSA_SHA1;
- } else if (Arrays.equals(PKI_ALGO_ID_DER_BYTES_RSA_SHA2_256, signAlgoBytes)) {
- return SIGNATURE_ALGO_RSA_SHA2_256;
- } else if (Arrays.equals(PKI_ALGO_ID_DER_BYTES_RSA_SHA2_384, signAlgoBytes)) {
- return SIGNATURE_ALGO_RSA_SHA2_384;
- } else if (Arrays.equals(PKI_ALGO_ID_DER_BYTES_RSA_SHA2_512, signAlgoBytes)) {
- return SIGNATURE_ALGO_RSA_SHA2_512;
- } else {
- throw new AuthenticationFailedException(
- "Unrecognized ASN.1 objects for Signature algorithm and Hash");
- }
- }
-
- /**
- * Verify received signature in an inbound IKE packet.
- *
- * <p>Since IKE library is always a client, inbound IkeAuthDigitalSignPayload always signs IKE
- * responder's SignedOctets, which is concatenation of the IKE_INIT response message, the Nonce
- * of IKE initiator and the signed ID-Responder payload body.
- *
- * @param certificate received end certificate to verify the signature.
- * @param ikeInitBytes IKE_INIT response for calculating IKE responder's SignedOctets.
- * @param nonce nonce of IKE initiator for calculating IKE responder's SignedOctets.
- * @param idPayloadBodyBytes ID-Responder payload body for calculating IKE responder's
- * SignedOctets.
- * @param ikePrf the negotiated PRF.
- * @param prfKeyBytes the negotiated PRF responder key.
- * @throws AuthenticationFailedException if received signature verification failed.
- */
- public void verifyInboundSignature(
- X509Certificate certificate,
- byte[] ikeInitBytes,
- byte[] nonce,
- byte[] idPayloadBodyBytes,
- IkeMacPrf ikePrf,
- byte[] prfKeyBytes)
- throws AuthenticationFailedException {
- byte[] dataToSignBytes =
- getSignedOctets(ikeInitBytes, nonce, idPayloadBodyBytes, ikePrf, prfKeyBytes);
-
- try {
- Signature signValidator =
- Signature.getInstance(signatureAlgoAndHash, IkeMessage.getSecurityProvider());
- signValidator.initVerify(certificate);
- signValidator.update(dataToSignBytes);
-
- if (!signValidator.verify(signature)) {
- throw new AuthenticationFailedException("Signature verification failed.");
- }
- } catch (SignatureException | InvalidKeyException e) {
- throw new AuthenticationFailedException(e);
- } catch (NoSuchAlgorithmException e) {
- throw new ProviderException(
- "Security Provider does not support " + signatureAlgoAndHash);
- }
- }
-
- // TODO: Add methods for generating signature.
-
- @Override
- protected void encodeAuthDataToByteBuffer(ByteBuffer byteBuffer) {
- // TODO: Implement it.
- throw new UnsupportedOperationException(
- "It is not supported to encode a " + getTypeString());
- }
-
- @Override
- protected int getAuthDataLength() {
- // TODO: Implement it.
- throw new UnsupportedOperationException(
- "It is not supported to get payload length of " + getTypeString());
- }
-
- @Override
- public String getTypeString() {
- return "Auth(Digital Sign)";
- }
-}
diff --git a/src/java/com/android/internal/net/ipsec/ike/message/IkeCertPayload.java b/src/java/com/android/internal/net/ipsec/ike/message/IkeCertPayload.java
deleted file mode 100644
index 9227dda9..00000000
--- a/src/java/com/android/internal/net/ipsec/ike/message/IkeCertPayload.java
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Copyright (C) 2018 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.message;
-
-import android.annotation.IntDef;
-import android.annotation.Nullable;
-import android.net.ipsec.ike.exceptions.IkeProtocolException;
-
-import com.android.internal.net.ipsec.ike.exceptions.AuthenticationFailedException;
-
-import java.io.IOException;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.nio.ByteBuffer;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.ProviderException;
-import java.security.cert.CertificateException;
-import java.security.cert.TrustAnchor;
-import java.security.cert.X509CRL;
-import java.security.cert.X509Certificate;
-import java.util.List;
-import java.util.Set;
-
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.TrustManagerFactory;
-import javax.net.ssl.X509TrustManager;
-
-/**
- * IkeCertPayload is an abstract class that represents the common information for all Certificate
- * Payload carrying different types of certifciate-related data and static methods related to
- * certificate validation.
- *
- * <p>Certificate Payload is only sent in IKE_AUTH exchange.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.6">RFC 7296, Internet Key Exchange
- * Protocol Version 2 (IKEv2)</a>
- */
-public abstract class IkeCertPayload extends IkePayload {
- // Length of certificate encoding type field in octets.
- private static final int CERT_ENCODING_LEN = 1;
-
- private static final String KEY_STORE_TYPE_PKCS12 = "PKCS12";
- private static final String CERT_PATH_ALGO_PKIX = "PKIX";
- private static final String CERT_AUTH_TYPE_RSA = "RSA";
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({
- CERTIFICATE_ENCODING_X509_CERT_SIGNATURE,
- CERTIFICATE_ENCODING_CRL,
- CERTIFICATE_ENCODING_X509_CERT_HASH_URL,
- })
- public @interface CertificateEncoding {}
-
- public static final int CERTIFICATE_ENCODING_X509_CERT_SIGNATURE = 4;
- public static final int CERTIFICATE_ENCODING_CRL = 7;
- public static final int CERTIFICATE_ENCODING_X509_CERT_HASH_URL = 12;
-
- @CertificateEncoding public final int certEncodingType;
-
- protected IkeCertPayload(@CertificateEncoding int encodingType) {
- this(false /*critical*/, encodingType);
- }
-
- protected IkeCertPayload(boolean critical, @CertificateEncoding int encodingType) {
- super(PAYLOAD_TYPE_CERT, critical);
- certEncodingType = encodingType;
- }
-
- protected static IkeCertPayload getIkeCertPayload(boolean critical, byte[] payloadBody)
- throws IkeProtocolException {
- ByteBuffer inputBuffer = ByteBuffer.wrap(payloadBody);
-
- int certEncodingType = Byte.toUnsignedInt(inputBuffer.get());
- byte[] certData = new byte[payloadBody.length - CERT_ENCODING_LEN];
- inputBuffer.get(certData);
- switch (certEncodingType) {
- case CERTIFICATE_ENCODING_X509_CERT_SIGNATURE:
- return new IkeCertX509CertPayload(critical, certData);
- // TODO: Support decoding CRL and "Hash and URL".
- case CERTIFICATE_ENCODING_CRL:
- throw new AuthenticationFailedException(
- "CERTIFICATE_ENCODING_CRL decoding is unsupported.");
- case CERTIFICATE_ENCODING_X509_CERT_HASH_URL:
- throw new AuthenticationFailedException(
- "CERTIFICATE_ENCODING_X509_CERT_HASH_URL decoding is unsupported");
- default:
- throw new AuthenticationFailedException("Unrecognized certificate encoding type.");
- }
- }
-
- /**
- * Validate an end certificate against the received chain and trust anchors.
- *
- * <p>Validation is done by checking if there is a valid certificate path from end certificate
- * to provided trust anchors.
- *
- * <p>TrustManager implementation used in this method MUST conforms RFC 4158 and RFC 5280. As
- * indicated in RFC 4158, Key Identifiers(KIDs) are not required to match during certification
- * path validation and cannot be used to eliminate certificates.
- *
- * <p>Validation will fail if any certficate in the certificate chain is using RSA public key
- * whose RSA modulus is smaller than 1024 bits.
- *
- * @param endCert the end certificate that will be used to verify AUTH payload
- * @param certList all the received certificates (include the end certificate)
- * @param crlList the certificate revocation lists
- * @param trustAnchorSet the certificate authority set to validate the end certificate
- * @throws AuthenticationFailedException if there is no valid certificate path
- */
- public static void validateCertificates(
- X509Certificate endCert,
- List<X509Certificate> certList,
- @Nullable List<X509CRL> crlList,
- Set<TrustAnchor> trustAnchorSet)
- throws AuthenticationFailedException {
- try {
- // TODO: b/122676944 Support CRL checking
-
- // Create a new keyStore with all trusted anchors
- KeyStore keyStore =
- KeyStore.getInstance(KEY_STORE_TYPE_PKCS12, IkeMessage.getSecurityProvider());
- keyStore.load(null);
- for (TrustAnchor t : trustAnchorSet) {
- X509Certificate trustedCert = t.getTrustedCert();
- String alias =
- trustedCert.getSubjectX500Principal().getName() + trustedCert.hashCode();
- keyStore.setCertificateEntry(alias, trustedCert);
- }
-
- // Build X509TrustManager with all keystore
- TrustManagerFactory tmFactory =
- TrustManagerFactory.getInstance(
- CERT_PATH_ALGO_PKIX, IkeMessage.getTrustManagerProvider());
- tmFactory.init(keyStore);
-
- X509TrustManager trustManager = null;
- for (TrustManager tm : tmFactory.getTrustManagers()) {
- if (tm instanceof X509TrustManager) {
- trustManager = (X509TrustManager) tm;
- }
- }
- if (trustManager == null) {
- throw new ProviderException(
- "X509TrustManager is not supported by "
- + IkeMessage.getTrustManagerProvider().getName());
- }
-
- // Build and validate certificate path
- trustManager.checkServerTrusted(
- certList.toArray(new X509Certificate[certList.size()]), CERT_AUTH_TYPE_RSA);
- } catch (NoSuchAlgorithmException e) {
- throw new ProviderException("Algorithm is not supported by the provider", e);
- } catch (IOException | KeyStoreException e) {
- throw new IllegalStateException(e);
- } catch (CertificateException e) {
- throw new AuthenticationFailedException(e);
- }
- }
-}
diff --git a/src/java/com/android/internal/net/ipsec/ike/message/IkeConfigPayload.java b/src/java/com/android/internal/net/ipsec/ike/message/IkeConfigPayload.java
deleted file mode 100644
index ddd1b3ed..00000000
--- a/src/java/com/android/internal/net/ipsec/ike/message/IkeConfigPayload.java
+++ /dev/null
@@ -1,767 +0,0 @@
-/*
- * Copyright (C) 2019 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.message;
-
-import android.annotation.IntDef;
-import android.net.LinkAddress;
-import android.net.ipsec.ike.IkeManager;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.net.ipsec.ike.exceptions.InvalidSyntaxException;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.nio.ByteBuffer;
-import java.util.LinkedList;
-import java.util.List;
-
-/**
- * This class represents Configuration payload.
- *
- * <p>Configuration payload is used to exchange configuration information between IKE peers.
- *
- * <p>Configuration type should be consistent with the IKE message direction (e.g. a request Config
- * Payload should be in a request IKE message). IKE library will ignore Config Payload with
- * inconsistent type or with unrecognized type.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.6">RFC 7296, Internet Key Exchange
- * Protocol Version 2 (IKEv2)</a>
- */
-public final class IkeConfigPayload extends IkePayload {
- private static final int CONFIG_HEADER_RESERVED_LEN = 3;
- private static final int CONFIG_HEADER_LEN = 4;
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({
- CONFIG_ATTR_INTERNAL_IP4_ADDRESS,
- CONFIG_ATTR_INTERNAL_IP4_NETMASK,
- CONFIG_ATTR_INTERNAL_IP4_DNS,
- CONFIG_ATTR_INTERNAL_IP4_DHCP,
- CONFIG_ATTR_APPLICATION_VERSION,
- CONFIG_ATTR_INTERNAL_IP6_ADDRESS,
- CONFIG_ATTR_INTERNAL_IP6_DNS,
- CONFIG_ATTR_INTERNAL_IP4_SUBNET,
- CONFIG_ATTR_SUPPORTED_ATTRIBUTES,
- CONFIG_ATTR_INTERNAL_IP6_SUBNET
- })
- public @interface ConfigAttr {}
-
- public static final int CONFIG_ATTR_INTERNAL_IP4_ADDRESS = 1;
- public static final int CONFIG_ATTR_INTERNAL_IP4_NETMASK = 2;
- public static final int CONFIG_ATTR_INTERNAL_IP4_DNS = 3;
- public static final int CONFIG_ATTR_INTERNAL_IP4_DHCP = 6;
- public static final int CONFIG_ATTR_APPLICATION_VERSION = 7;
- public static final int CONFIG_ATTR_INTERNAL_IP6_ADDRESS = 8;
- public static final int CONFIG_ATTR_INTERNAL_IP6_DNS = 10;
- public static final int CONFIG_ATTR_INTERNAL_IP4_SUBNET = 13;
- public static final int CONFIG_ATTR_SUPPORTED_ATTRIBUTES = 14;
- public static final int CONFIG_ATTR_INTERNAL_IP6_SUBNET = 15;
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({CONFIG_TYPE_REQUEST, CONFIG_TYPE_REPLY})
- public @interface ConfigType {}
-
- // We don't support CONFIG_TYPE_SET and CONFIG_TYPE_ACK
- public static final int CONFIG_TYPE_REQUEST = 1;
- public static final int CONFIG_TYPE_REPLY = 2;
-
- @ConfigType public final int configType;
- public final List<ConfigAttribute> recognizedAttributeList;
-
- /** Build an IkeConfigPayload from a decoded inbound IKE packet. */
- IkeConfigPayload(boolean critical, byte[] payloadBody) throws InvalidSyntaxException {
- super(PAYLOAD_TYPE_CP, critical);
-
- ByteBuffer inputBuffer = ByteBuffer.wrap(payloadBody);
- configType = Byte.toUnsignedInt(inputBuffer.get());
- inputBuffer.get(new byte[CONFIG_HEADER_RESERVED_LEN]);
-
- recognizedAttributeList = ConfigAttribute.decodeAttributeFrom(inputBuffer);
-
- // For an inbound Config Payload, IKE library is only able to handle a Config Reply or IKE
- // Session attribute requests in a Config Request. For interoperability, netmask validation
- // will be skipped for Config(Request) and config payloads with unsupported config types.
- if (configType == CONFIG_TYPE_REPLY) {
- validateNetmaskInReply();
- }
- }
-
- /** Build an IkeConfigPayload instance for an outbound IKE packet. */
- public IkeConfigPayload(boolean isReply, List<ConfigAttribute> attributeList) {
- super(PAYLOAD_TYPE_CP, false);
- this.configType = isReply ? CONFIG_TYPE_REPLY : CONFIG_TYPE_REQUEST;
- this.recognizedAttributeList = attributeList;
- }
-
- private void validateNetmaskInReply() throws InvalidSyntaxException {
- boolean hasIpv4Address = false;
- int numNetmask = 0;
-
- for (ConfigAttribute attr : recognizedAttributeList) {
- if (attr.isEmptyValue()) {
- IkeManager.getIkeLog()
- .d(
- "IkeConfigPayload",
- "Found empty attribute in a Config Payload reply "
- + attr.attributeType);
- }
- switch (attr.attributeType) {
- case CONFIG_ATTR_INTERNAL_IP4_ADDRESS:
- if (!attr.isEmptyValue()) hasIpv4Address = true;
- break;
- case CONFIG_ATTR_INTERNAL_IP4_NETMASK:
- if (!attr.isEmptyValue()) numNetmask++;
- break;
- default:
- continue;
- }
- }
-
- if (!hasIpv4Address && numNetmask > 0) {
- throw new InvalidSyntaxException(
- "Found INTERNAL_IP4_NETMASK attribute but no INTERNAL_IP4_ADDRESS attribute");
- }
-
- if (numNetmask > 1) {
- throw new InvalidSyntaxException("Found more than one INTERNAL_IP4_NETMASK");
- }
- }
-
- // TODO: Create ConfigAttribute subclasses for each attribute.
-
- /** This class represents common information of all Configuration Attributes. */
- public abstract static class ConfigAttribute {
- private static final int ATTRIBUTE_TYPE_MASK = 0x7fff;
-
- private static final int ATTRIBUTE_HEADER_LEN = 4;
- private static final int IPV4_PREFIX_LEN_MAX = 32;
-
- protected static final int VALUE_LEN_NOT_INCLUDED = 0;
-
- protected static final int IPV4_ADDRESS_LEN = 4;
- protected static final int IPV6_ADDRESS_LEN = 16;
- protected static final int PREFIX_LEN_LEN = 1;
-
- public final int attributeType;
-
- protected ConfigAttribute(int attributeType) {
- this.attributeType = attributeType;
- }
-
- protected ConfigAttribute(int attributeType, int len) throws InvalidSyntaxException {
- this(attributeType);
-
- if (!isLengthValid(len)) {
- throw new InvalidSyntaxException("Invalid configuration length");
- }
- }
-
- /**
- * Package private method to decode ConfigAttribute list from an inbound packet
- *
- * <p>NegativeArraySizeException and BufferUnderflowException will be caught in {@link
- * IkeMessage}
- */
- static List<ConfigAttribute> decodeAttributeFrom(ByteBuffer inputBuffer)
- throws InvalidSyntaxException {
- List<ConfigAttribute> configList = new LinkedList();
-
- while (inputBuffer.hasRemaining()) {
- int attributeType = Short.toUnsignedInt(inputBuffer.getShort());
- int length = Short.toUnsignedInt(inputBuffer.getShort());
- byte[] value = new byte[length];
- inputBuffer.get(value);
-
- switch (attributeType) {
- case CONFIG_ATTR_INTERNAL_IP4_ADDRESS:
- configList.add(new ConfigAttributeIpv4Address(value));
- break;
- case CONFIG_ATTR_INTERNAL_IP4_NETMASK:
- configList.add(new ConfigAttributeIpv4Netmask(value));
- break;
- case CONFIG_ATTR_INTERNAL_IP4_DNS:
- configList.add(new ConfigAttributeIpv4Dns(value));
- break;
- case CONFIG_ATTR_INTERNAL_IP4_DHCP:
- configList.add(new ConfigAttributeIpv4Dhcp(value));
- break;
- case CONFIG_ATTR_INTERNAL_IP6_ADDRESS:
- configList.add(new ConfigAttributeIpv6Address(value));
- break;
- case CONFIG_ATTR_INTERNAL_IP6_DNS:
- configList.add(new ConfigAttributeIpv6Dns(value));
- break;
- case CONFIG_ATTR_INTERNAL_IP4_SUBNET:
- configList.add(new ConfigAttributeIpv4Subnet(value));
- break;
- case CONFIG_ATTR_INTERNAL_IP6_SUBNET:
- configList.add(new ConfigAttributeIpv6Subnet(value));
- break;
- default:
- IkeManager.getIkeLog()
- .i(
- "IkeConfigPayload",
- "Unrecognized attribute type: " + attributeType);
- }
-
- // TODO: Support App version and supported attribute list
- }
-
- return configList;
- }
-
- /** Encode attribute to ByteBuffer. */
- public void encodeAttributeToByteBuffer(ByteBuffer buffer) {
- buffer.putShort((short) (attributeType & ATTRIBUTE_TYPE_MASK))
- .putShort((short) getValueLength());
- encodeValueToByteBuffer(buffer);
- }
-
- /** Get attribute length. */
- public int getAttributeLen() {
- return ATTRIBUTE_HEADER_LEN + getValueLength();
- }
-
- /** Returns if this attribute value is empty. */
- public boolean isEmptyValue() {
- return getValueLength() == VALUE_LEN_NOT_INCLUDED;
- }
-
- protected static int netmaskToPrefixLen(Inet4Address address) {
- byte[] bytes = address.getAddress();
-
- int netmaskInt = ByteBuffer.wrap(bytes).getInt();
- int leftmostBitMask = 0x80000000;
-
- int prefixLen = 0;
- while ((netmaskInt & leftmostBitMask) == leftmostBitMask) {
- prefixLen++;
- netmaskInt <<= 1;
- }
-
- if (netmaskInt != 0) {
- throw new IllegalArgumentException("Invalid netmask address");
- }
-
- return prefixLen;
- }
-
- protected static byte[] prefixToNetmaskBytes(int prefixLen) {
- if (prefixLen > IPV4_PREFIX_LEN_MAX || prefixLen < 0) {
- throw new IllegalArgumentException("Invalid IPv4 prefix length.");
- }
-
- int netmaskInt = (int) (((long) 0xffffffff) << (IPV4_PREFIX_LEN_MAX - prefixLen));
- byte[] netmask = new byte[IPV4_ADDRESS_LEN];
-
- ByteBuffer buffer = ByteBuffer.allocate(IPV4_ADDRESS_LEN);
- buffer.putInt(netmaskInt);
- return buffer.array();
- }
-
- protected abstract void encodeValueToByteBuffer(ByteBuffer buffer);
-
- protected abstract int getValueLength();
-
- protected abstract boolean isLengthValid(int length);
- }
-
- /**
- * This class represents common information of all Configuration Attributes whoses value is one
- * IPv4 address or empty.
- */
- abstract static class ConfigAttrIpv4AddressBase extends ConfigAttribute {
- public final Inet4Address address;
-
- protected ConfigAttrIpv4AddressBase(int attributeType, Inet4Address address) {
- super(attributeType);
- this.address = address;
- }
-
- protected ConfigAttrIpv4AddressBase(int attributeType) {
- super(attributeType);
- this.address = null;
- }
-
- protected ConfigAttrIpv4AddressBase(int attributeType, byte[] value)
- throws InvalidSyntaxException {
- super(attributeType, value.length);
-
- if (value.length == VALUE_LEN_NOT_INCLUDED) {
- address = null;
- return;
- }
-
- try {
- address = (Inet4Address) Inet4Address.getByAddress(value);
- } catch (UnknownHostException e) {
- throw new InvalidSyntaxException("Invalid attribute value", e);
- }
- }
-
- @Override
- protected void encodeValueToByteBuffer(ByteBuffer buffer) {
- if (address == null) {
- buffer.put(new byte[0]);
- return;
- }
-
- buffer.put(address.getAddress());
- }
-
- @Override
- protected int getValueLength() {
- return address == null ? 0 : IPV4_ADDRESS_LEN;
- }
-
- @Override
- protected boolean isLengthValid(int length) {
- return length == IPV4_ADDRESS_LEN || length == VALUE_LEN_NOT_INCLUDED;
- }
- }
-
- /** This class represents Configuration Attribute for IPv4 internal address. */
- public static class ConfigAttributeIpv4Address extends ConfigAttrIpv4AddressBase {
- /** Construct an instance with specified address for an outbound packet. */
- public ConfigAttributeIpv4Address(Inet4Address ipv4Address) {
- super(CONFIG_ATTR_INTERNAL_IP4_ADDRESS, ipv4Address);
- }
-
- /**
- * Construct an instance without a specified address for an outbound packet.
- *
- * <p>It must be only used in a configuration request.
- */
- public ConfigAttributeIpv4Address() {
- super(CONFIG_ATTR_INTERNAL_IP4_ADDRESS);
- }
-
- /** Construct an instance with a decoded inbound packet. */
- @VisibleForTesting
- ConfigAttributeIpv4Address(byte[] value) throws InvalidSyntaxException {
- super(CONFIG_ATTR_INTERNAL_IP4_ADDRESS, value);
- }
- }
-
- /**
- * This class represents Configuration Attribute for IPv4 netmask.
- *
- * <p>Non-empty values for this attribute in a CFG_REQUEST do not make sense and thus MUST NOT
- * be included
- */
- public static class ConfigAttributeIpv4Netmask extends ConfigAttrIpv4AddressBase {
- /**
- * Construct an instance without a specified netmask for an outbound packet.
- *
- * <p>It must be only used in a configuration request.
- */
- public ConfigAttributeIpv4Netmask() {
- super(CONFIG_ATTR_INTERNAL_IP4_NETMASK);
- }
-
- /** Construct an instance with a decoded inbound packet. */
- @VisibleForTesting
- public ConfigAttributeIpv4Netmask(byte[] value) throws InvalidSyntaxException {
- super(CONFIG_ATTR_INTERNAL_IP4_NETMASK, value);
-
- if (address == null) return;
- try {
- netmaskToPrefixLen(address);
- } catch (IllegalArgumentException e) {
- throw new InvalidSyntaxException("Invalid attribute value", e);
- }
- }
-
- /** Convert netmask to prefix length. */
- public int getPrefixLen() {
- return netmaskToPrefixLen(address);
- }
- }
-
- /** This class represents Configuration Attribute for IPv4 DHCP server. */
- public static class ConfigAttributeIpv4Dhcp extends ConfigAttrIpv4AddressBase {
- /** Construct an instance with specified DHCP server address for an outbound packet. */
- public ConfigAttributeIpv4Dhcp(Inet4Address ipv4Address) {
- super(CONFIG_ATTR_INTERNAL_IP4_DHCP, ipv4Address);
- }
-
- /**
- * Construct an instance without a specified DHCP server address for an outbound packet.
- *
- * <p>It must be only used in a configuration request.
- */
- public ConfigAttributeIpv4Dhcp() {
- super(CONFIG_ATTR_INTERNAL_IP4_DHCP);
- }
-
- /** Construct an instance with a decoded inbound packet. */
- @VisibleForTesting
- ConfigAttributeIpv4Dhcp(byte[] value) throws InvalidSyntaxException {
- super(CONFIG_ATTR_INTERNAL_IP4_DHCP, value);
- }
- }
-
- /**
- * This class represents Configuration Attribute for IPv4 DNS.
- *
- * <p>There is no use case to create a DNS request for a specfic DNS server address. As an IKE
- * client, we will only support building an empty DNS attribute for an outbound IKE packet.
- */
- public static class ConfigAttributeIpv4Dns extends ConfigAttrIpv4AddressBase {
- /** Construct an instance with specified DNS server address for an outbound packet. */
- public ConfigAttributeIpv4Dns(Inet4Address ipv4Address) {
- super(CONFIG_ATTR_INTERNAL_IP4_DNS, ipv4Address);
- }
-
- /**
- * Construct an instance without a specified DNS server address for an outbound packet.
- *
- * <p>It must be only used in a configuration request.
- */
- public ConfigAttributeIpv4Dns() {
- super(CONFIG_ATTR_INTERNAL_IP4_DNS);
- }
-
- /** Construct an instance with a decoded inbound packet. */
- @VisibleForTesting
- ConfigAttributeIpv4Dns(byte[] value) throws InvalidSyntaxException {
- super(CONFIG_ATTR_INTERNAL_IP4_DNS, value);
- }
- }
-
- /** This class represents Configuration Attribute for IPv4 subnets. */
- public static class ConfigAttributeIpv4Subnet extends ConfigAttribute {
- private static final int VALUE_LEN = 2 * IPV4_ADDRESS_LEN;
-
- public final LinkAddress linkAddress;
-
- /** Construct an instance with specified subnet for an outbound packet. */
- public ConfigAttributeIpv4Subnet(LinkAddress ipv4LinkAddress) {
- super(CONFIG_ATTR_INTERNAL_IP4_SUBNET);
-
- if (!ipv4LinkAddress.isIpv4()) {
- throw new IllegalArgumentException("Input LinkAddress is not IPv4");
- }
-
- this.linkAddress = ipv4LinkAddress;
- }
-
- /**
- * Construct an instance without a specified subnet for an outbound packet.
- *
- * <p>It must be only used in a configuration request.
- */
- public ConfigAttributeIpv4Subnet() {
- super(CONFIG_ATTR_INTERNAL_IP4_SUBNET);
- this.linkAddress = null;
- }
-
- /** Construct an instance with a decoded inbound packet. */
- @VisibleForTesting
- ConfigAttributeIpv4Subnet(byte[] value) throws InvalidSyntaxException {
- super(CONFIG_ATTR_INTERNAL_IP4_SUBNET, value.length);
-
- if (value.length == VALUE_LEN_NOT_INCLUDED) {
- linkAddress = null;
- return;
- }
-
- try {
- ByteBuffer inputBuffer = ByteBuffer.wrap(value);
- byte[] ipBytes = new byte[IPV4_ADDRESS_LEN];
- inputBuffer.get(ipBytes);
- byte[] netmaskBytes = new byte[IPV4_ADDRESS_LEN];
- inputBuffer.get(netmaskBytes);
-
- InetAddress address = InetAddress.getByAddress(ipBytes);
- InetAddress netmask = InetAddress.getByAddress(netmaskBytes);
- validateInet4AddressTypeOrThrow(address);
- validateInet4AddressTypeOrThrow(netmask);
-
- linkAddress = new LinkAddress(address, netmaskToPrefixLen((Inet4Address) netmask));
- } catch (UnknownHostException | IllegalArgumentException e) {
- throw new InvalidSyntaxException("Invalid attribute value", e);
- }
- }
-
- private void validateInet4AddressTypeOrThrow(InetAddress address) {
- if (!(address instanceof Inet4Address)) {
- throw new IllegalArgumentException("Input InetAddress is not IPv4");
- }
- }
-
- @Override
- protected void encodeValueToByteBuffer(ByteBuffer buffer) {
- if (linkAddress == null) {
- buffer.put(new byte[VALUE_LEN_NOT_INCLUDED]);
- return;
- }
- byte[] netmaskBytes = prefixToNetmaskBytes(linkAddress.getPrefixLength());
- buffer.put(linkAddress.getAddress().getAddress()).put(netmaskBytes);
- }
-
- @Override
- protected int getValueLength() {
- return linkAddress == null ? 0 : VALUE_LEN;
- }
-
- @Override
- protected boolean isLengthValid(int length) {
- return length == VALUE_LEN || length == VALUE_LEN_NOT_INCLUDED;
- }
- }
-
- /**
- * This class represents common information of all Configuration Attributes whoses value is an
- * IPv6 address range.
- *
- * <p>These attributes contains an IPv6 address and a prefix length.
- */
- abstract static class ConfigAttrIpv6AddrRangeBase extends ConfigAttribute {
- private static final int VALUE_LEN = IPV6_ADDRESS_LEN + PREFIX_LEN_LEN;
-
- public final LinkAddress linkAddress;
-
- protected ConfigAttrIpv6AddrRangeBase(int attributeType, LinkAddress ipv6LinkAddress) {
- super(attributeType);
-
- validateIpv6LinkAddressTypeOrThrow(ipv6LinkAddress);
- linkAddress = ipv6LinkAddress;
- }
-
- protected ConfigAttrIpv6AddrRangeBase(int attributeType) {
- super(attributeType);
- linkAddress = null;
- }
-
- protected ConfigAttrIpv6AddrRangeBase(int attributeType, byte[] value)
- throws InvalidSyntaxException {
- super(attributeType, value.length);
-
- if (value.length == VALUE_LEN_NOT_INCLUDED) {
- linkAddress = null;
- return;
- }
-
- try {
- ByteBuffer inputBuffer = ByteBuffer.wrap(value);
- byte[] ip6AddrBytes = new byte[IPV6_ADDRESS_LEN];
- inputBuffer.get(ip6AddrBytes);
- InetAddress address = InetAddress.getByAddress(ip6AddrBytes);
-
- int prefixLen = Byte.toUnsignedInt(inputBuffer.get());
-
- linkAddress = new LinkAddress(address, prefixLen);
- validateIpv6LinkAddressTypeOrThrow(linkAddress);
- } catch (UnknownHostException | IllegalArgumentException e) {
- throw new InvalidSyntaxException("Invalid attribute value", e);
- }
- }
-
- private void validateIpv6LinkAddressTypeOrThrow(LinkAddress address) {
- if (!address.isIpv6()) {
- throw new IllegalArgumentException("Input LinkAddress is not IPv6");
- }
- }
-
- @Override
- protected void encodeValueToByteBuffer(ByteBuffer buffer) {
- if (linkAddress == null) {
- buffer.put(new byte[VALUE_LEN_NOT_INCLUDED]);
- return;
- }
-
- buffer.put(linkAddress.getAddress().getAddress())
- .put((byte) linkAddress.getPrefixLength());
- }
-
- @Override
- protected int getValueLength() {
- return linkAddress == null ? VALUE_LEN_NOT_INCLUDED : VALUE_LEN;
- }
-
- @Override
- protected boolean isLengthValid(int length) {
- return length == VALUE_LEN || length == VALUE_LEN_NOT_INCLUDED;
- }
- }
-
- /** This class represents Configuration Attribute for IPv6 internal addresses. */
- public static class ConfigAttributeIpv6Address extends ConfigAttrIpv6AddrRangeBase {
- /** Construct an instance with specified address for an outbound packet. */
- public ConfigAttributeIpv6Address(LinkAddress ipv6LinkAddress) {
- super(CONFIG_ATTR_INTERNAL_IP6_ADDRESS, ipv6LinkAddress);
- }
-
- /**
- * Construct an instance without a specified address for an outbound packet.
- *
- * <p>It must be only used in a configuration request.
- */
- public ConfigAttributeIpv6Address() {
- super(CONFIG_ATTR_INTERNAL_IP6_ADDRESS);
- }
-
- /** Construct an instance with a decoded inbound packet. */
- @VisibleForTesting
- ConfigAttributeIpv6Address(byte[] value) throws InvalidSyntaxException {
- super(CONFIG_ATTR_INTERNAL_IP6_ADDRESS, value);
- }
- }
-
- /** This class represents Configuration Attribute for IPv6 subnets. */
- public static class ConfigAttributeIpv6Subnet extends ConfigAttrIpv6AddrRangeBase {
- /** Construct an instance with specified subnet for an outbound packet. */
- public ConfigAttributeIpv6Subnet(LinkAddress ipv6LinkAddress) {
- super(CONFIG_ATTR_INTERNAL_IP6_SUBNET, ipv6LinkAddress);
- }
-
- /**
- * Construct an instance without a specified subnet for an outbound packet.
- *
- * <p>It must be only used in a configuration request.
- */
- public ConfigAttributeIpv6Subnet() {
- super(CONFIG_ATTR_INTERNAL_IP6_SUBNET);
- }
-
- /** Construct an instance with a decoded inbound packet. */
- @VisibleForTesting
- ConfigAttributeIpv6Subnet(byte[] value) throws InvalidSyntaxException {
- super(CONFIG_ATTR_INTERNAL_IP6_SUBNET, value);
- }
- }
-
- /**
- * This class represents Configuration Attribute for IPv6 DNS.
- *
- * <p>There is no use case to create a DNS request for a specfic DNS server address. As an IKE
- * client, we will only support building an empty DNS attribute for an outbound IKE packet.
- */
- public static class ConfigAttributeIpv6Dns extends ConfigAttribute {
- public final Inet6Address address;
-
- /** Construct an instance with specified DNS server address for an outbound packet. */
- public ConfigAttributeIpv6Dns(Inet6Address ipv6Address) {
- super(CONFIG_ATTR_INTERNAL_IP6_DNS);
- address = ipv6Address;
- }
-
- /**
- * Construct an instance without a specified DNS server address for an outbound packet.
- *
- * <p>It must be only used in a configuration request.
- */
- public ConfigAttributeIpv6Dns() {
- super(CONFIG_ATTR_INTERNAL_IP6_DNS);
- this.address = null;
- }
-
- protected ConfigAttributeIpv6Dns(byte[] value) throws InvalidSyntaxException {
- super(CONFIG_ATTR_INTERNAL_IP6_DNS, value.length);
-
- if (value.length == VALUE_LEN_NOT_INCLUDED) {
- address = null;
- return;
- }
-
- try {
- InetAddress netAddress = InetAddress.getByAddress(value);
-
- if (!(netAddress instanceof Inet6Address)) {
- throw new InvalidSyntaxException("Invalid IPv6 address.");
- }
- address = (Inet6Address) netAddress;
- } catch (UnknownHostException e) {
- throw new InvalidSyntaxException("Invalid attribute value", e);
- }
- }
-
- @Override
- protected void encodeValueToByteBuffer(ByteBuffer buffer) {
- if (address == null) {
- buffer.put(new byte[0]);
- return;
- }
-
- buffer.put(address.getAddress());
- }
-
- @Override
- protected int getValueLength() {
- return address == null ? 0 : IPV6_ADDRESS_LEN;
- }
-
- @Override
- protected boolean isLengthValid(int length) {
- return length == IPV6_ADDRESS_LEN || length == VALUE_LEN_NOT_INCLUDED;
- }
- }
-
- /**
- * Encode Configuration payload to ByteBUffer.
- *
- * @param nextPayload type of payload that follows this payload.
- * @param byteBuffer destination ByteBuffer that stores encoded payload.
- */
- @Override
- protected void encodeToByteBuffer(@PayloadType int nextPayload, ByteBuffer byteBuffer) {
- encodePayloadHeaderToByteBuffer(nextPayload, getPayloadLength(), byteBuffer);
- byteBuffer.put((byte) configType).put(new byte[CONFIG_HEADER_RESERVED_LEN]);
-
- for (ConfigAttribute attr : recognizedAttributeList) {
- attr.encodeAttributeToByteBuffer(byteBuffer);
- }
- }
-
- /**
- * Get entire payload length.
- *
- * @return entire payload length.
- */
- @Override
- protected int getPayloadLength() {
- int len = GENERIC_HEADER_LENGTH + CONFIG_HEADER_LEN;
-
- for (ConfigAttribute attr : recognizedAttributeList) {
- len += attr.getAttributeLen();
- }
-
- return len;
- }
-
- /**
- * Return the payload type as a String.
- *
- * @return the payload type as a String.
- */
- @Override
- public String getTypeString() {
- switch (configType) {
- case CONFIG_TYPE_REQUEST:
- return "CP(Req)";
- case CONFIG_TYPE_REPLY:
- return "CP(Reply)";
- default:
- return "CP(" + configType + ")";
- }
- }
-}
diff --git a/src/java/com/android/internal/net/ipsec/ike/message/IkeEapPayload.java b/src/java/com/android/internal/net/ipsec/ike/message/IkeEapPayload.java
deleted file mode 100644
index 5dc14971..00000000
--- a/src/java/com/android/internal/net/ipsec/ike/message/IkeEapPayload.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2018 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.message;
-
-import com.android.internal.net.eap.message.EapMessage;
-
-import java.nio.ByteBuffer;
-
-/**
- * IkeEapPayload represents an EAP payload.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.8">RFC 7296, Internet Key Exchange
- * Protocol Version 2 (IKEv2)</a>
- * @see <a href="https://tools.ietf.org/html/rfc3748#section-4">RFC 3748, Extensible Authentication
- * Protocol (EAP)</a>
- */
-public final class IkeEapPayload extends IkePayload {
- public final byte[] eapMessage;
-
- /**
- * Construct an instance of IkeEapPayload from a decoded inbound IKE packet.
- *
- * <p>Any syntax errors contained in the eapMessage will be handled in {@link EapMessage}.
- *
- * @param isCritical indicates if this payload is critical. Ignored in supported payload as
- * instructed by the RFC 7296.
- * @param eapMessage byte-array encoded EapMessage
- */
- IkeEapPayload(boolean isCritical, byte[] eapMessage) {
- super(PAYLOAD_TYPE_EAP, isCritical);
-
- this.eapMessage = eapMessage;
- }
-
- /**
- * Construct an instance of IkeEapPayload for an outbound IKE EAP message.
- *
- * <p>This eapMessage is constructed in the IKE session and is guaranteed to have valid syntax.
- *
- * @param eapMessage byte-array encoded EapMessage
- */
- public IkeEapPayload(byte[] eapMessage) {
- super(PAYLOAD_TYPE_EAP, false);
-
- this.eapMessage = eapMessage;
- }
-
- /**
- * Encode EAP Payload to ByteBuffer.
- *
- * @param nextPayload type of payload that follows this payload.
- * @param byteBuffer destination ByteBuffer that stores encoded payload.
- */
- @Override
- protected void encodeToByteBuffer(@PayloadType int nextPayload, ByteBuffer byteBuffer) {
- encodePayloadHeaderToByteBuffer(nextPayload, getPayloadLength(), byteBuffer);
- byteBuffer.put(eapMessage);
- }
-
- /**
- * Get entire payload length.
- *
- * @return entire payload length.
- */
- @Override
- protected int getPayloadLength() {
- return GENERIC_HEADER_LENGTH + eapMessage.length;
- }
-
- /**
- * Return the payload type as a String.
- *
- * @return the payload type as a String.
- */
- @Override
- public String getTypeString() {
- return "EAP";
- }
-}
diff --git a/src/java/com/android/internal/net/ipsec/ike/message/IkeEncryptedPayloadBody.java b/src/java/com/android/internal/net/ipsec/ike/message/IkeEncryptedPayloadBody.java
deleted file mode 100644
index 77cc9f4e..00000000
--- a/src/java/com/android/internal/net/ipsec/ike/message/IkeEncryptedPayloadBody.java
+++ /dev/null
@@ -1,390 +0,0 @@
-/*
- * Copyright (C) 2019 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.message;
-
-import android.net.ipsec.ike.exceptions.IkeProtocolException;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.net.ipsec.ike.crypto.IkeCipher;
-import com.android.internal.net.ipsec.ike.crypto.IkeCombinedModeCipher;
-import com.android.internal.net.ipsec.ike.crypto.IkeMacIntegrity;
-import com.android.internal.net.ipsec.ike.crypto.IkeNormalModeCipher;
-
-import java.nio.ByteBuffer;
-import java.security.GeneralSecurityException;
-import java.security.SecureRandom;
-import java.util.Arrays;
-
-import javax.crypto.AEADBadTagException;
-import javax.crypto.IllegalBlockSizeException;
-
-/**
- * IkeEncryptedPayloadBody is a package private class that represents an IKE payload substructure
- * that contains initialization vector, encrypted content, padding, pad length and integrity
- * checksum.
- *
- * <p>Both an Encrypted Payload (IkeSkPayload) and an EncryptedFragmentPayload (IkeSkfPayload)
- * consists of an IkeEncryptedPayloadBody instance.
- *
- * <p>When using normal cipher with separate integrity algorithm, data to authenticate includes
- * bytes from beginning of IKE header to the pad length, which are concatenation of IKE header,
- * current payload header, iv and encrypted and padded data.
- *
- * <p>When using AEAD, additional authentication data(also known as) associated data is required. It
- * MUST include bytes from beginning of IKE header to the last octet of the Payload Header of the
- * Encrypted Payload. Note fragment number and total fragments are also included if Encrypted
- * Payload is SKF.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#page-105">RFC 7296, Internet Key Exchange
- * Protocol Version 2 (IKEv2)</a>
- * @see <a href="https://tools.ietf.org/html/rfc7383#page-6">RFC 7383, Internet Key Exchange
- * Protocol Version 2 (IKEv2) Message Fragmentation</a>
- */
-final class IkeEncryptedPayloadBody {
- // Length of pad length field.
- private static final int PAD_LEN_LEN = 1;
-
- private final byte[] mUnencryptedData;
- private final byte[] mEncryptedAndPaddedData;
- private final byte[] mIv;
- private final byte[] mIntegrityChecksum;
-
- /**
- * Package private constructor for constructing an instance of IkeEncryptedPayloadBody from
- * decrypting an incoming packet.
- */
- IkeEncryptedPayloadBody(
- byte[] message,
- int encryptedBodyOffset,
- IkeMacIntegrity integrityMac,
- IkeCipher decryptCipher,
- byte[] integrityKey,
- byte[] decryptionKey)
- throws IkeProtocolException, GeneralSecurityException {
- ByteBuffer inputBuffer = ByteBuffer.wrap(message);
-
- // Skip IKE header and generic payload header (and SKF header)
- inputBuffer.get(new byte[encryptedBodyOffset]);
-
- // Extract bytes for authentication and decryption.
- int expectedIvLen = decryptCipher.getIvLen();
- mIv = new byte[expectedIvLen];
-
- int checksumLen = getChecksum(integrityMac, decryptCipher);
- int encryptedDataLen = message.length - (encryptedBodyOffset + expectedIvLen + checksumLen);
- // IkeMessage will catch exception if encryptedDataLen is negative.
- mEncryptedAndPaddedData = new byte[encryptedDataLen];
-
- mIntegrityChecksum = new byte[checksumLen];
- inputBuffer.get(mIv).get(mEncryptedAndPaddedData).get(mIntegrityChecksum);
-
- if (decryptCipher.isAead()) {
- byte[] dataToAuthenticate = Arrays.copyOfRange(message, 0, encryptedBodyOffset);
- mUnencryptedData =
- combinedModeDecrypt(
- (IkeCombinedModeCipher) decryptCipher,
- mEncryptedAndPaddedData,
- mIntegrityChecksum,
- dataToAuthenticate,
- decryptionKey,
- mIv);
- } else {
- byte[] dataToAuthenticate =
- Arrays.copyOfRange(message, 0, message.length - checksumLen);
-
- validateInboundChecksumOrThrow(
- dataToAuthenticate, integrityMac, integrityKey, mIntegrityChecksum);
- mUnencryptedData =
- normalModeDecrypt(
- mEncryptedAndPaddedData,
- (IkeNormalModeCipher) decryptCipher,
- decryptionKey,
- mIv);
- }
- }
-
- /**
- * Package private constructor for constructing an instance of IkeEncryptedPayloadBody for
- * building an outbound packet.
- */
- IkeEncryptedPayloadBody(
- IkeHeader ikeHeader,
- @IkePayload.PayloadType int firstPayloadType,
- byte[] skfHeaderBytes,
- byte[] unencryptedPayloads,
- IkeMacIntegrity integrityMac,
- IkeCipher encryptCipher,
- byte[] integrityKey,
- byte[] encryptionKey) {
- this(
- ikeHeader,
- firstPayloadType,
- skfHeaderBytes,
- unencryptedPayloads,
- integrityMac,
- encryptCipher,
- integrityKey,
- encryptionKey,
- encryptCipher.generateIv(),
- calculatePadding(unencryptedPayloads.length, encryptCipher.getBlockSize()));
- }
-
- /** Package private constructor only for testing. */
- @VisibleForTesting
- IkeEncryptedPayloadBody(
- IkeHeader ikeHeader,
- @IkePayload.PayloadType int firstPayloadType,
- byte[] skfHeaderBytes,
- byte[] unencryptedPayloads,
- IkeMacIntegrity integrityMac,
- IkeCipher encryptCipher,
- byte[] integrityKey,
- byte[] encryptionKey,
- byte[] iv,
- byte[] padding) {
- mUnencryptedData = unencryptedPayloads;
-
- mIv = iv;
- if (encryptCipher.isAead()) {
- byte[] paddedDataWithChecksum =
- combinedModeEncrypt(
- (IkeCombinedModeCipher) encryptCipher,
- ikeHeader,
- firstPayloadType,
- skfHeaderBytes,
- unencryptedPayloads,
- encryptionKey,
- iv,
- padding);
-
- int checkSumLen = ((IkeCombinedModeCipher) encryptCipher).getChecksumLen();
- mIntegrityChecksum = new byte[checkSumLen];
- mEncryptedAndPaddedData = new byte[paddedDataWithChecksum.length - checkSumLen];
-
- ByteBuffer buffer = ByteBuffer.wrap(paddedDataWithChecksum);
- buffer.get(mEncryptedAndPaddedData);
- buffer.get(mIntegrityChecksum);
- } else {
- // Encrypt data
- mEncryptedAndPaddedData =
- normalModeEncrypt(
- unencryptedPayloads,
- (IkeNormalModeCipher) encryptCipher,
- encryptionKey,
- iv,
- padding);
- // Calculate checksum
- mIntegrityChecksum =
- generateOutboundChecksum(
- ikeHeader,
- firstPayloadType,
- skfHeaderBytes,
- integrityMac,
- iv,
- mEncryptedAndPaddedData,
- integrityKey);
- }
- }
-
- private int getChecksum(IkeMacIntegrity integrityMac, IkeCipher decryptCipher) {
- if (decryptCipher.isAead()) {
- return ((IkeCombinedModeCipher) decryptCipher).getChecksumLen();
- } else {
- return integrityMac.getChecksumLen();
- }
- }
-
- /** Package private for testing */
- @VisibleForTesting
- static byte[] generateOutboundChecksum(
- IkeHeader ikeHeader,
- @IkePayload.PayloadType int firstPayloadType,
- byte[] skfHeaderBytes,
- IkeMacIntegrity integrityMac,
- byte[] iv,
- byte[] encryptedAndPaddedData,
- byte[] integrityKey) {
- // Length from encrypted payload header to the Pad Length field
- int encryptedPayloadHeaderToPadLen =
- IkePayload.GENERIC_HEADER_LENGTH
- + skfHeaderBytes.length
- + iv.length
- + encryptedAndPaddedData.length;
-
- // Calculate length of authentication data and allocate ByteBuffer.
- int dataToAuthenticateLength = IkeHeader.IKE_HEADER_LENGTH + encryptedPayloadHeaderToPadLen;
- ByteBuffer authenticatedSectionBuffer = ByteBuffer.allocate(dataToAuthenticateLength);
-
- // Build data to authenticate.
- int encryptedPayloadLength = encryptedPayloadHeaderToPadLen + integrityMac.getChecksumLen();
- ikeHeader.encodeToByteBuffer(authenticatedSectionBuffer, encryptedPayloadLength);
- IkePayload.encodePayloadHeaderToByteBuffer(
- firstPayloadType, encryptedPayloadLength, authenticatedSectionBuffer);
- authenticatedSectionBuffer.put(skfHeaderBytes).put(iv).put(encryptedAndPaddedData);
-
- // Calculate checksum
- return integrityMac.generateChecksum(integrityKey, authenticatedSectionBuffer.array());
- }
-
- /** Package private for testing */
- @VisibleForTesting
- static void validateInboundChecksumOrThrow(
- byte[] dataToAuthenticate,
- IkeMacIntegrity integrityMac,
- byte[] integrityKey,
- byte[] integrityChecksum)
- throws GeneralSecurityException {
- // TODO: Make it package private and add test.
- int checkSumLen = integrityChecksum.length;
- byte[] calculatedChecksum = integrityMac.generateChecksum(integrityKey, dataToAuthenticate);
-
- if (!Arrays.equals(integrityChecksum, calculatedChecksum)) {
- throw new GeneralSecurityException("Message authentication failed.");
- }
- }
-
- /** Package private for testing */
- @VisibleForTesting
- static byte[] normalModeEncrypt(
- byte[] dataToEncrypt,
- IkeNormalModeCipher encryptCipher,
- byte[] encryptionKey,
- byte[] iv,
- byte[] padding) {
- byte[] paddedData = getPaddedData(dataToEncrypt, padding);
-
- // Encrypt data.
- return encryptCipher.encrypt(paddedData, encryptionKey, iv);
- }
-
- /** Package private for testing */
- @VisibleForTesting
- static byte[] normalModeDecrypt(
- byte[] encryptedData,
- IkeNormalModeCipher decryptCipher,
- byte[] decryptionKey,
- byte[] iv)
- throws IllegalBlockSizeException {
- byte[] paddedPlaintext = decryptCipher.decrypt(encryptedData, decryptionKey, iv);
-
- return stripPadding(paddedPlaintext);
- }
-
- /** Package private for testing */
- @VisibleForTesting
- static byte[] combinedModeEncrypt(
- IkeCombinedModeCipher encryptCipher,
- IkeHeader ikeHeader,
- @IkePayload.PayloadType int firstPayloadType,
- byte[] skfHeaderBytes,
- byte[] dataToEncrypt,
- byte[] encryptionKey,
- byte[] iv,
- byte[] padding) {
- int dataToAuthenticateLength =
- IkeHeader.IKE_HEADER_LENGTH
- + IkePayload.GENERIC_HEADER_LENGTH
- + skfHeaderBytes.length;
- ByteBuffer authenticatedSectionBuffer = ByteBuffer.allocate(dataToAuthenticateLength);
-
- byte[] paddedData = getPaddedData(dataToEncrypt, padding);
- int encryptedPayloadLength =
- IkePayload.GENERIC_HEADER_LENGTH
- + skfHeaderBytes.length
- + iv.length
- + paddedData.length
- + encryptCipher.getChecksumLen();
- ikeHeader.encodeToByteBuffer(authenticatedSectionBuffer, encryptedPayloadLength);
- IkePayload.encodePayloadHeaderToByteBuffer(
- firstPayloadType, encryptedPayloadLength, authenticatedSectionBuffer);
- authenticatedSectionBuffer.put(skfHeaderBytes);
-
- return encryptCipher.encrypt(
- paddedData, authenticatedSectionBuffer.array(), encryptionKey, iv);
- }
-
- /** Package private for testing */
- @VisibleForTesting
- static byte[] combinedModeDecrypt(
- IkeCombinedModeCipher decryptCipher,
- byte[] encryptedData,
- byte[] checksum,
- byte[] dataToAuthenticate,
- byte[] decryptionKey,
- byte[] iv)
- throws AEADBadTagException {
- ByteBuffer dataWithChecksumBuffer =
- ByteBuffer.allocate(encryptedData.length + checksum.length);
- dataWithChecksumBuffer.put(encryptedData);
- dataWithChecksumBuffer.put(checksum);
- dataWithChecksumBuffer.rewind();
-
- byte[] paddedPlaintext =
- decryptCipher.decrypt(
- dataWithChecksumBuffer.array(), dataToAuthenticate, decryptionKey, iv);
-
- return stripPadding(paddedPlaintext);
- }
-
- /** Package private for testing */
- @VisibleForTesting
- static byte[] calculatePadding(int dataToEncryptLength, int blockSize) {
- // Sum of dataToEncryptLength, PAD_LEN_LEN and padLength should be aligned with block size.
- int unpaddedLen = dataToEncryptLength + PAD_LEN_LEN;
- int padLength = (unpaddedLen + blockSize - 1) / blockSize * blockSize - unpaddedLen;
- byte[] padding = new byte[padLength];
-
- // According to RFC 7296, "Padding MAY contain any value".
- new SecureRandom().nextBytes(padding);
-
- return padding;
- }
-
- private static byte[] getPaddedData(byte[] data, byte[] padding) {
- int padLength = padding.length;
- int paddedDataLength = data.length + padLength + PAD_LEN_LEN;
- ByteBuffer padBuffer = ByteBuffer.allocate(paddedDataLength);
- padBuffer.put(data).put(padding).put((byte) padLength);
-
- return padBuffer.array();
- }
-
- private static byte[] stripPadding(byte[] paddedPlaintext) {
- // Remove padding. Pad length value is the last byte of the padded unencrypted data.
- int padLength = Byte.toUnsignedInt(paddedPlaintext[paddedPlaintext.length - 1]);
- int decryptedDataLen = paddedPlaintext.length - padLength - PAD_LEN_LEN;
-
- return Arrays.copyOfRange(paddedPlaintext, 0, decryptedDataLen);
- }
-
- /** Package private */
- byte[] getUnencryptedData() {
- return mUnencryptedData;
- }
-
- /** Package private */
- int getLength() {
- return (mIv.length + mEncryptedAndPaddedData.length + mIntegrityChecksum.length);
- }
-
- /** Package private */
- byte[] encode() {
- ByteBuffer buffer = ByteBuffer.allocate(getLength());
- buffer.put(mIv).put(mEncryptedAndPaddedData).put(mIntegrityChecksum);
- return buffer.array();
- }
-}
diff --git a/src/java/com/android/internal/net/ipsec/ike/message/IkeInformationalPayload.java b/src/java/com/android/internal/net/ipsec/ike/message/IkeInformationalPayload.java
deleted file mode 100644
index 606c38f8..00000000
--- a/src/java/com/android/internal/net/ipsec/ike/message/IkeInformationalPayload.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2019 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.message;
-
-/**
- * IkeInformationalPayload abstracts all Payloads sent in INFORMATIONAL exchanges.
- *
- * <p>This class is a non-RFC payload for implementation simplicity.
- */
-public abstract class IkeInformationalPayload extends IkePayload {
- IkeInformationalPayload(int payloadType, boolean isCritical) {
- super(payloadType, isCritical);
- }
-}
diff --git a/src/java/com/android/internal/net/ipsec/ike/message/IkeMessage.java b/src/java/com/android/internal/net/ipsec/ike/message/IkeMessage.java
deleted file mode 100644
index 27fb9651..00000000
--- a/src/java/com/android/internal/net/ipsec/ike/message/IkeMessage.java
+++ /dev/null
@@ -1,981 +0,0 @@
-/*
- * Copyright (C) 2018 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.message;
-
-import static android.net.ipsec.ike.IkeManager.getIkeLog;
-
-import static com.android.internal.net.ipsec.ike.message.IkePayload.PayloadType;
-
-import android.annotation.IntDef;
-import android.annotation.Nullable;
-import android.net.ipsec.ike.exceptions.IkeException;
-import android.net.ipsec.ike.exceptions.IkeInternalException;
-import android.net.ipsec.ike.exceptions.IkeProtocolException;
-import android.util.Pair;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.net.ipsec.ike.SaRecord.IkeSaRecord;
-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.exceptions.InvalidMessageIdException;
-import com.android.internal.net.ipsec.ike.exceptions.InvalidSyntaxException;
-import com.android.internal.net.ipsec.ike.exceptions.UnsupportedCriticalPayloadException;
-import com.android.org.bouncycastle.jce.provider.BouncyCastleProvider;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.nio.BufferUnderflowException;
-import java.nio.ByteBuffer;
-import java.security.GeneralSecurityException;
-import java.security.Provider;
-import java.security.Security;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Set;
-
-/**
- * IkeMessage represents an IKE message.
- *
- * <p>It contains all attributes and provides methods for encoding, decoding, encrypting and
- * decrypting.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#section-3">RFC 7296, Internet Key Exchange
- * 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();
-
- // TODO: b/142070035 Use Conscrypt as default security provider instead of BC
-
- // Currently use HarmonyJSSE as TrustManager provider
- static final Provider TRUST_MANAGER_PROVIDER = Security.getProvider("HarmonyJSSE");
-
- // Payload types in this set may be included multiple times within an IKE message. All other
- // payload types can be included at most once.
- private static final Set<Integer> REPEATABLE_PAYLOAD_TYPES = new HashSet<>();
-
- static {
- REPEATABLE_PAYLOAD_TYPES.add(IkePayload.PAYLOAD_TYPE_CERT);
- REPEATABLE_PAYLOAD_TYPES.add(IkePayload.PAYLOAD_TYPE_CERT_REQUEST);
- REPEATABLE_PAYLOAD_TYPES.add(IkePayload.PAYLOAD_TYPE_NOTIFY);
- REPEATABLE_PAYLOAD_TYPES.add(IkePayload.PAYLOAD_TYPE_DELETE);
- REPEATABLE_PAYLOAD_TYPES.add(IkePayload.PAYLOAD_TYPE_VENDOR);
- }
-
- public final IkeHeader ikeHeader;
- public final List<IkePayload> ikePayloadList;
- /**
- * Conctruct an instance of IkeMessage. It is called by decode or for building outbound message.
- *
- * @param header the header of this IKE message
- * @param payloadList the list of decoded IKE payloads in this IKE message
- */
- public IkeMessage(IkeHeader header, List<IkePayload> payloadList) {
- ikeHeader = header;
- ikePayloadList = payloadList;
- }
-
- /**
- * Get security provider for IKE library
- *
- * <p>Use BouncyCastleProvider as the default security provider.
- *
- * @return the security provider of IKE library.
- */
- public static Provider getSecurityProvider() {
- // TODO: Move this getter out of IKE message package since not only this package uses it.
- return SECURITY_PROVIDER;
- }
-
- /**
- * Get security provider for X509TrustManager to do certificate validation.
- *
- * <p>Use JSSEProvdier as the default security provider.
- *
- * @return the provider for X509TrustManager
- */
- public static Provider getTrustManagerProvider() {
- return TRUST_MANAGER_PROVIDER;
- }
-
- /**
- * Decode unencrypted IKE message body and create an instance of IkeMessage.
- *
- * <p>This method catches all RuntimeException during decoding incoming IKE packet.
- *
- * @param expectedMsgId the expected message ID to validate against.
- * @param header the IKE header that is decoded but not validated.
- * @param inputPacket the byte array contains the whole IKE message.
- * @return the decoding result.
- */
- public static DecodeResult decode(int expectedMsgId, IkeHeader header, byte[] inputPacket) {
- return sIkeMessageHelper.decode(expectedMsgId, header, inputPacket);
- }
-
- /**
- * Decrypt and decode encrypted IKE message body and create an instance of IkeMessage.
- *
- * @param expectedMsgId the expected message ID to validate against.
- * @param integrityMac the negotiated integrity algorithm.
- * @param decryptCipher the negotiated encryption algorithm.
- * @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(
- int expectedMsgId,
- @Nullable IkeMacIntegrity integrityMac,
- IkeCipher decryptCipher,
- IkeSaRecord ikeSaRecord,
- IkeHeader ikeHeader,
- byte[] packet,
- DecodeResultPartial collectedFragments) {
- return sIkeMessageHelper.decode(
- expectedMsgId,
- integrityMac,
- decryptCipher,
- ikeSaRecord,
- ikeHeader,
- packet,
- collectedFragments);
- }
-
- private static List<IkePayload> decodePayloadList(
- @PayloadType int firstPayloadType, boolean isResp, byte[] unencryptedPayloads)
- throws IkeProtocolException {
- ByteBuffer inputBuffer = ByteBuffer.wrap(unencryptedPayloads);
- int currentPayloadType = firstPayloadType;
- // For supported payload
- List<IkePayload> supportedPayloadList = new LinkedList<>();
- // For unsupported critical payload
- List<Integer> unsupportedCriticalPayloadList = new LinkedList<>();
-
- // For marking the existence of supported payloads in this message.
- HashSet<Integer> supportedTypesFoundSet = new HashSet<>();
-
- StringBuilder logPayloadsSb = new StringBuilder();
- logPayloadsSb.append("Decoded payloads [ ");
-
- while (currentPayloadType != IkePayload.PAYLOAD_TYPE_NO_NEXT) {
- Pair<IkePayload, Integer> pair =
- IkePayloadFactory.getIkePayload(currentPayloadType, isResp, inputBuffer);
- IkePayload payload = pair.first;
- logPayloadsSb.append(payload.getTypeString()).append(" ");
-
- if (!(payload instanceof IkeUnsupportedPayload)) {
- int type = payload.payloadType;
- if (!supportedTypesFoundSet.add(type) && !REPEATABLE_PAYLOAD_TYPES.contains(type)) {
- throw new InvalidSyntaxException(
- "It is not allowed to have multiple payloads with payload type: "
- + type);
- }
-
- supportedPayloadList.add(payload);
- } else if (payload.isCritical) {
- unsupportedCriticalPayloadList.add(payload.payloadType);
- }
- // Simply ignore unsupported uncritical payload.
-
- currentPayloadType = pair.second;
- }
-
- logPayloadsSb.append("]");
- getIkeLog().d("IkeMessage", logPayloadsSb.toString());
-
- if (inputBuffer.remaining() > 0) {
- throw new InvalidSyntaxException(
- "Malformed IKE Payload: Unexpected bytes at the end of packet.");
- }
-
- if (unsupportedCriticalPayloadList.size() > 0) {
- throw new UnsupportedCriticalPayloadException(unsupportedCriticalPayloadList);
- }
-
- // TODO: Verify that for all status notification payloads, only
- // NOTIFY_TYPE_NAT_DETECTION_SOURCE_IP and NOTIFY_TYPE_IPCOMP_SUPPORTED can be included
- // multiple times in a request message. There is not a clear number restriction for
- // error notification payloads.
-
- return supportedPayloadList;
- }
-
- /**
- * Encode unencrypted IKE message.
- *
- * @return encoded IKE message in byte array.
- */
- public byte[] encode() {
- return sIkeMessageHelper.encode(this);
- }
-
- /**
- * Encrypt and encode packet.
- *
- * @param integrityMac the negotiated integrity algorithm.
- * @param encryptCipher the negotiated encryption algortihm.
- * @param ikeSaRecord the ikeSaRecord where this packet is sent on.
- * @param supportFragment if IKE fragmentation is supported
- * @param fragSize the maximum size of IKE fragment
- * @return encoded IKE message in byte array.
- */
- public byte[][] encryptAndEncode(
- @Nullable IkeMacIntegrity integrityMac,
- IkeCipher encryptCipher,
- IkeSaRecord ikeSaRecord,
- boolean supportFragment,
- int fragSize) {
- return sIkeMessageHelper.encryptAndEncode(
- integrityMac, encryptCipher, ikeSaRecord, this, supportFragment, fragSize);
- }
-
- /**
- * Encode all payloads to a byte array.
- *
- * @return byte array contains all encoded payloads
- */
- private byte[] encodePayloads() {
- StringBuilder logPayloadsSb = new StringBuilder();
- logPayloadsSb.append("Generating payloads [ ");
-
- int payloadLengthSum = 0;
- for (IkePayload payload : ikePayloadList) {
- payloadLengthSum += payload.getPayloadLength();
- logPayloadsSb.append(payload.getTypeString()).append(" ");
- }
- logPayloadsSb.append("]");
- getIkeLog().d("IkeMessage", logPayloadsSb.toString());
-
- if (ikePayloadList.isEmpty()) return new byte[0];
-
- ByteBuffer byteBuffer = ByteBuffer.allocate(payloadLengthSum);
- for (int i = 0; i < ikePayloadList.size() - 1; i++) {
- ikePayloadList
- .get(i)
- .encodeToByteBuffer(ikePayloadList.get(i + 1).payloadType, byteBuffer);
- }
- ikePayloadList
- .get(ikePayloadList.size() - 1)
- .encodeToByteBuffer(IkePayload.PAYLOAD_TYPE_NO_NEXT, byteBuffer);
-
- return byteBuffer.array();
- }
-
- /** Package */
- @VisibleForTesting
- byte[] attachEncodedHeader(byte[] encodedIkeBody) {
- ByteBuffer outputBuffer =
- ByteBuffer.allocate(IkeHeader.IKE_HEADER_LENGTH + encodedIkeBody.length);
- ikeHeader.encodeToByteBuffer(outputBuffer, encodedIkeBody.length);
- outputBuffer.put(encodedIkeBody);
- return outputBuffer.array();
- }
-
- /**
- * Obtain all payloads with input payload type.
- *
- * <p>This method can be only applied to the payload types that can be included multiple times
- * within an IKE message.
- *
- * @param payloadType the payloadType to look for.
- * @param payloadClass the class of the desired payloads.
- * @return a list of IkePayloads with the payloadType.
- */
- public <T extends IkePayload> List<T> getPayloadListForType(
- @IkePayload.PayloadType int payloadType, Class<T> payloadClass) {
- // STOPSHIP: b/130190639 Notify user the error and close IKE session.
- if (!REPEATABLE_PAYLOAD_TYPES.contains(payloadType)) {
- throw new IllegalArgumentException(
- "Received unexpected payloadType: "
- + payloadType
- + " that can be included at most once within an IKE message.");
- }
-
- return IkePayload.getPayloadListForTypeInProvidedList(
- payloadType, payloadClass, ikePayloadList);
- }
-
- /**
- * Obtain the payload with the input payload type.
- *
- * <p>This method can be only applied to the payload type that can be included at most once
- * within an IKE message.
- *
- * @param payloadType the payloadType to look for.
- * @param payloadClass the class of the desired payload.
- * @return the IkePayload with the payloadType.
- */
- public <T extends IkePayload> T getPayloadForType(
- @IkePayload.PayloadType int payloadType, Class<T> payloadClass) {
- // STOPSHIP: b/130190639 Notify user the error and close IKE session.
- if (REPEATABLE_PAYLOAD_TYPES.contains(payloadType)) {
- throw new IllegalArgumentException(
- "Received unexpected payloadType: "
- + payloadType
- + " that may be included multiple times within an IKE message.");
- }
-
- return IkePayload.getPayloadForTypeInProvidedList(
- payloadType, payloadClass, ikePayloadList);
- }
-
- /**
- * Checks if this Request IkeMessage was a DPD message
- *
- * <p>An IKE message is a DPD request iff the message was encrypted (has a SK payload) and there
- * were no payloads within the SK payload (or outside the SK payload).
- */
- public boolean isDpdRequest() {
- return !ikeHeader.isResponseMsg
- && ikeHeader.exchangeType == IkeHeader.EXCHANGE_TYPE_INFORMATIONAL
- && ikePayloadList.isEmpty()
- && ikeHeader.nextPayloadType == IkePayload.PAYLOAD_TYPE_SK;
- }
-
- /**
- * IIkeMessageHelper provides interface for decoding, encoding and processing IKE packet.
- *
- * <p>IkeMessageHelper exists so that the interface is injectable for testing.
- */
- @VisibleForTesting
- public interface IIkeMessageHelper {
- /**
- * Encode IKE message.
- *
- * @param ikeMessage message need to be encoded.
- * @return encoded IKE message in byte array.
- */
- byte[] encode(IkeMessage ikeMessage);
-
- /**
- * Encrypt and encode IKE message.
- *
- * @param integrityMac the negotiated integrity algorithm.
- * @param encryptCipher the negotiated encryption algortihm.
- * @param ikeSaRecord the ikeSaRecord where this packet is sent on.
- * @param ikeMessage message need to be encoded. * @param supportFragment if IKE
- * fragmentation is supported.
- * @param fragSize the maximum size of IKE fragment.
- * @return encoded IKE message in byte array.
- */
- byte[][] encryptAndEncode(
- @Nullable IkeMacIntegrity integrityMac,
- IkeCipher encryptCipher,
- IkeSaRecord ikeSaRecord,
- IkeMessage ikeMessage,
- boolean supportFragment,
- int fragSize);
-
- // TODO: Return DecodeResult when decoding unencrypted message
- /**
- * Decode unencrypted packet.
- *
- * @param expectedMsgId the expected message ID to validate against.
- * @param ikeHeader header of IKE packet.
- * @param packet IKE packet as a byte array.
- * @return the decoding result.
- */
- DecodeResult decode(int expectedMsgId, IkeHeader ikeHeader, byte[] packet);
-
- /**
- * Decrypt and decode packet.
- *
- * @param expectedMsgId the expected message ID to validate against.
- * @param integrityMac the negotiated integrity algorithm.
- * @param decryptCipher the negotiated encryption algorithm.
- * @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(
- int expectedMsgId,
- @Nullable IkeMacIntegrity integrityMac,
- IkeCipher decryptCipher,
- IkeSaRecord ikeSaRecord,
- IkeHeader ikeHeader,
- byte[] packet,
- DecodeResultPartial collectedFragments);
- }
-
- /** IkeMessageHelper provides methods for decoding, encoding and processing IKE packet. */
- public static final class IkeMessageHelper implements IIkeMessageHelper {
- @Override
- public byte[] encode(IkeMessage ikeMessage) {
- getIkeLog().d("IkeMessage", "Generating " + ikeMessage.ikeHeader.getBasicInfoString());
-
- byte[] encodedIkeBody = ikeMessage.encodePayloads();
- byte[] packet = ikeMessage.attachEncodedHeader(encodedIkeBody);
- getIkeLog().d("IkeMessage", "Build a complete IKE message: " + getIkeLog().pii(packet));
- return packet;
- }
-
- @Override
- public byte[][] encryptAndEncode(
- @Nullable IkeMacIntegrity integrityMac,
- IkeCipher encryptCipher,
- IkeSaRecord ikeSaRecord,
- IkeMessage ikeMessage,
- boolean supportFragment,
- int fragSize) {
- getIkeLog().d("IkeMessage", "Generating " + ikeMessage.ikeHeader.getBasicInfoString());
-
- return encryptAndEncode(
- ikeMessage.ikeHeader,
- ikeMessage.ikePayloadList.isEmpty()
- ? IkePayload.PAYLOAD_TYPE_NO_NEXT
- : ikeMessage.ikePayloadList.get(0).payloadType,
- ikeMessage.encodePayloads(),
- integrityMac,
- encryptCipher,
- ikeSaRecord.getOutboundIntegrityKey(),
- ikeSaRecord.getOutboundEncryptionKey(),
- supportFragment,
- fragSize);
- }
-
- @VisibleForTesting
- byte[][] encryptAndEncode(
- IkeHeader ikeHeader,
- @PayloadType int firstInnerPayload,
- byte[] unencryptedPayloads,
- @Nullable IkeMacIntegrity integrityMac,
- IkeCipher encryptCipher,
- byte[] integrityKey,
- byte[] encryptionKey,
- boolean supportFragment,
- int fragSize) {
-
- IkeSkPayload skPayload =
- new IkeSkPayload(
- ikeHeader,
- firstInnerPayload,
- unencryptedPayloads,
- integrityMac,
- encryptCipher,
- integrityKey,
- encryptionKey);
- int msgLen = IkeHeader.IKE_HEADER_LENGTH + skPayload.getPayloadLength();
-
- // Build complete IKE message
- if (!supportFragment || msgLen <= fragSize) {
- byte[][] packetList = new byte[1][];
- packetList[0] = encodeHeaderAndBody(ikeHeader, skPayload, firstInnerPayload);
-
- getIkeLog()
- .d(
- "IkeMessage",
- "Build a complete IKE message: " + getIkeLog().pii(packetList[0]));
- return packetList;
- }
-
- // Build IKE fragments
- int dataLenPerPacket =
- fragSize
- - IkeHeader.IKE_HEADER_LENGTH
- - IkePayload.GENERIC_HEADER_LENGTH
- - IkeSkfPayload.SKF_HEADER_LEN
- - encryptCipher.getIvLen()
- - integrityMac.getChecksumLen()
- - encryptCipher.getBlockSize();
-
- // Caller of this method MUST validate fragSize is valid.
- if (dataLenPerPacket <= 0) {
- throw new IllegalArgumentException(
- "Max fragment size is too small for an IKE fragment.");
- }
-
- int totalFragments =
- (unencryptedPayloads.length + dataLenPerPacket - 1) / dataLenPerPacket;
- IkeHeader skfHeader = ikeHeader.makeSkfHeaderFromSkHeader();
- byte[][] packetList = new byte[totalFragments][];
-
- ByteBuffer unencryptedDataBuffer = ByteBuffer.wrap(unencryptedPayloads);
- for (int i = 0; i < totalFragments; i++) {
- byte[] unencryptedData =
- new byte[Math.min(dataLenPerPacket, unencryptedDataBuffer.remaining())];
- unencryptedDataBuffer.get(unencryptedData);
-
- int fragNum = i + 1; // 1-based
-
- IkeSkfPayload skfPayload =
- new IkeSkfPayload(
- ikeHeader,
- firstInnerPayload,
- unencryptedData,
- integrityMac,
- encryptCipher,
- integrityKey,
- encryptionKey,
- fragNum,
- totalFragments);
-
- packetList[i] =
- encodeHeaderAndBody(
- skfHeader,
- skfPayload,
- i == 0 ? firstInnerPayload : IkePayload.PAYLOAD_TYPE_NO_NEXT);
- getIkeLog()
- .d(
- "IkeMessage",
- "Build an IKE fragment ("
- + (i + 1)
- + "/"
- + totalFragments
- + "): "
- + getIkeLog().pii(packetList[0]));
- }
-
- return packetList;
- }
-
- private byte[] encodeHeaderAndBody(
- IkeHeader ikeHeader, IkeSkPayload skPayload, @PayloadType int firstInnerPayload) {
- ByteBuffer outputBuffer =
- ByteBuffer.allocate(IkeHeader.IKE_HEADER_LENGTH + skPayload.getPayloadLength());
- ikeHeader.encodeToByteBuffer(outputBuffer, skPayload.getPayloadLength());
- skPayload.encodeToByteBuffer(firstInnerPayload, outputBuffer);
- return outputBuffer.array();
- }
-
- @Override
- public DecodeResult decode(int expectedMsgId, IkeHeader header, byte[] inputPacket) {
- try {
- if (header.messageId != expectedMsgId) {
- throw new InvalidMessageIdException(header.messageId);
- }
-
- header.validateMajorVersion();
- header.validateInboundHeader(inputPacket.length);
-
- byte[] unencryptedPayloads =
- Arrays.copyOfRange(
- inputPacket, IkeHeader.IKE_HEADER_LENGTH, inputPacket.length);
- List<IkePayload> supportedPayloadList =
- decodePayloadList(
- header.nextPayloadType, header.isResponseMsg, unencryptedPayloads);
- return new DecodeResultOk(
- new IkeMessage(header, supportedPayloadList), inputPacket);
- } catch (NegativeArraySizeException | BufferUnderflowException e) {
- // Invalid length error when parsing payload bodies.
- return new DecodeResultUnprotectedError(
- new InvalidSyntaxException("Malformed IKE Payload"));
- } catch (IkeProtocolException e) {
- return new DecodeResultUnprotectedError(e);
- }
- }
-
- @Override
- public DecodeResult decode(
- int expectedMsgId,
- @Nullable IkeMacIntegrity integrityMac,
- IkeCipher decryptCipher,
- IkeSaRecord ikeSaRecord,
- IkeHeader ikeHeader,
- byte[] packet,
- DecodeResultPartial collectedFragments) {
- return decode(
- expectedMsgId,
- ikeHeader,
- packet,
- integrityMac,
- decryptCipher,
- ikeSaRecord.getInboundIntegrityKey(),
- ikeSaRecord.getInboundDecryptionKey(),
- collectedFragments);
- }
-
- private DecodeResult decode(
- int expectedMsgId,
- IkeHeader header,
- byte[] inputPacket,
- @Nullable IkeMacIntegrity integrityMac,
- IkeCipher decryptCipher,
- byte[] integrityKey,
- 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");
- }
-
- // Decrypt message and do authentication
- Pair<IkeSkPayload, Integer> pair;
- try {
- pair =
- decryptAndAuthenticate(
- expectedMsgId,
- header,
- inputPacket,
- integrityMac,
- decryptCipher,
- integrityKey,
- decryptionKey);
- } catch (IkeException e) {
- if (collectedFragments == null) {
- return new DecodeResultUnprotectedError(e);
- } else {
- getIkeLog()
- .i(
- TAG,
- "Message authentication or decryption failed on received"
- + " message. Discard it ",
- e);
- return collectedFragments;
- }
- }
-
- // 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[] firstPacket = inputPacket;
- 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,
- inputPacket,
- (IkeSkfPayload) (pair.first),
- pair.second,
- collectedFragments);
-
- if (!DecodeResultPartial.isAllFragmentsReceived()) return DecodeResultPartial;
-
- firstPayloadType = DecodeResultPartial.firstPayloadType;
- decryptedBytes = DecodeResultPartial.reassembleAllFrags();
- firstPacket = DecodeResultPartial.firstFragBytes;
- }
-
- // Received or has reassembled a complete IKE message. Check if there is protocol error.
- try {
- // TODO: Log IKE header information and payload types
-
- List<IkePayload> supportedPayloadList =
- decodePayloadList(firstPayloadType, header.isResponseMsg, decryptedBytes);
-
- header.validateInboundHeader(inputPacket.length);
- return new DecodeResultOk(
- new IkeMessage(header, supportedPayloadList), firstPacket);
- } catch (NegativeArraySizeException | BufferUnderflowException e) {
- // Invalid length error when parsing payload bodies.
- return new DecodeResultProtectedError(
- new InvalidSyntaxException("Malformed IKE Payload", e), firstPacket);
- } catch (IkeProtocolException e) {
- return new DecodeResultProtectedError(e, firstPacket);
- }
- }
-
- 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,
- byte[] inputPacket,
- IkeSkfPayload skf,
- int nextPayloadType,
- @Nullable DecodeResultPartial collectedFragments) {
- if (collectedFragments == null) {
- return new DecodeResultPartial(
- header, inputPacket, 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, inputPacket, 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, inputPacket, skf, nextPayloadType, collectedFragments);
- }
- }
-
- /** Status to describe the result of decoding an inbound IKE message. */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({
- DECODE_STATUS_OK,
- DECODE_STATUS_PARTIAL,
- DECODE_STATUS_PROTECTED_ERROR,
- DECODE_STATUS_UNPROTECTED_ERROR,
- })
- public @interface DecodeStatus {}
-
- /**
- * Represents a message that has been successfully (decrypted and) decoded or reassembled from
- * IKE fragments
- */
- public static final int DECODE_STATUS_OK = 0;
- /** Represents that reassembly process of IKE fragments has started but has not finished */
- public static final int DECODE_STATUS_PARTIAL = 1;
- /** Represents a crypto protected message with correct message ID but has parsing error. */
- public static final int DECODE_STATUS_PROTECTED_ERROR = 2;
- /**
- * Represents an unencrypted message with parsing error, an encrypted message with
- * authentication or decryption error, or any message with wrong message ID.
- */
- public static final int DECODE_STATUS_UNPROTECTED_ERROR = 3;
-
- /** This class represents common decoding result of an IKE message. */
- public abstract static class DecodeResult {
- public final int status;
-
- /** Construct an instance of DecodeResult. */
- protected DecodeResult(int status) {
- this.status = status;
- }
- }
-
- /** This class represents an IKE message has been successfully (decrypted and) decoded. */
- public static class DecodeResultOk extends DecodeResult {
- public final IkeMessage ikeMessage;
- public final byte[] firstPacket;
-
- public DecodeResultOk(IkeMessage ikeMessage, byte[] firstPacket) {
- super(DECODE_STATUS_OK);
- this.ikeMessage = ikeMessage;
- this.firstPacket = firstPacket;
- }
- }
-
- /**
- * This class represents IKE fragments are being reassembled to build a complete IKE message.
- *
- * <p>All IKE fragments should have the same IKE headers, except for the message length. This
- * class only stores the IKE header of the first arrived IKE fragment to represent the IKE
- * header of the complete IKE message. In this way we can verify all subsequent fragments'
- * headers against it.
- *
- * <p>The first payload type is only stored in the first fragment, as indicated in RFC 7383. So
- * this class only stores the next payload type field taken from the first fragment.
- */
- public static class DecodeResultPartial extends DecodeResult {
- public final int firstPayloadType;
- public final byte[] firstFragBytes;
- public final IkeHeader ikeHeader;
- public final byte[][] collectedFragsList;
-
- /**
- * Construct an instance of DecodeResultPartial with collected fragments and the newly
- * received fragment.
- *
- * <p>The newly received fragment has been validated against collected fragments during
- * decoding that all fragments have the same total fragments number and the newly received
- * fragment is not a replay.
- */
- public DecodeResultPartial(
- IkeHeader ikeHeader,
- byte[] inputPacket,
- IkeSkfPayload skfPayload,
- int nextPayloadType,
- @Nullable DecodeResultPartial collectedFragments) {
- super(DECODE_STATUS_PARTIAL);
-
- boolean isFirstFragment = 1 == skfPayload.fragmentNum;
- if (collectedFragments == null) {
- // First arrived IKE fragment
- this.ikeHeader = ikeHeader;
- this.firstPayloadType =
- isFirstFragment ? nextPayloadType : IkePayload.PAYLOAD_TYPE_NO_NEXT;
- this.firstFragBytes = isFirstFragment ? inputPacket : null;
- this.collectedFragsList = new byte[skfPayload.totalFragments][];
- } else {
- this.ikeHeader = collectedFragments.ikeHeader;
- this.firstPayloadType =
- isFirstFragment ? nextPayloadType : collectedFragments.firstPayloadType;
- this.firstFragBytes =
- isFirstFragment ? inputPacket : collectedFragments.firstFragBytes;
- this.collectedFragsList = collectedFragments.collectedFragsList;
- }
-
- this.collectedFragsList[skfPayload.fragmentNum - 1] = skfPayload.getUnencryptedData();
- }
-
- /** Return if all IKE fragments have been collected */
- public boolean isAllFragmentsReceived() {
- for (byte[] frag : collectedFragsList) {
- if (frag == null) return false;
- }
- return true;
- }
-
- /** Reassemble all IKE fragments and return the unencrypted message body in byte array. */
- public byte[] reassembleAllFrags() {
- if (!isAllFragmentsReceived()) {
- throw new IllegalStateException("Not all fragments have been received");
- }
-
- int len = 0;
- for (byte[] frag : collectedFragsList) {
- len += frag.length;
- }
-
- ByteBuffer buffer = ByteBuffer.allocate(len);
- for (byte[] frag : collectedFragsList) {
- buffer.put(frag);
- }
-
- return buffer.array();
- }
- }
-
- /**
- * This class represents common information of error cases in decrypting and decoding message.
- */
- public abstract static class DecodeResultError extends DecodeResult {
- public final IkeException ikeException;
-
- protected DecodeResultError(int status, IkeException ikeException) {
- super(status);
- this.ikeException = ikeException;
- }
- }
- /**
- * This class represents that decoding errors have been found after the IKE message is
- * authenticated and decrypted.
- */
- public static class DecodeResultProtectedError extends DecodeResultError {
- public final byte[] firstPacket;
-
- public DecodeResultProtectedError(IkeException ikeException, byte[] firstPacket) {
- super(DECODE_STATUS_PROTECTED_ERROR, ikeException);
- this.firstPacket = firstPacket;
- }
- }
- /** This class represents errors have been found during message authentication or decryption. */
- public static class DecodeResultUnprotectedError extends DecodeResultError {
- public DecodeResultUnprotectedError(IkeException ikeException) {
- super(DECODE_STATUS_UNPROTECTED_ERROR, ikeException);
- }
- }
-
- /**
- * For setting mocked IIkeMessageHelper for testing
- *
- * @param helper the mocked IIkeMessageHelper
- */
- public static void setIkeMessageHelper(IIkeMessageHelper helper) {
- sIkeMessageHelper = helper;
- }
-}
diff --git a/src/java/com/android/internal/net/ipsec/ike/message/IkeNotifyPayload.java b/src/java/com/android/internal/net/ipsec/ike/message/IkeNotifyPayload.java
deleted file mode 100644
index ce9529ee..00000000
--- a/src/java/com/android/internal/net/ipsec/ike/message/IkeNotifyPayload.java
+++ /dev/null
@@ -1,462 +0,0 @@
-/*
- * Copyright (C) 2018 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.message;
-
-import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_AUTHENTICATION_FAILED;
-import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_CHILD_SA_NOT_FOUND;
-import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_FAILED_CP_REQUIRED;
-import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_INTERNAL_ADDRESS_FAILURE;
-import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_INVALID_IKE_SPI;
-import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_INVALID_KE_PAYLOAD;
-import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_INVALID_MAJOR_VERSION;
-import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_INVALID_MESSAGE_ID;
-import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_INVALID_SELECTORS;
-import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_INVALID_SYNTAX;
-import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_NO_ADDITIONAL_SAS;
-import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_NO_PROPOSAL_CHOSEN;
-import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_SINGLE_PAIR_REQUIRED;
-import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_TEMPORARY_FAILURE;
-import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_TS_UNACCEPTABLE;
-import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_UNSUPPORTED_CRITICAL_PAYLOAD;
-
-import android.annotation.IntDef;
-import android.net.ipsec.ike.exceptions.IkeProtocolException;
-import android.util.ArraySet;
-import android.util.SparseArray;
-
-import com.android.internal.net.ipsec.ike.exceptions.AuthenticationFailedException;
-import com.android.internal.net.ipsec.ike.exceptions.InvalidKeException;
-import com.android.internal.net.ipsec.ike.exceptions.InvalidMajorVersionException;
-import com.android.internal.net.ipsec.ike.exceptions.InvalidMessageIdException;
-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.exceptions.TemporaryFailureException;
-import com.android.internal.net.ipsec.ike.exceptions.TsUnacceptableException;
-import com.android.internal.net.ipsec.ike.exceptions.UnrecognizedIkeProtocolException;
-import com.android.internal.net.ipsec.ike.exceptions.UnsupportedCriticalPayloadException;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.net.InetAddress;
-import java.nio.ByteBuffer;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.security.ProviderException;
-import java.util.Set;
-
-/**
- * IkeNotifyPayload represents a Notify Payload.
- *
- * <p>As instructed by RFC 7296, for IKE SA concerned Notify Payload, Protocol ID and SPI Size must
- * be zero. Unrecognized notify message type must be ignored but should be logged.
- *
- * <p>Notification types that smaller or equal than ERROR_NOTIFY_TYPE_MAX are error types. The rest
- * of them are status types.
- *
- * <p>Critical bit for this payload must be ignored in received packet and must not be set in
- * outbound packet.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296">RFC 7296, Internet Key Exchange Protocol
- * Version 2 (IKEv2)</a>
- */
-public final class IkeNotifyPayload extends IkeInformationalPayload {
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({
- NOTIFY_TYPE_ADDITIONAL_TS_POSSIBLE,
- NOTIFY_TYPE_IPCOMP_SUPPORTED,
- NOTIFY_TYPE_NAT_DETECTION_SOURCE_IP,
- NOTIFY_TYPE_NAT_DETECTION_DESTINATION_IP,
- NOTIFY_TYPE_USE_TRANSPORT_MODE,
- NOTIFY_TYPE_REKEY_SA,
- NOTIFY_TYPE_ESP_TFC_PADDING_NOT_SUPPORTED
- })
- public @interface NotifyType {}
-
- /**
- * Indicates that the responder has narrowed the proposed Traffic Selectors but other Traffic
- * Selectors would also have been acceptable. Only allowed in the response for negotiating a
- * Child SA.
- */
- public static final int NOTIFY_TYPE_ADDITIONAL_TS_POSSIBLE = 16386;
- /**
- * Indicates a willingness by its sender to use IPComp on this Child SA. Only allowed in the
- * request/response for negotiating a Child SA.
- */
- public static final int NOTIFY_TYPE_IPCOMP_SUPPORTED = 16387;
- /**
- * Used for detecting if the IKE initiator is behind a NAT. Only allowed in the request/response
- * of IKE_SA_INIT exchange.
- */
- public static final int NOTIFY_TYPE_NAT_DETECTION_SOURCE_IP = 16388;
- /**
- * Used for detecting if the IKE responder is behind a NAT. Only allowed in the request/response
- * of IKE_SA_INIT exchange.
- */
- public static final int NOTIFY_TYPE_NAT_DETECTION_DESTINATION_IP = 16389;
- /**
- * Indicates a willingness by its sender to use transport mode rather than tunnel mode on this
- * Child SA. Only allowed in the request/response for negotiating a Child SA.
- */
- public static final int NOTIFY_TYPE_USE_TRANSPORT_MODE = 16391;
- /**
- * Used for rekeying a Child SA or an IKE SA. Only allowed in the request/response of
- * CREATE_CHILD_SA exchange.
- */
- public static final int NOTIFY_TYPE_REKEY_SA = 16393;
- /**
- * Indicates that the sender will not accept packets that contain TFC padding over the Child SA
- * being negotiated. Only allowed in the request/response for negotiating a Child SA.
- */
- public static final int NOTIFY_TYPE_ESP_TFC_PADDING_NOT_SUPPORTED = 16394;
- /** Indicates that the sender supports IKE fragmentation. */
- public static final int NOTIFY_TYPE_IKEV2_FRAGMENTATION_SUPPORTED = 16430;
-
- private static final int NOTIFY_HEADER_LEN = 4;
- private static final int ERROR_NOTIFY_TYPE_MAX = 16383;
-
- private static final String NAT_DETECTION_DIGEST_ALGORITHM = "SHA-1";
-
- private static final Set<Integer> VALID_NOTIFY_TYPES_FOR_EXISTING_CHILD_SA;
- private static final Set<Integer> VALID_NOTIFY_TYPES_FOR_NEW_CHILD_SA;
-
- private static final SparseArray<String> NOTIFY_TYPE_TO_STRING;
-
- static {
- VALID_NOTIFY_TYPES_FOR_EXISTING_CHILD_SA = new ArraySet<>();
- VALID_NOTIFY_TYPES_FOR_EXISTING_CHILD_SA.add(ERROR_TYPE_INVALID_SELECTORS);
- VALID_NOTIFY_TYPES_FOR_EXISTING_CHILD_SA.add(ERROR_TYPE_CHILD_SA_NOT_FOUND);
- VALID_NOTIFY_TYPES_FOR_EXISTING_CHILD_SA.add(NOTIFY_TYPE_REKEY_SA);
- }
-
- static {
- VALID_NOTIFY_TYPES_FOR_NEW_CHILD_SA = new ArraySet<>();
- VALID_NOTIFY_TYPES_FOR_NEW_CHILD_SA.add(IkeProtocolException.ERROR_TYPE_NO_PROPOSAL_CHOSEN);
- VALID_NOTIFY_TYPES_FOR_NEW_CHILD_SA.add(IkeProtocolException.ERROR_TYPE_INVALID_KE_PAYLOAD);
- VALID_NOTIFY_TYPES_FOR_NEW_CHILD_SA.add(
- IkeProtocolException.ERROR_TYPE_SINGLE_PAIR_REQUIRED);
- VALID_NOTIFY_TYPES_FOR_NEW_CHILD_SA.add(IkeProtocolException.ERROR_TYPE_NO_ADDITIONAL_SAS);
- VALID_NOTIFY_TYPES_FOR_NEW_CHILD_SA.add(
- IkeProtocolException.ERROR_TYPE_INTERNAL_ADDRESS_FAILURE);
- VALID_NOTIFY_TYPES_FOR_NEW_CHILD_SA.add(IkeProtocolException.ERROR_TYPE_FAILED_CP_REQUIRED);
- VALID_NOTIFY_TYPES_FOR_NEW_CHILD_SA.add(IkeProtocolException.ERROR_TYPE_TS_UNACCEPTABLE);
-
- VALID_NOTIFY_TYPES_FOR_NEW_CHILD_SA.add(NOTIFY_TYPE_ADDITIONAL_TS_POSSIBLE);
- VALID_NOTIFY_TYPES_FOR_NEW_CHILD_SA.add(NOTIFY_TYPE_IPCOMP_SUPPORTED);
- VALID_NOTIFY_TYPES_FOR_NEW_CHILD_SA.add(NOTIFY_TYPE_USE_TRANSPORT_MODE);
- VALID_NOTIFY_TYPES_FOR_NEW_CHILD_SA.add(NOTIFY_TYPE_ESP_TFC_PADDING_NOT_SUPPORTED);
- }
-
- static {
- NOTIFY_TYPE_TO_STRING = new SparseArray<>();
- NOTIFY_TYPE_TO_STRING.put(
- ERROR_TYPE_UNSUPPORTED_CRITICAL_PAYLOAD, "Unsupported critical payload");
- NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_INVALID_IKE_SPI, "Invalid IKE SPI");
- NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_INVALID_MAJOR_VERSION, "Invalid major version");
- NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_INVALID_SYNTAX, "Invalid syntax");
- NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_INVALID_MESSAGE_ID, "Invalid message ID");
- NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_NO_PROPOSAL_CHOSEN, "No proposal chosen");
- NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_INVALID_KE_PAYLOAD, "Invalid KE payload");
- NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_AUTHENTICATION_FAILED, "Authentication failed");
- NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_SINGLE_PAIR_REQUIRED, "Single pair required");
- NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_NO_ADDITIONAL_SAS, "No additional SAs");
- NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_INTERNAL_ADDRESS_FAILURE, "Internal address failure");
- NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_FAILED_CP_REQUIRED, "Failed CP required");
- NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_TS_UNACCEPTABLE, "TS unacceptable");
- NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_INVALID_SELECTORS, "Invalid selectors");
- NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_TEMPORARY_FAILURE, "Temporary failure");
- NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_CHILD_SA_NOT_FOUND, "Child SA not found");
-
- NOTIFY_TYPE_TO_STRING.put(NOTIFY_TYPE_ADDITIONAL_TS_POSSIBLE, "Additional TS possible");
- NOTIFY_TYPE_TO_STRING.put(NOTIFY_TYPE_IPCOMP_SUPPORTED, "IPCOMP supported");
- NOTIFY_TYPE_TO_STRING.put(NOTIFY_TYPE_NAT_DETECTION_SOURCE_IP, "NAT detection source IP");
- NOTIFY_TYPE_TO_STRING.put(
- NOTIFY_TYPE_NAT_DETECTION_DESTINATION_IP, "NAT detection destination IP");
- NOTIFY_TYPE_TO_STRING.put(NOTIFY_TYPE_USE_TRANSPORT_MODE, "Use transport mode");
- NOTIFY_TYPE_TO_STRING.put(NOTIFY_TYPE_REKEY_SA, "Rekey SA");
- NOTIFY_TYPE_TO_STRING.put(
- NOTIFY_TYPE_ESP_TFC_PADDING_NOT_SUPPORTED, "ESP TCP Padding not supported");
- NOTIFY_TYPE_TO_STRING.put(
- NOTIFY_TYPE_IKEV2_FRAGMENTATION_SUPPORTED, "Fragmentation supported");
- }
-
- public final int protocolId;
- public final byte spiSize;
- public final int notifyType;
- public final int spi;
- public final byte[] notifyData;
-
- /**
- * Construct an instance of IkeNotifyPayload in the context of IkePayloadFactory
- *
- * @param critical indicates if this payload is critical. Ignored in supported payload as
- * instructed by the RFC 7296.
- * @param payloadBody payload body in byte array
- * @throws IkeProtocolException if there is any error
- */
- IkeNotifyPayload(boolean isCritical, byte[] payloadBody) throws IkeProtocolException {
- super(PAYLOAD_TYPE_NOTIFY, isCritical);
-
- ByteBuffer inputBuffer = ByteBuffer.wrap(payloadBody);
-
- protocolId = Byte.toUnsignedInt(inputBuffer.get());
- spiSize = inputBuffer.get();
- notifyType = Short.toUnsignedInt(inputBuffer.getShort());
-
- // Validate syntax of spiSize, protocolId and notifyType.
- // Reference: <https://tools.ietf.org/html/rfc7296#page-100>
- if (spiSize == SPI_LEN_IPSEC) {
- // For message concerning existing Child SA
- validateNotifyPayloadForExistingChildSa();
- spi = inputBuffer.getInt();
-
- } else if (spiSize == SPI_LEN_NOT_INCLUDED) {
- // For message concerning IKE SA or for new Child SA that to be negotiated.
- validateNotifyPayloadForIkeAndNewChild();
- spi = SPI_NOT_INCLUDED;
-
- } else {
- throw new InvalidSyntaxException("Invalid SPI Size: " + spiSize);
- }
-
- notifyData = new byte[payloadBody.length - NOTIFY_HEADER_LEN - spiSize];
- inputBuffer.get(notifyData);
- }
-
- private void validateNotifyPayloadForExistingChildSa() throws InvalidSyntaxException {
- if (protocolId != PROTOCOL_ID_AH && protocolId != PROTOCOL_ID_ESP) {
- throw new InvalidSyntaxException(
- "Expected Procotol ID AH(2) or ESP(3): Protocol ID is " + protocolId);
- }
-
- if (!VALID_NOTIFY_TYPES_FOR_EXISTING_CHILD_SA.contains(notifyType)) {
- throw new InvalidSyntaxException(
- "Expected Notify Type for existing Child SA: Notify Type is " + notifyType);
- }
- }
-
- private void validateNotifyPayloadForIkeAndNewChild() throws InvalidSyntaxException {
- if (protocolId != PROTOCOL_ID_UNSET) {
- throw new InvalidSyntaxException(
- "Expected Procotol ID unset: Protocol ID is " + protocolId);
- }
-
- if (notifyType == ERROR_TYPE_INVALID_SELECTORS
- || notifyType == ERROR_TYPE_CHILD_SA_NOT_FOUND) {
- throw new InvalidSyntaxException(
- "Expected Notify Type concerning IKE SA or new Child SA under negotiation"
- + ": Notify Type is "
- + notifyType);
- }
- }
-
- /**
- * Generate NAT DETECTION notification data.
- *
- * <p>This method calculates NAT DETECTION notification data which is a SHA-1 digest of the IKE
- * initiator's SPI, IKE responder's SPI, IP address and port. Source address and port should be
- * used for generating NAT_DETECTION_SOURCE_IP data. Destination address and port should be used
- * for generating NAT_DETECTION_DESTINATION_IP data. Here "source" and "destination" mean the
- * direction of this IKE message.
- *
- * @param initiatorIkeSpi the SPI of IKE initiator
- * @param responderIkeSpi the SPI of IKE responder
- * @param ipAddress the IP address
- * @param port the port
- * @return the generated NAT DETECTION notification data as a byte array.
- */
- public static byte[] generateNatDetectionData(
- long initiatorIkeSpi, long responderIkeSpi, InetAddress ipAddress, int port) {
- byte[] rawIpAddr = ipAddress.getAddress();
-
- ByteBuffer byteBuffer =
- ByteBuffer.allocate(2 * SPI_LEN_IKE + rawIpAddr.length + IP_PORT_LEN);
- byteBuffer
- .putLong(initiatorIkeSpi)
- .putLong(responderIkeSpi)
- .put(rawIpAddr)
- .putShort((short) port);
-
- try {
- MessageDigest natDetectionDataDigest =
- MessageDigest.getInstance(
- NAT_DETECTION_DIGEST_ALGORITHM, IkeMessage.getSecurityProvider());
- return natDetectionDataDigest.digest(byteBuffer.array());
- } catch (NoSuchAlgorithmException e) {
- throw new ProviderException(
- "Failed to obtain algorithm :" + NAT_DETECTION_DIGEST_ALGORITHM, e);
- }
- }
-
- /**
- * Encode Notify payload to ByteBuffer.
- *
- * @param nextPayload type of payload that follows this payload.
- * @param byteBuffer destination ByteBuffer that stores encoded payload.
- */
- @Override
- protected void encodeToByteBuffer(@PayloadType int nextPayload, ByteBuffer byteBuffer) {
- encodePayloadHeaderToByteBuffer(nextPayload, getPayloadLength(), byteBuffer);
- byteBuffer.put((byte) protocolId).put(spiSize).putShort((short) notifyType);
- if (spiSize == SPI_LEN_IPSEC) {
- byteBuffer.putInt(spi);
- }
- byteBuffer.put(notifyData);
- }
-
- /**
- * Get entire payload length.
- *
- * @return entire payload length.
- */
- @Override
- protected int getPayloadLength() {
- return GENERIC_HEADER_LENGTH + NOTIFY_HEADER_LEN + spiSize + notifyData.length;
- }
-
- protected IkeNotifyPayload(
- @ProtocolId int protocolId, byte spiSize, int spi, int notifyType, byte[] notifyData) {
- super(PAYLOAD_TYPE_NOTIFY, false);
- this.protocolId = protocolId;
- this.spiSize = spiSize;
- this.spi = spi;
- this.notifyType = notifyType;
- this.notifyData = notifyData;
- }
-
- /**
- * Construct IkeNotifyPayload concerning either an IKE SA, or Child SA that is going to be
- * negotiated with associated notification data.
- *
- * @param notifyType the notify type concerning IKE SA
- * @param notifytData status or error data transmitted. Values for this field are notify type
- * specific.
- */
- public IkeNotifyPayload(int notifyType, byte[] notifyData) {
- this(PROTOCOL_ID_UNSET, SPI_LEN_NOT_INCLUDED, SPI_NOT_INCLUDED, notifyType, notifyData);
- try {
- validateNotifyPayloadForIkeAndNewChild();
- } catch (InvalidSyntaxException e) {
- throw new IllegalArgumentException(e);
- }
- }
-
- /**
- * Construct IkeNotifyPayload concerning either an IKE SA, or Child SA that is going to be
- * negotiated without additional notification data.
- *
- * @param notifyType the notify type concerning IKE SA
- */
- public IkeNotifyPayload(int notifyType) {
- this(notifyType, new byte[0]);
- }
-
- /**
- * Construct IkeNotifyPayload concerning existing Child SA
- *
- * @param notifyType the notify type concerning Child SA
- * @param notifytData status or error data transmitted. Values for this field are notify type
- * specific.
- */
- public IkeNotifyPayload(
- @ProtocolId int protocolId, int spi, int notifyType, byte[] notifyData) {
- this(protocolId, SPI_LEN_IPSEC, spi, notifyType, notifyData);
- try {
- validateNotifyPayloadForExistingChildSa();
- } catch (InvalidSyntaxException e) {
- throw new IllegalArgumentException(e);
- }
- }
-
- /**
- * Indicates if this is an error notification payload.
- *
- * @return if this is an error notification payload.
- */
- public boolean isErrorNotify() {
- return notifyType <= ERROR_NOTIFY_TYPE_MAX;
- }
-
- /**
- * Indicates if this is an notification for a new Child SA negotiation.
- *
- * <p>This notification may provide additional configuration information for negotiating a new
- * Child SA or is an error notification of the Child SA negotiation failure.
- *
- * @return if this is an notification for a new Child SA negotiation.
- */
- public boolean isNewChildSaNotify() {
- return VALID_NOTIFY_TYPES_FOR_NEW_CHILD_SA.contains(notifyType);
- }
-
- /**
- * Validate error data and build IkeProtocolException for this error notification.
- *
- * @return the IkeProtocolException that represents this error.
- * @throws InvalidSyntaxException if error data has invalid size.
- */
- public IkeProtocolException validateAndBuildIkeException() throws InvalidSyntaxException {
- if (!isErrorNotify()) {
- throw new IllegalArgumentException(
- "Do not support building IkeException for a non-error notificaton. Notify"
- + " type: "
- + notifyType);
- }
-
- try {
- switch (notifyType) {
- case ERROR_TYPE_UNSUPPORTED_CRITICAL_PAYLOAD:
- return new UnsupportedCriticalPayloadException(notifyData);
- case ERROR_TYPE_INVALID_MAJOR_VERSION:
- return new InvalidMajorVersionException(notifyData);
- case ERROR_TYPE_INVALID_SYNTAX:
- return new InvalidSyntaxException(notifyData);
- case ERROR_TYPE_INVALID_MESSAGE_ID:
- return new InvalidMessageIdException(notifyData);
- case ERROR_TYPE_NO_PROPOSAL_CHOSEN:
- return new NoValidProposalChosenException(notifyData);
- case ERROR_TYPE_INVALID_KE_PAYLOAD:
- return new InvalidKeException(notifyData);
- case ERROR_TYPE_AUTHENTICATION_FAILED:
- return new AuthenticationFailedException(notifyData);
- case ERROR_TYPE_TS_UNACCEPTABLE:
- return new TsUnacceptableException(notifyData);
- case ERROR_TYPE_TEMPORARY_FAILURE:
- return new TemporaryFailureException(notifyData);
- default:
- return new UnrecognizedIkeProtocolException(notifyType, notifyData);
- }
- } catch (IllegalArgumentException e) {
- // Notification data length is invalid.
- throw new InvalidSyntaxException(e);
- }
- }
-
- /**
- * Return the payload type as a String.
- *
- * @return the payload type as a String.
- */
- @Override
- public String getTypeString() {
- String notifyTypeString = NOTIFY_TYPE_TO_STRING.get(notifyType);
-
- if (notifyTypeString == null) {
- return "Notify(" + notifyType + ")";
- }
- return "Notify(" + notifyTypeString + ")";
- }
-}
diff --git a/src/java/com/android/internal/net/ipsec/ike/message/IkeSkPayload.java b/src/java/com/android/internal/net/ipsec/ike/message/IkeSkPayload.java
deleted file mode 100644
index 0c2d1fff..00000000
--- a/src/java/com/android/internal/net/ipsec/ike/message/IkeSkPayload.java
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * Copyright (C) 2018 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.message;
-
-import android.annotation.Nullable;
-import android.net.ipsec.ike.exceptions.IkeProtocolException;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.net.ipsec.ike.crypto.IkeCipher;
-import com.android.internal.net.ipsec.ike.crypto.IkeMacIntegrity;
-
-import java.nio.ByteBuffer;
-import java.security.GeneralSecurityException;
-
-/**
- * IkeSkPayload represents the common information of an Encrypted and Authenticated Payload and an
- * Encrypted and Authenticated Fragment Payload.
- *
- * <p>It contains other payloads in encrypted form. It is must be the last payload in the message.
- * It should be the only payload in this implementation.
- *
- * <p>Critical bit must be ignored when doing decoding.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#page-105">RFC 7296, Internet Key Exchange
- * Protocol Version 2 (IKEv2)</a>
- */
-public class IkeSkPayload extends IkePayload {
-
- protected final IkeEncryptedPayloadBody mIkeEncryptedPayloadBody;
-
- /**
- * Construct an instance of IkeSkPayload from decrypting an incoming packet.
- *
- * @param critical indicates if it is a critical payload.
- * @param message the byte array contains the whole IKE message.
- * @param integrityMac the negotiated integrity algorithm.
- * @param decryptCipher the negotiated encryption algorithm.
- * @param integrityKey the negotiated integrity algorithm key.
- * @param decryptionKey the negotiated decryption key.
- */
- @VisibleForTesting
- IkeSkPayload(
- boolean critical,
- byte[] message,
- @Nullable IkeMacIntegrity integrityMac,
- IkeCipher decryptCipher,
- byte[] integrityKey,
- byte[] decryptionKey)
- throws IkeProtocolException, GeneralSecurityException {
-
- this(
- false /*isSkf*/,
- critical,
- IkeHeader.IKE_HEADER_LENGTH + GENERIC_HEADER_LENGTH,
- message,
- integrityMac,
- decryptCipher,
- integrityKey,
- decryptionKey);
- }
-
- /** Construct an instance of IkeSkPayload for testing.*/
- @VisibleForTesting
- IkeSkPayload(boolean isSkf, IkeEncryptedPayloadBody encryptedPayloadBody) {
- super(isSkf ? PAYLOAD_TYPE_SKF : PAYLOAD_TYPE_SK, false/*critical*/);
- mIkeEncryptedPayloadBody = encryptedPayloadBody;
- }
-
- /** Construct an instance of IkeSkPayload from decrypting an incoming packet. */
- protected IkeSkPayload(
- boolean isSkf,
- boolean critical,
- int encryptedBodyOffset,
- byte[] message,
- @Nullable IkeMacIntegrity integrityMac,
- IkeCipher decryptCipher,
- byte[] integrityKey,
- byte[] decryptionKey)
- throws IkeProtocolException, GeneralSecurityException {
- super(isSkf ? PAYLOAD_TYPE_SKF : PAYLOAD_TYPE_SK, critical);
-
- // TODO: Support constructing IkeEncryptedPayloadBody using AEAD.
-
- mIkeEncryptedPayloadBody =
- new IkeEncryptedPayloadBody(
- message,
- encryptedBodyOffset,
- integrityMac,
- decryptCipher,
- integrityKey,
- decryptionKey);
- }
-
- /**
- * Construct an instance of IkeSkPayload for building outbound packet.
- *
- * @param ikeHeader the IKE header.
- * @param firstPayloadType the type of first payload nested in SkPayload.
- * @param unencryptedPayloads the encoded payload list to protect.
- * @param integrityMac the negotiated integrity algorithm.
- * @param encryptCipher the negotiated encryption algorithm.
- * @param integrityKey the negotiated integrity algorithm key.
- * @param encryptionKey the negotiated encryption key.
- */
- @VisibleForTesting
- IkeSkPayload(
- IkeHeader ikeHeader,
- @PayloadType int firstPayloadType,
- byte[] unencryptedPayloads,
- @Nullable IkeMacIntegrity integrityMac,
- IkeCipher encryptCipher,
- byte[] integrityKey,
- byte[] encryptionKey) {
-
- this(
- ikeHeader,
- firstPayloadType,
- new byte[0] /*skfHeaderBytes*/,
- unencryptedPayloads,
- integrityMac,
- encryptCipher,
- integrityKey,
- encryptionKey);
- }
-
- /** Construct an instance of IkeSkPayload for building outbound packet. */
- @VisibleForTesting
- protected IkeSkPayload(
- IkeHeader ikeHeader,
- @PayloadType int firstPayloadType,
- byte[] skfHeaderBytes,
- byte[] unencryptedPayloads,
- @Nullable IkeMacIntegrity integrityMac,
- IkeCipher encryptCipher,
- byte[] integrityKey,
- byte[] encryptionKey) {
- super(skfHeaderBytes.length == 0 ? PAYLOAD_TYPE_SK : PAYLOAD_TYPE_SKF, false);
-
- // TODO: Support constructing IkeEncryptedPayloadBody using AEAD.
-
- mIkeEncryptedPayloadBody =
- new IkeEncryptedPayloadBody(
- ikeHeader,
- firstPayloadType,
- skfHeaderBytes,
- unencryptedPayloads,
- integrityMac,
- encryptCipher,
- integrityKey,
- encryptionKey);
- }
-
- /**
- * Return unencrypted data.
- *
- * @return unencrypted data in a byte array.
- */
- public byte[] getUnencryptedData() {
- return mIkeEncryptedPayloadBody.getUnencryptedData();
- }
-
- /**
- * Encode this payload to a ByteBuffer.
- *
- * @param nextPayload type of payload that follows this payload.
- * @param byteBuffer destination ByteBuffer that stores encoded payload.
- */
- @Override
- protected void encodeToByteBuffer(@PayloadType int nextPayload, ByteBuffer byteBuffer) {
- encodePayloadHeaderToByteBuffer(nextPayload, getPayloadLength(), byteBuffer);
- byteBuffer.put(mIkeEncryptedPayloadBody.encode());
- }
-
- /**
- * Get entire payload length.
- *
- * @return entire payload length.
- */
- @Override
- protected int getPayloadLength() {
- return GENERIC_HEADER_LENGTH + mIkeEncryptedPayloadBody.getLength();
- }
-
- /**
- * Return the payload type as a String.
- *
- * @return the payload type as a String.
- */
- @Override
- public String getTypeString() {
- return "SK";
- }
-}
diff --git a/src/java/com/android/internal/net/ipsec/ike/message/IkeSkfPayload.java b/src/java/com/android/internal/net/ipsec/ike/message/IkeSkfPayload.java
deleted file mode 100644
index 6faea123..00000000
--- a/src/java/com/android/internal/net/ipsec/ike/message/IkeSkfPayload.java
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Copyright (C) 2019 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.message;
-
-import android.annotation.Nullable;
-import android.net.ipsec.ike.exceptions.IkeProtocolException;
-
-import com.android.internal.annotations.VisibleForTesting;
-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.exceptions.InvalidSyntaxException;
-
-import java.nio.ByteBuffer;
-import java.security.GeneralSecurityException;
-
-/**
- * IkeSkfPayload represents an Encrypted and Authenticated Fragment Payload.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7383">RFC 7383, Internet Key Exchange Protocol
- * Version 2 (IKEv2) Message Fragmentation</a>
- */
-public final class IkeSkfPayload extends IkeSkPayload {
- public static final int SKF_HEADER_LEN = 4;
-
- /** Current Fragment message number, starting from 1 */
- public final int fragmentNum;
- /** Number of Fragment messages into which the original message was divided */
- public final int totalFragments;
-
- /**
- * Construct an instance of IkeSkfPayload by authenticating and decrypting an incoming packet.
- *
- * <p>SKF Payload with invalid fragmentNum or invalid totalFragments, or cannot be authenticated
- * or decrypted MUST be discarded
- *
- * @param critical indicates if it is a critical payload.
- * @param message the byte array contains the whole IKE message.
- * @param integrityMac the negotiated integrity algorithm.
- * @param decryptCipher the negotiated encryption algorithm.
- * @param integrityKey the negotiated integrity algorithm key.
- * @param decryptionKey the negotiated decryption key.
- */
- IkeSkfPayload(
- boolean critical,
- byte[] message,
- @Nullable IkeMacIntegrity integrityMac,
- IkeCipher decryptCipher,
- byte[] integrityKey,
- byte[] decryptionKey)
- throws IkeProtocolException, GeneralSecurityException {
- super(
- true /*isSkf*/,
- critical,
- IkeHeader.IKE_HEADER_LENGTH + GENERIC_HEADER_LENGTH + SKF_HEADER_LEN,
- message,
- integrityMac,
- decryptCipher,
- integrityKey,
- decryptionKey);
-
- // TODO: Support constructing IkeEncryptedPayloadBody using AEAD.
-
- ByteBuffer inputBuffer = ByteBuffer.wrap(message);
- inputBuffer.get(new byte[IkeHeader.IKE_HEADER_LENGTH + GENERIC_HEADER_LENGTH]);
-
- fragmentNum = Short.toUnsignedInt(inputBuffer.getShort());
- totalFragments = Short.toUnsignedInt(inputBuffer.getShort());
-
- if (fragmentNum < 1 || totalFragments < 1 || fragmentNum > totalFragments) {
- throw new InvalidSyntaxException(
- "Received invalid Fragment Number or Total Fragments Number. Fragment Number: "
- + fragmentNum
- + " Total Fragments: "
- + totalFragments);
- }
- }
-
- /**
- * Construct an instance of IkeSkfPayload for building outbound packet.
- *
- * @param ikeHeader the IKE header.
- * @param firstPayloadType the type of first payload nested in SkPayload.
- * @param unencryptedPayloads the encoded payload list to protect.
- * @param integrityMac the negotiated integrity algorithm.
- * @param encryptCipher the negotiated encryption algorithm.
- * @param integrityKey the negotiated integrity algorithm key.
- * @param encryptionKey the negotiated encryption key.
- */
- IkeSkfPayload(
- IkeHeader ikeHeader,
- @PayloadType int firstPayloadType,
- byte[] unencryptedPayloads,
- @Nullable IkeMacIntegrity integrityMac,
- IkeCipher encryptCipher,
- byte[] integrityKey,
- byte[] encryptionKey,
- int fragNum,
- int totalFrags) {
- super(
- ikeHeader,
- firstPayloadType,
- encodeSkfHeader(fragNum, totalFrags),
- unencryptedPayloads,
- integrityMac,
- encryptCipher,
- integrityKey,
- encryptionKey);
- fragmentNum = fragNum;
- totalFragments = totalFrags;
- }
-
- /** Construct an instance of IkeSkfPayload for testing. */
- @VisibleForTesting
- IkeSkfPayload(IkeEncryptedPayloadBody encryptedPayloadBody, int fragNum, int totalFrags) {
- super(true /*isSkf*/, encryptedPayloadBody);
- fragmentNum = fragNum;
- totalFragments = totalFrags;
- }
-
- @VisibleForTesting
- static byte[] encodeSkfHeader(int fragNum, int totalFrags) {
- ByteBuffer buffer = ByteBuffer.allocate(SKF_HEADER_LEN);
- buffer.putShort((short) fragNum).putShort((short) totalFrags);
- return buffer.array();
- }
-
- /**
- * Encode this payload to a ByteBuffer.
- *
- * @param nextPayload type of payload that follows this payload.
- * @param byteBuffer destination ByteBuffer that stores encoded payload.
- */
- @Override
- protected void encodeToByteBuffer(@PayloadType int nextPayload, ByteBuffer byteBuffer) {
- encodePayloadHeaderToByteBuffer(nextPayload, getPayloadLength(), byteBuffer);
- byteBuffer
- .putShort((short) fragmentNum)
- .putShort((short) totalFragments)
- .put(mIkeEncryptedPayloadBody.encode());
- }
-
- /**
- * Get entire payload length.
- *
- * @return entire payload length.
- */
- @Override
- protected int getPayloadLength() {
- return GENERIC_HEADER_LENGTH + SKF_HEADER_LEN + mIkeEncryptedPayloadBody.getLength();
- }
-
- /**
- * Return the payload type as a String.
- *
- * @return the payload type as a String.
- */
- @Override
- public String getTypeString() {
- return "SKF";
- }
-}
diff --git a/src/java/com/android/internal/net/ipsec/ike/message/IkeTsPayload.java b/src/java/com/android/internal/net/ipsec/ike/message/IkeTsPayload.java
deleted file mode 100644
index 207bdc36..00000000
--- a/src/java/com/android/internal/net/ipsec/ike/message/IkeTsPayload.java
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Copyright (C) 2019 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.message;
-
-import android.net.ipsec.ike.IkeTrafficSelector;
-import android.net.ipsec.ike.exceptions.IkeProtocolException;
-
-import com.android.internal.net.ipsec.ike.exceptions.InvalidSyntaxException;
-
-import java.nio.ByteBuffer;
-
-/**
- * IkeTsPayload represents an Traffic Selector Initiator Payload or an Traffic Selector Responder
- * Payload.
- *
- * <p>Traffic Selector Initiator Payload and Traffic Selector Responder Payload have same format but
- * different payload types. They describe the address ranges and port ranges of Child SA initiator
- * and Child SA responder.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.13">RFC 7296, Internet Key Exchange
- * Protocol Version 2 (IKEv2)</a>
- */
-public final class IkeTsPayload extends IkePayload {
- // Length of Traffic Selector Payload header.
- private static final int TS_HEADER_LEN = 4;
- // Length of reserved field in octets.
- private static final int TS_HEADER_RESERVED_LEN = 3;
-
- /** Number of Traffic Selectors */
- public final int numTs;
- /** Array of Traffic Selectors */
- public final IkeTrafficSelector[] trafficSelectors;
-
- IkeTsPayload(boolean critical, byte[] payloadBody, boolean isInitiator)
- throws IkeProtocolException {
- super((isInitiator ? PAYLOAD_TYPE_TS_INITIATOR : PAYLOAD_TYPE_TS_RESPONDER), critical);
-
- ByteBuffer inputBuffer = ByteBuffer.wrap(payloadBody);
- numTs = Byte.toUnsignedInt(inputBuffer.get());
- if (numTs == 0) {
- throw new InvalidSyntaxException("Cannot find Traffic Selector in TS payload.");
- }
-
- // Skip RESERVED byte
- inputBuffer.get(new byte[TS_HEADER_RESERVED_LEN]);
-
- // Decode Traffic Selectors
- byte[] tsBytes = new byte[inputBuffer.remaining()];
- inputBuffer.get(tsBytes);
- trafficSelectors = IkeTrafficSelector.decodeIkeTrafficSelectors(numTs, tsBytes);
- }
-
- /**
- * Construct an instance of IkeTsPayload for building an outbound IKE message.
- *
- * @param isInitiator indicates if this payload is for a Child SA initiator or responder.
- * @param ikeTrafficSelectors the array of included traffic selectors.
- */
- public IkeTsPayload(boolean isInitiator, IkeTrafficSelector[] ikeTrafficSelectors) {
- super((isInitiator ? PAYLOAD_TYPE_TS_INITIATOR : PAYLOAD_TYPE_TS_RESPONDER), false);
-
- if (ikeTrafficSelectors == null || ikeTrafficSelectors.length == 0) {
- throw new IllegalArgumentException(
- "TS Payload requires at least one Traffic Selector.");
- }
-
- numTs = ikeTrafficSelectors.length;
- trafficSelectors = ikeTrafficSelectors;
- }
-
- /**
- * Check if this TS payload contains the all TS in the provided TS payload.
- *
- * <p>A TS response cannot be narrower than a TS request. When doing rekey, the newly negotiated
- * TS cannot be narrower than old negotiated TS.
- *
- * <p>This method will be used to (1) validate that an inbound response is subset of a locally
- * generated request; and (2) validate that an inbound rekey request/response is superset of
- * current negotiated TS.
- *
- * @param tsPayload the other TS payload to validate
- * @return true if current TS Payload contains all TS in the input tsPayload
- */
- public boolean contains(IkeTsPayload tsPayload) {
- subTsLoop:
- for (IkeTrafficSelector subTs : tsPayload.trafficSelectors) {
- for (IkeTrafficSelector superTs : this.trafficSelectors) {
- if (superTs.contains(subTs)) {
- continue subTsLoop;
- }
- }
- return false;
- }
- return true;
- }
-
- /**
- * Encode Traffic Selector Payload to ByteBuffer.
- *
- * @param nextPayload type of payload that follows this payload.
- * @param byteBuffer destination ByteBuffer that stores encoded payload.
- */
- @Override
- protected void encodeToByteBuffer(@PayloadType int nextPayload, ByteBuffer byteBuffer) {
- encodePayloadHeaderToByteBuffer(nextPayload, getPayloadLength(), byteBuffer);
-
- byteBuffer.put((byte) numTs).put(new byte[TS_HEADER_RESERVED_LEN]);
- for (IkeTrafficSelector ts : trafficSelectors) {
- ts.encodeToByteBuffer(byteBuffer);
- }
- }
-
- /**
- * Get entire payload length.
- *
- * @return entire payload length.
- */
- @Override
- protected int getPayloadLength() {
- int len = GENERIC_HEADER_LENGTH + TS_HEADER_LEN;
- for (IkeTrafficSelector ts : trafficSelectors) {
- len += ts.selectorLength;
- }
-
- return len;
- }
-
- /**
- * Return the payload type as a String.
- *
- * @return the payload type as a String.
- */
- @Override
- public String getTypeString() {
- switch (payloadType) {
- case PAYLOAD_TYPE_TS_INITIATOR:
- return "TSi";
- case PAYLOAD_TYPE_TS_RESPONDER:
- return "TSr";
- default:
- // Won't reach here.
- throw new IllegalArgumentException(
- "Invalid Payload Type for Traffic Selector Payload.");
- }
- }
-}
diff --git a/src/java/com/android/internal/net/ipsec/ike/utils/FdEventsReader.java b/src/java/com/android/internal/net/ipsec/ike/utils/FdEventsReader.java
deleted file mode 100644
index 65f9cedc..00000000
--- a/src/java/com/android/internal/net/ipsec/ike/utils/FdEventsReader.java
+++ /dev/null
@@ -1,270 +0,0 @@
-/*
- * Copyright (C) 2019 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 static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_ERROR;
-import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.net.util.SocketUtils;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.MessageQueue;
-import android.system.ErrnoException;
-import android.system.OsConstants;
-
-import java.io.FileDescriptor;
-import java.io.IOException;
-
-/**
- * This class encapsulates the mechanics of registering a file descriptor
- * with a thread's Looper and handling read events (and errors).
- *
- * Subclasses MUST implement createFd() and SHOULD override handlePacket(). They MAY override
- * onStop() and onStart().
- *
- * Subclasses can expect a call life-cycle like the following:
- *
- * [1] when a client calls start(), createFd() is called, followed by the onStart() hook if all
- * goes well. Implementations may override onStart() for additional initialization.
- *
- * [2] yield, waiting for read event or error notification:
- *
- * [a] readPacket() && handlePacket()
- *
- * [b] if (no error):
- * goto 2
- * else:
- * goto 3
- *
- * [3] when a client calls stop(), the onStop() hook is called (unless already stopped or never
- * started). Implementations may override onStop() for additional cleanup.
- *
- * The packet receive buffer is recycled on every read call, so subclasses
- * should make any copies they would like inside their handlePacket()
- * implementation.
- *
- * All public methods MUST only be called from the same thread with which
- * the Handler constructor argument is associated.
- *
- * <p> This code is an exact copy of {@link FdEventsReader} in
- * frameworks/base/packages/NetworkStack/src/android/net/util/FdEventsReader.java, except the class
- * name is changed to avoid confusion.
- *
- * FIXME: b/130058477 Find a way to share the code between network stack and code outside.
- *
- * @param <BufferType> the type of the buffer used to read data.
- * @hide
- */
-public abstract class FdEventsReader<BufferType> {
- private static final int FD_EVENTS = EVENT_INPUT | EVENT_ERROR;
- private static final int UNREGISTER_THIS_FD = 0;
-
- @NonNull
- private final Handler mHandler;
- @NonNull
- private final MessageQueue mQueue;
- @NonNull
- private final BufferType mBuffer;
- @Nullable
- private FileDescriptor mFd;
- private long mPacketsReceived;
-
- protected static void closeFd(FileDescriptor fd) {
- try {
- SocketUtils.closeSocket(fd);
- } catch (IOException ignored) {
- }
- }
-
- protected FdEventsReader(@NonNull Handler h, @NonNull BufferType buffer) {
- mHandler = h;
- mQueue = mHandler.getLooper().getQueue();
- mBuffer = buffer;
- }
-
- /** Start this FdEventsReader. */
- public void start() {
- if (onCorrectThread()) {
- createAndRegisterFd();
- } else {
- mHandler.post(() -> {
- logError("start() called from off-thread", null);
- createAndRegisterFd();
- });
- }
- }
-
- /** Stop this FdEventsReader and destroy the file descriptor. */
- public void stop() {
- if (onCorrectThread()) {
- unregisterAndDestroyFd();
- } else {
- mHandler.post(() -> {
- logError("stop() called from off-thread", null);
- unregisterAndDestroyFd();
- });
- }
- }
-
- @NonNull
- public Handler getHandler() {
- return mHandler;
- }
-
- protected abstract int recvBufSize(@NonNull BufferType buffer);
-
- /** Returns the size of the receive buffer. */
- public int recvBufSize() {
- return recvBufSize(mBuffer);
- }
-
- /**
- * Get the number of successful calls to {@link #readPacket(FileDescriptor, Object)}.
- *
- * <p>A call was successful if {@link #readPacket(FileDescriptor, Object)} returned a value > 0.
- */
- public final long numPacketsReceived() {
- return mPacketsReceived;
- }
-
- /**
- * Subclasses MUST create the listening socket here, including setting all desired socket
- * options, interface or address/port binding, etc. The socket MUST be created nonblocking.
- */
- @Nullable
- protected abstract FileDescriptor createFd();
-
- /**
- * Implementations MUST return the bytes read or throw an Exception.
- *
- * <p>The caller may throw a {@link ErrnoException} with {@link OsConstants#EAGAIN} or
- * {@link OsConstants#EINTR}, in which case {@link FdEventsReader} will ignore the buffer
- * contents and respectively wait for further input or retry the read immediately. For all other
- * exceptions, the {@link FdEventsReader} will be stopped with no more interactions with this
- * method.
- */
- protected abstract int readPacket(@NonNull FileDescriptor fd, @NonNull BufferType buffer)
- throws Exception;
-
- /**
- * Called by the main loop for every packet. Any desired copies of
- * |recvbuf| should be made in here, as the underlying byte array is
- * reused across all reads.
- */
- protected void handlePacket(@NonNull BufferType recvbuf, int length) {}
-
- /**
- * Called by the main loop to log errors. In some cases |e| may be null.
- */
- protected void logError(@NonNull String msg, @Nullable Exception e) {}
-
- /**
- * Called by start(), if successful, just prior to returning.
- */
- protected void onStart() {}
-
- /**
- * Called by stop() just prior to returning.
- */
- protected void onStop() {}
-
- private void createAndRegisterFd() {
- if (mFd != null) return;
-
- try {
- mFd = createFd();
- } catch (Exception e) {
- logError("Failed to create socket: ", e);
- closeFd(mFd);
- mFd = null;
- }
-
- if (mFd == null) return;
-
- mQueue.addOnFileDescriptorEventListener(
- mFd,
- FD_EVENTS,
- (fd, events) -> {
- // Always call handleInput() so read/recvfrom are given
- // a proper chance to encounter a meaningful errno and
- // perhaps log a useful error message.
- if (!isRunning() || !handleInput()) {
- unregisterAndDestroyFd();
- return UNREGISTER_THIS_FD;
- }
- return FD_EVENTS;
- });
- onStart();
- }
-
- private boolean isRunning() {
- return (mFd != null) && mFd.valid();
- }
-
- // Keep trying to read until we get EAGAIN/EWOULDBLOCK or some fatal error.
- private boolean handleInput() {
- while (isRunning()) {
- final int bytesRead;
-
- try {
- bytesRead = readPacket(mFd, mBuffer);
- if (bytesRead < 1) {
- if (isRunning()) logError("Socket closed, exiting", null);
- break;
- }
- mPacketsReceived++;
- } catch (ErrnoException e) {
- if (e.errno == OsConstants.EAGAIN) {
- // We've read everything there is to read this time around.
- return true;
- } else if (e.errno == OsConstants.EINTR) {
- continue;
- } else {
- if (isRunning()) logError("readPacket error: ", e);
- break;
- }
- } catch (Exception e) {
- if (isRunning()) logError("readPacket error: ", e);
- break;
- }
-
- try {
- handlePacket(mBuffer, bytesRead);
- } catch (Exception e) {
- logError("handlePacket error: ", e);
- break;
- }
- }
-
- return false;
- }
-
- private void unregisterAndDestroyFd() {
- if (mFd == null) return;
-
- mQueue.removeOnFileDescriptorEventListener(mFd);
- closeFd(mFd);
- mFd = null;
- onStop();
- }
-
- private boolean onCorrectThread() {
- return (mHandler.getLooper() == Looper.myLooper());
- }
-}
diff --git a/src/java/com/android/internal/net/ipsec/ike/utils/PacketReader.java b/src/java/com/android/internal/net/ipsec/ike/utils/PacketReader.java
deleted file mode 100644
index cd6b98d2..00000000
--- a/src/java/com/android/internal/net/ipsec/ike/utils/PacketReader.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2019 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 static java.lang.Math.max;
-
-import android.os.Handler;
-import android.system.Os;
-
-import java.io.FileDescriptor;
-
-/**
- * Specialization of {@link FdEventsReader} that reads packets into a byte array.
- *
- * TODO: rename this class to something more correctly descriptive (something
- * like [or less horrible than] IkeFdReadEventsHandler?).
- *
- * <p> This code is a exact copy of {@link PacketReader} in
- * frameworks/base/packages/NetworkStack/src/android/net/util/PacketReader.java, except the class
- * name is changed to avoid confusion.
- *
- * FIXME: b/130058477 Find a way to share the code between network stack and code outside.
- *
- * @hide
- */
-public abstract class PacketReader extends FdEventsReader<byte[]> {
-
- public static final int DEFAULT_RECV_BUF_SIZE = 2 * 1024;
-
- protected PacketReader(Handler h) {
- this(h, DEFAULT_RECV_BUF_SIZE);
- }
-
- protected PacketReader(Handler h, int recvBufSize) {
- super(h, new byte[max(recvBufSize, DEFAULT_RECV_BUF_SIZE)]);
- }
-
- @Override
- protected final int recvBufSize(byte[] buffer) {
- return buffer.length;
- }
-
- /**
- * Subclasses MAY override this to change the default read() implementation
- * in favour of, say, recvfrom().
- *
- * Implementations MUST return the bytes read or throw an Exception.
- */
- @Override
- protected int readPacket(FileDescriptor fd, byte[] packetBuffer) throws Exception {
- return Os.read(fd, packetBuffer, 0, packetBuffer.length);
- }
-}
diff --git a/src/java/com/android/internal/net/ipsec/ike/utils/Retransmitter.java b/src/java/com/android/internal/net/ipsec/ike/utils/Retransmitter.java
deleted file mode 100644
index 778d6859..00000000
--- a/src/java/com/android/internal/net/ipsec/ike/utils/Retransmitter.java
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright (C) 2019 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 static com.android.internal.net.ipsec.ike.IkeSessionStateMachine.CMD_RETRANSMIT;
-
-import android.os.Handler;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.net.ipsec.ike.message.IkeMessage;
-
-/**
- * Retransmitter represents a class that will send a message and trigger delayed retransmissions
- *
- * <p>The Retransmitter class will queue retransmission signals on the provided handler. The owner
- * of this retransmitter instance is expected to wait for the signal, and call retransmit() on the
- * instance of this class.
- */
-public abstract class Retransmitter {
- private static IBackoffTimeoutCalculator sBackoffTimeoutCalculator =
- new BackoffTimeoutCalculator();
-
- /*
- * Retransmit parameters
- *
- * (Re)transmission count | Relative timeout | Absolute timeout
- * -------------------------+-------------------+------------------
- * 0 | 500ms | 500ms
- * 1 | 1s | 1.5s
- * 2 | 2s | 3.5s
- * 3 | 4s | 7.5s
- * 4 | 8s | 15.5s
- * 5 | 16s | 31.5s
- *
- * TODO: Add retransmitter configurability
- */
- static final double RETRANSMIT_BACKOFF_FACTOR = 2.0;
- static final long RETRANSMIT_TIMEOUT_MS = 500L;
- static final int RETRANSMIT_MAX_ATTEMPTS = 5;
-
- private final Handler mHandler;
- private final IkeMessage mRetransmitMsg;
- private int mRetransmitCount = 0;
-
- public Retransmitter(Handler handler, IkeMessage msg) {
- mHandler = handler;
- mRetransmitMsg = msg;
- }
-
- /**
- * Triggers a (re)transmission. Will enqueue a future retransmission signal on the given handler
- */
- public void retransmit() {
- if (mRetransmitMsg == null) {
- return;
- }
-
- // If the failed iteration is beyond the max attempts, clean up and shut down.
- if (mRetransmitCount > RETRANSMIT_MAX_ATTEMPTS) {
- handleRetransmissionFailure();
- return;
- }
-
- send(mRetransmitMsg);
-
- long timeout = sBackoffTimeoutCalculator.getExponentialBackoffTimeout(mRetransmitCount++);
- mHandler.sendMessageDelayed(mHandler.obtainMessage(CMD_RETRANSMIT, this), timeout);
- }
-
- /** Cancels any future retransmissions */
- public void stopRetransmitting() {
- mHandler.removeMessages(CMD_RETRANSMIT, this);
- }
-
- /** Retrieves the message this retransmitter is tracking */
- public IkeMessage getMessage() {
- return mRetransmitMsg;
- }
-
- /**
- * Implementation-provided sender
- *
- * <p>For Retransmitter-internal use only.
- *
- * @param msg the message to be sent
- */
- protected abstract void send(IkeMessage msg);
-
- /**
- * Callback for implementations to be informed that we have reached the max retransmissions.
- *
- * <p>For Retransmitter-internal use only.
- */
- protected abstract void handleRetransmissionFailure();
-
- /**
- * IBackoffTimeoutCalculator provides interface for calculating retransmission backoff timeout.
- *
- * <p>IBackoffTimeoutCalculator exists so that the interface is injectable for testing.
- */
- @VisibleForTesting
- public interface IBackoffTimeoutCalculator {
- /** Calculate retransmission backoff timeout */
- long getExponentialBackoffTimeout(int retransmitCount);
- }
-
- private static final class BackoffTimeoutCalculator implements IBackoffTimeoutCalculator {
- @Override
- public long getExponentialBackoffTimeout(int retransmitCount) {
- double expBackoffFactor = Math.pow(RETRANSMIT_BACKOFF_FACTOR, retransmitCount);
- return (long) (RETRANSMIT_TIMEOUT_MS * expBackoffFactor);
- }
- }
-
- /** Sets IBackoffTimeoutCalculator */
- @VisibleForTesting
- public static void setBackoffTimeoutCalculator(IBackoffTimeoutCalculator calculator) {
- sBackoffTimeoutCalculator = calculator;
- }
-
- /** Resets BackoffTimeoutCalculator of retransmitter */
- @VisibleForTesting
- public static void resetBackoffTimeoutCalculator() {
- sBackoffTimeoutCalculator = new BackoffTimeoutCalculator();
- }
-}
diff --git a/src/java/com/android/internal/net/utils/Log.java b/src/java/com/android/internal/net/utils/Log.java
deleted file mode 100644
index 55ea0910..00000000
--- a/src/java/com/android/internal/net/utils/Log.java
+++ /dev/null
@@ -1,284 +0,0 @@
-/*
- * Copyright (C) 2019 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.utils;
-
-import android.os.Build;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.util.Locale;
-import java.util.Objects;
-
-/**
- * Manages logging for all IKE packages. Wraps Android's Log class to prevent leakage of PII.
- */
-public class Log {
- private final String mTAG;
- private final boolean mIsEngBuild;
- private final boolean mLogSensitive;
-
- /**
- * Constructs a Log instance configured with the given tag and logSensitive flag
- *
- * @param tag the String tag to be used for this Log's logging
- * @param logSensitive boolean flag marking whether sensitive data (PII) should be logged
- */
- public Log(String tag, boolean logSensitive) {
- this(tag, Build.IS_ENG, logSensitive);
- }
-
- @VisibleForTesting
- Log(String tag, boolean isEngBuild, boolean logSensitive) {
- this.mTAG = tag;
- this.mIsEngBuild = isEngBuild;
- this.mLogSensitive = logSensitive;
- }
-
- /**
- * Logs the given prefix and msg Strings.
- *
- * <p>Note: Logging is only done if this instance's logging level is {@link
- * android.util.Log#VERBOSE} or higher.
- *
- * @param prefix the String prefix to be used for this log entry
- * @param msg the String msg to be logged
- */
- public void v(String prefix, String msg) {
- if (isLoggable(android.util.Log.VERBOSE)) {
- android.util.Log.v(mTAG, prefix + ": " + msg);
- }
- }
-
- /**
- * Logs the given prefix and msg Strings.
- *
- * <p>Note: Logging is only done if this instance's logging level is {@link
- * android.util.Log#VERBOSE} or higher.
- *
- * @param prefix the String prefix to be used for this log entry
- * @param msg the String msg to be logged
- * @param tr an Exception to log
- */
- public void v(String prefix, String msg, Throwable tr) {
- if (isLoggable(android.util.Log.VERBOSE)) {
- android.util.Log.v(mTAG, prefix + ": " + msg, tr);
- }
- }
-
- /**
- * Logs the given prefix and msg Strings.
- *
- * <p>Note: Logging is only done if this instance's logging level is {@link
- * android.util.Log#DEBUG} or higher.
- *
- * @param prefix the String prefix to be used for this log entry
- * @param msg the String msg to be logged
- */
- public void d(String prefix, String msg) {
- if (isLoggable(android.util.Log.DEBUG)) {
- android.util.Log.d(mTAG, prefix + ": " + msg);
- }
- }
-
- /**
- * Logs the given prefix and msg Strings.
- *
- * <p>Note: Logging is only done if this instance's logging level is {@link
- * android.util.Log#DEBUG} or higher.
- *
- * @param prefix the String prefix to be used for this log entry
- * @param msg the String msg to be logged
- * @param tr an Exception to log
- */
- public void d(String prefix, String msg, Throwable tr) {
- if (isLoggable(android.util.Log.DEBUG)) {
- android.util.Log.d(mTAG, prefix + ": " + msg, tr);
- }
- }
-
- /**
- * Logs the given prefix and msg Strings.
- *
- * <p>Note: Logging is only done if this instance's logging level is {@link
- * android.util.Log#INFO} or higher.
- *
- * @param prefix the String prefix to be used for this log entry
- * @param msg the String msg to be logged
- */
- public void i(String prefix, String msg) {
- if (isLoggable(android.util.Log.INFO)) {
- android.util.Log.i(mTAG, prefix + ": " + msg);
- }
- }
-
- /**
- * Logs the given prefix and msg Strings.
- *
- * <p>Note: Logging is only done if this instance's logging level is {@link
- * android.util.Log#INFO} or higher.
- *
- * @param prefix the String prefix to be used for this log entry
- * @param msg the String msg to be logged
- * @param tr an Exception to log
- */
- public void i(String prefix, String msg, Throwable tr) {
- if (isLoggable(android.util.Log.INFO)) {
- android.util.Log.i(mTAG, prefix + ": " + msg, tr);
- }
- }
-
- /**
- * Logs the given prefix and msg Strings.
- *
- * <p>Note: Logging is only done if this instance's logging level is {@link
- * android.util.Log#WARN} or higher.
- *
- * @param prefix the String prefix to be used for this log entry
- * @param msg the String msg to be logged
- */
- public void w(String prefix, String msg) {
- if (isLoggable(android.util.Log.WARN)) {
- android.util.Log.w(mTAG, prefix + ": " + msg);
- }
- }
-
- /**
- * Logs the given prefix and msg Strings.
- *
- * <p>Note: Logging is only done if this instance's logging level is {@link
- * android.util.Log#WARN} or higher.
- *
- * @param prefix the String prefix to be used for this log entry
- * @param msg the String msg to be logged
- * @param tr an Exception to log
- */
- public void w(String prefix, String msg, Throwable tr) {
- if (isLoggable(android.util.Log.WARN)) {
- android.util.Log.w(mTAG, prefix + ": " + msg, tr);
- }
- }
-
- /**
- * Logs the given prefix and msg Strings.
- *
- * <p>Note: Logging is only done if this instance's logging level is {@link
- * android.util.Log#ERROR} or higher.
- *
- * @param prefix the String prefix to be used for this log entry
- * @param msg the String msg to be logged
- */
- public void e(String prefix, String msg) {
- if (isLoggable(android.util.Log.ERROR)) {
- android.util.Log.e(mTAG, prefix + ": " + msg);
- }
- }
-
- /**
- * Logs the given prefix and msg Strings.
- *
- * <p>Note: Logging is only done if this instance's logging level is {@link
- * android.util.Log#ERROR} or higher.
- *
- * @param prefix the String prefix to be used for this log entry
- * @param msg the String msg to be logged
- * @param tr an Exception to log
- */
- public void e(String prefix, String msg, Throwable tr) {
- if (isLoggable(android.util.Log.ERROR)) {
- android.util.Log.e(mTAG, prefix + ": " + msg, tr);
- }
- }
-
- /**
- * What a Terrible Failure: Report a condition that should never happen.
- * The error will always be logged at level ASSERT with the call stack.
- * Depending on system configuration, a report may be added to the
- * {@link android.os.DropBoxManager} and/or the process may be terminated
- * immediately with an error dialog.
- *
- * @param prefix the String prefix to be used for this log entry
- * @param msg the String msg to be logged
- */
- public void wtf(String prefix, String msg) {
- android.util.Log.wtf(mTAG, prefix + ": " + msg);
-
- }
-
- /**
- * What a Terrible Failure: Report a condition that should never happen.
- * The error will always be logged at level ASSERT with the call stack.
- * Depending on system configuration, a report may be added to the
- * {@link android.os.DropBoxManager} and/or the process may be terminated
- * immediately with an error dialog.
- *
- * @param prefix the String prefix to be used for this log entry
- * @param msg the String msg to be logged
- * @param tr an Exception to log
- */
- public void wtf(String prefix, String msg, Throwable tr) {
- android.util.Log.wtf(mTAG, prefix + ": " + msg, tr);
- }
-
- /**
- * Returns a String-formatted version of the given PII.
- *
- * <p>Depending on the logging configurations and build-type, the returned PII may be
- * obfuscated.
- *
- * @param pii the PII to be formatted
- * @return the String-formatted version of the PII
- */
- public String pii(Object pii) {
- if (!mIsEngBuild || !mLogSensitive) {
- return String.valueOf(Objects.hashCode(pii));
- } else {
- if (pii instanceof byte[]) {
- return byteArrayToHexString((byte[]) pii);
- }
- return String.valueOf(pii);
- }
- }
-
- /**
- * Checks whether the given logging level (defined in {@link android.util.Log}) is loggable for
- * this Log.
- *
- * @param level the logging level to be checked for being loggable
- * @return true iff level is at the configured logging level or higher
- */
- private boolean isLoggable(int level) {
- return android.util.Log.isLoggable(mTAG, level);
- }
-
- /**
- * Returns the hex-String representation of the given byte[].
- *
- * @param data the byte[] to be represented
- * @return the String representation of data
- */
- public static String byteArrayToHexString(byte[] data) {
- if (data == null || data.length == 0) {
- return "";
- }
-
- StringBuilder sb = new StringBuilder();
- for (byte b : data) {
- sb.append(String.format(Locale.US, "%02X", b));
- }
- return sb.toString();
- }
-}
diff --git a/src/java/com/android/internal/net/utils/SimpleStateMachine.java b/src/java/com/android/internal/net/utils/SimpleStateMachine.java
deleted file mode 100644
index a2fffddf..00000000
--- a/src/java/com/android/internal/net/utils/SimpleStateMachine.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2019 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.utils;
-
-/**
- * SimpleStateMachine provides a minimal, synchronous state machine framework.
- *
- * <p>This state machine is of limited functionality, but sufficient for implementation of simple
- * protocols. Due to the limited functionality, it is also easy to read and maintain.
- *
- * SimpleStateMachine defaults to the null state. Implementers should immediately transition
- * to their default state when instantiated.
- *
- * @param <T> The input message type.
- * @param <R> The result type. For SimpleStateMachines without a return value, use {@link
- * java.lang.Void}
- */
-public abstract class SimpleStateMachine<T, R> {
- protected final SimpleState mNullState =
- new SimpleState() {
- public R process(T msg) {
- throw new IllegalStateException("Process called on null state");
- }
- };
-
- protected SimpleState mState = mNullState;
-
- // Non-static to allow for compiler verification of T, R from SimpleStateMachine
- protected abstract class SimpleState {
- public abstract R process(T msg);
- }
-
- /**
- * Processes the given message based on the current {@link SimpleState}
- *
- * @param msg The message to be processed by the current state
- * @return The result of the processing by the current state
- */
- public R process(T msg) {
- return mState.process(msg);
- }
-
- /**
- * Transitions to a new state
- *
- * @param newState The {@link SimpleState} that the {@link SimpleStateMachine} should
- * transition to
- * @throws IllegalArgumentException if newState is null
- */
- protected void transitionTo(SimpleState newState) {
- if (newState == null) {
- throw new IllegalArgumentException("SimpleState value must be non-null.");
- }
-
- mState = newState;
- }
-
- /**
- * Transitions to a new state, and lets the new state process the given message
- *
- * @param newState The {@link SimpleState} that the {@link SimpleStateMachine} should transition
- * to. This state will immediately be requested to process the given message.
- * @param msg The message that should be processed by the new state
- * @return The result of the processing by the new state
- * @throws IllegalArgumentException if newState is null
- */
- protected R transitionAndProcess(SimpleState newState, T msg) {
- transitionTo(newState);
- return mState.process(msg);
- }
-}
diff --git a/tests/Android.mk b/tests/Android.mk
new file mode 100644
index 00000000..caa27f66
--- /dev/null
+++ b/tests/Android.mk
@@ -0,0 +1,18 @@
+# Copyright (C) 2018 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.
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+include $(call all-makefiles-under,$(LOCAL_PATH)) \ No newline at end of file
diff --git a/tests/iketests/Android.bp b/tests/iketests/Android.bp
deleted file mode 100644
index c5263536..00000000
--- a/tests/iketests/Android.bp
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright (C) 2018 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.
-
-android_test {
- name: "FrameworksIkeTests",
-
- srcs: ["src/java/**/*.java"],
-
- platform_apis: false,
- certificate: "platform",
- test_suites: ["device-tests"],
-
- libs: ["android.test.runner"],
-
- static_libs: [
- "ike",
- "androidx.test.rules",
- "frameworks-base-testutils",
- "mockito-target-inline-minus-junit4",
- "services.core",
- ],
-
- jni_libs: [
- "libdexmakerjvmtiagent",
- "libstaticjvmtiagent",
- "libmultiplejvmtiagentsinterferenceagent",
- ],
-}
diff --git a/tests/iketests/Android.mk b/tests/iketests/Android.mk
new file mode 100644
index 00000000..0da49b47
--- /dev/null
+++ b/tests/iketests/Android.mk
@@ -0,0 +1,35 @@
+# Copyright (C) 2018 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.
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src/java)
+
+LOCAL_PACKAGE_NAME := FrameworksIkeTests
+LOCAL_PRIVATE_PLATFORM_APIS := false
+LOCAL_CERTIFICATE := platform
+LOCAL_COMPATIBILITY_SUITE := device-tests
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+LOCAL_STATIC_JAVA_LIBRARIES := ike \
+ androidx.test.rules \
+ frameworks-base-testutils \
+ mockito-target-minus-junit4 \
+ NetworkStackBase
+
+include $(BUILD_PACKAGE) \ No newline at end of file
diff --git a/tests/iketests/AndroidManifest.xml b/tests/iketests/AndroidManifest.xml
index 7260e621..d69cbc8f 100644
--- a/tests/iketests/AndroidManifest.xml
+++ b/tests/iketests/AndroidManifest.xml
@@ -20,14 +20,7 @@
<uses-permission android:name="android.permission.INTERNET"/>
- <!--
- 'debuggable=true' is required to properly load mockito jvmti dependencies,
- otherwise it gives the following error at runtime:
-
- Openjdkjvmti plugin was loaded on a non-debuggable Runtime.
- Plugin was loaded too late to change runtime state to DEBUGGABLE.
- -->
- <application android:label="FrameworksIkeTests" android:debuggable="true">
+ <application android:label="FrameworksIkeTests">
<uses-library android:name="android.test.runner" />
</application>
diff --git a/tests/iketests/assets/key/end-cert-key-a.key b/tests/iketests/assets/key/end-cert-key-a.key
deleted file mode 100644
index a506a350..00000000
--- a/tests/iketests/assets/key/end-cert-key-a.key
+++ /dev/null
@@ -1,10 +0,0 @@
------BEGIN PRIVATE KEY-----
-MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAphl0fstit/XcelkX
-2iKoosGsZ2U5rU+mYWR/9RJIY+qR3OYrBeqqtdvjPOu2fNjHEtsO//dCRvdxVWdx
-20ADPQIDAQABAkApsawXg/Bk4zeUErc1D4wrRtiDH9rJkXvfaL3iA9PeGIU2j2ci
-WwqbJY6HhGSJiNAKMVHRMRAtoaBeX80DOqH1AiEA0pWj6kItG2zTww09sqc6ymTc
-1aknFaGuXZY+RO0MTF8CIQDJ68uKQ8LV6labUnnmLPUnIYfVPY8XTNpvkwazeTuV
-4wIgDy60u637vI9zEQwCV8AQ0AjHlyvz4m5euOadJLEGgvcCIQCc9BpsySsjmFnl
-tgBm+L8+wYOSL52QYP7SB5kH3M6CPQIgQQIVYRKf44G9agh09utnaiw11FCwRr0M
-EKsdiVmkw+o=
------END PRIVATE KEY----- \ No newline at end of file
diff --git a/tests/iketests/assets/pem/end-cert-a.pem b/tests/iketests/assets/pem/end-cert-a.pem
deleted file mode 100644
index 2e872952..00000000
--- a/tests/iketests/assets/pem/end-cert-a.pem
+++ /dev/null
@@ -1,20 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDRzCCAi+gAwIBAgIIZSciRUaEUakwDQYJKoZIhvcNAQELBQAwPTELMAkGA1UE
-BhMCVVMxEDAOBgNVBAoTB0FuZHJvaWQxHDAaBgNVBAMTE2NhLnRlc3QuYW5kcm9p
-ZC5uZXQwHhcNMTkwNzE2MTcxODMxWhcNMjQwNzE0MTcxODMxWjBBMQswCQYDVQQG
-EwJVUzEQMA4GA1UEChMHQW5kcm9pZDEgMB4GA1UEAxMXc2VydmVyLnRlc3QuYW5k
-cm9pZC5uZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDpU5M+c3Qg
-Sej5NeCboB5T6R0XaODqo/hpZFkjTXt5ku2lvsioLU0xC38K9Cym7kPU0kGMAl1p
-tatMZ2Uxde/sDiLyFwYgx//TniDNnxdDXYYxcZNbfV4ERcuPmTexq9t86MneVkxn
-hJ9dEBJcr2goFaFIebCUlj3DF827/JQhWgV54M9trPOGOyoRy5HvH+IxOOt8PXaL
-vySQZxo4bC6m+qeQQZCgZAwvGagFF9KjVFyKt9ZAVp97wQi7yo+Bzm5I54C4EUbT
-XnTRITQXqFKOUXVGYPChwgZTEz/2s6Wh1CR0LjNFTaDMlsUJkUbGn27iZc90nd5w
-6WAXYQgsmXnTAgMBAAGjRzBFMB8GA1UdIwQYMBaAFGYUzuvZUaVJl8mcxejuFiUN
-GcTfMCIGA1UdEQQbMBmCF3NlcnZlci50ZXN0LmFuZHJvaWQubmV0MA0GCSqGSIb3
-DQEBCwUAA4IBAQByajAzcLrMc2gjDSzTd+5/VTgLhoJfJul3FgsUzZHa9EiRUChV
-O94ZCLWWoZxeB0iejaUqrLz/xCJqeC3wbNP7LejiW2qgUAoJdOvNtDGiVx2P7wid
-iXS4y49+IYP+T1BVWNNrI+zcAycN2uiQlEKR5KQ3cNXVHZoiVOroheHzi8ezSeYM
-j5bhJ2GbpOw9/4PkaBonnQNs9sljkyZ2keYrir1xzf4PI9gieXniJcNuAjYNaAAA
-oaHKXah9NggbAVEXEZjLoKtQQqWFz9wNE8AXsIdoD4gOeBuwNQSyn+FmDJdI/mpA
-enbz3qbTVurltTHySye0+nhlP7XTifyEanXM
------END CERTIFICATE----- \ No newline at end of file
diff --git a/tests/iketests/assets/pem/end-cert-b.pem b/tests/iketests/assets/pem/end-cert-b.pem
deleted file mode 100644
index f25d3524..00000000
--- a/tests/iketests/assets/pem/end-cert-b.pem
+++ /dev/null
@@ -1,20 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDWDCCAkCgAwIBAgIIRs9N2RKvOUYwDQYJKoZIhvcNAQELBQAwQTELMAkGA1UE
-BhMCVVMxEDAOBgNVBAoTB0FuZHJvaWQxIDAeBgNVBAMTF3R3by5jYS50ZXN0LmFu
-ZHJvaWQubmV0MB4XDTE5MDkzMDE4NDg1MVoXDTI0MDkyODE4NDg1MVowQTELMAkG
-A1UEBhMCVVMxEDAOBgNVBAoTB0FuZHJvaWQxIDAeBgNVBAMTF3NlcnZlci50ZXN0
-LmFuZHJvaWQubmV0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxmhy
-posM/dhFPvmHpiqk+bJR2yfw5AeWhspnjuIJB1X3/TFCRTmLLsQ8VGRQnSKYlAYJ
-2r5XpgYQ09r4DYAbHwL2oSYtktMzqax22JlR73czZH4D3UTtKk7CdLtc1NPFXYFm
-lJ9uE/TD1pXvXwj9vdYp8tVuls2Rv+hBNtgM4nT1FqyMpp1sr5t2LIdx+WpDR4PC
-8C7HExeuw4wOBY6mWp4uErWqDFBfQNI3dzwpySRtnuMVKSX5Qcj6Z+bqKmtAgAnZ
-qdoLegn4sBbELDFW1QYNqp9QgdJO9P9R2lI8LZvKcd2yB8zJ2+JK1Efh9ErzhqFn
-Rc1BzbsBxKJBbppZXQIDAQABo1QwUjAfBgNVHSMEGDAWgBRypK7W5FhP8MtsugM1
-TPfyca8IpDAaBgNVHREEEzARgg9pa2UuYW5kcm9pZC5uZXQwEwYDVR0lBAwwCgYI
-KwYBBQUHAwEwDQYJKoZIhvcNAQELBQADggEBADJu4bfbDO/PUSjTMuH1u6x9iTdx
-PKVkzFHqeiAsEKccyenuFKrwkkoIF+gieJeKKDj6lKFDP4uPOYIuNxs9td8G52+1
-5XKX2v9heaw6uFU3AlMmoAHKwIiM+U6eweuG+rVG2doTbMW2OOrEfJ5mgQtky7tx
-EIPUL9gUpAKqvsC7pJ7nrakm6TBkhYaTtDYOvdD97LyH9/5h32WKn9zU2H4dog+4
-87K6icdjBpd4ViPXbOBuOLvEsnMDmbSC3/12hv59swAf865SZN10B7ScYbg/yS9V
-x2YtMxPMNOOqC71Z/JE5mc80Un0nd9eJFxPueWqeH/4cGA6gL7ZtAeor0BE=
------END CERTIFICATE----- \ No newline at end of file
diff --git a/tests/iketests/assets/pem/end-cert-small.pem b/tests/iketests/assets/pem/end-cert-small.pem
deleted file mode 100644
index b21aa0df..00000000
--- a/tests/iketests/assets/pem/end-cert-small.pem
+++ /dev/null
@@ -1,12 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIBtjCCAWCgAwIBAgIIC0mN0a99ZR0wDQYJKoZIhvcNAQELBQAwQzELMAkGA1UE
-BhMCVVMxEDAOBgNVBAoTB0FuZHJvaWQxIjAgBgNVBAMTGXNtYWxsLmNhLnRlc3Qu
-YW5kcm9pZC5uZXQwHhcNMTkwNzE2MjIyMzM0WhcNMjQwNzE0MjIyMzM0WjBHMQsw
-CQYDVQQGEwJVUzEQMA4GA1UEChMHQW5kcm9pZDEmMCQGA1UEAxMdc21hbGwuc2Vy
-dmVyLnRlc3QuYW5kcm9pZC5uZXQwXDANBgkqhkiG9w0BAQEFAANLADBIAkEAphl0
-fstit/XcelkX2iKoosGsZ2U5rU+mYWR/9RJIY+qR3OYrBeqqtdvjPOu2fNjHEtsO
-//dCRvdxVWdx20ADPQIDAQABozQwMjAfBgNVHSMEGDAWgBRuPvsaYu/KSLILNs2l
-qzN0Q3bo8jAPBgNVHREECDAGhwTAqCuKMA0GCSqGSIb3DQEBCwUAA0EA1HWQseq+
-kfL5YaYN7Klb3WiPPg8Vxj4dMNYiQTSH7AG7Gt1Yc6NqBLhmMpa+1T+gwlDdvkD4
-RPIxjfK12sbbog==
------END CERTIFICATE----- \ No newline at end of file
diff --git a/tests/iketests/assets/pem/intermediate-ca-b-one.pem b/tests/iketests/assets/pem/intermediate-ca-b-one.pem
deleted file mode 100644
index 707e575b..00000000
--- a/tests/iketests/assets/pem/intermediate-ca-b-one.pem
+++ /dev/null
@@ -1,21 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDaDCCAlCgAwIBAgIIIbjMyRn2770wDQYJKoZIhvcNAQELBQAwQjELMAkGA1UE
-BhMCVVMxEDAOBgNVBAoTB0FuZHJvaWQxITAfBgNVBAMTGHJvb3QuY2EudGVzdC5h
-bmRyb2lkLm5ldDAeFw0xOTA5MzAxODQzMThaFw0yNDA5MjgxODQzMThaMEExCzAJ
-BgNVBAYTAlVTMRAwDgYDVQQKEwdBbmRyb2lkMSAwHgYDVQQDExdvbmUuY2EudGVz
-dC5hbmRyb2lkLm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKNN
-sRr5Z30rAEw2jrAh/BIekbEy/MvOucAr1w0lxH71p+ybRBx5Bj7G07UGXbL659gm
-meMV6nabY4HjQXNMq22POiJBZj+U+rw34br6waljBttxCmmJac1VvgqNsSspXjRy
-NbiVQdFjyKSX0NOPcEkwANk15mZbOgJBaYYc8jQCY2G/p8eARVBTLJCy8LEwEU6j
-XRv/4eYST79qpBFc7gQQj2FLmh9oppDIvcIVBHwtd1tBoVuehRSud1o8vQRkl/HJ
-Mrwp24nO5YYhmVNSFRtBpmWMSu1KknFUwkOebINUNsKXXHebVa7cP4XIQUL8mRT3
-5X9rFJFSQJE01S3NjNMCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B
-Af8EBAMCAQYwHQYDVR0OBBYEFHK3FIm7g8dxEIwK9zMAO8EWhRYxMB8GA1UdIwQY
-MBaAFEmfqEeF14Nj91ekIpR+sVhCEoAaMA0GCSqGSIb3DQEBCwUAA4IBAQAeMlXT
-TnxZo8oz0204gKZ63RzlgDpJ7SqA3qFG+pV+TiqGfSuVkXuIdOskjxJnA9VxUzrr
-LdMTCn5e0FK6wCYjZ2GT/CD7oD3vSMkzGbLGNcNJhhDHUq8BOLPkPzz/rwQFPBSb
-zr6hsiVXphEt/psGoN7Eu9blPeQaIwMfWnaufAwF664S/3dmCRbNMWSam1qzzz8q
-jr0cDOIMa//ZIAcM16cvoBK6pFGnUmuoJYYRtfpY5MmfCWz0sCJxENIX/lxyhd7N
-FdRALA1ZP3E//Tn2vQoeFjbKaAba527RE26HgHJ9zZDo1nn8J8J/YwYRJdBWM/3S
-LYebNiMtcyB5nIkj
------END CERTIFICATE----- \ No newline at end of file
diff --git a/tests/iketests/assets/pem/intermediate-ca-b-two.pem b/tests/iketests/assets/pem/intermediate-ca-b-two.pem
deleted file mode 100644
index 39808f88..00000000
--- a/tests/iketests/assets/pem/intermediate-ca-b-two.pem
+++ /dev/null
@@ -1,21 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDZzCCAk+gAwIBAgIIKWCREnNCs+wwDQYJKoZIhvcNAQELBQAwQTELMAkGA1UE
-BhMCVVMxEDAOBgNVBAoTB0FuZHJvaWQxIDAeBgNVBAMTF29uZS5jYS50ZXN0LmFu
-ZHJvaWQubmV0MB4XDTE5MDkzMDE4NDQwMloXDTI0MDkyODE4NDQwMlowQTELMAkG
-A1UEBhMCVVMxEDAOBgNVBAoTB0FuZHJvaWQxIDAeBgNVBAMTF3R3by5jYS50ZXN0
-LmFuZHJvaWQubmV0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxLUa
-RqkYl2m7lUmMnkooqO0DNNY1aN9r7mJc3ndYn5gjkpb3yLgOYPDNLcQerV6uWk/u
-qKudNHed2dInGonl3oxwwv7++6oUvvtrSWLDZlRg16GsdIE1Y98DSMQWkSxevYy9
-Nh6FGTdlBFQVMpiMa8qHEkrOyKsy85yCW1sgzlpGTIBwbDAqYtwe3rgbwyHwUtfy
-0EU++DBcR4ll/pDqB0OQtW5E3AOq2GH1iaGeFLKSUQ5KAbdI8y4/b8IkSDffvxcc
-kXig7S54aLrNlL/ZjQ+H4Chgjj2A5wMucd81+Fb60Udej73ICL9PpMPnXQ1+BVYd
-MJ/txjLNmrOJG9yEHQIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB
-/wQEAwIBBjAdBgNVHQ4EFgQUcqSu1uRYT/DLbLoDNUz38nGvCKQwHwYDVR0jBBgw
-FoAUcrcUibuDx3EQjAr3MwA7wRaFFjEwDQYJKoZIhvcNAQELBQADggEBADY461GT
-Rw0dGnD07xaGJcI0i0pV+WnGSrl1s1PAIdMYihJAqYnh10fXbFXLm2WMWVmv/pxs
-FI/xDJno+pd4mCa/sIhm63ar/Nv+lFQmcpIlvSlKnhhV4SLNBeqbVhPBGTCHfrG4
-aIyCwm1KJsnkWbf03crhSskR/2CXIjX6lcAy7K3fE2u1ELpAdH0kMJR7VXkLFLUm
-gqe9YCluR0weMpe2sCaOGzdVzQSmMMCzGP5cxeFR5U6K40kMOpiW11JNmQ06xI/m
-YVkMNwoiV/ITT0/C/g9FxJmkO0mVSLEqxaLS/hNiQNDlroVM0rbxhzviXLI3R3AO
-50VvlOQYGxWed/I=
------END CERTIFICATE----- \ No newline at end of file
diff --git a/tests/iketests/assets/pem/self-signed-ca-a.pem b/tests/iketests/assets/pem/self-signed-ca-a.pem
deleted file mode 100644
index 5135ea70..00000000
--- a/tests/iketests/assets/pem/self-signed-ca-a.pem
+++ /dev/null
@@ -1,20 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDPjCCAiagAwIBAgIICrKLpR7LxlowDQYJKoZIhvcNAQELBQAwPTELMAkGA1UE
-BhMCVVMxEDAOBgNVBAoTB0FuZHJvaWQxHDAaBgNVBAMTE2NhLnRlc3QuYW5kcm9p
-ZC5uZXQwHhcNMTkwNzE2MTcxNTUyWhcNMjkwNzEzMTcxNTUyWjA9MQswCQYDVQQG
-EwJVUzEQMA4GA1UEChMHQW5kcm9pZDEcMBoGA1UEAxMTY2EudGVzdC5hbmRyb2lk
-Lm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANsvTwad2Nie0VOy
-Xb1VtHL0R760Jm4vr14JWMcX4oiE6jUdTNdXQ0CGb65wvulP2aEeukFH0D/cvBMR
-Bv9+haEwo9/grIXg9ALNKp+GfuZYw/dfnUMHFn3g2+SUgP6BoMZc4lkHktjkDKxp
-99Q6h4NP/ip1labkhBeB9+Z6l78LTixKRKspNITWASJed9bjzshYxKHi6dJy3maQ
-1LwYKmK7PEGRpoDoT8yZhFbxsVDUojGnJKH1RLXVOn/psG6dI/+IsbTipAttj5zc
-g2VAD56PZG2Jd+vsup+g4Dy72hyy242x5c/H2LKZn4X0B0B+IXyii/ZVc+DJldQ5
-JqplOL8CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw
-HQYDVR0OBBYEFGYUzuvZUaVJl8mcxejuFiUNGcTfMA0GCSqGSIb3DQEBCwUAA4IB
-AQDQYeqjvHsK2ZqSqxakDp0nu36Plbj48Wvx1ru7GW2faz7i0w/Zkxh06zniILCb
-QJRjDebSTHc5SSbCFrRTvqagaLDhbH42/hQncWqIoJqW+pmznJET4JiBO0sqzm05
-yQWsLI/h9Ir28Y2g5N+XPBU0VVVejQqH4iI0iwQx7y7ABssQ0Xa/K73VPbeGaKd6
-Prt4wjJvTlIL2yE2+0MggJ3F2rNptL5SDpg3g+4/YQ6wVRBFil95kUqplEsCtU4P
-t+8RghiEmsRx/8CywKfZ5Hex87ODhsSDmDApcefbd5gxoWVkqxZUkPcKwYv1ucm8
-u4r44fj4/9W0Zeooav5Yoh1q
------END CERTIFICATE----- \ No newline at end of file
diff --git a/tests/iketests/assets/pem/self-signed-ca-b.pem b/tests/iketests/assets/pem/self-signed-ca-b.pem
deleted file mode 100644
index 972fd553..00000000
--- a/tests/iketests/assets/pem/self-signed-ca-b.pem
+++ /dev/null
@@ -1,20 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDSDCCAjCgAwIBAgIITJQJ6HC1rjwwDQYJKoZIhvcNAQELBQAwQjELMAkGA1UE
-BhMCVVMxEDAOBgNVBAoTB0FuZHJvaWQxITAfBgNVBAMTGHJvb3QuY2EudGVzdC5h
-bmRyb2lkLm5ldDAeFw0xOTA5MzAxNzU1NTJaFw0yOTA5MjcxNzU1NTJaMEIxCzAJ
-BgNVBAYTAlVTMRAwDgYDVQQKEwdBbmRyb2lkMSEwHwYDVQQDExhyb290LmNhLnRl
-c3QuYW5kcm9pZC5uZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCT
-q3hGF+JvLaB1xW7KGKmaxiQ7BxX2Sn7cbp7ggoVYXsFlBUuPPv3+Vg5PfPCPhsJ8
-/7w4HyKo3uc/vHs5HpQ7rSd9blhAkfmJci2ULLq73FB8Mix4CzPwMx29RrN1X9bU
-z4G0vJMczIBGxbZ0uw7n8bKcXBV7AIeax+J8lseEZ3k8iSuBkUJqGIpPFKTqByFZ
-A1Lvt47xkON5SZh6c/Oe+o6291wXaCOJUSAKv6PAWZkq9HeD2fqKA/ck9dBaz1M3
-YvzQ9V/7so3/dECjAfKia388h1I6XSGNUM+d5hpxMXpAFgG42eUXHpJ10OjDvSwd
-7ZSC91/kRQewUomEKBK1AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P
-AQH/BAQDAgEGMB0GA1UdDgQWBBRJn6hHhdeDY/dXpCKUfrFYQhKAGjANBgkqhkiG
-9w0BAQsFAAOCAQEAig/94aGfHBhZuvbbhwAK4rUNpizmR567u0ZJ+QUEKyAlo9lT
-ZWYHSm7qTAZYvPEjzTQIptnAlxCHePXh3Cfwgo+r82lhG2rcdI03iRyvHWjM8gyk
-BXCJTi0Q08JHHpTP6GnAqpz58qEIFkk8P766zNXdhYrGPOydF+p7MFcb1Zv1gum3
-zmRLt0XUAMfjPUv1Bl8kTKFxH5lkMBLR1E0jnoJoTTfgRPrf9CuFSoh48n7YhoBT
-KV75xZY8b8+SuB0v6BvQmkpKZGoxBjuVsShyG7q1+4JTAtwhiP7BlkDvVkaBEi7t
-WIMFp2r2ZDisHgastNaeYFyzHYz9g1FCCrHQ4w==
------END CERTIFICATE----- \ No newline at end of file
diff --git a/tests/iketests/assets/pem/self-signed-ca-small.pem b/tests/iketests/assets/pem/self-signed-ca-small.pem
deleted file mode 100644
index bb587bcc..00000000
--- a/tests/iketests/assets/pem/self-signed-ca-small.pem
+++ /dev/null
@@ -1,12 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIBwDCCAWqgAwIBAgIIWKLr7BJ1wyEwDQYJKoZIhvcNAQELBQAwQzELMAkGA1UE
-BhMCVVMxEDAOBgNVBAoTB0FuZHJvaWQxIjAgBgNVBAMTGXNtYWxsLmNhLnRlc3Qu
-YW5kcm9pZC5uZXQwHhcNMTkwNzE2MjIwNjAzWhcNMjkwNzEzMjIwNjAzWjBDMQsw
-CQYDVQQGEwJVUzEQMA4GA1UEChMHQW5kcm9pZDEiMCAGA1UEAxMZc21hbGwuY2Eu
-dGVzdC5hbmRyb2lkLm5ldDBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQDY/gUvbZjF
-YuslvcYduKyWeUr30dgOcC6UmAy0toNjnowtsjwp1Zqkp6+SB/vkmRatrMIDgyu9
-KXKRfy9TFUY9AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD
-AgEGMB0GA1UdDgQWBBRuPvsaYu/KSLILNs2lqzN0Q3bo8jANBgkqhkiG9w0BAQsF
-AANBAMRtcdhE8Ebew9PGNwZtfsp1KiI0ZGLE6zP9YKZYk5VZxqpr914LzEMKZpXA
-BqlgNWIcp4nRbuIhLNLyvWRdW0A=
------END CERTIFICATE----- \ No newline at end of file
diff --git a/tests/iketests/src/java/android/net/eap/EapSessionConfigTest.java b/tests/iketests/src/java/android/net/eap/EapSessionConfigTest.java
deleted file mode 100644
index eed32e3e..00000000
--- a/tests/iketests/src/java/android/net/eap/EapSessionConfigTest.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright (C) 2019 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 android.net.eap;
-
-import static android.net.eap.EapSessionConfig.DEFAULT_IDENTITY;
-import static android.telephony.TelephonyManager.APPTYPE_USIM;
-
-import static com.android.internal.net.eap.message.EapData.EAP_TYPE_AKA;
-import static com.android.internal.net.eap.message.EapData.EAP_TYPE_AKA_PRIME;
-import static com.android.internal.net.eap.message.EapData.EAP_TYPE_MSCHAP_V2;
-import static com.android.internal.net.eap.message.EapData.EAP_TYPE_SIM;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.net.eap.EapSessionConfig.EapAkaConfig;
-import android.net.eap.EapSessionConfig.EapAkaPrimeConfig;
-import android.net.eap.EapSessionConfig.EapMethodConfig;
-import android.net.eap.EapSessionConfig.EapMsChapV2Config;
-import android.net.eap.EapSessionConfig.EapSimConfig;
-
-import org.junit.Test;
-
-import java.nio.charset.StandardCharsets;
-
-public class EapSessionConfigTest {
- private static final byte[] EAP_IDENTITY =
- "test@android.net".getBytes(StandardCharsets.US_ASCII);
- private static final int SUB_ID = 1;
- private static final String NETWORK_NAME = "android.net";
- private static final boolean ALLOW_MISMATCHED_NETWORK_NAMES = true;
- private static final String USERNAME = "username";
- private static final String PASSWORD = "password";
-
- @Test
- public void testBuildEapSim() {
- EapSessionConfig result = new EapSessionConfig.Builder()
- .setEapIdentity(EAP_IDENTITY)
- .setEapSimConfig(SUB_ID, APPTYPE_USIM)
- .build();
-
- assertArrayEquals(EAP_IDENTITY, result.eapIdentity);
-
- EapMethodConfig eapMethodConfig = result.eapConfigs.get(EAP_TYPE_SIM);
- assertEquals(EAP_TYPE_SIM, eapMethodConfig.methodType);
- EapSimConfig eapSimConfig = (EapSimConfig) eapMethodConfig;
- assertEquals(SUB_ID, eapSimConfig.subId);
- assertEquals(APPTYPE_USIM, eapSimConfig.apptype);
- }
-
- @Test
- public void testBuildEapAka() {
- EapSessionConfig result = new EapSessionConfig.Builder()
- .setEapAkaConfig(SUB_ID, APPTYPE_USIM)
- .build();
-
- assertArrayEquals(DEFAULT_IDENTITY, result.eapIdentity);
- EapMethodConfig eapMethodConfig = result.eapConfigs.get(EAP_TYPE_AKA);
- EapAkaConfig eapAkaConfig = (EapAkaConfig) eapMethodConfig;
- assertEquals(SUB_ID, eapAkaConfig.subId);
- assertEquals(APPTYPE_USIM, eapAkaConfig.apptype);
- }
-
- @Test
- public void testBuildEapAkaPrime() {
- EapSessionConfig result =
- new EapSessionConfig.Builder()
- .setEapAkaPrimeConfig(
- SUB_ID, APPTYPE_USIM, NETWORK_NAME, ALLOW_MISMATCHED_NETWORK_NAMES)
- .build();
-
- assertEquals(DEFAULT_IDENTITY, result.eapIdentity);
- EapMethodConfig eapMethodConfig = result.eapConfigs.get(EAP_TYPE_AKA_PRIME);
- EapAkaPrimeConfig eapAkaPrimeConfig = (EapAkaPrimeConfig) eapMethodConfig;
- assertEquals(SUB_ID, eapAkaPrimeConfig.subId);
- assertEquals(APPTYPE_USIM, eapAkaPrimeConfig.apptype);
- assertEquals(NETWORK_NAME, eapAkaPrimeConfig.networkName);
- assertTrue(eapAkaPrimeConfig.allowMismatchedNetworkNames);
- }
-
- @Test
- public void testBuildEapMsChapV2() {
- EapSessionConfig result =
- new EapSessionConfig.Builder().setEapMsChapV2Config(USERNAME, PASSWORD).build();
-
- EapMsChapV2Config config = (EapMsChapV2Config) result.eapConfigs.get(EAP_TYPE_MSCHAP_V2);
- assertEquals(USERNAME, config.username);
- assertEquals(PASSWORD, config.password);
- }
-
- @Test
- public void testBuildWithoutConfigs() {
- try {
- new EapSessionConfig.Builder().build();
- fail("build() should throw an IllegalStateException if no EAP methods are configured");
- } catch (IllegalStateException expected) {
- }
- }
-}
diff --git a/tests/iketests/src/java/android/net/ipsec/ike/ChildSessionConfigurationTest.java b/tests/iketests/src/java/android/net/ipsec/ike/ChildSessionConfigurationTest.java
deleted file mode 100644
index 08d89942..00000000
--- a/tests/iketests/src/java/android/net/ipsec/ike/ChildSessionConfigurationTest.java
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Copyright (C) 2019 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 android.net.ipsec.ike;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.mock;
-
-import android.net.LinkAddress;
-
-import com.android.internal.net.ipsec.ike.message.IkeConfigPayload;
-import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttribute;
-import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv4Address;
-import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv4Netmask;
-import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv6Address;
-
-import libcore.net.InetAddressUtils;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.util.LinkedList;
-import java.util.List;
-
-public final class ChildSessionConfigurationTest {
- private static final int IP4_PREFIX_LEN = 28;
- private static final Inet4Address IPV4_ADDRESS =
- (Inet4Address) (InetAddressUtils.parseNumericAddress("192.0.2.100"));
- private static final Inet4Address IPV4_NETMASK =
- (Inet4Address) (InetAddressUtils.parseNumericAddress("255.255.255.240"));
- private static final LinkAddress IPV4_LINK_ADDRESS =
- new LinkAddress(IPV4_ADDRESS, IP4_PREFIX_LEN);
-
- private static final int IP6_PREFIX_LEN = 64;
- private static final Inet6Address IPV6_ADDRESS =
- (Inet6Address) (InetAddressUtils.parseNumericAddress("2001:db8::1"));
- private static final LinkAddress IPV6_LINK_ADDRESS =
- new LinkAddress(IPV6_ADDRESS, IP6_PREFIX_LEN);
-
- private List mMockInTsList;
- private List mMockOutTsList;
-
- private ConfigAttributeIpv4Address mIpv4Attr;
- private ConfigAttributeIpv4Netmask mNetmaskAttr;
- private ConfigAttributeIpv6Address mIpv6Attr;
-
- @Before
- public void setUp() throws Exception {
- mMockInTsList = new LinkedList<IkeTrafficSelector>();
- mMockInTsList.add(mock(IkeTrafficSelector.class));
-
- mMockOutTsList = new LinkedList<IkeTrafficSelector>();
- mMockOutTsList.add(mock(IkeTrafficSelector.class));
- mMockOutTsList.add(mock(IkeTrafficSelector.class));
-
- mIpv4Attr = new ConfigAttributeIpv4Address(IPV4_ADDRESS);
- mNetmaskAttr = new ConfigAttributeIpv4Netmask(IPV4_NETMASK.getAddress());
- mIpv6Attr = new ConfigAttributeIpv6Address(IPV6_LINK_ADDRESS);
- }
-
- private void verifySessionConfigCommon(ChildSessionConfiguration sessionConfig) {
- verifyTsList(mMockInTsList, sessionConfig.getInboundTrafficSelectors());
- verifyTsList(mMockOutTsList, sessionConfig.getOutboundTrafficSelectors());
- }
-
- private void verifyTsList(
- List<IkeTrafficSelector> expectedList, List<IkeTrafficSelector> tsList) {
- assertEquals(expectedList.size(), tsList.size());
- for (int i = 0; i < expectedList.size(); i++) {
- assertEquals(expectedList.get(i), tsList.get(i));
- }
- }
-
- @Test
- public void testBuildWithoutConfig() {
- ChildSessionConfiguration sessionConfig =
- new ChildSessionConfiguration(mMockInTsList, mMockOutTsList);
-
- verifySessionConfigCommon(sessionConfig);
- }
-
- @Test
- public void testBuildWithNetmaskAttr() {
- List<ConfigAttribute> attributeList = new LinkedList<>();
- attributeList.add(mIpv4Attr);
- attributeList.add(mNetmaskAttr);
- attributeList.add(mIpv6Attr);
-
- IkeConfigPayload configPayload = new IkeConfigPayload(true /*isReply*/, attributeList);
-
- ChildSessionConfiguration sessionConfig =
- new ChildSessionConfiguration(mMockInTsList, mMockOutTsList, configPayload);
-
- verifySessionConfigCommon(sessionConfig);
-
- List<LinkAddress> expectedInternalAddrList = new LinkedList<>();
- expectedInternalAddrList.add(IPV4_LINK_ADDRESS);
- expectedInternalAddrList.add(IPV6_LINK_ADDRESS);
-
- assertEquals(
- expectedInternalAddrList.size(), sessionConfig.getInternalAddressList().size());
- for (int i = 0; i < expectedInternalAddrList.size(); i++) {
- assertEquals(
- expectedInternalAddrList.get(i), sessionConfig.getInternalAddressList().get(i));
- }
- }
-
- @Test
- public void testBuildWithoutNetmaskAttr() {
- List<ConfigAttribute> attributeList = new LinkedList<>();
- attributeList.add(mIpv4Attr);
- attributeList.add(mIpv6Attr);
-
- IkeConfigPayload configPayload = new IkeConfigPayload(true /*isReply*/, attributeList);
-
- ChildSessionConfiguration sessionConfig =
- new ChildSessionConfiguration(mMockInTsList, mMockOutTsList, configPayload);
-
- verifySessionConfigCommon(sessionConfig);
-
- List<LinkAddress> expectedInternalAddrList = new LinkedList<>();
- expectedInternalAddrList.add(new LinkAddress(IPV4_ADDRESS, 32));
- expectedInternalAddrList.add(IPV6_LINK_ADDRESS);
-
- assertEquals(
- expectedInternalAddrList.size(), sessionConfig.getInternalAddressList().size());
- for (int i = 0; i < expectedInternalAddrList.size(); i++) {
- assertEquals(
- expectedInternalAddrList.get(i), sessionConfig.getInternalAddressList().get(i));
- }
- }
-
- @Test
- public void testBuildWithConfigReq() {
- List<ConfigAttribute> attributeList = new LinkedList<>();
- attributeList.add(mIpv4Attr);
- attributeList.add(mIpv6Attr);
-
- IkeConfigPayload configPayload = new IkeConfigPayload(false /*isReply*/, attributeList);
-
- try {
- new ChildSessionConfiguration(mMockInTsList, mMockOutTsList, configPayload);
- fail("Expected to fail because provided config paylaod is not a reply.");
- } catch (IllegalArgumentException expected) {
-
- }
- }
-}
diff --git a/tests/iketests/src/java/android/net/ipsec/ike/ChildSessionOptionsTest.java b/tests/iketests/src/java/android/net/ipsec/ike/ChildSessionOptionsTest.java
deleted file mode 100644
index 242957d6..00000000
--- a/tests/iketests/src/java/android/net/ipsec/ike/ChildSessionOptionsTest.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2019 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 android.net.ipsec.ike;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.fail;
-
-import org.junit.Test;
-
-public final class ChildSessionOptionsTest {
- private static final int NUM_TS = 1;
-
- @Test
- public void testBuild() throws Exception {
- ChildSaProposal saProposal =
- new ChildSaProposal.Builder()
- .addEncryptionAlgorithm(
- SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12,
- SaProposal.KEY_LEN_AES_128)
- .build();
- ChildSessionOptions sessionOptions =
- new TunnelModeChildSessionOptions.Builder().addSaProposal(saProposal).build();
-
- assertArrayEquals(new SaProposal[] {saProposal}, sessionOptions.getSaProposals());
- assertEquals(NUM_TS, sessionOptions.getLocalTrafficSelectors().length);
- assertEquals(NUM_TS, sessionOptions.getRemoteTrafficSelectors().length);
- assertFalse(sessionOptions.isTransportMode());
- }
-
- @Test
- public void testBuildWithoutSaProposal() throws Exception {
- try {
- new TunnelModeChildSessionOptions.Builder().build();
- fail("Expected to fail due to the absence of SA proposal.");
- } catch (IllegalArgumentException expected) {
- }
- }
-}
diff --git a/tests/iketests/src/java/android/net/ipsec/ike/IkeSessionOptionsTest.java b/tests/iketests/src/java/android/net/ipsec/ike/IkeSessionOptionsTest.java
deleted file mode 100644
index fa077d17..00000000
--- a/tests/iketests/src/java/android/net/ipsec/ike/IkeSessionOptionsTest.java
+++ /dev/null
@@ -1,258 +0,0 @@
-/*
- * Copyright (C) 2019 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 android.net.ipsec.ike;
-
-import static android.net.ipsec.ike.IkeSessionOptions.IkeAuthConfig;
-import static android.net.ipsec.ike.IkeSessionOptions.IkeAuthDigitalSignLocalConfig;
-import static android.net.ipsec.ike.IkeSessionOptions.IkeAuthDigitalSignRemoteConfig;
-import static android.net.ipsec.ike.IkeSessionOptions.IkeAuthEapConfig;
-import static android.net.ipsec.ike.IkeSessionOptions.IkeAuthPskConfig;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.mock;
-
-import android.content.Context;
-import android.net.IpSecManager;
-import android.net.IpSecManager.UdpEncapsulationSocket;
-import android.net.eap.EapSessionConfig;
-
-import androidx.test.InstrumentationRegistry;
-
-import com.android.internal.net.TestUtils;
-
-import libcore.net.InetAddressUtils;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import java.net.Inet4Address;
-import java.security.PrivateKey;
-import java.security.cert.X509Certificate;
-import java.security.interfaces.DSAPrivateKey;
-import java.security.interfaces.RSAPrivateKey;
-
-public final class IkeSessionOptionsTest {
- private static final String PSK_HEX_STRING = "6A756E69706572313233";
- private static final byte[] PSK = TestUtils.hexStringToByteArray(PSK_HEX_STRING);
-
- private static final Inet4Address LOCAL_IPV4_ADDRESS =
- (Inet4Address) (InetAddressUtils.parseNumericAddress("192.0.2.200"));
- private static final Inet4Address REMOTE_IPV4_ADDRESS =
- (Inet4Address) (InetAddressUtils.parseNumericAddress("192.0.2.100"));
-
- private UdpEncapsulationSocket mUdpEncapSocket;
- private IkeSaProposal mIkeSaProposal;
- private IkeIdentification mLocalIdentification;
- private IkeIdentification mRemoteIdentification;
-
- private X509Certificate mMockServerCaCert;
- private X509Certificate mMockClientEndCert;
- private PrivateKey mMockRsaPrivateKey;
-
- @Before
- public void setUp() throws Exception {
- Context context = InstrumentationRegistry.getContext();
- IpSecManager ipSecManager = (IpSecManager) context.getSystemService(Context.IPSEC_SERVICE);
- mUdpEncapSocket = ipSecManager.openUdpEncapsulationSocket();
-
- mIkeSaProposal =
- new IkeSaProposal.Builder()
- .addEncryptionAlgorithm(
- SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8,
- SaProposal.KEY_LEN_AES_128)
- .addPseudorandomFunction(SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC)
- .addDhGroup(SaProposal.DH_GROUP_1024_BIT_MODP)
- .build();
- mLocalIdentification = new IkeIpv4AddrIdentification(LOCAL_IPV4_ADDRESS);
- mRemoteIdentification = new IkeIpv4AddrIdentification(REMOTE_IPV4_ADDRESS);
-
- mMockServerCaCert = mock(X509Certificate.class);
- mMockClientEndCert = mock(X509Certificate.class);
- mMockRsaPrivateKey = mock(RSAPrivateKey.class);
- }
-
- @After
- public void tearDown() throws Exception {
- mUdpEncapSocket.close();
- }
-
- private void verifyIkeSessionOptionsCommon(IkeSessionOptions sessionOptions) {
- assertEquals(REMOTE_IPV4_ADDRESS, sessionOptions.getServerAddress());
- assertEquals(mUdpEncapSocket, sessionOptions.getUdpEncapsulationSocket());
- assertArrayEquals(new SaProposal[] {mIkeSaProposal}, sessionOptions.getSaProposals());
-
- assertEquals(mLocalIdentification, sessionOptions.getLocalIdentification());
- assertEquals(mRemoteIdentification, sessionOptions.getRemoteIdentification());
-
- assertFalse(sessionOptions.isIkeFragmentationSupported());
- }
-
- @Test
- public void testBuildWithPsk() throws Exception {
- IkeSessionOptions sessionOptions =
- new IkeSessionOptions.Builder()
- .setServerAddress(REMOTE_IPV4_ADDRESS)
- .setUdpEncapsulationSocket(mUdpEncapSocket)
- .addSaProposal(mIkeSaProposal)
- .setLocalIdentification(mLocalIdentification)
- .setRemoteIdentification(mRemoteIdentification)
- .setAuthPsk(PSK)
- .build();
-
- verifyIkeSessionOptionsCommon(sessionOptions);
-
- IkeAuthConfig localConfig = sessionOptions.getLocalAuthConfig();
- assertTrue(localConfig instanceof IkeAuthPskConfig);
- assertEquals(IkeSessionOptions.IKE_AUTH_METHOD_PSK, localConfig.mAuthMethod);
- assertArrayEquals(PSK, ((IkeAuthPskConfig) localConfig).mPsk);
-
- IkeAuthConfig remoteConfig = sessionOptions.getRemoteAuthConfig();
- assertTrue(remoteConfig instanceof IkeAuthPskConfig);
- assertEquals(IkeSessionOptions.IKE_AUTH_METHOD_PSK, remoteConfig.mAuthMethod);
- assertArrayEquals(PSK, ((IkeAuthPskConfig) remoteConfig).mPsk);
- }
-
- @Test
- public void testBuildWithEap() throws Exception {
- EapSessionConfig eapConfig = mock(EapSessionConfig.class);
-
- IkeSessionOptions sessionOptions =
- new IkeSessionOptions.Builder()
- .setServerAddress(REMOTE_IPV4_ADDRESS)
- .setUdpEncapsulationSocket(mUdpEncapSocket)
- .addSaProposal(mIkeSaProposal)
- .setLocalIdentification(mLocalIdentification)
- .setRemoteIdentification(mRemoteIdentification)
- .setAuthEap(mMockServerCaCert, eapConfig)
- .build();
-
- verifyIkeSessionOptionsCommon(sessionOptions);
-
- IkeAuthConfig localConfig = sessionOptions.getLocalAuthConfig();
- assertTrue(localConfig instanceof IkeAuthEapConfig);
- assertEquals(IkeSessionOptions.IKE_AUTH_METHOD_EAP, localConfig.mAuthMethod);
- assertEquals(eapConfig, ((IkeAuthEapConfig) localConfig).mEapConfig);
-
- IkeAuthConfig remoteConfig = sessionOptions.getRemoteAuthConfig();
- assertTrue(remoteConfig instanceof IkeAuthDigitalSignRemoteConfig);
- assertEquals(IkeSessionOptions.IKE_AUTH_METHOD_PUB_KEY_SIGNATURE, remoteConfig.mAuthMethod);
- assertEquals(
- mMockServerCaCert,
- ((IkeAuthDigitalSignRemoteConfig) remoteConfig).mTrustAnchor.getTrustedCert());
- }
-
- @Test
- public void testBuildWithDigitalSignatureAuth() throws Exception {
- IkeSessionOptions sessionOptions =
- new IkeSessionOptions.Builder()
- .setServerAddress(REMOTE_IPV4_ADDRESS)
- .setUdpEncapsulationSocket(mUdpEncapSocket)
- .addSaProposal(mIkeSaProposal)
- .setLocalIdentification(mLocalIdentification)
- .setRemoteIdentification(mRemoteIdentification)
- .setAuthDigitalSignature(
- mMockServerCaCert, mMockClientEndCert, mMockRsaPrivateKey)
- .build();
-
- verifyIkeSessionOptionsCommon(sessionOptions);
-
- IkeAuthConfig localConfig = sessionOptions.getLocalAuthConfig();
- assertTrue(localConfig instanceof IkeAuthDigitalSignLocalConfig);
-
- IkeAuthDigitalSignLocalConfig localAuthConfig = (IkeAuthDigitalSignLocalConfig) localConfig;
- assertEquals(
- IkeSessionOptions.IKE_AUTH_METHOD_PUB_KEY_SIGNATURE, localAuthConfig.mAuthMethod);
- assertEquals(mMockClientEndCert, localAuthConfig.mEndCert);
- assertTrue(localAuthConfig.mIntermediateCerts.isEmpty());
- assertEquals(mMockRsaPrivateKey, localAuthConfig.mPrivateKey);
-
- IkeAuthConfig remoteConfig = sessionOptions.getRemoteAuthConfig();
- assertTrue(remoteConfig instanceof IkeAuthDigitalSignRemoteConfig);
- assertEquals(IkeSessionOptions.IKE_AUTH_METHOD_PUB_KEY_SIGNATURE, remoteConfig.mAuthMethod);
- assertEquals(
- mMockServerCaCert,
- ((IkeAuthDigitalSignRemoteConfig) remoteConfig).mTrustAnchor.getTrustedCert());
- }
-
- @Test
- public void testBuildWithDsaDigitalSignatureAuth() throws Exception {
- try {
- IkeSessionOptions sessionOptions =
- new IkeSessionOptions.Builder()
- .setServerAddress(REMOTE_IPV4_ADDRESS)
- .setUdpEncapsulationSocket(mUdpEncapSocket)
- .addSaProposal(mIkeSaProposal)
- .setLocalIdentification(mLocalIdentification)
- .setRemoteIdentification(mRemoteIdentification)
- .setAuthDigitalSignature(
- mMockServerCaCert,
- mMockClientEndCert,
- mock(DSAPrivateKey.class))
- .build();
- fail("Expected to fail because DSA is not supported");
- } catch (IllegalArgumentException expected) {
-
- }
- }
-
- @Test
- public void testBuildWithoutSaProposal() throws Exception {
- try {
- new IkeSessionOptions.Builder()
- .setServerAddress(REMOTE_IPV4_ADDRESS)
- .setUdpEncapsulationSocket(mUdpEncapSocket)
- .build();
- fail("Expected to fail due to absence of SA proposal.");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void testBuildWithoutLocalId() throws Exception {
- try {
- new IkeSessionOptions.Builder()
- .setServerAddress(REMOTE_IPV4_ADDRESS)
- .setUdpEncapsulationSocket(mUdpEncapSocket)
- .addSaProposal(mIkeSaProposal)
- .setRemoteIdentification(mRemoteIdentification)
- .setAuthPsk(PSK)
- .build();
- fail("Expected to fail because local identification is not set.");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void testBuildWithoutSetAuth() throws Exception {
- try {
- new IkeSessionOptions.Builder()
- .setServerAddress(REMOTE_IPV4_ADDRESS)
- .setUdpEncapsulationSocket(mUdpEncapSocket)
- .addSaProposal(mIkeSaProposal)
- .setLocalIdentification(mLocalIdentification)
- .setRemoteIdentification(mRemoteIdentification)
- .build();
- fail("Expected to fail because authentiction method is not set.");
- } catch (IllegalArgumentException expected) {
- }
- }
-}
diff --git a/tests/iketests/src/java/android/net/ipsec/ike/IkeSessionTest.java b/tests/iketests/src/java/android/net/ipsec/ike/IkeSessionTest.java
deleted file mode 100644
index 8bf1281d..00000000
--- a/tests/iketests/src/java/android/net/ipsec/ike/IkeSessionTest.java
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright (C) 2019 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 android.net.ipsec.ike;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
-
-import android.content.Context;
-import android.net.IpSecManager;
-import android.os.Looper;
-import android.os.test.TestLooper;
-import android.util.Log;
-
-import com.android.internal.net.ipsec.ike.IkeSessionStateMachine;
-import com.android.internal.net.ipsec.ike.IkeSessionStateMachineTest;
-import com.android.internal.net.ipsec.ike.testutils.MockIpSecTestUtils;
-
-import libcore.net.InetAddressUtils;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.net.Inet4Address;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.Executor;
-import java.util.concurrent.TimeUnit;
-
-public final class IkeSessionTest {
- private static final int TIMEOUT_MS = 500;
-
- private static final Inet4Address LOCAL_ADDRESS =
- (Inet4Address) (InetAddressUtils.parseNumericAddress("192.0.2.200"));
- private static final Inet4Address REMOTE_ADDRESS =
- (Inet4Address) (InetAddressUtils.parseNumericAddress("127.0.0.1"));
-
- private MockIpSecTestUtils mMockIpSecTestUtils;
- private IpSecManager mIpSecManager;
- private Context mContext;
-
- private IkeSessionOptions mIkeSessionOptions;
- private ChildSessionOptions mMockChildSessionOptions;
- private Executor mUserCbExecutor;
- private IkeSessionCallback mMockIkeSessionCb;
- private ChildSessionCallback mMockChildSessionCb;
-
- @Before
- public void setUp() throws Exception {
- if (Looper.myLooper() == null) Looper.prepare();
-
- mMockIpSecTestUtils = MockIpSecTestUtils.setUpMockIpSec();
- mIpSecManager = mMockIpSecTestUtils.getIpSecManager();
- mContext = mMockIpSecTestUtils.getContext();
-
- mIkeSessionOptions = buildIkeSessionOptions();
- mMockChildSessionOptions = mock(ChildSessionOptions.class);
- mUserCbExecutor = (r) -> r.run(); // Inline executor for testing purposes.
- mMockIkeSessionCb = mock(IkeSessionCallback.class);
- mMockChildSessionCb = mock(ChildSessionCallback.class);
- }
-
- private IkeSessionOptions buildIkeSessionOptions() throws Exception {
- return new IkeSessionOptions.Builder()
- .setServerAddress(REMOTE_ADDRESS)
- .setUdpEncapsulationSocket(mIpSecManager.openUdpEncapsulationSocket())
- .addSaProposal(IkeSessionStateMachineTest.buildSaProposal())
- .setLocalIdentification(new IkeIpv4AddrIdentification((Inet4Address) LOCAL_ADDRESS))
- .setRemoteIdentification(
- new IkeIpv4AddrIdentification((Inet4Address) REMOTE_ADDRESS))
- .setAuthPsk(new byte[0] /* psk, unused */)
- .build();
- }
-
- @Test
- public void testConstructIkeSession() throws Exception {
- IkeSession ikeSession =
- new IkeSession(
- mContext,
- mIkeSessionOptions,
- mMockChildSessionOptions,
- mUserCbExecutor,
- mMockIkeSessionCb,
- mMockChildSessionCb);
- assertNotNull(ikeSession.mIkeSessionStateMachine.getHandler().getLooper());
- }
-
- /**
- * Test that when users construct IkeSessions from different threads, these IkeSessions will
- * still be running on the same IKE worker thread.
- */
- @Test
- public void testConstructFromDifferentThreads() throws Exception {
- final int numSession = 2;
- IkeSession[] sessions = new IkeSession[numSession];
-
- final CountDownLatch cntLatch = new CountDownLatch(2);
-
- for (int i = 0; i < numSession; i++) {
- int index = i;
- new Thread() {
- @Override
- public void run() {
- try {
- sessions[index] =
- new IkeSession(
- mContext,
- mIkeSessionOptions,
- mMockChildSessionOptions,
- mUserCbExecutor,
- mMockIkeSessionCb,
- mMockChildSessionCb);
- cntLatch.countDown();
- } catch (Exception e) {
- Log.e("IkeSessionTest", "error encountered constructing IkeSession. ", e);
- }
- }
- }.start();
- }
-
- assertTrue(cntLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
-
- // Verify that two sessions use the same looper.
- assertEquals(
- sessions[0].mIkeSessionStateMachine.getHandler().getLooper(),
- sessions[1].mIkeSessionStateMachine.getHandler().getLooper());
- }
-
- @Test
- public void testOpensIkeSession() throws Exception {
- TestLooper testLooper = new TestLooper();
- IkeSession ikeSession =
- new IkeSession(
- testLooper.getLooper(),
- mContext,
- mIpSecManager,
- mIkeSessionOptions,
- mMockChildSessionOptions,
- mUserCbExecutor,
- mMockIkeSessionCb,
- mMockChildSessionCb);
- testLooper.dispatchAll();
-
- assertTrue(
- ikeSession.mIkeSessionStateMachine.getCurrentState()
- instanceof IkeSessionStateMachine.CreateIkeLocalIkeInit);
- }
-}
diff --git a/tests/iketests/src/java/android/net/ipsec/ike/TunnelModeChildSessionOptionsTest.java b/tests/iketests/src/java/android/net/ipsec/ike/TunnelModeChildSessionOptionsTest.java
deleted file mode 100644
index b0f81dc2..00000000
--- a/tests/iketests/src/java/android/net/ipsec/ike/TunnelModeChildSessionOptionsTest.java
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * Copyright (C) 2019 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 android.net.ipsec.ike;
-
-import static android.system.OsConstants.AF_INET;
-import static android.system.OsConstants.AF_INET6;
-
-import static com.android.internal.net.ipsec.ike.message.IkeConfigPayload.CONFIG_ATTR_INTERNAL_IP4_ADDRESS;
-import static com.android.internal.net.ipsec.ike.message.IkeConfigPayload.CONFIG_ATTR_INTERNAL_IP4_DHCP;
-import static com.android.internal.net.ipsec.ike.message.IkeConfigPayload.CONFIG_ATTR_INTERNAL_IP4_DNS;
-import static com.android.internal.net.ipsec.ike.message.IkeConfigPayload.CONFIG_ATTR_INTERNAL_IP4_NETMASK;
-import static com.android.internal.net.ipsec.ike.message.IkeConfigPayload.CONFIG_ATTR_INTERNAL_IP4_SUBNET;
-import static com.android.internal.net.ipsec.ike.message.IkeConfigPayload.CONFIG_ATTR_INTERNAL_IP6_ADDRESS;
-import static com.android.internal.net.ipsec.ike.message.IkeConfigPayload.CONFIG_ATTR_INTERNAL_IP6_DNS;
-import static com.android.internal.net.ipsec.ike.message.IkeConfigPayload.CONFIG_ATTR_INTERNAL_IP6_SUBNET;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.fail;
-
-import android.util.SparseArray;
-
-import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttribute;
-
-import libcore.net.InetAddressUtils;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-
-public final class TunnelModeChildSessionOptionsTest {
- private static final int NUM_TS = 1;
-
- private static final int IP4_PREFIX_LEN = 32;
- private static final int IP6_PREFIX_LEN = 64;
-
- private static final int INVALID_ADDR_FAMILY = 5;
-
- private static final Inet4Address IPV4_ADDRESS =
- (Inet4Address) (InetAddressUtils.parseNumericAddress("192.0.2.100"));
- private static final Inet6Address IPV6_ADDRESS =
- (Inet6Address) (InetAddressUtils.parseNumericAddress("2001:db8::1"));
-
- private static final Inet4Address IPV4_DNS_SERVER =
- (Inet4Address) (InetAddressUtils.parseNumericAddress("8.8.8.8"));
- private static final Inet6Address IPV6_DNS_SERVER =
- (Inet6Address) (InetAddressUtils.parseNumericAddress("2001:4860:4860::8888"));
-
- private static final Inet4Address IPV4_DHCP_SERVER =
- (Inet4Address) (InetAddressUtils.parseNumericAddress("192.0.2.200"));
- private ChildSaProposal mSaProposal;
-
- @Before
- public void setup() {
- mSaProposal =
- new ChildSaProposal.Builder()
- .addEncryptionAlgorithm(
- SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12,
- SaProposal.KEY_LEN_AES_128)
- .build();
- }
-
- private void verifyCommon(TunnelModeChildSessionOptions childOptions) {
- assertArrayEquals(new SaProposal[] {mSaProposal}, childOptions.getSaProposals());
- assertEquals(NUM_TS, childOptions.getLocalTrafficSelectors().length);
- assertEquals(NUM_TS, childOptions.getRemoteTrafficSelectors().length);
- assertFalse(childOptions.isTransportMode());
- }
-
- private void verifyAttrTypes(
- SparseArray expectedAttrCntMap, TunnelModeChildSessionOptions childOptions) {
- ConfigAttribute[] configAttributes = childOptions.getConfigurationRequests();
-
- SparseArray<Integer> atrrCntMap = expectedAttrCntMap.clone();
-
- for (int i = 0; i < configAttributes.length; i++) {
- int attType = configAttributes[i].attributeType;
- assertNotNull(atrrCntMap.get(attType));
-
- atrrCntMap.put(attType, atrrCntMap.get(attType) - 1);
- if (atrrCntMap.get(attType) == 0) atrrCntMap.remove(attType);
- }
-
- assertEquals(0, atrrCntMap.size());
- }
-
- @Test
- public void testBuildChildSessionOptionsWithoutConfigReq() {
- TunnelModeChildSessionOptions childOptions =
- new TunnelModeChildSessionOptions.Builder().addSaProposal(mSaProposal).build();
-
- verifyCommon(childOptions);
- assertEquals(0, childOptions.getConfigurationRequests().length);
- }
-
- @Test
- public void testBuildChildSessionOptionsWithAddressReq() {
- TunnelModeChildSessionOptions childOptions =
- new TunnelModeChildSessionOptions.Builder()
- .addSaProposal(mSaProposal)
- .addInternalAddressRequest(AF_INET, 1)
- .addInternalAddressRequest(AF_INET6, 2)
- .addInternalAddressRequest(IPV4_ADDRESS, IP4_PREFIX_LEN)
- .addInternalAddressRequest(IPV6_ADDRESS, IP6_PREFIX_LEN)
- .build();
-
- verifyCommon(childOptions);
-
- SparseArray<Integer> expectedAttrCntMap = new SparseArray<>();
- expectedAttrCntMap.put(CONFIG_ATTR_INTERNAL_IP4_ADDRESS, 2);
- expectedAttrCntMap.put(CONFIG_ATTR_INTERNAL_IP6_ADDRESS, 3);
- expectedAttrCntMap.put(CONFIG_ATTR_INTERNAL_IP4_NETMASK, 1);
-
- verifyAttrTypes(expectedAttrCntMap, childOptions);
- }
-
- @Test
- public void testBuildChildSessionOptionsWithInvalidAddressReq() {
- try {
- new TunnelModeChildSessionOptions.Builder()
- .addSaProposal(mSaProposal)
- .addInternalAddressRequest(IPV4_ADDRESS, 31)
- .build();
- fail("Expected to fail due to invalid IPv4 prefix length.");
- } catch (IllegalArgumentException expected) {
-
- }
- }
-
- @Test
- public void testBuildChildSessionOptionsWithDnsServerReq() {
- TunnelModeChildSessionOptions childOptions =
- new TunnelModeChildSessionOptions.Builder()
- .addSaProposal(mSaProposal)
- .addInternalDnsServerRequest(AF_INET, 1)
- .addInternalDnsServerRequest(AF_INET6, 1)
- .addInternalDnsServerRequest(IPV4_DNS_SERVER)
- .addInternalDnsServerRequest(IPV6_DNS_SERVER)
- .build();
-
- verifyCommon(childOptions);
-
- SparseArray<Integer> expectedAttrCntMap = new SparseArray<>();
- expectedAttrCntMap.put(CONFIG_ATTR_INTERNAL_IP4_DNS, 2);
- expectedAttrCntMap.put(CONFIG_ATTR_INTERNAL_IP6_DNS, 2);
-
- verifyAttrTypes(expectedAttrCntMap, childOptions);
- }
-
- @Test
- public void testBuildChildSessionOptionsWithSubnetReq() {
- TunnelModeChildSessionOptions childOptions =
- new TunnelModeChildSessionOptions.Builder()
- .addSaProposal(mSaProposal)
- .addInternalSubnetRequest(AF_INET, 1)
- .addInternalSubnetRequest(AF_INET6, 1)
- .build();
-
- verifyCommon(childOptions);
-
- SparseArray<Integer> expectedAttrCntMap = new SparseArray<>();
- expectedAttrCntMap.put(CONFIG_ATTR_INTERNAL_IP4_SUBNET, 1);
- expectedAttrCntMap.put(CONFIG_ATTR_INTERNAL_IP6_SUBNET, 1);
-
- verifyAttrTypes(expectedAttrCntMap, childOptions);
- }
-
- @Test
- public void testBuildChildSessionOptionsWithDhcpServerReq() {
- TunnelModeChildSessionOptions childOptions =
- new TunnelModeChildSessionOptions.Builder()
- .addSaProposal(mSaProposal)
- .addInternalDhcpServerRequest(AF_INET, 3)
- .addInternalDhcpServerRequest(IPV4_DHCP_SERVER)
- .build();
-
- verifyCommon(childOptions);
-
- SparseArray<Integer> expectedAttrCntMap = new SparseArray<>();
- expectedAttrCntMap.put(CONFIG_ATTR_INTERNAL_IP4_DHCP, 4);
-
- verifyAttrTypes(expectedAttrCntMap, childOptions);
- }
-
- @Test
- public void testBuildChildSessionOptionsWithDhcp6SeverReq() {
- try {
- new TunnelModeChildSessionOptions.Builder()
- .addSaProposal(mSaProposal)
- .addInternalDhcpServerRequest(AF_INET6, 3)
- .build();
- fail("Expected to fail because DHCP6 is not supported.");
- } catch (IllegalArgumentException expected) {
-
- }
- }
-
- @Test
- public void testBuildChildSessionOptionsWithInvalidDhcpReq() {
- try {
- new TunnelModeChildSessionOptions.Builder()
- .addSaProposal(mSaProposal)
- .addInternalDhcpServerRequest(INVALID_ADDR_FAMILY, 3)
- .build();
- fail("Expected to fail due to invalid address family value");
- } catch (IllegalArgumentException expected) {
-
- }
- }
-}
-
diff --git a/tests/iketests/src/java/android/net/ipsec/ike/exceptions/IkeProtocolExceptionTest.java b/tests/iketests/src/java/android/net/ipsec/ike/exceptions/IkeProtocolExceptionTest.java
deleted file mode 100644
index 8c3b16da..00000000
--- a/tests/iketests/src/java/android/net/ipsec/ike/exceptions/IkeProtocolExceptionTest.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2018 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 android.net.ipsec.ike.exceptions;
-
-import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_NO_PROPOSAL_CHOSEN;
-import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_UNSUPPORTED_CRITICAL_PAYLOAD;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-
-import com.android.internal.net.ipsec.ike.exceptions.NoValidProposalChosenException;
-import com.android.internal.net.ipsec.ike.exceptions.UnsupportedCriticalPayloadException;
-import com.android.internal.net.ipsec.ike.message.IkeNotifyPayload;
-
-import org.junit.Test;
-
-import java.util.LinkedList;
-import java.util.List;
-
-public final class IkeProtocolExceptionTest {
- @Test
- public void buildNotifyPayloadWithData() throws Exception {
- List<Integer> unsupportedTypes = new LinkedList<>();
- unsupportedTypes.add(55); // 0x37 in hex
- unsupportedTypes.add(56);
- unsupportedTypes.add(57);
- UnsupportedCriticalPayloadException exception =
- new UnsupportedCriticalPayloadException(unsupportedTypes);
-
- IkeNotifyPayload payload = exception.buildNotifyPayload();
- assertEquals(ERROR_TYPE_UNSUPPORTED_CRITICAL_PAYLOAD, payload.notifyType);
- assertArrayEquals(new byte[] {(byte) 0x37}, payload.notifyData);
- }
-
- @Test
- public void buildNotifyPayloadWithoutData() throws Exception {
- NoValidProposalChosenException exception =
- new NoValidProposalChosenException("IkeProtocolExceptionTest");
-
- IkeNotifyPayload payload = exception.buildNotifyPayload();
- assertEquals(ERROR_TYPE_NO_PROPOSAL_CHOSEN, payload.notifyType);
- assertArrayEquals(new byte[0], payload.notifyData);
- }
-}
diff --git a/tests/iketests/src/java/com/android/ike/ikev2/ChildSessionStateMachineTest.java b/tests/iketests/src/java/com/android/ike/ikev2/ChildSessionStateMachineTest.java
new file mode 100644
index 00000000..1d760b7e
--- /dev/null
+++ b/tests/iketests/src/java/com/android/ike/ikev2/ChildSessionStateMachineTest.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2019 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.ike.ikev2;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.os.test.TestLooper;
+
+import com.android.ike.ikev2.IkeSessionStateMachine.IChildSessionCallback;
+import com.android.ike.ikev2.SaRecord.ChildSaRecord;
+import com.android.ike.ikev2.SaRecord.ISaRecordHelper;
+import com.android.ike.ikev2.SaRecord.SaRecordHelper;
+import com.android.ike.ikev2.exceptions.IkeException;
+import com.android.ike.ikev2.message.IkePayload;
+import com.android.ike.ikev2.message.TestUtils;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.nio.ByteBuffer;
+import java.util.LinkedList;
+import java.util.List;
+
+public final class ChildSessionStateMachineTest {
+ private static final String IKE_AUTH_REQ_SA_PAYLOAD =
+ "2c00002c00000028010304032ad4c0a20300000c0100000c800e0080"
+ + "03000008030000020000000805000000";
+ private static final String IKE_AUTH_RESP_SA_PAYLOAD =
+ "2c00002c0000002801030403cae7019f0300000c0100000c800e0080"
+ + "03000008030000020000000805000000";
+
+ private static final String CURRENT_CHILD_SA_SPI_IN = "2ad4c0a2";
+ private static final String CURRENT_CHILD_SA_SPI_OUT = "cae7019f";
+
+ private TestLooper mLooper;
+ private ChildSessionStateMachine mChildSessionStateMachine;
+
+ private List<IkePayload> mAuthReqSaNegoPayloads = new LinkedList<>();
+ private List<IkePayload> mAuthRespSaNegoPayloads = new LinkedList<>();
+
+ private ChildSaRecord mSpyCurrentChildSaRecord;
+
+ private ISaRecordHelper mMockSaRecordHelper;
+ private IChildSessionCallback mMockChildSessionCallback;
+ private ChildSessionOptions mChildSessionOptions;
+
+ public ChildSessionStateMachineTest() {
+ mMockSaRecordHelper = mock(SaRecord.ISaRecordHelper.class);
+ mMockChildSessionCallback = mock(IChildSessionCallback.class);
+
+ mChildSessionOptions = new ChildSessionOptions();
+ }
+
+ @Before
+ public void setup() throws Exception {
+ // Setup thread and looper
+ mLooper = new TestLooper();
+ mChildSessionStateMachine =
+ new ChildSessionStateMachine(
+ "ChildSessionStateMachine", mLooper.getLooper(), mChildSessionOptions);
+ mChildSessionStateMachine.setDbg(true);
+ SaRecord.setSaRecordHelper(mMockSaRecordHelper);
+
+ setUpPayloadLists();
+ setUpChildSaRecords();
+
+ mChildSessionStateMachine.start();
+ }
+
+ private void setUpPayloadLists() throws IkeException {
+ mAuthReqSaNegoPayloads.add(
+ TestUtils.hexStringToIkePayload(
+ IkePayload.PAYLOAD_TYPE_SA, false, IKE_AUTH_REQ_SA_PAYLOAD));
+ mAuthRespSaNegoPayloads.add(
+ TestUtils.hexStringToIkePayload(
+ IkePayload.PAYLOAD_TYPE_SA, true, IKE_AUTH_RESP_SA_PAYLOAD));
+ // TODO: Build and add Traffic Selector Payloads to two payload lists.
+ }
+
+ private void setUpChildSaRecords() {
+ mSpyCurrentChildSaRecord =
+ spy(makeDummyChildSaRecord(CURRENT_CHILD_SA_SPI_IN, CURRENT_CHILD_SA_SPI_OUT));
+ }
+
+ private ChildSaRecord makeDummyChildSaRecord(String inboundSpiHex, String outboundSpiHex) {
+ byte[] spiInBytes = TestUtils.hexStringToByteArray(CURRENT_CHILD_SA_SPI_IN);
+ int spiIn = ByteBuffer.wrap(spiInBytes).getInt();
+
+ byte[] spiOutBytes = TestUtils.hexStringToByteArray(CURRENT_CHILD_SA_SPI_OUT);
+ int spiOut = ByteBuffer.wrap(spiOutBytes).getInt();
+
+ return new ChildSaRecord(spiIn, spiOut, null, null);
+ }
+
+ @After
+ public void tearDown() {
+ mChildSessionStateMachine.quit();
+ mChildSessionStateMachine.setDbg(false);
+
+ SaRecord.setSaRecordHelper(new SaRecordHelper());
+ }
+
+ @Test
+ public void testCreateFirstChild() throws Exception {
+ when(mMockSaRecordHelper.makeChildSaRecord(any(), any()))
+ .thenReturn(mSpyCurrentChildSaRecord);
+ mChildSessionStateMachine.handleFirstChildExchange(
+ mAuthReqSaNegoPayloads, mAuthRespSaNegoPayloads, mMockChildSessionCallback);
+
+ mLooper.dispatchAll();
+ verify(mMockChildSessionCallback)
+ .onCreateChildSa(mSpyCurrentChildSaRecord.outboundSpi, mChildSessionStateMachine);
+ assertTrue(
+ mChildSessionStateMachine.getCurrentState()
+ instanceof ChildSessionStateMachine.Idle);
+ assertEquals(mSpyCurrentChildSaRecord, mChildSessionStateMachine.mCurrentChildSaRecord);
+ }
+}
diff --git a/tests/iketests/src/java/com/android/ike/ikev2/IkeSessionOptionsTest.java b/tests/iketests/src/java/com/android/ike/ikev2/IkeSessionOptionsTest.java
new file mode 100644
index 00000000..bdaf135a
--- /dev/null
+++ b/tests/iketests/src/java/com/android/ike/ikev2/IkeSessionOptionsTest.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2019 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.ike.ikev2;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.fail;
+
+import android.content.Context;
+import android.net.IpSecManager;
+import android.net.IpSecManager.UdpEncapsulationSocket;
+
+import androidx.test.InstrumentationRegistry;
+
+import libcore.net.InetAddressUtils;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.net.Inet4Address;
+
+public final class IkeSessionOptionsTest {
+ private static final Inet4Address IPV4_ADDRESS =
+ (Inet4Address) (InetAddressUtils.parseNumericAddress("192.0.2.100"));
+
+ private UdpEncapsulationSocket mUdpEncapSocket;
+
+ @Before
+ public void setUp() throws Exception {
+ Context context = InstrumentationRegistry.getContext();
+ IpSecManager ipSecManager = (IpSecManager) context.getSystemService(Context.IPSEC_SERVICE);
+ mUdpEncapSocket = ipSecManager.openUdpEncapsulationSocket();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ mUdpEncapSocket.close();
+ }
+
+ @Test
+ public void testBuild() throws Exception {
+ SaProposal saProposal =
+ SaProposal.Builder.newIkeSaProposalBuilder()
+ .addEncryptionAlgorithm(
+ SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8,
+ SaProposal.KEY_LEN_AES_128)
+ .addPseudorandomFunction(SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC)
+ .addDhGroup(SaProposal.DH_GROUP_1024_BIT_MODP)
+ .build();
+
+ IkeSessionOptions sessionOptions =
+ new IkeSessionOptions.Builder(IPV4_ADDRESS, mUdpEncapSocket)
+ .addSaProposal(saProposal)
+ .build();
+
+ assertEquals(IPV4_ADDRESS, sessionOptions.getServerAddress());
+ assertEquals(mUdpEncapSocket, sessionOptions.getUdpEncapsulationSocket());
+ assertArrayEquals(new SaProposal[] {saProposal}, sessionOptions.getSaProposals());
+ assertFalse(sessionOptions.isIkeFragmentationSupported());
+ }
+
+ @Test
+ public void testBuildWithoutSaProposal() throws Exception {
+ try {
+ new IkeSessionOptions.Builder(IPV4_ADDRESS, mUdpEncapSocket).build();
+ fail("Expected to fail due to absence of SA proposal.");
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ @Test
+ public void testBuildWithChildSaProposal() throws Exception {
+ SaProposal saProposal =
+ SaProposal.Builder.newChildSaProposalBuilder(true)
+ .addEncryptionAlgorithm(
+ SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8,
+ SaProposal.KEY_LEN_AES_128)
+ .build();
+ try {
+ new IkeSessionOptions.Builder(IPV4_ADDRESS, mUdpEncapSocket)
+ .addSaProposal(saProposal)
+ .build();
+ fail("Expected to fail due to wrong type of SA proposal.");
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+}
diff --git a/tests/iketests/src/java/com/android/ike/ikev2/IkeSessionStateMachineTest.java b/tests/iketests/src/java/com/android/ike/ikev2/IkeSessionStateMachineTest.java
new file mode 100644
index 00000000..1dcf5b82
--- /dev/null
+++ b/tests/iketests/src/java/com/android/ike/ikev2/IkeSessionStateMachineTest.java
@@ -0,0 +1,401 @@
+/*
+ * Copyright (C) 2019 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.ike.ikev2;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.net.IpSecManager;
+import android.net.IpSecManager.UdpEncapsulationSocket;
+import android.os.Looper;
+import android.os.test.TestLooper;
+
+import androidx.test.InstrumentationRegistry;
+
+import com.android.ike.ikev2.ChildSessionStateMachineFactory.ChildSessionFactoryHelper;
+import com.android.ike.ikev2.ChildSessionStateMachineFactory.IChildSessionFactoryHelper;
+import com.android.ike.ikev2.IkeSessionStateMachine.ReceivedIkePacket;
+import com.android.ike.ikev2.SaRecord.ISaRecordHelper;
+import com.android.ike.ikev2.SaRecord.IkeSaRecord;
+import com.android.ike.ikev2.SaRecord.SaRecordHelper;
+import com.android.ike.ikev2.message.IkeHeader;
+import com.android.ike.ikev2.message.IkeMessage;
+import com.android.ike.ikev2.message.IkeMessage.IIkeMessageHelper;
+import com.android.ike.ikev2.message.IkeMessage.IkeMessageHelper;
+import com.android.ike.ikev2.message.IkePayload;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+
+import java.net.InetAddress;
+import java.util.LinkedList;
+import java.util.List;
+
+public final class IkeSessionStateMachineTest {
+
+ private static final String SERVER_ADDRESS = "192.0.2.100";
+
+ private UdpEncapsulationSocket mUdpEncapSocket;
+
+ private TestLooper mLooper;
+ private IkeSessionStateMachine mIkeSessionStateMachine;
+
+ private IkeSessionOptions mIkeSessionOptions;
+ private ChildSessionOptions mChildSessionOptions;
+
+ private IIkeMessageHelper mMockIkeMessageHelper;
+ private ISaRecordHelper mMockSaRecordHelper;
+
+ private ChildSessionStateMachine mMockChildSessionStateMachine;
+ private IChildSessionFactoryHelper mMockChildSessionFactoryHelper;
+
+ private IkeSaRecord mSpyCurrentIkeSaRecord;
+ private IkeSaRecord mSpyLocalInitIkeSaRecord;
+ private IkeSaRecord mSpyRemoteInitIkeSaRecord;
+
+ private ArgumentCaptor<IkeMessage> mIkeMessageCaptor =
+ ArgumentCaptor.forClass(IkeMessage.class);
+
+ private ReceivedIkePacket makeDummyUnencryptedReceivedIkePacket(int packetType)
+ throws Exception {
+ IkeMessage dummyIkeMessage = makeDummyIkeMessageForTest(0, 0, false, false);
+ byte[] dummyIkePacketBytes = new byte[0];
+
+ when(mMockIkeMessageHelper.decode(dummyIkeMessage.ikeHeader, dummyIkePacketBytes))
+ .thenReturn(dummyIkeMessage);
+ when(mMockIkeMessageHelper.getMessageType(dummyIkeMessage)).thenReturn(packetType);
+ return new ReceivedIkePacket(dummyIkeMessage.ikeHeader, dummyIkePacketBytes);
+ }
+
+ private ReceivedIkePacket makeDummyEncryptedReceivedIkePacket(
+ int packetType, IkeSaRecord ikeSaRecord) throws Exception {
+ boolean fromIkeInit = !ikeSaRecord.isLocalInit;
+ IkeMessage dummyIkeMessage =
+ makeDummyIkeMessageForTest(
+ ikeSaRecord.initiatorSpi, ikeSaRecord.responderSpi, fromIkeInit, true);
+ byte[] dummyIkePacketBytes = new byte[0];
+
+ when(mMockIkeMessageHelper.decode(
+ mIkeSessionOptions,
+ ikeSaRecord,
+ dummyIkeMessage.ikeHeader,
+ dummyIkePacketBytes))
+ .thenReturn(dummyIkeMessage);
+ when(mMockIkeMessageHelper.getMessageType(dummyIkeMessage)).thenReturn(packetType);
+ return new ReceivedIkePacket(dummyIkeMessage.ikeHeader, dummyIkePacketBytes);
+ }
+
+ private IkeMessage makeDummyIkeMessageForTest(
+ long initSpi, long respSpi, boolean fromikeInit, boolean isEncrypted) {
+ int firstPayloadType =
+ isEncrypted ? IkePayload.PAYLOAD_TYPE_SK : IkePayload.PAYLOAD_TYPE_NO_NEXT;
+ IkeHeader header =
+ new IkeHeader(initSpi, respSpi, firstPayloadType, 0, true, fromikeInit, 0);
+ return new IkeMessage(header, new LinkedList<IkePayload>());
+ }
+
+ private void verifyDecodeEncryptedMessage(IkeSaRecord record, ReceivedIkePacket rcvPacket)
+ throws Exception {
+ verify(mMockIkeMessageHelper)
+ .decode(mIkeSessionOptions, record, rcvPacket.ikeHeader, rcvPacket.ikePacketBytes);
+ }
+
+ public IkeSessionStateMachineTest() {
+ mMockIkeMessageHelper = mock(IkeMessage.IIkeMessageHelper.class);
+ mMockSaRecordHelper = mock(SaRecord.ISaRecordHelper.class);
+
+ mMockChildSessionStateMachine = mock(ChildSessionStateMachine.class);
+ mMockChildSessionFactoryHelper = mock(IChildSessionFactoryHelper.class);
+
+ mSpyCurrentIkeSaRecord = spy(new IkeSaRecord(11, 12, true, null, null));
+ mSpyLocalInitIkeSaRecord = spy(new IkeSaRecord(21, 22, true, null, null));
+ mSpyRemoteInitIkeSaRecord = spy(new IkeSaRecord(31, 32, false, null, null));
+
+ when(mMockIkeMessageHelper.encode(any())).thenReturn(new byte[0]);
+ when(mMockIkeMessageHelper.encode(any(), any(), any())).thenReturn(new byte[0]);
+ when(mMockChildSessionFactoryHelper.makeChildSessionStateMachine(any(), any(), any()))
+ .thenReturn(mMockChildSessionStateMachine);
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ Context context = InstrumentationRegistry.getContext();
+ IpSecManager ipSecManager = (IpSecManager) context.getSystemService(Context.IPSEC_SERVICE);
+ mUdpEncapSocket = ipSecManager.openUdpEncapsulationSocket();
+
+ mIkeSessionOptions = buildIkeSessionOptions();
+ mChildSessionOptions = new ChildSessionOptions();
+
+ // Setup thread and looper
+ mLooper = new TestLooper();
+ mIkeSessionStateMachine =
+ new IkeSessionStateMachine(
+ "IkeSessionStateMachine",
+ mLooper.getLooper(),
+ mIkeSessionOptions,
+ mChildSessionOptions);
+ mIkeSessionStateMachine.setDbg(true);
+ mIkeSessionStateMachine.start();
+
+ IkeMessage.setIkeMessageHelper(mMockIkeMessageHelper);
+ SaRecord.setSaRecordHelper(mMockSaRecordHelper);
+ ChildSessionStateMachineFactory.setChildSessionFactoryHelper(
+ mMockChildSessionFactoryHelper);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ mIkeSessionStateMachine.quit();
+ mIkeSessionStateMachine.setDbg(false);
+ mUdpEncapSocket.close();
+
+ IkeMessage.setIkeMessageHelper(new IkeMessageHelper());
+ SaRecord.setSaRecordHelper(new SaRecordHelper());
+ ChildSessionStateMachineFactory.setChildSessionFactoryHelper(
+ new ChildSessionFactoryHelper());
+ }
+
+ private IkeSessionOptions buildIkeSessionOptions() throws Exception {
+ SaProposal saProposal =
+ SaProposal.Builder.newIkeSaProposalBuilder()
+ .addEncryptionAlgorithm(
+ SaProposal.ENCRYPTION_ALGORITHM_AES_CBC, SaProposal.KEY_LEN_AES_128)
+ .addIntegrityAlgorithm(SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96)
+ .addPseudorandomFunction(SaProposal.PSEUDORANDOM_FUNCTION_HMAC_SHA1)
+ .addDhGroup(SaProposal.DH_GROUP_1024_BIT_MODP)
+ .build();
+
+ InetAddress serveAddress = InetAddress.getByName(SERVER_ADDRESS);
+ IkeSessionOptions sessionOptions =
+ new IkeSessionOptions.Builder(serveAddress, mUdpEncapSocket)
+ .addSaProposal(saProposal)
+ .build();
+ return sessionOptions;
+ }
+
+ private static boolean isIkePayloadExist(
+ List<IkePayload> payloadList, @IkePayload.PayloadType int payloadType) {
+ for (IkePayload payload : payloadList) {
+ if (payload.payloadType == payloadType) return true;
+ }
+ return false;
+ }
+
+ @Test
+ public void testCreateIkeLocalIkeInit() throws Exception {
+ if (Looper.myLooper() == null) Looper.myLooper().prepare();
+ // Mock IKE_INIT response.
+ ReceivedIkePacket dummyReceivedIkePacket =
+ makeDummyUnencryptedReceivedIkePacket(IkeMessage.MESSAGE_TYPE_IKE_INIT_RESP);
+ when(mMockSaRecordHelper.makeFirstIkeSaRecord(any(), any()))
+ .thenReturn(mSpyCurrentIkeSaRecord);
+
+ mIkeSessionStateMachine.sendMessage(IkeSessionStateMachine.CMD_LOCAL_REQUEST_CREATE_IKE);
+ mIkeSessionStateMachine.sendMessage(
+ IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, dummyReceivedIkePacket);
+
+ mLooper.dispatchAll();
+
+ // Validate outbound IKE INIT request
+ verify(mMockIkeMessageHelper).encode(mIkeMessageCaptor.capture());
+ IkeMessage ikeInitReqMessage = mIkeMessageCaptor.getValue();
+
+ IkeHeader ikeHeader = ikeInitReqMessage.ikeHeader;
+ assertEquals(IkeHeader.EXCHANGE_TYPE_IKE_SA_INIT, ikeHeader.exchangeType);
+ assertFalse(ikeHeader.isResponseMsg);
+ assertTrue(ikeHeader.fromIkeInitiator);
+
+ List<IkePayload> payloadList = ikeInitReqMessage.ikePayloadList;
+ assertTrue(isIkePayloadExist(payloadList, IkePayload.PAYLOAD_TYPE_SA));
+ assertTrue(isIkePayloadExist(payloadList, IkePayload.PAYLOAD_TYPE_KE));
+ assertTrue(isIkePayloadExist(payloadList, IkePayload.PAYLOAD_TYPE_NONCE));
+
+ IkeSocket ikeSocket = mIkeSessionStateMachine.mIkeSocket;
+ assertNotNull(ikeSocket);
+ assertNotEquals(
+ -1 /*not found*/, ikeSocket.mSpiToIkeSession.indexOfValue(mIkeSessionStateMachine));
+
+ verify(mMockIkeMessageHelper)
+ .decode(dummyReceivedIkePacket.ikeHeader, dummyReceivedIkePacket.ikePacketBytes);
+ verify(mMockIkeMessageHelper).getMessageType(any());
+
+ assertTrue(
+ mIkeSessionStateMachine.getCurrentState()
+ instanceof IkeSessionStateMachine.CreateIkeLocalIkeAuth);
+ }
+
+ private void mockIkeSetup() throws Exception {
+ if (Looper.myLooper() == null) Looper.myLooper().prepare();
+ // Mock IKE_INIT response
+ ReceivedIkePacket dummyIkeInitRespReceivedPacket =
+ makeDummyUnencryptedReceivedIkePacket(IkeMessage.MESSAGE_TYPE_IKE_INIT_RESP);
+ when(mMockSaRecordHelper.makeFirstIkeSaRecord(any(), any()))
+ .thenReturn(mSpyCurrentIkeSaRecord);
+
+ // Mock IKE_AUTH response
+ ReceivedIkePacket dummyIkeAuthRespReceivedPacket =
+ makeDummyEncryptedReceivedIkePacket(
+ IkeMessage.MESSAGE_TYPE_IKE_AUTH_RESP, mSpyCurrentIkeSaRecord);
+
+ mIkeSessionStateMachine.sendMessage(IkeSessionStateMachine.CMD_LOCAL_REQUEST_CREATE_IKE);
+ mIkeSessionStateMachine.sendMessage(
+ IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, dummyIkeInitRespReceivedPacket);
+ mIkeSessionStateMachine.sendMessage(
+ IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, dummyIkeAuthRespReceivedPacket);
+ }
+
+ @Test
+ public void testCreateIkeLocalIkeAuth() throws Exception {
+ mockIkeSetup();
+
+ mLooper.dispatchAll();
+ verify(mMockIkeMessageHelper).decode(any(), any(), any(), any());
+ verify(mMockIkeMessageHelper, times(2)).getMessageType(any());
+ verify(mMockChildSessionStateMachine).handleFirstChildExchange(any(), any(), any());
+ assertTrue(
+ mIkeSessionStateMachine.getCurrentState() instanceof IkeSessionStateMachine.Idle);
+ }
+
+ @Test
+ public void testRekeyIkeLocal() throws Exception {
+ // Mock Rekey IKE response
+ ReceivedIkePacket dummyRekeyIkeRespReceivedPacket =
+ makeDummyEncryptedReceivedIkePacket(
+ IkeMessage.MESSAGE_TYPE_REKEY_IKE_RESP, mSpyCurrentIkeSaRecord);
+ when(mMockSaRecordHelper.makeNewIkeSaRecord(eq(mSpyCurrentIkeSaRecord), any(), any()))
+ .thenReturn(mSpyLocalInitIkeSaRecord);
+ // Mock Delete old IKE response;
+ ReceivedIkePacket dummyDeleteIkeRespReceivedPacket =
+ makeDummyEncryptedReceivedIkePacket(
+ IkeMessage.MESSAGE_TYPE_DELETE_IKE_RESP, mSpyCurrentIkeSaRecord);
+
+ mockIkeSetup();
+
+ // Testing creating new IKE
+ mIkeSessionStateMachine.sendMessage(IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_IKE);
+ mIkeSessionStateMachine.sendMessage(
+ IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, dummyRekeyIkeRespReceivedPacket);
+ // Testing deleting old IKE
+ mIkeSessionStateMachine.sendMessage(
+ IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, dummyDeleteIkeRespReceivedPacket);
+
+ mLooper.dispatchAll();
+ verifyDecodeEncryptedMessage(mSpyCurrentIkeSaRecord, dummyRekeyIkeRespReceivedPacket);
+ verifyDecodeEncryptedMessage(mSpyCurrentIkeSaRecord, dummyDeleteIkeRespReceivedPacket);
+ assertTrue(
+ mIkeSessionStateMachine.getCurrentState() instanceof IkeSessionStateMachine.Idle);
+ assertEquals(mIkeSessionStateMachine.mCurrentIkeSaRecord, mSpyLocalInitIkeSaRecord);
+ }
+
+ @Test
+ public void testRekeyIkeRemote() throws Exception {
+ // Mock Rekey IKE request
+ ReceivedIkePacket dummyRekeyIkeRequestReceivedPacket =
+ makeDummyEncryptedReceivedIkePacket(
+ IkeMessage.MESSAGE_TYPE_REKEY_IKE_REQ, mSpyCurrentIkeSaRecord);
+ when(mMockSaRecordHelper.makeNewIkeSaRecord(eq(mSpyCurrentIkeSaRecord), any(), any()))
+ .thenReturn(mSpyRemoteInitIkeSaRecord);
+
+ // Mock Delete IKE request
+ ReceivedIkePacket dummyDeleteIkeRequestReceivedPacket =
+ makeDummyEncryptedReceivedIkePacket(
+ IkeMessage.MESSAGE_TYPE_DELETE_IKE_REQ, mSpyCurrentIkeSaRecord);
+ mockIkeSetup();
+
+ mIkeSessionStateMachine.sendMessage(
+ IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, dummyRekeyIkeRequestReceivedPacket);
+ mIkeSessionStateMachine.sendMessage(
+ IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, dummyDeleteIkeRequestReceivedPacket);
+
+ mLooper.dispatchAll();
+ verifyDecodeEncryptedMessage(mSpyCurrentIkeSaRecord, dummyRekeyIkeRequestReceivedPacket);
+ verifyDecodeEncryptedMessage(mSpyCurrentIkeSaRecord, dummyDeleteIkeRequestReceivedPacket);
+ assertTrue(
+ mIkeSessionStateMachine.getCurrentState() instanceof IkeSessionStateMachine.Idle);
+ assertEquals(mIkeSessionStateMachine.mCurrentIkeSaRecord, mSpyRemoteInitIkeSaRecord);
+ }
+
+ @Test
+ public void testSimulRekey() throws Exception {
+ // Mock Rekey IKE response
+ ReceivedIkePacket dummyRekeyIkeRespReceivedPacket =
+ makeDummyEncryptedReceivedIkePacket(
+ IkeMessage.MESSAGE_TYPE_REKEY_IKE_RESP, mSpyCurrentIkeSaRecord);
+ when(mMockSaRecordHelper.makeNewIkeSaRecord(eq(mSpyCurrentIkeSaRecord), any(), any()))
+ .thenReturn(mSpyLocalInitIkeSaRecord);
+
+ // Mock Rekey IKE request
+ ReceivedIkePacket dummyRekeyIkeRequestReceivedPacket =
+ makeDummyEncryptedReceivedIkePacket(
+ IkeMessage.MESSAGE_TYPE_REKEY_IKE_REQ, mSpyCurrentIkeSaRecord);
+
+ when(mMockSaRecordHelper.makeNewIkeSaRecord(eq(mSpyCurrentIkeSaRecord), any(), any()))
+ .thenReturn(mSpyRemoteInitIkeSaRecord)
+ .thenReturn(mSpyLocalInitIkeSaRecord);
+
+ // Mock nonce comparison
+ when(mSpyLocalInitIkeSaRecord.compareTo(mSpyRemoteInitIkeSaRecord)).thenReturn(1);
+
+ // Mock Delete old IKE response;
+ ReceivedIkePacket dummyDeleteIkeRespReceivedPacket =
+ makeDummyEncryptedReceivedIkePacket(
+ IkeMessage.MESSAGE_TYPE_DELETE_IKE_RESP, mSpyCurrentIkeSaRecord);
+
+ // Mock Delete IKE request on remotely initiated IKE SA
+ ReceivedIkePacket dummyDeleteIkeRequestReceivedPacket =
+ makeDummyEncryptedReceivedIkePacket(
+ IkeMessage.MESSAGE_TYPE_DELETE_IKE_REQ, mSpyRemoteInitIkeSaRecord);
+
+ mockIkeSetup();
+
+ // Testing creating new IKE
+ mIkeSessionStateMachine.sendMessage(IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_IKE);
+ mIkeSessionStateMachine.sendMessage(
+ IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, dummyRekeyIkeRequestReceivedPacket);
+
+ mIkeSessionStateMachine.sendMessage(
+ IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, dummyRekeyIkeRespReceivedPacket);
+ // Testing deleting old IKE and losing new IKE
+ mIkeSessionStateMachine.sendMessage(
+ IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, dummyDeleteIkeRespReceivedPacket);
+ mIkeSessionStateMachine.sendMessage(
+ IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, dummyDeleteIkeRequestReceivedPacket);
+
+ mLooper.dispatchAll();
+ verifyDecodeEncryptedMessage(mSpyCurrentIkeSaRecord, dummyRekeyIkeRequestReceivedPacket);
+ verifyDecodeEncryptedMessage(mSpyCurrentIkeSaRecord, dummyRekeyIkeRespReceivedPacket);
+ verifyDecodeEncryptedMessage(mSpyCurrentIkeSaRecord, dummyDeleteIkeRespReceivedPacket);
+ verifyDecodeEncryptedMessage(
+ mSpyRemoteInitIkeSaRecord, dummyDeleteIkeRequestReceivedPacket);
+ assertTrue(
+ mIkeSessionStateMachine.getCurrentState() instanceof IkeSessionStateMachine.Idle);
+ assertEquals(mIkeSessionStateMachine.mCurrentIkeSaRecord, mSpyLocalInitIkeSaRecord);
+ }
+}
diff --git a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/IkeSocketTest.java b/tests/iketests/src/java/com/android/ike/ikev2/IkeSocketTest.java
index 1b8761f7..5f15f554 100644
--- a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/IkeSocketTest.java
+++ b/tests/iketests/src/java/com/android/ike/ikev2/IkeSocketTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.internal.net.ipsec.ike;
+package com.android.ike.ikev2;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
@@ -39,9 +39,9 @@ import android.util.LongSparseArray;
import androidx.test.InstrumentationRegistry;
-import com.android.internal.net.TestUtils;
-import com.android.internal.net.ipsec.ike.IkeSocket.PacketReceiver;
-import com.android.internal.net.ipsec.ike.message.IkeHeader;
+import com.android.ike.ikev2.IkeSocket.PacketReceiver;
+import com.android.ike.ikev2.message.IkeHeader;
+import com.android.ike.ikev2.message.TestUtils;
import org.junit.After;
import org.junit.Before;
@@ -141,35 +141,28 @@ public final class IkeSocketTest {
@Test
public void testGetAndCloseIkeSocket() throws Exception {
- // Must be prepared here; AndroidJUnitRunner runs tests on different threads from the
- // setUp() call. Since the new Handler() call is run in getIkeSocket, the Looper must be
- // prepared here.
- if (Looper.myLooper() == null) Looper.prepare();
+ if (Looper.myLooper() == null) Looper.myLooper().prepare();
- IkeSessionStateMachine mMockIkeSessionOne = mock(IkeSessionStateMachine.class);
- IkeSessionStateMachine mMockIkeSessionTwo = mock(IkeSessionStateMachine.class);
+ IkeSocket ikeSocketOne = IkeSocket.getIkeSocket(mClientUdpEncapSocket);
+ assertEquals(1, ikeSocketOne.mRefCount);
- IkeSocket ikeSocketOne = IkeSocket.getIkeSocket(mClientUdpEncapSocket, mMockIkeSessionOne);
- assertEquals(1, ikeSocketOne.mAliveIkeSessions.size());
-
- IkeSocket ikeSocketTwo = IkeSocket.getIkeSocket(mClientUdpEncapSocket, mMockIkeSessionTwo);
+ IkeSocket ikeSocketTwo = IkeSocket.getIkeSocket(mClientUdpEncapSocket);
assertEquals(ikeSocketOne, ikeSocketTwo);
- assertEquals(2, ikeSocketTwo.mAliveIkeSessions.size());
+ assertEquals(2, ikeSocketTwo.mRefCount);
- ikeSocketOne.releaseReference(mMockIkeSessionOne);
- assertEquals(1, ikeSocketOne.mAliveIkeSessions.size());
+ ikeSocketOne.releaseReference();
+ assertEquals(1, ikeSocketOne.mRefCount);
- ikeSocketTwo.releaseReference(mMockIkeSessionTwo);
- assertEquals(0, ikeSocketTwo.mAliveIkeSessions.size());
+ ikeSocketTwo.releaseReference();
+ assertEquals(0, ikeSocketTwo.mRefCount);
}
@Test
public void testSendIkePacket() throws Exception {
- if (Looper.myLooper() == null) Looper.prepare();
+ if (Looper.myLooper() == null) Looper.myLooper().prepare();
// Send IKE packet
- IkeSocket ikeSocket =
- IkeSocket.getIkeSocket(mClientUdpEncapSocket, mMockIkeSessionStateMachine);
+ IkeSocket ikeSocket = IkeSocket.getIkeSocket(mClientUdpEncapSocket);
ikeSocket.sendIkePacket(mDataOne, mLocalAddress);
byte[] receivedData = receive(mDummyRemoteServerFd);
@@ -181,7 +174,7 @@ public final class IkeSocketTest {
assertArrayEquals(expectedBuffer.array(), receivedData);
- ikeSocket.releaseReference(mMockIkeSessionStateMachine);
+ ikeSocket.releaseReference();
}
@Test
@@ -199,9 +192,7 @@ public final class IkeSocketTest {
() -> {
try {
socketReceiver.setIkeSocket(
- IkeSocket.getIkeSocket(
- mClientUdpEncapSocket,
- mMockIkeSessionStateMachine));
+ IkeSocket.getIkeSocket(mClientUdpEncapSocket));
createLatch.countDown();
Log.d("IkeSocketTest", "IkeSocket created.");
} catch (ErrnoException e) {
@@ -238,7 +229,7 @@ public final class IkeSocketTest {
.getHandler()
.post(
() -> {
- ikeSocket.releaseReference(mMockIkeSessionStateMachine);
+ ikeSocket.releaseReference();
closeLatch.countDown();
});
closeLatch.await();
diff --git a/tests/iketests/src/java/android/net/ipsec/ike/IkeTrafficSelectorTest.java b/tests/iketests/src/java/com/android/ike/ikev2/IkeTrafficSelectorTest.java
index 65cf0566..1982e62f 100644
--- a/tests/iketests/src/java/android/net/ipsec/ike/IkeTrafficSelectorTest.java
+++ b/tests/iketests/src/java/com/android/ike/ikev2/IkeTrafficSelectorTest.java
@@ -14,25 +14,19 @@
* limitations under the License.
*/
-package android.net.ipsec.ike;
+package com.android.ike.ikev2;
-import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import com.android.internal.net.TestUtils;
-import com.android.internal.net.ipsec.ike.exceptions.InvalidSyntaxException;
+import com.android.ike.ikev2.exceptions.InvalidSyntaxException;
+import com.android.ike.ikev2.message.TestUtils;
import libcore.net.InetAddressUtils;
import org.junit.Test;
import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.nio.ByteBuffer;
public final class IkeTrafficSelectorTest {
private static final String TS_IPV4_ONE_HEX_STRING = "070000100010fff0c0000264c0000365";
@@ -60,26 +54,6 @@ public final class IkeTrafficSelectorTest {
private static final int PROTOCOL_ID_OFFSET = 1;
private static final int TS_LENGTH_OFFSET = 2;
- private IkeTrafficSelector mTsOne;
- private IkeTrafficSelector mTsTwo;
-
- public IkeTrafficSelectorTest() {
- mTsOne =
- new IkeTrafficSelector(
- IkeTrafficSelector.TRAFFIC_SELECTOR_TYPE_IPV4_ADDR_RANGE,
- TS_ONE_START_PORT,
- TS_ONE_END_PORT,
- TS_ONE_START_ADDRESS,
- TS_ONE_END_ADDRESS);
- mTsTwo =
- new IkeTrafficSelector(
- IkeTrafficSelector.TRAFFIC_SELECTOR_TYPE_IPV4_ADDR_RANGE,
- TS_TWO_START_PORT,
- TS_TWO_END_PORT,
- TS_TWO_START_ADDRESS,
- TS_TWO_END_ADDRESS);
- }
-
@Test
public void testDecodeIkeTrafficSelectors() throws Exception {
int numTs = 2;
@@ -115,53 +89,6 @@ public final class IkeTrafficSelectorTest {
}
@Test
- public void testBuildAndEncodeIkeTrafficSelector() throws Exception {
- IkeTrafficSelector ts =
- new IkeTrafficSelector(
- IkeTrafficSelector.TRAFFIC_SELECTOR_TYPE_IPV4_ADDR_RANGE,
- TS_ONE_START_PORT,
- TS_ONE_END_PORT,
- TS_ONE_START_ADDRESS,
- TS_ONE_END_ADDRESS);
-
- ByteBuffer byteBuffer = ByteBuffer.allocate(ts.selectorLength);
- ts.encodeToByteBuffer(byteBuffer);
-
- byte[] expectedBytes = TestUtils.hexStringToByteArray(TS_IPV4_ONE_HEX_STRING);
- assertArrayEquals(expectedBytes, byteBuffer.array());
- }
-
- @Test
- public void testEquals() throws Exception {
- IkeTrafficSelector tsOneOther =
- new IkeTrafficSelector(
- IkeTrafficSelector.TRAFFIC_SELECTOR_TYPE_IPV4_ADDR_RANGE,
- TS_ONE_START_PORT,
- TS_ONE_END_PORT,
- TS_ONE_START_ADDRESS,
- TS_ONE_END_ADDRESS);
-
- assertEquals(mTsOne, tsOneOther);
- assertNotEquals(mTsOne, mTsTwo);
- }
-
- @Test
- public void testContains() throws Exception {
- IkeTrafficSelector tsOneSubset =
- new IkeTrafficSelector(
- IkeTrafficSelector.TRAFFIC_SELECTOR_TYPE_IPV4_ADDR_RANGE,
- TS_ONE_START_PORT + 1,
- TS_ONE_END_PORT,
- TS_ONE_START_ADDRESS,
- TS_ONE_END_ADDRESS);
- assertTrue(mTsOne.contains(tsOneSubset));
- assertFalse(tsOneSubset.contains(mTsOne));
-
- assertTrue(mTsOne.contains(mTsOne));
- assertFalse(mTsOne.contains(mTsTwo));
- }
-
- @Test
public void testDecodeIkeTrafficSelectorWithInvalidTsType() throws Exception {
int numTs = 1;
byte[] tsBytes = TestUtils.hexStringToByteArray(TS_IPV4_ONE_HEX_STRING);
@@ -244,69 +171,4 @@ public final class IkeTrafficSelectorTest {
}
}
-
- @Test
- public void testBuildIkeTrafficSelectorWithInvalidTsType() throws Exception {
- try {
- IkeTrafficSelector ts =
- new IkeTrafficSelector(
- 0,
- TS_ONE_START_PORT,
- TS_ONE_END_PORT,
- TS_ONE_START_ADDRESS,
- TS_ONE_END_ADDRESS);
- fail("Expected to fail due to unrecognized Traffic Selector type.");
- } catch (IllegalArgumentException expected) {
-
- }
- }
-
- @Test
- public void testBuildIkeTrafficSelectorWithInvalidPortRange() throws Exception {
- try {
- IkeTrafficSelector ts =
- new IkeTrafficSelector(
- IkeTrafficSelector.TRAFFIC_SELECTOR_TYPE_IPV4_ADDR_RANGE,
- TS_ONE_END_PORT,
- TS_ONE_START_PORT,
- TS_ONE_START_ADDRESS,
- TS_ONE_END_ADDRESS);
- fail("Expected to fail due to invalid port range.");
- } catch (IllegalArgumentException expected) {
-
- }
- }
-
- @Test
- public void testBuildIkeTrafficSelectorWithMismatchedAddressType() throws Exception {
- Inet6Address inet6Address =
- (Inet6Address) (InetAddressUtils.parseNumericAddress("0:2001:0:db8::1"));
- try {
- IkeTrafficSelector ts =
- new IkeTrafficSelector(
- IkeTrafficSelector.TRAFFIC_SELECTOR_TYPE_IPV4_ADDR_RANGE,
- TS_ONE_START_PORT,
- TS_ONE_END_PORT,
- inet6Address,
- TS_ONE_END_ADDRESS);
- fail("Expected to fail due to mismatched address format.");
- } catch (IllegalArgumentException expected) {
-
- }
- }
-
- @Test
- public void testBuildIkeTrafficSelectorWithInvalidAddressRange() throws Exception {
- try {
- IkeTrafficSelector ts =
- new IkeTrafficSelector(
- IkeTrafficSelector.TRAFFIC_SELECTOR_TYPE_IPV4_ADDR_RANGE,
- TS_ONE_START_PORT,
- TS_ONE_END_PORT,
- TS_ONE_END_ADDRESS,
- TS_ONE_START_ADDRESS);
- fail("Expected to fail due to invalid address range.");
- } catch (IllegalArgumentException e) {
- }
- }
}
diff --git a/tests/iketests/src/java/android/net/ipsec/ike/SaProposalTest.java b/tests/iketests/src/java/com/android/ike/ikev2/SaProposalTest.java
index d4efb0c3..7f40d729 100644
--- a/tests/iketests/src/java/android/net/ipsec/ike/SaProposalTest.java
+++ b/tests/iketests/src/java/com/android/ike/ikev2/SaProposalTest.java
@@ -14,10 +14,7 @@
* limitations under the License.
*/
-package android.net.ipsec.ike;
-
-import static android.net.ipsec.ike.SaProposal.KEY_LEN_AES_128;
-import static android.net.ipsec.ike.SaProposal.KEY_LEN_UNUSED;
+package com.android.ike.ikev2;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
@@ -25,12 +22,13 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import com.android.internal.net.ipsec.ike.message.IkePayload;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload.DhGroupTransform;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload.EncryptionTransform;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload.IntegrityTransform;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload.PrfTransform;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload.Transform;
+import com.android.ike.ikev2.SaProposal.Builder;
+import com.android.ike.ikev2.message.IkePayload;
+import com.android.ike.ikev2.message.IkeSaPayload.DhGroupTransform;
+import com.android.ike.ikev2.message.IkeSaPayload.EncryptionTransform;
+import com.android.ike.ikev2.message.IkeSaPayload.IntegrityTransform;
+import com.android.ike.ikev2.message.IkeSaPayload.PrfTransform;
+import com.android.ike.ikev2.message.IkeSaPayload.Transform;
import org.junit.Test;
@@ -44,8 +42,7 @@ public final class SaProposalTest {
private final DhGroupTransform mDhGroup1024Transform;
public SaProposalTest() {
- mEncryption3DesTransform =
- new EncryptionTransform(SaProposal.ENCRYPTION_ALGORITHM_3DES, KEY_LEN_UNUSED);
+ mEncryption3DesTransform = new EncryptionTransform(SaProposal.ENCRYPTION_ALGORITHM_3DES);
mEncryptionAesGcm8Transform =
new EncryptionTransform(
SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8, SaProposal.KEY_LEN_AES_128);
@@ -61,10 +58,9 @@ public final class SaProposalTest {
@Test
public void testBuildIkeSaProposalWithNormalModeCipher() throws Exception {
- IkeSaProposal proposal =
- new IkeSaProposal.Builder()
- .addEncryptionAlgorithm(
- SaProposal.ENCRYPTION_ALGORITHM_3DES, KEY_LEN_UNUSED)
+ Builder builder = Builder.newIkeSaProposalBuilder();
+ SaProposal proposal =
+ builder.addEncryptionAlgorithm(SaProposal.ENCRYPTION_ALGORITHM_3DES)
.addIntegrityAlgorithm(SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96)
.addPseudorandomFunction(SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC)
.addDhGroup(SaProposal.DH_GROUP_1024_BIT_MODP)
@@ -85,9 +81,9 @@ public final class SaProposalTest {
@Test
public void testBuildIkeSaProposalWithCombinedModeCipher() throws Exception {
- IkeSaProposal proposal =
- new IkeSaProposal.Builder()
- .addEncryptionAlgorithm(
+ Builder builder = Builder.newIkeSaProposalBuilder();
+ SaProposal proposal =
+ builder.addEncryptionAlgorithm(
SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8,
SaProposal.KEY_LEN_AES_128)
.addPseudorandomFunction(SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC)
@@ -106,49 +102,53 @@ public final class SaProposalTest {
}
@Test
- public void testBuildChildSaProposalWithNormalCipher() throws Exception {
- ChildSaProposal proposal =
- new ChildSaProposal.Builder()
- .addEncryptionAlgorithm(
- SaProposal.ENCRYPTION_ALGORITHM_3DES, KEY_LEN_UNUSED)
+ public void testBuildFirstChildSaProposalWithCombinedCipher() throws Exception {
+ Builder builder = Builder.newChildSaProposalBuilder(true);
+ SaProposal proposal =
+ builder.addEncryptionAlgorithm(
+ SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8,
+ SaProposal.KEY_LEN_AES_128)
.addIntegrityAlgorithm(SaProposal.INTEGRITY_ALGORITHM_NONE)
- .addDhGroup(SaProposal.DH_GROUP_1024_BIT_MODP)
.build();
assertEquals(IkePayload.PROTOCOL_ID_ESP, proposal.getProtocolId());
assertArrayEquals(
- new EncryptionTransform[] {mEncryption3DesTransform},
+ new EncryptionTransform[] {mEncryptionAesGcm8Transform},
proposal.getEncryptionTransforms());
assertArrayEquals(
new IntegrityTransform[] {mIntegrityNoneTransform},
proposal.getIntegrityTransforms());
- assertArrayEquals(
- new DhGroupTransform[] {mDhGroup1024Transform}, proposal.getDhGroupTransforms());
+ assertTrue(proposal.getPrfTransforms().length == 0);
+ assertTrue(proposal.getDhGroupTransforms().length == 0);
}
@Test
- public void testGetCopyWithoutDhGroup() throws Exception {
- ChildSaProposal proposal =
- new ChildSaProposal.Builder()
- .addEncryptionAlgorithm(
- SaProposal.ENCRYPTION_ALGORITHM_3DES, KEY_LEN_UNUSED)
+ public void testBuildAdditionalChildSaProposalWithNormalCipher() throws Exception {
+ Builder builder = Builder.newChildSaProposalBuilder(false);
+
+ SaProposal proposal =
+ builder.addEncryptionAlgorithm(SaProposal.ENCRYPTION_ALGORITHM_3DES)
.addIntegrityAlgorithm(SaProposal.INTEGRITY_ALGORITHM_NONE)
.addDhGroup(SaProposal.DH_GROUP_1024_BIT_MODP)
.build();
- ChildSaProposal proposalWithoutDh = proposal.getCopyWithoutDhTransform();
+ assertEquals(IkePayload.PROTOCOL_ID_ESP, proposal.getProtocolId());
assertArrayEquals(
- proposal.getEncryptionTransforms(), proposalWithoutDh.getEncryptionTransforms());
+ new EncryptionTransform[] {mEncryption3DesTransform},
+ proposal.getEncryptionTransforms());
+ assertArrayEquals(
+ new IntegrityTransform[] {mIntegrityNoneTransform},
+ proposal.getIntegrityTransforms());
assertArrayEquals(
- proposal.getIntegrityTransforms(), proposalWithoutDh.getIntegrityTransforms());
- assertTrue(proposal.getDhGroupTransforms().length == 1);
- assertTrue(proposalWithoutDh.getDhGroupTransforms().length == 0);
+ new DhGroupTransform[] {mDhGroup1024Transform}, proposal.getDhGroupTransforms());
+ assertTrue(proposal.getPrfTransforms().length == 0);
}
@Test
public void testBuildEncryptAlgosWithNoAlgorithm() throws Exception {
+ Builder builder = Builder.newIkeSaProposalBuilder();
try {
- new IkeSaProposal.Builder().build();
+ builder.build();
fail("Expected to fail when no encryption algorithm is proposed.");
} catch (IllegalArgumentException expected) {
@@ -157,8 +157,9 @@ public final class SaProposalTest {
@Test
public void testBuildEncryptAlgosWithUnrecognizedAlgorithm() throws Exception {
+ Builder builder = Builder.newIkeSaProposalBuilder();
try {
- new IkeSaProposal.Builder().addEncryptionAlgorithm(-1, KEY_LEN_UNUSED);
+ builder.addEncryptionAlgorithm(-1);
fail("Expected to fail when unrecognized encryption algorithm is proposed.");
} catch (IllegalArgumentException expected) {
@@ -167,11 +168,10 @@ public final class SaProposalTest {
@Test
public void testBuildEncryptAlgosWithTwoModes() throws Exception {
+ Builder builder = Builder.newIkeSaProposalBuilder();
try {
- new IkeSaProposal.Builder()
- .addEncryptionAlgorithm(SaProposal.ENCRYPTION_ALGORITHM_3DES, KEY_LEN_UNUSED)
- .addEncryptionAlgorithm(
- SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12, KEY_LEN_AES_128);
+ builder.addEncryptionAlgorithm(SaProposal.ENCRYPTION_ALGORITHM_3DES)
+ .addEncryptionAlgorithm(SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12);
fail(
"Expected to fail when "
+ "normal and combined-mode ciphers are proposed together.");
@@ -182,24 +182,36 @@ public final class SaProposalTest {
@Test
public void testBuildIkeProposalWithoutPrf() throws Exception {
+ Builder builder = Builder.newIkeSaProposalBuilder();
try {
- new IkeSaProposal.Builder()
- .addEncryptionAlgorithm(SaProposal.ENCRYPTION_ALGORITHM_3DES, KEY_LEN_UNUSED)
- .build();
+ builder.addEncryptionAlgorithm(SaProposal.ENCRYPTION_ALGORITHM_3DES).build();
fail("Expected to fail when PRF is not provided in IKE SA proposal.");
} catch (IllegalArgumentException expected) {
}
}
+ @Test
+ public void testBuildChildProposalWithPrf() throws Exception {
+ Builder builder = Builder.newChildSaProposalBuilder(false);
+ try {
+ builder.addEncryptionAlgorithm(SaProposal.ENCRYPTION_ALGORITHM_3DES)
+ .addPseudorandomFunction(SaProposal.PSEUDORANDOM_FUNCTION_HMAC_SHA1)
+ .build();
+
+ fail("Expected to fail when PRF is provided in Child SA proposal.");
+ } catch (IllegalArgumentException expected) {
+
+ }
+ }
+
// Test throwing exception when building IKE SA Proposal with AEAD and not-none integrity
// algorithm.
@Test
public void testBuildAeadWithIntegrityAlgo() throws Exception {
+ Builder builder = Builder.newChildSaProposalBuilder(false);
try {
- new ChildSaProposal.Builder()
- .addEncryptionAlgorithm(
- SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12, KEY_LEN_AES_128)
+ builder.addEncryptionAlgorithm(SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12)
.addIntegrityAlgorithm(SaProposal.INTEGRITY_ALGORITHM_NONE)
.addIntegrityAlgorithm(SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96)
.build();
@@ -214,9 +226,9 @@ public final class SaProposalTest {
// integrity algorithm.
@Test
public void testBuildIkeProposalNormalCipherWithoutIntegrityAlgo() throws Exception {
+ Builder builder = Builder.newChildSaProposalBuilder(false);
try {
- new IkeSaProposal.Builder()
- .addEncryptionAlgorithm(SaProposal.ENCRYPTION_ALGORITHM_3DES, KEY_LEN_UNUSED)
+ builder.addEncryptionAlgorithm(SaProposal.ENCRYPTION_ALGORITHM_3DES)
.addPseudorandomFunction(SaProposal.PSEUDORANDOM_FUNCTION_HMAC_SHA1)
.build();
@@ -232,9 +244,9 @@ public final class SaProposalTest {
// integrity algorithm.
@Test
public void testBuildIkeProposalNormalCipherWithNoneValueIntegrityAlgo() throws Exception {
+ Builder builder = Builder.newChildSaProposalBuilder(false);
try {
- new IkeSaProposal.Builder()
- .addEncryptionAlgorithm(SaProposal.ENCRYPTION_ALGORITHM_3DES, KEY_LEN_UNUSED)
+ builder.addEncryptionAlgorithm(SaProposal.ENCRYPTION_ALGORITHM_3DES)
.addPseudorandomFunction(SaProposal.PSEUDORANDOM_FUNCTION_HMAC_SHA1)
.addIntegrityAlgorithm(SaProposal.INTEGRITY_ALGORITHM_NONE)
.addIntegrityAlgorithm(SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96)
@@ -250,9 +262,9 @@ public final class SaProposalTest {
@Test
public void testBuildIkeProposalWithoutDhGroup() throws Exception {
+ Builder builder = Builder.newIkeSaProposalBuilder();
try {
- new IkeSaProposal.Builder()
- .addEncryptionAlgorithm(SaProposal.ENCRYPTION_ALGORITHM_3DES, KEY_LEN_UNUSED)
+ builder.addEncryptionAlgorithm(SaProposal.ENCRYPTION_ALGORITHM_3DES)
.addIntegrityAlgorithm(SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96)
.addPseudorandomFunction(SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC)
.build();
@@ -265,9 +277,9 @@ public final class SaProposalTest {
@Test
public void testBuildIkeProposalWithNoneValueDhGroup() throws Exception {
+ Builder builder = Builder.newIkeSaProposalBuilder();
try {
- new IkeSaProposal.Builder()
- .addEncryptionAlgorithm(SaProposal.ENCRYPTION_ALGORITHM_3DES, KEY_LEN_UNUSED)
+ builder.addEncryptionAlgorithm(SaProposal.ENCRYPTION_ALGORITHM_3DES)
.addIntegrityAlgorithm(SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96)
.addPseudorandomFunction(SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC)
.addDhGroup(SaProposal.DH_GROUP_1024_BIT_MODP)
@@ -280,6 +292,24 @@ public final class SaProposalTest {
}
}
+ // Test throwing exception when building first Child SA Proposal with not-none-value DH Group.
+ @Test
+ public void testBuildFirstChildProposalWithNotNoneValueDhGroup() throws Exception {
+ Builder builder = Builder.newChildSaProposalBuilder(true);
+ try {
+ builder.addEncryptionAlgorithm(SaProposal.ENCRYPTION_ALGORITHM_3DES)
+ .addIntegrityAlgorithm(SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96)
+ .addDhGroup(SaProposal.DH_GROUP_1024_BIT_MODP)
+ .build();
+
+ fail(
+ "Expected to fail when"
+ + " not-none-value DH Group is proposed in first Child SA proposal.");
+ } catch (IllegalArgumentException expected) {
+
+ }
+ }
+
@Test
public void testIsTransformSelectedFrom() throws Exception {
assertTrue(SaProposal.isTransformSelectedFrom(new Transform[0], new Transform[0]));
diff --git a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/crypto/IkeMacPrfTest.java b/tests/iketests/src/java/com/android/ike/ikev2/SaRecordTest.java
index 717886f7..5c61105c 100644
--- a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/crypto/IkeMacPrfTest.java
+++ b/tests/iketests/src/java/com/android/ike/ikev2/SaRecordTest.java
@@ -14,32 +14,15 @@
* limitations under the License.
*/
-package com.android.internal.net.ipsec.ike.crypto;
+package com.android.ike.ikev2;
import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertFalse;
-import android.net.ipsec.ike.SaProposal;
+import com.android.ike.ikev2.message.TestUtils;
-import com.android.internal.net.TestUtils;
-import com.android.internal.net.ipsec.ike.message.IkeMessage;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload.PrfTransform;
-
-import org.junit.Before;
import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-import java.util.Arrays;
-
-@RunWith(JUnit4.class)
-public final class IkeMacPrfTest {
-
- 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 =
- "D83B20CC6A0932B2A7CEF26E4020ABAAB64F0C6A";
+public final class SaRecordTest {
private static final String IKE_INIT_SPI = "5F54BF6D8B48E6E1";
private static final String IKE_RESP_SPI = "909232B3D1EDCB5C";
@@ -100,58 +83,24 @@ public final class IkeMacPrfTest {
private static final int FIRST_CHILD_AUTH_ALGO_KEY_LEN = 20;
private static final int FIRST_CHILD_ENCR_ALGO_KEY_LEN = 16;
- private IkeMacPrf mIkeHmacSha1Prf;
-
- @Before
- public void setUp() throws Exception {
- mIkeHmacSha1Prf =
- IkeMacPrf.create(
- new PrfTransform(SaProposal.PSEUDORANDOM_FUNCTION_HMAC_SHA1),
- IkeMessage.getSecurityProvider());
- }
-
- @Test
- public void testsignBytes() throws Exception {
- byte[] skpBytes = TestUtils.hexStringToByteArray(PRF_KEY_HEX_STRING);
- byte[] dataBytes = TestUtils.hexStringToByteArray(DATA_TO_SIGN_HEX_STRING);
-
- byte[] calculatedBytes = mIkeHmacSha1Prf.signBytes(skpBytes, dataBytes);
-
- byte[] expectedBytes = TestUtils.hexStringToByteArray(CALCULATED_MAC_HEX_STRING);
- assertArrayEquals(expectedBytes, calculatedBytes);
- }
+ private static final String PRF_HMAC_SHA1_ALGO_NAME = "HmacSHA1";
@Test
- public void testGenerateSKeySeed() throws Exception {
+ public void testCalculateSKeySeed() throws Exception {
byte[] nonceInit = TestUtils.hexStringToByteArray(IKE_NONCE_INIT_HEX_STRING);
byte[] nonceResp = TestUtils.hexStringToByteArray(IKE_NONCE_RESP_HEX_STRING);
byte[] sharedDhKey = TestUtils.hexStringToByteArray(IKE_SHARED_DH_KEY_HEX_STRING);
byte[] calculatedSKeySeed =
- mIkeHmacSha1Prf.generateSKeySeed(nonceInit, nonceResp, sharedDhKey);
+ SaRecord.generateSKeySeed(
+ PRF_HMAC_SHA1_ALGO_NAME, nonceInit, nonceResp, sharedDhKey);
byte[] expectedSKeySeed = TestUtils.hexStringToByteArray(IKE_SKEYSEED_HEX_STRING);
assertArrayEquals(expectedSKeySeed, calculatedSKeySeed);
}
@Test
- public void testGenerateRekeyedSKeySeed() throws Exception {
- byte[] nonceInit = TestUtils.hexStringToByteArray(IKE_NONCE_INIT_HEX_STRING);
- byte[] nonceResp = TestUtils.hexStringToByteArray(IKE_NONCE_RESP_HEX_STRING);
- byte[] sharedDhKey = TestUtils.hexStringToByteArray(IKE_SHARED_DH_KEY_HEX_STRING);
- byte[] old_skd = TestUtils.hexStringToByteArray(IKE_SK_D_HEX_STRING);
-
- byte[] calculatedSKeySeed =
- mIkeHmacSha1Prf.generateRekeyedSKeySeed(old_skd, nonceInit, nonceResp, sharedDhKey);
-
- // Verify that the new sKeySeed is different.
- // TODO: Find actual test vectors to test positive case.
- byte[] oldSKeySeed = TestUtils.hexStringToByteArray(IKE_SKEYSEED_HEX_STRING);
- assertFalse(Arrays.equals(oldSKeySeed, calculatedSKeySeed));
- }
-
- @Test
- public void testGenerateKeyMatForIke() throws Exception {
+ public void testSignWithPrfPlusForIke() throws Exception {
byte[] prfKey = TestUtils.hexStringToByteArray(IKE_SKEYSEED_HEX_STRING);
byte[] prfData =
TestUtils.hexStringToByteArray(
@@ -165,21 +114,23 @@ public final class IkeMacPrfTest {
+ IKE_ENCR_ALGO_KEY_LEN * 2
+ IKE_PRF_KEY_LEN * 2;
- byte[] calculatedKeyMat = mIkeHmacSha1Prf.generateKeyMat(prfKey, prfData, keyMaterialLen);
+ byte[] calculatedKeyMat =
+ SaRecord.generateKeyMat(PRF_HMAC_SHA1_ALGO_NAME, prfKey, prfData, keyMaterialLen);
byte[] expectedKeyMat = TestUtils.hexStringToByteArray(IKE_KEY_MAT);
assertArrayEquals(expectedKeyMat, calculatedKeyMat);
}
@Test
- public void testGenerateKeyMatForFirstChild() throws Exception {
+ public void testSignWithPrfPlusForFirstChild() throws Exception {
byte[] prfKey = TestUtils.hexStringToByteArray(IKE_SK_D_HEX_STRING);
byte[] prfData =
TestUtils.hexStringToByteArray(
IKE_NONCE_INIT_HEX_STRING + IKE_NONCE_RESP_HEX_STRING);
int keyMaterialLen = FIRST_CHILD_AUTH_ALGO_KEY_LEN * 2 + FIRST_CHILD_ENCR_ALGO_KEY_LEN * 2;
- byte[] calculatedKeyMat = mIkeHmacSha1Prf.generateKeyMat(prfKey, prfData, keyMaterialLen);
+ byte[] calculatedKeyMat =
+ SaRecord.generateKeyMat(PRF_HMAC_SHA1_ALGO_NAME, prfKey, prfData, keyMaterialLen);
byte[] expectedKeyMat = TestUtils.hexStringToByteArray(FIRST_CHILD_KEY_MAT);
assertArrayEquals(expectedKeyMat, calculatedKeyMat);
diff --git a/tests/iketests/src/java/com/android/ike/ikev2/message/IkeAuthDigitalSignPayloadTest.java b/tests/iketests/src/java/com/android/ike/ikev2/message/IkeAuthDigitalSignPayloadTest.java
new file mode 100644
index 00000000..a2c4d1f0
--- /dev/null
+++ b/tests/iketests/src/java/com/android/ike/ikev2/message/IkeAuthDigitalSignPayloadTest.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2019 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.ike.ikev2.message;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+public final class IkeAuthDigitalSignPayloadTest {
+
+ private static final String AUTH_PAYLOAD_BODY_GENERIC_DIGITAL_SIGN_HEX_STRING =
+ "0e0000000f300d06092a864886f70d01010b05007b2f4456878b1344e803f094"
+ + "159a59361bc639071b69de41915452c478b77a46ce4a2c96ddc7ba2c18d08406"
+ + "50ce51c77124605423a2f75d8ed4b5a1ec5944c3396221a39e25def09abe5c9f"
+ + "6d9cd70e8f6254d4c835015256c9d6c26f0c6d31ac96a2ed802ccb16e48e7ff3"
+ + "daf736221b18c2a972130a69edb197a505a312882baed95d38a47bf6784533f2"
+ + "ffee671d742b5ae463216e46ef970ee6a335ffb3fc9c170a680fb802bb950cb0"
+ + "5601339be8869a73f8f85254d792b6e91697d8893ccd34b5fb6aad6268c4ab0f"
+ + "9ead7b3f8a4a255e1b2eabfa3da0de284f3954cf49271918dd2d2db95c8e7812"
+ + "9aea77e5761ac5683a0b5af300ceb52f5e8d8168";
+ // TODO: Build a RSA_SHA1 signature and add tests for it.
+
+ @Test
+ public void testDecodeGenericDigitalSignPayload() throws Exception {
+ byte[] inputPacket =
+ TestUtils.hexStringToByteArray(AUTH_PAYLOAD_BODY_GENERIC_DIGITAL_SIGN_HEX_STRING);
+ IkeAuthPayload payload = IkeAuthPayload.getIkeAuthPayload(false, inputPacket);
+
+ assertTrue(payload instanceof IkeAuthDigitalSignPayload);
+ IkeAuthDigitalSignPayload dsPayload = (IkeAuthDigitalSignPayload) payload;
+ assertEquals(
+ IkeAuthDigitalSignPayload.SIGNATURE_ALGO_RSA_SHA2_256,
+ dsPayload.signatureAlgoAndHash);
+ }
+}
diff --git a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeAuthPayloadTest.java b/tests/iketests/src/java/com/android/ike/ikev2/message/IkeAuthPayloadTest.java
index 989b4689..7c630b76 100644
--- a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeAuthPayloadTest.java
+++ b/tests/iketests/src/java/com/android/ike/ikev2/message/IkeAuthPayloadTest.java
@@ -14,23 +14,17 @@
* limitations under the License.
*/
-package com.android.internal.net.ipsec.ike.message;
+package com.android.ike.ikev2.message;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import android.net.ipsec.ike.SaProposal;
-
-import com.android.internal.net.TestUtils;
-import com.android.internal.net.ipsec.ike.crypto.IkeMacPrf;
-import com.android.internal.net.ipsec.ike.exceptions.AuthenticationFailedException;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload.PrfTransform;
-
-import org.junit.Before;
import org.junit.Test;
+import javax.crypto.Mac;
+
public final class IkeAuthPayloadTest {
private static final String PSK_AUTH_PAYLOAD_HEX_STRING =
"02000000df7c038aefaaa32d3f44b228b52a332744dfb2c1";
@@ -84,15 +78,7 @@ public final class IkeAuthPayloadTest {
private static final int AUTH_METHOD_POSITION = 0;
- private IkeMacPrf mIkeHmacSha1Prf;
-
- @Before
- public void setUp() throws Exception {
- mIkeHmacSha1Prf =
- IkeMacPrf.create(
- new PrfTransform(SaProposal.PSEUDORANDOM_FUNCTION_HMAC_SHA1),
- IkeMessage.getSecurityProvider());
- }
+ private static final String PRF_HMAC_SHA1_ALGO_NAME = "HmacSHA1";
@Test
public void testDecodeIkeAuthPayload() throws Exception {
@@ -114,12 +100,26 @@ public final class IkeAuthPayloadTest {
try {
IkeAuthPayload payload = IkeAuthPayload.getIkeAuthPayload(false, inputPacket);
fail("Expected Exception: authentication method is not supported");
- } catch (AuthenticationFailedException e) {
+ } catch (UnsupportedOperationException e) {
+ // TODO: Catch AuthenticationFailedException after it is implemented.
}
}
@Test
+ public void testSignWithPrf() throws Exception {
+ Mac prfMac = Mac.getInstance(PRF_HMAC_SHA1_ALGO_NAME, IkeMessage.getSecurityProvider());
+ byte[] skpBytes = TestUtils.hexStringToByteArray(PSK_SKP_HEX_STRING);
+ byte[] idBytes = TestUtils.hexStringToByteArray(PSK_ID_PAYLOAD_HEX_STRING);
+ byte[] calculatedBytes = IkeAuthPayload.signWithPrf(prfMac, skpBytes, idBytes);
+
+ byte[] expectedBytes =
+ TestUtils.hexStringToByteArray(PSK_SIGNED_OCTETS_APPENDIX_HEX_STRING);
+ assertArrayEquals(expectedBytes, calculatedBytes);
+ }
+
+ @Test
public void testGetSignedOctets() throws Exception {
+ Mac prfMac = Mac.getInstance(PRF_HMAC_SHA1_ALGO_NAME, IkeMessage.getSecurityProvider());
byte[] skpBytes = TestUtils.hexStringToByteArray(PSK_SKP_HEX_STRING);
byte[] idBytes = TestUtils.hexStringToByteArray(PSK_ID_PAYLOAD_HEX_STRING);
byte[] ikeInitRequest = TestUtils.hexStringToByteArray(PSK_IKE_INIT_REQUEST_HEX_STRING);
@@ -127,7 +127,7 @@ public final class IkeAuthPayloadTest {
byte[] calculatedBytes =
IkeAuthPayload.getSignedOctets(
- ikeInitRequest, nonceResp, idBytes, mIkeHmacSha1Prf, skpBytes);
+ ikeInitRequest, nonceResp, idBytes, prfMac, skpBytes);
byte[] expectedBytes = TestUtils.hexStringToByteArray(PSK_INIT_SIGNED_OCTETS);
}
}
diff --git a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeAuthPskPayloadTest.java b/tests/iketests/src/java/com/android/ike/ikev2/message/IkeAuthPskPayloadTest.java
index cad60522..baa8059c 100644
--- a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeAuthPskPayloadTest.java
+++ b/tests/iketests/src/java/com/android/ike/ikev2/message/IkeAuthPskPayloadTest.java
@@ -14,25 +14,21 @@
* limitations under the License.
*/
-package com.android.internal.net.ipsec.ike.message;
+package com.android.ike.ikev2.message;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
-import android.net.ipsec.ike.SaProposal;
+import com.android.ike.ikev2.exceptions.AuthenticationFailedException;
-import com.android.internal.net.TestUtils;
-import com.android.internal.net.ipsec.ike.crypto.IkeMacPrf;
-import com.android.internal.net.ipsec.ike.exceptions.AuthenticationFailedException;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload.PrfTransform;
-
-import org.junit.Before;
import org.junit.Test;
import java.nio.ByteBuffer;
import java.util.Arrays;
+import javax.crypto.Mac;
+
public final class IkeAuthPskPayloadTest {
private static final String PSK_AUTH_PAYLOAD_HEX_STRING =
"2100001c02000000df7c038aefaaa32d3f44b228b52a332744dfb2c1";
@@ -66,6 +62,8 @@ public final class IkeAuthPskPayloadTest {
private static final String PSK_HEX_STRING = "6A756E69706572313233";
private static final String PSK_SKP_HEX_STRING = "094787780EE466E2CB049FA327B43908BC57E485";
+ private static final String PRF_HMAC_SHA1_ALGO_NAME = "HmacSHA1";
+
private static final byte[] PSK = TestUtils.hexStringToByteArray(PSK_HEX_STRING);
private static final byte[] IKE_INIT_REQUEST =
TestUtils.hexStringToByteArray(PSK_IKE_INIT_REQUEST_HEX_STRING);
@@ -76,21 +74,13 @@ public final class IkeAuthPskPayloadTest {
private static final byte[] SIGNATURE =
TestUtils.hexStringToByteArray(PSK_AUTH_PAYLOAD_SIGNATURE_HEX_STRING);
- private IkeMacPrf mIkeHmacSha1Prf;
-
- @Before
- public void setUp() throws Exception {
- mIkeHmacSha1Prf =
- IkeMacPrf.create(
- new PrfTransform(SaProposal.PSEUDORANDOM_FUNCTION_HMAC_SHA1),
- IkeMessage.getSecurityProvider());
- }
-
@Test
public void testBuildOutboundIkeAuthPskPayload() throws Exception {
+ Mac prfMac = Mac.getInstance(PRF_HMAC_SHA1_ALGO_NAME, IkeMessage.getSecurityProvider());
+
IkeAuthPskPayload payload =
new IkeAuthPskPayload(
- PSK, IKE_INIT_REQUEST, NONCE, ID_PAYLOAD_BODY, mIkeHmacSha1Prf, PRF_KEY);
+ PSK, IKE_INIT_REQUEST, NONCE, ID_PAYLOAD_BODY, prfMac, PRF_KEY);
assertEquals(IkeAuthPayload.AUTH_METHOD_PRE_SHARED_KEY, payload.authMethod);
assertArrayEquals(SIGNATURE, payload.signature);
@@ -122,21 +112,23 @@ public final class IkeAuthPskPayloadTest {
@Test
public void testVerifyReceivedSignature() throws Exception {
+ Mac prfMac = Mac.getInstance(PRF_HMAC_SHA1_ALGO_NAME, IkeMessage.getSecurityProvider());
IkeAuthPskPayload pskPayload = buildPskPayload();
pskPayload.verifyInboundSignature(
- PSK, IKE_INIT_REQUEST, NONCE, ID_PAYLOAD_BODY, mIkeHmacSha1Prf, PRF_KEY);
+ PSK, IKE_INIT_REQUEST, NONCE, ID_PAYLOAD_BODY, prfMac, PRF_KEY);
}
@Test
public void testVerifyReceivedSignatureFailure() throws Exception {
+ Mac prfMac = Mac.getInstance(PRF_HMAC_SHA1_ALGO_NAME, IkeMessage.getSecurityProvider());
IkeAuthPskPayload pskPayload = buildPskPayload();
byte[] nonce = Arrays.copyOf(NONCE, NONCE.length);
nonce[0]++;
try {
pskPayload.verifyInboundSignature(
- PSK, IKE_INIT_REQUEST, nonce, ID_PAYLOAD_BODY, mIkeHmacSha1Prf, PRF_KEY);
+ PSK, IKE_INIT_REQUEST, nonce, ID_PAYLOAD_BODY, prfMac, PRF_KEY);
fail("Expected signature verification to have failed due to mismatched signatures.");
} catch (AuthenticationFailedException expected) {
}
diff --git a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeCertX509CertPayloadTest.java b/tests/iketests/src/java/com/android/ike/ikev2/message/IkeCertX509CertPayloadTest.java
index ef6ec289..fcf5f555 100644
--- a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeCertX509CertPayloadTest.java
+++ b/tests/iketests/src/java/com/android/ike/ikev2/message/IkeCertX509CertPayloadTest.java
@@ -14,14 +14,13 @@
* limitations under the License.
*/
-package com.android.internal.net.ipsec.ike.message;
+package com.android.ike.ikev2.message;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import com.android.internal.net.TestUtils;
-import com.android.internal.net.ipsec.ike.exceptions.AuthenticationFailedException;
+import com.android.ike.ikev2.exceptions.AuthenticationFailedException;
import org.junit.Test;
diff --git a/tests/iketests/src/java/com/android/ike/ikev2/message/IkeDeletePayloadTest.java b/tests/iketests/src/java/com/android/ike/ikev2/message/IkeDeletePayloadTest.java
new file mode 100644
index 00000000..1a7b9a29
--- /dev/null
+++ b/tests/iketests/src/java/com/android/ike/ikev2/message/IkeDeletePayloadTest.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2019 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.ike.ikev2.message;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import com.android.ike.ikev2.exceptions.InvalidSyntaxException;
+
+import org.junit.Test;
+
+import java.nio.ByteBuffer;
+
+public final class IkeDeletePayloadTest {
+ private static final String DELETE_IKE_PAYLOAD_HEX_STRING = "0000000801000000";
+ private static final String DELETE_CHILD_PAYLOAD_HEX_STRING = "0000000c030400012ad4c0a2";
+ private static final String CHILD_SPI = "2ad4c0a2";
+
+ private static final int NUM_CHILD_SPI = 1;
+
+ private static final int PROTOCOL_ID_OFFSET = 4;
+ private static final int SPI_SIZE_OFFSET = 5;
+ private static final int NUM_OF_SPI_OFFSET = 6;
+
+ @Test
+ public void testDecodeDeleteIkePayload() throws Exception {
+ ByteBuffer inputBuffer =
+ ByteBuffer.wrap(TestUtils.hexStringToByteArray(DELETE_IKE_PAYLOAD_HEX_STRING));
+
+ IkePayload payload =
+ IkePayloadFactory.getIkePayload(
+ IkePayload.PAYLOAD_TYPE_DELETE, false /*is request*/, inputBuffer)
+ .first;
+
+ assertTrue(payload instanceof IkeDeletePayload);
+
+ IkeDeletePayload deletePayload = (IkeDeletePayload) payload;
+ assertEquals(IkePayload.PROTOCOL_ID_IKE, deletePayload.protocolId);
+ assertEquals(IkePayload.SPI_LEN_NOT_INCLUDED, deletePayload.spiSize);
+ assertEquals(0, deletePayload.numSpi);
+ assertArrayEquals(new int[0], deletePayload.spisToDelete);
+ }
+
+ @Test
+ public void testDecodeDeleteChildPayload() throws Exception {
+ ByteBuffer inputBuffer =
+ ByteBuffer.wrap(TestUtils.hexStringToByteArray(DELETE_CHILD_PAYLOAD_HEX_STRING));
+
+ IkePayload payload =
+ IkePayloadFactory.getIkePayload(
+ IkePayload.PAYLOAD_TYPE_DELETE, false /*is request*/, inputBuffer)
+ .first;
+
+ assertTrue(payload instanceof IkeDeletePayload);
+
+ IkeDeletePayload deletePayload = (IkeDeletePayload) payload;
+ assertEquals(IkePayload.PROTOCOL_ID_ESP, deletePayload.protocolId);
+ assertEquals(IkePayload.SPI_LEN_IPSEC, deletePayload.spiSize);
+ assertEquals(NUM_CHILD_SPI, deletePayload.numSpi);
+
+ byte[] childSpiBytes = TestUtils.hexStringToByteArray(CHILD_SPI);
+ ByteBuffer buffer = ByteBuffer.wrap(childSpiBytes);
+ int expectedChildSpi = buffer.getInt();
+
+ assertArrayEquals(new int[] {expectedChildSpi}, deletePayload.spisToDelete);
+ }
+
+ @Test
+ public void testDecodeWithInvalidProtocol() throws Exception {
+ byte[] deletePayloadBytes = TestUtils.hexStringToByteArray(DELETE_IKE_PAYLOAD_HEX_STRING);
+ deletePayloadBytes[PROTOCOL_ID_OFFSET] = -1;
+ ByteBuffer inputBuffer = ByteBuffer.wrap(deletePayloadBytes);
+
+ try {
+ IkePayloadFactory.getIkePayload(
+ IkePayload.PAYLOAD_TYPE_DELETE, false /*is request*/, inputBuffer);
+ fail("Expected to fail due to unrecognized protocol ID.");
+ } catch (InvalidSyntaxException expected) {
+
+ }
+ }
+
+ @Test
+ public void testDecodeWithInvalidSpiSize() throws Exception {
+ byte[] deletePayloadBytes = TestUtils.hexStringToByteArray(DELETE_IKE_PAYLOAD_HEX_STRING);
+ deletePayloadBytes[SPI_SIZE_OFFSET] = IkePayload.SPI_LEN_IPSEC;
+ ByteBuffer inputBuffer = ByteBuffer.wrap(deletePayloadBytes);
+
+ try {
+ IkePayloadFactory.getIkePayload(
+ IkePayload.PAYLOAD_TYPE_DELETE, false /*is request*/, inputBuffer);
+ fail("Expected to fail due to invalid SPI size in Delete IKE Payload.");
+ } catch (InvalidSyntaxException expected) {
+
+ }
+ }
+
+ @Test
+ public void testDecodeWithInvalidNumSpi() throws Exception {
+ byte[] deletePayloadBytes = TestUtils.hexStringToByteArray(DELETE_IKE_PAYLOAD_HEX_STRING);
+ deletePayloadBytes[NUM_OF_SPI_OFFSET] = 1;
+ ByteBuffer inputBuffer = ByteBuffer.wrap(deletePayloadBytes);
+
+ try {
+ IkePayloadFactory.getIkePayload(
+ IkePayload.PAYLOAD_TYPE_DELETE, false /*is request*/, inputBuffer);
+ fail("Expected to fail because number of SPI is not zero in Delete IKE Payload.");
+ } catch (InvalidSyntaxException expected) {
+
+ }
+ }
+
+ @Test
+ public void testDecodeWithInvalidNumSpiAndSpiSize() throws Exception {
+ byte[] deletePayloadBytes = TestUtils.hexStringToByteArray(DELETE_IKE_PAYLOAD_HEX_STRING);
+ deletePayloadBytes[SPI_SIZE_OFFSET] = 1;
+ deletePayloadBytes[NUM_CHILD_SPI] = 4;
+ ByteBuffer inputBuffer = ByteBuffer.wrap(deletePayloadBytes);
+
+ try {
+ IkePayloadFactory.getIkePayload(
+ IkePayload.PAYLOAD_TYPE_DELETE, false /*is request*/, inputBuffer);
+ fail("Expected to fail due to invalid SPI size in Delete IKE Payload.");
+ } catch (InvalidSyntaxException expected) {
+
+ }
+ }
+}
diff --git a/tests/iketests/src/java/com/android/ike/ikev2/message/IkeEncryptedPayloadBodyTest.java b/tests/iketests/src/java/com/android/ike/ikev2/message/IkeEncryptedPayloadBodyTest.java
new file mode 100644
index 00000000..fcb3eff6
--- /dev/null
+++ b/tests/iketests/src/java/com/android/ike/ikev2/message/IkeEncryptedPayloadBodyTest.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2019 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.ike.ikev2.message;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.security.GeneralSecurityException;
+import java.util.Arrays;
+
+import javax.crypto.Cipher;
+import javax.crypto.Mac;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+
+public final class IkeEncryptedPayloadBodyTest {
+
+ private static final String IKE_AUTH_INIT_REQUEST_HEADER =
+ "5f54bf6d8b48e6e1909232b3d1edcb5c2e20230800000001000000ec";
+ private static final String IKE_AUTH_INIT_REQUEST_SK_HEADER = "230000d0";
+ private static final String IKE_AUTH_INIT_REQUEST_IV = "b9132b7bb9f658dfdc648e5017a6322a";
+ private static final String IKE_AUTH_INIT_REQUEST_ENCRYPT_PADDED_DATA =
+ "030c316ce55f365760d46426ce5cfc78bd1ed9abff63eb9594c1bd58"
+ + "46de333ecd3ea2b705d18293b130395300ba92a351041345"
+ + "0a10525cea51b2753b4e92b081fd78d995659a98f742278f"
+ + "f9b8fd3e21554865c15c79a5134d66b2744966089e416c60"
+ + "a274e44a9a3f084eb02f3bdce1e7de9de8d9a62773ab563b"
+ + "9a69ba1db03c752acb6136452b8a86c41addb4210d68c423"
+ + "efed80e26edca5fa3fe5d0a5ca9375ce332c474b93fb1fa3"
+ + "59eb4e81";
+ private static final String IKE_AUTH_INIT_REQUEST_CHECKSUM = "ae6e0f22abdad69ba8007d50";
+
+ private static final String IKE_AUTH_INIT_REQUEST_UNENCRYPTED_DATA =
+ "2400000c010000000a50500d2700000c010000000a505050"
+ + "2100001c02000000df7c038aefaaa32d3f44b228b52a3327"
+ + "44dfb2c12c00002c00000028010304032ad4c0a20300000c"
+ + "0100000c800e008003000008030000020000000805000000"
+ + "2d00001801000000070000100000ffff00000000ffffffff"
+ + "2900001801000000070000100000ffff00000000ffffffff"
+ + "29000008000040000000000c0000400100000001";
+ private static final String IKE_AUTH_INIT_REQUEST_PADDING = "0000000000000000000000";
+ private static final int HMAC_SHA1_CHECKSUM_LEN = 12;
+
+ private static final String ENCR_KEY_FROM_INIT_TO_RESP = "5cbfd33f75796c0188c4a3a546aec4a1";
+ private static final String INTE_KEY_FROM_INIT_TO_RESP =
+ "554fbf5a05b7f511e05a30ce23d874db9ef55e51";
+
+ private static final String ENCR_ALGO_AES_CBC = "AES/CBC/NoPadding";
+ private static final String INTE_ALGO_HMAC_SHA1 = "HmacSHA1";
+
+ private Cipher mAesCbcCipher;
+ private SecretKey mAesCbcKey;
+ private Mac mHmacSha1IntegrityMac;
+
+ private byte[] mDataToPadAndEncrypt;
+ private byte[] mDataToAuthenticate;
+ private byte[] mEncryptedPaddedData;
+ private byte[] mIkeMessage;
+
+ private byte[] mChecksum;
+ private byte[] mIv;
+ private byte[] mPadding;
+
+ // TODO: Add tests for authenticating and decrypting received message.
+ @Before
+ public void setUp() throws Exception {
+ mDataToPadAndEncrypt =
+ TestUtils.hexStringToByteArray(IKE_AUTH_INIT_REQUEST_UNENCRYPTED_DATA);
+ String hexStringToAuthenticate =
+ IKE_AUTH_INIT_REQUEST_HEADER
+ + IKE_AUTH_INIT_REQUEST_SK_HEADER
+ + IKE_AUTH_INIT_REQUEST_IV
+ + IKE_AUTH_INIT_REQUEST_ENCRYPT_PADDED_DATA;
+ mDataToAuthenticate = TestUtils.hexStringToByteArray(hexStringToAuthenticate);
+ mEncryptedPaddedData =
+ TestUtils.hexStringToByteArray(IKE_AUTH_INIT_REQUEST_ENCRYPT_PADDED_DATA);
+ mIkeMessage =
+ TestUtils.hexStringToByteArray(
+ IKE_AUTH_INIT_REQUEST_HEADER
+ + IKE_AUTH_INIT_REQUEST_SK_HEADER
+ + IKE_AUTH_INIT_REQUEST_IV
+ + IKE_AUTH_INIT_REQUEST_ENCRYPT_PADDED_DATA
+ + IKE_AUTH_INIT_REQUEST_CHECKSUM);
+
+ mChecksum = TestUtils.hexStringToByteArray(IKE_AUTH_INIT_REQUEST_CHECKSUM);
+ mIv = TestUtils.hexStringToByteArray(IKE_AUTH_INIT_REQUEST_IV);
+ mPadding = TestUtils.hexStringToByteArray(IKE_AUTH_INIT_REQUEST_PADDING);
+
+ mAesCbcCipher = Cipher.getInstance(ENCR_ALGO_AES_CBC, IkeMessage.getSecurityProvider());
+ byte[] encryptKeyBytes = TestUtils.hexStringToByteArray(ENCR_KEY_FROM_INIT_TO_RESP);
+ mAesCbcKey = new SecretKeySpec(encryptKeyBytes, ENCR_ALGO_AES_CBC);
+
+ mHmacSha1IntegrityMac =
+ Mac.getInstance(INTE_ALGO_HMAC_SHA1, IkeMessage.getSecurityProvider());
+ byte[] integrityKeyBytes = TestUtils.hexStringToByteArray(INTE_KEY_FROM_INIT_TO_RESP);
+ SecretKeySpec integrityKey = new SecretKeySpec(integrityKeyBytes, INTE_ALGO_HMAC_SHA1);
+ mHmacSha1IntegrityMac.init(integrityKey);
+ }
+
+ @Test
+ public void testCalculateChecksum() throws Exception {
+ byte[] calculatedChecksum =
+ IkeEncryptedPayloadBody.calculateChecksum(
+ mDataToAuthenticate, mHmacSha1IntegrityMac, HMAC_SHA1_CHECKSUM_LEN);
+
+ assertArrayEquals(mChecksum, calculatedChecksum);
+ }
+
+ @Test
+ public void testValidateChecksum() throws Exception {
+ IkeEncryptedPayloadBody.validateChecksumOrThrow(
+ mDataToAuthenticate, mHmacSha1IntegrityMac, mChecksum);
+ }
+
+ @Test
+ public void testThrowForInvalidChecksum() throws Exception {
+ byte[] dataToAuthenticate = Arrays.copyOf(mDataToAuthenticate, mDataToAuthenticate.length);
+ dataToAuthenticate[0]++;
+
+ try {
+ IkeEncryptedPayloadBody.validateChecksumOrThrow(
+ dataToAuthenticate, mHmacSha1IntegrityMac, mChecksum);
+ fail("Expected GeneralSecurityException due to mismatched checksum.");
+ } catch (GeneralSecurityException expected) {
+ }
+ }
+
+ @Test
+ public void testCalculatePaddingPlaintextShorterThanBlockSize() throws Exception {
+ int blockSize = 16;
+ int plainTextLength = 15;
+ int expectedPadLength = 0;
+
+ byte[] calculatedPadding =
+ IkeEncryptedPayloadBody.calculatePadding(plainTextLength, blockSize);
+ assertEquals(expectedPadLength, calculatedPadding.length);
+ }
+
+ @Test
+ public void testCalculatePaddingPlaintextInBlockSize() throws Exception {
+ int blockSize = 16;
+ int plainTextLength = 16;
+ int expectedPadLength = 15;
+
+ byte[] calculatedPadding =
+ IkeEncryptedPayloadBody.calculatePadding(plainTextLength, blockSize);
+ assertEquals(expectedPadLength, calculatedPadding.length);
+ }
+
+ @Test
+ public void testCalculatePaddingPlaintextLongerThanBlockSize() throws Exception {
+ int blockSize = 16;
+ int plainTextLength = 17;
+ int expectedPadLength = 14;
+
+ byte[] calculatedPadding =
+ IkeEncryptedPayloadBody.calculatePadding(plainTextLength, blockSize);
+ assertEquals(expectedPadLength, calculatedPadding.length);
+ }
+
+ @Test
+ public void testEncrypt() throws Exception {
+ byte[] calculatedData =
+ IkeEncryptedPayloadBody.encrypt(
+ mDataToPadAndEncrypt, mAesCbcCipher, mAesCbcKey, mIv, mPadding);
+
+ assertArrayEquals(mEncryptedPaddedData, calculatedData);
+ }
+
+ @Test
+ public void testDecrypt() throws Exception {
+ byte[] calculatedPlainText =
+ IkeEncryptedPayloadBody.decrypt(
+ mEncryptedPaddedData, mAesCbcCipher, mAesCbcKey, mIv);
+
+ assertArrayEquals(mDataToPadAndEncrypt, calculatedPlainText);
+ }
+
+ @Test
+ public void testBuildAndEncodeOutboundIkeEncryptedPayloadBody() throws Exception {
+ IkeHeader ikeHeader = new IkeHeader(mIkeMessage);
+
+ IkeEncryptedPayloadBody paylaodBody =
+ new IkeEncryptedPayloadBody(
+ ikeHeader,
+ IkePayload.PAYLOAD_TYPE_ID_INITIATOR,
+ mDataToPadAndEncrypt,
+ mHmacSha1IntegrityMac,
+ HMAC_SHA1_CHECKSUM_LEN,
+ mAesCbcCipher,
+ mAesCbcKey,
+ mIv,
+ mPadding);
+
+ byte[] expectedEncodedData =
+ TestUtils.hexStringToByteArray(
+ IKE_AUTH_INIT_REQUEST_IV
+ + IKE_AUTH_INIT_REQUEST_ENCRYPT_PADDED_DATA
+ + IKE_AUTH_INIT_REQUEST_CHECKSUM);
+ assertArrayEquals(expectedEncodedData, paylaodBody.encode());
+ }
+
+ @Test
+ public void testAuthenticateAndDecryptInboundIkeEncryptedPayloadBody() throws Exception {
+ IkeEncryptedPayloadBody paylaodBody =
+ new IkeEncryptedPayloadBody(
+ mIkeMessage,
+ mHmacSha1IntegrityMac,
+ HMAC_SHA1_CHECKSUM_LEN,
+ mAesCbcCipher,
+ mAesCbcKey);
+
+ assertArrayEquals(mDataToPadAndEncrypt, paylaodBody.getUnencryptedData());
+ }
+}
diff --git a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeHeaderTest.java b/tests/iketests/src/java/com/android/ike/ikev2/message/IkeHeaderTest.java
index 4592815d..08b1612b 100644
--- a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeHeaderTest.java
+++ b/tests/iketests/src/java/com/android/ike/ikev2/message/IkeHeaderTest.java
@@ -14,16 +14,16 @@
* limitations under the License.
*/
-package com.android.internal.net.ipsec.ike.message;
+package com.android.ike.ikev2.message;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
-import com.android.internal.net.TestUtils;
-import com.android.internal.net.ipsec.ike.exceptions.InvalidMajorVersionException;
-import com.android.internal.net.ipsec.ike.exceptions.InvalidSyntaxException;
+import com.android.ike.ikev2.exceptions.InvalidMajorVersionException;
+import com.android.ike.ikev2.exceptions.InvalidSyntaxException;
import org.junit.Test;
@@ -100,12 +100,15 @@ public final class IkeHeaderTest {
inputPacket[VERSION_OFFSET] = (byte) 0x30;
// Set Exchange type 0
inputPacket[EXCHANGE_TYPE_OFFSET] = (byte) 0x00;
-
- InvalidMajorVersionException exception =
- IkeTestUtils.decodeAndVerifyUnprotectedErrorMsg(
- inputPacket, InvalidMajorVersionException.class);
-
- assertEquals(3, exception.getMajorVerion());
+ IkeHeader header = new IkeHeader(inputPacket);
+ try {
+ IkeMessage.decode(header, inputPacket);
+ fail(
+ "Expected InvalidMajorVersionException: major version is 3"
+ + "and exchange type is 0");
+ } catch (InvalidMajorVersionException expected) {
+ assertEquals(3, expected.receivedMajorVersion);
+ }
}
@Test
@@ -113,8 +116,12 @@ public final class IkeHeaderTest {
byte[] inputPacket = TestUtils.hexStringToByteArray(IKE_SA_INIT_RAW_PACKET);
// Set Exchange type 0
inputPacket[EXCHANGE_TYPE_OFFSET] = (byte) 0x00;
-
- IkeTestUtils.decodeAndVerifyUnprotectedErrorMsg(inputPacket, InvalidSyntaxException.class);
+ IkeHeader header = new IkeHeader(inputPacket);
+ try {
+ IkeMessage.decode(header, inputPacket);
+ fail("Expected InvalidSyntaxException: exchange type is 0");
+ } catch (InvalidSyntaxException expected) {
+ }
}
@Test
@@ -122,8 +129,12 @@ public final class IkeHeaderTest {
byte[] inputPacket = TestUtils.hexStringToByteArray(IKE_SA_INIT_RAW_PACKET);
// Set Exchange type 0
inputPacket[MESSAGE_LENGTH_OFFSET] = (byte) 0x01;
-
- IkeTestUtils.decodeAndVerifyUnprotectedErrorMsg(inputPacket, InvalidSyntaxException.class);
+ IkeHeader header = new IkeHeader(inputPacket);
+ try {
+ IkeMessage.decode(header, inputPacket);
+ fail("Expected InvalidSyntaxException: IKE message length.");
+ } catch (InvalidSyntaxException expected) {
+ }
}
@Test
diff --git a/tests/iketests/src/java/com/android/ike/ikev2/message/IkeIdPayloadTest.java b/tests/iketests/src/java/com/android/ike/ikev2/message/IkeIdPayloadTest.java
new file mode 100644
index 00000000..893857a8
--- /dev/null
+++ b/tests/iketests/src/java/com/android/ike/ikev2/message/IkeIdPayloadTest.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2018 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.ike.ikev2.message;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import com.android.ike.ikev2.IkeIdentification;
+import com.android.ike.ikev2.IkeIdentification.IkeIpv4AddrIdentification;
+import com.android.ike.ikev2.IkeIdentification.IkeIpv6AddrIdentification;
+import com.android.ike.ikev2.exceptions.AuthenticationFailedException;
+
+import org.junit.Test;
+
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.nio.ByteBuffer;
+
+public final class IkeIdPayloadTest {
+
+ private static final String IPV4_ADDR_ID_PAYLOAD_RESPONDER_HEX_STRING =
+ "2700000c01000000c0000264";
+ private static final String IPV4_ADDR_ID_PAYLOAD_RESPONDER_BODY_HEX_STRING = "01000000c0000264";
+ private static final String IPV4_ADDR_STRING = "192.0.2.100";
+
+ private static final String IPV6_ADDR_ID_PAYLOAD_RESPONDER_HEX_STRING =
+ "27000018050000000000200100000db80000000000000001";
+ private static final String IPV6_ADDR_ID_PAYLOAD_RESPONDER_BODY_HEX_STRING =
+ "050000000000200100000db80000000000000001";
+ private static final String IPV6_ADDR_STRING = "0:2001:0:db8::1";
+
+ private static final int ID_TYPE_OFFSET = 0;
+
+ @Test
+ public void testDecodeIpv4AddrIdPayload() throws Exception {
+ byte[] inputPacket =
+ TestUtils.hexStringToByteArray(IPV4_ADDR_ID_PAYLOAD_RESPONDER_BODY_HEX_STRING);
+ IkeIdPayload payload = new IkeIdPayload(false, inputPacket, false);
+
+ assertEquals(IkePayload.PAYLOAD_TYPE_ID_RESPONDER, payload.payloadType);
+ assertEquals(IkeIdentification.ID_TYPE_IPV4_ADDR, payload.ikeId.idType);
+ IkeIpv4AddrIdentification ikeId = (IkeIpv4AddrIdentification) payload.ikeId;
+ Inet4Address expectedAddr = (Inet4Address) Inet4Address.getByName(IPV4_ADDR_STRING);
+ assertEquals(expectedAddr, ikeId.ipv4Address);
+ }
+
+ @Test
+ public void testDecodeIpv6AddrIdPayload() throws Exception {
+ byte[] inputPacket =
+ TestUtils.hexStringToByteArray(IPV6_ADDR_ID_PAYLOAD_RESPONDER_BODY_HEX_STRING);
+ IkeIdPayload payload = new IkeIdPayload(false, inputPacket, false);
+
+ assertEquals(IkePayload.PAYLOAD_TYPE_ID_RESPONDER, payload.payloadType);
+ assertEquals(IkeIdentification.ID_TYPE_IPV6_ADDR, payload.ikeId.idType);
+ IkeIpv6AddrIdentification ikeId = (IkeIpv6AddrIdentification) payload.ikeId;
+ Inet6Address expectedAddr = (Inet6Address) Inet6Address.getByName(IPV6_ADDR_STRING);
+ assertEquals(expectedAddr, ikeId.ipv6Address);
+ }
+
+ @Test
+ public void testDecodeUnsupportedIdType() throws Exception {
+ byte[] inputPacket =
+ TestUtils.hexStringToByteArray(IPV4_ADDR_ID_PAYLOAD_RESPONDER_BODY_HEX_STRING);
+ inputPacket[ID_TYPE_OFFSET] = 0;
+
+ try {
+ new IkeIdPayload(false, inputPacket, true);
+ fail("Expected AuthenticationFailedException: ID Type is unsupported.");
+ } catch (AuthenticationFailedException expected) {
+ }
+ }
+
+ @Test
+ public void testConstructAndEncodeIpv4AddrIdPayload() throws Exception {
+ Inet4Address ipv4Address = (Inet4Address) Inet4Address.getByName(IPV4_ADDR_STRING);
+ IkeIdPayload payload = new IkeIdPayload(false, new IkeIpv4AddrIdentification(ipv4Address));
+
+ ByteBuffer inputBuffer = ByteBuffer.allocate(payload.getPayloadLength());
+ payload.encodeToByteBuffer(IkePayload.PAYLOAD_TYPE_AUTH, inputBuffer);
+
+ byte[] expectedBytes =
+ TestUtils.hexStringToByteArray(IPV4_ADDR_ID_PAYLOAD_RESPONDER_HEX_STRING);
+ assertArrayEquals(expectedBytes, inputBuffer.array());
+ }
+
+ @Test
+ public void testConstructAndEncodeIpv6AddrIdPayload() throws Exception {
+ Inet6Address ipv6Address = (Inet6Address) Inet6Address.getByName(IPV6_ADDR_STRING);
+ IkeIdPayload payload = new IkeIdPayload(false, new IkeIpv6AddrIdentification(ipv6Address));
+
+ ByteBuffer inputBuffer = ByteBuffer.allocate(payload.getPayloadLength());
+ payload.encodeToByteBuffer(IkePayload.PAYLOAD_TYPE_AUTH, inputBuffer);
+
+ byte[] expectedBytes =
+ TestUtils.hexStringToByteArray(IPV6_ADDR_ID_PAYLOAD_RESPONDER_HEX_STRING);
+ assertArrayEquals(expectedBytes, inputBuffer.array());
+ }
+}
diff --git a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeKePayloadTest.java b/tests/iketests/src/java/com/android/ike/ikev2/message/IkeKePayloadTest.java
index f5046dca..1bb0b709 100644
--- a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeKePayloadTest.java
+++ b/tests/iketests/src/java/com/android/ike/ikev2/message/IkeKePayloadTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.internal.net.ipsec.ike.message;
+package com.android.ike.ikev2.message;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
@@ -22,19 +22,15 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import android.net.ipsec.ike.SaProposal;
+import com.android.ike.ikev2.IkeDhParams;
+import com.android.ike.ikev2.SaProposal;
+import com.android.ike.ikev2.exceptions.InvalidSyntaxException;
+import com.android.ike.ikev2.utils.BigIntegerUtils;
-import com.android.internal.net.TestUtils;
-import com.android.internal.net.ipsec.ike.IkeDhParams;
-import com.android.internal.net.ipsec.ike.exceptions.InvalidSyntaxException;
-import com.android.internal.net.utils.BigIntegerUtils;
-
-import org.junit.Before;
import org.junit.Test;
import java.math.BigInteger;
import java.nio.ByteBuffer;
-import java.security.GeneralSecurityException;
import java.util.Arrays;
import javax.crypto.spec.DHPrivateKeySpec;
@@ -97,19 +93,6 @@ public final class IkeKePayloadTest {
+ "F408ED31B63C6E6D";
private static final String KEY_EXCHANGE_ALGORITHM = "DH";
- private DHPrivateKeySpec mPrivateKeySpec;
-
- @Before
- public void setUp() throws Exception {
- BigInteger primeValue =
- BigIntegerUtils.unsignedHexStringToBigInteger(PRIME_1024_BIT_MODP_160_SUBGROUP);
- BigInteger baseGenValue =
- BigIntegerUtils.unsignedHexStringToBigInteger(GENERATOR_1024_BIT_MODP_160_SUBGROUP);
- BigInteger privateKeyValue =
- BigIntegerUtils.unsignedHexStringToBigInteger(PRIVATE_KEY_LOCAL);
- mPrivateKeySpec = new DHPrivateKeySpec(privateKeyValue, primeValue, baseGenValue);
- }
-
@Test
public void testDecodeIkeKePayload() throws Exception {
byte[] inputPacket = TestUtils.hexStringToByteArray(KE_PAYLOAD_RAW_PACKET);
@@ -180,21 +163,19 @@ public final class IkeKePayloadTest {
// recipient test in real Key Exchange process. But it is suitable for testing.
@Test
public void testGetSharedkey() throws Exception {
+ BigInteger primeValue =
+ BigIntegerUtils.unsignedHexStringToBigInteger(PRIME_1024_BIT_MODP_160_SUBGROUP);
+ BigInteger baseGenValue =
+ BigIntegerUtils.unsignedHexStringToBigInteger(GENERATOR_1024_BIT_MODP_160_SUBGROUP);
+ BigInteger privateKeyValue =
+ BigIntegerUtils.unsignedHexStringToBigInteger(PRIVATE_KEY_LOCAL);
byte[] remotePublicKey = TestUtils.hexStringToByteArray(PUBLIC_KEY_REMOTE);
- byte[] sharedKeyBytes = IkeKePayload.getSharedKey(mPrivateKeySpec, remotePublicKey);
+
+ DHPrivateKeySpec privateKeySpec =
+ new DHPrivateKeySpec(privateKeyValue, primeValue, baseGenValue);
+ byte[] sharedKeyBytes = IkeKePayload.getSharedKey(privateKeySpec, remotePublicKey);
byte[] expectedSharedKeyBytes = TestUtils.hexStringToByteArray(EXPECTED_SHARED_KEY);
assertTrue(Arrays.equals(expectedSharedKeyBytes, sharedKeyBytes));
}
-
- @Test
- public void testGetSharedkeyWithInvalidRemoteKey() throws Exception {
- byte[] remotePublicKey = TestUtils.hexStringToByteArray(PRIME_1024_BIT_MODP_160_SUBGROUP);
-
- try {
- byte[] sharedKeyBytes = IkeKePayload.getSharedKey(mPrivateKeySpec, remotePublicKey);
- fail("Expected to fail because of invalid remote public key.");
- } catch (GeneralSecurityException expected) {
- }
- }
}
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
new file mode 100644
index 00000000..961abb30
--- /dev/null
+++ b/tests/iketests/src/java/com/android/ike/ikev2/message/IkeMessageTest.java
@@ -0,0 +1,218 @@
+/*
+ * Copyright (C) 2018 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.ike.ikev2.message;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import com.android.ike.ikev2.exceptions.IkeException;
+import com.android.ike.ikev2.exceptions.InvalidSyntaxException;
+import com.android.ike.ikev2.exceptions.UnsupportedCriticalPayloadException;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.nio.ByteBuffer;
+
+public final class IkeMessageTest {
+ private static final String IKE_SA_INIT_HEADER_RAW_PACKET =
+ "8f54bf6d8b48e6e10000000000000000212022080000000000000150";
+ private static final String IKE_SA_INIT_BODY_RAW_PACKET =
+ "220000300000002c010100040300000c0100000c"
+ + "800e00800300000803000002030000080400000200000008"
+ + "020000022800008800020000b4a2faf4bb54878ae21d6385"
+ + "12ece55d9236fc5046ab6cef82220f421f3ce6361faf3656"
+ + "4ecb6d28798a94aad7b2b4b603ddeaaa5630adb9ece8ac37"
+ + "534036040610ebdd92f46bef84f0be7db860351843858f8a"
+ + "cf87056e272377f70c9f2d81e29c7b0ce4f291a3a72476bb"
+ + "0b278fd4b7b0a4c26bbeb08214c707137607958729000024"
+ + "c39b7f368f4681b89fa9b7be6465abd7c5f68b6ed5d3b4c7"
+ + "2cb4240eb5c464122900001c00004004e54f73b7d83f6beb"
+ + "881eab2051d8663f421d10b02b00001c00004005d915368c"
+ + "a036004cb578ae3e3fb268509aeab1900000002069936922"
+ + "8741c6d4ca094c93e242c9de19e7b7c60000000500000500";
+ private static final String IKE_SA_INIT_RAW_PACKET =
+ IKE_SA_INIT_HEADER_RAW_PACKET + IKE_SA_INIT_BODY_RAW_PACKET;
+
+ // Byte offsets of first payload type in IKE message header.
+ private static final int FIRST_PAYLOAD_TYPE_OFFSET = 16;
+ // Byte offsets of first payload's critical bit in IKE message body.
+ private static final int PAYLOAD_CRITICAL_BIT_OFFSET = 1;
+ // Byte offsets of first payload length in IKE message body.
+ private static final int FIRST_PAYLOAD_LENGTH_OFFSET = 2;
+ // Byte offsets of last payload length in IKE message body.
+ private static final int LAST_PAYLOAD_LENGTH_OFFSET = 278;
+
+ private static final int[] SUPPORTED_PAYLOAD_LIST = {
+ IkePayload.PAYLOAD_TYPE_SA,
+ IkePayload.PAYLOAD_TYPE_KE,
+ IkePayload.PAYLOAD_TYPE_NONCE,
+ IkePayload.PAYLOAD_TYPE_NOTIFY,
+ IkePayload.PAYLOAD_TYPE_NOTIFY,
+ IkePayload.PAYLOAD_TYPE_VENDOR
+ };
+
+ class TestIkeSupportedPayload extends IkePayload {
+ TestIkeSupportedPayload(int payload, boolean critical) {
+ super(payload, critical);
+ }
+
+ @Override
+ protected void encodeToByteBuffer(@PayloadType int nextPayload, ByteBuffer byteBuffer) {
+ throw new UnsupportedOperationException(
+ "It is not supported to encode " + getTypeString());
+ }
+
+ @Override
+ protected int getPayloadLength() {
+ throw new UnsupportedOperationException(
+ "It is not supported to get payload length of " + getTypeString());
+ }
+
+ @Override
+ public String getTypeString() {
+ return "Test Payload";
+ }
+ }
+
+ @Before
+ public void setUp() {
+ IkePayloadFactory.sDecoderInstance =
+ new IkePayloadFactory.IIkePayloadDecoder() {
+
+ @Override
+ public IkePayload decodeIkePayload(
+ int payloadType, boolean isCritical, boolean isResp, byte[] payloadBody)
+ throws IkeException {
+ if (support(payloadType)) {
+ return new TestIkeSupportedPayload(payloadType, isCritical);
+ } else {
+ return new IkeUnsupportedPayload(payloadType, isCritical);
+ }
+ }
+ };
+ }
+
+ @After
+ public void tearDown() {
+ IkePayloadFactory.sDecoderInstance = new IkePayloadFactory.IkePayloadDecoder();
+ }
+
+ @Test
+ public void testDecodeIkeMessage() throws Exception {
+ byte[] inputPacket = TestUtils.hexStringToByteArray(IKE_SA_INIT_RAW_PACKET);
+ IkeHeader header = new IkeHeader(inputPacket);
+ IkeMessage message = IkeMessage.decode(header, inputPacket);
+ assertEquals(SUPPORTED_PAYLOAD_LIST.length, message.ikePayloadList.size());
+ for (int i = 0; i < SUPPORTED_PAYLOAD_LIST.length; i++) {
+ assertEquals(SUPPORTED_PAYLOAD_LIST[i], message.ikePayloadList.get(i).payloadType);
+ }
+ }
+
+ @Test
+ public void testDecodeMessageWithUnsupportedUncriticalPayload() throws Exception {
+ byte[] inputPacket = TestUtils.hexStringToByteArray(IKE_SA_INIT_RAW_PACKET);
+ // Set first payload unsupported uncritical
+ inputPacket[FIRST_PAYLOAD_TYPE_OFFSET] = (byte) 0xff;
+ IkeHeader header = new IkeHeader(inputPacket);
+ IkeMessage message = IkeMessage.decode(header, inputPacket);
+ assertEquals(SUPPORTED_PAYLOAD_LIST.length - 1, message.ikePayloadList.size());
+ for (int i = 0; i < SUPPORTED_PAYLOAD_LIST.length - 1; i++) {
+ assertEquals(SUPPORTED_PAYLOAD_LIST[i + 1], message.ikePayloadList.get(i).payloadType);
+ }
+ }
+
+ @Test
+ public void testThrowUnsupportedCriticalPayloadException() throws Exception {
+ byte[] inputPacket = TestUtils.hexStringToByteArray(IKE_SA_INIT_RAW_PACKET);
+ // Set first payload unsupported critical
+ inputPacket[FIRST_PAYLOAD_TYPE_OFFSET] = (byte) 0xff;
+ inputPacket[IkeHeader.IKE_HEADER_LENGTH + PAYLOAD_CRITICAL_BIT_OFFSET] = (byte) 0x80;
+
+ IkeHeader header = new IkeHeader(inputPacket);
+ try {
+ IkeMessage.decode(header, inputPacket);
+ fail(
+ "Expected UnsupportedCriticalPayloadException: first"
+ + "payload is unsupported critical.");
+ } catch (UnsupportedCriticalPayloadException expected) {
+ assertEquals(1, expected.payloadTypeList.size());
+ }
+ }
+
+ @Test
+ public void testDecodeMessageWithTooShortPayloadLength() throws Exception {
+ byte[] inputPacket = TestUtils.hexStringToByteArray(IKE_SA_INIT_RAW_PACKET);
+ // Set first payload length to 0
+ inputPacket[IkeHeader.IKE_HEADER_LENGTH + FIRST_PAYLOAD_LENGTH_OFFSET] = (byte) 0;
+ inputPacket[IkeHeader.IKE_HEADER_LENGTH + FIRST_PAYLOAD_LENGTH_OFFSET + 1] = (byte) 0;
+ IkeHeader header = new IkeHeader(inputPacket);
+ try {
+ IkeMessage message = IkeMessage.decode(header, inputPacket);
+ fail("Expected InvalidSyntaxException: Payload length is too short.");
+ } catch (InvalidSyntaxException expected) {
+ }
+ }
+
+ @Test
+ public void testDecodeMessageWithTooLongPayloadLength() throws Exception {
+ byte[] inputPacket = TestUtils.hexStringToByteArray(IKE_SA_INIT_RAW_PACKET);
+ // Increase last payload length by one byte
+ inputPacket[IkeHeader.IKE_HEADER_LENGTH + LAST_PAYLOAD_LENGTH_OFFSET]++;
+ IkeHeader header = new IkeHeader(inputPacket);
+ try {
+ IkeMessage message = IkeMessage.decode(header, inputPacket);
+ fail("Expected InvalidSyntaxException: Payload length is too long.");
+ } catch (InvalidSyntaxException expected) {
+ }
+ }
+
+ @Test
+ public void testDecodeMessageWithExpectedBytesInTheEnd() throws Exception {
+ byte[] inputPacket = TestUtils.hexStringToByteArray(IKE_SA_INIT_RAW_PACKET + "0000");
+ IkeHeader header = new IkeHeader(inputPacket);
+ try {
+ IkeMessage message = IkeMessage.decode(header, inputPacket);
+ fail("Expected InvalidSyntaxException: Unexpected bytes in the end of packet.");
+ } catch (InvalidSyntaxException expected) {
+ }
+ }
+
+ private boolean support(int payloadType) {
+ return (payloadType == IkePayload.PAYLOAD_TYPE_SA
+ || payloadType == IkePayload.PAYLOAD_TYPE_KE
+ || payloadType == IkePayload.PAYLOAD_TYPE_NONCE
+ || payloadType == IkePayload.PAYLOAD_TYPE_NOTIFY
+ || payloadType == IkePayload.PAYLOAD_TYPE_VENDOR
+ || payloadType == IkePayload.PAYLOAD_TYPE_SK);
+ }
+
+ @Test
+ public void testAttachEncodedHeader() throws Exception {
+ byte[] inputPacket = TestUtils.hexStringToByteArray(IKE_SA_INIT_RAW_PACKET);
+ byte[] ikeBodyBytes = TestUtils.hexStringToByteArray(IKE_SA_INIT_BODY_RAW_PACKET);
+ IkeHeader header = new IkeHeader(inputPacket);
+ IkeMessage message = IkeMessage.decode(header, inputPacket);
+
+ byte[] encodedIkeMessage = message.attachEncodedHeader(ikeBodyBytes);
+ assertArrayEquals(inputPacket, encodedIkeMessage);
+ }
+
+ // TODO: Implement encodeToByteBuffer() of each payload and add test for encoding message
+}
diff --git a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeNoncePayloadTest.java b/tests/iketests/src/java/com/android/ike/ikev2/message/IkeNoncePayloadTest.java
index dd92a45e..f4e4a984 100644
--- a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeNoncePayloadTest.java
+++ b/tests/iketests/src/java/com/android/ike/ikev2/message/IkeNoncePayloadTest.java
@@ -14,12 +14,10 @@
* limitations under the License.
*/
-package com.android.internal.net.ipsec.ike.message;
+package com.android.ike.ikev2.message;
import static org.junit.Assert.assertArrayEquals;
-import com.android.internal.net.TestUtils;
-
import org.junit.Test;
import java.nio.ByteBuffer;
diff --git a/tests/iketests/src/java/com/android/ike/ikev2/message/IkeNotifyPayloadTest.java b/tests/iketests/src/java/com/android/ike/ikev2/message/IkeNotifyPayloadTest.java
new file mode 100644
index 00000000..3e9ba80f
--- /dev/null
+++ b/tests/iketests/src/java/com/android/ike/ikev2/message/IkeNotifyPayloadTest.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2018 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.ike.ikev2.message;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import com.android.ike.ikev2.exceptions.InvalidSyntaxException;
+
+import org.junit.Test;
+
+import java.net.InetAddress;
+import java.nio.ByteBuffer;
+
+public final class IkeNotifyPayloadTest {
+ private static final String NOTIFY_PAYLOAD_GENERIC_HEADER = "2900001c";
+ private static final String NOTIFY_PAYLOAD_BODY_RAW_PACKET =
+ "00004004e54f73b7d83f6beb881eab2051d8663f421d10b0";
+
+ private static final String NAT_DETECTION_SOURCE_IP_DATA_HEX_STRING =
+ "e54f73b7d83f6beb881eab2051d8663f421d10b0";
+ private static final String IKE_INITIATOR_SPI_HEX_STRING = "5f54bf6d8b48e6e1";
+ private static final String IKE_RESPODNER_SPI_HEX_STRING = "0000000000000000";
+ private static final String IP_ADDR = "10.80.80.13";
+ private static final int PORT = 500;
+
+ private static final int EXPECTED_PROTOCOL_ID = IkePayload.PROTOCOL_ID_UNSET;
+ private static final int EXPECTED_SPI_SIZE = IkePayload.SPI_LEN_NOT_INCLUDED;
+
+ @IkePayload.PayloadType
+ private static final int NEXT_PAYLOAD_TYPE = IkePayload.PAYLOAD_TYPE_NOTIFY;
+
+ @IkeNotifyPayload.NotifyType
+ private static final int EXPECTED_NOTIFY_TYPE =
+ IkeNotifyPayload.NOTIFY_TYPE_NAT_DETECTION_SOURCE_IP;
+
+ private static final int EXPECTED_NOTIFY_DATA_LEN = 20;
+
+ private static final int POS_PROTOCOL_ID = 0;
+
+ @Test
+ public void testDecodeNotifyPayload() throws Exception {
+ byte[] inputPacket = TestUtils.hexStringToByteArray(NOTIFY_PAYLOAD_BODY_RAW_PACKET);
+ IkeNotifyPayload payload = new IkeNotifyPayload(false, inputPacket);
+ assertEquals(EXPECTED_PROTOCOL_ID, payload.protocolId);
+ assertEquals(EXPECTED_SPI_SIZE, payload.spiSize);
+ assertEquals(EXPECTED_NOTIFY_TYPE, payload.notifyType);
+ assertEquals(EXPECTED_SPI_SIZE, payload.spi);
+ assertEquals(EXPECTED_NOTIFY_DATA_LEN, payload.notifyData.length);
+ }
+
+ @Test
+ public void testDecodeNotifyPayloadThrowException() throws Exception {
+ byte[] inputPacket = TestUtils.hexStringToByteArray(NOTIFY_PAYLOAD_BODY_RAW_PACKET);
+ // Change Protocol ID to ESP
+ inputPacket[POS_PROTOCOL_ID] = (byte) (IkePayload.PROTOCOL_ID_ESP & 0xFF);
+ try {
+ IkeNotifyPayload payload = new IkeNotifyPayload(false, inputPacket);
+ fail("Expected InvalidSyntaxException: Protocol ID should not be ESP");
+ } catch (InvalidSyntaxException expected) {
+ }
+ }
+
+ @Test
+ public void testGenerateNatDetectionData() throws Exception {
+ long initiatorIkeSpi = Long.parseLong(IKE_INITIATOR_SPI_HEX_STRING, 16);
+ long responderIkespi = Long.parseLong(IKE_RESPODNER_SPI_HEX_STRING, 16);
+ InetAddress inetAddress = InetAddress.getByName(IP_ADDR);
+
+ byte[] netDetectionData =
+ IkeNotifyPayload.generateNatDetectionData(
+ initiatorIkeSpi, responderIkespi, inetAddress, PORT);
+
+ byte[] expectedBytes =
+ TestUtils.hexStringToByteArray(NAT_DETECTION_SOURCE_IP_DATA_HEX_STRING);
+ assertArrayEquals(expectedBytes, netDetectionData);
+ }
+
+ @Test
+ public void testEncodeNotifyPayload() throws Exception {
+ byte[] inputPacket = TestUtils.hexStringToByteArray(NOTIFY_PAYLOAD_BODY_RAW_PACKET);
+ IkeNotifyPayload payload = new IkeNotifyPayload(false, inputPacket);
+
+ ByteBuffer byteBuffer = ByteBuffer.allocate(payload.getPayloadLength());
+ payload.encodeToByteBuffer(NEXT_PAYLOAD_TYPE, byteBuffer);
+
+ byte[] expectedNoncePayload =
+ TestUtils.hexStringToByteArray(
+ NOTIFY_PAYLOAD_GENERIC_HEADER + NOTIFY_PAYLOAD_BODY_RAW_PACKET);
+ assertArrayEquals(expectedNoncePayload, byteBuffer.array());
+ }
+}
diff --git a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeSaPayloadTest.java b/tests/iketests/src/java/com/android/ike/ikev2/message/IkeSaPayloadTest.java
index 750ff463..afb3a810 100644
--- a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeSaPayloadTest.java
+++ b/tests/iketests/src/java/com/android/ike/ikev2/message/IkeSaPayloadTest.java
@@ -14,69 +14,54 @@
* limitations under the License.
*/
-package com.android.internal.net.ipsec.ike.message;
+package com.android.ike.ikev2.message;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyObject;
-import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
-import android.net.IpSecManager;
-import android.net.IpSecSpiResponse;
-import android.net.ipsec.ike.ChildSaProposal;
-import android.net.ipsec.ike.IkeSaProposal;
-import android.net.ipsec.ike.SaProposal;
-import android.net.ipsec.ike.exceptions.IkeProtocolException;
import android.util.Pair;
-import com.android.internal.net.TestUtils;
-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.message.IkeSaPayload.Attribute;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload.AttributeDecoder;
-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.IkeSaPayload.EncryptionTransform;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload.EsnTransform;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload.IkeProposal;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload.IntegrityTransform;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload.KeyLengthAttribute;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload.PrfTransform;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload.Proposal;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload.Transform;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload.TransformDecoder;
-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.server.IpSecService;
-
-import libcore.net.InetAddressUtils;
+import com.android.ike.ikev2.SaProposal;
+import com.android.ike.ikev2.exceptions.IkeException;
+import com.android.ike.ikev2.exceptions.InvalidSyntaxException;
+import com.android.ike.ikev2.exceptions.NoValidProposalChosenException;
+import com.android.ike.ikev2.message.IkeSaPayload.Attribute;
+import com.android.ike.ikev2.message.IkeSaPayload.AttributeDecoder;
+import com.android.ike.ikev2.message.IkeSaPayload.DhGroupTransform;
+import com.android.ike.ikev2.message.IkeSaPayload.EncryptionTransform;
+import com.android.ike.ikev2.message.IkeSaPayload.EsnTransform;
+import com.android.ike.ikev2.message.IkeSaPayload.IntegrityTransform;
+import com.android.ike.ikev2.message.IkeSaPayload.KeyLengthAttribute;
+import com.android.ike.ikev2.message.IkeSaPayload.PrfTransform;
+import com.android.ike.ikev2.message.IkeSaPayload.Proposal;
+import com.android.ike.ikev2.message.IkeSaPayload.Transform;
+import com.android.ike.ikev2.message.IkeSaPayload.TransformDecoder;
+import com.android.ike.ikev2.message.IkeSaPayload.UnrecognizedAttribute;
+import com.android.ike.ikev2.message.IkeSaPayload.UnrecognizedTransform;
import org.junit.Before;
import org.junit.Test;
-import java.net.Inet4Address;
-import java.net.InetAddress;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
+import java.util.Random;
public final class IkeSaPayloadTest {
private static final String OUTBOUND_SA_PAYLOAD_HEADER = "22000030";
private static final String OUTBOUND_PROPOSAL_RAW_PACKET =
- "0000002C010100040300000C0100000C800E0080030000080300000203000008040"
- + "000020000000802000002";
+ "0000002C010100040300000C0100000C800E0080030000080200000203000008030"
+ + "000020000000804000002";
private static final String INBOUND_PROPOSAL_RAW_PACKET =
"0000002c010100040300000c0100000c800e0080030000080300000203000008040"
+ "000020000000802000002";
@@ -98,12 +83,6 @@ public final class IkeSaPayloadTest {
+ "0300000804000015030000080400001c030000080400001d030000080"
+ "400001e030000080400001f030000080400000f030000080400001003"
+ "00000804000012000000080400000e";
- private static final String INBOUND_CHILD_PROPOSAL_RAW_PACKET =
- "0000002801030403cae7019f0300000c0100000c800e00800300000803000002000" + "0000805000000";
- private static final String INBOUND_CHILD_TWO_PROPOSAL_RAW_PACKET =
- "0200002801030403cae7019f0300000c0100000c800e00800300000803000002000"
- + "00008050000000000001802030401cae7019e0000000c01000012800e"
- + "0080";
private static final String ENCR_TRANSFORM_RAW_PACKET = "0300000c0100000c800e0080";
private static final String PRF_TRANSFORM_RAW_PACKET = "0000000802000002";
private static final String INTEG_TRANSFORM_RAW_PACKET = "0300000803000002";
@@ -123,19 +102,6 @@ public final class IkeSaPayloadTest {
// Constants for multiple proposals test
private static final byte[] PROPOSAL_NUMBER_LIST = {1, 2};
- private static final Inet4Address LOCAL_ADDRESS =
- (Inet4Address) (InetAddressUtils.parseNumericAddress("8.8.4.4"));
- private static final Inet4Address REMOTE_ADDRESS =
- (Inet4Address) (InetAddressUtils.parseNumericAddress("8.8.8.8"));
-
- private static final int DUMMY_CHILD_SPI_RESOURCE_ID_LOCAL_ONE = 0x1234;
- private static final int DUMMY_CHILD_SPI_RESOURCE_ID_LOCAL_TWO = 0x1235;
- private static final int DUMMY_CHILD_SPI_RESOURCE_ID_REMOTE = 0x2234;
-
- private static final int CHILD_SPI_LOCAL_ONE = 0x2ad4c0a2;
- private static final int CHILD_SPI_LOCAL_TWO = 0x2ad4c0a3;
- private static final int CHILD_SPI_REMOTE = 0xcae70197;
-
private AttributeDecoder mMockedAttributeDecoder;
private KeyLengthAttribute mAttributeKeyLength128;
private List<Attribute> mAttributeListWithKeyLength128;
@@ -148,21 +114,9 @@ public final class IkeSaPayloadTest {
private Transform[] mValidNegotiatedTransformSet;
- private IkeSaProposal mIkeSaProposalOne;
- private IkeSaProposal mIkeSaProposalTwo;
- private IkeSaProposal[] mTwoIkeSaProposalsArray;
-
- private ChildSaProposal mChildSaProposalOne;
- private ChildSaProposal mChildSaProposalTwo;
- private ChildSaProposal[] mTwoChildSaProposalsArray;
-
- private MockIpSecTestUtils mMockIpSecTestUtils;
- private IpSecService mMockIpSecService;
- private IpSecManager mIpSecManager;
-
- private IpSecSpiResponse mDummyIpSecSpiResponseLocalOne;
- private IpSecSpiResponse mDummyIpSecSpiResponseLocalTwo;
- private IpSecSpiResponse mDummyIpSecSpiResponseRemote;
+ private SaProposal mSaProposalOne;
+ private SaProposal mSaProposalTwo;
+ private SaProposal[] mTwoSaProposalsArray;
@Before
public void setUp() throws Exception {
@@ -190,8 +144,8 @@ public final class IkeSaPayloadTest {
mDhGroup1024Transform
};
- mIkeSaProposalOne =
- new IkeSaProposal.Builder()
+ mSaProposalOne =
+ SaProposal.Builder.newIkeSaProposalBuilder()
.addEncryptionAlgorithm(
SaProposal.ENCRYPTION_ALGORITHM_AES_CBC, SaProposal.KEY_LEN_AES_128)
.addIntegrityAlgorithm(SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96)
@@ -199,8 +153,8 @@ public final class IkeSaPayloadTest {
.addPseudorandomFunction(SaProposal.PSEUDORANDOM_FUNCTION_HMAC_SHA1)
.build();
- mIkeSaProposalTwo =
- new IkeSaProposal.Builder()
+ mSaProposalTwo =
+ SaProposal.Builder.newIkeSaProposalBuilder()
.addEncryptionAlgorithm(
SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8,
SaProposal.KEY_LEN_AES_128)
@@ -211,35 +165,7 @@ public final class IkeSaPayloadTest {
.addDhGroup(SaProposal.DH_GROUP_1024_BIT_MODP)
.addDhGroup(SaProposal.DH_GROUP_2048_BIT_MODP)
.build();
- mTwoIkeSaProposalsArray = new IkeSaProposal[] {mIkeSaProposalOne, mIkeSaProposalTwo};
-
- mChildSaProposalOne =
- new ChildSaProposal.Builder()
- .addEncryptionAlgorithm(
- SaProposal.ENCRYPTION_ALGORITHM_AES_CBC, SaProposal.KEY_LEN_AES_128)
- .addIntegrityAlgorithm(SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96)
- .build();
- mChildSaProposalTwo =
- new ChildSaProposal.Builder()
- .addEncryptionAlgorithm(
- SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8,
- SaProposal.KEY_LEN_AES_128)
- .build();
- mTwoChildSaProposalsArray =
- new ChildSaProposal[] {mChildSaProposalOne, mChildSaProposalTwo};
-
- mMockIpSecTestUtils = MockIpSecTestUtils.setUpMockIpSec();
- mIpSecManager = mMockIpSecTestUtils.getIpSecManager();
-
- IpSecService mMockIpSecService = mMockIpSecTestUtils.getIpSecService();
- when(mMockIpSecService.allocateSecurityParameterIndex(
- eq(LOCAL_ADDRESS.getHostAddress()), anyInt(), anyObject()))
- .thenReturn(MockIpSecTestUtils.buildDummyIpSecSpiResponse(CHILD_SPI_LOCAL_ONE))
- .thenReturn(MockIpSecTestUtils.buildDummyIpSecSpiResponse(CHILD_SPI_LOCAL_TWO));
-
- when(mMockIpSecService.allocateSecurityParameterIndex(
- eq(REMOTE_ADDRESS.getHostAddress()), anyInt(), anyObject()))
- .thenReturn(MockIpSecTestUtils.buildDummyIpSecSpiResponse(CHILD_SPI_REMOTE));
+ mTwoSaProposalsArray = new SaProposal[] {mSaProposalOne, mSaProposalTwo};
}
// TODO: Add tearDown() to reset Proposal.sTransformDecoder and Transform.sAttributeDecoder.
@@ -602,7 +528,7 @@ public final class IkeSaPayloadTest {
return new TransformDecoder() {
@Override
public Transform[] decodeTransforms(int count, ByteBuffer inputBuffer)
- throws IkeProtocolException {
+ throws IkeException {
for (int i = 0; i < count; i++) {
// Read length field and move position
inputBuffer.getShort();
@@ -628,7 +554,7 @@ public final class IkeSaPayloadTest {
assertEquals(IkePayload.SPI_LEN_NOT_INCLUDED, proposal.spiSize);
assertEquals(IkePayload.SPI_NOT_INCLUDED, proposal.spi);
assertFalse(proposal.hasUnrecognizedTransform);
- assertNotNull(proposal.getSaProposal());
+ assertNotNull(proposal.saProposal);
}
@Test
@@ -649,13 +575,14 @@ public final class IkeSaPayloadTest {
@Test
public void testEncodeProposal() throws Exception {
- // Construct Proposal for IKE INIT exchange.
- IkeProposal proposal =
- IkeProposal.createIkeProposal(
+ Proposal proposal =
+ new Proposal(
(byte) PROPOSAL_NUMBER,
+ IkePayload.PROTOCOL_ID_IKE,
IkePayload.SPI_LEN_NOT_INCLUDED,
- mIkeSaProposalOne,
- LOCAL_ADDRESS);
+ IkePayload.SPI_NOT_INCLUDED,
+ mSaProposalOne,
+ false /*has no unrecognized Tramsform*/);
ByteBuffer byteBuffer = ByteBuffer.allocate(proposal.getProposalLength());
proposal.encodeToByteBuffer(true /*is the last*/, byteBuffer);
@@ -678,66 +605,42 @@ public final class IkeSaPayloadTest {
}
@Test
- public void testBuildOutboundIkeRekeySaResponsePayload() throws Exception {
+ public void testBuildIkeSaResponsePayload() throws Exception {
+ final long ikeSpi = new Random().nextLong();
+ final SaProposal[] saProposals = new SaProposal[] {mSaProposalOne};
IkeSaPayload saPayload =
- IkeSaPayload.createRekeyIkeSaResponsePayload(
- (byte) 1, mIkeSaProposalOne, LOCAL_ADDRESS);
+ new IkeSaPayload(
+ true, true, IkePayload.SPI_LEN_IKE, new long[] {ikeSpi}, saProposals);
assertTrue(saPayload.isSaResponse);
- assertEquals(1, saPayload.proposalList.size());
+ assertEquals(saProposals.length, saPayload.proposalList.size());
- IkeProposal proposal = (IkeProposal) saPayload.proposalList.get(0);
+ Proposal proposal = saPayload.proposalList.get(0);
assertEquals(IkePayload.PROTOCOL_ID_IKE, proposal.protocolId);
assertEquals(IkePayload.SPI_LEN_IKE, proposal.spiSize);
- assertEquals(mIkeSaProposalOne, proposal.saProposal);
-
- assertNotNull(proposal.getIkeSpiResource());
+ assertEquals(ikeSpi, proposal.spi);
+ assertEquals(mSaProposalOne, proposal.saProposal);
}
@Test
- public void testBuildOutboundInitialIkeSaRequestPayload() throws Exception {
- IkeSaPayload saPayload = IkeSaPayload.createInitialIkeSaPayload(mTwoIkeSaProposalsArray);
+ public void testBuildInitialIkeSaRequestPayload() throws Exception {
+ IkeSaPayload saPayload = new IkeSaPayload(mTwoSaProposalsArray);
assertFalse(saPayload.isSaResponse);
assertEquals(PROPOSAL_NUMBER_LIST.length, saPayload.proposalList.size());
for (int i = 0; i < saPayload.proposalList.size(); i++) {
- IkeProposal proposal = (IkeProposal) saPayload.proposalList.get(i);
+ Proposal proposal = saPayload.proposalList.get(i);
assertEquals(PROPOSAL_NUMBER_LIST[i], proposal.number);
assertEquals(IkePayload.PROTOCOL_ID_IKE, proposal.protocolId);
assertEquals(IkePayload.SPI_LEN_NOT_INCLUDED, proposal.spiSize);
- assertEquals(mTwoIkeSaProposalsArray[i], proposal.saProposal);
-
- // SA Payload for IKE INIT exchange does not include IKE SPIs.
- assertNull(proposal.getIkeSpiResource());
- }
- }
-
- @Test
- public void testBuildOutboundChildSaRequest() throws Exception {
- IkeSaPayload saPayload =
- IkeSaPayload.createChildSaRequestPayload(
- mTwoChildSaProposalsArray, mIpSecManager, LOCAL_ADDRESS);
-
- assertFalse(saPayload.isSaResponse);
- assertEquals(PROPOSAL_NUMBER_LIST.length, saPayload.proposalList.size());
-
- int[] expectedSpis = new int[] {CHILD_SPI_LOCAL_ONE, CHILD_SPI_LOCAL_TWO};
- for (int i = 0; i < saPayload.proposalList.size(); i++) {
- ChildProposal proposal = (ChildProposal) saPayload.proposalList.get(i);
- assertEquals(PROPOSAL_NUMBER_LIST[i], proposal.number);
- assertEquals(IkePayload.PROTOCOL_ID_ESP, proposal.protocolId);
- assertEquals(IkePayload.SPI_LEN_IPSEC, proposal.spiSize);
- assertEquals(mTwoChildSaProposalsArray[i], proposal.saProposal);
-
- assertEquals(expectedSpis[i], proposal.getChildSpiResource().getSpi());
+ assertEquals(mTwoSaProposalsArray[i], proposal.saProposal);
}
}
@Test
public void testEncodeIkeSaPayload() throws Exception {
- IkeSaPayload saPayload =
- IkeSaPayload.createInitialIkeSaPayload(new IkeSaProposal[] {mIkeSaProposalOne});
+ IkeSaPayload saPayload = new IkeSaPayload(new SaProposal[] {mSaProposalOne});
ByteBuffer byteBuffer = ByteBuffer.allocate(saPayload.getPayloadLength());
saPayload.encodeToByteBuffer(IkePayload.PAYLOAD_TYPE_KE, byteBuffer);
@@ -748,109 +651,25 @@ public final class IkeSaPayloadTest {
assertArrayEquals(expectedBytes, byteBuffer.array());
}
- private void buildAndVerifyIkeSaRespProposal(
- byte[] saResponseBytes, Transform[] decodedTransforms) throws Exception {
+ private void buildAndVerifySaRespProposal(byte[] saResponseBytes, Transform[] decodedTransforms)
+ throws Exception {
// Build response SA payload from decoding bytes.
Proposal.sTransformDecoder = getDummyTransformDecoder(decodedTransforms);
IkeSaPayload respPayload = new IkeSaPayload(false, true, saResponseBytes);
- // Build request SA payload for IKE INIT exchange from SaProposal.
- IkeSaPayload reqPayload = IkeSaPayload.createInitialIkeSaPayload(mTwoIkeSaProposalsArray);
-
- Pair<IkeProposal, IkeProposal> negotiatedProposalPair =
- IkeSaPayload.getVerifiedNegotiatedIkeProposalPair(
- reqPayload, respPayload, REMOTE_ADDRESS);
- IkeProposal reqProposal = negotiatedProposalPair.first;
- IkeProposal respProposal = negotiatedProposalPair.second;
+ // Build request SA payload from SaProposal.
+ IkeSaPayload reqPayload = new IkeSaPayload(mTwoSaProposalsArray);
- assertEquals(respPayload.proposalList.get(0).getSaProposal(), respProposal.getSaProposal());
+ SaProposal saProposal = respPayload.getVerifiedNegotiatedProposal(reqPayload);
- // SA Payload for IKE INIT exchange does not include IKE SPIs.
- assertNull(reqProposal.getIkeSpiResource());
- assertNull(respProposal.getIkeSpiResource());
+ assertEquals(respPayload.proposalList.get(0).saProposal, saProposal);
}
@Test
- public void testGetVerifiedNegotiatedIkeProposal() throws Exception {
+ public void testGetVerifiedNegotiatedProposal() throws Exception {
byte[] inputPacket = TestUtils.hexStringToByteArray(INBOUND_PROPOSAL_RAW_PACKET);
- buildAndVerifyIkeSaRespProposal(inputPacket, mValidNegotiatedTransformSet);
- }
-
- private void verifyChildSaNegotiation(
- IkeSaPayload reqPayload,
- IkeSaPayload respPayload,
- IpSecManager ipSecManager,
- InetAddress remoteAddress,
- boolean isLocalInit)
- throws Exception {
- // SA negotiation
- Pair<ChildProposal, ChildProposal> negotiatedProposalPair =
- IkeSaPayload.getVerifiedNegotiatedChildProposalPair(
- reqPayload, respPayload, ipSecManager, remoteAddress);
- ChildProposal reqProposal = negotiatedProposalPair.first;
- ChildProposal respProposal = negotiatedProposalPair.second;
-
- // Verify results
- assertEquals(respPayload.proposalList.get(0).getSaProposal(), respProposal.getSaProposal());
-
- int initSpi = isLocalInit ? CHILD_SPI_LOCAL_ONE : CHILD_SPI_REMOTE;
- int respSpi = isLocalInit ? CHILD_SPI_REMOTE : CHILD_SPI_LOCAL_ONE;
- assertEquals(initSpi, reqProposal.getChildSpiResource().getSpi());
- assertEquals(respSpi, respProposal.getChildSpiResource().getSpi());
-
- // Verify SPIs in unselected Proposals have been released.
- for (Proposal proposal : reqPayload.proposalList) {
- if (proposal != reqProposal) {
- assertNull(((ChildProposal) proposal).getChildSpiResource());
- }
- }
- }
-
- @Test
- public void testGetVerifiedNegotiatedChildProposalForLocalCreate() throws Exception {
- // Build local request
- IkeSaPayload reqPayload =
- IkeSaPayload.createChildSaRequestPayload(
- mTwoChildSaProposalsArray, mIpSecManager, LOCAL_ADDRESS);
-
- // Build remote response
- Proposal.sTransformDecoder =
- getDummyTransformDecoder(mChildSaProposalOne.getAllTransforms());
- IkeSaPayload respPayload =
- new IkeSaPayload(
- false /*critical*/,
- true /*isResp*/,
- TestUtils.hexStringToByteArray(INBOUND_CHILD_PROPOSAL_RAW_PACKET));
-
- verifyChildSaNegotiation(
- reqPayload, respPayload, mIpSecManager, REMOTE_ADDRESS, true /*isLocalInit*/);
- }
-
- @Test
- public void testGetVerifiedNegotiatedChildProposalForRemoteCreate() throws Exception {
- Transform[] transformsOne = mChildSaProposalOne.getAllTransforms();
- Transform[] transformsTwo = mChildSaProposalTwo.getAllTransforms();
- Transform[] decodedTransforms = new Transform[transformsOne.length + transformsTwo.length];
- System.arraycopy(transformsOne, 0, decodedTransforms, 0, transformsOne.length);
- System.arraycopy(
- transformsTwo, 0, decodedTransforms, transformsOne.length, transformsTwo.length);
-
- // Build remote request
- Proposal.sTransformDecoder = getDummyTransformDecoder(decodedTransforms);
- IkeSaPayload reqPayload =
- new IkeSaPayload(
- false /*critical*/,
- false /*isResp*/,
- TestUtils.hexStringToByteArray(INBOUND_CHILD_TWO_PROPOSAL_RAW_PACKET));
-
- // Build local response
- IkeSaPayload respPayload =
- IkeSaPayload.createChildSaResponsePayload(
- (byte) 1, mChildSaProposalOne, mIpSecManager, LOCAL_ADDRESS);
-
- verifyChildSaNegotiation(
- reqPayload, respPayload, mIpSecManager, REMOTE_ADDRESS, false /*isLocalInit*/);
+ buildAndVerifySaRespProposal(inputPacket, mValidNegotiatedTransformSet);
}
// Test throwing when negotiated proposal in SA response payload has unrecognized Transform.
@@ -864,7 +683,7 @@ public final class IkeSaPayloadTest {
negotiatedTransformSet[0] = new UnrecognizedTransform(-1, 1, new LinkedList<>());
try {
- buildAndVerifyIkeSaRespProposal(inputPacket, negotiatedTransformSet);
+ buildAndVerifySaRespProposal(inputPacket, negotiatedTransformSet);
fail("Expected to fail because negotiated proposal has unrecognized Transform.");
} catch (NoValidProposalChosenException expected) {
}
@@ -877,7 +696,7 @@ public final class IkeSaPayloadTest {
inputPacket[PROPOSAL_NUMBER_OFFSET] = (byte) 10;
try {
- buildAndVerifyIkeSaRespProposal(inputPacket, mValidNegotiatedTransformSet);
+ buildAndVerifySaRespProposal(inputPacket, mValidNegotiatedTransformSet);
fail("Expected to fail due to invalid proposal number.");
} catch (NoValidProposalChosenException expected) {
}
@@ -890,7 +709,7 @@ public final class IkeSaPayloadTest {
inputPacket[PROTOCOL_ID_OFFSET] = IkePayload.PROTOCOL_ID_ESP;
try {
- buildAndVerifyIkeSaRespProposal(inputPacket, mValidNegotiatedTransformSet);
+ buildAndVerifySaRespProposal(inputPacket, mValidNegotiatedTransformSet);
fail("Expected to fail due to mismatched protocol ID.");
} catch (NoValidProposalChosenException expected) {
}
@@ -907,7 +726,7 @@ public final class IkeSaPayloadTest {
negotiatedTransformSet[0] = mEncrAesGcm8Key128Transform;
try {
- buildAndVerifyIkeSaRespProposal(inputPacket, negotiatedTransformSet);
+ buildAndVerifySaRespProposal(inputPacket, negotiatedTransformSet);
fail("Expected to fail due to mismatched Transform.");
} catch (NoValidProposalChosenException expected) {
}
@@ -919,7 +738,7 @@ public final class IkeSaPayloadTest {
byte[] inputPacket = TestUtils.hexStringToByteArray(INBOUND_PROPOSAL_RAW_PACKET);
try {
- buildAndVerifyIkeSaRespProposal(inputPacket, new Transform[0]);
+ buildAndVerifySaRespProposal(inputPacket, new Transform[0]);
fail("Expected to fail due to absence of Transform.");
} catch (NoValidProposalChosenException expected) {
}
diff --git a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeSkPayloadTest.java b/tests/iketests/src/java/com/android/ike/ikev2/message/IkeSkPayloadTest.java
index 898db30f..13866fb6 100644
--- a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeSkPayloadTest.java
+++ b/tests/iketests/src/java/com/android/ike/ikev2/message/IkeSkPayloadTest.java
@@ -14,24 +14,21 @@
* limitations under the License.
*/
-package com.android.internal.net.ipsec.ike.message;
+package com.android.ike.ikev2.message;
import static org.junit.Assert.assertArrayEquals;
-import android.net.ipsec.ike.SaProposal;
-
-import com.android.internal.net.TestUtils;
-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.message.IkeSaPayload.EncryptionTransform;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload.IntegrityTransform;
-
import org.junit.Before;
import org.junit.Test;
import java.nio.ByteBuffer;
import java.util.Arrays;
+import javax.crypto.Cipher;
+import javax.crypto.Mac;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+
public final class IkeSkPayloadTest {
private static final String IKE_AUTH_INIT_REQUEST_HEX_STRING =
@@ -60,29 +57,26 @@ public final class IkeSkPayloadTest {
"554fbf5a05b7f511e05a30ce23d874db9ef55e51";
private static final String ENCR_ALGO_AES_CBC = "AES/CBC/NoPadding";
+ private static final String INTE_ALGO_HMAC_SHA1 = "HmacSHA1";
private static final int CHECKSUM_LEN = 12;
- private IkeCipher mAesCbcDecryptCipher;
- private byte[] mAesCbcDecryptionKey;
-
- private IkeMacIntegrity mHmacSha1IntegrityMac;
- private byte[] mHmacSha1IntegrityKey;
+ private Cipher mAesCbcDecryptCipher;
+ private SecretKey mAesCbcDecryptKey;
+ private Mac mHmacSha1IntegrityMac;
@Before
public void setUp() throws Exception {
mAesCbcDecryptCipher =
- IkeCipher.create(
- new EncryptionTransform(
- SaProposal.ENCRYPTION_ALGORITHM_AES_CBC,
- SaProposal.KEY_LEN_AES_128),
- IkeMessage.getSecurityProvider());
- mAesCbcDecryptionKey = TestUtils.hexStringToByteArray(ENCR_KEY_FROM_INIT_TO_RESP);
+ Cipher.getInstance(ENCR_ALGO_AES_CBC, IkeMessage.getSecurityProvider());
+ byte[] decryptKeyBytes = TestUtils.hexStringToByteArray(ENCR_KEY_FROM_INIT_TO_RESP);
+ mAesCbcDecryptKey = new SecretKeySpec(decryptKeyBytes, ENCR_ALGO_AES_CBC);
+
mHmacSha1IntegrityMac =
- IkeMacIntegrity.create(
- new IntegrityTransform(SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96),
- IkeMessage.getSecurityProvider());
- mHmacSha1IntegrityKey = TestUtils.hexStringToByteArray(INTE_KEY_FROM_INIT_TO_RESP);
+ Mac.getInstance(INTE_ALGO_HMAC_SHA1, IkeMessage.getSecurityProvider());
+ byte[] integrityKeyBytes = TestUtils.hexStringToByteArray(INTE_KEY_FROM_INIT_TO_RESP);
+ SecretKeySpec integrityKey = new SecretKeySpec(integrityKeyBytes, INTE_ALGO_HMAC_SHA1);
+ mHmacSha1IntegrityMac.init(integrityKey);
}
@Test
@@ -93,12 +87,11 @@ public final class IkeSkPayloadTest {
IkeSkPayload payload =
IkePayloadFactory.getIkeSkPayload(
- false /*isSkf*/,
message,
mHmacSha1IntegrityMac,
+ CHECKSUM_LEN,
mAesCbcDecryptCipher,
- mHmacSha1IntegrityKey,
- mAesCbcDecryptionKey)
+ mAesCbcDecryptKey)
.first;
int payloadLength = payload.getPayloadLength();
ByteBuffer buffer = ByteBuffer.allocate(payloadLength);
diff --git a/tests/iketests/src/java/com/android/ike/ikev2/message/IkeTsPayloadTest.java b/tests/iketests/src/java/com/android/ike/ikev2/message/IkeTsPayloadTest.java
new file mode 100644
index 00000000..f547526a
--- /dev/null
+++ b/tests/iketests/src/java/com/android/ike/ikev2/message/IkeTsPayloadTest.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2019 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.ike.ikev2.message;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+import java.nio.ByteBuffer;
+
+public final class IkeTsPayloadTest {
+ private static final String TS_INITIATOR_PAYLOAD_HEX_STRING =
+ "2d00002802000000070000100000ffff00000000ffffffff070000100000ffff00000001fffffffe";
+ private static final int NUMBER_OF_TS = 2;
+
+ @Test
+ public void testDecodeTsInitiatorPayload() throws Exception {
+ ByteBuffer inputBuffer =
+ ByteBuffer.wrap(TestUtils.hexStringToByteArray(TS_INITIATOR_PAYLOAD_HEX_STRING));
+
+ IkePayload payload =
+ IkePayloadFactory.getIkePayload(
+ IkePayload.PAYLOAD_TYPE_TS_INITIATOR, false, inputBuffer)
+ .first;
+ assertTrue(payload instanceof IkeTsPayload);
+
+ IkeTsPayload tsPayload = (IkeTsPayload) payload;
+ assertEquals(IkePayload.PAYLOAD_TYPE_TS_INITIATOR, tsPayload.payloadType);
+ assertEquals(NUMBER_OF_TS, tsPayload.numTs);
+ }
+}
diff --git a/tests/iketests/src/java/com/android/ike/ikev2/message/TestUtils.java b/tests/iketests/src/java/com/android/ike/ikev2/message/TestUtils.java
new file mode 100644
index 00000000..1fcdac06
--- /dev/null
+++ b/tests/iketests/src/java/com/android/ike/ikev2/message/TestUtils.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2018 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.ike.ikev2.message;
+
+import android.util.Pair;
+
+import com.android.ike.ikev2.exceptions.IkeException;
+
+import java.nio.ByteBuffer;
+
+/** TestUtils provides utility methods for parsing Hex String */
+public final class TestUtils {
+
+ public static byte[] hexStringToByteArray(String hexString) throws IllegalArgumentException {
+ int len = hexString.length();
+ if (len % 2 != 0) {
+ throw new IllegalArgumentException("Invalid Hex String");
+ }
+ byte[] data = new byte[len / 2];
+ for (int i = 0; i < len; i += 2) {
+ data[i / 2] =
+ (byte)
+ ((Character.digit(hexString.charAt(i), 16) << 4)
+ + Character.digit(hexString.charAt(i + 1), 16));
+ }
+ return data;
+ }
+
+ public static IkePayload hexStringToIkePayload(
+ @IkePayload.PayloadType int payloadType, boolean isResp, String payloadHexString)
+ throws IkeException {
+ byte[] payloadBytes = hexStringToByteArray(payloadHexString);
+ // Returned Pair consists of the IkePayload and the following IkePayload's type.
+ Pair<IkePayload, Integer> pair =
+ IkePayloadFactory.getIkePayload(payloadType, isResp, ByteBuffer.wrap(payloadBytes));
+ return pair.first;
+ }
+}
diff --git a/tests/iketests/src/java/com/android/internal/net/utils/BigIntegerUtilsTest.java b/tests/iketests/src/java/com/android/ike/ikev2/utils/BigIntegerUtilsTest.java
index 29bb313d..e3d06ce7 100644
--- a/tests/iketests/src/java/com/android/internal/net/utils/BigIntegerUtilsTest.java
+++ b/tests/iketests/src/java/com/android/ike/ikev2/utils/BigIntegerUtilsTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.internal.net.utils;
+package com.android.ike.ikev2.utils;
import static org.junit.Assert.assertArrayEquals;
diff --git a/tests/iketests/src/java/com/android/internal/net/TestUtils.java b/tests/iketests/src/java/com/android/internal/net/TestUtils.java
deleted file mode 100644
index 6dd5ce5e..00000000
--- a/tests/iketests/src/java/com/android/internal/net/TestUtils.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2019 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;
-
-import static org.mockito.Matchers.anyObject;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.spy;
-
-import com.android.internal.net.utils.Log;
-
-import java.nio.ByteBuffer;
-
-/** TestUtils provides utility methods for parsing Hex String and constructing testing Logger. */
-public class TestUtils {
- public static byte[] hexStringToByteArray(String hexString) {
- int len = hexString.length();
- if (len % 2 != 0) {
- throw new IllegalArgumentException("Invalid Hex String");
- }
- byte[] data = new byte[len / 2];
- for (int i = 0; i < len; i += 2) {
- data[i / 2] =
- (byte)
- ((Character.digit(hexString.charAt(i), 16) << 4)
- + Character.digit(hexString.charAt(i + 1), 16));
- }
- return data;
- }
-
- public static int hexStringToInt(String hexString) {
- if (hexString.length() > 8) {
- throw new IllegalArgumentException("Invalid hex string length for integer type");
- }
-
- for (int i = hexString.length(); i < 8; i++) {
- hexString = "0" + hexString;
- }
-
- return ByteBuffer.wrap(hexStringToByteArray(hexString)).getInt();
- }
-
- public static String stringToHexString(String s) {
- // two hex characters for each char in s
- StringBuilder sb = new StringBuilder(s.length() * 2);
- char[] chars = s.toCharArray();
- for (char c : chars) {
- sb.append(Integer.toHexString(c));
- }
- return sb.toString();
- }
-
- public static Log makeSpyLogThrowExceptionForWtf(String tag) {
- Log spyLog = spy(new Log(tag, true /*logSensitive*/));
-
- doAnswer(
- (invocation) -> {
- throw new IllegalStateException((String) invocation.getArguments()[1]);
- })
- .when(spyLog)
- .wtf(anyString(), anyString());
-
- doAnswer(
- (invocation) -> {
- throw (Throwable) invocation.getArguments()[2];
- })
- .when(spyLog)
- .wtf(anyString(), anyString(), anyObject());
-
- return spyLog;
- }
-
- public static Log makeSpyLogDoLogErrorForWtf(String tag) {
- Log spyLog = spy(new Log(tag, true /*logSensitive*/));
-
- doAnswer(
- (invocation) -> {
- spyLog.e(
- "Mock logging WTF: " + invocation.getArguments()[0],
- (String) invocation.getArguments()[1]);
- return null;
- })
- .when(spyLog)
- .wtf(anyString(), anyString());
-
- doAnswer(
- (invocation) -> {
- spyLog.e(
- "Mock logging WTF: " + invocation.getArguments()[0],
- (String) invocation.getArguments()[1],
- (Throwable) invocation.getArguments()[2]);
- return null;
- })
- .when(spyLog)
- .wtf(anyString(), anyString(), anyObject());
-
- return spyLog;
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/EapAkaPrimeTest.java b/tests/iketests/src/java/com/android/internal/net/eap/EapAkaPrimeTest.java
deleted file mode 100644
index 0872b67f..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/EapAkaPrimeTest.java
+++ /dev/null
@@ -1,382 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap;
-
-import static android.telephony.TelephonyManager.APPTYPE_USIM;
-
-import static com.android.internal.net.TestUtils.hexStringToByteArray;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_REQUEST_SIM_START_PACKET;
-
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.net.eap.EapSessionConfig;
-import android.telephony.TelephonyManager;
-
-import com.android.internal.net.eap.statemachine.EapStateMachine;
-
-import org.junit.Before;
-import org.junit.Test;
-
-public class EapAkaPrimeTest extends EapMethodEndToEndTest {
- private static final long AUTHENTICATOR_TIMEOUT_MILLIS = 250L;
-
- private static final int SUB_ID = 1;
- private static final String UNFORMATTED_IDENTITY = "123456789ABCDEF"; // IMSI
-
- // EAP_IDENTITY = hex("test@android.net")
- private static final byte[] EAP_IDENTITY =
- hexStringToByteArray("7465737440616E64726F69642E6E6574");
- private static final boolean ALLOW_MISMATCHED_NETWORK_NAMES = false;
- private static final String PEER_NETWORK_NAME_1 = "foo:bar";
- private static final String PEER_NETWORK_NAME_2 = "bar";
-
- // hex("foo:bar:buzz")
- private static final String SERVER_NETWORK_NAME = "666F6F3A6261723A62757A7A";
-
- // TODO(b/142667016): replace with externally generated test values
-
- // IK: 7320EE404E055EF2B5AB0F86E96C48BE
- // CK: E9D1707652E13BF3E05975F601678E5C
- // Server Network Name: 666F6F3A6261723A62757A7A
- // SQN ^ AK: 35A9143ED9E1
- // IK': 79DC30692F3D2303D148549E5D50D0AA
- // CK': BBD0A7AD3F14757BA604C4CBE70F9090
- // K_encr: 4c22c289bcf40367cf2bdb6a6e3fe56b
- // K_aut: c64abd508ab628f842e9fb40a14fea769d2ccc67a8412794fe3b4c2556431e78
- // K_re: 5454ccf7ecc227f25c6cd1023e09394fa5cedc14a2f155e9d96a70dc404b4dca
- private static final String RAND_1 = "D6A296F030A305601B311D38A004505C";
- private static final String RAND_2 = "000102030405060708090A0B0C0D0E0F";
- private static final String AUTN = "35A9143ED9E100011795E785DAFAAD9B";
- private static final String RES = "E5167A255FDCDE9248AF6B50ADA0D944";
- private static final String AUTS = "0102030405060708090A0B0C0D0E";
- private static final byte[] MSK =
- hexStringToByteArray(
- "695788d8f33af56b5b2fea065a0e8656"
- + "7dc48120d6070d96056f9668614ec3e7"
- + "feb4933a3aaab3587980a624998c8b5e"
- + "a69d7295b824ef4a2201720be89d04df");
- private static final byte[] EMSK =
- hexStringToByteArray(
- "2db1f574d6e92cec294779defef5a7f0"
- + "49319cc75367102815d0244087f23660"
- + "0986b47a862c1aeeca418c84a2f9581b"
- + "0738fdefd229a5f7a4ca76709379bf00");
-
- // IK: 7320EE404E055EF2B5AB0F86E96C48BE
- // CK: E9D1707652E13BF3E05975F601678E5C
- // Server Network Name: 666F6F3A6261723A62757A7A
- // SQN ^ AK: 35A9143ED9E1
- // IK': 6C45FB0B12FF8172223B6D0E599EAE20
- // CK': A01C894696BEB759ABE0340F71A20D7B
- // K_encr: c039213c78fcf78a34bef30219a77822
- // K_aut: 95b014e569144eba71a387f91fb6b72e06781df12d61bfe88e5149477cd232aa
- // K_re: 1000c2e2f01766a4d2581ac454e41fce1ee17bcccbc32dfad78815075d884c5e
- private static final byte[] MSK_WITHOUT_IDENTITY_REQ =
- hexStringToByteArray(
- "ad75a86586773134dcd9e78e3f75b282"
- + "7a42435cb1be7235be58cddc60a0ba19"
- + "dd5c30accfdb0db5ef065f46c3c25d7b"
- + "9f8703d9493a2dc6fb6563dbdc854658");
- private static final byte[] EMSK_WITHOUT_IDENTITY_REQ =
- hexStringToByteArray(
- "31a3f2bb0e3e831d991dc8666438297f"
- + "4a5bc157fc1e31537e5a4927206d7b4b"
- + "db830761eea3441d9b90da48aebb9734"
- + "d3cbdec96072230a64043f54932a8841");
-
- // Base 64 of: [Length][RAND_1][Length][AUTN]
- private static final String BASE64_CHALLENGE_1 =
- "ENailvAwowVgGzEdOKAEUFwQNakUPtnhAAEXleeF2vqtmw==";
-
- // Base 64 of: ['DB'][Length][RES][Length][IK][Length][CK]
- private static final String BASE_64_RESPONSE_SUCCESS =
- "2xDlFnolX9zekkiva1CtoNlEEHMg7kBOBV7ytasPhulsSL4Q6dFwdlLhO/PgWXX2AWeOXA==";
-
- // Base 64 of: [Length][RAND_2][Length][AUTN]
- private static final String BASE64_CHALLENGE_2 =
- "EAABAgMEBQYHCAkKCwwNDg8QNakUPtnhAAEXleeF2vqtmw==";
-
- // Base 64 of: ['DC'][Length][AUTS]
- private static final String BASE_64_RESPONSE_SYNC_FAIL = "3A4BAgMEBQYHCAkKCwwNDg==";
-
- private static final String REQUEST_MAC = "9089f89b2f99bb85f2f2b529779f98db";
- private static final String RESPONSE_MAC = "48d7d6a80e1e2ff26a1e4148e0a2303e";
- private static final String REQUEST_MAC_WITHOUT_IDENTITY_REQ =
- "59f680ede020a3d0156eef56affb6997";
- private static final String RESPONSE_MAC_WITHOUT_IDENTITY_REQ =
- "e15322ff4abe51479c0fa92d00e343d7";
-
- private static final byte[] EAP_AKA_PRIME_IDENTITY_REQUEST =
- hexStringToByteArray(
- "01CD000C" // EAP-Request | ID | length in bytes
- + "32050000" // EAP-AKA' | Identity | 2B padding
- + "0D010000"); // AT_ANY_ID_REQ attribute
- private static final byte[] EAP_AKA_PRIME_IDENTITY_RESPONSE =
- hexStringToByteArray(
- "02CD001C" // EAP-Response | ID | length in bytes
- + "32050000" // EAP-AKA' | Identity | 2B padding
- + "0E05001036313233343536373839414243444546"); // AT_IDENTITY attribute
-
- private static final byte[] EAP_AKA_PRIME_CHALLENGE_REQUEST =
- hexStringToByteArray(
- "01CE0044" // EAP-Request | ID | length in bytes
- + "32010000" // EAP-AKA' | Challenge | 2B padding
- + "01050000" + RAND_1 // AT_RAND attribute
- + "02050000" + AUTN // AT_AUTN attribute
- + "1704000C" + SERVER_NETWORK_NAME // AT_KDF_INPUT attribute
- + "18010001" // AT_KDF attribute
- + "0B050000" + REQUEST_MAC); // AT_MAC attribute
- private static final byte[] EAP_AKA_PRIME_CHALLENGE_RESPONSE =
- hexStringToByteArray(
- "02CE0030" // EAP-Response | ID | length in bytes
- + "32010000" // EAP-AKA' | Challenge | 2B padding
- + "03050080" + RES // AT_RES attribute
- + "0B050000" + RESPONSE_MAC); // AT_MAC attribute
-
- private static final byte[] EAP_AKA_PRIME_CHALLENGE_REQUEST_WITHOUT_IDENTITY_REQ =
- hexStringToByteArray(
- "01CE0044" // EAP-Request | ID | length in bytes
- + "32010000" // EAP-AKA' | Challenge | 2B padding
- + "01050000" + RAND_1 // AT_RAND attribute
- + "02050000" + AUTN // AT_AUTN attribute
- + "1704000C" + SERVER_NETWORK_NAME // AT_KDF_INPUT attribute
- + "18010001" // AT_KDF attribute
- + "0B050000" + REQUEST_MAC_WITHOUT_IDENTITY_REQ); // AT_MAC attribute
- private static final byte[] EAP_AKA_PRIME_CHALLENGE_RESPONSE_WITHOUT_IDENTITY_REQUEST =
- hexStringToByteArray(
- "02CE0030" // EAP-Response | ID | length in bytes
- + "32010000" // EAP-AKA' | Challenge | 2B padding
- + "03050080" + RES // AT_RES attribute
- + "0B050000" + RESPONSE_MAC_WITHOUT_IDENTITY_REQ); // AT_MAC attribute
-
- private static final byte[] EAP_AKA_PRIME_CHALLENGE_REQUEST_SYNC_FAIL =
- hexStringToByteArray(
- "01CE0044" // EAP-Request | ID | length in bytes
- + "32010000" // EAP-AKA' | Challenge | 2B padding
- + "01050000" + RAND_2 // AT_RAND attribute
- + "02050000" + AUTN // AT_AUTN attribute
- + "1704000C" + SERVER_NETWORK_NAME // AT_KDF_INPUT attribute
- + "18010001" // AT_KDF attribute
- + "0B050000" + REQUEST_MAC); // AT_MAC attribute
- private static final byte[] EAP_AKA_PRIME_SYNC_FAIL_RESPONSE =
- hexStringToByteArray(
- "02CE0018" // EAP-Response | ID | length in bytes
- + "32040000" // EAP-AKA' | Synchronization-Failure | 2B padding
- + "0404" + AUTS); // AT_AUTS attribute
-
- private static final byte[] EAP_AKA_PRIME_AUTHENTICATION_REJECT =
- hexStringToByteArray(
- "02CE0008" // EAP-Response | ID | length in bytes
- + "32020000"); // EAP-AKA' | Authentication-Reject | 2B padding
-
- private static final byte[] EAP_RESPONSE_NAK_PACKET =
- hexStringToByteArray("021000060332"); // NAK with EAP-AKA' listed
-
- private TelephonyManager mMockTelephonyManager;
-
- @Before
- @Override
- public void setUp() {
- super.setUp();
-
- setUp(ALLOW_MISMATCHED_NETWORK_NAMES, PEER_NETWORK_NAME_1);
- }
-
- private void setUp(boolean allowMismatchedNetworkNames, String peerNetworkName) {
- mMockTelephonyManager = mock(TelephonyManager.class);
-
- mEapSessionConfig =
- new EapSessionConfig.Builder()
- .setEapIdentity(EAP_IDENTITY)
- .setEapAkaPrimeConfig(
- SUB_ID, APPTYPE_USIM, peerNetworkName, allowMismatchedNetworkNames)
- .build();
- mEapAuthenticator =
- new EapAuthenticator(
- mTestLooper.getLooper(),
- mMockCallback,
- new EapStateMachine(mMockContext, mEapSessionConfig, mMockSecureRandom),
- (runnable) -> runnable.run(),
- AUTHENTICATOR_TIMEOUT_MILLIS);
-
- when(mMockContext.getSystemService(Context.TELEPHONY_SERVICE))
- .thenReturn(mMockTelephonyManager);
- when(mMockTelephonyManager.createForSubscriptionId(SUB_ID))
- .thenReturn(mMockTelephonyManager);
- }
-
- @Test
- public void testEapAkaPrimeEndToEnd() {
- verifyEapPrimeAkaIdentity();
- verifyEapAkaPrimeChallenge(BASE_64_RESPONSE_SUCCESS, EAP_AKA_PRIME_CHALLENGE_RESPONSE);
- verifyEapSuccess(MSK, EMSK);
- }
-
- @Test
- public void testEapAkaPrimeEndToEndWithoutIdentityRequest() {
- verifyEapAkaPrimeChallengeWithoutIdentityReq();
- verifyEapSuccess(MSK_WITHOUT_IDENTITY_REQ, EMSK_WITHOUT_IDENTITY_REQ);
- }
-
- @Test
- public void testEapAkaPrimeWithEapNotifications() {
- verifyEapNotification(1);
- verifyEapPrimeAkaIdentity();
-
- verifyEapNotification(2);
- verifyEapAkaPrimeChallenge(BASE_64_RESPONSE_SUCCESS, EAP_AKA_PRIME_CHALLENGE_RESPONSE);
-
- verifyEapNotification(3);
- verifyEapSuccess(MSK, EMSK);
- }
-
- @Test
- public void testEapAkaPrimeUnsupportedType() {
- verifyUnsupportedType(EAP_REQUEST_SIM_START_PACKET, EAP_RESPONSE_NAK_PACKET);
-
- verifyEapPrimeAkaIdentity();
- verifyEapAkaPrimeChallenge(BASE_64_RESPONSE_SUCCESS, EAP_AKA_PRIME_CHALLENGE_RESPONSE);
- verifyEapSuccess(MSK, EMSK);
- }
-
- @Test
- public void testEapAkaPrimeSynchronizationFailure() {
- verifyEapPrimeAkaIdentity();
- verifyEapAkaPrimeSynchronizationFailure();
- verifyEapAkaPrimeChallenge(BASE_64_RESPONSE_SUCCESS, EAP_AKA_PRIME_CHALLENGE_RESPONSE);
- verifyEapSuccess(MSK, EMSK);
- }
-
- @Test
- public void testEapAkaPrimeAuthenticationReject() {
- verifyEapPrimeAkaIdentity();
-
- // return null from TelephonyManager to simluate rejection of AUTN
- verifyEapAkaPrimeChallenge(null, EAP_AKA_PRIME_AUTHENTICATION_REJECT);
- verifyEapFailure();
- }
-
- @Test
- public void testEapAkaPrimeMismatchedNetworkNamesNotAllowed() {
- // use mismatched peer network name
- setUp(false, PEER_NETWORK_NAME_2);
- verifyEapPrimeAkaIdentity();
- verifyEapAkaPrimeChallengeMismatchedNetworkNames();
- verifyEapFailure();
- }
-
- @Test
- public void testEapAkaPrimeMismatchedNetworkNamesAllowed() {
- setUp(true, PEER_NETWORK_NAME_2);
- verifyEapPrimeAkaIdentity();
- verifyEapAkaPrimeChallenge(BASE_64_RESPONSE_SUCCESS, EAP_AKA_PRIME_CHALLENGE_RESPONSE);
- verifyEapSuccess(MSK, EMSK);
- }
-
- private void verifyEapPrimeAkaIdentity() {
- // EAP-AKA'/Identity request
- when(mMockTelephonyManager.getSubscriberId()).thenReturn(UNFORMATTED_IDENTITY);
-
- mEapAuthenticator.processEapMessage(EAP_AKA_PRIME_IDENTITY_REQUEST);
- mTestLooper.dispatchAll();
-
- // verify EAP-AKA'/Identity response
- verify(mMockContext).getSystemService(eq(Context.TELEPHONY_SERVICE));
- verify(mMockTelephonyManager).createForSubscriptionId(SUB_ID);
- verify(mMockTelephonyManager).getSubscriberId();
- verify(mMockCallback).onResponse(eq(EAP_AKA_PRIME_IDENTITY_RESPONSE));
- verifyNoMoreInteractions(
- mMockContext, mMockTelephonyManager, mMockSecureRandom, mMockCallback);
- }
-
- private void verifyEapAkaPrimeChallenge(
- String challengeBase64,
- String responseBase64,
- byte[] incomingEapPacket,
- byte[] outgoingEapPacket) {
- // EAP-AKA'/Challenge request
- when(mMockTelephonyManager.getIccAuthentication(
- TelephonyManager.APPTYPE_USIM,
- TelephonyManager.AUTHTYPE_EAP_AKA,
- challengeBase64))
- .thenReturn(responseBase64);
-
- mEapAuthenticator.processEapMessage(incomingEapPacket);
- mTestLooper.dispatchAll();
-
- // verify EAP-AKA'/Challenge response
- verify(mMockTelephonyManager)
- .getIccAuthentication(
- TelephonyManager.APPTYPE_USIM,
- TelephonyManager.AUTHTYPE_EAP_AKA,
- challengeBase64);
- verify(mMockCallback).onResponse(eq(outgoingEapPacket));
- }
-
- private void verifyEapAkaPrimeChallenge(String responseBase64, byte[] outgoingPacket) {
- verifyEapAkaPrimeChallenge(
- BASE64_CHALLENGE_1,
- responseBase64,
- EAP_AKA_PRIME_CHALLENGE_REQUEST,
- outgoingPacket);
- verifyNoMoreInteractions(
- mMockContext, mMockTelephonyManager, mMockSecureRandom, mMockCallback);
- }
-
- private void verifyEapAkaPrimeChallengeWithoutIdentityReq() {
- verifyEapAkaPrimeChallenge(
- BASE64_CHALLENGE_1,
- BASE_64_RESPONSE_SUCCESS,
- EAP_AKA_PRIME_CHALLENGE_REQUEST_WITHOUT_IDENTITY_REQ,
- EAP_AKA_PRIME_CHALLENGE_RESPONSE_WITHOUT_IDENTITY_REQUEST);
-
- // also need to verify interactions with Context and TelephonyManager
- verify(mMockContext).getSystemService(eq(Context.TELEPHONY_SERVICE));
- verify(mMockTelephonyManager).createForSubscriptionId(SUB_ID);
- verifyNoMoreInteractions(
- mMockContext, mMockTelephonyManager, mMockSecureRandom, mMockCallback);
- }
-
- private void verifyEapAkaPrimeSynchronizationFailure() {
- verifyEapAkaPrimeChallenge(
- BASE64_CHALLENGE_2,
- BASE_64_RESPONSE_SYNC_FAIL,
- EAP_AKA_PRIME_CHALLENGE_REQUEST_SYNC_FAIL,
- EAP_AKA_PRIME_SYNC_FAIL_RESPONSE);
- verifyNoMoreInteractions(
- mMockContext, mMockTelephonyManager, mMockSecureRandom, mMockCallback);
- }
-
- private void verifyEapAkaPrimeChallengeMismatchedNetworkNames() {
- // EAP-AKA'/Challenge request
- mEapAuthenticator.processEapMessage(EAP_AKA_PRIME_CHALLENGE_REQUEST);
- mTestLooper.dispatchAll();
- verify(mMockCallback).onResponse(eq(EAP_AKA_PRIME_AUTHENTICATION_REJECT));
- }
-
- @Override
- protected void verifyEapSuccess(byte[] msk, byte[] emsk) {
- super.verifyEapSuccess(msk, emsk);
-
- verifyNoMoreInteractions(mMockTelephonyManager);
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/EapAkaTest.java b/tests/iketests/src/java/com/android/internal/net/eap/EapAkaTest.java
deleted file mode 100644
index e982a85d..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/EapAkaTest.java
+++ /dev/null
@@ -1,332 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap;
-
-import static android.telephony.TelephonyManager.APPTYPE_USIM;
-
-import static com.android.internal.net.TestUtils.hexStringToByteArray;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_REQUEST_SIM_START_PACKET;
-
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.net.eap.EapSessionConfig;
-import android.telephony.TelephonyManager;
-
-import com.android.internal.net.eap.statemachine.EapStateMachine;
-
-import org.junit.Before;
-import org.junit.Test;
-
-/**
- * This test verifies that EAP-AKA is functional for an end-to-end implementation
- */
-public class EapAkaTest extends EapMethodEndToEndTest {
- private static final long AUTHENTICATOR_TIMEOUT_MILLIS = 250L;
-
- private static final int SUB_ID = 1;
- private static final String UNFORMATTED_IDENTITY = "123456789ABCDEF"; // IMSI
-
- // EAP_IDENTITY = hex("test@android.net")
- private static final byte[] EAP_IDENTITY =
- hexStringToByteArray("7465737440616E64726F69642E6E6574");
-
- // TODO(b/140797965): find valid AUTN/RAND values for the CTS test sim
- // IK: 7320EE404E055EF2B5AB0F86E96C48BE
- // CK: E9D1707652E13BF3E05975F601678E5C
- // MK: 2AE8AD50432246E6ACED9AA0FC794A22CE9CE4BB
- // K_encr: DB6F06910D5D19CC9DA5F2687F5C5737
- // K_aut: B20A586592796E08E7408FB53356E9B1
- private static final String RAND_1 = "D6A296F030A305601B311D38A004505C";
- private static final String RAND_2 = "000102030405060708090A0B0C0D0E0F";
- private static final String AUTN = "35A9143ED9E100011795E785DAFAAD9B";
- private static final String RES = "E5167A255FDCDE9248AF6B50ADA0D944";
- private static final String AUTS = "0102030405060708090A0B0C0D0E";
- private static final byte[] MSK =
- hexStringToByteArray(
- "EFC4FB9F54D99A3F4A04B756993CA813"
- + "E463CA0ADBF3CB2A296519ED4C600FF5"
- + "81898B1C425C20FE7471FC43A4BB3C00"
- + "DDF80A7083972B660BC7153CBF2C9AA1");
- private static final byte[] EMSK =
- hexStringToByteArray(
- "5C95F3E2476ED4D6588CE6DE2618D808"
- + "9ECA12A4636C8A1B0C678562CBFC31D3"
- + "94B578DE0A3686E17F96F14D5341FE75"
- + "2012944CA394E5288BA1B2C70CB65063");
-
- // IK: 7320EE404E055EF2B5AB0F86E96C48BE
- // CK: E9D1707652E13BF3E05975F601678E5C
- // MK: 8183017CD8ADDB4617F4A2274DD5BCEA99354FB7
- // K_encr: 891D5DB8CACAF657D68BE72371F927A2
- // K_aut: E042A1CC5672358685EC012881EA02DE
- private static final byte[] MSK_WITHOUT_IDENTITY_REQ =
- hexStringToByteArray(
- "629DE03704E15EF1B8BADFF7FA5D84D5"
- + "8574B6A3A46F274796346A86AE3455AC"
- + "711E2D4D3F96EE71E664B1B947D7E9E7"
- + "D227CBB6199A68BD7D43E6E4863D08D6");
- private static final byte[] EMSK_WITHOUT_IDENTITY_REQ =
- hexStringToByteArray(
- "30A6638AE3AB5C5D29554D8256C3A287"
- + "FDF6255E4D726C0622DDF89609C16A8D"
- + "563768166A8111A083547DE4C8E280D6"
- + "113A608DE9227FC7C02679A1E04DB3CF");
-
- // Base 64 of: [Length][RAND_1][Length][AUTN]
- private static final String BASE64_CHALLENGE_1 =
- "ENailvAwowVgGzEdOKAEUFwQNakUPtnhAAEXleeF2vqtmw==";
-
- // Base 64 of: ['DB'][Length][RES][Length][IK][Length][CK]
- private static final String BASE_64_RESPONSE_SUCCESS =
- "2xDlFnolX9zekkiva1CtoNlEEHMg7kBOBV7ytasPhulsSL4Q6dFwdlLhO/PgWXX2AWeOXA==";
-
- // Base 64 of: [Length][RAND_2][Length][AUTN]
- private static final String BASE64_CHALLENGE_2 =
- "EAABAgMEBQYHCAkKCwwNDg8QNakUPtnhAAEXleeF2vqtmw==";
-
- // Base 64 of: ['DC'][Length][AUTS]
- private static final String BASE_64_RESPONSE_SYNC_FAIL = "3A4BAgMEBQYHCAkKCwwNDg==";
-
- private static final String REQUEST_MAC = "90C3554783D49A18F9EAA231F3C261EC";
- private static final String RESPONSE_MAC = "D085987D3D15FA50A80D0CECFA2412EB";
- private static final String REQUEST_MAC_WITHOUT_IDENTITY_REQ =
- "6AD7E3F43ED99384E751F55AB8EA48B4";
- private static final String RESPONSE_MAC_WITHOUT_IDENTITY_REQ =
- "83E9F5B8B44BDE39B50538BF49864209";
-
- private static final byte[] EAP_AKA_IDENTITY_REQUEST =
- hexStringToByteArray(
- "01CD000C" // EAP-Request | ID | length in bytes
- + "17050000" // EAP-AKA | Identity | 2B padding
- + "0D010000"); // AT_ANY_ID_REQ attribute
- private static final byte[] EAP_AKA_IDENTITY_RESPONSE =
- hexStringToByteArray(
- "02CD001C" // EAP-Response | ID | length in bytes
- + "17050000" // EAP-AKA | Identity | 2B padding
- + "0E05001030313233343536373839414243444546"); // AT_IDENTITY attribute
-
- private static final byte[] EAP_AKA_CHALLENGE_REQUEST =
- hexStringToByteArray(
- "01CE0044" // EAP-Request | ID | length in bytes
- + "17010000" // EAP-AKA | Challenge | 2B padding
- + "01050000" + RAND_1 // AT_RAND attribute
- + "02050000" + AUTN // AT_AUTN attribute
- + "0B050000" + REQUEST_MAC); // AT_MAC attribute
- private static final byte[] EAP_AKA_CHALLENGE_RESPONSE =
- hexStringToByteArray(
- "02CE0030" // EAP-Response | ID | length in bytes
- + "17010000" // EAP-AKA | Challenge | 2B padding
- + "03050080" + RES // AT_RES attribute
- + "0B050000" + RESPONSE_MAC); // AT_MAC attribute
-
- private static final byte[] EAP_AKA_CHALLENGE_REQUEST_WITHOUT_IDENTITY_REQ =
- hexStringToByteArray(
- "01CE0044" // EAP-Request | ID | length in bytes
- + "17010000" // EAP-AKA | Challenge | 2B padding
- + "01050000" + RAND_1 // AT_RAND attribute
- + "02050000" + AUTN // AT_AUTN attribute
- + "0B050000" + REQUEST_MAC_WITHOUT_IDENTITY_REQ); // AT_MAC attribute
- private static final byte[] EAP_AKA_CHALLENGE_RESPONSE_WITHOUT_IDENTITY_REQUEST =
- hexStringToByteArray(
- "02CE0030" // EAP-Response | ID | length in bytes
- + "17010000" // EAP-AKA | Challenge | 2B padding
- + "03050080" + RES // AT_RES attribute
- + "0B050000" + RESPONSE_MAC_WITHOUT_IDENTITY_REQ); // AT_MAC attribute
-
- private static final byte[] EAP_AKA_CHALLENGE_REQUEST_SYNC_FAIL =
- hexStringToByteArray(
- "01CE0044" // EAP-Request | ID | length in bytes
- + "17010000" // EAP-AKA | Challenge | 2B padding
- + "01050000" + RAND_2 // AT_RAND attribute
- + "02050000" + AUTN // AT_AUTN attribute
- + "0B050000" + REQUEST_MAC); // AT_MAC attribute
- private static final byte[] EAP_AKA_SYNC_FAIL_RESPONSE =
- hexStringToByteArray(
- "02CE0018" // EAP-Response | ID | length in bytes
- + "17040000" // EAP-AKA | Synchronization-Failure | 2B padding
- + "0404" + AUTS); // AT_AUTS attribute
-
- private static final byte[] EAP_AKA_AUTHENTICATION_REJECT =
- hexStringToByteArray(
- "02CE0008" // EAP-Response | ID | length in bytes
- + "17020000"); // EAP-AKA | Authentication-Reject | 2B padding
-
- private static final byte[] EAP_RESPONSE_NAK_PACKET =
- hexStringToByteArray("021000060317"); // NAK with EAP-AKA listed
-
- private TelephonyManager mMockTelephonyManager;
-
- @Before
- @Override
- public void setUp() {
- super.setUp();
-
- mMockTelephonyManager = mock(TelephonyManager.class);
-
- mEapSessionConfig =
- new EapSessionConfig.Builder()
- .setEapIdentity(EAP_IDENTITY)
- .setEapAkaConfig(SUB_ID, APPTYPE_USIM)
- .build();
- mEapAuthenticator =
- new EapAuthenticator(
- mTestLooper.getLooper(),
- mMockCallback,
- new EapStateMachine(mMockContext, mEapSessionConfig, mMockSecureRandom),
- (runnable) -> runnable.run(),
- AUTHENTICATOR_TIMEOUT_MILLIS);
-
- when(mMockContext.getSystemService(Context.TELEPHONY_SERVICE))
- .thenReturn(mMockTelephonyManager);
- when(mMockTelephonyManager.createForSubscriptionId(SUB_ID))
- .thenReturn(mMockTelephonyManager);
- }
-
- @Test
- public void testEapAkaEndToEnd() {
- verifyEapAkaIdentity();
- verifyEapAkaChallenge(BASE_64_RESPONSE_SUCCESS, EAP_AKA_CHALLENGE_RESPONSE);
- verifyEapSuccess(MSK, EMSK);
- }
-
- @Test
- public void testEapAkaEndToEndWithoutIdentityRequest() {
- verifyEapAkaChallengeWithoutIdentityReq();
- verifyEapSuccess(MSK_WITHOUT_IDENTITY_REQ, EMSK_WITHOUT_IDENTITY_REQ);
- }
-
- @Test
- public void testEapAkaWithEapNotifications() {
- verifyEapNotification(1);
- verifyEapAkaIdentity();
-
- verifyEapNotification(2);
- verifyEapAkaChallenge(BASE_64_RESPONSE_SUCCESS, EAP_AKA_CHALLENGE_RESPONSE);
-
- verifyEapNotification(3);
- verifyEapSuccess(MSK, EMSK);
- }
-
- @Test
- public void testEapAkaUnsupportedType() {
- verifyUnsupportedType(EAP_REQUEST_SIM_START_PACKET, EAP_RESPONSE_NAK_PACKET);
-
- verifyEapAkaIdentity();
- verifyEapAkaChallenge(BASE_64_RESPONSE_SUCCESS, EAP_AKA_CHALLENGE_RESPONSE);
- verifyEapSuccess(MSK, EMSK);
- }
-
- @Test
- public void testEapAkaSynchronizationFailure() {
- verifyEapAkaIdentity();
- verifyEapAkaSynchronizationFailure();
- verifyEapAkaChallenge(BASE_64_RESPONSE_SUCCESS, EAP_AKA_CHALLENGE_RESPONSE);
- verifyEapSuccess(MSK, EMSK);
- }
-
- @Test
- public void testEapAkaAuthenticationReject() {
- verifyEapAkaIdentity();
-
- // return null from TelephonyManager to simluate rejection of AUTN
- verifyEapAkaChallenge(null, EAP_AKA_AUTHENTICATION_REJECT);
- verifyEapFailure();
- }
-
- private void verifyEapAkaIdentity() {
- // EAP-AKA/Identity request
- when(mMockTelephonyManager.getSubscriberId()).thenReturn(UNFORMATTED_IDENTITY);
-
- mEapAuthenticator.processEapMessage(EAP_AKA_IDENTITY_REQUEST);
- mTestLooper.dispatchAll();
-
- // verify EAP-AKA/Identity response
- verify(mMockContext).getSystemService(eq(Context.TELEPHONY_SERVICE));
- verify(mMockTelephonyManager).createForSubscriptionId(SUB_ID);
- verify(mMockTelephonyManager).getSubscriberId();
- verify(mMockCallback).onResponse(eq(EAP_AKA_IDENTITY_RESPONSE));
- verifyNoMoreInteractions(
- mMockContext, mMockTelephonyManager, mMockSecureRandom, mMockCallback);
- }
-
- private void verifyEapAkaChallenge(
- String challengeBase64,
- String responseBase64,
- byte[] incomingEapPacket,
- byte[] outgoingEapPacket) {
- // EAP-AKA/Challenge request
- when(mMockTelephonyManager.getIccAuthentication(
- TelephonyManager.APPTYPE_USIM,
- TelephonyManager.AUTHTYPE_EAP_AKA,
- challengeBase64))
- .thenReturn(responseBase64);
-
- mEapAuthenticator.processEapMessage(incomingEapPacket);
- mTestLooper.dispatchAll();
-
- // verify EAP-AKA/Challenge response
- verify(mMockTelephonyManager)
- .getIccAuthentication(
- TelephonyManager.APPTYPE_USIM,
- TelephonyManager.AUTHTYPE_EAP_AKA,
- challengeBase64);
- verify(mMockCallback).onResponse(eq(outgoingEapPacket));
- }
-
- private void verifyEapAkaChallenge(String responseBase64, byte[] outgoingPacket) {
- verifyEapAkaChallenge(
- BASE64_CHALLENGE_1, responseBase64, EAP_AKA_CHALLENGE_REQUEST, outgoingPacket);
- verifyNoMoreInteractions(
- mMockContext, mMockTelephonyManager, mMockSecureRandom, mMockCallback);
- }
-
- private void verifyEapAkaChallengeWithoutIdentityReq() {
- verifyEapAkaChallenge(
- BASE64_CHALLENGE_1,
- BASE_64_RESPONSE_SUCCESS,
- EAP_AKA_CHALLENGE_REQUEST_WITHOUT_IDENTITY_REQ,
- EAP_AKA_CHALLENGE_RESPONSE_WITHOUT_IDENTITY_REQUEST);
-
- // also need to verify interactions with Context and TelephonyManager
- verify(mMockContext).getSystemService(eq(Context.TELEPHONY_SERVICE));
- verify(mMockTelephonyManager).createForSubscriptionId(SUB_ID);
- verifyNoMoreInteractions(
- mMockContext, mMockTelephonyManager, mMockSecureRandom, mMockCallback);
- }
-
- private void verifyEapAkaSynchronizationFailure() {
- verifyEapAkaChallenge(
- BASE64_CHALLENGE_2,
- BASE_64_RESPONSE_SYNC_FAIL,
- EAP_AKA_CHALLENGE_REQUEST_SYNC_FAIL,
- EAP_AKA_SYNC_FAIL_RESPONSE);
- verifyNoMoreInteractions(
- mMockContext, mMockTelephonyManager, mMockSecureRandom, mMockCallback);
- }
-
- @Override
- protected void verifyEapSuccess(byte[] msk, byte[] emsk) {
- super.verifyEapSuccess(msk, emsk);
-
- verifyNoMoreInteractions(mMockTelephonyManager);
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/EapAuthenticatorTest.java b/tests/iketests/src/java/com/android/internal/net/eap/EapAuthenticatorTest.java
deleted file mode 100644
index 4c868a03..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/EapAuthenticatorTest.java
+++ /dev/null
@@ -1,256 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap;
-
-import static com.android.internal.net.TestUtils.hexStringToByteArray;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_FAILURE_PACKET;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_REQUEST_SIM_START_PACKET;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_SIM_RESPONSE_PACKET;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_SUCCESS_PACKET;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.REQUEST_UNSUPPORTED_TYPE_PACKET;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-import android.os.Looper;
-import android.os.test.TestLooper;
-
-import com.android.internal.net.eap.EapResult.EapError;
-import com.android.internal.net.eap.EapResult.EapFailure;
-import com.android.internal.net.eap.EapResult.EapResponse;
-import com.android.internal.net.eap.EapResult.EapSuccess;
-import com.android.internal.net.eap.exceptions.EapInvalidRequestException;
-import com.android.internal.net.eap.statemachine.EapStateMachine;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.util.concurrent.TimeoutException;
-
-public class EapAuthenticatorTest {
- private static final long AUTHENTICATOR_TIMEOUT_MILLIS = 250L;
- private static final long TEST_TIMEOUT_MILLIS = 2 * AUTHENTICATOR_TIMEOUT_MILLIS;
- private static final byte[] MSK = hexStringToByteArray(
- "00112233445566778899AABBCCDDEEFF"
- + "00112233445566778899AABBCCDDEEFF"
- + "00112233445566778899AABBCCDDEEFF"
- + "00112233445566778899AABBCCDDEEFF");
- private static final byte[] EMSK = hexStringToByteArray(
- "FFEEDDCCBBAA99887766554433221100"
- + "FFEEDDCCBBAA99887766554433221100"
- + "FFEEDDCCBBAA99887766554433221100"
- + "FFEEDDCCBBAA99887766554433221100");
-
- private EapStateMachine mMockEapStateMachine;
-
- private TestLooper mTestLooper;
- private boolean mCallbackFired;
-
- @Before
- public void setUp() {
- if (Looper.myLooper() == null) Looper.prepare();
-
- mMockEapStateMachine = mock(EapStateMachine.class);
-
- mTestLooper = new TestLooper();
- mCallbackFired = false;
- }
-
- @Test
- public void testProcessEapMessageResponse() {
- EapCallback eapCallback = new EapCallback() {
- @Override
- public void onResponse(byte[] eapMsg) {
- assertArrayEquals(EAP_SIM_RESPONSE_PACKET, eapMsg);
- assertFalse("Callback has already been fired", mCallbackFired);
- mCallbackFired = true;
- }
- };
-
- EapResponse eapResponse = new EapResponse(EAP_SIM_RESPONSE_PACKET);
- when(mMockEapStateMachine.process(eq(EAP_REQUEST_SIM_START_PACKET)))
- .thenReturn(eapResponse);
-
- getEapAuthenticatorWithCallback(eapCallback)
- .processEapMessage(EAP_REQUEST_SIM_START_PACKET);
- mTestLooper.dispatchAll();
-
- assertTrue("Callback didn't fire", mCallbackFired);
- verify(mMockEapStateMachine).process(eq(EAP_REQUEST_SIM_START_PACKET));
- verifyNoMoreInteractions(mMockEapStateMachine);
- }
-
- @Test
- public void testProcessEapMessageError() {
- EapCallback eapCallback = new EapCallback() {
- @Override
- public void onError(Throwable cause) {
- assertTrue(cause instanceof EapInvalidRequestException);
- assertFalse("Callback has already been fired", mCallbackFired);
- mCallbackFired = true;
- }
- };
- Exception cause = new EapInvalidRequestException("Error");
- EapError eapError = new EapError(cause);
- when(mMockEapStateMachine.process(eq(REQUEST_UNSUPPORTED_TYPE_PACKET)))
- .thenReturn(eapError);
-
- getEapAuthenticatorWithCallback(eapCallback)
- .processEapMessage(REQUEST_UNSUPPORTED_TYPE_PACKET);
- mTestLooper.dispatchAll();
-
- assertTrue("Callback didn't fire", mCallbackFired);
- verify(mMockEapStateMachine).process(eq(REQUEST_UNSUPPORTED_TYPE_PACKET));
- verifyNoMoreInteractions(mMockEapStateMachine);
- }
-
- @Test
- public void testProcessEapMessageSuccess() {
- EapCallback eapCallback = new EapCallback() {
- @Override
- public void onSuccess(byte[] msk, byte[] emsk) {
- assertArrayEquals(MSK, msk);
- assertArrayEquals(EMSK, emsk);
- assertFalse("Callback has already been fired", mCallbackFired);
- mCallbackFired = true;
- }
- };
- EapSuccess eapSuccess = new EapSuccess(MSK, EMSK);
- when(mMockEapStateMachine.process(eq(EAP_SUCCESS_PACKET)))
- .thenReturn(eapSuccess);
-
- getEapAuthenticatorWithCallback(eapCallback)
- .processEapMessage(EAP_SUCCESS_PACKET);
- mTestLooper.dispatchAll();
-
- assertTrue("Callback didn't fire", mCallbackFired);
- verify(mMockEapStateMachine).process(eq(EAP_SUCCESS_PACKET));
- verifyNoMoreInteractions(mMockEapStateMachine);
- }
-
- @Test
- public void testProcessEapMessageFailure() {
- EapCallback eapCallback = new EapCallback() {
- @Override
- public void onFail() {
- // nothing to check here
- assertFalse("Callback has already been fired", mCallbackFired);
- mCallbackFired = true;
- }
- };
- when(mMockEapStateMachine.process(eq(EAP_FAILURE_PACKET)))
- .thenReturn(new EapFailure());
-
- getEapAuthenticatorWithCallback(eapCallback)
- .processEapMessage(EAP_FAILURE_PACKET);
- mTestLooper.dispatchAll();
-
- assertTrue("Callback didn't fire", mCallbackFired);
- verify(mMockEapStateMachine).process(eq(EAP_FAILURE_PACKET));
- verifyNoMoreInteractions(mMockEapStateMachine);
- }
-
- @Test
- public void testProcessEapMessageExceptionThrown() {
- EapCallback eapCallback = new EapCallback() {
- @Override
- public void onError(Throwable cause) {
- assertTrue(cause instanceof NullPointerException);
- assertFalse("Callback has already been fired", mCallbackFired);
- mCallbackFired = true;
- }
- };
- when(mMockEapStateMachine.process(EAP_REQUEST_SIM_START_PACKET))
- .thenThrow(new NullPointerException());
-
- getEapAuthenticatorWithCallback(eapCallback)
- .processEapMessage(EAP_REQUEST_SIM_START_PACKET);
- mTestLooper.dispatchAll();
-
- assertTrue("Callback didn't fire", mCallbackFired);
- verify(mMockEapStateMachine).process(eq(EAP_REQUEST_SIM_START_PACKET));
- verifyNoMoreInteractions(mMockEapStateMachine);
- }
-
- @Test
- public void testProcessEapMessageStateMachineTimeout() {
- EapCallback eapCallback = new EapCallback() {
- @Override
- public void onError(Throwable cause) {
- assertTrue(cause instanceof TimeoutException);
- assertFalse("Callback has already been fired", mCallbackFired);
- mCallbackFired = true;
- }
- };
- EapResponse eapResponse = new EapResponse(EAP_SIM_RESPONSE_PACKET);
- when(mMockEapStateMachine.process(eq(EAP_REQUEST_SIM_START_PACKET)))
- .then((invocation) -> {
- // move time forward to trigger the timeout
- mTestLooper.moveTimeForward(TEST_TIMEOUT_MILLIS);
- return eapResponse;
- });
-
- getEapAuthenticatorWithCallback(eapCallback)
- .processEapMessage(EAP_REQUEST_SIM_START_PACKET);
- mTestLooper.dispatchAll();
-
- assertTrue("Callback didn't fire", mCallbackFired);
- verify(mMockEapStateMachine).process(eq(EAP_REQUEST_SIM_START_PACKET));
- verifyNoMoreInteractions(mMockEapStateMachine);
- }
-
- private EapAuthenticator getEapAuthenticatorWithCallback(EapCallback eapCallback) {
- return new EapAuthenticator(
- mTestLooper.getLooper(),
- eapCallback,
- mMockEapStateMachine,
- (runnable) -> runnable.run(),
- AUTHENTICATOR_TIMEOUT_MILLIS);
- }
-
- /**
- * Default {@link IEapCallback} implementation that throws {@link UnsupportedOperationException}
- * for all calls.
- */
- private abstract static class EapCallback implements IEapCallback {
- @Override
- public void onSuccess(byte[] msk, byte[] emsk) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void onFail() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void onResponse(byte[] eapMsg) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void onError(Throwable cause) {
- throw new UnsupportedOperationException();
- }
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/EapErrorTest.java b/tests/iketests/src/java/com/android/internal/net/eap/EapErrorTest.java
deleted file mode 100644
index ce497635..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/EapErrorTest.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap;
-
-import static org.junit.Assert.assertEquals;
-
-import com.android.internal.net.eap.EapResult.EapError;
-
-import org.junit.Test;
-
-public class EapErrorTest {
- private static final RuntimeException EXPECTED_EXCEPTION = new RuntimeException("expected");
-
- @Test
- public void testEapErrorConstructor() {
- EapError eapError = new EapError(EXPECTED_EXCEPTION);
- assertEquals(EXPECTED_EXCEPTION, eapError.cause);
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/EapMethodEndToEndTest.java b/tests/iketests/src/java/com/android/internal/net/eap/EapMethodEndToEndTest.java
deleted file mode 100644
index 412a4cf1..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/EapMethodEndToEndTest.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap;
-
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_FAILURE_PACKET;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_REQUEST_NOTIFICATION_PACKET;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_RESPONSE_NOTIFICATION_PACKET;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_SUCCESS;
-
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-
-import android.content.Context;
-import android.net.eap.EapSessionConfig;
-import android.os.test.TestLooper;
-
-import org.junit.Before;
-
-import java.security.SecureRandom;
-
-public class EapMethodEndToEndTest {
- protected Context mMockContext;
- protected SecureRandom mMockSecureRandom;
- protected IEapCallback mMockCallback;
-
- protected TestLooper mTestLooper;
- protected EapSessionConfig mEapSessionConfig;
- protected EapAuthenticator mEapAuthenticator;
-
- @Before
- public void setUp() {
- mMockContext = mock(Context.class);
- mMockSecureRandom = mock(SecureRandom.class);
- mMockCallback = mock(IEapCallback.class);
-
- mTestLooper = new TestLooper();
- }
-
- protected void verifyUnsupportedType(byte[] invalidMessageType, byte[] nakResponse) {
- mEapAuthenticator.processEapMessage(invalidMessageType);
- mTestLooper.dispatchAll();
-
- // verify EAP-Response/Nak returned
- verify(mMockCallback).onResponse(eq(nakResponse));
- verifyNoMoreInteractions(mMockCallback);
- }
-
- protected void verifyEapNotification(int callsToVerify) {
- mEapAuthenticator.processEapMessage(EAP_REQUEST_NOTIFICATION_PACKET);
- mTestLooper.dispatchAll();
-
- verify(mMockCallback, times(callsToVerify))
- .onResponse(eq(EAP_RESPONSE_NOTIFICATION_PACKET));
- verifyNoMoreInteractions(mMockCallback);
- }
-
- protected void verifyEapSuccess(byte[] msk, byte[] emsk) {
- // EAP-Success
- mEapAuthenticator.processEapMessage(EAP_SUCCESS);
- mTestLooper.dispatchAll();
-
- // verify that onSuccess callback made
- verify(mMockCallback).onSuccess(eq(msk), eq(emsk));
- verifyNoMoreInteractions(mMockContext, mMockSecureRandom, mMockCallback);
- }
-
- protected void verifyEapFailure() {
- mEapAuthenticator.processEapMessage(EAP_FAILURE_PACKET);
- mTestLooper.dispatchAll();
-
- verify(mMockCallback).onFail();
- verifyNoMoreInteractions(mMockCallback);
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/EapMsChapV2Test.java b/tests/iketests/src/java/com/android/internal/net/eap/EapMsChapV2Test.java
deleted file mode 100644
index 01264f9d..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/EapMsChapV2Test.java
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap;
-
-import static com.android.internal.net.TestUtils.hexStringToByteArray;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_REQUEST_AKA_IDENTITY_PACKET;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-
-import android.net.eap.EapSessionConfig;
-
-import com.android.internal.net.eap.statemachine.EapStateMachine;
-
-import org.junit.Before;
-import org.junit.Test;
-
-public class EapMsChapV2Test extends EapMethodEndToEndTest {
- private static final long AUTHENTICATOR_TIMEOUT_MILLIS = 250L;
-
- private static final String USERNAME = "User";
- private static final String PASSWORD = "clientPass";
-
- private static final byte[] PEER_CHALLENGE =
- hexStringToByteArray("21402324255E262A28295F2B3A337C7E");
- private static final byte[] MSK =
- hexStringToByteArray(
- "D5F0E9521E3EA9589645E86051C822268B7CDC149B993A1BA118CB153F56DCCB");
-
- // Server-Name = hex("authenticator@android.net")
- private static final byte[] EAP_MSCHAP_V2_CHALLENGE_REQUEST =
- hexStringToByteArray("01110033" // EAP-Request | ID | length in bytes
- + "1A0142" // EAP-MSCHAPv2 | Request | MSCHAPv2 ID
- + "002E10" // MS length | Value Size (0x10)
- + "5B5D7C7D7B3F2F3E3C2C602132262628" // Authenticator-Challenge
- + "61757468656E74696361746F7240616E64726F69642E6E6574"); // Server-Name
- private static final byte[] EAP_MSCHAP_V2_CHALLENGE_RESPONSE =
- hexStringToByteArray("0211003F" // EAP-Response | ID | length in bytes
- + "1A0242" // EAP-MSCHAPv2 | Response | MSCHAPv2 ID
- + "003A31" // MS length | Value Size (0x31)
- + "21402324255E262A28295F2B3A337C7E" // Peer-Challenge
- + "0000000000000000" // 8B (reserved)
- + "82309ECD8D708B5EA08FAA3981CD83544233114A3D85D6DF" // NT-Response
- + "00" // Flags
- + "55736572"); // hex(USERNAME)
- private static final byte[] EAP_MSCHAP_V2_SUCCESS_REQUEST =
- hexStringToByteArray("01120047" // EAP-Request | ID | length in bytes
- + "1A03420042" // EAP-MSCHAPv2 | Success | MSCHAPv2 ID | MS length
- + "533D" // hex("S=")
- + "3430374135353839313135464430443632303946"
- + "3531304645394330343536363933324344413536" // hex("<auth_string>")
- + "204D3D" // hex(" M=")
- + "7465737420416E64726F69642031323334"); // hex("test Android 1234")
- private static final byte[] EAP_MSCHAP_V2_SUCCESS_RESPONSE =
- hexStringToByteArray("02120006" // EAP-Response | ID | length in bytes
- + "1A03"); // EAP-MSCHAPv2 | Success
- private static final byte[] EAP_MSCHAP_V2_FAILURE_REQUEST =
- hexStringToByteArray("01130049" // EAP-Request | ID | length in bytes
- + "1A04420044" // EAP-MSCHAPv2 | Failure | MSCHAPv2 ID | MS length
- + "453D363437" // hex("E=647")
- + "20523D31" // hex(" R=1")
- + "20433D" // hex(" C=")
- + "30303031303230333034303530363037"
- + "30383039304130423043304430453046" // hex("<authenticator challenge>")
- + "20563D33" // hex(" V=3")
- + "204D3D" // hex(" M=")
- + "7465737420416E64726F69642031323334"); // hex("test Android 1234")
- private static final byte[] EAP_MSCHAP_V2_FAILURE_RESPONSE =
- hexStringToByteArray("02130006" // EAP-Response | ID | length in bytes
- + "1A04"); // EAP-MSCHAPv2 | Failure
-
- private static final byte[] EAP_RESPONSE_NAK_PACKET = hexStringToByteArray("02100006031A");
-
- @Before
- @Override
- public void setUp() {
- super.setUp();
-
- mEapSessionConfig =
- new EapSessionConfig.Builder().setEapMsChapV2Config(USERNAME, PASSWORD).build();
- mEapAuthenticator =
- new EapAuthenticator(
- mTestLooper.getLooper(),
- mMockCallback,
- new EapStateMachine(mMockContext, mEapSessionConfig, mMockSecureRandom),
- (runnable) -> runnable.run(),
- AUTHENTICATOR_TIMEOUT_MILLIS);
- }
-
- @Test
- public void testEapMsChapV2EndToEndSuccess() {
- verifyEapMsChapV2Challenge();
- verifyEapMsChapV2SuccessRequest();
- verifyEapSuccess(MSK, new byte[0]);
- }
-
- @Test
- public void testEapMsChapV2EndToEndFailure() {
- verifyEapMsChapV2Challenge();
- verifyEapMsChapV2FailureRequest();
- verifyEapFailure();
- }
-
- @Test
- public void testEapMsChapV2UnsupportedType() {
- verifyUnsupportedType(EAP_REQUEST_AKA_IDENTITY_PACKET, EAP_RESPONSE_NAK_PACKET);
-
- verifyEapMsChapV2Challenge();
- verifyEapMsChapV2SuccessRequest();
- verifyEapSuccess(MSK, new byte[0]);
- }
-
- @Test
- public void verifyEapMsChapV2WithEapNotifications() {
- verifyEapNotification(1);
-
- verifyEapMsChapV2Challenge();
- verifyEapNotification(2);
-
- verifyEapMsChapV2SuccessRequest();
- verifyEapNotification(3);
-
- verifyEapSuccess(MSK, new byte[0]);
- }
-
- private void verifyEapMsChapV2Challenge() {
- doAnswer(invocation -> {
- byte[] dst = invocation.getArgument(0);
- System.arraycopy(PEER_CHALLENGE, 0, dst, 0, PEER_CHALLENGE.length);
- return null;
- }).when(mMockSecureRandom).nextBytes(eq(new byte[PEER_CHALLENGE.length]));
-
- mEapAuthenticator.processEapMessage(EAP_MSCHAP_V2_CHALLENGE_REQUEST);
- mTestLooper.dispatchAll();
-
- verify(mMockCallback).onResponse(eq(EAP_MSCHAP_V2_CHALLENGE_RESPONSE));
- verify(mMockSecureRandom).nextBytes(any(byte[].class));
- verifyNoMoreInteractions(mMockCallback);
- }
-
- private void verifyEapMsChapV2SuccessRequest() {
- mEapAuthenticator.processEapMessage(EAP_MSCHAP_V2_SUCCESS_REQUEST);
- mTestLooper.dispatchAll();
-
- verify(mMockCallback).onResponse(eq(EAP_MSCHAP_V2_SUCCESS_RESPONSE));
- verifyNoMoreInteractions(mMockCallback);
- }
-
- private void verifyEapMsChapV2FailureRequest() {
- mEapAuthenticator.processEapMessage(EAP_MSCHAP_V2_FAILURE_REQUEST);
- mTestLooper.dispatchAll();
-
- verify(mMockCallback).onResponse(eq(EAP_MSCHAP_V2_FAILURE_RESPONSE));
- verifyNoMoreInteractions(mMockCallback);
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/EapResponseTest.java b/tests/iketests/src/java/com/android/internal/net/eap/EapResponseTest.java
deleted file mode 100644
index 0c6dd52d..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/EapResponseTest.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap;
-
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_RESPONSE_NAK_PACKET;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_SUCCESS_PACKET;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import com.android.internal.net.eap.EapResult.EapError;
-import com.android.internal.net.eap.EapResult.EapResponse;
-import com.android.internal.net.eap.exceptions.InvalidEapResponseException;
-import com.android.internal.net.eap.message.EapMessage;
-
-import org.junit.Before;
-import org.junit.Test;
-
-public class EapResponseTest {
- private EapMessage mEapResponse;
- private EapMessage mEapSuccess;
-
- @Before
- public void setUp() throws Exception {
- mEapResponse = EapMessage.decode(EAP_RESPONSE_NAK_PACKET);
- mEapSuccess = EapMessage.decode(EAP_SUCCESS_PACKET);
- }
-
- @Test
- public void testGetEapResponse() {
- EapResult eapResult = EapResponse.getEapResponse(mEapResponse);
- assertTrue(eapResult instanceof EapResponse);
-
- EapResponse eapResponse = (EapResponse) eapResult;
- assertArrayEquals(EAP_RESPONSE_NAK_PACKET, eapResponse.packet);
- }
-
- @Test
- public void testGetEapResponseNullMessage() {
- try {
- EapResponse.getEapResponse(null);
- fail("Expected IllegalArgumentException for null EapMessage");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void testGetEapResponseNonRequestMessage() {
- EapResult eapResult = EapResponse.getEapResponse(mEapSuccess);
- assertTrue(eapResult instanceof EapError);
-
- EapError eapError = (EapError) eapResult;
- assertTrue(eapError.cause instanceof InvalidEapResponseException);
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/EapSimTest.java b/tests/iketests/src/java/com/android/internal/net/eap/EapSimTest.java
deleted file mode 100644
index 8b11d278..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/EapSimTest.java
+++ /dev/null
@@ -1,298 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap;
-
-import static android.telephony.TelephonyManager.APPTYPE_USIM;
-
-import static com.android.internal.net.TestUtils.hexStringToByteArray;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_REQUEST_AKA_IDENTITY_PACKET;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_RESPONSE_NAK_PACKET;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.net.eap.EapSessionConfig;
-import android.telephony.TelephonyManager;
-
-import com.android.internal.net.eap.statemachine.EapStateMachine;
-
-import org.junit.Before;
-import org.junit.Test;
-
-/**
- * This test verifies that EAP-SIM is functional for an end-to-end implementation
- */
-public class EapSimTest extends EapMethodEndToEndTest {
- private static final long AUTHENTICATOR_TIMEOUT_MILLIS = 250L;
-
- private static final byte[] NONCE = hexStringToByteArray("37f3ddd3954c4831a5ee08c574844398");
- private static final String UNFORMATTED_IDENTITY = "123456789ABCDEF"; // IMSI
-
- // EAP_IDENTITY = hex("test@android.net")
- private static final byte[] EAP_IDENTITY =
- hexStringToByteArray("7465737440616E64726F69642E6E6574");
-
- private static final int SUB_ID = 1;
-
- // Base 64 of: RAND
- private static final String BASE64_RAND_1 = "EAEjRWeJq83vESNFZ4mrze8=";
- private static final String BASE64_RAND_2 = "EBEjRWeJq83vESNFZ4mrze8=";
- private static final String BASE64_RAND_3 = "ECEjRWeJq83vESNFZ4mrze8=";
-
- // BASE 64 of: "04" + SRES + "08" + KC
- // SRES 1: 0ABCDEF0 KC 1: FEDCBA9876543210
- // SRES 2: 1ABCDEF1 KC 2: FEDCBA9876543211
- // SRES 3: 2ABCDEF2 KC 3: FEDCBA9876543212
- private static final String BASE64_RESP_1 = "BAq83vAI/ty6mHZUMhA=";
- private static final String BASE64_RESP_2 = "BBq83vEI/ty6mHZUMhE=";
- private static final String BASE64_RESP_3 = "BCq83vII/ty6mHZUMhI=";
-
- // MK: 202FC68A3335E8A939A33BC0A0EA8C435DC10060
- // K_encr: F63E152461391FF655C2632E35D076ED
- // K_aut: 48E001C8DBA37120FD0465153A56F712
- private static final byte[] MSK =
- hexStringToByteArray(
- "9B1E2B6892BC113F6B6D0B5789DD8ADD"
- + "B83BE2A84AA50FCAECD0003F92D8DA16"
- + "4BF983C923695C309F1D7D68DB6992B0"
- + "76EA8CE7129647A6F198F3A6AA8ADED9");
- private static final byte[] EMSK = hexStringToByteArray(
- "88210b6724400313539c740f417076b0"
- + "41da7e64658ec365bd2901a7cd7c2763"
- + "dad1a0508b92a42fdf85ac53c6f7e756"
- + "7f99b62bcaf467441b567f19b58d86ae");
-
- // MK: ED275A588A4C1AEC15C55261DCCD851189E5C5FD
- // K_encr: FED573CFA6FC81267C08E264F50A0BB9
- // K_aut: 277B5D6A68FE5156A387996510AC5D61
- private static final byte[] MSK_WITHOUT_IDENTITY_REQ =
- hexStringToByteArray(
- "8023A49840433464DA1A4F2457FAB3D6"
- + "B1A3CA6E5E1DB212FA1AEA17F0A5C933"
- + "5541DE7448FE448AC3F09DC25BBAE1EE"
- + "17DCE3D32099519CC75840F0E3FB612B");
- private static final byte[] EMSK_WITHOUT_IDENTITY_REQ =
- hexStringToByteArray(
- "F7E213F0E8F14A21C87F9B5DFADA9A75"
- + "A8EAF4AD718BF8C3ED6557BDB60E4671"
- + "E6AE109448B2F32F9B984667AE6C2B3F"
- + "2FDFE67F97AF4D4727A2EA37F06B7785");
-
- private static final byte[] EAP_SIM_START_REQUEST = hexStringToByteArray(
- "01850014120a0000" // EAP header
- + "0f02000200010000" // AT_VERSION_LIST attribute
- + "0d010000"); // AT_ANY_ID_REQ attribute
- private static final byte[] EAP_SIM_START_RESPONSE = hexStringToByteArray(
- "02850034120a0000" // EAP header
- + "0705000037f3ddd3954c4831a5ee08c574844398" // AT_NONCE_MT attribute
- + "10010001" // AT_SELECTED_VERSION attribute
- + "0e05001031313233343536373839414243444546"); // AT_IDENTITY attribute
- private static final byte[] EAP_SIM_CHALLENGE_REQUEST = hexStringToByteArray(
- "01860050120b0000" // EAP header
- + "010d0000" // AT_RAND attribute
- + "0123456789abcdef1123456789abcdef" // Rand 1
- + "1123456789abcdef1123456789abcdef" // Rand 2
- + "2123456789abcdef1123456789abcdef" // Rand 3
- + "0b050000e4675b17fa7ba4d93db48d1af9ecbb01"); // AT_MAC attribute
- private static final byte[] EAP_SIM_CHALLENGE_RESPONSE =
- hexStringToByteArray(
- "0286001c120b0000" // EAP header
- + "0b050000e5df9cb1d935ea5f54d449a038bed061"); // AT_MAC attribute
-
- private static final byte[] EAP_SIM_START_REQUEST_WITHOUT_IDENTITY_REQ =
- hexStringToByteArray(
- "01850010" // EAP-Request | ID | length in bytes
- + "120a0000" // EAP-SIM | Start| 2B padding
- + "0f02000200010000"); // AT_VERSION_LIST attribute
- private static final byte[] EAP_SIM_START_RESPONSE_WITHOUT_IDENTITY_REQ =
- hexStringToByteArray(
- "02850020" // EAP-Response | ID | length in bytes
- + "120a0000" // EAP-SIM | Start | 2B padding
- + "0705000037f3ddd3954c4831a5ee08c574844398" // AT_NONCE_MT attribute
- + "10010001"); // AT_SELECTED_VERSION attribute
- private static final byte[] EAP_SIM_CHALLENGE_REQUEST_WITHOUT_IDENTITY_REQ =
- hexStringToByteArray(
- "01860050" // EAP-Request | ID | length in bytes
- + "120b0000" // EAP-SIM | Challenge | 2B padding
- + "010d0000" // AT_RAND attribute
- + "0123456789abcdef1123456789abcdef" // Rand 1
- + "1123456789abcdef1123456789abcdef" // Rand 2
- + "2123456789abcdef1123456789abcdef" // Rand 3
- + "0b050000F2F8C10FCA946AAFE9555E2BD3693DF6"); // AT_MAC attribute
- private static final byte[] EAP_SIM_CHALLENGE_RESPONSE_WITHOUT_IDENTITY_REQ =
- hexStringToByteArray(
- "0286001c" // EAP-Response | ID | length in bytes
- + "120b0000" // EAP-SIM | Challenge | 2B padding
- + "0b050000DAC3C1B7D9DBFBC923464A94F186E410"); // AT_MAC attribute
-
- private TelephonyManager mMockTelephonyManager;
-
- @Before
- @Override
- public void setUp() {
- super.setUp();
-
- mMockTelephonyManager = mock(TelephonyManager.class);
-
- mEapSessionConfig =
- new EapSessionConfig.Builder()
- .setEapIdentity(EAP_IDENTITY)
- .setEapSimConfig(SUB_ID, APPTYPE_USIM)
- .build();
- mEapAuthenticator =
- new EapAuthenticator(
- mTestLooper.getLooper(),
- mMockCallback,
- new EapStateMachine(mMockContext, mEapSessionConfig, mMockSecureRandom),
- (runnable) -> runnable.run(),
- AUTHENTICATOR_TIMEOUT_MILLIS);
- }
-
- @Test
- public void testEapSimEndToEnd() {
- verifyEapSimStart(EAP_SIM_START_REQUEST, EAP_SIM_START_RESPONSE, true);
- verifyEapSimChallenge(EAP_SIM_CHALLENGE_REQUEST, EAP_SIM_CHALLENGE_RESPONSE);
- verifyEapSuccess(MSK, EMSK);
- }
-
- @Test
- public void testEapSimEndToEndWithoutIdentityRequest() {
- verifyEapSimStart(
- EAP_SIM_START_REQUEST_WITHOUT_IDENTITY_REQ,
- EAP_SIM_START_RESPONSE_WITHOUT_IDENTITY_REQ,
- false);
- verifyEapSimChallenge(
- EAP_SIM_CHALLENGE_REQUEST_WITHOUT_IDENTITY_REQ,
- EAP_SIM_CHALLENGE_RESPONSE_WITHOUT_IDENTITY_REQ);
- verifyEapSuccess(MSK_WITHOUT_IDENTITY_REQ, EMSK_WITHOUT_IDENTITY_REQ);
- }
-
- @Test
- public void testEapSimUnsupportedType() {
- verifyUnsupportedType(EAP_REQUEST_AKA_IDENTITY_PACKET, EAP_RESPONSE_NAK_PACKET);
-
- verifyEapSimStart(EAP_SIM_START_REQUEST, EAP_SIM_START_RESPONSE, true);
- verifyEapSimChallenge(EAP_SIM_CHALLENGE_REQUEST, EAP_SIM_CHALLENGE_RESPONSE);
- verifyEapSuccess(MSK, EMSK);
- }
-
- @Test
- public void verifyEapSimWithEapNotifications() {
- verifyEapNotification(1);
- verifyEapSimStart(EAP_SIM_START_REQUEST, EAP_SIM_START_RESPONSE, true);
-
- verifyEapNotification(2);
- verifyEapSimChallenge(EAP_SIM_CHALLENGE_REQUEST, EAP_SIM_CHALLENGE_RESPONSE);
- verifyEapNotification(3);
- verifyEapSuccess(MSK, EMSK);
- }
-
- private void verifyEapSimStart(
- byte[] incomingEapPacket, byte[] outgoingEapPacket, boolean expectIdentityRequest) {
- // EAP-SIM/Start request
- when(mMockContext.getSystemService(Context.TELEPHONY_SERVICE))
- .thenReturn(mMockTelephonyManager);
- when(mMockTelephonyManager.createForSubscriptionId(SUB_ID))
- .thenReturn(mMockTelephonyManager);
- when(mMockTelephonyManager.getSubscriberId()).thenReturn(UNFORMATTED_IDENTITY);
- doAnswer(invocation -> {
- byte[] dst = invocation.getArgument(0);
- System.arraycopy(NONCE, 0, dst, 0, NONCE.length);
- return null;
- }).when(mMockSecureRandom).nextBytes(eq(new byte[NONCE.length]));
-
- mEapAuthenticator.processEapMessage(incomingEapPacket);
- mTestLooper.dispatchAll();
- verify(mMockContext).getSystemService(eq(Context.TELEPHONY_SERVICE));
- verify(mMockTelephonyManager).createForSubscriptionId(SUB_ID);
-
- if (expectIdentityRequest) {
- verify(mMockTelephonyManager).getSubscriberId();
- }
-
- verify(mMockSecureRandom).nextBytes(any(byte[].class));
-
- // verify EAP-SIM/Start response
- verify(mMockCallback).onResponse(eq(outgoingEapPacket));
- verifyNoMoreInteractions(
- mMockContext,
- mMockTelephonyManager,
- mMockSecureRandom,
- mMockCallback);
- }
-
- private void verifyEapSimChallenge(byte[] incomingEapPacket, byte[] outgoingEapPacket) {
- // EAP-SIM/Challenge request
- when(mMockTelephonyManager
- .getIccAuthentication(
- TelephonyManager.APPTYPE_USIM,
- TelephonyManager.AUTHTYPE_EAP_SIM,
- BASE64_RAND_1))
- .thenReturn(BASE64_RESP_1);
- when(mMockTelephonyManager
- .getIccAuthentication(
- TelephonyManager.APPTYPE_USIM,
- TelephonyManager.AUTHTYPE_EAP_SIM,
- BASE64_RAND_2))
- .thenReturn(BASE64_RESP_2);
- when(mMockTelephonyManager
- .getIccAuthentication(
- TelephonyManager.APPTYPE_USIM,
- TelephonyManager.AUTHTYPE_EAP_SIM,
- BASE64_RAND_3))
- .thenReturn(BASE64_RESP_3);
-
- mEapAuthenticator.processEapMessage(incomingEapPacket);
- mTestLooper.dispatchAll();
-
- // verify EAP-SIM/Challenge response
- verify(mMockTelephonyManager)
- .getIccAuthentication(
- eq(TelephonyManager.APPTYPE_USIM),
- eq(TelephonyManager.AUTHTYPE_EAP_SIM),
- eq(BASE64_RAND_1));
- verify(mMockTelephonyManager)
- .getIccAuthentication(
- eq(TelephonyManager.APPTYPE_USIM),
- eq(TelephonyManager.AUTHTYPE_EAP_SIM),
- eq(BASE64_RAND_2));
- verify(mMockTelephonyManager)
- .getIccAuthentication(
- eq(TelephonyManager.APPTYPE_USIM),
- eq(TelephonyManager.AUTHTYPE_EAP_SIM),
- eq(BASE64_RAND_3));
- verify(mMockCallback).onResponse(eq(outgoingEapPacket));
- verifyNoMoreInteractions(
- mMockContext,
- mMockTelephonyManager,
- mMockSecureRandom,
- mMockCallback);
- }
-
- @Override
- protected void verifyEapSuccess(byte[] msk, byte[] emsk) {
- super.verifyEapSuccess(msk, emsk);
-
- verifyNoMoreInteractions(mMockTelephonyManager);
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/EapSuccessTest.java b/tests/iketests/src/java/com/android/internal/net/eap/EapSuccessTest.java
deleted file mode 100644
index d7410540..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/EapSuccessTest.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.fail;
-
-import com.android.internal.net.eap.EapResult.EapSuccess;
-
-import org.junit.Test;
-
-public class EapSuccessTest {
- public static final byte[] MSK = new byte[] {(byte) 1, (byte) 2, (byte) 3};
- public static final byte[] EMSK = new byte[] {(byte) 4, (byte) 5, (byte) 6};
-
- @Test
- public void testEapSuccessConstructor() {
- EapSuccess eapSuccess = new EapSuccess(MSK, EMSK);
- assertArrayEquals(MSK, eapSuccess.msk);
- assertArrayEquals(EMSK, eapSuccess.emsk);
- }
-
- @Test
- public void testEapSuccessConstructorNullMsk() {
- try {
- new EapSuccess(null, EMSK);
- fail("Expected IllegalArgumentException");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void testEapSuccessConstructorNullEmsk() {
- try {
- new EapSuccess(MSK, null);
- fail("Expected IllegalArgumentException");
- } catch (IllegalArgumentException expected) {
- }
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/EapTestUtils.java b/tests/iketests/src/java/com/android/internal/net/eap/EapTestUtils.java
deleted file mode 100644
index de058d15..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/EapTestUtils.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap;
-
-import static android.telephony.TelephonyManager.APPTYPE_USIM;
-
-import android.net.eap.EapSessionConfig;
-
-import java.util.HashMap;
-
-/**
- * EapTestUtils is a util class for providing test-values of EAP-related objects.
- */
-public class EapTestUtils {
- /**
- * Creates and returns a dummy EapSessionConfig instance.
- *
- * @return a new, empty EapSessionConfig instance
- */
- public static EapSessionConfig getDummyEapSessionConfig() {
- return new EapSessionConfig(new HashMap<>(), new byte[0]);
- }
-
- /**
- * Creates and returns a dummy EapSessionConfig instance with the given EAP-Identity.
- *
- * @param eapIdentity byte-array representing the EAP-Identity of the client
- * @return a new, empty EapSessionConfig instance with the given EAP-Identity
- */
- public static EapSessionConfig getDummyEapSessionConfig(byte[] eapIdentity) {
- return new EapSessionConfig(new HashMap<>(), eapIdentity);
- }
-
- /**
- * Creates and returns a dummy EapSessionConfig instance with EAP-SIM configured.
- *
- * @return a new EapSessionConfig with EAP-SIM configs set
- */
- public static EapSessionConfig getDummyEapSimSessionConfig() {
- return new EapSessionConfig.Builder().setEapSimConfig(0, APPTYPE_USIM).build();
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/crypto/Fips186_2PrfTest.java b/tests/iketests/src/java/com/android/internal/net/eap/crypto/Fips186_2PrfTest.java
deleted file mode 100644
index 978f070f..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/crypto/Fips186_2PrfTest.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2018 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.eap.crypto;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.fail;
-
-import com.android.internal.net.TestUtils;
-
-import org.junit.Before;
-import org.junit.Test;
-
-/**
- * The test vectors in this file come directly from NIST:
- *
- * <p>The original link to the test vectors was here:
- * http://csrc.nist.gov/publications/fips/fips186-2/fips186-2-change1.pdf
- *
- * <p>But has since been removed. A cached copy was found here:
- * https://web.archive.org/web/20041031202951/http://www.csrc.nist.gov/CryptoToolkit/dss/Examples-
- * 1024bit.pdf
- */
-public final class Fips186_2PrfTest {
- private static final String SEED = "bd029bbe7f51960bcf9edb2b61f06f0feb5a38b6";
- private static final String EXPECTED_RESULT =
- "2070b3223dba372fde1c0ffc7b2e3b498b2606143c6c18bacb0f6c55babb13788e20d737a3275116";
-
- private Fips186_2Prf mFipsPrf;
-
- @Before
- public void setUp() {
- mFipsPrf = new Fips186_2Prf();
- }
-
- @Test
- public void testFips186_2Prf_Invalid_Seed() throws Exception {
- try {
- mFipsPrf.getRandom(new byte[0], 40);
- fail("Expected exception for invalid length seed");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void testFips186_2Prf() throws Exception {
- byte[] seed = TestUtils.hexStringToByteArray(SEED);
- byte[] actual = mFipsPrf.getRandom(seed, 40);
-
- assertArrayEquals(TestUtils.hexStringToByteArray(EXPECTED_RESULT), actual);
- }
-
- // TODO: (b/136177143) Add more test vectors
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/crypto/HmacSha256ByteSignerTest.java b/tests/iketests/src/java/com/android/internal/net/eap/crypto/HmacSha256ByteSignerTest.java
deleted file mode 100644
index 355c1db1..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/crypto/HmacSha256ByteSignerTest.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.crypto;
-
-import static com.android.internal.net.TestUtils.hexStringToByteArray;
-
-import static org.junit.Assert.assertArrayEquals;
-
-import org.junit.Before;
-import org.junit.Test;
-
-/**
- * HmacSha256ByteSignerTest tests that {@link HmacSha256ByteSigner} correctly signs data using the
- * HMAC-SHA-256 algorithm.
- *
- * <p>These test vectors are defined in RFC 4231#4.
- *
- * @see <a href="https://tools.ietf.org/html/rfc4231#section-4">Test Vectors</a>
- */
-public class HmacSha256ByteSignerTest {
- private static final String[] KEYS = {
- "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
- "4a656665",
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
- "0102030405060708090a0b0c0d0e0f10111213141516171819",
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
- + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
- + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
- + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
- + "aaaaaa",
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
- + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
- + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
- + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
- + "aaaaaa"
- };
- private static final String[] DATA = {
- "4869205468657265",
- "7768617420646f2079612077616e7420666f72206e6f7468696e673f",
- "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"
- + "dddddddddddddddddddddddddddddddddddd",
- "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"
- + "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd",
- "54657374205573696e67204c6172676572205468616e20426c6f636b2d53697a"
- + "65204b6579202d2048617368204b6579204669727374",
- "5468697320697320612074657374207573696e672061206c6172676572207468"
- + "616e20626c6f636b2d73697a65206b657920616e642061206c61726765722074"
- + "68616e20626c6f636b2d73697a6520646174612e20546865206b6579206e6565"
- + "647320746f20626520686173686564206265666f7265206265696e6720757365"
- + "642062792074686520484d414320616c676f726974686d2e"
- };
- private static final String[] MACS = {
- "b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7",
- "5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843",
- "773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe",
- "82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b",
- "60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54",
- "9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2"
- };
-
- private HmacSha256ByteSigner mMacByteSigner;
-
- @Before
- public void setUp() {
- mMacByteSigner = HmacSha256ByteSigner.getInstance();
- }
-
- @Test
- public void testSignBytes() {
- for (int i = 0; i < KEYS.length; i++) {
- byte[] key = hexStringToByteArray(KEYS[i]);
- byte[] data = hexStringToByteArray(DATA[i]);
-
- byte[] expected = hexStringToByteArray(MACS[i]);
-
- assertArrayEquals(expected, mMacByteSigner.signBytes(key, data));
- }
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/crypto/ParityBitUtilTest.java b/tests/iketests/src/java/com/android/internal/net/eap/crypto/ParityBitUtilTest.java
deleted file mode 100644
index 7ba024e5..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/crypto/ParityBitUtilTest.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.crypto;
-
-import static com.android.internal.net.TestUtils.hexStringToByteArray;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-
-import org.junit.Test;
-
-/**
- * Inputs taken from RFC 2759 Section 9.3.
- *
- * @see <a href="https://tools.ietf.org/html/rfc2759#section-9.3">RFC 2759 Section 9.3, Examples of
- * DES Key Generation</a>
- */
-public class ParityBitUtilTest {
- private static final byte[] INPUT_BYTES = {(byte) 0xFC, (byte) 0x0E, (byte) 0x7E, (byte) 0x37};
- private static final byte[] OUTPUT_BYTES = {(byte) 0xFD, (byte) 0x0E, (byte) 0x7F, (byte) 0x37};
-
- private static final String[] RAW_KEYS = {"FC156AF7EDCD6C", "0EDDE3337D427F"};
- private static final long[] RAW_KEY_LONGS = {0xFC156AF7EDCD6CL, 0xEDDE3337D427FL};
- private static final String[] PARITY_CORRECTED_KEYS = {"FD0B5B5E7F6E34D9", "0E6E796737EA08FE"};
-
- @Test
- public void testGetByteWithParityBit() {
- for (int i = 0; i < INPUT_BYTES.length; i++) {
- assertEquals(OUTPUT_BYTES[i], ParityBitUtil.getByteWithParityBit(INPUT_BYTES[i]));
- }
- }
-
- @Test
- public void testByteArrayToLong() {
- for (int i = 0; i < RAW_KEYS.length; i++) {
- byte[] rawKey = hexStringToByteArray(RAW_KEYS[i]);
-
- assertEquals(RAW_KEY_LONGS[i], ParityBitUtil.byteArrayToLong(rawKey));
- }
- }
-
- @Test
- public void testAddParityBits() {
- for (int i = 0; i < RAW_KEYS.length; i++) {
- byte[] rawKey = hexStringToByteArray(RAW_KEYS[i]);
- byte[] parityCorrectedKey = hexStringToByteArray(PARITY_CORRECTED_KEYS[i]);
-
- assertArrayEquals(parityCorrectedKey, ParityBitUtil.addParityBits(rawKey));
- }
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/message/EapDataTest.java b/tests/iketests/src/java/com/android/internal/net/eap/message/EapDataTest.java
deleted file mode 100644
index 9d4cc7ca..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/message/EapDataTest.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.message;
-
-import static com.android.internal.net.eap.message.EapData.EAP_TYPE_SIM;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.fail;
-
-import org.junit.Test;
-
-import java.nio.ByteBuffer;
-
-public class EapDataTest {
- private static final byte[] EXPECTED_EAP_DATA_BYTES = new byte[] {
- EAP_TYPE_SIM,
- (byte) 1,
- (byte) 2,
- (byte) 3
- };
- private static final byte[] EAP_TYPE_DATA = new byte[] {(byte) 1, (byte) 2, (byte) 3};
- private static final int UNSUPPORTED_EAP_TYPE = -1;
-
- @Test
- public void testEapDataConstructor() {
- new EapData(EAP_TYPE_SIM, EAP_TYPE_DATA);
- }
-
- @Test
- public void testEapDataConstructorNullEapData() {
- try {
- new EapData(EAP_TYPE_SIM, null);
- fail("IllegalArgumentException expected for null eapTypeData");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void testEapDataConstructorUnsupportedType() {
- try {
- new EapData(UNSUPPORTED_EAP_TYPE, EAP_TYPE_DATA);
- fail("Expected IllegalArgumentException");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void testGetLength() {
- EapData eapData = new EapData(EAP_TYPE_SIM, EAP_TYPE_DATA);
- assertEquals(EAP_TYPE_DATA.length + 1, eapData.getLength());
- }
-
- @Test
- public void testEquals() throws Exception {
- EapData eapData = new EapData(EAP_TYPE_SIM, EAP_TYPE_DATA);
- EapData eapDataCopy = new EapData(EAP_TYPE_SIM, EAP_TYPE_DATA);
- assertEquals(eapData, eapDataCopy);
-
- EapData eapDataDifferent = new EapData(EAP_TYPE_SIM, new byte[0]);
- assertNotEquals(eapData, eapDataDifferent);
- }
-
- @Test
- public void testHashCode() throws Exception {
- EapData eapData = new EapData(EAP_TYPE_SIM, EAP_TYPE_DATA);
- EapData eapDataCopy = new EapData(EAP_TYPE_SIM, EAP_TYPE_DATA);
- assertNotEquals(0, eapData.hashCode());
- assertEquals(eapData.hashCode(), eapDataCopy.hashCode());
- }
-
- @Test
- public void testEncodeToByteBuffer() {
- EapData eapData = new EapData(EAP_TYPE_SIM, EAP_TYPE_DATA);
-
- ByteBuffer b = ByteBuffer.allocate(eapData.getLength());
- eapData.encodeToByteBuffer(b);
- assertArrayEquals(EXPECTED_EAP_DATA_BYTES, b.array());
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/message/EapMessageTest.java b/tests/iketests/src/java/com/android/internal/net/eap/message/EapMessageTest.java
deleted file mode 100644
index 813a30f7..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/message/EapMessageTest.java
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.message;
-
-import static com.android.internal.net.TestUtils.hexStringToByteArray;
-import static com.android.internal.net.eap.message.EapData.EAP_NAK;
-import static com.android.internal.net.eap.message.EapData.EAP_TYPE_SIM;
-import static com.android.internal.net.eap.message.EapMessage.EAP_CODE_REQUEST;
-import static com.android.internal.net.eap.message.EapMessage.EAP_CODE_RESPONSE;
-import static com.android.internal.net.eap.message.EapMessage.EAP_CODE_SUCCESS;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_REQUEST_SIM_START_PACKET;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_REQUEST_SIM_TYPE_DATA;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_RESPONSE_NAK_PACKET;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_RESPONSE_NOTIFICATION_PACKET;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_SUCCESS_PACKET;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.ID_INT;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.INCOMPLETE_HEADER_PACKET;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.INVALID_CODE_PACKET;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.LONG_SUCCESS_PACKET;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.REQUEST_MISSING_TYPE_PACKET;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.REQUEST_UNSUPPORTED_TYPE_PACKET;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.SHORT_PACKET;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import com.android.internal.net.eap.EapResult;
-import com.android.internal.net.eap.EapResult.EapResponse;
-import com.android.internal.net.eap.exceptions.EapInvalidPacketLengthException;
-import com.android.internal.net.eap.exceptions.InvalidEapCodeException;
-import com.android.internal.net.eap.exceptions.UnsupportedEapTypeException;
-
-import org.junit.Test;
-
-import java.util.Arrays;
-
-public class EapMessageTest {
- @Test
- public void testConstructorRequestWithoutType() throws Exception {
- try {
- new EapMessage(EAP_CODE_REQUEST, ID_INT, null);
- fail("Expected EapInvalidPacketLengthException for an EAP-Request without Type value");
- } catch (EapInvalidPacketLengthException expected) {
- }
- }
-
- @Test
- public void testDecode() throws Exception {
- EapMessage result = EapMessage.decode(EAP_SUCCESS_PACKET);
- assertEquals(EAP_CODE_SUCCESS, result.eapCode);
- assertEquals(ID_INT, result.eapIdentifier);
- assertEquals(EAP_SUCCESS_PACKET.length, result.eapLength);
- assertNull(result.eapData);
-
- EapData expectedEapData = new EapData(EAP_TYPE_SIM,
- hexStringToByteArray(EAP_REQUEST_SIM_TYPE_DATA));
- result = EapMessage.decode(EAP_REQUEST_SIM_START_PACKET);
- assertEquals(EAP_CODE_REQUEST, result.eapCode);
- assertEquals(ID_INT, result.eapIdentifier);
- assertEquals(EAP_REQUEST_SIM_START_PACKET.length, result.eapLength);
- assertEquals(expectedEapData, result.eapData);
- }
-
- @Test
- public void testDecodeInvalidCode() throws Exception {
- try {
- EapMessage.decode(INVALID_CODE_PACKET);
- fail("Expected InvalidEapCodeException");
- } catch (InvalidEapCodeException expected) {
- }
- }
-
- @Test
- public void testDecodeIncompleteHeader() throws Exception {
- try {
- EapMessage.decode(INCOMPLETE_HEADER_PACKET);
- fail("Expected EapInvalidPacketLengthException");
- } catch (EapInvalidPacketLengthException expected) {
- }
- }
-
- @Test
- public void testDecodeShortPacket() throws Exception {
- try {
- EapMessage.decode(SHORT_PACKET);
- fail("Expected EapInvalidPacketLengthException");
- } catch (EapInvalidPacketLengthException expected) {
- }
- }
-
- @Test
- public void testDecodeSuccessIncorrectLength() throws Exception {
- try {
- EapMessage.decode(LONG_SUCCESS_PACKET);
- fail("Expected EapInvalidPacketLengthException");
- } catch (EapInvalidPacketLengthException expected) {
- }
- }
-
- @Test
- public void testDecodeMissingTypeData() throws Exception {
- try {
- EapMessage.decode(REQUEST_MISSING_TYPE_PACKET);
- fail("Expected EapInvalidPacketLengthException");
- } catch (EapInvalidPacketLengthException expected) {
- }
- }
-
- @Test
- public void testDecodeUnsupportedEapType() throws Exception {
- try {
- EapMessage.decode(REQUEST_UNSUPPORTED_TYPE_PACKET);
- fail("Expected UnsupportedEapDataTypeException");
- } catch (UnsupportedEapTypeException expected) {
- assertEquals(ID_INT, expected.eapIdentifier);
- }
- }
-
- @Test
- public void testEncode() throws Exception {
- EapMessage eapMessage = new EapMessage(EAP_CODE_SUCCESS, ID_INT, null);
- byte[] actualPacket = eapMessage.encode();
- assertArrayEquals(EAP_SUCCESS_PACKET, actualPacket);
-
- EapData nakData = new EapData(EAP_NAK, new byte[] {EAP_TYPE_SIM});
- eapMessage = new EapMessage(EAP_CODE_RESPONSE, ID_INT, nakData);
- actualPacket = eapMessage.encode();
- assertArrayEquals(EAP_RESPONSE_NAK_PACKET, actualPacket);
- }
-
- @Test
- public void testEncodeDecode() throws Exception {
- EapMessage eapMessage = new EapMessage(EAP_CODE_SUCCESS, ID_INT, null);
- EapMessage result = EapMessage.decode(eapMessage.encode());
-
- assertEquals(eapMessage.eapCode, result.eapCode);
- assertEquals(eapMessage.eapIdentifier, result.eapIdentifier);
- assertEquals(eapMessage.eapLength, result.eapLength);
- assertEquals(eapMessage.eapData, result.eapData);
- }
-
- @Test
- public void testDecodeEncode() throws Exception {
- byte[] result = EapMessage.decode(EAP_REQUEST_SIM_START_PACKET).encode();
- assertArrayEquals(EAP_REQUEST_SIM_START_PACKET, result);
- }
-
- @Test
- public void testGetNakResponse() {
- EapResult nakResponse = EapMessage.getNakResponse(ID_INT, Arrays.asList(EAP_TYPE_SIM));
-
- assertTrue(nakResponse instanceof EapResponse);
- EapResponse eapResponse = (EapResponse) nakResponse;
- assertArrayEquals(EAP_RESPONSE_NAK_PACKET, eapResponse.packet);
- }
-
- @Test
- public void testGetNotificationResponse() {
- EapResult notificationResponse = EapMessage.getNotificationResponse(ID_INT);
-
- assertTrue(notificationResponse instanceof EapResponse);
- EapResponse eapResponse = (EapResponse) notificationResponse;
- assertArrayEquals(EAP_RESPONSE_NOTIFICATION_PACKET, eapResponse.packet);
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/message/EapTestMessageDefinitions.java b/tests/iketests/src/java/com/android/internal/net/eap/message/EapTestMessageDefinitions.java
deleted file mode 100644
index 20517583..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/message/EapTestMessageDefinitions.java
+++ /dev/null
@@ -1,327 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.message;
-
-import static com.android.internal.net.TestUtils.hexStringToByteArray;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.AT_VERSION_LIST_DATA;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.IDENTITY_STRING;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.NONCE_MT_STRING;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.RAND_1;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.RAND_2;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.RES;
-
-/**
- * EapTestMessageDefinitions provides byte[] encodings of commonly used EAP Messages.
- *
- * @see <a href="https://tools.ietf.org/html/rfc3748#section-4">RFC 3748, Extensible Authentication
- * Protocol (EAP)</a>
- */
-public class EapTestMessageDefinitions {
- public static final String ID = "10";
- public static final int ID_INT = Integer.parseInt(ID, 16 /* radix */);
-
- // EAP-AKA Identity request
- public static final String EAP_REQUEST_TYPE_DATA = "0500000D010000";
- public static final byte[] EAP_AKA_IDENTITY_REQUEST =
- hexStringToByteArray(EAP_REQUEST_TYPE_DATA);
-
- // EAP-AKA/Identity request with no attributes
- public static final byte[] EAP_REQUEST_AKA = hexStringToByteArray("01" + ID + "000817050000");
- public static final byte[] EAP_REQUEST_AKA_IDENTITY_PACKET =
- hexStringToByteArray("01" + ID + "000A17" + EAP_REQUEST_TYPE_DATA);
- public static final byte[] EAP_REQUEST_IDENTITY_PACKET =
- hexStringToByteArray("01" + ID + "000501");
-
- // EAP-Identity: hex for ASCII in "test@android.net"
- public static final String EAP_IDENTITY_STRING = "7465737440616E64726F69642E6E6574";
- public static final byte[] EAP_IDENTITY = hexStringToByteArray(EAP_IDENTITY_STRING);
- public static final byte[] EAP_RESPONSE_IDENTITY_PACKET =
- hexStringToByteArray("02" + ID + "001501" + EAP_IDENTITY_STRING);
- public static final byte[] EAP_RESPONSE_IDENTITY_DEFAULT_PACKET =
- hexStringToByteArray("02" + ID + "000501");
- public static final byte[] EAP_REQUEST_NOTIFICATION_PACKET =
- hexStringToByteArray("01" + ID + "000802AABBCC");
- public static final byte[] EAP_SUCCESS_PACKET = hexStringToByteArray("03" + ID + "0004");
- public static final byte[] EAP_FAILURE_PACKET = hexStringToByteArray("04" + ID + "0004");
- public static final byte[] EAP_SIM_CLIENT_ERROR_RESPONSE =
- hexStringToByteArray("02" + ID + "000C120E000016010001");
- public static final byte[] EAP_SIM_CLIENT_ERROR_INSUFFICIENT_CHALLENGES =
- hexStringToByteArray("02" + ID + "000C120E000016010002");
- public static final byte[] EAP_SIM_CLIENT_ERROR_UNABLE_TO_PROCESS =
- hexStringToByteArray("02" + ID + "000C120E000016010000");
- public static final byte[] EAP_AKA_CLIENT_ERROR_UNABLE_TO_PROCESS =
- hexStringToByteArray("02" + ID + "000C170E000016010000");
-
- // EAP-SIM response containing SELECTED_VERSION (1) and IDENTITY attributes
- public static final byte[] EAP_SIM_RESPONSE_PACKET = hexStringToByteArray(
- "02" + ID + "0024120A0000100100010E060011" + IDENTITY_STRING + "000000");
- public static final byte[] EAP_SIM_RESPONSE_WITHOUT_IDENTITY =
- hexStringToByteArray("02" + ID + "0020120A000007050000" + NONCE_MT_STRING + "10010001");
- public static final byte[] EAP_SIM_NOTIFICATION_RESPONSE = hexStringToByteArray(
- "02" + ID + "0008120C0000");
- public static final byte[] EAP_AKA_NOTIFICATION_RESPONSE =
- hexStringToByteArray("02" + ID + "0008170C0000");
-
- // Body of EapData is the list of supported methods
- public static final byte[] EAP_RESPONSE_NAK_PACKET =
- hexStringToByteArray("02" + ID + "00060312");
- public static final byte[] EAP_RESPONSE_NOTIFICATION_PACKET =
- hexStringToByteArray("02" + ID + "000502");
- public static final byte[] EAP_REQUEST_MD5_CHALLENGE =
- hexStringToByteArray("01" + ID + "000504");
- public static final byte[] EAP_REQUEST_NAK_PACKET =
- hexStringToByteArray("01" + ID + "000503");
- public static final String EAP_REQUEST_SIM_TYPE_DATA = "0A00000F02000200010000";
- public static final byte[] EAP_REQUEST_SIM_START_PACKET =
- hexStringToByteArray("01" + ID + "001012" + EAP_REQUEST_SIM_TYPE_DATA);
-
- public static final byte[] REQUEST_UNSUPPORTED_TYPE_PACKET =
- hexStringToByteArray("01" + ID + "0005FF");
- public static final byte[] REQUEST_MISSING_TYPE_PACKET =
- hexStringToByteArray("01" + ID + "0004");
- public static final byte[] LONG_SUCCESS_PACKET = hexStringToByteArray("03" + ID + "000500");
- public static final byte[] SHORT_PACKET = hexStringToByteArray("01" + ID + "0005");
- public static final byte[] INCOMPLETE_HEADER_PACKET = hexStringToByteArray("03" + ID);
- public static final byte[] INVALID_CODE_PACKET = hexStringToByteArray("F0" + ID + "0004");
-
- // Attributes
- public static final String SKIPPABLE_DATA = "112233445566";
- public static final byte[] SKIPPABLE_DATA_BYTES = hexStringToByteArray(SKIPPABLE_DATA);
- public static final byte[] SKIPPABLE_INVALID_ATTRIBUTE =
- hexStringToByteArray("FF02" + SKIPPABLE_DATA);
- public static final byte[] NON_SKIPPABLE_INVALID_ATTRIBUTE =
- hexStringToByteArray("7F010000");
-
- // Type-Data
- public static final byte[] EAP_SIM_START_SUBTYPE =
- hexStringToByteArray("0A00000F02" + AT_VERSION_LIST_DATA + "0A010000");
- public static final byte[] INVALID_SUBTYPE = hexStringToByteArray("FF");
- public static final byte[] TYPE_DATA_INVALID_AT_RAND =
- hexStringToByteArray("0A000001050000" + RAND_1);
- public static final byte[] SHORT_TYPE_DATA = hexStringToByteArray("0A");
- public static final byte[] TYPE_DATA_INVALID_ATTRIBUTE =
- hexStringToByteArray("0A00007F01");
- public static final byte[] EAP_SIM_START_DUPLICATE_ATTRIBUTES =
- hexStringToByteArray("0A00000F02" + "0A010000" + "0A010000");
-
- // RAND Challenge Results
- public static final String SRES_1 = "11223344";
- public static final byte[] SRES_1_BYTES = hexStringToByteArray(SRES_1);
- public static final String SRES_2 = "44332211";
- public static final byte[] SRES_2_BYTES = hexStringToByteArray(SRES_2);
- public static final byte[] SRES_BYTES = hexStringToByteArray(SRES_1 + SRES_2);
- public static final String KC_1 = "0102030405060708";
- public static final byte[] KC_1_BYTES = hexStringToByteArray(KC_1);
- public static final String KC_2 = "0807060504030201";
- public static final byte[] KC_2_BYTES = hexStringToByteArray(KC_2);
- public static final byte[] VALID_CHALLENGE_RESPONSE =
- hexStringToByteArray("04" + SRES_1 + "08" + KC_1);
- public static final byte[] CHALLENGE_RESPONSE_INVALID_SRES = hexStringToByteArray("03");
- public static final byte[] CHALLENGE_RESPONSE_INVALID_KC =
- hexStringToByteArray("04" + SRES_1 + "04");
-
- public static final String IMSI = "123456789012345";
- public static final String EAP_SIM_IDENTITY = "1" + IMSI;
- public static final byte[] EAP_SIM_IDENTITY_BYTES = hexStringToByteArray(EAP_SIM_IDENTITY);
-
- // ASCII hex for "0" + IMSI (EAP-AKA identity format)
- public static final String EAP_AKA_IDENTITY_BYTES = "30313233343536373839303132333435";
-
- // Master Key generation
- public static final String MK_STRING = "0123456789ABCDEF0123456789ABCDEF01234567";
- public static final byte[] MK = hexStringToByteArray(MK_STRING);
- public static final String K_ENCR_STRING = "000102030405060708090A0B0C0D0E0F";
- public static final byte[] K_ENCR = hexStringToByteArray(K_ENCR_STRING);
- public static final String K_AUT_STRING = "0F0E0D0C0B0A09080706050403020100";
- public static final byte[] K_AUT = hexStringToByteArray(K_AUT_STRING);
- public static final String MSK_STRING =
- "00112233445566778899AABBCCDDEEFF"
- + "00112233445566778899AABBCCDDEEFF"
- + "00112233445566778899AABBCCDDEEFF"
- + "00112233445566778899AABBCCDDEEFF";
- public static final byte[] MSK = hexStringToByteArray(MSK_STRING);
- public static final String EMSK_STRING =
- "FFEEDDCCBBAA99887766554433221100"
- + "FFEEDDCCBBAA99887766554433221100"
- + "FFEEDDCCBBAA99887766554433221100"
- + "FFEEDDCCBBAA99887766554433221100";
- public static final byte[] EMSK = hexStringToByteArray(EMSK_STRING);
-
- // MAC computation
- public static final String ORIGINAL_MAC_STRING = "112233445566778899AABBCCDDEEFF11";
- public static final byte[] ORIGINAL_MAC = hexStringToByteArray(ORIGINAL_MAC_STRING);
- public static final String COMPUTED_MAC_STRING = "FFEEDDCCBBAA998877665544332211FF";
- public static final byte[] COMPUTED_MAC = hexStringToByteArray(COMPUTED_MAC_STRING);
- public static final String EAP_SIM_CHALLENGE_REQUEST_STRING =
- "01" + ID + "0040" // EAP-Request | ID | length in bytes
- + "120b0000" // EAP-SIM | Challenge | 2B padding
- + "01090000" + RAND_1 + RAND_2 // EAP-SIM AT_RAND attribute
- + "0B05000000000000000000000000000000000000"; // AT_MAC attribute with no MAC
- public static final byte[] MAC_INPUT =
- hexStringToByteArray(EAP_SIM_CHALLENGE_REQUEST_STRING + NONCE_MT_STRING);
-
- // Response Message with MAC
- public static final String EAP_SIM_CHALLENGE_RESPONSE_EMPTY_MAC =
- "02" + ID + "001C" // EAP-Response | ID | length in bytes
- + "120b0000" // EAP-SIM | Challenge | 2B padding
- + "0B05000000000000000000000000000000000000"; // AT_MAC attribute with no MAC
- public static final byte[] EAP_SIM_CHALLENGE_RESPONSE_MAC_INPUT =
- hexStringToByteArray(EAP_SIM_CHALLENGE_RESPONSE_EMPTY_MAC + SRES_1 + SRES_2);
- public static final byte[] EAP_SIM_CHALLENGE_RESPONSE_WITH_MAC = hexStringToByteArray(
- "02" + ID + "001C" // EAP-Response | ID | length in bytes
- + "120b0000" // EAP-SIM | Challenge | 2B padding
- + "0B050000" + COMPUTED_MAC_STRING); // AT_MAC attribute
- public static final byte[] EAP_SIM_NOTIFICATION_REQUEST_WITH_EMPTY_MAC = hexStringToByteArray(
- "01" + ID + "0020" // EAP-Request | ID | length in bytes
- + "120C0000" // EAP-SIM | Notification | 2B padding
- + "0C010000" // AT_NOTIFICATION attribute
- + "0B05000000000000000000000000000000000000"); // empty AT_MAC attribute
- public static final byte[] EAP_SIM_NOTIFICATION_RESPONSE_WITH_EMPTY_MAC = hexStringToByteArray(
- "02" + ID + "001C" // EAP-Response | ID | length in bytes
- + "120C0000" // EAP-SIM | Notification | 2B padding
- + "0B05000000000000000000000000000000000000"); // empty AT_MAC attribute
- public static final byte[] EAP_SIM_NOTIFICATION_RESPONSE_WITH_MAC = hexStringToByteArray(
- "02" + ID + "001C" // EAP-Response | ID | length in bytes
- + "120C0000" // EAP-SIM | Notification | 2B padding
- + "0B050000" + COMPUTED_MAC_STRING); // AT_MAC attribute
-
- public static final byte[] EAP_AKA_IDENTITY_RESPONSE =
- hexStringToByteArray("02" + ID + "001C" // EAP-Response | ID | length in bytes
- + "17050000" // EAP-AKA | Identity | 2B padding
- + "0E050010" + EAP_AKA_IDENTITY_BYTES); // AT_IDENTITY ("0" + IMSI)
-
- // Base64 of: FF0111
- public static final String EAP_AKA_UICC_RESP_INVALID_TAG = "/wER";
-
- // Base64 of: DC0E112233445566778899AABBCCDDEE
- public static final String EAP_AKA_UICC_RESP_SYNCHRONIZE_BASE_64 = "3A4RIjNEVWZ3iJmqu8zd7g==";
-
- public static final byte[] EAP_AKA_SYNCHRONIZATION_FAILURE =
- hexStringToByteArray("02" + ID + "0018" // EAP-Response | ID | length in bytes
- + "17040000" // EAP-SIM | Synchronization-Failure | 2B padding
- + "0404112233445566778899AABBCCDDEE"); // AT_AUTS attribute
-
- public static final String IK = "00112233445566778899AABBCCDDEEFF";
- public static final byte[] IK_BYTES = hexStringToByteArray(IK);
- public static final String CK = "FFEEDDCCBBAA99887766554433221100";
- public static final byte[] CK_BYTES = hexStringToByteArray(CK);
-
- // Base-64 of: 'DB05' + RES_BYTES + '10' + IK + '10' + CK
- // 'DB0511223344551000112233445566778899AABBCCDDEEFF10FFEEDDCCBBAA99887766554433221100'
- public static final String EAP_AKA_UICC_RESP_SUCCESS_BASE_64 =
- "2wURIjNEVRAAESIzRFVmd4iZqrvM3e7/EP/u3cy7qpmId2ZVRDMiEQA=";
-
- public static final byte[] EAP_AKA_AUTHENTICATION_REJECT =
- hexStringToByteArray("02" + ID + "000817020000");
- public static final String EAP_AKA_CHALLENGE_RESPONSE_MAC = "C70366512D9C5EBA8E3484509A25DCE4";
- public static final byte[] EAP_AKA_CHALLENGE_RESPONSE_MAC_BYTES =
- hexStringToByteArray(EAP_AKA_CHALLENGE_RESPONSE_MAC);
- public static final byte[] EAP_AKA_CHALLENGE_RESPONSE_TYPE_DATA =
- hexStringToByteArray(
- "01000003030028" + RES + "0000000B050000" + EAP_AKA_CHALLENGE_RESPONSE_MAC);
- public static final byte[] EAP_AKA_CHALLENGE_RESPONSE =
- hexStringToByteArray(
- "02100028" // EAP-Response | ID | length in bytes
- + "17010000" // EAP-AKA | Challenge | 2B padding
- + "03030028" + RES + "000000" // AT_RES attribute
- + "0B050000" + EAP_AKA_CHALLENGE_RESPONSE_MAC); // AT_MAC attribute
-
- public static final byte[] EAP_SUCCESS = hexStringToByteArray("03860004");
-
- public static final byte[] EAP_REQUEST_MSCHAP_V2 =
- hexStringToByteArray("01" + ID + "00061A01");
-
- // MSCHAPv2 Test vectors taken from RFC 2759#9.2 and RFC 3079#3.5.3
- public static final String MSCHAP_V2_USERNAME = "User";
- public static final String MSCHAP_V2_USERNAME_HEX = "55736572";
- public static final byte[] MSCHAP_V2_USERNAME_ASCII_BYTES =
- hexStringToByteArray(MSCHAP_V2_USERNAME_HEX);
- public static final String MSCHAP_V2_PASSWORD = "clientPass";
- public static final byte[] MSCHAP_V2_PASSWORD_UTF_BYTES =
- hexStringToByteArray("63006C00690065006E0074005000610073007300");
- public static final String MSCHAP_V2_AUTHENTICATOR_CHALLENGE_STRING =
- "5B5D7C7D7B3F2F3E3C2C602132262628";
- public static final byte[] MSCHAP_V2_AUTHENTICATOR_CHALLENGE =
- hexStringToByteArray(MSCHAP_V2_AUTHENTICATOR_CHALLENGE_STRING);
- public static final String MSCHAP_V2_PEER_CHALLENGE_STRING = "21402324255E262A28295F2B3A337C7E";
- public static final byte[] MSCHAP_V2_PEER_CHALLENGE =
- hexStringToByteArray(MSCHAP_V2_PEER_CHALLENGE_STRING);
- public static final byte[] MSCHAP_V2_CHALLENGE = hexStringToByteArray("D02E4386BCE91226");
- public static final byte[] MSCHAP_V2_PASSWORD_HASH =
- hexStringToByteArray("44EBBA8D5312B8D611474411F56989AE");
- public static final byte[] MSCHAP_V2_PASSWORD_HASH_HASH =
- hexStringToByteArray("41C00C584BD2D91C4017A2A12FA59F3F");
- public static final String MSCHAP_V2_NT_RESPONSE_STRING =
- "82309ECD8D708B5EA08FAA3981CD83544233114A3D85D6DF";
- public static final byte[] MSCHAP_V2_NT_RESPONSE =
- hexStringToByteArray(MSCHAP_V2_NT_RESPONSE_STRING);
- public static final byte[] MSCHAP_V2_AUTHENTICATOR_RESPONSE =
- hexStringToByteArray("407A5589115FD0D6209F510FE9C04566932CDA56");
- public static final byte[] MSCHAP_V2_MASTER_KEY =
- hexStringToByteArray("FDECE3717A8C838CB388E527AE3CDD31");
-
- // generated based on RFC 3079#3.5.3 params
- public static final String SEND_KEY = "D5F0E9521E3EA9589645E86051C82226";
- public static final byte[] MSCHAP_V2_SEND_START_KEY = hexStringToByteArray(SEND_KEY);
-
- // This value is labeled 'send key' in RFC 3079#3.5.3. However, it's used as 'receive key' here,
- // because send and receive keys are swapped for peers relative to authenticators.
- public static final String RECEIVE_KEY = "8B7CDC149B993A1BA118CB153F56DCCB";
- public static final byte[] MSCHAP_V2_RECEIVE_START_KEY = hexStringToByteArray(RECEIVE_KEY);
-
- // MSK: MSCHAP_V2_SEND_START_KEY + MSCHAP_V2_RECEIVE_START_KEY
- public static final byte[] MSCHAP_V2_MSK = hexStringToByteArray(SEND_KEY + RECEIVE_KEY);
-
- public static final String MSCHAP_V2_ID = "42";
- public static final int MSCHAP_V2_ID_INT = Integer.parseInt(MSCHAP_V2_ID, 16 /* radix */);
- public static final byte[] EAP_MSCHAP_V2_CHALLENGE_RESPONSE =
- hexStringToByteArray("02" + ID + "003F" // EAP-Response | ID | length in bytes
- + "1A02" + MSCHAP_V2_ID // EAP-MSCHAPv2 | Response | MSCHAPv2 ID
- + "003A31" // MS length | Value Size (0x31)
- + MSCHAP_V2_PEER_CHALLENGE_STRING
- + "0000000000000000" // 8B (reserved)
- + MSCHAP_V2_NT_RESPONSE_STRING
- + "00" // Flags (always 0)
- + MSCHAP_V2_USERNAME_HEX);
-
- public static final byte[] EAP_MSCHAP_V2_SUCCESS_RESPONSE =
- hexStringToByteArray("02" + ID + "0006" // EAP-Response | ID | length in bytes
- + "1A03"); // EAP-MSCHAPv2 | Success
-
- public static final byte[] INVALID_AUTHENTICATOR_RESPONSE = new byte[20];
-
- public static final byte[] EAP_MSCHAP_V2_FAILURE_RESPONSE =
- hexStringToByteArray("02" + ID + "0006" // EAP-Response | ID | length in bytes
- + "1A04"); // EAP-MSCHAPv2 | Failure
-
- public static final byte[] EAP_AKA_PRIME_REQUEST =
- hexStringToByteArray("01" + ID + "000832050000");
- public static final byte[] EAP_AKA_PRIME_CLIENT_ERROR_UNABLE_TO_PROCESS =
- hexStringToByteArray("02" + ID + "000C320E000016010000");
- public static final String EAP_AKA_PRIME_IDENTITY = "36313233343536373839303132333435";
- public static final byte[] EAP_AKA_PRIME_IDENTITY_BYTES =
- hexStringToByteArray(EAP_AKA_PRIME_IDENTITY);
- public static final byte[] EAP_AKA_PRIME_IDENTITY_RESPONSE =
- hexStringToByteArray(
- "02" + ID + "001C" // EAP-Response | ID | length in bytes
- + "32050000" // EAP-AKA' | Identity | 2B padding
- + "0E050010" + EAP_AKA_PRIME_IDENTITY); // AT_IDENTITY ("6" + IMSI)
- public static final byte[] EAP_AKA_PRIME_AUTHENTICATION_REJECT =
- hexStringToByteArray(
- "02" + ID + "0008" // EAP-Response | ID | length in bytes
- + "32020000"); // EAP-AKA' | Authentication Reject | 2B padding
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/message/mschapv2/EapMsChapV2ChallengeRequestTest.java b/tests/iketests/src/java/com/android/internal/net/eap/message/mschapv2/EapMsChapV2ChallengeRequestTest.java
deleted file mode 100644
index 45a86735..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/message/mschapv2/EapMsChapV2ChallengeRequestTest.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.message.mschapv2;
-
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.CHALLENGE_BYTES;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.CHALLENGE_REQUEST_LONG_MS_LENGTH;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.CHALLENGE_REQUEST_SHORT_CHALLENGE;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.CHALLENGE_REQUEST_SHORT_MS_LENGTH;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.CHALLENGE_REQUEST_WRONG_OP_CODE;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.EAP_MSCHAP_V2_CHALLENGE_REQUEST;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.ID_INT;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.SERVER_NAME_BYTES;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2TypeData.EAP_MSCHAP_V2_CHALLENGE;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import com.android.internal.net.eap.EapResult.EapError;
-import com.android.internal.net.eap.exceptions.mschapv2.EapMsChapV2ParsingException;
-import com.android.internal.net.eap.message.mschapv2.EapMsChapV2TypeData.EapMsChapV2ChallengeRequest;
-import com.android.internal.net.eap.message.mschapv2.EapMsChapV2TypeData.EapMsChapV2TypeDataDecoder;
-import com.android.internal.net.eap.message.mschapv2.EapMsChapV2TypeData.EapMsChapV2TypeDataDecoder.DecodeResult;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.nio.BufferUnderflowException;
-
-public class EapMsChapV2ChallengeRequestTest {
- private static final String TAG = EapMsChapV2ChallengeRequestTest.class.getSimpleName();
-
- private EapMsChapV2TypeDataDecoder mTypeDataDecoder;
-
- @Before
- public void setUp() {
- mTypeDataDecoder = new EapMsChapV2TypeDataDecoder();
- }
-
- @Test
- public void testDecodeChallengeRequest() {
- DecodeResult<EapMsChapV2ChallengeRequest> result =
- mTypeDataDecoder.decodeChallengeRequest(TAG, EAP_MSCHAP_V2_CHALLENGE_REQUEST);
- assertTrue(result.isSuccessfulDecode());
- EapMsChapV2ChallengeRequest challengeRequest = result.eapTypeData;
-
- assertEquals(EAP_MSCHAP_V2_CHALLENGE, challengeRequest.opCode);
- assertEquals(ID_INT, challengeRequest.msChapV2Id);
- assertEquals(EAP_MSCHAP_V2_CHALLENGE_REQUEST.length, challengeRequest.msLength);
- assertArrayEquals(CHALLENGE_BYTES, challengeRequest.challenge);
- assertArrayEquals(SERVER_NAME_BYTES, challengeRequest.name);
- }
-
- @Test
- public void testDecodeChallengeRequestWrongOpCode() {
- DecodeResult<EapMsChapV2ChallengeRequest> result =
- mTypeDataDecoder.decodeChallengeRequest(TAG, CHALLENGE_REQUEST_WRONG_OP_CODE);
- assertFalse(result.isSuccessfulDecode());
- EapError eapError = result.eapError;
- assertTrue(eapError.cause instanceof EapMsChapV2ParsingException);
- }
-
- @Test
- public void testDecodeChallengeRequestShortChallenge() {
- DecodeResult<EapMsChapV2ChallengeRequest> result =
- mTypeDataDecoder.decodeChallengeRequest(TAG, CHALLENGE_REQUEST_SHORT_CHALLENGE);
- assertFalse(result.isSuccessfulDecode());
- EapError eapError = result.eapError;
- assertTrue(eapError.cause instanceof EapMsChapV2ParsingException);
- }
-
- @Test
- public void testDecodeChallengeRequestShortMsLength() {
- DecodeResult<EapMsChapV2ChallengeRequest> result =
- mTypeDataDecoder.decodeChallengeRequest(TAG, CHALLENGE_REQUEST_SHORT_MS_LENGTH);
- assertFalse(result.isSuccessfulDecode());
- EapError eapError = result.eapError;
- assertTrue(eapError.cause instanceof EapMsChapV2ParsingException);
- }
-
- @Test
- public void testDecodeChallengeRequestLongMsLength() {
- DecodeResult<EapMsChapV2ChallengeRequest> result =
- mTypeDataDecoder.decodeChallengeRequest(TAG, CHALLENGE_REQUEST_LONG_MS_LENGTH);
- assertFalse(result.isSuccessfulDecode());
- EapError eapError = result.eapError;
- assertTrue(eapError.cause instanceof BufferUnderflowException);
- }
-
- @Test
- public void testEncodeChallengeRequestFails() throws Exception {
- EapMsChapV2ChallengeRequest challengeRequest =
- new EapMsChapV2ChallengeRequest(
- ID_INT,
- EAP_MSCHAP_V2_CHALLENGE_REQUEST.length,
- CHALLENGE_BYTES,
- SERVER_NAME_BYTES);
- try {
- challengeRequest.encode();
- fail("Expected UnsupportedOperationException for encoding a Challenge Request");
- } catch (UnsupportedOperationException expected) {
- }
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/message/mschapv2/EapMsChapV2ChallengeResponseTest.java b/tests/iketests/src/java/com/android/internal/net/eap/message/mschapv2/EapMsChapV2ChallengeResponseTest.java
deleted file mode 100644
index 3e243a98..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/message/mschapv2/EapMsChapV2ChallengeResponseTest.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.message.mschapv2;
-
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.EAP_MSCHAP_V2_CHALLENGE_RESPONSE;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.ID_INT;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.NT_RESPONSE_BYTES;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.PEER_CHALLENGE_BYTES;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.PEER_NAME_BYTES;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.SHORT_CHALLENGE_BYTES;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.SHORT_NT_RESPONSE;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2TypeData.EAP_MSCHAP_V2_RESPONSE;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-
-import com.android.internal.net.eap.exceptions.mschapv2.EapMsChapV2ParsingException;
-import com.android.internal.net.eap.message.mschapv2.EapMsChapV2TypeData.EapMsChapV2ChallengeResponse;
-
-import org.junit.Test;
-
-public class EapMsChapV2ChallengeResponseTest {
- private static final int FLAGS = 0;
- private static final int INVALID_FLAGS = 0xFF;
-
- @Test
- public void testConstructor() throws Exception {
- EapMsChapV2ChallengeResponse challengeResponse =
- new EapMsChapV2ChallengeResponse(
- ID_INT, PEER_CHALLENGE_BYTES, NT_RESPONSE_BYTES, FLAGS, PEER_NAME_BYTES);
- assertEquals(EAP_MSCHAP_V2_RESPONSE, challengeResponse.opCode);
- assertEquals(ID_INT, challengeResponse.msChapV2Id);
- assertEquals(EAP_MSCHAP_V2_CHALLENGE_RESPONSE.length, challengeResponse.msLength);
- assertArrayEquals(PEER_CHALLENGE_BYTES, challengeResponse.peerChallenge);
- assertArrayEquals(NT_RESPONSE_BYTES, challengeResponse.ntResponse);
- assertEquals(FLAGS, challengeResponse.flags);
- assertArrayEquals(PEER_NAME_BYTES, challengeResponse.name);
- }
-
- @Test
- public void testConstructorInvalidChallenge() {
- try {
- EapMsChapV2ChallengeResponse challengeResponse =
- new EapMsChapV2ChallengeResponse(
- ID_INT,
- SHORT_CHALLENGE_BYTES,
- NT_RESPONSE_BYTES,
- FLAGS,
- PEER_NAME_BYTES);
- fail("Expected EapMsChapV2ParsingException for invalid Peer Challenge length");
- } catch (EapMsChapV2ParsingException expected) {
- }
- }
-
- @Test
- public void testConstructorInvalidNtResponse() {
- try {
- EapMsChapV2ChallengeResponse challengeResponse =
- new EapMsChapV2ChallengeResponse(
- ID_INT,
- PEER_CHALLENGE_BYTES,
- SHORT_NT_RESPONSE,
- FLAGS,
- PEER_NAME_BYTES);
- fail("Expected EapMsChapV2ParsingException for invalid NT-Response length");
- } catch (EapMsChapV2ParsingException expected) {
- }
- }
-
- @Test
- public void testConstructorInvalidFlags() {
- try {
- EapMsChapV2ChallengeResponse challengeResponse =
- new EapMsChapV2ChallengeResponse(
- ID_INT,
- PEER_CHALLENGE_BYTES,
- NT_RESPONSE_BYTES,
- INVALID_FLAGS,
- PEER_NAME_BYTES);
- fail("Expected EapMsChapV2ParsingException for non-zero Flags value");
- } catch (EapMsChapV2ParsingException expected) {
- }
- }
-
- @Test
- public void testEncode() throws Exception {
- EapMsChapV2ChallengeResponse challengeResponse =
- new EapMsChapV2ChallengeResponse(
- ID_INT, PEER_CHALLENGE_BYTES, NT_RESPONSE_BYTES, FLAGS, PEER_NAME_BYTES);
- byte[] encodedChallengeResponse = challengeResponse.encode();
-
- assertArrayEquals(EAP_MSCHAP_V2_CHALLENGE_RESPONSE, encodedChallengeResponse);
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/message/mschapv2/EapMsChapV2FailureRequestTest.java b/tests/iketests/src/java/com/android/internal/net/eap/message/mschapv2/EapMsChapV2FailureRequestTest.java
deleted file mode 100644
index ead8022a..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/message/mschapv2/EapMsChapV2FailureRequestTest.java
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.message.mschapv2;
-
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.CHALLENGE_BYTES;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.EAP_MSCHAP_V2_FAILURE_REQUEST;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.EAP_MSCHAP_V2_FAILURE_REQUEST_MISSING_MESSAGE;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.EAP_MSCHAP_V2_FAILURE_REQUEST_MISSING_MESSAGE_WITH_SPACE;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.ERROR_CODE;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.FAILURE_REQUEST_EXTRA_ATTRIBUTE;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.FAILURE_REQUEST_INVALID_CHALLENGE;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.FAILURE_REQUEST_INVALID_ERROR_CODE;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.FAILURE_REQUEST_INVALID_PASSWORD_CHANGE_PROTOCOL;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.FAILURE_REQUEST_SHORT_CHALLENGE;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.ID_INT;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.MESSAGE;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.MESSAGE_MISSING_TEXT;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.PASSWORD_CHANGE_PROTOCOL;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.RETRY_BIT;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2TypeData.EAP_MSCHAP_V2_FAILURE;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import com.android.internal.net.eap.exceptions.mschapv2.EapMsChapV2ParsingException;
-import com.android.internal.net.eap.message.mschapv2.EapMsChapV2TypeData.EapMsChapV2FailureRequest;
-import com.android.internal.net.eap.message.mschapv2.EapMsChapV2TypeData.EapMsChapV2TypeDataDecoder;
-import com.android.internal.net.eap.message.mschapv2.EapMsChapV2TypeData.EapMsChapV2TypeDataDecoder.DecodeResult;
-
-import org.junit.Before;
-import org.junit.Test;
-
-public class EapMsChapV2FailureRequestTest {
- private static final String TAG = EapMsChapV2FailureRequestTest.class.getSimpleName();
-
- private EapMsChapV2TypeDataDecoder mTypeDataDecoder;
-
- @Before
- public void setUp() {
- mTypeDataDecoder = new EapMsChapV2TypeDataDecoder();
- }
-
- @Test
- public void testDecodeFailureRequest() {
- DecodeResult<EapMsChapV2FailureRequest> result =
- mTypeDataDecoder.decodeFailureRequest(TAG, EAP_MSCHAP_V2_FAILURE_REQUEST);
- assertTrue(result.isSuccessfulDecode());
-
- EapMsChapV2FailureRequest failureRequest = result.eapTypeData;
- assertEquals(EAP_MSCHAP_V2_FAILURE, failureRequest.opCode);
- assertEquals(ID_INT, failureRequest.msChapV2Id);
- assertEquals(EAP_MSCHAP_V2_FAILURE_REQUEST.length, failureRequest.msLength);
- assertEquals(ERROR_CODE, failureRequest.errorCode);
- assertEquals(RETRY_BIT, failureRequest.isRetryable);
- assertArrayEquals(CHALLENGE_BYTES, failureRequest.challenge);
- assertEquals(PASSWORD_CHANGE_PROTOCOL, failureRequest.passwordChangeProtocol);
- assertEquals(MESSAGE, failureRequest.message);
- }
-
- @Test
- public void testDecodeFailureRequestMissingMessage() {
- DecodeResult<EapMsChapV2FailureRequest> result =
- mTypeDataDecoder.decodeFailureRequest(
- TAG, EAP_MSCHAP_V2_FAILURE_REQUEST_MISSING_MESSAGE);
- assertTrue(result.isSuccessfulDecode());
-
- EapMsChapV2FailureRequest failureRequest = result.eapTypeData;
- assertEquals(EAP_MSCHAP_V2_FAILURE, failureRequest.opCode);
- assertEquals(ID_INT, failureRequest.msChapV2Id);
- assertEquals(EAP_MSCHAP_V2_FAILURE_REQUEST_MISSING_MESSAGE.length, failureRequest.msLength);
- assertEquals(ERROR_CODE, failureRequest.errorCode);
- assertEquals(RETRY_BIT, failureRequest.isRetryable);
- assertArrayEquals(CHALLENGE_BYTES, failureRequest.challenge);
- assertEquals(PASSWORD_CHANGE_PROTOCOL, failureRequest.passwordChangeProtocol);
- assertEquals(MESSAGE_MISSING_TEXT, failureRequest.message);
- }
-
- @Test
- public void testDecodeFailureRequestMissingMessageWithSpace() {
- DecodeResult<EapMsChapV2FailureRequest> result =
- mTypeDataDecoder.decodeFailureRequest(
- TAG, EAP_MSCHAP_V2_FAILURE_REQUEST_MISSING_MESSAGE_WITH_SPACE);
- assertTrue(result.isSuccessfulDecode());
-
- EapMsChapV2FailureRequest failureRequest = result.eapTypeData;
- assertEquals(EAP_MSCHAP_V2_FAILURE, failureRequest.opCode);
- assertEquals(ID_INT, failureRequest.msChapV2Id);
- assertEquals(
- EAP_MSCHAP_V2_FAILURE_REQUEST_MISSING_MESSAGE_WITH_SPACE.length,
- failureRequest.msLength);
- assertEquals(ERROR_CODE, failureRequest.errorCode);
- assertEquals(RETRY_BIT, failureRequest.isRetryable);
- assertArrayEquals(CHALLENGE_BYTES, failureRequest.challenge);
- assertEquals(PASSWORD_CHANGE_PROTOCOL, failureRequest.passwordChangeProtocol);
- assertEquals(MESSAGE_MISSING_TEXT, failureRequest.message);
- }
-
- @Test
- public void testDecodeFailureRequestInvalidErrorCode() {
- DecodeResult<EapMsChapV2FailureRequest> result =
- mTypeDataDecoder.decodeFailureRequest(TAG, FAILURE_REQUEST_INVALID_ERROR_CODE);
- assertTrue(!result.isSuccessfulDecode());
- assertTrue(result.eapError.cause instanceof NumberFormatException);
- }
-
- @Test
- public void testDecodeFailureRequestInvalidChallenge() {
- DecodeResult<EapMsChapV2FailureRequest> result =
- mTypeDataDecoder.decodeFailureRequest(TAG, FAILURE_REQUEST_INVALID_CHALLENGE);
- assertTrue(!result.isSuccessfulDecode());
- assertTrue(result.eapError.cause instanceof NumberFormatException);
- }
-
- @Test
- public void testDecodeFailureRequestShortChallenge() {
- DecodeResult<EapMsChapV2FailureRequest> result =
- mTypeDataDecoder.decodeFailureRequest(TAG, FAILURE_REQUEST_SHORT_CHALLENGE);
- assertTrue(!result.isSuccessfulDecode());
- assertTrue(result.eapError.cause instanceof EapMsChapV2ParsingException);
- }
-
- @Test
- public void testDecodeFailureRequestInvalidPasswordChangeProtocol() {
- DecodeResult<EapMsChapV2FailureRequest> result =
- mTypeDataDecoder.decodeFailureRequest(
- TAG, FAILURE_REQUEST_INVALID_PASSWORD_CHANGE_PROTOCOL);
- assertTrue(!result.isSuccessfulDecode());
- assertTrue(result.eapError.cause instanceof NumberFormatException);
- }
-
- @Test
- public void testDecodeFailureExtraAttribute() {
- DecodeResult<EapMsChapV2FailureRequest> result =
- mTypeDataDecoder.decodeFailureRequest(TAG, FAILURE_REQUEST_EXTRA_ATTRIBUTE);
- assertTrue(!result.isSuccessfulDecode());
- assertTrue(result.eapError.cause instanceof EapMsChapV2ParsingException);
- }
-
- @Test
- public void testEncodeFails() throws Exception {
- EapMsChapV2FailureRequest failureRequest =
- new EapMsChapV2FailureRequest(
- ID_INT,
- EAP_MSCHAP_V2_FAILURE_REQUEST.length,
- ERROR_CODE,
- RETRY_BIT,
- CHALLENGE_BYTES,
- PASSWORD_CHANGE_PROTOCOL,
- MESSAGE);
- try {
- failureRequest.encode();
- fail("Expected UnsupportedOperationException for encoding a request");
- } catch (UnsupportedOperationException expected) {
- }
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/message/mschapv2/EapMsChapV2FailureResponseTest.java b/tests/iketests/src/java/com/android/internal/net/eap/message/mschapv2/EapMsChapV2FailureResponseTest.java
deleted file mode 100644
index 261ddb28..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/message/mschapv2/EapMsChapV2FailureResponseTest.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.message.mschapv2;
-
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.EAP_MSCHAP_V2_FAILURE_RESPONSE;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2TypeData.EAP_MSCHAP_V2_FAILURE;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-
-import com.android.internal.net.eap.message.mschapv2.EapMsChapV2TypeData.EapMsChapV2FailureResponse;
-
-import org.junit.Test;
-
-public class EapMsChapV2FailureResponseTest {
- @Test
- public void testGetEapMsChapV2FailureResponse() {
- EapMsChapV2FailureResponse failureResponse =
- EapMsChapV2FailureResponse.getEapMsChapV2FailureResponse();
- assertEquals(EAP_MSCHAP_V2_FAILURE, failureResponse.opCode);
- }
-
- @Test
- public void testEncode() {
- EapMsChapV2FailureResponse failureResponse =
- EapMsChapV2FailureResponse.getEapMsChapV2FailureResponse();
- assertArrayEquals(EAP_MSCHAP_V2_FAILURE_RESPONSE, failureResponse.encode());
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/message/mschapv2/EapMsChapV2PacketDefinitions.java b/tests/iketests/src/java/com/android/internal/net/eap/message/mschapv2/EapMsChapV2PacketDefinitions.java
deleted file mode 100644
index e70c2a2f..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/message/mschapv2/EapMsChapV2PacketDefinitions.java
+++ /dev/null
@@ -1,284 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.message.mschapv2;
-
-import static com.android.internal.net.TestUtils.hexStringToByteArray;
-
-public class EapMsChapV2PacketDefinitions {
- public static final String ID = "1F";
- public static final int ID_INT = Integer.parseInt(ID, 16 /* radix */);
-
- public static final String CHALLENGE = "000102030405060708090A0B0C0D0E0F";
- public static final byte[] CHALLENGE_BYTES = hexStringToByteArray(CHALLENGE);
-
- // server name is the ASCII hex for "authenticator@android.net"
- public static final String SERVER_NAME = "61757468656E74696361746F7240616E64726F69642E6E6574";
- public static final byte[] SERVER_NAME_BYTES = hexStringToByteArray(SERVER_NAME);
- public static final byte[] EAP_MSCHAP_V2_CHALLENGE_REQUEST =
- hexStringToByteArray("01" + ID + "002E10" + CHALLENGE + SERVER_NAME);
-
- public static final byte[] CHALLENGE_REQUEST_WRONG_OP_CODE = hexStringToByteArray("02");
- public static final String SHORT_CHALLENGE = "001122334455";
- public static final byte[] SHORT_CHALLENGE_BYTES = hexStringToByteArray(SHORT_CHALLENGE);
- public static final byte[] CHALLENGE_REQUEST_SHORT_CHALLENGE =
- hexStringToByteArray("01" + ID + "002406" + SHORT_CHALLENGE + SERVER_NAME);
- public static final byte[] CHALLENGE_REQUEST_SHORT_MS_LENGTH =
- hexStringToByteArray("01" + ID + "000110" + CHALLENGE + SERVER_NAME);
- public static final byte[] CHALLENGE_REQUEST_LONG_MS_LENGTH =
- hexStringToByteArray("01" + ID + "00FF10" + CHALLENGE + SERVER_NAME);
-
- public static final String PEER_CHALLENGE = "00112233445566778899AABBCCDDEEFF";
- public static final byte[] PEER_CHALLENGE_BYTES = hexStringToByteArray(PEER_CHALLENGE);
- public static final String NT_RESPONSE = "FFEEDDCCBBAA998877665544332211000011223344556677";
- public static final byte[] NT_RESPONSE_BYTES = hexStringToByteArray(NT_RESPONSE);
-
- // peer name is the ASCII hex for "peer@android.net"
- public static final String PEER_NAME = "7065657240616E64726F69642E6E6574";
- public static final byte[] PEER_NAME_BYTES = hexStringToByteArray(PEER_NAME);
- public static final byte[] EAP_MSCHAP_V2_CHALLENGE_RESPONSE =
- hexStringToByteArray(
- "02"
- + ID
- + "004631"
- + PEER_CHALLENGE
- + "0000000000000000"
- + NT_RESPONSE
- + "00"
- + PEER_NAME);
-
- public static final byte[] SHORT_NT_RESPONSE = hexStringToByteArray("0011223344");
-
- public static final String AUTH_STRING = "00112233445566778899AABBCCDDEEFF00112233";
-
- // ASCII hex for AUTH_STRING
- public static final String AUTH_STRING_HEX =
- "30303131323233333434353536363737383839394141424243434444454546463030313132323333";
- public static final byte[] AUTH_BYTES = hexStringToByteArray(AUTH_STRING);
-
- // hex("S=") + AUTH_STRING_HEX
- public static final String FORMATTED_AUTH_STRING = "533D" + AUTH_STRING_HEX;
-
- public static final String SPACE_HEX = "20";
-
- // ASCII hex for: "test Android 1234"
- public static final String MESSAGE = "test Android 1234";
- public static final String MESSAGE_HEX = "7465737420416E64726F69642031323334";
-
- // hex("M=") + MESSAGE_HEX
- public static final String FORMATTED_MESSAGE = "4D3D" + MESSAGE_HEX;
-
- public static final byte[] EAP_MSCHAP_V2_SUCCESS_REQUEST =
- hexStringToByteArray(
- "03" + ID + "0042" + FORMATTED_AUTH_STRING + SPACE_HEX + FORMATTED_MESSAGE);
- public static final byte[] EAP_MSCHAP_V2_SUCCESS_REQUEST_EMPTY_MESSAGE =
- hexStringToByteArray("03" + ID + "0031" + FORMATTED_AUTH_STRING + SPACE_HEX + "4D3D");
- public static final byte[] EAP_MSCHAP_V2_SUCCESS_REQUEST_MISSING_MESSAGE =
- hexStringToByteArray("03" + ID + "002E" + FORMATTED_AUTH_STRING);
- public static final byte[] EAP_MSCHAP_V2_SUCCESS_REQUEST_MISSING_MESSAGE_WITH_SPACE =
- hexStringToByteArray("03" + ID + "002F" + FORMATTED_AUTH_STRING + SPACE_HEX);
- public static final String MESSAGE_MISSING_TEXT = "<omitted by authenticator>";
-
- public static final String SHORT_AUTH_STRING = "001122334455";
-
- public static final byte[] SUCCESS_REQUEST_WRONG_OP_CODE = hexStringToByteArray("02");
-
- // message format: hex("M=") + AUTH_STRING_HEX + hex("M=") + MESSAGE_HEX
- public static final byte[] SUCCESS_REQUEST_WRONG_PREFIX =
- hexStringToByteArray("03" + ID + "00314D3D" + AUTH_STRING_HEX + SPACE_HEX + "4D3D");
-
- // message format: hex("S=") + SHORT_AUTH_STRING + hex("M=") + MESSAGE_HEX
- public static final byte[] SUCCESS_REQUEST_SHORT_AUTH_STRING =
- hexStringToByteArray("03" + ID + "0031533D" + SHORT_AUTH_STRING + SPACE_HEX + "4D3D");
-
- public static final String INVALID_AUTH_HEX =
- "3030313132323333343435353636373738383939414142424343444445454646303031317A7A7979";
- public static final byte[] SUCCESS_REQUEST_INVALID_AUTH_STRING =
- hexStringToByteArray("03" + ID + "0031533D" + INVALID_AUTH_HEX + SPACE_HEX + "4D3D");
-
- // extra key-value: hex("N=12")
- public static final String EXTRA_KEY = "4E3D3132";
- public static final byte[] SUCCESS_REQUEST_EXTRA_ATTRIBUTE =
- hexStringToByteArray(
- "03"
- + ID
- + "0042"
- + FORMATTED_AUTH_STRING
- + SPACE_HEX
- + EXTRA_KEY
- + SPACE_HEX
- + FORMATTED_MESSAGE);
-
- public static final String SUCCESS_REQUEST = "S=" + AUTH_STRING + " M=" + MESSAGE;
- public static final String EXTRA_M_MESSAGE = "M=" + MESSAGE;
- public static final String SUCCESS_REQUEST_EXTRA_M =
- "S=" + AUTH_STRING + " M=" + EXTRA_M_MESSAGE;
- public static final String SUCCESS_REQUEST_MISSING_M = "S=" + AUTH_STRING;
- public static final String SUCCESS_REQUEST_INVALID_FORMAT =
- "S==" + AUTH_STRING + "M=" + MESSAGE;
- public static final String SUCCESS_REQUEST_DUPLICATE_KEY =
- "S=" + AUTH_STRING + " S=" + AUTH_STRING + " M=" + MESSAGE;
-
- public static final byte[] EAP_MSCHAP_V2_SUCCESS_RESPONSE = hexStringToByteArray("03");
-
- public static final int ERROR_CODE = 647; // account disabled
-
- // formatted error code: hex("E=" + ERROR_CODE)
- public static final String FORMATTED_ERROR_CODE = "453D363437";
- public static final boolean RETRY_BIT = true;
-
- // formatted retry bit: hex("R=1")
- public static final String FORMATTED_RETRY_BIT = "523D31";
-
- // challenge hex: hex(CHALLENGE)
- public static final String CHALLENGE_HEX =
- "3030303130323033303430353036303730383039304130423043304430453046";
-
- // formatted challenge: hex("C=") + CHALLENGE_HEX
- public static final String FORMATTED_CHALLENGE = "433D" + CHALLENGE_HEX;
-
- public static final int PASSWORD_CHANGE_PROTOCOL = 3;
-
- // formatted password change protocol: hex("V=3")
- public static final String FORMATTED_PASSWORD_CHANGE_PROTOCOL = "563D33";
-
- public static final byte[] EAP_MSCHAP_V2_FAILURE_REQUEST =
- hexStringToByteArray(
- "04"
- + ID
- + "0048"
- + FORMATTED_ERROR_CODE
- + SPACE_HEX
- + FORMATTED_RETRY_BIT
- + SPACE_HEX
- + FORMATTED_CHALLENGE
- + SPACE_HEX
- + FORMATTED_PASSWORD_CHANGE_PROTOCOL
- + SPACE_HEX
- + FORMATTED_MESSAGE);
- public static final byte[] EAP_MSCHAP_V2_FAILURE_REQUEST_MISSING_MESSAGE =
- hexStringToByteArray(
- "04"
- + ID
- + "0034"
- + FORMATTED_ERROR_CODE
- + SPACE_HEX
- + FORMATTED_RETRY_BIT
- + SPACE_HEX
- + FORMATTED_CHALLENGE
- + SPACE_HEX
- + FORMATTED_PASSWORD_CHANGE_PROTOCOL);
- public static final byte[] EAP_MSCHAP_V2_FAILURE_REQUEST_MISSING_MESSAGE_WITH_SPACE =
- hexStringToByteArray(
- "04"
- + ID
- + "0035"
- + FORMATTED_ERROR_CODE
- + SPACE_HEX
- + FORMATTED_RETRY_BIT
- + SPACE_HEX
- + FORMATTED_CHALLENGE
- + SPACE_HEX
- + FORMATTED_PASSWORD_CHANGE_PROTOCOL
- + SPACE_HEX);
-
- // invalid error code: hex("E=abc")
- public static final String INVALID_ERROR_CODE = "453D616263";
- public static final byte[] FAILURE_REQUEST_INVALID_ERROR_CODE =
- hexStringToByteArray(
- "04"
- + ID
- + "0048"
- + INVALID_ERROR_CODE
- + SPACE_HEX
- + FORMATTED_RETRY_BIT
- + SPACE_HEX
- + FORMATTED_CHALLENGE
- + SPACE_HEX
- + FORMATTED_PASSWORD_CHANGE_PROTOCOL
- + SPACE_HEX
- + FORMATTED_MESSAGE);
-
- // invalid challenge: hex("C=zyxd")
- public static final String INVALID_CHALLENGE = "433D7A797864";
- public static final byte[] FAILURE_REQUEST_INVALID_CHALLENGE =
- hexStringToByteArray(
- "04"
- + ID
- + "0032"
- + FORMATTED_ERROR_CODE
- + SPACE_HEX
- + FORMATTED_RETRY_BIT
- + SPACE_HEX
- + INVALID_CHALLENGE
- + SPACE_HEX
- + FORMATTED_PASSWORD_CHANGE_PROTOCOL
- + SPACE_HEX
- + FORMATTED_MESSAGE);
-
- // short challenge: hex("C=" + SHORT_CHALLENGE)
- public static final String FORMATTED_SHORT_CHALLENGE = "433D303031313232333334343535";
- public static final byte[] FAILURE_REQUEST_SHORT_CHALLENGE =
- hexStringToByteArray(
- "04"
- + ID
- + "0034"
- + FORMATTED_ERROR_CODE
- + SPACE_HEX
- + FORMATTED_RETRY_BIT
- + SPACE_HEX
- + FORMATTED_SHORT_CHALLENGE
- + SPACE_HEX
- + FORMATTED_PASSWORD_CHANGE_PROTOCOL
- + SPACE_HEX
- + FORMATTED_MESSAGE);
-
- // invalid password change protocol: hex("V=d")
- public static final String INVALID_PASSWORD_CHANGE_PROTOCOL = "563D64";
- public static final byte[] FAILURE_REQUEST_INVALID_PASSWORD_CHANGE_PROTOCOL =
- hexStringToByteArray(
- "04"
- + ID
- + "0048"
- + FORMATTED_ERROR_CODE
- + SPACE_HEX
- + FORMATTED_RETRY_BIT
- + SPACE_HEX
- + FORMATTED_CHALLENGE
- + SPACE_HEX
- + INVALID_PASSWORD_CHANGE_PROTOCOL
- + SPACE_HEX
- + FORMATTED_MESSAGE);
-
- public static final byte[] FAILURE_REQUEST_EXTRA_ATTRIBUTE =
- hexStringToByteArray(
- "04"
- + ID
- + "0048"
- + FORMATTED_ERROR_CODE
- + SPACE_HEX
- + FORMATTED_RETRY_BIT
- + SPACE_HEX
- + FORMATTED_CHALLENGE
- + SPACE_HEX
- + FORMATTED_PASSWORD_CHANGE_PROTOCOL
- + SPACE_HEX
- + EXTRA_KEY
- + SPACE_HEX
- + FORMATTED_MESSAGE);
-
- public static final byte[] EAP_MSCHAP_V2_FAILURE_RESPONSE = hexStringToByteArray("04");
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/message/mschapv2/EapMsChapV2SuccessRequestTest.java b/tests/iketests/src/java/com/android/internal/net/eap/message/mschapv2/EapMsChapV2SuccessRequestTest.java
deleted file mode 100644
index 1e0909ed..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/message/mschapv2/EapMsChapV2SuccessRequestTest.java
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.message.mschapv2;
-
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.AUTH_BYTES;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.EAP_MSCHAP_V2_SUCCESS_REQUEST;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.EAP_MSCHAP_V2_SUCCESS_REQUEST_EMPTY_MESSAGE;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.EAP_MSCHAP_V2_SUCCESS_REQUEST_MISSING_MESSAGE;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.EAP_MSCHAP_V2_SUCCESS_REQUEST_MISSING_MESSAGE_WITH_SPACE;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.ID_INT;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.MESSAGE;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.MESSAGE_MISSING_TEXT;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.SUCCESS_REQUEST_EXTRA_ATTRIBUTE;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.SUCCESS_REQUEST_INVALID_AUTH_STRING;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.SUCCESS_REQUEST_SHORT_AUTH_STRING;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.SUCCESS_REQUEST_WRONG_OP_CODE;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.SUCCESS_REQUEST_WRONG_PREFIX;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2TypeData.EAP_MSCHAP_V2_SUCCESS;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import com.android.internal.net.eap.EapResult.EapError;
-import com.android.internal.net.eap.exceptions.mschapv2.EapMsChapV2ParsingException;
-import com.android.internal.net.eap.message.mschapv2.EapMsChapV2TypeData.EapMsChapV2SuccessRequest;
-import com.android.internal.net.eap.message.mschapv2.EapMsChapV2TypeData.EapMsChapV2TypeDataDecoder;
-import com.android.internal.net.eap.message.mschapv2.EapMsChapV2TypeData.EapMsChapV2TypeDataDecoder.DecodeResult;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.nio.BufferUnderflowException;
-
-public class EapMsChapV2SuccessRequestTest {
- private static final String TAG = EapMsChapV2SuccessRequestTest.class.getSimpleName();
-
- private EapMsChapV2TypeDataDecoder mTypeDataDecoder;
-
- @Before
- public void setUp() {
- mTypeDataDecoder = new EapMsChapV2TypeDataDecoder();
- }
-
- @Test
- public void testDecodeSuccessRequest() {
- DecodeResult<EapMsChapV2SuccessRequest> result =
- mTypeDataDecoder.decodeSuccessRequest(TAG, EAP_MSCHAP_V2_SUCCESS_REQUEST);
- assertTrue(result.isSuccessfulDecode());
-
- EapMsChapV2SuccessRequest successRequest = result.eapTypeData;
- assertEquals(EAP_MSCHAP_V2_SUCCESS, successRequest.opCode);
- assertEquals(ID_INT, successRequest.msChapV2Id);
- assertEquals(EAP_MSCHAP_V2_SUCCESS_REQUEST.length, successRequest.msLength);
- assertArrayEquals(AUTH_BYTES, successRequest.authBytes);
- assertEquals(MESSAGE, successRequest.message);
- }
-
- @Test
- public void testDecodeSuccessRequestEmptyMessage() {
- DecodeResult<EapMsChapV2SuccessRequest> result =
- mTypeDataDecoder.decodeSuccessRequest(
- TAG, EAP_MSCHAP_V2_SUCCESS_REQUEST_EMPTY_MESSAGE);
- assertTrue(result.isSuccessfulDecode());
-
- EapMsChapV2SuccessRequest successRequest = result.eapTypeData;
- assertEquals(EAP_MSCHAP_V2_SUCCESS, successRequest.opCode);
- assertEquals(ID_INT, successRequest.msChapV2Id);
- assertEquals(EAP_MSCHAP_V2_SUCCESS_REQUEST_EMPTY_MESSAGE.length, successRequest.msLength);
- assertArrayEquals(AUTH_BYTES, successRequest.authBytes);
- assertTrue(successRequest.message.isEmpty());
- }
-
- @Test
- public void testDecodeSuccessRequestMissingMessage() {
- DecodeResult<EapMsChapV2SuccessRequest> result =
- mTypeDataDecoder.decodeSuccessRequest(
- TAG, EAP_MSCHAP_V2_SUCCESS_REQUEST_MISSING_MESSAGE);
- assertTrue(result.isSuccessfulDecode());
-
- EapMsChapV2SuccessRequest successRequest = result.eapTypeData;
- assertEquals(EAP_MSCHAP_V2_SUCCESS, successRequest.opCode);
- assertEquals(ID_INT, successRequest.msChapV2Id);
- assertEquals(EAP_MSCHAP_V2_SUCCESS_REQUEST_MISSING_MESSAGE.length, successRequest.msLength);
- assertArrayEquals(AUTH_BYTES, successRequest.authBytes);
- assertEquals(MESSAGE_MISSING_TEXT, successRequest.message);
- }
-
- @Test
- public void testDecodeSuccessRequestMissingMessageWithSpace() {
- DecodeResult<EapMsChapV2SuccessRequest> result =
- mTypeDataDecoder.decodeSuccessRequest(
- TAG, EAP_MSCHAP_V2_SUCCESS_REQUEST_MISSING_MESSAGE_WITH_SPACE);
- assertTrue(result.isSuccessfulDecode());
-
- EapMsChapV2SuccessRequest successRequest = result.eapTypeData;
- assertEquals(EAP_MSCHAP_V2_SUCCESS, successRequest.opCode);
- assertEquals(ID_INT, successRequest.msChapV2Id);
- assertEquals(
- EAP_MSCHAP_V2_SUCCESS_REQUEST_MISSING_MESSAGE_WITH_SPACE.length,
- successRequest.msLength);
- assertArrayEquals(AUTH_BYTES, successRequest.authBytes);
- assertEquals(MESSAGE_MISSING_TEXT, successRequest.message);
- }
-
- @Test
- public void testDecodeSuccessRequestWrongOpCode() {
- DecodeResult<EapMsChapV2SuccessRequest> result =
- mTypeDataDecoder.decodeSuccessRequest(TAG, SUCCESS_REQUEST_WRONG_OP_CODE);
- assertFalse(result.isSuccessfulDecode());
- EapError eapError = result.eapError;
- assertTrue(eapError.cause instanceof EapMsChapV2ParsingException);
- }
-
- @Test
- public void testDecodeSuccessRequestShortMessage() {
- DecodeResult<EapMsChapV2SuccessRequest> result =
- mTypeDataDecoder.decodeSuccessRequest(TAG, new byte[0]);
- assertFalse(result.isSuccessfulDecode());
- EapError eapError = result.eapError;
- assertTrue(eapError.cause instanceof BufferUnderflowException);
- }
-
- @Test
- public void testDecodeSuccessRequestInvalidPrefix() {
- DecodeResult<EapMsChapV2SuccessRequest> result =
- mTypeDataDecoder.decodeSuccessRequest(TAG, SUCCESS_REQUEST_WRONG_PREFIX);
- assertFalse(result.isSuccessfulDecode());
- EapError eapError = result.eapError;
- assertTrue(eapError.cause instanceof EapMsChapV2ParsingException);
- }
-
- @Test
- public void testDecodeSuccessRequestShortAuthString() {
- DecodeResult<EapMsChapV2SuccessRequest> result =
- mTypeDataDecoder.decodeSuccessRequest(TAG, SUCCESS_REQUEST_SHORT_AUTH_STRING);
- assertFalse(result.isSuccessfulDecode());
- EapError eapError = result.eapError;
- assertTrue(eapError.cause instanceof EapMsChapV2ParsingException);
- }
-
- @Test
- public void testDecodeSuccessRequestInvalidAuthString() {
- DecodeResult<EapMsChapV2SuccessRequest> result =
- mTypeDataDecoder.decodeSuccessRequest(TAG, SUCCESS_REQUEST_INVALID_AUTH_STRING);
- assertFalse(result.isSuccessfulDecode());
- EapError eapError = result.eapError;
- assertTrue(eapError.cause instanceof NumberFormatException);
- }
-
- @Test
- public void testDecodeSuccessRequestExtraAttribute() {
- DecodeResult<EapMsChapV2SuccessRequest> result =
- mTypeDataDecoder.decodeSuccessRequest(TAG, SUCCESS_REQUEST_EXTRA_ATTRIBUTE);
- assertFalse(result.isSuccessfulDecode());
- EapError eapError = result.eapError;
- assertTrue(eapError.cause instanceof EapMsChapV2ParsingException);
- }
-
- @Test
- public void testEncodeFails() throws Exception {
- EapMsChapV2SuccessRequest successRequest =
- new EapMsChapV2SuccessRequest(
- ID_INT, EAP_MSCHAP_V2_SUCCESS_REQUEST.length, AUTH_BYTES, MESSAGE);
- try {
- successRequest.encode();
- fail("Expected UnsupportedOperationException for encoding a request");
- } catch (UnsupportedOperationException expected) {
- }
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/message/mschapv2/EapMsChapV2SuccessResponseTest.java b/tests/iketests/src/java/com/android/internal/net/eap/message/mschapv2/EapMsChapV2SuccessResponseTest.java
deleted file mode 100644
index 524b3ecf..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/message/mschapv2/EapMsChapV2SuccessResponseTest.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.message.mschapv2;
-
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.EAP_MSCHAP_V2_SUCCESS_RESPONSE;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2TypeData.EAP_MSCHAP_V2_SUCCESS;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-
-import com.android.internal.net.eap.message.mschapv2.EapMsChapV2TypeData.EapMsChapV2SuccessResponse;
-
-import org.junit.Test;
-
-public class EapMsChapV2SuccessResponseTest {
- @Test
- public void testGetEapMsChapV2SuccessResponse() {
- EapMsChapV2SuccessResponse successResponse =
- EapMsChapV2SuccessResponse.getEapMsChapV2SuccessResponse();
- assertEquals(EAP_MSCHAP_V2_SUCCESS, successResponse.opCode);
- }
-
- @Test
- public void testEncode() {
- EapMsChapV2SuccessResponse successResponse =
- EapMsChapV2SuccessResponse.getEapMsChapV2SuccessResponse();
- assertArrayEquals(EAP_MSCHAP_V2_SUCCESS_RESPONSE, successResponse.encode());
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/message/mschapv2/EapMsChapV2TypeDataTest.java b/tests/iketests/src/java/com/android/internal/net/eap/message/mschapv2/EapMsChapV2TypeDataTest.java
deleted file mode 100644
index 45f1c641..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/message/mschapv2/EapMsChapV2TypeDataTest.java
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.message.mschapv2;
-
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.AUTH_BYTES;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.AUTH_STRING;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.EXTRA_M_MESSAGE;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.MESSAGE;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.MESSAGE_MISSING_TEXT;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.SUCCESS_REQUEST;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.SUCCESS_REQUEST_DUPLICATE_KEY;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.SUCCESS_REQUEST_EXTRA_M;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.SUCCESS_REQUEST_INVALID_FORMAT;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.SUCCESS_REQUEST_MISSING_M;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2TypeData.EAP_MSCHAP_V2_CHALLENGE;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import com.android.internal.net.eap.EapResult.EapError;
-import com.android.internal.net.eap.exceptions.mschapv2.EapMsChapV2ParsingException;
-import com.android.internal.net.eap.message.mschapv2.EapMsChapV2TypeData.EapMsChapV2TypeDataDecoder.DecodeResult;
-import com.android.internal.net.eap.message.mschapv2.EapMsChapV2TypeData.EapMsChapV2VariableTypeData;
-
-import org.junit.Test;
-
-import java.util.HashMap;
-import java.util.Map;
-
-public class EapMsChapV2TypeDataTest {
- private static final int INVALID_OPCODE = -1;
- private static final int MSCHAP_V2_ID = 1;
- private static final int MS_LENGTH = 32;
- private static final String HEX_STRING_INVALID_LENGTH = "00112";
- private static final String HEX_STRING_INVALID_CHARS = "001122z-+x";
-
- @Test
- public void testEapMsChapV2TypeDataConstructor() throws Exception {
- EapMsChapV2TypeData typeData = new EapMsChapV2TypeData(EAP_MSCHAP_V2_CHALLENGE) {};
- assertEquals(EAP_MSCHAP_V2_CHALLENGE, typeData.opCode);
-
- try {
- new EapMsChapV2TypeData(INVALID_OPCODE) {};
- fail("ExpectedEapMsChapV2ParsingException for invalid OpCode");
- } catch (EapMsChapV2ParsingException expected) {
- }
- }
-
- @Test
- public void testEapMsChapV2VariableTypeDataConstructor() throws Exception {
- EapMsChapV2VariableTypeData typeData =
- new EapMsChapV2VariableTypeData(
- EAP_MSCHAP_V2_CHALLENGE, MSCHAP_V2_ID, MS_LENGTH) {};
- assertEquals(EAP_MSCHAP_V2_CHALLENGE, typeData.opCode);
- assertEquals(MSCHAP_V2_ID, typeData.msChapV2Id);
- assertEquals(MS_LENGTH, typeData.msLength);
-
- try {
- new EapMsChapV2VariableTypeData(INVALID_OPCODE, MSCHAP_V2_ID, MS_LENGTH) {};
- fail("ExpectedEapMsChapV2ParsingException for invalid OpCode");
- } catch (EapMsChapV2ParsingException expected) {
- }
- }
-
- @Test
- public void testDecodeResultIsSuccessfulDecode() throws Exception {
- DecodeResult<EapMsChapV2TypeData> result =
- new DecodeResult(new EapMsChapV2TypeData(EAP_MSCHAP_V2_CHALLENGE) {});
- assertTrue(result.isSuccessfulDecode());
-
- result = new DecodeResult(new EapError(new Exception()));
- assertFalse(result.isSuccessfulDecode());
- }
-
- @Test
- public void testGetMessageMappings() throws Exception {
- Map<String, String> expectedMappings = new HashMap<>();
- expectedMappings.put("S", AUTH_STRING);
- expectedMappings.put("M", MESSAGE);
- assertEquals(expectedMappings, EapMsChapV2TypeData.getMessageMappings(SUCCESS_REQUEST));
-
- expectedMappings = new HashMap<>();
- expectedMappings.put("S", AUTH_STRING);
- expectedMappings.put("M", EXTRA_M_MESSAGE);
- assertEquals(
- expectedMappings, EapMsChapV2TypeData.getMessageMappings(SUCCESS_REQUEST_EXTRA_M));
-
- expectedMappings = new HashMap<>();
- expectedMappings.put("S", AUTH_STRING);
- expectedMappings.put("M", MESSAGE_MISSING_TEXT);
- assertEquals(
- expectedMappings,
- EapMsChapV2TypeData.getMessageMappings(SUCCESS_REQUEST_MISSING_M));
- }
-
- @Test
- public void testGetMessageMappingsInvalidFormat() {
- try {
- EapMsChapV2TypeData.getMessageMappings(SUCCESS_REQUEST_INVALID_FORMAT);
- fail("Expected EapMsChapV2ParsingException for extra '='s in message");
- } catch (EapMsChapV2ParsingException expected) {
- }
- }
-
- @Test
- public void testGetMessageMappingDuplicateKey() {
- try {
- EapMsChapV2TypeData.getMessageMappings(SUCCESS_REQUEST_DUPLICATE_KEY);
- fail("Expected EapMsChapV2ParsingException for duplicate key in message");
- } catch (EapMsChapV2ParsingException expected) {
- }
- }
-
- @Test
- public void testHexStringToByteArray() throws Exception {
- byte[] result = EapMsChapV2TypeData.hexStringToByteArray(AUTH_STRING);
- assertArrayEquals(AUTH_BYTES, result);
- }
-
- @Test
- public void testHexStringToByteArrayInvalidLength() {
- try {
- EapMsChapV2TypeData.hexStringToByteArray(HEX_STRING_INVALID_LENGTH);
- fail("Expected EapMsChapV2ParsingException for invalid hex string length");
- } catch (EapMsChapV2ParsingException expected) {
- }
- }
-
- @Test
- public void testHexStringToByteArrayInvalidChars() throws Exception {
- try {
- EapMsChapV2TypeData.hexStringToByteArray(HEX_STRING_INVALID_CHARS);
- fail("Expected NumberFormatException for invalid hex chars");
- } catch (NumberFormatException expected) {
- }
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/EapAkaPrimeTypeDataTest.java b/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/EapAkaPrimeTypeDataTest.java
deleted file mode 100644
index 6a9e517f..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/EapAkaPrimeTypeDataTest.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.message.simaka;
-
-import static com.android.internal.net.TestUtils.hexStringToByteArray;
-import static com.android.internal.net.eap.message.simaka.EapAkaTypeData.EAP_AKA_CHALLENGE;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_AUTN;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_KDF;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_KDF_INPUT;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_MAC;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_RAND;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.AT_KDF_INPUT;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.KDF_VERSION;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.NETWORK_NAME_BYTES;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.NETWORK_NAME_HEX;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import com.android.internal.net.eap.message.simaka.EapAkaPrimeTypeData.EapAkaPrimeTypeDataDecoder;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtAutn;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtClientErrorCode;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtKdf;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtKdfInput;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtMac;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtRandAka;
-import com.android.internal.net.eap.message.simaka.EapSimAkaTypeData.DecodeResult;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.Map.Entry;
-
-public class EapAkaPrimeTypeDataTest {
- private static final String RAND = "7A1FCDC0034BA1227E7B9FCEAFD47D53";
- private static final byte[] RAND_BYTES = hexStringToByteArray(RAND);
- private static final String AUTN = "000102030405060708090A0B0C0D0E0F";
- private static final byte[] AUTN_BYTES = hexStringToByteArray(AUTN);
- private static final String MAC = "95FEB9E70427F34B4FAC8F2C7A65A302";
- private static final byte[] MAC_BYTES = hexStringToByteArray(MAC);
- private static final byte[] EAP_AKA_PRIME_CHALLENGE_REQUEST =
- hexStringToByteArray(
- "010000" // Challenge | 2B padding
- + "01050000" + RAND // AT_RAND attribute
- + "02050000" + AUTN // AT_AUTN attribute
- + "1704000B" + NETWORK_NAME_HEX + "00" // AT_KDF_INPUT
- + "18010001" // AT_KDF
- + "0B050000" + MAC); // AT_MAC attribute
- private static final byte[] EAP_AKA_PRIME_MULTIPLE_AT_KDF =
- hexStringToByteArray(
- "010000" // Challenge | 2B padding
- + "01050000" + RAND // AT_RAND attribute
- + "02050000" + AUTN // AT_AUTN attribute
- + "1704000B" + NETWORK_NAME_HEX + "00" // AT_KDF_INPUT
- + "18010001" // AT_KDF
- + "18010002" // AT_KDF
- + "0B050000" + MAC); // AT_MAC attribute
-
- private EapAkaPrimeTypeDataDecoder mTypeDataDecoder;
-
- @Before
- public void setUp() {
- mTypeDataDecoder = EapAkaPrimeTypeData.getEapAkaPrimeTypeDataDecoder();
- }
-
- @Test
- public void testDecode() {
- DecodeResult<EapAkaTypeData> result =
- mTypeDataDecoder.decode(EAP_AKA_PRIME_CHALLENGE_REQUEST);
-
- assertTrue(result.isSuccessfulDecode());
- EapAkaPrimeTypeData eapAkaPrimeTypeData = (EapAkaPrimeTypeData) result.eapTypeData;
- assertEquals(EAP_AKA_CHALLENGE, eapAkaPrimeTypeData.eapSubtype);
-
- // also check Map entries (needs to match input order)
- Iterator<Entry<Integer, EapSimAkaAttribute>> itr =
- eapAkaPrimeTypeData.attributeMap.entrySet().iterator();
- Entry<Integer, EapSimAkaAttribute> entry = itr.next();
- assertEquals(EAP_AT_RAND, (int) entry.getKey());
- assertArrayEquals(RAND_BYTES, ((AtRandAka) entry.getValue()).rand);
-
- entry = itr.next();
- assertEquals(EAP_AT_AUTN, (int) entry.getKey());
- assertArrayEquals(AUTN_BYTES, ((AtAutn) entry.getValue()).autn);
-
- entry = itr.next();
- assertEquals(EAP_AT_KDF_INPUT, (int) entry.getKey());
- assertArrayEquals(NETWORK_NAME_BYTES, ((AtKdfInput) entry.getValue()).networkName);
-
- entry = itr.next();
- assertEquals(EAP_AT_KDF, (int) entry.getKey());
- assertEquals(KDF_VERSION, ((AtKdf) entry.getValue()).kdf);
-
- entry = itr.next();
- assertEquals(EAP_AT_MAC, (int) entry.getKey());
- assertArrayEquals(MAC_BYTES, ((AtMac) entry.getValue()).mac);
-
- assertFalse(itr.hasNext());
- }
-
- @Test
- public void testDecodeMultipleAtKdfAttributes() {
- DecodeResult<EapAkaTypeData> result =
- mTypeDataDecoder.decode(EAP_AKA_PRIME_MULTIPLE_AT_KDF);
-
- assertFalse(result.isSuccessfulDecode());
- assertEquals(AtClientErrorCode.UNABLE_TO_PROCESS, result.atClientErrorCode);
- }
-
- @Test
- public void testEncode() throws Exception {
- LinkedHashMap<Integer, EapSimAkaAttribute> attributes = new LinkedHashMap<>();
- attributes.put(EAP_AT_RAND, new AtRandAka(RAND_BYTES));
- attributes.put(EAP_AT_AUTN, new AtAutn(AUTN_BYTES));
- attributes.put(EAP_AT_KDF_INPUT, new AtKdfInput(AT_KDF_INPUT.length, NETWORK_NAME_BYTES));
- attributes.put(EAP_AT_KDF, new AtKdf(KDF_VERSION));
- attributes.put(EAP_AT_MAC, new AtMac(MAC_BYTES));
- EapAkaPrimeTypeData eapAkaPrimeTypeData =
- new EapAkaPrimeTypeData(EAP_AKA_CHALLENGE, attributes);
-
- byte[] result = eapAkaPrimeTypeData.encode();
- assertArrayEquals(EAP_AKA_PRIME_CHALLENGE_REQUEST, result);
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/EapAkaTypeDataTest.java b/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/EapAkaTypeDataTest.java
deleted file mode 100644
index b2d89d16..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/EapAkaTypeDataTest.java
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.message.simaka;
-
-import static com.android.internal.net.TestUtils.hexStringToByteArray;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_AKA_CHALLENGE_RESPONSE_MAC_BYTES;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_AKA_CHALLENGE_RESPONSE_TYPE_DATA;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_AKA_IDENTITY_REQUEST;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.INVALID_SUBTYPE;
-import static com.android.internal.net.eap.message.simaka.EapAkaTypeData.EAP_AKA_CHALLENGE;
-import static com.android.internal.net.eap.message.simaka.EapAkaTypeData.EAP_AKA_IDENTITY;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_ANY_ID_REQ;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_AUTN;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_CHECKCODE;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_MAC;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_RAND;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_RES;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.RES_BYTES;
-
-import static junit.framework.TestCase.fail;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import com.android.internal.net.eap.message.simaka.EapAkaTypeData.EapAkaTypeDataDecoder;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtAnyIdReq;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtAutn;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtMac;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtRandAka;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtRes;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EapSimAkaUnsupportedAttribute;
-import com.android.internal.net.eap.message.simaka.EapSimAkaTypeData.DecodeResult;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.util.Arrays;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.Map.Entry;
-
-public class EapAkaTypeDataTest {
- private static final int UNABLE_TO_PROCESS_CODE = 0;
- private static final int INVALID_SUBTYPE_INT = -1;
-
- private static final int EAP_AT_TRUST_IND = 139;
- private static final String RAND = "7A1FCDC0034BA1227E7B9FCEAFD47D53";
- private static final byte[] RAND_BYTES = hexStringToByteArray(RAND);
- private static final String AUTN = "000102030405060708090A0B0C0D0E0F";
- private static final byte[] AUTN_BYTES = hexStringToByteArray(AUTN);
- private static final String MAC = "95FEB9E70427F34B4FAC8F2C7A65A302";
- private static final byte[] MAC_BYTES = hexStringToByteArray(MAC);
- private static final byte[] EAP_AKA_REQUEST =
- hexStringToByteArray(
- "010000" // Challenge | 2B padding
- + "01050000" + RAND // AT_RAND attribute
- + "02050000" + AUTN // AT_AUTN attribute
- + "8B010002" // AT_RESULT_IND attribute (TS 124 302#8.2.3.1)
- + "0B050000" + MAC // AT_MAC attribute
- + "86010000"); // AT_CHECKCODE attribute
-
- private EapAkaTypeDataDecoder mEapAkaTypeDataDecoder;
-
- @Before
- public void setUp() {
- mEapAkaTypeDataDecoder = EapAkaTypeData.getEapAkaTypeDataDecoder();
- }
-
- @Test
- public void testDecode() {
- DecodeResult<EapAkaTypeData> result =
- mEapAkaTypeDataDecoder.decode(EAP_AKA_CHALLENGE_RESPONSE_TYPE_DATA);
-
- assertTrue(result.isSuccessfulDecode());
- EapAkaTypeData eapAkaTypeData = result.eapTypeData;
- assertEquals(EAP_AKA_CHALLENGE, eapAkaTypeData.eapSubtype);
-
- // also check Map entries (needs to match input order)
- Iterator<Entry<Integer, EapSimAkaAttribute>> itr =
- eapAkaTypeData.attributeMap.entrySet().iterator();
- Entry<Integer, EapSimAkaAttribute> entry = itr.next();
- assertEquals(EAP_AT_RES, (int) entry.getKey());
- assertArrayEquals(RES_BYTES, ((AtRes) entry.getValue()).res);
-
- entry = itr.next();
- assertEquals(EAP_AT_MAC, (int) entry.getKey());
- assertArrayEquals(EAP_AKA_CHALLENGE_RESPONSE_MAC_BYTES, ((AtMac) entry.getValue()).mac);
-
- assertFalse(itr.hasNext());
- }
-
- @Test
- public void testDecodeWithOptionalAttributes() {
- DecodeResult<EapAkaTypeData> result = mEapAkaTypeDataDecoder.decode(EAP_AKA_REQUEST);
-
- assertTrue(result.isSuccessfulDecode());
- EapAkaTypeData eapAkaTypeData = result.eapTypeData;
- assertEquals(EAP_AKA_CHALLENGE, eapAkaTypeData.eapSubtype);
-
- // also check Map entries (needs to match input order)
- Iterator<Entry<Integer, EapSimAkaAttribute>> itr =
- eapAkaTypeData.attributeMap.entrySet().iterator();
- Entry<Integer, EapSimAkaAttribute> entry = itr.next();
- assertEquals(EAP_AT_RAND, (int) entry.getKey());
- assertArrayEquals(RAND_BYTES, ((AtRandAka) entry.getValue()).rand);
-
- entry = itr.next();
- assertEquals(EAP_AT_AUTN, (int) entry.getKey());
- assertArrayEquals(AUTN_BYTES, ((AtAutn) entry.getValue()).autn);
-
- entry = itr.next();
- assertEquals(EAP_AT_TRUST_IND, (int) entry.getKey());
- assertTrue(entry.getValue() instanceof EapSimAkaUnsupportedAttribute);
-
- entry = itr.next();
- assertEquals(EAP_AT_MAC, (int) entry.getKey());
- assertArrayEquals(MAC_BYTES, ((AtMac) entry.getValue()).mac);
-
- entry = itr.next();
- assertEquals(EAP_AT_CHECKCODE, (int) entry.getKey());
- assertTrue(entry.getValue() instanceof EapSimAkaUnsupportedAttribute);
-
- assertFalse(itr.hasNext());
- }
-
- @Test
- public void testDecodeInvalidSubtype() {
- DecodeResult<EapAkaTypeData> result = mEapAkaTypeDataDecoder.decode(INVALID_SUBTYPE);
- assertFalse(result.isSuccessfulDecode());
- assertEquals(UNABLE_TO_PROCESS_CODE, result.atClientErrorCode.errorCode);
- }
-
- @Test
- public void testEncode() throws Exception {
- LinkedHashMap<Integer, EapSimAkaAttribute> attributes = new LinkedHashMap<>();
- attributes.put(EAP_AT_ANY_ID_REQ, new AtAnyIdReq());
- EapAkaTypeData eapAkaTypeData = new EapAkaTypeData(EAP_AKA_IDENTITY, attributes);
-
- byte[] result = eapAkaTypeData.encode();
- assertArrayEquals(EAP_AKA_IDENTITY_REQUEST, result);
- }
-
- @Test
- public void testConstructorInvalidSubtype() throws Exception {
- try {
- new EapAkaTypeData(INVALID_SUBTYPE_INT, Arrays.asList(new AtAnyIdReq()));
- fail("Expected IllegalArgumentException for invalid subtype");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void testConstructorDuplicateAttributes() throws Exception {
- try {
- new EapAkaTypeData(EAP_AKA_IDENTITY, Arrays.asList(new AtAnyIdReq(), new AtAnyIdReq()));
- fail("Expected IllegalArgumentException for duplicate attributes");
- } catch (IllegalArgumentException expected) {
- }
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/EapSimAkaAttributeFactoryTest.java b/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/EapSimAkaAttributeFactoryTest.java
deleted file mode 100644
index 5b6f5d60..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/EapSimAkaAttributeFactoryTest.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.message.simaka;
-
-import static com.android.internal.net.TestUtils.hexStringToByteArray;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.SKIPPABLE_DATA;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.SKIPPABLE_DATA_BYTES;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.SKIPPABLE_INVALID_ATTRIBUTE;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import com.android.internal.net.eap.exceptions.simaka.EapSimAkaUnsupportedAttributeException;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EapSimAkaUnsupportedAttribute;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.nio.ByteBuffer;
-
-public class EapSimAkaAttributeFactoryTest {
- private static final int SKIPPABLE_ATTRIBUTE_TYPE = 0xFF;
- private static final int SKIPPABLE_EXPECTED_LENGTH = 8;
-
- private static final int NON_SKIPPABLE_ATTRIBUTE_TYPE = 0x7F;
- private static final int NON_SKIPPABLE_ATTRIBUTE_LENGTH = 4;
-
- private EapSimAkaAttributeFactory mAttributeFactory;
-
- @Before
- public void setUp() {
- mAttributeFactory = new EapSimAkaAttributeFactory() {};
- }
-
- @Test
- public void testDecodeInvalidSkippable() throws Exception {
- ByteBuffer byteBuffer = ByteBuffer.wrap(SKIPPABLE_DATA_BYTES);
-
- EapSimAkaAttribute result = mAttributeFactory.getAttribute(
- SKIPPABLE_ATTRIBUTE_TYPE,
- SKIPPABLE_EXPECTED_LENGTH,
- byteBuffer);
- assertTrue(result instanceof EapSimAkaUnsupportedAttribute);
- EapSimAkaUnsupportedAttribute unsupportedAttribute = (EapSimAkaUnsupportedAttribute) result;
- assertEquals(SKIPPABLE_ATTRIBUTE_TYPE, unsupportedAttribute.attributeType);
- assertEquals(SKIPPABLE_EXPECTED_LENGTH, unsupportedAttribute.lengthInBytes);
- assertArrayEquals(hexStringToByteArray(SKIPPABLE_DATA), unsupportedAttribute.data);
- }
-
- @Test
- public void testEncodeInvalidSkippable() throws Exception {
- EapSimAkaUnsupportedAttribute unsupportedAttribute = new EapSimAkaUnsupportedAttribute(
- SKIPPABLE_ATTRIBUTE_TYPE,
- SKIPPABLE_EXPECTED_LENGTH,
- hexStringToByteArray(SKIPPABLE_DATA));
-
- ByteBuffer result = ByteBuffer.allocate(SKIPPABLE_EXPECTED_LENGTH);
- unsupportedAttribute.encode(result);
- assertArrayEquals(SKIPPABLE_INVALID_ATTRIBUTE, result.array());
- }
-
- @Test
- public void testDecodeInvalidNonSkippable() throws Exception {
- // Unskippable type + length + byte[] represent shortest legitimate attribute: "7F040000"
- ByteBuffer byteBuffer = ByteBuffer.wrap(new byte[2]);
-
- try {
- mAttributeFactory.getAttribute(
- NON_SKIPPABLE_ATTRIBUTE_TYPE,
- NON_SKIPPABLE_ATTRIBUTE_LENGTH,
- byteBuffer);
- fail("Expected EapSimAkaUnsupportedAttributeException for decoding invalid"
- + " non-skippable Attribute");
- } catch (EapSimAkaUnsupportedAttributeException expected) {
- }
- }
-
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/EapSimTypeDataTest.java b/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/EapSimTypeDataTest.java
deleted file mode 100644
index 678a812b..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/EapSimTypeDataTest.java
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.message.simaka;
-
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_SIM_START_DUPLICATE_ATTRIBUTES;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_SIM_START_SUBTYPE;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.INVALID_SUBTYPE;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.SHORT_TYPE_DATA;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.TYPE_DATA_INVALID_ATTRIBUTE;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.TYPE_DATA_INVALID_AT_RAND;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_PERMANENT_ID_REQ;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_VERSION_LIST;
-
-import static junit.framework.TestCase.fail;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtPermanentIdReq;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtVersionList;
-import com.android.internal.net.eap.message.simaka.EapSimAkaTypeData.DecodeResult;
-import com.android.internal.net.eap.message.simaka.EapSimTypeData.EapSimTypeDataDecoder;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.util.Arrays;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map.Entry;
-
-public class EapSimTypeDataTest {
- private static final int UNABLE_TO_PROCESS_CODE = 0;
- private static final int INSUFFICIENT_CHALLENGES_CODE = 2;
- private static final int EAP_SIM_START = 10;
- private static final int INVALID_SUBTYPE_INT = -1;
-
- private EapSimTypeDataDecoder mEapSimTypeDataDecoder;
-
- @Before
- public void setUp() {
- mEapSimTypeDataDecoder = EapSimTypeData.getEapSimTypeDataDecoder();
- }
-
- @Test
- public void testConstructor() throws Exception {
- List<EapSimAkaAttribute> attributes = Arrays.asList(
- new AtVersionList(8, 1), new AtPermanentIdReq());
-
- EapSimTypeData eapSimTypeData = new EapSimTypeData(EAP_SIM_START, attributes);
- assertEquals(EAP_SIM_START, eapSimTypeData.eapSubtype);
-
- // check order of entries in EapSimTypeData.attributeMap
- Iterator<Entry<Integer, EapSimAkaAttribute>> itr =
- eapSimTypeData.attributeMap.entrySet().iterator();
- Entry<Integer, EapSimAkaAttribute> pair = itr.next();
- assertEquals(EAP_AT_VERSION_LIST, (int) pair.getKey());
- assertEquals(Arrays.asList(1), ((AtVersionList) pair.getValue()).versions);
-
- pair = itr.next();
- assertEquals(EAP_AT_PERMANENT_ID_REQ, (int) pair.getKey());
- assertTrue(pair.getValue() instanceof AtPermanentIdReq);
- }
-
- @Test
- public void testDecode() {
- DecodeResult<EapSimTypeData> result = mEapSimTypeDataDecoder.decode(EAP_SIM_START_SUBTYPE);
-
- assertTrue(result.isSuccessfulDecode());
- EapSimTypeData eapSimTypeData = result.eapTypeData;
- assertEquals(EAP_SIM_START, eapSimTypeData.eapSubtype);
- assertTrue(eapSimTypeData.attributeMap.containsKey(EAP_AT_VERSION_LIST));
- AtVersionList atVersionList = (AtVersionList)
- eapSimTypeData.attributeMap.get(EAP_AT_VERSION_LIST);
- assertEquals(Arrays.asList(1), atVersionList.versions);
- assertTrue(eapSimTypeData.attributeMap.containsKey(EAP_AT_PERMANENT_ID_REQ));
-
- // also check order of Map entries (needs to match input order)
- Iterator<Integer> itr = eapSimTypeData.attributeMap.keySet().iterator();
- assertEquals(EAP_AT_VERSION_LIST, (int) itr.next());
- assertEquals(EAP_AT_PERMANENT_ID_REQ, (int) itr.next());
- assertFalse(itr.hasNext());
- }
-
- @Test
- public void testDecodeNullTypeData() {
- DecodeResult<EapSimTypeData> result = mEapSimTypeDataDecoder.decode(null);
- assertFalse(result.isSuccessfulDecode());
- assertEquals(UNABLE_TO_PROCESS_CODE, result.atClientErrorCode.errorCode);
- }
-
- @Test
- public void testDecodeInvalidSubtype() {
- DecodeResult<EapSimTypeData> result = mEapSimTypeDataDecoder.decode(INVALID_SUBTYPE);
- assertFalse(result.isSuccessfulDecode());
- assertEquals(UNABLE_TO_PROCESS_CODE, result.atClientErrorCode.errorCode);
- }
-
- @Test
- public void testDecodeInvalidAtRand() {
- DecodeResult<EapSimTypeData> result =
- mEapSimTypeDataDecoder.decode(TYPE_DATA_INVALID_AT_RAND);
- assertFalse(result.isSuccessfulDecode());
- assertEquals(INSUFFICIENT_CHALLENGES_CODE, result.atClientErrorCode.errorCode);
- }
-
- @Test
- public void testDecodeShortPacket() {
- DecodeResult<EapSimTypeData> result = mEapSimTypeDataDecoder.decode(SHORT_TYPE_DATA);
- assertFalse(result.isSuccessfulDecode());
- assertEquals(UNABLE_TO_PROCESS_CODE, result.atClientErrorCode.errorCode);
- }
-
- @Test
- public void testDecodeInvalidEapAttribute() {
- DecodeResult<EapSimTypeData> result =
- mEapSimTypeDataDecoder.decode(TYPE_DATA_INVALID_ATTRIBUTE);
- assertFalse(result.isSuccessfulDecode());
- assertEquals(UNABLE_TO_PROCESS_CODE, result.atClientErrorCode.errorCode);
- }
-
- @Test
- public void testEncode() throws Exception {
- LinkedHashMap<Integer, EapSimAkaAttribute> attributes = new LinkedHashMap<>();
- attributes.put(EAP_AT_VERSION_LIST, new AtVersionList(8, 1));
- attributes.put(EAP_AT_PERMANENT_ID_REQ, new AtPermanentIdReq());
- EapSimTypeData eapSimTypeData = new EapSimTypeData(EAP_SIM_START, attributes);
-
- byte[] result = eapSimTypeData.encode();
- assertArrayEquals(EAP_SIM_START_SUBTYPE, result);
- }
-
- @Test
- public void testDecodeDuplicateAttributes() {
- DecodeResult<EapSimTypeData> result =
- mEapSimTypeDataDecoder.decode(EAP_SIM_START_DUPLICATE_ATTRIBUTES);
- assertFalse(result.isSuccessfulDecode());
- assertEquals(UNABLE_TO_PROCESS_CODE, result.atClientErrorCode.errorCode);
- }
-
- @Test
- public void testConstructorInvalidSubtype() throws Exception {
- try {
- new EapSimTypeData(INVALID_SUBTYPE_INT, Arrays.asList(new AtPermanentIdReq()));
- fail("Expected IllegalArgumentException for invalid subtype");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void testConstructorDuplicateAttributes() throws Exception {
- try {
- new EapSimTypeData(
- EAP_SIM_START, Arrays.asList(new AtPermanentIdReq(), new AtPermanentIdReq()));
- fail("Expected IllegalArgumentException for duplicate attributes");
- } catch (IllegalArgumentException expected) {
- }
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtAutnTest.java b/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtAutnTest.java
deleted file mode 100644
index ebf22e4f..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtAutnTest.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.message.simaka.attributes;
-
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_AUTN;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.AT_AUTN;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.AT_AUTN_INVALID_LENGTH;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.AUTN_BYTES;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.fail;
-
-import com.android.internal.net.eap.exceptions.simaka.EapSimAkaInvalidAttributeException;
-import com.android.internal.net.eap.message.simaka.EapAkaAttributeFactory;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtAutn;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.nio.ByteBuffer;
-
-public class AtAutnTest {
- private EapAkaAttributeFactory mEapAkaAttributeFactory;
-
- @Before
- public void setUp() {
- mEapAkaAttributeFactory = EapAkaAttributeFactory.getInstance();
- }
-
- @Test
- public void testDecode() throws Exception {
- ByteBuffer input = ByteBuffer.wrap(AT_AUTN);
- EapSimAkaAttribute result = mEapAkaAttributeFactory.getAttribute(input);
-
- assertFalse(input.hasRemaining());
- AtAutn atAutn = (AtAutn) result;
- assertEquals(EAP_AT_AUTN, atAutn.attributeType);
- assertEquals(AT_AUTN.length, atAutn.lengthInBytes);
- assertArrayEquals(AUTN_BYTES, atAutn.autn);
- }
-
- @Test
- public void testDecodeInvalidLength() throws Exception {
- ByteBuffer input = ByteBuffer.wrap(AT_AUTN_INVALID_LENGTH);
- try {
- mEapAkaAttributeFactory.getAttribute(input);
- fail("Expected EapSimAkaInvalidAttributeException for invalid length");
- } catch (EapSimAkaInvalidAttributeException expected) {
- }
- }
-
- @Test
- public void testEncode() throws Exception {
- AtAutn atAutn = new AtAutn(AUTN_BYTES);
-
- ByteBuffer result = ByteBuffer.allocate(AT_AUTN.length);
- atAutn.encode(result);
- assertArrayEquals(AT_AUTN, result.array());
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtAutsTest.java b/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtAutsTest.java
deleted file mode 100644
index d65a735f..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtAutsTest.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.message.simaka.attributes;
-
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_AUTS;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.AT_AUTS;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.AT_AUTS_INVALID_LENGTH;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.AUTS_BYTES;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.fail;
-
-import com.android.internal.net.eap.exceptions.simaka.EapSimAkaInvalidAttributeException;
-import com.android.internal.net.eap.message.simaka.EapAkaAttributeFactory;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtAuts;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.nio.ByteBuffer;
-
-public class AtAutsTest {
- private EapAkaAttributeFactory mEapAkaAttributeFactory;
-
- @Before
- public void setUp() {
- mEapAkaAttributeFactory = EapAkaAttributeFactory.getInstance();
- }
-
- @Test
- public void testDecode() throws Exception {
- ByteBuffer input = ByteBuffer.wrap(AT_AUTS);
- EapSimAkaAttribute result = mEapAkaAttributeFactory.getAttribute(input);
-
- assertFalse(input.hasRemaining());
- AtAuts atAuts = (AtAuts) result;
- assertEquals(EAP_AT_AUTS, atAuts.attributeType);
- assertEquals(AT_AUTS.length, atAuts.lengthInBytes);
- assertArrayEquals(AUTS_BYTES, atAuts.auts);
- }
-
- @Test
- public void testDecodeInvalidLength() throws Exception {
- ByteBuffer input = ByteBuffer.wrap(AT_AUTS_INVALID_LENGTH);
- try {
- mEapAkaAttributeFactory.getAttribute(input);
- fail("Expected EapSimAkaInvalidAttributeException for invalid length");
- } catch (EapSimAkaInvalidAttributeException expected) {
- }
- }
-
- @Test
- public void testEncode() throws Exception {
- AtAuts atAuts = new AtAuts(AUTS_BYTES);
-
- ByteBuffer result = ByteBuffer.allocate(AT_AUTS.length);
- atAuts.encode(result);
- assertArrayEquals(AT_AUTS, result.array());
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtBiddingTest.java b/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtBiddingTest.java
deleted file mode 100644
index efdfcc2e..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtBiddingTest.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.message.simaka.attributes;
-
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_BIDDING;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.AT_BIDDING_DOES_NOT_SUPPORT_AKA_PRIME;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.AT_BIDDING_INVALID_LENGTH;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.AT_BIDDING_SUPPORTS_AKA_PRIME;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import com.android.internal.net.eap.exceptions.simaka.EapSimAkaInvalidAttributeException;
-import com.android.internal.net.eap.message.simaka.EapAkaAttributeFactory;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtBidding;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.nio.ByteBuffer;
-
-public class AtBiddingTest {
- private EapAkaAttributeFactory mAttributeFactory;
-
- @Before
- public void setUp() {
- mAttributeFactory = EapAkaAttributeFactory.getInstance();
- }
-
- @Test
- public void testDecodeServerSupportsAkaPrime() throws Exception {
- ByteBuffer input = ByteBuffer.wrap(AT_BIDDING_SUPPORTS_AKA_PRIME);
- EapSimAkaAttribute result = mAttributeFactory.getAttribute(input);
-
- assertFalse(input.hasRemaining());
- AtBidding atBidding = (AtBidding) result;
- assertEquals(EAP_AT_BIDDING, atBidding.attributeType);
- assertEquals(AT_BIDDING_SUPPORTS_AKA_PRIME.length, atBidding.lengthInBytes);
- assertTrue(atBidding.doesServerSupportEapAkaPrime);
- }
-
- @Test
- public void testDecodeDoesNotSupportAkaPrime() throws Exception {
- ByteBuffer input = ByteBuffer.wrap(AT_BIDDING_DOES_NOT_SUPPORT_AKA_PRIME);
- EapSimAkaAttribute result = mAttributeFactory.getAttribute(input);
-
- assertFalse(input.hasRemaining());
- AtBidding atBidding = (AtBidding) result;
- assertEquals(EAP_AT_BIDDING, atBidding.attributeType);
- assertEquals(AT_BIDDING_DOES_NOT_SUPPORT_AKA_PRIME.length, atBidding.lengthInBytes);
- assertFalse(atBidding.doesServerSupportEapAkaPrime);
- }
-
- @Test
- public void testDecodeInvalidLength() throws Exception {
- ByteBuffer input = ByteBuffer.wrap(AT_BIDDING_INVALID_LENGTH);
- try {
- mAttributeFactory.getAttribute(input);
- fail("Expected EapSimAkaInvalidAttributeException for invalid length");
- } catch (EapSimAkaInvalidAttributeException expected) {
- }
- }
-
- @Test
- public void testEncodeServerSupportsAkaPrime() throws Exception {
- AtBidding atBidding = new AtBidding(true);
-
- ByteBuffer result = ByteBuffer.allocate(AT_BIDDING_SUPPORTS_AKA_PRIME.length);
- atBidding.encode(result);
- assertArrayEquals(AT_BIDDING_SUPPORTS_AKA_PRIME, result.array());
- }
-
- @Test
- public void testEncodeDoesNotSupportAkaPrime() throws Exception {
- AtBidding atBidding = new AtBidding(false);
-
- ByteBuffer result = ByteBuffer.allocate(AT_BIDDING_DOES_NOT_SUPPORT_AKA_PRIME.length);
- atBidding.encode(result);
- assertArrayEquals(AT_BIDDING_DOES_NOT_SUPPORT_AKA_PRIME, result.array());
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtClientErrorCodeTest.java b/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtClientErrorCodeTest.java
deleted file mode 100644
index 2051414c..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtClientErrorCodeTest.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.message.simaka.attributes;
-
-import static com.android.internal.net.TestUtils.hexStringToInt;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_CLIENT_ERROR_CODE;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.AT_CLIENT_ERROR_CODE;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.AT_CLIENT_ERROR_CODE_INVALID_LENGTH;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.ERROR_CODE;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtClientErrorCode;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttributeFactory;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.nio.BufferUnderflowException;
-import java.nio.ByteBuffer;
-
-public class AtClientErrorCodeTest {
- private static final int EXPECTED_LENGTH = 4;
-
- private EapSimAkaAttributeFactory mAttributeFactory;
-
- @Before
- public void setUp() {
- mAttributeFactory = new EapSimAkaAttributeFactory() {};
- }
-
- @Test
- public void testDecode() throws Exception {
- ByteBuffer input = ByteBuffer.wrap(AT_CLIENT_ERROR_CODE);
- EapSimAkaAttribute result = mAttributeFactory.getAttribute(input);
-
- assertFalse(input.hasRemaining());
- assertTrue(result instanceof AtClientErrorCode);
- AtClientErrorCode atClientErrorCode = (AtClientErrorCode) result;
- assertEquals(EAP_AT_CLIENT_ERROR_CODE, atClientErrorCode.attributeType);
- assertEquals(EXPECTED_LENGTH, atClientErrorCode.lengthInBytes);
- assertEquals(hexStringToInt(ERROR_CODE), atClientErrorCode.errorCode);
- }
-
- @Test
- public void testDecodeInvalidLength() throws Exception {
- ByteBuffer input = ByteBuffer.wrap(AT_CLIENT_ERROR_CODE_INVALID_LENGTH);
- try {
- mAttributeFactory.getAttribute(input);
- fail("Expected BufferUnderflowException for invalid attribute length");
- } catch (BufferUnderflowException expected) {
- }
- }
-
- @Test
- public void testEncode() throws Exception {
- AtClientErrorCode atNotification = new AtClientErrorCode(
- EXPECTED_LENGTH, hexStringToInt(ERROR_CODE));
- ByteBuffer result = ByteBuffer.allocate(EXPECTED_LENGTH);
-
- atNotification.encode(result);
- assertArrayEquals(AT_CLIENT_ERROR_CODE, result.array());
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtCounterTest.java b/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtCounterTest.java
deleted file mode 100644
index eb1086d5..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtCounterTest.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.message.simaka.attributes;
-
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_COUNTER;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_COUNTER_TOO_SMALL;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.AT_COUNTER;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.AT_COUNTER_INVALID_LENGTH;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.AT_COUNTER_TOO_SMALL;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.AT_COUNTER_TOO_SMALL_INVALID_LENGTH;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.COUNTER_INT;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import com.android.internal.net.eap.exceptions.simaka.EapSimAkaInvalidAttributeException;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtCounter;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtCounterTooSmall;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttributeFactory;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.nio.ByteBuffer;
-
-public class AtCounterTest {
- private static final int EXPECTED_LENGTH = 4;
-
- private EapSimAkaAttributeFactory mAttributeFactory;
-
- @Before
- public void setUp() {
- mAttributeFactory = new EapSimAkaAttributeFactory() {};
- }
-
- @Test
- public void testDecodeAtCounter() throws Exception {
- ByteBuffer input = ByteBuffer.wrap(AT_COUNTER);
- EapSimAkaAttribute result = mAttributeFactory.getAttribute(input);
-
- assertFalse(input.hasRemaining());
- assertTrue(result instanceof AtCounter);
- AtCounter atCounter = (AtCounter) result;
- assertEquals(EAP_AT_COUNTER, atCounter.attributeType);
- assertEquals(EXPECTED_LENGTH, atCounter.lengthInBytes);
- assertEquals(COUNTER_INT, atCounter.counter);
- }
-
- @Test
- public void testDecodeAtCounterInvalidLength() throws Exception {
- ByteBuffer input = ByteBuffer.wrap(AT_COUNTER_INVALID_LENGTH);
- try {
- mAttributeFactory.getAttribute(input);
- fail("Expected EapSimAkaInvalidAttributeException for invalid length");
- } catch (EapSimAkaInvalidAttributeException expected) {
- }
- }
-
- @Test
- public void testEncodeAtCounter() throws Exception {
- AtCounter atCounter = new AtCounter(COUNTER_INT);
-
- ByteBuffer result = ByteBuffer.allocate(EXPECTED_LENGTH);
- atCounter.encode(result);
- assertArrayEquals(AT_COUNTER, result.array());
- }
-
- @Test
- public void testAtCounterTooSmallConstructor() throws Exception {
- AtCounterTooSmall atCounterTooSmall = new AtCounterTooSmall();
- assertEquals(EAP_AT_COUNTER_TOO_SMALL, atCounterTooSmall.attributeType);
- assertEquals(EXPECTED_LENGTH, atCounterTooSmall.lengthInBytes);
- }
-
- @Test
- public void testDecodeAtCounterTooSmall() throws Exception {
- ByteBuffer input = ByteBuffer.wrap(AT_COUNTER_TOO_SMALL);
- EapSimAkaAttribute result = mAttributeFactory.getAttribute(input);
-
- assertFalse(input.hasRemaining());
- assertTrue(result instanceof AtCounterTooSmall);
- AtCounterTooSmall atCounterTooSmall = (AtCounterTooSmall) result;
- assertEquals(EAP_AT_COUNTER_TOO_SMALL, atCounterTooSmall.attributeType);
- assertEquals(EXPECTED_LENGTH, atCounterTooSmall.lengthInBytes);
- }
-
- @Test
- public void testDecodeAtCounterTooSmallInvalidLength() throws Exception {
- ByteBuffer input = ByteBuffer.wrap(AT_COUNTER_TOO_SMALL_INVALID_LENGTH);
- try {
- mAttributeFactory.getAttribute(input);
- fail("Expected EapSimAkaInvalidAttributeException for invalid length");
- } catch (EapSimAkaInvalidAttributeException expected) {
- }
- }
-
- @Test
- public void testEncodeAtCounterTooSmall() throws Exception {
- AtCounterTooSmall atCounterTooSmall = new AtCounterTooSmall();
- ByteBuffer result = ByteBuffer.allocate(EXPECTED_LENGTH);
- atCounterTooSmall.encode(result);
- assertArrayEquals(AT_COUNTER_TOO_SMALL, result.array());
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtIdReqTest.java b/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtIdReqTest.java
deleted file mode 100644
index d006053e..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtIdReqTest.java
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.message.simaka.attributes;
-
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_ANY_ID_REQ;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_FULLAUTH_ID_REQ;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_PERMANENT_ID_REQ;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.ANY_ID_INVALID_LENGTH;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.AT_ANY_ID_REQ;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.AT_FULL_AUTH_ID_REQ;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.AT_PERMANENT_ID_REQ;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.FULL_AUTH_ID_INVALID_LENGTH;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.PERMANENT_ID_INVALID_LENGTH;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import com.android.internal.net.eap.exceptions.simaka.EapSimAkaInvalidAttributeException;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtAnyIdReq;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtFullauthIdReq;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtPermanentIdReq;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttributeFactory;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.nio.ByteBuffer;
-
-public class AtIdReqTest {
- private static final int EXPECTED_LENGTH = 4;
-
- private EapSimAkaAttributeFactory mAttributeFactory;
-
- @Before
- public void setUp() {
- mAttributeFactory = new EapSimAkaAttributeFactory() {};
- }
-
- @Test
- public void testDecodeAtPermanentIdReq() throws Exception {
- ByteBuffer input = ByteBuffer.wrap(AT_PERMANENT_ID_REQ);
- EapSimAkaAttribute result = mAttributeFactory.getAttribute(input);
-
- assertFalse(input.hasRemaining());
- assertTrue(result instanceof AtPermanentIdReq);
- AtPermanentIdReq atPermanentIdReq = (AtPermanentIdReq) result;
- assertEquals(EAP_AT_PERMANENT_ID_REQ, atPermanentIdReq.attributeType);
- assertEquals(EXPECTED_LENGTH, atPermanentIdReq.lengthInBytes);
- }
-
- @Test
- public void testDecodeAtPermanentIdReqInvalidLength() throws Exception {
- ByteBuffer input = ByteBuffer.wrap(PERMANENT_ID_INVALID_LENGTH);
- try {
- mAttributeFactory.getAttribute(input);
- fail("Expected EapSimAkaInvalidAttributeException for invalid attribute length");
- } catch (EapSimAkaInvalidAttributeException expected) {
- }
- }
-
- @Test
- public void testEncodeAtPermanentIdReq() throws Exception {
- AtPermanentIdReq atPermanentIdReq = new AtPermanentIdReq();
- ByteBuffer result = ByteBuffer.allocate(EXPECTED_LENGTH);
-
- atPermanentIdReq.encode(result);
- assertArrayEquals(AT_PERMANENT_ID_REQ, result.array());
- }
-
- @Test
- public void testDecodeAtAnyIdReq() throws Exception {
- ByteBuffer input = ByteBuffer.wrap(AT_ANY_ID_REQ);
- EapSimAkaAttribute result = mAttributeFactory.getAttribute(input);
-
- assertFalse(input.hasRemaining());
- assertTrue(result instanceof AtAnyIdReq);
- AtAnyIdReq atAnyIdReq = (AtAnyIdReq) result;
- assertEquals(EAP_AT_ANY_ID_REQ, atAnyIdReq.attributeType);
- assertEquals(EXPECTED_LENGTH, atAnyIdReq.lengthInBytes);
- }
-
- @Test
- public void testDecodeAtAnyIdReqInvalidLength() throws Exception {
- ByteBuffer input = ByteBuffer.wrap(ANY_ID_INVALID_LENGTH);
- try {
- mAttributeFactory.getAttribute(input);
- fail("Expected EapSimAkaInvalidAttributeException for invalid attribute length");
- } catch (EapSimAkaInvalidAttributeException expected) {
- }
- }
-
- @Test
- public void testEncodeAtAnyIdReq() throws Exception {
- AtAnyIdReq atPermanentIdReq = new AtAnyIdReq();
- ByteBuffer result = ByteBuffer.allocate(EXPECTED_LENGTH);
-
- atPermanentIdReq.encode(result);
- assertArrayEquals(AT_ANY_ID_REQ, result.array());
- }
-
- @Test
- public void testDecodeAtFullauthIdReq() throws Exception {
- ByteBuffer input = ByteBuffer.wrap(AT_FULL_AUTH_ID_REQ);
- EapSimAkaAttribute result = mAttributeFactory.getAttribute(input);
-
- assertFalse(input.hasRemaining());
- assertTrue(result instanceof AtFullauthIdReq);
- AtFullauthIdReq atFullauthIdReq = (AtFullauthIdReq) result;
- assertEquals(EAP_AT_FULLAUTH_ID_REQ, atFullauthIdReq.attributeType);
- assertEquals(EXPECTED_LENGTH, atFullauthIdReq.lengthInBytes);
- }
-
- @Test
- public void testDecodeAtFullauthIdReqInvalidLength() throws Exception {
- ByteBuffer input = ByteBuffer.wrap(FULL_AUTH_ID_INVALID_LENGTH);
- try {
- mAttributeFactory.getAttribute(input);
- fail("Expected EapSimAkaInvalidAttributeException for invalid attribute length");
- } catch (EapSimAkaInvalidAttributeException expected) {
- }
- }
-
- @Test
- public void testEncodeAtFullauthIdReq() throws Exception {
- AtFullauthIdReq atPermanentIdReq = new AtFullauthIdReq();
- ByteBuffer result = ByteBuffer.allocate(EXPECTED_LENGTH);
-
- atPermanentIdReq.encode(result);
- assertArrayEquals(AT_FULL_AUTH_ID_REQ, result.array());
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtIdentityTest.java b/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtIdentityTest.java
deleted file mode 100644
index cf8e8803..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtIdentityTest.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.message.simaka.attributes;
-
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_IDENTITY;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.AT_IDENTITY;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.IDENTITY;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtIdentity;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttributeFactory;
-import com.android.internal.net.eap.message.simaka.EapSimAttributeFactory;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.nio.ByteBuffer;
-
-public class AtIdentityTest {
- private EapSimAkaAttributeFactory mAttributeFactory;
-
- @Before
- public void setUp() {
- mAttributeFactory = new EapSimAkaAttributeFactory() {};
- }
-
- @Test
- public void testDecode() throws Exception {
- ByteBuffer input = ByteBuffer.wrap(AT_IDENTITY);
- EapSimAkaAttribute result = mAttributeFactory.getAttribute(input);
-
- assertFalse(input.hasRemaining());
- assertTrue(result instanceof AtIdentity);
- AtIdentity atIdentity = (AtIdentity) result;
- assertEquals(EAP_AT_IDENTITY, atIdentity.attributeType);
- assertEquals(AT_IDENTITY.length, atIdentity.lengthInBytes);
- assertArrayEquals(IDENTITY, atIdentity.identity);
- }
-
- @Test
- public void testEncode() throws Exception {
- AtIdentity atIdentity = new AtIdentity(AT_IDENTITY.length, IDENTITY);
- ByteBuffer result = ByteBuffer.allocate(AT_IDENTITY.length);
- atIdentity.encode(result);
-
- assertArrayEquals(AT_IDENTITY, result.array());
- }
-
- @Test
- public void testGetAtIdentity() throws Exception {
- AtIdentity atIdentity = AtIdentity.getAtIdentity(IDENTITY);
-
- assertArrayEquals(IDENTITY, atIdentity.identity);
-
- ByteBuffer buffer = ByteBuffer.allocate(atIdentity.lengthInBytes);
- atIdentity.encode(buffer);
- buffer.rewind();
-
- EapSimAkaAttribute eapSimAkaAttribute =
- EapSimAttributeFactory.getInstance().getAttribute(buffer);
- assertTrue(eapSimAkaAttribute instanceof AtIdentity);
- AtIdentity newAtIdentity = (AtIdentity) eapSimAkaAttribute;
- assertEquals(atIdentity.lengthInBytes, newAtIdentity.lengthInBytes);
- assertArrayEquals(atIdentity.identity, newAtIdentity.identity);
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtKdfInputTest.java b/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtKdfInputTest.java
deleted file mode 100644
index 51ea3f14..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtKdfInputTest.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.message.simaka.attributes;
-
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_KDF_INPUT;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.AT_KDF_INPUT;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.AT_KDF_INPUT_EMPTY_NETWORK_NAME;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.NETWORK_NAME_BYTES;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-
-import com.android.internal.net.eap.message.simaka.EapAkaPrimeAttributeFactory;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtKdfInput;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.nio.ByteBuffer;
-
-public class AtKdfInputTest {
- private EapAkaPrimeAttributeFactory mAttributeFactory;
-
- @Before
- public void setUp() {
- mAttributeFactory = EapAkaPrimeAttributeFactory.getInstance();
- }
-
- @Test
- public void testDecode() throws Exception {
- ByteBuffer input = ByteBuffer.wrap(AT_KDF_INPUT);
- EapSimAkaAttribute result = mAttributeFactory.getAttribute(input);
-
- assertFalse(input.hasRemaining());
- AtKdfInput atKdfInput = (AtKdfInput) result;
- assertEquals(EAP_AT_KDF_INPUT, atKdfInput.attributeType);
- assertEquals(AT_KDF_INPUT.length, atKdfInput.lengthInBytes);
- assertArrayEquals(NETWORK_NAME_BYTES, atKdfInput.networkName);
- }
-
- @Test
- public void testDecodeEmptyNetworkName() throws Exception {
- ByteBuffer input = ByteBuffer.wrap(AT_KDF_INPUT_EMPTY_NETWORK_NAME);
- EapSimAkaAttribute result = mAttributeFactory.getAttribute(input);
-
- assertFalse(input.hasRemaining());
- AtKdfInput atKdfInput = (AtKdfInput) result;
- assertEquals(EAP_AT_KDF_INPUT, atKdfInput.attributeType);
- assertEquals(AT_KDF_INPUT_EMPTY_NETWORK_NAME.length, atKdfInput.lengthInBytes);
- assertArrayEquals(new byte[0], atKdfInput.networkName);
- }
-
- @Test
- public void testEncode() throws Exception {
- AtKdfInput atKdfInput = new AtKdfInput(AT_KDF_INPUT.length, NETWORK_NAME_BYTES);
- ByteBuffer result = ByteBuffer.allocate(AT_KDF_INPUT.length);
-
- atKdfInput.encode(result);
- assertArrayEquals(AT_KDF_INPUT, result.array());
- assertFalse(result.hasRemaining());
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtKdfTest.java b/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtKdfTest.java
deleted file mode 100644
index 0bb07326..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtKdfTest.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.message.simaka.attributes;
-
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_KDF;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.AT_KDF;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.AT_KDF_INVALID_LENGTH;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.KDF_VERSION;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.fail;
-
-import com.android.internal.net.eap.exceptions.simaka.EapSimAkaInvalidAttributeException;
-import com.android.internal.net.eap.message.simaka.EapAkaPrimeAttributeFactory;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtKdf;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.nio.ByteBuffer;
-
-public class AtKdfTest {
- private EapAkaPrimeAttributeFactory mAttributeFactory;
-
- @Before
- public void setUp() {
- mAttributeFactory = EapAkaPrimeAttributeFactory.getInstance();
- }
-
- @Test
- public void testDecode() throws Exception {
- ByteBuffer input = ByteBuffer.wrap(AT_KDF);
- EapSimAkaAttribute result = mAttributeFactory.getAttribute(input);
-
- assertFalse(input.hasRemaining());
- AtKdf atKdf = (AtKdf) result;
- assertEquals(EAP_AT_KDF, atKdf.attributeType);
- assertEquals(AT_KDF.length, atKdf.lengthInBytes);
- assertEquals(KDF_VERSION, atKdf.kdf);
- }
-
- @Test
- public void testDecodeInvalidLength() throws Exception {
- ByteBuffer input = ByteBuffer.wrap(AT_KDF_INVALID_LENGTH);
- try {
- mAttributeFactory.getAttribute(input);
- fail("Expected EapSimAkaInvalidAttributeException for invalid length");
- } catch (EapSimAkaInvalidAttributeException expected) {
- }
- }
-
- @Test
- public void testEncode() throws Exception {
- AtKdf atKdf = new AtKdf(KDF_VERSION);
- ByteBuffer result = ByteBuffer.allocate(AT_KDF.length);
-
- atKdf.encode(result);
- assertArrayEquals(AT_KDF, result.array());
- assertFalse(result.hasRemaining());
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtMacTest.java b/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtMacTest.java
deleted file mode 100644
index 82b066d5..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtMacTest.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.message.simaka.attributes;
-
-import static com.android.internal.net.TestUtils.hexStringToByteArray;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_MAC;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.AT_MAC;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.AT_MAC_INVALID_LENGTH;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.MAC;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import com.android.internal.net.eap.exceptions.simaka.EapSimAkaInvalidAttributeException;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtMac;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttributeFactory;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.nio.ByteBuffer;
-
-public class AtMacTest {
- private static final int EXPECTED_LENGTH = 20;
- private static final int MAC_LENGTH = 16;
- private static final byte[] MAC_BYTES = hexStringToByteArray(MAC);
- private static final byte[] INVALID_MAC = {(byte) 1, (byte) 2, (byte) 3};
-
- private EapSimAkaAttributeFactory mAttributeFactory;
-
- @Before
- public void setUp() {
- mAttributeFactory = new EapSimAkaAttributeFactory() {};
- }
-
- @Test
- public void testConstructor() throws Exception {
- AtMac atMac = new AtMac();
- assertEquals(EAP_AT_MAC, atMac.attributeType);
- assertEquals(EXPECTED_LENGTH, atMac.lengthInBytes);
- assertArrayEquals(new byte[MAC_LENGTH], atMac.mac);
- }
-
- @Test
- public void testParameterizedConstructor() throws Exception {
- AtMac atMac = new AtMac(MAC_BYTES);
- assertEquals(EAP_AT_MAC, atMac.attributeType);
- assertEquals(EXPECTED_LENGTH, atMac.lengthInBytes);
- assertArrayEquals(MAC_BYTES, atMac.mac);
- }
-
- @Test
- public void testParameterizedConstructorInvalidMac() {
- try {
- AtMac atMac = new AtMac(INVALID_MAC);
- fail("Expected EapSimAkaInvalidAttributeException for invalid MAC length");
- } catch (EapSimAkaInvalidAttributeException expected) {
- }
- }
-
- @Test
- public void testDecode() throws Exception {
- ByteBuffer input = ByteBuffer.wrap(AT_MAC);
- EapSimAkaAttribute result = mAttributeFactory.getAttribute(input);
-
- assertFalse(input.hasRemaining());
- assertTrue(result instanceof AtMac);
- AtMac atMac = (AtMac) result;
- assertEquals(EAP_AT_MAC, atMac.attributeType);
- assertEquals(EXPECTED_LENGTH, atMac.lengthInBytes);
- assertArrayEquals(MAC_BYTES, atMac.mac);
- }
-
- @Test
- public void testDecodeInvalidLength() throws Exception {
- ByteBuffer input = ByteBuffer.wrap(AT_MAC_INVALID_LENGTH);
- try {
- mAttributeFactory.getAttribute(input);
- fail("Expected EapSimAkaInvalidAttributeException for invalid length");
- } catch (EapSimAkaInvalidAttributeException expected) {
- }
- }
-
- @Test
- public void testEncode() throws Exception {
- AtMac atMac = new AtMac(MAC_BYTES);
-
- ByteBuffer result = ByteBuffer.allocate(EXPECTED_LENGTH);
- atMac.encode(result);
- assertArrayEquals(AT_MAC, result.array());
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtNonceMtTest.java b/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtNonceMtTest.java
deleted file mode 100644
index 751908a2..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtNonceMtTest.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.message.simaka.attributes;
-
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_NONCE_MT;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.AT_NONCE_INVALID_LENGTH;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.AT_NONCE_MT;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.NONCE_MT;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import com.android.internal.net.eap.exceptions.simaka.EapSimAkaInvalidAttributeException;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtNonceMt;
-import com.android.internal.net.eap.message.simaka.EapSimAttributeFactory;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.nio.ByteBuffer;
-
-public class AtNonceMtTest {
- private static final byte[] INVALID_NONCE = new byte[10];
- private static final int EXPECTED_LENGTH = 20;
-
- private EapSimAttributeFactory mEapSimAttributeFactory;
-
- @Before
- public void setUp() {
- mEapSimAttributeFactory = EapSimAttributeFactory.getInstance();
- }
-
- @Test
- public void testConstructorInvalidNonceLength() {
- try {
- new AtNonceMt(INVALID_NONCE);
- fail("Expected EapSimAkaInvalidAttributeException for invalid NonceMt length");
- } catch (EapSimAkaInvalidAttributeException expected) {
- }
- }
-
- @Test
- public void testDecode() throws Exception {
- ByteBuffer input = ByteBuffer.wrap(AT_NONCE_MT);
- EapSimAkaAttribute result = mEapSimAttributeFactory.getAttribute(input);
-
- assertFalse(input.hasRemaining());
- assertTrue(result instanceof AtNonceMt);
- AtNonceMt atNonceMt = (AtNonceMt) result;
- assertEquals(EAP_AT_NONCE_MT, atNonceMt.attributeType);
- assertEquals(EXPECTED_LENGTH, atNonceMt.lengthInBytes);
- assertArrayEquals(NONCE_MT, atNonceMt.nonceMt);
- }
-
- @Test
- public void testDecodeInvalidLength() throws Exception {
- ByteBuffer input = ByteBuffer.wrap(AT_NONCE_INVALID_LENGTH);
- try {
- mEapSimAttributeFactory.getAttribute(input);
- fail("Expected EapSimAkaInvalidAttributeException for invalid attribute length");
- } catch (EapSimAkaInvalidAttributeException expected) {
- }
- }
-
- @Test
- public void testEncode() throws EapSimAkaInvalidAttributeException {
- AtNonceMt atNonceMt = new AtNonceMt(NONCE_MT);
- ByteBuffer result = ByteBuffer.allocate(EXPECTED_LENGTH);
-
- atNonceMt.encode(result);
- assertArrayEquals(AT_NONCE_MT, result.array());
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtNonceSTest.java b/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtNonceSTest.java
deleted file mode 100644
index 1ad64669..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtNonceSTest.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.message.simaka.attributes;
-
-import static com.android.internal.net.TestUtils.hexStringToByteArray;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_NONCE_S;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.AT_NONCE_S;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.AT_NONCE_S_INVALID_LENGTH;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.NONCE_S;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import com.android.internal.net.eap.exceptions.simaka.EapSimAkaInvalidAttributeException;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtNonceS;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttributeFactory;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.nio.ByteBuffer;
-
-public class AtNonceSTest {
- private static final byte[] INVALID_NONCE = new byte[10];
- private static final int EXPECTED_LENGTH = 20;
-
- private EapSimAkaAttributeFactory mAttributeFactory;
-
- @Before
- public void setUp() {
- mAttributeFactory = new EapSimAkaAttributeFactory() {};
- }
-
- @Test
- public void testConstructorInvalidNonceLength() {
- try {
- new AtNonceS(INVALID_NONCE);
- fail("Expected EapSimAkaInvalidAttributeException for invalid NonceMt length");
- } catch (EapSimAkaInvalidAttributeException expected) {
- }
- }
-
- @Test
- public void testDecode() throws Exception {
- ByteBuffer input = ByteBuffer.wrap(AT_NONCE_S);
- EapSimAkaAttribute result = mAttributeFactory.getAttribute(input);
-
- assertFalse(input.hasRemaining());
- assertTrue(result instanceof AtNonceS);
- AtNonceS atNonceS = (AtNonceS) result;
- assertEquals(EAP_AT_NONCE_S, atNonceS.attributeType);
- assertEquals(EXPECTED_LENGTH, atNonceS.lengthInBytes);
- assertArrayEquals(hexStringToByteArray(NONCE_S), atNonceS.nonceS);
- }
-
- @Test
- public void testDecodeInvalidLength() throws Exception {
- ByteBuffer input = ByteBuffer.wrap(AT_NONCE_S_INVALID_LENGTH);
- try {
- mAttributeFactory.getAttribute(input);
- fail("Expected EapSimAkaInvalidAttributeException for invalid length");
- } catch (EapSimAkaInvalidAttributeException expected) {
- }
- }
-
- @Test
- public void testEncode() throws Exception {
- AtNonceS atNonceS = new AtNonceS(hexStringToByteArray(NONCE_S));
-
- ByteBuffer result = ByteBuffer.allocate(EXPECTED_LENGTH);
- atNonceS.encode(result);
- assertArrayEquals(AT_NONCE_S, result.array());
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtNotificationTest.java b/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtNotificationTest.java
deleted file mode 100644
index 2db3cbb2..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtNotificationTest.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.message.simaka.attributes;
-
-import static com.android.internal.net.TestUtils.hexStringToInt;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtNotification.GENERAL_FAILURE_POST_CHALLENGE;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_NOTIFICATION;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.AT_NOTIFICATION;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.AT_NOTIFICATION_INVALID_LENGTH;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.AT_NOTIFICATION_INVALID_STATE;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.NOTIFICATION_CODE;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import com.android.internal.net.eap.exceptions.simaka.EapSimAkaInvalidAttributeException;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtNotification;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttributeFactory;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.nio.ByteBuffer;
-
-public class AtNotificationTest {
- private static final int EXPECTED_LENGTH = 4;
- private static final int UNKNOWN_CODE = 0xA0FF;
-
- private EapSimAkaAttributeFactory mAttributeFactory;
-
- @Before
- public void setUp() {
- mAttributeFactory = new EapSimAkaAttributeFactory() {};
- }
-
- @Test
- public void testDecode() throws Exception {
- ByteBuffer input = ByteBuffer.wrap(AT_NOTIFICATION);
- EapSimAkaAttribute result = mAttributeFactory.getAttribute(input);
-
- assertFalse(input.hasRemaining());
- assertTrue(result instanceof AtNotification);
- AtNotification atNotification = (AtNotification) result;
- assertEquals(EAP_AT_NOTIFICATION, atNotification.attributeType);
- assertEquals(EXPECTED_LENGTH, atNotification.lengthInBytes);
- assertTrue(atNotification.isSuccessCode);
- assertFalse(atNotification.isPreSuccessfulChallenge);
- assertEquals(hexStringToInt(NOTIFICATION_CODE), atNotification.notificationCode);
- }
-
- @Test
- public void testDecodeInvalidLength() throws Exception {
- ByteBuffer input = ByteBuffer.wrap(AT_NOTIFICATION_INVALID_LENGTH);
- try {
- mAttributeFactory.getAttribute(input);
- fail("Expected EapSimAkaInvalidAttributeException for invalid attribute length");
- } catch (EapSimAkaInvalidAttributeException expected) {
- }
- }
-
- @Test
- public void testDecodeInvalidState() throws Exception {
- ByteBuffer input = ByteBuffer.wrap(AT_NOTIFICATION_INVALID_STATE);
- try {
- mAttributeFactory.getAttribute(input);
- fail("Expected EapSimAkaInvalidAttributeException for invalid state");
- } catch (EapSimAkaInvalidAttributeException expected) {
- }
- }
-
- @Test
- public void testEncode() throws Exception {
- AtNotification atNotification = new AtNotification(hexStringToInt(NOTIFICATION_CODE));
- ByteBuffer result = ByteBuffer.allocate(EXPECTED_LENGTH);
-
- atNotification.encode(result);
- assertArrayEquals(AT_NOTIFICATION, result.array());
- }
-
- @Test
- public void testToString() throws Exception {
- AtNotification knownCode = new AtNotification(GENERAL_FAILURE_POST_CHALLENGE);
- AtNotification unknownCode = new AtNotification(UNKNOWN_CODE);
-
- assertNotNull(knownCode.toString());
- assertNotNull(unknownCode.toString());
- assertNotEquals(knownCode.toString(), unknownCode.toString());
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtPaddingTest.java b/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtPaddingTest.java
deleted file mode 100644
index d310d504..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtPaddingTest.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.message.simaka.attributes;
-
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_PADDING;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.AT_PADDING;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.AT_PADDING_INVALID_PADDING;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import com.android.internal.net.eap.exceptions.simaka.EapSimAkaInvalidAtPaddingException;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtPadding;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttributeFactory;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.nio.ByteBuffer;
-
-public class AtPaddingTest {
- private static final int EXPECTED_LENGTH = 8;
-
- private EapSimAkaAttributeFactory mAttributeFactory;
-
- @Before
- public void setUp() {
- mAttributeFactory = new EapSimAkaAttributeFactory() {};
- }
-
- @Test
- public void testDecode() throws Exception {
- ByteBuffer input = ByteBuffer.wrap(AT_PADDING);
- EapSimAkaAttribute result = mAttributeFactory.getAttribute(input);
-
- assertFalse(input.hasRemaining());
- assertTrue(result instanceof AtPadding);
- AtPadding atPadding = (AtPadding) result;
- assertEquals(EAP_AT_PADDING, atPadding.attributeType);
- assertEquals(EXPECTED_LENGTH, atPadding.lengthInBytes);
- }
-
- @Test
- public void testDecodeInvalidPadding() throws Exception {
- ByteBuffer input = ByteBuffer.wrap(AT_PADDING_INVALID_PADDING);
- try {
- mAttributeFactory.getAttribute(input);
- fail("Expected EapSimAkaInvalidAtPaddingException for nonzero padding bytes");
- } catch (EapSimAkaInvalidAtPaddingException expected) {
- }
- }
-
- @Test
- public void testEncode() throws Exception {
- AtPadding atPadding = new AtPadding(EXPECTED_LENGTH);
-
- ByteBuffer result = ByteBuffer.allocate(EXPECTED_LENGTH);
- atPadding.encode(result);
-
- assertFalse(result.hasRemaining());
- assertArrayEquals(AT_PADDING, result.array());
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtRandAkaTest.java b/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtRandAkaTest.java
deleted file mode 100644
index bdffdda9..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtRandAkaTest.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.message.simaka.attributes;
-
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_RAND;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.AT_RAND_AKA;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.AT_RAND_AKA_INVALID_LENGTH;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.RAND_1_BYTES;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.fail;
-
-import com.android.internal.net.eap.exceptions.simaka.EapSimAkaInvalidAttributeException;
-import com.android.internal.net.eap.message.simaka.EapAkaAttributeFactory;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtRandAka;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.nio.ByteBuffer;
-
-public class AtRandAkaTest {
- private EapAkaAttributeFactory mEapAkaAttributeFactory;
-
- @Before
- public void setUp() {
- mEapAkaAttributeFactory = EapAkaAttributeFactory.getInstance();
- }
-
- @Test
- public void testDecode() throws Exception {
- ByteBuffer input = ByteBuffer.wrap(AT_RAND_AKA);
- EapSimAkaAttribute result = mEapAkaAttributeFactory.getAttribute(input);
-
- assertFalse(input.hasRemaining());
- AtRandAka atRandAka = (AtRandAka) result;
- assertEquals(EAP_AT_RAND, atRandAka.attributeType);
- assertEquals(AT_RAND_AKA.length, atRandAka.lengthInBytes);
- assertArrayEquals(RAND_1_BYTES, atRandAka.rand);
- }
-
- @Test
- public void testDecodeInvalidLength() throws Exception {
- ByteBuffer input = ByteBuffer.wrap(AT_RAND_AKA_INVALID_LENGTH);
- try {
- mEapAkaAttributeFactory.getAttribute(input);
- fail("Expected EapSimAkaInvalidAttributeException for invalid length");
- } catch (EapSimAkaInvalidAttributeException expected) {
- }
- }
-
- @Test
- public void testEncode() throws Exception {
- AtRandAka atRandAka = new AtRandAka(RAND_1_BYTES);
-
- ByteBuffer result = ByteBuffer.allocate(AT_RAND_AKA.length);
- atRandAka.encode(result);
- assertArrayEquals(AT_RAND_AKA, result.array());
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtRandSimTest.java b/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtRandSimTest.java
deleted file mode 100644
index 7456be6c..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtRandSimTest.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.message.simaka.attributes;
-
-import static com.android.internal.net.TestUtils.hexStringToByteArray;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_RAND;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.AT_RAND_SIM;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.AT_RAND_SIM_DUPLICATE_RANDS;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.AT_RAND_SIM_INVALID_NUM_RANDS;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.RAND_1;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.RAND_2;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import com.android.internal.net.eap.exceptions.simaka.EapSimAkaInvalidAttributeException;
-import com.android.internal.net.eap.exceptions.simaka.EapSimInvalidAtRandException;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtRandSim;
-import com.android.internal.net.eap.message.simaka.EapSimAttributeFactory;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.nio.ByteBuffer;
-
-public class AtRandSimTest {
- private static final int EXPECTED_NUM_RANDS = 2;
-
- private EapSimAttributeFactory mEapSimAttributeFactory;
-
- @Before
- public void setUp() {
- mEapSimAttributeFactory = EapSimAttributeFactory.getInstance();
- }
-
- @Test
- public void testDecode() throws Exception {
- ByteBuffer input = ByteBuffer.wrap(AT_RAND_SIM);
- EapSimAkaAttribute result = mEapSimAttributeFactory.getAttribute(input);
-
- assertFalse(input.hasRemaining());
- assertTrue(result instanceof AtRandSim);
- AtRandSim atRandSim = (AtRandSim) result;
- assertEquals(EAP_AT_RAND, atRandSim.attributeType);
- assertEquals(AT_RAND_SIM.length, atRandSim.lengthInBytes);
- assertEquals(EXPECTED_NUM_RANDS, atRandSim.rands.size());
- assertArrayEquals(hexStringToByteArray(RAND_1), atRandSim.rands.get(0));
- assertArrayEquals(hexStringToByteArray(RAND_2), atRandSim.rands.get(1));
- }
-
- @Test
- public void testDecodeInvalidNumRands() throws Exception {
- ByteBuffer input = ByteBuffer.wrap(AT_RAND_SIM_INVALID_NUM_RANDS);
- try {
- mEapSimAttributeFactory.getAttribute(input);
- fail("Expected EapSimInvalidAtRandException for invalid number of RANDs");
- } catch (EapSimInvalidAtRandException expected) {
- }
- }
-
- @Test
- public void testDecodeDuplicateRands() throws Exception {
- ByteBuffer input = ByteBuffer.wrap(AT_RAND_SIM_DUPLICATE_RANDS);
- try {
- mEapSimAttributeFactory.getAttribute(input);
- fail("Expected EapSimAkaInvalidAttributeException for duplicate RANDs");
- } catch (EapSimAkaInvalidAttributeException expected) {
- }
- }
-
- @Test
- public void testEncode() throws Exception {
- byte[][] expectedRands = new byte[][] {
- hexStringToByteArray(RAND_1),
- hexStringToByteArray(RAND_2)
- };
- AtRandSim atRandSim = new AtRandSim(AT_RAND_SIM.length, expectedRands);
-
- ByteBuffer result = ByteBuffer.allocate(AT_RAND_SIM.length);
- atRandSim.encode(result);
- assertArrayEquals(AT_RAND_SIM, result.array());
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtResTest.java b/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtResTest.java
deleted file mode 100644
index 34c2ff39..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtResTest.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.message.simaka.attributes;
-
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_RES;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.AT_RES;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.AT_RES_INVALID_RES_LENGTH;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.AT_RES_LONG_RES;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.AT_RES_SHORT_RES;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.RES_BYTES;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import com.android.internal.net.eap.exceptions.simaka.EapSimAkaInvalidAttributeException;
-import com.android.internal.net.eap.message.simaka.EapAkaAttributeFactory;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtRes;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.nio.ByteBuffer;
-
-public class AtResTest {
- private EapAkaAttributeFactory mEapAkaAttributeFactory;
-
- @Before
- public void setUp() {
- mEapAkaAttributeFactory = EapAkaAttributeFactory.getInstance();
- }
-
- @Test
- public void testDecode() throws Exception {
- ByteBuffer input = ByteBuffer.wrap(AT_RES);
- EapSimAkaAttribute result = mEapAkaAttributeFactory.getAttribute(input);
-
- assertFalse(input.hasRemaining());
- AtRes atRes = (AtRes) result;
- assertEquals(EAP_AT_RES, atRes.attributeType);
- assertEquals(AT_RES.length, atRes.lengthInBytes);
- assertArrayEquals(RES_BYTES, atRes.res);
- }
-
- @Test
- public void testDecodeInvalidResLength() throws Exception {
- ByteBuffer input = ByteBuffer.wrap(AT_RES_INVALID_RES_LENGTH);
- try {
- mEapAkaAttributeFactory.getAttribute(input);
- fail("Expected EapSimAkaInvalidAttributeException for invalid RES length");
- } catch (EapSimAkaInvalidAttributeException expected) {
- }
- }
-
- @Test
- public void testDecodeShortResLength() throws Exception {
- ByteBuffer input = ByteBuffer.wrap(AT_RES_SHORT_RES);
- try {
- mEapAkaAttributeFactory.getAttribute(input);
- fail("Expected EapSimAkaInvalidAttributeException for too short RES");
- } catch (EapSimAkaInvalidAttributeException expected) {
- }
- }
-
- @Test
- public void testDecodeLongResLength() throws Exception {
- ByteBuffer input = ByteBuffer.wrap(AT_RES_LONG_RES);
- try {
- mEapAkaAttributeFactory.getAttribute(input);
- fail("Expected EapSimAkaInvalidAttributeException for too long RES");
- } catch (EapSimAkaInvalidAttributeException expected) {
- }
- }
-
- @Test
- public void testEncode() throws Exception {
- AtRes atRes = new AtRes(AT_RES.length, RES_BYTES);
-
- ByteBuffer result = ByteBuffer.allocate(AT_RES.length);
- atRes.encode(result);
- assertArrayEquals(AT_RES, result.array());
- }
-
- @Test
- public void testGetAtRes() throws Exception {
- AtRes atRes = AtRes.getAtRes(RES_BYTES);
-
- ByteBuffer result = ByteBuffer.allocate(AT_RES.length);
- atRes.encode(result);
- assertArrayEquals(AT_RES, result.array());
- }
-
- @Test
- public void testIsValidResLen() {
- // valid RES length: 4 <= RES length <= 16
- assertTrue(AtRes.isValidResLen(5));
- assertFalse(AtRes.isValidResLen(0));
- assertFalse(AtRes.isValidResLen(20));
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtSelectedVersionTest.java b/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtSelectedVersionTest.java
deleted file mode 100644
index 659fe9a8..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtSelectedVersionTest.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.message.simaka.attributes;
-
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_SELECTED_VERSION;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.AT_SELECTED_VERSION;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.AT_SELECTED_VERSION_INVALID_LENGTH;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import com.android.internal.net.eap.exceptions.simaka.EapSimAkaInvalidAttributeException;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtSelectedVersion;
-import com.android.internal.net.eap.message.simaka.EapSimAttributeFactory;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.nio.ByteBuffer;
-
-public class AtSelectedVersionTest {
- private static final int EXPECTED_LENGTH = 4;
- private static final int EXPECTED_VERSION = 1;
-
- private EapSimAttributeFactory mEapSimAttributeFactory;
-
- @Before
- public void setUp() {
- mEapSimAttributeFactory = EapSimAttributeFactory.getInstance();
- }
-
-
- @Test
- public void testDecode() throws Exception {
- ByteBuffer input = ByteBuffer.wrap(AT_SELECTED_VERSION);
- EapSimAkaAttribute result = mEapSimAttributeFactory.getAttribute(input);
-
- assertFalse(input.hasRemaining());
- assertTrue(result instanceof AtSelectedVersion);
- AtSelectedVersion atSelectedVersion = (AtSelectedVersion) result;
- assertEquals(EAP_AT_SELECTED_VERSION, atSelectedVersion.attributeType);
- assertEquals(EXPECTED_LENGTH, atSelectedVersion.lengthInBytes);
- assertEquals(EXPECTED_VERSION, atSelectedVersion.selectedVersion);
- }
-
- @Test
- public void testDecodeInvalidLength() throws Exception {
- ByteBuffer input = ByteBuffer.wrap(AT_SELECTED_VERSION_INVALID_LENGTH);
- try {
- mEapSimAttributeFactory.getAttribute(input);
- fail("Expected EapSimAkaInvalidAttributeException for invalid actual list length");
- } catch (EapSimAkaInvalidAttributeException expected) {
- }
- }
-
- @Test
- public void testEncode() throws Exception {
- AtSelectedVersion atSelectedVersion = new AtSelectedVersion(
- EXPECTED_LENGTH, EXPECTED_VERSION);
- ByteBuffer result = ByteBuffer.allocate(EXPECTED_LENGTH);
-
- atSelectedVersion.encode(result);
- assertArrayEquals(AT_SELECTED_VERSION, result.array());
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtVersionListTest.java b/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtVersionListTest.java
deleted file mode 100644
index 96bb7ca3..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/AtVersionListTest.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.message.simaka.attributes;
-
-import static com.android.internal.net.TestUtils.hexStringToInt;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_VERSION_LIST;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.AT_VERSION_LIST;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.AT_VERSION_LIST_INVALID_LENGTH;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.VERSION;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import com.android.internal.net.eap.exceptions.simaka.EapSimAkaInvalidAttributeException;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtVersionList;
-import com.android.internal.net.eap.message.simaka.EapSimAttributeFactory;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.nio.ByteBuffer;
-import java.util.Arrays;
-import java.util.List;
-
-public class AtVersionListTest {
- private static final int EXPECTED_LENGTH = 8;
- private static final List<Integer> EXPECTED_VERSIONS = Arrays.asList(1);
-
- private EapSimAttributeFactory mEapSimAttributeFactory;
-
- @Before
- public void setUp() {
- mEapSimAttributeFactory = EapSimAttributeFactory.getInstance();
- }
-
- @Test
- public void testDecode() throws Exception {
- ByteBuffer input = ByteBuffer.wrap(AT_VERSION_LIST);
- EapSimAkaAttribute result = mEapSimAttributeFactory.getAttribute(input);
-
- assertFalse(input.hasRemaining());
- assertTrue(result instanceof AtVersionList);
- AtVersionList atVersionList = (AtVersionList) result;
- assertEquals(EAP_AT_VERSION_LIST, atVersionList.attributeType);
- assertEquals(EXPECTED_LENGTH, atVersionList.lengthInBytes);
- assertEquals(EXPECTED_VERSIONS, atVersionList.versions);
- }
-
- @Test
- public void testDecodeInvalidActualLength() throws Exception {
- ByteBuffer input = ByteBuffer.wrap(AT_VERSION_LIST_INVALID_LENGTH);
- try {
- mEapSimAttributeFactory.getAttribute(input);
- fail("Expected EapSimAkaInvalidAttributeException for invalid actual list length");
- } catch (EapSimAkaInvalidAttributeException expected) {
- }
- }
-
- @Test
- public void testEncode() throws Exception {
- AtVersionList atVersionList = new AtVersionList(EXPECTED_LENGTH, hexStringToInt(VERSION));
- ByteBuffer result = ByteBuffer.allocate(EXPECTED_LENGTH);
-
- atVersionList.encode(result);
- assertArrayEquals(AT_VERSION_LIST, result.array());
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/EapSimAkaAttributeTest.java b/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/EapSimAkaAttributeTest.java
deleted file mode 100644
index 98ea222c..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/EapSimAkaAttributeTest.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.message.simaka.attributes;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertFalse;
-
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute;
-
-import org.junit.Test;
-
-import java.nio.ByteBuffer;
-
-public class EapSimAkaAttributeTest {
- private static final int EXPECTED_ATTRIBUTE_TYPE = 1;
- private static final int EXPECTED_LENGTH_IN_BYTES = 4;
- private static final int BUFFER_LENGTH = 2;
- private static final int EXPECTED_LENGTH_ENCODED = 1;
- private static final byte[] EXPECTED_ENCODING = {
- (byte) EXPECTED_ATTRIBUTE_TYPE,
- (byte) EXPECTED_LENGTH_ENCODED
- };
-
- @Test
- public void testEncode() throws Exception {
- EapSimAkaAttribute eapSimAkaAttribute = new EapSimAkaAttribute(
- EXPECTED_ATTRIBUTE_TYPE,
- EXPECTED_LENGTH_IN_BYTES) {
- public void encode(ByteBuffer byteBuffer) {
- encodeAttributeHeader(byteBuffer);
- }
- };
-
- ByteBuffer result = ByteBuffer.allocate(BUFFER_LENGTH);
- eapSimAkaAttribute.encode(result);
- assertArrayEquals(EXPECTED_ENCODING, result.array());
- assertFalse(result.hasRemaining());
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/EapTestAttributeDefinitions.java b/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/EapTestAttributeDefinitions.java
deleted file mode 100644
index 60397e1f..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/message/simaka/attributes/EapTestAttributeDefinitions.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.message.simaka.attributes;
-
-import static com.android.internal.net.TestUtils.hexStringToByteArray;
-
-/**
- * EapTestAttributeDefinitions provides byte[] encodings of commonly used EAP Messages.
- *
- * @ee <a href="https://tools.ietf.org/html/rfc4186#section-10">RFC 4186, EAP-SIM Authentication,
- * Section 10</a>
- * @see <a href="https://tools.ietf.org/html/rfc4187#section-10">RFC 4187, EAP-AKA Authentication,
- * Section 10</a>
- */
-public class EapTestAttributeDefinitions {
- public static final String VERSION = "0001";
- public static final String AT_VERSION_LIST_DATA = "0002" + VERSION + "0000";
- public static final byte[] AT_VERSION_LIST =
- hexStringToByteArray("0F02" + AT_VERSION_LIST_DATA);
- public static final byte[] AT_SELECTED_VERSION = hexStringToByteArray("10010001");
- public static final String NONCE_MT_STRING = "0123456789ABCDEFFEDCBA9876543210";
- public static final byte[] NONCE_MT = hexStringToByteArray(NONCE_MT_STRING);
- public static final byte[] AT_NONCE_MT = hexStringToByteArray("07050000" + NONCE_MT_STRING);
- public static final byte[] AT_PERMANENT_ID_REQ = hexStringToByteArray("0A010000");
- public static final byte[] AT_ANY_ID_REQ = hexStringToByteArray("0D010000");
- public static final byte[] AT_FULL_AUTH_ID_REQ = hexStringToByteArray("11010000");
-
- // Identity = "test1@android.net"
- public static final String IDENTITY_STRING = "746573743140616E64726F69642E6E6574";
- public static final byte[] IDENTITY = hexStringToByteArray(IDENTITY_STRING);
- public static final byte[] AT_IDENTITY =
- hexStringToByteArray("0E060011" + IDENTITY_STRING + "000000");
- public static final String RAND_1 = "00112233445566778899AABBCCDDEEFF";
- public static final byte[] RAND_1_BYTES = hexStringToByteArray(RAND_1);
- public static final String RAND_2 = "FFEEDDCCBBAA99887766554433221100";
- public static final byte[] RAND_2_BYTES = hexStringToByteArray(RAND_2);
- public static final byte[] AT_RAND_SIM = hexStringToByteArray("01090000" + RAND_1 + RAND_2);
- public static final byte[] AT_RAND_AKA = hexStringToByteArray("01050000" + RAND_1);
- public static final byte[] AT_PADDING = hexStringToByteArray("0602000000000000");
- public static final String MAC = "112233445566778899AABBCCDDEEFF11";
- public static final byte[] MAC_BYTES = hexStringToByteArray(MAC);
- public static final byte[] AT_MAC = hexStringToByteArray("0B050000" + MAC);
- public static final String COUNTER = "000A";
- public static final int COUNTER_INT = Integer.parseInt(COUNTER, 16 /* radix */);
- public static final byte[] AT_COUNTER = hexStringToByteArray("1301" + COUNTER);
- public static final byte[] AT_COUNTER_TOO_SMALL = hexStringToByteArray("14010000");
- public static final String NONCE_S = "0123456789ABCDEFFEDCBA9876543210";
- public static final byte[] AT_NONCE_S = hexStringToByteArray("15050000" + NONCE_S);
- public static final String NOTIFICATION_CODE = "8000";
- public static final byte[] AT_NOTIFICATION = hexStringToByteArray("0C01" + NOTIFICATION_CODE);
- public static final String ERROR_CODE = "0001";
- public static final byte[] AT_CLIENT_ERROR_CODE = hexStringToByteArray("1601" + ERROR_CODE);
- public static final String AUTN = "0123456789ABCDEFFEDCBA9876543210";
- public static final byte[] AUTN_BYTES = hexStringToByteArray(AUTN);
- public static final byte[] AT_AUTN = hexStringToByteArray("02050000" + AUTN);
- public static final String RES = "1122334455";
- public static final byte[] RES_BYTES = hexStringToByteArray(RES);
- public static final byte[] AT_RES = hexStringToByteArray("03030028" + RES + "000000");
- public static final String AUTS = "112233445566778899AABBCCDDEE";
- public static final byte[] AUTS_BYTES = hexStringToByteArray(AUTS);
- public static final byte[] AT_AUTS = hexStringToByteArray("0404" + AUTS);
- public static final byte[] AT_BIDDING_SUPPORTS_AKA_PRIME = hexStringToByteArray("88018000");
- public static final byte[] AT_BIDDING_DOES_NOT_SUPPORT_AKA_PRIME =
- hexStringToByteArray("88010000");
-
- // Network Name = "android.net"
- public static final String NETWORK_NAME_HEX = "616E64726F69642E6E6574";
- public static final byte[] NETWORK_NAME_BYTES = hexStringToByteArray(NETWORK_NAME_HEX);
- public static final byte[] AT_KDF_INPUT =
- hexStringToByteArray("1704000B" + NETWORK_NAME_HEX + "00");
- public static final byte[] AT_KDF_INPUT_EMPTY_NETWORK_NAME = hexStringToByteArray("17010000");
- public static final int KDF_VERSION = 1;
- public static final byte[] AT_KDF = hexStringToByteArray("18010001");
-
- public static final byte[] AT_VERSION_LIST_INVALID_LENGTH = hexStringToByteArray("0F020003");
- public static final byte[] AT_SELECTED_VERSION_INVALID_LENGTH =
- hexStringToByteArray("10020001");
- public static final byte[] AT_NONCE_INVALID_LENGTH =
- hexStringToByteArray("07060000" + NONCE_MT_STRING);
- public static final byte[] PERMANENT_ID_INVALID_LENGTH = hexStringToByteArray("0A020000");
- public static final byte[] ANY_ID_INVALID_LENGTH = hexStringToByteArray("0D020000");
- public static final byte[] FULL_AUTH_ID_INVALID_LENGTH = hexStringToByteArray("11020000");
- public static final byte[] AT_RAND_SIM_INVALID_NUM_RANDS =
- hexStringToByteArray("01050000" + RAND_1);
- public static final byte[] AT_RAND_SIM_DUPLICATE_RANDS =
- hexStringToByteArray("01090000" + RAND_1 + RAND_1);
- public static final byte[] AT_RAND_AKA_INVALID_LENGTH = hexStringToByteArray("01010000");
- public static final byte[] AT_PADDING_INVALID_PADDING = hexStringToByteArray("0601FFFF");
- public static final byte[] AT_MAC_INVALID_LENGTH = hexStringToByteArray("0B06");
- public static final byte[] AT_COUNTER_INVALID_LENGTH = hexStringToByteArray("1302");
- public static final byte[] AT_COUNTER_TOO_SMALL_INVALID_LENGTH = hexStringToByteArray("1402");
- public static final byte[] AT_NONCE_S_INVALID_LENGTH = hexStringToByteArray("1506");
- public static final byte[] AT_NOTIFICATION_INVALID_LENGTH = hexStringToByteArray("0C02");
- public static final byte[] AT_NOTIFICATION_INVALID_STATE = hexStringToByteArray("0C01C000");
- public static final byte[] AT_CLIENT_ERROR_CODE_INVALID_LENGTH = hexStringToByteArray("1602");
- public static final byte[] AT_AUTN_INVALID_LENGTH = hexStringToByteArray("02010000");
- public static final byte[] AT_RES_INVALID_RES_LENGTH =
- hexStringToByteArray("030300241122334450000000");
- public static final byte[] AT_RES_SHORT_RES =
- hexStringToByteArray("0302000811000000");
- public static final byte[] AT_RES_LONG_RES =
- hexStringToByteArray("0306008800112233445566778899AABBCCDDEEFF11000000");
- public static final byte[] AT_AUTS_INVALID_LENGTH = hexStringToByteArray("03010000");
- public static final byte[] AT_KDF_INVALID_LENGTH = hexStringToByteArray("18020001");
- public static final byte[] AT_BIDDING_INVALID_LENGTH = hexStringToByteArray("88020000");
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/statemachine/CreatedStateTest.java b/tests/iketests/src/java/com/android/internal/net/eap/statemachine/CreatedStateTest.java
deleted file mode 100644
index a452fa6f..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/statemachine/CreatedStateTest.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.statemachine;
-
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_REQUEST_IDENTITY_PACKET;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_REQUEST_NOTIFICATION_PACKET;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_REQUEST_SIM_START_PACKET;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_RESPONSE_NOTIFICATION_PACKET;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-
-import com.android.internal.net.eap.EapResult;
-import com.android.internal.net.eap.EapResult.EapResponse;
-import com.android.internal.net.eap.statemachine.EapStateMachine.IdentityState;
-import com.android.internal.net.eap.statemachine.EapStateMachine.MethodState;
-
-import org.junit.Before;
-import org.junit.Test;
-
-public class CreatedStateTest extends EapStateTest {
- private EapStateMachine mEapStateMachineSpy;
-
- @Before
- @Override
- public void setUp() {
- super.setUp();
-
- mEapStateMachineSpy = spy(mEapStateMachine);
- mEapState = mEapStateMachineSpy.new CreatedState();
- }
-
- @Test
- public void testProcessIdentityRequest() {
- mEapState.process(EAP_REQUEST_IDENTITY_PACKET);
-
- verify(mEapStateMachineSpy).transitionAndProcess(
- any(IdentityState.class), eq(EAP_REQUEST_IDENTITY_PACKET));
- }
-
- @Test
- public void testProcessNotificationRequest() {
- EapResult eapResult = mEapState.process(EAP_REQUEST_NOTIFICATION_PACKET);
-
- // state shouldn't change after Notification request
- assertTrue(eapResult instanceof EapResponse);
- EapResponse eapResponse = (EapResponse) eapResult;
- assertArrayEquals(EAP_RESPONSE_NOTIFICATION_PACKET, eapResponse.packet);
- verify(mEapStateMachineSpy, never()).transitionAndProcess(any(), any());
- }
-
- @Test
- public void testProcessSimStart() {
- mEapState.process(EAP_REQUEST_SIM_START_PACKET);
-
- // EapStateMachine should change to MethodState for method-type packet
- verify(mEapStateMachineSpy).transitionAndProcess(
- any(MethodState.class), eq(EAP_REQUEST_SIM_START_PACKET));
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapAkaChallengeStateTest.java b/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapAkaChallengeStateTest.java
deleted file mode 100644
index b07d1ff3..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapAkaChallengeStateTest.java
+++ /dev/null
@@ -1,430 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.statemachine;
-
-import static com.android.internal.net.TestUtils.hexStringToByteArray;
-import static com.android.internal.net.eap.message.EapData.EAP_IDENTITY;
-import static com.android.internal.net.eap.message.EapData.EAP_TYPE_AKA;
-import static com.android.internal.net.eap.message.EapMessage.EAP_CODE_FAILURE;
-import static com.android.internal.net.eap.message.EapMessage.EAP_CODE_REQUEST;
-import static com.android.internal.net.eap.message.EapMessage.EAP_CODE_SUCCESS;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.CK_BYTES;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_AKA_AUTHENTICATION_REJECT;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_AKA_CHALLENGE_RESPONSE;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_AKA_CLIENT_ERROR_UNABLE_TO_PROCESS;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_AKA_SYNCHRONIZATION_FAILURE;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_AKA_UICC_RESP_INVALID_TAG;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_AKA_UICC_RESP_SUCCESS_BASE_64;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_AKA_UICC_RESP_SYNCHRONIZE_BASE_64;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EMSK;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.ID_INT;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.IK_BYTES;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.MSK;
-import static com.android.internal.net.eap.message.simaka.EapAkaTypeData.EAP_AKA_CHALLENGE;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.AUTN_BYTES;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.AUTS_BYTES;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.IDENTITY;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.RAND_1_BYTES;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.RES_BYTES;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-import android.telephony.TelephonyManager;
-
-import com.android.internal.net.eap.EapResult;
-import com.android.internal.net.eap.EapResult.EapError;
-import com.android.internal.net.eap.EapResult.EapFailure;
-import com.android.internal.net.eap.EapResult.EapResponse;
-import com.android.internal.net.eap.EapResult.EapSuccess;
-import com.android.internal.net.eap.exceptions.EapInvalidRequestException;
-import com.android.internal.net.eap.exceptions.simaka.EapAkaInvalidAuthenticationResponse;
-import com.android.internal.net.eap.exceptions.simaka.EapSimAkaInvalidLengthException;
-import com.android.internal.net.eap.message.EapData;
-import com.android.internal.net.eap.message.EapMessage;
-import com.android.internal.net.eap.message.simaka.EapAkaTypeData;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtAutn;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtBidding;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtMac;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtRandAka;
-import com.android.internal.net.eap.message.simaka.EapSimAkaTypeData.DecodeResult;
-import com.android.internal.net.eap.statemachine.EapAkaMethodStateMachine.ChallengeState;
-import com.android.internal.net.eap.statemachine.EapAkaMethodStateMachine.ChallengeState.RandChallengeResult;
-import com.android.internal.net.eap.statemachine.EapMethodStateMachine.FinalState;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.util.Arrays;
-
-public class EapAkaChallengeStateTest extends EapAkaStateTest {
- private ChallengeState mChallengeState;
-
- // '10' + RAND_1_BYTES + '10' + AUTN_BYTES
- private static final String BASE_64_CHALLENGE =
- "EAARIjNEVWZ3iJmqu8zd7v8QASNFZ4mrze/+3LqYdlQyEA==";
-
- /**
- * Process to generate MAC:
- *
- * message = 01100044 | EAP-Request, ID, length in bytes
- * 17010000 | EAP-AKA, AKA-Challenge, padding
- * 0105000000112233445566778899AABBCCDDEEFF | AT_RAND
- * 020500000123456789ABCDEFFEDCBA9876543210 | AT_AUTN
- * 0B05000000000000000000000000000000000000 | AT_MAC (zeroed out)
- *
- * MK = SHA-1(Identity | IK | CK)
- * K_encr, K_aut, MSK, EMSK = PRF(MK)
- * MAC = HMAC-SHA-1(K_aut, message)
- */
- private static final byte[] REQUEST_MAC_BYTES =
- hexStringToByteArray("3EB97A1D0E62894FD0DA384D24D8983C");
-
- /**
- * message = 01100048 | EAP-Request, ID, length in bytes
- * 17010000 | EAP-AKA, AKA-Challenge, padding
- * 0105000000112233445566778899AABBCCDDEEFF | AT_RAND
- * 020500000123456789ABCDEFFEDCBA9876543210 | AT_AUTN
- * 88018000 | AT_BIDDING
- * 0B05000000000000000000000000000000000000 | AT_MAC (zeroed out)
- */
- private static final byte[] BIDDING_DOWN_MAC =
- hexStringToByteArray("9CB543894A5EFDC32DF6A6CE1AB0E01A");
-
- @Before
- public void setUp() {
- super.setUp();
-
- mChallengeState = mEapAkaMethodStateMachine.new ChallengeState(IDENTITY);
- mEapAkaMethodStateMachine.transitionTo(mChallengeState);
- }
-
- @Test
- public void testProcessIncorrectEapMethodType() throws Exception {
- EapData eapData = new EapData(EAP_IDENTITY, DUMMY_EAP_TYPE_DATA);
- EapMessage eapMessage = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
-
- EapResult result = mChallengeState.process(eapMessage);
- EapError eapError = (EapError) result;
- assertTrue(eapError.cause instanceof EapInvalidRequestException);
- }
-
- @Test
- public void testProcessSuccess() throws Exception {
- System.arraycopy(MSK, 0, mEapAkaMethodStateMachine.mMsk, 0, MSK.length);
- System.arraycopy(EMSK, 0, mEapAkaMethodStateMachine.mEmsk, 0, EMSK.length);
-
- mChallengeState.mHadSuccessfulChallenge = true;
- EapMessage input = new EapMessage(EAP_CODE_SUCCESS, ID_INT, null);
-
- EapSuccess eapSuccess = (EapSuccess) mEapAkaMethodStateMachine.process(input);
- assertArrayEquals(MSK, eapSuccess.msk);
- assertArrayEquals(EMSK, eapSuccess.emsk);
- assertTrue(mEapAkaMethodStateMachine.getState() instanceof FinalState);
- }
-
- @Test
- public void testProcessInvalidSuccess() throws Exception {
- EapMessage input = new EapMessage(EAP_CODE_SUCCESS, ID_INT, null);
-
- EapError eapError = (EapError) mEapAkaMethodStateMachine.process(input);
- assertTrue(eapError.cause instanceof EapInvalidRequestException);
- }
-
- @Test
- public void testProcessFailure() throws Exception {
- EapMessage input = new EapMessage(EAP_CODE_FAILURE, ID_INT, null);
- EapResult result = mEapAkaMethodStateMachine.process(input);
- assertTrue(mEapAkaMethodStateMachine.getState() instanceof FinalState);
-
- assertTrue(result instanceof EapFailure);
- }
-
- @Test
- public void testProcessMissingAtRand() throws Exception {
- EapData eapData = new EapData(EAP_TYPE_AKA, DUMMY_EAP_TYPE_DATA);
- EapMessage eapMessage = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
-
- AtAutn atAutn = new AtAutn(AUTN_BYTES);
- AtMac atMac = new AtMac(REQUEST_MAC_BYTES);
-
- DecodeResult<EapAkaTypeData> decodeResult =
- new DecodeResult<>(
- new EapAkaTypeData(EAP_AKA_CHALLENGE, Arrays.asList(atAutn, atMac)));
- when(mMockEapAkaTypeDataDecoder.decode(eq(DUMMY_EAP_TYPE_DATA))).thenReturn(decodeResult);
-
- EapResponse eapResponse = (EapResponse) mEapAkaMethodStateMachine.process(eapMessage);
- assertArrayEquals(EAP_AKA_CLIENT_ERROR_UNABLE_TO_PROCESS, eapResponse.packet);
-
- verify(mMockEapAkaTypeDataDecoder).decode(eq(DUMMY_EAP_TYPE_DATA));
- verifyNoMoreInteractions(mMockEapAkaTypeDataDecoder, mMockTelephonyManager);
- }
-
- @Test
- public void testProcessMissingAtAutn() throws Exception {
- EapData eapData = new EapData(EAP_TYPE_AKA, DUMMY_EAP_TYPE_DATA);
- EapMessage eapMessage = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
-
- AtRandAka atRandAka = new AtRandAka(RAND_1_BYTES);
- AtMac atMac = new AtMac(REQUEST_MAC_BYTES);
-
- DecodeResult<EapAkaTypeData> decodeResult =
- new DecodeResult<>(
- new EapAkaTypeData(EAP_AKA_CHALLENGE, Arrays.asList(atRandAka, atMac)));
- when(mMockEapAkaTypeDataDecoder.decode(eq(DUMMY_EAP_TYPE_DATA))).thenReturn(decodeResult);
-
- EapResponse eapResponse = (EapResponse) mEapAkaMethodStateMachine.process(eapMessage);
- assertArrayEquals(EAP_AKA_CLIENT_ERROR_UNABLE_TO_PROCESS, eapResponse.packet);
-
- verify(mMockEapAkaTypeDataDecoder).decode(eq(DUMMY_EAP_TYPE_DATA));
- verifyNoMoreInteractions(mMockEapAkaTypeDataDecoder, mMockTelephonyManager);
- }
-
- @Test
- public void testProcessMissingAtMac() throws Exception {
- EapData eapData = new EapData(EAP_TYPE_AKA, DUMMY_EAP_TYPE_DATA);
- EapMessage eapMessage = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
-
- AtRandAka atRandAka = new AtRandAka(RAND_1_BYTES);
- AtAutn atAutn = new AtAutn(AUTN_BYTES);
-
- DecodeResult<EapAkaTypeData> decodeResult =
- new DecodeResult<>(
- new EapAkaTypeData(EAP_AKA_CHALLENGE, Arrays.asList(atRandAka, atAutn)));
- when(mMockEapAkaTypeDataDecoder.decode(eq(DUMMY_EAP_TYPE_DATA))).thenReturn(decodeResult);
-
- EapResponse eapResponse = (EapResponse) mEapAkaMethodStateMachine.process(eapMessage);
- assertArrayEquals(EAP_AKA_CLIENT_ERROR_UNABLE_TO_PROCESS, eapResponse.packet);
-
- verify(mMockEapAkaTypeDataDecoder).decode(eq(DUMMY_EAP_TYPE_DATA));
- verifyNoMoreInteractions(mMockEapAkaTypeDataDecoder, mMockTelephonyManager);
- }
-
- @Test
- public void testRandChallengeResultConstructor() throws Exception {
- RandChallengeResult result =
- mChallengeState.new RandChallengeResult(RES_BYTES, IK_BYTES, CK_BYTES);
- assertArrayEquals(RES_BYTES, result.res);
- assertArrayEquals(IK_BYTES, result.ik);
- assertArrayEquals(CK_BYTES, result.ck);
- assertNull(result.auts);
-
- result = mChallengeState.new RandChallengeResult(AUTS_BYTES);
- assertArrayEquals(AUTS_BYTES, result.auts);
- assertNull(result.res);
- assertNull(result.ik);
- assertNull(result.ck);
-
- try {
- mChallengeState.new RandChallengeResult(new byte[0], IK_BYTES, CK_BYTES);
- fail("Expected EapSimAkaInvalidLengthException for invalid RES length");
- } catch (EapSimAkaInvalidLengthException ex) {
- }
-
- try {
- mChallengeState.new RandChallengeResult(RES_BYTES, new byte[0], CK_BYTES);
- fail("Expected EapSimAkaInvalidLengthException for invalid IK length");
- } catch (EapSimAkaInvalidLengthException ex) {
- }
-
- try {
- mChallengeState.new RandChallengeResult(RES_BYTES, IK_BYTES, new byte[0]);
- fail("Expected EapSimAkaInvalidLengthException for invalid CK length");
- } catch (EapSimAkaInvalidLengthException ex) {
- }
-
- try {
- mChallengeState.new RandChallengeResult(new byte[0]);
- fail("Expected EapSimAkaInvalidLengthException for invalid AUTS length");
- } catch (EapSimAkaInvalidLengthException ex) {
- }
- }
-
- @Test
- public void testProcessIccAuthenticationNullResponse() throws Exception {
- EapData eapData = new EapData(EAP_TYPE_AKA, DUMMY_EAP_TYPE_DATA);
- EapMessage eapMessage = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
-
- AtRandAka atRandAka = new AtRandAka(RAND_1_BYTES);
- AtAutn atAutn = new AtAutn(AUTN_BYTES);
- AtMac atMac = new AtMac(REQUEST_MAC_BYTES);
-
- DecodeResult<EapAkaTypeData> decodeResult =
- new DecodeResult<>(
- new EapAkaTypeData(
- EAP_AKA_CHALLENGE,
- Arrays.asList(atRandAka, atAutn, atMac)));
- when(mMockEapAkaTypeDataDecoder.decode(eq(DUMMY_EAP_TYPE_DATA))).thenReturn(decodeResult);
- when(mMockTelephonyManager
- .getIccAuthentication(
- TelephonyManager.APPTYPE_USIM,
- TelephonyManager.AUTHTYPE_EAP_AKA,
- BASE_64_CHALLENGE))
- .thenReturn(null);
-
- EapResponse eapResponse = (EapResponse) mEapAkaMethodStateMachine.process(eapMessage);
- assertArrayEquals(EAP_AKA_AUTHENTICATION_REJECT, eapResponse.packet);
-
- verify(mMockEapAkaTypeDataDecoder).decode(eq(DUMMY_EAP_TYPE_DATA));
- verify(mMockTelephonyManager)
- .getIccAuthentication(
- TelephonyManager.APPTYPE_USIM,
- TelephonyManager.AUTHTYPE_EAP_AKA,
- BASE_64_CHALLENGE);
- verifyNoMoreInteractions(mMockEapAkaTypeDataDecoder, mMockTelephonyManager);
- }
-
- @Test
- public void testProcessIccAuthenticationInvalidTag() throws Exception {
- EapData eapData = new EapData(EAP_TYPE_AKA, DUMMY_EAP_TYPE_DATA);
- EapMessage eapMessage = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
-
- AtRandAka atRandAka = new AtRandAka(RAND_1_BYTES);
- AtAutn atAutn = new AtAutn(AUTN_BYTES);
- AtMac atMac = new AtMac(REQUEST_MAC_BYTES);
-
- DecodeResult<EapAkaTypeData> decodeResult =
- new DecodeResult<>(
- new EapAkaTypeData(
- EAP_AKA_CHALLENGE,
- Arrays.asList(atRandAka, atAutn, atMac)));
- when(mMockEapAkaTypeDataDecoder.decode(eq(DUMMY_EAP_TYPE_DATA))).thenReturn(decodeResult);
- when(mMockTelephonyManager
- .getIccAuthentication(
- TelephonyManager.APPTYPE_USIM,
- TelephonyManager.AUTHTYPE_EAP_AKA,
- BASE_64_CHALLENGE))
- .thenReturn(EAP_AKA_UICC_RESP_INVALID_TAG);
-
- EapError eapError = (EapError) mEapAkaMethodStateMachine.process(eapMessage);
- assertTrue(eapError.cause instanceof EapAkaInvalidAuthenticationResponse);
-
- verify(mMockEapAkaTypeDataDecoder).decode(eq(DUMMY_EAP_TYPE_DATA));
- verify(mMockTelephonyManager)
- .getIccAuthentication(
- TelephonyManager.APPTYPE_USIM,
- TelephonyManager.AUTHTYPE_EAP_AKA,
- BASE_64_CHALLENGE);
- verifyNoMoreInteractions(mMockEapAkaTypeDataDecoder, mMockTelephonyManager);
- }
-
- @Test
- public void testProcessIccAuthenticationSynchronizeTag() throws Exception {
- EapData eapData = new EapData(EAP_TYPE_AKA, DUMMY_EAP_TYPE_DATA);
- EapMessage eapMessage = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
-
- AtRandAka atRandAka = new AtRandAka(RAND_1_BYTES);
- AtAutn atAutn = new AtAutn(AUTN_BYTES);
- AtMac atMac = new AtMac(REQUEST_MAC_BYTES);
-
- DecodeResult<EapAkaTypeData> decodeResult =
- new DecodeResult<>(
- new EapAkaTypeData(
- EAP_AKA_CHALLENGE,
- Arrays.asList(atRandAka, atAutn, atMac)));
- when(mMockEapAkaTypeDataDecoder.decode(eq(DUMMY_EAP_TYPE_DATA))).thenReturn(decodeResult);
- when(mMockTelephonyManager
- .getIccAuthentication(
- TelephonyManager.APPTYPE_USIM,
- TelephonyManager.AUTHTYPE_EAP_AKA,
- BASE_64_CHALLENGE))
- .thenReturn(EAP_AKA_UICC_RESP_SYNCHRONIZE_BASE_64);
-
- EapResponse eapResponse = (EapResponse) mEapAkaMethodStateMachine.process(eapMessage);
- assertArrayEquals(EAP_AKA_SYNCHRONIZATION_FAILURE, eapResponse.packet);
-
- verify(mMockEapAkaTypeDataDecoder).decode(eq(DUMMY_EAP_TYPE_DATA));
- verify(mMockTelephonyManager)
- .getIccAuthentication(
- TelephonyManager.APPTYPE_USIM,
- TelephonyManager.AUTHTYPE_EAP_AKA,
- BASE_64_CHALLENGE);
- verifyNoMoreInteractions(mMockEapAkaTypeDataDecoder, mMockTelephonyManager);
- }
-
- @Test
- public void testProcessValidChallenge() throws Exception {
- EapData eapData = new EapData(EAP_TYPE_AKA, DUMMY_EAP_TYPE_DATA);
- EapMessage eapMessage = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
-
- AtRandAka atRandAka = new AtRandAka(RAND_1_BYTES);
- AtAutn atAutn = new AtAutn(AUTN_BYTES);
- AtMac atMac = new AtMac(REQUEST_MAC_BYTES);
-
- DecodeResult<EapAkaTypeData> decodeResult =
- new DecodeResult<>(
- new EapAkaTypeData(
- EAP_AKA_CHALLENGE, Arrays.asList(atRandAka, atAutn, atMac)));
- when(mMockEapAkaTypeDataDecoder.decode(eq(DUMMY_EAP_TYPE_DATA))).thenReturn(decodeResult);
- when(mMockTelephonyManager.getIccAuthentication(
- TelephonyManager.APPTYPE_USIM,
- TelephonyManager.AUTHTYPE_EAP_AKA,
- BASE_64_CHALLENGE))
- .thenReturn(EAP_AKA_UICC_RESP_SUCCESS_BASE_64);
-
- EapResponse eapResponse = (EapResponse) mEapAkaMethodStateMachine.process(eapMessage);
- assertArrayEquals(EAP_AKA_CHALLENGE_RESPONSE, eapResponse.packet);
-
- verify(mMockEapAkaTypeDataDecoder).decode(eq(DUMMY_EAP_TYPE_DATA));
- verify(mMockTelephonyManager)
- .getIccAuthentication(
- TelephonyManager.APPTYPE_USIM,
- TelephonyManager.AUTHTYPE_EAP_AKA,
- BASE_64_CHALLENGE);
- verifyNoMoreInteractions(mMockEapAkaTypeDataDecoder, mMockTelephonyManager);
- }
-
- @Test
- public void testProcessBiddingDownAttack() throws Exception {
- EapData eapData = new EapData(EAP_TYPE_AKA, DUMMY_EAP_TYPE_DATA);
- EapMessage eapMessage = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
-
- AtRandAka atRandAka = new AtRandAka(RAND_1_BYTES);
- AtAutn atAutn = new AtAutn(AUTN_BYTES);
- AtBidding atBidding = new AtBidding(true);
- AtMac atMac = new AtMac(BIDDING_DOWN_MAC);
-
- DecodeResult<EapAkaTypeData> decodeResult =
- new DecodeResult<>(
- new EapAkaTypeData(
- EAP_AKA_CHALLENGE,
- Arrays.asList(atRandAka, atAutn, atBidding, atMac)));
- when(mMockEapAkaTypeDataDecoder.decode(eq(DUMMY_EAP_TYPE_DATA))).thenReturn(decodeResult);
- when(mMockTelephonyManager.getIccAuthentication(
- TelephonyManager.APPTYPE_USIM,
- TelephonyManager.AUTHTYPE_EAP_AKA,
- BASE_64_CHALLENGE))
- .thenReturn(EAP_AKA_UICC_RESP_SUCCESS_BASE_64);
-
- EapResponse eapResponse = (EapResponse) mEapAkaMethodStateMachine.process(eapMessage);
- assertArrayEquals(EAP_AKA_AUTHENTICATION_REJECT, eapResponse.packet);
-
- verify(mMockEapAkaTypeDataDecoder).decode(eq(DUMMY_EAP_TYPE_DATA));
- verify(mMockTelephonyManager)
- .getIccAuthentication(
- TelephonyManager.APPTYPE_USIM,
- TelephonyManager.AUTHTYPE_EAP_AKA,
- BASE_64_CHALLENGE);
- verifyNoMoreInteractions(mMockEapAkaTypeDataDecoder, mMockTelephonyManager);
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapAkaCreatedStateTest.java b/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapAkaCreatedStateTest.java
deleted file mode 100644
index 6e100dbf..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapAkaCreatedStateTest.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.statemachine;
-
-import static com.android.internal.net.eap.message.EapData.EAP_TYPE_AKA;
-import static com.android.internal.net.eap.message.EapMessage.EAP_CODE_FAILURE;
-import static com.android.internal.net.eap.message.EapMessage.EAP_CODE_REQUEST;
-import static com.android.internal.net.eap.message.EapMessage.EAP_CODE_SUCCESS;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.ID_INT;
-import static com.android.internal.net.eap.message.simaka.EapAkaTypeData.EAP_AKA_CHALLENGE;
-import static com.android.internal.net.eap.message.simaka.EapAkaTypeData.EAP_AKA_IDENTITY;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-import com.android.internal.net.eap.EapResult;
-import com.android.internal.net.eap.EapResult.EapError;
-import com.android.internal.net.eap.EapResult.EapFailure;
-import com.android.internal.net.eap.exceptions.EapInvalidRequestException;
-import com.android.internal.net.eap.message.EapData;
-import com.android.internal.net.eap.message.EapMessage;
-import com.android.internal.net.eap.message.simaka.EapAkaTypeData;
-import com.android.internal.net.eap.message.simaka.EapSimAkaTypeData.DecodeResult;
-import com.android.internal.net.eap.statemachine.EapAkaMethodStateMachine.ChallengeState;
-import com.android.internal.net.eap.statemachine.EapAkaMethodStateMachine.IdentityState;
-import com.android.internal.net.eap.statemachine.EapMethodStateMachine.FinalState;
-
-import org.junit.Test;
-
-import java.util.LinkedHashMap;
-
-public class EapAkaCreatedStateTest extends EapAkaStateTest {
- @Test
- public void testProcessTransitionToIdentityState() throws Exception {
- EapData eapData = new EapData(EAP_TYPE_AKA, DUMMY_EAP_TYPE_DATA);
- EapMessage eapMessage = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
-
- // Don't actually need any attributes in the attributeMap, since we only care about the
- // state transition here.
- DecodeResult<EapAkaTypeData> decodeResult =
- new DecodeResult<>(new EapAkaTypeData(EAP_AKA_IDENTITY, new LinkedHashMap<>()));
- when(mMockEapAkaTypeDataDecoder.decode(eq(DUMMY_EAP_TYPE_DATA))).thenReturn(decodeResult);
-
- mEapAkaMethodStateMachine.process(eapMessage);
-
- assertTrue(mEapAkaMethodStateMachine.getState() instanceof IdentityState);
-
- // decoded in CreatedState and IdentityState
- verify(mMockEapAkaTypeDataDecoder, times(2)).decode(eq(DUMMY_EAP_TYPE_DATA));
- verifyNoMoreInteractions(mMockTelephonyManager, mMockEapAkaTypeDataDecoder);
- }
-
- @Test
- public void testProcessTransitionToChallengeState() throws Exception {
- EapData eapData = new EapData(EAP_TYPE_AKA, DUMMY_EAP_TYPE_DATA);
- EapMessage eapMessage = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
-
- // Don't actually need any attributes in the attributeMap, since we only care about the
- // state transition here.
- DecodeResult<EapAkaTypeData> decodeResult =
- new DecodeResult<>(new EapAkaTypeData(EAP_AKA_CHALLENGE, new LinkedHashMap<>()));
- when(mMockEapAkaTypeDataDecoder.decode(eq(DUMMY_EAP_TYPE_DATA))).thenReturn(decodeResult);
-
- mEapAkaMethodStateMachine.process(eapMessage);
-
- ChallengeState challengeState = (ChallengeState) mEapAkaMethodStateMachine.getState();
- assertArrayEquals(EAP_IDENTITY_BYTES, challengeState.mIdentity);
-
- // decoded in CreatedState and ChallengeState
- verify(mMockEapAkaTypeDataDecoder, times(2)).decode(DUMMY_EAP_TYPE_DATA);
- verifyNoMoreInteractions(mMockTelephonyManager, mMockEapAkaTypeDataDecoder);
- }
-
- @Test
- public void testProcessSuccess() throws Exception {
- EapMessage input = new EapMessage(EAP_CODE_SUCCESS, ID_INT, null);
- EapResult result = mEapAkaMethodStateMachine.process(input);
-
- EapError eapError = (EapError) result;
- assertTrue(eapError.cause instanceof EapInvalidRequestException);
- }
-
- @Test
- public void testProcessFailure() throws Exception {
- EapMessage input = new EapMessage(EAP_CODE_FAILURE, ID_INT, null);
- EapResult result = mEapAkaMethodStateMachine.process(input);
- assertTrue(mEapAkaMethodStateMachine.getState() instanceof FinalState);
-
- assertTrue(result instanceof EapFailure);
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapAkaIdentityStateTest.java b/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapAkaIdentityStateTest.java
deleted file mode 100644
index 20175f95..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapAkaIdentityStateTest.java
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.statemachine;
-
-import static com.android.internal.net.eap.message.EapData.EAP_TYPE_AKA;
-import static com.android.internal.net.eap.message.EapMessage.EAP_CODE_REQUEST;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_AKA_CLIENT_ERROR_UNABLE_TO_PROCESS;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_AKA_IDENTITY_RESPONSE;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.ID_INT;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.IMSI;
-import static com.android.internal.net.eap.message.simaka.EapAkaTypeData.EAP_AKA_CHALLENGE;
-import static com.android.internal.net.eap.message.simaka.EapAkaTypeData.EAP_AKA_IDENTITY;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-import com.android.internal.net.eap.EapResult.EapError;
-import com.android.internal.net.eap.EapResult.EapResponse;
-import com.android.internal.net.eap.exceptions.simaka.EapSimAkaIdentityUnavailableException;
-import com.android.internal.net.eap.message.EapData;
-import com.android.internal.net.eap.message.EapMessage;
-import com.android.internal.net.eap.message.simaka.EapAkaTypeData;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtAnyIdReq;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtPermanentIdReq;
-import com.android.internal.net.eap.message.simaka.EapSimAkaTypeData.DecodeResult;
-import com.android.internal.net.eap.statemachine.EapAkaMethodStateMachine.ChallengeState;
-import com.android.internal.net.eap.statemachine.EapAkaMethodStateMachine.IdentityState;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.util.Arrays;
-import java.util.LinkedHashMap;
-
-public class EapAkaIdentityStateTest extends EapAkaStateTest {
- private IdentityState mIdentityState;
-
- @Before
- public void setUp() {
- super.setUp();
-
- mIdentityState = mEapAkaMethodStateMachine.new IdentityState();
- mEapAkaMethodStateMachine.transitionTo(mIdentityState);
- }
-
- @Test
- public void testProcessIdentityRequest() throws Exception {
- EapData eapData = new EapData(EAP_TYPE_AKA, DUMMY_EAP_TYPE_DATA);
- EapMessage eapMessage = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
-
- DecodeResult<EapAkaTypeData> decodeResult =
- new DecodeResult<>(
- new EapAkaTypeData(EAP_AKA_IDENTITY, Arrays.asList(new AtAnyIdReq())));
- when(mMockEapAkaTypeDataDecoder.decode(eq(DUMMY_EAP_TYPE_DATA))).thenReturn(decodeResult);
- when(mMockTelephonyManager.getSubscriberId()).thenReturn(IMSI);
-
- EapResponse eapResponse = (EapResponse) mEapAkaMethodStateMachine.process(eapMessage);
- assertArrayEquals(EAP_AKA_IDENTITY_RESPONSE, eapResponse.packet);
-
- verify(mMockEapAkaTypeDataDecoder).decode(eq(DUMMY_EAP_TYPE_DATA));
- verify(mMockTelephonyManager).getSubscriberId();
- verifyNoMoreInteractions(mMockEapAkaTypeDataDecoder, mMockTelephonyManager);
- }
-
- @Test
- public void testProcessWithoutIdentityRequestAttributes() throws Exception {
- EapData eapData = new EapData(EAP_TYPE_AKA, DUMMY_EAP_TYPE_DATA);
- EapMessage eapMessage = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
-
- DecodeResult<EapAkaTypeData> decodeResult =
- new DecodeResult<>(new EapAkaTypeData(EAP_AKA_IDENTITY, new LinkedHashMap<>()));
- when(mMockEapAkaTypeDataDecoder.decode(eq(DUMMY_EAP_TYPE_DATA))).thenReturn(decodeResult);
-
- EapResponse eapResponse = (EapResponse) mEapAkaMethodStateMachine.process(eapMessage);
- assertArrayEquals(EAP_AKA_CLIENT_ERROR_UNABLE_TO_PROCESS, eapResponse.packet);
-
- verify(mMockEapAkaTypeDataDecoder).decode(eq(DUMMY_EAP_TYPE_DATA));
- verifyNoMoreInteractions(mMockEapAkaTypeDataDecoder, mMockTelephonyManager);
- }
-
- @Test
- public void testProcessMultipleIdentityRequestAttributes() throws Exception {
- EapData eapData = new EapData(EAP_TYPE_AKA, DUMMY_EAP_TYPE_DATA);
- EapMessage eapMessage = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
-
- DecodeResult<EapAkaTypeData> decodeResult =
- new DecodeResult<>(
- new EapAkaTypeData(
- EAP_AKA_IDENTITY,
- Arrays.asList(new AtAnyIdReq(), new AtPermanentIdReq())));
- when(mMockEapAkaTypeDataDecoder.decode(eq(DUMMY_EAP_TYPE_DATA))).thenReturn(decodeResult);
-
- EapResponse eapResponse = (EapResponse) mEapAkaMethodStateMachine.process(eapMessage);
- assertArrayEquals(EAP_AKA_CLIENT_ERROR_UNABLE_TO_PROCESS, eapResponse.packet);
-
- verify(mMockEapAkaTypeDataDecoder).decode(eq(DUMMY_EAP_TYPE_DATA));
- verifyNoMoreInteractions(mMockEapAkaTypeDataDecoder, mMockTelephonyManager);
- }
-
- @Test
- public void testProcessImsiUnavailable() throws Exception {
- EapData eapData = new EapData(EAP_TYPE_AKA, DUMMY_EAP_TYPE_DATA);
- EapMessage eapMessage = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
-
- DecodeResult<EapAkaTypeData> decodeResult =
- new DecodeResult<>(
- new EapAkaTypeData(EAP_AKA_IDENTITY, Arrays.asList(new AtAnyIdReq())));
- when(mMockEapAkaTypeDataDecoder.decode(eq(DUMMY_EAP_TYPE_DATA))).thenReturn(decodeResult);
- when(mMockTelephonyManager.getSubscriberId()).thenReturn(null);
-
- EapError eapError = (EapError) mEapAkaMethodStateMachine.process(eapMessage);
- assertTrue(eapError.cause instanceof EapSimAkaIdentityUnavailableException);
-
- verify(mMockEapAkaTypeDataDecoder).decode(eq(DUMMY_EAP_TYPE_DATA));
- verify(mMockTelephonyManager).getSubscriberId();
- verifyNoMoreInteractions(mMockEapAkaTypeDataDecoder, mMockTelephonyManager);
- }
-
- @Test
- public void testProcessTransitionToChallengeState() throws Exception {
- // transition to IdentityState so we can verify the transition to ChallengeState
- IdentityState identityState = mEapAkaMethodStateMachine.new IdentityState();
- mEapAkaMethodStateMachine.transitionTo(identityState);
-
- EapData eapData = new EapData(EAP_TYPE_AKA, DUMMY_EAP_TYPE_DATA);
- EapMessage eapMessage = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
-
- // Don't actually need any attributes in the attributeMap, since we only care about the
- // state transition here.
- DecodeResult<EapAkaTypeData> decodeResult =
- new DecodeResult<>(new EapAkaTypeData(EAP_AKA_CHALLENGE, new LinkedHashMap<>()));
- when(mMockEapAkaTypeDataDecoder.decode(eq(DUMMY_EAP_TYPE_DATA))).thenReturn(decodeResult);
-
- mEapAkaMethodStateMachine.process(eapMessage);
-
- assertTrue(mEapAkaMethodStateMachine.getState() instanceof ChallengeState);
-
- // decoded in IdentityState and ChallengeState
- verify(mMockEapAkaTypeDataDecoder, times(2)).decode(DUMMY_EAP_TYPE_DATA);
- verifyNoMoreInteractions(mMockTelephonyManager, mMockEapAkaTypeDataDecoder);
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapAkaMethodStateMachineTest.java b/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapAkaMethodStateMachineTest.java
deleted file mode 100644
index db2899b6..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapAkaMethodStateMachineTest.java
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.statemachine;
-
-import static android.telephony.TelephonyManager.APPTYPE_USIM;
-
-import static com.android.internal.net.TestUtils.hexStringToByteArray;
-import static com.android.internal.net.eap.message.EapData.EAP_TYPE_AKA;
-import static com.android.internal.net.eap.message.EapMessage.EAP_CODE_REQUEST;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_AKA_CLIENT_ERROR_UNABLE_TO_PROCESS;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_AKA_NOTIFICATION_RESPONSE;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.ID_INT;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.IMSI;
-import static com.android.internal.net.eap.message.simaka.EapAkaTypeData.EAP_AKA_IDENTITY;
-import static com.android.internal.net.eap.message.simaka.EapAkaTypeData.EAP_AKA_NOTIFICATION;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtNotification.GENERAL_FAILURE_PRE_CHALLENGE;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-import android.net.eap.EapSessionConfig.EapAkaConfig;
-import android.telephony.TelephonyManager;
-
-import com.android.internal.net.eap.EapResult.EapError;
-import com.android.internal.net.eap.EapResult.EapResponse;
-import com.android.internal.net.eap.exceptions.EapInvalidRequestException;
-import com.android.internal.net.eap.message.EapData;
-import com.android.internal.net.eap.message.EapMessage;
-import com.android.internal.net.eap.message.simaka.EapAkaTypeData;
-import com.android.internal.net.eap.message.simaka.EapAkaTypeData.EapAkaTypeDataDecoder;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtAnyIdReq;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtNotification;
-import com.android.internal.net.eap.message.simaka.EapSimAkaTypeData.DecodeResult;
-import com.android.internal.net.eap.statemachine.EapAkaMethodStateMachine.CreatedState;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.util.Arrays;
-
-public class EapAkaMethodStateMachineTest {
- private static final int SUB_ID = 1;
- private static final byte[] DUMMY_EAP_TYPE_DATA = hexStringToByteArray("112233445566");
-
- // EAP-Identity = hex("test@android.net")
- protected static final byte[] EAP_IDENTITY_BYTES =
- hexStringToByteArray("7465737440616E64726F69642E6E6574");
-
- protected TelephonyManager mMockTelephonyManager;
- private EapAkaTypeDataDecoder mMockEapAkaTypeDataDecoder;
-
- private EapAkaConfig mEapAkaConfig = new EapAkaConfig(SUB_ID, APPTYPE_USIM);
- private EapAkaMethodStateMachine mEapAkaMethodStateMachine;
-
- @Before
- public void setUp() {
- mMockTelephonyManager = mock(TelephonyManager.class);
- mMockEapAkaTypeDataDecoder = mock(EapAkaTypeDataDecoder.class);
-
- when(mMockTelephonyManager.createForSubscriptionId(SUB_ID))
- .thenReturn(mMockTelephonyManager);
-
- mEapAkaMethodStateMachine =
- new EapAkaMethodStateMachine(
- mMockTelephonyManager,
- EAP_IDENTITY_BYTES,
- mEapAkaConfig,
- mMockEapAkaTypeDataDecoder,
- false);
-
- verify(mMockTelephonyManager).createForSubscriptionId(SUB_ID);
- }
-
- @Test
- public void testEapAkaMethodStateMachineStartState() {
- assertTrue(mEapAkaMethodStateMachine.getState() instanceof CreatedState);
- }
-
- @Test
- public void testGetEapMethod() {
- assertEquals(EAP_TYPE_AKA, mEapAkaMethodStateMachine.getEapMethod());
- }
-
- @Test
- public void testEapAkaFailsOnMultipleAkaNotifications() throws Exception {
- EapData eapData = new EapData(EAP_TYPE_AKA, DUMMY_EAP_TYPE_DATA);
- EapMessage eapMessage = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
-
- // First EAP-AKA/Notification
- EapAkaTypeData notificationTypeData =
- new EapAkaTypeData(
- EAP_AKA_NOTIFICATION,
- Arrays.asList(new AtNotification(GENERAL_FAILURE_PRE_CHALLENGE)));
- DecodeResult<EapAkaTypeData> decodeResult = new DecodeResult<>(notificationTypeData);
- when(mMockEapAkaTypeDataDecoder.decode(eq(DUMMY_EAP_TYPE_DATA))).thenReturn(decodeResult);
-
- EapResponse eapResponse = (EapResponse) mEapAkaMethodStateMachine.process(eapMessage);
- assertArrayEquals(EAP_AKA_NOTIFICATION_RESPONSE, eapResponse.packet);
- verify(mMockEapAkaTypeDataDecoder).decode(DUMMY_EAP_TYPE_DATA);
- verifyNoMoreInteractions(mMockTelephonyManager, mMockEapAkaTypeDataDecoder);
-
- // Transition to IdentityState
- decodeResult =
- new DecodeResult<>(
- new EapAkaTypeData(EAP_AKA_IDENTITY, Arrays.asList(new AtAnyIdReq())));
- when(mMockEapAkaTypeDataDecoder.decode(eq(DUMMY_EAP_TYPE_DATA))).thenReturn(decodeResult);
- when(mMockTelephonyManager.getSubscriberId()).thenReturn(IMSI);
-
- eapResponse = (EapResponse) mEapAkaMethodStateMachine.process(eapMessage);
- assertFalse(
- "EAP-Request/AKA-Identity returned a Client-Error response",
- Arrays.equals(EAP_AKA_CLIENT_ERROR_UNABLE_TO_PROCESS, eapResponse.packet));
-
- // decoded in: previous 1 time + in CreatedState and IdentityState
- verify(mMockEapAkaTypeDataDecoder, times(3)).decode(eq(DUMMY_EAP_TYPE_DATA));
- verify(mMockTelephonyManager).getSubscriberId();
- verifyNoMoreInteractions(mMockTelephonyManager, mMockEapAkaTypeDataDecoder);
-
- // Second EAP-AKA/Notification
- decodeResult = new DecodeResult<>(notificationTypeData);
- when(mMockEapAkaTypeDataDecoder.decode(eq(DUMMY_EAP_TYPE_DATA))).thenReturn(decodeResult);
-
- EapError eapError = (EapError) mEapAkaMethodStateMachine.process(eapMessage);
- assertTrue(eapError.cause instanceof EapInvalidRequestException);
-
- // decoded previous 3 times + 1
- verify(mMockEapAkaTypeDataDecoder, times(4)).decode(DUMMY_EAP_TYPE_DATA);
- verifyNoMoreInteractions(mMockTelephonyManager, mMockEapAkaTypeDataDecoder);
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapAkaPrimeChallengeStateTest.java b/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapAkaPrimeChallengeStateTest.java
deleted file mode 100644
index 731eb6bd..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapAkaPrimeChallengeStateTest.java
+++ /dev/null
@@ -1,354 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.statemachine;
-
-import static android.telephony.TelephonyManager.APPTYPE_USIM;
-
-import static com.android.internal.net.TestUtils.hexStringToByteArray;
-import static com.android.internal.net.eap.message.EapData.EAP_TYPE_AKA_PRIME;
-import static com.android.internal.net.eap.message.EapMessage.EAP_CODE_REQUEST;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.CK_BYTES;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_AKA_PRIME_AUTHENTICATION_REJECT;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_AKA_PRIME_IDENTITY_BYTES;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_AKA_PRIME_IDENTITY_RESPONSE;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.ID_INT;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.IK_BYTES;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.IMSI;
-import static com.android.internal.net.eap.message.simaka.EapAkaTypeData.EAP_AKA_CHALLENGE;
-import static com.android.internal.net.eap.message.simaka.EapAkaTypeData.EAP_AKA_IDENTITY;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.AUTN_BYTES;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.MAC_BYTES;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.RAND_1_BYTES;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.RES_BYTES;
-
-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;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.net.eap.EapSessionConfig;
-
-import com.android.internal.net.eap.EapResult.EapResponse;
-import com.android.internal.net.eap.message.EapData;
-import com.android.internal.net.eap.message.EapMessage;
-import com.android.internal.net.eap.message.simaka.EapAkaPrimeTypeData;
-import com.android.internal.net.eap.message.simaka.EapAkaTypeData;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtAnyIdReq;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtAutn;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtKdf;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtKdfInput;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtMac;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtRandAka;
-import com.android.internal.net.eap.message.simaka.EapSimAkaTypeData.DecodeResult;
-import com.android.internal.net.eap.statemachine.EapAkaMethodStateMachine.ChallengeState.RandChallengeResult;
-import com.android.internal.net.eap.statemachine.EapAkaPrimeMethodStateMachine.ChallengeState;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.Arrays;
-
-public class EapAkaPrimeChallengeStateTest extends EapAkaPrimeStateTest {
- private static final String SERVER_NETWORK_NAME_STRING = "foo:bar:buzz";
- private static final byte[] SERVER_NETWORK_NAME =
- SERVER_NETWORK_NAME_STRING.getBytes(StandardCharsets.UTF_8);
- private static final String INCORRECT_NETWORK_NAME = "foo:buzz";
- private static final byte[] INCORRECT_SERVER_NETWORK_NAME =
- INCORRECT_NETWORK_NAME.getBytes(StandardCharsets.UTF_8);
- private static final int VALID_KDF = 1;
- private static final int INVALID_KDF = 10;
-
- 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;
-
- @Before
- public void setUp() {
- super.setUp();
-
- mState = mStateMachine.new ChallengeState();
- mStateMachine.transitionTo(mState);
- }
-
- @Test
- public void testTransitionWithEapIdentity() throws Exception {
- mStateMachine.transitionTo(mStateMachine.new CreatedState());
-
- EapData eapData = new EapData(EAP_TYPE_AKA_PRIME, DUMMY_EAP_TYPE_DATA);
- EapMessage eapMessage = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
-
- DecodeResult<EapAkaTypeData> decodeResult =
- new DecodeResult<>(new EapAkaPrimeTypeData(EAP_AKA_CHALLENGE, new ArrayList<>()));
- when(mMockTypeDataDecoder.decode(eq(DUMMY_EAP_TYPE_DATA))).thenReturn(decodeResult);
-
- mStateMachine.process(eapMessage);
-
- ChallengeState challengeState = (ChallengeState) mStateMachine.getState();
- assertArrayEquals(EAP_IDENTITY_BYTES, challengeState.mIdentity);
-
- // decode() is called in CreatedState and ChallengeState
- verify(mMockTypeDataDecoder, times(2)).decode(eq(DUMMY_EAP_TYPE_DATA));
- }
-
- @Test
- public void testTransitionWithEapAkaPrimeIdentity() throws Exception {
- mStateMachine.transitionTo(mStateMachine.new CreatedState());
-
- // Process AKA' Identity Request
- EapData eapData = new EapData(EAP_TYPE_AKA_PRIME, DUMMY_EAP_TYPE_DATA);
- EapMessage eapMessage = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
-
- DecodeResult<EapAkaTypeData> decodeResult =
- new DecodeResult<>(
- new EapAkaPrimeTypeData(EAP_AKA_IDENTITY, Arrays.asList(new AtAnyIdReq())));
- when(mMockTypeDataDecoder.decode(eq(DUMMY_EAP_TYPE_DATA))).thenReturn(decodeResult);
- when(mMockTelephonyManager.getSubscriberId()).thenReturn(IMSI);
-
- EapResponse eapResponse = (EapResponse) mStateMachine.process(eapMessage);
- assertArrayEquals(EAP_AKA_PRIME_IDENTITY_RESPONSE, eapResponse.packet);
-
- // decode() is called in CreatedState and IdentityState
- verify(mMockTypeDataDecoder, times(2)).decode(eq(DUMMY_EAP_TYPE_DATA));
- verify(mMockTelephonyManager).getSubscriberId();
-
- // Process AKA' Challenge Request
- decodeResult =
- new DecodeResult<>(new EapAkaPrimeTypeData(EAP_AKA_CHALLENGE, new ArrayList<>()));
- when(mMockTypeDataDecoder.decode(eq(DUMMY_EAP_TYPE_DATA))).thenReturn(decodeResult);
-
- mStateMachine.process(eapMessage);
-
- ChallengeState challengeState = (ChallengeState) mStateMachine.getState();
- assertArrayEquals(EAP_AKA_PRIME_IDENTITY_BYTES, challengeState.mIdentity);
-
- // decode() called again in IdentityState and ChallengeState
- verify(mMockTypeDataDecoder, times(4)).decode(eq(DUMMY_EAP_TYPE_DATA));
- }
-
- @Test
- public void testProcessMissingAtKdf() throws Exception {
- EapData eapData = new EapData(EAP_TYPE_AKA_PRIME, DUMMY_EAP_TYPE_DATA);
- EapMessage eapMessage = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
-
- AtRandAka atRandAka = new AtRandAka(RAND_1_BYTES);
- AtAutn atAutn = new AtAutn(AUTN_BYTES);
- AtMac atMac = new AtMac(MAC_BYTES);
- AtKdfInput atKdfInput = new AtKdfInput(0, SERVER_NETWORK_NAME);
-
- DecodeResult<EapAkaTypeData> decodeResult =
- new DecodeResult<>(
- new EapAkaPrimeTypeData(
- EAP_AKA_CHALLENGE,
- Arrays.asList(atRandAka, atAutn, atMac, atKdfInput)));
- when(mMockTypeDataDecoder.decode(eq(DUMMY_EAP_TYPE_DATA))).thenReturn(decodeResult);
-
- EapResponse eapResponse = (EapResponse) mStateMachine.process(eapMessage);
- assertArrayEquals(EAP_AKA_PRIME_AUTHENTICATION_REJECT, eapResponse.packet);
- verify(mMockTypeDataDecoder).decode(eq(DUMMY_EAP_TYPE_DATA));
- }
-
- @Test
- public void testProcessMissingAtKdfInput() throws Exception {
- EapData eapData = new EapData(EAP_TYPE_AKA_PRIME, DUMMY_EAP_TYPE_DATA);
- EapMessage eapMessage = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
-
- AtRandAka atRandAka = new AtRandAka(RAND_1_BYTES);
- AtAutn atAutn = new AtAutn(AUTN_BYTES);
- AtMac atMac = new AtMac(MAC_BYTES);
- AtKdf atKdf = new AtKdf(VALID_KDF);
-
- DecodeResult<EapAkaTypeData> decodeResult =
- new DecodeResult<>(
- new EapAkaPrimeTypeData(
- EAP_AKA_CHALLENGE, Arrays.asList(atRandAka, atAutn, atMac, atKdf)));
- when(mMockTypeDataDecoder.decode(eq(DUMMY_EAP_TYPE_DATA))).thenReturn(decodeResult);
-
- EapResponse eapResponse = (EapResponse) mStateMachine.process(eapMessage);
- assertArrayEquals(EAP_AKA_PRIME_AUTHENTICATION_REJECT, eapResponse.packet);
- verify(mMockTypeDataDecoder).decode(eq(DUMMY_EAP_TYPE_DATA));
- }
-
- @Test
- public void testProcessUnsupportedKdf() throws Exception {
- EapData eapData = new EapData(EAP_TYPE_AKA_PRIME, DUMMY_EAP_TYPE_DATA);
- EapMessage eapMessage = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
-
- AtRandAka atRandAka = new AtRandAka(RAND_1_BYTES);
- AtAutn atAutn = new AtAutn(AUTN_BYTES);
- AtMac atMac = new AtMac(MAC_BYTES);
- AtKdfInput atKdfInput = new AtKdfInput(0, SERVER_NETWORK_NAME);
- AtKdf atKdf = new AtKdf(INVALID_KDF);
-
- DecodeResult<EapAkaTypeData> decodeResult =
- new DecodeResult<>(
- new EapAkaPrimeTypeData(
- EAP_AKA_CHALLENGE,
- Arrays.asList(atRandAka, atAutn, atMac, atKdfInput, atKdf)));
- when(mMockTypeDataDecoder.decode(eq(DUMMY_EAP_TYPE_DATA))).thenReturn(decodeResult);
-
- EapResponse eapResponse = (EapResponse) mStateMachine.process(eapMessage);
- assertArrayEquals(EAP_AKA_PRIME_AUTHENTICATION_REJECT, eapResponse.packet);
- verify(mMockTypeDataDecoder).decode(eq(DUMMY_EAP_TYPE_DATA));
- }
-
- @Test
- public void testProcessIncorrectNetworkName() throws Exception {
- EapData eapData = new EapData(EAP_TYPE_AKA_PRIME, DUMMY_EAP_TYPE_DATA);
- EapMessage eapMessage = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
-
- AtRandAka atRandAka = new AtRandAka(RAND_1_BYTES);
- AtAutn atAutn = new AtAutn(AUTN_BYTES);
- AtMac atMac = new AtMac(MAC_BYTES);
- AtKdfInput atKdfInput = new AtKdfInput(0, INCORRECT_SERVER_NETWORK_NAME);
- AtKdf atKdf = new AtKdf(VALID_KDF);
-
- DecodeResult<EapAkaTypeData> decodeResult =
- new DecodeResult<>(
- new EapAkaPrimeTypeData(
- EAP_AKA_CHALLENGE,
- Arrays.asList(atRandAka, atAutn, atMac, atKdfInput, atKdf)));
- when(mMockTypeDataDecoder.decode(eq(DUMMY_EAP_TYPE_DATA))).thenReturn(decodeResult);
-
- EapResponse eapResponse = (EapResponse) mStateMachine.process(eapMessage);
- assertArrayEquals(EAP_AKA_PRIME_AUTHENTICATION_REJECT, eapResponse.packet);
- verify(mMockTypeDataDecoder).decode(eq(DUMMY_EAP_TYPE_DATA));
- }
-
- @Test
- public void testProcessIncorrectNetworkNameIsIgnored() throws Exception {
- // Create state machine with configs allowing invalid network name to be ignored
- mStateMachine =
- new EapAkaPrimeMethodStateMachine(
- mMockContext,
- EAP_IDENTITY_BYTES,
- new EapSessionConfig.EapAkaPrimeConfig(
- SUB_ID, APPTYPE_USIM, PEER_NETWORK_NAME, true),
- mMockTypeDataDecoder);
- mState = mStateMachine.new ChallengeState();
- mStateMachine.transitionTo(mState);
-
- AtRandAka atRandAka = new AtRandAka(RAND_1_BYTES);
- AtAutn atAutn = new AtAutn(AUTN_BYTES);
- AtMac atMac = new AtMac(MAC_BYTES);
- AtKdfInput atKdfInput = new AtKdfInput(0, INCORRECT_SERVER_NETWORK_NAME);
- AtKdf atKdf = new AtKdf(VALID_KDF);
-
- EapAkaPrimeTypeData eapAkaPrimeTypeData =
- new EapAkaPrimeTypeData(
- EAP_AKA_CHALLENGE,
- Arrays.asList(atRandAka, atAutn, atMac, atKdfInput, atKdf));
- assertTrue(
- "Incorrect network names should be ignored",
- mState.isValidChallengeAttributes(eapAkaPrimeTypeData));
- }
-
- @Test
- public void testHasMatchingNetworkNames() {
- // "" should match anything
- assertTrue(mState.hasMatchingNetworkNames("", SERVER_NETWORK_NAME_STRING));
- assertTrue(mState.hasMatchingNetworkNames(SERVER_NETWORK_NAME_STRING, ""));
-
- // "foo:bar" should match "foo:bar:buzz"
- assertTrue(mState.hasMatchingNetworkNames(PEER_NETWORK_NAME, SERVER_NETWORK_NAME_STRING));
- assertTrue(mState.hasMatchingNetworkNames(SERVER_NETWORK_NAME_STRING, PEER_NETWORK_NAME));
-
- // "foo:buzz" shouldn't match "foo:bar:buzz"
- assertFalse(
- mState.hasMatchingNetworkNames(SERVER_NETWORK_NAME_STRING, INCORRECT_NETWORK_NAME));
- assertFalse(
- mState.hasMatchingNetworkNames(INCORRECT_NETWORK_NAME, SERVER_NETWORK_NAME_STRING));
- }
-
- @Test
- public void testDeriveCkIkPrime() throws Exception {
- RandChallengeResult randChallengeResult =
- mState.new RandChallengeResult(RES_BYTES, IK_BYTES, CK_BYTES);
- AtKdfInput atKdfInput =
- new AtKdfInput(0, PEER_NETWORK_NAME.getBytes(StandardCharsets.UTF_8));
- AtAutn atAutn = new AtAutn(AUTN_BYTES);
-
- // S = FC | Network Name | len(Network Name) | SQN ^ AK | len(SQN ^ AK)
- // = 20666F6F3A62617200070123456789AB0006
- // K = CK | IK
- // = FFEEDDCCBBAA9988776655443322110000112233445566778899AABBCCDDEEFF
- // CK' | IK' = HMAC-SHA256(K, S)
- // = A0B37E7C7E9CC4F37A5C0AAA55DC87BE51FDA70A9D8F37E62E23B15F1B3941E6
- 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/internal/net/eap/statemachine/EapAkaPrimeCreatedStateTest.java b/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapAkaPrimeCreatedStateTest.java
deleted file mode 100644
index 90d0bf66..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapAkaPrimeCreatedStateTest.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.statemachine;
-
-import static com.android.internal.net.eap.message.EapData.EAP_TYPE_AKA_PRIME;
-import static com.android.internal.net.eap.message.EapMessage.EAP_CODE_REQUEST;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.ID_INT;
-import static com.android.internal.net.eap.message.simaka.EapAkaTypeData.EAP_AKA_CHALLENGE;
-import static com.android.internal.net.eap.message.simaka.EapAkaTypeData.EAP_AKA_IDENTITY;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-import com.android.internal.net.eap.message.EapData;
-import com.android.internal.net.eap.message.EapMessage;
-import com.android.internal.net.eap.message.simaka.EapAkaPrimeTypeData;
-import com.android.internal.net.eap.message.simaka.EapAkaTypeData;
-import com.android.internal.net.eap.message.simaka.EapSimAkaTypeData.DecodeResult;
-import com.android.internal.net.eap.statemachine.EapAkaPrimeMethodStateMachine.ChallengeState;
-
-import org.junit.Test;
-
-import java.util.ArrayList;
-
-public class EapAkaPrimeCreatedStateTest extends EapAkaPrimeStateTest {
- @Test
- public void testProcessTransitionToIdentityState() throws Exception {
- EapData eapData = new EapData(EAP_TYPE_AKA_PRIME, DUMMY_EAP_TYPE_DATA);
- EapMessage eapMessage = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
-
- // Don't actually need any attributes in the attributeMap, since we only care about the
- // state transition here.
- DecodeResult<EapAkaTypeData> decodeResult =
- new DecodeResult<>(new EapAkaPrimeTypeData(EAP_AKA_IDENTITY, new ArrayList<>()));
- when(mMockTypeDataDecoder.decode(eq(DUMMY_EAP_TYPE_DATA))).thenReturn(decodeResult);
-
- mStateMachine.process(eapMessage);
-
- assertTrue(mStateMachine.getState() instanceof EapAkaMethodStateMachine.IdentityState);
-
- // decoded in CreatedState and IdentityState
- verify(mMockTypeDataDecoder, times(2)).decode(eq(DUMMY_EAP_TYPE_DATA));
- verifyNoMoreInteractions(mMockTelephonyManager, mMockTypeDataDecoder);
- }
-
- @Test
- public void testProcessTransitionToChallengeState() throws Exception {
- EapData eapData = new EapData(EAP_TYPE_AKA_PRIME, DUMMY_EAP_TYPE_DATA);
- EapMessage eapMessage = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
-
- // Don't actually need any attributes in the attributeMap, since we only care about the
- // state transition here.
- DecodeResult<EapAkaTypeData> decodeResult =
- new DecodeResult<>(new EapAkaPrimeTypeData(EAP_AKA_CHALLENGE, new ArrayList<>()));
- when(mMockTypeDataDecoder.decode(eq(DUMMY_EAP_TYPE_DATA))).thenReturn(decodeResult);
-
- mStateMachine.process(eapMessage);
-
- ChallengeState challengeState = (ChallengeState) mStateMachine.getState();
- assertArrayEquals(EAP_IDENTITY_BYTES, challengeState.mIdentity);
-
- // decoded in CreatedState and ChallengeState
- verify(mMockTypeDataDecoder, times(2)).decode(DUMMY_EAP_TYPE_DATA);
- verifyNoMoreInteractions(mMockTelephonyManager, mMockTypeDataDecoder);
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapAkaPrimeIdentityStateTest.java b/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapAkaPrimeIdentityStateTest.java
deleted file mode 100644
index 73191fb0..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapAkaPrimeIdentityStateTest.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.statemachine;
-
-import static com.android.internal.net.eap.message.EapData.EAP_TYPE_AKA_PRIME;
-import static com.android.internal.net.eap.message.EapMessage.EAP_CODE_REQUEST;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_AKA_PRIME_IDENTITY_RESPONSE;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.ID_INT;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.IMSI;
-import static com.android.internal.net.eap.message.simaka.EapAkaTypeData.EAP_AKA_CHALLENGE;
-import static com.android.internal.net.eap.message.simaka.EapAkaTypeData.EAP_AKA_IDENTITY;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-import com.android.internal.net.eap.EapResult.EapResponse;
-import com.android.internal.net.eap.message.EapData;
-import com.android.internal.net.eap.message.EapMessage;
-import com.android.internal.net.eap.message.simaka.EapAkaPrimeTypeData;
-import com.android.internal.net.eap.message.simaka.EapAkaTypeData;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtAnyIdReq;
-import com.android.internal.net.eap.message.simaka.EapSimAkaTypeData.DecodeResult;
-import com.android.internal.net.eap.statemachine.EapAkaPrimeMethodStateMachine.ChallengeState;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-
-public class EapAkaPrimeIdentityStateTest extends EapAkaPrimeStateTest {
- @Before
- public void setUp() {
- super.setUp();
-
- mStateMachine.transitionTo(mStateMachine.new IdentityState());
- }
-
- @Test
- public void testProcessIdentityRequest() throws Exception {
- EapData eapData = new EapData(EAP_TYPE_AKA_PRIME, DUMMY_EAP_TYPE_DATA);
- EapMessage eapMessage = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
-
- DecodeResult<EapAkaTypeData> decodeResult =
- new DecodeResult<>(
- new EapAkaPrimeTypeData(EAP_AKA_IDENTITY, Arrays.asList(new AtAnyIdReq())));
- when(mMockTypeDataDecoder.decode(eq(DUMMY_EAP_TYPE_DATA))).thenReturn(decodeResult);
- when(mMockTelephonyManager.getSubscriberId()).thenReturn(IMSI);
-
- EapResponse eapResponse = (EapResponse) mStateMachine.process(eapMessage);
- assertArrayEquals(EAP_AKA_PRIME_IDENTITY_RESPONSE, eapResponse.packet);
-
- verify(mMockTypeDataDecoder).decode(eq(DUMMY_EAP_TYPE_DATA));
- verify(mMockTelephonyManager).getSubscriberId();
- verifyNoMoreInteractions(mMockTypeDataDecoder, mMockTelephonyManager);
- }
-
- @Test
- public void testProcessTransitionToChallengeState() throws Exception {
- EapData eapData = new EapData(EAP_TYPE_AKA_PRIME, DUMMY_EAP_TYPE_DATA);
- EapMessage eapMessage = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
-
- // Don't actually need any attributes in the attributeMap, since we only care about the
- // state transition here.
- DecodeResult<EapAkaTypeData> decodeResult =
- new DecodeResult<>(new EapAkaPrimeTypeData(EAP_AKA_CHALLENGE, new ArrayList<>()));
- when(mMockTypeDataDecoder.decode(eq(DUMMY_EAP_TYPE_DATA))).thenReturn(decodeResult);
-
- mStateMachine.process(eapMessage);
-
- assertTrue(mStateMachine.getState() instanceof ChallengeState);
-
- // decoded in IdentityState and ChallengeState
- verify(mMockTypeDataDecoder, times(2)).decode(DUMMY_EAP_TYPE_DATA);
- verifyNoMoreInteractions(mMockTelephonyManager, mMockTypeDataDecoder);
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapAkaPrimeMethodStateMachineTest.java b/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapAkaPrimeMethodStateMachineTest.java
deleted file mode 100644
index 125b3235..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapAkaPrimeMethodStateMachineTest.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.statemachine;
-
-import static com.android.internal.net.TestUtils.hexStringToByteArray;
-import static com.android.internal.net.eap.message.EapData.EAP_TYPE_AKA_PRIME;
-import static com.android.internal.net.eap.message.EapMessage.EAP_CODE_REQUEST;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.ID_INT;
-import static com.android.internal.net.eap.message.simaka.EapAkaTypeData.EAP_AKA_CHALLENGE;
-import static com.android.internal.net.eap.statemachine.EapAkaPrimeMethodStateMachine.K_AUT_LEN;
-import static com.android.internal.net.eap.statemachine.EapAkaPrimeMethodStateMachine.K_RE_LEN;
-import static com.android.internal.net.eap.statemachine.EapSimAkaMethodStateMachine.KEY_LEN;
-import static com.android.internal.net.eap.statemachine.EapSimAkaMethodStateMachine.SESSION_KEY_LENGTH;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import com.android.internal.net.eap.message.EapData;
-import com.android.internal.net.eap.message.EapMessage;
-import com.android.internal.net.eap.message.simaka.EapAkaPrimeTypeData;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtMac;
-import com.android.internal.net.eap.statemachine.EapAkaMethodStateMachine.CreatedState;
-
-import org.junit.Test;
-
-import java.util.Arrays;
-
-public class EapAkaPrimeMethodStateMachineTest extends EapAkaPrimeTest {
- private static final String TAG = EapAkaPrimeMethodStateMachineTest.class.getSimpleName();
- private static final byte[] K_AUT =
- hexStringToByteArray(
- "000102030405060708090A0B0C0D0E0F000102030405060708090A0B0C0D0E0F");
- private static final byte[] MAC = hexStringToByteArray("0322b08b59cae2df8f766162ac76f30b");
-
- @Test
- 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());
- }
-
- @Test
- public void testIsValidMacUsesHmacSha256() throws Exception {
- System.arraycopy(K_AUT, 0, mStateMachine.mKAut, 0, K_AUT.length);
-
- EapData eapData = new EapData(EAP_TYPE_AKA_PRIME, new byte[0]);
- EapMessage eapMessage = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
- EapAkaPrimeTypeData eapAkaPrimeTypeData =
- new EapAkaPrimeTypeData(EAP_AKA_CHALLENGE, Arrays.asList(new AtMac(MAC)));
-
- assertTrue(mStateMachine.isValidMac(TAG, eapMessage, eapAkaPrimeTypeData, new byte[0]));
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapAkaPrimeStateTest.java b/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapAkaPrimeStateTest.java
deleted file mode 100644
index 18fce265..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapAkaPrimeStateTest.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.statemachine;
-
-import static com.android.internal.net.eap.message.EapData.EAP_NOTIFICATION;
-import static com.android.internal.net.eap.message.EapData.EAP_TYPE_AKA_PRIME;
-import static com.android.internal.net.eap.message.EapMessage.EAP_CODE_FAILURE;
-import static com.android.internal.net.eap.message.EapMessage.EAP_CODE_REQUEST;
-import static com.android.internal.net.eap.message.EapMessage.EAP_CODE_SUCCESS;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_AKA_PRIME_CLIENT_ERROR_UNABLE_TO_PROCESS;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_RESPONSE_NOTIFICATION_PACKET;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.ID_INT;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-import com.android.internal.net.eap.EapResult;
-import com.android.internal.net.eap.EapResult.EapError;
-import com.android.internal.net.eap.EapResult.EapFailure;
-import com.android.internal.net.eap.EapResult.EapResponse;
-import com.android.internal.net.eap.exceptions.EapInvalidRequestException;
-import com.android.internal.net.eap.message.EapData;
-import com.android.internal.net.eap.message.EapMessage;
-import com.android.internal.net.eap.message.simaka.EapAkaTypeData;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtClientErrorCode;
-import com.android.internal.net.eap.message.simaka.EapSimAkaTypeData.DecodeResult;
-import com.android.internal.net.eap.statemachine.EapMethodStateMachine.EapMethodState;
-import com.android.internal.net.eap.statemachine.EapMethodStateMachine.FinalState;
-
-import org.junit.Test;
-
-public class EapAkaPrimeStateTest extends EapAkaPrimeTest {
- protected static final String NOTIFICATION_MESSAGE = "test";
-
- @Test
- public void testProcessNotification() throws Exception {
- EapData eapData = new EapData(EAP_NOTIFICATION, NOTIFICATION_MESSAGE.getBytes());
- EapMessage notification = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
- EapMethodState preNotification = (EapMethodState) mStateMachine.getState();
-
- EapResult result = mStateMachine.process(notification);
- assertEquals(preNotification, mStateMachine.getState());
- verifyNoMoreInteractions(mMockTelephonyManager, mMockTypeDataDecoder);
-
- EapResponse eapResponse = (EapResponse) result;
- assertArrayEquals(EAP_RESPONSE_NOTIFICATION_PACKET, eapResponse.packet);
- }
-
- @Test
- public void testProcessInvalidDecodeResult() throws Exception {
- EapData eapData = new EapData(EAP_TYPE_AKA_PRIME, DUMMY_EAP_TYPE_DATA);
- EapMessage eapMessage = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
- EapMethodState preProcess = (EapMethodState) mStateMachine.getState();
-
- AtClientErrorCode atClientErrorCode = AtClientErrorCode.UNABLE_TO_PROCESS;
- DecodeResult<EapAkaTypeData> decodeResult = new DecodeResult<>(atClientErrorCode);
- when(mMockTypeDataDecoder.decode(eq(DUMMY_EAP_TYPE_DATA))).thenReturn(decodeResult);
-
- EapResult result = mStateMachine.process(eapMessage);
- assertEquals(preProcess, mStateMachine.getState());
- verify(mMockTypeDataDecoder).decode(DUMMY_EAP_TYPE_DATA);
- verifyNoMoreInteractions(mMockTelephonyManager, mMockTypeDataDecoder);
-
- EapResponse eapResponse = (EapResponse) result;
- assertArrayEquals(EAP_AKA_PRIME_CLIENT_ERROR_UNABLE_TO_PROCESS, eapResponse.packet);
- }
-
- @Test
- public void testHandleEapFailure() throws Exception {
- EapResult result = mStateMachine.process(new EapMessage(EAP_CODE_FAILURE, ID_INT, null));
- assertTrue(result instanceof EapFailure);
- assertTrue(mStateMachine.getState() instanceof FinalState);
- }
-
- @Test
- public void testHandleEapSuccess() throws Exception {
- EapResult result = mStateMachine.process(new EapMessage(EAP_CODE_SUCCESS, ID_INT, null));
- EapError eapError = (EapError) result;
- assertTrue(eapError.cause instanceof EapInvalidRequestException);
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapAkaPrimeTest.java b/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapAkaPrimeTest.java
deleted file mode 100644
index 48371bbd..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapAkaPrimeTest.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.statemachine;
-
-import static android.telephony.TelephonyManager.APPTYPE_USIM;
-
-import static com.android.internal.net.TestUtils.hexStringToByteArray;
-
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.net.eap.EapSessionConfig.EapAkaPrimeConfig;
-import android.telephony.TelephonyManager;
-
-import com.android.internal.net.eap.message.simaka.EapAkaPrimeTypeData;
-
-import org.junit.Before;
-
-public class EapAkaPrimeTest {
-
- // newtork name example in RFC 5448#3.1
- protected static final int SUB_ID = 1;
- protected static final String PEER_NETWORK_NAME = "foo:bar";
- protected static final boolean ALLOW_MISMATCHED_NETWORK_NAMES = false;
- protected static final EapAkaPrimeConfig EAP_AKA_PRIME_CONFIG =
- new EapAkaPrimeConfig(
- SUB_ID, APPTYPE_USIM, PEER_NETWORK_NAME, ALLOW_MISMATCHED_NETWORK_NAMES);
- protected static final byte[] DUMMY_EAP_TYPE_DATA = hexStringToByteArray("112233445566");
-
- // EAP-Identity = hex("test@android.net")
- protected static final byte[] EAP_IDENTITY_BYTES =
- hexStringToByteArray("7465737440616E64726F69642E6E6574");
-
- protected Context mMockContext;
- protected TelephonyManager mMockTelephonyManager;
- protected EapAkaPrimeTypeData.EapAkaPrimeTypeDataDecoder mMockTypeDataDecoder;
-
- protected EapAkaPrimeMethodStateMachine mStateMachine;
-
- @Before
- public void setUp() {
- mMockContext = mock(Context.class);
- mMockTelephonyManager = mock(TelephonyManager.class);
- mMockTypeDataDecoder = mock(EapAkaPrimeTypeData.EapAkaPrimeTypeDataDecoder.class);
-
- when(mMockContext.getSystemService(eq(Context.TELEPHONY_SERVICE)))
- .thenReturn(mMockTelephonyManager);
- when(mMockTelephonyManager.createForSubscriptionId(SUB_ID))
- .thenReturn(mMockTelephonyManager);
-
- mStateMachine =
- new EapAkaPrimeMethodStateMachine(
- mMockContext,
- EAP_IDENTITY_BYTES,
- EAP_AKA_PRIME_CONFIG,
- mMockTypeDataDecoder);
-
- verify(mMockContext).getSystemService(eq(Context.TELEPHONY_SERVICE));
- verify(mMockTelephonyManager).createForSubscriptionId(SUB_ID);
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapAkaStateTest.java b/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapAkaStateTest.java
deleted file mode 100644
index 23b240b9..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapAkaStateTest.java
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.statemachine;
-
-import static android.telephony.TelephonyManager.APPTYPE_USIM;
-
-import static com.android.internal.net.TestUtils.hexStringToByteArray;
-import static com.android.internal.net.eap.message.EapData.EAP_NOTIFICATION;
-import static com.android.internal.net.eap.message.EapData.EAP_TYPE_AKA;
-import static com.android.internal.net.eap.message.EapMessage.EAP_CODE_REQUEST;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_AKA_CLIENT_ERROR_UNABLE_TO_PROCESS;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_AKA_NOTIFICATION_RESPONSE;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_RESPONSE_NOTIFICATION_PACKET;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.ID_INT;
-import static com.android.internal.net.eap.message.simaka.EapAkaTypeData.EAP_AKA_NOTIFICATION;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtNotification.GENERAL_FAILURE_PRE_CHALLENGE;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-import android.net.eap.EapSessionConfig.EapAkaConfig;
-import android.telephony.TelephonyManager;
-
-import com.android.internal.net.eap.EapResult;
-import com.android.internal.net.eap.EapResult.EapResponse;
-import com.android.internal.net.eap.message.EapData;
-import com.android.internal.net.eap.message.EapMessage;
-import com.android.internal.net.eap.message.simaka.EapAkaTypeData;
-import com.android.internal.net.eap.message.simaka.EapAkaTypeData.EapAkaTypeDataDecoder;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtClientErrorCode;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtNotification;
-import com.android.internal.net.eap.message.simaka.EapSimAkaTypeData.DecodeResult;
-import com.android.internal.net.eap.statemachine.EapMethodStateMachine.EapMethodState;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.util.Arrays;
-
-public class EapAkaStateTest {
- protected static final int SUB_ID = 1;
- protected static final String NOTIFICATION_MESSAGE = "test";
- protected static final byte[] DUMMY_EAP_TYPE_DATA = hexStringToByteArray("112233445566");
-
- // EAP-Identity = hex("test@android.net")
- protected static final byte[] EAP_IDENTITY_BYTES =
- hexStringToByteArray("7465737440616E64726F69642E6E6574");
-
- protected TelephonyManager mMockTelephonyManager;
- protected EapAkaTypeDataDecoder mMockEapAkaTypeDataDecoder;
-
- protected EapAkaConfig mEapAkaConfig = new EapAkaConfig(SUB_ID, APPTYPE_USIM);
- protected EapAkaMethodStateMachine mEapAkaMethodStateMachine;
-
- @Before
- public void setUp() {
- mMockTelephonyManager = mock(TelephonyManager.class);
- mMockEapAkaTypeDataDecoder = mock(EapAkaTypeDataDecoder.class);
-
- when(mMockTelephonyManager.createForSubscriptionId(SUB_ID))
- .thenReturn(mMockTelephonyManager);
-
- mEapAkaMethodStateMachine =
- new EapAkaMethodStateMachine(
- mMockTelephonyManager,
- EAP_IDENTITY_BYTES,
- mEapAkaConfig,
- mMockEapAkaTypeDataDecoder,
- true);
-
- verify(mMockTelephonyManager).createForSubscriptionId(SUB_ID);
- }
-
- @Test
- public void testProcessNotification() throws Exception {
- EapData eapData = new EapData(EAP_NOTIFICATION, NOTIFICATION_MESSAGE.getBytes());
- EapMessage notification = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
- EapMethodState preNotification = (EapMethodState) mEapAkaMethodStateMachine.getState();
-
- EapResult result = mEapAkaMethodStateMachine.process(notification);
- assertEquals(preNotification, mEapAkaMethodStateMachine.getState());
- verifyNoMoreInteractions(mMockTelephonyManager, mMockEapAkaTypeDataDecoder);
-
- assertTrue(result instanceof EapResult.EapResponse);
- EapResult.EapResponse eapResponse = (EapResult.EapResponse) result;
- assertArrayEquals(EAP_RESPONSE_NOTIFICATION_PACKET, eapResponse.packet);
- }
-
- @Test
- public void testProcessEapAkaNotification() throws Exception {
- EapData eapData = new EapData(EAP_TYPE_AKA, DUMMY_EAP_TYPE_DATA);
- EapMessage eapMessage = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
- EapMethodState preProcess = (EapMethodState) mEapAkaMethodStateMachine.getState();
- EapAkaTypeData typeData =
- new EapAkaTypeData(
- EAP_AKA_NOTIFICATION,
- Arrays.asList(new AtNotification(GENERAL_FAILURE_PRE_CHALLENGE)));
-
- DecodeResult<EapAkaTypeData> decodeResult = new DecodeResult<>(typeData);
- when(mMockEapAkaTypeDataDecoder.decode(eq(DUMMY_EAP_TYPE_DATA))).thenReturn(decodeResult);
-
- EapResponse eapResponse = (EapResponse) mEapAkaMethodStateMachine.process(eapMessage);
- assertArrayEquals(EAP_AKA_NOTIFICATION_RESPONSE, eapResponse.packet);
- assertEquals(preProcess, mEapAkaMethodStateMachine.getState());
- verify(mMockEapAkaTypeDataDecoder).decode(DUMMY_EAP_TYPE_DATA);
- verifyNoMoreInteractions(mMockTelephonyManager, mMockEapAkaTypeDataDecoder);
- }
-
- @Test
- public void testProcessInvalidDecodeResult() throws Exception {
- EapData eapData = new EapData(EAP_TYPE_AKA, DUMMY_EAP_TYPE_DATA);
- EapMessage eapMessage = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
- EapMethodState preProcess = (EapMethodState) mEapAkaMethodStateMachine.getState();
-
- AtClientErrorCode atClientErrorCode = AtClientErrorCode.UNABLE_TO_PROCESS;
- DecodeResult<EapAkaTypeData> decodeResult = new DecodeResult<>(atClientErrorCode);
- when(mMockEapAkaTypeDataDecoder.decode(eq(DUMMY_EAP_TYPE_DATA))).thenReturn(decodeResult);
-
- EapResult result = mEapAkaMethodStateMachine.process(eapMessage);
- assertEquals(preProcess, mEapAkaMethodStateMachine.getState());
- verify(mMockEapAkaTypeDataDecoder).decode(DUMMY_EAP_TYPE_DATA);
- verifyNoMoreInteractions(mMockTelephonyManager, mMockEapAkaTypeDataDecoder);
-
- EapResponse eapResponse = (EapResponse) result;
- assertArrayEquals(EAP_AKA_CLIENT_ERROR_UNABLE_TO_PROCESS, eapResponse.packet);
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapMsChapV2AwaitingEapSuccessStateTest.java b/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapMsChapV2AwaitingEapSuccessStateTest.java
deleted file mode 100644
index d4377cb6..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapMsChapV2AwaitingEapSuccessStateTest.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.statemachine;
-
-import static com.android.internal.net.eap.message.EapMessage.EAP_CODE_SUCCESS;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.ID_INT;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.MSCHAP_V2_MSK;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.MSCHAP_V2_NT_RESPONSE;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertTrue;
-
-import com.android.internal.net.eap.EapResult;
-import com.android.internal.net.eap.EapResult.EapSuccess;
-import com.android.internal.net.eap.message.EapMessage;
-import com.android.internal.net.eap.statemachine.EapMethodStateMachine.FinalState;
-
-import org.junit.Before;
-import org.junit.Test;
-
-public class EapMsChapV2AwaitingEapSuccessStateTest extends EapMsChapV2StateTest {
- @Before
- @Override
- public void setUp() {
- super.setUp();
-
- mStateMachine.transitionTo(
- mStateMachine.new AwaitingEapSuccessState(MSCHAP_V2_NT_RESPONSE));
- }
-
- @Test
- @Override
- public void testHandleEapSuccess() throws Exception {
- EapResult result = mStateMachine.process(new EapMessage(EAP_CODE_SUCCESS, ID_INT, null));
- EapSuccess eapSuccess = (EapSuccess) result;
- assertArrayEquals(MSCHAP_V2_MSK, eapSuccess.msk);
- assertArrayEquals(new byte[0], eapSuccess.emsk);
- assertTrue(mStateMachine.getState() instanceof FinalState);
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapMsChapV2ChallengeStateTest.java b/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapMsChapV2ChallengeStateTest.java
deleted file mode 100644
index ec442dab..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapMsChapV2ChallengeStateTest.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.statemachine;
-
-import static com.android.internal.net.eap.message.EapData.EAP_TYPE_MSCHAP_V2;
-import static com.android.internal.net.eap.message.EapMessage.EAP_CODE_REQUEST;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_MSCHAP_V2_CHALLENGE_RESPONSE;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.ID_INT;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.MSCHAP_V2_AUTHENTICATOR_CHALLENGE;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.MSCHAP_V2_ID_INT;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.MSCHAP_V2_PEER_CHALLENGE;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.SERVER_NAME_BYTES;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2TypeData.EapMsChapV2ChallengeRequest.TYPE_DATA_HEADER_SIZE;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2TypeData.EapMsChapV2ChallengeRequest.VALUE_SIZE;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import com.android.internal.net.eap.EapResult;
-import com.android.internal.net.eap.EapResult.EapError;
-import com.android.internal.net.eap.EapResult.EapResponse;
-import com.android.internal.net.eap.exceptions.mschapv2.EapMsChapV2ParsingException;
-import com.android.internal.net.eap.message.EapData;
-import com.android.internal.net.eap.message.EapMessage;
-import com.android.internal.net.eap.message.mschapv2.EapMsChapV2TypeData.EapMsChapV2ChallengeRequest;
-import com.android.internal.net.eap.message.mschapv2.EapMsChapV2TypeData.EapMsChapV2TypeDataDecoder.DecodeResult;
-import com.android.internal.net.eap.statemachine.EapMsChapV2MethodStateMachine.ValidateAuthenticatorState;
-
-import org.junit.Before;
-import org.junit.Test;
-
-public class EapMsChapV2ChallengeStateTest extends EapMsChapV2StateTest {
- @Before
- @Override
- public void setUp() {
- super.setUp();
-
- mStateMachine.transitionTo(mStateMachine.new ChallengeState());
- }
-
- @Test
- public void testProcessChallenge() throws Exception {
- EapData eapData = new EapData(EAP_TYPE_MSCHAP_V2, DUMMY_TYPE_DATA);
- EapMessage eapMessage = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
-
- EapMsChapV2ChallengeRequest challengeRequest =
- new EapMsChapV2ChallengeRequest(
- MSCHAP_V2_ID_INT,
- TYPE_DATA_HEADER_SIZE + VALUE_SIZE + SERVER_NAME_BYTES.length,
- MSCHAP_V2_AUTHENTICATOR_CHALLENGE,
- SERVER_NAME_BYTES);
- when(mMockTypeDataDecoder.decodeChallengeRequest(any(String.class), eq(DUMMY_TYPE_DATA)))
- .thenReturn(new DecodeResult<>(challengeRequest));
-
- doAnswer(invocation -> {
- byte[] dst = invocation.getArgument(0);
- System.arraycopy(MSCHAP_V2_PEER_CHALLENGE, 0, dst, 0, MSCHAP_V2_PEER_CHALLENGE.length);
- return null;
- }).when(mMockSecureRandom).nextBytes(eq(new byte[MSCHAP_V2_PEER_CHALLENGE.length]));
-
- EapResult result = mStateMachine.process(eapMessage);
- EapResponse eapResponse = (EapResponse) result;
- assertArrayEquals(EAP_MSCHAP_V2_CHALLENGE_RESPONSE, eapResponse.packet);
- assertTrue(mStateMachine.getState() instanceof ValidateAuthenticatorState);
- verify(mMockSecureRandom).nextBytes(any(byte[].class));
- verify(mMockTypeDataDecoder).decodeChallengeRequest(any(String.class), eq(DUMMY_TYPE_DATA));
- }
-
- @Test
- public void testIncorrectTypeData() throws Exception {
- EapData eapData = new EapData(EAP_TYPE_MSCHAP_V2, DUMMY_TYPE_DATA);
- EapMessage eapMessage = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
-
- when(mMockTypeDataDecoder.decodeChallengeRequest(any(String.class), eq(DUMMY_TYPE_DATA)))
- .thenReturn(
- new DecodeResult<>(
- new EapError(
- new EapMsChapV2ParsingException("incorrect type data"))));
-
- EapResult result = mStateMachine.process(eapMessage);
- EapError eapError = (EapError) result;
- assertTrue(eapError.cause instanceof EapMsChapV2ParsingException);
- verify(mMockTypeDataDecoder).decodeChallengeRequest(any(String.class), eq(DUMMY_TYPE_DATA));
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapMsChapV2CreatedStateTest.java b/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapMsChapV2CreatedStateTest.java
deleted file mode 100644
index 633e0ebd..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapMsChapV2CreatedStateTest.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.statemachine;
-
-import static com.android.internal.net.eap.message.EapData.EAP_TYPE_MSCHAP_V2;
-import static com.android.internal.net.eap.message.EapMessage.EAP_CODE_REQUEST;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.ID_INT;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.CHALLENGE_BYTES;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.SERVER_NAME_BYTES;
-
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import com.android.internal.net.eap.EapResult;
-import com.android.internal.net.eap.EapResult.EapError;
-import com.android.internal.net.eap.exceptions.mschapv2.EapMsChapV2ParsingException;
-import com.android.internal.net.eap.message.EapData;
-import com.android.internal.net.eap.message.EapMessage;
-import com.android.internal.net.eap.message.mschapv2.EapMsChapV2TypeData.EapMsChapV2ChallengeRequest;
-import com.android.internal.net.eap.message.mschapv2.EapMsChapV2TypeData.EapMsChapV2TypeDataDecoder.DecodeResult;
-import com.android.internal.net.eap.statemachine.EapMsChapV2MethodStateMachine.ValidateAuthenticatorState;
-
-import org.junit.Test;
-
-public class EapMsChapV2CreatedStateTest extends EapMsChapV2StateTest {
- @Test
- public void testProcessChallengeRequest() throws Exception {
- EapData eapData = new EapData(EAP_TYPE_MSCHAP_V2, DUMMY_TYPE_DATA);
- EapMessage eapMessage = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
-
- when(mMockTypeDataDecoder.decodeChallengeRequest(any(String.class), eq(DUMMY_TYPE_DATA)))
- .thenReturn(
- new DecodeResult<>(
- new EapMsChapV2ChallengeRequest(
- 0, 0, CHALLENGE_BYTES, SERVER_NAME_BYTES)));
-
- mStateMachine.process(eapMessage);
-
- assertTrue(mStateMachine.getState() instanceof ValidateAuthenticatorState);
- verify(mMockTypeDataDecoder, times(2))
- .decodeChallengeRequest(any(String.class), eq(DUMMY_TYPE_DATA));
- }
-
- @Test
- public void testIncorrectTypeData() throws Exception {
- EapData eapData = new EapData(EAP_TYPE_MSCHAP_V2, DUMMY_TYPE_DATA);
- EapMessage eapMessage = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
-
- when(mMockTypeDataDecoder.decodeChallengeRequest(
- eq(CREATED_STATE_TAG), eq(DUMMY_TYPE_DATA)))
- .thenReturn(
- new DecodeResult<>(
- new EapError(
- new EapMsChapV2ParsingException("incorrect type data"))));
-
- EapResult result = mStateMachine.process(eapMessage);
- EapError eapError = (EapError) result;
- assertTrue(eapError.cause instanceof EapMsChapV2ParsingException);
- verify(mMockTypeDataDecoder)
- .decodeChallengeRequest(eq(CREATED_STATE_TAG), eq(DUMMY_TYPE_DATA));
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapMsChapV2MethodStateMachineTest.java b/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapMsChapV2MethodStateMachineTest.java
deleted file mode 100644
index b24c3f82..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapMsChapV2MethodStateMachineTest.java
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.statemachine;
-
-import static com.android.internal.net.eap.message.EapData.EAP_TYPE_MSCHAP_V2;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.MSCHAP_V2_AUTHENTICATOR_CHALLENGE;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.MSCHAP_V2_AUTHENTICATOR_RESPONSE;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.MSCHAP_V2_CHALLENGE;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.MSCHAP_V2_MASTER_KEY;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.MSCHAP_V2_MSK;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.MSCHAP_V2_NT_RESPONSE;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.MSCHAP_V2_PASSWORD;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.MSCHAP_V2_PASSWORD_HASH;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.MSCHAP_V2_PASSWORD_HASH_HASH;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.MSCHAP_V2_PASSWORD_UTF_BYTES;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.MSCHAP_V2_PEER_CHALLENGE;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.MSCHAP_V2_RECEIVE_START_KEY;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.MSCHAP_V2_SEND_START_KEY;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.MSCHAP_V2_USERNAME;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.MSCHAP_V2_USERNAME_ASCII_BYTES;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import android.net.eap.EapSessionConfig.EapMsChapV2Config;
-
-import com.android.internal.net.eap.statemachine.EapMsChapV2MethodStateMachine.CreatedState;
-import com.android.internal.net.utils.Log;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.security.SecureRandom;
-
-public class EapMsChapV2MethodStateMachineTest {
- private EapMsChapV2Config mEapMsChapV2Config;
- private EapMsChapV2MethodStateMachine mStateMachine;
-
- @Before
- public void setUp() {
- mEapMsChapV2Config = new EapMsChapV2Config(MSCHAP_V2_USERNAME, MSCHAP_V2_PASSWORD);
- mStateMachine = new EapMsChapV2MethodStateMachine(mEapMsChapV2Config, new SecureRandom());
- }
-
- @Test
- public void testGetEapMethod() {
- assertEquals(EAP_TYPE_MSCHAP_V2, mStateMachine.getEapMethod());
- }
-
- @Test
- public void testStartsOnCreatedState() {
- assertTrue(mStateMachine.getState() instanceof CreatedState);
- }
-
- // Tests for MS CHAPv2 authentication utils. Test vectors from RFC 2759#9.2.
-
- @Test
- public void testUsernameToBytes() {
- assertArrayEquals(
- MSCHAP_V2_USERNAME_ASCII_BYTES,
- EapMsChapV2MethodStateMachine.usernameToBytes(MSCHAP_V2_USERNAME));
- }
-
- @Test
- public void testPasswordToBytes() {
- assertArrayEquals(
- MSCHAP_V2_PASSWORD_UTF_BYTES,
- EapMsChapV2MethodStateMachine.passwordToBytes(MSCHAP_V2_PASSWORD));
- }
-
- @Test
- public void testGenerateNtResponse() throws Exception {
- byte[] ntResponse =
- EapMsChapV2MethodStateMachine.generateNtResponse(
- MSCHAP_V2_AUTHENTICATOR_CHALLENGE,
- MSCHAP_V2_PEER_CHALLENGE,
- MSCHAP_V2_USERNAME,
- MSCHAP_V2_PASSWORD);
- assertArrayEquals(MSCHAP_V2_NT_RESPONSE, ntResponse);
- }
-
- @Test
- public void testChallengeHash() throws Exception {
- byte[] challenge =
- EapMsChapV2MethodStateMachine.challengeHash(
- MSCHAP_V2_PEER_CHALLENGE,
- MSCHAP_V2_AUTHENTICATOR_CHALLENGE,
- MSCHAP_V2_USERNAME);
- assertArrayEquals(MSCHAP_V2_CHALLENGE, challenge);
- }
-
- @Test
- public void testNtPasswordHash() {
- byte[] passwordHash = EapMsChapV2MethodStateMachine.ntPasswordHash(MSCHAP_V2_PASSWORD);
- assertArrayEquals(MSCHAP_V2_PASSWORD_HASH, passwordHash);
- }
-
- @Test
- public void testHashNtPasswordHash() {
- byte[] passwordHashHash =
- EapMsChapV2MethodStateMachine.hashNtPasswordHash(MSCHAP_V2_PASSWORD_HASH);
- assertArrayEquals(MSCHAP_V2_PASSWORD_HASH_HASH, passwordHashHash);
- }
-
- @Test
- public void testChallengeResponse() throws Exception {
- byte[] challengeResponse =
- EapMsChapV2MethodStateMachine.challengeResponse(
- MSCHAP_V2_CHALLENGE, MSCHAP_V2_PASSWORD_HASH);
- assertArrayEquals(MSCHAP_V2_NT_RESPONSE, challengeResponse);
- }
-
- @Test
- public void testGenerateAuthenticatorResponse() throws Exception {
- byte[] authenticatorResponse =
- EapMsChapV2MethodStateMachine.generateAuthenticatorResponse(
- MSCHAP_V2_PASSWORD,
- MSCHAP_V2_NT_RESPONSE,
- MSCHAP_V2_PEER_CHALLENGE,
- MSCHAP_V2_AUTHENTICATOR_CHALLENGE,
- MSCHAP_V2_USERNAME);
- assertArrayEquals(MSCHAP_V2_AUTHENTICATOR_RESPONSE, authenticatorResponse);
- }
-
- @Test
- public void testCheckAuthenticatorResponse() throws Exception {
- assertTrue(
- "AuthenticatorResponse didn't match computed response",
- EapMsChapV2MethodStateMachine.checkAuthenticatorResponse(
- MSCHAP_V2_PASSWORD,
- MSCHAP_V2_NT_RESPONSE,
- MSCHAP_V2_PEER_CHALLENGE,
- MSCHAP_V2_AUTHENTICATOR_CHALLENGE,
- MSCHAP_V2_USERNAME,
- MSCHAP_V2_AUTHENTICATOR_RESPONSE));
- }
-
- @Test
- public void testGetMasterKey() throws Exception {
- byte[] masterKey =
- EapMsChapV2MethodStateMachine.getMasterKey(
- MSCHAP_V2_PASSWORD_HASH_HASH, MSCHAP_V2_NT_RESPONSE);
- assertArrayEquals(MSCHAP_V2_MASTER_KEY, masterKey);
- }
-
- @Test
- public void testGetAsymmetricStartKeySendKey() throws Exception {
- byte[] startKey =
- EapMsChapV2MethodStateMachine.getAsymmetricStartKey(MSCHAP_V2_MASTER_KEY, true);
- assertArrayEquals(Log.byteArrayToHexString(startKey), MSCHAP_V2_SEND_START_KEY, startKey);
- }
-
- @Test
- public void testGetAsymmetricStartKeyReceiveKey() throws Exception {
- byte[] receiveKey =
- EapMsChapV2MethodStateMachine.getAsymmetricStartKey(MSCHAP_V2_MASTER_KEY, false);
- assertArrayEquals(MSCHAP_V2_RECEIVE_START_KEY, receiveKey);
- }
-
- @Test
- public void testGenerateMsk() throws Exception {
- byte[] msk =
- EapMsChapV2MethodStateMachine.generateMsk(
- MSCHAP_V2_PASSWORD, MSCHAP_V2_NT_RESPONSE);
- assertArrayEquals(MSCHAP_V2_MSK, msk);
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapMsChapV2StateTest.java b/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapMsChapV2StateTest.java
deleted file mode 100644
index 1e4a0c58..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapMsChapV2StateTest.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.statemachine;
-
-import static com.android.internal.net.TestUtils.hexStringToByteArray;
-import static com.android.internal.net.eap.message.EapData.EAP_NOTIFICATION;
-import static com.android.internal.net.eap.message.EapMessage.EAP_CODE_FAILURE;
-import static com.android.internal.net.eap.message.EapMessage.EAP_CODE_REQUEST;
-import static com.android.internal.net.eap.message.EapMessage.EAP_CODE_SUCCESS;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_RESPONSE_NOTIFICATION_PACKET;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.ID_INT;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.MSCHAP_V2_PASSWORD;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.MSCHAP_V2_USERNAME;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
-
-import android.net.eap.EapSessionConfig.EapMsChapV2Config;
-
-import com.android.internal.net.eap.EapResult;
-import com.android.internal.net.eap.EapResult.EapError;
-import com.android.internal.net.eap.EapResult.EapFailure;
-import com.android.internal.net.eap.EapResult.EapResponse;
-import com.android.internal.net.eap.exceptions.EapInvalidRequestException;
-import com.android.internal.net.eap.message.EapData;
-import com.android.internal.net.eap.message.EapMessage;
-import com.android.internal.net.eap.message.mschapv2.EapMsChapV2TypeData.EapMsChapV2TypeDataDecoder;
-import com.android.internal.net.eap.statemachine.EapMethodStateMachine.EapMethodState;
-import com.android.internal.net.eap.statemachine.EapMethodStateMachine.FinalState;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.security.SecureRandom;
-
-public class EapMsChapV2StateTest {
- protected static final String CREATED_STATE_TAG = "CreatedState";
- protected static final String NOTIFICATION_MESSAGE = "test";
- protected static final byte[] DUMMY_TYPE_DATA = hexStringToByteArray("00112233");
-
- protected SecureRandom mMockSecureRandom;
- protected EapMsChapV2TypeDataDecoder mMockTypeDataDecoder;
-
- protected EapMsChapV2Config mEapMsChapV2Config;
- protected EapMsChapV2MethodStateMachine mStateMachine;
-
- @Before
- public void setUp() {
- mMockSecureRandom = mock(SecureRandom.class);
- mMockTypeDataDecoder = mock(EapMsChapV2TypeDataDecoder.class);
-
- mEapMsChapV2Config = new EapMsChapV2Config(MSCHAP_V2_USERNAME, MSCHAP_V2_PASSWORD);
- mStateMachine =
- new EapMsChapV2MethodStateMachine(
- mEapMsChapV2Config, mMockSecureRandom, mMockTypeDataDecoder);
- }
-
- @Test
- public void testHandleEapFailure() throws Exception {
- EapResult result = mStateMachine.process(new EapMessage(EAP_CODE_FAILURE, ID_INT, null));
- assertTrue(result instanceof EapFailure);
- assertTrue(mStateMachine.getState() instanceof FinalState);
- }
-
- @Test
- public void testHandleEapSuccess() throws Exception {
- EapResult result = mStateMachine.process(new EapMessage(EAP_CODE_SUCCESS, ID_INT, null));
- EapError eapError = (EapError) result;
- assertTrue(eapError.cause instanceof EapInvalidRequestException);
- }
-
- @Test
- public void testHandleEapNotification() throws Exception {
- EapData eapData = new EapData(EAP_NOTIFICATION, NOTIFICATION_MESSAGE.getBytes());
- EapMessage notification = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
- EapMethodState preNotification = (EapMethodState) mStateMachine.getState();
-
- EapResult result = mStateMachine.process(notification);
- assertEquals(preNotification, mStateMachine.getState());
-
- EapResponse eapResponse = (EapResponse) result;
- assertArrayEquals(EAP_RESPONSE_NOTIFICATION_PACKET, eapResponse.packet);
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapMsChapV2ValidateAuthenticatorStateTest.java b/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapMsChapV2ValidateAuthenticatorStateTest.java
deleted file mode 100644
index dda7d5bc..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapMsChapV2ValidateAuthenticatorStateTest.java
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.statemachine;
-
-import static com.android.internal.net.eap.message.EapData.EAP_TYPE_MSCHAP_V2;
-import static com.android.internal.net.eap.message.EapMessage.EAP_CODE_REQUEST;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_MSCHAP_V2_FAILURE_RESPONSE;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_MSCHAP_V2_SUCCESS_RESPONSE;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.ID_INT;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.INVALID_AUTHENTICATOR_RESPONSE;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.MSCHAP_V2_AUTHENTICATOR_CHALLENGE;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.MSCHAP_V2_AUTHENTICATOR_RESPONSE;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.MSCHAP_V2_ID_INT;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.MSCHAP_V2_NT_RESPONSE;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.MSCHAP_V2_PEER_CHALLENGE;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.CHALLENGE_BYTES;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.ERROR_CODE;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.MESSAGE;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.PASSWORD_CHANGE_PROTOCOL;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2PacketDefinitions.RETRY_BIT;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2TypeData.EAP_MSCHAP_V2_FAILURE;
-import static com.android.internal.net.eap.message.mschapv2.EapMsChapV2TypeData.EAP_MSCHAP_V2_SUCCESS;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import com.android.internal.net.eap.EapResult;
-import com.android.internal.net.eap.EapResult.EapError;
-import com.android.internal.net.eap.EapResult.EapFailure;
-import com.android.internal.net.eap.EapResult.EapResponse;
-import com.android.internal.net.eap.exceptions.EapInvalidRequestException;
-import com.android.internal.net.eap.message.EapData;
-import com.android.internal.net.eap.message.EapMessage;
-import com.android.internal.net.eap.message.mschapv2.EapMsChapV2TypeData.EapMsChapV2FailureRequest;
-import com.android.internal.net.eap.message.mschapv2.EapMsChapV2TypeData.EapMsChapV2SuccessRequest;
-import com.android.internal.net.eap.message.mschapv2.EapMsChapV2TypeData.EapMsChapV2TypeDataDecoder.DecodeResult;
-import com.android.internal.net.eap.statemachine.EapMethodStateMachine.FinalState;
-import com.android.internal.net.eap.statemachine.EapMsChapV2MethodStateMachine.AwaitingEapFailureState;
-import com.android.internal.net.eap.statemachine.EapMsChapV2MethodStateMachine.AwaitingEapSuccessState;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.nio.BufferUnderflowException;
-
-public class EapMsChapV2ValidateAuthenticatorStateTest extends EapMsChapV2StateTest {
- private static final int INVALID_OP_CODE = -1;
-
- @Before
- @Override
- public void setUp() {
- super.setUp();
-
- mStateMachine.transitionTo(
- mStateMachine.new ValidateAuthenticatorState(
- MSCHAP_V2_AUTHENTICATOR_CHALLENGE,
- MSCHAP_V2_PEER_CHALLENGE,
- MSCHAP_V2_NT_RESPONSE));
- }
-
- @Test
- public void testProcessSuccessRequest() throws Exception {
- EapData eapData = new EapData(EAP_TYPE_MSCHAP_V2, DUMMY_TYPE_DATA);
- EapMessage eapMessage = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
-
- EapMsChapV2SuccessRequest successRequest =
- new EapMsChapV2SuccessRequest(
- MSCHAP_V2_ID_INT, 0, MSCHAP_V2_AUTHENTICATOR_RESPONSE, MESSAGE);
-
- when(mMockTypeDataDecoder.getOpCode(eq(DUMMY_TYPE_DATA))).thenReturn(EAP_MSCHAP_V2_SUCCESS);
- when(mMockTypeDataDecoder.decodeSuccessRequest(any(String.class), eq(DUMMY_TYPE_DATA)))
- .thenReturn(new DecodeResult<>(successRequest));
-
- EapResult result = mStateMachine.process(eapMessage);
- EapResponse eapResponse = (EapResponse) result;
- assertArrayEquals(EAP_MSCHAP_V2_SUCCESS_RESPONSE, eapResponse.packet);
- assertTrue(mStateMachine.getState() instanceof AwaitingEapSuccessState);
- verify(mMockTypeDataDecoder).getOpCode(eq(DUMMY_TYPE_DATA));
- verify(mMockTypeDataDecoder).decodeSuccessRequest(any(String.class), eq(DUMMY_TYPE_DATA));
- }
-
- @Test
- public void testProcessInvalidSuccessRequest() throws Exception {
- EapData eapData = new EapData(EAP_TYPE_MSCHAP_V2, DUMMY_TYPE_DATA);
- EapMessage eapMessage = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
-
- EapMsChapV2SuccessRequest successRequest =
- new EapMsChapV2SuccessRequest(
- MSCHAP_V2_ID_INT, 0, INVALID_AUTHENTICATOR_RESPONSE, MESSAGE);
-
- when(mMockTypeDataDecoder.getOpCode(eq(DUMMY_TYPE_DATA))).thenReturn(EAP_MSCHAP_V2_SUCCESS);
- when(mMockTypeDataDecoder.decodeSuccessRequest(any(String.class), eq(DUMMY_TYPE_DATA)))
- .thenReturn(new DecodeResult<>(successRequest));
-
- EapResult result = mStateMachine.process(eapMessage);
- assertTrue(result instanceof EapFailure);
- assertTrue(mStateMachine.getState() instanceof FinalState);
- verify(mMockTypeDataDecoder).getOpCode(eq(DUMMY_TYPE_DATA));
- verify(mMockTypeDataDecoder).decodeSuccessRequest(any(String.class), eq(DUMMY_TYPE_DATA));
- }
-
- @Test
- public void testProcessFailureRequest() throws Exception {
- EapData eapData = new EapData(EAP_TYPE_MSCHAP_V2, DUMMY_TYPE_DATA);
- EapMessage eapMessage = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
-
- EapMsChapV2FailureRequest failureRequest =
- new EapMsChapV2FailureRequest(
- MSCHAP_V2_ID_INT,
- 0,
- ERROR_CODE,
- RETRY_BIT,
- CHALLENGE_BYTES,
- PASSWORD_CHANGE_PROTOCOL,
- MESSAGE);
-
- when(mMockTypeDataDecoder.getOpCode(eq(DUMMY_TYPE_DATA))).thenReturn(EAP_MSCHAP_V2_FAILURE);
- when(mMockTypeDataDecoder.decodeFailureRequest(any(String.class), eq(DUMMY_TYPE_DATA)))
- .thenReturn(new DecodeResult<>(failureRequest));
-
- EapResult result = mStateMachine.process(eapMessage);
- EapResponse eapResponse = (EapResponse) result;
- assertArrayEquals(EAP_MSCHAP_V2_FAILURE_RESPONSE, eapResponse.packet);
- assertTrue(mStateMachine.getState() instanceof AwaitingEapFailureState);
- verify(mMockTypeDataDecoder).getOpCode(eq(DUMMY_TYPE_DATA));
- verify(mMockTypeDataDecoder).decodeFailureRequest(any(String.class), eq(DUMMY_TYPE_DATA));
- }
-
- @Test
- public void testProcessEmptyTypeData() throws Exception {
- EapData eapData = new EapData(EAP_TYPE_MSCHAP_V2, new byte[0]);
- EapMessage eapMessage = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
-
- when(mMockTypeDataDecoder.getOpCode(eq(new byte[0])))
- .thenThrow(new BufferUnderflowException());
-
- EapResult result = mStateMachine.process(eapMessage);
- EapError eapError = (EapError) result;
- assertTrue(eapError.cause instanceof BufferUnderflowException);
- verify(mMockTypeDataDecoder).getOpCode(eq(new byte[0]));
- }
-
- @Test
- public void testProcessInvalidPacket() throws Exception {
- EapData eapData = new EapData(EAP_TYPE_MSCHAP_V2, DUMMY_TYPE_DATA);
- EapMessage eapMessage = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
-
- when(mMockTypeDataDecoder.getOpCode(eq(DUMMY_TYPE_DATA))).thenReturn(INVALID_OP_CODE);
-
- EapResult result = mStateMachine.process(eapMessage);
- EapError eapError = (EapError) result;
- assertTrue(eapError.cause instanceof EapInvalidRequestException);
- verify(mMockTypeDataDecoder).getOpCode(eq(DUMMY_TYPE_DATA));
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapSimAkaMethodStateMachineTest.java b/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapSimAkaMethodStateMachineTest.java
deleted file mode 100644
index 7adc9f75..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapSimAkaMethodStateMachineTest.java
+++ /dev/null
@@ -1,475 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.statemachine;
-
-import static com.android.internal.net.TestUtils.hexStringToByteArray;
-import static com.android.internal.net.eap.message.EapData.EAP_TYPE_SIM;
-import static com.android.internal.net.eap.message.EapMessage.EAP_CODE_REQUEST;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.COMPUTED_MAC;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_SIM_CHALLENGE_RESPONSE_MAC_INPUT;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_SIM_CHALLENGE_RESPONSE_WITH_MAC;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_SIM_CLIENT_ERROR_RESPONSE;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_SIM_CLIENT_ERROR_UNABLE_TO_PROCESS;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_SIM_IDENTITY;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_SIM_NOTIFICATION_REQUEST_WITH_EMPTY_MAC;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_SIM_NOTIFICATION_RESPONSE;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_SIM_NOTIFICATION_RESPONSE_WITH_EMPTY_MAC;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_SIM_NOTIFICATION_RESPONSE_WITH_MAC;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_SIM_RESPONSE_PACKET;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EMSK;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EMSK_STRING;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.ID_INT;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.KC_1;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.KC_2;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.K_AUT;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.K_AUT_STRING;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.K_ENCR;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.K_ENCR_STRING;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.MAC_INPUT;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.MK;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.MSK;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.MSK_STRING;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.ORIGINAL_MAC;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.SRES_1;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.SRES_BYTES;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtNotification.GENERAL_FAILURE_POST_CHALLENGE;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtNotification.GENERAL_FAILURE_PRE_CHALLENGE;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_MAC;
-import static com.android.internal.net.eap.message.simaka.EapSimTypeData.EAP_SIM_CHALLENGE;
-import static com.android.internal.net.eap.message.simaka.EapSimTypeData.EAP_SIM_CLIENT_ERROR;
-import static com.android.internal.net.eap.message.simaka.EapSimTypeData.EAP_SIM_NOTIFICATION;
-import static com.android.internal.net.eap.message.simaka.EapSimTypeData.EAP_SIM_START;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.AT_IDENTITY;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.IDENTITY;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.NONCE_MT;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.NONCE_MT_STRING;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.RAND_1_BYTES;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.RAND_2_BYTES;
-import static com.android.internal.net.eap.statemachine.EapSimAkaMethodStateMachine.KEY_LEN;
-import static com.android.internal.net.eap.statemachine.EapSimAkaMethodStateMachine.MAC_ALGORITHM_STRING;
-import static com.android.internal.net.eap.statemachine.EapSimAkaMethodStateMachine.MASTER_KEY_GENERATION_ALG;
-import static com.android.internal.net.eap.statemachine.EapSimAkaMethodStateMachine.SESSION_KEY_LENGTH;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-import android.net.eap.EapSessionConfig.EapSimConfig;
-import android.telephony.TelephonyManager;
-
-import com.android.internal.net.eap.EapResult;
-import com.android.internal.net.eap.EapResult.EapError;
-import com.android.internal.net.eap.EapResult.EapResponse;
-import com.android.internal.net.eap.crypto.Fips186_2Prf;
-import com.android.internal.net.eap.exceptions.EapInvalidRequestException;
-import com.android.internal.net.eap.exceptions.simaka.EapSimAkaAuthenticationFailureException;
-import com.android.internal.net.eap.message.EapData;
-import com.android.internal.net.eap.message.EapMessage;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtClientErrorCode;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtIdentity;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtMac;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtNotification;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtRandSim;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtSelectedVersion;
-import com.android.internal.net.eap.message.simaka.EapSimAkaTypeData;
-import com.android.internal.net.eap.message.simaka.EapSimTypeData;
-import com.android.internal.net.eap.statemachine.EapMethodStateMachine.EapMethodState;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.security.MessageDigest;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-import javax.crypto.Mac;
-import javax.crypto.spec.SecretKeySpec;
-
-public class EapSimAkaMethodStateMachineTest {
- private static final String TAG = EapSimAkaMethodStateMachineTest.class.getSimpleName();
- private static final int SUB_ID = 1;
- private static final int AT_RAND_LEN = 36;
- private static final String VERSIONS_STRING = "0001";
- private static final String SELECTED_VERSION = "0001";
- private static final byte[] SHA_1_INPUT = hexStringToByteArray("0123456789ABCDEF");
- private static final byte[] FORMATTED_UICC_CHALLENGE =
- hexStringToByteArray("1000112233445566778899AABBCCDDEEFF");
- private static final String BASE_64_CHALLENGE = "EAARIjNEVWZ3iJmqu8zd7v8=";
- private static final String BASE_64_RESPONSE = "BBEiM0QIAQIDBAUGBwg=";
- private static final byte[] UICC_RESPONSE =
- hexStringToByteArray("04" + SRES_1 + "08" + KC_1);
-
- // EAP-Identity = hex("test@android.net")
- protected static final byte[] EAP_IDENTITY_BYTES =
- hexStringToByteArray("7465737440616E64726F69642E6E6574");
-
- // K_encr + K_aut + MSK + EMSK
- private static final int PRF_OUTPUT_BYTES = (2 * KEY_LEN) + (2 * SESSION_KEY_LENGTH);
-
- private TelephonyManager mMockTelephonyManager;
- private EapSimConfig mEapSimConfig;
- private EapSimAkaMethodStateMachine mStateMachine;
-
- @Before
- public void setUp() {
- mMockTelephonyManager = mock(TelephonyManager.class);
- mEapSimConfig = new EapSimConfig(SUB_ID, TelephonyManager.APPTYPE_USIM);
-
- mStateMachine =
- new EapSimAkaMethodStateMachine(
- mMockTelephonyManager, EAP_IDENTITY_BYTES, mEapSimConfig) {
- @Override
- EapSimAkaTypeData getEapSimAkaTypeData(AtClientErrorCode clientErrorCode) {
- return new EapSimTypeData(
- EAP_SIM_CLIENT_ERROR, Arrays.asList(clientErrorCode));
- }
-
- @Override
- EapSimAkaTypeData getEapSimAkaTypeData(
- int eapSubtype, List<EapSimAkaAttribute> attributes) {
- return new EapSimTypeData(eapSubtype, attributes);
- }
-
- @Override
- int getEapMethod() {
- return EAP_TYPE_SIM;
- }
- };
- mStateMachine = spy(mStateMachine);
- }
-
- @Test
- public void testBuildClientErrorResponse() {
- AtClientErrorCode errorCode = AtClientErrorCode.UNSUPPORTED_VERSION;
-
- EapResult result =
- mStateMachine.buildClientErrorResponse(ID_INT, EAP_TYPE_SIM, errorCode);
- assertTrue(result instanceof EapResult.EapResponse);
- EapResult.EapResponse eapResponse = (EapResult.EapResponse) result;
- assertArrayEquals(EAP_SIM_CLIENT_ERROR_RESPONSE, eapResponse.packet);
- }
-
- @Test
- public void testBuildResponseMessage() throws Exception {
- List<EapSimAkaAttribute> attributes = new ArrayList<>();
- attributes.add(new AtSelectedVersion(1));
- attributes.add(new AtIdentity(AT_IDENTITY.length, IDENTITY));
- int identifier = ID_INT;
-
- EapResult result =
- mStateMachine.buildResponseMessage(
- EAP_TYPE_SIM,
- EAP_SIM_START,
- identifier,
- attributes);
- assertTrue(result instanceof EapResult);
- EapResponse eapResponse = (EapResponse) result;
- assertArrayEquals(EAP_SIM_RESPONSE_PACKET, eapResponse.packet);
- }
-
- @Test
- public void testGenerateAndPersistKeys() {
- byte[] mkInput = hexStringToByteArray(
- EAP_SIM_IDENTITY
- + KC_1
- + KC_2
- + NONCE_MT_STRING
- + VERSIONS_STRING
- + SELECTED_VERSION);
- MessageDigest mockSha1 = mock(MessageDigest.class);
- when(mockSha1.digest(eq(mkInput))).thenReturn(MK);
-
- byte[] keys = hexStringToByteArray(K_ENCR_STRING + K_AUT_STRING + MSK_STRING + EMSK_STRING);
- Fips186_2Prf mockFips186_2Prf = mock(Fips186_2Prf.class);
- when(mockFips186_2Prf.getRandom(eq(MK), eq(PRF_OUTPUT_BYTES))).thenReturn(keys);
-
- mStateMachine.generateAndPersistKeys(TAG, mockSha1, mockFips186_2Prf, mkInput);
- assertArrayEquals(K_ENCR, mStateMachine.mKEncr);
- assertArrayEquals(K_AUT, mStateMachine.mKAut);
- assertArrayEquals(MSK, mStateMachine.mMsk);
- assertArrayEquals(EMSK, mStateMachine.mEmsk);
-
- verify(mockSha1).digest(eq(mkInput));
- verify(mockFips186_2Prf).getRandom(eq(MK), eq(PRF_OUTPUT_BYTES));
- verifyNoMoreInteractions(mockSha1, mockFips186_2Prf);
- }
-
- /**
- * Test that we can actually instantiate and use the SHA-1algorithm.
- */
- @Test
- public void testCreateSha1() throws Exception {
- MessageDigest sha1 = MessageDigest.getInstance(MASTER_KEY_GENERATION_ALG);
- byte[] sha1Result = sha1.digest(SHA_1_INPUT);
- assertFalse(Arrays.equals(SHA_1_INPUT, sha1Result));
- }
-
- /**
- * Test that we can actually instantiate and use the HMAC-SHA-1 algorithm.
- */
- @Test
- public void testCreateHmacSha1() throws Exception {
- Mac macAlgorithm = Mac.getInstance(MAC_ALGORITHM_STRING);
- macAlgorithm.init(new SecretKeySpec(K_AUT, MAC_ALGORITHM_STRING));
- byte[] mac = macAlgorithm.doFinal(MAC_INPUT);
- assertFalse(Arrays.equals(MAC_INPUT, mac));
- }
-
- @Test
- public void testProcessUiccAuthentication() throws Exception {
- when(mMockTelephonyManager
- .getIccAuthentication(
- TelephonyManager.APPTYPE_USIM,
- TelephonyManager.AUTHTYPE_EAP_AKA,
- BASE_64_CHALLENGE)).thenReturn(BASE_64_RESPONSE);
-
- byte[] result =
- mStateMachine.processUiccAuthentication(
- TAG,
- TelephonyManager.AUTHTYPE_EAP_AKA,
- FORMATTED_UICC_CHALLENGE);
-
- assertArrayEquals(UICC_RESPONSE, result);
- verify(mMockTelephonyManager)
- .getIccAuthentication(
- TelephonyManager.APPTYPE_USIM,
- TelephonyManager.AUTHTYPE_EAP_AKA,
- BASE_64_CHALLENGE);
- verifyNoMoreInteractions(mMockTelephonyManager);
- }
-
- @Test
- public void testProcessUiccAuthenticationNullResponse() throws Exception {
- when(mMockTelephonyManager
- .getIccAuthentication(
- TelephonyManager.APPTYPE_USIM,
- TelephonyManager.AUTHTYPE_EAP_AKA,
- BASE_64_CHALLENGE)).thenReturn(null);
-
- try {
- mStateMachine.processUiccAuthentication(
- TAG,
- TelephonyManager.AUTHTYPE_EAP_AKA,
- FORMATTED_UICC_CHALLENGE);
- fail("EapSimAkaAuthenticationFailureException expected for null TelMan response");
- } catch (EapSimAkaAuthenticationFailureException expected) {
- }
-
- verify(mMockTelephonyManager)
- .getIccAuthentication(
- TelephonyManager.APPTYPE_USIM,
- TelephonyManager.AUTHTYPE_EAP_AKA,
- BASE_64_CHALLENGE);
- verifyNoMoreInteractions(mMockTelephonyManager);
- }
-
- @Test
- public void testGetMac() throws Exception {
- AtMac atMac = new AtMac(ORIGINAL_MAC);
- AtRandSim atRandSim = new AtRandSim(AT_RAND_LEN, RAND_1_BYTES, RAND_2_BYTES);
- EapSimTypeData eapSimTypeData =
- new EapSimTypeData(EAP_SIM_CHALLENGE, Arrays.asList(atRandSim, atMac));
-
- Mac mockMac = mock(Mac.class);
- when(mockMac.doFinal(eq(MAC_INPUT))).thenReturn(COMPUTED_MAC);
- mStateMachine.mMacAlgorithm = mockMac;
-
- byte[] mac = mStateMachine.getMac(EAP_CODE_REQUEST, ID_INT, eapSimTypeData, NONCE_MT);
- assertArrayEquals(COMPUTED_MAC, mac);
- AtMac postCalculationAtMac = (AtMac) eapSimTypeData.attributeMap.get(EAP_AT_MAC);
- assertArrayEquals(ORIGINAL_MAC, postCalculationAtMac.mac);
-
- verify(mockMac).doFinal(eq(MAC_INPUT));
- verifyNoMoreInteractions(mockMac);
- }
-
- @Test
- public void testGetMacNoMacAlgorithm() throws Exception {
- try {
- mStateMachine.getMac(EAP_CODE_REQUEST, ID_INT, null, null);
- fail("Expected IllegalStateException if Mac not set");
- } catch (IllegalStateException expected) {
- }
- }
-
- @Test
- public void testReceivedValidMac() throws Exception {
- AtMac atMac = new AtMac(ORIGINAL_MAC);
- AtRandSim atRandSim = new AtRandSim(AT_RAND_LEN, RAND_1_BYTES, RAND_2_BYTES);
- EapSimTypeData eapSimTypeData =
- new EapSimTypeData(EAP_SIM_CHALLENGE, Arrays.asList(atRandSim, atMac));
- EapData eapData = new EapData(EAP_TYPE_SIM, new byte[0]);
- EapMessage message = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
-
- doReturn(ORIGINAL_MAC)
- .when(mStateMachine)
- .getMac(eq(EAP_CODE_REQUEST), eq(ID_INT), eq(eapSimTypeData), eq(NONCE_MT));
-
- assertTrue(mStateMachine.isValidMac(TAG, message, eapSimTypeData, NONCE_MT));
-
- doReturn(new byte[0])
- .when(mStateMachine)
- .getMac(eq(EAP_CODE_REQUEST), eq(ID_INT), eq(eapSimTypeData), eq(NONCE_MT));
-
- assertFalse(mStateMachine.isValidMac(TAG, message, eapSimTypeData, NONCE_MT));
-
- verify(mStateMachine, times(2))
- .getMac(eq(EAP_CODE_REQUEST), eq(ID_INT), eq(eapSimTypeData), eq(NONCE_MT));
- }
-
- @Test
- public void testBuildResponseMessageWithMac() {
- Mac mockMac = mock(Mac.class);
- when(mockMac.doFinal(eq(EAP_SIM_CHALLENGE_RESPONSE_MAC_INPUT))).thenReturn(COMPUTED_MAC);
- mStateMachine.mMacAlgorithm = mockMac;
-
- EapResult result =
- mStateMachine.buildResponseMessageWithMac(ID_INT, EAP_SIM_CHALLENGE, SRES_BYTES);
-
- EapResponse eapResponse = (EapResponse) result;
- assertArrayEquals(EAP_SIM_CHALLENGE_RESPONSE_WITH_MAC, eapResponse.packet);
- verify(mockMac).doFinal(eq(EAP_SIM_CHALLENGE_RESPONSE_MAC_INPUT));
- verifyNoMoreInteractions(mockMac);
- }
-
- @Test
- public void testHandleEapSimNotificationPreChallenge() throws Exception {
- EapSimTypeData typeData =
- new EapSimTypeData(
- EAP_SIM_NOTIFICATION,
- Arrays.asList(new AtNotification(GENERAL_FAILURE_PRE_CHALLENGE)));
-
- EapResponse eapResponse =
- (EapResponse)
- mStateMachine.handleEapSimAkaNotification(TAG, true, ID_INT, typeData);
- assertArrayEquals(EAP_SIM_NOTIFICATION_RESPONSE, eapResponse.packet);
- assertTrue(mStateMachine.mHasReceivedSimAkaNotification);
- verify(mStateMachine, never()).transitionTo(any(EapMethodState.class));
- }
-
- @Test
- public void testHandleEapSimNotificationPreChallengeInvalidPBit() throws Exception {
- EapSimTypeData typeData =
- new EapSimTypeData(
- EAP_SIM_NOTIFICATION,
- Arrays.asList(new AtNotification(GENERAL_FAILURE_POST_CHALLENGE)));
-
- EapResponse eapResponse =
- (EapResponse)
- mStateMachine.handleEapSimAkaNotification(TAG, true, ID_INT, typeData);
- assertArrayEquals(EAP_SIM_CLIENT_ERROR_UNABLE_TO_PROCESS, eapResponse.packet);
- verify(mStateMachine, never())
- .transitionTo(any(EapMethodStateMachine.EapMethodState.class));
- }
-
- @Test
- public void testHandleEapSimNotificationMultipleNotifications() throws Exception {
- EapSimTypeData typeData =
- new EapSimTypeData(
- EAP_SIM_NOTIFICATION,
- Arrays.asList(new AtNotification(GENERAL_FAILURE_PRE_CHALLENGE)));
-
- mStateMachine.handleEapSimAkaNotification(TAG, true, ID_INT, typeData);
-
- EapError eapError =
- (EapError) mStateMachine.handleEapSimAkaNotification(TAG, true, ID_INT, typeData);
- assertTrue(eapError.cause instanceof EapInvalidRequestException);
- assertTrue(mStateMachine.mHasReceivedSimAkaNotification);
- verify(mStateMachine, never())
- .transitionTo(any(EapMethodStateMachine.EapMethodState.class));
- }
-
- @Test
- public void testHandleEapSimNotificationInvalidAtMac() throws Exception {
- EapSimTypeData typeData =
- new EapSimTypeData(
- EAP_SIM_NOTIFICATION,
- Arrays.asList(
- new AtNotification(GENERAL_FAILURE_PRE_CHALLENGE), new AtMac()));
-
- EapResponse eapResponse =
- (EapResponse)
- mStateMachine.handleEapSimAkaNotification(TAG, true, ID_INT, typeData);
- assertArrayEquals(EAP_SIM_CLIENT_ERROR_UNABLE_TO_PROCESS, eapResponse.packet);
- verify(mStateMachine, never())
- .transitionTo(any(EapMethodStateMachine.EapMethodState.class));
- }
-
- @Test
- public void testHandleEapSimNotificationPostChallenge() throws Exception {
- EapSimTypeData typeData =
- new EapSimTypeData(
- EAP_SIM_NOTIFICATION,
- Arrays.asList(
- new AtNotification(GENERAL_FAILURE_POST_CHALLENGE),
- new AtMac(ORIGINAL_MAC)));
-
- Mac mockMac = mock(Mac.class);
- when(mockMac.doFinal(eq(EAP_SIM_NOTIFICATION_REQUEST_WITH_EMPTY_MAC)))
- .thenReturn(ORIGINAL_MAC);
- when(mockMac.doFinal(eq(EAP_SIM_NOTIFICATION_RESPONSE_WITH_EMPTY_MAC)))
- .thenReturn(COMPUTED_MAC);
- mStateMachine.mMacAlgorithm = mockMac;
-
- EapResponse eapResponse =
- (EapResponse)
- mStateMachine.handleEapSimAkaNotification(TAG, false, ID_INT, typeData);
- assertArrayEquals(EAP_SIM_NOTIFICATION_RESPONSE_WITH_MAC, eapResponse.packet);
- assertTrue(mStateMachine.mHasReceivedSimAkaNotification);
- verify(mStateMachine, never()).transitionTo(any(EapMethodState.class));
-
- verify(mockMac).doFinal(eq(EAP_SIM_NOTIFICATION_REQUEST_WITH_EMPTY_MAC));
- verify(mockMac).doFinal(eq(EAP_SIM_NOTIFICATION_RESPONSE_WITH_EMPTY_MAC));
- verifyNoMoreInteractions(mockMac);
- }
-
- @Test
- public void testHandleEapSimNotificationPostChallengeInvalidAtMac() throws Exception {
- EapSimTypeData typeData =
- new EapSimTypeData(
- EAP_SIM_NOTIFICATION,
- Arrays.asList(new AtNotification(GENERAL_FAILURE_POST_CHALLENGE)));
-
- EapResponse eapResponse =
- (EapResponse)
- mStateMachine.handleEapSimAkaNotification(TAG, false, ID_INT, typeData);
- assertArrayEquals(EAP_SIM_CLIENT_ERROR_UNABLE_TO_PROCESS, eapResponse.packet);
- verify(mStateMachine, never()).transitionTo(any(EapMethodState.class));
- }
-
- @Test
- public void testKeyLengths() {
- assertEquals(KEY_LEN, mStateMachine.getKEncrLength());
- assertEquals(KEY_LEN, mStateMachine.getKAutLength());
- assertEquals(SESSION_KEY_LENGTH, mStateMachine.getMskLength());
- assertEquals(SESSION_KEY_LENGTH, mStateMachine.getEmskLength());
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapSimChallengeStateTest.java b/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapSimChallengeStateTest.java
deleted file mode 100644
index bffc03ab..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapSimChallengeStateTest.java
+++ /dev/null
@@ -1,356 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.statemachine;
-
-import static com.android.internal.net.TestUtils.hexStringToByteArray;
-import static com.android.internal.net.eap.message.EapData.EAP_IDENTITY;
-import static com.android.internal.net.eap.message.EapData.EAP_TYPE_SIM;
-import static com.android.internal.net.eap.message.EapMessage.EAP_CODE_FAILURE;
-import static com.android.internal.net.eap.message.EapMessage.EAP_CODE_REQUEST;
-import static com.android.internal.net.eap.message.EapMessage.EAP_CODE_SUCCESS;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.CHALLENGE_RESPONSE_INVALID_KC;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.CHALLENGE_RESPONSE_INVALID_SRES;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_SIM_IDENTITY_BYTES;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EMSK;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.ID_INT;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.KC_1_BYTES;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.KC_2_BYTES;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.MSK;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.SRES_1_BYTES;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.SRES_2_BYTES;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.VALID_CHALLENGE_RESPONSE;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_MAC;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_RAND;
-import static com.android.internal.net.eap.message.simaka.EapSimTypeData.EAP_SIM_CHALLENGE;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.NONCE_MT;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.RAND_1;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.RAND_1_BYTES;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.RAND_2;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.RAND_2_BYTES;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-import android.telephony.TelephonyManager;
-
-import com.android.internal.net.eap.EapResult;
-import com.android.internal.net.eap.EapResult.EapError;
-import com.android.internal.net.eap.EapResult.EapFailure;
-import com.android.internal.net.eap.EapResult.EapSuccess;
-import com.android.internal.net.eap.exceptions.EapInvalidRequestException;
-import com.android.internal.net.eap.exceptions.simaka.EapSimAkaAuthenticationFailureException;
-import com.android.internal.net.eap.exceptions.simaka.EapSimAkaInvalidAttributeException;
-import com.android.internal.net.eap.exceptions.simaka.EapSimAkaInvalidLengthException;
-import com.android.internal.net.eap.message.EapData;
-import com.android.internal.net.eap.message.EapMessage;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtMac;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtNonceMt;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtRandSim;
-import com.android.internal.net.eap.message.simaka.EapSimAkaTypeData.DecodeResult;
-import com.android.internal.net.eap.message.simaka.EapSimTypeData;
-import com.android.internal.net.eap.statemachine.EapMethodStateMachine.FinalState;
-import com.android.internal.net.eap.statemachine.EapSimMethodStateMachine.ChallengeState;
-import com.android.internal.net.eap.statemachine.EapSimMethodStateMachine.ChallengeState.RandChallengeResult;
-
-import org.junit.Test;
-
-import java.nio.BufferUnderflowException;
-import java.util.Arrays;
-import java.util.LinkedHashMap;
-import java.util.List;
-
-public class EapSimChallengeStateTest extends EapSimStateTest {
- private static final int VALID_SRES_LENGTH = 4;
- private static final int INVALID_SRES_LENGTH = 5;
- private static final int VALID_KC_LENGTH = 8;
- private static final int INVALID_KC_LENGTH = 9;
- private static final int AT_RAND_LENGTH = 36;
- private static final List<Integer> VERSIONS = Arrays.asList(1);
-
- // Base64 of {@link EapTestAttributeDefinitions#RAND_1}
- private static final String BASE_64_RAND_1 = "EAARIjNEVWZ3iJmqu8zd7v8=";
-
- // Base64 of {@link EapTestAttributeDefinitions#RAND_2}
- private static final String BASE_64_RAND_2 = "EP/u3cy7qpmId2ZVRDMiEQA=";
-
- // Base64 of "04" + SRES_1 + "08" + KC_1
- private static final String BASE_64_RESP_1 = "BBEiM0QIAQIDBAUGBwg=";
-
- // Base64 of "04" + SRES_2 + "08" + KC_2
- private static final String BASE_64_RESP_2 = "BEQzIhEICAcGBQQDAgE=";
-
- // Base64 of "04" + SRES_1 + '081122"
- private static final String BASE_64_INVALID_RESP = "BBEiM0QIESI=";
-
- private AtNonceMt mAtNonceMt;
- private ChallengeState mChallengeState;
-
- @Override
- public void setUp() {
- super.setUp();
-
- try {
- mAtNonceMt = new AtNonceMt(NONCE_MT);
- } catch (EapSimAkaInvalidAttributeException ex) {
- // this will never happen
- }
- mChallengeState = mEapSimMethodStateMachine
- .new ChallengeState(VERSIONS, mAtNonceMt, EAP_SIM_IDENTITY_BYTES);
- mEapSimMethodStateMachine.transitionTo(mChallengeState);
- }
-
- @Test
- public void testProcessIncorrectEapMethodType() throws Exception {
- EapData eapData = new EapData(EAP_IDENTITY, DUMMY_EAP_TYPE_DATA);
- EapMessage eapMessage = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
-
- EapResult result = mChallengeState.process(eapMessage);
- EapError eapError = (EapError) result;
- assertTrue(eapError.cause instanceof EapInvalidRequestException);
- }
-
- @Test
- public void testProcessSuccess() throws Exception {
- System.arraycopy(MSK, 0, mEapSimMethodStateMachine.mMsk, 0, MSK.length);
- System.arraycopy(EMSK, 0, mEapSimMethodStateMachine.mEmsk, 0, EMSK.length);
-
- EapMessage input = new EapMessage(EAP_CODE_SUCCESS, ID_INT, null);
- EapResult result = mEapSimMethodStateMachine.process(input);
- assertTrue(mEapSimMethodStateMachine.getState() instanceof FinalState);
-
- EapSuccess eapSuccess = (EapSuccess) result;
- assertArrayEquals(MSK, eapSuccess.msk);
- assertArrayEquals(EMSK, eapSuccess.emsk);
- }
-
- @Test
- public void testProcessFailure() throws Exception {
- EapMessage input = new EapMessage(EAP_CODE_FAILURE, ID_INT, null);
- EapResult result = mEapSimMethodStateMachine.process(input);
- assertTrue(mEapSimMethodStateMachine.getState() instanceof FinalState);
-
- assertTrue(result instanceof EapFailure);
- }
-
- @Test
- public void testIsValidChallengeAttributes() {
- LinkedHashMap<Integer, EapSimAkaAttribute> attributeMap = new LinkedHashMap<>();
- EapSimTypeData eapSimTypeData = new EapSimTypeData(EAP_SIM_CHALLENGE, attributeMap);
- assertFalse(mChallengeState.isValidChallengeAttributes(eapSimTypeData));
-
- attributeMap.put(EAP_AT_RAND, null); // value doesn't matter, just need key
- eapSimTypeData = new EapSimTypeData(EAP_SIM_CHALLENGE, attributeMap);
- assertFalse(mChallengeState.isValidChallengeAttributes(eapSimTypeData));
-
- attributeMap.put(EAP_AT_MAC, null); // value doesn't matter, just need key
- eapSimTypeData = new EapSimTypeData(EAP_SIM_CHALLENGE, attributeMap);
- assertTrue(mChallengeState.isValidChallengeAttributes(eapSimTypeData));
- }
-
- @Test
- public void testRandChallengeResultConstructor() {
- try {
- mChallengeState.new RandChallengeResult(
- new byte[VALID_SRES_LENGTH], new byte[INVALID_KC_LENGTH]);
- fail("EapSimAkaInvalidLengthException expected for invalid SRES lengths");
- } catch (EapSimAkaInvalidLengthException expected) {
- }
-
- try {
- mChallengeState.new RandChallengeResult(
- new byte[INVALID_SRES_LENGTH], new byte[VALID_KC_LENGTH]);
- fail("EapSimAkaInvalidLengthException expected for invalid Kc lengths");
- } catch (EapSimAkaInvalidLengthException expected) {
- }
- }
-
- @Test
- public void testRandChallengeResultEquals() throws Exception {
- RandChallengeResult resultA =
- mChallengeState.new RandChallengeResult(SRES_1_BYTES, KC_1_BYTES);
- RandChallengeResult resultB =
- mChallengeState.new RandChallengeResult(SRES_1_BYTES, KC_1_BYTES);
- RandChallengeResult resultC =
- mChallengeState.new RandChallengeResult(SRES_2_BYTES, KC_2_BYTES);
-
- assertEquals(resultA, resultB);
- assertNotEquals(resultA, resultC);
- }
-
- @Test
- public void testRandChallengeResultHashCode() throws Exception {
- RandChallengeResult resultA =
- mChallengeState.new RandChallengeResult(SRES_1_BYTES, KC_1_BYTES);
- RandChallengeResult resultB =
- mChallengeState.new RandChallengeResult(SRES_1_BYTES, KC_1_BYTES);
- RandChallengeResult resultC =
- mChallengeState.new RandChallengeResult(SRES_2_BYTES, KC_2_BYTES);
-
- assertEquals(resultA.hashCode(), resultB.hashCode());
- assertNotEquals(resultA.hashCode(), resultC.hashCode());
- }
-
- @Test
- public void testGetRandChallengeResultFromResponse() throws Exception {
- RandChallengeResult result =
- mChallengeState.getRandChallengeResultFromResponse(VALID_CHALLENGE_RESPONSE);
-
- assertArrayEquals(SRES_1_BYTES, result.sres);
- assertArrayEquals(KC_1_BYTES, result.kc);
- }
-
- @Test
- public void testGetRandChallengeResultFromResponseInvalidSres() {
- try {
- mChallengeState.getRandChallengeResultFromResponse(CHALLENGE_RESPONSE_INVALID_SRES);
- fail("EapSimAkaInvalidLengthException expected for invalid SRES_1 length");
- } catch (EapSimAkaInvalidLengthException expected) {
- }
- }
-
- @Test
- public void testGetRandChallengeResultFromResponseInvalidKc() {
- try {
- mChallengeState.getRandChallengeResultFromResponse(CHALLENGE_RESPONSE_INVALID_KC);
- fail("EapSimAkaInvalidLengthException expected for invalid KC length");
- } catch (EapSimAkaInvalidLengthException expected) {
- }
- }
-
- @Test
- public void testGetRandChallengeResults() throws Exception {
- EapSimTypeData eapSimTypeData =
- new EapSimTypeData(EAP_SIM_CHALLENGE, Arrays.asList(
- new AtRandSim(AT_RAND_LENGTH,
- hexStringToByteArray(RAND_1),
- hexStringToByteArray(RAND_2))));
-
- when(mMockTelephonyManager
- .getIccAuthentication(
- TelephonyManager.APPTYPE_USIM,
- TelephonyManager.AUTHTYPE_EAP_SIM,
- BASE_64_RAND_1))
- .thenReturn(BASE_64_RESP_1);
- when(mMockTelephonyManager
- .getIccAuthentication(
- TelephonyManager.APPTYPE_USIM,
- TelephonyManager.AUTHTYPE_EAP_SIM,
- BASE_64_RAND_2))
- .thenReturn(BASE_64_RESP_2);
-
- List<RandChallengeResult> actualResult =
- mChallengeState.getRandChallengeResults(eapSimTypeData);
-
- List<RandChallengeResult> expectedResult = Arrays.asList(
- mChallengeState.new RandChallengeResult(SRES_1_BYTES, KC_1_BYTES),
- mChallengeState.new RandChallengeResult(SRES_2_BYTES, KC_2_BYTES));
- assertEquals(expectedResult, actualResult);
-
- verify(mMockTelephonyManager)
- .getIccAuthentication(
- TelephonyManager.APPTYPE_USIM,
- TelephonyManager.AUTHTYPE_EAP_SIM,
- BASE_64_RAND_1);
- verify(mMockTelephonyManager)
- .getIccAuthentication(
- TelephonyManager.APPTYPE_USIM,
- TelephonyManager.AUTHTYPE_EAP_SIM,
- BASE_64_RAND_2);
- verifyNoMoreInteractions(mMockTelephonyManager);
- }
-
- @Test
- public void testGetRandChallengeResultsBufferUnderflow() throws Exception {
- EapSimTypeData eapSimTypeData =
- new EapSimTypeData(EAP_SIM_CHALLENGE, Arrays.asList(
- new AtRandSim(AT_RAND_LENGTH,
- hexStringToByteArray(RAND_1),
- hexStringToByteArray(RAND_2))));
-
- when(mMockTelephonyManager
- .getIccAuthentication(
- TelephonyManager.APPTYPE_USIM,
- TelephonyManager.AUTHTYPE_EAP_SIM,
- BASE_64_RAND_1))
- .thenReturn(BASE_64_RESP_1);
- when(mMockTelephonyManager
- .getIccAuthentication(
- TelephonyManager.APPTYPE_USIM,
- TelephonyManager.AUTHTYPE_EAP_SIM,
- BASE_64_RAND_2))
- .thenReturn(BASE_64_INVALID_RESP);
-
- try {
- mChallengeState.getRandChallengeResults(eapSimTypeData);
- fail("BufferUnderflowException expected for short Kc value");
- } catch (BufferUnderflowException ex) {
- }
-
- verify(mMockTelephonyManager)
- .getIccAuthentication(
- TelephonyManager.APPTYPE_USIM,
- TelephonyManager.AUTHTYPE_EAP_SIM,
- BASE_64_RAND_1);
- verify(mMockTelephonyManager)
- .getIccAuthentication(
- TelephonyManager.APPTYPE_USIM,
- TelephonyManager.AUTHTYPE_EAP_SIM,
- BASE_64_RAND_2);
- verifyNoMoreInteractions(mMockTelephonyManager);
- }
-
- @Test
- public void testProcessUiccAuthenticationNullResponse() throws Exception {
- EapData eapData = new EapData(EAP_TYPE_SIM, DUMMY_EAP_TYPE_DATA);
- EapMessage eapMessage = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
-
- AtRandSim atRandSim = new AtRandSim(AT_RAND_LENGTH, RAND_1_BYTES, RAND_2_BYTES);
-
- DecodeResult<EapSimTypeData> decodeResult =
- new DecodeResult<>(
- new EapSimTypeData(
- EAP_SIM_CHALLENGE,
- Arrays.asList(atRandSim, new AtMac())));
- when(mMockEapSimTypeDataDecoder.decode(eq(DUMMY_EAP_TYPE_DATA))).thenReturn(decodeResult);
- when(mMockTelephonyManager
- .getIccAuthentication(
- TelephonyManager.APPTYPE_USIM,
- TelephonyManager.AUTHTYPE_EAP_SIM,
- BASE_64_RAND_1))
- .thenReturn(null);
-
- EapError eapError = (EapError) mEapSimMethodStateMachine.process(eapMessage);
- assertTrue(eapError.cause instanceof EapSimAkaAuthenticationFailureException);
-
- verify(mMockEapSimTypeDataDecoder).decode(eq(DUMMY_EAP_TYPE_DATA));
- verify(mMockTelephonyManager)
- .getIccAuthentication(
- TelephonyManager.APPTYPE_USIM,
- TelephonyManager.AUTHTYPE_EAP_SIM,
- BASE_64_RAND_1);
- verifyNoMoreInteractions(mMockEapSimTypeDataDecoder, mMockTelephonyManager);
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapSimCreatedStateTest.java b/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapSimCreatedStateTest.java
deleted file mode 100644
index bdd19201..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapSimCreatedStateTest.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.statemachine;
-
-import static com.android.internal.net.eap.message.EapData.EAP_IDENTITY;
-import static com.android.internal.net.eap.message.EapData.EAP_TYPE_SIM;
-import static com.android.internal.net.eap.message.EapMessage.EAP_CODE_FAILURE;
-import static com.android.internal.net.eap.message.EapMessage.EAP_CODE_REQUEST;
-import static com.android.internal.net.eap.message.EapMessage.EAP_CODE_SUCCESS;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.ID_INT;
-
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-import com.android.internal.net.eap.EapResult;
-import com.android.internal.net.eap.EapResult.EapError;
-import com.android.internal.net.eap.EapResult.EapFailure;
-import com.android.internal.net.eap.exceptions.EapInvalidRequestException;
-import com.android.internal.net.eap.message.EapData;
-import com.android.internal.net.eap.message.EapMessage;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtPermanentIdReq;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtVersionList;
-import com.android.internal.net.eap.message.simaka.EapSimAkaTypeData.DecodeResult;
-import com.android.internal.net.eap.message.simaka.EapSimTypeData;
-import com.android.internal.net.eap.statemachine.EapMethodStateMachine.FinalState;
-import com.android.internal.net.eap.statemachine.EapSimMethodStateMachine.CreatedState;
-import com.android.internal.net.eap.statemachine.EapSimMethodStateMachine.StartState;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.util.Arrays;
-import java.util.List;
-
-public class EapSimCreatedStateTest extends EapSimStateTest {
- private static final int EAP_SIM_START = 10;
-
- private CreatedState mCreatedState;
-
- @Before
- public void setUp() {
- super.setUp();
- mCreatedState = mEapSimMethodStateMachine.new CreatedState();
- }
-
- @Test
- public void testProcessSuccess() throws Exception {
- EapMessage input = new EapMessage(EAP_CODE_SUCCESS, ID_INT, null);
- EapResult result = mCreatedState.process(input);
-
- EapError eapError = (EapError) result;
- assertTrue(eapError.cause instanceof EapInvalidRequestException);
- }
-
- @Test
- public void testProcessFailure() throws Exception {
- EapMessage input = new EapMessage(EAP_CODE_FAILURE, ID_INT, null);
- EapResult result = mCreatedState.process(input);
- assertTrue(mEapSimMethodStateMachine.getState() instanceof FinalState);
-
- assertTrue(result instanceof EapFailure);
- }
-
- @Test
- public void testTransitionToStartState() throws Exception {
- EapData eapData = new EapData(EAP_TYPE_SIM, DUMMY_EAP_TYPE_DATA);
- EapMessage eapMessage = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
-
- List<EapSimAkaAttribute> attributes = Arrays.asList(
- new AtVersionList(8, 1), new AtPermanentIdReq());
- DecodeResult<EapSimTypeData> decodeResult =
- new DecodeResult<>(new EapSimTypeData(EAP_SIM_START, attributes));
- when(mMockEapSimTypeDataDecoder.decode(eq(DUMMY_EAP_TYPE_DATA))).thenReturn(decodeResult);
-
- mEapSimMethodStateMachine.process(eapMessage);
- assertTrue(mEapSimMethodStateMachine.getState() instanceof StartState);
-
- // decoded in CreatedState and StartState
- verify(mMockEapSimTypeDataDecoder, times(2)).decode(eq(DUMMY_EAP_TYPE_DATA));
- verifyNoMoreInteractions(mMockEapSimTypeDataDecoder);
- }
-
- @Test
- public void testProcessIncorrectEapMethodType() throws Exception {
- EapData eapData = new EapData(EAP_IDENTITY, DUMMY_EAP_TYPE_DATA);
- EapMessage eapMessage = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
-
- EapResult result = mEapSimMethodStateMachine.process(eapMessage);
- EapError eapError = (EapError) result;
- assertTrue(eapError.cause instanceof EapInvalidRequestException);
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapSimMethodStateMachineTest.java b/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapSimMethodStateMachineTest.java
deleted file mode 100644
index ac1d01ca..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapSimMethodStateMachineTest.java
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.statemachine;
-
-import static android.telephony.TelephonyManager.APPTYPE_USIM;
-
-import static com.android.internal.net.TestUtils.hexStringToByteArray;
-import static com.android.internal.net.eap.message.EapData.EAP_TYPE_SIM;
-import static com.android.internal.net.eap.message.EapMessage.EAP_CODE_REQUEST;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_SIM_CLIENT_ERROR_UNABLE_TO_PROCESS;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_SIM_NOTIFICATION_RESPONSE;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.ID_INT;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtNotification.GENERAL_FAILURE_PRE_CHALLENGE;
-import static com.android.internal.net.eap.message.simaka.EapSimTypeData.EAP_SIM_NOTIFICATION;
-import static com.android.internal.net.eap.message.simaka.EapSimTypeData.EAP_SIM_START;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-import android.net.eap.EapSessionConfig.EapSimConfig;
-import android.telephony.TelephonyManager;
-
-import com.android.internal.net.eap.EapResult.EapError;
-import com.android.internal.net.eap.EapResult.EapResponse;
-import com.android.internal.net.eap.exceptions.EapInvalidRequestException;
-import com.android.internal.net.eap.message.EapData;
-import com.android.internal.net.eap.message.EapMessage;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtNotification;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtVersionList;
-import com.android.internal.net.eap.message.simaka.EapSimAkaTypeData;
-import com.android.internal.net.eap.message.simaka.EapSimAkaTypeData.DecodeResult;
-import com.android.internal.net.eap.message.simaka.EapSimTypeData;
-import com.android.internal.net.eap.message.simaka.EapSimTypeData.EapSimTypeDataDecoder;
-import com.android.internal.net.eap.statemachine.EapSimMethodStateMachine.CreatedState;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.security.SecureRandom;
-import java.util.Arrays;
-
-public class EapSimMethodStateMachineTest {
- private static final int SUB_ID = 1;
- private static final byte[] DUMMY_EAP_TYPE_DATA = hexStringToByteArray("112233445566");
-
- // EAP-Identity = hex("test@android.net")
- protected static final byte[] EAP_IDENTITY_BYTES =
- hexStringToByteArray("7465737440616E64726F69642E6E6574");
-
- private TelephonyManager mMockTelephonyManager;
- private EapSimTypeDataDecoder mMockEapSimTypeDataDecoder;
-
- private EapSimConfig mEapSimConfig = new EapSimConfig(SUB_ID, APPTYPE_USIM);
- private EapSimMethodStateMachine mEapSimMethodStateMachine;
-
-
- @Before
- public void setUp() {
- mMockTelephonyManager = mock(TelephonyManager.class);
- mMockEapSimTypeDataDecoder = mock(EapSimTypeDataDecoder.class);
-
- when(mMockTelephonyManager.createForSubscriptionId(SUB_ID))
- .thenReturn(mMockTelephonyManager);
-
- mEapSimMethodStateMachine =
- new EapSimMethodStateMachine(
- mMockTelephonyManager,
- EAP_IDENTITY_BYTES,
- mEapSimConfig,
- new SecureRandom(),
- mMockEapSimTypeDataDecoder);
-
- verify(mMockTelephonyManager).createForSubscriptionId(SUB_ID);
- }
-
- @Test
- public void testEapSimMethodStateMachineStartState() {
- assertTrue(mEapSimMethodStateMachine.getState() instanceof CreatedState);
- }
-
- @Test
- public void testGetMethod() {
- assertEquals(EAP_TYPE_SIM, mEapSimMethodStateMachine.getEapMethod());
- }
-
- @Test
- public void testEapSimFailsOnMultipleSimNotifications() throws Exception {
- EapData eapData = new EapData(EAP_TYPE_SIM, DUMMY_EAP_TYPE_DATA);
- EapMessage eapMessage = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
-
- // First EAP-SIM/Notification
- EapSimTypeData notificationTypeData =
- new EapSimTypeData(
- EAP_SIM_NOTIFICATION,
- Arrays.asList(new AtNotification(GENERAL_FAILURE_PRE_CHALLENGE)));
- DecodeResult<EapSimTypeData> decodeResult = new DecodeResult<>(notificationTypeData);
- when(mMockEapSimTypeDataDecoder.decode(eq(DUMMY_EAP_TYPE_DATA))).thenReturn(decodeResult);
-
- EapResponse eapResponse = (EapResponse) mEapSimMethodStateMachine.process(eapMessage);
- assertArrayEquals(EAP_SIM_NOTIFICATION_RESPONSE, eapResponse.packet);
- verify(mMockEapSimTypeDataDecoder).decode(DUMMY_EAP_TYPE_DATA);
- verifyNoMoreInteractions(mMockTelephonyManager, mMockEapSimTypeDataDecoder);
-
- // Transition to StartState
- decodeResult =
- new DecodeResult<>(
- new EapSimTypeData(EAP_SIM_START, Arrays.asList(new AtVersionList(8, 1))));
- when(mMockEapSimTypeDataDecoder.decode(eq(DUMMY_EAP_TYPE_DATA))).thenReturn(decodeResult);
-
- eapResponse = (EapResponse) mEapSimMethodStateMachine.process(eapMessage);
- assertFalse(
- "EAP-Request/SIM-Start returned a Client-Error response",
- Arrays.equals(EAP_SIM_CLIENT_ERROR_UNABLE_TO_PROCESS, eapResponse.packet));
-
- // decoded in: previous 1 time + in CreatedState and StartState
- verify(mMockEapSimTypeDataDecoder, times(3)).decode(eq(DUMMY_EAP_TYPE_DATA));
- verifyNoMoreInteractions(mMockTelephonyManager, mMockEapSimTypeDataDecoder);
-
- // Second EAP-SIM/Notification
- decodeResult = new EapSimAkaTypeData.DecodeResult<>(notificationTypeData);
- when(mMockEapSimTypeDataDecoder.decode(eq(DUMMY_EAP_TYPE_DATA))).thenReturn(decodeResult);
-
- EapError eapError = (EapError) mEapSimMethodStateMachine.process(eapMessage);
- assertTrue(eapError.cause instanceof EapInvalidRequestException);
-
- // decoded previous 3 times + 1
- verify(mMockEapSimTypeDataDecoder, times(4)).decode(DUMMY_EAP_TYPE_DATA);
- verifyNoMoreInteractions(mMockTelephonyManager, mMockEapSimTypeDataDecoder);
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapSimStartStateTest.java b/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapSimStartStateTest.java
deleted file mode 100644
index ccb746ab..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapSimStartStateTest.java
+++ /dev/null
@@ -1,254 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.statemachine;
-
-import static com.android.internal.net.eap.message.EapData.EAP_IDENTITY;
-import static com.android.internal.net.eap.message.EapData.EAP_TYPE_SIM;
-import static com.android.internal.net.eap.message.EapMessage.EAP_CODE_FAILURE;
-import static com.android.internal.net.eap.message.EapMessage.EAP_CODE_REQUEST;
-import static com.android.internal.net.eap.message.EapMessage.EAP_CODE_SUCCESS;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_SIM_IDENTITY;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_SIM_RESPONSE_WITHOUT_IDENTITY;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.ID_INT;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.IMSI;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_ANY_ID_REQ;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_ENCR_DATA;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_IV;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_MAC;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_PERMANENT_ID_REQ;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.EAP_AT_VERSION_LIST;
-import static com.android.internal.net.eap.message.simaka.EapSimTypeData.EAP_SIM_CHALLENGE;
-import static com.android.internal.net.eap.message.simaka.EapSimTypeData.EAP_SIM_START;
-import static com.android.internal.net.eap.message.simaka.attributes.EapTestAttributeDefinitions.NONCE_MT;
-
-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.junit.Assert.fail;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-import com.android.internal.net.eap.EapResult;
-import com.android.internal.net.eap.EapResult.EapError;
-import com.android.internal.net.eap.EapResult.EapFailure;
-import com.android.internal.net.eap.EapResult.EapResponse;
-import com.android.internal.net.eap.exceptions.EapInvalidRequestException;
-import com.android.internal.net.eap.exceptions.simaka.EapSimAkaIdentityUnavailableException;
-import com.android.internal.net.eap.message.EapData;
-import com.android.internal.net.eap.message.EapMessage;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtAnyIdReq;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtIdentity;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtMac;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtNonceMt;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtPermanentIdReq;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtVersionList;
-import com.android.internal.net.eap.message.simaka.EapSimAkaTypeData.DecodeResult;
-import com.android.internal.net.eap.message.simaka.EapSimTypeData;
-import com.android.internal.net.eap.statemachine.EapMethodStateMachine.FinalState;
-import com.android.internal.net.eap.statemachine.EapSimMethodStateMachine.ChallengeState;
-import com.android.internal.net.eap.statemachine.EapSimMethodStateMachine.StartState;
-import com.android.internal.net.utils.Log;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.util.Arrays;
-import java.util.LinkedHashMap;
-
-public class EapSimStartStateTest extends EapSimStateTest {
-
- private StartState mStartState;
- private LinkedHashMap<Integer, EapSimAkaAttribute> mAttributes;
-
- @Before
- public void setUp() {
- super.setUp();
-
- AtNonceMt atNonceMt = null;
- try {
- atNonceMt = new AtNonceMt(NONCE_MT);
- } catch (Exception e) {
- fail("Failed to create AtNonceMt attribute in setUp()");
- }
-
- mStartState = mEapSimMethodStateMachine.new StartState(atNonceMt);
- mEapSimMethodStateMachine.transitionTo(mStartState);
-
- mAttributes = new LinkedHashMap<>();
- }
-
- @Test
- public void testProcessSuccess() throws Exception {
- EapMessage input = new EapMessage(EAP_CODE_SUCCESS, ID_INT, null);
- EapResult result = mStartState.process(input);
-
- EapError eapError = (EapError) result;
- assertTrue(eapError.cause instanceof EapInvalidRequestException);
- }
-
- @Test
- public void testProcessFailure() throws Exception {
- EapMessage input = new EapMessage(EAP_CODE_FAILURE, ID_INT, null);
- EapResult result = mStartState.process(input);
- assertTrue(mEapSimMethodStateMachine.getState() instanceof FinalState);
-
- assertTrue(result instanceof EapFailure);
- }
-
- @Test
- public void testProcessIncorrectEapMethodType() throws Exception {
- EapData eapData = new EapData(EAP_IDENTITY, DUMMY_EAP_TYPE_DATA);
- EapMessage eapMessage = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
-
- EapResult result = mStartState.process(eapMessage);
- EapError eapError = (EapError) result;
- assertTrue(eapError.cause instanceof EapInvalidRequestException);
- }
-
- @Test
- public void testIsValidStartAttributes() throws Exception {
- mAttributes.put(EAP_AT_VERSION_LIST, new AtVersionList(8, 1));
- mAttributes.put(EAP_AT_PERMANENT_ID_REQ, new AtPermanentIdReq());
- EapSimTypeData eapSimTypeData = new EapSimTypeData(EAP_SIM_START, mAttributes);
- assertTrue(mStartState.isValidStartAttributes(eapSimTypeData));
- }
-
- @Test
- public void testIsValidStartAttributesMissingVersionList() throws Exception {
- mAttributes.put(EAP_AT_PERMANENT_ID_REQ, new AtPermanentIdReq());
- EapSimTypeData eapSimTypeData = new EapSimTypeData(EAP_SIM_START, mAttributes);
- assertFalse(mStartState.isValidStartAttributes(eapSimTypeData));
- }
-
- @Test
- public void testIsValidStartAttributesMultipleIdRequests() throws Exception {
- mAttributes.put(EAP_AT_VERSION_LIST, new AtVersionList(8, 1));
- mAttributes.put(EAP_AT_PERMANENT_ID_REQ, new AtPermanentIdReq());
- mAttributes.put(EAP_AT_ANY_ID_REQ, new AtAnyIdReq());
- EapSimTypeData eapSimTypeData = new EapSimTypeData(EAP_SIM_START, mAttributes);
- assertFalse(mStartState.isValidStartAttributes(eapSimTypeData));
- }
-
- @Test
- public void testIsValidStartAttributesInvalidAttributes() throws Exception {
- mAttributes.put(EAP_AT_VERSION_LIST, new AtVersionList(8, 1));
- mAttributes.put(EAP_AT_PERMANENT_ID_REQ, new AtPermanentIdReq());
- mAttributes.put(EAP_AT_MAC, new AtMac());
- EapSimTypeData eapSimTypeData = new EapSimTypeData(EAP_SIM_START, mAttributes);
- assertFalse(mStartState.isValidStartAttributes(eapSimTypeData));
-
- mAttributes.remove(EAP_AT_MAC);
- mAttributes.put(EAP_AT_IV, null); // just need <K, V> pair in the map
- eapSimTypeData = new EapSimTypeData(EAP_SIM_START, mAttributes);
- assertFalse(mStartState.isValidStartAttributes(eapSimTypeData));
-
- mAttributes.remove(EAP_AT_IV);
- mAttributes.put(EAP_AT_ENCR_DATA, null); // just need <K, V> pair in the map
- eapSimTypeData = new EapSimTypeData(EAP_SIM_START, mAttributes);
- assertFalse(mStartState.isValidStartAttributes(eapSimTypeData));
- }
-
- @Test
- public void testAddIdentityAttributeToResponse() throws Exception {
- EapSimTypeData eapSimTypeData = new EapSimTypeData(
- EAP_SIM_START, Arrays.asList(new AtPermanentIdReq()));
-
- when(mMockTelephonyManager.getSubscriberId()).thenReturn(IMSI);
-
- AtIdentity atIdentity = mStartState.getIdentityResponse(eapSimTypeData);
- assertArrayEquals(EAP_SIM_IDENTITY.getBytes(), mStartState.mIdentity);
- verify(mMockTelephonyManager).getSubscriberId();
- assertArrayEquals(EAP_SIM_IDENTITY.getBytes(), atIdentity.identity);
- verifyNoMoreInteractions(mMockTelephonyManager);
- }
-
- @Test
- public void testAddIdentityAttributeToResponseImsiUnavailable() throws Exception {
- EapMessage eapMessage = new EapMessage(
- EAP_CODE_REQUEST,
- ID_INT,
- new EapData(EAP_TYPE_SIM, DUMMY_EAP_TYPE_DATA));
- mAttributes.put(EAP_AT_VERSION_LIST, new AtVersionList(8, 1));
- mAttributes.put(EAP_AT_PERMANENT_ID_REQ, new AtPermanentIdReq());
- EapSimTypeData eapSimTypeData = new EapSimTypeData(EAP_SIM_START, mAttributes);
- DecodeResult decodeResult = new DecodeResult(eapSimTypeData);
-
- when(mMockEapSimTypeDataDecoder.decode(DUMMY_EAP_TYPE_DATA)).thenReturn(decodeResult);
- when(mMockTelephonyManager.getSubscriberId()).thenReturn(null);
-
- EapResult result = mStartState.process(eapMessage);
- EapError eapError = (EapError) result;
- assertTrue(eapError.cause instanceof EapSimAkaIdentityUnavailableException);
-
- verify(mMockTelephonyManager).getSubscriberId();
- verifyNoMoreInteractions(mMockTelephonyManager);
- }
-
- @Test
- public void testAddIdentityAttributeToResponseNoIdRequest() throws Exception {
- EapSimTypeData eapSimTypeData = new EapSimTypeData(EAP_SIM_START, Arrays.asList());
-
- AtIdentity atIdentity = mStartState.getIdentityResponse(eapSimTypeData);
- assertNull(atIdentity);
- verifyNoMoreInteractions(mMockTelephonyManager);
- }
-
- @Test
- public void testProcessWithoutIdentityRequest() throws Exception {
- EapMessage eapMessage =
- new EapMessage(
- EAP_CODE_REQUEST, ID_INT, new EapData(EAP_TYPE_SIM, DUMMY_EAP_TYPE_DATA));
-
- // Send EAP-SIM/Start message without Identity request
- mAttributes.put(EAP_AT_VERSION_LIST, new AtVersionList(8, 1));
- DecodeResult eapSimStartDecodeResult =
- new DecodeResult(new EapSimTypeData(EAP_SIM_START, mAttributes));
- when(mMockEapSimTypeDataDecoder.decode(DUMMY_EAP_TYPE_DATA))
- .thenReturn(eapSimStartDecodeResult);
-
- EapResult result = mEapSimMethodStateMachine.process(eapMessage);
- EapResponse eapResponse = (EapResponse) result;
- assertArrayEquals(
- Log.byteArrayToHexString(eapResponse.packet),
- EAP_SIM_RESPONSE_WITHOUT_IDENTITY,
- eapResponse.packet);
-
- verify(mMockEapSimTypeDataDecoder).decode(eq(DUMMY_EAP_TYPE_DATA));
-
- // Send EAP-SIM/Challenge message
- DecodeResult eapSimChallengeDecodeResult =
- new DecodeResult(new EapSimTypeData(EAP_SIM_CHALLENGE, new LinkedHashMap<>()));
- when(mMockEapSimTypeDataDecoder.decode(DUMMY_EAP_TYPE_DATA))
- .thenReturn(eapSimChallengeDecodeResult);
-
- // We only care about the transition to ChallengeState - the response doesn't matter
- mEapSimMethodStateMachine.process(eapMessage);
- ChallengeState challengeState = (ChallengeState) mEapSimMethodStateMachine.getState();
- assertArrayEquals(EAP_IDENTITY_BYTES, challengeState.mIdentity);
-
- // verify decode called 3x times:
- // 1. decode in EAP-SIM/Start test above
- // 2. decode in EAP-SIM/Challenge test for StartState
- // 3. decode in EAP-SIM/Challenge test for ChallengeState
- verify(mMockEapSimTypeDataDecoder, times(3)).decode(eq(DUMMY_EAP_TYPE_DATA));
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapSimStateTest.java b/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapSimStateTest.java
deleted file mode 100644
index d8d18416..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapSimStateTest.java
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.statemachine;
-
-import static android.telephony.TelephonyManager.APPTYPE_USIM;
-
-import static com.android.internal.net.TestUtils.hexStringToByteArray;
-import static com.android.internal.net.eap.message.EapData.EAP_NOTIFICATION;
-import static com.android.internal.net.eap.message.EapData.EAP_TYPE_SIM;
-import static com.android.internal.net.eap.message.EapMessage.EAP_CODE_REQUEST;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_RESPONSE_NOTIFICATION_PACKET;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_SIM_CLIENT_ERROR_INSUFFICIENT_CHALLENGES;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_SIM_NOTIFICATION_RESPONSE;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.ID_INT;
-import static com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtNotification.GENERAL_FAILURE_PRE_CHALLENGE;
-import static com.android.internal.net.eap.message.simaka.EapSimTypeData.EAP_SIM_NOTIFICATION;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-import android.net.eap.EapSessionConfig.EapSimConfig;
-import android.telephony.TelephonyManager;
-
-import com.android.internal.net.eap.EapResult;
-import com.android.internal.net.eap.EapResult.EapResponse;
-import com.android.internal.net.eap.message.EapData;
-import com.android.internal.net.eap.message.EapMessage;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtClientErrorCode;
-import com.android.internal.net.eap.message.simaka.EapSimAkaAttribute.AtNotification;
-import com.android.internal.net.eap.message.simaka.EapSimAkaTypeData.DecodeResult;
-import com.android.internal.net.eap.message.simaka.EapSimTypeData;
-import com.android.internal.net.eap.message.simaka.EapSimTypeData.EapSimTypeDataDecoder;
-import com.android.internal.net.eap.statemachine.EapMethodStateMachine.EapMethodState;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.security.SecureRandom;
-import java.util.Arrays;
-
-public class EapSimStateTest {
- protected static final int SUB_ID = 1;
- protected static final String NOTIFICATION_MESSAGE = "test";
- protected static final byte[] DUMMY_EAP_TYPE_DATA = hexStringToByteArray("112233445566");
-
- // EAP-Identity = hex("test@android.net")
- protected static final byte[] EAP_IDENTITY_BYTES =
- hexStringToByteArray("7465737440616E64726F69642E6E6574");
-
- protected TelephonyManager mMockTelephonyManager;
- protected EapSimTypeDataDecoder mMockEapSimTypeDataDecoder;
-
- protected EapSimConfig mEapSimConfig = new EapSimConfig(SUB_ID, APPTYPE_USIM);
- protected EapSimMethodStateMachine mEapSimMethodStateMachine;
-
- @Before
- public void setUp() {
- mMockTelephonyManager = mock(TelephonyManager.class);
- mMockEapSimTypeDataDecoder = mock(EapSimTypeDataDecoder.class);
-
- when(mMockTelephonyManager.createForSubscriptionId(SUB_ID))
- .thenReturn(mMockTelephonyManager);
-
- mEapSimMethodStateMachine =
- new EapSimMethodStateMachine(
- mMockTelephonyManager,
- EAP_IDENTITY_BYTES,
- mEapSimConfig,
- new SecureRandom(),
- mMockEapSimTypeDataDecoder);
-
- verify(mMockTelephonyManager).createForSubscriptionId(SUB_ID);
- }
-
- @Test
- public void testProcessNotification() throws Exception {
- EapData eapData = new EapData(EAP_NOTIFICATION, NOTIFICATION_MESSAGE.getBytes());
- EapMessage notification = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
- EapMethodState preNotification = (EapMethodState) mEapSimMethodStateMachine.getState();
-
- EapResult result = mEapSimMethodStateMachine.process(notification);
- assertEquals(preNotification, mEapSimMethodStateMachine.getState());
- verifyNoMoreInteractions(mMockTelephonyManager, mMockEapSimTypeDataDecoder);
-
- assertTrue(result instanceof EapResponse);
- EapResponse eapResponse = (EapResponse) result;
- assertArrayEquals(EAP_RESPONSE_NOTIFICATION_PACKET, eapResponse.packet);
- }
-
- @Test
- public void testProcessEapSimNotification() throws Exception {
- EapData eapData = new EapData(EAP_TYPE_SIM, DUMMY_EAP_TYPE_DATA);
- EapMessage eapMessage = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
- EapMethodState preProcess = (EapMethodState) mEapSimMethodStateMachine.getState();
- EapSimTypeData typeData =
- new EapSimTypeData(
- EAP_SIM_NOTIFICATION,
- Arrays.asList(new AtNotification(GENERAL_FAILURE_PRE_CHALLENGE)));
-
- DecodeResult<EapSimTypeData> decodeResult = new DecodeResult<>(typeData);
- when(mMockEapSimTypeDataDecoder.decode(eq(DUMMY_EAP_TYPE_DATA))).thenReturn(decodeResult);
-
- EapResponse eapResponse = (EapResponse) mEapSimMethodStateMachine.process(eapMessage);
- assertArrayEquals(EAP_SIM_NOTIFICATION_RESPONSE, eapResponse.packet);
- assertEquals(preProcess, mEapSimMethodStateMachine.getState());
- verify(mMockEapSimTypeDataDecoder).decode(DUMMY_EAP_TYPE_DATA);
- verifyNoMoreInteractions(mMockTelephonyManager, mMockEapSimTypeDataDecoder);
- }
-
- @Test
- public void testProcessInvalidDecodeResult() throws Exception {
- EapData eapData = new EapData(EAP_TYPE_SIM, DUMMY_EAP_TYPE_DATA);
- EapMessage eapMessage = new EapMessage(EAP_CODE_REQUEST, ID_INT, eapData);
- EapMethodState preProcess = (EapMethodState) mEapSimMethodStateMachine.getState();
-
- AtClientErrorCode atClientErrorCode = AtClientErrorCode.INSUFFICIENT_CHALLENGES;
- DecodeResult<EapSimTypeData> decodeResult = new DecodeResult<>(atClientErrorCode);
- when(mMockEapSimTypeDataDecoder.decode(eq(DUMMY_EAP_TYPE_DATA))).thenReturn(decodeResult);
-
- EapResult result = mEapSimMethodStateMachine.process(eapMessage);
- assertEquals(preProcess, mEapSimMethodStateMachine.getState());
- verify(mMockEapSimTypeDataDecoder).decode(DUMMY_EAP_TYPE_DATA);
- verifyNoMoreInteractions(mMockTelephonyManager, mMockEapSimTypeDataDecoder);
-
- assertTrue(result instanceof EapResponse);
- EapResponse eapResponse = (EapResponse) result;
- assertArrayEquals(EAP_SIM_CLIENT_ERROR_INSUFFICIENT_CHALLENGES, eapResponse.packet);
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapStateMachineTest.java b/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapStateMachineTest.java
deleted file mode 100644
index 288fc85f..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapStateMachineTest.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.statemachine;
-
-import static androidx.test.InstrumentationRegistry.getInstrumentation;
-
-import static com.android.internal.net.eap.EapTestUtils.getDummyEapSessionConfig;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_SUCCESS_PACKET;
-
-import static org.junit.Assert.assertTrue;
-
-import android.content.Context;
-import android.net.eap.EapSessionConfig;
-
-import com.android.internal.net.eap.EapResult;
-import com.android.internal.net.eap.EapResult.EapError;
-import com.android.internal.net.eap.exceptions.EapInvalidRequestException;
-import com.android.internal.net.eap.statemachine.EapStateMachine.CreatedState;
-import com.android.internal.net.eap.statemachine.EapStateMachine.FailureState;
-import com.android.internal.net.eap.statemachine.EapStateMachine.SuccessState;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.security.SecureRandom;
-
-public class EapStateMachineTest {
- private Context mContext;
- private EapSessionConfig mEapSessionConfig;
-
- @Before
- public void setUp() {
- mContext = getInstrumentation().getContext();
- mEapSessionConfig = getDummyEapSessionConfig();
- }
-
- @Test
- public void testEapStateMachineStartState() {
- EapStateMachine eapStateMachine =
- new EapStateMachine(mContext, mEapSessionConfig, new SecureRandom());
- assertTrue(eapStateMachine.getState() instanceof CreatedState);
- }
-
- @Test
- public void testSuccessStateProcessFails() {
- SuccessState successState =
- new EapStateMachine(mContext, mEapSessionConfig, new SecureRandom())
- .new SuccessState();
- EapResult result = successState.process(EAP_SUCCESS_PACKET);
- assertTrue(result instanceof EapError);
-
- EapError eapError = (EapError) result;
- assertTrue(eapError.cause instanceof EapInvalidRequestException);
- }
-
- @Test
- public void testFailureStateProcessFails() {
- FailureState failureState =
- new EapStateMachine(mContext, mEapSessionConfig, new SecureRandom())
- .new FailureState();
- EapResult result = failureState.process(EAP_SUCCESS_PACKET);
- assertTrue(result instanceof EapError);
-
- EapError eapError = (EapError) result;
- assertTrue(eapError.cause instanceof EapInvalidRequestException);
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapStateTest.java b/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapStateTest.java
deleted file mode 100644
index 0193cb4e..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/statemachine/EapStateTest.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.statemachine;
-
-import static androidx.test.InstrumentationRegistry.getInstrumentation;
-
-import static com.android.internal.net.eap.EapTestUtils.getDummyEapSimSessionConfig;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_REQUEST_MD5_CHALLENGE;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_REQUEST_NAK_PACKET;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_RESPONSE_NAK_PACKET;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_RESPONSE_NOTIFICATION_PACKET;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.REQUEST_UNSUPPORTED_TYPE_PACKET;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.SHORT_PACKET;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertTrue;
-
-import android.content.Context;
-import android.net.eap.EapSessionConfig;
-
-import com.android.internal.net.eap.EapResult;
-import com.android.internal.net.eap.EapResult.EapError;
-import com.android.internal.net.eap.EapResult.EapResponse;
-import com.android.internal.net.eap.exceptions.EapInvalidPacketLengthException;
-import com.android.internal.net.eap.exceptions.EapInvalidRequestException;
-import com.android.internal.net.eap.statemachine.EapStateMachine.EapState;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.security.SecureRandom;
-
-/**
- * EapStateTest is a test template for testing EapState implementations.
- *
- * <p>Specifically, testing for CreatedState, IdentityState, and MethodState should subclass
- * EapStateTest
- */
-public class EapStateTest {
- protected Context mContext;
- protected EapSessionConfig mEapSessionConfig;
- protected EapStateMachine mEapStateMachine;
- protected EapState mEapState;
-
- @Before
- public void setUp() {
- mContext = getInstrumentation().getContext();
- mEapSessionConfig = getDummyEapSimSessionConfig();
- mEapStateMachine = new EapStateMachine(mContext, mEapSessionConfig, new SecureRandom());
-
- // this EapState definition is used to make sure all non-Success/Failure EAP states
- // produce the same results for error cases.
- mEapState = mEapStateMachine.new EapState() {
- @Override
- public EapResult process(byte[] msg) {
- return decode(msg).eapResult;
- }
- };
- }
-
- @Test
- public void testProcessNullPacket() {
- EapResult result = mEapState.process(null);
- assertTrue(result instanceof EapError);
-
- EapError eapError = (EapError) result;
- assertTrue(eapError.cause instanceof IllegalArgumentException);
- }
-
- @Test
- public void testProcessUnsupportedEapDataType() {
- EapResult result = mEapState.process(REQUEST_UNSUPPORTED_TYPE_PACKET);
- assertTrue(result instanceof EapResponse);
-
- EapResponse eapResponse = (EapResponse) result;
- assertArrayEquals(EAP_RESPONSE_NAK_PACKET, eapResponse.packet);
- }
-
- @Test
- public void testProcessDecodeFailure() {
- EapResult result = mEapState.process(SHORT_PACKET);
- assertTrue(result instanceof EapError);
-
- EapError eapError = (EapError) result;
- assertTrue(eapError.cause instanceof EapInvalidPacketLengthException);
- }
-
- @Test
- public void testProcessResponse() {
- EapResult result = mEapState.process(EAP_RESPONSE_NOTIFICATION_PACKET);
- assertTrue(result instanceof EapError);
-
- EapError eapError = (EapError) result;
- assertTrue(eapError.cause instanceof EapInvalidRequestException);
- }
-
- @Test
- public void testProcessNakRequest() {
- EapResult result = mEapState.process(EAP_REQUEST_NAK_PACKET);
- assertTrue(result instanceof EapError);
-
- EapError eapError = (EapError) result;
- assertTrue(eapError.cause instanceof EapInvalidRequestException);
- }
-
- @Test
- public void testProcessMd5Challenge() {
- EapResult result = mEapState.process(EAP_REQUEST_MD5_CHALLENGE);
- assertTrue(result instanceof EapResponse);
-
- EapResponse eapResponse = (EapResponse) result;
- assertArrayEquals(EAP_RESPONSE_NAK_PACKET, eapResponse.packet);
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/statemachine/IdentityStateTest.java b/tests/iketests/src/java/com/android/internal/net/eap/statemachine/IdentityStateTest.java
deleted file mode 100644
index abe4e824..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/statemachine/IdentityStateTest.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.statemachine;
-
-import static com.android.internal.net.eap.EapTestUtils.getDummyEapSessionConfig;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_IDENTITY;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_REQUEST_IDENTITY_PACKET;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_REQUEST_NOTIFICATION_PACKET;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_REQUEST_SIM_START_PACKET;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_RESPONSE_IDENTITY_DEFAULT_PACKET;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_RESPONSE_IDENTITY_PACKET;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_RESPONSE_NOTIFICATION_PACKET;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-
-import com.android.internal.net.eap.EapResult;
-import com.android.internal.net.eap.EapResult.EapResponse;
-import com.android.internal.net.eap.statemachine.EapStateMachine.MethodState;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.security.SecureRandom;
-
-public class IdentityStateTest extends EapStateTest {
- private EapStateMachine mEapStateMachineSpy;
-
- @Before
- @Override
- public void setUp() {
- super.setUp();
-
- mEapStateMachineSpy = spy(mEapStateMachine);
- mEapState = mEapStateMachineSpy.new IdentityState();
- }
-
- @Test
- public void testProcess() {
- mEapSessionConfig = getDummyEapSessionConfig(EAP_IDENTITY);
- mEapStateMachineSpy = spy(
- new EapStateMachine(mContext, mEapSessionConfig, new SecureRandom()));
- mEapState = mEapStateMachineSpy.new IdentityState();
-
- EapResult eapResult = mEapState.process(EAP_REQUEST_IDENTITY_PACKET);
-
- assertTrue(eapResult instanceof EapResponse);
- EapResponse eapResponse = (EapResponse) eapResult;
- assertArrayEquals(EAP_RESPONSE_IDENTITY_PACKET, eapResponse.packet);
- verify(mEapStateMachineSpy, never()).transitionAndProcess(any(), any());
- }
-
- @Test
- public void testProcessDefaultIdentity() {
- EapResult eapResult = mEapState.process(EAP_REQUEST_IDENTITY_PACKET);
-
- assertTrue(eapResult instanceof EapResponse);
- EapResponse eapResponse = (EapResponse) eapResult;
- assertArrayEquals(EAP_RESPONSE_IDENTITY_DEFAULT_PACKET, eapResponse.packet);
- verify(mEapStateMachineSpy, never()).transitionAndProcess(any(), any());
- }
-
- @Test
- public void testProcessNotificationRequest() {
- EapResult eapResult = mEapState.process(EAP_REQUEST_NOTIFICATION_PACKET);
-
- // state shouldn't change after Notification request
- assertTrue(eapResult instanceof EapResponse);
- EapResponse eapResponse = (EapResponse) eapResult;
- assertArrayEquals(EAP_RESPONSE_NOTIFICATION_PACKET, eapResponse.packet);
- verify(mEapStateMachineSpy, never()).transitionAndProcess(any(), any());
- }
-
- @Test
- public void testProcessSimStart() {
- mEapState.process(EAP_REQUEST_SIM_START_PACKET);
-
- // EapStateMachine should change to MethodState for method-type packet
- verify(mEapStateMachineSpy).transitionAndProcess(
- any(MethodState.class), eq(EAP_REQUEST_SIM_START_PACKET));
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/eap/statemachine/MethodStateTest.java b/tests/iketests/src/java/com/android/internal/net/eap/statemachine/MethodStateTest.java
deleted file mode 100644
index 9df06e56..00000000
--- a/tests/iketests/src/java/com/android/internal/net/eap/statemachine/MethodStateTest.java
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * Copyright (C) 2019 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.eap.statemachine;
-
-import static android.telephony.TelephonyManager.APPTYPE_USIM;
-
-import static com.android.internal.net.eap.message.EapMessage.EAP_CODE_FAILURE;
-import static com.android.internal.net.eap.message.EapMessage.EAP_CODE_SUCCESS;
-import static com.android.internal.net.eap.message.EapMessage.EAP_HEADER_LENGTH;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_AKA_PRIME_REQUEST;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_FAILURE_PACKET;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_REQUEST_AKA;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_REQUEST_IDENTITY_PACKET;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_REQUEST_MSCHAP_V2;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_REQUEST_NOTIFICATION_PACKET;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_REQUEST_SIM_START_PACKET;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_RESPONSE_NAK_PACKET;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_RESPONSE_NOTIFICATION_PACKET;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_SUCCESS_PACKET;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EMSK;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.ID_INT;
-import static com.android.internal.net.eap.message.EapTestMessageDefinitions.MSK;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.argThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-import android.net.eap.EapSessionConfig;
-
-import com.android.internal.net.eap.EapResult;
-import com.android.internal.net.eap.EapResult.EapError;
-import com.android.internal.net.eap.EapResult.EapFailure;
-import com.android.internal.net.eap.EapResult.EapResponse;
-import com.android.internal.net.eap.EapResult.EapSuccess;
-import com.android.internal.net.eap.exceptions.EapInvalidRequestException;
-import com.android.internal.net.eap.message.EapMessage;
-import com.android.internal.net.eap.statemachine.EapStateMachine.FailureState;
-import com.android.internal.net.eap.statemachine.EapStateMachine.MethodState;
-import com.android.internal.net.eap.statemachine.EapStateMachine.SuccessState;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.ArgumentMatcher;
-
-import java.security.SecureRandom;
-
-public class MethodStateTest extends EapStateTest {
- private static final String USERNAME = "username";
- private static final String PASSWORD = "password";
- private static final String NETWORK_NAME = "android.net";
- private static final boolean ALLOW_MISMATCHED_NETWORK_NAMES = true;
-
- @Before
- @Override
- public void setUp() {
- super.setUp();
- mEapState = mEapStateMachine.new MethodState();
- mEapStateMachine.transitionTo(mEapState);
- }
-
- @Test
- public void testProcessUnsupportedEapType() {
- mEapState = mEapStateMachine.new MethodState();
- EapResult result = mEapState.process(EAP_REQUEST_IDENTITY_PACKET);
-
- EapResponse eapResponse = (EapResponse) result;
- assertArrayEquals(EAP_RESPONSE_NAK_PACKET, eapResponse.packet);
- }
-
- @Test
- public void testProcessTransitionsToEapSim() {
- mEapStateMachine.process(EAP_REQUEST_SIM_START_PACKET);
-
- assertTrue(mEapStateMachine.getState() instanceof MethodState);
- MethodState methodState = (MethodState) mEapStateMachine.getState();
- assertTrue(methodState.mEapMethodStateMachine instanceof EapSimMethodStateMachine);
- }
-
- @Test
- public void testProcessTransitionToEapAka() {
- // make EapStateMachine with EAP-AKA configurations
- EapSessionConfig eapSessionConfig = new EapSessionConfig.Builder()
- .setEapAkaConfig(0, APPTYPE_USIM).build();
- mEapStateMachine = new EapStateMachine(mContext, eapSessionConfig, new SecureRandom());
-
- mEapStateMachine.process(EAP_REQUEST_AKA);
-
- assertTrue(mEapStateMachine.getState() instanceof MethodState);
- MethodState methodState = (MethodState) mEapStateMachine.getState();
- assertTrue(methodState.mEapMethodStateMachine instanceof EapAkaMethodStateMachine);
- }
-
- @Test
- public void testProcessTransitionToEapAkaPrime() {
- // make EapStateMachine with EAP-AKA' configurations
- EapSessionConfig eapSessionConfig =
- new EapSessionConfig.Builder()
- .setEapAkaPrimeConfig(
- 0, APPTYPE_USIM, NETWORK_NAME, ALLOW_MISMATCHED_NETWORK_NAMES)
- .build();
- mEapStateMachine = new EapStateMachine(mContext, eapSessionConfig, new SecureRandom());
-
- mEapStateMachine.process(EAP_AKA_PRIME_REQUEST);
-
- assertTrue(mEapStateMachine.getState() instanceof MethodState);
- MethodState methodState = (MethodState) mEapStateMachine.getState();
- assertTrue(methodState.mEapMethodStateMachine instanceof EapAkaPrimeMethodStateMachine);
- }
-
- @Test
- public void testProcessTransitionToEapMsChapV2() {
- // make EapStateMachine with EAP MSCHAPv2 configurations
- EapSessionConfig eapSessionConfig =
- new EapSessionConfig.Builder().setEapMsChapV2Config(USERNAME, PASSWORD).build();
- mEapStateMachine = new EapStateMachine(mContext, eapSessionConfig, new SecureRandom());
-
- mEapStateMachine.process(EAP_REQUEST_MSCHAP_V2);
-
- assertTrue(mEapStateMachine.getState() instanceof MethodState);
- MethodState methodState = (MethodState) mEapStateMachine.getState();
- assertTrue(methodState.mEapMethodStateMachine instanceof EapMsChapV2MethodStateMachine);
- }
-
- @Test
- public void testProcessTransitionToSuccessState() {
- EapSuccess eapSuccess = new EapSuccess(MSK, EMSK);
-
- ArgumentMatcher<EapMessage> eapSuccessMatcher = msg ->
- msg.eapCode == EAP_CODE_SUCCESS
- && msg.eapIdentifier == ID_INT
- && msg.eapLength == EAP_HEADER_LENGTH
- && msg.eapData == null;
-
- EapMethodStateMachine mockEapMethodStateMachine = mock(EapMethodStateMachine.class);
- when(mockEapMethodStateMachine.process(argThat(eapSuccessMatcher))).thenReturn(eapSuccess);
- ((MethodState) mEapState).mEapMethodStateMachine = mockEapMethodStateMachine;
-
- mEapState.process(EAP_SUCCESS_PACKET);
- verify(mockEapMethodStateMachine).process(argThat(eapSuccessMatcher));
- assertTrue(mEapStateMachine.getState() instanceof SuccessState);
- verifyNoMoreInteractions(mockEapMethodStateMachine);
- }
-
- @Test
- public void testProcessTransitionToFailureState() {
- EapFailure eapFailure = new EapFailure();
-
- ArgumentMatcher<EapMessage> eapSuccessMatcher = msg ->
- msg.eapCode == EAP_CODE_FAILURE
- && msg.eapIdentifier == ID_INT
- && msg.eapLength == EAP_HEADER_LENGTH
- && msg.eapData == null;
-
- EapMethodStateMachine mockEapMethodStateMachine = mock(EapMethodStateMachine.class);
- when(mockEapMethodStateMachine.process(argThat(eapSuccessMatcher))).thenReturn(eapFailure);
- ((MethodState) mEapState).mEapMethodStateMachine = mockEapMethodStateMachine;
-
- mEapState.process(EAP_FAILURE_PACKET);
- verify(mockEapMethodStateMachine).process(argThat(eapSuccessMatcher));
- assertTrue(mEapStateMachine.getState() instanceof FailureState);
- verifyNoMoreInteractions(mockEapMethodStateMachine);
- }
-
- @Test
- public void testProcessEapFailureWithNoEapMethodState() {
- EapResult result = mEapStateMachine.process(EAP_FAILURE_PACKET);
- assertTrue(result instanceof EapFailure);
- assertTrue(mEapStateMachine.getState() instanceof FailureState);
- }
-
- @Test
- public void testProcessEapSuccessWithNoEapMethodState() {
- EapResult result = mEapStateMachine.process(EAP_SUCCESS_PACKET);
- EapError eapError = (EapError) result;
- assertTrue(eapError.cause instanceof EapInvalidRequestException);
- assertTrue(mEapStateMachine.getState() instanceof MethodState);
- }
-
- @Test
- public void testProcessEapNotificationWithNoEapMethodState() {
- EapResult result = mEapStateMachine.process(EAP_REQUEST_NOTIFICATION_PACKET);
- EapResponse eapResponse = (EapResponse) result;
- assertArrayEquals(EAP_RESPONSE_NOTIFICATION_PACKET, eapResponse.packet);
- assertTrue(mEapStateMachine.getState() instanceof MethodState);
- }
-}
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
deleted file mode 100644
index f6c32eef..00000000
--- a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/ChildSessionStateMachineTest.java
+++ /dev/null
@@ -1,1646 +0,0 @@
-/*
- * Copyright (C) 2019 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;
-
-import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_INTERNAL_ADDRESS_FAILURE;
-import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_NO_PROPOSAL_CHOSEN;
-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.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;
-import static com.android.internal.net.ipsec.ike.IkeSessionStateMachine.IKE_EXCHANGE_SUBTYPE_REKEY_CHILD;
-import static com.android.internal.net.ipsec.ike.IkeSessionStateMachine.REKEY_DELETE_TIMEOUT_MS;
-import static com.android.internal.net.ipsec.ike.message.IkeHeader.EXCHANGE_TYPE_CREATE_CHILD_SA;
-import static com.android.internal.net.ipsec.ike.message.IkeHeader.EXCHANGE_TYPE_INFORMATIONAL;
-import static com.android.internal.net.ipsec.ike.message.IkeNotifyPayload.NOTIFY_TYPE_REKEY_SA;
-import static com.android.internal.net.ipsec.ike.message.IkePayload.PAYLOAD_TYPE_CP;
-import static com.android.internal.net.ipsec.ike.message.IkePayload.PAYLOAD_TYPE_DELETE;
-import static com.android.internal.net.ipsec.ike.message.IkePayload.PAYLOAD_TYPE_KE;
-import static com.android.internal.net.ipsec.ike.message.IkePayload.PAYLOAD_TYPE_NONCE;
-import static com.android.internal.net.ipsec.ike.message.IkePayload.PAYLOAD_TYPE_NOTIFY;
-import static com.android.internal.net.ipsec.ike.message.IkePayload.PAYLOAD_TYPE_SA;
-import static com.android.internal.net.ipsec.ike.message.IkePayload.PAYLOAD_TYPE_TS_INITIATOR;
-import static com.android.internal.net.ipsec.ike.message.IkePayload.PAYLOAD_TYPE_TS_RESPONDER;
-import static com.android.internal.net.ipsec.ike.message.IkePayload.PROTOCOL_ID_ESP;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.ArgumentMatchers.argThat;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyBoolean;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyLong;
-import static org.mockito.Matchers.anyObject;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.net.IpSecManager;
-import android.net.IpSecManager.UdpEncapsulationSocket;
-import android.net.IpSecTransform;
-import android.net.LinkAddress;
-import android.net.ipsec.ike.ChildSaProposal;
-import android.net.ipsec.ike.ChildSessionCallback;
-import android.net.ipsec.ike.ChildSessionConfiguration;
-import android.net.ipsec.ike.ChildSessionOptions;
-import android.net.ipsec.ike.IkeManager;
-import android.net.ipsec.ike.IkeTrafficSelector;
-import android.net.ipsec.ike.SaProposal;
-import android.net.ipsec.ike.TunnelModeChildSessionOptions;
-import android.net.ipsec.ike.exceptions.IkeException;
-import android.net.ipsec.ike.exceptions.IkeInternalException;
-import android.os.test.TestLooper;
-
-import androidx.test.InstrumentationRegistry;
-
-import com.android.internal.net.TestUtils;
-import com.android.internal.net.ipsec.ike.ChildSessionStateMachine.CreateChildSaHelper;
-import com.android.internal.net.ipsec.ike.ChildSessionStateMachine.IChildSessionSmCallback;
-import com.android.internal.net.ipsec.ike.IkeLocalRequestScheduler.ChildLocalRequest;
-import com.android.internal.net.ipsec.ike.SaRecord.ChildSaRecord;
-import com.android.internal.net.ipsec.ike.SaRecord.ChildSaRecordConfig;
-import com.android.internal.net.ipsec.ike.SaRecord.ISaRecordHelper;
-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;
-import com.android.internal.net.ipsec.ike.crypto.IkeMacPrf;
-import com.android.internal.net.ipsec.ike.exceptions.InvalidKeException;
-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.message.IkeConfigPayload;
-import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttribute;
-import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv4Address;
-import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv4Netmask;
-import com.android.internal.net.ipsec.ike.message.IkeDeletePayload;
-import com.android.internal.net.ipsec.ike.message.IkeKePayload;
-import com.android.internal.net.ipsec.ike.message.IkeMessage;
-import com.android.internal.net.ipsec.ike.message.IkeNoncePayload;
-import com.android.internal.net.ipsec.ike.message.IkeNotifyPayload;
-import com.android.internal.net.ipsec.ike.message.IkePayload;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload.DhGroupTransform;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload.EncryptionTransform;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload.IntegrityTransform;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload.PrfTransform;
-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.utils.Log;
-import com.android.server.IpSecService;
-
-import libcore.net.InetAddressUtils;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-import org.mockito.ArgumentMatcher;
-
-import java.net.Inet4Address;
-import java.net.InetAddress;
-import java.security.GeneralSecurityException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.concurrent.Executor;
-
-public final class ChildSessionStateMachineTest {
- private static final String TAG = "ChildSessionStateMachineTest";
-
- private static final Inet4Address LOCAL_ADDRESS =
- (Inet4Address) (InetAddressUtils.parseNumericAddress("192.0.2.200"));
- private static final Inet4Address REMOTE_ADDRESS =
- (Inet4Address) (InetAddressUtils.parseNumericAddress("192.0.2.100"));
- private static final Inet4Address INTERNAL_ADDRESS =
- (Inet4Address) (InetAddressUtils.parseNumericAddress("203.0.113.100"));
-
- private static final int IPV4_PREFIX_LEN = 32;
-
- private static final String IKE_AUTH_RESP_SA_PAYLOAD =
- "2c00002c0000002801030403cae7019f0300000c0100000c800e0080"
- + "03000008030000020000000805000000";
- private static final String REKEY_CHILD_RESP_SA_PAYLOAD =
- "2800002c0000002801030403cd1736b30300000c0100000c800e0080"
- + "03000008030000020000000805000000";
- private static final String REKEY_CHILD_REQ_SA_PAYLOAD =
- "2800002c0000002801030403c88336490300000c0100000c800e0080"
- + "03000008030000020000000805000000";
- private static final String REKEY_CHILD_UNACCEPTABLE_REQ_SA_PAYLOAD =
- "2800002c0000002801030403c88336490300000c0100000c800e00c0"
- + "03000008030000020000000805000000";
-
- private static final int CURRENT_CHILD_SA_SPI_IN = 0x2ad4c0a2;
- private static final int CURRENT_CHILD_SA_SPI_OUT = 0xcae7019f;
-
- private static final int LOCAL_INIT_NEW_CHILD_SA_SPI_IN = 0x57a09b0f;
- private static final int LOCAL_INIT_NEW_CHILD_SA_SPI_OUT = 0xcd1736b3;
-
- private static final int REMOTE_INIT_NEW_CHILD_SA_SPI_IN = 0xd2d01795;
- private static final int REMOTE_INIT_NEW_CHILD_SA_SPI_OUT = 0xc8833649;
-
- private static final String IKE_SK_D_HEX_STRING = "C86B56EFCF684DCC2877578AEF3137167FE0EBF6";
- private static final byte[] SK_D = TestUtils.hexStringToByteArray(IKE_SK_D_HEX_STRING);
-
- private static final int KEY_LEN_IKE_SKD = 20;
-
- private IkeMacPrf mIkePrf;
-
- private Context mContext;
- private IpSecService mMockIpSecService;
- private IpSecManager mMockIpSecManager;
- private UdpEncapsulationSocket mMockUdpEncapSocket;
-
- private TestLooper mLooper;
- private ChildSessionStateMachine mChildSessionStateMachine;
-
- private List<IkePayload> mFirstSaReqPayloads = new LinkedList<>();
- private List<IkePayload> mFirstSaRespPayloads = new LinkedList<>();
-
- private ChildSaRecord mSpyCurrentChildSaRecord;
- private ChildSaRecord mSpyLocalInitNewChildSaRecord;
- private ChildSaRecord mSpyRemoteInitNewChildSaRecord;
-
- private Log mSpyIkeLog;
-
- private ISaRecordHelper mMockSaRecordHelper;
-
- private ChildSessionOptions mChildSessionOptions;
- private EncryptionTransform mChildEncryptionTransform;
- private IntegrityTransform mChildIntegrityTransform;
- private DhGroupTransform mChildDhGroupTransform;
-
- private ChildSaProposal mMockNegotiatedProposal;
-
- private Executor mSpyUserCbExecutor;
- private ChildSessionCallback mMockChildSessionCallback;
- private IChildSessionSmCallback mMockChildSessionSmCallback;
-
- private ArgumentCaptor<ChildSaRecordConfig> mChildSaRecordConfigCaptor =
- ArgumentCaptor.forClass(ChildSaRecordConfig.class);
- private ArgumentCaptor<List<IkePayload>> mPayloadListCaptor =
- ArgumentCaptor.forClass(List.class);
- private ArgumentCaptor<ChildSessionConfiguration> mChildConfigCaptor =
- ArgumentCaptor.forClass(ChildSessionConfiguration.class);
-
- private ArgumentMatcher<ChildLocalRequest> mRekeyChildLocalReqMatcher =
- (argument) -> {
- return CMD_LOCAL_REQUEST_REKEY_CHILD == argument.procedureType
- && mMockChildSessionCallback == argument.childSessionCallback;
- };
-
- public ChildSessionStateMachineTest() {
- mMockSaRecordHelper = mock(SaRecord.ISaRecordHelper.class);
- mMockChildSessionSmCallback = mock(IChildSessionSmCallback.class);
-
- mChildEncryptionTransform =
- new EncryptionTransform(
- SaProposal.ENCRYPTION_ALGORITHM_AES_CBC, SaProposal.KEY_LEN_AES_128);
- mChildIntegrityTransform =
- new IntegrityTransform(SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96);
-
- mChildDhGroupTransform = new DhGroupTransform(SaProposal.DH_GROUP_1024_BIT_MODP);
- }
-
- @Before
- public void setup() throws Exception {
- mSpyIkeLog = TestUtils.makeSpyLogThrowExceptionForWtf(TAG);
- IkeManager.setIkeLog(mSpyIkeLog);
-
- mIkePrf =
- IkeMacPrf.create(
- new PrfTransform(SaProposal.PSEUDORANDOM_FUNCTION_HMAC_SHA1),
- IkeMessage.getSecurityProvider());
-
- mContext = InstrumentationRegistry.getContext();
- mMockIpSecService = mock(IpSecService.class);
- mMockIpSecManager = new IpSecManager(mContext, mMockIpSecService);
- mMockUdpEncapSocket = mock(UdpEncapsulationSocket.class);
-
- mMockNegotiatedProposal = mock(ChildSaProposal.class);
-
- mSpyUserCbExecutor =
- spy(
- (command) -> {
- command.run();
- });
-
- mMockChildSessionCallback = mock(ChildSessionCallback.class);
- mChildSessionOptions = buildChildSessionOptions();
-
- // Setup thread and looper
- mLooper = new TestLooper();
- mChildSessionStateMachine =
- new ChildSessionStateMachine(
- mLooper.getLooper(),
- mContext,
- mMockIpSecManager,
- mChildSessionOptions,
- mSpyUserCbExecutor,
- mMockChildSessionCallback,
- mMockChildSessionSmCallback);
- mChildSessionStateMachine.setDbg(true);
- SaRecord.setSaRecordHelper(mMockSaRecordHelper);
-
- setUpFirstSaNegoPayloadLists();
- setUpChildSaRecords();
-
- mChildSessionStateMachine.start();
- }
-
- @After
- public void tearDown() {
- mChildSessionStateMachine.setDbg(false);
- IkeManager.resetIkeLog();
- SaRecord.setSaRecordHelper(new SaRecordHelper());
- }
-
- private ChildSaProposal buildSaProposal() throws Exception {
- return new ChildSaProposal.Builder()
- .addEncryptionAlgorithm(
- SaProposal.ENCRYPTION_ALGORITHM_AES_CBC, SaProposal.KEY_LEN_AES_128)
- .addIntegrityAlgorithm(SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96)
- .build();
- }
-
- private ChildSessionOptions buildChildSessionOptions() throws Exception {
- return new TunnelModeChildSessionOptions.Builder()
- .addSaProposal(buildSaProposal())
- .addInternalAddressRequest(AF_INET, 1)
- .addInternalAddressRequest(INTERNAL_ADDRESS, IPV4_PREFIX_LEN)
- .build();
- }
-
- private void setUpChildSaRecords() {
- mSpyCurrentChildSaRecord =
- makeSpyChildSaRecord(CURRENT_CHILD_SA_SPI_IN, CURRENT_CHILD_SA_SPI_OUT);
- mSpyLocalInitNewChildSaRecord =
- makeSpyChildSaRecord(
- LOCAL_INIT_NEW_CHILD_SA_SPI_IN, LOCAL_INIT_NEW_CHILD_SA_SPI_OUT);
- mSpyRemoteInitNewChildSaRecord =
- makeSpyChildSaRecord(
- REMOTE_INIT_NEW_CHILD_SA_SPI_IN, REMOTE_INIT_NEW_CHILD_SA_SPI_OUT);
- }
-
- private void setUpSpiResource(InetAddress address, int spiRequested) throws Exception {
- when(mMockIpSecService.allocateSecurityParameterIndex(
- eq(address.getHostAddress()), anyInt(), anyObject()))
- .thenReturn(MockIpSecTestUtils.buildDummyIpSecSpiResponse(spiRequested));
- }
-
- private void setUpFirstSaNegoPayloadLists() throws Exception {
- // Build locally generated SA payload that has its SPI resource allocated.
- setUpSpiResource(LOCAL_ADDRESS, CURRENT_CHILD_SA_SPI_IN);
- IkeSaPayload reqSaPayload =
- IkeSaPayload.createChildSaRequestPayload(
- mChildSessionOptions.getSaProposals(), mMockIpSecManager, LOCAL_ADDRESS);
- mFirstSaReqPayloads.add(reqSaPayload);
-
- // Build a remotely generated SA payload whoes SPI resource has not been allocated.
- setUpSpiResource(REMOTE_ADDRESS, CURRENT_CHILD_SA_SPI_OUT);
- IkeSaPayload respSaPayload =
- (IkeSaPayload)
- (IkeTestUtils.hexStringToIkePayload(
- IkePayload.PAYLOAD_TYPE_SA, true, IKE_AUTH_RESP_SA_PAYLOAD));
- mFirstSaRespPayloads.add(respSaPayload);
-
- // Build TS Payloads
- IkeTsPayload tsInitPayload =
- new IkeTsPayload(
- true /*isInitiator*/, mChildSessionOptions.getLocalTrafficSelectors());
- IkeTsPayload tsRespPayload =
- new IkeTsPayload(
- false /*isInitiator*/, mChildSessionOptions.getRemoteTrafficSelectors());
-
- mFirstSaReqPayloads.add(tsInitPayload);
- mFirstSaReqPayloads.add(tsRespPayload);
- mFirstSaRespPayloads.add(tsInitPayload);
- mFirstSaRespPayloads.add(tsRespPayload);
-
- // Build Nonce Payloads
- mFirstSaReqPayloads.add(new IkeNoncePayload());
- mFirstSaRespPayloads.add(new IkeNoncePayload());
-
- // Build Config Request Payload
- List<ConfigAttribute> attrReqList = new LinkedList<>();
- attrReqList.add(new ConfigAttributeIpv4Address(INTERNAL_ADDRESS));
- attrReqList.add(new ConfigAttributeIpv4Netmask());
- mFirstSaReqPayloads.add(new IkeConfigPayload(false /*isReply*/, attrReqList));
-
- // Build Config Reply Payload
- List<ConfigAttribute> attrRespList = new LinkedList<>();
- attrRespList.add(new ConfigAttributeIpv4Address(INTERNAL_ADDRESS));
- mFirstSaRespPayloads.add(new IkeConfigPayload(true /*isReply*/, attrRespList));
- }
-
- private ChildSaRecord makeSpyChildSaRecord(int inboundSpi, int outboundSpi) {
- ChildSaRecord child =
- spy(
- new ChildSaRecord(
- inboundSpi,
- outboundSpi,
- true /*localInit*/,
- null,
- null,
- null,
- null,
- null,
- null,
- mock(IpSecTransform.class),
- mock(IpSecTransform.class),
- mock(ChildLocalRequest.class)));
- doNothing().when(child).close();
- return child;
- }
-
- private void quitAndVerify() {
- mChildSessionStateMachine.mCurrentChildSaRecord = null;
- mChildSessionStateMachine.mLocalInitNewChildSaRecord = null;
- mChildSessionStateMachine.mRemoteInitNewChildSaRecord = null;
-
- reset(mMockChildSessionSmCallback);
- mChildSessionStateMachine.quit();
- mLooper.dispatchAll();
-
- verify(mMockChildSessionSmCallback).onProcedureFinished(mChildSessionStateMachine);
- verify(mMockChildSessionSmCallback).onChildSessionClosed(mMockChildSessionCallback);
- }
-
- private void verifyChildSaRecordConfig(
- ChildSaRecordConfig childSaRecordConfig,
- int initSpi,
- int respSpi,
- boolean isLocalInit) {
- assertEquals(mContext, childSaRecordConfig.context);
- assertEquals(initSpi, childSaRecordConfig.initSpi.getSpi());
- assertEquals(respSpi, childSaRecordConfig.respSpi.getSpi());
-
- if (isLocalInit) {
- assertEquals(LOCAL_ADDRESS, childSaRecordConfig.initAddress);
- assertEquals(REMOTE_ADDRESS, childSaRecordConfig.respAddress);
- } else {
- assertEquals(REMOTE_ADDRESS, childSaRecordConfig.initAddress);
- assertEquals(LOCAL_ADDRESS, childSaRecordConfig.respAddress);
- }
-
- assertEquals(mMockUdpEncapSocket, childSaRecordConfig.udpEncapSocket);
- assertEquals(mIkePrf, childSaRecordConfig.ikePrf);
- assertArrayEquals(SK_D, childSaRecordConfig.skD);
- assertFalse(childSaRecordConfig.isTransport);
- assertEquals(isLocalInit, childSaRecordConfig.isLocalInit);
- assertTrue(childSaRecordConfig.hasIntegrityAlgo);
- assertEquals(
- CMD_LOCAL_REQUEST_REKEY_CHILD, childSaRecordConfig.futureRekeyEvent.procedureType);
- assertEquals(
- mMockChildSessionCallback,
- childSaRecordConfig.futureRekeyEvent.childSessionCallback);
- }
-
- private void verifyNotifyUsersCreateIpSecSa(
- ChildSaRecord childSaRecord, boolean expectInbound) {
- IpSecTransform transform =
- expectInbound
- ? childSaRecord.getInboundIpSecTransform()
- : childSaRecord.getOutboundIpSecTransform();
- int direction = expectInbound ? IpSecManager.DIRECTION_IN : IpSecManager.DIRECTION_OUT;
-
- verify(mMockChildSessionCallback).onIpSecTransformCreated(eq(transform), eq(direction));
- }
-
- private void verifyInitCreateChildResp(
- List<IkePayload> reqPayloads, List<IkePayload> respPayloads) throws Exception {
- verify(mMockChildSessionSmCallback)
- .onChildSaCreated(
- mSpyCurrentChildSaRecord.getRemoteSpi(), mChildSessionStateMachine);
- verify(mMockChildSessionSmCallback).onProcedureFinished(mChildSessionStateMachine);
- assertTrue(
- mChildSessionStateMachine.getCurrentState()
- instanceof ChildSessionStateMachine.Idle);
-
- // Validate negotiated SA proposal.
- ChildSaProposal negotiatedProposal = mChildSessionStateMachine.mSaProposal;
- assertNotNull(negotiatedProposal);
- assertEquals(
- new EncryptionTransform[] {mChildEncryptionTransform},
- negotiatedProposal.getEncryptionTransforms());
- assertEquals(
- new IntegrityTransform[] {mChildIntegrityTransform},
- negotiatedProposal.getIntegrityTransforms());
-
- // Validate current ChildSaRecord
- verify(mMockSaRecordHelper)
- .makeChildSaRecord(
- eq(reqPayloads), eq(respPayloads), mChildSaRecordConfigCaptor.capture());
- ChildSaRecordConfig childSaRecordConfig = mChildSaRecordConfigCaptor.getValue();
-
- verifyChildSaRecordConfig(
- childSaRecordConfig,
- CURRENT_CHILD_SA_SPI_IN,
- CURRENT_CHILD_SA_SPI_OUT,
- true /*isLocalInit*/);
-
- assertEquals(mSpyCurrentChildSaRecord, mChildSessionStateMachine.mCurrentChildSaRecord);
-
- verify(mMockChildSessionSmCallback)
- .onChildSaCreated(anyInt(), eq(mChildSessionStateMachine));
- verify(mMockChildSessionSmCallback)
- .scheduleLocalRequest(argThat(mRekeyChildLocalReqMatcher), anyLong());
- verify(mMockChildSessionSmCallback).onProcedureFinished(mChildSessionStateMachine);
- assertTrue(
- mChildSessionStateMachine.getCurrentState()
- instanceof ChildSessionStateMachine.Idle);
-
- // Verify users have been notified
- verify(mSpyUserCbExecutor).execute(any(Runnable.class));
- verifyNotifyUsersCreateIpSecSa(mSpyCurrentChildSaRecord, true /*expectInbound*/);
- verifyNotifyUsersCreateIpSecSa(mSpyCurrentChildSaRecord, false /*expectInbound*/);
- verify(mMockChildSessionCallback).onOpened(mChildConfigCaptor.capture());
-
- // Verify Child Session Configuration
- ChildSessionConfiguration sessionConfig = mChildConfigCaptor.getValue();
- verifyTsList(
- Arrays.asList(mChildSessionOptions.getLocalTrafficSelectors()),
- sessionConfig.getInboundTrafficSelectors());
- verifyTsList(
- Arrays.asList(mChildSessionOptions.getRemoteTrafficSelectors()),
- sessionConfig.getOutboundTrafficSelectors());
-
- List<LinkAddress> addrList = sessionConfig.getInternalAddressList();
- assertEquals(1, addrList.size());
- assertEquals(INTERNAL_ADDRESS, addrList.get(0).getAddress());
- assertEquals(IPV4_PREFIX_LEN, addrList.get(0).getPrefixLength());
- }
-
- private void verifyTsList(
- List<IkeTrafficSelector> expectedList, List<IkeTrafficSelector> tsList) {
- assertEquals(expectedList.size(), tsList.size());
- for (int i = 0; i < expectedList.size(); i++) {
- assertEquals(expectedList.get(i), tsList.get(i));
- }
- }
-
- @Test
- public void testCreateFirstChild() throws Exception {
- when(mMockSaRecordHelper.makeChildSaRecord(any(), any(), any()))
- .thenReturn(mSpyCurrentChildSaRecord);
-
- mChildSessionStateMachine.handleFirstChildExchange(
- mFirstSaReqPayloads,
- mFirstSaRespPayloads,
- LOCAL_ADDRESS,
- REMOTE_ADDRESS,
- mMockUdpEncapSocket,
- mIkePrf,
- SK_D);
- mLooper.dispatchAll();
-
- verifyInitCreateChildResp(mFirstSaReqPayloads, mFirstSaRespPayloads);
-
- quitAndVerify();
- }
-
- private void verifyOutboundCreatePayloadTypes(
- List<IkePayload> outboundPayloads, boolean isRekey) {
- assertNotNull(
- IkePayload.getPayloadForTypeInProvidedList(
- PAYLOAD_TYPE_SA, IkeSaPayload.class, outboundPayloads));
- assertNotNull(
- IkePayload.getPayloadForTypeInProvidedList(
- PAYLOAD_TYPE_TS_INITIATOR, IkeTsPayload.class, outboundPayloads));
- assertNotNull(
- IkePayload.getPayloadForTypeInProvidedList(
- PAYLOAD_TYPE_TS_RESPONDER, IkeTsPayload.class, outboundPayloads));
- assertNotNull(
- IkePayload.getPayloadForTypeInProvidedList(
- PAYLOAD_TYPE_NONCE, IkeNoncePayload.class, outboundPayloads));
- assertNull(
- IkePayload.getPayloadForTypeInProvidedList(
- PAYLOAD_TYPE_KE, IkeKePayload.class, outboundPayloads));
-
- IkeConfigPayload configPayload =
- IkePayload.getPayloadForTypeInProvidedList(
- PAYLOAD_TYPE_CP, IkeConfigPayload.class, outboundPayloads);
- if (isRekey) {
- assertNull(configPayload);
- } else {
- assertNotNull(configPayload);
- assertEquals(IkeConfigPayload.CONFIG_TYPE_REQUEST, configPayload.configType);
- }
- }
-
- @Test
- public void testCreateChild() throws Exception {
- when(mMockSaRecordHelper.makeChildSaRecord(any(), any(), any()))
- .thenReturn(mSpyCurrentChildSaRecord);
-
- mChildSessionStateMachine.createChildSession(
- LOCAL_ADDRESS, REMOTE_ADDRESS, mMockUdpEncapSocket, mIkePrf, SK_D);
- mLooper.dispatchAll();
-
- // Validate outbound payload list
- verify(mMockChildSessionSmCallback)
- .onOutboundPayloadsReady(
- eq(EXCHANGE_TYPE_CREATE_CHILD_SA),
- eq(false),
- mPayloadListCaptor.capture(),
- eq(mChildSessionStateMachine));
-
- List<IkePayload> reqPayloadList = mPayloadListCaptor.getValue();
- verifyOutboundCreatePayloadTypes(reqPayloadList, false /*isRekey*/);
- assertTrue(
- IkePayload.getPayloadListForTypeInProvidedList(
- PAYLOAD_TYPE_NOTIFY, IkeNotifyPayload.class, reqPayloadList)
- .isEmpty());
-
- mChildSessionStateMachine.receiveResponse(
- EXCHANGE_TYPE_CREATE_CHILD_SA, mFirstSaRespPayloads);
- mLooper.dispatchAll();
-
- verifyInitCreateChildResp(reqPayloadList, mFirstSaRespPayloads);
-
- quitAndVerify();
- }
-
- private <T extends IkeException> void verifyHandleFatalErrorAndQuit(Class<T> exceptionClass) {
- assertNull(mChildSessionStateMachine.getCurrentState());
- verify(mMockChildSessionSmCallback).onProcedureFinished(mChildSessionStateMachine);
- verify(mMockChildSessionSmCallback).onChildSessionClosed(mMockChildSessionCallback);
-
- verify(mMockChildSessionCallback).onClosedExceptionally(any(exceptionClass));
- }
-
- @Test
- public void testCreateChildHandlesErrorNotifyResp() throws Exception {
- // Send out Create request
- mChildSessionStateMachine.createChildSession(
- LOCAL_ADDRESS, REMOTE_ADDRESS, mMockUdpEncapSocket, mIkePrf, SK_D);
- mLooper.dispatchAll();
-
- // Receive error notification in Create response
- IkeNotifyPayload notifyPayload = new IkeNotifyPayload(ERROR_TYPE_NO_PROPOSAL_CHOSEN);
- List<IkePayload> respPayloads = new LinkedList<>();
- respPayloads.add(notifyPayload);
- mChildSessionStateMachine.receiveResponse(EXCHANGE_TYPE_CREATE_CHILD_SA, respPayloads);
- mLooper.dispatchAll();
-
- // Verify no SPI for provisional Child was registered.
- verify(mMockChildSessionSmCallback, never())
- .onChildSaCreated(anyInt(), eq(mChildSessionStateMachine));
-
- // Verify user was notified and state machine has quit.
- verifyHandleFatalErrorAndQuit(NoValidProposalChosenException.class);
- }
-
- @Test
- public void testCreateChildHandlesRespWithMissingPayload() throws Exception {
- // Send out Create request
- mChildSessionStateMachine.createChildSession(
- LOCAL_ADDRESS, REMOTE_ADDRESS, mMockUdpEncapSocket, mIkePrf, SK_D);
- mLooper.dispatchAll();
-
- // Receive response with no Nonce Payload
- List<IkePayload> respPayloads = new LinkedList<>();
- for (IkePayload payload : mFirstSaRespPayloads) {
- if (IkePayload.PAYLOAD_TYPE_NONCE == payload.payloadType) continue;
- respPayloads.add(payload);
- }
- mChildSessionStateMachine.receiveResponse(EXCHANGE_TYPE_CREATE_CHILD_SA, respPayloads);
- mLooper.dispatchAll();
-
- // Verify SPI for provisional Child was registered and unregistered.
- verify(mMockChildSessionSmCallback)
- .onChildSaCreated(CURRENT_CHILD_SA_SPI_OUT, mChildSessionStateMachine);
- verify(mMockChildSessionSmCallback).onChildSaDeleted(CURRENT_CHILD_SA_SPI_OUT);
-
- // Verify user was notified and state machine has quit.
- verifyHandleFatalErrorAndQuit(InvalidSyntaxException.class);
- }
-
- @Test
- public void testCreateChildHandlesKeyCalculationFail() throws Exception {
- // Throw exception when building ChildSaRecord
- when(mMockSaRecordHelper.makeChildSaRecord(any(), any(), any()))
- .thenThrow(
- new GeneralSecurityException("testCreateChildHandlesKeyCalculationFail"));
-
- // Send out and receive Create Child message
- mChildSessionStateMachine.createChildSession(
- LOCAL_ADDRESS, REMOTE_ADDRESS, mMockUdpEncapSocket, mIkePrf, SK_D);
- mLooper.dispatchAll();
- mChildSessionStateMachine.receiveResponse(
- EXCHANGE_TYPE_CREATE_CHILD_SA, mFirstSaRespPayloads);
- mLooper.dispatchAll();
-
- // Verify SPI for provisional Child was registered and unregistered.
- verify(mMockChildSessionSmCallback)
- .onChildSaCreated(CURRENT_CHILD_SA_SPI_OUT, mChildSessionStateMachine);
- verify(mMockChildSessionSmCallback).onChildSaDeleted(CURRENT_CHILD_SA_SPI_OUT);
-
- // Verify user was notified and state machine has quit.
- verifyHandleFatalErrorAndQuit(IkeInternalException.class);
- }
-
- private void setupIdleStateMachine() throws Exception {
- mChildSessionStateMachine.mLocalAddress = LOCAL_ADDRESS;
- mChildSessionStateMachine.mRemoteAddress = REMOTE_ADDRESS;
- mChildSessionStateMachine.mUdpEncapSocket = mMockUdpEncapSocket;
- mChildSessionStateMachine.mIkePrf = mIkePrf;
- mChildSessionStateMachine.mSkD = SK_D;
-
- mChildSessionStateMachine.mSaProposal = buildSaProposal();
- mChildSessionStateMachine.mChildCipher = mock(IkeCipher.class);
- mChildSessionStateMachine.mChildIntegrity = mock(IkeMacIntegrity.class);
- mChildSessionStateMachine.mLocalTs = mChildSessionOptions.getLocalTrafficSelectors();
- mChildSessionStateMachine.mRemoteTs = mChildSessionOptions.getRemoteTrafficSelectors();
-
- mChildSessionStateMachine.mCurrentChildSaRecord = mSpyCurrentChildSaRecord;
-
- mChildSessionStateMachine.sendMessage(
- CMD_FORCE_TRANSITION, mChildSessionStateMachine.mIdle);
- mLooper.dispatchAll();
-
- assertTrue(
- mChildSessionStateMachine.getCurrentState()
- instanceof ChildSessionStateMachine.Idle);
- }
-
- private List<IkePayload> makeDeletePayloads(int spi) {
- List<IkePayload> inboundPayloads = new ArrayList<>(1);
- inboundPayloads.add(new IkeDeletePayload(new int[] {spi}));
- return inboundPayloads;
- }
-
- private void verifyOutboundDeletePayload(int expectedSpi, boolean isResp) {
- verify(mMockChildSessionSmCallback)
- .onOutboundPayloadsReady(
- eq(EXCHANGE_TYPE_INFORMATIONAL),
- eq(isResp),
- mPayloadListCaptor.capture(),
- eq(mChildSessionStateMachine));
-
- List<IkePayload> outPayloadList = mPayloadListCaptor.getValue();
- assertEquals(1, outPayloadList.size());
-
- List<IkeDeletePayload> deletePayloads =
- IkePayload.getPayloadListForTypeInProvidedList(
- PAYLOAD_TYPE_DELETE, IkeDeletePayload.class, outPayloadList);
- assertEquals(1, deletePayloads.size());
- IkeDeletePayload deletePayload = deletePayloads.get(0);
- assertEquals(expectedSpi, deletePayload.spisToDelete[0]);
- }
-
- private void verifyNotifyUserDeleteChildSa(ChildSaRecord childSaRecord) {
- verify(mMockChildSessionCallback)
- .onIpSecTransformDeleted(
- eq(childSaRecord.getInboundIpSecTransform()),
- eq(IpSecManager.DIRECTION_IN));
- verify(mMockChildSessionCallback)
- .onIpSecTransformDeleted(
- eq(childSaRecord.getOutboundIpSecTransform()),
- eq(IpSecManager.DIRECTION_OUT));
- }
-
- private void verifyNotifyUsersDeleteSession() {
- verify(mSpyUserCbExecutor).execute(any(Runnable.class));
- verify(mMockChildSessionCallback).onClosed();
- verifyNotifyUserDeleteChildSa(mSpyCurrentChildSaRecord);
- }
-
- @Test
- public void testDeleteChildLocal() throws Exception {
- setupIdleStateMachine();
-
- // Test initiating Delete request
- mChildSessionStateMachine.deleteChildSession();
- mLooper.dispatchAll();
-
- assertTrue(
- mChildSessionStateMachine.getCurrentState()
- instanceof ChildSessionStateMachine.DeleteChildLocalDelete);
- verifyOutboundDeletePayload(mSpyCurrentChildSaRecord.getLocalSpi(), false /*isResp*/);
-
- // Test receiving Delete response
- mChildSessionStateMachine.receiveResponse(
- EXCHANGE_TYPE_INFORMATIONAL,
- makeDeletePayloads(mSpyCurrentChildSaRecord.getRemoteSpi()));
- mLooper.dispatchAll();
-
- assertNull(mChildSessionStateMachine.getCurrentState());
-
- verifyNotifyUsersDeleteSession();
- }
-
- @Test
- public void testDeleteChildLocalHandlesInvalidResp() throws Exception {
- setupIdleStateMachine();
-
- // Test initiating Delete request
- mChildSessionStateMachine.deleteChildSession();
- mLooper.dispatchAll();
-
- // Test receiving response with no Delete Payload
- mChildSessionStateMachine.receiveResponse(EXCHANGE_TYPE_INFORMATIONAL, new LinkedList<>());
- mLooper.dispatchAll();
-
- assertNull(mChildSessionStateMachine.getCurrentState());
- verify(mMockChildSessionCallback).onClosedExceptionally(any(InvalidSyntaxException.class));
- verifyNotifyUserDeleteChildSa(mSpyCurrentChildSaRecord);
- }
-
- @Test
- public void testDeleteChildLocalInInitial() throws Exception {
- mChildSessionStateMachine.deleteChildSession();
- mLooper.dispatchAll();
-
- assertNull(mChildSessionStateMachine.getCurrentState());
- verify(mSpyUserCbExecutor).execute(any(Runnable.class));
- verify(mMockChildSessionCallback).onClosed();
- }
-
- @Test
- public void testSimultaneousDeleteChild() throws Exception {
- setupIdleStateMachine();
-
- mChildSessionStateMachine.deleteChildSession();
- mChildSessionStateMachine.receiveRequest(
- IKE_EXCHANGE_SUBTYPE_DELETE_CHILD,
- EXCHANGE_TYPE_INFORMATIONAL,
- makeDeletePayloads(mSpyCurrentChildSaRecord.getRemoteSpi()));
- mLooper.dispatchAll();
-
- verify(mMockChildSessionSmCallback)
- .onOutboundPayloadsReady(
- eq(EXCHANGE_TYPE_INFORMATIONAL),
- eq(true),
- mPayloadListCaptor.capture(),
- eq(mChildSessionStateMachine));
- List<IkePayload> respPayloadList = mPayloadListCaptor.getValue();
- assertTrue(respPayloadList.isEmpty());
-
- mChildSessionStateMachine.receiveResponse(EXCHANGE_TYPE_INFORMATIONAL, new LinkedList<>());
- mLooper.dispatchAll();
-
- assertNull(mChildSessionStateMachine.getCurrentState());
-
- verifyNotifyUsersDeleteSession();
- }
-
- @Test
- public void testReplyRekeyRequestDuringDeletion() throws Exception {
- setupIdleStateMachine();
-
- mChildSessionStateMachine.deleteChildSession();
- mChildSessionStateMachine.receiveRequest(
- IKE_EXCHANGE_SUBTYPE_REKEY_CHILD, EXCHANGE_TYPE_CREATE_CHILD_SA, mock(List.class));
- mLooper.dispatchAll();
-
- // Verify outbound response to Rekey Child request
- verify(mMockChildSessionSmCallback)
- .onOutboundPayloadsReady(
- eq(EXCHANGE_TYPE_INFORMATIONAL),
- eq(true),
- mPayloadListCaptor.capture(),
- eq(mChildSessionStateMachine));
- List<IkePayload> respPayloadList = mPayloadListCaptor.getValue();
- assertEquals(1, respPayloadList.size());
-
- IkeNotifyPayload notifyPayload = (IkeNotifyPayload) respPayloadList.get(0);
- assertEquals(ERROR_TYPE_TEMPORARY_FAILURE, notifyPayload.notifyType);
- assertEquals(0, notifyPayload.notifyData.length);
-
- assertTrue(
- mChildSessionStateMachine.getCurrentState()
- instanceof ChildSessionStateMachine.DeleteChildLocalDelete);
- }
-
- @Test
- public void testDeleteChildRemote() throws Exception {
- setupIdleStateMachine();
-
- mChildSessionStateMachine.receiveRequest(
- IKE_EXCHANGE_SUBTYPE_DELETE_CHILD,
- EXCHANGE_TYPE_INFORMATIONAL,
- makeDeletePayloads(mSpyCurrentChildSaRecord.getRemoteSpi()));
- mLooper.dispatchAll();
-
- assertNull(mChildSessionStateMachine.getCurrentState());
- // Verify response
- verify(mMockChildSessionSmCallback)
- .onOutboundPayloadsReady(
- eq(EXCHANGE_TYPE_INFORMATIONAL),
- eq(true),
- mPayloadListCaptor.capture(),
- eq(mChildSessionStateMachine));
- List<IkePayload> respPayloadList = mPayloadListCaptor.getValue();
-
- assertEquals(1, respPayloadList.size());
- assertArrayEquals(
- new int[] {mSpyCurrentChildSaRecord.getLocalSpi()},
- ((IkeDeletePayload) respPayloadList.get(0)).spisToDelete);
-
- verifyNotifyUsersDeleteSession();
- }
-
- private void verifyOutboundRekeySaPayload(List<IkePayload> outboundPayloads, boolean isResp) {
- IkeSaPayload saPayload =
- IkePayload.getPayloadForTypeInProvidedList(
- PAYLOAD_TYPE_SA, IkeSaPayload.class, outboundPayloads);
- assertEquals(isResp, saPayload.isSaResponse);
- assertEquals(1, saPayload.proposalList.size());
-
- IkeSaPayload.ChildProposal proposal =
- (IkeSaPayload.ChildProposal) saPayload.proposalList.get(0);
- assertEquals(1, proposal.number); // Must be 1-indexed
- assertEquals(mChildSessionStateMachine.mSaProposal, proposal.saProposal);
- }
-
- private void verifyOutboundRekeyNotifyPayload(List<IkePayload> outboundPayloads) {
- List<IkeNotifyPayload> notifyPayloads =
- IkePayload.getPayloadListForTypeInProvidedList(
- PAYLOAD_TYPE_NOTIFY, IkeNotifyPayload.class, outboundPayloads);
- assertEquals(1, notifyPayloads.size());
- IkeNotifyPayload notifyPayload = notifyPayloads.get(0);
- assertEquals(NOTIFY_TYPE_REKEY_SA, notifyPayload.notifyType);
- assertEquals(PROTOCOL_ID_ESP, notifyPayload.protocolId);
- assertEquals(mSpyCurrentChildSaRecord.getLocalSpi(), notifyPayload.spi);
- }
-
- @Test
- public void testRekeyChildLocalCreateSendsRequest() throws Exception {
- setupIdleStateMachine();
-
- // Send Rekey-Create request
- mChildSessionStateMachine.rekeyChildSession();
- mLooper.dispatchAll();
- assertTrue(
- mChildSessionStateMachine.getCurrentState()
- instanceof ChildSessionStateMachine.RekeyChildLocalCreate);
- verify(mMockChildSessionSmCallback)
- .onOutboundPayloadsReady(
- eq(EXCHANGE_TYPE_CREATE_CHILD_SA),
- eq(false),
- mPayloadListCaptor.capture(),
- eq(mChildSessionStateMachine));
-
- // Verify outbound payload list
- List<IkePayload> reqPayloadList = mPayloadListCaptor.getValue();
- verifyOutboundCreatePayloadTypes(reqPayloadList, true /*isRekey*/);
-
- verifyOutboundRekeySaPayload(reqPayloadList, false /*isResp*/);
- verifyOutboundRekeyNotifyPayload(reqPayloadList);
- }
-
- private List<IkePayload> makeInboundRekeyChildPayloads(
- int remoteSpi, String inboundSaHexString, boolean isLocalInitRekey) throws Exception {
- List<IkePayload> inboundPayloads = new LinkedList<>();
-
- IkeSaPayload saPayload =
- (IkeSaPayload)
- (IkeTestUtils.hexStringToIkePayload(
- IkePayload.PAYLOAD_TYPE_SA, true, inboundSaHexString));
- inboundPayloads.add(saPayload);
-
- // Build TS Payloads
- IkeTrafficSelector[] initTs =
- isLocalInitRekey
- ? mChildSessionStateMachine.mLocalTs
- : mChildSessionStateMachine.mRemoteTs;
- IkeTrafficSelector[] respTs =
- isLocalInitRekey
- ? mChildSessionStateMachine.mRemoteTs
- : mChildSessionStateMachine.mLocalTs;
- inboundPayloads.add(new IkeTsPayload(true /*isInitiator*/, initTs));
- inboundPayloads.add(new IkeTsPayload(false /*isInitiator*/, respTs));
-
- // Build Nonce Payloads
- inboundPayloads.add(new IkeNoncePayload());
-
- if (isLocalInitRekey) {
- // Rekey-Create response without Notify-Rekey payload is valid.
- return inboundPayloads;
- }
-
- // Build Rekey-Notification
- inboundPayloads.add(
- new IkeNotifyPayload(
- PROTOCOL_ID_ESP,
- mSpyCurrentChildSaRecord.getRemoteSpi(),
- NOTIFY_TYPE_REKEY_SA,
- new byte[0]));
-
- return inboundPayloads;
- }
-
- @Test
- public void testRekeyChildLocalCreateValidatesResponse() throws Exception {
- setupIdleStateMachine();
- setUpSpiResource(LOCAL_ADDRESS, LOCAL_INIT_NEW_CHILD_SA_SPI_IN);
- setUpSpiResource(REMOTE_ADDRESS, LOCAL_INIT_NEW_CHILD_SA_SPI_OUT);
-
- // Send Rekey-Create request
- mChildSessionStateMachine.rekeyChildSession();
- mLooper.dispatchAll();
- assertTrue(
- mChildSessionStateMachine.getCurrentState()
- instanceof ChildSessionStateMachine.RekeyChildLocalCreate);
-
- // Prepare "rekeyed" SA and receive Rekey response
- List<IkePayload> rekeyRespPayloads =
- makeInboundRekeyChildPayloads(
- LOCAL_INIT_NEW_CHILD_SA_SPI_OUT,
- REKEY_CHILD_RESP_SA_PAYLOAD,
- true /*isLocalInitRekey*/);
- when(mMockSaRecordHelper.makeChildSaRecord(
- any(List.class), eq(rekeyRespPayloads), any(ChildSaRecordConfig.class)))
- .thenReturn(mSpyLocalInitNewChildSaRecord);
-
- mChildSessionStateMachine.receiveResponse(EXCHANGE_TYPE_CREATE_CHILD_SA, rekeyRespPayloads);
- mLooper.dispatchAll();
-
- // Verify state transition
- assertTrue(
- mChildSessionStateMachine.getCurrentState()
- instanceof ChildSessionStateMachine.RekeyChildLocalDelete);
-
- // Verify newly created ChildSaRecord
- assertEquals(
- mSpyLocalInitNewChildSaRecord,
- mChildSessionStateMachine.mLocalInitNewChildSaRecord);
- verify(mMockChildSessionSmCallback)
- .onChildSaCreated(
- eq(mSpyLocalInitNewChildSaRecord.getRemoteSpi()),
- eq(mChildSessionStateMachine));
- verify(mMockChildSessionSmCallback)
- .scheduleLocalRequest(argThat(mRekeyChildLocalReqMatcher), anyLong());
-
- verify(mMockSaRecordHelper)
- .makeChildSaRecord(
- any(List.class),
- eq(rekeyRespPayloads),
- mChildSaRecordConfigCaptor.capture());
- ChildSaRecordConfig childSaRecordConfig = mChildSaRecordConfigCaptor.getValue();
- verifyChildSaRecordConfig(
- childSaRecordConfig,
- LOCAL_INIT_NEW_CHILD_SA_SPI_IN,
- LOCAL_INIT_NEW_CHILD_SA_SPI_OUT,
- true /*isLocalInit*/);
-
- // Verify users have been notified
- verify(mSpyUserCbExecutor).execute(any(Runnable.class));
- verifyNotifyUsersCreateIpSecSa(mSpyLocalInitNewChildSaRecord, true /*expectInbound*/);
- verifyNotifyUsersCreateIpSecSa(mSpyLocalInitNewChildSaRecord, false /*expectInbound*/);
- }
-
- @Test
- public void testRekeyLocalCreateHandlesErrorNotifyResp() throws Exception {
- setupIdleStateMachine();
- setUpSpiResource(LOCAL_ADDRESS, LOCAL_INIT_NEW_CHILD_SA_SPI_IN);
-
- // Send Rekey-Create request
- mChildSessionStateMachine.rekeyChildSession();
- mLooper.dispatchAll();
-
- // Receive error notification in Create response
- IkeNotifyPayload notifyPayload = new IkeNotifyPayload(ERROR_TYPE_INTERNAL_ADDRESS_FAILURE);
- List<IkePayload> respPayloads = new LinkedList<>();
- respPayloads.add(notifyPayload);
- mChildSessionStateMachine.receiveResponse(EXCHANGE_TYPE_CREATE_CHILD_SA, respPayloads);
- mLooper.dispatchAll();
-
- // Verify rekey has been rescheduled and Child Session is alive
- verify(mMockChildSessionSmCallback)
- .scheduleRetryLocalRequest(
- (ChildLocalRequest) mSpyCurrentChildSaRecord.getFutureRekeyEvent());
- assertTrue(
- mChildSessionStateMachine.getCurrentState()
- instanceof ChildSessionStateMachine.Idle);
-
- // Verify no SPI for provisional Child was registered.
- verify(mMockChildSessionSmCallback, never())
- .onChildSaCreated(anyInt(), eq(mChildSessionStateMachine));
- }
-
- @Test
- public void testRekeyLocalCreateHandlesRespWithMissingPayload() throws Exception {
- setupIdleStateMachine();
- setUpSpiResource(LOCAL_ADDRESS, LOCAL_INIT_NEW_CHILD_SA_SPI_IN);
- reset(mMockChildSessionSmCallback);
-
- // Send Rekey-Create request
- mChildSessionStateMachine.rekeyChildSession();
- mLooper.dispatchAll();
-
- // Receive response with no SA Payload
- List<IkePayload> validRekeyRespPayloads =
- makeInboundRekeyChildPayloads(
- LOCAL_INIT_NEW_CHILD_SA_SPI_OUT,
- REKEY_CHILD_RESP_SA_PAYLOAD,
- true /*isLocalInitRekey*/);
- List<IkePayload> respPayloads = new LinkedList<>();
- for (IkePayload payload : validRekeyRespPayloads) {
- if (IkePayload.PAYLOAD_TYPE_SA == payload.payloadType) continue;
- respPayloads.add(payload);
- }
- mChildSessionStateMachine.receiveResponse(EXCHANGE_TYPE_CREATE_CHILD_SA, respPayloads);
- mLooper.dispatchAll();
-
- // Verify user was notified and state machine has quit.
- verifyHandleFatalErrorAndQuit(InvalidSyntaxException.class);
- verifyNotifyUserDeleteChildSa(mSpyCurrentChildSaRecord);
-
- // Verify no SPI for provisional Child was registered.
- verify(mMockChildSessionSmCallback, never())
- .onChildSaCreated(anyInt(), eq(mChildSessionStateMachine));
-
- // Verify retry was not scheduled
- verify(mMockChildSessionSmCallback, never()).scheduleRetryLocalRequest(any());
- }
-
- @Test
- public void testRekeyLocalCreateChildHandlesKeyCalculationFail() throws Exception {
- // Throw exception when building ChildSaRecord
- when(mMockSaRecordHelper.makeChildSaRecord(any(), any(), any()))
- .thenThrow(
- new GeneralSecurityException(
- "testRekeyCreateChildHandlesKeyCalculationFail"));
-
- // Setup for rekey negotiation
- setupIdleStateMachine();
- setUpSpiResource(LOCAL_ADDRESS, LOCAL_INIT_NEW_CHILD_SA_SPI_IN);
- setUpSpiResource(REMOTE_ADDRESS, LOCAL_INIT_NEW_CHILD_SA_SPI_OUT);
- reset(mMockChildSessionSmCallback);
-
- // Send Rekey-Create request
- mChildSessionStateMachine.rekeyChildSession();
- mLooper.dispatchAll();
- assertTrue(
- mChildSessionStateMachine.getCurrentState()
- instanceof ChildSessionStateMachine.RekeyChildLocalCreate);
-
- // Receive Rekey response
- List<IkePayload> rekeyRespPayloads =
- makeInboundRekeyChildPayloads(
- LOCAL_INIT_NEW_CHILD_SA_SPI_OUT,
- REKEY_CHILD_RESP_SA_PAYLOAD,
- true /*isLocalInitRekey*/);
- mChildSessionStateMachine.receiveResponse(EXCHANGE_TYPE_CREATE_CHILD_SA, rekeyRespPayloads);
- mLooper.dispatchAll();
-
- // Verify user was notified and state machine has quit.
- verifyHandleFatalErrorAndQuit(IkeInternalException.class);
- verifyNotifyUserDeleteChildSa(mSpyCurrentChildSaRecord);
-
- // Verify SPI for provisional Child was registered and unregistered.
- verify(mMockChildSessionSmCallback)
- .onChildSaCreated(LOCAL_INIT_NEW_CHILD_SA_SPI_OUT, mChildSessionStateMachine);
- verify(mMockChildSessionSmCallback).onChildSaDeleted(LOCAL_INIT_NEW_CHILD_SA_SPI_OUT);
-
- // Verify retry was not scheduled
- verify(mMockChildSessionSmCallback, never()).scheduleRetryLocalRequest(any());
- }
-
- @Test
- public void testRekeyChildLocalDeleteSendsRequest() throws Exception {
- setupIdleStateMachine();
-
- // Seed fake rekey data and force transition to RekeyChildLocalDelete
- mChildSessionStateMachine.mLocalInitNewChildSaRecord = mSpyLocalInitNewChildSaRecord;
- mChildSessionStateMachine.sendMessage(
- CMD_FORCE_TRANSITION, mChildSessionStateMachine.mRekeyChildLocalDelete);
- mLooper.dispatchAll();
-
- // Verify outbound delete request
- assertTrue(
- mChildSessionStateMachine.getCurrentState()
- instanceof ChildSessionStateMachine.RekeyChildLocalDelete);
- verifyOutboundDeletePayload(mSpyCurrentChildSaRecord.getLocalSpi(), false /*isResp*/);
-
- assertEquals(mSpyCurrentChildSaRecord, mChildSessionStateMachine.mCurrentChildSaRecord);
- assertEquals(
- mSpyLocalInitNewChildSaRecord, mChildSessionStateMachine.mChildSaRecordSurviving);
- }
-
- void verifyChildSaUpdated(ChildSaRecord oldSaRecord, ChildSaRecord newSaRecord) {
- verify(mMockChildSessionSmCallback).onChildSaDeleted(oldSaRecord.getRemoteSpi());
- verify(oldSaRecord).close();
-
- assertNull(mChildSessionStateMachine.mChildSaRecordSurviving);
- assertEquals(newSaRecord, mChildSessionStateMachine.mCurrentChildSaRecord);
- }
-
- @Test
- public void testRekeyChildLocalDeleteValidatesResponse() throws Exception {
- setupIdleStateMachine();
-
- // Seed fake rekey data and force transition to RekeyChildLocalDelete
- mChildSessionStateMachine.mLocalInitNewChildSaRecord = mSpyLocalInitNewChildSaRecord;
- mChildSessionStateMachine.sendMessage(
- CMD_FORCE_TRANSITION, mChildSessionStateMachine.mRekeyChildLocalDelete);
- mLooper.dispatchAll();
-
- // Test receiving Delete response
- mChildSessionStateMachine.receiveResponse(
- EXCHANGE_TYPE_INFORMATIONAL,
- makeDeletePayloads(mSpyCurrentChildSaRecord.getRemoteSpi()));
- mLooper.dispatchAll();
-
- assertTrue(
- mChildSessionStateMachine.getCurrentState()
- instanceof ChildSessionStateMachine.Idle);
-
- // First invoked in #setupIdleStateMachine
- verify(mMockChildSessionSmCallback, times(2))
- .onProcedureFinished(mChildSessionStateMachine);
-
- verifyChildSaUpdated(mSpyCurrentChildSaRecord, mSpyLocalInitNewChildSaRecord);
-
- verify(mSpyUserCbExecutor).execute(any(Runnable.class));
- verify(mMockChildSessionCallback, never()).onClosed();
- verifyNotifyUserDeleteChildSa(mSpyCurrentChildSaRecord);
- }
-
- @Test
- public void testRekeyChildLocalDeleteHandlesInvalidResp() throws Exception {
- setupIdleStateMachine();
-
- // Seed fake rekey data and force transition to RekeyChildLocalDelete
- mChildSessionStateMachine.mLocalInitNewChildSaRecord = mSpyLocalInitNewChildSaRecord;
- mChildSessionStateMachine.sendMessage(
- CMD_FORCE_TRANSITION, mChildSessionStateMachine.mRekeyChildLocalDelete);
- mLooper.dispatchAll();
-
- // Test receiving Delete response with missing Delete payload
- mChildSessionStateMachine.receiveResponse(
- EXCHANGE_TYPE_INFORMATIONAL, new ArrayList<IkePayload>());
- mLooper.dispatchAll();
-
- // Verify rekey has finished
- assertTrue(
- mChildSessionStateMachine.getCurrentState()
- instanceof ChildSessionStateMachine.Idle);
- verifyChildSaUpdated(mSpyCurrentChildSaRecord, mSpyLocalInitNewChildSaRecord);
- verifyNotifyUserDeleteChildSa(mSpyCurrentChildSaRecord);
-
- // First invoked in #setupIdleStateMachine
- verify(mMockChildSessionSmCallback, times(2))
- .onProcedureFinished(mChildSessionStateMachine);
- }
-
- @Test
- public void testRekeyChildRemoteCreate() throws Exception {
- setupIdleStateMachine();
-
- // Setup for new Child SA negotiation.
- setUpSpiResource(LOCAL_ADDRESS, REMOTE_INIT_NEW_CHILD_SA_SPI_IN);
- setUpSpiResource(REMOTE_ADDRESS, REMOTE_INIT_NEW_CHILD_SA_SPI_OUT);
-
- List<IkePayload> rekeyReqPayloads =
- makeInboundRekeyChildPayloads(
- REMOTE_INIT_NEW_CHILD_SA_SPI_OUT,
- REKEY_CHILD_REQ_SA_PAYLOAD,
- false /*isLocalInitRekey*/);
- when(mMockSaRecordHelper.makeChildSaRecord(
- eq(rekeyReqPayloads), any(List.class), any(ChildSaRecordConfig.class)))
- .thenReturn(mSpyRemoteInitNewChildSaRecord);
-
- // Receive rekey Child request
- mChildSessionStateMachine.receiveRequest(
- IKE_EXCHANGE_SUBTYPE_REKEY_CHILD, EXCHANGE_TYPE_CREATE_CHILD_SA, rekeyReqPayloads);
- mLooper.dispatchAll();
-
- assertTrue(
- mChildSessionStateMachine.getCurrentState()
- instanceof ChildSessionStateMachine.RekeyChildRemoteDelete);
-
- // Verify outbound rekey response
- verify(mMockChildSessionSmCallback)
- .onOutboundPayloadsReady(
- eq(EXCHANGE_TYPE_CREATE_CHILD_SA),
- eq(true),
- mPayloadListCaptor.capture(),
- eq(mChildSessionStateMachine));
- List<IkePayload> respPayloadList = mPayloadListCaptor.getValue();
- verifyOutboundCreatePayloadTypes(respPayloadList, true /*isRekey*/);
-
- verifyOutboundRekeySaPayload(respPayloadList, true /*isResp*/);
- verifyOutboundRekeyNotifyPayload(respPayloadList);
-
- // Verify new Child SA
- assertEquals(
- mSpyRemoteInitNewChildSaRecord,
- mChildSessionStateMachine.mRemoteInitNewChildSaRecord);
-
- verify(mMockChildSessionSmCallback)
- .onChildSaCreated(
- eq(mSpyRemoteInitNewChildSaRecord.getRemoteSpi()),
- eq(mChildSessionStateMachine));
- verify(mMockChildSessionSmCallback)
- .scheduleLocalRequest(argThat(mRekeyChildLocalReqMatcher), anyLong());
-
- verify(mMockSaRecordHelper)
- .makeChildSaRecord(
- eq(rekeyReqPayloads),
- any(List.class),
- mChildSaRecordConfigCaptor.capture());
- ChildSaRecordConfig childSaRecordConfig = mChildSaRecordConfigCaptor.getValue();
- verifyChildSaRecordConfig(
- childSaRecordConfig,
- REMOTE_INIT_NEW_CHILD_SA_SPI_OUT,
- REMOTE_INIT_NEW_CHILD_SA_SPI_IN,
- false /*isLocalInit*/);
-
- // Verify that users are notified the creation of new inbound IpSecTransform
- verify(mSpyUserCbExecutor).execute(any(Runnable.class));
- verifyNotifyUsersCreateIpSecSa(mSpyRemoteInitNewChildSaRecord, true /*expectInbound*/);
- }
-
- private void verifyOutboundErrorNotify(int exchangeType, int errorCode) {
- verify(mMockChildSessionSmCallback)
- .onOutboundPayloadsReady(
- eq(exchangeType),
- eq(true),
- mPayloadListCaptor.capture(),
- eq(mChildSessionStateMachine));
- List<IkePayload> respPayloadList = mPayloadListCaptor.getValue();
-
- assertEquals(1, respPayloadList.size());
- IkePayload payload = respPayloadList.get(0);
- assertEquals(IkePayload.PAYLOAD_TYPE_NOTIFY, payload.payloadType);
- assertEquals(errorCode, ((IkeNotifyPayload) payload).notifyType);
- }
-
- @Test
- public void testRekeyChildRemoteCreateHandlesInvalidReq() throws Exception {
- setupIdleStateMachine();
-
- List<IkePayload> rekeyReqPayloads =
- makeInboundRekeyChildPayloads(
- REMOTE_INIT_NEW_CHILD_SA_SPI_OUT,
- REKEY_CHILD_UNACCEPTABLE_REQ_SA_PAYLOAD,
- false /*isLocalInitRekey*/);
-
- // Receive rekey Child request
- mChildSessionStateMachine.receiveRequest(
- IKE_EXCHANGE_SUBTYPE_REKEY_CHILD, EXCHANGE_TYPE_CREATE_CHILD_SA, rekeyReqPayloads);
- mLooper.dispatchAll();
-
- // Verify error notification was sent and state machind was back to Idle
- verifyOutboundErrorNotify(EXCHANGE_TYPE_CREATE_CHILD_SA, ERROR_TYPE_NO_PROPOSAL_CHOSEN);
-
- assertTrue(
- mChildSessionStateMachine.getCurrentState()
- instanceof ChildSessionStateMachine.Idle);
- }
-
- @Test
- public void testRekeyChildRemoteCreateSaCreationFail() throws Exception {
- // Throw exception when building ChildSaRecord
- when(mMockSaRecordHelper.makeChildSaRecord(any(), any(), any()))
- .thenThrow(
- new GeneralSecurityException("testRekeyChildRemoteCreateSaCreationFail"));
-
- setupIdleStateMachine();
-
- List<IkePayload> rekeyReqPayloads =
- makeInboundRekeyChildPayloads(
- REMOTE_INIT_NEW_CHILD_SA_SPI_OUT,
- REKEY_CHILD_REQ_SA_PAYLOAD,
- false /*isLocalInitRekey*/);
-
- // Receive rekey Child request
- mChildSessionStateMachine.receiveRequest(
- IKE_EXCHANGE_SUBTYPE_REKEY_CHILD, EXCHANGE_TYPE_CREATE_CHILD_SA, rekeyReqPayloads);
- mLooper.dispatchAll();
-
- // Verify error notification was sent and state machind was back to Idle
- verifyOutboundErrorNotify(EXCHANGE_TYPE_CREATE_CHILD_SA, ERROR_TYPE_NO_PROPOSAL_CHOSEN);
-
- assertTrue(
- mChildSessionStateMachine.getCurrentState()
- instanceof ChildSessionStateMachine.Idle);
- }
-
- @Test
- public void testRekeyChildRemoteDelete() throws Exception {
- setupIdleStateMachine();
-
- // Seed fake rekey data and force transition to RekeyChildRemoteDelete
- mChildSessionStateMachine.mRemoteInitNewChildSaRecord = mSpyRemoteInitNewChildSaRecord;
- mChildSessionStateMachine.sendMessage(
- CMD_FORCE_TRANSITION, mChildSessionStateMachine.mRekeyChildRemoteDelete);
-
- // Test receiving Delete request
- mChildSessionStateMachine.receiveRequest(
- IKE_EXCHANGE_SUBTYPE_DELETE_CHILD,
- EXCHANGE_TYPE_INFORMATIONAL,
- makeDeletePayloads(mSpyCurrentChildSaRecord.getRemoteSpi()));
- mLooper.dispatchAll();
-
- // Verify outbound Delete response
- verifyOutboundDeletePayload(mSpyCurrentChildSaRecord.getLocalSpi(), true /*isResp*/);
-
- // Verify Child SA has been updated
- verifyChildSaUpdated(mSpyCurrentChildSaRecord, mSpyRemoteInitNewChildSaRecord);
-
- // Verify procedure has been finished. #onProcedureFinished was first invoked in
- // #setupIdleStateMachine
- verify(mMockChildSessionSmCallback, times(2))
- .onProcedureFinished(mChildSessionStateMachine);
- assertTrue(
- mChildSessionStateMachine.getCurrentState()
- instanceof ChildSessionStateMachine.Idle);
-
- verify(mSpyUserCbExecutor, times(2)).execute(any(Runnable.class));
-
- verifyNotifyUserDeleteChildSa(mSpyCurrentChildSaRecord);
- verifyNotifyUsersCreateIpSecSa(mSpyRemoteInitNewChildSaRecord, false /*expectInbound*/);
- verify(mMockChildSessionCallback, never()).onClosed();
- }
-
- @Test
- public void testRekeyChildLocalDeleteWithReqForNewSa() throws Exception {
- setupIdleStateMachine();
-
- // Seed fake rekey data and force transition to RekeyChildLocalDelete
- mChildSessionStateMachine.mLocalInitNewChildSaRecord = mSpyLocalInitNewChildSaRecord;
- mChildSessionStateMachine.sendMessage(
- CMD_FORCE_TRANSITION, mChildSessionStateMachine.mRekeyChildLocalDelete);
- mLooper.dispatchAll();
-
- // Test receiving Delete new Child SA request
- mChildSessionStateMachine.receiveRequest(
- IKE_EXCHANGE_SUBTYPE_DELETE_CHILD,
- EXCHANGE_TYPE_INFORMATIONAL,
- makeDeletePayloads(mSpyLocalInitNewChildSaRecord.getRemoteSpi()));
- mLooper.dispatchAll();
-
- // Verify outbound Delete response on new Child SA
- verifyOutboundDeletePayload(mSpyLocalInitNewChildSaRecord.getLocalSpi(), true /*isResp*/);
- verify(mMockChildSessionSmCallback)
- .onChildSaDeleted(mSpyLocalInitNewChildSaRecord.getRemoteSpi());
- verify(mSpyLocalInitNewChildSaRecord).close();
-
- assertNull(mChildSessionStateMachine.getCurrentState());
-
- verify(mSpyUserCbExecutor, times(2)).execute(any(Runnable.class));
-
- verifyNotifyUserDeleteChildSa(mSpyCurrentChildSaRecord);
- verifyNotifyUserDeleteChildSa(mSpyLocalInitNewChildSaRecord);
-
- verify(mMockChildSessionCallback).onClosed();
- }
-
- @Test
- public void testRekeyChildRemoteDeleteWithReqForNewSa() throws Exception {
- setupIdleStateMachine();
-
- // Seed fake rekey data and force transition to RekeyChildRemoteDelete
- mChildSessionStateMachine.mRemoteInitNewChildSaRecord = mSpyRemoteInitNewChildSaRecord;
- mChildSessionStateMachine.sendMessage(
- CMD_FORCE_TRANSITION, mChildSessionStateMachine.mRekeyChildRemoteDelete);
- mLooper.dispatchAll();
-
- // Test receiving Delete new Child SA request
- mChildSessionStateMachine.receiveRequest(
- IKE_EXCHANGE_SUBTYPE_DELETE_CHILD,
- EXCHANGE_TYPE_INFORMATIONAL,
- makeDeletePayloads(mSpyRemoteInitNewChildSaRecord.getRemoteSpi()));
- mLooper.dispatchAll();
-
- // Verify outbound Delete response on new Child SA
- verifyOutboundDeletePayload(mSpyRemoteInitNewChildSaRecord.getLocalSpi(), true /*isResp*/);
- verify(mMockChildSessionSmCallback)
- .onChildSaDeleted(mSpyRemoteInitNewChildSaRecord.getRemoteSpi());
- verify(mSpyRemoteInitNewChildSaRecord).close();
-
- assertNull(mChildSessionStateMachine.getCurrentState());
-
- verify(mSpyUserCbExecutor, times(3)).execute(any(Runnable.class));
-
- verifyNotifyUserDeleteChildSa(mSpyCurrentChildSaRecord);
- verifyNotifyUserDeleteChildSa(mSpyRemoteInitNewChildSaRecord);
- verifyNotifyUsersCreateIpSecSa(mSpyRemoteInitNewChildSaRecord, false /*expectInbound*/);
-
- verify(mMockChildSessionCallback).onClosed();
- }
-
- @Test
- public void testRekeyChildRemoteDeleteTimeout() throws Exception {
- setupIdleStateMachine();
-
- // Seed fake rekey data and force transition to RekeyChildRemoteDelete
- mChildSessionStateMachine.mRemoteInitNewChildSaRecord = mSpyRemoteInitNewChildSaRecord;
- mChildSessionStateMachine.sendMessage(
- CMD_FORCE_TRANSITION, mChildSessionStateMachine.mRekeyChildRemoteDelete);
- mLooper.dispatchAll();
-
- mLooper.moveTimeForward(REKEY_DELETE_TIMEOUT_MS);
- mLooper.dispatchAll();
-
- // Verify no response sent.
- verify(mMockChildSessionSmCallback, never())
- .onOutboundPayloadsReady(anyInt(), anyBoolean(), any(List.class), anyObject());
-
- // Verify Child SA has been renewed
- verifyChildSaUpdated(mSpyCurrentChildSaRecord, mSpyRemoteInitNewChildSaRecord);
-
- // Verify procedure has been finished. #onProcedureFinished was first invoked in
- // #setupIdleStateMachine
- verify(mMockChildSessionSmCallback, times(2))
- .onProcedureFinished(mChildSessionStateMachine);
- assertTrue(
- mChildSessionStateMachine.getCurrentState()
- instanceof ChildSessionStateMachine.Idle);
-
- verify(mSpyUserCbExecutor, times(2)).execute(any(Runnable.class));
-
- verifyNotifyUserDeleteChildSa(mSpyCurrentChildSaRecord);
- verifyNotifyUsersCreateIpSecSa(mSpyRemoteInitNewChildSaRecord, false /*expectInbound*/);
-
- verify(mMockChildSessionCallback, never()).onClosed();
- }
-
- @Test
- public void testRekeyChildRemoteDeleteExitAndRenter() throws Exception {
- setupIdleStateMachine();
-
- // Seed fake rekey data and force transition to RekeyChildRemoteDelete
- mChildSessionStateMachine.mRemoteInitNewChildSaRecord = mSpyRemoteInitNewChildSaRecord;
- mChildSessionStateMachine.sendMessage(
- CMD_FORCE_TRANSITION, mChildSessionStateMachine.mRekeyChildRemoteDelete);
- mLooper.dispatchAll();
-
- // Trigger a timeout, and immediately re-enter remote-delete
- mLooper.moveTimeForward(REKEY_DELETE_TIMEOUT_MS / 2 + 1);
- mChildSessionStateMachine.sendMessage(ChildSessionStateMachine.TIMEOUT_REKEY_REMOTE_DELETE);
- mChildSessionStateMachine.sendMessage(
- CMD_FORCE_TRANSITION, mChildSessionStateMachine.mRekeyChildRemoteDelete);
- mLooper.dispatchAll();
-
- // Shift time forward
- mLooper.moveTimeForward(REKEY_DELETE_TIMEOUT_MS / 2 + 1);
- mLooper.dispatchAll();
-
- // Verify final state has not changed - timeout was not triggered.
- assertTrue(
- mChildSessionStateMachine.getCurrentState()
- instanceof ChildSessionStateMachine.RekeyChildRemoteDelete);
-
- verify(mSpyUserCbExecutor, times(2)).execute(any(Runnable.class));
-
- verifyNotifyUserDeleteChildSa(mSpyCurrentChildSaRecord);
- verifyNotifyUsersCreateIpSecSa(mSpyRemoteInitNewChildSaRecord, false /*expectInbound*/);
-
- verify(mMockChildSessionCallback, never()).onClosed();
- }
-
- @Test
- public void testCloseSessionNow() throws Exception {
- setupIdleStateMachine();
-
- // Seed fake rekey data and force transition to RekeyChildLocalDelete
- mChildSessionStateMachine.mLocalInitNewChildSaRecord = mSpyLocalInitNewChildSaRecord;
- mChildSessionStateMachine.sendMessage(
- CMD_FORCE_TRANSITION, mChildSessionStateMachine.mRekeyChildLocalDelete);
-
- mChildSessionStateMachine.killSession();
- mLooper.dispatchAll();
-
- assertNull(mChildSessionStateMachine.getCurrentState());
-
- verify(mSpyUserCbExecutor, times(3)).execute(any(Runnable.class));
-
- verifyNotifyUserDeleteChildSa(mSpyCurrentChildSaRecord);
- verifyNotifyUserDeleteChildSa(mSpyLocalInitNewChildSaRecord);
-
- verify(mMockChildSessionCallback).onClosed();
- }
-
- @Test
- public void testValidateExpectKeExistCase() throws Exception {
- when(mMockNegotiatedProposal.getDhGroupTransforms())
- .thenReturn(new DhGroupTransform[] {mChildDhGroupTransform});
- List<IkePayload> payloadList = new LinkedList<>();
- payloadList.add(new IkeKePayload(SaProposal.DH_GROUP_1024_BIT_MODP));
-
- CreateChildSaHelper.validateKePayloads(
- payloadList, true /*isResp*/, mMockNegotiatedProposal);
- CreateChildSaHelper.validateKePayloads(
- payloadList, false /*isResp*/, mMockNegotiatedProposal);
- }
-
- @Test
- public void testValidateExpectNoKeExistCase() throws Exception {
- when(mMockNegotiatedProposal.getDhGroupTransforms()).thenReturn(new DhGroupTransform[0]);
- List<IkePayload> payloadList = new LinkedList<>();
-
- CreateChildSaHelper.validateKePayloads(
- payloadList, true /*isResp*/, mMockNegotiatedProposal);
- CreateChildSaHelper.validateKePayloads(
- payloadList, false /*isResp*/, mMockNegotiatedProposal);
- }
-
- @Test
- public void testThrowWhenKeMissing() throws Exception {
- when(mMockNegotiatedProposal.getDhGroupTransforms())
- .thenReturn(new DhGroupTransform[] {mChildDhGroupTransform});
- List<IkePayload> payloadList = new LinkedList<>();
-
- try {
- CreateChildSaHelper.validateKePayloads(
- payloadList, true /*isResp*/, mMockNegotiatedProposal);
- fail("Expected to fail due to the absence of KE Payload");
- } catch (InvalidSyntaxException expected) {
- }
-
- try {
- CreateChildSaHelper.validateKePayloads(
- payloadList, false /*isResp*/, mMockNegotiatedProposal);
- fail("Expected to fail due to the absence of KE Payload");
- } catch (InvalidKeException expected) {
- }
- }
-
- @Test
- public void testThrowWhenKeHasMismatchedDhGroup() throws Exception {
- when(mMockNegotiatedProposal.getDhGroupTransforms())
- .thenReturn(new DhGroupTransform[] {mChildDhGroupTransform});
- List<IkePayload> payloadList = new LinkedList<>();
- payloadList.add(new IkeKePayload(SaProposal.DH_GROUP_2048_BIT_MODP));
-
- try {
- CreateChildSaHelper.validateKePayloads(
- payloadList, true /*isResp*/, mMockNegotiatedProposal);
- fail("Expected to fail due to mismatched DH Group");
- } catch (InvalidSyntaxException expected) {
- }
-
- try {
- CreateChildSaHelper.validateKePayloads(
- payloadList, false /*isResp*/, mMockNegotiatedProposal);
- fail("Expected to fail due to mismatched DH Group");
- } catch (InvalidKeException expected) {
- }
- }
-
- @Test
- public void testThrowForUnexpectedKe() throws Exception {
- DhGroupTransform noneGroup = new DhGroupTransform(SaProposal.DH_GROUP_NONE);
- when(mMockNegotiatedProposal.getDhGroupTransforms())
- .thenReturn(new DhGroupTransform[] {noneGroup});
- List<IkePayload> payloadList = new LinkedList<>();
- payloadList.add(new IkeKePayload(SaProposal.DH_GROUP_2048_BIT_MODP));
-
- try {
- CreateChildSaHelper.validateKePayloads(
- payloadList, true /*isResp*/, mMockNegotiatedProposal);
- fail("Expected to fail due to unexpected KE payload.");
- } catch (InvalidSyntaxException expected) {
- }
-
- CreateChildSaHelper.validateKePayloads(
- payloadList, false /*isResp*/, mMockNegotiatedProposal);
- }
-
- @Test
- public void testHandleUnexpectedException() throws Exception {
- Log spyIkeLog = TestUtils.makeSpyLogDoLogErrorForWtf(TAG);
- IkeManager.setIkeLog(spyIkeLog);
-
- mChildSessionStateMachine.createChildSession(
- null /*localAddress*/, REMOTE_ADDRESS, mMockUdpEncapSocket, mIkePrf, SK_D);
- mLooper.dispatchAll();
-
- verifyHandleFatalErrorAndQuit(IkeInternalException.class);
- verify(spyIkeLog).wtf(anyString(), anyString(), any(RuntimeException.class));
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/IkeLocalRequestSchedulerTest.java b/tests/iketests/src/java/com/android/internal/net/ipsec/ike/IkeLocalRequestSchedulerTest.java
deleted file mode 100644
index 3406d014..00000000
--- a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/IkeLocalRequestSchedulerTest.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (C) 2019 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;
-
-import static com.android.internal.net.ipsec.ike.IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_IKE;
-
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.inOrder;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-import com.android.internal.net.ipsec.ike.IkeLocalRequestScheduler.IProcedureConsumer;
-import com.android.internal.net.ipsec.ike.IkeLocalRequestScheduler.LocalRequest;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-import org.mockito.InOrder;
-
-public final class IkeLocalRequestSchedulerTest {
- private IkeLocalRequestScheduler mScheduler;
-
- private IProcedureConsumer mMockConsumer;
- private LocalRequest[] mMockRequestArray;
-
- private ArgumentCaptor<LocalRequest> mLocalRequestCaptor =
- ArgumentCaptor.forClass(LocalRequest.class);
-
- @Before
- public void setUp() {
- mMockConsumer = mock(IProcedureConsumer.class);
- mScheduler = new IkeLocalRequestScheduler(mMockConsumer);
-
- mMockRequestArray = new LocalRequest[10];
- for (int i = 0; i < mMockRequestArray.length; i++) {
- mMockRequestArray[i] = mock(LocalRequest.class);
- }
- }
-
- @Test
- public void testAddMultipleRequestProcessOnlyOne() {
- for (LocalRequest r : mMockRequestArray) mScheduler.addRequest(r);
-
- // Verify that no procedure was preemptively pulled from the queue
- verify(mMockConsumer, never()).onNewProcedureReady(any());
-
- // Check that the onNewPrcedureReady called exactly once, on the first item
- mScheduler.readyForNextProcedure();
- verify(mMockConsumer, times(1)).onNewProcedureReady(any());
- verify(mMockConsumer, times(1)).onNewProcedureReady(mMockRequestArray[0]);
- for (int i = 1; i < mMockRequestArray.length; i++) {
- verify(mMockConsumer, never()).onNewProcedureReady(mMockRequestArray[i]);
- }
- }
-
- @Test
- public void testProcessOrder() {
- InOrder inOrder = inOrder(mMockConsumer);
-
- for (LocalRequest r : mMockRequestArray) mScheduler.addRequest(r);
- for (int i = 0; i < mMockRequestArray.length; i++) mScheduler.readyForNextProcedure();
-
- for (LocalRequest r : mMockRequestArray) {
- inOrder.verify(mMockConsumer).onNewProcedureReady(r);
- }
- }
-
- @Test
- public void testAddRequestToFrontProcessOrder() {
- InOrder inOrder = inOrder(mMockConsumer);
-
- LocalRequest[] mockHighPriorityRequestArray = new LocalRequest[10];
- for (int i = 0; i < mockHighPriorityRequestArray.length; i++) {
- mockHighPriorityRequestArray[i] = mock(LocalRequest.class);
- }
-
- for (LocalRequest r : mMockRequestArray) mScheduler.addRequest(r);
- for (LocalRequest r : mockHighPriorityRequestArray) mScheduler.addRequestAtFront(r);
-
- for (int i = 0; i < mockHighPriorityRequestArray.length + mMockRequestArray.length; i++) {
- mScheduler.readyForNextProcedure();
- }
-
- // Verify processing order. mockHighPriorityRequestArray is processed in reverse order
- for (int i = mockHighPriorityRequestArray.length - 1; i >= 0; i--) {
- inOrder.verify(mMockConsumer).onNewProcedureReady(mockHighPriorityRequestArray[i]);
- }
- for (LocalRequest r : mMockRequestArray) {
- inOrder.verify(mMockConsumer).onNewProcedureReady(r);
- }
- }
-
- @Test
- public void testDoNotProcessCanceledRequest() {
- LocalRequest[] requestArray = new LocalRequest[4];
-
- for (int i = 0; i < requestArray.length; i++) {
- requestArray[i] = new LocalRequest(CMD_LOCAL_REQUEST_REKEY_IKE);
- mScheduler.addRequest(requestArray[i]);
- }
-
- mScheduler.readyForNextProcedure();
- verify(mMockConsumer).onNewProcedureReady(eq(requestArray[0]));
-
- requestArray[1].cancel();
- mScheduler.readyForNextProcedure();
- verify(mMockConsumer, never()).onNewProcedureReady(eq(requestArray[1]));
- verify(mMockConsumer).onNewProcedureReady(eq(requestArray[2]));
-
- mScheduler.readyForNextProcedure();
- verify(mMockConsumer).onNewProcedureReady(eq(requestArray[3]));
- }
-}
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
deleted file mode 100644
index 94f4d622..00000000
--- a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/IkeSessionStateMachineTest.java
+++ /dev/null
@@ -1,4036 +0,0 @@
-/*
- * Copyright (C) 2019 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;
-
-import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_CHILD_SA_NOT_FOUND;
-import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_INVALID_SYNTAX;
-import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_NO_ADDITIONAL_SAS;
-import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_NO_PROPOSAL_CHOSEN;
-import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_TEMPORARY_FAILURE;
-import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_UNSUPPORTED_CRITICAL_PAYLOAD;
-
-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;
-import static com.android.internal.net.ipsec.ike.IkeSessionStateMachine.IKE_EXCHANGE_SUBTYPE_REKEY_CHILD;
-import static com.android.internal.net.ipsec.ike.IkeSessionStateMachine.RETRY_INTERVAL_MS;
-import static com.android.internal.net.ipsec.ike.IkeSessionStateMachine.SA_SOFT_LIFETIME_MS;
-import static com.android.internal.net.ipsec.ike.IkeSessionStateMachine.TEMP_FAILURE_RETRY_TIMEOUT_MS;
-import static com.android.internal.net.ipsec.ike.message.IkeHeader.EXCHANGE_TYPE_CREATE_CHILD_SA;
-import static com.android.internal.net.ipsec.ike.message.IkeHeader.EXCHANGE_TYPE_INFORMATIONAL;
-import static com.android.internal.net.ipsec.ike.message.IkeNotifyPayload.NOTIFY_TYPE_IKEV2_FRAGMENTATION_SUPPORTED;
-import static com.android.internal.net.ipsec.ike.message.IkeNotifyPayload.NOTIFY_TYPE_NAT_DETECTION_DESTINATION_IP;
-import static com.android.internal.net.ipsec.ike.message.IkeNotifyPayload.NOTIFY_TYPE_NAT_DETECTION_SOURCE_IP;
-import static com.android.internal.net.ipsec.ike.message.IkePayload.PAYLOAD_TYPE_AUTH;
-import static com.android.internal.net.ipsec.ike.message.IkePayload.PAYLOAD_TYPE_NOTIFY;
-import static com.android.internal.net.ipsec.ike.message.IkePayload.PAYLOAD_TYPE_SA;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-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.Matchers.anyObject;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.argThat;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.net.IpSecManager;
-import android.net.IpSecManager.UdpEncapsulationSocket;
-import android.net.eap.EapSessionConfig;
-import android.net.ipsec.ike.ChildSaProposal;
-import android.net.ipsec.ike.ChildSessionCallback;
-import android.net.ipsec.ike.ChildSessionOptions;
-import android.net.ipsec.ike.IkeIpv4AddrIdentification;
-import android.net.ipsec.ike.IkeManager;
-import android.net.ipsec.ike.IkeSaProposal;
-import android.net.ipsec.ike.IkeSessionCallback;
-import android.net.ipsec.ike.IkeSessionOptions;
-import android.net.ipsec.ike.SaProposal;
-import android.net.ipsec.ike.TransportModeChildSessionOptions;
-import android.net.ipsec.ike.exceptions.IkeException;
-import android.net.ipsec.ike.exceptions.IkeInternalException;
-import android.net.ipsec.ike.exceptions.IkeProtocolException;
-import android.os.test.TestLooper;
-import android.telephony.TelephonyManager;
-
-import com.android.internal.net.TestUtils;
-import com.android.internal.net.eap.EapAuthenticator;
-import com.android.internal.net.eap.IEapCallback;
-import com.android.internal.net.ipsec.ike.ChildSessionStateMachine.IChildSessionSmCallback;
-import com.android.internal.net.ipsec.ike.ChildSessionStateMachineFactory.ChildSessionFactoryHelper;
-import com.android.internal.net.ipsec.ike.ChildSessionStateMachineFactory.IChildSessionFactoryHelper;
-import com.android.internal.net.ipsec.ike.IkeLocalRequestScheduler.ChildLocalRequest;
-import com.android.internal.net.ipsec.ike.IkeLocalRequestScheduler.LocalRequest;
-import com.android.internal.net.ipsec.ike.IkeSessionStateMachine.IkeSecurityParameterIndex;
-import com.android.internal.net.ipsec.ike.IkeSessionStateMachine.ReceivedIkePacket;
-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.SaRecordHelper;
-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;
-import com.android.internal.net.ipsec.ike.exceptions.AuthenticationFailedException;
-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.exceptions.UnsupportedCriticalPayloadException;
-import com.android.internal.net.ipsec.ike.message.IkeAuthDigitalSignPayload;
-import com.android.internal.net.ipsec.ike.message.IkeAuthPayload;
-import com.android.internal.net.ipsec.ike.message.IkeAuthPskPayload;
-import com.android.internal.net.ipsec.ike.message.IkeCertX509CertPayload;
-import com.android.internal.net.ipsec.ike.message.IkeDeletePayload;
-import com.android.internal.net.ipsec.ike.message.IkeEapPayload;
-import com.android.internal.net.ipsec.ike.message.IkeHeader;
-import com.android.internal.net.ipsec.ike.message.IkeIdPayload;
-import com.android.internal.net.ipsec.ike.message.IkeInformationalPayload;
-import com.android.internal.net.ipsec.ike.message.IkeKePayload;
-import com.android.internal.net.ipsec.ike.message.IkeMessage;
-import com.android.internal.net.ipsec.ike.message.IkeMessage.DecodeResult;
-import com.android.internal.net.ipsec.ike.message.IkeMessage.DecodeResultOk;
-import com.android.internal.net.ipsec.ike.message.IkeMessage.DecodeResultPartial;
-import com.android.internal.net.ipsec.ike.message.IkeMessage.DecodeResultProtectedError;
-import com.android.internal.net.ipsec.ike.message.IkeMessage.DecodeResultUnprotectedError;
-import com.android.internal.net.ipsec.ike.message.IkeMessage.IIkeMessageHelper;
-import com.android.internal.net.ipsec.ike.message.IkeMessage.IkeMessageHelper;
-import com.android.internal.net.ipsec.ike.message.IkeNoncePayload;
-import com.android.internal.net.ipsec.ike.message.IkeNotifyPayload;
-import com.android.internal.net.ipsec.ike.message.IkePayload;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload.DhGroupTransform;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload.EncryptionTransform;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload.IntegrityTransform;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload.PrfTransform;
-import com.android.internal.net.ipsec.ike.message.IkeSkfPayload;
-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.CertUtils;
-import com.android.internal.net.ipsec.ike.testutils.MockIpSecTestUtils;
-import com.android.internal.net.ipsec.ike.utils.Retransmitter;
-import com.android.internal.net.ipsec.ike.utils.Retransmitter.IBackoffTimeoutCalculator;
-import com.android.internal.net.utils.Log;
-import com.android.internal.util.State;
-
-import libcore.net.InetAddressUtils;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-import org.mockito.invocation.InvocationOnMock;
-
-import java.io.IOException;
-import java.net.Inet4Address;
-import java.security.GeneralSecurityException;
-import java.security.cert.X509Certificate;
-import java.util.Arrays;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.concurrent.Executor;
-
-public final class IkeSessionStateMachineTest {
- private static final String TAG = "IkeSessionStateMachineTest";
-
- private static final Inet4Address LOCAL_ADDRESS =
- (Inet4Address) (InetAddressUtils.parseNumericAddress("192.0.2.200"));
- private static final Inet4Address REMOTE_ADDRESS =
- (Inet4Address) (InetAddressUtils.parseNumericAddress("127.0.0.1"));
-
- private static final String IKE_INIT_RESP_HEX_STRING =
- "5f54bf6d8b48e6e1909232b3d1edcb5c21202220000000000000014c220000300000"
- + "002c010100040300000c0100000c800e008003000008030000020300000802000002"
- + "00000008040000022800008800020000fe014fefed55a4229928bfa3dad1ea6ffaca"
- + "abfb5f5bdd71790e99a192530e3f849d3a3d96dc6e0a7a10ff6f72a6162103ac573c"
- + "acd41d08b7a034cad8f5eab09c14ced5a9e4af5692dff028f21c1119dd75226b6af6"
- + "b2f009245369c9892cc5742e5c94a254ebff052470771fb2cb4f29a35d8953e18a1a"
- + "6c6fbc56acc188a5290000249756112ca539f5c25abacc7ee92b73091942a9c06950"
- + "f98848f1af1694c4ddff2900001c00004004c53f054b976a25d75fde72dbf1c7b6c8"
- + "c9aa9ca12900001c00004005b16d79b21c1bc89ca7350f42de805be0227e2ed62b00"
- + "00080000401400000014882fe56d6fd20dbc2251613b2ebe5beb";
- private static final String IKE_SA_PAYLOAD_HEX_STRING =
- "220000300000002c010100040300000c0100000c800e00800300000803000002030"
- + "00008020000020000000804000002";
- private static final String IKE_REKEY_SA_PAYLOAD_HEX_STRING =
- "22000038000000340101080400000000000000FF0300000c0100000c800e0080030"
- + "000080300000203000008020000020000000804000002";
- private static final String IKE_REKEY_UNACCEPTABLE_SA_PAYLOAD_HEX_STRING =
- "22000038000000340101080400000000000000FF0300000c0100000c800e0080030"
- + "00008030000020300000802000002000000080400000e";
- private static final int IKE_REKEY_SA_INITIATOR_SPI = 0xff;
- private static final String KE_PAYLOAD_HEX_STRING =
- "2800008800020000b4a2faf4bb54878ae21d638512ece55d9236fc50"
- + "46ab6cef82220f421f3ce6361faf36564ecb6d28798a94aa"
- + "d7b2b4b603ddeaaa5630adb9ece8ac37534036040610ebdd"
- + "92f46bef84f0be7db860351843858f8acf87056e272377f7"
- + "0c9f2d81e29c7b0ce4f291a3a72476bb0b278fd4b7b0a4c2"
- + "6bbeb08214c7071376079587";
- private static final String NONCE_INIT_PAYLOAD_HEX_STRING =
- "29000024c39b7f368f4681b89fa9b7be6465abd7c5f68b6ed5d3b4c72cb4240eb5c46412";
- private static final String NONCE_RESP_PAYLOAD_HEX_STRING =
- "290000249756112ca539f5c25abacc7ee92b73091942a9c06950f98848f1af1694c4ddff";
- private static final String NONCE_INIT_HEX_STRING =
- "c39b7f368f4681b89fa9b7be6465abd7c5f68b6ed5d3b4c72cb4240eb5c46412";
- private static final String NONCE_RESP_HEX_STRING =
- "9756112ca539f5c25abacc7ee92b73091942a9c06950f98848f1af1694c4ddff";
- private static final String NAT_DETECTION_SOURCE_PAYLOAD_HEX_STRING =
- "2900001c00004004e54f73b7d83f6beb881eab2051d8663f421d10b0";
- private static final String NAT_DETECTION_DESTINATION_PAYLOAD_HEX_STRING =
- "2b00001c00004005d915368ca036004cb578ae3e3fb268509aeab190";
- private static final String FRAGMENTATION_SUPPORTED_PAYLOAD_HEX_STRING = "290000080000402e";
- private static final String DELETE_IKE_PAYLOAD_HEX_STRING = "0000000801000000";
- private static final String NOTIFY_REKEY_IKE_PAYLOAD_HEX_STRING = "2100000800004009";
- private static final String ID_PAYLOAD_INITIATOR_HEX_STRING =
- "290000180200000031313233343536373839414243444546";
- private static final String ID_PAYLOAD_RESPONDER_HEX_STRING = "2700000c010000007f000001";
- private static final String PSK_AUTH_RESP_PAYLOAD_HEX_STRING =
- "2100001c0200000058f36412e9b7b38df817a9f7779b7a008dacdd25";
- private static final String GENERIC_DIGITAL_SIGN_AUTH_RESP_HEX_STRING =
- "300000580e0000000f300d06092a864886f70d01010b05006f76af4150d653c5d413"
- + "6b9f69d905849bf075c563e6d14ccda42361ec3e7d12c72e2dece5711ea1d952f7b8e"
- + "12c5d982aa4efdaeac36a02b222aa96242cc424";
- private static final String CHILD_SA_PAYLOAD_HEX_STRING =
- "2c00002c0000002801030403cae7019f0300000c0100000c800e008003000008030"
- + "000020000000805000000";
- private static final String TS_INIT_PAYLOAD_HEX_STRING =
- "2d00001801000000070000100000ffff00000000ffffffff";
- private static final String TS_RESP_PAYLOAD_HEX_STRING =
- "2900001801000000070000100000ffff000000000fffffff";
-
- private static final String PSK_HEX_STRING = "6A756E69706572313233";
-
- private static final String PRF_KEY_INIT_HEX_STRING =
- "094787780EE466E2CB049FA327B43908BC57E485";
- private static final String PRF_KEY_RESP_HEX_STRING =
- "A30E6B08BE56C0E6BFF4744143C75219299E1BEB";
-
- private static final byte[] EAP_DUMMY_MSG = "EAP Message".getBytes();
-
- private static final int KEY_LEN_IKE_INTE = 20;
- private static final int KEY_LEN_IKE_ENCR = 16;
- private static final int KEY_LEN_IKE_PRF = 20;
- private static final int KEY_LEN_IKE_SKD = KEY_LEN_IKE_PRF;
-
- private static final int CHILD_SPI_LOCAL = 0x2ad4c0a2;
- private static final int CHILD_SPI_REMOTE = 0xcae7019f;
-
- private static final int DUMMY_UDP_ENCAP_RESOURCE_ID = 0x3234;
- private static final int UDP_ENCAP_PORT = 34567;
-
- private static final int EAP_SIM_SUB_ID = 1;
-
- private static final int PAYLOAD_TYPE_UNSUPPORTED = 127;
-
- private static final long RETRANSMIT_BACKOFF_TIMEOUT_MS = 5000L;
-
- private MockIpSecTestUtils mMockIpSecTestUtils;
- private Context mContext;
- private IpSecManager mIpSecManager;
- private UdpEncapsulationSocket mUdpEncapSocket;
-
- private IkeSocket mSpyIkeSocket;
-
- private TestLooper mLooper;
- private IkeSessionStateMachine mIkeSessionStateMachine;
-
- private byte[] mPsk;
-
- private ChildSessionOptions mChildSessionOptions;
-
- private Executor mSpyUserCbExecutor;
- private IkeSessionCallback mMockIkeSessionCallback;
- private ChildSessionCallback mMockChildSessionCallback;
-
- private EncryptionTransform mIkeEncryptionTransform;
- private IntegrityTransform mIkeIntegrityTransform;
- private PrfTransform mIkePrfTransform;
- private DhGroupTransform mIkeDhGroupTransform;
-
- private IIkeMessageHelper mMockIkeMessageHelper;
- private ISaRecordHelper mMockSaRecordHelper;
- private IBackoffTimeoutCalculator mMockBackoffTimeoutCalculator;
-
- private ChildSessionStateMachine mMockChildSessionStateMachine;
- private IChildSessionFactoryHelper mMockChildSessionFactoryHelper;
- private IChildSessionSmCallback mDummyChildSmCallback;
-
- private IkeSaRecord mSpyCurrentIkeSaRecord;
- private IkeSaRecord mSpyLocalInitIkeSaRecord;
- private IkeSaRecord mSpyRemoteInitIkeSaRecord;
-
- private Log mSpyIkeLog;
-
- private int mExpectedCurrentSaLocalReqMsgId;
- private int mExpectedCurrentSaRemoteReqMsgId;
-
- private EapSessionConfig mEapSessionConfig;
- private IkeEapAuthenticatorFactory mMockEapAuthenticatorFactory;
- private EapAuthenticator mMockEapAuthenticator;
-
- private X509Certificate mRootCertificate;
- private X509Certificate mServerEndCertificate;
-
- private ArgumentCaptor<IkeMessage> mIkeMessageCaptor =
- ArgumentCaptor.forClass(IkeMessage.class);
- private ArgumentCaptor<IkeSaRecordConfig> mIkeSaRecordConfigCaptor =
- ArgumentCaptor.forClass(IkeSaRecordConfig.class);
- private ArgumentCaptor<IChildSessionSmCallback> mChildSessionSmCbCaptor =
- ArgumentCaptor.forClass(IChildSessionSmCallback.class);
- private ArgumentCaptor<List<IkePayload>> mPayloadListCaptor =
- ArgumentCaptor.forClass(List.class);
-
- private ReceivedIkePacket makeDummyReceivedIkeInitRespPacket(
- long initiatorSpi,
- long responderSpi,
- @IkeHeader.ExchangeType int eType,
- boolean isResp,
- boolean fromIkeInit,
- List<Integer> payloadTypeList,
- List<String> payloadHexStringList)
- throws Exception {
-
- List<IkePayload> payloadList =
- hexStrListToIkePayloadList(payloadTypeList, payloadHexStringList, isResp);
- // Build a remotely generated NAT_DETECTION_SOURCE_IP payload to mock a remote node's
- // network that is not behind NAT.
- IkePayload sourceNatPayload =
- new IkeNotifyPayload(
- NOTIFY_TYPE_NAT_DETECTION_SOURCE_IP,
- IkeNotifyPayload.generateNatDetectionData(
- initiatorSpi,
- responderSpi,
- REMOTE_ADDRESS,
- IkeSocket.IKE_SERVER_PORT));
- payloadList.add(sourceNatPayload);
- return makeDummyUnencryptedReceivedIkePacket(
- initiatorSpi, responderSpi, eType, isResp, fromIkeInit, payloadList);
- }
-
- private ReceivedIkePacket makeDummyUnencryptedReceivedIkePacket(
- long initiatorSpi,
- long responderSpi,
- @IkeHeader.ExchangeType int eType,
- boolean isResp,
- boolean fromIkeInit,
- List<IkePayload> payloadList)
- throws Exception {
- IkeMessage dummyIkeMessage =
- makeDummyIkeMessageForTest(
- initiatorSpi,
- responderSpi,
- eType,
- isResp,
- fromIkeInit,
- 0,
- false /*isEncrypted*/,
- payloadList);
-
- byte[] dummyIkePacketBytes = new byte[0];
- when(mMockIkeMessageHelper.decode(0, dummyIkeMessage.ikeHeader, dummyIkePacketBytes))
- .thenReturn(new DecodeResultOk(dummyIkeMessage, dummyIkePacketBytes));
-
- return new ReceivedIkePacket(dummyIkeMessage.ikeHeader, dummyIkePacketBytes);
- }
-
- private ReceivedIkePacket makeDummyEncryptedReceivedIkePacket(
- IkeSaRecord ikeSaRecord,
- @IkeHeader.ExchangeType int eType,
- boolean isResp,
- List<Integer> payloadTypeList,
- List<String> payloadHexStringList)
- throws Exception {
- List<IkePayload> payloadList =
- hexStrListToIkePayloadList(payloadTypeList, payloadHexStringList, isResp);
- return makeDummyEncryptedReceivedIkePacketWithPayloadList(
- ikeSaRecord, eType, isResp, payloadList);
- }
-
- private ReceivedIkePacket makeDummyEncryptedReceivedIkePacketWithPayloadList(
- IkeSaRecord ikeSaRecord,
- @IkeHeader.ExchangeType int eType,
- boolean isResp,
- List<IkePayload> payloadList)
- throws Exception {
- return makeDummyEncryptedReceivedIkePacketWithPayloadList(
- ikeSaRecord,
- eType,
- isResp,
- isResp
- ? ikeSaRecord.getLocalRequestMessageId()
- : ikeSaRecord.getRemoteRequestMessageId(),
- payloadList,
- new byte[0] /*dummyIkePacketBytes*/);
- }
-
- private ReceivedIkePacket makeDummyEncryptedReceivedIkePacketWithPayloadList(
- IkeSaRecord ikeSaRecord,
- @IkeHeader.ExchangeType int eType,
- boolean isResp,
- int msgId,
- List<IkePayload> payloadList,
- byte[] dummyIkePacketBytes)
- throws Exception {
- boolean fromIkeInit = !ikeSaRecord.isLocalInit;
- IkeMessage dummyIkeMessage =
- makeDummyIkeMessageForTest(
- ikeSaRecord.getInitiatorSpi(),
- ikeSaRecord.getResponderSpi(),
- eType,
- isResp,
- fromIkeInit,
- msgId,
- true /*isEncyprted*/,
- payloadList);
-
- setDecodeEncryptedPacketResult(
- ikeSaRecord,
- dummyIkeMessage.ikeHeader,
- null /*collectedFrags*/,
- new DecodeResultOk(dummyIkeMessage, dummyIkePacketBytes));
-
- return new ReceivedIkePacket(dummyIkeMessage.ikeHeader, dummyIkePacketBytes);
- }
-
- private ReceivedIkePacket makeDummyReceivedIkePacketWithInvalidSyntax(
- IkeSaRecord ikeSaRecord, boolean isResp, int eType) {
- return makeDummyReceivedIkePacketWithDecodingError(
- ikeSaRecord, isResp, eType, new InvalidSyntaxException("IkeStateMachineTest"));
- }
-
- private ReceivedIkePacket makeDummyReceivedIkePacketWithDecodingError(
- IkeSaRecord ikeSaRecord, boolean isResp, int eType, IkeProtocolException exception) {
- IkeHeader header =
- makeDummyIkeHeader(ikeSaRecord, isResp, eType, IkePayload.PAYLOAD_TYPE_SK);
- byte[] dummyPacket = new byte[0];
- when(mMockIkeMessageHelper.decode(
- anyInt(), any(), any(), eq(ikeSaRecord), eq(header), any(), any()))
- .thenReturn(new DecodeResultProtectedError(exception, dummyPacket));
-
- return new ReceivedIkePacket(header, dummyPacket);
- }
-
- private ReceivedIkePacket makeDummyReceivedIkePacketWithUnprotectedError(
- IkeSaRecord ikeSaRecord, boolean isResp, int eType, IkeException exception) {
- IkeHeader header =
- makeDummyIkeHeader(ikeSaRecord, isResp, eType, IkePayload.PAYLOAD_TYPE_SK);
- byte[] dummyPacket = new byte[0];
- when(mMockIkeMessageHelper.decode(
- anyInt(), any(), any(), eq(ikeSaRecord), eq(header), any(), any()))
- .thenReturn(new DecodeResultUnprotectedError(exception));
-
- return new ReceivedIkePacket(header, dummyPacket);
- }
-
- private ReceivedIkePacket makeDummyReceivedIkeFragmentPacket(
- IkeSaRecord ikeSaRecord,
- boolean isResp,
- int eType,
- IkeSkfPayload skfPayload,
- int nextPayloadType,
- DecodeResultPartial collectedFrags) {
- IkeHeader header =
- makeDummyIkeHeader(ikeSaRecord, isResp, eType, IkePayload.PAYLOAD_TYPE_SKF);
-
- byte[] dummyPacket = new byte[0];
- DecodeResultPartial resultFrags =
- new DecodeResultPartial(
- header, dummyPacket, skfPayload, nextPayloadType, collectedFrags);
- setDecodeEncryptedPacketResult(ikeSaRecord, header, collectedFrags, resultFrags);
-
- return new ReceivedIkePacket(header, dummyPacket);
- }
-
- private ReceivedIkePacket makeDummyReceivedLastIkeFragmentPacketOk(
- IkeSaRecord ikeSaRecord,
- boolean isResp,
- int eType,
- DecodeResultPartial collectedFrags,
- List<IkePayload> payloadList,
- byte[] firstFragBytes) {
- IkeHeader header =
- makeDummyIkeHeader(ikeSaRecord, isResp, eType, IkePayload.PAYLOAD_TYPE_SKF);
-
- IkeMessage completeMessage = new IkeMessage(header, payloadList);
-
- setDecodeEncryptedPacketResult(
- ikeSaRecord,
- header,
- collectedFrags,
- new DecodeResultOk(completeMessage, firstFragBytes));
-
- return new ReceivedIkePacket(header, new byte[0] /*dummyIkePacketBytes*/);
- }
-
- private ReceivedIkePacket makeDummyReceivedLastIkeFragmentPacketError(
- IkeSaRecord ikeSaRecord,
- boolean isResp,
- int eType,
- DecodeResultPartial collectedFrags,
- IkeException exception) {
- IkeHeader header =
- makeDummyIkeHeader(ikeSaRecord, isResp, eType, IkePayload.PAYLOAD_TYPE_SKF);
-
- byte[] dummyIkePacketBytes = new byte[0];
- setDecodeEncryptedPacketResult(
- ikeSaRecord,
- header,
- collectedFrags,
- new DecodeResultProtectedError(exception, dummyIkePacketBytes));
-
- return new ReceivedIkePacket(header, dummyIkePacketBytes);
- }
-
- private IkeHeader makeDummyIkeHeader(
- IkeSaRecord ikeSaRecord, boolean isResp, int eType, int firstPayloadType) {
- return new IkeHeader(
- ikeSaRecord.getInitiatorSpi(),
- ikeSaRecord.getResponderSpi(),
- firstPayloadType,
- eType,
- isResp,
- !ikeSaRecord.isLocalInit,
- isResp
- ? ikeSaRecord.getLocalRequestMessageId()
- : ikeSaRecord.getRemoteRequestMessageId());
- }
-
- private void setDecodeEncryptedPacketResult(
- IkeSaRecord ikeSaRecord,
- IkeHeader header,
- DecodeResultPartial collectedFrags,
- DecodeResult result) {
- when(mMockIkeMessageHelper.decode(
- anyInt(),
- any(),
- any(),
- eq(ikeSaRecord),
- eq(header),
- any(),
- eq(collectedFrags)))
- .thenReturn(result);
- }
-
- private IkeMessage makeDummyIkeMessageForTest(
- long initSpi,
- long respSpi,
- @IkeHeader.ExchangeType int eType,
- boolean isResp,
- boolean fromikeInit,
- int messageId,
- boolean isEncrypted,
- List<IkePayload> payloadList)
- throws Exception {
- int firstPayloadType =
- isEncrypted ? IkePayload.PAYLOAD_TYPE_SK : IkePayload.PAYLOAD_TYPE_NO_NEXT;
-
- IkeHeader header =
- new IkeHeader(
- initSpi, respSpi, firstPayloadType, eType, isResp, fromikeInit, messageId);
-
- return new IkeMessage(header, payloadList);
- }
-
- private static List<IkePayload> hexStrListToIkePayloadList(
- List<Integer> payloadTypeList, List<String> payloadHexStringList, boolean isResp)
- throws Exception {
- List<IkePayload> payloadList = new LinkedList<>();
- for (int i = 0; i < payloadTypeList.size(); i++) {
- payloadList.add(
- IkeTestUtils.hexStringToIkePayload(
- payloadTypeList.get(i), isResp, payloadHexStringList.get(i)));
- }
- return payloadList;
- }
-
- private void verifyDecodeEncryptedMessage(IkeSaRecord record, ReceivedIkePacket rcvPacket)
- throws Exception {
- verify(mMockIkeMessageHelper)
- .decode(
- anyInt(),
- any(),
- any(),
- eq(record),
- eq(rcvPacket.ikeHeader),
- eq(rcvPacket.ikePacketBytes),
- eq(null));
- }
-
- private static IkeSaRecord makeDummyIkeSaRecord(long initSpi, long respSpi, boolean isLocalInit)
- throws IOException {
- Inet4Address initAddress = isLocalInit ? LOCAL_ADDRESS : REMOTE_ADDRESS;
- Inet4Address respAddress = isLocalInit ? REMOTE_ADDRESS : LOCAL_ADDRESS;
-
- return new IkeSaRecord(
- IkeSecurityParameterIndex.allocateSecurityParameterIndex(initAddress, initSpi),
- IkeSecurityParameterIndex.allocateSecurityParameterIndex(respAddress, respSpi),
- isLocalInit,
- TestUtils.hexStringToByteArray(NONCE_INIT_HEX_STRING),
- TestUtils.hexStringToByteArray(NONCE_RESP_HEX_STRING),
- new byte[KEY_LEN_IKE_SKD],
- new byte[KEY_LEN_IKE_INTE],
- new byte[KEY_LEN_IKE_INTE],
- new byte[KEY_LEN_IKE_ENCR],
- new byte[KEY_LEN_IKE_ENCR],
- TestUtils.hexStringToByteArray(PRF_KEY_INIT_HEX_STRING),
- TestUtils.hexStringToByteArray(PRF_KEY_RESP_HEX_STRING),
- new LocalRequest(CMD_LOCAL_REQUEST_REKEY_IKE));
- }
-
- @Before
- public void setUp() throws Exception {
- mSpyIkeLog = TestUtils.makeSpyLogThrowExceptionForWtf(TAG);
- IkeManager.setIkeLog(mSpyIkeLog);
-
- mMockIpSecTestUtils = MockIpSecTestUtils.setUpMockIpSec();
- mIpSecManager = mMockIpSecTestUtils.getIpSecManager();
- mContext = mMockIpSecTestUtils.getContext();
- mUdpEncapSocket = mIpSecManager.openUdpEncapsulationSocket();
- mEapSessionConfig =
- new EapSessionConfig.Builder()
- .setEapSimConfig(EAP_SIM_SUB_ID, TelephonyManager.APPTYPE_USIM)
- .build();
-
- mMockEapAuthenticatorFactory = mock(IkeEapAuthenticatorFactory.class);
- mMockEapAuthenticator = mock(EapAuthenticator.class);
- when(mMockEapAuthenticatorFactory.newEapAuthenticator(any(), any(), any(), any()))
- .thenReturn(mMockEapAuthenticator);
-
- mRootCertificate = CertUtils.createCertFromPemFile("self-signed-ca-a.pem");
- mServerEndCertificate = CertUtils.createCertFromPemFile("end-cert-a.pem");
-
- mPsk = TestUtils.hexStringToByteArray(PSK_HEX_STRING);
-
- mChildSessionOptions = buildChildSessionOptions();
-
- mIkeEncryptionTransform =
- new EncryptionTransform(
- SaProposal.ENCRYPTION_ALGORITHM_AES_CBC, SaProposal.KEY_LEN_AES_128);
- mIkeIntegrityTransform =
- new IntegrityTransform(SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96);
- mIkePrfTransform = new PrfTransform(SaProposal.PSEUDORANDOM_FUNCTION_HMAC_SHA1);
- mIkeDhGroupTransform = new DhGroupTransform(SaProposal.DH_GROUP_1024_BIT_MODP);
-
- mSpyUserCbExecutor =
- spy(
- (command) -> {
- command.run();
- });
-
- mMockIkeSessionCallback = mock(IkeSessionCallback.class);
- mMockChildSessionCallback = mock(ChildSessionCallback.class);
-
- mLooper = new TestLooper();
-
- mMockChildSessionStateMachine = mock(ChildSessionStateMachine.class);
- mMockChildSessionFactoryHelper = mock(IChildSessionFactoryHelper.class);
- ChildSessionStateMachineFactory.setChildSessionFactoryHelper(
- mMockChildSessionFactoryHelper);
- setupChildStateMachineFactory(mMockChildSessionStateMachine);
-
- // Inject longer retransmission timeout
- mMockBackoffTimeoutCalculator = mock(IBackoffTimeoutCalculator.class);
- when(mMockBackoffTimeoutCalculator.getExponentialBackoffTimeout(anyInt()))
- .thenReturn(RETRANSMIT_BACKOFF_TIMEOUT_MS);
- Retransmitter.setBackoffTimeoutCalculator(mMockBackoffTimeoutCalculator);
-
- // Setup state machine
- mIkeSessionStateMachine = makeAndStartIkeSession(buildIkeSessionOptionsPsk(mPsk));
-
- mMockIkeMessageHelper = mock(IkeMessage.IIkeMessageHelper.class);
- IkeMessage.setIkeMessageHelper(mMockIkeMessageHelper);
- resetMockIkeMessageHelper();
-
- mMockSaRecordHelper = mock(SaRecord.ISaRecordHelper.class);
- SaRecord.setSaRecordHelper(mMockSaRecordHelper);
-
- mSpyCurrentIkeSaRecord = spy(makeDummyIkeSaRecord(11, 12, true));
- mSpyLocalInitIkeSaRecord = spy(makeDummyIkeSaRecord(21, 22, true));
- mSpyRemoteInitIkeSaRecord = spy(makeDummyIkeSaRecord(31, 32, false));
-
- mExpectedCurrentSaLocalReqMsgId = 0;
- mExpectedCurrentSaRemoteReqMsgId = 0;
- }
-
- @After
- public void tearDown() throws Exception {
- mIkeSessionStateMachine.quit();
- mIkeSessionStateMachine.setDbg(false);
- mUdpEncapSocket.close();
-
- mSpyCurrentIkeSaRecord.close();
- mSpyLocalInitIkeSaRecord.close();
- mSpyRemoteInitIkeSaRecord.close();
-
- IkeManager.resetIkeLog();
- Retransmitter.resetBackoffTimeoutCalculator();
- IkeMessage.setIkeMessageHelper(new IkeMessageHelper());
- SaRecord.setSaRecordHelper(new SaRecordHelper());
- ChildSessionStateMachineFactory.setChildSessionFactoryHelper(
- new ChildSessionFactoryHelper());
- }
-
- private IkeSessionStateMachine makeAndStartIkeSession(IkeSessionOptions ikeOptions)
- throws Exception {
- IkeSessionStateMachine ikeSession =
- new IkeSessionStateMachine(
- mLooper.getLooper(),
- mContext,
- mIpSecManager,
- ikeOptions,
- mChildSessionOptions,
- mSpyUserCbExecutor,
- mMockIkeSessionCallback,
- mMockChildSessionCallback,
- mMockEapAuthenticatorFactory);
- ikeSession.setDbg(true);
-
- mLooper.dispatchAll();
- ikeSession.mLocalAddress = LOCAL_ADDRESS;
-
- mSpyIkeSocket = spy(IkeSocket.getIkeSocket(mUdpEncapSocket, ikeSession));
- doNothing().when(mSpyIkeSocket).sendIkePacket(any(), any());
- ikeSession.mIkeSocket = mSpyIkeSocket;
-
- return ikeSession;
- }
-
- public static IkeSaProposal buildSaProposal() throws Exception {
- return new IkeSaProposal.Builder()
- .addEncryptionAlgorithm(
- SaProposal.ENCRYPTION_ALGORITHM_AES_CBC, SaProposal.KEY_LEN_AES_128)
- .addIntegrityAlgorithm(SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96)
- .addPseudorandomFunction(SaProposal.PSEUDORANDOM_FUNCTION_HMAC_SHA1)
- .addDhGroup(SaProposal.DH_GROUP_1024_BIT_MODP)
- .build();
- }
-
- private IkeSessionOptions.Builder buildIkeSessionOptionsCommon() throws Exception {
- return new IkeSessionOptions.Builder()
- .setServerAddress(REMOTE_ADDRESS)
- .setUdpEncapsulationSocket(mUdpEncapSocket)
- .addSaProposal(buildSaProposal())
- .setLocalIdentification(new IkeIpv4AddrIdentification((Inet4Address) LOCAL_ADDRESS))
- .setRemoteIdentification(
- new IkeIpv4AddrIdentification((Inet4Address) REMOTE_ADDRESS));
- }
-
- private IkeSessionOptions buildIkeSessionOptionsPsk(byte[] psk) throws Exception {
- return buildIkeSessionOptionsCommon().setAuthPsk(psk).build();
- }
-
- private IkeSessionOptions buildIkeSessionOptionsEap() throws Exception {
- return buildIkeSessionOptionsCommon()
- .setAuthEap(mRootCertificate, mEapSessionConfig)
- .build();
- }
-
- private ChildSessionOptions buildChildSessionOptions() throws Exception {
- ChildSaProposal saProposal =
- new ChildSaProposal.Builder()
- .addEncryptionAlgorithm(
- SaProposal.ENCRYPTION_ALGORITHM_AES_CBC, SaProposal.KEY_LEN_AES_128)
- .addIntegrityAlgorithm(SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96)
- .build();
-
- return new TransportModeChildSessionOptions.Builder().addSaProposal(saProposal).build();
- }
-
- private ReceivedIkePacket makeIkeInitResponse() throws Exception {
- // TODO: Build real IKE INIT response when IKE INIT response validation is implemented.
- List<Integer> payloadTypeList = new LinkedList<>();
- List<String> payloadHexStringList = new LinkedList<>();
-
- payloadTypeList.add(IkePayload.PAYLOAD_TYPE_SA);
- payloadTypeList.add(IkePayload.PAYLOAD_TYPE_KE);
- payloadTypeList.add(IkePayload.PAYLOAD_TYPE_NONCE);
- payloadTypeList.add(IkePayload.PAYLOAD_TYPE_NOTIFY);
- payloadTypeList.add(IkePayload.PAYLOAD_TYPE_NOTIFY);
- payloadTypeList.add(IkePayload.PAYLOAD_TYPE_NOTIFY);
-
- payloadHexStringList.add(IKE_SA_PAYLOAD_HEX_STRING);
- payloadHexStringList.add(KE_PAYLOAD_HEX_STRING);
- payloadHexStringList.add(NONCE_RESP_PAYLOAD_HEX_STRING);
- payloadHexStringList.add(NAT_DETECTION_SOURCE_PAYLOAD_HEX_STRING);
- payloadHexStringList.add(NAT_DETECTION_DESTINATION_PAYLOAD_HEX_STRING);
- payloadHexStringList.add(FRAGMENTATION_SUPPORTED_PAYLOAD_HEX_STRING);
-
- // In each test assign different IKE responder SPI in IKE INIT response to avoid remote SPI
- // collision during response validation.
- // STOPSHIP: b/131617794 allow #mockIkeSetup to be independent in each test after we can
- // support IkeSession cleanup.
- return makeDummyReceivedIkeInitRespPacket(
- 1L /*initiator SPI*/,
- 2L /*responder SPI*/,
- IkeHeader.EXCHANGE_TYPE_IKE_SA_INIT,
- true /*isResp*/,
- false /*fromIkeInit*/,
- payloadTypeList,
- payloadHexStringList);
- }
-
- private List<IkePayload> getIkeAuthPayloadListWithChildPayloads(
- List<IkePayload> authRelatedPayloads) throws Exception {
- List<Integer> payloadTypeList = new LinkedList<>();
- List<String> payloadHexStringList = new LinkedList<>();
-
- payloadTypeList.add(IkePayload.PAYLOAD_TYPE_SA);
- payloadTypeList.add(IkePayload.PAYLOAD_TYPE_TS_INITIATOR);
- payloadTypeList.add(IkePayload.PAYLOAD_TYPE_TS_RESPONDER);
-
- payloadHexStringList.add(CHILD_SA_PAYLOAD_HEX_STRING);
- payloadHexStringList.add(TS_INIT_PAYLOAD_HEX_STRING);
- payloadHexStringList.add(TS_RESP_PAYLOAD_HEX_STRING);
-
- List<IkePayload> payloadList =
- hexStrListToIkePayloadList(payloadTypeList, payloadHexStringList, true /*isResp*/);
- payloadList.addAll(authRelatedPayloads);
-
- return payloadList;
- }
-
- private ReceivedIkePacket makeIkeAuthRespWithChildPayloads(List<IkePayload> authRelatedPayloads)
- throws Exception {
- List<IkePayload> payloadList = getIkeAuthPayloadListWithChildPayloads(authRelatedPayloads);
-
- return makeDummyEncryptedReceivedIkePacketWithPayloadList(
- mSpyCurrentIkeSaRecord,
- IkeHeader.EXCHANGE_TYPE_IKE_AUTH,
- true /*isResp*/,
- payloadList);
- }
-
- private ReceivedIkePacket makeIkeAuthRespWithoutChildPayloads(
- List<IkePayload> authRelatedPayloads) throws Exception {
- return makeDummyEncryptedReceivedIkePacketWithPayloadList(
- mSpyCurrentIkeSaRecord,
- IkeHeader.EXCHANGE_TYPE_IKE_AUTH,
- true /*isResp*/,
- authRelatedPayloads);
- }
-
- private ReceivedIkePacket makeCreateChildCreateMessage(boolean isResp) throws Exception {
- return makeDummyEncryptedReceivedIkePacketWithPayloadList(
- mSpyCurrentIkeSaRecord,
- IkeHeader.EXCHANGE_TYPE_CREATE_CHILD_SA,
- isResp,
- makeCreateChildPayloadList(isResp));
- }
-
- private ReceivedIkePacket makeRekeyChildCreateMessage(boolean isResp, int spi)
- throws Exception {
- IkeNotifyPayload rekeyPayload =
- new IkeNotifyPayload(
- IkePayload.PROTOCOL_ID_ESP,
- spi,
- IkeNotifyPayload.NOTIFY_TYPE_REKEY_SA,
- new byte[0]);
-
- List<IkePayload> payloadList = makeCreateChildPayloadList(isResp);
- payloadList.add(rekeyPayload);
-
- return makeDummyEncryptedReceivedIkePacketWithPayloadList(
- mSpyCurrentIkeSaRecord,
- IkeHeader.EXCHANGE_TYPE_CREATE_CHILD_SA,
- isResp,
- payloadList);
- }
-
- private List<IkePayload> makeCreateChildPayloadList(boolean isResp) throws Exception {
- List<Integer> payloadTypeList = new LinkedList<>();
- List<String> payloadHexStringList = new LinkedList<>();
-
- payloadTypeList.add(IkePayload.PAYLOAD_TYPE_SA);
- payloadTypeList.add(IkePayload.PAYLOAD_TYPE_NONCE);
- payloadTypeList.add(IkePayload.PAYLOAD_TYPE_TS_INITIATOR);
- payloadTypeList.add(IkePayload.PAYLOAD_TYPE_TS_RESPONDER);
-
- payloadHexStringList.add(CHILD_SA_PAYLOAD_HEX_STRING);
- payloadHexStringList.add(NONCE_RESP_PAYLOAD_HEX_STRING);
- payloadHexStringList.add(TS_INIT_PAYLOAD_HEX_STRING);
- payloadHexStringList.add(TS_RESP_PAYLOAD_HEX_STRING);
-
- return hexStrListToIkePayloadList(payloadTypeList, payloadHexStringList, isResp);
- }
-
- private ReceivedIkePacket makeDeleteChildPacket(IkeDeletePayload[] payloads, boolean isResp)
- throws Exception {
- return makeDummyEncryptedReceivedIkePacketWithPayloadList(
- mSpyCurrentIkeSaRecord,
- IkeHeader.EXCHANGE_TYPE_INFORMATIONAL,
- isResp,
- Arrays.asList(payloads));
- }
-
- private ReceivedIkePacket makeRekeyIkeResponse() throws Exception {
- List<Integer> payloadTypeList = new LinkedList<>();
- List<String> payloadHexStringList = new LinkedList<>();
-
- payloadTypeList.add(IkePayload.PAYLOAD_TYPE_SA);
- payloadTypeList.add(IkePayload.PAYLOAD_TYPE_KE);
- payloadTypeList.add(IkePayload.PAYLOAD_TYPE_NONCE);
-
- payloadHexStringList.add(IKE_REKEY_SA_PAYLOAD_HEX_STRING);
- payloadHexStringList.add(KE_PAYLOAD_HEX_STRING);
- payloadHexStringList.add(NONCE_RESP_PAYLOAD_HEX_STRING);
-
- return makeDummyEncryptedReceivedIkePacket(
- mSpyCurrentIkeSaRecord,
- IkeHeader.EXCHANGE_TYPE_CREATE_CHILD_SA,
- true /*isResp*/,
- payloadTypeList,
- payloadHexStringList);
- }
-
- private ReceivedIkePacket makeDeleteIkeResponse(IkeSaRecord ikeSaRecord) throws Exception {
- return makeDummyEncryptedReceivedIkePacket(
- ikeSaRecord,
- IkeHeader.EXCHANGE_TYPE_INFORMATIONAL,
- true /*isResp*/,
- new LinkedList<>(),
- new LinkedList<>());
- }
-
- private ReceivedIkePacket makeDpdIkeRequest(IkeSaRecord saRecord) throws Exception {
- return makeDummyEncryptedReceivedIkePacket(
- saRecord,
- IkeHeader.EXCHANGE_TYPE_INFORMATIONAL,
- false /*isResp*/,
- new LinkedList<>(),
- new LinkedList<>());
- }
-
- private ReceivedIkePacket makeDpdIkeRequest(int msgId, byte[] dummyIkePacketBytes)
- throws Exception {
- return makeDummyEncryptedReceivedIkePacketWithPayloadList(
- mSpyCurrentIkeSaRecord,
- EXCHANGE_TYPE_INFORMATIONAL,
- false /*isResp*/,
- msgId,
- new LinkedList<>(),
- dummyIkePacketBytes);
- }
-
- private ReceivedIkePacket makeRekeyIkeRequest() throws Exception {
- IkeSaPayload saPayload =
- (IkeSaPayload)
- IkeTestUtils.hexStringToIkePayload(
- IkePayload.PAYLOAD_TYPE_SA,
- false /*isResp*/,
- IKE_REKEY_SA_PAYLOAD_HEX_STRING);
- return makeRekeyIkeRequest(saPayload);
- }
-
- private ReceivedIkePacket makeRekeyIkeRequestWithUnacceptableProposal() throws Exception {
- IkeSaPayload saPayload =
- (IkeSaPayload)
- IkeTestUtils.hexStringToIkePayload(
- IkePayload.PAYLOAD_TYPE_SA,
- false /*isResp*/,
- IKE_REKEY_UNACCEPTABLE_SA_PAYLOAD_HEX_STRING);
- return makeRekeyIkeRequest(saPayload);
- }
-
- private ReceivedIkePacket makeRekeyIkeRequest(IkeSaPayload saPayload) throws Exception {
- List<Integer> payloadTypeList = new LinkedList<>();
- List<String> payloadHexStringList = new LinkedList<>();
-
- payloadTypeList.add(IkePayload.PAYLOAD_TYPE_KE);
- payloadTypeList.add(IkePayload.PAYLOAD_TYPE_NONCE);
-
- payloadHexStringList.add(KE_PAYLOAD_HEX_STRING);
- payloadHexStringList.add(NONCE_INIT_PAYLOAD_HEX_STRING);
-
- List<IkePayload> payloadList =
- hexStrListToIkePayloadList(payloadTypeList, payloadHexStringList, false /*isResp*/);
- payloadList.add(saPayload);
-
- return makeDummyEncryptedReceivedIkePacketWithPayloadList(
- mSpyCurrentIkeSaRecord,
- IkeHeader.EXCHANGE_TYPE_CREATE_CHILD_SA,
- false /*isResp*/,
- payloadList);
- }
-
- private ReceivedIkePacket makeDeleteIkeRequest(IkeSaRecord saRecord) throws Exception {
- List<Integer> payloadTypeList = new LinkedList<>();
- List<String> payloadHexStringList = new LinkedList<>();
-
- payloadTypeList.add(IkePayload.PAYLOAD_TYPE_DELETE);
-
- payloadHexStringList.add(DELETE_IKE_PAYLOAD_HEX_STRING);
-
- return makeDummyEncryptedReceivedIkePacket(
- saRecord,
- IkeHeader.EXCHANGE_TYPE_INFORMATIONAL,
- false /*isResp*/,
- payloadTypeList,
- payloadHexStringList);
- }
-
- private ReceivedIkePacket makeResponseWithErrorNotify(IkeNotifyPayload notify)
- throws Exception {
- List<IkePayload> payloads = new LinkedList<>();
- payloads.add(notify);
- return makeDummyEncryptedReceivedIkePacketWithPayloadList(
- mSpyCurrentIkeSaRecord, EXCHANGE_TYPE_INFORMATIONAL, true /*isResp*/, payloads);
- }
-
- private static boolean isIkePayloadExist(
- List<IkePayload> payloadList, @IkePayload.PayloadType int payloadType) {
- for (IkePayload payload : payloadList) {
- if (payload.payloadType == payloadType) return true;
- }
- return false;
- }
-
- private static boolean isNotifyExist(
- List<IkePayload> payloadList, @IkeNotifyPayload.NotifyType int notifyType) {
- for (IkeNotifyPayload notify :
- IkePayload.getPayloadListForTypeInProvidedList(
- PAYLOAD_TYPE_NOTIFY, IkeNotifyPayload.class, payloadList)) {
- if (notify.notifyType == notifyType) return true;
- }
- return false;
- }
-
- private void verifyIncrementLocaReqMsgId() {
- assertEquals(
- ++mExpectedCurrentSaLocalReqMsgId,
- mSpyCurrentIkeSaRecord.getLocalRequestMessageId());
- }
-
- private void verifyIncrementRemoteReqMsgId() {
- assertEquals(
- ++mExpectedCurrentSaRemoteReqMsgId,
- mSpyCurrentIkeSaRecord.getRemoteRequestMessageId());
- }
-
- private void verifyRetransmissionStarted() {
- assertTrue(
- mIkeSessionStateMachine
- .getHandler()
- .hasMessages(IkeSessionStateMachine.CMD_RETRANSMIT));
- }
-
- private void verifyRetransmissionStopped() {
- assertFalse(
- mIkeSessionStateMachine
- .getHandler()
- .hasMessages(IkeSessionStateMachine.CMD_RETRANSMIT));
- }
-
- private IkeMessage verifyEncryptAndEncodeAndGetMessage(IkeSaRecord ikeSaRecord) {
- verify(mMockIkeMessageHelper)
- .encryptAndEncode(
- anyObject(),
- anyObject(),
- eq(ikeSaRecord),
- mIkeMessageCaptor.capture(),
- anyBoolean(),
- anyInt());
- return mIkeMessageCaptor.getValue();
- }
-
- private void verifyEncryptAndEncodeNeverCalled(IkeSaRecord ikeSaRecord) {
- verify(mMockIkeMessageHelper, never())
- .encryptAndEncode(
- anyObject(),
- anyObject(),
- eq(ikeSaRecord),
- any(IkeMessage.class),
- anyBoolean(),
- anyInt());
- }
-
- private void verifyEncryptAndEncodeNeverCalled() {
- verify(mMockIkeMessageHelper, never())
- .encryptAndEncode(
- anyObject(),
- anyObject(),
- any(IkeSaRecord.class),
- any(IkeMessage.class),
- anyBoolean(),
- anyInt());
- }
-
- private void resetMockIkeMessageHelper() {
- reset(mMockIkeMessageHelper);
- when(mMockIkeMessageHelper.encode(any())).thenReturn(new byte[0]);
- when(mMockIkeMessageHelper.encryptAndEncode(
- any(), any(), any(), any(), anyBoolean(), anyInt()))
- .thenReturn(new byte[1][0]);
- }
-
- @Test
- public void testQuit() {
- mIkeSessionStateMachine.quit();
- mLooper.dispatchAll();
-
- verify(mSpyIkeSocket).releaseReference(eq(mIkeSessionStateMachine));
- verify(mSpyIkeSocket).close();
- }
-
- @Test
- public void testAllocateIkeSpi() throws Exception {
- // Test randomness.
- IkeSecurityParameterIndex ikeSpiOne =
- IkeSecurityParameterIndex.allocateSecurityParameterIndex(LOCAL_ADDRESS);
- IkeSecurityParameterIndex ikeSpiTwo =
- IkeSecurityParameterIndex.allocateSecurityParameterIndex(LOCAL_ADDRESS);
-
- assertNotEquals(ikeSpiOne.getSpi(), ikeSpiTwo.getSpi());
- ikeSpiTwo.close();
-
- // Test duplicate SPIs.
- long spiValue = ikeSpiOne.getSpi();
- try {
- IkeSecurityParameterIndex.allocateSecurityParameterIndex(LOCAL_ADDRESS, spiValue);
- fail("Expected to fail because duplicate SPI was assigned to the same address.");
- } catch (IOException expected) {
-
- }
-
- ikeSpiOne.close();
- IkeSecurityParameterIndex ikeSpiThree =
- IkeSecurityParameterIndex.allocateSecurityParameterIndex(LOCAL_ADDRESS, spiValue);
- ikeSpiThree.close();
- }
-
- private void setupFirstIkeSa() throws Exception {
- // Inject IkeSaRecord and release IKE SPI resource since we will lose their references
- // later.
- when(mMockSaRecordHelper.makeFirstIkeSaRecord(any(), any(), any()))
- .thenAnswer(
- (invocation) -> {
- captureAndReleaseIkeSpiResource(invocation, 2);
- return mSpyCurrentIkeSaRecord;
- });
- }
-
- private void setupRekeyedIkeSa(IkeSaRecord rekeySaRecord) throws Exception {
- // Inject IkeSaRecord and release IKE SPI resource since we will lose their references
- // later.
- when(mMockSaRecordHelper.makeRekeyedIkeSaRecord(
- eq(mSpyCurrentIkeSaRecord), any(), any(), any(), any()))
- .thenAnswer(
- (invocation) -> {
- captureAndReleaseIkeSpiResource(invocation, 4);
- return rekeySaRecord;
- });
- }
-
- private void throwExceptionWhenMakeRekeyIkeSa(Exception exception) throws Exception {
- // Inject IkeSaRecord and release IKE SPI resource since we will lose their references
- // later.
- when(mMockSaRecordHelper.makeRekeyedIkeSaRecord(
- eq(mSpyCurrentIkeSaRecord), any(), any(), any(), any()))
- .thenAnswer(
- (invocation) -> {
- captureAndReleaseIkeSpiResource(invocation, 4);
- throw exception;
- });
- }
-
- private void captureAndReleaseIkeSpiResource(InvocationOnMock invocation, int ikeConfigIndex) {
- IkeSaRecordConfig config = (IkeSaRecordConfig) invocation.getArguments()[ikeConfigIndex];
- config.initSpi.close();
- config.respSpi.close();
- }
-
- @Test
- public void testCreateIkeLocalIkeInit() throws Exception {
- setupFirstIkeSa();
-
- // Send IKE INIT request
- mIkeSessionStateMachine.sendMessage(IkeSessionStateMachine.CMD_LOCAL_REQUEST_CREATE_IKE);
- mLooper.dispatchAll();
- verifyRetransmissionStarted();
-
- // Receive IKE INIT response
- ReceivedIkePacket dummyReceivedIkePacket = makeIkeInitResponse();
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, dummyReceivedIkePacket);
- mLooper.dispatchAll();
- verifyIncrementLocaReqMsgId();
-
- // Validate outbound IKE INIT request
- verify(mMockIkeMessageHelper, times(2)).encode(mIkeMessageCaptor.capture());
- IkeMessage ikeInitReqMessage = mIkeMessageCaptor.getValue();
-
- IkeHeader ikeHeader = ikeInitReqMessage.ikeHeader;
- assertEquals(IkeHeader.EXCHANGE_TYPE_IKE_SA_INIT, ikeHeader.exchangeType);
- assertFalse(ikeHeader.isResponseMsg);
- assertTrue(ikeHeader.fromIkeInitiator);
-
- List<IkePayload> payloadList = ikeInitReqMessage.ikePayloadList;
- assertTrue(isIkePayloadExist(payloadList, IkePayload.PAYLOAD_TYPE_SA));
- assertTrue(isIkePayloadExist(payloadList, IkePayload.PAYLOAD_TYPE_KE));
- assertTrue(isIkePayloadExist(payloadList, IkePayload.PAYLOAD_TYPE_NONCE));
- assertTrue(isNotifyExist(payloadList, NOTIFY_TYPE_NAT_DETECTION_SOURCE_IP));
- assertTrue(isNotifyExist(payloadList, NOTIFY_TYPE_NAT_DETECTION_DESTINATION_IP));
- assertTrue(isNotifyExist(payloadList, NOTIFY_TYPE_IKEV2_FRAGMENTATION_SUPPORTED));
-
- verify(mSpyIkeSocket)
- .registerIke(eq(mSpyCurrentIkeSaRecord.getLocalSpi()), eq(mIkeSessionStateMachine));
-
- verify(mMockIkeMessageHelper)
- .decode(0, dummyReceivedIkePacket.ikeHeader, dummyReceivedIkePacket.ikePacketBytes);
- assertTrue(
- mIkeSessionStateMachine.getCurrentState()
- instanceof IkeSessionStateMachine.CreateIkeLocalIkeAuth);
- verifyRetransmissionStarted();
-
- // Validate negotiated SA proposal.
- IkeSaProposal negotiatedProposal = mIkeSessionStateMachine.mSaProposal;
- assertNotNull(negotiatedProposal);
-
- assertEquals(
- new EncryptionTransform[] {mIkeEncryptionTransform},
- negotiatedProposal.getEncryptionTransforms());
- assertEquals(
- new IntegrityTransform[] {mIkeIntegrityTransform},
- negotiatedProposal.getIntegrityTransforms());
- assertEquals(new PrfTransform[] {mIkePrfTransform}, negotiatedProposal.getPrfTransforms());
-
- // Validate current IkeSaRecord.
- verify(mMockSaRecordHelper)
- .makeFirstIkeSaRecord(
- any(IkeMessage.class),
- any(IkeMessage.class),
- mIkeSaRecordConfigCaptor.capture());
-
- IkeSaRecordConfig ikeSaRecordConfig = mIkeSaRecordConfigCaptor.getValue();
- assertEquals(KEY_LEN_IKE_PRF, ikeSaRecordConfig.prf.getKeyLength());
- assertEquals(KEY_LEN_IKE_INTE, ikeSaRecordConfig.integrityKeyLength);
- assertEquals(KEY_LEN_IKE_ENCR, ikeSaRecordConfig.encryptionKeyLength);
- assertEquals(CMD_LOCAL_REQUEST_REKEY_IKE, ikeSaRecordConfig.futureRekeyEvent.procedureType);
-
- // Validate NAT detection
- assertTrue(mIkeSessionStateMachine.mIsLocalBehindNat);
- assertFalse(mIkeSessionStateMachine.mIsRemoteBehindNat);
-
- // Validate fragmentation support negotiation
- assertTrue(mIkeSessionStateMachine.mSupportFragment);
- }
-
- private void setIkeInitResults() throws Exception {
- mIkeSessionStateMachine.mIkeCipher = mock(IkeCipher.class);
- mIkeSessionStateMachine.mIkeIntegrity = mock(IkeMacIntegrity.class);
- mIkeSessionStateMachine.mIkePrf = mock(IkeMacPrf.class);
- mIkeSessionStateMachine.mSaProposal = buildSaProposal();
- mIkeSessionStateMachine.mCurrentIkeSaRecord = mSpyCurrentIkeSaRecord;
- mIkeSessionStateMachine.mLocalAddress = LOCAL_ADDRESS;
- mIkeSessionStateMachine.mIsLocalBehindNat = true;
- mIkeSessionStateMachine.mIsRemoteBehindNat = false;
- mIkeSessionStateMachine.mSupportFragment = true;
- mIkeSessionStateMachine.addIkeSaRecord(mSpyCurrentIkeSaRecord);
- }
-
- /** Initializes the mIkeSessionStateMachine in the IDLE state. */
- private void setupIdleStateMachine() throws Exception {
- setIkeInitResults();
-
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_FORCE_TRANSITION, mIkeSessionStateMachine.mIdle);
- mLooper.dispatchAll();
-
- mDummyChildSmCallback =
- createChildAndGetChildSessionSmCallback(
- mMockChildSessionStateMachine, CHILD_SPI_REMOTE, mMockChildSessionCallback);
-
- assertTrue(
- mIkeSessionStateMachine.getCurrentState() instanceof IkeSessionStateMachine.Idle);
- }
-
- private void mockIkeInitAndTransitionToIkeAuth(State authState) throws Exception {
- setIkeInitResults();
-
- // Need to create a real IkeMacPrf instance for authentication because we cannot inject a
- // method stub for IkeMacPrf#signBytes. IkeMacPrf#signBytes is inheritted from a package
- // protected class IkePrf. We don't have the visibility to mock it.
- mIkeSessionStateMachine.mIkePrf =
- IkeMacPrf.create(
- new PrfTransform(SaProposal.PSEUDORANDOM_FUNCTION_HMAC_SHA1),
- IkeMessage.getSecurityProvider());
-
- mIkeSessionStateMachine.mIkeInitRequestBytes = new byte[0];
- mIkeSessionStateMachine.mIkeInitResponseBytes = new byte[0];
- mIkeSessionStateMachine.mIkeInitNoncePayload = new IkeNoncePayload();
- mIkeSessionStateMachine.mIkeRespNoncePayload = new IkeNoncePayload();
-
- mIkeSessionStateMachine.sendMessage(IkeSessionStateMachine.CMD_FORCE_TRANSITION, authState);
- mLooper.dispatchAll();
- }
-
- private void setupChildStateMachineFactory(ChildSessionStateMachine child) {
- // After state machine start, add to the callback->statemachine map
- when(mMockChildSessionFactoryHelper.makeChildSessionStateMachine(
- eq(mLooper.getLooper()),
- eq(mContext),
- eq(mChildSessionOptions),
- eq(mSpyUserCbExecutor),
- any(ChildSessionCallback.class),
- any(IChildSessionSmCallback.class)))
- .thenReturn(child);
- }
-
- /**
- * Utility to register a new callback -> state machine mapping.
- *
- * <p>Must be used if IkeSessionStateMachine.openChildSession() is not called, but commands
- * injected instead.
- *
- * @param callback The callback to be used for the mapping
- * @param sm The ChildSessionStateMachine instance to be used.
- */
- private void registerChildStateMachine(
- ChildSessionCallback callback, ChildSessionStateMachine sm) {
- setupChildStateMachineFactory(sm);
- mIkeSessionStateMachine.registerChildSessionCallback(
- mChildSessionOptions, callback, false /*isFirstChild*/);
- }
-
- @Test
- public void testCreateAdditionalChild() throws Exception {
- setupIdleStateMachine();
-
- ChildSessionCallback childCallback = mock(ChildSessionCallback.class);
- ChildSessionStateMachine childStateMachine = mock(ChildSessionStateMachine.class);
- registerChildStateMachine(childCallback, childStateMachine);
-
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_EXECUTE_LOCAL_REQ,
- new ChildLocalRequest(
- IkeSessionStateMachine.CMD_LOCAL_REQUEST_CREATE_CHILD,
- childCallback,
- mChildSessionOptions));
- mLooper.dispatchAll();
-
- assertTrue(
- mIkeSessionStateMachine.getCurrentState()
- instanceof IkeSessionStateMachine.ChildProcedureOngoing);
- verify(childStateMachine)
- .createChildSession(
- eq(LOCAL_ADDRESS),
- eq(REMOTE_ADDRESS),
- any(), // udpEncapSocket
- eq(mIkeSessionStateMachine.mIkePrf),
- any()); // sk_d
-
- // Once for initial child, a second time for the additional child.
- verify(mMockChildSessionFactoryHelper)
- .makeChildSessionStateMachine(
- eq(mLooper.getLooper()),
- eq(mContext),
- eq(mChildSessionOptions),
- eq(mSpyUserCbExecutor),
- eq(childCallback),
- mChildSessionSmCbCaptor.capture());
- IChildSessionSmCallback cb = mChildSessionSmCbCaptor.getValue();
-
- // Mocking sending request
- cb.onOutboundPayloadsReady(
- IkeHeader.EXCHANGE_TYPE_CREATE_CHILD_SA,
- false /*isResp*/,
- new LinkedList<>(),
- childStateMachine);
- mLooper.dispatchAll();
- verifyRetransmissionStarted();
-
- IkeMessage createChildRequest = verifyEncryptAndEncodeAndGetMessage(mSpyCurrentIkeSaRecord);
-
- IkeHeader ikeHeader = createChildRequest.ikeHeader;
- assertEquals(IkeHeader.EXCHANGE_TYPE_CREATE_CHILD_SA, ikeHeader.exchangeType);
- assertFalse(ikeHeader.isResponseMsg);
- assertTrue(ikeHeader.fromIkeInitiator);
- assertEquals(mSpyCurrentIkeSaRecord.getLocalRequestMessageId(), ikeHeader.messageId);
- assertTrue(createChildRequest.ikePayloadList.isEmpty());
-
- assertTrue(
- mIkeSessionStateMachine.getCurrentState()
- instanceof IkeSessionStateMachine.ChildProcedureOngoing);
-
- // Mocking receiving response
- ReceivedIkePacket dummyCreateChildResp = makeCreateChildCreateMessage(true /*isResp*/);
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, dummyCreateChildResp);
- mLooper.dispatchAll();
-
- verifyIncrementLocaReqMsgId();
- verifyDecodeEncryptedMessage(mSpyCurrentIkeSaRecord, dummyCreateChildResp);
-
- verify(childStateMachine)
- .receiveResponse(
- eq(IkeHeader.EXCHANGE_TYPE_CREATE_CHILD_SA), mPayloadListCaptor.capture());
-
- List<IkePayload> childRespList = mPayloadListCaptor.getValue();
- assertTrue(isIkePayloadExist(childRespList, IkePayload.PAYLOAD_TYPE_SA));
- assertTrue(isIkePayloadExist(childRespList, IkePayload.PAYLOAD_TYPE_TS_INITIATOR));
- assertTrue(isIkePayloadExist(childRespList, IkePayload.PAYLOAD_TYPE_TS_RESPONDER));
- assertTrue(isIkePayloadExist(childRespList, IkePayload.PAYLOAD_TYPE_NONCE));
-
- // Mock finishing procedure
- cb.onProcedureFinished(childStateMachine);
- mLooper.dispatchAll();
- assertTrue(
- mIkeSessionStateMachine.getCurrentState() instanceof IkeSessionStateMachine.Idle);
- verifyRetransmissionStopped();
- }
-
- @Test
- public void testTriggerDeleteChildLocal() throws Exception {
- setupIdleStateMachine();
-
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_EXECUTE_LOCAL_REQ,
- new ChildLocalRequest(
- IkeSessionStateMachine.CMD_LOCAL_REQUEST_DELETE_CHILD,
- mMockChildSessionCallback,
- null /*childOptions*/));
- mLooper.dispatchAll();
-
- assertTrue(
- mIkeSessionStateMachine.getCurrentState()
- instanceof IkeSessionStateMachine.ChildProcedureOngoing);
- verify(mMockChildSessionStateMachine).deleteChildSession();
- }
-
- @Test
- public void testHandleDeleteChildBeforeCreation() throws Exception {
- setupIdleStateMachine();
-
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_EXECUTE_LOCAL_REQ,
- new ChildLocalRequest(
- IkeSessionStateMachine.CMD_LOCAL_REQUEST_DELETE_CHILD,
- mock(ChildSessionCallback.class),
- null /*childOptions*/));
- mLooper.dispatchAll();
-
- assertTrue(
- mIkeSessionStateMachine.getCurrentState() instanceof IkeSessionStateMachine.Idle);
- }
-
- @Test
- public void testTriggerRekeyChildLocal() throws Exception {
- setupIdleStateMachine();
-
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_EXECUTE_LOCAL_REQ,
- new ChildLocalRequest(
- IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_CHILD,
- mMockChildSessionCallback,
- null /*childOptions*/));
- mLooper.dispatchAll();
-
- assertTrue(
- mIkeSessionStateMachine.getCurrentState()
- instanceof IkeSessionStateMachine.ChildProcedureOngoing);
- verify(mMockChildSessionStateMachine).rekeyChildSession();
- }
-
- @Test
- public void testScheduleAndTriggerRekeyChildLocal() throws Exception {
- setupIdleStateMachine();
- long dummyRekeyTimeout = 10000L;
-
- ChildLocalRequest rekeyRequest =
- new ChildLocalRequest(
- IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_CHILD,
- mMockChildSessionCallback,
- null /*childOptions*/);
- mDummyChildSmCallback.scheduleLocalRequest(rekeyRequest, dummyRekeyTimeout);
-
- mLooper.moveTimeForward(dummyRekeyTimeout);
- mLooper.dispatchAll();
-
- assertTrue(
- mIkeSessionStateMachine.getCurrentState()
- instanceof IkeSessionStateMachine.ChildProcedureOngoing);
- verify(mMockChildSessionStateMachine).rekeyChildSession();
- }
-
- private IChildSessionSmCallback createChildAndGetChildSessionSmCallback(
- ChildSessionStateMachine child, int remoteSpi) throws Exception {
- return createChildAndGetChildSessionSmCallback(
- child, remoteSpi, mock(ChildSessionCallback.class));
- }
-
- private IChildSessionSmCallback createChildAndGetChildSessionSmCallback(
- ChildSessionStateMachine child, int remoteSpi, ChildSessionCallback childCallback)
- throws Exception {
- registerChildStateMachine(childCallback, child);
-
- IChildSessionSmCallback cb = mIkeSessionStateMachine.new ChildSessionSmCallback();
- cb.onChildSaCreated(remoteSpi, child);
- mLooper.dispatchAll();
-
- return cb;
- }
-
- private void transitionToChildProcedureOngoing() {
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_FORCE_TRANSITION,
- mIkeSessionStateMachine.mChildProcedureOngoing);
- mLooper.dispatchAll();
- assertTrue(
- mIkeSessionStateMachine.getCurrentState()
- instanceof IkeSessionStateMachine.ChildProcedureOngoing);
- }
-
- private void verifyChildReceiveDeleteRequest(
- ChildSessionStateMachine child, IkeDeletePayload[] expectedDelPayloads) {
- verify(child)
- .receiveRequest(
- eq(IKE_EXCHANGE_SUBTYPE_DELETE_CHILD),
- eq(EXCHANGE_TYPE_INFORMATIONAL),
- mPayloadListCaptor.capture());
- List<IkePayload> reqPayloads = mPayloadListCaptor.getValue();
-
- int numExpectedDelPayloads = expectedDelPayloads.length;
- assertEquals(numExpectedDelPayloads, reqPayloads.size());
-
- for (int i = 0; i < numExpectedDelPayloads; i++) {
- assertEquals(expectedDelPayloads[i], (IkeDeletePayload) reqPayloads.get(i));
- }
- }
-
- private void outboundDeleteChildPayloadsReady(
- IChildSessionSmCallback childSmCb,
- IkeDeletePayload delPayload,
- boolean isResp,
- ChildSessionStateMachine child) {
- List<IkePayload> outPayloadList = new LinkedList<>();
- outPayloadList.add(delPayload);
- childSmCb.onOutboundPayloadsReady(
- IkeHeader.EXCHANGE_TYPE_INFORMATIONAL, isResp, outPayloadList, child);
- mLooper.dispatchAll();
- }
-
- private List<IkePayload> verifyOutInfoMsgHeaderAndGetPayloads(boolean isResp) {
- IkeMessage deleteChildMessage = verifyEncryptAndEncodeAndGetMessage(mSpyCurrentIkeSaRecord);
-
- IkeHeader ikeHeader = deleteChildMessage.ikeHeader;
- assertEquals(mSpyCurrentIkeSaRecord.getInitiatorSpi(), ikeHeader.ikeInitiatorSpi);
- assertEquals(mSpyCurrentIkeSaRecord.getResponderSpi(), ikeHeader.ikeResponderSpi);
- assertEquals(IkePayload.PAYLOAD_TYPE_SK, ikeHeader.nextPayloadType);
- assertEquals(IkeHeader.EXCHANGE_TYPE_INFORMATIONAL, ikeHeader.exchangeType);
- assertEquals(mSpyCurrentIkeSaRecord.isLocalInit, ikeHeader.fromIkeInitiator);
- assertEquals(isResp, ikeHeader.isResponseMsg);
-
- return deleteChildMessage.ikePayloadList;
- }
-
- @Test
- public void testDeferChildRequestToChildProcedureOngoing() throws Exception {
- setupIdleStateMachine();
-
- IkeDeletePayload[] inboundDelPayloads =
- new IkeDeletePayload[] {new IkeDeletePayload(new int[] {CHILD_SPI_REMOTE})};
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET,
- makeDeleteChildPacket(inboundDelPayloads, false /*isResp*/));
- mLooper.dispatchAll();
-
- assertTrue(
- mIkeSessionStateMachine.getCurrentState()
- instanceof IkeSessionStateMachine.ChildProcedureOngoing);
- verifyChildReceiveDeleteRequest(mMockChildSessionStateMachine, inboundDelPayloads);
- }
-
- @Test
- public void testRemoteDeleteOneChild() throws Exception {
- setupIdleStateMachine();
- transitionToChildProcedureOngoing();
-
- // Receive Delete Child Request
- IkeDeletePayload[] inboundDelPayloads =
- new IkeDeletePayload[] {new IkeDeletePayload(new int[] {CHILD_SPI_REMOTE})};
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET,
- makeDeleteChildPacket(inboundDelPayloads, false /*isResp*/));
- mLooper.dispatchAll();
-
- // Verify received payloads
- verifyChildReceiveDeleteRequest(mMockChildSessionStateMachine, inboundDelPayloads);
-
- // Outbound payload list ready
- IkeDeletePayload outDelPayload = new IkeDeletePayload(new int[] {CHILD_SPI_LOCAL});
- outboundDeleteChildPayloadsReady(
- mDummyChildSmCallback,
- outDelPayload,
- true /*isResp*/,
- mMockChildSessionStateMachine);
-
- // Verify outbound response
- List<IkePayload> payloadList = verifyOutInfoMsgHeaderAndGetPayloads(true /*isResp*/);
- assertEquals(1, payloadList.size());
- assertEquals(outDelPayload, ((IkeDeletePayload) payloadList.get(0)));
- }
-
- @Test
- public void testRemoteDeleteMultipleChildSession() throws Exception {
- ChildSessionStateMachine childOne = mock(ChildSessionStateMachine.class);
- int childOneRemoteSpi = 11;
- int childOneLocalSpi = 12;
-
- ChildSessionStateMachine childTwo = mock(ChildSessionStateMachine.class);
- int childTwoRemoteSpi = 21;
- int childTwoLocalSpi = 22;
-
- setupIdleStateMachine();
- IChildSessionSmCallback childSmCbOne =
- createChildAndGetChildSessionSmCallback(childOne, childOneRemoteSpi);
- IChildSessionSmCallback childSmCbTwo =
- createChildAndGetChildSessionSmCallback(childTwo, childTwoRemoteSpi);
-
- transitionToChildProcedureOngoing();
-
- // Receive Delete Child Request
- IkeDeletePayload[] inboundDelPayloads =
- new IkeDeletePayload[] {
- new IkeDeletePayload(new int[] {childOneRemoteSpi, childTwoRemoteSpi})
- };
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET,
- makeDeleteChildPacket(inboundDelPayloads, false /*isResp*/));
- mLooper.dispatchAll();
-
- // Verify received payloads
- verifyChildReceiveDeleteRequest(childOne, inboundDelPayloads);
- verifyChildReceiveDeleteRequest(childTwo, inboundDelPayloads);
-
- // childOne outbound payload list ready
- IkeDeletePayload outDelPayloadOne = new IkeDeletePayload(new int[] {childOneLocalSpi});
- outboundDeleteChildPayloadsReady(childSmCbOne, outDelPayloadOne, true /*isResp*/, childOne);
- mLooper.dispatchAll();
-
- // Verify that no response is sent
- verifyEncryptAndEncodeNeverCalled(mSpyCurrentIkeSaRecord);
-
- // childTwo outbound payload list ready
- IkeDeletePayload outDelPayloadTwo = new IkeDeletePayload(new int[] {childTwoLocalSpi});
- outboundDeleteChildPayloadsReady(childSmCbTwo, outDelPayloadTwo, true /*isResp*/, childTwo);
- mLooper.dispatchAll();
-
- // Verify outbound response
- List<IkePayload> payloadList = verifyOutInfoMsgHeaderAndGetPayloads(true /*isResp*/);
- assertEquals(2, payloadList.size());
- assertEquals(outDelPayloadOne, ((IkeDeletePayload) payloadList.get(0)));
- assertEquals(outDelPayloadTwo, ((IkeDeletePayload) payloadList.get(1)));
- }
-
- @Test
- public void testRemoteDeleteMultipleChildSaInSameSession() throws Exception {
- int newChildRemoteSpi = 21;
- int newChildLocalSpi = 22;
-
- setupIdleStateMachine();
- mDummyChildSmCallback.onChildSaCreated(newChildRemoteSpi, mMockChildSessionStateMachine);
-
- transitionToChildProcedureOngoing();
-
- // Receive Delete Child Request
- IkeDeletePayload[] inboundDelPayloads =
- new IkeDeletePayload[] {
- new IkeDeletePayload(new int[] {CHILD_SPI_REMOTE}),
- new IkeDeletePayload(new int[] {newChildRemoteSpi})
- };
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET,
- makeDeleteChildPacket(inboundDelPayloads, false /*isResp*/));
- mLooper.dispatchAll();
-
- // Verify received payloads
- verifyChildReceiveDeleteRequest(mMockChildSessionStateMachine, inboundDelPayloads);
-
- // child outbound payload list ready
- IkeDeletePayload outDelPayload =
- new IkeDeletePayload(new int[] {CHILD_SPI_LOCAL, newChildLocalSpi});
- outboundDeleteChildPayloadsReady(
- mDummyChildSmCallback,
- outDelPayload,
- true /*isResp*/,
- mMockChildSessionStateMachine);
- mLooper.dispatchAll();
-
- // Verify outbound response
- List<IkePayload> payloadList = verifyOutInfoMsgHeaderAndGetPayloads(true /*isResp*/);
- assertEquals(1, payloadList.size());
- assertEquals(outDelPayload, ((IkeDeletePayload) payloadList.get(0)));
- }
-
- @Test
- public void testIgnoreUnrecognizedChildSpi() throws Exception {
- int unrecognizedSpi = 2;
-
- setupIdleStateMachine();
- transitionToChildProcedureOngoing();
-
- // Receive Delete Child Request
- IkeDeletePayload[] inboundDelPayloads =
- new IkeDeletePayload[] {
- new IkeDeletePayload(new int[] {unrecognizedSpi, CHILD_SPI_REMOTE})
- };
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET,
- makeDeleteChildPacket(inboundDelPayloads, false /*isResp*/));
- mLooper.dispatchAll();
-
- // Verify received payloads
- verifyChildReceiveDeleteRequest(mMockChildSessionStateMachine, inboundDelPayloads);
-
- // child outbound payload list ready
- IkeDeletePayload outPayload = new IkeDeletePayload(new int[] {CHILD_SPI_LOCAL});
- outboundDeleteChildPayloadsReady(
- mDummyChildSmCallback, outPayload, true /*isResp*/, mMockChildSessionStateMachine);
- mLooper.dispatchAll();
-
- // Verify outbound response
- List<IkePayload> payloadList = verifyOutInfoMsgHeaderAndGetPayloads(true /*isResp*/);
- assertEquals(1, payloadList.size());
- assertEquals(outPayload, ((IkeDeletePayload) payloadList.get(0)));
- }
-
- @Test
- public void testRemoteDeleteChildHandlesReqWithNoRecognizedSpi() throws Exception {
- int unrecognizedSpi = 2;
-
- setupIdleStateMachine();
-
- // Receive Delete Child Request without any recognized SPI
- IkeDeletePayload[] inboundDelPayloads =
- new IkeDeletePayload[] {new IkeDeletePayload(new int[] {unrecognizedSpi})};
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET,
- makeDeleteChildPacket(inboundDelPayloads, false /*isResp*/));
- mLooper.dispatchAll();
-
- // Verify outbound empty response was sent
- List<IkePayload> payloadList = verifyOutInfoMsgHeaderAndGetPayloads(true /*isResp*/);
- assertTrue(payloadList.isEmpty());
-
- // Verify IKE Session was back to Idle
- assertTrue(
- mIkeSessionStateMachine.getCurrentState() instanceof IkeSessionStateMachine.Idle);
- }
-
- @Test
- public void testRemoteCreateChild() throws Exception {
- setupIdleStateMachine();
-
- mIkeSessionStateMachine.sendMessage(
- CMD_RECEIVE_IKE_PACKET, makeCreateChildCreateMessage(false /*isResp*/));
-
- mLooper.dispatchAll();
-
- assertTrue(
- mIkeSessionStateMachine.getCurrentState() instanceof IkeSessionStateMachine.Idle);
-
- List<IkePayload> ikePayloadList = verifyOutInfoMsgHeaderAndGetPayloads(true /*isResp*/);
- assertEquals(1, ikePayloadList.size());
- assertEquals(
- ERROR_TYPE_NO_ADDITIONAL_SAS,
- ((IkeNotifyPayload) ikePayloadList.get(0)).notifyType);
- }
-
- @Test
- public void testTriggerRemoteRekeyChild() throws Exception {
- setupIdleStateMachine();
-
- mIkeSessionStateMachine.sendMessage(
- CMD_RECEIVE_IKE_PACKET,
- makeRekeyChildCreateMessage(false /*isResp*/, CHILD_SPI_REMOTE));
- mLooper.dispatchAll();
-
- verify(mMockChildSessionStateMachine)
- .receiveRequest(
- eq(IKE_EXCHANGE_SUBTYPE_REKEY_CHILD),
- eq(EXCHANGE_TYPE_CREATE_CHILD_SA),
- any(List.class));
- assertTrue(
- mIkeSessionStateMachine.getCurrentState()
- instanceof IkeSessionStateMachine.ChildProcedureOngoing);
- }
-
- @Test
- public void testHandleRekeyChildReqWithUnrecognizedSpi() throws Exception {
- int unrecognizedSpi = 2;
-
- setupIdleStateMachine();
-
- mIkeSessionStateMachine.sendMessage(
- CMD_RECEIVE_IKE_PACKET,
- makeRekeyChildCreateMessage(false /*isResp*/, unrecognizedSpi));
- mLooper.dispatchAll();
-
- verify(mMockChildSessionStateMachine, never()).receiveRequest(anyInt(), anyInt(), any());
- assertTrue(
- mIkeSessionStateMachine.getCurrentState() instanceof IkeSessionStateMachine.Idle);
-
- List<IkePayload> ikePayloadList = verifyOutInfoMsgHeaderAndGetPayloads(true /*isResp*/);
- assertEquals(1, ikePayloadList.size());
- IkeNotifyPayload notifyPayload = (IkeNotifyPayload) ikePayloadList.get(0);
- assertEquals(ERROR_TYPE_CHILD_SA_NOT_FOUND, notifyPayload.notifyType);
- assertEquals(unrecognizedSpi, notifyPayload.spi);
- }
-
- private void verifyNotifyUserCloseSession() {
- verify(mSpyUserCbExecutor).execute(any(Runnable.class));
- verify(mMockIkeSessionCallback).onClosed();
- }
-
- @Test
- public void testRcvRemoteDeleteIkeWhenChildProcedureOngoing() throws Exception {
- setupIdleStateMachine();
- transitionToChildProcedureOngoing();
-
- mIkeSessionStateMachine.sendMessage(
- CMD_RECEIVE_IKE_PACKET, makeDeleteIkeRequest(mSpyCurrentIkeSaRecord));
-
- mLooper.dispatchAll();
-
- verifyNotifyUserCloseSession();
-
- // Verify state machine quit properly
- assertNull(mIkeSessionStateMachine.getCurrentState());
-
- List<IkePayload> ikePayloadList = verifyOutInfoMsgHeaderAndGetPayloads(true /*isResp*/);
- assertTrue(ikePayloadList.isEmpty());
- }
-
- @Test
- public void testRcvRemoteRekeyIkeWhenChildProcedureOngoing() throws Exception {
- setupIdleStateMachine();
- transitionToChildProcedureOngoing();
-
- mIkeSessionStateMachine.sendMessage(CMD_RECEIVE_IKE_PACKET, makeRekeyIkeRequest());
-
- mLooper.dispatchAll();
-
- // Since we have forced state machine to transition to ChildProcedureOngoing state without
- // really starting any Child procedure, it should transition to Idle at this time.
- assertTrue(
- mIkeSessionStateMachine.getCurrentState() instanceof IkeSessionStateMachine.Idle);
-
- List<IkePayload> ikePayloadList = verifyOutInfoMsgHeaderAndGetPayloads(true /*isResp*/);
- assertEquals(1, ikePayloadList.size());
- assertEquals(
- ERROR_TYPE_TEMPORARY_FAILURE,
- ((IkeNotifyPayload) ikePayloadList.get(0)).notifyType);
- }
-
- @Test
- public void testKillChildSessions() throws Exception {
- setupIdleStateMachine();
-
- ChildSessionStateMachine childOne = mock(ChildSessionStateMachine.class);
- ChildSessionStateMachine childTwo = mock(ChildSessionStateMachine.class);
- registerChildStateMachine(mock(ChildSessionCallback.class), childOne);
- registerChildStateMachine(mock(ChildSessionCallback.class), childTwo);
-
- mIkeSessionStateMachine.mCurrentIkeSaRecord = null;
-
- mIkeSessionStateMachine.quitNow();
-
- mLooper.dispatchAll();
-
- verify(childOne).killSession();
- verify(childTwo).killSession();
- }
-
- private IkeMessage verifyAuthReqAndGetMsg() {
- IkeMessage ikeAuthReqMessage = verifyEncryptAndEncodeAndGetMessage(mSpyCurrentIkeSaRecord);
-
- IkeHeader ikeHeader = ikeAuthReqMessage.ikeHeader;
- assertEquals(IkeHeader.EXCHANGE_TYPE_IKE_AUTH, ikeHeader.exchangeType);
- assertFalse(ikeHeader.isResponseMsg);
- assertTrue(ikeHeader.fromIkeInitiator);
-
- return ikeAuthReqMessage;
- }
-
- private IkeMessage verifyAuthReqWithChildPayloadsAndGetMsg() {
- IkeMessage ikeAuthReqMessage = verifyAuthReqAndGetMsg();
-
- assertNotNull(
- ikeAuthReqMessage.getPayloadForType(
- IkePayload.PAYLOAD_TYPE_ID_INITIATOR, IkeIdPayload.class));
- assertNotNull(
- ikeAuthReqMessage.getPayloadForType(
- IkePayload.PAYLOAD_TYPE_ID_RESPONDER, IkeIdPayload.class));
- assertNotNull(
- ikeAuthReqMessage.getPayloadForType(
- IkePayload.PAYLOAD_TYPE_SA, IkeSaPayload.class));
- assertNotNull(
- ikeAuthReqMessage.getPayloadForType(
- IkePayload.PAYLOAD_TYPE_TS_INITIATOR, IkeTsPayload.class));
- assertNotNull(
- ikeAuthReqMessage.getPayloadForType(
- IkePayload.PAYLOAD_TYPE_TS_RESPONDER, IkeTsPayload.class));
-
- return ikeAuthReqMessage;
- }
-
- private void verifySharedKeyAuthentication(
- IkeAuthPskPayload spyAuthPayload,
- IkeIdPayload respIdPayload,
- List<IkePayload> authRelatedPayloads,
- boolean hasChildPayloads)
- throws Exception {
- // Send IKE AUTH response to IKE state machine
- ReceivedIkePacket authResp = makeIkeAuthRespWithChildPayloads(authRelatedPayloads);
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, authResp);
- mLooper.dispatchAll();
-
- // Validate outbound IKE AUTH request
- IkeMessage ikeAuthReqMessage;
- if (hasChildPayloads) {
- ikeAuthReqMessage = verifyAuthReqWithChildPayloadsAndGetMsg();
- } else {
- ikeAuthReqMessage = verifyAuthReqAndGetMsg();
- }
- assertNotNull(
- ikeAuthReqMessage.getPayloadForType(
- IkePayload.PAYLOAD_TYPE_AUTH, IkeAuthPskPayload.class));
-
- // Validate inbound IKE AUTH response
- verifyIncrementLocaReqMsgId();
- verifyDecodeEncryptedMessage(mSpyCurrentIkeSaRecord, authResp);
-
- // Validate authentication is done. Cannot use matchers because IkeAuthPskPayload is final.
- verify(spyAuthPayload)
- .verifyInboundSignature(
- mPsk,
- mIkeSessionStateMachine.mIkeInitRequestBytes,
- mSpyCurrentIkeSaRecord.nonceInitiator,
- respIdPayload.getEncodedPayloadBody(),
- mIkeSessionStateMachine.mIkePrf,
- mSpyCurrentIkeSaRecord.getSkPr());
-
- // Validate that user has been notified
- verify(mSpyUserCbExecutor).execute(any(Runnable.class));
- verify(mMockIkeSessionCallback).onOpened(any());
- // TODO: Verify sessionConfiguration
-
- // Verify payload list pair for first Child negotiation
- ArgumentCaptor<List<IkePayload>> mReqPayloadListCaptor =
- ArgumentCaptor.forClass(List.class);
- ArgumentCaptor<List<IkePayload>> mRespPayloadListCaptor =
- ArgumentCaptor.forClass(List.class);
- verify(mMockChildSessionStateMachine)
- .handleFirstChildExchange(
- mReqPayloadListCaptor.capture(),
- mRespPayloadListCaptor.capture(),
- eq(LOCAL_ADDRESS),
- eq(REMOTE_ADDRESS),
- any(), // udpEncapSocket
- eq(mIkeSessionStateMachine.mIkePrf),
- any()); // sk_d
- List<IkePayload> childReqList = mReqPayloadListCaptor.getValue();
- List<IkePayload> childRespList = mRespPayloadListCaptor.getValue();
-
- assertTrue(isIkePayloadExist(childReqList, IkePayload.PAYLOAD_TYPE_SA));
- assertTrue(isIkePayloadExist(childReqList, IkePayload.PAYLOAD_TYPE_TS_INITIATOR));
- assertTrue(isIkePayloadExist(childReqList, IkePayload.PAYLOAD_TYPE_TS_RESPONDER));
- assertTrue(isIkePayloadExist(childReqList, IkePayload.PAYLOAD_TYPE_NONCE));
- IkeSaPayload reqSaPayload =
- IkePayload.getPayloadForTypeInProvidedList(
- IkePayload.PAYLOAD_TYPE_SA, IkeSaPayload.class, childReqList);
- assertFalse(reqSaPayload.isSaResponse);
-
- assertTrue(isIkePayloadExist(childRespList, IkePayload.PAYLOAD_TYPE_SA));
- assertTrue(isIkePayloadExist(childRespList, IkePayload.PAYLOAD_TYPE_TS_INITIATOR));
- assertTrue(isIkePayloadExist(childRespList, IkePayload.PAYLOAD_TYPE_TS_RESPONDER));
- assertTrue(isIkePayloadExist(childRespList, IkePayload.PAYLOAD_TYPE_NONCE));
- IkeSaPayload respSaPayload =
- IkePayload.getPayloadForTypeInProvidedList(
- IkePayload.PAYLOAD_TYPE_SA, IkeSaPayload.class, childRespList);
- assertTrue(respSaPayload.isSaResponse);
-
- // Mock finishing first Child SA negotiation.
- assertTrue(
- mIkeSessionStateMachine.getCurrentState()
- instanceof IkeSessionStateMachine.ChildProcedureOngoing);
-
- verify(mMockChildSessionFactoryHelper)
- .makeChildSessionStateMachine(
- eq(mLooper.getLooper()),
- eq(mContext),
- eq(mChildSessionOptions),
- eq(mSpyUserCbExecutor),
- eq(mMockChildSessionCallback),
- mChildSessionSmCbCaptor.capture());
- IChildSessionSmCallback cb = mChildSessionSmCbCaptor.getValue();
-
- cb.onProcedureFinished(mMockChildSessionStateMachine);
- mLooper.dispatchAll();
- assertTrue(
- mIkeSessionStateMachine.getCurrentState() instanceof IkeSessionStateMachine.Idle);
- }
-
- private IkeAuthPskPayload makeSpyRespPskPayload() throws Exception {
- IkeAuthPskPayload spyAuthPayload =
- spy(
- (IkeAuthPskPayload)
- IkeTestUtils.hexStringToIkePayload(
- IkePayload.PAYLOAD_TYPE_AUTH,
- true /*isResp*/,
- PSK_AUTH_RESP_PAYLOAD_HEX_STRING));
-
- doNothing()
- .when(spyAuthPayload)
- .verifyInboundSignature(any(), any(), any(), any(), any(), any());
- return spyAuthPayload;
- }
-
- private IkeAuthDigitalSignPayload makeSpyDigitalSignAuthPayload() throws Exception {
- IkeAuthDigitalSignPayload spyAuthPayload =
- spy(
- (IkeAuthDigitalSignPayload)
- IkeTestUtils.hexStringToIkePayload(
- IkePayload.PAYLOAD_TYPE_AUTH,
- true /*isResp*/,
- GENERIC_DIGITAL_SIGN_AUTH_RESP_HEX_STRING));
- doNothing()
- .when(spyAuthPayload)
- .verifyInboundSignature(any(), any(), any(), any(), any(), any());
- return spyAuthPayload;
- }
-
- private IkeIdPayload makeRespIdPayload() throws Exception {
- return (IkeIdPayload)
- IkeTestUtils.hexStringToIkePayload(
- IkePayload.PAYLOAD_TYPE_ID_RESPONDER,
- true /*isResp*/,
- ID_PAYLOAD_RESPONDER_HEX_STRING);
- }
-
- @Test
- public void testCreateIkeLocalIkeAuthPsk() throws Exception {
- mockIkeInitAndTransitionToIkeAuth(mIkeSessionStateMachine.mCreateIkeLocalIkeAuth);
- verifyRetransmissionStarted();
-
- // Build IKE AUTH response with Auth-PSK Payload and ID-Responder Payload.
- List<IkePayload> authRelatedPayloads = new LinkedList<>();
- IkeAuthPskPayload spyAuthPayload = makeSpyRespPskPayload();
- authRelatedPayloads.add(spyAuthPayload);
-
- IkeIdPayload respIdPayload = makeRespIdPayload();
- authRelatedPayloads.add(respIdPayload);
-
- verifySharedKeyAuthentication(spyAuthPayload, respIdPayload, authRelatedPayloads, true);
- verifyRetransmissionStopped();
- }
-
- @Test
- public void testCreateIkeLocalIkeAuthPskVerifyFail() throws Exception {
- mockIkeInitAndTransitionToIkeAuth(mIkeSessionStateMachine.mCreateIkeLocalIkeAuth);
- verifyRetransmissionStarted();
- resetMockIkeMessageHelper();
-
- // Build IKE AUTH response with invalid Auth-PSK Payload and ID-Responder Payload.
- List<IkePayload> authRelatedPayloads = new LinkedList<>();
- IkeAuthPskPayload spyAuthPayload = makeSpyRespPskPayload();
- doThrow(new AuthenticationFailedException("DummyAuthFailException"))
- .when(spyAuthPayload)
- .verifyInboundSignature(any(), any(), any(), any(), any(), any());
- authRelatedPayloads.add(spyAuthPayload);
-
- IkeIdPayload respIdPayload = makeRespIdPayload();
- authRelatedPayloads.add(respIdPayload);
-
- // Send response to IKE state machine
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET,
- makeIkeAuthRespWithChildPayloads(authRelatedPayloads));
- mLooper.dispatchAll();
-
- // Verify Delete request was sent
- List<IkePayload> payloads = verifyOutInfoMsgHeaderAndGetPayloads(false /*isResp*/);
- assertEquals(1, payloads.size());
- assertEquals(IkePayload.PAYLOAD_TYPE_DELETE, payloads.get(0).payloadType);
-
- // Verify IKE Session was closed properly
- assertNull(mIkeSessionStateMachine.getCurrentState());
- verify(mMockIkeSessionCallback)
- .onClosedExceptionally(any(AuthenticationFailedException.class));
- }
-
- @Test
- public void testAuthPskHandleRespWithParsingError() throws Exception {
- mockIkeInitAndTransitionToIkeAuth(mIkeSessionStateMachine.mCreateIkeLocalIkeAuth);
- verifyRetransmissionStarted();
- resetMockIkeMessageHelper();
-
- // Mock receiving packet with syntax error
- ReceivedIkePacket mockInvalidPacket =
- makeDummyReceivedIkePacketWithInvalidSyntax(
- mSpyCurrentIkeSaRecord, true /*isResp*/, IkeHeader.EXCHANGE_TYPE_IKE_AUTH);
- mIkeSessionStateMachine.sendMessage(CMD_RECEIVE_IKE_PACKET, mockInvalidPacket);
- mLooper.dispatchAll();
-
- // Verify Delete request was sent
- List<IkePayload> payloads = verifyOutInfoMsgHeaderAndGetPayloads(false /*isResp*/);
- assertEquals(1, payloads.size());
- assertEquals(IkePayload.PAYLOAD_TYPE_DELETE, payloads.get(0).payloadType);
-
- // Verify IKE Session is closed properly
- assertNull(mIkeSessionStateMachine.getCurrentState());
- verify(mMockIkeSessionCallback).onClosedExceptionally(any(InvalidSyntaxException.class));
- }
-
- @Test
- public void testCreateIkeLocalIkeAuthPreEap() throws Exception {
- mIkeSessionStateMachine.quitNow();
- mIkeSessionStateMachine = makeAndStartIkeSession(buildIkeSessionOptionsEap());
-
- // Mock IKE INIT
- mockIkeInitAndTransitionToIkeAuth(mIkeSessionStateMachine.mCreateIkeLocalIkeAuth);
- verifyRetransmissionStarted();
-
- // Build IKE AUTH response with EAP. Auth, ID-Resp and Cert payloads.
- List<IkePayload> authRelatedPayloads = new LinkedList<>();
-
- authRelatedPayloads.add(new IkeEapPayload(EAP_DUMMY_MSG));
- authRelatedPayloads.add(makeSpyDigitalSignAuthPayload());
- authRelatedPayloads.add(makeRespIdPayload());
-
- IkeCertX509CertPayload certPayload = new IkeCertX509CertPayload(mServerEndCertificate);
- authRelatedPayloads.add(certPayload);
-
- // Send IKE AUTH response to IKE state machine
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET,
- makeIkeAuthRespWithoutChildPayloads(authRelatedPayloads));
- mLooper.dispatchAll();
-
- // Validate outbound IKE AUTH request
- IkeMessage ikeAuthReqMessage = verifyAuthReqWithChildPayloadsAndGetMsg();
- assertNull(
- ikeAuthReqMessage.getPayloadForType(
- IkePayload.PAYLOAD_TYPE_AUTH, IkeAuthPayload.class));
-
- assertTrue(
- mIkeSessionStateMachine.getCurrentState()
- instanceof IkeSessionStateMachine.CreateIkeLocalIkeAuthInEap);
- verifyRetransmissionStopped();
- assertNotNull(mIkeSessionStateMachine.mInitIdPayload);
- assertNotNull(mIkeSessionStateMachine.mRespIdPayload);
- }
-
- private IEapCallback verifyEapAuthenticatorCreatedAndGetCallback() {
- ArgumentCaptor<IEapCallback> captor = ArgumentCaptor.forClass(IEapCallback.class);
-
- verify(mMockEapAuthenticatorFactory)
- .newEapAuthenticator(
- eq(mIkeSessionStateMachine.getHandler().getLooper()),
- captor.capture(),
- eq(mContext),
- eq(mEapSessionConfig));
-
- return captor.getValue();
- }
-
- @Test
- public void testCreateIkeLocalIkeAuthInEapStartsAuthenticatorAndProxiesMessage()
- throws Exception {
- mIkeSessionStateMachine.quitNow();
- mIkeSessionStateMachine = makeAndStartIkeSession(buildIkeSessionOptionsEap());
-
- // Setup state and go to IN_EAP state
- mockIkeInitAndTransitionToIkeAuth(mIkeSessionStateMachine.mCreateIkeLocalIkeAuthInEap);
- mLooper.dispatchAll();
-
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_EAP_START_EAP_AUTH, new IkeEapPayload(EAP_DUMMY_MSG));
- mLooper.dispatchAll();
-
- verifyEapAuthenticatorCreatedAndGetCallback();
-
- verify(mMockEapAuthenticator).processEapMessage(eq(EAP_DUMMY_MSG));
- }
-
- @Test
- public void testCreateIkeLocalIkeAuthInEapHandlesOutboundResponse() throws Exception {
- mIkeSessionStateMachine.quitNow();
- mIkeSessionStateMachine = makeAndStartIkeSession(buildIkeSessionOptionsEap());
-
- // Setup state and go to IN_EAP state
- mockIkeInitAndTransitionToIkeAuth(mIkeSessionStateMachine.mCreateIkeLocalIkeAuthInEap);
- mLooper.dispatchAll();
-
- IEapCallback callback = verifyEapAuthenticatorCreatedAndGetCallback();
- callback.onResponse(EAP_DUMMY_MSG);
- mLooper.dispatchAll();
- verifyRetransmissionStarted();
-
- // Verify EAP response
- IkeMessage resp = verifyEncryptAndEncodeAndGetMessage(mSpyCurrentIkeSaRecord);
- IkeHeader ikeHeader = resp.ikeHeader;
- assertEquals(IkePayload.PAYLOAD_TYPE_SK, ikeHeader.nextPayloadType);
- assertEquals(IkeHeader.EXCHANGE_TYPE_IKE_AUTH, ikeHeader.exchangeType);
- assertFalse(ikeHeader.isResponseMsg);
- assertEquals(mSpyCurrentIkeSaRecord.isLocalInit, ikeHeader.fromIkeInitiator);
-
- assertEquals(1, resp.ikePayloadList.size());
- assertArrayEquals(EAP_DUMMY_MSG, ((IkeEapPayload) resp.ikePayloadList.get(0)).eapMessage);
- }
-
- @Test
- public void testCreateIkeLocalIkeAuthInEapHandlesMissingEapPacket() throws Exception {
- mIkeSessionStateMachine.quitNow();
- mIkeSessionStateMachine = makeAndStartIkeSession(buildIkeSessionOptionsEap());
-
- // Setup state and go to IN_EAP state
- mockIkeInitAndTransitionToIkeAuth(mIkeSessionStateMachine.mCreateIkeLocalIkeAuthInEap);
- mLooper.dispatchAll();
-
- // Mock sending IKE_AUTH{EAP} request
- IEapCallback callback = verifyEapAuthenticatorCreatedAndGetCallback();
- callback.onResponse(EAP_DUMMY_MSG);
- mLooper.dispatchAll();
- verifyRetransmissionStarted();
-
- // Send IKE AUTH response with no EAP Payload to IKE state machine
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET,
- makeIkeAuthRespWithoutChildPayloads(new LinkedList<>()));
- mLooper.dispatchAll();
-
- // Verify state machine quit properly
- verify(mMockIkeSessionCallback)
- .onClosedExceptionally(any(AuthenticationFailedException.class));
- assertNull(mIkeSessionStateMachine.getCurrentState());
- }
-
- @Test
- public void testCreateIkeLocalIkeAuthInEapHandlesSuccess() throws Exception {
- mIkeSessionStateMachine.quitNow();
- mIkeSessionStateMachine = makeAndStartIkeSession(buildIkeSessionOptionsEap());
-
- // Setup state and go to IN_EAP state
- mockIkeInitAndTransitionToIkeAuth(mIkeSessionStateMachine.mCreateIkeLocalIkeAuthInEap);
- mLooper.dispatchAll();
-
- IEapCallback callback = verifyEapAuthenticatorCreatedAndGetCallback();
-
- // Setup dummy initIdPayload for next state.
- mIkeSessionStateMachine.mInitIdPayload = mock(IkeIdPayload.class);
- when(mIkeSessionStateMachine.mInitIdPayload.getEncodedPayloadBody())
- .thenReturn(new byte[0]);
-
- callback.onSuccess(mPsk, new byte[0]); // use mPsk as MSK, eMSK does not matter
- mLooper.dispatchAll();
-
- assertTrue(
- mIkeSessionStateMachine.getCurrentState()
- instanceof IkeSessionStateMachine.CreateIkeLocalIkeAuthPostEap);
- }
-
- @Test
- public void testCreateIkeLocalIkeAuthInEapHandlesError() throws Exception {
- mIkeSessionStateMachine.quitNow();
- mIkeSessionStateMachine = makeAndStartIkeSession(buildIkeSessionOptionsEap());
-
- // Setup state and go to IN_EAP state
- mockIkeInitAndTransitionToIkeAuth(mIkeSessionStateMachine.mCreateIkeLocalIkeAuthInEap);
- mLooper.dispatchAll();
-
- IEapCallback callback = verifyEapAuthenticatorCreatedAndGetCallback();
-
- Throwable error = new IllegalArgumentException();
- callback.onError(error);
- mLooper.dispatchAll();
-
- // Fires user error callbacks
- verify(mMockIkeSessionCallback)
- .onClosedExceptionally(argThat(err -> err.getCause() == error));
-
- // Verify state machine quit properly
- verify(mSpyCurrentIkeSaRecord).close();
- assertNull(mIkeSessionStateMachine.getCurrentState());
- }
-
- @Test
- public void testCreateIkeLocalIkeAuthInEapHandlesFailure() throws Exception {
- mIkeSessionStateMachine.quitNow();
- mIkeSessionStateMachine = makeAndStartIkeSession(buildIkeSessionOptionsEap());
-
- // Setup state and go to IN_EAP state
- mockIkeInitAndTransitionToIkeAuth(mIkeSessionStateMachine.mCreateIkeLocalIkeAuthInEap);
- mLooper.dispatchAll();
-
- IEapCallback callback = verifyEapAuthenticatorCreatedAndGetCallback();
- callback.onFail();
- mLooper.dispatchAll();
-
- // Fires user error callbacks
- verify(mMockIkeSessionCallback)
- .onClosedExceptionally(any(AuthenticationFailedException.class));
-
- // Verify state machine quit properly
- verify(mSpyCurrentIkeSaRecord).close();
- assertNull(mIkeSessionStateMachine.getCurrentState());
- }
-
- @Test
- public void testCreateIkeLocalIkeAuthPostEap() throws Exception {
- mIkeSessionStateMachine.quitNow();
- reset(mMockChildSessionFactoryHelper);
- setupChildStateMachineFactory(mMockChildSessionStateMachine);
- mIkeSessionStateMachine = makeAndStartIkeSession(buildIkeSessionOptionsEap());
-
- // Setup dummy state from IkeAuthPreEap for next state.
- mIkeSessionStateMachine.mInitIdPayload = mock(IkeIdPayload.class);
- when(mIkeSessionStateMachine.mInitIdPayload.getEncodedPayloadBody())
- .thenReturn(new byte[0]);
- mIkeSessionStateMachine.mRespIdPayload =
- (IkeIdPayload)
- IkeTestUtils.hexStringToIkePayload(
- IkePayload.PAYLOAD_TYPE_ID_RESPONDER,
- true /*isResp*/,
- ID_PAYLOAD_RESPONDER_HEX_STRING);
-
- List<Integer> payloadTypeList = new LinkedList<>();
- List<String> payloadHexStringList = new LinkedList<>();
-
- payloadTypeList.add(IkePayload.PAYLOAD_TYPE_SA);
- payloadTypeList.add(IkePayload.PAYLOAD_TYPE_TS_INITIATOR);
- payloadTypeList.add(IkePayload.PAYLOAD_TYPE_TS_RESPONDER);
-
- payloadHexStringList.add(CHILD_SA_PAYLOAD_HEX_STRING);
- payloadHexStringList.add(TS_INIT_PAYLOAD_HEX_STRING);
- payloadHexStringList.add(TS_RESP_PAYLOAD_HEX_STRING);
-
- mIkeSessionStateMachine.mFirstChildReqList =
- hexStrListToIkePayloadList(payloadTypeList, payloadHexStringList, false /*isResp*/);
-
- // Setup state and go to IN_EAP state
- mockIkeInitAndTransitionToIkeAuth(mIkeSessionStateMachine.mCreateIkeLocalIkeAuthPostEap);
- mIkeSessionStateMachine.sendMessage(IkeSessionStateMachine.CMD_EAP_FINISH_EAP_AUTH, mPsk);
- mLooper.dispatchAll();
- verifyRetransmissionStarted();
-
- // Build IKE AUTH response with Auth-PSK Payload and ID-Responder Payload.
- List<IkePayload> authRelatedPayloads = new LinkedList<>();
- IkeAuthPskPayload spyAuthPayload = makeSpyRespPskPayload();
- authRelatedPayloads.add(spyAuthPayload);
-
- IkeIdPayload respIdPayload = makeRespIdPayload();
-
- verifySharedKeyAuthentication(spyAuthPayload, respIdPayload, authRelatedPayloads, false);
- verifyRetransmissionStopped();
- }
-
- @Test
- public void testCreateIkeLocalIkeAuthHandlesFirstFrag() throws Exception {
- mockIkeInitAndTransitionToIkeAuth(mIkeSessionStateMachine.mCreateIkeLocalIkeAuth);
- verifyRetransmissionStarted();
-
- // Received IKE fragment
- byte[] unencryptedData = "testCreateIkeLocalIkeAuthHandlesFrag".getBytes();
- int fragNum = 1;
- int totalFragments = 2;
- IkeSkfPayload skfPayload =
- IkeTestUtils.makeDummySkfPayload(unencryptedData, fragNum, totalFragments);
-
- ReceivedIkePacket packet =
- makeDummyReceivedIkeFragmentPacket(
- mSpyCurrentIkeSaRecord,
- true /*isResp*/,
- IkeHeader.EXCHANGE_TYPE_IKE_AUTH,
- skfPayload,
- PAYLOAD_TYPE_AUTH,
- null /* collectedFrags*/);
- mIkeSessionStateMachine.sendMessage(IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, packet);
- mLooper.dispatchAll();
-
- // Verify state doesn't change
- assertTrue(
- mIkeSessionStateMachine.getCurrentState()
- instanceof IkeSessionStateMachine.CreateIkeLocalIkeAuth);
-
- // Verify the IkeSaRecord has stored the fragment.
- DecodeResultPartial resultPartial =
- mSpyCurrentIkeSaRecord.getCollectedFragments(true /*isResp*/);
- assertEquals(PAYLOAD_TYPE_AUTH, resultPartial.firstPayloadType);
- assertEquals(totalFragments, resultPartial.collectedFragsList.length);
- assertArrayEquals(unencryptedData, resultPartial.collectedFragsList[fragNum - 1]);
- assertFalse(resultPartial.isAllFragmentsReceived());
-
- assertNull(mSpyCurrentIkeSaRecord.getCollectedFragments(false /*isResp*/));
- }
-
- @Test
- public void testCreateIkeLocalIkeAuthHandlesLastFragOk() throws Exception {
- mockIkeInitAndTransitionToIkeAuth(mIkeSessionStateMachine.mCreateIkeLocalIkeAuth);
- verifyRetransmissionStarted();
-
- // Set previously collected IKE fragments
- DecodeResultPartial mockCollectedFrags = mock(DecodeResultPartial.class);
- mSpyCurrentIkeSaRecord.updateCollectedFragments(mockCollectedFrags, true /*isResp*/);
-
- // Build reassembled IKE AUTH response with Auth-PSK Payload and ID-Responder Payload.
- List<IkePayload> authRelatedPayloads = new LinkedList<>();
- IkeAuthPskPayload spyAuthPayload = makeSpyRespPskPayload();
- authRelatedPayloads.add(spyAuthPayload);
-
- IkeIdPayload respIdPayload = makeRespIdPayload();
- authRelatedPayloads.add(respIdPayload);
-
- List<IkePayload> authPayloadList =
- getIkeAuthPayloadListWithChildPayloads(authRelatedPayloads);
-
- // Receive last auth response and do IKE_AUTH
- ReceivedIkePacket packet =
- makeDummyReceivedLastIkeFragmentPacketOk(
- mSpyCurrentIkeSaRecord,
- true /*isResp*/,
- IkeHeader.EXCHANGE_TYPE_IKE_AUTH,
- mockCollectedFrags,
- authPayloadList,
- "FirstFrag".getBytes());
- mIkeSessionStateMachine.sendMessage(IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, packet);
- mLooper.dispatchAll();
-
- // Verify IKE AUTH is done
- assertTrue(
- mIkeSessionStateMachine.getCurrentState()
- instanceof IkeSessionStateMachine.ChildProcedureOngoing);
-
- // Verify collected response fragments are cleared.
- assertNull(mSpyCurrentIkeSaRecord.getCollectedFragments(true /*isResp*/));
- verify(mSpyCurrentIkeSaRecord).resetCollectedFragments(true /*isResp*/);
- }
-
- @Test
- public void testCreateIkeLocalIkeAuthHandlesLastFragError() throws Exception {
- mockIkeInitAndTransitionToIkeAuth(mIkeSessionStateMachine.mCreateIkeLocalIkeAuth);
- verifyRetransmissionStarted();
- resetMockIkeMessageHelper();
-
- // Set previously collected IKE fragments
- DecodeResultPartial mockCollectedFrags = mock(DecodeResultPartial.class);
- mSpyCurrentIkeSaRecord.updateCollectedFragments(mockCollectedFrags, true /*isResp*/);
-
- // Receive last auth response with syntax error
- ReceivedIkePacket packet =
- makeDummyReceivedLastIkeFragmentPacketError(
- mSpyCurrentIkeSaRecord,
- true /*isResp*/,
- IkeHeader.EXCHANGE_TYPE_IKE_AUTH,
- mockCollectedFrags,
- new InvalidSyntaxException("IkeStateMachineTest"));
- mIkeSessionStateMachine.sendMessage(IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, packet);
- mLooper.dispatchAll();
-
- // Verify Delete request is sent
- List<IkePayload> payloads = verifyOutInfoMsgHeaderAndGetPayloads(false /*isResp*/);
- assertEquals(1, payloads.size());
- assertEquals(IkePayload.PAYLOAD_TYPE_DELETE, payloads.get(0).payloadType);
-
- // Verify IKE Session is closed properly
- assertNull(mIkeSessionStateMachine.getCurrentState());
- verify(mMockIkeSessionCallback).onClosedExceptionally(any(InvalidSyntaxException.class));
-
- // Collected response fragments are cleared
- assertNull(mSpyCurrentIkeSaRecord.getCollectedFragments(true /*isResp*/));
- verify(mSpyCurrentIkeSaRecord).resetCollectedFragments(true /*isResp*/);
- }
-
- @Test
- public void testRekeyIkeLocalCreateSendsRequest() throws Exception {
- setupIdleStateMachine();
-
- // Send Rekey-Create request
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_EXECUTE_LOCAL_REQ,
- new LocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_IKE));
- mLooper.dispatchAll();
- assertTrue(
- mIkeSessionStateMachine.getCurrentState()
- instanceof IkeSessionStateMachine.RekeyIkeLocalCreate);
- verifyRetransmissionStarted();
-
- // Verify outbound message
- IkeMessage rekeyMsg = verifyEncryptAndEncodeAndGetMessage(mSpyCurrentIkeSaRecord);
-
- IkeHeader ikeHeader = rekeyMsg.ikeHeader;
- assertEquals(IkePayload.PAYLOAD_TYPE_SK, ikeHeader.nextPayloadType);
- assertEquals(IkeHeader.EXCHANGE_TYPE_CREATE_CHILD_SA, ikeHeader.exchangeType);
- assertEquals(mSpyCurrentIkeSaRecord.getLocalRequestMessageId(), ikeHeader.messageId);
- assertFalse(ikeHeader.isResponseMsg);
- assertTrue(ikeHeader.fromIkeInitiator);
-
- // Verify SA payload & proposals
- IkeSaPayload saPayload =
- rekeyMsg.getPayloadForType(IkePayload.PAYLOAD_TYPE_SA, IkeSaPayload.class);
- assertFalse(saPayload.isSaResponse);
- assertEquals(1, saPayload.proposalList.size());
-
- IkeSaPayload.IkeProposal proposal =
- (IkeSaPayload.IkeProposal) saPayload.proposalList.get(0);
- assertEquals(1, proposal.number); // Must be 1-indexed
- assertEquals(IkePayload.PROTOCOL_ID_IKE, proposal.protocolId);
- assertEquals(IkePayload.SPI_LEN_IKE, proposal.spiSize);
- assertEquals(mIkeSessionStateMachine.mSaProposal, proposal.saProposal);
-
- // Verify Nonce and KE payloads exist.
- assertNotNull(
- rekeyMsg.getPayloadForType(IkePayload.PAYLOAD_TYPE_NONCE, IkeNoncePayload.class));
-
- IkeKePayload kePayload =
- rekeyMsg.getPayloadForType(IkePayload.PAYLOAD_TYPE_KE, IkeKePayload.class);
- assertNotNull(kePayload);
- assertTrue(kePayload.isOutbound);
- }
-
- @Test
- public void testRekeyIkeLocalCreateHandlesResponse() throws Exception {
- setupIdleStateMachine();
-
- // Send Rekey-Create request
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_EXECUTE_LOCAL_REQ,
- new LocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_IKE));
- mLooper.dispatchAll();
- verifyRetransmissionStarted();
-
- // Prepare "rekeyed" SA
- setupRekeyedIkeSa(mSpyLocalInitIkeSaRecord);
-
- // Receive Rekey response
- ReceivedIkePacket dummyRekeyIkeRespReceivedPacket = makeRekeyIkeResponse();
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, dummyRekeyIkeRespReceivedPacket);
- mLooper.dispatchAll();
- verifyIncrementLocaReqMsgId();
- verifyDecodeEncryptedMessage(mSpyCurrentIkeSaRecord, dummyRekeyIkeRespReceivedPacket);
-
- // Verify in delete state, and new SA record was saved:
- assertTrue(
- mIkeSessionStateMachine.getCurrentState()
- instanceof IkeSessionStateMachine.RekeyIkeLocalDelete);
- verifyRetransmissionStarted();
- assertEquals(mSpyLocalInitIkeSaRecord, mIkeSessionStateMachine.mLocalInitNewIkeSaRecord);
- verify(mSpyIkeSocket)
- .registerIke(
- eq(mSpyLocalInitIkeSaRecord.getLocalSpi()), eq(mIkeSessionStateMachine));
- }
-
- @Test
- public void testRekeyIkeLocalCreateHandleRespWithParsingError() throws Exception {
- setupIdleStateMachine();
-
- // Send Rekey-Create request
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_EXECUTE_LOCAL_REQ,
- new LocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_IKE));
- mLooper.dispatchAll();
- verifyRetransmissionStarted();
- resetMockIkeMessageHelper();
-
- // Mock receiving packet with syntax error
- ReceivedIkePacket mockInvalidPacket =
- makeDummyReceivedIkePacketWithInvalidSyntax(
- mSpyCurrentIkeSaRecord,
- true /*isResp*/,
- IkeHeader.EXCHANGE_TYPE_CREATE_CHILD_SA);
- mIkeSessionStateMachine.sendMessage(CMD_RECEIVE_IKE_PACKET, mockInvalidPacket);
- mLooper.dispatchAll();
-
- // Verify Delete request was sent
- List<IkePayload> payloads = verifyOutInfoMsgHeaderAndGetPayloads(false /*isResp*/);
- assertEquals(1, payloads.size());
- assertEquals(IkePayload.PAYLOAD_TYPE_DELETE, payloads.get(0).payloadType);
-
- // Verify IKE Session is closed properly
- assertNull(mIkeSessionStateMachine.getCurrentState());
- verify(mMockIkeSessionCallback).onClosedExceptionally(any(InvalidSyntaxException.class));
- }
-
- @Test
- public void testRekeyIkeLocalCreateHandleRespWithNonFatalErrorNotify() throws Exception {
- setupIdleStateMachine();
-
- // Send Rekey-Create request
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_EXECUTE_LOCAL_REQ,
- new LocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_IKE));
- mLooper.dispatchAll();
-
- // Mock receiving packet with NO_PROPOSAL_CHOSEN
- ReceivedIkePacket resp =
- makeResponseWithErrorNotify(new IkeNotifyPayload(ERROR_TYPE_NO_PROPOSAL_CHOSEN));
- mIkeSessionStateMachine.sendMessage(CMD_RECEIVE_IKE_PACKET, resp);
- mLooper.dispatchAll();
-
- // Verify IKE Session goes back to Idle
- assertTrue(
- mIkeSessionStateMachine.getCurrentState() instanceof IkeSessionStateMachine.Idle);
-
- // Move time forward to trigger retry
- mLooper.moveTimeForward(IkeSessionStateMachine.RETRY_INTERVAL_MS);
- mLooper.dispatchAll();
-
- assertTrue(
- mIkeSessionStateMachine.getCurrentState()
- instanceof IkeSessionStateMachine.RekeyIkeLocalCreate);
- }
-
- @Test
- public void testRekeyIkeLocalCreateHandleRespWithFatalErrorNotify() throws Exception {
- setupIdleStateMachine();
-
- // Send Rekey-Create request
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_EXECUTE_LOCAL_REQ,
- new LocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_IKE));
- mLooper.dispatchAll();
- resetMockIkeMessageHelper();
-
- // Mock receiving packet with NO_PROPOSAL_CHOSEN
- ReceivedIkePacket resp =
- makeResponseWithErrorNotify(new IkeNotifyPayload(ERROR_TYPE_INVALID_SYNTAX));
- mIkeSessionStateMachine.sendMessage(CMD_RECEIVE_IKE_PACKET, resp);
- mLooper.dispatchAll();
-
- // Verify no message was sent because a fatal error notification was received
- verifyEncryptAndEncodeNeverCalled(mSpyCurrentIkeSaRecord);
-
- // Verify IKE Session is closed properly
- assertNull(mIkeSessionStateMachine.getCurrentState());
- verify(mMockIkeSessionCallback).onClosedExceptionally(any(InvalidSyntaxException.class));
- }
-
- @Test
- public void testRekeyIkeLocalCreateSaCreationFail() throws Exception {
- // Throw error when building new IKE SA
- throwExceptionWhenMakeRekeyIkeSa(
- new GeneralSecurityException("testRekeyIkeLocalCreateSaCreationFail"));
-
- setupIdleStateMachine();
-
- // Send Rekey-Create request
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_EXECUTE_LOCAL_REQ,
- new LocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_IKE));
- mLooper.dispatchAll();
- resetMockIkeMessageHelper();
-
- // Receive Rekey response
- ReceivedIkePacket dummyRekeyIkeRespReceivedPacket = makeRekeyIkeResponse();
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, dummyRekeyIkeRespReceivedPacket);
- mLooper.dispatchAll();
-
- // Verify Delete request was sent
- List<IkePayload> payloads = verifyOutInfoMsgHeaderAndGetPayloads(false /*isResp*/);
- assertEquals(1, payloads.size());
- assertEquals(IkePayload.PAYLOAD_TYPE_DELETE, payloads.get(0).payloadType);
-
- // Verify IKE Session is closed properly
- assertNull(mIkeSessionStateMachine.getCurrentState());
- verify(mMockIkeSessionCallback).onClosedExceptionally(any(IkeInternalException.class));
- }
-
- @Test
- public void testRekeyIkeLocalCreateHandleReqWithNonFatalError() throws Exception {
- setupIdleStateMachine();
-
- // Send Rekey-Create request
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_EXECUTE_LOCAL_REQ,
- new LocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_IKE));
- mLooper.dispatchAll();
- verifyRetransmissionStarted();
- resetMockIkeMessageHelper();
-
- // Build protocol exception
- List<Integer> unsupportedPayloads = new LinkedList<>();
- unsupportedPayloads.add(PAYLOAD_TYPE_UNSUPPORTED);
- UnsupportedCriticalPayloadException exception =
- new UnsupportedCriticalPayloadException(unsupportedPayloads);
-
- // Mock receiving packet with unsupported critical payload
- ReceivedIkePacket mockInvalidPacket =
- makeDummyReceivedIkePacketWithDecodingError(
- mSpyCurrentIkeSaRecord,
- false /*isResp*/,
- IkeHeader.EXCHANGE_TYPE_CREATE_CHILD_SA,
- exception);
- mIkeSessionStateMachine.sendMessage(CMD_RECEIVE_IKE_PACKET, mockInvalidPacket);
- mLooper.dispatchAll();
-
- // Verify error notification was sent
- List<IkePayload> payloads = verifyOutInfoMsgHeaderAndGetPayloads(true /*isResp*/);
- assertEquals(1, payloads.size());
-
- IkePayload payload = payloads.get(0);
- assertEquals(IkePayload.PAYLOAD_TYPE_NOTIFY, payload.payloadType);
- assertEquals(
- ERROR_TYPE_UNSUPPORTED_CRITICAL_PAYLOAD, ((IkeNotifyPayload) payload).notifyType);
-
- // Verify IKE Session stays in the same state
- assertTrue(
- mIkeSessionStateMachine.getCurrentState()
- instanceof IkeSessionStateMachine.RekeyIkeLocalCreate);
- }
-
- private void mockCreateAndTransitionToRekeyDeleteLocal() {
- // Seed fake rekey data and force transition to RekeyIkeLocalDelete
- mIkeSessionStateMachine.mLocalInitNewIkeSaRecord = mSpyLocalInitIkeSaRecord;
- mIkeSessionStateMachine.addIkeSaRecord(mSpyLocalInitIkeSaRecord);
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_FORCE_TRANSITION,
- mIkeSessionStateMachine.mRekeyIkeLocalDelete);
- mLooper.dispatchAll();
- verifyRetransmissionStarted();
- }
-
- @Test
- public void testRekeyIkeLocalDeleteSendsRequest() throws Exception {
- setupIdleStateMachine();
- mockCreateAndTransitionToRekeyDeleteLocal();
-
- // Verify Rekey-Delete request
- assertTrue(
- mIkeSessionStateMachine.getCurrentState()
- instanceof IkeSessionStateMachine.RekeyIkeLocalDelete);
- verifyRetransmissionStarted();
-
- // Verify outbound message
- IkeMessage delMsg = verifyEncryptAndEncodeAndGetMessage(mSpyCurrentIkeSaRecord);
-
- IkeHeader ikeHeader = delMsg.ikeHeader;
- assertEquals(mSpyCurrentIkeSaRecord.getInitiatorSpi(), ikeHeader.ikeInitiatorSpi);
- assertEquals(mSpyCurrentIkeSaRecord.getResponderSpi(), ikeHeader.ikeResponderSpi);
- assertEquals(IkePayload.PAYLOAD_TYPE_SK, ikeHeader.nextPayloadType);
- assertEquals(IkeHeader.EXCHANGE_TYPE_INFORMATIONAL, ikeHeader.exchangeType);
- assertEquals(mSpyCurrentIkeSaRecord.isLocalInit, ikeHeader.fromIkeInitiator);
- assertFalse(ikeHeader.isResponseMsg);
-
- List<IkeDeletePayload> deletePayloadList =
- delMsg.getPayloadListForType(
- IkePayload.PAYLOAD_TYPE_DELETE, IkeDeletePayload.class);
- assertEquals(1, deletePayloadList.size());
-
- IkeDeletePayload deletePayload = deletePayloadList.get(0);
- assertEquals(IkePayload.PROTOCOL_ID_IKE, deletePayload.protocolId);
- assertEquals(0, deletePayload.numSpi);
- assertEquals(0, deletePayload.spiSize);
- assertArrayEquals(new int[0], deletePayload.spisToDelete);
- }
-
- private void verifyRekeyReplaceSa(IkeSaRecord newSaRecord) {
- verify(mSpyCurrentIkeSaRecord).close();
- verify(mSpyIkeSocket).unregisterIke(eq(mSpyCurrentIkeSaRecord.getLocalSpi()));
- verify(mSpyIkeSocket, never()).unregisterIke(eq(newSaRecord.getLocalSpi()));
-
- assertEquals(mIkeSessionStateMachine.mCurrentIkeSaRecord, newSaRecord);
-
- verify(mMockChildSessionStateMachine).setSkD(newSaRecord.getSkD());
- }
-
- @Test
- public void testRekeyIkeLocalDeleteHandlesResponse() throws Exception {
- setupIdleStateMachine();
- mockCreateAndTransitionToRekeyDeleteLocal();
-
- // Receive Delete response
- ReceivedIkePacket dummyDeleteIkeRespReceivedPacket =
- makeDeleteIkeResponse(mSpyCurrentIkeSaRecord);
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, dummyDeleteIkeRespReceivedPacket);
- mLooper.dispatchAll();
- verifyIncrementLocaReqMsgId();
- verifyDecodeEncryptedMessage(mSpyCurrentIkeSaRecord, dummyDeleteIkeRespReceivedPacket);
-
- // Verify final state - Idle, with new SA, and old SA closed.
- verifyRekeyReplaceSa(mSpyLocalInitIkeSaRecord);
- verify(mMockIkeSessionCallback, never()).onClosed();
- assertTrue(
- mIkeSessionStateMachine.getCurrentState() instanceof IkeSessionStateMachine.Idle);
- verifyRetransmissionStopped();
- }
-
- @Test
- public void testRekeyIkeLocalDeleteHandlesRespWithParsingError() throws Exception {
- setupIdleStateMachine();
- mockCreateAndTransitionToRekeyDeleteLocal();
- resetMockIkeMessageHelper();
-
- // Mock receiving packet with syntax error
- ReceivedIkePacket mockInvalidPacket =
- makeDummyReceivedIkePacketWithInvalidSyntax(
- mSpyCurrentIkeSaRecord,
- true /*isResp*/,
- IkeHeader.EXCHANGE_TYPE_INFORMATIONAL);
- mIkeSessionStateMachine.sendMessage(CMD_RECEIVE_IKE_PACKET, mockInvalidPacket);
- mLooper.dispatchAll();
-
- // Verify no more request out
- verifyEncryptAndEncodeNeverCalled(mSpyCurrentIkeSaRecord);
-
- // Verify final state - Idle, with new SA, and old SA closed.
- verifyRekeyReplaceSa(mSpyLocalInitIkeSaRecord);
- assertTrue(
- mIkeSessionStateMachine.getCurrentState() instanceof IkeSessionStateMachine.Idle);
- verifyRetransmissionStopped();
- }
-
- @Test
- public void testRekeyIkeLocalDeleteWithRequestOnNewSa() throws Exception {
- setupIdleStateMachine();
- mockCreateAndTransitionToRekeyDeleteLocal();
-
- // Receive an empty (DPD) request on the new IKE SA
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET,
- makeDpdIkeRequest(mSpyLocalInitIkeSaRecord));
- mLooper.dispatchAll();
-
- // Verify final state - Idle, with new SA, and old SA closed.
- verifyRekeyReplaceSa(mSpyLocalInitIkeSaRecord);
- assertTrue(
- mIkeSessionStateMachine.getCurrentState() instanceof IkeSessionStateMachine.Idle);
- verifyRetransmissionStopped();
- }
-
- @Test
- public void testRekeyIkeLocalDeleteWithRequestFragOnNewSa() throws Exception {
- setupIdleStateMachine();
- mockCreateAndTransitionToRekeyDeleteLocal();
-
- // Received IKE fragment
- byte[] unencryptedData = "testRekeyIkeLocalDeleteWithRequestFragOnNewSa".getBytes();
- int fragNum = 1;
- int totalFragments = 2;
- IkeSkfPayload skfPayload =
- IkeTestUtils.makeDummySkfPayload(unencryptedData, fragNum, totalFragments);
-
- ReceivedIkePacket packet =
- makeDummyReceivedIkeFragmentPacket(
- mSpyLocalInitIkeSaRecord,
- false /*isResp*/,
- IkeHeader.EXCHANGE_TYPE_CREATE_CHILD_SA,
- skfPayload,
- PAYLOAD_TYPE_SA,
- null /* collectedFrags*/);
- mIkeSessionStateMachine.sendMessage(IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, packet);
- mLooper.dispatchAll();
-
- // Verify rekey is done.
- verifyRekeyReplaceSa(mSpyLocalInitIkeSaRecord);
- verifyRetransmissionStopped();
-
- // Verify the IkeSaRecord has stored the new fragment.
- DecodeResultPartial resultPartial =
- mSpyLocalInitIkeSaRecord.getCollectedFragments(false /*isResp*/);
- assertEquals(PAYLOAD_TYPE_SA, resultPartial.firstPayloadType);
- assertEquals(totalFragments, resultPartial.collectedFragsList.length);
- assertArrayEquals(unencryptedData, resultPartial.collectedFragsList[fragNum - 1]);
- assertFalse(resultPartial.isAllFragmentsReceived());
- }
-
- @Test
- public void testRekeyIkeRemoteDeleteWithRequestOnNewSa() throws Exception {
- setupIdleStateMachine();
-
- // Seed fake rekey data and force transition to RekeyIkeRemoteDelete
- mIkeSessionStateMachine.mRemoteInitNewIkeSaRecord = mSpyRemoteInitIkeSaRecord;
- mIkeSessionStateMachine.addIkeSaRecord(mSpyRemoteInitIkeSaRecord);
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_FORCE_TRANSITION,
- mIkeSessionStateMachine.mRekeyIkeRemoteDelete);
- mLooper.dispatchAll();
-
- // Receive an empty (DPD) request on the new IKE SA
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET,
- makeDpdIkeRequest(mSpyRemoteInitIkeSaRecord));
- mLooper.dispatchAll();
-
- // Verify final state - Idle, with new SA, and old SA closed.
- verifyRekeyReplaceSa(mSpyRemoteInitIkeSaRecord);
- assertTrue(
- mIkeSessionStateMachine.getCurrentState() instanceof IkeSessionStateMachine.Idle);
- }
-
- @Test
- public void testRekeyIkeRemoteCreate() throws Exception {
- setupIdleStateMachine();
-
- setupRekeyedIkeSa(mSpyRemoteInitIkeSaRecord);
-
- // Receive Rekey request
- ReceivedIkePacket dummyRekeyIkeRequestReceivedPacket = makeRekeyIkeRequest();
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, dummyRekeyIkeRequestReceivedPacket);
- mLooper.dispatchAll();
- verifyIncrementRemoteReqMsgId();
- verifyDecodeEncryptedMessage(mSpyCurrentIkeSaRecord, dummyRekeyIkeRequestReceivedPacket);
-
- // Verify SA created with correct parameters
- ArgumentCaptor<SaRecord.IkeSaRecordConfig> recordConfigCaptor =
- ArgumentCaptor.forClass(SaRecord.IkeSaRecordConfig.class);
- verify(mMockSaRecordHelper)
- .makeRekeyedIkeSaRecord(any(), any(), any(), any(), recordConfigCaptor.capture());
- assertEquals(IKE_REKEY_SA_INITIATOR_SPI, recordConfigCaptor.getValue().initSpi.getSpi());
-
- // Verify outbound CREATE_CHILD_SA message
- IkeMessage rekeyCreateResp = verifyEncryptAndEncodeAndGetMessage(mSpyCurrentIkeSaRecord);
- IkeHeader rekeyCreateRespHeader = rekeyCreateResp.ikeHeader;
- assertEquals(IkePayload.PAYLOAD_TYPE_SK, rekeyCreateRespHeader.nextPayloadType);
- assertEquals(IkeHeader.EXCHANGE_TYPE_CREATE_CHILD_SA, rekeyCreateRespHeader.exchangeType);
- assertTrue(rekeyCreateRespHeader.isResponseMsg);
- assertTrue(rekeyCreateRespHeader.fromIkeInitiator);
- assertNotNull(
- rekeyCreateResp.getPayloadForType(IkePayload.PAYLOAD_TYPE_SA, IkeSaPayload.class));
- assertNotNull(
- rekeyCreateResp.getPayloadForType(IkePayload.PAYLOAD_TYPE_KE, IkeKePayload.class));
- assertNotNull(
- rekeyCreateResp.getPayloadForType(
- IkePayload.PAYLOAD_TYPE_NONCE, IkeNoncePayload.class));
-
- // Verify SA, StateMachine state
- assertEquals(mSpyCurrentIkeSaRecord, mIkeSessionStateMachine.mIkeSaRecordAwaitingRemoteDel);
- assertEquals(mSpyRemoteInitIkeSaRecord, mIkeSessionStateMachine.mIkeSaRecordSurviving);
- assertTrue(
- mIkeSessionStateMachine.getCurrentState()
- instanceof IkeSessionStateMachine.RekeyIkeRemoteDelete);
- verify(mSpyIkeSocket)
- .registerIke(
- eq(mSpyRemoteInitIkeSaRecord.getLocalSpi()), eq(mIkeSessionStateMachine));
- }
-
- @Test
- public void testRekeyIkeRemoteCreateHandlesInvalidReq() throws Exception {
- setupIdleStateMachine();
-
- // Receive Rekey request
- ReceivedIkePacket request = makeRekeyIkeRequestWithUnacceptableProposal();
- mIkeSessionStateMachine.sendMessage(IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, request);
- mLooper.dispatchAll();
-
- verifyProcessRekeyReqFailure(ERROR_TYPE_NO_PROPOSAL_CHOSEN);
- }
-
- @Test
- public void testRekeyIkeRemoteCreateSaCreationFailure() throws Exception {
- // Throw error when building new IKE SA
- throwExceptionWhenMakeRekeyIkeSa(
- new GeneralSecurityException("testRekeyIkeRemoteCreateSaCreationFailure"));
- setupIdleStateMachine();
-
- // Receive Rekey request
- ReceivedIkePacket request = makeRekeyIkeRequest();
- mIkeSessionStateMachine.sendMessage(IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, request);
- mLooper.dispatchAll();
-
- verifyProcessRekeyReqFailure(ERROR_TYPE_NO_PROPOSAL_CHOSEN);
- }
-
- private void verifyProcessRekeyReqFailure(int expectedErrorCode) {
- // Verify IKE Session is back to Idle
- assertTrue(
- mIkeSessionStateMachine.getCurrentState() instanceof IkeSessionStateMachine.Idle);
-
- // Verify error notification was sent
- List<IkePayload> payloads = verifyOutInfoMsgHeaderAndGetPayloads(true /*isResp*/);
- assertEquals(1, payloads.size());
- IkeNotifyPayload notify = (IkeNotifyPayload) payloads.get(0);
- assertEquals(expectedErrorCode, notify.notifyType);
- }
-
- @Test
- public void testRekeyIkeRemoteDelete() throws Exception {
- setupIdleStateMachine();
-
- // Seed fake rekey data and force transition to RekeyIkeLocalDelete
- mIkeSessionStateMachine.mRemoteInitNewIkeSaRecord = mSpyRemoteInitIkeSaRecord;
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_FORCE_TRANSITION,
- mIkeSessionStateMachine.mRekeyIkeRemoteDelete);
- mLooper.dispatchAll();
-
- // Rekey Delete request
- ReceivedIkePacket dummyDeleteIkeRequestReceivedPacket =
- makeDeleteIkeRequest(mSpyCurrentIkeSaRecord);
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, dummyDeleteIkeRequestReceivedPacket);
- mLooper.dispatchAll();
- verifyIncrementRemoteReqMsgId();
- verifyDecodeEncryptedMessage(mSpyCurrentIkeSaRecord, dummyDeleteIkeRequestReceivedPacket);
-
- // Verify outbound DELETE_IKE_SA message
- IkeMessage rekeyDeleteResp = verifyEncryptAndEncodeAndGetMessage(mSpyCurrentIkeSaRecord);
- IkeHeader rekeyDeleteRespHeader = rekeyDeleteResp.ikeHeader;
- assertEquals(IkePayload.PAYLOAD_TYPE_SK, rekeyDeleteRespHeader.nextPayloadType);
- assertEquals(IkeHeader.EXCHANGE_TYPE_INFORMATIONAL, rekeyDeleteRespHeader.exchangeType);
- assertTrue(rekeyDeleteRespHeader.isResponseMsg);
- assertTrue(rekeyDeleteRespHeader.fromIkeInitiator);
- assertTrue(rekeyDeleteResp.ikePayloadList.isEmpty());
-
- // Verify final state - Idle, with new SA, and old SA closed.
- verifyRekeyReplaceSa(mSpyRemoteInitIkeSaRecord);
-
- verify(mMockIkeSessionCallback, never()).onClosed();
-
- verifyDecodeEncryptedMessage(mSpyCurrentIkeSaRecord, dummyDeleteIkeRequestReceivedPacket);
- assertTrue(
- mIkeSessionStateMachine.getCurrentState() instanceof IkeSessionStateMachine.Idle);
- }
-
- @Test
- public void testRekeyIkeRemoteDeleteExitAndRenter() throws Exception {
- setupIdleStateMachine();
-
- // Seed fake rekey data and force transition to RekeyIkeLocalDelete
- mIkeSessionStateMachine.mRemoteInitNewIkeSaRecord = mSpyRemoteInitIkeSaRecord;
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_FORCE_TRANSITION,
- mIkeSessionStateMachine.mRekeyIkeRemoteDelete);
- mLooper.dispatchAll();
-
- // Trigger a timeout, and immediately re-enter remote-delete
- mLooper.moveTimeForward(IkeSessionStateMachine.REKEY_DELETE_TIMEOUT_MS / 2 + 1);
- mIkeSessionStateMachine.sendMessage(IkeSessionStateMachine.TIMEOUT_REKEY_REMOTE_DELETE);
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_FORCE_TRANSITION,
- mIkeSessionStateMachine.mRekeyIkeRemoteDelete);
- mLooper.dispatchAll();
-
- // Shift time forward, and assert the previous timeout was NOT fired.
- mLooper.moveTimeForward(IkeSessionStateMachine.REKEY_DELETE_TIMEOUT_MS / 2 + 1);
- mLooper.dispatchAll();
-
- // Verify no request received, or response sent.
- verify(mMockIkeMessageHelper, never()).decode(anyInt(), anyObject(), anyObject());
- verifyEncryptAndEncodeNeverCalled(mSpyCurrentIkeSaRecord);
-
- // Verify final state has not changed - signal was not sent.
- assertTrue(
- mIkeSessionStateMachine.getCurrentState()
- instanceof IkeSessionStateMachine.RekeyIkeRemoteDelete);
- }
-
- @Test
- public void testRekeyIkeRemoteDeleteTimedOut() throws Exception {
- setupIdleStateMachine();
-
- // Seed fake rekey data and force transition to RekeyIkeLocalDelete
- mIkeSessionStateMachine.mRemoteInitNewIkeSaRecord = mSpyRemoteInitIkeSaRecord;
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_FORCE_TRANSITION,
- mIkeSessionStateMachine.mRekeyIkeRemoteDelete);
- mLooper.dispatchAll();
-
- mLooper.moveTimeForward(IkeSessionStateMachine.REKEY_DELETE_TIMEOUT_MS);
- mLooper.dispatchAll();
-
- // Verify no request received, or response sent.
- verify(mMockIkeMessageHelper, never()).decode(anyInt(), anyObject(), anyObject());
- verifyEncryptAndEncodeNeverCalled(mSpyCurrentIkeSaRecord);
-
- // Verify final state - Idle, with new SA, and old SA closed.
- verifyRekeyReplaceSa(mSpyRemoteInitIkeSaRecord);
-
- assertTrue(
- mIkeSessionStateMachine.getCurrentState() instanceof IkeSessionStateMachine.Idle);
- }
-
- @Test
- public void testSimulRekey() throws Exception {
- setupIdleStateMachine();
-
- // Prepare "rekeyed" SA
- setupRekeyedIkeSa(mSpyLocalInitIkeSaRecord);
- when(mSpyLocalInitIkeSaRecord.compareTo(mSpyRemoteInitIkeSaRecord)).thenReturn(1);
-
- // Send Rekey request on mSpyCurrentIkeSaRecord
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_EXECUTE_LOCAL_REQ,
- new LocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_IKE));
-
- // Receive Rekey request on mSpyCurrentIkeSaRecord
- ReceivedIkePacket dummyRekeyIkeRequestReceivedPacket = makeRekeyIkeRequest();
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, dummyRekeyIkeRequestReceivedPacket);
- mLooper.dispatchAll();
- verifyIncrementRemoteReqMsgId();
-
- // Receive Rekey response on mSpyCurrentIkeSaRecord
- ReceivedIkePacket dummyRekeyIkeRespReceivedPacket = makeRekeyIkeResponse();
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, dummyRekeyIkeRespReceivedPacket);
- mLooper.dispatchAll();
- verifyIncrementLocaReqMsgId();
- verify(mSpyIkeSocket)
- .registerIke(
- eq(mSpyLocalInitIkeSaRecord.getLocalSpi()), eq(mIkeSessionStateMachine));
-
- // Receive Delete response on mSpyCurrentIkeSaRecord
- ReceivedIkePacket dummyDeleteIkeRespReceivedPacket =
- makeDeleteIkeResponse(mSpyCurrentIkeSaRecord);
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, dummyDeleteIkeRespReceivedPacket);
- mLooper.dispatchAll();
- verifyIncrementLocaReqMsgId();
-
- // Verify
- verifyDecodeEncryptedMessage(mSpyCurrentIkeSaRecord, dummyRekeyIkeRequestReceivedPacket);
- verifyDecodeEncryptedMessage(mSpyCurrentIkeSaRecord, dummyRekeyIkeRespReceivedPacket);
- verifyDecodeEncryptedMessage(mSpyCurrentIkeSaRecord, dummyDeleteIkeRespReceivedPacket);
- assertTrue(
- mIkeSessionStateMachine.getCurrentState() instanceof IkeSessionStateMachine.Idle);
-
- verifyRekeyReplaceSa(mSpyLocalInitIkeSaRecord);
- verify(mMockIkeSessionCallback, never()).onClosed();
- }
-
- @Test
- public void testOpenIkeSession() throws Exception {
- assertTrue(
- mIkeSessionStateMachine.getCurrentState()
- instanceof IkeSessionStateMachine.Initial);
-
- mIkeSessionStateMachine.openSession();
- mLooper.dispatchAll();
-
- assertTrue(
- mIkeSessionStateMachine.getCurrentState()
- instanceof IkeSessionStateMachine.CreateIkeLocalIkeInit);
- }
-
- @Test
- public void testIkeInitSchedulesRekey() throws Exception {
- setupFirstIkeSa();
-
- // Send IKE INIT request
- mIkeSessionStateMachine.sendMessage(IkeSessionStateMachine.CMD_LOCAL_REQUEST_CREATE_IKE);
-
- // Receive IKE INIT response
- ReceivedIkePacket dummyReceivedIkePacket = makeIkeInitResponse();
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, dummyReceivedIkePacket);
-
- // Mock IKE AUTH and transition to Idle
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_FORCE_TRANSITION, mIkeSessionStateMachine.mIdle);
- mLooper.dispatchAll();
- mIkeSessionStateMachine.mSaProposal = buildSaProposal();
-
- // Move time forward to trigger rekey
- mLooper.moveTimeForward(SA_SOFT_LIFETIME_MS);
- mLooper.dispatchAll();
-
- assertTrue(
- mIkeSessionStateMachine.getCurrentState()
- instanceof IkeSessionStateMachine.RekeyIkeLocalCreate);
- }
-
- @Test
- public void testRekeyCreateIkeSchedulesRekey() throws Exception {
- setupIdleStateMachine();
-
- // Send Rekey-Create request
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_EXECUTE_LOCAL_REQ,
- new LocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_IKE));
- mLooper.dispatchAll();
-
- // Prepare "rekeyed" SA
- setupRekeyedIkeSa(mSpyLocalInitIkeSaRecord);
-
- // Receive Rekey response
- ReceivedIkePacket dummyRekeyIkeRespReceivedPacket = makeRekeyIkeResponse();
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, dummyRekeyIkeRespReceivedPacket);
- mLooper.dispatchAll();
-
- // Mock rekey delete and transition to Idle
- mIkeSessionStateMachine.mCurrentIkeSaRecord = mSpyLocalInitIkeSaRecord;
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_FORCE_TRANSITION, mIkeSessionStateMachine.mIdle);
- mLooper.dispatchAll();
-
- // Move time forward to trigger rekey
- mLooper.moveTimeForward(SA_SOFT_LIFETIME_MS);
- mLooper.dispatchAll();
-
- assertTrue(
- mIkeSessionStateMachine.getCurrentState()
- instanceof IkeSessionStateMachine.RekeyIkeLocalCreate);
- }
-
- @Test
- public void testBuildEncryptedInformationalMessage() throws Exception {
- IkeNotifyPayload payload = new IkeNotifyPayload(ERROR_TYPE_INVALID_SYNTAX, new byte[0]);
-
- boolean isResp = false;
- IkeMessage generated =
- mIkeSessionStateMachine.buildEncryptedInformationalMessage(
- mSpyCurrentIkeSaRecord, new IkeInformationalPayload[] {payload}, isResp, 0);
-
- assertEquals(mSpyCurrentIkeSaRecord.getInitiatorSpi(), generated.ikeHeader.ikeInitiatorSpi);
- assertEquals(mSpyCurrentIkeSaRecord.getResponderSpi(), generated.ikeHeader.ikeResponderSpi);
- assertEquals(
- mSpyCurrentIkeSaRecord.getLocalRequestMessageId(), generated.ikeHeader.messageId);
- assertEquals(isResp, generated.ikeHeader.isResponseMsg);
- assertEquals(IkePayload.PAYLOAD_TYPE_SK, generated.ikeHeader.nextPayloadType);
-
- List<IkeNotifyPayload> generatedPayloads =
- generated.getPayloadListForType(
- IkePayload.PAYLOAD_TYPE_NOTIFY, IkeNotifyPayload.class);
- assertEquals(1, generatedPayloads.size());
-
- IkeNotifyPayload generatedPayload = generatedPayloads.get(0);
- assertArrayEquals(new byte[0], generatedPayload.notifyData);
- assertEquals(ERROR_TYPE_INVALID_SYNTAX, generatedPayload.notifyType);
- }
-
- private void verifyLastSentRespAllPackets(byte[][] expectedPackets, IkeSaRecord saRecord) {
- if (expectedPackets == null) {
- assertNull(saRecord.getLastSentRespAllPackets());
- return;
- }
-
- assertEquals(expectedPackets.length, saRecord.getLastSentRespAllPackets().size());
- for (int i = 0; i < expectedPackets.length; i++) {
- assertArrayEquals(expectedPackets[i], saRecord.getLastSentRespAllPackets().get(i));
- }
- }
-
- @Test
- public void testEncryptedRetransmitterImmediatelySendsRequest() throws Exception {
- setupIdleStateMachine();
- byte[][] dummyLastRespBytes =
- new byte[][] {"testRetransmitterSendsRequestLastResp".getBytes()};
- mSpyCurrentIkeSaRecord.updateLastSentRespAllPackets(Arrays.asList(dummyLastRespBytes));
-
- IkeMessage spyIkeReqMessage =
- spy(
- new IkeMessage(
- new IkeHeader(
- mSpyCurrentIkeSaRecord.getInitiatorSpi(),
- mSpyCurrentIkeSaRecord.getResponderSpi(),
- IkePayload.PAYLOAD_TYPE_SK,
- EXCHANGE_TYPE_INFORMATIONAL,
- false /*isResp*/,
- mSpyCurrentIkeSaRecord.isLocalInit,
- mSpyCurrentIkeSaRecord.getLocalRequestMessageId()),
- new LinkedList<>()));
-
- // Use something unique as a sentinel value
- byte[][] dummyReqBytesList =
- new byte[][] {
- "testRetransmitterSendsReqFrag1".getBytes(),
- "testRetransmitterSendsReqFrag2".getBytes()
- };
-
- doReturn(dummyReqBytesList)
- .when(spyIkeReqMessage)
- .encryptAndEncode(any(), any(), eq(mSpyCurrentIkeSaRecord), anyBoolean(), anyInt());
-
- IkeSessionStateMachine.EncryptedRetransmitter retransmitter =
- mIkeSessionStateMachine.new EncryptedRetransmitter(spyIkeReqMessage);
-
- // Verify message is sent out, and that request does not change cached retransmit-response
- // mLastSentIkeResp.
- verify(mSpyIkeSocket).sendIkePacket(eq(dummyReqBytesList[0]), eq(REMOTE_ADDRESS));
- verify(mSpyIkeSocket).sendIkePacket(eq(dummyReqBytesList[1]), eq(REMOTE_ADDRESS));
- verifyLastSentRespAllPackets(dummyLastRespBytes, mSpyCurrentIkeSaRecord);
- }
-
- // TODO: b/141275871 Test retransmisstions are fired for correct times within certain time.
-
- @Test
- public void testCacheLastRequestAndResponse() throws Exception {
- setupIdleStateMachine();
- mSpyCurrentIkeSaRecord.updateLastReceivedReqFirstPacket(null /*reqPacket*/);
- mSpyCurrentIkeSaRecord.updateLastSentRespAllPackets(null /*respPacketList*/);
-
- byte[] dummyIkeReqFirstPacket = "testLastSentRequest".getBytes();
- byte[][] dummyIkeResp =
- new byte[][] {
- "testLastSentRespFrag1".getBytes(), "testLastSentRespFrag2".getBytes()
- };
-
- when(mMockIkeMessageHelper.encryptAndEncode(
- any(),
- any(),
- eq(mSpyCurrentIkeSaRecord),
- any(IkeMessage.class),
- anyBoolean(),
- anyInt()))
- .thenReturn(dummyIkeResp);
-
- // Receive a DPD request, expect to send dummyIkeResp
- ReceivedIkePacket dummyDpdRequest =
- makeDpdIkeRequest(
- mSpyCurrentIkeSaRecord.getRemoteRequestMessageId(), dummyIkeReqFirstPacket);
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, dummyDpdRequest);
- mLooper.dispatchAll();
-
- verify(mSpyIkeSocket).sendIkePacket(eq(dummyIkeResp[0]), eq(REMOTE_ADDRESS));
- verify(mSpyIkeSocket).sendIkePacket(eq(dummyIkeResp[1]), eq(REMOTE_ADDRESS));
-
- verifyLastSentRespAllPackets(dummyIkeResp, mSpyCurrentIkeSaRecord);
- assertTrue(mSpyCurrentIkeSaRecord.isRetransmittedRequest(dummyIkeReqFirstPacket));
-
- assertTrue(
- mIkeSessionStateMachine.getCurrentState() instanceof IkeSessionStateMachine.Idle);
- }
-
- @Test
- public void testReplyRetransmittedRequest() throws Exception {
- setupIdleStateMachine();
-
- // Mock last sent request and response
- byte[] dummyIkeReqFirstPacket = "testRcvRetransmittedRequestReq".getBytes();
- byte[][] dummyIkeResp = new byte[][] {"testRcvRetransmittedRequestResp".getBytes()};
-
- mSpyCurrentIkeSaRecord.updateLastReceivedReqFirstPacket(dummyIkeReqFirstPacket);
- mSpyCurrentIkeSaRecord.updateLastSentRespAllPackets(Arrays.asList(dummyIkeResp));
- mSpyCurrentIkeSaRecord.incrementRemoteRequestMessageId();
-
- // Build request with last validated message ID
- ReceivedIkePacket request =
- makeDpdIkeRequest(
- mSpyCurrentIkeSaRecord.getRemoteRequestMessageId() - 1,
- dummyIkeReqFirstPacket);
-
- mIkeSessionStateMachine.sendMessage(IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, request);
-
- mLooper.dispatchAll();
-
- verifyLastSentRespAllPackets(dummyIkeResp, mSpyCurrentIkeSaRecord);
- verify(mSpyIkeSocket).sendIkePacket(eq(dummyIkeResp[0]), eq(REMOTE_ADDRESS));
-
- assertTrue(
- mIkeSessionStateMachine.getCurrentState() instanceof IkeSessionStateMachine.Idle);
- }
-
- @Test
- public void testDiscardFakeRetransmittedRequest() throws Exception {
- setupIdleStateMachine();
-
- // Mock last sent request and response
- byte[] dummyIkeReqFirstPacket = "testDiscardFakeRetransmittedRequestReq".getBytes();
- byte[][] dummyIkeResp = new byte[][] {"testDiscardFakeRetransmittedRequestResp".getBytes()};
- mSpyCurrentIkeSaRecord.updateLastReceivedReqFirstPacket(dummyIkeReqFirstPacket);
- mSpyCurrentIkeSaRecord.updateLastSentRespAllPackets(Arrays.asList(dummyIkeResp));
- mSpyCurrentIkeSaRecord.incrementRemoteRequestMessageId();
-
- // Build request with last validated message ID but different bytes
- ReceivedIkePacket request =
- makeDpdIkeRequest(
- mSpyCurrentIkeSaRecord.getRemoteRequestMessageId() - 1, new byte[0]);
-
- mIkeSessionStateMachine.sendMessage(IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, request);
-
- mLooper.dispatchAll();
-
- verifyLastSentRespAllPackets(dummyIkeResp, mSpyCurrentIkeSaRecord);
- verify(mSpyIkeSocket, never()).sendIkePacket(any(), any());
-
- assertTrue(
- mIkeSessionStateMachine.getCurrentState() instanceof IkeSessionStateMachine.Idle);
- }
-
- @Test
- public void testDiscardRetransmittedResponse() throws Exception {
- mockIkeInitAndTransitionToIkeAuth(mIkeSessionStateMachine.mCreateIkeLocalIkeAuth);
- verifyRetransmissionStarted();
-
- // Build and send fake response with last validated message ID to IKE state machine
- ReceivedIkePacket resp =
- makeDummyEncryptedReceivedIkePacketWithPayloadList(
- mSpyCurrentIkeSaRecord,
- IkeHeader.EXCHANGE_TYPE_IKE_SA_INIT,
- true /*isResp*/,
- mSpyCurrentIkeSaRecord.getLocalRequestMessageId() - 1,
- new LinkedList<>(),
- new byte[0]);
-
- mIkeSessionStateMachine.sendMessage(IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, resp);
- mLooper.dispatchAll();
-
- // Verify current state does not change
- verifyRetransmissionStarted();
- assertTrue(
- mIkeSessionStateMachine.getCurrentState()
- instanceof IkeSessionStateMachine.CreateIkeLocalIkeAuth);
- }
-
- @Test
- public void testDeleteIkeLocalDeleteRequest() throws Exception {
- setupIdleStateMachine();
-
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_EXECUTE_LOCAL_REQ,
- new LocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_DELETE_IKE));
- mLooper.dispatchAll();
- verifyRetransmissionStarted();
-
- // Verify outbound message
- IkeMessage delMsg = verifyEncryptAndEncodeAndGetMessage(mSpyCurrentIkeSaRecord);
-
- IkeHeader ikeHeader = delMsg.ikeHeader;
- assertEquals(IkePayload.PAYLOAD_TYPE_SK, ikeHeader.nextPayloadType);
- assertEquals(IkeHeader.EXCHANGE_TYPE_INFORMATIONAL, ikeHeader.exchangeType);
- assertFalse(ikeHeader.isResponseMsg);
- assertTrue(ikeHeader.fromIkeInitiator);
-
- List<IkeDeletePayload> deletePayloadList =
- delMsg.getPayloadListForType(
- IkePayload.PAYLOAD_TYPE_DELETE, IkeDeletePayload.class);
- assertEquals(1, deletePayloadList.size());
-
- IkeDeletePayload deletePayload = deletePayloadList.get(0);
- assertEquals(IkePayload.PROTOCOL_ID_IKE, deletePayload.protocolId);
- assertEquals(0, deletePayload.numSpi);
- assertEquals(0, deletePayload.spiSize);
- assertArrayEquals(new int[0], deletePayload.spisToDelete);
- }
-
- @Test
- public void testDeleteIkeLocalDeleteResponse() throws Exception {
- setupIdleStateMachine();
-
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_EXECUTE_LOCAL_REQ,
- new LocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_DELETE_IKE));
- mLooper.dispatchAll();
- verifyRetransmissionStarted();
-
- ReceivedIkePacket received = makeDeleteIkeResponse(mSpyCurrentIkeSaRecord);
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, received);
- mLooper.dispatchAll();
- verifyIncrementLocaReqMsgId();
-
- verifyNotifyUserCloseSession();
-
- // Verify state machine quit properly
- assertNull(mIkeSessionStateMachine.getCurrentState());
- }
-
- @Test
- public void testDeleteIkeLocalDeleteResponseWithParsingError() throws Exception {
- setupIdleStateMachine();
-
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_EXECUTE_LOCAL_REQ,
- new LocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_DELETE_IKE));
- mLooper.dispatchAll();
- verifyRetransmissionStarted();
- resetMockIkeMessageHelper();
-
- // Mock receiving response with syntax error
- ReceivedIkePacket mockInvalidPacket =
- makeDummyReceivedIkePacketWithInvalidSyntax(
- mSpyCurrentIkeSaRecord,
- true /*isResp*/,
- IkeHeader.EXCHANGE_TYPE_INFORMATIONAL);
- mIkeSessionStateMachine.sendMessage(CMD_RECEIVE_IKE_PACKET, mockInvalidPacket);
- mLooper.dispatchAll();
-
- // Verify no more request out
- verifyEncryptAndEncodeNeverCalled(mSpyCurrentIkeSaRecord);
-
- // Verify state machine quit properly
- verify(mMockIkeSessionCallback).onClosedExceptionally(any(InvalidSyntaxException.class));
- assertNull(mIkeSessionStateMachine.getCurrentState());
- }
-
- @Test
- public void testDeleteIkeLocalDeleteHandlesInvalidResp() throws Exception {
- setupIdleStateMachine();
-
- // Send delete request
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_EXECUTE_LOCAL_REQ,
- new LocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_DELETE_IKE));
- mLooper.dispatchAll();
-
- // Receive response with wrong exchange type
- ReceivedIkePacket resp =
- makeDummyReceivedIkePacketWithInvalidSyntax(
- mSpyCurrentIkeSaRecord,
- true /*isResp*/,
- IkeHeader.EXCHANGE_TYPE_CREATE_CHILD_SA);
- mIkeSessionStateMachine.sendMessage(CMD_RECEIVE_IKE_PACKET, resp);
- mLooper.dispatchAll();
-
- // Verify state machine quit properly
- verify(mMockIkeSessionCallback).onClosedExceptionally(any(InvalidSyntaxException.class));
- assertNull(mIkeSessionStateMachine.getCurrentState());
- }
-
- @Test
- public void testDeleteIkeLocalDeleteReceivedNonDeleteRequest() throws Exception {
- setupIdleStateMachine();
-
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_EXECUTE_LOCAL_REQ,
- new LocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_DELETE_IKE));
- mLooper.dispatchAll();
- verifyRetransmissionStarted();
-
- // Verify delete sent out.
- verifyEncryptAndEncodeAndGetMessage(mSpyCurrentIkeSaRecord);
-
- resetMockIkeMessageHelper(); // Discard value.
-
- ReceivedIkePacket received = makeRekeyIkeRequest();
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, received);
-
- mLooper.dispatchAll();
- verifyRetransmissionStarted();
- verifyIncrementRemoteReqMsgId();
-
- // Verify outbound response
- IkeMessage resp = verifyEncryptAndEncodeAndGetMessage(mSpyCurrentIkeSaRecord);
-
- IkeHeader ikeHeader = resp.ikeHeader;
- assertEquals(IkePayload.PAYLOAD_TYPE_SK, ikeHeader.nextPayloadType);
- assertEquals(IkeHeader.EXCHANGE_TYPE_INFORMATIONAL, ikeHeader.exchangeType);
- assertTrue(ikeHeader.isResponseMsg);
- assertEquals(mSpyCurrentIkeSaRecord.isLocalInit, ikeHeader.fromIkeInitiator);
-
- List<IkeNotifyPayload> notificationPayloadList =
- resp.getPayloadListForType(IkePayload.PAYLOAD_TYPE_NOTIFY, IkeNotifyPayload.class);
- assertEquals(1, notificationPayloadList.size());
-
- IkeNotifyPayload notifyPayload = notificationPayloadList.get(0);
- assertEquals(IkeProtocolException.ERROR_TYPE_TEMPORARY_FAILURE, notifyPayload.notifyType);
- }
-
- @Test
- public void testDeleteIkeRemoteDelete() throws Exception {
- setupIdleStateMachine();
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET,
- makeDeleteIkeRequest(mSpyCurrentIkeSaRecord));
-
- mLooper.dispatchAll();
- verifyIncrementRemoteReqMsgId();
-
- // Verify outbound message
- IkeMessage delMsg = verifyEncryptAndEncodeAndGetMessage(mSpyCurrentIkeSaRecord);
-
- IkeHeader ikeHeader = delMsg.ikeHeader;
- assertEquals(IkePayload.PAYLOAD_TYPE_SK, ikeHeader.nextPayloadType);
- assertEquals(IkeHeader.EXCHANGE_TYPE_INFORMATIONAL, ikeHeader.exchangeType);
- assertTrue(ikeHeader.isResponseMsg);
- assertEquals(mSpyCurrentIkeSaRecord.isLocalInit, ikeHeader.fromIkeInitiator);
-
- assertTrue(delMsg.ikePayloadList.isEmpty());
-
- verifyNotifyUserCloseSession();
-
- // Verify state machine quit properly
- assertNull(mIkeSessionStateMachine.getCurrentState());
- }
-
- @Test
- public void testReceiveDpd() throws Exception {
- setupIdleStateMachine();
-
- // Receive a DPD request, expect to stay in IDLE state
- ReceivedIkePacket dummyDpdRequest = makeDpdIkeRequest(mSpyCurrentIkeSaRecord);
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, dummyDpdRequest);
- mLooper.dispatchAll();
- assertTrue(
- mIkeSessionStateMachine.getCurrentState() instanceof IkeSessionStateMachine.Idle);
-
- verifyDecodeEncryptedMessage(mSpyCurrentIkeSaRecord, dummyDpdRequest);
-
- // Verify outbound response
- IkeMessage resp = verifyEncryptAndEncodeAndGetMessage(mSpyCurrentIkeSaRecord);
- IkeHeader ikeHeader = resp.ikeHeader;
- assertEquals(IkePayload.PAYLOAD_TYPE_SK, ikeHeader.nextPayloadType);
- assertEquals(IkeHeader.EXCHANGE_TYPE_INFORMATIONAL, ikeHeader.exchangeType);
- assertTrue(ikeHeader.isResponseMsg);
- assertEquals(mSpyCurrentIkeSaRecord.isLocalInit, ikeHeader.fromIkeInitiator);
- assertTrue(resp.ikePayloadList.isEmpty());
- }
-
- @Test
- public void testReceiveDpdNonIdle() throws Exception {
- setupIdleStateMachine();
-
- // Move to a non-idle state. Use RekeyIkeRemoteDelete, as it doesn't send out any requests.
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_FORCE_TRANSITION,
- mIkeSessionStateMachine.mRekeyIkeRemoteDelete);
- mLooper.dispatchAll();
-
- // In a rekey state, receiving (and handling) a DPD should not result in a change of states
- ReceivedIkePacket dummyDpdRequest = makeDpdIkeRequest(mSpyCurrentIkeSaRecord);
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, dummyDpdRequest);
- mLooper.dispatchAll();
- assertTrue(
- mIkeSessionStateMachine.getCurrentState()
- instanceof IkeSessionStateMachine.RekeyIkeRemoteDelete);
-
- verifyDecodeEncryptedMessage(mSpyCurrentIkeSaRecord, dummyDpdRequest);
-
- // Verify outbound response
- IkeMessage resp = verifyEncryptAndEncodeAndGetMessage(mSpyCurrentIkeSaRecord);
- IkeHeader ikeHeader = resp.ikeHeader;
- assertEquals(IkePayload.PAYLOAD_TYPE_SK, ikeHeader.nextPayloadType);
- assertEquals(IkeHeader.EXCHANGE_TYPE_INFORMATIONAL, ikeHeader.exchangeType);
- assertTrue(ikeHeader.isResponseMsg);
- assertEquals(mSpyCurrentIkeSaRecord.isLocalInit, ikeHeader.fromIkeInitiator);
- assertTrue(resp.ikePayloadList.isEmpty());
- }
-
- @Test
- public void testIdleTriggersNewRequests() throws Exception {
- setupIdleStateMachine();
-
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_EXECUTE_LOCAL_REQ,
- new LocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_IKE));
- mLooper.dispatchAll();
-
- // Verify that the command is executed, and the state machine transitions to the right state
- assertTrue(
- mIkeSessionStateMachine.getCurrentState()
- instanceof IkeSessionStateMachine.RekeyIkeLocalCreate);
- verifyRetransmissionStarted();
- }
-
- @Test
- public void testNonIdleStateDoesNotTriggerNewRequests() throws Exception {
- setupIdleStateMachine();
-
- // Force ourselves into a non-idle state
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_FORCE_TRANSITION, mIkeSessionStateMachine.mReceiving);
- mLooper.dispatchAll();
- verifyEncryptAndEncodeNeverCalled();
-
- // Queue a local request, and expect that it is not run (yet)
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_IKE,
- new LocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_IKE));
- mLooper.dispatchAll();
-
- // Verify that the state machine is still in the Receiving state
- verifyEncryptAndEncodeNeverCalled();
- assertTrue(
- mIkeSessionStateMachine.getCurrentState()
- instanceof IkeSessionStateMachine.Receiving);
-
- // Go back to Idle, and expect to immediately transition to RekeyIkeLocalCreate from the
- // queued request
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_FORCE_TRANSITION, mIkeSessionStateMachine.mIdle);
- mLooper.dispatchAll();
- assertTrue(
- mIkeSessionStateMachine.getCurrentState()
- instanceof IkeSessionStateMachine.RekeyIkeLocalCreate);
- verifyEncryptAndEncodeAndGetMessage(mSpyCurrentIkeSaRecord);
- }
-
- @Test
- public void testOpenChildSessionValidatesArgs() throws Exception {
- setupIdleStateMachine();
-
- // Expect failure - no callbacks provided
- try {
- mIkeSessionStateMachine.openChildSession(mChildSessionOptions, null);
- } catch (IllegalArgumentException expected) {
- }
-
- // Expect failure - callbacks already registered
- try {
- mIkeSessionStateMachine.openChildSession(
- mChildSessionOptions, mMockChildSessionCallback);
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void testOpenChildSession() throws Exception {
- setupIdleStateMachine();
-
- ChildSessionCallback cb = mock(ChildSessionCallback.class);
- mIkeSessionStateMachine.openChildSession(mChildSessionOptions, cb);
-
- // Test that inserting the same cb returns an error, even before the state
- // machine has a chance to process it.
- try {
- mIkeSessionStateMachine.openChildSession(mChildSessionOptions, cb);
- } catch (IllegalArgumentException expected) {
- }
-
- verify(mMockChildSessionFactoryHelper)
- .makeChildSessionStateMachine(
- eq(mLooper.getLooper()),
- eq(mContext),
- eq(mChildSessionOptions),
- eq(mSpyUserCbExecutor),
- eq(cb),
- any());
-
- // Verify state in IkeSessionStateMachine
- mLooper.dispatchAll();
- assertTrue(
- mIkeSessionStateMachine.getCurrentState()
- instanceof IkeSessionStateMachine.ChildProcedureOngoing);
-
- synchronized (mIkeSessionStateMachine.mChildCbToSessions) {
- assertTrue(mIkeSessionStateMachine.mChildCbToSessions.containsKey(cb));
- }
- }
-
- @Test
- public void testCloseChildSessionValidatesArgs() throws Exception {
- setupIdleStateMachine();
-
- // Expect failure - callbacks not registered
- try {
- mIkeSessionStateMachine.closeChildSession(mock(ChildSessionCallback.class));
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void testCloseChildSession() throws Exception {
- setupIdleStateMachine();
-
- mIkeSessionStateMachine.closeChildSession(mMockChildSessionCallback);
- mLooper.dispatchAll();
-
- assertTrue(
- mIkeSessionStateMachine.getCurrentState()
- instanceof IkeSessionStateMachine.ChildProcedureOngoing);
- }
-
- @Test
- public void testCloseImmediatelyAfterOpenChildSession() throws Exception {
- setupIdleStateMachine();
-
- ChildSessionCallback cb = mock(ChildSessionCallback.class);
- mIkeSessionStateMachine.openChildSession(mChildSessionOptions, cb);
-
- // Verify that closing the session immediately still picks up the child callback
- // even before the looper has a chance to run.
- mIkeSessionStateMachine.closeChildSession(mMockChildSessionCallback);
- }
-
- @Test
- public void testOnChildSessionClosed() throws Exception {
- setupIdleStateMachine();
-
- mDummyChildSmCallback.onChildSessionClosed(mMockChildSessionCallback);
-
- synchronized (mIkeSessionStateMachine.mChildCbToSessions) {
- assertFalse(
- mIkeSessionStateMachine.mChildCbToSessions.containsKey(
- mMockChildSessionCallback));
- }
- }
-
- @Test
- public void testHandleUnexpectedExceptionInEnterState() throws Exception {
- Log spyIkeLog = TestUtils.makeSpyLogDoLogErrorForWtf(TAG);
- IkeManager.setIkeLog(spyIkeLog);
-
- IkeSessionOptions mockSessionOptions = mock(IkeSessionOptions.class);
- when(mockSessionOptions.getSaProposals()).thenThrow(mock(RuntimeException.class));
-
- IkeSessionStateMachine ikeSession =
- new IkeSessionStateMachine(
- mLooper.getLooper(),
- mContext,
- mIpSecManager,
- mockSessionOptions,
- mChildSessionOptions,
- mSpyUserCbExecutor,
- mMockIkeSessionCallback,
- mMockChildSessionCallback,
- mMockEapAuthenticatorFactory);
- // Send IKE INIT request
- mIkeSessionStateMachine.sendMessage(IkeSessionStateMachine.CMD_LOCAL_REQUEST_CREATE_IKE);
- mLooper.dispatchAll();
-
- assertNull(ikeSession.getCurrentState());
- verify(mSpyUserCbExecutor).execute(any(Runnable.class));
- verify(mMockIkeSessionCallback).onClosedExceptionally(any(IkeInternalException.class));
- verify(spyIkeLog).wtf(anyString(), anyString(), any(RuntimeException.class));
- }
-
- @Test
- public void testHandleUnexpectedExceptionInProcessStateMsg() throws Exception {
- Log spyIkeLog = TestUtils.makeSpyLogDoLogErrorForWtf(TAG);
- IkeManager.setIkeLog(spyIkeLog);
-
- setupIdleStateMachine();
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, null /*receivedIkePacket*/);
- mLooper.dispatchAll();
-
- assertNull(mIkeSessionStateMachine.getCurrentState());
- verify(mSpyUserCbExecutor).execute(any(Runnable.class));
- verify(mMockIkeSessionCallback).onClosedExceptionally(any(IkeInternalException.class));
- verify(spyIkeLog).wtf(anyString(), anyString(), any(RuntimeException.class));
- }
-
- @Test
- public void testCreateIkeLocalIkeInitRcvErrorNotify() throws Exception {
- // Send IKE INIT request
- mIkeSessionStateMachine.sendMessage(IkeSessionStateMachine.CMD_LOCAL_REQUEST_CREATE_IKE);
- mLooper.dispatchAll();
- verifyRetransmissionStarted();
-
- // Receive IKE INIT response with erro notification.
- List<IkePayload> payloads = new LinkedList<>();
- payloads.add(new IkeNotifyPayload(IkeProtocolException.ERROR_TYPE_NO_PROPOSAL_CHOSEN));
- ReceivedIkePacket resp =
- makeDummyUnencryptedReceivedIkePacket(
- 1L /*initiator SPI*/,
- 2L /*respodner SPI*/,
- IkeHeader.EXCHANGE_TYPE_IKE_SA_INIT,
- true /*isResp*/,
- false /*fromIkeInit*/,
- payloads);
-
- mIkeSessionStateMachine.sendMessage(IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, resp);
- mLooper.dispatchAll();
-
- // Fires user error callbacks
- verify(mMockIkeSessionCallback)
- .onClosedExceptionally(
- argThat(err -> err instanceof NoValidProposalChosenException));
- // Verify state machine quit properly
- assertNull(mIkeSessionStateMachine.getCurrentState());
- }
-
- private void mockSendRekeyChildReq() throws Exception {
- setupIdleStateMachine();
-
- ChildLocalRequest childLocalRequest =
- new ChildLocalRequest(
- IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_CHILD,
- mMockChildSessionCallback,
- null /*childOptions*/);
-
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_EXECUTE_LOCAL_REQ, childLocalRequest);
- mLooper.dispatchAll();
-
- assertTrue(
- mIkeSessionStateMachine.getCurrentState()
- instanceof IkeSessionStateMachine.ChildProcedureOngoing);
- verify(mMockChildSessionStateMachine).rekeyChildSession();
-
- // Mocking sending request
- mDummyChildSmCallback.onOutboundPayloadsReady(
- IkeHeader.EXCHANGE_TYPE_CREATE_CHILD_SA,
- false /*isResp*/,
- new LinkedList<>(),
- mMockChildSessionStateMachine);
- mLooper.dispatchAll();
- }
-
- private void mockRcvTempFail() throws Exception {
- ReceivedIkePacket resp =
- makeResponseWithErrorNotify(new IkeNotifyPayload(ERROR_TYPE_TEMPORARY_FAILURE));
-
- mIkeSessionStateMachine.sendMessage(IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, resp);
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_FORCE_TRANSITION, mIkeSessionStateMachine.mIdle);
- mLooper.dispatchAll();
- }
-
- @Test
- public void testTempFailureHandlerScheduleRetry() throws Exception {
- mockSendRekeyChildReq();
-
- // Mock sending TEMPORARY_FAILURE response
- mockRcvTempFail();
-
- // Move time forward to trigger retry
- mLooper.moveTimeForward(IkeSessionStateMachine.RETRY_INTERVAL_MS);
- mLooper.dispatchAll();
-
- // Verify that rekey is triggered again
- assertTrue(
- mIkeSessionStateMachine.getCurrentState()
- instanceof IkeSessionStateMachine.ChildProcedureOngoing);
- verify(mMockChildSessionStateMachine, times(2)).rekeyChildSession();
- }
-
- @Test
- public void testTempFailureHandlerTimeout() throws Exception {
- long currentTime = 0;
- int retryCnt = 0;
-
- mockSendRekeyChildReq();
-
- while (currentTime + RETRY_INTERVAL_MS < TEMP_FAILURE_RETRY_TIMEOUT_MS) {
- mockRcvTempFail();
-
- mLooper.moveTimeForward(RETRY_INTERVAL_MS);
- currentTime += RETRY_INTERVAL_MS;
- mLooper.dispatchAll();
-
- retryCnt++;
- verify(mMockChildSessionStateMachine, times(1 + retryCnt)).rekeyChildSession();
- }
-
- mLooper.moveTimeForward(RETRY_INTERVAL_MS);
- mLooper.dispatchAll();
-
- assertNull(mIkeSessionStateMachine.getCurrentState());
- verify(mMockIkeSessionCallback).onClosedExceptionally(any(IkeInternalException.class));
- }
-
- @Test
- public void testTempFailureHandlerCancelTimer() throws Exception {
- mockSendRekeyChildReq();
-
- // Mock sending TEMPORARY_FAILURE response
- mockRcvTempFail();
-
- // Move time forward to trigger retry
- mLooper.moveTimeForward(IkeSessionStateMachine.RETRY_INTERVAL_MS);
- mLooper.dispatchAll();
- verify(mMockChildSessionStateMachine, times(2)).rekeyChildSession();
-
- // Mock sending a valid response
- ReceivedIkePacket resp =
- makeDummyEncryptedReceivedIkePacketWithPayloadList(
- mSpyCurrentIkeSaRecord,
- EXCHANGE_TYPE_CREATE_CHILD_SA,
- true /*isResp*/,
- new LinkedList<>());
- mIkeSessionStateMachine.sendMessage(IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, resp);
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_FORCE_TRANSITION, mIkeSessionStateMachine.mIdle);
- mLooper.dispatchAll();
-
- // Move time forward
- mLooper.moveTimeForward(IkeSessionStateMachine.TEMP_FAILURE_RETRY_TIMEOUT_MS);
- mLooper.dispatchAll();
-
- // Validate IKE Session is not closed
- assertTrue(
- mIkeSessionStateMachine.getCurrentState() instanceof IkeSessionStateMachine.Idle);
- // Validate no more retry
- verify(mMockChildSessionStateMachine, times(2)).rekeyChildSession();
- }
-
- @Test
- public void testIdleReceiveRequestWithFatalError() throws Exception {
- setupIdleStateMachine();
-
- // Mock receiving packet with syntax error
- ReceivedIkePacket mockInvalidPacket =
- makeDummyReceivedIkePacketWithInvalidSyntax(
- mSpyCurrentIkeSaRecord,
- false /*isResp*/,
- IkeHeader.EXCHANGE_TYPE_CREATE_CHILD_SA);
- mIkeSessionStateMachine.sendMessage(CMD_RECEIVE_IKE_PACKET, mockInvalidPacket);
- mLooper.dispatchAll();
-
- // Verify Delete request was sent
- List<IkePayload> payloads = verifyOutInfoMsgHeaderAndGetPayloads(true /*isResp*/);
- assertEquals(1, payloads.size());
-
- IkePayload payload = payloads.get(0);
- assertEquals(IkePayload.PAYLOAD_TYPE_NOTIFY, payload.payloadType);
- assertEquals(ERROR_TYPE_INVALID_SYNTAX, ((IkeNotifyPayload) payload).notifyType);
-
- // Verify IKE Session is closed properly
- assertNull(mIkeSessionStateMachine.getCurrentState());
- verify(mMockIkeSessionCallback).onClosedExceptionally(any(InvalidSyntaxException.class));
- }
-
- @Test
- public void testHandlesInvalidRequest() throws Exception {
- setupIdleStateMachine();
-
- mIkeSessionStateMachine.sendMessage(
- IkeSessionStateMachine.CMD_FORCE_TRANSITION,
- mIkeSessionStateMachine.mChildProcedureOngoing);
-
- // Receive an IKE AUTH request
- ReceivedIkePacket request =
- makeDummyEncryptedReceivedIkePacketWithPayloadList(
- mSpyCurrentIkeSaRecord,
- IkeHeader.EXCHANGE_TYPE_IKE_AUTH,
- false /*isResp*/,
- new LinkedList<IkePayload>());
- mIkeSessionStateMachine.sendMessage(IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, request);
- mLooper.dispatchAll();
-
- // Verify error notification was sent
- List<IkePayload> ikePayloadList = verifyOutInfoMsgHeaderAndGetPayloads(true /*isResp*/);
- assertEquals(1, ikePayloadList.size());
- assertEquals(
- ERROR_TYPE_INVALID_SYNTAX, ((IkeNotifyPayload) ikePayloadList.get(0)).notifyType);
-
- // Verify IKE Session has quit
- assertNull(mIkeSessionStateMachine.getCurrentState());
- verify(mMockIkeSessionCallback).onClosedExceptionally(any(InvalidSyntaxException.class));
- }
-
- @Test
- public void testIdleHandlesUnprotectedPacket() throws Exception {
- setupIdleStateMachine();
-
- ReceivedIkePacket req =
- makeDummyReceivedIkePacketWithUnprotectedError(
- mSpyCurrentIkeSaRecord,
- false /*isResp*/,
- EXCHANGE_TYPE_INFORMATIONAL,
- mock(IkeException.class));
-
- mLooper.dispatchAll();
- assertTrue(
- mIkeSessionStateMachine.getCurrentState() instanceof IkeSessionStateMachine.Idle);
- }
-}
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
deleted file mode 100644
index 646b9d9a..00000000
--- a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/SaRecordTest.java
+++ /dev/null
@@ -1,336 +0,0 @@
-/*
- * Copyright (C) 2019 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;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.AdditionalMatchers.aryEq;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyObject;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.net.IpSecManager;
-import android.net.IpSecManager.SecurityParameterIndex;
-import android.net.IpSecManager.UdpEncapsulationSocket;
-import android.net.IpSecTransform;
-import android.net.ipsec.ike.SaProposal;
-
-import com.android.internal.net.TestUtils;
-import com.android.internal.net.ipsec.ike.IkeLocalRequestScheduler.ChildLocalRequest;
-import com.android.internal.net.ipsec.ike.IkeLocalRequestScheduler.LocalRequest;
-import com.android.internal.net.ipsec.ike.IkeSessionStateMachine.IkeSecurityParameterIndex;
-import com.android.internal.net.ipsec.ike.SaRecord.ChildSaRecord;
-import com.android.internal.net.ipsec.ike.SaRecord.ChildSaRecordConfig;
-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.SaRecordHelper;
-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;
-import com.android.internal.net.ipsec.ike.message.IkeMessage;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload.EncryptionTransform;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload.IntegrityTransform;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload.PrfTransform;
-import com.android.internal.net.ipsec.ike.testutils.MockIpSecTestUtils;
-import com.android.server.IpSecService;
-
-import libcore.net.InetAddressUtils;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-import java.net.Inet4Address;
-
-@RunWith(JUnit4.class)
-public final class SaRecordTest {
- private static final Inet4Address LOCAL_ADDRESS =
- (Inet4Address) (InetAddressUtils.parseNumericAddress("192.0.2.200"));
- private static final Inet4Address REMOTE_ADDRESS =
- (Inet4Address) (InetAddressUtils.parseNumericAddress("192.0.2.100"));
-
- 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 =
- "D83B20CC6A0932B2A7CEF26E4020ABAAB64F0C6A";
-
- private static final long IKE_INIT_SPI = 0x5F54BF6D8B48E6E1L;
- private static final long IKE_RESP_SPI = 0x909232B3D1EDCB5CL;
-
- private static final String IKE_NONCE_INIT_HEX_STRING =
- "C39B7F368F4681B89FA9B7BE6465ABD7C5F68B6ED5D3B4C72CB4240EB5C46412";
- private static final String IKE_NONCE_RESP_HEX_STRING =
- "9756112CA539F5C25ABACC7EE92B73091942A9C06950F98848F1AF1694C4DDFF";
-
- private static final String IKE_SHARED_DH_KEY_HEX_STRING =
- "C14155DEA40056BD9C76FB4819687B7A397582F4CD5AFF4B"
- + "8F441C56E0C08C84234147A0BA249A555835A048E3CA2980"
- + "7D057A61DD26EEFAD9AF9C01497005E52858E29FB42EB849"
- + "6731DF96A11CCE1F51137A9A1B900FA81AEE7898E373D4E4"
- + "8B899BBECA091314ECD4B6E412EF4B0FEF798F54735F3180"
- + "7424A318287F20E8";
-
- private static final String IKE_SKEYSEED_HEX_STRING =
- "8C42F3B1F5F81C7BAAC5F33E9A4F01987B2F9657";
- private static final String IKE_SK_D_HEX_STRING = "C86B56EFCF684DCC2877578AEF3137167FE0EBF6";
- private static final String IKE_SK_AUTH_INIT_HEX_STRING =
- "554FBF5A05B7F511E05A30CE23D874DB9EF55E51";
- private static final String IKE_SK_AUTH_RESP_HEX_STRING =
- "36D83420788337CA32ECAA46892C48808DCD58B1";
- private static final String IKE_SK_ENCR_INIT_HEX_STRING = "5CBFD33F75796C0188C4A3A546AEC4A1";
- private static final String IKE_SK_ENCR_RESP_HEX_STRING = "C33B35FCF29514CD9D8B4A695E1A816E";
- private static final String IKE_SK_PRF_INIT_HEX_STRING =
- "094787780EE466E2CB049FA327B43908BC57E485";
- private static final String IKE_SK_PRF_RESP_HEX_STRING =
- "A30E6B08BE56C0E6BFF4744143C75219299E1BEB";
- private static final String IKE_KEY_MAT =
- IKE_SK_D_HEX_STRING
- + IKE_SK_AUTH_INIT_HEX_STRING
- + IKE_SK_AUTH_RESP_HEX_STRING
- + IKE_SK_ENCR_INIT_HEX_STRING
- + IKE_SK_ENCR_RESP_HEX_STRING
- + IKE_SK_PRF_INIT_HEX_STRING
- + IKE_SK_PRF_RESP_HEX_STRING;
-
- private static final int IKE_AUTH_ALGO_KEY_LEN = 20;
- private static final int IKE_ENCR_ALGO_KEY_LEN = 16;
- private static final int IKE_PRF_KEY_LEN = 20;
- private static final int IKE_SK_D_KEY_LEN = IKE_PRF_KEY_LEN;
-
- private static final int FIRST_CHILD_INIT_SPI = 0x2ad4c0a2;
- private static final int FIRST_CHILD_RESP_SPI = 0xcae7019f;
-
- private static final String FIRST_CHILD_ENCR_INIT_HEX_STRING =
- "1B865CEA6E2C23973E8C5452ADC5CD7D";
- private static final String FIRST_CHILD_ENCR_RESP_HEX_STRING =
- "5E82FEDACC6DCB0756DDD7553907EBD1";
- private static final String FIRST_CHILD_AUTH_INIT_HEX_STRING =
- "A7A5A44F7EF4409657206C7DC52B7E692593B51E";
- private static final String FIRST_CHILD_AUTH_RESP_HEX_STRING =
- "CDE612189FD46DE870FAEC04F92B40B0BFDBD9E1";
- private static final String FIRST_CHILD_KEY_MAT =
- FIRST_CHILD_ENCR_INIT_HEX_STRING
- + FIRST_CHILD_AUTH_INIT_HEX_STRING
- + FIRST_CHILD_ENCR_RESP_HEX_STRING
- + FIRST_CHILD_AUTH_RESP_HEX_STRING;
-
- private static final int FIRST_CHILD_AUTH_ALGO_KEY_LEN = 20;
- private static final int FIRST_CHILD_ENCR_ALGO_KEY_LEN = 16;
-
- private IkeMacPrf mIkeHmacSha1Prf;
- private IkeMacIntegrity mHmacSha1IntegrityMac;
- private IkeCipher mAesCbcCipher;
-
- private LocalRequest mMockFutureRekeyIkeEvent;
- private ChildLocalRequest mMockFutureRekeyChildEvent;
-
- private SaRecordHelper mSaRecordHelper = new SaRecordHelper();
-
- @Before
- public void setUp() throws Exception {
- mIkeHmacSha1Prf =
- IkeMacPrf.create(
- new PrfTransform(SaProposal.PSEUDORANDOM_FUNCTION_HMAC_SHA1),
- IkeMessage.getSecurityProvider());
- mHmacSha1IntegrityMac =
- IkeMacIntegrity.create(
- new IntegrityTransform(SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96),
- IkeMessage.getSecurityProvider());
- mAesCbcCipher =
- IkeCipher.create(
- new EncryptionTransform(
- SaProposal.ENCRYPTION_ALGORITHM_AES_CBC,
- SaProposal.KEY_LEN_AES_128),
- IkeMessage.getSecurityProvider());
-
- mMockFutureRekeyIkeEvent = mock(LocalRequest.class);
- mMockFutureRekeyChildEvent = mock(ChildLocalRequest.class);
- }
-
- // Test generating keying material for making IKE SA.
- @Test
- public void testMakeIkeSaRecord() throws Exception {
- byte[] sKeySeed = TestUtils.hexStringToByteArray(IKE_SKEYSEED_HEX_STRING);
- byte[] nonceInit = TestUtils.hexStringToByteArray(IKE_NONCE_INIT_HEX_STRING);
- byte[] nonceResp = TestUtils.hexStringToByteArray(IKE_NONCE_RESP_HEX_STRING);
-
- IkeSecurityParameterIndex ikeInitSpi =
- IkeSecurityParameterIndex.allocateSecurityParameterIndex(
- LOCAL_ADDRESS, IKE_INIT_SPI);
- IkeSecurityParameterIndex ikeRespSpi =
- IkeSecurityParameterIndex.allocateSecurityParameterIndex(
- REMOTE_ADDRESS, IKE_RESP_SPI);
- IkeSaRecordConfig ikeSaRecordConfig =
- new IkeSaRecordConfig(
- ikeInitSpi,
- ikeRespSpi,
- mIkeHmacSha1Prf,
- IKE_AUTH_ALGO_KEY_LEN,
- IKE_ENCR_ALGO_KEY_LEN,
- true /*isLocalInit*/,
- mMockFutureRekeyIkeEvent);
-
- int keyMaterialLen =
- IKE_SK_D_KEY_LEN
- + IKE_AUTH_ALGO_KEY_LEN * 2
- + IKE_ENCR_ALGO_KEY_LEN * 2
- + IKE_PRF_KEY_LEN * 2;
-
- IkeSaRecord ikeSaRecord =
- mSaRecordHelper.makeIkeSaRecord(sKeySeed, nonceInit, nonceResp, ikeSaRecordConfig);
-
- assertTrue(ikeSaRecord.isLocalInit);
- assertEquals(IKE_INIT_SPI, ikeSaRecord.getInitiatorSpi());
- assertEquals(IKE_RESP_SPI, ikeSaRecord.getResponderSpi());
- assertArrayEquals(
- TestUtils.hexStringToByteArray(IKE_SK_D_HEX_STRING), ikeSaRecord.getSkD());
- assertArrayEquals(
- TestUtils.hexStringToByteArray(IKE_SK_AUTH_INIT_HEX_STRING),
- ikeSaRecord.getOutboundIntegrityKey());
- assertArrayEquals(
- TestUtils.hexStringToByteArray(IKE_SK_AUTH_RESP_HEX_STRING),
- ikeSaRecord.getInboundIntegrityKey());
- assertArrayEquals(
- TestUtils.hexStringToByteArray(IKE_SK_ENCR_INIT_HEX_STRING),
- ikeSaRecord.getOutboundEncryptionKey());
- assertArrayEquals(
- TestUtils.hexStringToByteArray(IKE_SK_ENCR_RESP_HEX_STRING),
- ikeSaRecord.getInboundDecryptionKey());
- assertArrayEquals(
- TestUtils.hexStringToByteArray(IKE_SK_PRF_INIT_HEX_STRING), ikeSaRecord.getSkPi());
- assertArrayEquals(
- TestUtils.hexStringToByteArray(IKE_SK_PRF_RESP_HEX_STRING), ikeSaRecord.getSkPr());
-
- ikeSaRecord.close();
-
- verify(mMockFutureRekeyIkeEvent).cancel();
- }
-
- // Test generating keying material and building IpSecTransform for making Child SA.
- @Test
- public void testMakeChildSaRecord() throws Exception {
- byte[] sharedKey = new byte[0];
- byte[] nonceInit = TestUtils.hexStringToByteArray(IKE_NONCE_INIT_HEX_STRING);
- byte[] nonceResp = TestUtils.hexStringToByteArray(IKE_NONCE_RESP_HEX_STRING);
-
- MockIpSecTestUtils mockIpSecTestUtils = MockIpSecTestUtils.setUpMockIpSec();
- IpSecManager ipSecManager = mockIpSecTestUtils.getIpSecManager();
- IpSecService mockIpSecService = mockIpSecTestUtils.getIpSecService();
- Context context = mockIpSecTestUtils.getContext();
-
- when(mockIpSecService.allocateSecurityParameterIndex(
- eq(LOCAL_ADDRESS.getHostAddress()), anyInt(), anyObject()))
- .thenReturn(MockIpSecTestUtils.buildDummyIpSecSpiResponse(FIRST_CHILD_INIT_SPI));
- when(mockIpSecService.allocateSecurityParameterIndex(
- eq(REMOTE_ADDRESS.getHostAddress()), anyInt(), anyObject()))
- .thenReturn(MockIpSecTestUtils.buildDummyIpSecSpiResponse(FIRST_CHILD_RESP_SPI));
-
- SecurityParameterIndex childInitSpi =
- ipSecManager.allocateSecurityParameterIndex(LOCAL_ADDRESS);
- SecurityParameterIndex childRespSpi =
- ipSecManager.allocateSecurityParameterIndex(REMOTE_ADDRESS);
-
- byte[] initAuthKey = TestUtils.hexStringToByteArray(FIRST_CHILD_AUTH_INIT_HEX_STRING);
- byte[] respAuthKey = TestUtils.hexStringToByteArray(FIRST_CHILD_AUTH_RESP_HEX_STRING);
- byte[] initEncryptionKey = TestUtils.hexStringToByteArray(FIRST_CHILD_ENCR_INIT_HEX_STRING);
- byte[] respEncryptionKey = TestUtils.hexStringToByteArray(FIRST_CHILD_ENCR_RESP_HEX_STRING);
-
- IIpSecTransformHelper mockIpSecHelper;
- mockIpSecHelper = mock(IIpSecTransformHelper.class);
- SaRecord.setIpSecTransformHelper(mockIpSecHelper);
-
- IpSecTransform mockInTransform = mock(IpSecTransform.class);
- IpSecTransform mockOutTransform = mock(IpSecTransform.class);
- UdpEncapsulationSocket mockUdpEncapSocket = mock(UdpEncapsulationSocket.class);
-
- when(mockIpSecHelper.makeIpSecTransform(
- eq(context),
- eq(LOCAL_ADDRESS),
- eq(mockUdpEncapSocket),
- eq(childRespSpi),
- eq(mHmacSha1IntegrityMac),
- eq(mAesCbcCipher),
- aryEq(initAuthKey),
- aryEq(initEncryptionKey),
- eq(false)))
- .thenReturn(mockOutTransform);
-
- when(mockIpSecHelper.makeIpSecTransform(
- eq(context),
- eq(REMOTE_ADDRESS),
- eq(mockUdpEncapSocket),
- eq(childInitSpi),
- eq(mHmacSha1IntegrityMac),
- eq(mAesCbcCipher),
- aryEq(respAuthKey),
- aryEq(respEncryptionKey),
- eq(false)))
- .thenReturn(mockInTransform);
-
- ChildSaRecordConfig childSaRecordConfig =
- new ChildSaRecordConfig(
- mockIpSecTestUtils.getContext(),
- childInitSpi,
- childRespSpi,
- LOCAL_ADDRESS,
- REMOTE_ADDRESS,
- mockUdpEncapSocket,
- mIkeHmacSha1Prf,
- mHmacSha1IntegrityMac,
- mAesCbcCipher,
- TestUtils.hexStringToByteArray(IKE_SK_D_HEX_STRING),
- false /*isTransport*/,
- true /*isLocalInit*/,
- mMockFutureRekeyChildEvent);
-
- ChildSaRecord childSaRecord =
- mSaRecordHelper.makeChildSaRecord(
- sharedKey, nonceInit, nonceResp, childSaRecordConfig);
-
- assertTrue(childSaRecord.isLocalInit);
- assertEquals(FIRST_CHILD_INIT_SPI, childSaRecord.getLocalSpi());
- assertEquals(FIRST_CHILD_RESP_SPI, childSaRecord.getRemoteSpi());
- assertEquals(mockInTransform, childSaRecord.getInboundIpSecTransform());
- assertEquals(mockOutTransform, childSaRecord.getOutboundIpSecTransform());
-
- assertArrayEquals(
- TestUtils.hexStringToByteArray(FIRST_CHILD_AUTH_INIT_HEX_STRING),
- childSaRecord.getOutboundIntegrityKey());
- assertArrayEquals(
- TestUtils.hexStringToByteArray(FIRST_CHILD_AUTH_RESP_HEX_STRING),
- childSaRecord.getInboundIntegrityKey());
- assertArrayEquals(
- TestUtils.hexStringToByteArray(FIRST_CHILD_ENCR_INIT_HEX_STRING),
- childSaRecord.getOutboundEncryptionKey());
- assertArrayEquals(
- TestUtils.hexStringToByteArray(FIRST_CHILD_ENCR_RESP_HEX_STRING),
- childSaRecord.getInboundDecryptionKey());
-
- childSaRecord.close();
- verify(mMockFutureRekeyChildEvent).cancel();
-
- SaRecord.setIpSecTransformHelper(new IpSecTransformHelper());
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/crypto/IkeCombinedModeCipherTest.java b/tests/iketests/src/java/com/android/internal/net/ipsec/ike/crypto/IkeCombinedModeCipherTest.java
deleted file mode 100644
index a3b2253e..00000000
--- a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/crypto/IkeCombinedModeCipherTest.java
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Copyright (C) 2019 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.crypto;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.net.IpSecAlgorithm;
-import android.net.ipsec.ike.SaProposal;
-
-import com.android.internal.net.TestUtils;
-import com.android.internal.net.ipsec.ike.message.IkeMessage;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload.EncryptionTransform;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-import java.util.Arrays;
-import java.util.Random;
-
-import javax.crypto.AEADBadTagException;
-
-@RunWith(JUnit4.class)
-public final class IkeCombinedModeCipherTest {
- private static final String IV = "fbd69d9de2dafc5e";
- private static final String ENCRYPTED_PADDED_DATA_WITH_CHECKSUM =
- "f4109834e9f3559758c05edf119917521b885f67f0d14ced43";
- private static final String UNENCRYPTED_PADDED_DATA = "000000080000400f00";
- private static final String ADDITIONAL_AUTH_DATA =
- "77c708b4523e39a471dc683c1d4f21362e202508000000060000004129000025";
- private static final String KEY =
- "7C04513660DEC572D896105254EF92608054F8E6EE19E79CE52AB8697B2B5F2C2AA90C29";
-
- private static final int AES_GCM_IV_LEN = 8;
- private static final int AES_GCM_16_CHECKSUM_LEN = 128;
-
- private IkeCombinedModeCipher mAesGcm16Cipher;
-
- private byte[] mAesGcmKey;
- private byte[] mIv;
- private byte[] mEncryptedPaddedDataWithChecksum;
- private byte[] mUnencryptedPaddedData;
- private byte[] mAdditionalAuthData;
-
- @Before
- public void setUp() {
- mAesGcm16Cipher =
- (IkeCombinedModeCipher)
- IkeCipher.create(
- new EncryptionTransform(
- SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_16,
- SaProposal.KEY_LEN_AES_256),
- IkeMessage.getSecurityProvider());
-
- mAesGcmKey = TestUtils.hexStringToByteArray(KEY);
- mIv = TestUtils.hexStringToByteArray(IV);
- mEncryptedPaddedDataWithChecksum =
- TestUtils.hexStringToByteArray(ENCRYPTED_PADDED_DATA_WITH_CHECKSUM);
- mUnencryptedPaddedData = TestUtils.hexStringToByteArray(UNENCRYPTED_PADDED_DATA);
- mAdditionalAuthData = TestUtils.hexStringToByteArray(ADDITIONAL_AUTH_DATA);
- }
-
- @Test
- public void testBuild() throws Exception {
- assertTrue(mAesGcm16Cipher.isAead());
- assertEquals(AES_GCM_IV_LEN, mAesGcm16Cipher.generateIv().length);
- }
-
- @Test
- public void testGenerateRandomIv() throws Exception {
- assertFalse(Arrays.equals(mAesGcm16Cipher.generateIv(), mAesGcm16Cipher.generateIv()));
- }
-
- @Test
- public void testEncrypt() throws Exception {
- byte[] calculatedData =
- mAesGcm16Cipher.encrypt(
- mUnencryptedPaddedData, mAdditionalAuthData, mAesGcmKey, mIv);
-
- assertArrayEquals(mEncryptedPaddedDataWithChecksum, calculatedData);
- }
-
- @Test
- public void testDecrypt() throws Exception {
- byte[] calculatedData =
- mAesGcm16Cipher.decrypt(
- mEncryptedPaddedDataWithChecksum, mAdditionalAuthData, mAesGcmKey, mIv);
-
- assertArrayEquals(mUnencryptedPaddedData, calculatedData);
- }
-
- @Test
- public void testEncryptWithWrongKeyLen() throws Exception {
- byte[] encryptionKey = TestUtils.hexStringToByteArray(KEY + "00");
-
- try {
- mAesGcm16Cipher.encrypt(
- mUnencryptedPaddedData, mAdditionalAuthData, encryptionKey, mIv);
- fail("Expected to fail because encryption key has wrong length.");
- } catch (IllegalArgumentException expected) {
-
- }
- }
-
- @Test
- public void testDecrypWithWrongKey() throws Exception {
- byte[] encryptionKey = new byte[mAesGcmKey.length];
- new Random().nextBytes(encryptionKey);
-
- try {
- mAesGcm16Cipher.decrypt(
- mEncryptedPaddedDataWithChecksum, mAdditionalAuthData, encryptionKey, mIv);
- fail("Expected to fail because decryption key is wrong");
- } catch (AEADBadTagException expected) {
-
- }
- }
-
- @Test
- public void testBuildIpSecAlgorithm() throws Exception {
- IpSecAlgorithm ipsecAlgorithm = mAesGcm16Cipher.buildIpSecAlgorithmWithKey(mAesGcmKey);
-
- IpSecAlgorithm expectedIpSecAlgorithm =
- new IpSecAlgorithm(
- IpSecAlgorithm.AUTH_CRYPT_AES_GCM, mAesGcmKey, AES_GCM_16_CHECKSUM_LEN);
-
- assertTrue(IpSecAlgorithm.equals(expectedIpSecAlgorithm, ipsecAlgorithm));
- }
-
- @Test
- public void buildIpSecAlgorithmWithInvalidKey() throws Exception {
- byte[] encryptionKey = TestUtils.hexStringToByteArray(KEY + "00");
-
- try {
- mAesGcm16Cipher.buildIpSecAlgorithmWithKey(encryptionKey);
- fail("Expected to fail because encryption key has wrong length.");
- } catch (IllegalArgumentException expected) {
-
- }
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/crypto/IkeMacIntegrityTest.java b/tests/iketests/src/java/com/android/internal/net/ipsec/ike/crypto/IkeMacIntegrityTest.java
deleted file mode 100644
index ed625660..00000000
--- a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/crypto/IkeMacIntegrityTest.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (C) 2019 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.crypto;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.net.IpSecAlgorithm;
-import android.net.ipsec.ike.SaProposal;
-
-import com.android.internal.net.TestUtils;
-import com.android.internal.net.ipsec.ike.message.IkeMessage;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload.IntegrityTransform;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-import java.util.Arrays;
-
-@RunWith(JUnit4.class)
-public final class IkeMacIntegrityTest {
- private static final String DATA_TO_AUTH_HEX_STRING =
- "5f54bf6d8b48e6e1909232b3d1edcb5c2e20230800000001000000ec"
- + "230000d0b9132b7bb9f658dfdc648e5017a6322a030c316c"
- + "e55f365760d46426ce5cfc78bd1ed9abff63eb9594c1bd58"
- + "46de333ecd3ea2b705d18293b130395300ba92a351041345"
- + "0a10525cea51b2753b4e92b081fd78d995659a98f742278f"
- + "f9b8fd3e21554865c15c79a5134d66b2744966089e416c60"
- + "a274e44a9a3f084eb02f3bdce1e7de9de8d9a62773ab563b"
- + "9a69ba1db03c752acb6136452b8a86c41addb4210d68c423"
- + "efed80e26edca5fa3fe5d0a5ca9375ce332c474b93fb1fa3"
- + "59eb4e81";
- private static final String INTEGRITY_KEY_HEX_STRING =
- "554fbf5a05b7f511e05a30ce23d874db9ef55e51";
- private static final String CHECKSUM_HEX_STRING = "ae6e0f22abdad69ba8007d50";
-
- private IkeMacIntegrity mHmacSha1IntegrityMac;
- private byte[] mHmacSha1IntegrityKey;
-
- private byte[] mDataToAuthenticate;
-
- @Before
- public void setUp() throws Exception {
- mHmacSha1IntegrityMac =
- IkeMacIntegrity.create(
- new IntegrityTransform(SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96),
- IkeMessage.getSecurityProvider());
- mHmacSha1IntegrityKey = TestUtils.hexStringToByteArray(INTEGRITY_KEY_HEX_STRING);
-
- mDataToAuthenticate = TestUtils.hexStringToByteArray(DATA_TO_AUTH_HEX_STRING);
- }
-
- @Test
- public void testGenerateChecksum() throws Exception {
- byte[] calculatedChecksum =
- mHmacSha1IntegrityMac.generateChecksum(mHmacSha1IntegrityKey, mDataToAuthenticate);
-
- byte[] expectedChecksum = TestUtils.hexStringToByteArray(CHECKSUM_HEX_STRING);
- assertArrayEquals(expectedChecksum, calculatedChecksum);
- }
-
- @Test
- public void testGenerateChecksumWithDifferentKey() throws Exception {
- byte[] integrityKey = mHmacSha1IntegrityKey.clone();
- integrityKey[0]++;
-
- byte[] calculatedChecksum =
- mHmacSha1IntegrityMac.generateChecksum(integrityKey, mDataToAuthenticate);
-
- byte[] expectedChecksum = TestUtils.hexStringToByteArray(CHECKSUM_HEX_STRING);
- assertFalse(Arrays.equals(expectedChecksum, calculatedChecksum));
- }
-
- @Test
- public void testGenerateChecksumWithInvalidKey() throws Exception {
- byte[] integrityKey = TestUtils.hexStringToByteArray(INTEGRITY_KEY_HEX_STRING + "0000");
-
- try {
- byte[] calculatedChecksum =
- mHmacSha1IntegrityMac.generateChecksum(integrityKey, mDataToAuthenticate);
- fail("Expected to fail due to invalid authentication key.");
- } catch (IllegalArgumentException expected) {
-
- }
- }
-
- @Test
- public void testBuildIpSecAlgorithm() throws Exception {
- IpSecAlgorithm ipsecAlgorithm =
- mHmacSha1IntegrityMac.buildIpSecAlgorithmWithKey(mHmacSha1IntegrityKey);
-
- IpSecAlgorithm expectedIpSecAlgorithm =
- new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA1, mHmacSha1IntegrityKey, 96);
-
- assertTrue(IpSecAlgorithm.equals(expectedIpSecAlgorithm, ipsecAlgorithm));
- }
-
- @Test
- public void buildIpSecAlgorithmWithInvalidKey() throws Exception {
- byte[] encryptionKey = TestUtils.hexStringToByteArray(INTEGRITY_KEY_HEX_STRING + "00");
-
- try {
- mHmacSha1IntegrityMac.buildIpSecAlgorithmWithKey(encryptionKey);
-
- fail("Expected to fail due to integrity key with wrong length.");
- } catch (IllegalArgumentException expected) {
-
- }
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/crypto/IkeNormalModeCipherTest.java b/tests/iketests/src/java/com/android/internal/net/ipsec/ike/crypto/IkeNormalModeCipherTest.java
deleted file mode 100644
index 3f3a0e10..00000000
--- a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/crypto/IkeNormalModeCipherTest.java
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Copyright (C) 2019 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.crypto;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.net.IpSecAlgorithm;
-import android.net.ipsec.ike.SaProposal;
-
-import com.android.internal.net.TestUtils;
-import com.android.internal.net.ipsec.ike.message.IkeMessage;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload.EncryptionTransform;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-import java.util.Arrays;
-
-import javax.crypto.IllegalBlockSizeException;
-
-@RunWith(JUnit4.class)
-public final class IkeNormalModeCipherTest {
- private static final String IKE_AUTH_INIT_REQUEST_IV = "b9132b7bb9f658dfdc648e5017a6322a";
- private static final String IKE_AUTH_INIT_REQUEST_ENCRYPT_PADDED_DATA =
- "030c316ce55f365760d46426ce5cfc78bd1ed9abff63eb9594c1bd58"
- + "46de333ecd3ea2b705d18293b130395300ba92a351041345"
- + "0a10525cea51b2753b4e92b081fd78d995659a98f742278f"
- + "f9b8fd3e21554865c15c79a5134d66b2744966089e416c60"
- + "a274e44a9a3f084eb02f3bdce1e7de9de8d9a62773ab563b"
- + "9a69ba1db03c752acb6136452b8a86c41addb4210d68c423"
- + "efed80e26edca5fa3fe5d0a5ca9375ce332c474b93fb1fa3"
- + "59eb4e81";
- private static final String IKE_AUTH_INIT_REQUEST_UNENCRYPTED_PADDED_DATA =
- "2400000c010000000a50500d2700000c010000000a505050"
- + "2100001c02000000df7c038aefaaa32d3f44b228b52a3327"
- + "44dfb2c12c00002c00000028010304032ad4c0a20300000c"
- + "0100000c800e008003000008030000020000000805000000"
- + "2d00001801000000070000100000ffff00000000ffffffff"
- + "2900001801000000070000100000ffff00000000ffffffff"
- + "29000008000040000000000c000040010000000100000000"
- + "000000000000000b";
-
- private static final String ENCR_KEY_FROM_INIT_TO_RESP = "5cbfd33f75796c0188c4a3a546aec4a1";
-
- private static final int AES_BLOCK_SIZE = 16;
-
- private IkeNormalModeCipher mAesCbcCipher;
- private byte[] mAesCbcKey;
-
- private byte[] mIv;
- private byte[] mEncryptedPaddedData;
- private byte[] mUnencryptedPaddedData;
-
- @Before
- public void setUp() throws Exception {
- mAesCbcCipher =
- (IkeNormalModeCipher)
- IkeCipher.create(
- new EncryptionTransform(
- SaProposal.ENCRYPTION_ALGORITHM_AES_CBC,
- SaProposal.KEY_LEN_AES_128),
- IkeMessage.getSecurityProvider());
- mAesCbcKey = TestUtils.hexStringToByteArray(ENCR_KEY_FROM_INIT_TO_RESP);
-
- mIv = TestUtils.hexStringToByteArray(IKE_AUTH_INIT_REQUEST_IV);
- mEncryptedPaddedData =
- TestUtils.hexStringToByteArray(IKE_AUTH_INIT_REQUEST_ENCRYPT_PADDED_DATA);
- mUnencryptedPaddedData =
- TestUtils.hexStringToByteArray(IKE_AUTH_INIT_REQUEST_UNENCRYPTED_PADDED_DATA);
- }
-
- @Test
- public void testBuild() throws Exception {
- assertFalse(mAesCbcCipher.isAead());
- assertEquals(AES_BLOCK_SIZE, mAesCbcCipher.getBlockSize());
- assertEquals(AES_BLOCK_SIZE, mAesCbcCipher.generateIv().length);
- }
-
- @Test
- public void testGenerateRandomIv() throws Exception {
- assertFalse(Arrays.equals(mAesCbcCipher.generateIv(), mAesCbcCipher.generateIv()));
- }
-
- @Test
- public void testEncryptWithNormalCipher() throws Exception {
- byte[] calculatedData = mAesCbcCipher.encrypt(mUnencryptedPaddedData, mAesCbcKey, mIv);
-
- assertArrayEquals(mEncryptedPaddedData, calculatedData);
- }
-
- @Test
- public void testDecryptWithNormalCipher() throws Exception {
- byte[] calculatedData = mAesCbcCipher.decrypt(mEncryptedPaddedData, mAesCbcKey, mIv);
- assertArrayEquals(mUnencryptedPaddedData, calculatedData);
- }
-
- @Test
- public void testEncryptWithWrongKey() throws Exception {
- byte[] encryptionKey = TestUtils.hexStringToByteArray(ENCR_KEY_FROM_INIT_TO_RESP + "00");
-
- try {
- mAesCbcCipher.encrypt(mEncryptedPaddedData, encryptionKey, mIv);
- fail("Expected to fail due to encryption key with wrong length.");
- } catch (IllegalArgumentException expected) {
-
- }
- }
-
- @Test
- public void testDecryptWithNormalCipherWithBadPad() throws Exception {
- byte[] dataToDecrypt =
- TestUtils.hexStringToByteArray(
- IKE_AUTH_INIT_REQUEST_UNENCRYPTED_PADDED_DATA + "00");
- try {
- mAesCbcCipher.decrypt(dataToDecrypt, mAesCbcKey, mIv);
- fail("Expected to fail when try to decrypt data with bad padding");
- } catch (IllegalBlockSizeException expected) {
-
- }
- }
-
- @Test
- public void testBuildIpSecAlgorithm() throws Exception {
- IpSecAlgorithm ipsecAlgorithm = mAesCbcCipher.buildIpSecAlgorithmWithKey(mAesCbcKey);
-
- IpSecAlgorithm expectedIpSecAlgorithm =
- new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, mAesCbcKey);
-
- assertTrue(IpSecAlgorithm.equals(expectedIpSecAlgorithm, ipsecAlgorithm));
- }
-
- @Test
- public void buildIpSecAlgorithmWithInvalidKey() throws Exception {
- byte[] encryptionKey = TestUtils.hexStringToByteArray(ENCR_KEY_FROM_INIT_TO_RESP + "00");
-
- try {
- mAesCbcCipher.buildIpSecAlgorithmWithKey(encryptionKey);
-
- fail("Expected to fail due to encryption key with wrong length.");
- } catch (IllegalArgumentException expected) {
-
- }
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeAuthDigitalSignPayloadTest.java b/tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeAuthDigitalSignPayloadTest.java
deleted file mode 100644
index 96921c30..00000000
--- a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeAuthDigitalSignPayloadTest.java
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright (C) 2019 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.message;
-
-import static com.android.internal.net.ipsec.ike.message.IkeAuthDigitalSignPayload.SIGNATURE_ALGO_RSA_SHA2_256;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.net.ipsec.ike.SaProposal;
-
-import com.android.internal.net.TestUtils;
-import com.android.internal.net.ipsec.ike.crypto.IkeMacPrf;
-import com.android.internal.net.ipsec.ike.exceptions.AuthenticationFailedException;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload.PrfTransform;
-import com.android.internal.net.ipsec.ike.testutils.CertUtils;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.security.PrivateKey;
-import java.security.cert.X509Certificate;
-
-public final class IkeAuthDigitalSignPayloadTest {
- // TODO: Build a RSA_SHA1 signature and add tests for it.
-
- // RSA_SHA2_256
- private static final String AUTH_PAYLOAD_BODY_GENERIC_DIGITAL_SIGN_HEX_STRING =
- "0e0000000f300d06092a864886f70d01010b05006f76af4150d653c5d4136b9f"
- + "69d905849bf075c563e6d14ccda42361ec3e7d12c72e2dece5711ea1d952f7b8"
- + "e12c5d982aa4efdaeac36a02b222aa96242cc424";
- private static final String SIGNATURE =
- "6f76af4150d653c5d4136b9f69d905849bf075c563e6d14ccda42361ec3e7d12"
- + "c72e2dece5711ea1d952f7b8e12c5d982aa4efdaeac36a02b222aa96242cc424";
-
- private static final String IKE_INIT_RESP_HEX_STRING =
- "02458497587b09d488d5b76480bce53d2120222000000000000001cc2200002c"
- + "00000028010100040300000801000003030000080300000203000008020000020"
- + "00000080400000e28000108000e000013d60e51c40922cb121e395bacbd627cdd"
- + "d3240baa4fcefd29f65f8dd37329d68d4fb4854f8b8f07cfb60900e276d99a396"
- + "1112ee866b5456cf588dc1092fd3bc19668fb8fa42872f51c0ee748bdb665dcbe"
- + "15ac454f6ed966149954dac5187638d1ab61869d97a4873c4733c48cbe3acc8a6"
- + "5cfea3ce83fd09fba174bf0ec56d73a0585859399e61c2c38e695841f8df8a511"
- + "aadd438f56634165ad9b88e858c1585f1bee646943b8a96f5397721079a127b87"
- + "fd286e8f869ae021ce82adf91fa360217ac32268b39b698bf06a4e89b8d0267af"
- + "1c5b979b6493adb10a0e14aa707309e914b8d377903e75cb13cffbfde9c26842f"
- + "b49a07a4497c9907d39515b290000244b8aed6297c09a5a0dda06c873f5573b34"
- + "886dd779e90c19beca3fc54ab3cae02900001c00004004d8e7cb9d1e689ae8c84"
- + "c5078355436f3347376ff2900001c0000400545bc3f2113770de91c769094f1bd"
- + "614534e765ea290000080000402e290000100000402f000100020003000400000"
- + "00800004014";
- private static final String NONCE_INIT_HEX_STRING =
- "a5dded450b5ffd2670f37954367fce28279a085c830a03358b10b0872c0578f9";
- private static final String ID_RESP_PAYLOAD_BODY_HEX_STRING = "01000000c0a82b8a";
- private static final String SKP_RESP_HEX_STRING = "8FE8EC3153EDE924C23D6630D3C992A494E2F256";
-
- private static final byte[] IKE_INIT_RESP_REQUEST =
- TestUtils.hexStringToByteArray(IKE_INIT_RESP_HEX_STRING);
- private static final byte[] NONCE_INIT_RESP =
- TestUtils.hexStringToByteArray(NONCE_INIT_HEX_STRING);
- private static final byte[] ID_RESP_PAYLOAD_BODY =
- TestUtils.hexStringToByteArray(ID_RESP_PAYLOAD_BODY_HEX_STRING);
- private static final byte[] PRF_RESP_KEY = TestUtils.hexStringToByteArray(SKP_RESP_HEX_STRING);
-
- private IkeMacPrf mIkeHmacSha1Prf;
-
- @Before
- public void setUp() throws Exception {
- mIkeHmacSha1Prf =
- IkeMacPrf.create(
- new PrfTransform(SaProposal.PSEUDORANDOM_FUNCTION_HMAC_SHA1),
- IkeMessage.getSecurityProvider());
- }
-
- @Test
- public void testDecodeGenericDigitalSignPayload() throws Exception {
- byte[] inputPacket =
- TestUtils.hexStringToByteArray(AUTH_PAYLOAD_BODY_GENERIC_DIGITAL_SIGN_HEX_STRING);
- IkeAuthPayload payload = IkeAuthPayload.getIkeAuthPayload(false, inputPacket);
-
- assertTrue(payload instanceof IkeAuthDigitalSignPayload);
- IkeAuthDigitalSignPayload dsPayload = (IkeAuthDigitalSignPayload) payload;
- assertEquals(SIGNATURE_ALGO_RSA_SHA2_256, dsPayload.signatureAlgoAndHash);
- assertArrayEquals(dsPayload.signature, TestUtils.hexStringToByteArray(SIGNATURE));
- }
-
- @Test
- public void testVerifyInboundSignature() throws Exception {
- byte[] inputPacket =
- TestUtils.hexStringToByteArray(AUTH_PAYLOAD_BODY_GENERIC_DIGITAL_SIGN_HEX_STRING);
- IkeAuthDigitalSignPayload payload =
- (IkeAuthDigitalSignPayload) IkeAuthPayload.getIkeAuthPayload(false, inputPacket);
-
- X509Certificate cert = CertUtils.createCertFromPemFile("end-cert-small.pem");
-
- payload.verifyInboundSignature(
- cert,
- IKE_INIT_RESP_REQUEST,
- NONCE_INIT_RESP,
- ID_RESP_PAYLOAD_BODY,
- mIkeHmacSha1Prf,
- PRF_RESP_KEY);
- }
-
- @Test
- public void testVerifyInboundSignatureFail() throws Exception {
- byte[] inputPacket =
- TestUtils.hexStringToByteArray(AUTH_PAYLOAD_BODY_GENERIC_DIGITAL_SIGN_HEX_STRING);
- IkeAuthDigitalSignPayload payload =
- (IkeAuthDigitalSignPayload) IkeAuthPayload.getIkeAuthPayload(false, inputPacket);
-
- assertArrayEquals(payload.signature, TestUtils.hexStringToByteArray(SIGNATURE));
- X509Certificate cert = CertUtils.createCertFromPemFile("end-cert-a.pem");
-
- try {
- payload.verifyInboundSignature(
- cert,
- IKE_INIT_RESP_REQUEST,
- NONCE_INIT_RESP,
- ID_RESP_PAYLOAD_BODY,
- mIkeHmacSha1Prf,
- PRF_RESP_KEY);
- fail("Expected to fail due to wrong certificate.");
- } catch (AuthenticationFailedException expected) {
- }
- }
-
- @Test
- public void testGenerateSignature() throws Exception {
- PrivateKey key = CertUtils.createRsaPrivateKeyFromKeyFile("end-cert-key-a.key");
-
- IkeAuthDigitalSignPayload authPayload =
- new IkeAuthDigitalSignPayload(
- SIGNATURE_ALGO_RSA_SHA2_256,
- key,
- IKE_INIT_RESP_REQUEST,
- NONCE_INIT_RESP,
- ID_RESP_PAYLOAD_BODY,
- mIkeHmacSha1Prf,
- PRF_RESP_KEY);
-
- assertEquals(SIGNATURE_ALGO_RSA_SHA2_256, authPayload.signatureAlgoAndHash);
- assertArrayEquals(authPayload.signature, TestUtils.hexStringToByteArray(SIGNATURE));
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeCertPayloadTest.java b/tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeCertPayloadTest.java
deleted file mode 100644
index 2bb72e33..00000000
--- a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeCertPayloadTest.java
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Copyright (C) 2019 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.message;
-
-import static org.junit.Assert.fail;
-
-import com.android.internal.net.ipsec.ike.exceptions.AuthenticationFailedException;
-import com.android.internal.net.ipsec.ike.testutils.CertUtils;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.security.cert.TrustAnchor;
-import java.security.cert.X509Certificate;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Set;
-
-public final class IkeCertPayloadTest {
- private X509Certificate mEndCertA;
- private X509Certificate mEndCertB;
- private X509Certificate mEndCertSmall;
-
- private X509Certificate mIntermediateCertBOne;
- private X509Certificate mIntermediateCertBTwo;
-
- private TrustAnchor mTrustAnchorA;
- private TrustAnchor mTrustAnchorB;
- private TrustAnchor mTrustAnchorSmall;
-
- @Before
- public void setUp() throws Exception {
- mEndCertA = CertUtils.createCertFromPemFile("end-cert-a.pem");
- mTrustAnchorA =
- new TrustAnchor(
- CertUtils.createCertFromPemFile("self-signed-ca-a.pem"),
- null /*nameConstraints*/);
-
- mEndCertB = CertUtils.createCertFromPemFile("end-cert-b.pem");
- mIntermediateCertBOne = CertUtils.createCertFromPemFile("intermediate-ca-b-one.pem");
- mIntermediateCertBTwo = CertUtils.createCertFromPemFile("intermediate-ca-b-two.pem");
- mTrustAnchorB =
- new TrustAnchor(
- CertUtils.createCertFromPemFile("self-signed-ca-b.pem"),
- null /*nameConstraints*/);
-
- mEndCertSmall = CertUtils.createCertFromPemFile("end-cert-small.pem");
- mTrustAnchorSmall =
- new TrustAnchor(
- CertUtils.createCertFromPemFile("self-signed-ca-small.pem"),
- null /*nameConstraints*/);
- }
-
- @Test
- public void testValidateCertsNoIntermediateCerts() throws Exception {
- List<X509Certificate> certList = new LinkedList<>();
- certList.add(mEndCertA);
-
- Set<TrustAnchor> trustAnchors = new HashSet<>();
- trustAnchors.add(mTrustAnchorA);
-
- IkeCertPayload.validateCertificates(mEndCertA, certList, null /*crlList*/, trustAnchors);
- }
-
- @Test
- public void testValidateCertsWithIntermediateCerts() throws Exception {
- List<X509Certificate> certList = new LinkedList<>();
-
- certList.add(mEndCertB);
- certList.add(mIntermediateCertBTwo);
- certList.add(mIntermediateCertBOne);
-
- Set<TrustAnchor> trustAnchors = new HashSet<>();
- trustAnchors.add(mTrustAnchorB);
-
- IkeCertPayload.validateCertificates(mEndCertB, certList, null /*crlList*/, trustAnchors);
- }
-
- @Test
- public void testValidateCertsWithMultiTrustAnchors() throws Exception {
- List<X509Certificate> certList = new LinkedList<>();
- certList.add(mEndCertA);
-
- Set<TrustAnchor> trustAnchors = new HashSet<>();
- trustAnchors.add(mTrustAnchorA);
- trustAnchors.add(mTrustAnchorB);
-
- IkeCertPayload.validateCertificates(mEndCertA, certList, null /*crlList*/, trustAnchors);
- }
-
- @Test
- public void testValidateCertsWithWrongTrustAnchor() throws Exception {
- List<X509Certificate> certList = new LinkedList<>();
- certList.add(mEndCertA);
-
- Set<TrustAnchor> trustAnchors = new HashSet<>();
- trustAnchors.add(mTrustAnchorB);
-
- try {
- IkeCertPayload.validateCertificates(
- mEndCertA, certList, null /*crlList*/, trustAnchors);
- fail("Expected to fail due to absence of valid trust anchor.");
- } catch (AuthenticationFailedException expected) {
- }
- }
-
- @Test
- public void testValidateCertsWithMissingIntermediateCerts() throws Exception {
- List<X509Certificate> certList = new LinkedList<>();
- certList.add(mEndCertB);
- certList.add(mIntermediateCertBOne);
-
- Set<TrustAnchor> trustAnchors = new HashSet<>();
- trustAnchors.add(mTrustAnchorB);
-
- try {
- IkeCertPayload.validateCertificates(
- mEndCertA, certList, null /*crlList*/, trustAnchors);
- fail("Expected to fail due to absence of intermediate certificate.");
- } catch (AuthenticationFailedException expected) {
- }
- }
-
- @Test
- public void testValidateCertsWithSmallSizeKey() throws Exception {
- List<X509Certificate> certList = new LinkedList<>();
- certList.add(mEndCertSmall);
-
- Set<TrustAnchor> trustAnchors = new HashSet<>();
- trustAnchors.add(mTrustAnchorSmall);
-
- try {
- IkeCertPayload.validateCertificates(
- mEndCertSmall, certList, null /*crlList*/, trustAnchors);
- fail("Expected to fail because certificates use small size key");
- } catch (AuthenticationFailedException expected) {
- }
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeConfigPayloadTest.java b/tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeConfigPayloadTest.java
deleted file mode 100644
index 9fc32229..00000000
--- a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeConfigPayloadTest.java
+++ /dev/null
@@ -1,631 +0,0 @@
-/*
- * Copyright (C) 2019 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.message;
-
-import static com.android.internal.net.ipsec.ike.message.IkeConfigPayload.CONFIG_ATTR_INTERNAL_IP4_ADDRESS;
-import static com.android.internal.net.ipsec.ike.message.IkeConfigPayload.CONFIG_ATTR_INTERNAL_IP4_DHCP;
-import static com.android.internal.net.ipsec.ike.message.IkeConfigPayload.CONFIG_ATTR_INTERNAL_IP4_DNS;
-import static com.android.internal.net.ipsec.ike.message.IkeConfigPayload.CONFIG_ATTR_INTERNAL_IP4_NETMASK;
-import static com.android.internal.net.ipsec.ike.message.IkeConfigPayload.CONFIG_ATTR_INTERNAL_IP4_SUBNET;
-import static com.android.internal.net.ipsec.ike.message.IkeConfigPayload.CONFIG_ATTR_INTERNAL_IP6_ADDRESS;
-import static com.android.internal.net.ipsec.ike.message.IkeConfigPayload.CONFIG_ATTR_INTERNAL_IP6_DNS;
-import static com.android.internal.net.ipsec.ike.message.IkeConfigPayload.CONFIG_ATTR_INTERNAL_IP6_SUBNET;
-import static com.android.internal.net.ipsec.ike.message.IkeConfigPayload.CONFIG_TYPE_REPLY;
-import static com.android.internal.net.ipsec.ike.message.IkeConfigPayload.CONFIG_TYPE_REQUEST;
-import static com.android.internal.net.ipsec.ike.message.IkePayload.PAYLOAD_TYPE_CP;
-import static com.android.internal.net.ipsec.ike.message.IkePayload.PAYLOAD_TYPE_NOTIFY;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import android.net.LinkAddress;
-
-import com.android.internal.net.TestUtils;
-import com.android.internal.net.ipsec.ike.exceptions.InvalidSyntaxException;
-import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttrIpv4AddressBase;
-import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttrIpv6AddrRangeBase;
-import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttribute;
-import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv4Address;
-import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv4Dhcp;
-import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv4Dns;
-import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv4Netmask;
-import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv4Subnet;
-import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv6Address;
-import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv6Dns;
-import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv6Subnet;
-
-import libcore.net.InetAddressUtils;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.nio.ByteBuffer;
-import java.util.LinkedList;
-import java.util.List;
-
-public final class IkeConfigPayloadTest {
- private static final String CONFIG_REQ_PAYLOAD_HEX =
- "2900001801000000000100000008000000030000000a0000";
- private static final String CONFIG_RESP_PAYLOAD_HEX =
- "210000200200000000010004c000026400030004080808080003000408080404";
- private static final String CONFIG_RESP_PAYLOAD_INVALID_ONE_HEX =
- "210000200200000000010004c000026400020004fffffffe00020004fffffffe";
- private static final String CONFIG_RESP_PAYLOAD_INVALID_TWO_HEX =
- "210000100200000000020004fffffffe";
-
- private static final byte[] CONFIG_REQ_PAYLOAD =
- TestUtils.hexStringToByteArray(CONFIG_REQ_PAYLOAD_HEX);
- private static final byte[] CONFIG_RESP_PAYLOAD =
- TestUtils.hexStringToByteArray(CONFIG_RESP_PAYLOAD_HEX);
-
- private static final Inet4Address IPV4_ADDRESS =
- (Inet4Address) (InetAddressUtils.parseNumericAddress("192.0.2.100"));
- private static final Inet4Address IPV4_NETMASK =
- (Inet4Address) (InetAddressUtils.parseNumericAddress("255.255.255.240"));
- private static final int IP4_PREFIX_LEN = 28;
- private static final LinkAddress IPV4_LINK_ADDRESS =
- new LinkAddress(IPV4_ADDRESS, IP4_PREFIX_LEN);
-
- private static final byte[] IPV4_ADDRESS_ATTRIBUTE_WITH_VALUE =
- TestUtils.hexStringToByteArray("00010004c0000264");
- private static final byte[] IPV4_ADDRESS_ATTRIBUTE_WITHOUT_VALUE =
- TestUtils.hexStringToByteArray("00010000");
-
- private static final byte[] IPV4_NETMASK_ATTRIBUTE_WITHOUT_VALUE =
- TestUtils.hexStringToByteArray("00020000");
-
- private static final Inet4Address IPV4_DNS =
- (Inet4Address) (InetAddressUtils.parseNumericAddress("8.8.8.8"));
- private static final byte[] IPV4_DNS_ATTRIBUTE_VALUE =
- TestUtils.hexStringToByteArray("08080808");
- private static final byte[] IPV4_DNS_ATTRIBUTE_WITHOUT_VALUE =
- TestUtils.hexStringToByteArray("00030000");
-
- private static final Inet4Address IPV4_DHCP =
- (Inet4Address) (InetAddressUtils.parseNumericAddress("192.0.2.200"));
- private static final byte[] IPV4_DHCP_ATTRIBUTE_WITH_VALUE =
- TestUtils.hexStringToByteArray("00060004c00002c8");
- private static final byte[] IPV4_DHCP_ATTRIBUTE_WITHOUT_VALUE =
- TestUtils.hexStringToByteArray("00060000");
-
- private static final byte[] IPV4_SUBNET_ATTRIBUTE_VALUE =
- TestUtils.hexStringToByteArray("c0000264fffffff0");
- private static final byte[] IPV4_SUBNET_ATTRIBUTE_WITH_VALUE =
- TestUtils.hexStringToByteArray("000d0008c0000264fffffff0");
- private static final byte[] IPV4_SUBNET_ATTRIBUTE_WITHOUT_VALUE =
- TestUtils.hexStringToByteArray("000d0000");
-
- private static final Inet6Address IPV6_ADDRESS =
- (Inet6Address) (InetAddressUtils.parseNumericAddress("2001:db8::1"));
- private static final int IP6_PREFIX_LEN = 64;
- private static final LinkAddress IPV6_LINK_ADDRESS =
- new LinkAddress(IPV6_ADDRESS, IP6_PREFIX_LEN);
-
- private static final byte[] IPV6_ADDRESS_ATTRIBUTE_VALUE =
- TestUtils.hexStringToByteArray("20010db800000000000000000000000140");
- private static final byte[] IPV6_ADDRESS_ATTRIBUTE_WITH_VALUE =
- TestUtils.hexStringToByteArray("0008001120010db800000000000000000000000140");
- private static final byte[] IPV6_ADDRESS_ATTRIBUTE_WITHOUT_VALUE =
- TestUtils.hexStringToByteArray("00080000");
-
- private static final byte[] IPV6_SUBNET_ATTRIBUTE_VALUE = IPV6_ADDRESS_ATTRIBUTE_VALUE;
- private static final byte[] IPV6_SUBNET_ATTRIBUTE_WITH_VALUE =
- TestUtils.hexStringToByteArray("000f001120010db800000000000000000000000140");
- private static final byte[] IPV6_SUBNET_ATTRIBUTE_WITHOUT_VALUE =
- TestUtils.hexStringToByteArray("000f0000");
-
- private static final Inet6Address IPV6_DNS =
- (Inet6Address) (InetAddressUtils.parseNumericAddress("2001:db8:100::1"));
- private static final byte[] IPV6_DNS_ATTRIBUTE_WITHOUT_VALUE =
- TestUtils.hexStringToByteArray("000a0000");
-
- private Inet4Address[] mNetMasks;
- private int[] mIpv4PrefixLens;
-
- @Before
- public void setUp() throws Exception {
- mNetMasks =
- new Inet4Address[] {
- (Inet4Address) (InetAddressUtils.parseNumericAddress("0.0.0.0")),
- (Inet4Address) (InetAddressUtils.parseNumericAddress("255.255.255.255")),
- (Inet4Address) (InetAddressUtils.parseNumericAddress("255.255.255.240"))
- };
- mIpv4PrefixLens = new int[] {0, 32, 28};
- }
-
- private IkeConfigPayload verifyDecodeHeaderAndGetPayload(
- IkePayload payload, int expectedConfigType) {
- assertEquals(PAYLOAD_TYPE_CP, payload.payloadType);
- assertFalse(payload.isCritical);
- assertTrue(payload instanceof IkeConfigPayload);
-
- IkeConfigPayload configPayload = (IkeConfigPayload) payload;
- assertEquals(expectedConfigType, configPayload.configType);
-
- return configPayload;
- }
-
- @Test
- public void testDecodeConfigRequest() throws Exception {
- IkePayload payload =
- IkePayloadFactory.getIkePayload(
- PAYLOAD_TYPE_CP,
- false /*isResp*/,
- ByteBuffer.wrap(CONFIG_REQ_PAYLOAD))
- .first;
-
- IkeConfigPayload configPayload =
- verifyDecodeHeaderAndGetPayload(payload, CONFIG_TYPE_REQUEST);
-
- List<ConfigAttribute> recognizedAttributeList = configPayload.recognizedAttributeList;
- assertEquals(4, recognizedAttributeList.size());
-
- ConfigAttribute att = recognizedAttributeList.get(0);
- assertEquals(CONFIG_ATTR_INTERNAL_IP4_ADDRESS, att.attributeType);
- assertNull(((ConfigAttributeIpv4Address) att).address);
-
- att = recognizedAttributeList.get(1);
- assertEquals(CONFIG_ATTR_INTERNAL_IP6_ADDRESS, att.attributeType);
- assertNull(((ConfigAttributeIpv6Address) att).linkAddress);
-
- att = recognizedAttributeList.get(2);
- assertEquals(CONFIG_ATTR_INTERNAL_IP4_DNS, att.attributeType);
- assertNull(((ConfigAttributeIpv4Dns) att).address);
-
- att = recognizedAttributeList.get(3);
- assertEquals(CONFIG_ATTR_INTERNAL_IP6_DNS, att.attributeType);
- assertNull(((ConfigAttributeIpv6Dns) att).address);
- }
-
- @Test
- public void testDecodeConfigResponse() throws Exception {
- IkePayload payload =
- IkePayloadFactory.getIkePayload(
- PAYLOAD_TYPE_CP,
- true /*isResp*/,
- ByteBuffer.wrap(CONFIG_RESP_PAYLOAD))
- .first;
-
- IkeConfigPayload configPayload =
- verifyDecodeHeaderAndGetPayload(payload, CONFIG_TYPE_REPLY);
-
- List<ConfigAttribute> recognizedAttributeList = configPayload.recognizedAttributeList;
- assertEquals(3, recognizedAttributeList.size());
-
- ConfigAttribute att = recognizedAttributeList.get(0);
- assertEquals(CONFIG_ATTR_INTERNAL_IP4_ADDRESS, att.attributeType);
- assertEquals(IPV4_ADDRESS, ((ConfigAttributeIpv4Address) att).address);
-
- att = recognizedAttributeList.get(1);
- assertEquals(CONFIG_ATTR_INTERNAL_IP4_DNS, att.attributeType);
- assertEquals(IPV4_DNS, ((ConfigAttributeIpv4Dns) att).address);
-
- att = recognizedAttributeList.get(2);
- InetAddress expectedDns = InetAddress.getByName("8.8.4.4");
- assertEquals(CONFIG_ATTR_INTERNAL_IP4_DNS, att.attributeType);
- assertEquals(expectedDns, ((ConfigAttributeIpv4Dns) att).address);
- }
-
- @Test
- public void testDecodeConfigRespWithTwoNetmask() throws Exception {
- byte[] configPayloadBytes =
- TestUtils.hexStringToByteArray(CONFIG_RESP_PAYLOAD_INVALID_ONE_HEX);
- try {
- IkePayloadFactory.getIkePayload(
- PAYLOAD_TYPE_CP, true /*isResp*/, ByteBuffer.wrap(configPayloadBytes));
- fail("Expected to fail because more than on netmask found");
- } catch (InvalidSyntaxException expected) {
- }
- }
-
- @Test
- public void testDecodeConfigRespNetmaskFoundWithoutIpv4Addr() throws Exception {
- byte[] configPayloadBytes =
- TestUtils.hexStringToByteArray(CONFIG_RESP_PAYLOAD_INVALID_TWO_HEX);
- try {
- IkePayloadFactory.getIkePayload(
- PAYLOAD_TYPE_CP, true /*isResp*/, ByteBuffer.wrap(configPayloadBytes));
- fail("Expected to fail because netmask is found without a IPv4 address");
- } catch (InvalidSyntaxException expected) {
- }
- }
-
- private ConfigAttribute makeMockAttribute(byte[] encodedAttribute) {
- ConfigAttribute mockAttribute = mock(ConfigAttribute.class);
-
- when(mockAttribute.getAttributeLen()).thenReturn(encodedAttribute.length);
-
- doAnswer(
- (invocation) -> {
- ByteBuffer buffer = (ByteBuffer) invocation.getArguments()[0];
- buffer.put(encodedAttribute);
- return null;
- })
- .when(mockAttribute)
- .encodeAttributeToByteBuffer(any(ByteBuffer.class));
-
- return mockAttribute;
- }
-
- @Test
- public void testBuildAndEncodeOutboundConfig() throws Exception {
- List<ConfigAttribute> mockAttributeList = new LinkedList<>();
- mockAttributeList.add(makeMockAttribute(IPV4_ADDRESS_ATTRIBUTE_WITHOUT_VALUE));
- mockAttributeList.add(makeMockAttribute(IPV6_ADDRESS_ATTRIBUTE_WITHOUT_VALUE));
- mockAttributeList.add(makeMockAttribute(IPV4_DNS_ATTRIBUTE_WITHOUT_VALUE));
- mockAttributeList.add(makeMockAttribute(IPV6_DNS_ATTRIBUTE_WITHOUT_VALUE));
- IkeConfigPayload configPayload = new IkeConfigPayload(false /*isReply*/, mockAttributeList);
-
- assertEquals(PAYLOAD_TYPE_CP, configPayload.payloadType);
- assertFalse(configPayload.isCritical);
- assertEquals(CONFIG_TYPE_REQUEST, configPayload.configType);
- assertEquals(mockAttributeList, configPayload.recognizedAttributeList);
-
- ByteBuffer buffer = ByteBuffer.allocate(configPayload.getPayloadLength());
- configPayload.encodeToByteBuffer(PAYLOAD_TYPE_NOTIFY, buffer);
- assertArrayEquals(CONFIG_REQ_PAYLOAD, buffer.array());
- }
-
- private void verifyBuildAndEncodeAttributeCommon(
- ConfigAttribute attribute, int expectedAttributeType, byte[] expectedEncodedAttribute) {
- assertEquals(expectedAttributeType, attribute.attributeType);
-
- ByteBuffer buffer = ByteBuffer.allocate(attribute.getAttributeLen());
- attribute.encodeAttributeToByteBuffer(buffer);
- assertArrayEquals(expectedEncodedAttribute, buffer.array());
- }
-
- private void verifyEncodeIpv4AddresBaseAttribute(
- ConfigAttrIpv4AddressBase attribute,
- int expectedAttributeType,
- byte[] expectedEncodedAttribute,
- Inet4Address expectedAddress) {
- verifyBuildAndEncodeAttributeCommon(
- attribute, expectedAttributeType, expectedEncodedAttribute);
- assertEquals(expectedAddress, attribute.address);
- }
-
- private void verifyEncodeIpv6RangeBaseAttribute(
- ConfigAttrIpv6AddrRangeBase attribute,
- int expectedAttributeType,
- byte[] expectedEncodedAttribute,
- LinkAddress expectedLinkAddress) {
- verifyBuildAndEncodeAttributeCommon(
- attribute, expectedAttributeType, expectedEncodedAttribute);
- assertEquals(expectedLinkAddress, attribute.linkAddress);
- }
-
- @Test
- public void testDecodeIpv4AddressWithValue() throws Exception {
- ConfigAttributeIpv4Address attributeIp4Address =
- new ConfigAttributeIpv4Address(IPV4_ADDRESS.getAddress());
-
- assertEquals(CONFIG_ATTR_INTERNAL_IP4_ADDRESS, attributeIp4Address.attributeType);
- assertEquals(IPV4_ADDRESS, attributeIp4Address.address);
- }
-
- @Test
- public void testDecodeIpv4AddressWithoutValue() throws Exception {
- ConfigAttributeIpv4Address attributeIp4Address =
- new ConfigAttributeIpv4Address(new byte[0]);
-
- assertEquals(CONFIG_ATTR_INTERNAL_IP4_ADDRESS, attributeIp4Address.attributeType);
- assertNull(attributeIp4Address.address);
- }
-
- @Test
- public void testDecodeIpv4AddressWithInvalidValue() throws Exception {
- byte[] invalidValue = new byte[] {1};
-
- try {
- ConfigAttributeIpv4Address attributeIp4Address =
- new ConfigAttributeIpv4Address(invalidValue);
- fail("Expected to fail due to invalid attribute value");
- } catch (InvalidSyntaxException expected) {
- }
- }
-
- @Test
- public void testEncodeIpv4AddressWithValue() throws Exception {
- ConfigAttributeIpv4Address attributeIp4Address =
- new ConfigAttributeIpv4Address(IPV4_ADDRESS);
-
- verifyEncodeIpv4AddresBaseAttribute(
- attributeIp4Address,
- CONFIG_ATTR_INTERNAL_IP4_ADDRESS,
- IPV4_ADDRESS_ATTRIBUTE_WITH_VALUE,
- IPV4_ADDRESS);
- }
-
- @Test
- public void testEncodeIpv4AddressWithoutValue() throws Exception {
- ConfigAttributeIpv4Address attributeIp4Address = new ConfigAttributeIpv4Address();
-
- verifyEncodeIpv4AddresBaseAttribute(
- attributeIp4Address,
- CONFIG_ATTR_INTERNAL_IP4_ADDRESS,
- IPV4_ADDRESS_ATTRIBUTE_WITHOUT_VALUE,
- null /*expectedAddress*/);
- }
-
- @Test
- public void testDecodeIpv4NetmaskWithValue() throws Exception {
- ConfigAttributeIpv4Netmask attribute =
- new ConfigAttributeIpv4Netmask(IPV4_NETMASK.getAddress());
-
- assertEquals(CONFIG_ATTR_INTERNAL_IP4_NETMASK, attribute.attributeType);
- assertEquals(IPV4_NETMASK, attribute.address);
- }
-
- @Test
- public void testDecodeIpv4NetmaskWithoutValue() throws Exception {
- ConfigAttributeIpv4Netmask attribute = new ConfigAttributeIpv4Netmask(new byte[0]);
-
- assertEquals(CONFIG_ATTR_INTERNAL_IP4_NETMASK, attribute.attributeType);
- assertNull(attribute.address);
- }
-
- @Test
- public void testEncodeIpv4Netmask() throws Exception {
- ConfigAttributeIpv4Netmask attribute = new ConfigAttributeIpv4Netmask();
-
- verifyEncodeIpv4AddresBaseAttribute(
- attribute,
- CONFIG_ATTR_INTERNAL_IP4_NETMASK,
- IPV4_NETMASK_ATTRIBUTE_WITHOUT_VALUE,
- null /*expectedAddress*/);
- }
-
- @Test
- public void testDecodeIpv4DnsWithValue() throws Exception {
- ConfigAttributeIpv4Dns attribute = new ConfigAttributeIpv4Dns(IPV4_DNS.getAddress());
-
- assertEquals(CONFIG_ATTR_INTERNAL_IP4_DNS, attribute.attributeType);
- assertEquals(IPV4_DNS, attribute.address);
- }
-
- @Test
- public void testDecodeIpv4DnsWithoutValue() throws Exception {
- ConfigAttributeIpv4Dns attribute = new ConfigAttributeIpv4Dns(new byte[0]);
-
- assertEquals(CONFIG_ATTR_INTERNAL_IP4_DNS, attribute.attributeType);
- assertNull(attribute.address);
- }
-
- @Test
- public void testEncodeIpv4Dns() throws Exception {
- ConfigAttributeIpv4Dns attribute = new ConfigAttributeIpv4Dns();
-
- verifyEncodeIpv4AddresBaseAttribute(
- attribute,
- CONFIG_ATTR_INTERNAL_IP4_DNS,
- IPV4_DNS_ATTRIBUTE_WITHOUT_VALUE,
- null /*expectedAddress*/);
- }
-
- @Test
- public void testDecodeIpv4DhcpWithValue() throws Exception {
- ConfigAttributeIpv4Dhcp attribute = new ConfigAttributeIpv4Dhcp(IPV4_DHCP.getAddress());
-
- assertEquals(CONFIG_ATTR_INTERNAL_IP4_DHCP, attribute.attributeType);
- assertEquals(IPV4_DHCP, attribute.address);
- }
-
- @Test
- public void testDecodeIpv4DhcpWithoutValue() throws Exception {
- ConfigAttributeIpv4Dhcp attribute = new ConfigAttributeIpv4Dhcp(new byte[0]);
-
- assertEquals(CONFIG_ATTR_INTERNAL_IP4_DHCP, attribute.attributeType);
- assertNull(attribute.address);
- }
-
- @Test
- public void testEncodeIpv4DhcpWithValue() throws Exception {
- ConfigAttributeIpv4Dhcp attributeIp4Dhcp = new ConfigAttributeIpv4Dhcp(IPV4_DHCP);
-
- verifyEncodeIpv4AddresBaseAttribute(
- attributeIp4Dhcp,
- CONFIG_ATTR_INTERNAL_IP4_DHCP,
- IPV4_DHCP_ATTRIBUTE_WITH_VALUE,
- IPV4_DHCP);
- }
-
- @Test
- public void testEncodeIpv4DhcpWithoutValue() throws Exception {
- ConfigAttributeIpv4Dhcp attribute = new ConfigAttributeIpv4Dhcp();
-
- verifyEncodeIpv4AddresBaseAttribute(
- attribute,
- CONFIG_ATTR_INTERNAL_IP4_DHCP,
- IPV4_DHCP_ATTRIBUTE_WITHOUT_VALUE,
- null /*expectedAddress*/);
- }
-
- @Test
- public void testDecodeIpv4SubnetWithValue() throws Exception {
- ConfigAttributeIpv4Subnet attributeIp4Subnet =
- new ConfigAttributeIpv4Subnet(IPV4_SUBNET_ATTRIBUTE_VALUE);
-
- assertEquals(CONFIG_ATTR_INTERNAL_IP4_SUBNET, attributeIp4Subnet.attributeType);
- assertEquals(IPV4_LINK_ADDRESS, attributeIp4Subnet.linkAddress);
- }
-
- @Test
- public void testDecodeIpv4SubnetWithoutValue() throws Exception {
- ConfigAttributeIpv4Subnet attributeIp4Subnet = new ConfigAttributeIpv4Subnet(new byte[0]);
-
- assertEquals(CONFIG_ATTR_INTERNAL_IP4_SUBNET, attributeIp4Subnet.attributeType);
- assertNull(attributeIp4Subnet.linkAddress);
- }
-
- @Test
- public void testDecodeIpv4SubnetWithInvalidValue() throws Exception {
- byte[] ipAddress = IPV4_ADDRESS.getAddress();
- ByteBuffer buffer = ByteBuffer.allocate(ipAddress.length * 2);
- buffer.put(ipAddress).put(ipAddress);
-
- try {
- new ConfigAttributeIpv4Subnet(buffer.array());
- fail("Expected to fail due to invalid netmask.");
- } catch (InvalidSyntaxException expected) {
- }
- }
-
- @Test
- public void testEncodeIpv4SubnetWithoutValue() throws Exception {
- ConfigAttributeIpv4Subnet attributeIp4Subnet = new ConfigAttributeIpv4Subnet();
-
- verifyBuildAndEncodeAttributeCommon(
- attributeIp4Subnet,
- CONFIG_ATTR_INTERNAL_IP4_SUBNET,
- IPV4_SUBNET_ATTRIBUTE_WITHOUT_VALUE);
- assertNull(attributeIp4Subnet.linkAddress);
- }
-
- @Test
- public void testNetmaskToPrefixLen() throws Exception {
- for (int i = 0; i < mNetMasks.length; i++) {
- assertEquals(mIpv4PrefixLens[i], ConfigAttribute.netmaskToPrefixLen(mNetMasks[i]));
- }
- }
-
- @Test
- public void testPrefixToNetmaskBytes() throws Exception {
- for (int i = 0; i < mIpv4PrefixLens.length; i++) {
- assertArrayEquals(
- mNetMasks[i].getAddress(),
- ConfigAttribute.prefixToNetmaskBytes(mIpv4PrefixLens[i]));
- }
- }
-
- @Test
- public void testDecodeIpv6AddressWithValue() throws Exception {
- ConfigAttributeIpv6Address attributeIp6Address =
- new ConfigAttributeIpv6Address(IPV6_ADDRESS_ATTRIBUTE_VALUE);
-
- assertEquals(CONFIG_ATTR_INTERNAL_IP6_ADDRESS, attributeIp6Address.attributeType);
- assertEquals(IPV6_LINK_ADDRESS, attributeIp6Address.linkAddress);
- }
-
- @Test
- public void testDecodeIpv6AddressWithoutValue() throws Exception {
- ConfigAttributeIpv6Address attributeIp6Address =
- new ConfigAttributeIpv6Address(new byte[0]);
-
- assertEquals(CONFIG_ATTR_INTERNAL_IP6_ADDRESS, attributeIp6Address.attributeType);
- assertNull(attributeIp6Address.linkAddress);
- }
-
- @Test
- public void testDecodeIpv6AddressWithInvalidValue() throws Exception {
- byte[] invalidValue = new byte[] {1};
-
- try {
- ConfigAttributeIpv6Address attributeIp6Address =
- new ConfigAttributeIpv6Address(invalidValue);
- fail("Expected to fail due to invalid attribute value");
- } catch (InvalidSyntaxException expected) {
- }
- }
-
- @Test
- public void testEncodeIpv6AddressWithValue() throws Exception {
- ConfigAttributeIpv6Address attributeIp6Address =
- new ConfigAttributeIpv6Address(IPV6_LINK_ADDRESS);
-
- verifyEncodeIpv6RangeBaseAttribute(
- attributeIp6Address,
- CONFIG_ATTR_INTERNAL_IP6_ADDRESS,
- IPV6_ADDRESS_ATTRIBUTE_WITH_VALUE,
- IPV6_LINK_ADDRESS);
- }
-
- @Test
- public void testEncodeIpv6AddressWithoutValue() throws Exception {
- ConfigAttributeIpv6Address attributeIp6Address = new ConfigAttributeIpv6Address();
-
- verifyEncodeIpv6RangeBaseAttribute(
- attributeIp6Address,
- CONFIG_ATTR_INTERNAL_IP6_ADDRESS,
- IPV6_ADDRESS_ATTRIBUTE_WITHOUT_VALUE,
- null /*expectedLinkAddress*/);
- }
-
- @Test
- public void testDecodeIpv6SubnetWithValue() throws Exception {
- ConfigAttributeIpv6Subnet attributeIp6Subnet =
- new ConfigAttributeIpv6Subnet(IPV6_SUBNET_ATTRIBUTE_VALUE);
-
- assertEquals(CONFIG_ATTR_INTERNAL_IP6_SUBNET, attributeIp6Subnet.attributeType);
- assertEquals(IPV6_LINK_ADDRESS, attributeIp6Subnet.linkAddress);
- }
-
- @Test
- public void testDecodeIpv6SubnetWithoutValue() throws Exception {
- ConfigAttributeIpv6Subnet attributeIp6Subnet = new ConfigAttributeIpv6Subnet(new byte[0]);
-
- assertEquals(CONFIG_ATTR_INTERNAL_IP6_SUBNET, attributeIp6Subnet.attributeType);
- assertNull(attributeIp6Subnet.linkAddress);
- }
-
- @Test
- public void testEncodeIpv6SubnetWithoutValue() throws Exception {
- ConfigAttributeIpv6Subnet attributeIp6Subnet = new ConfigAttributeIpv6Subnet();
-
- verifyEncodeIpv6RangeBaseAttribute(
- attributeIp6Subnet,
- CONFIG_ATTR_INTERNAL_IP6_SUBNET,
- IPV6_SUBNET_ATTRIBUTE_WITHOUT_VALUE,
- null /*expectedLinkAddress*/);
- }
-
- @Test
- public void testDecodeIpv6DnsWithValue() throws Exception {
- ConfigAttributeIpv6Dns attribute = new ConfigAttributeIpv6Dns(IPV6_DNS.getAddress());
-
- assertEquals(CONFIG_ATTR_INTERNAL_IP6_DNS, attribute.attributeType);
- assertEquals(IPV6_DNS, attribute.address);
- }
-
- @Test
- public void testDecodeIpv6DnsWithoutValue() throws Exception {
- ConfigAttributeIpv6Dns attribute = new ConfigAttributeIpv6Dns(new byte[0]);
-
- assertEquals(CONFIG_ATTR_INTERNAL_IP6_DNS, attribute.attributeType);
- assertNull(attribute.address);
- }
-
- @Test
- public void testEncodeIpv6Dns() throws Exception {
- ConfigAttributeIpv6Dns attribute = new ConfigAttributeIpv6Dns();
-
- verifyBuildAndEncodeAttributeCommon(
- attribute, CONFIG_ATTR_INTERNAL_IP6_DNS, IPV6_DNS_ATTRIBUTE_WITHOUT_VALUE);
- assertNull(attribute.address);
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeDeletePayloadTest.java b/tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeDeletePayloadTest.java
deleted file mode 100644
index 6be5336f..00000000
--- a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeDeletePayloadTest.java
+++ /dev/null
@@ -1,264 +0,0 @@
-/*
- * Copyright (C) 2019 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.message;
-
-import static com.android.internal.net.ipsec.ike.message.IkePayload.PROTOCOL_ID_ESP;
-import static com.android.internal.net.ipsec.ike.message.IkePayload.PROTOCOL_ID_IKE;
-import static com.android.internal.net.ipsec.ike.message.IkePayload.SPI_LEN_IPSEC;
-import static com.android.internal.net.ipsec.ike.message.IkePayload.SPI_LEN_NOT_INCLUDED;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import com.android.internal.net.TestUtils;
-import com.android.internal.net.ipsec.ike.exceptions.InvalidSyntaxException;
-
-import org.junit.Test;
-
-import java.nio.ByteBuffer;
-import java.util.Arrays;
-
-public final class IkeDeletePayloadTest {
- private static final String DELETE_IKE_PAYLOAD_HEX_STRING = "0000000801000000";
- private static final String DELETE_CHILD_PAYLOAD_HEX_STRING = "0000000c030400012ad4c0a2";
- private static final String CHILD_SPI = "2ad4c0a2";
-
- private static final String DELETE_MULTIPLE_CHILD_PAYLOAD_HEX_STRING =
- "0000001003040002abcdef0120fedcba";
- private static final String[] MULTIPLE_CHILD_SPIS = new String[] {"abcdef01", "20fedcba"};
-
- private static final int NUM_CHILD_SPI = 1;
-
- private static final int PROTOCOL_ID_OFFSET = 4;
- private static final int SPI_SIZE_OFFSET = 5;
- private static final int NUM_OF_SPI_OFFSET = 6;
-
- @Test
- public void testDecodeDeleteIkePayload() throws Exception {
- ByteBuffer inputBuffer =
- ByteBuffer.wrap(TestUtils.hexStringToByteArray(DELETE_IKE_PAYLOAD_HEX_STRING));
-
- IkePayload payload =
- IkePayloadFactory.getIkePayload(
- IkePayload.PAYLOAD_TYPE_DELETE, false /*is request*/, inputBuffer)
- .first;
-
- assertTrue(payload instanceof IkeDeletePayload);
-
- IkeDeletePayload deletePayload = (IkeDeletePayload) payload;
- assertEquals(IkePayload.PROTOCOL_ID_IKE, deletePayload.protocolId);
- assertEquals(IkePayload.SPI_LEN_NOT_INCLUDED, deletePayload.spiSize);
- assertEquals(0, deletePayload.numSpi);
- assertArrayEquals(new int[0], deletePayload.spisToDelete);
- }
-
- @Test
- public void testDecodeDeleteChildPayload() throws Exception {
- ByteBuffer inputBuffer =
- ByteBuffer.wrap(TestUtils.hexStringToByteArray(DELETE_CHILD_PAYLOAD_HEX_STRING));
-
- IkePayload payload =
- IkePayloadFactory.getIkePayload(
- IkePayload.PAYLOAD_TYPE_DELETE, false /*is request*/, inputBuffer)
- .first;
-
- assertTrue(payload instanceof IkeDeletePayload);
-
- IkeDeletePayload deletePayload = (IkeDeletePayload) payload;
- assertEquals(IkePayload.PROTOCOL_ID_ESP, deletePayload.protocolId);
- assertEquals(IkePayload.SPI_LEN_IPSEC, deletePayload.spiSize);
- assertEquals(NUM_CHILD_SPI, deletePayload.numSpi);
-
- int expectedChildSpi = TestUtils.hexStringToInt(CHILD_SPI);
- assertArrayEquals(new int[] {expectedChildSpi}, deletePayload.spisToDelete);
- }
-
- @Test
- public void testDecodeWithInvalidProtocol() throws Exception {
- byte[] deletePayloadBytes = TestUtils.hexStringToByteArray(DELETE_IKE_PAYLOAD_HEX_STRING);
- deletePayloadBytes[PROTOCOL_ID_OFFSET] = -1;
- ByteBuffer inputBuffer = ByteBuffer.wrap(deletePayloadBytes);
-
- try {
- IkePayloadFactory.getIkePayload(
- IkePayload.PAYLOAD_TYPE_DELETE, false /*is request*/, inputBuffer);
- fail("Expected to fail due to unrecognized protocol ID.");
- } catch (InvalidSyntaxException expected) {
-
- }
- }
-
- @Test
- public void testDecodeWithInvalidSpiSize() throws Exception {
- byte[] deletePayloadBytes = TestUtils.hexStringToByteArray(DELETE_IKE_PAYLOAD_HEX_STRING);
- deletePayloadBytes[SPI_SIZE_OFFSET] = IkePayload.SPI_LEN_IPSEC;
- ByteBuffer inputBuffer = ByteBuffer.wrap(deletePayloadBytes);
-
- try {
- IkePayloadFactory.getIkePayload(
- IkePayload.PAYLOAD_TYPE_DELETE, false /*is request*/, inputBuffer);
- fail("Expected to fail due to invalid SPI size in Delete IKE Payload.");
- } catch (InvalidSyntaxException expected) {
-
- }
- }
-
- @Test
- public void testDecodeWithInvalidNumSpi() throws Exception {
- byte[] deletePayloadBytes = TestUtils.hexStringToByteArray(DELETE_IKE_PAYLOAD_HEX_STRING);
- deletePayloadBytes[NUM_OF_SPI_OFFSET] = 1;
- ByteBuffer inputBuffer = ByteBuffer.wrap(deletePayloadBytes);
-
- try {
- IkePayloadFactory.getIkePayload(
- IkePayload.PAYLOAD_TYPE_DELETE, false /*is request*/, inputBuffer);
- fail("Expected to fail because number of SPI is not zero in Delete IKE Payload.");
- } catch (InvalidSyntaxException expected) {
-
- }
- }
-
- @Test
- public void testDecodeWithInvalidNumSpiAndSpiSize() throws Exception {
- byte[] deletePayloadBytes = TestUtils.hexStringToByteArray(DELETE_IKE_PAYLOAD_HEX_STRING);
- deletePayloadBytes[SPI_SIZE_OFFSET] = 1;
- deletePayloadBytes[NUM_CHILD_SPI] = 4;
- ByteBuffer inputBuffer = ByteBuffer.wrap(deletePayloadBytes);
-
- try {
- IkePayloadFactory.getIkePayload(
- IkePayload.PAYLOAD_TYPE_DELETE, false /*is request*/, inputBuffer);
- fail("Expected to fail due to invalid SPI size in Delete IKE Payload.");
- } catch (InvalidSyntaxException expected) {
-
- }
- }
-
- @Test
- public void testOutboundConstructorForIke() throws Exception {
- IkeDeletePayload deletePayload = new IkeDeletePayload();
-
- assertEquals(PROTOCOL_ID_IKE, deletePayload.protocolId);
- assertEquals(SPI_LEN_NOT_INCLUDED, deletePayload.spiSize);
- assertEquals(0, deletePayload.numSpi);
- assertEquals(0, deletePayload.spisToDelete.length);
- }
-
- @Test
- public void testOutboundConstructorWithSingleChildSa() throws Exception {
- int[] childSpis = new int[] {TestUtils.hexStringToInt(CHILD_SPI)};
- IkeDeletePayload deletePayload = new IkeDeletePayload(childSpis);
-
- assertEquals(PROTOCOL_ID_ESP, deletePayload.protocolId);
- assertEquals(SPI_LEN_IPSEC, deletePayload.spiSize);
- assertEquals(NUM_CHILD_SPI, deletePayload.numSpi);
- assertArrayEquals(childSpis, deletePayload.spisToDelete);
- }
-
- @Test
- public void testOutboundConstructorWithMultipleChildSas() throws Exception {
- int[] childSpis = new int[] {0x1, 0x2, 0xfffffffd, 0xffffffff};
- IkeDeletePayload deletePayload = new IkeDeletePayload(childSpis);
-
- assertEquals(PROTOCOL_ID_ESP, deletePayload.protocolId);
- assertEquals(SPI_LEN_IPSEC, deletePayload.spiSize);
- assertEquals(childSpis.length, deletePayload.numSpi);
- assertArrayEquals(childSpis, deletePayload.spisToDelete);
- }
-
- @Test
- public void testOutboundConstructorWithNoChildSas() throws Exception {
- try {
- IkeDeletePayload deletePayload = new IkeDeletePayload(new int[] {});
- fail("Expected exception for invalid SPI list");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void testEncodeForIke() throws Exception {
- IkeDeletePayload deletePayload = new IkeDeletePayload();
- ByteBuffer bb = ByteBuffer.allocate(deletePayload.getPayloadLength());
-
- deletePayload.encodeToByteBuffer(IkePayload.PAYLOAD_TYPE_NO_NEXT, bb);
-
- byte[] expectedPayloadBytes = TestUtils.hexStringToByteArray(DELETE_IKE_PAYLOAD_HEX_STRING);
- assertArrayEquals(expectedPayloadBytes, bb.array());
- }
-
- @Test
- public void testEncodeWithSingleChildSa() throws Exception {
- int[] childSpis = new int[] {TestUtils.hexStringToInt(CHILD_SPI)};
- IkeDeletePayload deletePayload = new IkeDeletePayload(childSpis);
- ByteBuffer bb = ByteBuffer.allocate(deletePayload.getPayloadLength());
-
- deletePayload.encodeToByteBuffer(IkePayload.PAYLOAD_TYPE_NO_NEXT, bb);
-
- byte[] expectedPayloadBytes =
- TestUtils.hexStringToByteArray(DELETE_CHILD_PAYLOAD_HEX_STRING);
- assertArrayEquals(expectedPayloadBytes, bb.array());
- }
-
- @Test
- public void testEncodeWithMultipleChildSas() throws Exception {
- int[] childSpis =
- Arrays.stream(MULTIPLE_CHILD_SPIS)
- .mapToInt(val -> TestUtils.hexStringToInt(val))
- .toArray();
- IkeDeletePayload deletePayload = new IkeDeletePayload(childSpis);
- ByteBuffer bb = ByteBuffer.allocate(deletePayload.getPayloadLength());
-
- deletePayload.encodeToByteBuffer(IkePayload.PAYLOAD_TYPE_NO_NEXT, bb);
-
- byte[] expectedPayloadBytes =
- TestUtils.hexStringToByteArray(DELETE_MULTIPLE_CHILD_PAYLOAD_HEX_STRING);
- assertArrayEquals(expectedPayloadBytes, bb.array());
- }
-
- @Test
- public void testPayloadLengthForIke() throws Exception {
- IkeDeletePayload deletePayload = new IkeDeletePayload();
-
- byte[] expectedPayloadBytes = TestUtils.hexStringToByteArray(DELETE_IKE_PAYLOAD_HEX_STRING);
- assertEquals(expectedPayloadBytes.length, deletePayload.getPayloadLength());
- }
-
- @Test
- public void testPayloadLengthWithSingleChildSa() throws Exception {
- int[] childSpis = new int[] {TestUtils.hexStringToInt(CHILD_SPI)};
- IkeDeletePayload deletePayload = new IkeDeletePayload(childSpis);
-
- byte[] expectedPayloadBytes =
- TestUtils.hexStringToByteArray(DELETE_CHILD_PAYLOAD_HEX_STRING);
- assertEquals(expectedPayloadBytes.length, deletePayload.getPayloadLength());
- }
-
- @Test
- public void testPayloadLengthWithMultipleChildSas() throws Exception {
- int[] childSpis =
- Arrays.stream(MULTIPLE_CHILD_SPIS)
- .mapToInt(val -> TestUtils.hexStringToInt(val))
- .toArray();
- IkeDeletePayload deletePayload = new IkeDeletePayload(childSpis);
-
- byte[] expectedPayloadBytes =
- TestUtils.hexStringToByteArray(DELETE_MULTIPLE_CHILD_PAYLOAD_HEX_STRING);
- assertEquals(expectedPayloadBytes.length, deletePayload.getPayloadLength());
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeEapPayloadTest.java b/tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeEapPayloadTest.java
deleted file mode 100644
index fff82b60..00000000
--- a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeEapPayloadTest.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2018 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.message;
-
-import static com.android.internal.net.TestUtils.hexStringToByteArray;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import org.junit.Test;
-
-import java.nio.ByteBuffer;
-
-public class IkeEapPayloadTest {
- private static final String EAP_SUCCESS_STRING = "03010004";
- private static final byte[] EAP_SUCCESS_PACKET = hexStringToByteArray(EAP_SUCCESS_STRING);
-
- private static final byte[] IKE_EAP_PAYLOAD =
- hexStringToByteArray(
- "00000008" + EAP_SUCCESS_STRING);
-
- @Test
- public void testDecodeIkeEapPayload() throws Exception {
- ByteBuffer input = ByteBuffer.wrap(IKE_EAP_PAYLOAD);
- IkePayload result = IkePayloadFactory
- .getIkePayload(IkePayload.PAYLOAD_TYPE_EAP, true, input).first;
-
- assertTrue(result instanceof IkeEapPayload);
- IkeEapPayload ikeEapPayload = (IkeEapPayload) result;
- assertArrayEquals(EAP_SUCCESS_PACKET, ikeEapPayload.eapMessage);
- }
-
- @Test
- public void testEncodeToByteBuffer() {
- IkeEapPayload ikeEapPayload = new IkeEapPayload(EAP_SUCCESS_PACKET);
- ByteBuffer result = ByteBuffer.allocate(IKE_EAP_PAYLOAD.length);
-
- ikeEapPayload.encodeToByteBuffer(IkePayload.PAYLOAD_TYPE_NO_NEXT, result);
- assertArrayEquals(IKE_EAP_PAYLOAD, result.array());
- }
-
- @Test
- public void testOutboundConstructorForIke() {
- IkeEapPayload ikeEapPayload = new IkeEapPayload(EAP_SUCCESS_PACKET);
- assertArrayEquals(EAP_SUCCESS_PACKET, ikeEapPayload.eapMessage);
- }
-
- @Test
- public void testGetPayloadLength() {
- IkeEapPayload ikeEapPayload = new IkeEapPayload(EAP_SUCCESS_PACKET);
- assertEquals(IKE_EAP_PAYLOAD.length, ikeEapPayload.getPayloadLength());
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeEncryptedPayloadBodyTest.java b/tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeEncryptedPayloadBodyTest.java
deleted file mode 100644
index 36c7648a..00000000
--- a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeEncryptedPayloadBodyTest.java
+++ /dev/null
@@ -1,489 +0,0 @@
-/*
- * Copyright (C) 2019 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.message;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-
-import android.net.ipsec.ike.SaProposal;
-
-import com.android.internal.net.TestUtils;
-import com.android.internal.net.ipsec.ike.crypto.IkeCipher;
-import com.android.internal.net.ipsec.ike.crypto.IkeCombinedModeCipher;
-import com.android.internal.net.ipsec.ike.crypto.IkeMacIntegrity;
-import com.android.internal.net.ipsec.ike.crypto.IkeNormalModeCipher;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload.EncryptionTransform;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload.IntegrityTransform;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.security.GeneralSecurityException;
-import java.util.Arrays;
-
-public final class IkeEncryptedPayloadBodyTest {
- private static final String IKE_AUTH_INIT_REQUEST_HEADER =
- "5f54bf6d8b48e6e1909232b3d1edcb5c2e20230800000001000000ec";
- private static final String IKE_AUTH_INIT_REQUEST_SK_HEADER = "230000d0";
- private static final String IKE_AUTH_INIT_REQUEST_IV = "b9132b7bb9f658dfdc648e5017a6322a";
- private static final String IKE_AUTH_INIT_REQUEST_ENCRYPT_PADDED_DATA =
- "030c316ce55f365760d46426ce5cfc78bd1ed9abff63eb9594c1bd58"
- + "46de333ecd3ea2b705d18293b130395300ba92a351041345"
- + "0a10525cea51b2753b4e92b081fd78d995659a98f742278f"
- + "f9b8fd3e21554865c15c79a5134d66b2744966089e416c60"
- + "a274e44a9a3f084eb02f3bdce1e7de9de8d9a62773ab563b"
- + "9a69ba1db03c752acb6136452b8a86c41addb4210d68c423"
- + "efed80e26edca5fa3fe5d0a5ca9375ce332c474b93fb1fa3"
- + "59eb4e81";
- private static final String IKE_AUTH_INIT_REQUEST_CHECKSUM = "ae6e0f22abdad69ba8007d50";
-
- private static final String IKE_AUTH_INIT_REQUEST_UNENCRYPTED_DATA =
- "2400000c010000000a50500d2700000c010000000a505050"
- + "2100001c02000000df7c038aefaaa32d3f44b228b52a3327"
- + "44dfb2c12c00002c00000028010304032ad4c0a20300000c"
- + "0100000c800e008003000008030000020000000805000000"
- + "2d00001801000000070000100000ffff00000000ffffffff"
- + "2900001801000000070000100000ffff00000000ffffffff"
- + "29000008000040000000000c0000400100000001";
- private static final String IKE_AUTH_INIT_REQUEST_PADDING = "0000000000000000000000";
- private static final int HMAC_SHA1_CHECKSUM_LEN = 12;
-
- private static final String ENCR_KEY_FROM_INIT_TO_RESP = "5cbfd33f75796c0188c4a3a546aec4a1";
- private static final String INTE_KEY_FROM_INIT_TO_RESP =
- "554fbf5a05b7f511e05a30ce23d874db9ef55e51";
-
- private static final String ENCR_ALGO_AES_CBC = "AES/CBC/NoPadding";
-
- // Test vectors for IKE message protected by HmacSha1 and 3DES
- private static final String HMAC_SHA1_3DES_MSG_HEX_STRING =
- "5837b1bd28ec424f85ddd0c609c8dbfe2e20232000000002"
- + "00000064300000488beaf41d88544baabd95eac60269f19a"
- + "5986295fe318ce02f65368cd957985f36b183794c4c78d35"
- + "437762297a131a773d7f7806aaa0c590f48b9d71001f4d65"
- + "70a44533";
-
- private static final String HMAC_SHA1_3DES_DECRYPTED_BODY_HEX_STRING =
- "00000028013c00241a013c001f10dac4f8b759138776091dd0f00033c5b07374726f6e675377616e";
-
- private static final String HMAC_SHA1_3DES_MSG_ENCR_KEY =
- "ee0fdd6d35bbdbe9eeef2f24495b6632e5047bdd8e413c87";
- private static final String HMAC_SHA1_3DES_MSG_INTE_KEY =
- "867a0bd019108db856cf6984fc9fb62d70c0de74";
-
- // TODO: b/142753861 Test IKE fragment protected by AES_CBC instead of 3DES
-
- // Test vectors for IKE fragment protected by HmacSha1 and 3DES
- private static final String HMAC_SHA1_3DES_FRAG_HEX_STRING =
- "939ae1251d18eb9077a99551b15c6e933520232000000001"
- + "000000c0000000a400050005fd7c7931705af184b7be76bb"
- + "d45a8ecbb3ffd58b9438b93f67e9fe86b06229f80e9b52d2"
- + "ff6afde3f2c13ae93ce55a801f62e1a818c9003880a36bbe"
- + "986fe6979ba233b9f4f0ddc992d06dbad5a2b998be18fae9"
- + "47e5ccfb37775d069344e711fbf499bb289cf4cca245bd45"
- + "0ad89d18689207759507ba18d47247e920b9e000a25a7596"
- + "e4130929e5cdc37d5c1b0d90bbaae946c260f4d3cf815f6d";
- private static final String HMAC_SHA1_3DES_FRAG_DECRYPTED_BODY_HEX_STRING =
- "54ebd95c572100002002000000000100040a0a0a01000300"
- + "040808080800030004080804042c00002c00000028020304"
- + "03cc86090a0300000c0100000c800e010003000008030000"
- + "0200000008050000002d00001801000000070000100000ff"
- + "ff0a0a0a010a0a0a010000001801000000070000100000ff"
- + "ff00000000ffffffff";
- private static final String HMAC_SHA1_3DES_FRAG_IV = "fd7c7931705af184";
- private static final String HMAC_SHA1_3DES_FRAG_PADDING = "dcf0fa5e2b64";
-
- private static final int HMAC_SHA1_3DES_FRAGMENT_NUM = 5;
- private static final int HMAC_SHA1_3DES_TOTAL_FRAGMENTS = 5;
-
- private static final String HMAC_SHA1_3DES_FRAG_ENCR_KEY =
- "6BBF6CB3526D6492F4DA0AF45E9B9FD3E1FF534280352073";
- private static final String HMAC_SHA1_3DES_FRAG_INTE_KEY =
- "293449E8E518060780B9C06F15838A06EEF57814";
-
- // Test vectors for IKE message protected by AES_GCM_16
- private static final String AES_GCM_MSG_HEX_STRING =
- "77c708b4523e39a471dc683c1d4f21362e20230800000005"
- + "0000006127000045fbd69d9ee2dafc5e7c03a0106761065b2"
- + "8fa8d11aed6046f7f8af117e44da7635be6e0dfafcb0a387c"
- + "53fb46ba5d6fa9509161915929de97b7fbe23dc65723b0fe";
- private static final String AES_GCM_MSG_DECRYPTED_BODY_HEX_STRING =
- "000000280200000033233837e909ec805d56151bef5b1fa9b8e25b32419c9b3fc96ee699ec29d501";
- private static final String AES_GCM_MSG_IV = "fbd69d9ee2dafc5e";
- private static final String AES_GCM_MSG_ENCR_KEY =
- "7C04513660DEC572D896105254EF92608054F8E6EE19E79CE52AB8697B2B5F2C2AA90C29";
-
- // Test vectors for IKE fragment protected by AES_GCM_16
- private static final String AES_GCM_FRAG_HEX_STRING =
- "77c708b4523e39a471dc683c1d4f213635202320000000010"
- + "0000113000000f7000200026faf9e5c04c67571871681d443"
- + "01489f99fd78d318b0517a5a99bf6a3e1770f43d7d997c9e0"
- + "d186038d16df3fd525eda821f80b3a40fc6bce397ac67539e"
- + "40042919a5e9af38c70881d092a8571f0e131f594c0e8d6b8"
- + "4ea116f0c95619439b0a267b35bc47dac72bbfb3d3776feb3"
- + "86d7d4f819b0248f52f60bf4371ab6384e37819a9685c27d8"
- + "e41abe30cd6f60905dd5c05c351ec0a1fcf9b99360161d2f3"
- + "4dcf6401829df9392121d88e2201d279200e25d750678af6a"
- + "7f4892a5c8d4a7358ec50cdf12cfa7652488f756ba6d07441"
- + "e9a27aad3976ac8a705ff796857cb2df9ce360c3992e0285b"
- + "34834255b06";
- private static final String AES_GCM_FRAG_DECRYPTED_BODY_HEX_STRING =
- "0fce6e996f4936ec8db8097339c371c686be75f4bed3f259c"
- + "14d39c3ad90cb864085c6375f75b724d9f9daa8e7b22a106a"
- + "488bc48c081997b7416fd33b146882e51ff6a640edf760212"
- + "7f2454d502e92262ba3dd07cff52ee1bb1ea85f582db41a68"
- + "aaf6dace362e5d8b10cfeb65eebc7572690e2c415a11cae57"
- + "020810cf7aa56d9f2d5c2be3a633f8e4c6af5483a2b1f05bd"
- + "4340ab551ddf7f51def57eaf5a37793ff6aa1e1ec288a2adf"
- + "a647c369f15efa61a619966a320f24e1765c0e00c5ed394aa"
- + "ef14512032b005827c000000090100000501";
- private static final String AES_GCM_FRAG_IV = "6faf9e5c04c67571";
-
- private static final int AES_GCM_FRAGMENT_NUM = 2;
- private static final int AES_GCM_TOTAL_FRAGMENTS = 2;
-
- private static final String AES_GCM_FRAG_ENCR_KEY =
- "955ED949D6F18857220E97B17D9285C830A39F8D4DC46AB43943668093C62A3D66664F8C";
-
- private static final int ENCRYPTED_BODY_SK_OFFSET =
- IkeHeader.IKE_HEADER_LENGTH + IkePayload.GENERIC_HEADER_LENGTH;
- private static final int ENCRYPTED_BODY_SKF_OFFSET =
- ENCRYPTED_BODY_SK_OFFSET + IkeSkfPayload.SKF_HEADER_LEN;
-
- private IkeNormalModeCipher mAesCbcCipher;
- private byte[] mAesCbcKey;
-
- private IkeMacIntegrity mHmacSha1IntegrityMac;
- private byte[] mHmacSha1IntegrityKey;
-
- private byte[] mDataToPadAndEncrypt;
- private byte[] mDataToAuthenticate;
- private byte[] mEncryptedPaddedData;
- private byte[] mIkeMessage;
-
- private byte[] mChecksum;
- private byte[] mIv;
- private byte[] mPadding;
-
- private IkeNormalModeCipher m3DesCipher;
-
- private IkeCombinedModeCipher mAesGcm16Cipher;
-
- private byte[] mAesGcmMsgKey;
- private byte[] mAesGcmMsg;
- private byte[] mAesGcmUnencryptedData;
-
- private byte[] mAesGcmFragKey;
- private byte[] mAesGcmFragMsg;
- private byte[] mAesGcmFragUnencryptedData;
-
- @Before
- public void setUp() throws Exception {
- mDataToPadAndEncrypt =
- TestUtils.hexStringToByteArray(IKE_AUTH_INIT_REQUEST_UNENCRYPTED_DATA);
- String hexStringToAuthenticate =
- IKE_AUTH_INIT_REQUEST_HEADER
- + IKE_AUTH_INIT_REQUEST_SK_HEADER
- + IKE_AUTH_INIT_REQUEST_IV
- + IKE_AUTH_INIT_REQUEST_ENCRYPT_PADDED_DATA;
- mDataToAuthenticate = TestUtils.hexStringToByteArray(hexStringToAuthenticate);
- mEncryptedPaddedData =
- TestUtils.hexStringToByteArray(IKE_AUTH_INIT_REQUEST_ENCRYPT_PADDED_DATA);
- mIkeMessage =
- TestUtils.hexStringToByteArray(
- IKE_AUTH_INIT_REQUEST_HEADER
- + IKE_AUTH_INIT_REQUEST_SK_HEADER
- + IKE_AUTH_INIT_REQUEST_IV
- + IKE_AUTH_INIT_REQUEST_ENCRYPT_PADDED_DATA
- + IKE_AUTH_INIT_REQUEST_CHECKSUM);
-
- mChecksum = TestUtils.hexStringToByteArray(IKE_AUTH_INIT_REQUEST_CHECKSUM);
- mIv = TestUtils.hexStringToByteArray(IKE_AUTH_INIT_REQUEST_IV);
- mPadding = TestUtils.hexStringToByteArray(IKE_AUTH_INIT_REQUEST_PADDING);
-
- m3DesCipher =
- (IkeNormalModeCipher)
- IkeCipher.create(
- new EncryptionTransform(SaProposal.ENCRYPTION_ALGORITHM_3DES),
- IkeMessage.getSecurityProvider());
-
- mAesCbcCipher =
- (IkeNormalModeCipher)
- IkeCipher.create(
- new EncryptionTransform(
- SaProposal.ENCRYPTION_ALGORITHM_AES_CBC,
- SaProposal.KEY_LEN_AES_128),
- IkeMessage.getSecurityProvider());
- mAesCbcKey = TestUtils.hexStringToByteArray(ENCR_KEY_FROM_INIT_TO_RESP);
-
- mHmacSha1IntegrityMac =
- IkeMacIntegrity.create(
- new IntegrityTransform(SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96),
- IkeMessage.getSecurityProvider());
- mHmacSha1IntegrityKey = TestUtils.hexStringToByteArray(INTE_KEY_FROM_INIT_TO_RESP);
-
- mAesGcm16Cipher =
- (IkeCombinedModeCipher)
- IkeCipher.create(
- new EncryptionTransform(
- SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_16,
- SaProposal.KEY_LEN_AES_256),
- IkeMessage.getSecurityProvider());
-
- mAesGcmMsgKey = TestUtils.hexStringToByteArray(AES_GCM_MSG_ENCR_KEY);
- mAesGcmMsg = TestUtils.hexStringToByteArray(AES_GCM_MSG_HEX_STRING);
- mAesGcmUnencryptedData =
- TestUtils.hexStringToByteArray(AES_GCM_MSG_DECRYPTED_BODY_HEX_STRING);
-
- mAesGcmFragKey = TestUtils.hexStringToByteArray(AES_GCM_FRAG_ENCR_KEY);
- mAesGcmFragMsg = TestUtils.hexStringToByteArray(AES_GCM_FRAG_HEX_STRING);
- mAesGcmFragUnencryptedData =
- TestUtils.hexStringToByteArray(AES_GCM_FRAG_DECRYPTED_BODY_HEX_STRING);
- }
-
- @Test
- public void testValidateChecksum() throws Exception {
- IkeEncryptedPayloadBody.validateInboundChecksumOrThrow(
- mDataToAuthenticate, mHmacSha1IntegrityMac, mHmacSha1IntegrityKey, mChecksum);
- }
-
- @Test
- public void testThrowForInvalidChecksum() throws Exception {
- byte[] dataToAuthenticate = Arrays.copyOf(mDataToAuthenticate, mDataToAuthenticate.length);
- dataToAuthenticate[0]++;
-
- try {
- IkeEncryptedPayloadBody.validateInboundChecksumOrThrow(
- dataToAuthenticate, mHmacSha1IntegrityMac, mHmacSha1IntegrityKey, mChecksum);
- fail("Expected GeneralSecurityException due to mismatched checksum.");
- } catch (GeneralSecurityException expected) {
- }
- }
-
- @Test
- public void testCalculatePaddingPlaintextShorterThanBlockSize() throws Exception {
- int blockSize = 16;
- int plainTextLength = 15;
- int expectedPadLength = 0;
-
- byte[] calculatedPadding =
- IkeEncryptedPayloadBody.calculatePadding(plainTextLength, blockSize);
- assertEquals(expectedPadLength, calculatedPadding.length);
- }
-
- @Test
- public void testCalculatePaddingPlaintextInBlockSize() throws Exception {
- int blockSize = 16;
- int plainTextLength = 16;
- int expectedPadLength = 15;
-
- byte[] calculatedPadding =
- IkeEncryptedPayloadBody.calculatePadding(plainTextLength, blockSize);
- assertEquals(expectedPadLength, calculatedPadding.length);
- }
-
- @Test
- public void testCalculatePaddingPlaintextLongerThanBlockSize() throws Exception {
- int blockSize = 16;
- int plainTextLength = 17;
- int expectedPadLength = 14;
-
- byte[] calculatedPadding =
- IkeEncryptedPayloadBody.calculatePadding(plainTextLength, blockSize);
- assertEquals(expectedPadLength, calculatedPadding.length);
- }
-
- @Test
- public void testEncrypt() throws Exception {
- byte[] calculatedData =
- IkeEncryptedPayloadBody.normalModeEncrypt(
- mDataToPadAndEncrypt, mAesCbcCipher, mAesCbcKey, mIv, mPadding);
-
- assertArrayEquals(mEncryptedPaddedData, calculatedData);
- }
-
- @Test
- public void testDecrypt() throws Exception {
- byte[] calculatedPlainText =
- IkeEncryptedPayloadBody.normalModeDecrypt(
- mEncryptedPaddedData, mAesCbcCipher, mAesCbcKey, mIv);
-
- assertArrayEquals(mDataToPadAndEncrypt, calculatedPlainText);
- }
-
- @Test
- public void testBuildAndEncodeOutboundIkeEncryptedPayloadBody() throws Exception {
- IkeHeader ikeHeader = new IkeHeader(mIkeMessage);
-
- IkeEncryptedPayloadBody payloadBody =
- new IkeEncryptedPayloadBody(
- ikeHeader,
- IkePayload.PAYLOAD_TYPE_ID_INITIATOR,
- new byte[0] /*skfHeader*/,
- mDataToPadAndEncrypt,
- mHmacSha1IntegrityMac,
- mAesCbcCipher,
- mHmacSha1IntegrityKey,
- mAesCbcKey,
- mIv,
- mPadding);
-
- byte[] expectedEncodedData =
- TestUtils.hexStringToByteArray(
- IKE_AUTH_INIT_REQUEST_IV
- + IKE_AUTH_INIT_REQUEST_ENCRYPT_PADDED_DATA
- + IKE_AUTH_INIT_REQUEST_CHECKSUM);
- assertArrayEquals(expectedEncodedData, payloadBody.encode());
- }
-
- @Test
- public void testAuthAndDecodeHmacSha1AesCbc() throws Exception {
- IkeEncryptedPayloadBody payloadBody =
- new IkeEncryptedPayloadBody(
- mIkeMessage,
- ENCRYPTED_BODY_SK_OFFSET,
- mHmacSha1IntegrityMac,
- mAesCbcCipher,
- mHmacSha1IntegrityKey,
- mAesCbcKey);
-
- assertArrayEquals(mDataToPadAndEncrypt, payloadBody.getUnencryptedData());
- }
-
- @Test
- public void testAuthAndDecodeHmacSha13Des() throws Exception {
- byte[] message = TestUtils.hexStringToByteArray(HMAC_SHA1_3DES_MSG_HEX_STRING);
- byte[] expectedDecryptedData =
- TestUtils.hexStringToByteArray(HMAC_SHA1_3DES_DECRYPTED_BODY_HEX_STRING);
-
- IkeEncryptedPayloadBody payloadBody =
- new IkeEncryptedPayloadBody(
- message,
- ENCRYPTED_BODY_SK_OFFSET,
- mHmacSha1IntegrityMac,
- m3DesCipher,
- TestUtils.hexStringToByteArray(HMAC_SHA1_3DES_MSG_INTE_KEY),
- TestUtils.hexStringToByteArray(HMAC_SHA1_3DES_MSG_ENCR_KEY));
-
- assertArrayEquals(expectedDecryptedData, payloadBody.getUnencryptedData());
- }
-
- @Test
- public void testBuildAndEncodeWithHmacSha13Des() throws Exception {
- byte[] message = TestUtils.hexStringToByteArray(HMAC_SHA1_3DES_FRAG_HEX_STRING);
- IkeHeader ikeHeader = new IkeHeader(message);
-
- byte[] skfHeaderBytes =
- IkeSkfPayload.encodeSkfHeader(
- HMAC_SHA1_3DES_FRAGMENT_NUM, HMAC_SHA1_3DES_TOTAL_FRAGMENTS);
-
- IkeEncryptedPayloadBody payloadBody =
- new IkeEncryptedPayloadBody(
- ikeHeader,
- IkePayload.PAYLOAD_TYPE_NO_NEXT,
- skfHeaderBytes,
- TestUtils.hexStringToByteArray(
- HMAC_SHA1_3DES_FRAG_DECRYPTED_BODY_HEX_STRING),
- mHmacSha1IntegrityMac,
- m3DesCipher,
- TestUtils.hexStringToByteArray(HMAC_SHA1_3DES_FRAG_INTE_KEY),
- TestUtils.hexStringToByteArray(HMAC_SHA1_3DES_FRAG_ENCR_KEY),
- TestUtils.hexStringToByteArray(HMAC_SHA1_3DES_FRAG_IV),
- TestUtils.hexStringToByteArray(HMAC_SHA1_3DES_FRAG_PADDING));
-
- byte[] expectedEncodedData =
- Arrays.copyOfRange(message, ENCRYPTED_BODY_SKF_OFFSET, message.length);
-
- assertArrayEquals(expectedEncodedData, payloadBody.encode());
- }
-
- @Test
- public void testAuthAndDecodeFullMsgWithAesGcm() throws Exception {
- IkeEncryptedPayloadBody encryptedBody =
- new IkeEncryptedPayloadBody(
- mAesGcmMsg,
- ENCRYPTED_BODY_SK_OFFSET,
- null /*integrityMac*/,
- mAesGcm16Cipher,
- null /*integrityKey*/,
- mAesGcmMsgKey);
-
- assertArrayEquals(mAesGcmUnencryptedData, encryptedBody.getUnencryptedData());
- }
-
- @Test
- public void testBuildAndEncodeMsgWithAesGcm() throws Exception {
- IkeHeader ikeHeader = new IkeHeader(mAesGcmMsg);
-
- IkeEncryptedPayloadBody payloadBody =
- new IkeEncryptedPayloadBody(
- ikeHeader,
- IkePayload.PAYLOAD_TYPE_AUTH,
- new byte[0],
- mAesGcmUnencryptedData,
- null /*integrityMac*/,
- mAesGcm16Cipher,
- null /*integrityKey*/,
- mAesGcmMsgKey,
- TestUtils.hexStringToByteArray(AES_GCM_MSG_IV),
- new byte[0] /*padding*/);
-
- byte[] expectedEncodedData =
- Arrays.copyOfRange(mAesGcmMsg, ENCRYPTED_BODY_SK_OFFSET, mAesGcmMsg.length);
-
- assertArrayEquals(expectedEncodedData, payloadBody.encode());
- }
-
- @Test
- public void testAuthAndDecodeFragMsgWithAesGcm() throws Exception {
- IkeEncryptedPayloadBody encryptedBody =
- new IkeEncryptedPayloadBody(
- mAesGcmFragMsg,
- ENCRYPTED_BODY_SKF_OFFSET,
- null /*integrityMac*/,
- mAesGcm16Cipher,
- null /*integrityKey*/,
- mAesGcmFragKey);
-
- assertArrayEquals(mAesGcmFragUnencryptedData, encryptedBody.getUnencryptedData());
- }
-
- @Test
- public void testBuildAndEncodeFragMsgWithAesGcm() throws Exception {
- IkeHeader ikeHeader = new IkeHeader(mAesGcmFragMsg);
- byte[] skfHeaderBytes =
- IkeSkfPayload.encodeSkfHeader(AES_GCM_FRAGMENT_NUM, AES_GCM_TOTAL_FRAGMENTS);
-
- IkeEncryptedPayloadBody payloadBody =
- new IkeEncryptedPayloadBody(
- ikeHeader,
- IkePayload.PAYLOAD_TYPE_NO_NEXT,
- skfHeaderBytes,
- mAesGcmFragUnencryptedData,
- null /*integrityMac*/,
- mAesGcm16Cipher,
- null /*integrityKey*/,
- mAesGcmFragKey,
- TestUtils.hexStringToByteArray(AES_GCM_FRAG_IV),
- new byte[0] /*padding*/);
-
- byte[] expectedEncodedData =
- Arrays.copyOfRange(
- mAesGcmFragMsg, ENCRYPTED_BODY_SKF_OFFSET, mAesGcmFragMsg.length);
-
- assertArrayEquals(expectedEncodedData, payloadBody.encode());
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeIdPayloadTest.java b/tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeIdPayloadTest.java
deleted file mode 100644
index 75552b31..00000000
--- a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeIdPayloadTest.java
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * Copyright (C) 2018 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.message;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-
-import android.net.ipsec.ike.IkeFqdnIdentification;
-import android.net.ipsec.ike.IkeIdentification;
-import android.net.ipsec.ike.IkeIpv4AddrIdentification;
-import android.net.ipsec.ike.IkeIpv6AddrIdentification;
-import android.net.ipsec.ike.IkeKeyIdIdentification;
-import android.net.ipsec.ike.IkeRfc822AddrIdentification;
-
-import com.android.internal.net.TestUtils;
-import com.android.internal.net.ipsec.ike.exceptions.AuthenticationFailedException;
-
-import org.junit.Test;
-
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.nio.ByteBuffer;
-
-public final class IkeIdPayloadTest {
-
- private static final String IPV4_ADDR_ID_PAYLOAD_RESPONDER_HEX_STRING =
- "2700000c01000000c0000264";
- private static final String IPV4_ADDR_ID_PAYLOAD_RESPONDER_BODY_HEX_STRING = "01000000c0000264";
- private static final String IPV4_ADDR_STRING = "192.0.2.100";
-
- private static final String IPV6_ADDR_ID_PAYLOAD_RESPONDER_HEX_STRING =
- "27000018050000000000200100000db80000000000000001";
- private static final String IPV6_ADDR_ID_PAYLOAD_RESPONDER_BODY_HEX_STRING =
- "050000000000200100000db80000000000000001";
- private static final String IPV6_ADDR_STRING = "0:2001:0:db8::1";
-
- private static final String FQDN_ID_PAYLOAD_HEX_STRING =
- "2500001702000000696B652E616E64726F69642E6E6574";
- private static final String FQDN_ID_PAYLOAD_BODY_HEX_STRING =
- "02000000696B652E616E64726F69642E6E6574";
- private static final String FQDN = "ike.android.net";
-
- private static final String RFC822_ADDR_ID_PAYLOAD_HEX_STRING =
- "2500001e03000000616e64726f6964696b65406578616d706c652e636f6d";
- private static final String RFC822_ADDR_ID_PAYLOAD_BODY_HEX_STRING =
- "03000000616e64726f6964696b65406578616d706c652e636f6d";
- private static final String RFC822_NAME = "androidike@example.com";
-
- private static final String KEY_ID_PAYLOAD_HEX_STRING =
- "250000170b000000616E64726F6964496B654B65794964";
- private static final String KEY_ID_PAYLOAD_BODY_HEX_STRING =
- "0b000000616E64726F6964496B654B65794964";
- private static final byte[] KEY_ID = "androidIkeKeyId".getBytes();
-
- private static final int ID_TYPE_OFFSET = 0;
-
- @Test
- public void testDecodeIpv4AddrIdPayload() throws Exception {
- byte[] inputPacket =
- TestUtils.hexStringToByteArray(IPV4_ADDR_ID_PAYLOAD_RESPONDER_BODY_HEX_STRING);
- IkeIdPayload payload = new IkeIdPayload(false, inputPacket, false);
-
- assertEquals(IkePayload.PAYLOAD_TYPE_ID_RESPONDER, payload.payloadType);
- assertEquals(IkeIdentification.ID_TYPE_IPV4_ADDR, payload.ikeId.idType);
- IkeIpv4AddrIdentification ikeId = (IkeIpv4AddrIdentification) payload.ikeId;
- Inet4Address expectedAddr = (Inet4Address) Inet4Address.getByName(IPV4_ADDR_STRING);
- assertEquals(expectedAddr, ikeId.ipv4Address);
- }
-
- @Test
- public void testDecodeIpv6AddrIdPayload() throws Exception {
- byte[] inputPacket =
- TestUtils.hexStringToByteArray(IPV6_ADDR_ID_PAYLOAD_RESPONDER_BODY_HEX_STRING);
- IkeIdPayload payload = new IkeIdPayload(false, inputPacket, false);
-
- assertEquals(IkePayload.PAYLOAD_TYPE_ID_RESPONDER, payload.payloadType);
- assertEquals(IkeIdentification.ID_TYPE_IPV6_ADDR, payload.ikeId.idType);
- IkeIpv6AddrIdentification ikeId = (IkeIpv6AddrIdentification) payload.ikeId;
- Inet6Address expectedAddr = (Inet6Address) Inet6Address.getByName(IPV6_ADDR_STRING);
- assertEquals(expectedAddr, ikeId.ipv6Address);
- }
-
- @Test
- public void testDecodeFqdnIdPayload() throws Exception {
- byte[] inputPacket = TestUtils.hexStringToByteArray(FQDN_ID_PAYLOAD_BODY_HEX_STRING);
- IkeIdPayload payload =
- new IkeIdPayload(false /*critical*/, inputPacket, false /*isInitiator*/);
-
- assertEquals(IkePayload.PAYLOAD_TYPE_ID_RESPONDER, payload.payloadType);
- assertArrayEquals(inputPacket, payload.getEncodedPayloadBody());
- assertEquals(IkeIdentification.ID_TYPE_FQDN, payload.ikeId.idType);
- IkeFqdnIdentification ikeId = (IkeFqdnIdentification) payload.ikeId;
- assertEquals(FQDN, ikeId.fqdn);
- }
-
- @Test
- public void testDecodeRfc822AddrIdPayload() throws Exception {
- byte[] inputPacket = TestUtils.hexStringToByteArray(RFC822_ADDR_ID_PAYLOAD_BODY_HEX_STRING);
- IkeIdPayload payload =
- new IkeIdPayload(false /*critical*/, inputPacket, true /*isInitiator*/);
-
- assertEquals(IkePayload.PAYLOAD_TYPE_ID_INITIATOR, payload.payloadType);
- assertEquals(IkeIdentification.ID_TYPE_RFC822_ADDR, payload.ikeId.idType);
- IkeRfc822AddrIdentification ikeId = (IkeRfc822AddrIdentification) payload.ikeId;
- assertEquals(RFC822_NAME, ikeId.rfc822Name);
- }
-
- @Test
- public void testDecodeKeyIdPayload() throws Exception {
- byte[] inputPacket = TestUtils.hexStringToByteArray(KEY_ID_PAYLOAD_BODY_HEX_STRING);
- IkeIdPayload payload =
- new IkeIdPayload(false /*critical*/, inputPacket, true /*isInitiator*/);
-
- assertEquals(IkePayload.PAYLOAD_TYPE_ID_INITIATOR, payload.payloadType);
- assertEquals(IkeIdentification.ID_TYPE_KEY_ID, payload.ikeId.idType);
- IkeKeyIdIdentification ikeId = (IkeKeyIdIdentification) payload.ikeId;
- assertArrayEquals(KEY_ID, ikeId.keyId);
- }
-
- @Test
- public void testDecodeUnsupportedIdType() throws Exception {
- byte[] inputPacket =
- TestUtils.hexStringToByteArray(IPV4_ADDR_ID_PAYLOAD_RESPONDER_BODY_HEX_STRING);
- inputPacket[ID_TYPE_OFFSET] = 0;
-
- try {
- new IkeIdPayload(false, inputPacket, true);
- fail("Expected AuthenticationFailedException: ID Type is unsupported.");
- } catch (AuthenticationFailedException expected) {
- }
- }
-
- @Test
- public void testConstructAndEncodeIpv4AddrIdPayload() throws Exception {
- Inet4Address ipv4Address = (Inet4Address) Inet4Address.getByName(IPV4_ADDR_STRING);
- IkeIdPayload payload = new IkeIdPayload(false, new IkeIpv4AddrIdentification(ipv4Address));
-
- ByteBuffer inputBuffer = ByteBuffer.allocate(payload.getPayloadLength());
- payload.encodeToByteBuffer(IkePayload.PAYLOAD_TYPE_AUTH, inputBuffer);
-
- byte[] expectedBytes =
- TestUtils.hexStringToByteArray(IPV4_ADDR_ID_PAYLOAD_RESPONDER_HEX_STRING);
- assertArrayEquals(expectedBytes, inputBuffer.array());
- }
-
- @Test
- public void testConstructAndEncodeIpv6AddrIdPayload() throws Exception {
- Inet6Address ipv6Address = (Inet6Address) Inet6Address.getByName(IPV6_ADDR_STRING);
- IkeIdPayload payload = new IkeIdPayload(false, new IkeIpv6AddrIdentification(ipv6Address));
-
- ByteBuffer inputBuffer = ByteBuffer.allocate(payload.getPayloadLength());
- payload.encodeToByteBuffer(IkePayload.PAYLOAD_TYPE_AUTH, inputBuffer);
-
- byte[] expectedBytes =
- TestUtils.hexStringToByteArray(IPV6_ADDR_ID_PAYLOAD_RESPONDER_HEX_STRING);
- assertArrayEquals(expectedBytes, inputBuffer.array());
- }
-
- @Test
- public void testConstructAndEncodeFqdnIdPayload() throws Exception {
- IkeIdPayload payload =
- new IkeIdPayload(false /*isInitiator*/, new IkeFqdnIdentification(FQDN));
-
- ByteBuffer inputBuffer = ByteBuffer.allocate(payload.getPayloadLength());
- payload.encodeToByteBuffer(IkePayload.PAYLOAD_TYPE_CERT, inputBuffer);
-
- byte[] expectedBytes = TestUtils.hexStringToByteArray(FQDN_ID_PAYLOAD_HEX_STRING);
- assertArrayEquals(expectedBytes, inputBuffer.array());
- }
-
- @Test
- public void testConstructAndEncodeRfc822AddrIdPayload() throws Exception {
- IkeIdPayload payload =
- new IkeIdPayload(
- true /*isInitiator*/, new IkeRfc822AddrIdentification(RFC822_NAME));
-
- ByteBuffer inputBuffer = ByteBuffer.allocate(payload.getPayloadLength());
- payload.encodeToByteBuffer(IkePayload.PAYLOAD_TYPE_CERT, inputBuffer);
-
- byte[] expectedBytes = TestUtils.hexStringToByteArray(RFC822_ADDR_ID_PAYLOAD_HEX_STRING);
- assertArrayEquals(expectedBytes, inputBuffer.array());
- }
-
- @Test
- public void testConstructAndEncodeKeyIdPayload() throws Exception {
- IkeIdPayload payload =
- new IkeIdPayload(true /*isInitiator*/, new IkeKeyIdIdentification(KEY_ID));
-
- ByteBuffer inputBuffer = ByteBuffer.allocate(payload.getPayloadLength());
- payload.encodeToByteBuffer(IkePayload.PAYLOAD_TYPE_CERT, inputBuffer);
-
- byte[] expectedBytes = TestUtils.hexStringToByteArray(KEY_ID_PAYLOAD_HEX_STRING);
- assertArrayEquals(expectedBytes, inputBuffer.array());
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeMessageTest.java b/tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeMessageTest.java
deleted file mode 100644
index 38b41527..00000000
--- a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeMessageTest.java
+++ /dev/null
@@ -1,935 +0,0 @@
-/*
- * Copyright (C) 2018 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.message;
-
-import static com.android.internal.net.ipsec.ike.message.IkeMessage.DECODE_STATUS_OK;
-import static com.android.internal.net.ipsec.ike.message.IkeMessage.DECODE_STATUS_PROTECTED_ERROR;
-import static com.android.internal.net.ipsec.ike.message.IkeMessage.DECODE_STATUS_UNPROTECTED_ERROR;
-import static com.android.internal.net.ipsec.ike.message.IkePayload.PAYLOAD_TYPE_AUTH;
-import static com.android.internal.net.ipsec.ike.message.IkePayload.PAYLOAD_TYPE_ID_INITIATOR;
-import static com.android.internal.net.ipsec.ike.message.IkePayload.PAYLOAD_TYPE_NO_NEXT;
-import static com.android.internal.net.ipsec.ike.message.IkeTestUtils.makeDummySkfPayload;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-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.Matchers.eq;
-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.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.net.ipsec.ike.exceptions.IkeException;
-import android.net.ipsec.ike.exceptions.IkeInternalException;
-
-import com.android.internal.net.TestUtils;
-import com.android.internal.net.ipsec.ike.SaRecord.IkeSaRecord;
-import com.android.internal.net.ipsec.ike.crypto.IkeMacIntegrity;
-import com.android.internal.net.ipsec.ike.crypto.IkeNormalModeCipher;
-import com.android.internal.net.ipsec.ike.exceptions.InvalidMessageIdException;
-import com.android.internal.net.ipsec.ike.exceptions.InvalidSyntaxException;
-import com.android.internal.net.ipsec.ike.exceptions.UnsupportedCriticalPayloadException;
-import com.android.internal.net.ipsec.ike.message.IkeMessage.DecodeResult;
-import com.android.internal.net.ipsec.ike.message.IkeMessage.DecodeResultError;
-import com.android.internal.net.ipsec.ike.message.IkeMessage.DecodeResultOk;
-import com.android.internal.net.ipsec.ike.message.IkeMessage.DecodeResultPartial;
-import com.android.internal.net.ipsec.ike.message.IkePayloadFactory.IIkePayloadDecoder;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import java.nio.ByteBuffer;
-import java.security.GeneralSecurityException;
-import java.util.Arrays;
-import java.util.LinkedList;
-
-import javax.crypto.IllegalBlockSizeException;
-
-public final class IkeMessageTest {
- private static final String IKE_SA_INIT_HEADER_RAW_PACKET =
- "8f54bf6d8b48e6e10000000000000000212022080000000000000150";
- private static final String IKE_SA_INIT_BODY_RAW_PACKET =
- "220000300000002c010100040300000c0100000c"
- + "800e00800300000803000002030000080400000200000008"
- + "020000022800008800020000b4a2faf4bb54878ae21d6385"
- + "12ece55d9236fc5046ab6cef82220f421f3ce6361faf3656"
- + "4ecb6d28798a94aad7b2b4b603ddeaaa5630adb9ece8ac37"
- + "534036040610ebdd92f46bef84f0be7db860351843858f8a"
- + "cf87056e272377f70c9f2d81e29c7b0ce4f291a3a72476bb"
- + "0b278fd4b7b0a4c26bbeb08214c707137607958729000024"
- + "c39b7f368f4681b89fa9b7be6465abd7c5f68b6ed5d3b4c7"
- + "2cb4240eb5c464122900001c00004004e54f73b7d83f6beb"
- + "881eab2051d8663f421d10b02b00001c00004005d915368c"
- + "a036004cb578ae3e3fb268509aeab1900000002069936922"
- + "8741c6d4ca094c93e242c9de19e7b7c60000000500000500";
- private static final String IKE_SA_INIT_RAW_PACKET =
- IKE_SA_INIT_HEADER_RAW_PACKET + IKE_SA_INIT_BODY_RAW_PACKET;
-
- // Byte offsets of first payload type in IKE message header.
- private static final int FIRST_PAYLOAD_TYPE_OFFSET = 16;
- // Byte offsets of first payload's critical bit in IKE message body.
- private static final int PAYLOAD_CRITICAL_BIT_OFFSET = 1;
- // Byte offsets of first payload length in IKE message body.
- private static final int FIRST_PAYLOAD_LENGTH_OFFSET = 2;
- // Byte offsets of last payload length in IKE message body.
- private static final int LAST_PAYLOAD_LENGTH_OFFSET = 278;
-
- private static final String IKE_AUTH_HEADER_HEX_STRING =
- "5f54bf6d8b48e6e1909232b3d1edcb5c2e20230800000001000000ec";
- private static final String IKE_AUTH_BODY_HEX_STRING =
- "230000d0b9132b7bb9f658dfdc648e5017a6322a030c316c"
- + "e55f365760d46426ce5cfc78bd1ed9abff63eb9594c1bd58"
- + "46de333ecd3ea2b705d18293b130395300ba92a351041345"
- + "0a10525cea51b2753b4e92b081fd78d995659a98f742278f"
- + "f9b8fd3e21554865c15c79a5134d66b2744966089e416c60"
- + "a274e44a9a3f084eb02f3bdce1e7de9de8d9a62773ab563b"
- + "9a69ba1db03c752acb6136452b8a86c41addb4210d68c423"
- + "efed80e26edca5fa3fe5d0a5ca9375ce332c474b93fb1fa3"
- + "59eb4e81ae6e0f22abdad69ba8007d50";
-
- private static final String IKE_AUTH_EXPECTED_CHECKSUM_HEX_STRING = "ae6e0f22abdad69ba8007d50";
- private static final String IKE_AUTH_HEX_STRING =
- IKE_AUTH_HEADER_HEX_STRING + IKE_AUTH_BODY_HEX_STRING;
-
- private static final String IKE_AUTH_UNENCRYPTED_PADDED_DATA_HEX_STRING =
- "2400000c010000000a50500d2700000c010000000a505050"
- + "2100001c02000000df7c038aefaaa32d3f44b228b52a3327"
- + "44dfb2c12c00002c00000028010304032ad4c0a20300000c"
- + "0100000c800e008003000008030000020000000805000000"
- + "2d00001801000000070000100000ffff00000000ffffffff"
- + "2900001801000000070000100000ffff00000000ffffffff"
- + "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 =
- "5f54bf6d8b48e6e1909232b3d1edcb5c2e20252800000000"
- + "0000004c00000030e376871750fdba9f7012446c5dc3f97a"
- + "f83b48ba0dbc68bcc4a78136832100aa4192f251cd4d1b97"
- + "d298e550";
- private static final String IKE_EMPTY_INFO_MSG_IV_HEX_STRING =
- "e376871750fdba9f7012446c5dc3f97a";
- private static final String IKE_EMPTY_INFO_MSG_ENCRYPTED_DATA_HEX_STRING =
- "f83b48ba0dbc68bcc4a78136832100aa";
- private static final String IKE_EMPTY_INFO_MSG_CHECKSUM_HEX_STRING = "4192f251cd4d1b97d298e550";
-
- private static final byte[] FRAGMENT_ONE_UNENCRYPTED_DATA = "fragmentOne".getBytes();
- private static final byte[] FRAGMENT_TWO_UNENCRYPTED_DATA = "fragmentTwo".getBytes();
-
- private static final int TOTAL_FRAGMENTS = 2;
- 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 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;
- private static final int IKE_AUTH_PAYLOAD_SIZE = 8;
-
- private byte[] mIkeAuthPacket;
- private byte[] mUnencryptedPaddedData;
- private IkeHeader mIkeAuthHeader;
-
- private IIkePayloadDecoder mSpyIkePayloadDecoder;
-
- private IkeMacIntegrity mMockIntegrity;
- private IkeNormalModeCipher mMockCipher;
- private IkeSaRecord mMockIkeSaRecord;
-
- private byte[] mIkeFragPacketOne;
- private byte[] mIkeFragPacketTwo;
- private IkeHeader mFragOneHeader;
- private IkeHeader mFragTwoHeader;
-
- private IkeSkfPayload mDummySkfPayloadOne;
- private IkeSkfPayload mDummySkfPayloadTwo;
-
- private static final int[] EXPECTED_IKE_INIT_PAYLOAD_LIST = {
- IkePayload.PAYLOAD_TYPE_SA,
- IkePayload.PAYLOAD_TYPE_KE,
- IkePayload.PAYLOAD_TYPE_NONCE,
- IkePayload.PAYLOAD_TYPE_NOTIFY,
- IkePayload.PAYLOAD_TYPE_NOTIFY,
- IkePayload.PAYLOAD_TYPE_VENDOR
- };
-
- class TestIkeSupportedPayload extends IkePayload {
- TestIkeSupportedPayload(int payload, boolean critical) {
- super(payload, critical);
- }
-
- @Override
- protected void encodeToByteBuffer(@PayloadType int nextPayload, ByteBuffer byteBuffer) {
- throw new UnsupportedOperationException(
- "It is not supported to encode " + getTypeString());
- }
-
- @Override
- protected int getPayloadLength() {
- throw new UnsupportedOperationException(
- "It is not supported to get payload length of " + getTypeString());
- }
-
- @Override
- public String getTypeString() {
- return "Test(" + payloadType + ")";
- }
- }
-
- @Before
- public void setUp() throws Exception {
- 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 =
- TestUtils.hexStringToByteArray(IKE_AUTH_UNENCRYPTED_PADDED_DATA_HEX_STRING);
- mIkeAuthHeader = new IkeHeader(mIkeAuthPacket);
-
- mMockIntegrity = mock(IkeMacIntegrity.class);
- byte[] expectedChecksum =
- TestUtils.hexStringToByteArray(IKE_AUTH_EXPECTED_CHECKSUM_HEX_STRING);
- when(mMockIntegrity.generateChecksum(any(), any())).thenReturn(expectedChecksum);
- when(mMockIntegrity.getChecksumLen()).thenReturn(expectedChecksum.length);
-
- mMockCipher = mock(IkeNormalModeCipher.class);
- when(mMockCipher.getIvLen()).thenReturn(IKE_AUTH_CIPHER_IV_SIZE);
- when(mMockCipher.getBlockSize()).thenReturn(IKE_AUTH_CIPHER_BLOCK_SIZE);
- when(mMockCipher.decrypt(any(), any(), any())).thenReturn(mUnencryptedPaddedData);
-
- mMockIkeSaRecord = mock(IkeSaRecord.class);
- when(mMockIkeSaRecord.getInboundDecryptionKey()).thenReturn(new byte[0]);
- when(mMockIkeSaRecord.getInboundIntegrityKey()).thenReturn(new byte[0]);
-
- mIkeFragPacketOne = makeFragmentBytes(1 /*fragNum*/, 2 /*totalFragments*/);
- mIkeFragPacketTwo = makeFragmentBytes(2 /*fragNum*/, 2 /*totalFragments*/);
-
- mFragOneHeader = new IkeHeader(mIkeFragPacketOne);
- mFragTwoHeader = new IkeHeader(mIkeFragPacketTwo);
-
- mDummySkfPayloadOne =
- makeDummySkfPayload(
- FRAGMENT_ONE_UNENCRYPTED_DATA, FRAGMENT_NUM_ONE, TOTAL_FRAGMENTS);
- mDummySkfPayloadTwo =
- makeDummySkfPayload(
- FRAGMENT_TWO_UNENCRYPTED_DATA, FRAGMENT_NUM_TWO, TOTAL_FRAGMENTS);
- }
-
- private byte[] makeFragmentBytes(int fragNum, int totalFragments) {
- byte[] packet = TestUtils.hexStringToByteArray(IKE_FRAG_HEX_STRING);
- ByteBuffer byteBuffer = ByteBuffer.wrap(packet);
- byteBuffer.get(new byte[IkeHeader.IKE_HEADER_LENGTH + IkePayload.GENERIC_HEADER_LENGTH]);
-
- byteBuffer.putShort((short) fragNum).putShort((short) totalFragments);
- return byteBuffer.array();
- }
-
- @After
- public void tearDown() {
- IkePayloadFactory.sDecoderInstance = new IkePayloadFactory.IkePayloadDecoder();
- }
-
- private IkeMessage verifyDecodeResultOkAndGetMessage(
- DecodeResult decodeResult, byte[] firstPacket) throws Exception {
- assertEquals(DECODE_STATUS_OK, decodeResult.status);
-
- DecodeResultOk resultOk = (DecodeResultOk) decodeResult;
- assertNotNull(resultOk.ikeMessage);
- assertArrayEquals(firstPacket, resultOk.firstPacket);
-
- return resultOk.ikeMessage;
- }
-
- private IkeException verifyDecodeResultErrorAndGetIkeException(
- DecodeResult decodeResult, int decodeStatus, byte[] firstPacket) throws Exception {
- assertEquals(decodeStatus, decodeResult.status);
-
- DecodeResultError resultError = (DecodeResultError) decodeResult;
- assertNotNull(resultError.ikeException);
-
- return resultError.ikeException;
- }
-
- @Test
- public void testDecodeIkeMessage() throws Exception {
- byte[] inputPacket = TestUtils.hexStringToByteArray(IKE_SA_INIT_RAW_PACKET);
- IkeHeader header = new IkeHeader(inputPacket);
-
- DecodeResult decodeResult = IkeMessage.decode(0, header, inputPacket);
-
- IkeMessage message = verifyDecodeResultOkAndGetMessage(decodeResult, inputPacket);
-
- assertEquals(EXPECTED_IKE_INIT_PAYLOAD_LIST.length, message.ikePayloadList.size());
- for (int i = 0; i < EXPECTED_IKE_INIT_PAYLOAD_LIST.length; i++) {
- assertEquals(
- EXPECTED_IKE_INIT_PAYLOAD_LIST[i], message.ikePayloadList.get(i).payloadType);
- }
- }
-
- @Test
- public void testDecodeMessageWithUnsupportedUncriticalPayload() throws Exception {
- byte[] inputPacket = TestUtils.hexStringToByteArray(IKE_SA_INIT_RAW_PACKET);
- // Set first payload unsupported uncritical
- inputPacket[FIRST_PAYLOAD_TYPE_OFFSET] = (byte) 0xff;
- IkeHeader header = new IkeHeader(inputPacket);
-
- DecodeResult decodeResult = IkeMessage.decode(0, header, inputPacket);
-
- IkeMessage message = verifyDecodeResultOkAndGetMessage(decodeResult, inputPacket);
-
- assertEquals(EXPECTED_IKE_INIT_PAYLOAD_LIST.length - 1, message.ikePayloadList.size());
- for (int i = 0; i < EXPECTED_IKE_INIT_PAYLOAD_LIST.length - 1; i++) {
- assertEquals(
- EXPECTED_IKE_INIT_PAYLOAD_LIST[i + 1],
- message.ikePayloadList.get(i).payloadType);
- }
- }
-
- @Test
- public void testThrowUnsupportedCriticalPayloadException() throws Exception {
- byte[] inputPacket = TestUtils.hexStringToByteArray(IKE_SA_INIT_RAW_PACKET);
- // Set first payload unsupported critical
- inputPacket[FIRST_PAYLOAD_TYPE_OFFSET] = (byte) 0xff;
- inputPacket[IkeHeader.IKE_HEADER_LENGTH + PAYLOAD_CRITICAL_BIT_OFFSET] = (byte) 0x80;
-
- UnsupportedCriticalPayloadException exception =
- IkeTestUtils.decodeAndVerifyUnprotectedErrorMsg(
- inputPacket, UnsupportedCriticalPayloadException.class);
-
- assertEquals(1, exception.payloadTypeList.size());
- }
-
- @Test
- public void testDecodeMessageWithTooShortPayloadLength() throws Exception {
- byte[] inputPacket = TestUtils.hexStringToByteArray(IKE_SA_INIT_RAW_PACKET);
- // Set first payload length to 0
- inputPacket[IkeHeader.IKE_HEADER_LENGTH + FIRST_PAYLOAD_LENGTH_OFFSET] = (byte) 0;
- inputPacket[IkeHeader.IKE_HEADER_LENGTH + FIRST_PAYLOAD_LENGTH_OFFSET + 1] = (byte) 0;
-
- IkeTestUtils.decodeAndVerifyUnprotectedErrorMsg(inputPacket, InvalidSyntaxException.class);
- }
-
- @Test
- public void testDecodeMessageWithTooLongPayloadLength() throws Exception {
- byte[] inputPacket = TestUtils.hexStringToByteArray(IKE_SA_INIT_RAW_PACKET);
- // Increase last payload length by one byte
- inputPacket[IkeHeader.IKE_HEADER_LENGTH + LAST_PAYLOAD_LENGTH_OFFSET]++;
-
- IkeTestUtils.decodeAndVerifyUnprotectedErrorMsg(inputPacket, InvalidSyntaxException.class);
- }
-
- @Test
- public void testDecodeMessageWithUnexpectedBytesInTheEnd() throws Exception {
- byte[] inputPacket = TestUtils.hexStringToByteArray(IKE_SA_INIT_RAW_PACKET + "0000");
-
- IkeTestUtils.decodeAndVerifyUnprotectedErrorMsg(inputPacket, InvalidSyntaxException.class);
- }
-
- @Test
- public void testDecodeEncryptedMessage() throws Exception {
- DecodeResult decodeResult =
- IkeMessage.decode(
- IKE_AUTH_EXPECTED_MESSAGE_ID,
- mMockIntegrity,
- mMockCipher,
- mMockIkeSaRecord,
- mIkeAuthHeader,
- mIkeAuthPacket,
- null /*collectedFragments*/);
- IkeMessage ikeMessage = verifyDecodeResultOkAndGetMessage(decodeResult, mIkeAuthPacket);
-
- assertEquals(IKE_AUTH_PAYLOAD_SIZE, ikeMessage.ikePayloadList.size());
- }
-
- @Test
- public void testDecodeEncryptedMessageWithWrongId() throws Exception {
- DecodeResult decodeResult =
- IkeMessage.decode(
- 2,
- mMockIntegrity,
- mMockCipher,
- mMockIkeSaRecord,
- mIkeAuthHeader,
- mIkeAuthPacket,
- null /*collectedFragments*/);
- IkeException ikeException =
- verifyDecodeResultErrorAndGetIkeException(
- decodeResult, DECODE_STATUS_UNPROTECTED_ERROR, mIkeAuthPacket);
-
- assertTrue(ikeException instanceof InvalidMessageIdException);
- }
-
- @Test
- public void testDecodeEncryptedMessageWithWrongChecksum() throws Exception {
- when(mMockIntegrity.generateChecksum(any(), any())).thenReturn(new byte[0]);
-
- DecodeResult decodeResult =
- IkeMessage.decode(
- IKE_AUTH_EXPECTED_MESSAGE_ID,
- mMockIntegrity,
- mMockCipher,
- mMockIkeSaRecord,
- mIkeAuthHeader,
- mIkeAuthPacket,
- null /*collectedFragments*/);
- IkeException ikeException =
- verifyDecodeResultErrorAndGetIkeException(
- decodeResult, DECODE_STATUS_UNPROTECTED_ERROR, mIkeAuthPacket);
-
- assertTrue(
- ((IkeInternalException) ikeException).getCause()
- instanceof GeneralSecurityException);
- }
-
- @Test
- public void testDecryptFail() throws Exception {
- when(mMockCipher.decrypt(any(), any(), any())).thenThrow(IllegalBlockSizeException.class);
-
- DecodeResult decodeResult =
- IkeMessage.decode(
- IKE_AUTH_EXPECTED_MESSAGE_ID,
- mMockIntegrity,
- mMockCipher,
- mMockIkeSaRecord,
- mIkeAuthHeader,
- mIkeAuthPacket,
- null /*collectedFragments*/);
-
- IkeException ikeException =
- verifyDecodeResultErrorAndGetIkeException(
- decodeResult, DECODE_STATUS_UNPROTECTED_ERROR, mIkeAuthPacket);
- assertTrue(
- ((IkeInternalException) ikeException).getCause()
- instanceof IllegalBlockSizeException);
- }
-
- @Test
- public void testParsingErrorInEncryptedMessage() throws Exception {
- // Set first payload length to 0
- byte[] decryptedData =
- Arrays.copyOfRange(mUnencryptedPaddedData, 0, mUnencryptedPaddedData.length);
- decryptedData[FIRST_PAYLOAD_LENGTH_OFFSET] = (byte) 0;
- decryptedData[FIRST_PAYLOAD_LENGTH_OFFSET + 1] = (byte) 0;
- when(mMockCipher.decrypt(any(), any(), any())).thenReturn(decryptedData);
-
- DecodeResult decodeResult =
- IkeMessage.decode(
- IKE_AUTH_EXPECTED_MESSAGE_ID,
- mMockIntegrity,
- mMockCipher,
- mMockIkeSaRecord,
- mIkeAuthHeader,
- mIkeAuthPacket,
- null /*collectedFragments*/);
- IkeException ikeException =
- verifyDecodeResultErrorAndGetIkeException(
- decodeResult, DECODE_STATUS_PROTECTED_ERROR, mIkeAuthPacket);
-
- assertTrue(ikeException instanceof InvalidSyntaxException);
- }
-
- private boolean support(int payloadType) {
- // Supports all payload typs from 33 to 46
- return (payloadType >= 33 && payloadType <= 46);
- }
-
- @Test
- public void testAttachEncodedHeader() throws Exception {
- byte[] inputPacket = TestUtils.hexStringToByteArray(IKE_SA_INIT_RAW_PACKET);
- byte[] ikeBodyBytes = TestUtils.hexStringToByteArray(IKE_SA_INIT_BODY_RAW_PACKET);
- IkeHeader header = new IkeHeader(inputPacket);
- IkeMessage message =
- ((DecodeResultOk) IkeMessage.decode(0, header, inputPacket)).ikeMessage;
-
- byte[] encodedIkeMessage = message.attachEncodedHeader(ikeBodyBytes);
- assertArrayEquals(inputPacket, encodedIkeMessage);
- }
-
- @Test
- public void testEncodeAndEncryptEmptyMsg() throws Exception {
- when(mMockCipher.generateIv())
- .thenReturn(TestUtils.hexStringToByteArray(IKE_EMPTY_INFO_MSG_IV_HEX_STRING));
- when(mMockCipher.encrypt(any(), any(), any()))
- .thenReturn(
- TestUtils.hexStringToByteArray(
- IKE_EMPTY_INFO_MSG_ENCRYPTED_DATA_HEX_STRING));
-
- byte[] checkSum = TestUtils.hexStringToByteArray(IKE_EMPTY_INFO_MSG_CHECKSUM_HEX_STRING);
- when(mMockIntegrity.getChecksumLen()).thenReturn(checkSum.length);
- when(mMockIntegrity.generateChecksum(any(), any())).thenReturn(checkSum);
-
- IkeHeader ikeHeader =
- new IkeHeader(
- INIT_SPI,
- RESP_SPI,
- IkePayload.PAYLOAD_TYPE_SK,
- IkeHeader.EXCHANGE_TYPE_INFORMATIONAL,
- true /*isResp*/,
- true /*fromInit*/,
- 0);
- IkeMessage ikeMessage = new IkeMessage(ikeHeader, new LinkedList<>());
-
- byte[][] ikeMessageBytes =
- ikeMessage.encryptAndEncode(
- mMockIntegrity,
- mMockCipher,
- mMockIkeSaRecord,
- true /*supportFragment*/,
- 1280 /*fragSize*/);
- byte[][] expectedBytes =
- new byte[][] {TestUtils.hexStringToByteArray(IKE_EMPTY_INFO_MSG_HEX_STRING)};
-
- assertArrayEquals(expectedBytes, ikeMessageBytes);
- }
-
- private DecodeResultPartial makeDecodeResultForFragOne(DecodeResultPartial collectedFrags) {
- return new DecodeResultPartial(
- mFragOneHeader,
- mIkeFragPacketOne,
- mDummySkfPayloadOne,
- PAYLOAD_TYPE_AUTH,
- collectedFrags);
- }
-
- private DecodeResultPartial makeDecodeResultForFragTwo(DecodeResultPartial collectedFrags) {
- return new DecodeResultPartial(
- mFragTwoHeader,
- mIkeFragPacketTwo,
- mDummySkfPayloadTwo,
- PAYLOAD_TYPE_NO_NEXT,
- collectedFrags);
- }
-
- @Test
- public void testConstructDecodePartialFirstFragArriveFirst() throws Exception {
- DecodeResultPartial resultPartial = makeDecodeResultForFragOne(null /*collectedFragments*/);
-
- assertEquals(PAYLOAD_TYPE_AUTH, resultPartial.firstPayloadType);
- assertArrayEquals(mIkeFragPacketOne, resultPartial.firstFragBytes);
- assertEquals(mFragOneHeader, resultPartial.ikeHeader);
-
- assertEquals(TOTAL_FRAGMENTS, resultPartial.collectedFragsList.length);
- assertArrayEquals(
- FRAGMENT_ONE_UNENCRYPTED_DATA,
- resultPartial.collectedFragsList[FRAGMENT_NUM_ONE - 1]);
- assertFalse(resultPartial.isAllFragmentsReceived());
- }
-
- @Test
- public void testConstructDecodePartialSecondFragArriveFirst() throws Exception {
- DecodeResultPartial resultPartial = makeDecodeResultForFragTwo(null /*collectedFragments*/);
-
- assertEquals(PAYLOAD_TYPE_NO_NEXT, resultPartial.firstPayloadType);
- assertNull(resultPartial.firstFragBytes);
- 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 testConstructDecodeResultPartialWithCollectedFrags() throws Exception {
- DecodeResultPartial resultPartialIncomplete =
- makeDecodeResultForFragTwo(null /*collectedFragments*/);
- DecodeResultPartial resultPartialComplete =
- makeDecodeResultForFragOne(resultPartialIncomplete);
-
- assertEquals(PAYLOAD_TYPE_AUTH, resultPartialComplete.firstPayloadType);
- assertArrayEquals(mIkeFragPacketOne, resultPartialComplete.firstFragBytes);
- assertEquals(mFragTwoHeader, resultPartialComplete.ikeHeader);
-
- assertEquals(TOTAL_FRAGMENTS, resultPartialComplete.collectedFragsList.length);
- assertTrue(resultPartialComplete.isAllFragmentsReceived());
- }
-
- @Test
- public void testReassembleAllFrags() throws Exception {
- DecodeResultPartial resultPartialIncomplete =
- makeDecodeResultForFragOne(null /*collectedFragments*/);
- DecodeResultPartial resultPartialComplete =
- makeDecodeResultForFragTwo(resultPartialIncomplete);
-
- assertEquals(PAYLOAD_TYPE_AUTH, resultPartialIncomplete.firstPayloadType);
- assertArrayEquals(mIkeFragPacketOne, resultPartialIncomplete.firstFragBytes);
- assertEquals(mFragOneHeader, resultPartialIncomplete.ikeHeader);
-
- assertEquals(TOTAL_FRAGMENTS, resultPartialIncomplete.collectedFragsList.length);
- assertTrue(resultPartialIncomplete.isAllFragmentsReceived());
-
- // Verify reassembly result
- ByteBuffer expectedBuffer =
- ByteBuffer.allocate(
- FRAGMENT_ONE_UNENCRYPTED_DATA.length
- + FRAGMENT_TWO_UNENCRYPTED_DATA.length);
- expectedBuffer.put(FRAGMENT_ONE_UNENCRYPTED_DATA).put(FRAGMENT_TWO_UNENCRYPTED_DATA);
-
- byte[] reassembledBytes = resultPartialComplete.reassembleAllFrags();
- assertArrayEquals(expectedBuffer.array(), reassembledBytes);
- }
-
- @Test
- public void testReassembleIncompleteFragmentsThrows() throws Exception {
- DecodeResultPartial resultPartial = makeDecodeResultForFragTwo(null /*collectedFragments*/);
-
- assertFalse(resultPartial.isAllFragmentsReceived());
-
- try {
- resultPartial.reassembleAllFrags();
- fail("Expected to fail because reassembly is not done");
- } catch (IllegalStateException expected) {
-
- }
- }
-
- 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,
- mIkeFragPacketTwo,
- null /* collectedFragments*/);
-
- // Verify decoding result
- assertTrue(decodeResult instanceof DecodeResultPartial);
- DecodeResultPartial resultPartial = (DecodeResultPartial) decodeResult;
-
- assertEquals(PAYLOAD_TYPE_NO_NEXT, resultPartial.firstPayloadType);
- assertNull(resultPartial.firstFragBytes);
- 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,
- mIkeFragPacketOne,
- skfOne,
- PAYLOAD_TYPE_ID_INITIATOR,
- null /* collectedFragments*/);
-
- setDecryptSkfPayload(skfTwo);
- DecodeResult decodeResult =
- decodeSkf(
- IKE_FRAG_EXPECTED_MESSAGE_ID,
- mFragTwoHeader,
- mIkeFragPacketTwo,
- resultPartialIncomplete);
-
- // Verify fragments reassembly has been finished and complete message has been decoded.
- assertTrue(decodeResult instanceof DecodeResultOk);
- DecodeResultOk resultOk = (DecodeResultOk) decodeResult;
- assertArrayEquals(mIkeFragPacketOne, resultOk.firstPacket);
- assertEquals(2, resultOk.ikeMessage.ikePayloadList.size());
- }
-
- @Test
- public void testRcvFirstArrivedFragWithUnprotectedError() throws Exception {
- DecodeResult decodeResult =
- decodeSkf(
- IKE_FRAG_EXPECTED_MESSAGE_ID + 1,
- mFragTwoHeader,
- mIkeFragPacketTwo,
- null /* collectedFragments*/);
-
- // Verify that unprotected error was returned
- IkeException ikeException =
- verifyDecodeResultErrorAndGetIkeException(
- decodeResult, DECODE_STATUS_UNPROTECTED_ERROR, mIkeAuthPacket);
- 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,
- mIkeFragPacketTwo,
- resultPartialIncomplete);
-
- // Verify that newly received fragment was discarded
- assertEquals(resultPartialIncomplete, decodeResult);
- }
-
- @Test
- public void testRcvFragWithLargerTotalFragments() throws Exception {
- DecodeResultPartial resultPartialIncomplete =
- new DecodeResultPartial(
- mFragOneHeader,
- mIkeFragPacketOne,
- mDummySkfPayloadOne,
- PAYLOAD_TYPE_NO_NEXT,
- null /* collectedFragments*/);
-
- // Set total fragments of inbound fragment to 5
- int totalFragments = 5;
- byte[] fragPacket = makeFragmentBytes(2 /*fragNum*/, totalFragments);
-
- 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);
- assertNull(resultPartial.firstFragBytes);
- 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,
- mIkeFragPacketOne,
- skfPayload,
- PAYLOAD_TYPE_AUTH,
- null /* collectedFragments*/);
-
- setDecryptSkfPayload(mDummySkfPayloadTwo);
- DecodeResult decodeResult =
- decodeSkf(
- IKE_FRAG_EXPECTED_MESSAGE_ID,
- mFragTwoHeader,
- mIkeFragPacketTwo,
- 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,
- mIkeFragPacketTwo,
- 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);
- }
-
- @Test
- public void testEncodeAndEncryptFragments() throws Exception {
- int messageId = 1;
- int fragSize = 140;
- int expectedTotalFragments = 3;
-
- byte[] integrityKey = new byte[0];
- byte[] encryptionKey = new byte[0];
- byte[] iv = new byte[IKE_AUTH_CIPHER_IV_SIZE];
-
- when(mMockCipher.generateIv()).thenReturn(iv);
- when(mMockCipher.encrypt(any(), any(), any()))
- .thenAnswer(
- (invocation) -> {
- return (byte[]) invocation.getArguments()[0];
- });
-
- IkeHeader ikeHeader =
- new IkeHeader(
- INIT_SPI,
- RESP_SPI,
- IkePayload.PAYLOAD_TYPE_SK,
- IkeHeader.EXCHANGE_TYPE_IKE_AUTH,
- true /*isResp*/,
- false /*fromInit*/,
- messageId);
-
- byte[][] packetList =
- new IkeMessage.IkeMessageHelper()
- .encryptAndEncode(
- ikeHeader,
- IkePayload.PAYLOAD_TYPE_AUTH,
- mUnencryptedPaddedData,
- mMockIntegrity,
- mMockCipher,
- integrityKey,
- encryptionKey,
- true /*supportFragment*/,
- fragSize);
-
- assertEquals(expectedTotalFragments, packetList.length);
-
- IkeHeader expectedIkeHeader =
- new IkeHeader(
- INIT_SPI,
- RESP_SPI,
- IkePayload.PAYLOAD_TYPE_SKF,
- IkeHeader.EXCHANGE_TYPE_IKE_AUTH,
- true /*isResp*/,
- false /*fromInit*/,
- messageId);
- for (int i = 0; i < packetList.length; i++) {
- byte[] p = packetList[i];
-
- // Verify fragment length
- assertNotNull(p);
- assertTrue(p.length <= fragSize);
-
- ByteBuffer packetBuffer = ByteBuffer.wrap(p);
-
- // Verify IKE header
- byte[] headerBytes = new byte[IkeHeader.IKE_HEADER_LENGTH];
- packetBuffer.get(headerBytes);
-
- ByteBuffer expectedHeadBuffer = ByteBuffer.allocate(IkeHeader.IKE_HEADER_LENGTH);
- expectedIkeHeader.encodeToByteBuffer(
- expectedHeadBuffer, p.length - IkeHeader.IKE_HEADER_LENGTH);
-
- assertArrayEquals(expectedHeadBuffer.array(), headerBytes);
-
- // Verify fragment payload header
- packetBuffer.get(new byte[IkePayload.GENERIC_HEADER_LENGTH]);
- assertEquals(i + 1 /*expetced fragNum*/, Short.toUnsignedInt(packetBuffer.getShort()));
- assertEquals(expectedTotalFragments, Short.toUnsignedInt(packetBuffer.getShort()));
- }
-
- verify(mMockCipher, times(expectedTotalFragments + 1))
- .encrypt(any(), eq(encryptionKey), eq(iv));
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeNotifyPayloadTest.java b/tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeNotifyPayloadTest.java
deleted file mode 100644
index 884c76eb..00000000
--- a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeNotifyPayloadTest.java
+++ /dev/null
@@ -1,249 +0,0 @@
-/*
- * Copyright (C) 2018 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.message;
-
-import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_AUTHENTICATION_FAILED;
-import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_INVALID_KE_PAYLOAD;
-import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_UNSUPPORTED_CRITICAL_PAYLOAD;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.net.ipsec.ike.SaProposal;
-import android.net.ipsec.ike.exceptions.IkeProtocolException;
-
-import com.android.internal.net.TestUtils;
-import com.android.internal.net.ipsec.ike.exceptions.AuthenticationFailedException;
-import com.android.internal.net.ipsec.ike.exceptions.InvalidKeException;
-import com.android.internal.net.ipsec.ike.exceptions.InvalidSyntaxException;
-import com.android.internal.net.ipsec.ike.exceptions.UnrecognizedIkeProtocolException;
-
-import org.junit.Test;
-
-import java.net.InetAddress;
-import java.nio.ByteBuffer;
-
-public final class IkeNotifyPayloadTest {
- private static final String NOTIFY_NAT_DETECTION_PAYLOAD_HEX_STRING =
- "2900001c00004004e54f73b7d83f6beb881eab2051d8663f421d10b0";
- private static final String NOTIFY_NAT_DETECTION_PAYLOAD_BODY_HEX_STRING =
- "00004004e54f73b7d83f6beb881eab2051d8663f421d10b0";
- private static final String NAT_DETECTION_DATA_HEX_STRING =
- "e54f73b7d83f6beb881eab2051d8663f421d10b0";
-
- private static final String NOTIFY_REKEY_PAYLOAD_BODY_HEX_STRING = "030440092ad4c0a2";
- private static final int REKEY_SPI = 0x2ad4c0a2;
-
- private static final String IKE_INITIATOR_SPI_HEX_STRING = "5f54bf6d8b48e6e1";
- private static final String IKE_RESPODNER_SPI_HEX_STRING = "0000000000000000";
- private static final String IP_ADDR = "10.80.80.13";
- private static final int PORT = 500;
-
- private static final int PROTOCOL_ID_OFFSET = 0;
-
- @Test
- public void testDecodeNotifyPayloadSpiUnset() throws Exception {
- byte[] inputPacket =
- TestUtils.hexStringToByteArray(NOTIFY_NAT_DETECTION_PAYLOAD_BODY_HEX_STRING);
- byte[] notifyData = TestUtils.hexStringToByteArray(NAT_DETECTION_DATA_HEX_STRING);
-
- IkeNotifyPayload payload = new IkeNotifyPayload(false, inputPacket);
- assertEquals(IkePayload.PROTOCOL_ID_UNSET, payload.protocolId);
- assertEquals(IkePayload.SPI_LEN_NOT_INCLUDED, payload.spiSize);
- assertEquals(IkeNotifyPayload.NOTIFY_TYPE_NAT_DETECTION_SOURCE_IP, payload.notifyType);
- assertEquals(IkePayload.SPI_NOT_INCLUDED, payload.spi);
- assertArrayEquals(notifyData, payload.notifyData);
- }
-
- @Test
- public void testDecodeNotifyPayloadSpiSet() throws Exception {
- byte[] inputPacket = TestUtils.hexStringToByteArray(NOTIFY_REKEY_PAYLOAD_BODY_HEX_STRING);
-
- IkeNotifyPayload payload = new IkeNotifyPayload(false, inputPacket);
- assertEquals(IkePayload.PROTOCOL_ID_ESP, payload.protocolId);
- assertEquals(IkePayload.SPI_LEN_IPSEC, payload.spiSize);
- assertEquals(IkeNotifyPayload.NOTIFY_TYPE_REKEY_SA, payload.notifyType);
- assertEquals(REKEY_SPI, payload.spi);
- assertArrayEquals(new byte[0], payload.notifyData);
- }
-
- @Test
- public void testDecodeNotifyPayloadThrowException() throws Exception {
- byte[] inputPacket =
- TestUtils.hexStringToByteArray(NOTIFY_NAT_DETECTION_PAYLOAD_BODY_HEX_STRING);
- // Change Protocol ID to ESP
- inputPacket[PROTOCOL_ID_OFFSET] = (byte) (IkePayload.PROTOCOL_ID_ESP & 0xFF);
- try {
- IkeNotifyPayload payload = new IkeNotifyPayload(false, inputPacket);
- fail("Expected InvalidSyntaxException: Protocol ID should not be ESP");
- } catch (InvalidSyntaxException expected) {
- }
- }
-
- @Test
- public void testGenerateNatDetectionData() throws Exception {
- long initiatorIkeSpi = Long.parseLong(IKE_INITIATOR_SPI_HEX_STRING, 16);
- long responderIkespi = Long.parseLong(IKE_RESPODNER_SPI_HEX_STRING, 16);
- InetAddress inetAddress = InetAddress.getByName(IP_ADDR);
-
- byte[] netDetectionData =
- IkeNotifyPayload.generateNatDetectionData(
- initiatorIkeSpi, responderIkespi, inetAddress, PORT);
-
- byte[] expectedBytes = TestUtils.hexStringToByteArray(NAT_DETECTION_DATA_HEX_STRING);
- assertArrayEquals(expectedBytes, netDetectionData);
- }
-
- @Test
- public void testBuildIkeErrorNotifyWithData() throws Exception {
- int payloadType = 1;
- IkeNotifyPayload notifyPayload =
- new IkeNotifyPayload(
- IkeProtocolException.ERROR_TYPE_UNSUPPORTED_CRITICAL_PAYLOAD,
- new byte[] {(byte) payloadType});
-
- assertArrayEquals(new byte[] {(byte) payloadType}, notifyPayload.notifyData);
- assertTrue(notifyPayload.isErrorNotify());
- assertFalse(notifyPayload.isNewChildSaNotify());
- }
-
- @Test
- public void testBuildIkeErrorNotifyWithoutData() throws Exception {
- IkeNotifyPayload notifyPayload =
- new IkeNotifyPayload(IkeProtocolException.ERROR_TYPE_INVALID_SYNTAX);
-
- assertArrayEquals(new byte[0], notifyPayload.notifyData);
- assertTrue(notifyPayload.isErrorNotify());
- assertFalse(notifyPayload.isNewChildSaNotify());
- }
-
- @Test
- public void testBuildChildConfigNotify() throws Exception {
- IkeNotifyPayload notifyPayload =
- new IkeNotifyPayload(IkeNotifyPayload.NOTIFY_TYPE_USE_TRANSPORT_MODE);
-
- assertArrayEquals(new byte[0], notifyPayload.notifyData);
- assertFalse(notifyPayload.isErrorNotify());
- assertTrue(notifyPayload.isNewChildSaNotify());
- }
-
- @Test
- public void testBuildChildErrorNotify() throws Exception {
- IkeNotifyPayload notifyPayload =
- new IkeNotifyPayload(IkeProtocolException.ERROR_TYPE_INTERNAL_ADDRESS_FAILURE);
-
- assertArrayEquals(new byte[0], notifyPayload.notifyData);
- assertTrue(notifyPayload.isErrorNotify());
- assertTrue(notifyPayload.isNewChildSaNotify());
- }
-
- @Test
- public void testEncodeNotifyPayload() throws Exception {
- byte[] inputPacket =
- TestUtils.hexStringToByteArray(NOTIFY_NAT_DETECTION_PAYLOAD_BODY_HEX_STRING);
- IkeNotifyPayload payload = new IkeNotifyPayload(false, inputPacket);
-
- ByteBuffer byteBuffer = ByteBuffer.allocate(payload.getPayloadLength());
- payload.encodeToByteBuffer(IkePayload.PAYLOAD_TYPE_NOTIFY, byteBuffer);
-
- byte[] expectedNoncePayload =
- TestUtils.hexStringToByteArray(NOTIFY_NAT_DETECTION_PAYLOAD_HEX_STRING);
- assertArrayEquals(expectedNoncePayload, byteBuffer.array());
- }
-
- @Test
- public void testValidateAndBuildIkeExceptionWithData() throws Exception {
- // Invalid Message ID
- byte[] dhGroup = new byte[] {(byte) 0x00, (byte) 0x0e};
- int expectedDhGroup = SaProposal.DH_GROUP_2048_BIT_MODP;
-
- IkeNotifyPayload payload = new IkeNotifyPayload(ERROR_TYPE_INVALID_KE_PAYLOAD, dhGroup);
- IkeProtocolException exception = payload.validateAndBuildIkeException();
-
- assertTrue(exception instanceof InvalidKeException);
- assertEquals(ERROR_TYPE_INVALID_KE_PAYLOAD, exception.getErrorType());
- assertArrayEquals(dhGroup, exception.getErrorData());
- assertEquals(expectedDhGroup, ((InvalidKeException) exception).getDhGroup());
- }
-
- @Test
- public void testValidateAndBuildIkeExceptionWithoutData() throws Exception {
- // Invalid Syntax
- IkeNotifyPayload payload = new IkeNotifyPayload(ERROR_TYPE_AUTHENTICATION_FAILED);
- IkeProtocolException exception = payload.validateAndBuildIkeException();
-
- assertTrue(exception instanceof AuthenticationFailedException);
- assertEquals(ERROR_TYPE_AUTHENTICATION_FAILED, exception.getErrorType());
- assertArrayEquals(new byte[0], exception.getErrorData());
- }
-
- @Test
- public void testValidateAndBuildUnrecognizedIkeException() throws Exception {
- int unrecognizedType = 0;
- IkeNotifyPayload payload = new IkeNotifyPayload(unrecognizedType);
- IkeProtocolException exception = payload.validateAndBuildIkeException();
-
- assertTrue(exception instanceof UnrecognizedIkeProtocolException);
- assertEquals(unrecognizedType, exception.getErrorType());
- assertArrayEquals(new byte[0], exception.getErrorData());
- }
-
- @Test
- public void testValidateAndBuildIkeExceptionWithInvalidPayload() throws Exception {
- // Build a invalid notify payload
- IkeNotifyPayload payload = new IkeNotifyPayload(ERROR_TYPE_UNSUPPORTED_CRITICAL_PAYLOAD);
-
- try {
- payload.validateAndBuildIkeException();
- fail("Expected to fail due to invalid error data");
- } catch (InvalidSyntaxException expected) {
- }
- }
-
- @Test
- public void testBuildIkeExceptionWithStatusNotify() throws Exception {
- // Rekey notification
- byte[] inputPacket = TestUtils.hexStringToByteArray(NOTIFY_REKEY_PAYLOAD_BODY_HEX_STRING);
- IkeNotifyPayload payload = new IkeNotifyPayload(false, inputPacket);
-
- assertFalse(payload.isErrorNotify());
-
- try {
- payload.validateAndBuildIkeException();
- fail("Expected to fail because it is not error notification");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void testGetNotifyTypeString() throws Exception {
- IkeNotifyPayload payload = new IkeNotifyPayload(ERROR_TYPE_AUTHENTICATION_FAILED);
-
- assertEquals("Notify(Authentication failed)", payload.getTypeString());
- }
-
- @Test
- public void testGetNotifyTypeStringForUnrecoginizedNotify() throws Exception {
- int unrecognizedType = 0;
- IkeNotifyPayload payload = new IkeNotifyPayload(unrecognizedType);
-
- assertEquals("Notify(0)", payload.getTypeString());
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeSkfPayloadTest.java b/tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeSkfPayloadTest.java
deleted file mode 100644
index 3374a7dc..00000000
--- a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeSkfPayloadTest.java
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * Copyright (C) 2019 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.message;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.spy;
-
-import android.net.ipsec.ike.SaProposal;
-
-import com.android.internal.net.TestUtils;
-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.IkeNormalModeCipher;
-import com.android.internal.net.ipsec.ike.exceptions.InvalidSyntaxException;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload.EncryptionTransform;
-import com.android.internal.net.ipsec.ike.message.IkeSaPayload.IntegrityTransform;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.nio.ByteBuffer;
-import java.util.Arrays;
-
-public final class IkeSkfPayloadTest {
- private static final String IKE_FRAG_MSG_HEX_STRING =
- "bb3d5237aa558779db24aeb6c9ea183e352023200000000100000134"
- + "0000011800020002c1471fc7714a3b77a2bfd78dd2df4c048dfed913"
- + "c5de76cb1f4463ef541df2442b43c65308a47b873502268cc1195f99"
- + "4f6f1a945f56cb342969936af97d79c560c8e0f8bb1a0874ebfb5d0e"
- + "610b0fcff96d4197c06e7aef07a3a9ae487555bec95c78b87fe6483c"
- + "be07e3d132f8594c34dba5b5b463b871d0272af6a1ee701fc6b7b70a"
- + "22a1b8f63eed50ce6b2253ee63fe2cf0289a5eb715e56b389f72b5ba"
- + "ecfb7340f4abf9253a8c973d281ed62f3516d130fcaaf2c2145b3047"
- + "f3a243e60beb2fc28bf05183839caf46bfbfc4f28c9a2224e7d49686"
- + "52a236a403ecb203a1de1e2144a6f5ce28acc2f93989608af17381fc"
- + "f965cabe1a448274264b22167abfa047dc88e4bfdc5a492847d36d8b";
-
- private static final String IKE_FRAG_MSG_DECRYPTED_BODY_HEX_STRING =
- "dc89d82f4fccff8d3f0c4f4848571e57205f7dbdce954203983d2147"
- + "3a9e10ba36876b860d33afbdfe6ebf000240e31f2039f4213e882d1f"
- + "6f0a24887aed0584f4b50a016d989990fd58297757c7b842cd72b57c"
- + "2f68cba8a5f06d899ce3fcfbd0419402a1d59f1c5b5b23bd0a4ed525"
- + "27ed6cef9fd238552fcf6e4cd9f794d2b01ba61438fd21714fbc3e3f"
- + "443a816751e55d46009ae7fb9f52db0977e453a2d28b0453a9393778"
- + "3a0b625c27d186c052a7169807537d97e731a3543fc10dca605ca86d"
- + "1496882e1d009a9216d07d0000001801850014120a00000f02000200"
- + "0100000d010000";
-
- private static final String IKE_FRAG_MSG_CHECKSUM = "7abfa047dc88e4bfdc5a492847d36d8b";
- private static final String IKE_FRAG_MSG_PADDING = "05d925c1b3804aee08";
-
- private static final int FRAGMENT_NUM = 2;
- private static final int TOTAL_FRAGMENTS = 2;
-
- private static final int FRAGMENT_NUM_OFFSET =
- IkeHeader.IKE_HEADER_LENGTH + IkePayload.GENERIC_HEADER_LENGTH;
- private static final int TOTAL_FRAGMENTS_OFFET = FRAGMENT_NUM_OFFSET + 2;
-
- private byte[] mDecryptedData;
-
- private IkeMacIntegrity mSpyHmacSha256IntegrityMac;
- private IkeNormalModeCipher mSpyAesCbcCipher;
-
- @Before
- public void setUp() throws Exception {
- mDecryptedData = TestUtils.hexStringToByteArray(IKE_FRAG_MSG_DECRYPTED_BODY_HEX_STRING);
-
- // Set up integrity algorithm
- mSpyHmacSha256IntegrityMac =
- spy(
- IkeMacIntegrity.create(
- new IntegrityTransform(
- SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_256_128),
- IkeMessage.getSecurityProvider()));
- byte[] expectedChecksum = TestUtils.hexStringToByteArray(IKE_FRAG_MSG_CHECKSUM);
- doReturn(expectedChecksum).when(mSpyHmacSha256IntegrityMac).generateChecksum(any(), any());
-
- // Set up encryption algorithm
- mSpyAesCbcCipher =
- spy(
- (IkeNormalModeCipher)
- IkeCipher.create(
- new EncryptionTransform(
- SaProposal.ENCRYPTION_ALGORITHM_AES_CBC,
- SaProposal.KEY_LEN_AES_128),
- IkeMessage.getSecurityProvider()));
- byte[] expectedDecryptedPaddedData =
- TestUtils.hexStringToByteArray(
- IKE_FRAG_MSG_DECRYPTED_BODY_HEX_STRING + IKE_FRAG_MSG_PADDING);
- doReturn(expectedDecryptedPaddedData).when(mSpyAesCbcCipher).decrypt(any(), any(), any());
- }
-
- private IkeSkfPayload decodeAndDecryptFragMsg(byte[] message) throws Exception {
- IkeSkfPayload payload =
- (IkeSkfPayload)
- IkePayloadFactory.getIkeSkPayload(
- true /*isSkf*/,
- message,
- mSpyHmacSha256IntegrityMac,
- mSpyAesCbcCipher,
- new byte[0] /*integrityKey*/,
- new byte[0] /*decryptionKey*/)
- .first;
- return payload;
- }
-
- @Test
- public void testDecode() throws Exception {
- byte[] message = TestUtils.hexStringToByteArray(IKE_FRAG_MSG_HEX_STRING);
-
- IkeSkfPayload payload = decodeAndDecryptFragMsg(message);
-
- assertEquals(IkePayload.PAYLOAD_TYPE_SKF, payload.payloadType);
- assertEquals(FRAGMENT_NUM, payload.fragmentNum);
- assertEquals(TOTAL_FRAGMENTS, payload.totalFragments);
- assertArrayEquals(mDecryptedData, payload.getUnencryptedData());
- }
-
- @Test
- public void testDecodeThrowsForZeroFragNum() throws Exception {
- byte[] message = TestUtils.hexStringToByteArray(IKE_FRAG_MSG_HEX_STRING);
-
- // Set Fragment Number to zero
- message[FRAGMENT_NUM_OFFSET] = 0;
- message[FRAGMENT_NUM_OFFSET + 1] = 0;
-
- try {
- decodeAndDecryptFragMsg(message);
- fail("Expected to fail because Fragment Number is zero.");
- } catch (InvalidSyntaxException expected) {
- }
- }
-
- @Test
- public void testDecodeThrowsForZeroTotalFragments() throws Exception {
- byte[] message = TestUtils.hexStringToByteArray(IKE_FRAG_MSG_HEX_STRING);
-
- // Set Total Fragments Number to zero
- message[TOTAL_FRAGMENTS_OFFET] = 0;
- message[TOTAL_FRAGMENTS_OFFET + 1] = 0;
-
- try {
- decodeAndDecryptFragMsg(message);
- fail("Expected to fail because Total Fragments Number is zero.");
- } catch (InvalidSyntaxException expected) {
- }
- }
-
- @Test
- public void testDecodeThrowsWhenFragNumIsLargerThanTotalFragments() throws Exception {
- byte[] message = TestUtils.hexStringToByteArray(IKE_FRAG_MSG_HEX_STRING);
-
- // Set Fragment Number to 5
- message[FRAGMENT_NUM_OFFSET] = 0;
- message[FRAGMENT_NUM_OFFSET + 1] = 5;
-
- // Set Total Fragments Number to 2
- message[TOTAL_FRAGMENTS_OFFET] = 0;
- message[TOTAL_FRAGMENTS_OFFET + 1] = 2;
-
- try {
- decodeAndDecryptFragMsg(message);
- fail(
- "Expected to fail because Fragment Number is larger than"
- + " Total Fragments Number");
- } catch (InvalidSyntaxException expected) {
- }
- }
-
- @Test
- public void testEncode() throws Exception {
- byte[] message = TestUtils.hexStringToByteArray(IKE_FRAG_MSG_HEX_STRING);
- IkeSkfPayload payload = decodeAndDecryptFragMsg(message);
-
- int payloadLength = payload.getPayloadLength();
- ByteBuffer buffer = ByteBuffer.allocate(payloadLength);
- payload.encodeToByteBuffer(IkePayload.PAYLOAD_TYPE_NO_NEXT, buffer);
-
- byte[] expectedPayloadBytes =
- Arrays.copyOfRange(message, IkeHeader.IKE_HEADER_LENGTH, message.length);
- assertArrayEquals(expectedPayloadBytes, buffer.array());
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeTestUtils.java b/tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeTestUtils.java
deleted file mode 100644
index 05474379..00000000
--- a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeTestUtils.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2019 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.message;
-
-import static com.android.internal.net.ipsec.ike.message.IkeMessage.DECODE_STATUS_UNPROTECTED_ERROR;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import android.net.ipsec.ike.exceptions.IkeProtocolException;
-import android.util.Pair;
-
-import com.android.internal.net.TestUtils;
-import com.android.internal.net.ipsec.ike.message.IkeMessage.DecodeResult;
-import com.android.internal.net.ipsec.ike.message.IkeMessage.DecodeResultError;
-
-import java.nio.ByteBuffer;
-
-/**
- * IkeTestUtils provides utility methods for testing IKE library.
- *
- * <p>TODO: Consider moving it under ikev2/
- */
-public final class IkeTestUtils {
- public static IkePayload hexStringToIkePayload(
- @IkePayload.PayloadType int payloadType, boolean isResp, String payloadHexString)
- throws IkeProtocolException {
- byte[] payloadBytes = TestUtils.hexStringToByteArray(payloadHexString);
- // Returned Pair consists of the IkePayload and the following IkePayload's type.
- Pair<IkePayload, Integer> pair =
- IkePayloadFactory.getIkePayload(payloadType, isResp, ByteBuffer.wrap(payloadBytes));
- return pair.first;
- }
-
- public static <T extends IkeProtocolException> T decodeAndVerifyUnprotectedErrorMsg(
- byte[] inputPacket, Class<T> expectedException) throws Exception {
- IkeHeader header = new IkeHeader(inputPacket);
- DecodeResult decodeResult = IkeMessage.decode(0, header, inputPacket);
-
- assertEquals(DECODE_STATUS_UNPROTECTED_ERROR, decodeResult.status);
- DecodeResultError resultError = (DecodeResultError) decodeResult;
- assertNotNull(resultError.ikeException);
- assertTrue(expectedException.isInstance(resultError.ikeException));
-
- return (T) resultError.ikeException;
- }
-
- public static IkeSkfPayload makeDummySkfPayload(
- byte[] unencryptedData, int fragNum, int totalFrags) throws Exception {
- IkeEncryptedPayloadBody mockEncryptedBody = mock(IkeEncryptedPayloadBody.class);
- when(mockEncryptedBody.getUnencryptedData()).thenReturn(unencryptedData);
- return new IkeSkfPayload(mockEncryptedBody, fragNum, totalFrags);
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeTsPayloadTest.java b/tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeTsPayloadTest.java
deleted file mode 100644
index cbd6f930..00000000
--- a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/message/IkeTsPayloadTest.java
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (C) 2019 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.message;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import android.net.ipsec.ike.IkeTrafficSelector;
-
-import com.android.internal.net.TestUtils;
-
-import libcore.net.InetAddressUtils;
-
-import org.junit.Test;
-
-import java.net.Inet4Address;
-import java.nio.ByteBuffer;
-
-public final class IkeTsPayloadTest {
- private static final String TS_INITIATOR_PAYLOAD_HEX_STRING =
- "2d00002802000000070000100010fff0c0000264c0000365070000100000ffffc0000464c0000466";
-
- private static final int NUMBER_OF_TS = 2;
-
- private static final int TS_ONE_START_PORT = 16;
- private static final int TS_ONE_END_PORT = 65520;
- private static final Inet4Address TS_ONE_START_ADDRESS =
- (Inet4Address) (InetAddressUtils.parseNumericAddress("192.0.2.100"));
- private static final Inet4Address TS_ONE_END_ADDRESS =
- (Inet4Address) (InetAddressUtils.parseNumericAddress("192.0.3.101"));
-
- private static final int TS_TWO_START_PORT = 0;
- private static final int TS_TWO_END_PORT = 65535;
- private static final Inet4Address TS_TWO_START_ADDRESS =
- (Inet4Address) (InetAddressUtils.parseNumericAddress("192.0.4.100"));
- private static final Inet4Address TS_TWO_END_ADDRESS =
- (Inet4Address) (InetAddressUtils.parseNumericAddress("192.0.4.102"));
-
- private IkeTrafficSelector mTsOne;
- private IkeTrafficSelector mTsTwo;
-
- public IkeTsPayloadTest() {
- mTsOne =
- new IkeTrafficSelector(
- IkeTrafficSelector.TRAFFIC_SELECTOR_TYPE_IPV4_ADDR_RANGE,
- TS_ONE_START_PORT,
- TS_ONE_END_PORT,
- TS_ONE_START_ADDRESS,
- TS_ONE_END_ADDRESS);
- mTsTwo =
- new IkeTrafficSelector(
- IkeTrafficSelector.TRAFFIC_SELECTOR_TYPE_IPV4_ADDR_RANGE,
- TS_TWO_START_PORT,
- TS_TWO_END_PORT,
- TS_TWO_START_ADDRESS,
- TS_TWO_END_ADDRESS);
- }
-
- @Test
- public void testDecodeTsInitiatorPayload() throws Exception {
- ByteBuffer inputBuffer =
- ByteBuffer.wrap(TestUtils.hexStringToByteArray(TS_INITIATOR_PAYLOAD_HEX_STRING));
-
- IkePayload payload =
- IkePayloadFactory.getIkePayload(
- IkePayload.PAYLOAD_TYPE_TS_INITIATOR, false, inputBuffer)
- .first;
- assertTrue(payload instanceof IkeTsPayload);
-
- IkeTsPayload tsPayload = (IkeTsPayload) payload;
- assertEquals(IkePayload.PAYLOAD_TYPE_TS_INITIATOR, tsPayload.payloadType);
- assertEquals(NUMBER_OF_TS, tsPayload.numTs);
- }
-
- @Test
- public void testBuildAndEncodeTsPayload() throws Exception {
- IkeTsPayload tsPayload =
- new IkeTsPayload(true /*isInitiator*/, new IkeTrafficSelector[] {mTsOne, mTsTwo});
-
- ByteBuffer byteBuffer = ByteBuffer.allocate(tsPayload.getPayloadLength());
- tsPayload.encodeToByteBuffer(IkePayload.PAYLOAD_TYPE_TS_RESPONDER, byteBuffer);
-
- byte[] expectedBytes = TestUtils.hexStringToByteArray(TS_INITIATOR_PAYLOAD_HEX_STRING);
- assertArrayEquals(expectedBytes, byteBuffer.array());
- }
-
- @Test
- public void testContains() throws Exception {
- IkeTrafficSelector tsOneNarrowPortRange =
- new IkeTrafficSelector(
- IkeTrafficSelector.TRAFFIC_SELECTOR_TYPE_IPV4_ADDR_RANGE,
- TS_ONE_START_PORT + 1,
- TS_ONE_END_PORT,
- TS_ONE_START_ADDRESS,
- TS_ONE_END_ADDRESS);
-
- IkeTrafficSelector tsOneNarrowAddressRange =
- new IkeTrafficSelector(
- IkeTrafficSelector.TRAFFIC_SELECTOR_TYPE_IPV4_ADDR_RANGE,
- TS_ONE_START_PORT,
- TS_ONE_END_PORT,
- (Inet4Address) (InetAddressUtils.parseNumericAddress("192.0.2.200")),
- TS_ONE_END_ADDRESS);
-
- IkeTsPayload tsPayload =
- new IkeTsPayload(true /*isInitiator*/, new IkeTrafficSelector[] {mTsOne, mTsTwo});
-
- IkeTsPayload tsNarrowPortRangePayload =
- new IkeTsPayload(
- true /*isInitiator*/,
- new IkeTrafficSelector[] {tsOneNarrowPortRange, mTsTwo});
-
- IkeTsPayload tsNarrowAddressRangePayload =
- new IkeTsPayload(
- true /*isInitiator*/,
- new IkeTrafficSelector[] {tsOneNarrowAddressRange, mTsTwo});
-
- assertTrue(tsPayload.contains(tsPayload));
- assertTrue(tsPayload.contains(tsNarrowPortRangePayload));
- assertTrue(tsPayload.contains(tsNarrowAddressRangePayload));
-
- assertFalse(tsNarrowPortRangePayload.contains(tsPayload));
- assertFalse(tsNarrowAddressRangePayload.contains(tsPayload));
- assertFalse(tsNarrowAddressRangePayload.contains(tsNarrowPortRangePayload));
- assertFalse(tsNarrowPortRangePayload.contains(tsNarrowAddressRangePayload));
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/testutils/CertUtils.java b/tests/iketests/src/java/com/android/internal/net/ipsec/ike/testutils/CertUtils.java
deleted file mode 100644
index db128c80..00000000
--- a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/testutils/CertUtils.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2019 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.testutils;
-
-import android.content.Context;
-
-import androidx.test.InstrumentationRegistry;
-
-import com.android.internal.net.ipsec.ike.message.IkeMessage;
-import com.android.org.bouncycastle.util.io.pem.PemObject;
-import com.android.org.bouncycastle.util.io.pem.PemReader;
-
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.security.KeyFactory;
-import java.security.cert.CertificateFactory;
-import java.security.cert.X509Certificate;
-import java.security.interfaces.RSAPrivateKey;
-import java.security.spec.PKCS8EncodedKeySpec;
-
-/** CertUtils provides utility methods for creating X509 certificate and private key. */
-public final class CertUtils {
- private static final String PEM_FOLDER_NAME = "pem";
- private static final String KEY_FOLDER_NAME = "key";
-
- /** Creates an X509Certificate with a pem file */
- public static X509Certificate createCertFromPemFile(String fileName) throws Exception {
- Context context = InstrumentationRegistry.getContext();
- InputStream inputStream =
- context.getResources().getAssets().open(PEM_FOLDER_NAME + "/" + fileName);
-
- CertificateFactory factory =
- CertificateFactory.getInstance("X.509", IkeMessage.getSecurityProvider());
- return (X509Certificate) factory.generateCertificate(inputStream);
- }
-
- /** Creates an private key from a PKCS8 format key file */
- public static RSAPrivateKey createRsaPrivateKeyFromKeyFile(String fileName) throws Exception {
- Context context = InstrumentationRegistry.getContext();
- InputStream inputStream =
- context.getResources().getAssets().open(KEY_FOLDER_NAME + "/" + fileName);
-
- PemObject pemObject = new PemReader(new InputStreamReader(inputStream)).readPemObject();
-
- KeyFactory keyFactory = KeyFactory.getInstance("RSA");
- return (RSAPrivateKey)
- keyFactory.generatePrivate(new PKCS8EncodedKeySpec(pemObject.getContent()));
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/testutils/MockIpSecTestUtils.java b/tests/iketests/src/java/com/android/internal/net/ipsec/ike/testutils/MockIpSecTestUtils.java
deleted file mode 100644
index 742ff240..00000000
--- a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/testutils/MockIpSecTestUtils.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2019 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.testutils;
-
-import static android.system.OsConstants.AF_INET;
-import static android.system.OsConstants.IPPROTO_UDP;
-import static android.system.OsConstants.SOCK_DGRAM;
-
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyObject;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.net.IpSecManager;
-import android.net.IpSecSpiResponse;
-import android.net.IpSecUdpEncapResponse;
-import android.system.Os;
-
-import androidx.test.InstrumentationRegistry;
-
-import com.android.server.IpSecService;
-
-/** This class provides utility methods for mocking IPsec surface. */
-public final class MockIpSecTestUtils {
- private static final int DUMMY_CHILD_SPI = 0x2ad4c0a2;
- private static final int DUMMY_CHILD_SPI_RESOURCE_ID = 0x1234;
-
- private static final int DUMMY_UDP_ENCAP_PORT = 34567;
- private static final int DUMMY_UDP_ENCAP_RESOURCE_ID = 0x3234;
-
- private Context mContext;
- private IpSecService mMockIpSecService;
- private IpSecManager mIpSecManager;
-
- private MockIpSecTestUtils() throws Exception {
- mMockIpSecService = mock(IpSecService.class);
- mContext = InstrumentationRegistry.getContext();
- mIpSecManager = new IpSecManager(mContext, mMockIpSecService);
-
- when(mMockIpSecService.allocateSecurityParameterIndex(anyString(), anyInt(), anyObject()))
- .thenReturn(
- new IpSecSpiResponse(
- IpSecManager.Status.OK,
- DUMMY_CHILD_SPI_RESOURCE_ID,
- DUMMY_CHILD_SPI));
-
- when(mMockIpSecService.openUdpEncapsulationSocket(anyInt(), anyObject()))
- .thenReturn(
- new IpSecUdpEncapResponse(
- IpSecManager.Status.OK,
- DUMMY_UDP_ENCAP_RESOURCE_ID,
- DUMMY_UDP_ENCAP_PORT,
- Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)));
- }
-
- public static MockIpSecTestUtils setUpMockIpSec() throws Exception {
- return new MockIpSecTestUtils();
- }
-
- public static IpSecSpiResponse buildDummyIpSecSpiResponse(int spi) throws Exception {
- return new IpSecSpiResponse(IpSecManager.Status.OK, DUMMY_CHILD_SPI_RESOURCE_ID, spi);
- }
-
- public Context getContext() {
- return mContext;
- }
-
- public IpSecManager getIpSecManager() {
- return mIpSecManager;
- }
-
- public IpSecService getIpSecService() {
- return mMockIpSecService;
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/utils/RetransmitterTest.java b/tests/iketests/src/java/com/android/internal/net/ipsec/ike/utils/RetransmitterTest.java
deleted file mode 100644
index 1fddb1d9..00000000
--- a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/utils/RetransmitterTest.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (C) 2019 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 static com.android.internal.net.ipsec.ike.IkeSessionStateMachine.CMD_RETRANSMIT;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyObject;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-import android.os.Handler;
-import android.os.Message;
-
-import com.android.internal.net.ipsec.ike.message.IkeMessage;
-
-import org.junit.Before;
-import org.junit.Test;
-
-public final class RetransmitterTest {
- private Handler mMockHandler;
- private IkeMessage mMockIkeMessage;
- private TestRetransmitter mRetransmitter;
-
- private class TestRetransmitter extends Retransmitter {
- int mSendCallCount; // Defaults to 0
- boolean mFailed; // Defaults to false
-
- TestRetransmitter(Handler handler, IkeMessage message) {
- super(handler, message);
- }
-
- @Override
- public void send(IkeMessage msg) {
- mSendCallCount++;
- }
-
- @Override
- public void handleRetransmissionFailure() {
- mFailed = true;
- }
- }
-
- @Before
- public void setUp() throws Exception {
- mMockHandler = mock(Handler.class);
- when(mMockHandler.obtainMessage(eq(CMD_RETRANSMIT), anyObject()))
- .thenReturn(mock(Message.class));
-
- mMockIkeMessage = mock(IkeMessage.class);
- mRetransmitter = new TestRetransmitter(mMockHandler, mMockIkeMessage);
- }
-
- @Test
- public void testSendRequestAndQueueRetransmit() throws Exception {
- mRetransmitter.retransmit();
- assertEquals(1, mRetransmitter.mSendCallCount);
- verify(mMockHandler).obtainMessage(eq(CMD_RETRANSMIT), eq(mRetransmitter));
- verify(mMockHandler)
- .sendMessageDelayed(any(Message.class), eq(Retransmitter.RETRANSMIT_TIMEOUT_MS));
- }
-
- @Test
- public void testRetransmitQueuesExponentialRetransmit() throws Exception {
- mRetransmitter.retransmit();
-
- for (int i = 0; i <= Retransmitter.RETRANSMIT_MAX_ATTEMPTS; i++) {
- long expectedTimeout =
- (long)
- (Retransmitter.RETRANSMIT_TIMEOUT_MS
- * Math.pow(Retransmitter.RETRANSMIT_BACKOFF_FACTOR, i));
-
- assertEquals(i + 1, mRetransmitter.mSendCallCount);
- assertFalse(mRetransmitter.mFailed);
-
- // This call happens with the same arguments each time
- verify(mMockHandler, times(i + 1))
- .obtainMessage(eq(CMD_RETRANSMIT), eq(mRetransmitter));
-
- // But the expected timeout changes every time
- verify(mMockHandler).sendMessageDelayed(any(Message.class), eq(expectedTimeout));
-
- verifyNoMoreInteractions(mMockHandler);
-
- // Trigger next round of retransmissions.
- mRetransmitter.retransmit();
- }
- }
-
- @Test
- public void testRetransmitterCallsRetranmissionsFailedOnMaxTries() throws Exception {
- mRetransmitter.retransmit();
-
- // Exhaust all retransmit attempts
- for (int i = 0; i <= Retransmitter.RETRANSMIT_MAX_ATTEMPTS; i++) {
- mRetransmitter.retransmit();
- }
-
- assertTrue(mRetransmitter.mFailed);
- }
-
- @Test
- public void testRetransmitterStopsRetransmitting() throws Exception {
- mRetransmitter.stopRetransmitting();
-
- verify(mMockHandler).removeMessages(eq(CMD_RETRANSMIT), eq(mRetransmitter));
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/utils/LogTest.java b/tests/iketests/src/java/com/android/internal/net/utils/LogTest.java
deleted file mode 100644
index 23305aa7..00000000
--- a/tests/iketests/src/java/com/android/internal/net/utils/LogTest.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2019 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.utils;
-
-import static org.junit.Assert.assertEquals;
-
-import org.junit.Test;
-
-public class LogTest {
- private static final String TAG = "IkeLogTest";
- private static final String PII = "123456789ABCDEF"; // "IMSI"
- private static final String HEX_STRING = "00112233445566778899AABBCCDDEEFF";
- private static final byte[] HEX_BYTES = new byte[] {
- (byte) 0x00, (byte) 0x11, (byte) 0x22, (byte) 0x33, (byte) 0x44, (byte) 0x55,
- (byte) 0x66, (byte) 0x77, (byte) 0x88, (byte) 0x99, (byte) 0xAA, (byte) 0xBB,
- (byte) 0xCC, (byte) 0xDD, (byte) 0xEE, (byte) 0xFF
- };
-
- @Test
- public void testPii() {
- // Log(String tag, boolean isEngBuild, boolean logSensitive);
- String result = new Log(TAG, false, false).pii(PII);
- assertEquals(Integer.toString(PII.hashCode()), result);
-
- result = new Log(TAG, true, false).pii(PII);
- assertEquals(Integer.toString(PII.hashCode()), result);
-
- result = new Log(TAG, false, true).pii(PII);
- assertEquals(Integer.toString(PII.hashCode()), result);
-
- result = new Log(TAG, true, true).pii(PII);
- assertEquals(PII, result);
-
- result = new Log(TAG, true, true).pii(HEX_BYTES);
- assertEquals(HEX_STRING, result);
- }
-
- @Test
- public void testByteArrayToHexString() {
- assertEquals("", Log.byteArrayToHexString(null));
-
- assertEquals("", Log.byteArrayToHexString(new byte[0]));
-
- assertEquals(HEX_STRING, Log.byteArrayToHexString(HEX_BYTES));
- }
-}
diff --git a/tests/iketests/src/java/com/android/internal/net/utils/SimpleStateMachineTest.java b/tests/iketests/src/java/com/android/internal/net/utils/SimpleStateMachineTest.java
deleted file mode 100644
index 2ee8dc53..00000000
--- a/tests/iketests/src/java/com/android/internal/net/utils/SimpleStateMachineTest.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2019 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.utils;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import com.android.internal.net.utils.SimpleStateMachine.SimpleState;
-
-import org.junit.Before;
-import org.junit.Test;
-
-public class SimpleStateMachineTest {
- private static final String INPUT = "input";
- private static final String OUTPUT = "output";
-
- private SimpleStateMachine<String, String> mSimpleStateMachine;
- private SimpleState mMockStartState;
- private SimpleState mMockFinalState;
-
- @Before
- public void setUp() {
- mMockStartState = mock(SimpleState.class);
- mMockFinalState = mock(SimpleState.class);
-
- mSimpleStateMachine = new SimpleStateMachine(){};
- mSimpleStateMachine.transitionTo(mMockStartState);
- }
-
- @Test
- public void testProcess() {
- when(mMockStartState.process(INPUT)).thenReturn(OUTPUT);
- String result = mSimpleStateMachine.process(INPUT);
- assertEquals(OUTPUT, result);
- verify(mMockStartState).process(INPUT);
- }
-
- @Test
- public void testTransitionTo() {
- mSimpleStateMachine.transitionTo(mMockFinalState);
- assertEquals(mMockFinalState, mSimpleStateMachine.mState);
- }
-
- @Test
- public void testTransitionToNull() {
- try {
- mSimpleStateMachine.transitionTo(null);
- fail("IllegalArgumentException expected");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void testTransitionAndProcess() {
- when(mMockFinalState.process(INPUT)).thenReturn(OUTPUT);
- String result = mSimpleStateMachine.transitionAndProcess(mMockFinalState, INPUT);
- assertEquals(OUTPUT, result);
- verify(mMockFinalState).process(INPUT);
- }
-
- @Test
- public void testTransitionAndProcessToNull() {
- try {
- mSimpleStateMachine.transitionAndProcess(null, INPUT);
- fail("IllegalArgumentException expected");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void testProcessNullState() {
- SimpleStateMachine simpleStateMachine = new SimpleStateMachine() {};
- try {
- simpleStateMachine.process(new Object());
- fail("IllegalStateException expected");
- } catch (IllegalStateException expected) {
- }
- }
-}