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 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 void handle_change( sc_card_t *card, int pin1, int pin2, int do_change, u8 *newpin, int newlen) { sc_path_t p; sc_file_t *f; struct sc_apdu a; u8 ref; int i; printf("\n%s %s with %s: ", do_change ? "Changing" : "Unblocking", pinlist[pin1].label, pinlist[pin2].label); sc_format_path(pinlist[pin1].path,&p); if((i=sc_select_file(card,&p,&f))<0){ printf("\nCannot select %s, %s\n", pinlist[pin1].label, sc_strerror(i)); return; } ref=f->prop_attr[2] | (strlen(pinlist[pin1].path)>8 ? 0x80 : 0x00); if(do_change){ sc_format_apdu(card, &a, SC_APDU_CASE_3_SHORT, 0x24, 0x01, ref); a.data=newpin, a.lc=a.datalen=newlen; } else { sc_format_apdu(card, &a, SC_APDU_CASE_1, 0x2C, 0x03, ref); } if((i=sc_transmit_apdu(card, &a))<0){ printf("\nsc_transmit_apdu() failed, %s\n", sc_strerror(i)); return; } if(a.sw1!=0x90 && a.sw2!=0x00){ printf("%02X%02X\n", a.sw1, a.sw2); return; } printf("OK\n"); }
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 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 mcrd_match_card(sc_card_t * card) { int i = 0, r = 0; sc_apdu_t apdu; i = _sc_match_atr(card, mcrd_atrs, &card->type); if (i >= 0) { card->name = mcrd_atrs[i].name; return 1; } sc_format_apdu(card, &apdu, SC_APDU_CASE_3, 0xA4, 0x04, 0x00); apdu.lc = sizeof(EstEID_v35_AID); apdu.data = EstEID_v35_AID; apdu.datalen = sizeof(EstEID_v35_AID); apdu.resplen = 0; apdu.le = 0; r = sc_transmit_apdu(card, &apdu); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed"); sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "SELECT AID: %02X%02X", apdu.sw1, apdu.sw2); if(apdu.sw1 == 0x90 && apdu.sw2 == 0x00) { sc_log(card->ctx, "AID found"); card->type = SC_CARD_TYPE_MCRD_ESTEID_V30; return 1; } return 0; }
static int acos_get_serialnr(sc_card_t *card, sc_serial_number_t *serial) { int r; u8 rbuf[SC_MAX_APDU_BUFFER_SIZE]; sc_apdu_t apdu; if (!serial) return SC_ERROR_INVALID_ARGUMENTS; /* see if we have cached serial number */ if (card->serialnr.len) { memcpy(serial, &card->serialnr, sizeof(*serial)); return SC_SUCCESS; } /* get serial number via GET CARD DATA */ sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xf6, 0x00, 0x00); apdu.cla |= 0x80; apdu.resp = rbuf; apdu.resplen = sizeof(rbuf); apdu.le = 256; apdu.lc = 0; apdu.datalen = 0; 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_ERROR_INTERNAL; /* cache serial number */ memcpy(card->serialnr.value, apdu.resp, MIN(apdu.resplen, SC_MAX_SERIALNR)); card->serialnr.len = MIN(apdu.resplen, SC_MAX_SERIALNR); /* copy and return serial number */ memcpy(serial, &card->serialnr, sizeof(*serial)); return SC_SUCCESS; }
static int asepcos_akn_to_fileid(sc_card_t *card, sc_cardctl_asepcos_akn2fileid_t *p) { int r; u8 sbuf[32], rbuf[SC_MAX_APDU_BUFFER_SIZE]; sc_apdu_t apdu; sbuf[0] = p->akn & 0xff; sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x28, 0x02, 0x01); apdu.cla |= 0x80; apdu.resp = rbuf; apdu.resplen = sizeof(rbuf); apdu.le = 256; apdu.lc = 1; apdu.datalen = 1; apdu.data = sbuf; r = sc_transmit_apdu(card, &apdu); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed"); if (apdu.resplen != 4) return SC_ERROR_INTERNAL; p->fileid = (apdu.resp[1] << 16) | (apdu.resp[2] << 8) | apdu.resp[3]; return SC_SUCCESS; }
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_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 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); }
static int cardos_match_card(sc_card_t *card) { unsigned char atr[SC_MAX_ATR_SIZE]; int i; i = _sc_match_atr(card, cardos_atrs, &card->type); if (i < 0) return 0; memcpy(atr, card->atr.value, sizeof(atr)); /* Do not change card type for CIE! */ if (card->type == SC_CARD_TYPE_CARDOS_CIE_V1) return 1; if (card->type == SC_CARD_TYPE_CARDOS_M4_4) return 1; if (card->type == SC_CARD_TYPE_CARDOS_M4_2) { int rv; sc_apdu_t apdu; u8 rbuf[SC_MAX_APDU_BUFFER_SIZE]; /* first check some additional ATR bytes */ if ((atr[4] != 0xff && atr[4] != 0x02) || (atr[6] != 0x10 && atr[6] != 0x0a) || (atr[9] != 0x55 && atr[9] != 0x58)) return 0; /* get the os version using GET DATA and compare it with * version in the ATR */ sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "checking cardos version ..."); sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xca, 0x01, 0x82); apdu.resp = rbuf; apdu.resplen = sizeof(rbuf); apdu.le = 256; apdu.lc = 0; rv = sc_transmit_apdu(card, &apdu); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, rv, "APDU transmit failed"); if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00) return 0; if (apdu.resp[0] != atr[10] || apdu.resp[1] != atr[11]) /* version mismatch */ return 0; if (atr[11] <= 0x04) { sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "found cardos m4.01"); card->type = SC_CARD_TYPE_CARDOS_M4_01; } else if (atr[11] == 0x08) { sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "found cardos v4.3b"); card->type = SC_CARD_TYPE_CARDOS_M4_3; } else if (atr[11] == 0x09) { sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "found cardos v4.2b"); card->type = SC_CARD_TYPE_CARDOS_M4_2B; } else if (atr[11] >= 0x0B) { sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "found cardos v4.2c or higher"); card->type = SC_CARD_TYPE_CARDOS_M4_2C; } else { sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "found cardos m4.2"); } } return 1; }
static int autodetect_class(sc_card_t *card) { int classes[] = { 0x00, 0xC0, 0xB0, 0xA0 }; int class_count = sizeof(classes)/sizeof(int); u8 rbuf[SC_MAX_APDU_BUFFER_SIZE]; sc_apdu_t apdu; int i, r; sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "autodetecting CLA byte\n"); for (i = 0; i < class_count; i++) { sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "trying with 0x%02X\n", classes[i]); memset(&apdu, 0, sizeof(apdu)); apdu.cla = classes[i]; apdu.cse = SC_APDU_CASE_2_SHORT; apdu.ins = 0xC0; apdu.p1 = apdu.p2 = 0; apdu.datalen = 0; apdu.lc = 0; apdu.le = 256; 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 == 0x6E) continue; if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) break; if (apdu.sw1 == 0x61) break; sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "got strange SWs: 0x%02X 0x%02X\n", apdu.sw1, apdu.sw2); break; } if (i == class_count) return -1; card->cla = classes[i]; sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "detected CLA byte as 0x%02X\n", card->cla); if (apdu.resplen < 2) { sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "SELECT FILE returned %d bytes\n", apdu.resplen); return SC_SUCCESS; } if (rbuf[0] == 0x6F) { sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "SELECT FILE seems to behave according to ISO 7816-4\n"); return SC_SUCCESS; } if (rbuf[0] == 0x00 && rbuf[1] == 0x00) { struct sc_card_driver *drv; sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "SELECT FILE seems to return Schlumberger 'flex stuff\n"); drv = sc_get_cryptoflex_driver(); card->ops->select_file = drv->ops->select_file; return SC_SUCCESS; } return SC_SUCCESS; }
static int entersafe_transmit_apdu(sc_card_t *card, sc_apdu_t *apdu, u8 * key, size_t keylen, int cipher,int mac) { u8 *cipher_data=0,*mac_data=0; size_t cipher_data_size,mac_data_size; int blocks; int r=SC_SUCCESS; u8 *sbuf=NULL; size_t ssize=0; SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); assert(card); assert(apdu); if((cipher||mac) && (!key||(keylen!=8 && keylen!=16))) SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS); r = sc_apdu_get_octets(card->ctx, apdu, &sbuf, &ssize, SC_PROTO_RAW); if (r == SC_SUCCESS) sc_apdu_log(card->ctx, SC_LOG_DEBUG_VERBOSE, sbuf, ssize, 1); if(sbuf) free(sbuf); if(cipher) { blocks=(apdu->lc+2)/8+1; cipher_data_size=blocks*8; cipher_data=malloc(cipher_data_size); if(!cipher_data) { r = SC_ERROR_OUT_OF_MEMORY; goto out; } if((r = entersafe_cipher_apdu(card,apdu,key,keylen,cipher_data,cipher_data_size))<0) goto out; } if(mac) { mac_data_size=apdu->lc+4; mac_data=malloc(mac_data_size); r = entersafe_mac_apdu(card,apdu,key,keylen,mac_data,mac_data_size); if(r<0) goto out; } r = sc_transmit_apdu(card,apdu); out: if(cipher_data) free(cipher_data); if(mac_data) free(mac_data); SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r); }
int dnie_transmit_apdu(sc_card_t * card, sc_apdu_t * apdu) { int res = SC_SUCCESS; sc_context_t *ctx; cwa_provider_t *provider = NULL; ctx=card->ctx; provider = GET_DNIE_PRIV_DATA(card)->cwa_provider; if ((provider->status.session.state == CWA_SM_ACTIVE) && (card->sm_ctx.sm_mode == SM_MODE_TRANSMIT)) { res = sc_transmit_apdu(card, apdu); LOG_TEST_RET(ctx, res, "Error in dnie_wrap_apdu process"); res = cwa_decode_response(card, provider, apdu); LOG_TEST_RET(ctx, res, "Error in cwa_decode_response process"); } else res = sc_transmit_apdu(card, apdu); return res; }
static void handle_nullpin(sc_card_t *card, u8 *newpin, int newlen) { sc_path_t p; sc_file_t *f; struct sc_apdu a; u8 ref, buf[40]; int i; printf("\nSetting initial PIN-value: "); sc_format_path(pinlist[0].path,&p); if((i=sc_select_file(card,&p,&f))<0){ printf("\nCannot select %s, %s\n", pinlist[0].label, sc_strerror(i)); return; } ref=f->prop_attr[2]; sc_format_apdu(card, &a, SC_APDU_CASE_1, 0x20, 0x00, f->prop_attr[2]); if((i=sc_transmit_apdu(card, &a))<0){ printf("sc_transmit_apdu() failed, %s\n", sc_strerror(i)); return; } if(a.sw1!=0x69 && a.sw2!=0x85){ printf("global PIN is not in NullPin-state (%02X%02X)\n", a.sw1, a.sw2); return; } sc_format_apdu(card, &a, SC_APDU_CASE_3_SHORT, 0x24, 0x00, ref); for(i=0;i<6;++i) buf[i]=0; for(i=0;i<newlen;++i) buf[6+i]=newpin[i]; a.data=buf, a.lc=a.datalen=6+newlen; if((i=sc_transmit_apdu(card, &a))<0){ printf("sc_transmit_apdu() failed, %s\n", sc_strerror(i)); return; } if(a.sw1!=0x90 && a.sw2!=0x00){ printf("Error %02X%02X\n", a.sw1, a.sw2); return; } printf("OK\n"); }
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 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 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; }
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 cardos_have_verifyrc_package(sc_card_t *card) { sc_apdu_t apdu; u8 rbuf[SC_MAX_APDU_BUFFER_SIZE]; int r; const u8 *p = rbuf, *q; size_t len, tlen = 0, ilen = 0; sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xca, 0x01, 0x88); apdu.resp = rbuf; apdu.resplen = sizeof(rbuf); apdu.lc = 0; apdu.le = 256; r = sc_transmit_apdu(card, &apdu); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed"); if ((len = apdu.resplen) == 0) /* looks like no package has been installed */ return 0; while (len != 0) { p = sc_asn1_find_tag(card->ctx, p, len, 0xe1, &tlen); if (p == NULL) return 0; if (card->type == SC_CARD_TYPE_CARDOS_M4_3) { /* the verifyRC package on CardOS 4.3B use Manufacturer ID 0x01 */ /* and Package Number 0x07 */ q = sc_asn1_find_tag(card->ctx, p, tlen, 0x01, &ilen); if (q == NULL || ilen != 4) return 0; if (q[0] == 0x07) return 1; } else if (card->type == SC_CARD_TYPE_CARDOS_M4_4) { /* the verifyRC package on CardOS 4.4 use Manufacturer ID 0x03 */ /* and Package Number 0x02 */ q = sc_asn1_find_tag(card->ctx, p, tlen, 0x03, &ilen); if (q == NULL || ilen != 4) return 0; if (q[0] == 0x02) return 1; } else { return 0; } p += tlen; len -= tlen + 2; } return 0; }
int sc_sm_single_transmit(struct sc_card *card, struct sc_apdu *apdu) { struct sc_context *ctx = card->ctx; struct sc_apdu *sm_apdu = NULL; int rv; LOG_FUNC_CALLED(ctx); sc_log(ctx, "SM_MODE:%X", card->sm_ctx.sm_mode); if (!card->sm_ctx.ops.get_sm_apdu || !card->sm_ctx.ops.free_sm_apdu) LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED); /* get SM encoded APDU */ rv = card->sm_ctx.ops.get_sm_apdu(card, apdu, &sm_apdu); if (rv == SC_ERROR_SM_NOT_APPLIED) { /* SM wrap of this APDU is ignored by card driver. * Send plain APDU to the reader driver */ rv = card->reader->ops->transmit(card->reader, apdu); LOG_FUNC_RETURN(ctx, rv); } else { if (rv < 0) sc_sm_stop(card); } LOG_TEST_RET(ctx, rv, "get SM APDU error"); /* check if SM APDU is still valid */ rv = sc_check_apdu(card, sm_apdu); if (rv < 0) { card->sm_ctx.ops.free_sm_apdu(card, apdu, &sm_apdu); sc_sm_stop(card); LOG_TEST_RET(ctx, rv, "cannot validate SM encoded APDU"); } /* send APDU flagged as NO_SM */ sm_apdu->flags |= SC_APDU_FLAGS_NO_SM | SC_APDU_FLAGS_NO_RETRY_WL; rv = sc_transmit_apdu(card, sm_apdu); if (rv < 0) { card->sm_ctx.ops.free_sm_apdu(card, apdu, &sm_apdu); sc_sm_stop(card); LOG_TEST_RET(ctx, rv, "unable to transmit APDU"); } /* decode SM answer and free temporary SM related data */ rv = card->sm_ctx.ops.free_sm_apdu(card, apdu, &sm_apdu); if (rv < 0) sc_sm_stop(card); LOG_FUNC_RETURN(ctx, rv); }
/* 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 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); }
/* 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 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 }
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 npa_logout(sc_card_t *card) { struct sc_apdu apdu; sc_sm_stop(card); if (card->reader->capabilities & SC_READER_CAP_PACE_GENERIC) { /* If PACE is done between reader and card, SM is transparent to us as * it ends at the reader. With CLA=0x0C we provoque a SM error to * disable SM on the reader. */ sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0xA4, 0x00, 0x00); apdu.cla = 0x0C; sc_transmit_apdu(card, &apdu); /* ignore result */ } return sc_select_file(card, sc_get_mf_path(), NULL); }