diff --git a/src/libopensc/card.c b/src/libopensc/card.c index 175b918f..a2721e65 100644 --- a/src/libopensc/card.c +++ b/src/libopensc/card.c @@ -213,9 +213,7 @@ int sc_transmit_apdu(struct sc_card *card, struct sc_apdu *apdu) } } if (apdu->sw1 == 0x61 && apdu->resplen == 0) { - struct sc_apdu rspapdu; unsigned int le; - u8 rsp[SC_MAX_APDU_BUFFER_SIZE]; if (orig_resplen == 0) { apdu->sw1 = 0x90; /* FIXME: should we do this? */ @@ -226,39 +224,13 @@ int sc_transmit_apdu(struct sc_card *card, struct sc_apdu *apdu) le = apdu->sw2? (size_t) apdu->sw2 : 256; - sc_format_apdu(card, &rspapdu, SC_APDU_CASE_2_SHORT, - 0xC0, 0, 0); - rspapdu.le = le; - rspapdu.resp = rsp; - rspapdu.resplen = le; - r = sc_transceive(card, &rspapdu); - if (r != 0) { - error(card->ctx, "error while getting response: %s\n", - sc_strerror(r)); + if (card->ops->get_response == NULL) { sc_unlock(card); - return r; + SC_FUNC_RETURN(card->ctx, 2, SC_ERROR_NOT_SUPPORTED); } - if (card->ctx->debug >= 5) { - char buf[2048]; - buf[0] = 0; - if (rspapdu.resplen) { - sc_hex_dump(card->ctx, rspapdu.resp, - rspapdu.resplen, - buf, sizeof(buf)); - } - debug(card->ctx, "Response %d bytes (SW1=%02X SW2=%02X)\n%s", - rspapdu.resplen, rspapdu.sw1, rspapdu.sw2, buf); - } - if (rspapdu.resplen) { - size_t c = rspapdu.resplen; - - if (c > orig_resplen) - c = orig_resplen; - memcpy(apdu->resp, rspapdu.resp, c); - apdu->resplen = c; - } - apdu->sw1 = rspapdu.sw1; - apdu->sw2 = rspapdu.sw2; + r = card->ops->get_response(card, apdu, le); + sc_unlock(card); + return r; } sc_unlock(card); return 0; diff --git a/src/libopensc/iso7816.c b/src/libopensc/iso7816.c index 79111220..11bab8bc 100644 --- a/src/libopensc/iso7816.c +++ b/src/libopensc/iso7816.c @@ -557,6 +557,33 @@ static int iso7816_create_file(struct sc_card *card, struct sc_file *file) return sc_check_sw(card, apdu.sw1, apdu.sw2); } +static int iso7816_get_response(struct sc_card *card, sc_apdu_t *orig_apdu, size_t count) +{ + struct sc_apdu apdu; + u8 recvbuf[SC_MAX_APDU_BUFFER_SIZE]; + int r; + + sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xC0, 0x00, 0x00); + apdu.le = count; + apdu.resplen = count; + apdu.resp = orig_apdu->resp; + + 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)); + + if (apdu.resplen != count) { + SC_FUNC_RETURN(card->ctx, 2, SC_ERROR_WRONG_LENGTH); + } + + orig_apdu->resplen = apdu.resplen; + orig_apdu->sw1 = 0x90; + orig_apdu->sw2 = 0x00; + + SC_FUNC_RETURN(card->ctx, 3, apdu.resplen); +} + static int iso7816_delete_file(struct sc_card *card, const struct sc_path *path) { int r; @@ -931,6 +958,7 @@ struct sc_card_driver * sc_get_iso7816_driver(void) iso_ops.select_file = iso7816_select_file; iso_ops.get_challenge = iso7816_get_challenge; iso_ops.create_file = iso7816_create_file; + iso_ops.get_response = iso7816_get_response; iso_ops.delete_file = iso7816_delete_file; iso_ops.set_security_env = iso7816_set_security_env; iso_ops.restore_security_env = iso7816_restore_security_env; diff --git a/src/libopensc/opensc.h b/src/libopensc/opensc.h index 9a902cb3..c4dc6f7c 100644 --- a/src/libopensc/opensc.h +++ b/src/libopensc/opensc.h @@ -493,7 +493,7 @@ struct sc_card_operations { * , if not NULL. */ int (*select_file)(struct sc_card *card, const struct sc_path *path, struct sc_file **file_out); - int (*get_response)(struct sc_card *card, u8 * buf, size_t count); + int (*get_response)(struct sc_card *card, sc_apdu_t *orig_apdu, size_t count); int (*get_challenge)(struct sc_card *card, u8 * buf, size_t count); /*