int sm_cwa_decode_authentication_data(struct sc_context *ctx, struct sm_cwa_keyset *keyset, struct sm_cwa_session *session_data, unsigned char *auth_data) { DES_cblock icv = {0, 0, 0, 0, 0, 0, 0, 0}; DES_cblock cblock; unsigned char *decrypted = NULL; size_t decrypted_len; int rv; LOG_FUNC_CALLED(ctx); memset(icv, 0, sizeof(icv)); rv = sm_cwa_get_mac(ctx, keyset->mac, &icv, session_data->mdata, 0x40, &cblock, 1); LOG_TEST_RET(ctx, rv, "Decode authentication data: sm_ecc_get_mac failed"); sc_debug(ctx, SC_LOG_DEBUG_SM, "MAC:%s", sc_dump_hex(cblock, sizeof(cblock))); if(memcmp(session_data->mdata + 0x40, cblock, 8)) LOG_FUNC_RETURN(ctx, SC_ERROR_SM_AUTHENTICATION_FAILED); rv = sm_decrypt_des_cbc3(ctx, keyset->enc, session_data->mdata, session_data->mdata_len, &decrypted, &decrypted_len); LOG_TEST_RET(ctx, rv, "sm_ecc_decode_auth_data() DES CBC3 decrypt error"); sc_debug(ctx, SC_LOG_DEBUG_SM, "sm_ecc_decode_auth_data() decrypted(%"SC_FORMAT_LEN_SIZE_T"u) %s", decrypted_len, sc_dump_hex(decrypted, decrypted_len)); if (memcmp(decrypted, session_data->icc.rnd, 8)) { free(decrypted); LOG_FUNC_RETURN(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED); } if (memcmp(decrypted + 8, session_data->icc.sn, 8)) { free(decrypted); LOG_FUNC_RETURN(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED); } if (memcmp(decrypted + 16, session_data->ifd.rnd, 8)) { free(decrypted); LOG_FUNC_RETURN(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED); } if (memcmp(decrypted + 24, session_data->ifd.sn, 8)) { free(decrypted); LOG_FUNC_RETURN(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED); } memcpy(session_data->icc.k, decrypted + 32, 32); free(decrypted); LOG_FUNC_RETURN(ctx, SC_SUCCESS); }
int sm_cwa_securize_apdu(struct sc_context *ctx, struct sm_info *sm_info, struct sc_remote_apdu *rapdu) { struct sm_cwa_session *session_data = &sm_info->session.cwa; struct sc_apdu *apdu = &rapdu->apdu; unsigned char sbuf[0x400]; DES_cblock cblock, icv; unsigned char *encrypted = NULL, edfb_data[0x200], mac_data[0x200]; size_t encrypted_len, edfb_len = 0, mac_len = 0, offs; int rv; LOG_FUNC_CALLED(ctx); sc_log(ctx, "securize APDU (cla:%X,ins:%X,p1:%X,p2:%X,data(%i):%p)", apdu->cla, apdu->ins, apdu->p1, apdu->p2, apdu->datalen, apdu->data); sm_incr_ssc(session_data->ssc, sizeof(session_data->ssc)); rv = sm_encrypt_des_cbc3(ctx, session_data->session_enc, apdu->data, apdu->datalen, &encrypted, &encrypted_len, 0); LOG_TEST_RET(ctx, rv, "securize APDU: DES CBC3 encryption failed"); sc_log(ctx, "encrypted data (len:%i, %s)", encrypted_len, sc_dump_hex(encrypted, encrypted_len)); offs = 0; if (apdu->ins & 0x01) { edfb_data[offs++] = IASECC_SM_DO_TAG_TCG_ODD_INS; if (encrypted_len + 1 > 0x7F) edfb_data[offs++] = 0x81; edfb_data[offs++] = encrypted_len; } else { edfb_data[offs++] = IASECC_SM_DO_TAG_TCG_EVEN_INS; if (encrypted_len + 1 > 0x7F) edfb_data[offs++] = 0x81; edfb_data[offs++] = encrypted_len + 1; edfb_data[offs++] = 0x01; } memcpy(edfb_data + offs, encrypted, encrypted_len); offs += encrypted_len; edfb_len = offs; sc_log(ctx, "securize APDU: EDFB(len:%i,%sà", edfb_len, sc_dump_hex(edfb_data, edfb_len)); free(encrypted); encrypted = NULL; offs = 0; memcpy(mac_data + offs, session_data->ssc, 8); offs += 8; mac_data[offs++] = apdu->cla | 0x0C; mac_data[offs++] = apdu->ins; mac_data[offs++] = apdu->p1; mac_data[offs++] = apdu->p2; mac_data[offs++] = 0x80; mac_data[offs++] = 0x00; mac_data[offs++] = 0x00; mac_data[offs++] = 0x00; memcpy(mac_data + offs, edfb_data, edfb_len); offs += edfb_len; /* if (apdu->le) { */ mac_data[offs++] = IASECC_SM_DO_TAG_TLE; mac_data[offs++] = 1; mac_data[offs++] = apdu->le; /* } */ mac_len = offs; sc_log(ctx, "securize APDU: MAC data(len:%i,%s)", mac_len, sc_dump_hex(mac_data, mac_len)); memset(icv, 0, sizeof(icv)); rv = sm_cwa_get_mac(ctx, session_data->session_mac, &icv, mac_data, mac_len, &cblock, 0); LOG_TEST_RET(ctx, rv, "securize APDU: MAC calculation error"); sc_log(ctx, "securize APDU: MAC:%s", sc_dump_hex(cblock, sizeof(cblock))); offs = 0; if (edfb_len) { memcpy(sbuf + offs, edfb_data, edfb_len); offs += edfb_len; } /* if (apdu->le) { */ sbuf[offs++] = IASECC_SM_DO_TAG_TLE; sbuf[offs++] = 1; sbuf[offs++] = apdu->le; /* } */ sbuf[offs++] = IASECC_SM_DO_TAG_TCC; sbuf[offs++] = 8; memcpy(sbuf + offs, cblock, 8); offs += 8; sc_log(ctx, "securize APDU: SM data(len:%i,%s)", offs, sc_dump_hex(sbuf, offs)); if (offs > sizeof(rapdu->sbuf)) LOG_TEST_RET(ctx, SC_ERROR_BUFFER_TOO_SMALL, "securize APDU: buffer too small for encrypted data"); apdu->cse = SC_APDU_CASE_4_SHORT; apdu->cla |= 0x0C; apdu->lc = offs; apdu->datalen = offs; memcpy((unsigned char *)apdu->data, sbuf, offs); sm_incr_ssc(session_data->ssc, sizeof(session_data->ssc)); LOG_FUNC_RETURN(ctx, SC_SUCCESS); }
int sm_cwa_initialize(struct sc_context *ctx, struct sm_info *sm_info, struct sc_remote_data *rdata) { struct sm_cwa_session *cwa_session = &sm_info->session.cwa; struct sm_cwa_keyset *cwa_keyset = &sm_info->session.cwa.cwa_keyset; struct sc_serial_number sn = sm_info->serialnr; size_t icc_sn_len = sizeof(cwa_session->icc.sn); struct sc_remote_apdu *new_rapdu = NULL; struct sc_apdu *apdu = NULL; unsigned char buf[0x100], *encrypted; size_t encrypted_len; DES_cblock icv = {0, 0, 0, 0, 0, 0, 0, 0}, cblock; int rv, offs; LOG_FUNC_CALLED(ctx); sc_log(ctx, "SM IAS/ECC initialize: serial %s", sc_dump_hex(sm_info->serialnr.value, sm_info->serialnr.len)); sc_log(ctx, "SM IAS/ECC initialize: card challenge %s", sc_dump_hex(cwa_session->card_challenge, 8)); sc_log(ctx, "SM IAS/ECC initialize: current_df_path %s", sc_print_path(&sm_info->current_path_df)); sc_log(ctx, "SM IAS/ECC initialize: CRT_AT reference 0x%X", cwa_session->params.crt_at.refs[0]); if (!rdata || !rdata->alloc) LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); rv = rdata->alloc(rdata, &new_rapdu); LOG_TEST_RET(ctx, rv, "SM GP decode card answer: cannot allocate remote APDU"); apdu = &new_rapdu->apdu; memcpy(&cwa_session->icc.rnd[0], cwa_session->card_challenge, 8); if (sn.len > icc_sn_len) memcpy(&cwa_session->icc.sn[0], &sn.value[sn.len - icc_sn_len], icc_sn_len); else memcpy(&cwa_session->icc.sn[icc_sn_len - sn.len], &sn.value[0], sn.len); if (sm_info->cmd == SM_CMD_EXTERNAL_AUTH) { offs = sm_cwa_encode_external_auth_data(ctx, cwa_session, buf, sizeof(buf)); if (offs != 0x10) LOG_FUNC_RETURN(ctx, offs); } else { offs = sm_cwa_encode_mutual_auth_data(ctx, cwa_session, buf, sizeof(buf)); if (offs != 0x40) LOG_FUNC_RETURN(ctx, offs); } sc_log(ctx, "S(%i) %s", offs, sc_dump_hex(buf, offs)); rv = sm_encrypt_des_cbc3(ctx, cwa_keyset->enc, buf, offs, &encrypted, &encrypted_len, 1); LOG_TEST_RET(ctx, rv, "_encrypt_des_cbc3() failed"); sc_log(ctx, "ENCed(%i) %s", encrypted_len, sc_dump_hex(encrypted, encrypted_len)); memcpy(buf, encrypted, encrypted_len); offs = encrypted_len; rv = sm_cwa_get_mac(ctx, cwa_keyset->mac, &icv, buf, offs, &cblock, 1); LOG_TEST_RET(ctx, rv, "sm_ecc_get_mac() failed"); sc_log(ctx, "MACed(%i) %s", sizeof(cblock), sc_dump_hex(cblock, sizeof(cblock))); apdu->cse = SC_APDU_CASE_4_SHORT; apdu->cla = 0x00; apdu->ins = 0x82; apdu->p1 = 0x00; apdu->p2 = 0x00; apdu->lc = encrypted_len + sizeof(cblock); apdu->le = encrypted_len + sizeof(cblock); apdu->datalen = encrypted_len + sizeof(cblock); memcpy(new_rapdu->sbuf, encrypted, encrypted_len); memcpy(new_rapdu->sbuf + encrypted_len, cblock, sizeof(cblock)); free(encrypted); LOG_FUNC_RETURN(ctx, SC_SUCCESS); }