From ec144d24939a42d68aa0990f423549ed18b1483c Mon Sep 17 00:00:00 2001 From: Aveen Ismail Date: Fri, 22 Nov 2024 10:50:29 +0100 Subject: [PATCH] SCP11: Code optimization --- lib/aes_util.c | 6 +- lib/aes_util.h | 2 +- lib/internal.h | 2 + lib/util.c | 38 +++++------ lib/ykpiv.c | 177 +++++++++++++++++++++++++++++++------------------ 5 files changed, 136 insertions(+), 89 deletions(-) diff --git a/lib/aes_util.c b/lib/aes_util.c index 1eabdd58..c8c43557 100644 --- a/lib/aes_util.c +++ b/lib/aes_util.c @@ -193,7 +193,7 @@ static ykpiv_rc scp11_get_iv(uint8_t *key, uint8_t counter, uint8_t *iv, bool de #endif ykpiv_rc -aescbc_encrypt_data(uint8_t *key, uint8_t counter, uint8_t *data, size_t data_len, uint8_t *enc, size_t *enc_len) { +aescbc_encrypt_data(uint8_t *key, uint8_t counter, const uint8_t *data, size_t data_len, uint8_t *enc, size_t *enc_len) { ykpiv_rc rc = YKPIV_OK; #if (OPENSSL_VERSION_NUMBER > 0x10100000L) uint8_t iv[SCP11_BLOCK_SIZE] = {0}; @@ -251,7 +251,7 @@ ykpiv_rc aesecb_decrypt_data(uint8_t *key, uint8_t counter, uint8_t *enc, size_t enc_len, uint8_t *data, size_t *data_len) { ykpiv_rc rc = YKPIV_OK; #if (OPENSSL_VERSION_NUMBER > 0x10100000L) - if(enc_len == 0) { + if(enc_len <= 0) { DBG("No data to decrypt"); *data_len = 0; return YKPIV_OK; @@ -280,7 +280,7 @@ aesecb_decrypt_data(uint8_t *key, uint8_t counter, uint8_t *enc, size_t enc_len, } if (1 != EVP_DecryptUpdate(ctx, data, &len, enc, enc_len)) { - DBG("Failed to encrypt data"); + DBG("Failed to decrypt data"); rc = YKPIV_AUTHENTICATION_ERROR; goto aes_dec_clean; } diff --git a/lib/aes_util.h b/lib/aes_util.h index 3afe73a6..378fa931 100644 --- a/lib/aes_util.h +++ b/lib/aes_util.h @@ -41,7 +41,7 @@ ykpiv_rc unmac_data(uint8_t *key, uint8_t *mac_chain, uint8_t *data, size_t data //ykpiv_rc scp11_get_iv(uint8_t *key, uint8_t counter, uint8_t *iv); ykpiv_rc -aescbc_encrypt_data(uint8_t *key, uint8_t counter, uint8_t *data, size_t data_len, uint8_t *enc, size_t *enc_len); +aescbc_encrypt_data(uint8_t *key, uint8_t counter, const uint8_t *data, size_t data_len, uint8_t *enc, size_t *enc_len); ykpiv_rc aesecb_decrypt_data(uint8_t *key, uint8_t counter, uint8_t *enc, size_t enc_len, uint8_t *data, size_t *data_len); diff --git a/lib/internal.h b/lib/internal.h index be0f83e9..06790bba 100644 --- a/lib/internal.h +++ b/lib/internal.h @@ -220,8 +220,10 @@ bool yk_des_is_weak_key(const unsigned char *key, const size_t cb_key); prng_rc _ykpiv_prng_generate(unsigned char *buffer, const size_t cb_req); ykpiv_rc _ykpiv_begin_transaction(ykpiv_state *state); ykpiv_rc _ykpiv_end_transaction(ykpiv_state *state); +ykpiv_rc _ykpiv_ensure_application_selected_ex(ykpiv_state *state, bool scp11); ykpiv_rc _ykpiv_ensure_application_selected(ykpiv_state *state); ykpiv_rc _ykpiv_select_application(ykpiv_state *state); +ykpiv_rc _ykpiv_select_application_ex(ykpiv_state *state, bool scp11); ykpiv_rc _ykpiv_select_gp_application(ykpiv_state *state); size_t _ykpiv_get_length_size(size_t length); size_t _ykpiv_set_length(unsigned char *buffer, size_t length); diff --git a/lib/util.c b/lib/util.c index 022363a0..ea63d24f 100644 --- a/lib/util.c +++ b/lib/util.c @@ -118,7 +118,7 @@ ykpiv_rc ykpiv_util_get_cardid(ykpiv_state *state, ykpiv_cardid *cardid) { if (!cardid) return YKPIV_ARGUMENT_ERROR; if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return res; - if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup; + if (YKPIV_OK != (res = _ykpiv_ensure_application_selected_ex(state, state->scp11_state.security_level == SCP11_KEY_USAGE))) goto Cleanup; if ((res = _ykpiv_fetch_object(state, YKPIV_OBJ_CHUID, buf, &len)) == YKPIV_OK) { p_temp = buf; @@ -177,7 +177,7 @@ ykpiv_rc ykpiv_util_set_cardid(ykpiv_state *state, const ykpiv_cardid *cardid) { } if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return res; - if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup; + if (YKPIV_OK != (res = _ykpiv_ensure_application_selected_ex(state, state->scp11_state.security_level == SCP11_KEY_USAGE))) goto Cleanup; memcpy(buf, CHUID_TMPL, sizeof(CHUID_TMPL)); memcpy(buf + CHUID_GUID_OFFS, id, sizeof(id)); @@ -199,7 +199,7 @@ ykpiv_rc ykpiv_util_get_cccid(ykpiv_state *state, ykpiv_cccid *ccc) { if (!ccc) return YKPIV_ARGUMENT_ERROR; if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return res; - if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup; + if (YKPIV_OK != (res = _ykpiv_ensure_application_selected_ex(state, state->scp11_state.security_level == SCP11_KEY_USAGE))) goto Cleanup; res = _ykpiv_fetch_object(state, YKPIV_OBJ_CAPABILITY, buf, &len); if (YKPIV_OK == res) { @@ -235,7 +235,7 @@ ykpiv_rc ykpiv_util_set_cccid(ykpiv_state *state, const ykpiv_cccid *ccc) { } if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return res; - if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup; + if (YKPIV_OK != (res = _ykpiv_ensure_application_selected_ex(state, state->scp11_state.security_level == SCP11_KEY_USAGE))) goto Cleanup; len = sizeof(CCC_TMPL); memcpy(buf, CCC_TMPL, len); @@ -298,7 +298,7 @@ ykpiv_rc ykpiv_util_list_keys(ykpiv_state *state, uint8_t *key_count, ykpiv_key if ((NULL == data) || (NULL == data_len) || (NULL == key_count)) { return YKPIV_ARGUMENT_ERROR; } if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return res; - if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup; + if (YKPIV_OK != (res = _ykpiv_ensure_application_selected_ex(state, state->scp11_state.security_level == SCP11_KEY_USAGE))) goto Cleanup; // init return parameters *key_count = 0; @@ -384,7 +384,7 @@ ykpiv_rc ykpiv_util_read_cert(ykpiv_state *state, uint8_t slot, uint8_t **data, if ((NULL == data )|| (NULL == data_len)) return YKPIV_ARGUMENT_ERROR; if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return res; - if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup; + if (YKPIV_OK != (res = _ykpiv_ensure_application_selected_ex(state, state->scp11_state.security_level == SCP11_KEY_USAGE))) goto Cleanup; *data = 0; *data_len = 0; @@ -418,7 +418,7 @@ ykpiv_rc ykpiv_util_write_cert(ykpiv_state *state, uint8_t slot, uint8_t *data, ykpiv_rc res = YKPIV_OK; if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return res; - if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup; + if (YKPIV_OK != (res = _ykpiv_ensure_application_selected_ex(state, state->scp11_state.security_level == SCP11_KEY_USAGE))) goto Cleanup; res = _write_certificate(state, slot, data, data_len, certinfo); @@ -445,7 +445,7 @@ ykpiv_rc ykpiv_util_block_puk(ykpiv_state *state) { if (NULL == state) return YKPIV_ARGUMENT_ERROR; if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return res; - if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup; + if (YKPIV_OK != (res = _ykpiv_ensure_application_selected_ex(state, state->scp11_state.security_level == SCP11_KEY_USAGE))) goto Cleanup; while (tries != 0) { if (YKPIV_OK == (res = ykpiv_change_puk(state, (const char*)puk, sizeof(puk), (const char*)puk, sizeof(puk), &tries))) { @@ -501,7 +501,7 @@ ykpiv_rc ykpiv_util_read_mscmap(ykpiv_state *state, ykpiv_container **containers if ((NULL == containers) || (NULL == n_containers)) { res = YKPIV_ARGUMENT_ERROR; goto Cleanup; } if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return res; - if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup; + if (YKPIV_OK != (res = _ykpiv_ensure_application_selected_ex(state, state->scp11_state.security_level == SCP11_KEY_USAGE))) goto Cleanup; *containers = 0; *n_containers = 0; @@ -549,7 +549,7 @@ ykpiv_rc ykpiv_util_write_mscmap(ykpiv_state *state, ykpiv_container *containers size_t data_len = n_containers * sizeof(ykpiv_container); if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return res; - if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup; + if (YKPIV_OK != (res = _ykpiv_ensure_application_selected_ex(state, state->scp11_state.security_level == SCP11_KEY_USAGE))) goto Cleanup; // check if data and data_len are zero, this means that // we intend to delete the object @@ -608,7 +608,7 @@ ykpiv_rc ykpiv_util_read_msroots(ykpiv_state *state, uint8_t **data, size_t *dat if (!data || !data_len) return YKPIV_ARGUMENT_ERROR; if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return res; - if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup; + if (YKPIV_OK != (res = _ykpiv_ensure_application_selected_ex(state, state->scp11_state.security_level == SCP11_KEY_USAGE))) goto Cleanup; *data = 0; *data_len = 0; @@ -695,7 +695,7 @@ ykpiv_rc ykpiv_util_write_msroots(ykpiv_state *state, uint8_t *data, size_t data size_t cb_obj_max = _obj_size_max(state); if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return res; - if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup; + if (YKPIV_OK != (res = _ykpiv_ensure_application_selected_ex(state, state->scp11_state.security_level == SCP11_KEY_USAGE))) goto Cleanup; // check if either data and data_len are zero, this means that // we intend to delete the object @@ -847,7 +847,7 @@ ykpiv_rc ykpiv_util_generate_key(ykpiv_state *state, uint8_t slot, uint8_t algor } if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return res; - if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup; + if (YKPIV_OK != (res = _ykpiv_ensure_application_selected_ex(state, state->scp11_state.security_level == SCP11_KEY_USAGE))) goto Cleanup; templ[3] = slot; @@ -1022,7 +1022,7 @@ ykpiv_rc ykpiv_util_get_config(ykpiv_state *state, ykpiv_config *config) { config->mgm_type = YKPIV_CONFIG_MGM_MANUAL; if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return res; - if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup; + if (YKPIV_OK != (res = _ykpiv_ensure_application_selected_ex(state, state->scp11_state.security_level == SCP11_KEY_USAGE))) goto Cleanup; /* recover admin data */ if (YKPIV_OK == _read_metadata(state, TAG_ADMIN, data, &cb_data)) { @@ -1097,7 +1097,7 @@ ykpiv_rc ykpiv_util_set_pin_last_changed(ykpiv_state *state) { if (NULL == state) return YKPIV_ARGUMENT_ERROR; if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return res; - if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup; + if (YKPIV_OK != (res = _ykpiv_ensure_application_selected_ex(state, state->scp11_state.security_level == SCP11_KEY_USAGE))) goto Cleanup; /* recover admin data */ if (YKPIV_OK != (ykrc = _read_metadata(state, TAG_ADMIN, data, &cb_data))) { @@ -1134,7 +1134,7 @@ ykpiv_rc ykpiv_util_get_derived_mgm(ykpiv_state *state, const uint8_t *pin, cons if ((NULL == pin) || (0 == pin_len) || (NULL == mgm)) return YKPIV_ARGUMENT_ERROR; if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return res; - if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup; + if (YKPIV_OK != (res = _ykpiv_ensure_application_selected_ex(state, state->scp11_state.security_level == SCP11_KEY_USAGE))) goto Cleanup; /* recover management key */ if (YKPIV_OK == (res = _read_metadata(state, TAG_ADMIN, data, &cb_data))) { @@ -1170,7 +1170,7 @@ ykpiv_rc ykpiv_util_get_protected_mgm(ykpiv_state *state, ykpiv_mgm *mgm) { if (NULL == mgm) return YKPIV_ARGUMENT_ERROR; if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return res; - if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup; + if (YKPIV_OK != (res = _ykpiv_ensure_application_selected_ex(state, state->scp11_state.security_level == SCP11_KEY_USAGE))) goto Cleanup; if (YKPIV_OK != (res = _read_metadata(state, TAG_PROTECTED, data, &cb_data))) { DBG("could not read protected data, err = %d", res); @@ -1206,7 +1206,7 @@ ykpiv_rc ykpiv_util_update_protected_mgm(ykpiv_state *state, ykpiv_mgm *mgm) { size_t cb_data = sizeof(data); if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) goto Cleanup; - if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup; + if (YKPIV_OK != (res = _ykpiv_ensure_application_selected_ex(state, state->scp11_state.security_level == SCP11_KEY_USAGE))) goto Cleanup; if (YKPIV_OK != (res = _read_metadata(state, TAG_PROTECTED, data, &cb_data))) { cb_data = 0; /* set current metadata blob size to zero, we'll add to the blank blob */ @@ -1259,7 +1259,7 @@ ykpiv_rc ykpiv_util_set_protected_mgm(ykpiv_state *state, ykpiv_mgm *mgm) { } if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) goto Cleanup; - if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup; + if (YKPIV_OK != (res = _ykpiv_ensure_application_selected_ex(state, state->scp11_state.security_level == SCP11_KEY_USAGE))) goto Cleanup; /* try to set the mgm key as long as we don't encounter a fatal error */ do { diff --git a/lib/ykpiv.c b/lib/ykpiv.c index 7fb60130..bbe12747 100644 --- a/lib/ykpiv.c +++ b/lib/ykpiv.c @@ -591,12 +591,7 @@ static ykpiv_rc scp11_open_secure_channel(ykpiv_state *state) { return YKPIV_AUTHENTICATION_ERROR; } -#if ENABLE_APPLICATION_RESELECTION - res = _ykpiv_ensure_application_selected(state); -#else - res = _ykpiv_select_application(state); -#endif - if (res != YKPIV_OK) { + if ((res = _ykpiv_select_application(state)) != YKPIV_OK) { DBG("Failed to select PIV application after deriving SCP11 session keys"); return res; } @@ -705,16 +700,26 @@ static ykpiv_rc scp11_open_secure_channel(ykpiv_state *state) { } ykpiv_rc _ykpiv_select_application(ykpiv_state *state) { - unsigned char templ[] = {0x00, YKPIV_INS_SELECT_APPLICATION, 0x04, 0x00}; - unsigned char data[256] = {0}; - unsigned long recv_len = sizeof(data); - int sw = 0; + return _ykpiv_select_application_ex(state, false); +} + +ykpiv_rc _ykpiv_select_application_ex(ykpiv_state *state, bool scp11) { ykpiv_rc res = YKPIV_OK; - if((res = _ykpiv_transfer_data(state, templ, piv_aid, sizeof(piv_aid), data, &recv_len, &sw)) != YKPIV_OK) { - return res; + if(scp11) { + res = scp11_open_secure_channel(state); + } else { + unsigned char templ[] = {0x00, YKPIV_INS_SELECT_APPLICATION, 0x04, 0x00}; + unsigned char data[256] = {0}; + unsigned long recv_len = sizeof(data); + int sw = 0; + + + if ((res = _ykpiv_transfer_data(state, templ, piv_aid, sizeof(piv_aid), data, &recv_len, &sw)) != YKPIV_OK) { + return res; + } + res = ykpiv_translate_sw_ex(__FUNCTION__, sw); } - res = ykpiv_translate_sw_ex(__FUNCTION__, sw); if(res != YKPIV_OK) { DBG("Failed selecting application"); return res; @@ -746,8 +751,11 @@ ykpiv_rc _ykpiv_select_application(ykpiv_state *state) { return res; } + ykpiv_rc _ykpiv_ensure_application_selected(ykpiv_state *state) { + return _ykpiv_ensure_application_selected_ex(state, false); +} -ykpiv_rc _ykpiv_ensure_application_selected(ykpiv_state *state) { +ykpiv_rc _ykpiv_ensure_application_selected_ex(ykpiv_state *state, bool scp11) { ykpiv_rc res = YKPIV_OK; #if ENABLE_APPLICATION_RESELECTION if (NULL == state) { @@ -758,7 +766,7 @@ ykpiv_rc _ykpiv_ensure_application_selected(ykpiv_state *state) { if ((YKPIV_OK != res) && (YKPIV_WRONG_PIN != res) && (YKPIV_PIN_LOCKED != res)) { DBG("Failed to detect PIV application: '%s'", ykpiv_strerror(res)); - res = _ykpiv_select_application(state); + res = _ykpiv_select_application_ex(state, scp11); } else { res = YKPIV_OK; @@ -963,18 +971,12 @@ ykpiv_rc ykpiv_connect_ex(ykpiv_state *state, const char *wanted, bool scp11) { */ if (YKPIV_OK != (ret = _ykpiv_begin_transaction(state))) return ret; - if (scp11) { - if ((ret = scp11_open_secure_channel(state)) != YKPIV_OK) { - DBG("Unable to open encrypted session"); - return ret; - } - } else { + #if ENABLE_APPLICATION_RESELECTION - ret = _ykpiv_ensure_application_selected(state); + ret = _ykpiv_ensure_application_selected_ex(state, scp11); #else - ret = _ykpiv_select_application(state); + ret = _ykpiv_select_application_ex(state, scp11); #endif - } _ykpiv_end_transaction(state); return ret; @@ -1064,7 +1066,7 @@ ykpiv_rc _ykpiv_begin_transaction(ykpiv_state *state) { state->ver.minor = 0; state->ver.patch = 0; ykpiv_rc res; - if ((res = _ykpiv_select_application(state)) != YKPIV_OK) + if ((res = _ykpiv_select_application_ex(state, state->scp11_state.security_level == SCP11_KEY_USAGE)) != YKPIV_OK) return res; if(state->serial != serial) { DBG("Card #%u detected, was expecting card #%u", state->serial, serial); @@ -1181,14 +1183,14 @@ static const SCARD_IO_REQUEST* _pci(pcsc_word protocol) { static ykpiv_rc _ykpiv_transmit(ykpiv_state *state, const unsigned char *send_data, pcsc_word send_len, unsigned char *recv_data, pcsc_word *recv_len, int *sw) { - DBG2("> @", send_data, (size_t)send_len); + DBG("> @", send_data, (size_t)send_len); pcsc_long rc = SCardTransmit(state->card, _pci(state->protocol), send_data, send_len, NULL, recv_data, recv_len); if(rc != SCARD_S_SUCCESS) { DBG("SCardTransmit on card #%u failed, rc=%lx", state->serial, (long)rc); *sw = 0; return pcsc_to_yrc(rc); } - DBG2("< @", recv_data, (size_t)*recv_len); + DBG("< @", recv_data, (size_t)*recv_len); if(*recv_len >= 2) { *sw = (recv_data[*recv_len - 2] << 8) | recv_data[*recv_len - 1]; *recv_len -= 2; @@ -1198,12 +1200,12 @@ static ykpiv_rc _ykpiv_transmit(ykpiv_state *state, const unsigned char *send_da return YKPIV_OK; } -static ykpiv_rc scp11_prepare_transfer(ykpiv_scp11_state *state, APDU *apdu, size_t *apdu_len) { +static ykpiv_rc scp11_prepare_transfer(ykpiv_scp11_state *state, APDU *apdu, const uint8_t *apdu_data, size_t apdu_data_len, size_t *apdu_len) { ykpiv_rc rc = YKPIV_OK; - uint8_t enc[255] = {0}; + uint8_t enc[2048] = {0}; size_t enc_len = sizeof(enc); - if ((rc = aescbc_encrypt_data(state->senc, state->enc_counter++, apdu->st.data, apdu->st.lc, enc, &enc_len)) != + if ((rc = aescbc_encrypt_data(state->senc, state->enc_counter++, apdu_data, apdu_data_len, enc, &enc_len)) != YKPIV_OK) { DBG("Failed to perform AES ECD encryption on IV"); return rc; @@ -1235,7 +1237,13 @@ static ykpiv_rc scp11_prepare_transfer(ykpiv_scp11_state *state, APDU *apdu, siz return rc; } -static ykpiv_rc scp11_decrypt_response(ykpiv_scp11_state *state, uint8_t *data, size_t data_len, uint8_t *dec, size_t *dec_len, int sw) { +static ykpiv_rc +scp11_decrypt_response(ykpiv_scp11_state *state, uint8_t *data, size_t data_len, uint8_t *dec, size_t *dec_len, + int sw) { + if (data_len == 0) { + DBG("No response data to decrypt"); + return YKPIV_OK; + } ykpiv_rc rc = YKPIV_OK; if ((rc = unmac_data(state->srmac, state->mac_chain, data, data_len, sw)) != YKPIV_OK) { DBG("Failed to verify response MAC"); @@ -1249,7 +1257,7 @@ static ykpiv_rc scp11_decrypt_response(ykpiv_scp11_state *state, uint8_t *data, } return rc; -} + } ykpiv_rc _ykpiv_transfer_data(ykpiv_state *state, const unsigned char *templ, @@ -1265,34 +1273,67 @@ ykpiv_rc _ykpiv_transfer_data(ykpiv_state *state, APDU apdu = {templ[0], templ[1], templ[2], templ[3], 0xff}; unsigned char data[2048] = {0}; - if(in_len > 0xff) { - apdu.st.cla |= 0x10; - } else { - apdu.st.lc = (unsigned char)in_len; - } - - if (apdu.st.lc) { - memcpy(apdu.st.data, in_data, apdu.st.lc); - in_data += apdu.st.lc; - in_len -= apdu.st.lc; - } ykpiv_rc res = YKPIV_OK; pcsc_word apdu_len; + size_t apdu_length; if (state->scp11_state.security_level == SCP11_KEY_USAGE) { - if((res = scp11_prepare_transfer(&state->scp11_state, &apdu, &apdu_len)) != YKPIV_OK) { + if((res = scp11_prepare_transfer(&state->scp11_state, &apdu, in_data, in_len, &apdu_length)) != YKPIV_OK) { return res; } + in_len = 0; + apdu_len = apdu_length; } else { + if(in_len > 0xff) { + apdu.st.cla |= 0x10; + } else { + apdu.st.lc = (unsigned char)in_len; + } + apdu_len = apdu.st.lc + 5; - } - if (apdu.st.lc && state->protocol == SCARD_PROTOCOL_T1) { - apdu.st.data[apdu.st.lc] = 0; - apdu_len++; + if(apdu.st.lc) { + memcpy(apdu.st.data, in_data, apdu.st.lc); + in_data += apdu.st.lc; + in_len -= apdu.st.lc; + + // Add Le for T=1 + if (state->protocol == SCARD_PROTOCOL_T1) { + apdu.st.data[apdu.st.lc] = 0; + apdu_len++; + } + } } + + + +// if(in_len > 0xff) { +// apdu.st.cla |= 0x10; +// } else { +// apdu.st.lc = (unsigned char)in_len; +// } +// +// if (apdu.st.lc) { +// memcpy(apdu.st.data, in_data, apdu.st.lc); +// in_data += apdu.st.lc; +// in_len -= apdu.st.lc; +// } +// +// if (state->scp11_state.security_level == SCP11_KEY_USAGE) { +// if((res = scp11_prepare_transfer(&state->scp11_state, &apdu, &apdu_len)) != YKPIV_OK) { +// return res; +// } +// } else { +// apdu_len = apdu.st.lc + 5; +// } +// +// if (apdu.st.lc && state->protocol == SCARD_PROTOCOL_T1) { +// apdu.st.data[apdu.st.lc] = 0; +// apdu_len++; +// } + Retry: - DBG3("Going to send %u bytes in this go.", apdu_len); + DBG("Going to send %u bytes in this go.", apdu_len); pcsc_word recv_len = sizeof(data); if((res = _ykpiv_transmit(state, apdu.raw, apdu_len, data, &recv_len, sw)) != YKPIV_OK) { return res; @@ -1413,7 +1454,7 @@ ykpiv_rc ykpiv_authenticate2(ykpiv_state *state, unsigned const char *key, size_ if (NULL == state) return YKPIV_ARGUMENT_ERROR; if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return res; - if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup; + if (YKPIV_OK != (res = _ykpiv_ensure_application_selected_ex(state, state->scp11_state.security_level == SCP11_KEY_USAGE))) goto Cleanup; res = _ykpiv_authenticate2(state, key, len); @@ -1561,7 +1602,7 @@ ykpiv_rc ykpiv_set_mgmkey3(ykpiv_state *state, const unsigned char *new_key, siz ykpiv_rc res = YKPIV_OK; if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return res; - if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup; + if (YKPIV_OK != (res = _ykpiv_ensure_application_selected_ex(state, state->scp11_state.security_level == SCP11_KEY_USAGE))) goto Cleanup; if(algo == YKPIV_ALGO_AUTO || touch == YKPIV_TOUCHPOLICY_AUTO) { ykpiv_metadata metadata = {YKPIV_ALGO_3DES}; @@ -1662,7 +1703,7 @@ static ykpiv_rc _general_authenticate(ykpiv_state *state, unsigned char algorithm, unsigned char key, bool decipher) { unsigned char indata[YKPIV_OBJ_MAX_SIZE] = {0}; unsigned char *dataptr = indata; - unsigned char data[1024] = {0}; + unsigned char data[2048] = {0}; unsigned char templ[] = {0, YKPIV_INS_AUTHENTICATE, algorithm, key}; unsigned long recv_len = sizeof(data); size_t key_len = 0; @@ -1851,7 +1892,7 @@ ykpiv_rc ykpiv_get_version(ykpiv_state *state, char *version, size_t len) { ykpiv_rc res; if ((res = _ykpiv_begin_transaction(state)) < YKPIV_OK) return res; - if ((res = _ykpiv_ensure_application_selected(state)) < YKPIV_OK) goto Cleanup; + if ((res = _ykpiv_ensure_application_selected_ex(state, state->scp11_state.security_level == SCP11_KEY_USAGE)) < YKPIV_OK) goto Cleanup; if ((res = _ykpiv_get_version(state)) >= YKPIV_OK) { int result = snprintf(version, len, "%d.%d.%d", state->ver.major, state->ver.minor, state->ver.patch); @@ -1958,7 +1999,7 @@ ykpiv_rc ykpiv_get_serial(ykpiv_state *state, uint32_t *p_serial) { if (!state || !p_serial) return YKPIV_ARGUMENT_ERROR; if ((res = _ykpiv_begin_transaction(state)) != YKPIV_OK) return res; - if ((res = _ykpiv_ensure_application_selected(state)) != YKPIV_OK) goto Cleanup; + if ((res = _ykpiv_ensure_application_selected_ex(state, state->scp11_state.security_level == SCP11_KEY_USAGE)) != YKPIV_OK) goto Cleanup; res = _ykpiv_get_serial(state); *p_serial = state->serial; @@ -2149,7 +2190,7 @@ static ykpiv_rc _ykpiv_verify_select(ykpiv_state *state, char *pin, size_t* p_pi return res; } if (force_select) { - if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) { + if (YKPIV_OK != (res = _ykpiv_ensure_application_selected_ex(state, state->scp11_state.security_level == SCP11_KEY_USAGE))) { goto Cleanup; } } @@ -2196,7 +2237,7 @@ ykpiv_rc ykpiv_get_pin_retries(ykpiv_state *state, int *tries) { res = _ykpiv_auth_deauthenticate(state); if (res != YKPIV_OK) goto Cleanup; - res = _ykpiv_select_application(state); + res = _ykpiv_select_application_ex(state, state->scp11_state.security_level == SCP11_KEY_USAGE); if (res != YKPIV_OK) goto Cleanup; *tries = state->tries; Cleanup: @@ -2224,7 +2265,7 @@ ykpiv_rc ykpiv_set_pin_retries(ykpiv_state *state, int pin_tries, int puk_tries) templ[3] = (unsigned char)puk_tries; if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return res; - if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup; + if (YKPIV_OK != (res = _ykpiv_ensure_application_selected_ex(state, state->scp11_state.security_level == SCP11_KEY_USAGE))) goto Cleanup; res = _ykpiv_transfer_data(state, templ, NULL, 0, data, &recv_len, &sw); if (res == YKPIV_OK) { @@ -2286,7 +2327,7 @@ ykpiv_rc ykpiv_change_pin(ykpiv_state *state, const char * current_pin, size_t c ykpiv_rc res = YKPIV_GENERIC_ERROR; if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return res; - if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup; + if (YKPIV_OK != (res = _ykpiv_ensure_application_selected_ex(state, state->scp11_state.security_level == SCP11_KEY_USAGE))) goto Cleanup; res = _ykpiv_change_pin(state, CHREF_ACT_CHANGE_PIN, current_pin, current_pin_len, new_pin, new_pin_len, tries); if (res == YKPIV_OK && new_pin != NULL) { @@ -2304,7 +2345,7 @@ ykpiv_rc ykpiv_change_puk(ykpiv_state *state, const char * current_puk, size_t c ykpiv_rc res = YKPIV_GENERIC_ERROR; if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return res; - if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup; + if (YKPIV_OK != (res = _ykpiv_ensure_application_selected_ex(state, state->scp11_state.security_level == SCP11_KEY_USAGE))) goto Cleanup; res = _ykpiv_change_pin(state, CHREF_ACT_CHANGE_PUK, current_puk, current_puk_len, new_puk, new_puk_len, tries); @@ -2317,7 +2358,7 @@ ykpiv_rc ykpiv_unblock_pin(ykpiv_state *state, const char * puk, size_t puk_len, ykpiv_rc res = YKPIV_GENERIC_ERROR; if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return res; - if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup; + if (YKPIV_OK != (res = _ykpiv_ensure_application_selected_ex(state, state->scp11_state.security_level == SCP11_KEY_USAGE))) goto Cleanup; res = _ykpiv_change_pin(state, CHREF_ACT_UNBLOCK_PIN, puk, puk_len, new_pin, new_pin_len, tries); @@ -2331,7 +2372,7 @@ ykpiv_rc ykpiv_fetch_object(ykpiv_state *state, int object_id, ykpiv_rc res; if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return res; - if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup; + if (YKPIV_OK != (res = _ykpiv_ensure_application_selected_ex(state, state->scp11_state.security_level == SCP11_KEY_USAGE))) goto Cleanup; res = _ykpiv_fetch_object(state, object_id, data, len); @@ -2381,7 +2422,7 @@ ykpiv_rc ykpiv_save_object(ykpiv_state *state, int object_id, ykpiv_rc res; if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return res; - if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup; + if (YKPIV_OK != (res = _ykpiv_ensure_application_selected_ex(state, state->scp11_state.security_level == SCP11_KEY_USAGE))) goto Cleanup; res = _ykpiv_save_object(state, object_id, indata, len); @@ -2558,7 +2599,7 @@ ykpiv_rc ykpiv_import_private_key(ykpiv_state *state, const unsigned char key, u } if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return res; - if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup; + if (YKPIV_OK != (res = _ykpiv_ensure_application_selected_ex(state, state->scp11_state.security_level == SCP11_KEY_USAGE))) goto Cleanup; if ((res = _ykpiv_transfer_data(state, templ, key_data, (unsigned long)(in_ptr - key_data), data, &recv_len, &sw)) != YKPIV_OK) { goto Cleanup; @@ -2575,6 +2616,7 @@ ykpiv_rc ykpiv_import_private_key(ykpiv_state *state, const unsigned char key, u } ykpiv_rc ykpiv_attest(ykpiv_state *state, const unsigned char key, unsigned char *data, size_t *data_len) { + fprintf(stderr, "------------------------- ykpiv_attest()\n"); ykpiv_rc res; unsigned char templ[] = {0, YKPIV_INS_ATTEST, key, 0}; int sw = 0; @@ -2587,11 +2629,14 @@ ykpiv_rc ykpiv_attest(ykpiv_state *state, const unsigned char key, unsigned char ul_data_len = (unsigned long)*data_len; if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return res; - if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup; + fprintf(stderr, "------------------------- _ykpiv_begin_transaction() OK\n"); + if (YKPIV_OK != (res = _ykpiv_ensure_application_selected_ex(state, state->scp11_state.security_level == SCP11_KEY_USAGE))) goto Cleanup; + fprintf(stderr, "------------------------- _ykpiv_ensure_application_selected() OK\n"); if ((res = _ykpiv_transfer_data(state, templ, NULL, 0, data, &ul_data_len, &sw)) != YKPIV_OK) { goto Cleanup; } + fprintf(stderr, "------------------------- _ykpiv_transfer_data() OK\n"); res = ykpiv_translate_sw_ex(__FUNCTION__, sw); if (res != YKPIV_OK) { goto Cleanup; @@ -2619,7 +2664,7 @@ ykpiv_rc ykpiv_get_metadata(ykpiv_state *state, const unsigned char key, unsigne ul_data_len = (unsigned long)*data_len; if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return res; - if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup; + if (YKPIV_OK != (res = _ykpiv_ensure_application_selected_ex(state, state->scp11_state.security_level == SCP11_KEY_USAGE))) goto Cleanup; res = _ykpiv_get_metadata(state, key, data, &ul_data_len); @@ -2638,7 +2683,7 @@ ykpiv_rc ykpiv_auth_getchallenge(ykpiv_state *state, ykpiv_metadata *metadata, u if (NULL == challenge_len) return YKPIV_ARGUMENT_ERROR; if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return res; - if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup; + if (YKPIV_OK != (res = _ykpiv_ensure_application_selected_ex(state, state->scp11_state.security_level == SCP11_KEY_USAGE))) goto Cleanup; metadata->algorithm = YKPIV_ALGO_3DES;