blob: 938aca1fbcb3ec2e92dde36559e0ed87c3f7bbf0 [file] [log] [blame]
/*
* Copyright (C) 2020 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.crypto.TlsSessionTest.RESULT_FINISHED_OK;
import static com.android.internal.net.eap.crypto.TlsSessionTest.RESULT_NEED_UNWRAP_OK;
import static com.android.internal.net.eap.crypto.TlsSessionTest.RESULT_NEED_WRAP_OK;
import static com.android.internal.net.eap.crypto.TlsSessionTest.RESULT_NOT_HANDSHAKING_OK;
import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_REQUEST_AKA_IDENTITY_PACKET;
import static com.android.internal.net.eap.message.EapTestMessageDefinitions.EAP_SUCCESS;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.argThat;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
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.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import android.net.eap.EapSessionConfig;
import com.android.internal.net.eap.crypto.TlsSession;
import com.android.internal.net.eap.crypto.TlsSessionFactory;
import com.android.internal.net.eap.statemachine.EapStateMachine;
import com.android.internal.net.eap.statemachine.EapTtlsMethodStateMachine;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentMatcher;
import java.nio.ByteBuffer;
import java.util.Arrays;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLEngineResult;
import javax.net.ssl.SSLSession;
/**
* End-to-end tests for EAP-TTLS
*
* <p>Due to limitations where Conscrypt's SSLEngine offloads to native BoringSSL code, the TLS
* client random is generated by hardware and CANNOT be seeded or mocked. As such, this test mocks
* out the entire SSLEngine code.
*
* <p>The same is true for TLS keying material generation which is mocked via a TlsSession spy.
*/
// TODO(b/166781047): Add second SSLEngine to EAP-TTLS end-to-end testing
public class EapTtlsTest extends EapMethodEndToEndTest {
private static final long AUTHENTICATOR_TIMEOUT_MILLIS = 250L;
private static final int APPLICATION_BUFFER_SIZE_TLS_MESSAGE = 16384;
private static final int PACKET_BUFFER_SIZE_TLS_MESSAGE = 16384;
private static final byte[] EMPTY_BYTE_ARRAY = new byte[PACKET_BUFFER_SIZE_TLS_MESSAGE];
public static final byte[] TLS_MSK =
hexStringToByteArray(
"00112233445566778899AABBCCDDEEFF"
+ "00112233445566778899AABBCCDDEEFF"
+ "00112233445566778899AABBCCDDEEFF"
+ "00112233445566778899AABBCCDDEEFF");
public static final byte[] TLS_EMSK =
hexStringToByteArray(
"FFEEDDCCBBAA99887766554433221100"
+ "FFEEDDCCBBAA99887766554433221100"
+ "FFEEDDCCBBAA99887766554433221100"
+ "FFEEDDCCBBAA99887766554433221100");
// TUNNELED MSCHAPV2 (Phase 2)
private static final String MSCHAPV2_USERNAME = "mschapv2.android.net";
private static final String MSCHAPV2_PASSWORD = "mschappwd";
private static final byte[] PEER_CHALLENGE =
hexStringToByteArray("6592788337ED192AA396532E0AE65579");
private static final byte[] MSCHAPV2_MSK =
hexStringToByteArray(
"FA90B81CFF52D4FE37E029C84EC1E8B442AE19E482B0CA63FAEFF833C2DC86E60000"
+ "000000000000000000000000000000000000000000000000000000000000");
private static final int EMSK_LEN = 64;
private static final byte[] MSCHAPV2_EMSK = new byte[EMSK_LEN];
// TLSv1.2 Handshake Messages
private static final String CLIENT_HELLO_STRING =
"1603010085010000810303DE76A65F038E90315BB25B49CB9AB4E2540586C3B25851604C8D6E"
+ "FECA11C16D00001CC02BC02CCCA9C02FC030CCA8C009C00AC013C014009C009D00"
+ "2F00350100003C00170000FF01000100000A00080006001D00170018000B000201"
+ "00000500050100000000000D001400120403080404010503080505010806060102"
+ "01";
private static final byte[] CLIENT_HELLO_BYTES = hexStringToByteArray(CLIENT_HELLO_STRING);
private static final String SERVER_HELLO_INITIAL_FRAGMENT_STRING =
"16030304140200003603035F46FED4999A26EE4CA1E4DB034E3BADAD262359A36885E19187F8"
+ "5454F08E9E105188276593B74D74C1E95C9779EE83E9002F000B00037300037000"
+ "036D3082036930820251A0030201020208570C6688A0ABF919300D06092A864886"
+ "F70D01010B05003042310B30090603550406130255533110300E060355040A1307"
+ "416E64726F69643121301F06035504031318726F6F742E63612E746573742E616E"
+ "64726F69642E6E6574301E170D3230303530393031323331305A170D3233303530"
+ "393031323331305A3045310B30090603550406130255533110300E060355040A13"
+ "07416E64726F6964312430220603550403131B7365727665722E746573742E696B"
+ "652E616E64726F69642E6E657430820122300D06092A864886F70D010101050003"
+ "82010F003082010A0282010100C66872A68B0CFDD8453EF987A62AA4F9B251DB27"
+ "F0E4079686CA678EE2090755F7FD314245398B2EC43C5464509D2298940609DABE"
+ "57A60610D3DAF80D801B1F02F6A1262D92D333A9AC76D89951EF7733647E03DD44"
+ "ED2A4EC274BB5CD4D3C55D8166949F6E13F4C3D695EF5F08FDBDD629F2D56E96CD"
+ "91BFE84136D80CE274F516AC8CA69D6CAF9B762C8771F96A434783C2F02EC71317"
+ "AEC38C0E058EA65A9E2E12B5AA0C505F40D237773C29C9246D9EE3152925F941C8"
+ "FA67E6EA2A6B408009D9A9DA0B7A09F8B016C42C3156D5060DAA9F5081D24EF4FF"
+ "51DA523C2D9BCA71DDB207CCC9DBE24AD447E1F44AF386A16745CD41CDBB01C4A2"
+ "416E9A595D0203010001A360305E301F0603551D23041830168014499FA84785D7"
+ "8363F757A422947EB1584212801A30260603551D11041F301D821B736572766572"
+ "2E746573742E696B652E616E64726F69642E6E657430130603551D25040C300A06"
+ "082B06010505070301300D06092A864886F70D01010B050003820101007067F0B9"
+ "9698CA73410D703C83D294646D8734EF92C6CCBBE5E80A37A2B57DDD471739A8E2"
+ "5BF03C3BB571CEBA423B80B294AAD8341690A9094D680910057B36C5AF58431421"
+ "AE038A71A56FC9EA1C1B160C6B97F7326B364A0A5033A818DC37EDE5031FCF7D75"
+ "2683DAAFDE59FBB030F754F3D32FBCCD74D7A594967F2F8E2A921099689A61B7BF"
+ "9678F48F817BCF873B04A45112A17A4818981E7BF83F1DCB038C000DDCFD372A9D"
+ "00DADC7A43A5DA3C9C0BB36111844A72110CE7B3CED711705D5774B64C2419AAF7"
+ "888BBBC093CA0B7CFA8E118279B2AE30C0D28E0EE203B1D9DE34C29E58A8BA50B5"
+ "4CBB917CFFC87604C2646CFFB7511A557F951CDD4E0D00005B020140000E000C04"
+ "0105010601030102010101004600443042310B3009060355040613025553311030"
+ "0E060355040A1307416E64726F69643121301F";
private static final byte[] SERVER_HELLO_INITIAL_FRAGMENT_BYTES =
hexStringToByteArray(SERVER_HELLO_INITIAL_FRAGMENT_STRING);
private static final String SERVER_HELLO_FINAL_FRAGMENT_STRING =
"06035504031318726F6F742E63612E746573742E616E64726F69642E6E65740E000000";
private static final byte[] SERVER_HELLO_FINAL_FRAGMENT_BYTES =
hexStringToByteArray(SERVER_HELLO_FINAL_FRAGMENT_STRING);
private static final byte[] SERVER_HELLO_BYTES =
hexStringToByteArray(
SERVER_HELLO_INITIAL_FRAGMENT_STRING + SERVER_HELLO_FINAL_FRAGMENT_STRING);
private static final String CLIENT_FINISHED_STRING =
"16030300070B0000030000001603030106100001020100A061D18580E2ACA2FDBB714012D180C"
+ "595CB51ED7B89EF394CFF7265C68756CF55CBEE47284A0992B3FC64A77F28E5E98F"
+ "B4F681BD67A87CD4DA115D70C74F96EB7AFCA822C0000824AA6C73DAA1233535EE0"
+ "B63D0E52F5EB645BC617170957B68ADEDE770559899813C0F174787F0C73ED87A2A"
+ "ED88D3C4438D8990D16DE9D6125EA772342123609941DD99CDE4A79E24D6C300AE5"
+ "245266275EA73B5FE4955ED7C25D34D60E7E925B33EDA75BE14A5B16FC45E7E6BDA"
+ "11C449A21D7455DD42D6B9418D04210CF50FD7D0A2B79882A4BE3EE68C2E9149F65"
+ "465432B483255B1D0076F74030D252131FE92DEB72B7FA40DE649F51AAE4BC28A31"
+ "ED8670E3AC221403030001011603030040016BFABBF2C74A11DDCFAFC8D815FA7C0"
+ "B4D8705A4BC44699242B5C4D413A1EEDBAAD2F1951713E35B35A99D9B3EA916F12F"
+ "297CEEC349173FE75C1B87F1CD66";
private static final byte[] CLIENT_FINISHED_BYTES =
hexStringToByteArray(CLIENT_FINISHED_STRING);
private static final String SERVER_FINISHED_STRING =
"14030300010116030300404570EA39954A9A370FDFCADC5DEDC072B9C204974645FD9D3E22383"
+ "26B76D2160F6EB88433C2E64FEB0F9204AC963D92399417166EC7CBF2E4F723C879"
+ "0C1255";
private static final byte[] SERVER_FINISHED_BYTES =
hexStringToByteArray(SERVER_FINISHED_STRING);
// Phase 2 Messages (EAP-MSCHAPV2)
private static final String ENCRYPTED_EAP_IDENTITY_AVP_STRING =
"170303004070739851715B5BA7CC0237522560F811BFB47A7877E6882B524A3225B30EED1C66E7"
+ "BE834C94B411995CF01C824E19B51E9E6D17AB273E218733071390D16752";
private static final byte[] ENCRYPTED_EAP_IDENTITY_AVP_BYTES =
hexStringToByteArray(ENCRYPTED_EAP_IDENTITY_AVP_STRING);
private static final String DECRYPTED_EAP_IDENTITY_AVP_STRING =
"0000004F" + "40" + "00000D" // AVP Code | AVP Flags | AVP Length
+ "0210000501" // EAP-Response/Identity
+ "000000"; // Padding
private static final byte[] DECRYPTED_EAP_IDENTITY_AVP_BYTES =
hexStringToByteArray(DECRYPTED_EAP_IDENTITY_AVP_STRING);
private static final String EAP_MSCHAP_V2_ENCRYPTED_CHALLENGE_REQUEST_AVP_STRING =
"1703030060AB010671AA326B4421D4F7336C476D0595E7C9104ADD9975FAC10CDA63DB82DB989F7"
+ "6A6E41C2FAFE6C4C3BA4D4F49F08FF1FC88F0AD47BA9913D962A2D6F0C95D68AE879E"
+ "A305FFE6A9D999C79A4B20D3B4C067A0E17F848D44C16AF61B27F5";
private static final byte[] EAP_MSCHAP_V2_ENCRYPTED_CHALLENGE_REQUEST_AVP_BYTES =
hexStringToByteArray(EAP_MSCHAP_V2_ENCRYPTED_CHALLENGE_REQUEST_AVP_STRING);
private static final String EAP_MSCHAP_V2_DECRYPTED_CHALLENGE_REQUEST_AVP_STRING =
"0000004F" + "40" + "00002C" // AVP Code | AVP Flags | AVP Length
+ "01640024" // EAP-Request | ID | length in bytes
+ "1A0164" // EAP-MSCHAPv2 | Request | MSCHAPv2 ID
+ "001F10" // MS length | Value Size (0x10)
+ "DCB648175C0A8200F226F94F0964F9DE" // Authenticator-Challenge
+ "6D736368617074657374"; // Server-Name hex("mschaptest")
private static final byte[] EAP_MSCHAP_V2_DECRYPTED_CHALLENGE_REQUEST_AVP_BYTES =
hexStringToByteArray(EAP_MSCHAP_V2_DECRYPTED_CHALLENGE_REQUEST_AVP_STRING);
private static final String EAP_MSCHAP_V2_ENCRYPTED_CHALLENGE_RESPONSE_AVP_STRING =
"17030300805D5941EECB4D1F040B3C199FBB078393220526B3C7A7F73D16C0D45EBE56CBA1E80E0"
+ "1EB5B56E367B27B211C05D3713E389516B14568FB95679F960D61B5620F23D49B2A8F"
+ "999C308004B389111F49B56F3AFDFEE4765ADF2ADBBB82E7D5AE8D4E25FB10D67091E"
+ "E39E3A39F0F1AFB720231E3D824565349550BC7988C4E2E39";
private static final byte[] EAP_MSCHAP_V2_ENCRYPTED_CHALLENGE_RESPONSE_AVP_BYTES =
hexStringToByteArray(EAP_MSCHAP_V2_ENCRYPTED_CHALLENGE_RESPONSE_AVP_STRING);
private static final String EAP_MSCHAP_V2_DECRYPTED_CHALLENGE_RESPONSE_AVP_STRING =
"0000004F" + "40" + "000057" // AVP Code | AVP Flags | AVP Length
+ "0264004F" // EAP-Response | ID | length in bytes
+ "1A0264" // EAP-MSCHAPv2 | Response | MSCHAPv2 ID
+ "004A31" // MS length | Value Size (0x31)
+ "6592788337ED192AA396532E0AE65579" // Peer-Challenge
+ "0000000000000000" // 8B (reserved)
+ "6027E628F0090D596D4FF5FE451FC537CD54F7BD70F05C73" // NT-Response
+ "00" // Flags
+ "6D736368617076322E616E64726F69642E6E657400"; // hex(USERNAME)
private static final byte[] EAP_MSCHAP_V2_DECRYPTED_CHALLENGE_RESPONSE_AVP_BYTES =
hexStringToByteArray(EAP_MSCHAP_V2_DECRYPTED_CHALLENGE_RESPONSE_AVP_STRING);
private static final String EAP_MSCHAP_V2_ENCRYPTED_SUCCESS_REQUEST_AVP_STRING =
"17030300800A7516313DA811E690BAF1E76B5C25A1B57B891FC03AECDE89B5C75044B3111966EF91"
+ "49ADA96F0720C055C9A124001097F1BD5E9728A38CA160BA433A95077B5B5367EDF8E3"
+ "2EAAD7CDDED43BBDAEC4C1AD2CC919D591B3A744CCE1868295AD5F0115E7443E74AEA4"
+ "38CFF96E13ED36F0E539537CE676E251B82BA9B1153569";
private static final byte[] EAP_MSCHAP_V2_ENCRYPTED_SUCCESS_REQUEST_AVP_BYTES =
hexStringToByteArray(EAP_MSCHAP_V2_ENCRYPTED_SUCCESS_REQUEST_AVP_STRING);
private static final String EAP_MSCHAP_V2_DECRYPTED_SUCCESS_REQUEST_AVP_STRING =
"0000004F" + "40" + "000051" // AVP Code | AVP Flags | AVP Length
+ "01650049" // EAP-Request | ID | length in bytes
+ "1A03640044" // EAP-MSCHAPv2 | Success | MSCHAPv2 ID | MS length
+ "533D" // hex("S=")
+ "3744354237394335353736334632433341323442"
+ "4345334134323845353245364430314146444636" // hex("<auth_string>")
+ "204D3D" // hex(" M=")
+ "57656C636F6D65326561706D73636861703200000000"; // hex("Welcome2eapmschap2")
private static final byte[] EAP_MSCHAP_V2_DECRYPTED_SUCCESS_REQUEST_AVP_BYTES =
hexStringToByteArray(EAP_MSCHAP_V2_DECRYPTED_SUCCESS_REQUEST_AVP_STRING);
private static final String EAP_MSCHAP_V2_ENCRYPTED_SUCCESS_RESPONSE_AVP_STRING =
"1703030040CD43A46C500065962396E4BEDA72CD43B3316F923AB2108DF93ECFA70192A852485E6D"
+ "69105B0C57E2C57780C9C8D74BE705CC87F5C862FF30C1138390C8BE73";
private static final byte[] EAP_MSCHAP_V2_ENCRYPTED_SUCCESS_RESPONSE_AVP_BYTES =
hexStringToByteArray(EAP_MSCHAP_V2_ENCRYPTED_SUCCESS_RESPONSE_AVP_STRING);
private static final String EAP_MSCHAP_V2_DECRYPTED_SUCCESS_RESPONSE_AVP_STRING =
"0000004F" + "40" + "00000E" // AVP Code | AVP Flags | AVP Length
+ "02650006" // EAP-Response | ID | length in bytes
+ "1A030000"; // EAP-MSCHAPv2 | Success
private static final byte[] EAP_MSCHAP_V2_DECRYPTED_SUCCESS_RESPONSE_AVP_BYTES =
hexStringToByteArray(EAP_MSCHAP_V2_DECRYPTED_SUCCESS_RESPONSE_AVP_STRING);
private static final String EAP_MSCHAP_V2_ENCRYPTED_FAILURE_REQUEST_AVP_STRING =
"1703030040CD43A46C500065962396E4BEDA72CD43B3316F923AB2108DF93ECFA70192A852485E6D"
+ "69105B0C57E2C57780C9C8D74BE705CC87F5C862FF30C1138390C8BE73";
private static final byte[] EAP_MSCHAP_V2_ENCRYPTED_FAILURE_REQUEST_AVP_BYTES =
hexStringToByteArray(EAP_MSCHAP_V2_ENCRYPTED_FAILURE_REQUEST_AVP_STRING);
private static final String EAP_MSCHAP_V2_DECRYPTED_FAILURE_REQUEST_AVP_STRING =
"0000004F" + "40" + "000055" // AVP Code | AVP Flags | AVP Length
+ "0113004D" // 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=")
+ "57656C636F6D65326561706D7363686170320000"; // hex("Welcome2eapmschap2")
private static final byte[] EAP_MSCHAP_V2_DECRYPTED_FAILURE_REQUEST_AVP_BYTES =
hexStringToByteArray(EAP_MSCHAP_V2_DECRYPTED_FAILURE_REQUEST_AVP_STRING);
private static final String EAP_MSCHAP_V2_ENCRYPTED_FAILURE_RESPONSE_AVP_STRING =
"1703030040CD43A46C500065962396E4BEDA72CD43B3316F923AB21074BE705CC87F5C862F85E6D83"
+ "69105B0C57E2C57780CDA72CD43B3316F923AB21074BE70CC87F5C862F85E862F";
private static final byte[] EAP_MSCHAP_V2_ENCRYPTED_FAILURE_RESPONSE_AVP_BYTES =
hexStringToByteArray(EAP_MSCHAP_V2_ENCRYPTED_FAILURE_RESPONSE_AVP_STRING);
private static final String EAP_MSCHAP_V2_DECRYPTED_FAILURE_RESPONSE_AVP_STRING =
"0000004F" + "40" + "00000E" // AVP Code | AVP Flags | AVP Length
+ "02130006" // EAP-Response | ID | length in bytes
+ "1A040000"; // EAP-MSCHAPv2 | Failure
private static final byte[] EAP_MSCHAP_V2_DECRYPTED_FAILURE_RESPONSE_AVP_BYTES =
hexStringToByteArray(EAP_MSCHAP_V2_DECRYPTED_FAILURE_RESPONSE_AVP_STRING);
private static final String ENCRYPTED_EAP_AKA_IDENTITY_REQUEST_AVP_STRING =
"1703030040CD43A46C500065962396E4BEDA72CD43B3316F923AB21074BE705CC87F5C862F85E6D83"
+ "F9F56678251443C56";
private static final byte[] ENCRYPTED_EAP_AKA_IDENTITY_REQUEST_AVP_BYTES =
hexStringToByteArray(ENCRYPTED_EAP_AKA_IDENTITY_REQUEST_AVP_STRING);
private static final String DECRYPTED_EAP_AKA_IDENTITY_REQUEST_AVP_STRING =
"0000004F" + "40" + "00000D" // AVP Code | AVP Flags | AVP Length
+ "0110000517000000"; // AKA EAP-Identity Request
private static final byte[] DECRYPTED_EAP_AKA_IDENTITY_REQUEST_AVP_BYTES =
hexStringToByteArray(DECRYPTED_EAP_AKA_IDENTITY_REQUEST_AVP_STRING);
private static final String ENCRYPTED_NAK_RESPONSE_AVP_STRING =
"1703030040CD43A46C500065962396E4BEDA72CD43B3316F923AB21074BE705CC87F5C862F85E6D83"
+ "605B0C57E2C577923";
private static final byte[] ENCRYPTED_NAK_RESPONSE_AVP_BYTES =
hexStringToByteArray(ENCRYPTED_NAK_RESPONSE_AVP_STRING);
private static final String DECRYPTED_NAK_RESPONSE_AVP_STRING =
"0000004F" + "40" + "00000E" // AVP Code | AVP Flags | AVP Length
+ "02100006031A0000"; // NAK
private static final byte[] DECRYPTED_NAK_RESPONSE_AVP_BYTES =
hexStringToByteArray(DECRYPTED_NAK_RESPONSE_AVP_STRING);
private static final String ENCRYPTED_EAP_NOTIFICATION_REQUEST_AVP_STRING =
"1703030040CD43A46C500065962396E4BEDA72CD43B3316F923AB21074BE705CC87F5C862F85E6D83"
+ "17E15E7443E74AEA4";
private static final byte[] ENCRYPTED_EAP_NOTIFICATION_REQUEST_AVP_BYTES =
hexStringToByteArray(ENCRYPTED_EAP_NOTIFICATION_REQUEST_AVP_STRING);
private static final String DECRYPTED_EAP_NOTIFICATION_REQUEST_AVP_STRING =
"0000004F" + "40" + "000010" // AVP Code | AVP Flags | AVP Length
+ "0110000802AABBCC"; // Notification Request
private static final byte[] DECRYPTED_EAP_NOTIFICATION_REQUEST_AVP_BYTES =
hexStringToByteArray(DECRYPTED_EAP_NOTIFICATION_REQUEST_AVP_STRING);
private static final String ENCRYPTED_EAP_NOTIFICATION_RESPONSE_AVP_STRING =
"1703030040CD43A46C500065962396E4BEDA72CD43B3317F923AB21074BE705CC87F1C862F85E6D83"
+ "107FAA4BE705CCBE8";
private static final byte[] ENCRYPTED_EAP_NOTIFICATION_RESPONSE_AVP_BYTES =
hexStringToByteArray(ENCRYPTED_EAP_NOTIFICATION_RESPONSE_AVP_STRING);
private static final String DECRYPTED_EAP_NOTIFICATION_RESPONSE_AVP_STRING =
"0000004F" + "40" + "00000D" // AVP Code | AVP Flags | AVP Length
+ "0210000502000000"; // Notification Response
private static final byte[] DECRYPTED_EAP_NOTIFICATION_RESPONSE_AVP_BYTES =
hexStringToByteArray(DECRYPTED_EAP_NOTIFICATION_RESPONSE_AVP_STRING);
// EAP-TTLS Request/Responses
private static final byte[] EAP_RESPONSE_NAK_PACKET_TTLS = hexStringToByteArray("021000060315");
private static final byte[] EAP_RESPONSE_NAK_PACKET_MSCHAPV2 =
hexStringToByteArray("02080006031D");
// Phase 1 (Handshake)
private static final byte[] EAP_TTLS_START_REQUEST =
hexStringToByteArray(
"01" + "10" + "0006" // EAP-Request | ID | length in bytes
+ "1520"); // EAP-TTLS | flags);
private static final byte[] EAP_TTLS_CLIENT_HELLO_RESPONSE =
hexStringToByteArray(
"02" + "10" + "0094" // EAP-Response | ID | length in bytes
+ "15800000008A" // EAP-TTLS | Flags | message length
+ CLIENT_HELLO_STRING);
private static final byte[] EAP_TTLS_SERVER_HELLO_REQUEST_INITIAL_FRAGMENT =
hexStringToByteArray(
"01" + "10" + "0400" // EAP-Request | ID | length in bytes
+ "15C000000419" // EAP-TTLS | Flags | message length
+ SERVER_HELLO_INITIAL_FRAGMENT_STRING);
private static final byte[] EAP_TTLS_ACKNOWLEDGEMENT_RESPONSE_SERVER_HELLO_FRAGMENT =
hexStringToByteArray(
"02" + "10" + "0006" // EAP-Response | ID | length in bytes
+ "1500"); // EAP-TTLS | Flags
private static final byte[] EAP_TTLS_SERVER_HELLO_REQUEST_FINAL_FRAGMENT =
hexStringToByteArray(
"01" + "10" + "0029" // EAP-Request | ID | length in bytes
+ "1500" // EAP-TTLS | Flags
+ SERVER_HELLO_FINAL_FRAGMENT_STRING);
private static final byte[] EAP_TTLS_CLIENT_FINISHED_RESPONSE =
hexStringToByteArray(
"02" + "10" + "016C" // EAP-Response | ID | length in bytes
+ "158000000162" // EAP-TTLS | Flags | message length
+ CLIENT_FINISHED_STRING);
private static final byte[] EAP_TTLS_SERVER_FINISHED_REQUEST =
hexStringToByteArray(
"01" + "10" + "0055" // EAP-Request | ID | length in bytes
+ "15800000004B" // EAP-TTLS | Flags | message length
+ SERVER_FINISHED_STRING);
// Phase 2 (Tunnel)
private static final byte[] EAP_TTLS_TUNNELED_IDENTITY_RESPONSE =
hexStringToByteArray(
"02" + "10" + "004F" // EAP-Response | ID | length in bytes
+ "158000000045" // EAP-TTLS | Flags | message length
+ ENCRYPTED_EAP_IDENTITY_AVP_STRING);
private static final byte[] EAP_TTLS_TUNNELED_CHALLENGE_REQUEST =
hexStringToByteArray(
"01" + "05" + "006F" // EAP-Request | ID | length in bytes
+ "158000000065" // EAP-TTLS | Flags | message length
+ EAP_MSCHAP_V2_ENCRYPTED_CHALLENGE_REQUEST_AVP_STRING);
private static final byte[] EAP_TTLS_TUNNELED_CHALLENGE_RESPONSE =
hexStringToByteArray(
"02" + "05" + "008F" // EAP-Response | ID | length in bytes
+ "158000000085" // EAP-TTLS | Flags | message length
+ EAP_MSCHAP_V2_ENCRYPTED_CHALLENGE_RESPONSE_AVP_STRING);
private static final byte[] EAP_TTLS_TUNNELED_SUCCESS_REQUEST =
hexStringToByteArray(
"01" + "06" + "008F" // EAP-Request | ID | length in bytes
+ "158000000085" // EAP-TTLS | Flags | message length
+ EAP_MSCHAP_V2_ENCRYPTED_SUCCESS_REQUEST_AVP_STRING);
private static final byte[] EAP_TTLS_TUNNELED_SUCCESS_RESPONSE =
hexStringToByteArray(
"02" + "06" + "004F" // EAP-Response | ID | length in bytes
+ "158000000045" // EAP-TTLS | Flags | message length
+ EAP_MSCHAP_V2_ENCRYPTED_SUCCESS_RESPONSE_AVP_STRING);
private static final byte[] EAP_TTLS_TUNNELED_FAILURE_REQUEST =
hexStringToByteArray(
"01" + "07" + "004F" // EAP-Request | ID | length in bytes
+ "158000000045" // EAP-TTLS | Flags | message length
+ EAP_MSCHAP_V2_ENCRYPTED_FAILURE_REQUEST_AVP_STRING);
private static final byte[] EAP_TTLS_TUNNELED_FAILURE_RESPONSE =
hexStringToByteArray(
"02" + "07" + "0053" // EAP-Response | ID | length in bytes
+ "158000000049" // EAP-TTLS | Flags | message length
+ EAP_MSCHAP_V2_ENCRYPTED_FAILURE_RESPONSE_AVP_STRING);
private static final byte[] EAP_TTLS_TUNNELED_AKA_IDENTITY_AVP_REQUEST =
hexStringToByteArray(
"01" + "08" + "003B" // EAP-Request | ID | length in bytes
+ "158000000031" // EAP-TTLS | Flags | message length
+ ENCRYPTED_EAP_AKA_IDENTITY_REQUEST_AVP_STRING);
private static final byte[] EAP_TTLS_TUNNELED_NAK_RESPONSE =
hexStringToByteArray(
"02" + "08" + "003B" // EAP-Response | ID | length in bytes
+ "158000000031" // EAP-TTLS | Flags | message length
+ ENCRYPTED_NAK_RESPONSE_AVP_STRING);
private static final byte[] EAP_TTLS_TUNNELED_EAP_NOTIFICATION_REQUEST =
hexStringToByteArray(
"01" + "08" + "003B" // EAP-Response | ID | length in bytes
+ "158000000031" // EAP-TTLS | Flags | message length
+ ENCRYPTED_EAP_NOTIFICATION_REQUEST_AVP_STRING);
private static final byte[] EAP_TTLS_TUNNELED_EAP_NOTIFICATION_RESPONSE =
hexStringToByteArray(
"02" + "08" + "003B" // EAP-Response | ID | length in bytes
+ "158000000031" // EAP-TTLS | Flags | message length
+ ENCRYPTED_EAP_NOTIFICATION_RESPONSE_AVP_STRING);
private final TlsSessionFactory mMockTlsSessionFactory = mock(TlsSessionFactory.class);
private final SSLEngine mMockSslEngine = mock(SSLEngine.class);
private final SSLSession mMockSslSession = mock(SSLSession.class);
private TlsSession mTlsSessionSpy;
@Before
@Override
public void setUp() {
super.setUp();
EapSessionConfig innerEapSessionConfig =
new EapSessionConfig.Builder()
.setEapMsChapV2Config(MSCHAPV2_USERNAME, MSCHAPV2_PASSWORD)
.build();
mEapSessionConfig =
new EapSessionConfig.Builder()
.setEapTtlsConfig(null, innerEapSessionConfig)
.build();
mEapAuthenticator =
new EapAuthenticator(
mTestLooper.getLooper(),
mMockCallback,
new EapStateMachine(mMockContext, mEapSessionConfig, mMockSecureRandom),
Runnable::run,
AUTHENTICATOR_TIMEOUT_MILLIS);
when(mMockSslSession.getApplicationBufferSize())
.thenReturn(APPLICATION_BUFFER_SIZE_TLS_MESSAGE);
when(mMockSslSession.getPacketBufferSize()).thenReturn(PACKET_BUFFER_SIZE_TLS_MESSAGE);
// TODO(b/165823103): Switch EAP-TTLS to use CorePlatformApi for
// Conscrypt#exportKeyingMaterial
mTlsSessionSpy =
spy(
new TlsSession(
mock(SSLContext.class),
mMockSslEngine,
mMockSslSession,
mMockSecureRandom));
when(mTlsSessionSpy.generateKeyingMaterial())
.thenReturn(mTlsSessionSpy.new EapTtlsKeyingMaterial(TLS_MSK, TLS_EMSK));
EapTtlsMethodStateMachine.sTlsSessionFactory = mMockTlsSessionFactory;
try {
when(mMockTlsSessionFactory.newInstance(eq(null), eq(mMockSecureRandom)))
.thenReturn(mTlsSessionSpy);
} catch (Exception e) {
throw new AssertionError("TLS Session setup failed", e);
}
}
@AfterClass
public static void teardown() {
EapTtlsMethodStateMachine.sTlsSessionFactory = new TlsSessionFactory();
}
@Test
public void testEapTtlsEndToEndSuccess() throws Exception {
processAndVerifyStartRequest();
processAndVerifyServerHello_initialFragment();
processAndVerifyServerHello_finalFragment();
processAndVerifyServerFinished();
processAndVerifyMsChapV2ChallengeRequest();
processAndVerifyMsChapV2SuccessRequest();
processAndVerifyEapSuccess(TLS_MSK, TLS_EMSK);
}
@Test
public void testEapTtlsWithEapNotifications() throws Exception {
verifyEapNotification(1);
processAndVerifyStartRequest();
verifyEapNotification(2);
processAndVerifyServerHello_initialFragment();
processAndVerifyServerHello_finalFragment();
verifyEapNotification(3);
processAndVerifyServerFinished();
verifyEapNotification(4);
processAndVerifyMsChapV2ChallengeRequest();
verifyEapNotification(5);
processAndVerifyMsChapV2SuccessRequest();
verifyEapNotification(6);
processAndVerifyEapSuccess(TLS_MSK, TLS_EMSK);
}
@Test
public void testEapTtlsWithTunneledEapNotifications() throws Exception {
processAndVerifyStartRequest();
processAndVerifyServerHello_initialFragment();
processAndVerifyServerHello_finalFragment();
processAndVerifyServerFinished();
processAndVerifyTunneledEapNotification(1);
processAndVerifyMsChapV2ChallengeRequest();
processAndVerifyTunneledEapNotification(2);
processAndVerifyMsChapV2SuccessRequest();
processAndVerifyTunneledEapNotification(3);
processAndVerifyEapSuccess(TLS_MSK, TLS_EMSK);
}
@Test
public void testEapMsChapV2EndToEndFailure() throws Exception {
processAndVerifyStartRequest();
processAndVerifyServerHello_initialFragment();
processAndVerifyServerHello_finalFragment();
processAndVerifyServerFinished();
processAndVerifyMsChapV2ChallengeRequest();
processMessageAndVerifyMsChapV2FailureRequest();
verifyEapFailure();
}
@Test
public void testEapTtlsUnsupportedType() throws Exception {
verifyUnsupportedType(EAP_REQUEST_AKA_IDENTITY_PACKET, EAP_RESPONSE_NAK_PACKET_TTLS);
processAndVerifyStartRequest();
processAndVerifyServerHello_initialFragment();
processAndVerifyServerHello_finalFragment();
processAndVerifyServerFinished();
processAndVerifyMsChapV2ChallengeRequest();
processAndVerifyMsChapV2SuccessRequest();
processAndVerifyEapSuccess(TLS_MSK, TLS_EMSK);
}
@Test
public void testEapTtlsTunneledUnsupportedType() throws Exception {
processAndVerifyStartRequest();
processAndVerifyServerHello_initialFragment();
processAndVerifyServerHello_finalFragment();
processAndVerifyServerFinished();
processAndVerifyTunneledUnsupportedType();
processAndVerifyMsChapV2ChallengeRequest();
processAndVerifyMsChapV2SuccessRequest();
processAndVerifyEapSuccess(TLS_MSK, TLS_EMSK);
}
private void processAndVerifyStartRequest() throws Exception {
setupWrap(EMPTY_BYTE_ARRAY, CLIENT_HELLO_BYTES, RESULT_NEED_UNWRAP_OK);
mEapAuthenticator.processEapMessage(EAP_TTLS_START_REQUEST);
mTestLooper.dispatchAll();
// TODO(b/166794957): Verify SSLEngine wrap/unwrap in EAP-TTLS end-to-end tests
verify(mMockCallback).onResponse(eq(EAP_TTLS_CLIENT_HELLO_RESPONSE));
verifyNoMoreInteractions(mMockCallback);
}
private void processAndVerifyServerHello_initialFragment() throws Exception {
mEapAuthenticator.processEapMessage(EAP_TTLS_SERVER_HELLO_REQUEST_INITIAL_FRAGMENT);
mTestLooper.dispatchAll();
verify(mMockCallback)
.onResponse(eq(EAP_TTLS_ACKNOWLEDGEMENT_RESPONSE_SERVER_HELLO_FRAGMENT));
verifyNoMoreInteractions(mMockCallback);
}
private void processAndVerifyServerHello_finalFragment() throws Exception {
doReturn(RESULT_NEED_WRAP_OK)
.when(mMockSslEngine)
.unwrap(
argThat(containsData(SERVER_HELLO_BYTES)),
argThat(containsData(DECRYPTED_EAP_IDENTITY_AVP_BYTES)));
setupWrap(DECRYPTED_EAP_IDENTITY_AVP_BYTES, CLIENT_FINISHED_BYTES, RESULT_NEED_UNWRAP_OK);
mEapAuthenticator.processEapMessage(EAP_TTLS_SERVER_HELLO_REQUEST_FINAL_FRAGMENT);
mTestLooper.dispatchAll();
// TODO(b/166794957): Verify SSLEngine wrap/unwrap in EAP-TTLS end-to-end tests
verify(mMockCallback).onResponse(eq(EAP_TTLS_CLIENT_FINISHED_RESPONSE));
verifyNoMoreInteractions(mMockCallback);
}
private void processAndVerifyServerFinished() throws Exception {
doReturn(RESULT_NEED_UNWRAP_OK, RESULT_NEED_WRAP_OK)
.when(mMockSslEngine)
.unwrap(
argThat(containsData(SERVER_FINISHED_BYTES)),
argThat(containsData(DECRYPTED_EAP_IDENTITY_AVP_BYTES)));
setupWrap(
DECRYPTED_EAP_IDENTITY_AVP_BYTES,
ENCRYPTED_EAP_IDENTITY_AVP_BYTES,
RESULT_FINISHED_OK);
mEapAuthenticator.processEapMessage(EAP_TTLS_SERVER_FINISHED_REQUEST);
mTestLooper.dispatchAll();
// TODO(b/166794957): Verify SSLEngine wrap/unwrap in EAP-TTLS end-to-end tests
verify(mMockCallback).onResponse(eq(EAP_TTLS_TUNNELED_IDENTITY_RESPONSE));
verifyNoMoreInteractions(mMockCallback);
}
private void processAndVerifyMsChapV2ChallengeRequest() throws Exception {
doAnswer(invocation -> {
byte[] dst = invocation.getArgument(0);
System.arraycopy(PEER_CHALLENGE, 0, dst, 0, PEER_CHALLENGE.length);
return null;
})
.when(mMockSecureRandom)
.nextBytes(argThat(arr -> arr.length == PEER_CHALLENGE.length));
setupUnwrap(
EAP_MSCHAP_V2_DECRYPTED_CHALLENGE_REQUEST_AVP_BYTES,
EAP_MSCHAP_V2_ENCRYPTED_CHALLENGE_REQUEST_AVP_BYTES,
RESULT_NOT_HANDSHAKING_OK);
setupWrap(
EAP_MSCHAP_V2_DECRYPTED_CHALLENGE_RESPONSE_AVP_BYTES,
EAP_MSCHAP_V2_ENCRYPTED_CHALLENGE_RESPONSE_AVP_BYTES,
RESULT_NOT_HANDSHAKING_OK);
mEapAuthenticator.processEapMessage(EAP_TTLS_TUNNELED_CHALLENGE_REQUEST);
mTestLooper.dispatchAll();
// TODO(b/166794957): Verify SSLEngine wrap/unwrap in EAP-TTLS end-to-end tests
verify(mMockCallback).onResponse(eq(EAP_TTLS_TUNNELED_CHALLENGE_RESPONSE));
verify(mMockSecureRandom).nextBytes(argThat(arr -> arr.length == PEER_CHALLENGE.length));
verifyNoMoreInteractions(mMockCallback);
}
private void processAndVerifyMsChapV2SuccessRequest() throws Exception {
setupUnwrap(
EAP_MSCHAP_V2_DECRYPTED_SUCCESS_REQUEST_AVP_BYTES,
EAP_MSCHAP_V2_ENCRYPTED_SUCCESS_REQUEST_AVP_BYTES,
RESULT_NOT_HANDSHAKING_OK);
setupWrap(
EAP_MSCHAP_V2_DECRYPTED_SUCCESS_RESPONSE_AVP_BYTES,
EAP_MSCHAP_V2_ENCRYPTED_SUCCESS_RESPONSE_AVP_BYTES,
RESULT_NOT_HANDSHAKING_OK);
mEapAuthenticator.processEapMessage(EAP_TTLS_TUNNELED_SUCCESS_REQUEST);
mTestLooper.dispatchAll();
// TODO(b/166794957): Verify SSLEngine wrap/unwrap in EAP-TTLS end-to-end tests
verify(mMockCallback).onResponse(eq(EAP_TTLS_TUNNELED_SUCCESS_RESPONSE));
verifyNoMoreInteractions(mMockCallback);
}
private void processAndVerifyTunneledEapNotification(int callsToVerify) throws Exception {
setupUnwrap(
DECRYPTED_EAP_NOTIFICATION_REQUEST_AVP_BYTES,
ENCRYPTED_EAP_NOTIFICATION_REQUEST_AVP_BYTES,
RESULT_NOT_HANDSHAKING_OK);
setupWrap(
DECRYPTED_EAP_NOTIFICATION_RESPONSE_AVP_BYTES,
ENCRYPTED_EAP_NOTIFICATION_RESPONSE_AVP_BYTES,
RESULT_NOT_HANDSHAKING_OK);
mEapAuthenticator.processEapMessage(EAP_TTLS_TUNNELED_EAP_NOTIFICATION_REQUEST);
mTestLooper.dispatchAll();
// TODO(b/166794957): Verify SSLEngine wrap/unwrap in EAP-TTLS end-to-end tests
verify(mMockCallback, times(callsToVerify))
.onResponse(eq(EAP_TTLS_TUNNELED_EAP_NOTIFICATION_RESPONSE));
verifyNoMoreInteractions(mMockCallback);
}
private void processMessageAndVerifyMsChapV2FailureRequest() throws Exception {
setupUnwrap(
EAP_MSCHAP_V2_DECRYPTED_FAILURE_REQUEST_AVP_BYTES,
EAP_MSCHAP_V2_ENCRYPTED_FAILURE_REQUEST_AVP_BYTES,
RESULT_NOT_HANDSHAKING_OK);
setupWrap(
EAP_MSCHAP_V2_DECRYPTED_FAILURE_RESPONSE_AVP_BYTES,
EAP_MSCHAP_V2_ENCRYPTED_FAILURE_RESPONSE_AVP_BYTES,
RESULT_NOT_HANDSHAKING_OK);
mEapAuthenticator.processEapMessage(EAP_TTLS_TUNNELED_FAILURE_REQUEST);
mTestLooper.dispatchAll();
// TODO(b/166794957): Verify SSLEngine wrap/unwrap in EAP-TTLS end-to-end tests
verify(mMockCallback).onResponse(eq(EAP_TTLS_TUNNELED_FAILURE_RESPONSE));
verifyNoMoreInteractions(mMockCallback);
}
private void processAndVerifyTunneledUnsupportedType()
throws Exception {
setupUnwrap(
DECRYPTED_EAP_AKA_IDENTITY_REQUEST_AVP_BYTES,
ENCRYPTED_EAP_AKA_IDENTITY_REQUEST_AVP_BYTES,
RESULT_NOT_HANDSHAKING_OK);
setupWrap(
DECRYPTED_NAK_RESPONSE_AVP_BYTES,
ENCRYPTED_NAK_RESPONSE_AVP_BYTES,
RESULT_NOT_HANDSHAKING_OK);
mEapAuthenticator.processEapMessage(EAP_TTLS_TUNNELED_AKA_IDENTITY_AVP_REQUEST);
mTestLooper.dispatchAll();
// TODO(b/166794957): Verify SSLEngine wrap/unwrap in EAP-TTLS end-to-end tests
// verify EAP-Response/Nak returned
verify(mMockCallback).onResponse(eq(EAP_TTLS_TUNNELED_NAK_RESPONSE));
verifyNoMoreInteractions(mMockCallback);
}
private void processAndVerifyEapSuccess(byte[] msk, byte[] emsk) throws Exception {
// EAP-Success
mEapAuthenticator.processEapMessage(EAP_SUCCESS);
mTestLooper.dispatchAll();
// verify that onSuccess callback made
verify(mMockCallback).onSuccess(eq(msk), eq(emsk));
verify(mTlsSessionSpy).generateKeyingMaterial();
verifyNoMoreInteractions(mMockContext, mMockSecureRandom, mMockCallback);
}
private void setupUnwrap(
byte[] applicationData, byte[] packetData, SSLEngineResult result) throws Exception {
doAnswer(invocation -> {
ByteBuffer buffer = invocation.getArgument(1);
buffer.put(applicationData);
return result;
})
.when(mMockSslEngine)
.unwrap(argThat(containsData(packetData)), any(ByteBuffer.class));
}
void setupWrap(byte[] applicationData, byte[] packetData, SSLEngineResult result)
throws Exception {
doAnswer(invocation -> {
ByteBuffer buffer = invocation.getArgument(1);
buffer.put(packetData);
return result;
})
.when(mMockSslEngine)
.wrap(argThat(containsData(applicationData)), any(ByteBuffer.class));
}
private ArgumentMatcher<ByteBuffer> containsData(byte[] data) {
return buffer -> Arrays.equals(getByteArrayFromBufferLimit(buffer), data);
}
// The ByteBuffer is always initialized by ByteBuffer#allocate
@SuppressWarnings("ByteBufferBackingArray")
private byte[] getByteArrayFromBufferLimit(ByteBuffer buffer) {
return Arrays.copyOfRange(buffer.array(), 0, buffer.limit());
}
}