static int gemsafe_compute_signature(struct sc_card *card, const u8 * data, size_t data_len, u8 * out, size_t outlen) { int r, len; struct sc_apdu apdu; u8 rbuf[SC_MAX_APDU_BUFFER_SIZE]; u8 sbuf[SC_MAX_APDU_BUFFER_SIZE]; sc_context_t *ctx = card->ctx; SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); if (data_len > 36) { sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "error: input data too long: %lu bytes\n", data_len); return SC_ERROR_INVALID_ARGUMENTS; } /* the Portuguese eID card requires a two-phase exchange */ if(card->type == SC_CARD_TYPE_GEMSAFEV1_PTEID) { sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x2A, 0x90, 0xA0); } else { sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x2A, 0x9E, 0xAC); apdu.cla |= 0x80; apdu.resp = rbuf; apdu.resplen = sizeof(rbuf); apdu.le = 256; } /* we sign a digestInfo object => tag 0x90 */ sbuf[0] = 0x90; sbuf[1] = (u8)data_len; memcpy(sbuf + 2, data, data_len); apdu.data = sbuf; apdu.lc = data_len + 2; apdu.datalen = data_len + 2; r = sc_transmit_apdu(card, &apdu); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed"); if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) { if(card->type == SC_CARD_TYPE_GEMSAFEV1_PTEID) { /* finalize the exchange */ sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0x2A, 0x9E, 0x9A); apdu.le = 128; /* 1024 bit keys */ apdu.resp = rbuf; apdu.resplen = sizeof(rbuf); r = sc_transmit_apdu(card, &apdu); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed"); if(apdu.sw1 != 0x90 || apdu.sw2 != 0x00) SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2)); } len = apdu.resplen > outlen ? outlen : apdu.resplen; memcpy(out, apdu.resp, len); SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, len); } SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2)); }
static int iso7816_update_binary(sc_card_t *card, unsigned int idx, const u8 *buf, size_t count, unsigned long flags) { sc_apdu_t apdu; int r; assert(count <= card->max_send_size); if (idx > 0x7fff) { sc_error(card->ctx, "invalid EF offset: 0x%X > 0x7FFF", idx); return SC_ERROR_OFFSET_TOO_LARGE; } sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xD6, (idx >> 8) & 0x7F, idx & 0xFF); apdu.lc = count; apdu.datalen = count; apdu.data = buf; r = sc_transmit_apdu(card, &apdu); SC_TEST_RET(card->ctx, r, "APDU transmit failed"); SC_TEST_RET(card->ctx, sc_check_sw(card, apdu.sw1, apdu.sw2), "Card returned error"); SC_FUNC_RETURN(card->ctx, 3, count); }
static int iso7816_update_record(sc_card_t *card, unsigned int rec_nr, const u8 *buf, size_t count, unsigned long flags) { sc_apdu_t apdu; int r; if (count > 256) { sc_error(card->ctx, "Trying to send too many bytes\n"); return SC_ERROR_INVALID_ARGUMENTS; } sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xDC, rec_nr, 0); apdu.p2 = (flags & SC_RECORD_EF_ID_MASK) << 3; if (flags & SC_RECORD_BY_REC_NR) apdu.p2 |= 0x04; apdu.lc = count; apdu.datalen = count; apdu.data = buf; r = sc_transmit_apdu(card, &apdu); SC_TEST_RET(card->ctx, r, "APDU transmit failed"); SC_TEST_RET(card->ctx, sc_check_sw(card, apdu.sw1, apdu.sw2), "Card returned error"); SC_FUNC_RETURN(card->ctx, 3, count); }
static int iso7816_read_record(sc_card_t *card, unsigned int rec_nr, u8 *buf, size_t count, unsigned long flags) { sc_apdu_t apdu; u8 recvbuf[SC_MAX_APDU_BUFFER_SIZE]; int r; sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xB2, rec_nr, 0); apdu.p2 = (flags & SC_RECORD_EF_ID_MASK) << 3; if (flags & SC_RECORD_BY_REC_NR) apdu.p2 |= 0x04; apdu.le = count; apdu.resplen = count; apdu.resp = recvbuf; r = sc_transmit_apdu(card, &apdu); SC_TEST_RET(card->ctx, r, "APDU transmit failed"); if (apdu.resplen == 0) SC_FUNC_RETURN(card->ctx, 2, sc_check_sw(card, apdu.sw1, apdu.sw2)); memcpy(buf, recvbuf, apdu.resplen); SC_FUNC_RETURN(card->ctx, 3, apdu.resplen); }
/* Test the result code of the pin pad reader + the card's status bytes */ static int belpic_pp_test_res(sc_card_t *card, int r, const u8 * card_status, int *tries_left) { #if 0 printf("PP res: 0x%0x (%d), SW1-SW2 = %02x %02x\n", r, r, card_status[0], card_status[1]); #endif if (r != SCARD_S_SUCCESS) { switch (r) { case SCARD_E_CANCELLED: return SC_ERROR_KEYPAD_CANCELLED; case SCARD_W_REMOVED_CARD: return SC_ERROR_CARD_REMOVED; case SCR_I_PIN_CHECK_FAILED: return SC_ERROR_KEYPAD_PIN_MISMATCH; default: return SC_ERROR_TRANSMIT_FAILED; } } if (card_status[0] == 0xEC && card_status[1] == 0xD2) return SC_ERROR_KEYPAD_TIMEOUT; if (card_status[0] == 0xEC && card_status[1] == 0xD6) return SC_ERROR_KEYPAD_CANCELLED; if (card_status[0] == 0x63) { if ((card_status[1] & 0xF0) == 0xC0 && tries_left != NULL) *tries_left = card_status[1] & 0x0F; return SC_ERROR_PIN_CODE_INCORRECT; } return sc_check_sw(card, card_status[0], card_status[1]); }
static int entersafe_read_binary(sc_card_t *card, unsigned int idx, u8 *buf, size_t count, unsigned long flags) { sc_apdu_t apdu; u8 recvbuf[SC_MAX_APDU_BUFFER_SIZE]; int r; SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); assert(count <= card->max_recv_size); sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xB0, (idx >> 8) & 0xFF, idx & 0xFF); apdu.cla=idx > 0x7fff ? 0x80:0x00; apdu.le = count; apdu.resplen = count; apdu.resp = recvbuf; r = entersafe_transmit_apdu(card, &apdu,0,0,0,0); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed"); if (apdu.resplen == 0) SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2)); memcpy(buf, recvbuf, apdu.resplen); SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, apdu.resplen); }
static int ias_compute_signature(sc_card_t *card, const u8 *data, size_t data_len, u8 *out, size_t outlen) { sc_apdu_t apdu; size_t len; /* ** XXX: Ensure sufficient space exists for the card's response ** as the caller's buffer size may not be sufficient */ u8 rbuf[SC_MAX_APDU_BUFFER_SIZE]; sc_context_t *ctx = card->ctx; SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); if (data_len > 64) { sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "error: input data too long: %lu bytes\n", data_len); return SC_ERROR_INVALID_ARGUMENTS; } sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x88, 0x02, 0x00); apdu.data = (u8 *) data; apdu.lc = data_len; apdu.datalen = data_len; apdu.resp = rbuf; apdu.resplen = sizeof(rbuf); apdu.le = 256; LOG_TEST_RET(card->ctx, sc_transmit_apdu(card, &apdu), "APDU transmit failed"); LOG_TEST_RET(card->ctx, sc_check_sw(card, apdu.sw1, apdu.sw2), "INTERNAL AUTHENTICATE failed"); len = apdu.resplen > outlen ? outlen : apdu.resplen; memcpy(out, apdu.resp, len); LOG_FUNC_RETURN(card->ctx, apdu.resplen); }
static int gemsafe_decipher(struct sc_card *card, const u8 * crgram, size_t crgram_len, u8 *out, size_t outlen) { int r; struct sc_apdu apdu; u8 rbuf[SC_MAX_APDU_BUFFER_SIZE]; sc_context_t *ctx = card->ctx; SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); if (crgram_len > 255) SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS); sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x2A, 0x80, 0x84); apdu.cla |= 0x80; apdu.resp = rbuf; apdu.resplen = sizeof(rbuf); apdu.le = crgram_len; apdu.data = crgram; apdu.lc = crgram_len; apdu.datalen = crgram_len; r = sc_transmit_apdu(card, &apdu); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed"); if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) { int len = apdu.resplen > outlen ? outlen : apdu.resplen; memcpy(out, apdu.resp, len); SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, len); } SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2)); }
static int iasecc_sm_transmit_apdus(struct sc_card *card, struct sc_remote_data *rdata, unsigned char *out, size_t *out_len) { struct sc_context *ctx = card->ctx; struct sc_remote_apdu *rapdu = rdata->data; int rv = SC_SUCCESS, offs = 0; LOG_FUNC_CALLED(ctx); sc_log(ctx, "iasecc_sm_transmit_apdus() rdata-length %i", rdata->length); while (rapdu) { sc_log(ctx, "iasecc_sm_transmit_apdus() rAPDU flags 0x%lX", rapdu->apdu.flags); rv = sc_transmit_apdu(card, &rapdu->apdu); LOG_TEST_RET(ctx, rv, "iasecc_sm_transmit_apdus() failed to execute r-APDU"); rv = sc_check_sw(card, rapdu->apdu.sw1, rapdu->apdu.sw2); if (rv < 0 && !(rapdu->flags & SC_REMOTE_APDU_FLAG_NOT_FATAL)) LOG_TEST_RET(ctx, rv, "iasecc_sm_transmit_apdus() fatal error %i"); if (out && out_len && (rapdu->flags & SC_REMOTE_APDU_FLAG_RETURN_ANSWER)) { int len = rapdu->apdu.resplen > (*out_len - offs) ? (*out_len - offs) : rapdu->apdu.resplen; memcpy(out + offs, rapdu->apdu.resp, len); offs += len; /* TODO: decode and gather data answers */ } rapdu = rapdu->next; } if (out_len) *out_len = offs; LOG_FUNC_RETURN(ctx, rv); }
static int iso7816_read_binary(sc_card_t *card, unsigned int idx, u8 *buf, size_t count, unsigned long flags) { sc_apdu_t apdu; u8 recvbuf[SC_MAX_APDU_BUFFER_SIZE]; int r; if (idx > 0x7fff) { sc_error(card->ctx, "invalid EF offset: 0x%X > 0x7FFF", idx); return SC_ERROR_OFFSET_TOO_LARGE; } assert(count <= card->max_recv_size); sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xB0, (idx >> 8) & 0x7F, idx & 0xFF); apdu.le = count; apdu.resplen = count; apdu.resp = recvbuf; r = sc_transmit_apdu(card, &apdu); SC_TEST_RET(card->ctx, r, "APDU transmit failed"); if (apdu.resplen == 0) SC_FUNC_RETURN(card->ctx, 2, sc_check_sw(card, apdu.sw1, apdu.sw2)); memcpy(buf, recvbuf, apdu.resplen); SC_FUNC_RETURN(card->ctx, 3, apdu.resplen); }
static int atrust_acos_logout(struct sc_card *card) { int r; struct sc_apdu apdu; const u8 mf_buf[2] = {0x3f, 0x00}; sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xA4, 0x00, 0x0C); apdu.le = 0; apdu.lc = 2; apdu.data = mf_buf; apdu.datalen = 2; apdu.resplen = 0; sc_ctx_suppress_errors_on(card->ctx); r = sc_transmit_apdu(card, &apdu); sc_ctx_suppress_errors_off(card->ctx); SC_TEST_RET(card->ctx, r, "APDU re-transmit failed"); if (apdu.sw1 == 0x69 && apdu.sw2 == 0x85) /* the only possible reason for this error here is, afaik, * that no MF exists, but then there's no need to logout * => return SC_SUCCESS */ return SC_SUCCESS; return sc_check_sw(card, apdu.sw1, apdu.sw2); }
/** parse answer of SM protected APDU returned by APDU or by 'GET RESPONSE' * @param card 'sc_card' smartcard object * @param resp_data 'raw data returned by SM protected APDU * @param resp_len 'length of raw data returned by SM protected APDU * @param ref_rv 'status word returned by APDU or 'GET RESPONSE' (can be different from status word encoded into SM response date) * @param apdu 'sc_apdu' object to update * @return SC_SUCCESS on success and an error code otherwise */ static int sc_sm_update_apdu_response(struct sc_card *card, unsigned char *resp_data, size_t resp_len, int ref_rv, struct sc_apdu *apdu) { struct sm_card_response sm_resp; int r; if (!apdu) return SC_ERROR_INVALID_ARGUMENTS; else if (!resp_data || !resp_len) return SC_SUCCESS; memset(&sm_resp, 0, sizeof(sm_resp)); r = sc_sm_parse_answer(card->ctx, resp_data, resp_len, &sm_resp); if (r) return r; else if (!sm_resp.sw1 && !sm_resp.sw2) return SC_ERROR_INVALID_DATA; else if (ref_rv != sc_check_sw(card, sm_resp.sw1, sm_resp.sw2)) return SC_ERROR_INVALID_DATA; if (sm_resp.mac_len) { if (sm_resp.mac_len > sizeof(apdu->mac)) return SC_ERROR_INVALID_DATA; memcpy(apdu->mac, sm_resp.mac, sm_resp.mac_len); apdu->mac_len = sm_resp.mac_len; } apdu->sw1 = sm_resp.sw1; apdu->sw2 = sm_resp.sw2; return SC_SUCCESS; }
static int iso7816_update_binary(struct sc_card *card, unsigned int idx, const u8 *buf, size_t count, unsigned long flags) { struct sc_apdu apdu; int r; if (idx > 0x7fff) { sc_log(card->ctx, "invalid EF offset: 0x%X > 0x7FFF", idx); return SC_ERROR_OFFSET_TOO_LARGE; } sc_format_apdu(card, &apdu, SC_APDU_CASE_3, 0xD6, (idx >> 8) & 0x7F, idx & 0xFF); apdu.lc = count; apdu.datalen = count; apdu.data = buf; fixup_transceive_length(card, &apdu); r = sc_transmit_apdu(card, &apdu); LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); r = sc_check_sw(card, apdu.sw1, apdu.sw2); LOG_TEST_RET(card->ctx, r, "Card returned error"); LOG_FUNC_RETURN(card->ctx, count); }
static int entersafe_create_mf(sc_card_t *card, sc_entersafe_create_data * data) { int r; sc_apdu_t apdu; SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); memcpy(data->data.df.init_key, init_key, sizeof(init_key)); sc_format_apdu(card,&apdu,SC_APDU_CASE_3_SHORT,0xE0,0x00,0x00); apdu.cla=0x84; apdu.data=(u8*)&data->data.df; apdu.datalen=apdu.lc=sizeof(data->data.df); switch(card->type) { case SC_CARD_TYPE_ENTERSAFE_3K: { r = entersafe_transmit_apdu(card, &apdu,trans_code_3k,sizeof(trans_code_3k),0,1); }break; case SC_CARD_TYPE_ENTERSAFE_FTCOS_PK_01C: { r = entersafe_transmit_apdu(card, &apdu,trans_code_ftcos_pk_01c,sizeof(trans_code_ftcos_pk_01c),0,1); }break; default: { r = SC_ERROR_INTERNAL; }break; } SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed"); return sc_check_sw(card, apdu.sw1, apdu.sw2); }
/* * SELECT an applet on the smartcard. (Not in the emulated filesystem.) * The response will be written to resp. * * @param[in] card * @param[in] aid The applet ID. * @param[in] aid_len The legth of aid. * @param[out] resp The response of the applet upon selection. * @param[in,out] resp_len In: The buffer size of resp. Out: The length of the response. * * @return SC_SUCCESS: The applet is present and could be selected. * any other: Transmit failure or the card returned an error. * The card will return an error when the applet is * not present. */ static int isoApplet_select_applet(sc_card_t *card, const u8 *aid, const size_t aid_len, u8 *resp, size_t *resp_len) { int rv; sc_context_t *ctx = card->ctx; sc_apdu_t apdu; LOG_FUNC_CALLED(card->ctx); if(aid_len > SC_MAX_APDU_BUFFER_SIZE) LOG_FUNC_RETURN(card->ctx, SC_ERROR_BUFFER_TOO_SMALL); sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xa4, 0x04, 0x00); apdu.lc = aid_len; apdu.data = aid; apdu.datalen = aid_len; apdu.resp = resp; apdu.resplen = *resp_len; apdu.le = 0; rv = sc_transmit_apdu(card, &apdu); LOG_TEST_RET(ctx, rv, "APDU transmit faiure."); rv = sc_check_sw(card, apdu.sw1, apdu.sw2); LOG_TEST_RET(card->ctx, rv, "Card returned error"); *resp_len = apdu.resplen; LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); }
static int jpki_compute_signature(sc_card_t * card, const u8 * data, size_t datalen, u8 * out, size_t outlen) { int rc; sc_apdu_t apdu; unsigned char resp[SC_MAX_APDU_BUFFER_SIZE]; LOG_FUNC_CALLED(card->ctx); sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x2A, 0x00, 0x80); apdu.cla = 0x80; apdu.data = data; apdu.datalen = datalen; apdu.lc = datalen; apdu.resp = resp; apdu.resplen = sizeof(resp); apdu.le = 0; rc = sc_transmit_apdu(card, &apdu); LOG_TEST_RET(card->ctx, rc, "APDU transmit failed"); rc = sc_check_sw(card, apdu.sw1, apdu.sw2); LOG_TEST_RET(card->ctx, rc, "SW Check failed"); if (apdu.resplen > outlen) { LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); } memcpy(out, resp, apdu.resplen); LOG_FUNC_RETURN(card->ctx, apdu.resplen); }
static int gp_select_applet(sc_card_t *card, const u8 *aid, size_t aid_len) { int r; u8 buf[SC_MAX_APDU_BUFFER_SIZE]; struct sc_context *ctx = card->ctx; struct sc_apdu apdu; SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0xa4, 0x04, 0x00); apdu.lc = aid_len; apdu.data = aid; apdu.datalen = aid_len; apdu.resp = buf; apdu.le = 256; apdu.resplen = sizeof(buf); r = sc_transmit_apdu(card, &apdu); SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed"); r = sc_check_sw(card, apdu.sw1, apdu.sw2); if (r) SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE, r); return SC_SUCCESS; }
static int iasecc_sm_se_mutual_authentication(struct sc_card *card, unsigned se_num) { struct sc_context *ctx = card->ctx; #ifdef ENABLE_SM struct sm_info *sm_info = &card->sm_ctx.info; struct iasecc_se_info se; struct sc_crt *crt = &sm_info->session.cwa.params.crt_at; struct sc_apdu apdu; unsigned char sbuf[0x100]; int rv, offs; memset(&se, 0, sizeof(se)); se.reference = se_num; crt->usage = IASECC_UQB_AT_MUTUAL_AUTHENTICATION; crt->tag = IASECC_CRT_TAG_AT; rv = iasecc_se_get_info(card, &se); LOG_TEST_RET(ctx, rv, "Get SE info error"); rv = iasecc_se_get_crt(card, &se, crt); LOG_TEST_RET(ctx, rv, "Cannot get authentication CRT"); if (se.df) sc_file_free(se.df); /* MSE SET Mutual Authentication SK scheme */ offs = 0; sbuf[offs++] = IASECC_CRT_TAG_ALGO; sbuf[offs++] = 0x01; sbuf[offs++] = crt->algo; sbuf[offs++] = IASECC_CRT_TAG_REFERENCE; sbuf[offs++] = 0x01; sbuf[offs++] = crt->refs[0]; sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0xC1, 0xA4); apdu.data = sbuf; apdu.datalen = offs; apdu.lc = offs; rv = sc_transmit_apdu(card, &apdu); LOG_TEST_RET(ctx, rv, "SM set SE mutual auth.: APDU transmit failed"); rv = sc_check_sw(card, apdu.sw1, apdu.sw2); LOG_TEST_RET(ctx, rv, "SM set SE mutual auth.: set SE error"); LOG_FUNC_RETURN(ctx, rv); #else LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "built without support of Secure-Messaging"); return SC_ERROR_NOT_SUPPORTED; #endif }
static int incrypto34_list_files(sc_card_t *card, u8 *buf, size_t buflen) { sc_apdu_t apdu; u8 rbuf[256]; int r; size_t fids; u8 offset; SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); fids=0; offset=0; /* INS 0xFC: SCAN DF*/ /* P1 0x00: list both DF and EF */ /* P2 0x00/0x01: first/next element */ /* LE 0x03*/ /* returns 3 bytes: FILE_TYPE + FID_HI_BYTE + FID_LO_BYTE */ get_next_part: sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xFC, 0x00, offset?0x01:0x00); apdu.cla = 0xB0; apdu.le = 3; apdu.resplen = sizeof(rbuf); apdu.resp = rbuf; r = sc_transmit_apdu(card, &apdu); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed"); if (apdu.sw1 == 0x6a && apdu.sw2 == 0x82) goto end; /* no more files */ r = sc_check_sw(card, apdu.sw1, apdu.sw2); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "DIRECTORY command returned error"); if (apdu.resplen >= 3 && ((rbuf[0] >= 0x01 && rbuf[0] <= 0x07) || 0x38 == rbuf[0]) && fids + 2 >= buflen) { buf[fids++] = rbuf[1]; buf[fids++] = rbuf[2]; } ++offset; goto get_next_part; end: r = fids; SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r); }
static int iso7816_read_binary(struct sc_card *card, unsigned int idx, u8 *buf, size_t count, unsigned long flags) { struct sc_context *ctx = card->ctx; struct sc_apdu apdu; int r; if (idx > 0x7fff) { sc_log(ctx, "invalid EF offset: 0x%X > 0x7FFF", idx); return SC_ERROR_OFFSET_TOO_LARGE; } sc_format_apdu(card, &apdu, SC_APDU_CASE_2, 0xB0, (idx >> 8) & 0x7F, idx & 0xFF); apdu.le = count; apdu.resplen = count; apdu.resp = buf; fixup_transceive_length(card, &apdu); r = sc_transmit_apdu(card, &apdu); LOG_TEST_RET(ctx, r, "APDU transmit failed"); if (apdu.resplen == 0) LOG_FUNC_RETURN(ctx, sc_check_sw(card, apdu.sw1, apdu.sw2)); r = sc_check_sw(card, apdu.sw1, apdu.sw2); if (r == SC_ERROR_FILE_END_REACHED) LOG_FUNC_RETURN(ctx, apdu.resplen); LOG_TEST_RET(ctx, r, "Check SW error"); if (apdu.resplen < count) { r = iso7816_read_binary(card, idx + apdu.resplen, buf + apdu.resplen, count - apdu.resplen, flags); /* Ignore all but 'corrupted data' errors */ if (r == SC_ERROR_CORRUPTED_DATA) LOG_FUNC_RETURN(ctx, SC_ERROR_CORRUPTED_DATA); else if (r > 0) apdu.resplen += r; } LOG_FUNC_RETURN(ctx, apdu.resplen); }
static int do_apdu(int argc, char **argv) { sc_apdu_t apdu; u8 buf[SC_MAX_APDU_BUFFER_SIZE * 2]; u8 rbuf[SC_MAX_APDU_BUFFER_SIZE * 2]; size_t len, i; int r; if (argc < 1) return usage(do_apdu); for (i = 0, len = 0; i < (unsigned) argc; i++) { size_t len0 = strlen(argv[i]); if ((r = parse_string_or_hexdata(argv[i], buf + len, &len0)) < 0) { fprintf(stderr, "error parsing %s: %s\n", argv[i], sc_strerror(r)); return r; }; len += len0; } r = sc_bytes2apdu(card->ctx, buf, len, &apdu); if (r) { fprintf(stderr, "Invalid APDU: %s\n", sc_strerror(r)); return 2; } apdu.resp = rbuf; apdu.resplen = sizeof(rbuf); printf("Sending: "); util_hex_dump(stdout, buf, len, " "); printf("\n"); r = sc_transmit_apdu(card, &apdu); if (r) { fprintf(stderr, "APDU transmit failed: %s\n", sc_strerror(r)); return 1; } printf("Received (SW1=0x%02X, SW2=0x%02X)%s\n", apdu.sw1, apdu.sw2, apdu.resplen ? ":" : ""); if (apdu.resplen) util_hex_dump_asc(stdout, apdu.resp, apdu.resplen, -1); r = sc_check_sw(card, apdu.sw1, apdu.sw2); if (r) printf("Failure: %s\n", sc_strerror(r)); else printf("Success!\n"); return 0; }
static int gemsafe_restore_security_env(struct sc_card *card, int se_num) { int r; struct sc_apdu apdu; SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x22, 0x73, (u8) se_num); r = sc_transmit_apdu(card, &apdu); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed"); return sc_check_sw(card, apdu.sw1, apdu.sw2); }
static int belpic_select_file(sc_card_t *card, const sc_path_t *in_path, sc_file_t **file_out) { sc_context_t *ctx; sc_apdu_t apdu; u8 pathbuf[SC_MAX_PATH_SIZE], *path = pathbuf; int r, pathlen; sc_file_t *file = NULL; assert(card != NULL && in_path != NULL); ctx = card->ctx; memcpy(path, in_path->value, in_path->len); pathlen = in_path->len; sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xA4, 0x08, 0x0C); apdu.lc = pathlen; apdu.data = path; apdu.datalen = pathlen; apdu.resplen = 0; apdu.le = 0; r = sc_transmit_apdu(card, &apdu); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "Select File APDU transmit failed"); r = sc_check_sw(card, apdu.sw1, apdu.sw2); if (r) SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r); next_idx = (size_t)-1; /* reset */ if (file_out != NULL) { file = sc_file_new(); file->path = *in_path; if (pathlen >= 2) file->id = (in_path->value[pathlen - 2] << 8) | in_path->value[pathlen - 1]; file->size = BELPIC_MAX_FILE_SIZE; file->shareable = 1; file->ef_structure = SC_FILE_EF_TRANSPARENT; if (pathlen == 2 && memcmp("\x3F\x00", in_path->value, 2) == 0) file->type = SC_FILE_TYPE_DF; else file->type = SC_FILE_TYPE_WORKING_EF; *file_out = file; } return 0; }
/* sets the security attribute of a EF/DF */ static int asepcos_set_sec_attributes(sc_card_t *card, const u8 *data, size_t len, int is_ef) { int r, type = is_ef != 0 ? 0x02 : 0x04; sc_apdu_t apdu; sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x8a, type, 0xab); apdu.cla |= 0x80; apdu.lc = len; apdu.datalen = len; apdu.data = data; r = sc_transmit_apdu(card, &apdu); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed"); return sc_check_sw(card, apdu.sw1, apdu.sw2); }
static int entersafe_create_ef(sc_card_t *card, sc_entersafe_create_data * data) { int r; sc_apdu_t apdu; SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xE0, 0x02, 0x00); apdu.cla = 0x84; apdu.data = (u8*)&data->data.ef; apdu.lc = apdu.datalen = sizeof(data->data.ef); r = entersafe_transmit_apdu(card, &apdu,init_key,sizeof(init_key),0,1); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed"); return sc_check_sw(card, apdu.sw1, apdu.sw2); }
static int belpic_logout(sc_card_t *card) { sc_apdu_t apdu; int r; sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0xE6, 0x00, 0x00); apdu.cla = 0x80; r = sc_transmit_apdu(card, &apdu); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "LOGOFF: APDU transmit failed"); r = sc_check_sw(card, apdu.sw1, apdu.sw2); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "LOGOFF returned error"); SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r); }
static int mcrd_set_decipher_key_ref(sc_card_t * card, int key_reference) { sc_apdu_t apdu; sc_path_t path; int r; u8 sbuf[SC_MAX_APDU_BUFFER_SIZE]; u8 keyref_data[SC_ESTEID_KEYREF_FILE_RECLEN]; assert(card != NULL); sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0x41, 0xB8); /* track the active keypair */ sc_format_path("0033", &path); r = sc_select_file(card, &path, NULL); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "Can't select keyref info file 0x0033"); r = sc_read_record(card, 1, keyref_data, SC_ESTEID_KEYREF_FILE_RECLEN, SC_RECORD_BY_REC_NR); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "Can't read keyref info file!"); sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "authkey reference 0x%02x%02x\n", keyref_data[9], keyref_data[10]); sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "signkey reference 0x%02x%02x\n", keyref_data[19], keyref_data[20]); sbuf[0] = 0x83; sbuf[1] = 0x03; sbuf[2] = 0x80; switch (key_reference) { case 1: sbuf[3] = keyref_data[9]; sbuf[4] = keyref_data[10]; break; case 2: sbuf[3] = keyref_data[19]; sbuf[4] = keyref_data[20]; break; } apdu.data = sbuf; apdu.lc = 5; apdu.datalen = 5; r = sc_transmit_apdu(card, &apdu); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed"); SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2)); }
static int iasecc_sm_cmd(struct sc_card *card, struct sc_remote_data *rdata) { #define AUTH_SM_APDUS_MAX 12 #define ENCODED_APDUS_MAX_LENGTH (AUTH_SM_APDUS_MAX * (SC_MAX_APDU_BUFFER_SIZE * 2 + 64) + 32) struct sc_context *ctx = card->ctx; #ifdef ENABLE_SM struct sm_info *sm_info = &card->sm_ctx.info; struct sm_cwa_session *session = &sm_info->session.cwa; struct sc_remote_apdu *rapdu = NULL; int rv; LOG_FUNC_CALLED(ctx); if (!card->sm_ctx.module.ops.get_apdus) LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED); rv = card->sm_ctx.module.ops.get_apdus(ctx, sm_info, session->mdata, session->mdata_len, rdata); LOG_TEST_RET(ctx, rv, "iasecc_sm_cmd() 'GET APDUS' failed"); sc_log(ctx, "iasecc_sm_cmd() %i remote APDUs to transmit", rdata->length); for (rapdu = rdata->data; rapdu; rapdu = rapdu->next) { struct sc_apdu *apdu = &rapdu->apdu; sc_log(ctx, "iasecc_sm_cmd() apdu->ins:0x%X, resplen %i", apdu->ins, apdu->resplen); if (!apdu->ins) break; rv = sc_transmit_apdu(card, apdu); if (rv < 0) { sc_log(ctx, "iasecc_sm_cmd() APDU transmit error rv:%i", rv); break; } rv = sc_check_sw(card, apdu->sw1, apdu->sw2); if (rv < 0 && !(rapdu->flags & SC_REMOTE_APDU_FLAG_NOT_FATAL)) { sc_log(ctx, "iasecc_sm_cmd() APDU error rv:%i", rv); break; } sc_log(ctx, "iasecc_sm_cmd() apdu->resplen %i", apdu->resplen); } LOG_FUNC_RETURN(ctx, rv); #else LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "built without support of Secure-Messaging"); return SC_ERROR_NOT_SUPPORTED; #endif }
/* returns the currently selected DF (if a EF is currently selected * it returns the path from the MF to the DF in which the EF is * located. * @param card sc_card_t object to use * @param path OUT path from the MF to the current DF * @return SC_SUCCESS on success and an error value otherwise */ static int asepcos_get_current_df_path(sc_card_t *card, sc_path_t *path) { int r; sc_apdu_t apdu; u8 rbuf[SC_MAX_APDU_BUFFER_SIZE]; sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xca, 0x01, 0x83); apdu.resp = rbuf; apdu.resplen = sizeof(rbuf); apdu.le = 256; r = sc_transmit_apdu(card, &apdu); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed"); if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00) return sc_check_sw(card, apdu.sw1, apdu.sw2); return asepcos_tlvpath_to_scpath(path, apdu.resp, apdu.resplen); }
static int mcrd_delete_ref_to_authkey(sc_card_t * card) { sc_apdu_t apdu; int r; u8 sbuf[SC_MAX_APDU_BUFFER_SIZE]; assert(card != NULL); sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0x41, 0xA4); sbuf[0] = 0x83; sbuf[1] = 0x00; apdu.data = sbuf; apdu.lc = 2; apdu.datalen = 2; r = sc_transmit_apdu(card, &apdu); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed"); SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2)); }