diff --git a/client/src/cmdhfaliro.c b/client/src/cmdhfaliro.c index a0abc69d0..b3a1c19d1 100644 --- a/client/src/cmdhfaliro.c +++ b/client/src/cmdhfaliro.c @@ -59,6 +59,8 @@ static const uint8_t ALIRO_SECURE_CHANNEL_DEVICE_MODE[] = {0, 0, 0, 0, 0, 0, 0, static const uint8_t ALIRO_NFC_INTERFACE_BYTE = 0x5E; static const uint8_t ALIRO_AUTH0_DEFAULT_POLICY = 0x01; static const uint8_t ALIRO_AUTH1_REQUEST_PUBLIC_KEY = 0x01; +static const uint8_t ALIRO_EXCHANGE_INS = 0xC9; +static const uint8_t ALIRO_READER_STATUS_STATE_UNSECURE[] = {0x01, 0x01}; // UNSECURE means "opened" static const char ALIRO_DEFAULT_STEP_UP_SCOPE[] = "matter1"; #define ALIRO_MAX_BUFFER 2048 @@ -172,6 +174,13 @@ typedef struct { aliro_derived_keys_t keys; } aliro_standard_result_t; +typedef struct { + const uint8_t (*sk_reader)[32]; + uint32_t reader_counter; + const uint8_t (*sk_device)[32]; + uint32_t device_counter; +} aliro_secure_channel_state_t; + typedef struct { aliro_select_info_t select_info; uint8_t protocol_version[2]; @@ -188,11 +197,19 @@ typedef struct { aliro_fast_result_t fast_result; aliro_auth1_response_t auth1_parsed; aliro_standard_result_t standard_result; + aliro_secure_channel_state_t expedited_secure_channel; + aliro_secure_channel_state_t step_up_secure_channel; } aliro_read_state_t; static int CmdHelp(const char *Cmd); static const char *aliro_cbor_type_name(CborType type); static bool aliro_cbor_print_scalar(const char *label, const CborValue *value); +static int aliro_secure_channel_encrypt_reader_payload(aliro_secure_channel_state_t *channel, + const uint8_t *plaintext, size_t plaintext_len, + uint8_t *ciphertext, size_t ciphertext_max, size_t *ciphertext_len); +static int aliro_secure_channel_decrypt_device_payload(aliro_secure_channel_state_t *channel, + const uint8_t *ciphertext, size_t ciphertext_len, + uint8_t *plaintext, size_t plaintext_max, size_t *plaintext_len); static const char *get_aliro_application_type_name(uint16_t type) { for (size_t i = 0; i < ARRAYLEN(aliro_application_type_map); ++i) { @@ -1609,6 +1626,10 @@ aliro_append_tlv(0x4D, state->reader_identifier, 32, auth0_data, sizeof(auth0_da PrintAndLogEx(INFO, " Fast BleSKReader.......... %s", sprint_hex_inrow(state->fast_result.keys.ble_sk_reader, 32)); PrintAndLogEx(INFO, " Fast BleSKDevice.......... %s", sprint_hex_inrow(state->fast_result.keys.ble_sk_device, 32)); PrintAndLogEx(INFO, " Fast URSK................. %s", sprint_hex_inrow(state->fast_result.keys.ursk, 32)); + state->expedited_secure_channel.sk_reader = &state->fast_result.keys.exchange_sk_reader; + state->expedited_secure_channel.reader_counter = 1; + state->expedited_secure_channel.sk_device = &state->fast_result.keys.exchange_sk_device; + state->expedited_secure_channel.device_counter = 1; if (flow == ALIRO_FLOW_FAST) { *fast_flow_complete = true; return PM3_SUCCESS; @@ -1665,6 +1686,15 @@ static int aliro_read_prepare_auth1_keys(aliro_read_state_t *state, state->standard_result.keys.kpersistent_present = false; memset(state->standard_result.keys.kpersistent, 0, sizeof(state->standard_result.keys.kpersistent)); + state->expedited_secure_channel.sk_reader = &state->standard_result.keys.exchange_sk_reader; + state->expedited_secure_channel.reader_counter = 1; + state->expedited_secure_channel.sk_device = &state->standard_result.keys.exchange_sk_device; + state->expedited_secure_channel.device_counter = 1; + state->step_up_secure_channel.sk_reader = &state->standard_result.keys.step_up_sk_reader; + state->step_up_secure_channel.reader_counter = 1; + state->step_up_secure_channel.sk_device = &state->standard_result.keys.step_up_sk_device; + state->step_up_secure_channel.device_counter = 1; + return PM3_SUCCESS; } @@ -1739,18 +1769,17 @@ aliro_append_tlv(0x9E, auth1_signature, 64, return PM3_ESOFT; } - uint8_t auth1_iv[12] = {0}; - aliro_build_secure_channel_iv(ALIRO_SECURE_CHANNEL_DEVICE_MODE, 1, auth1_iv); - uint8_t auth1_plain[ALIRO_MAX_BUFFER] = {0}; - res = aliro_aes_gcm_decrypt(state->standard_result.keys.exchange_sk_device, auth1_iv, sizeof(auth1_iv), - auth1_response_enc, auth1_response_enc_len, auth1_plain); + size_t auth1_plain_len = 0; + res = aliro_secure_channel_decrypt_device_payload(&state->expedited_secure_channel, + auth1_response_enc, auth1_response_enc_len, + auth1_plain, sizeof(auth1_plain), + &auth1_plain_len); if (res != PM3_SUCCESS) { PrintAndLogEx(ERR, "Failed to decrypt AUTH1 response"); return res; } - size_t auth1_plain_len = auth1_response_enc_len - 16; res = aliro_parse_auth1_plaintext(auth1_plain, auth1_plain_len, &state->auth1_parsed); if (res != PM3_SUCCESS) { return res; @@ -2010,29 +2039,29 @@ static void aliro_print_step_up_scopes(const aliro_step_up_scopes_t *scopes) { PrintAndLogEx(INFO, "Step-up scopes............ %s", joined); } -static int aliro_secure_channel_encrypt_reader_payload(const uint8_t sk_reader[32], uint32_t *reader_counter, +static int aliro_secure_channel_encrypt_reader_payload(aliro_secure_channel_state_t *channel, const uint8_t *plaintext, size_t plaintext_len, uint8_t *ciphertext, size_t ciphertext_max, size_t *ciphertext_len) { - if (sk_reader == NULL || reader_counter == NULL || plaintext == NULL || + if (channel == NULL || channel->sk_reader == NULL || plaintext == NULL || ciphertext == NULL || ciphertext_len == NULL) { return PM3_EINVARG; } uint8_t iv[12] = {0}; - aliro_build_secure_channel_iv(ALIRO_SECURE_CHANNEL_READER_MODE, *reader_counter, iv); - int res = aliro_aes_gcm_encrypt(sk_reader, iv, sizeof(iv), + aliro_build_secure_channel_iv(ALIRO_SECURE_CHANNEL_READER_MODE, channel->reader_counter, iv); + int res = aliro_aes_gcm_encrypt(*channel->sk_reader, iv, sizeof(iv), plaintext, plaintext_len, ciphertext, ciphertext_max, ciphertext_len); if (res == PM3_SUCCESS) { - (*reader_counter)++; + channel->reader_counter++; } return res; } -static int aliro_secure_channel_decrypt_device_payload(const uint8_t sk_device[32], uint32_t *device_counter, +static int aliro_secure_channel_decrypt_device_payload(aliro_secure_channel_state_t *channel, const uint8_t *ciphertext, size_t ciphertext_len, uint8_t *plaintext, size_t plaintext_max, size_t *plaintext_len) { - if (sk_device == NULL || device_counter == NULL || ciphertext == NULL || + if (channel == NULL || channel->sk_device == NULL || ciphertext == NULL || plaintext == NULL || plaintext_len == NULL) { return PM3_EINVARG; } @@ -2041,15 +2070,84 @@ static int aliro_secure_channel_decrypt_device_payload(const uint8_t sk_device[3 } uint8_t iv[12] = {0}; - aliro_build_secure_channel_iv(ALIRO_SECURE_CHANNEL_DEVICE_MODE, *device_counter, iv); - int res = aliro_aes_gcm_decrypt(sk_device, iv, sizeof(iv), ciphertext, ciphertext_len, plaintext); + aliro_build_secure_channel_iv(ALIRO_SECURE_CHANNEL_DEVICE_MODE, channel->device_counter, iv); + int res = aliro_aes_gcm_decrypt(*channel->sk_device, iv, sizeof(iv), ciphertext, ciphertext_len, plaintext); if (res == PM3_SUCCESS) { - (*device_counter)++; + channel->device_counter++; *plaintext_len = ciphertext_len - 16; } return res; } +static int aliro_send_reader_status_exchange(aliro_secure_channel_state_t *channel, + const uint8_t reader_status[2]) { + if (channel == NULL || channel->sk_reader == NULL || + channel->sk_device == NULL || reader_status == NULL) { + return PM3_EINVARG; + } + PrintAndLogEx(INFO, ""); + PrintAndLogInfoHeader("EXCHANGE"); + + uint8_t status_plaintext[8] = {0}; + size_t status_plaintext_len = 0; + int res = aliro_append_tlv(0x97, reader_status, 2, + status_plaintext, sizeof(status_plaintext), &status_plaintext_len); + if (res != PM3_SUCCESS) { + PrintAndLogEx(ERR, "Failed to encode EXCHANGE reader status payload"); + return res; + } + + uint8_t status_ciphertext[ALIRO_MAX_BUFFER] = {0}; + size_t status_ciphertext_len = 0; + res = aliro_secure_channel_encrypt_reader_payload(channel, + status_plaintext, status_plaintext_len, + status_ciphertext, sizeof(status_ciphertext), + &status_ciphertext_len); + if (res != PM3_SUCCESS) { + PrintAndLogEx(ERR, "Failed to encrypt EXCHANGE reader status payload"); + return res; + } + + uint8_t exchange_response[ALIRO_MAX_BUFFER] = {0}; + size_t exchange_response_len = 0; + uint16_t exchange_sw = 0; + res = aliro_exchange_chained(false, true, 0x80, ALIRO_EXCHANGE_INS, 0x00, 0x00, + status_ciphertext, status_ciphertext_len, + exchange_response, sizeof(exchange_response), + &exchange_response_len, &exchange_sw); + if (res != PM3_SUCCESS) { + PrintAndLogEx(ERR, "Reader status EXCHANGE APDU exchange failed"); + return res; + } + + if (exchange_sw != ISO7816_OK) { + PrintAndLogEx(ERR, "Reader status EXCHANGE failed: %04x - %s", + exchange_sw, GetAPDUCodeDescription(exchange_sw >> 8, exchange_sw & 0xff)); + return PM3_ESOFT; + } + PrintAndLogEx(INFO, "Reader status EXCHANGE.... %04x", exchange_sw); + if (exchange_response_len == 0) { + return PM3_SUCCESS; + } + + uint8_t response_plaintext[ALIRO_MAX_BUFFER] = {0}; + size_t response_plaintext_len = 0; + res = aliro_secure_channel_decrypt_device_payload(channel, + exchange_response, exchange_response_len, + response_plaintext, sizeof(response_plaintext), + &response_plaintext_len); + if (res != PM3_SUCCESS) { + PrintAndLogEx(ERR, "Failed to decrypt reader status EXCHANGE response"); + return res; + } + if (response_plaintext_len > 0) { + PrintAndLogEx(INFO, "Reader status response.... %s", + sprint_hex_inrow(response_plaintext, response_plaintext_len)); + } + + return PM3_SUCCESS; +} + static bool aliro_cbor_key_equals(const CborValue *key, int int_key, const char *text_key) { if (key == NULL) { return false; @@ -3243,11 +3341,15 @@ static int aliro_step_up_print_device_response(const uint8_t *device_response, s return PM3_SUCCESS; } -static int aliro_read_do_step_up(const aliro_read_state_t *state, +static int aliro_read_do_step_up(aliro_read_state_t *state, const aliro_step_up_scopes_t *step_up_scopes) { - if (state == NULL || step_up_scopes == NULL) { + if (state == NULL || step_up_scopes == NULL || + state->step_up_secure_channel.sk_reader == NULL || + state->step_up_secure_channel.sk_device == NULL) { return PM3_EINVARG; } + aliro_secure_channel_state_t *step_up_channel = &state->step_up_secure_channel; + if (!state->standard_result.keys.step_up_keys_present) { PrintAndLogEx(ERR, "Step-up keys are not available"); return PM3_ESOFT; @@ -3314,12 +3416,9 @@ static int aliro_read_do_step_up(const aliro_read_state_t *state, } PrintAndLogEx(INFO, "DeviceRequest CBOR........ %s", sprint_hex_inrow(device_request, device_request_len)); - uint32_t step_up_reader_counter = 1; - uint32_t step_up_device_counter = 1; uint8_t encrypted_device_request[ALIRO_MAX_BUFFER] = {0}; size_t encrypted_device_request_len = 0; - res = aliro_secure_channel_encrypt_reader_payload(state->standard_result.keys.step_up_sk_reader, - &step_up_reader_counter, + res = aliro_secure_channel_encrypt_reader_payload(step_up_channel, device_request, device_request_len, encrypted_device_request, sizeof(encrypted_device_request), &encrypted_device_request_len); @@ -3386,8 +3485,7 @@ static int aliro_read_do_step_up(const aliro_read_state_t *state, uint8_t device_response_plaintext[ALIRO_MAX_BUFFER] = {0}; size_t device_response_plaintext_len = 0; - res = aliro_secure_channel_decrypt_device_payload(state->standard_result.keys.step_up_sk_device, - &step_up_device_counter, + res = aliro_secure_channel_decrypt_device_payload(step_up_channel, encrypted_device_response, encrypted_device_response_len, device_response_plaintext, sizeof(device_response_plaintext), &device_response_plaintext_len); @@ -3450,6 +3548,11 @@ static int aliro_read_auth_flow(const uint8_t *kpersistent, size_t kpersistent_l break; } if (fast_flow_complete) { + res = aliro_send_reader_status_exchange(&state.expedited_secure_channel, + ALIRO_READER_STATUS_STATE_UNSECURE); + if (res != PM3_SUCCESS) { + PrintAndLogEx(WARNING, "Completion EXCHANGE failed after fast auth; continuing"); + } status = PM3_SUCCESS; break; } @@ -3478,6 +3581,15 @@ static int aliro_read_auth_flow(const uint8_t *kpersistent, size_t kpersistent_l break; } } + aliro_secure_channel_state_t *completion_channel = (flow == ALIRO_FLOW_STEP_UP) + ? &state.step_up_secure_channel + : &state.expedited_secure_channel; + const char *completion_flow_name = (flow == ALIRO_FLOW_STEP_UP) ? "step-up" : "expedited"; + res = aliro_send_reader_status_exchange(completion_channel, + ALIRO_READER_STATUS_STATE_UNSECURE); + if (res != PM3_SUCCESS) { + PrintAndLogEx(WARNING, "Completion EXCHANGE failed after %s auth; continuing", completion_flow_name); + } status = PM3_SUCCESS; } while (0);