From c344e28a9269353884cb7082a4f9830ea6a74bed Mon Sep 17 00:00:00 2001 From: jey Date: Sat, 22 Dec 2001 20:43:09 +0000 Subject: [PATCH] - added card abstraction layer support - pretty much finished migrating to new ASN.1 code - changed call semantics for sc_select_file() - moved functions around git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@89 c6295689-39f2-0310-b995-f0e70906c6a9 --- src/libopensc/Makefile.am | 5 +- src/libopensc/asn1.c | 3 +- src/libopensc/card-setcos.c | 90 ++++++ src/libopensc/card.c | 558 ++++++++++++++++++++++++++++++++++ src/libopensc/defaults.c | 19 +- src/libopensc/iso7816.c | 263 ++++++++++++++++ src/libopensc/opensc-pkcs15.h | 5 +- src/libopensc/opensc.h | 87 ++++-- src/libopensc/pkcs15-cert.c | 8 +- src/libopensc/pkcs15-pin.c | 9 +- src/libopensc/pkcs15-prkey.c | 3 +- src/libopensc/pkcs15-sec.c | 14 +- src/libopensc/pkcs15.c | 61 ++-- src/libopensc/pkcs15.h | 5 +- src/libopensc/sc.c | 492 ++---------------------------- 15 files changed, 1045 insertions(+), 577 deletions(-) create mode 100644 src/libopensc/card-setcos.c create mode 100644 src/libopensc/card.c create mode 100644 src/libopensc/iso7816.c diff --git a/src/libopensc/Makefile.am b/src/libopensc/Makefile.am index c6f4df70..00c400f0 100644 --- a/src/libopensc/Makefile.am +++ b/src/libopensc/Makefile.am @@ -4,10 +4,11 @@ LD = ccmalloc gcc lib_LTLIBRARIES = libopensc.la libopensc_la_SOURCES = sc-asn1.c sc-base64.c sc-defaults.c \ - sc-sec.c sc-log.c sc.c sc-iso7816-4.c\ + sc-sec.c sc-log.c sc.c sc-card.c sc-iso7816.c\ sc-pkcs15.c sc-pkcs15-cert.c \ sc-pkcs15-pin.c sc-pkcs15-prkey.c \ - sc-pkcs15-defaults.c sc-pkcs15-sec.c + sc-pkcs15-defaults.c sc-pkcs15-sec.c \ + sc-card-setec.c libopensc_la_LDFLAGS = -version-info 0:4:0 libopensc_la_CFLAGS = $(AM_CFLAGS) -Werror include_HEADERS = opensc.h opensc-pkcs15.h diff --git a/src/libopensc/asn1.c b/src/libopensc/asn1.c index 90812124..a66abf6c 100644 --- a/src/libopensc/asn1.c +++ b/src/libopensc/asn1.c @@ -491,7 +491,8 @@ static int asn1_parse_path(struct sc_context *ctx, const u8 *in, int len, r = asn1_parse(ctx, asn1_path, in, len, NULL, NULL, 0, depth + 1); if (r) return r; - + path->type = SC_PATH_TYPE_PATH; + return 0; } diff --git a/src/libopensc/card-setcos.c b/src/libopensc/card-setcos.c new file mode 100644 index 00000000..68536933 --- /dev/null +++ b/src/libopensc/card-setcos.c @@ -0,0 +1,90 @@ +/* + * sc-card-setec.c: Support for PKI cards by Setec + * + * Copyright (C) 2001 Juha Yrjölä + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "opensc.h" + +static const char *setec_atrs[] = { + /* the current FINEID card has this ATR: */ + "3B:9F:94:40:1E:00:67:11:43:46:49:53:45:10:52:66:FF:81:90:00", + NULL +}; + +static struct sc_card_operations setec_ops; +static const struct sc_card_driver setec_drv = { + NULL, + "Setec", + &setec_ops +}; + +static int setec_finish(struct sc_card *card) +{ + return 0; +} + +static int setec_match_card(struct sc_card *card) +{ + int i, match = -1; + + for (i = 0; setec_atrs[i] != NULL; i++) { + u8 defatr[SC_MAX_ATR_SIZE]; + int len = sizeof(defatr); + const char *atrp = setec_atrs[i]; + + if (sc_hex_to_bin(atrp, defatr, &len)) + continue; + if (len != card->atr_len) + continue; + if (memcmp(card->atr, defatr, len) != 0) + continue; + match = i; + break; + } + if (match == -1) + return 0; + + return 1; +} + +static int setec_init(struct sc_card *card) +{ + card->ops_data = NULL; + card->cla = 0x00; + + return 0; +} + +static const struct sc_card_driver * sc_get_driver(void) +{ + const struct sc_card_driver *iso_drv = sc_get_iso7816_driver(); + + setec_ops = *iso_drv->ops; + setec_ops.match_card = setec_match_card; + setec_ops.init = setec_init; + setec_ops.finish = setec_finish; + + return &setec_drv; +} + +#if 1 +const struct sc_card_driver * sc_get_setec_driver(void) +{ + return sc_get_driver(); +} +#endif diff --git a/src/libopensc/card.c b/src/libopensc/card.c new file mode 100644 index 00000000..b11c90b0 --- /dev/null +++ b/src/libopensc/card.c @@ -0,0 +1,558 @@ +/* + * sc-card.c: General SmartCard functions + * + * Copyright (C) 2001 Juha Yrjölä + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "opensc.h" +#include "sc-log.h" +#include "sc-asn1.h" +#include +#include + +int sc_sw_to_errorcode(struct sc_card *card, int sw1, int sw2) +{ + switch (sw1) { + case 0x69: + switch (sw2) { + case 0x82: + return SC_ERROR_SECURITY_STATUS_NOT_SATISFIED; + default: + break; + } + break; + case 0x6A: + switch (sw2) { + case 0x81: + return SC_ERROR_NOT_SUPPORTED; + case 0x82: + case 0x83: + return SC_ERROR_FILE_NOT_FOUND; + case 0x86: + case 0x87: + return SC_ERROR_INVALID_ARGUMENTS; + default: + break; + } + break; + case 0x6D: + return SC_ERROR_NOT_SUPPORTED; + case 0x6E: + return SC_ERROR_UNKNOWN_SMARTCARD; + case 0x90: + if (sw2 == 0) + return 0; + } + error(card->ctx, "Unknown SW's: SW1=%02X, SW2=%02X\n", sw1, sw2); + return SC_ERROR_UNKNOWN_REPLY; +} + +static int sc_check_apdu(struct sc_context *ctx, const struct sc_apdu *apdu) +{ + switch (apdu->cse) { + case SC_APDU_CASE_1: + if (apdu->datalen > 0) + SC_FUNC_RETURN(ctx, 4, SC_ERROR_INVALID_ARGUMENTS); + break; + case SC_APDU_CASE_2_SHORT: + if (apdu->datalen > 0) + SC_FUNC_RETURN(ctx, 4, SC_ERROR_INVALID_ARGUMENTS); + if (apdu->resplen < apdu->le) + SC_FUNC_RETURN(ctx, 4, SC_ERROR_INVALID_ARGUMENTS); + break; + case SC_APDU_CASE_3_SHORT: + if (apdu->datalen == 0 || apdu->data == NULL) + SC_FUNC_RETURN(ctx, 4, SC_ERROR_INVALID_ARGUMENTS); + break; + case SC_APDU_CASE_4_SHORT: + if (apdu->datalen == 0 || apdu->data == NULL) + SC_FUNC_RETURN(ctx, 4, SC_ERROR_INVALID_ARGUMENTS); + if (apdu->resplen < apdu->le) + SC_FUNC_RETURN(ctx, 4, SC_ERROR_INVALID_ARGUMENTS); + break; + case SC_APDU_CASE_2_EXT: + case SC_APDU_CASE_3_EXT: + case SC_APDU_CASE_4_EXT: + SC_FUNC_RETURN(ctx, 4, SC_ERROR_INVALID_ARGUMENTS); + } + return 0; +} + +static int sc_transceive_t0(struct sc_card *card, struct sc_apdu *apdu) +{ + SCARD_IO_REQUEST sSendPci, sRecvPci; + BYTE s[SC_MAX_APDU_BUFFER_SIZE], r[SC_MAX_APDU_BUFFER_SIZE]; + DWORD dwSendLength, dwRecvLength; + LONG rv; + u8 *data = s; + size_t data_bytes = apdu->lc; + + if (data_bytes == 0) + data_bytes = 256; + *data++ = apdu->cla; + *data++ = apdu->ins; + *data++ = apdu->p1; + *data++ = apdu->p2; + switch (apdu->cse) { + case SC_APDU_CASE_1: + break; + case SC_APDU_CASE_2_SHORT: + *data++ = (u8) apdu->le; + break; + case SC_APDU_CASE_2_EXT: + *data++ = (u8) 0; + *data++ = (u8) (apdu->le >> 8); + *data++ = (u8) (apdu->le & 0xFF); + break; + case SC_APDU_CASE_3_SHORT: + *data++ = (u8) apdu->lc; + if (apdu->datalen != data_bytes) + return SC_ERROR_INVALID_ARGUMENTS; + memcpy(data, apdu->data, data_bytes); + data += data_bytes; + break; + case SC_APDU_CASE_4_SHORT: + *data++ = (u8) apdu->lc; + if (apdu->datalen != data_bytes) + return SC_ERROR_INVALID_ARGUMENTS; + memcpy(data, apdu->data, data_bytes); + data += data_bytes; + *data++ = (u8) apdu->le; + break; + } + + sSendPci.dwProtocol = SCARD_PROTOCOL_T0; + sSendPci.cbPciLength = 0; + sRecvPci.dwProtocol = SCARD_PROTOCOL_T0; + sRecvPci.cbPciLength = 0; + + dwSendLength = data - s; + dwRecvLength = apdu->resplen + 2; + if (dwRecvLength > 255) /* FIXME: PC/SC Lite quirk */ + dwRecvLength = 255; + if (card->ctx->debug >= 5) { + char buf[2048]; + + sc_hex_dump(card->ctx, s, (size_t) dwSendLength, buf, sizeof(buf)); + debug(card->ctx, "Sending %d bytes (resp. %d bytes):\n%s", + dwSendLength, dwRecvLength, buf); + } + rv = SCardTransmit(card->pcsc_card, &sSendPci, s, dwSendLength, + &sRecvPci, r, &dwRecvLength); + if (rv != SCARD_S_SUCCESS) { + switch (rv) { + case SCARD_W_REMOVED_CARD: + return SC_ERROR_CARD_REMOVED; + case SCARD_W_RESET_CARD: + return SC_ERROR_CARD_RESET; + case SCARD_E_NOT_TRANSACTED: + if (sc_detect_card(card->ctx, card->reader) != 1) + return SC_ERROR_CARD_REMOVED; + return SC_ERROR_TRANSMIT_FAILED; + default: + error(card->ctx, "SCardTransmit failed: %s\n", pcsc_stringify_error(rv)); + return SC_ERROR_TRANSMIT_FAILED; + } + } + if (dwRecvLength < 2) + return SC_ERROR_ILLEGAL_RESPONSE; + apdu->sw1 = (unsigned int) r[dwRecvLength-2]; + apdu->sw2 = (unsigned int) r[dwRecvLength-1]; + dwRecvLength -= 2; + if ((size_t) dwRecvLength > apdu->resplen) + dwRecvLength = (DWORD) apdu->resplen; + else + apdu->resplen = (size_t) dwRecvLength; + if (dwRecvLength > 0) + memcpy(apdu->resp, r, (size_t) dwRecvLength); + + return 0; +} + +int sc_transmit_apdu(struct sc_card *card, struct sc_apdu *apdu) +{ + int r; + + SC_FUNC_CALLED(card->ctx, 4); + r = sc_check_apdu(card->ctx, apdu); + SC_TEST_RET(card->ctx, r, "APDU sanity check failed"); + r = sc_transceive_t0(card, apdu); + SC_TEST_RET(card->ctx, r, "transceive_t0() failed"); + if (card->ctx->debug >= 5) { + char buf[2048]; + + buf[0] = '\0'; + if (apdu->resplen > 0) { + sc_hex_dump(card->ctx, apdu->resp, apdu->resplen, + buf, sizeof(buf)); + } + debug(card->ctx, "Received %d bytes (SW1=%02X SW2=%02X)\n%s", + apdu->resplen, apdu->sw1, apdu->sw2, buf); + } + if (apdu->sw1 == 0x61 && apdu->resplen == 0) { + struct sc_apdu rspapdu; + BYTE rsp[SC_MAX_APDU_BUFFER_SIZE]; + + if (apdu->no_response != 0) + return 0; + + sc_format_apdu(card, &rspapdu, SC_APDU_CASE_2_SHORT, + 0xC0, 0, 0); + rspapdu.le = (size_t) apdu->sw2; + rspapdu.resp = rsp; + rspapdu.resplen = (size_t) apdu->sw2; + r = sc_transceive_t0(card, &rspapdu); + if (r != 0) { + error(card->ctx, "error while getting response: %s\n", + sc_strerror(r)); + return r; + } + 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); + } + /* FIXME: Check apdu->resplen */ + memcpy(apdu->resp, rspapdu.resp, rspapdu.resplen); + apdu->resplen = rspapdu.resplen; + apdu->sw1 = rspapdu.sw1; + apdu->sw2 = rspapdu.sw2; + } + return 0; +} + +void sc_format_apdu(struct sc_card *card, struct sc_apdu *apdu, + int cse, int ins, int p1, int p2) +{ + assert(card != NULL && apdu != NULL); + memset(apdu, 0, sizeof(*apdu)); + apdu->cla = (u8) card->cla; + apdu->cse = cse; + apdu->ins = (u8) ins; + apdu->p1 = (u8) p1; + apdu->p2 = (u8) p2; + apdu->no_response = 0; + + return; +} + +int sc_connect_card(struct sc_context *ctx, + int reader, struct sc_card **card_out) +{ + struct sc_card *card; + DWORD active_proto; + SCARDHANDLE card_handle; + SCARD_READERSTATE_A rgReaderStates[SC_MAX_READERS]; + LONG rv; + int i; + + assert(card_out != NULL); + SC_FUNC_CALLED(ctx, 1); + if (reader >= ctx->reader_count || reader < 0) + SC_FUNC_RETURN(ctx, 1, SC_ERROR_OBJECT_NOT_FOUND); + + rgReaderStates[0].szReader = ctx->readers[reader]; + rgReaderStates[0].dwCurrentState = SCARD_STATE_UNAWARE; + rv = SCardGetStatusChange(ctx->pcsc_ctx, 0, rgReaderStates, 1); + if (rv != 0) { + error(ctx, "SCardGetStatusChange failed: %s\n", pcsc_stringify_error(rv)); + SC_FUNC_RETURN(ctx, 1, SC_ERROR_RESOURCE_MANAGER); /* FIXME */ + } + if (!(rgReaderStates[0].dwEventState & SCARD_STATE_PRESENT)) + SC_FUNC_RETURN(ctx, 1, SC_ERROR_CARD_NOT_PRESENT); + + card = malloc(sizeof(struct sc_card)); + if (card == NULL) + SC_FUNC_RETURN(ctx, 1, SC_ERROR_OUT_OF_MEMORY); + memset(card, 0, sizeof(struct sc_card)); + rv = SCardConnect(ctx->pcsc_ctx, ctx->readers[reader], + SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0, + &card_handle, &active_proto); + if (rv != 0) { + error(ctx, "SCardConnect failed: %s\n", pcsc_stringify_error(rv)); + free(card); + return -1; /* FIXME */ + } + card->reader = reader; + card->ctx = ctx; + card->pcsc_card = card_handle; + i = rgReaderStates[0].cbAtr; + if (i >= SC_MAX_ATR_SIZE) + i = SC_MAX_ATR_SIZE; + memcpy(card->atr, rgReaderStates[0].rgbAtr, i); + card->atr_len = i; + + for (i = 0; ctx->card_drivers[i] != NULL; i++) { + const struct sc_card_driver *drv = ctx->card_drivers[i]; + const struct sc_card_operations *ops = drv->ops; + if (ctx->debug >= 3) + debug(ctx, "trying driver: %s\n", drv->name); + if (ops == NULL || ops->match_card == NULL) + continue; + if (ops->match_card(card) == 1) { + if (ctx->debug >= 3) + debug(ctx, "matched\n"); + card->ops = ops; + } + } + if (card->ops == NULL) { + error(ctx, "unable to find driver for inserted card\n"); + free(card); + return SC_ERROR_INVALID_CARD; + } + pthread_mutex_init(&card->mutex, NULL); + *card_out = card; + + SC_FUNC_RETURN(ctx, 1, 0); +} + +int sc_disconnect_card(struct sc_card *card) +{ + struct sc_context *ctx = card->ctx; + assert(card != NULL); + SC_FUNC_CALLED(ctx, 1); + SCardDisconnect(card->pcsc_card, SCARD_LEAVE_CARD); + pthread_mutex_destroy(&card->mutex); + free(card); + SC_FUNC_RETURN(ctx, 1, 0); +} + +static int _sc_lock_int(struct sc_card *card) +{ + long rv; + + rv = SCardBeginTransaction(card->pcsc_card); + + if (rv != SCARD_S_SUCCESS) { + error(card->ctx, "SCardBeginTransaction failed: %s\n", pcsc_stringify_error(rv)); + return -1; + } + return 0; +} + +int sc_lock(struct sc_card *card) +{ + SC_FUNC_CALLED(card->ctx, 2); + pthread_mutex_lock(&card->mutex); + SC_FUNC_RETURN(card->ctx, 2, _sc_lock_int(card)); +} + +static int _sc_unlock_int(struct sc_card *card) +{ + long rv; + + rv = SCardEndTransaction(card->pcsc_card, SCARD_LEAVE_CARD); + if (rv != SCARD_S_SUCCESS) { + error(card->ctx, "SCardEndTransaction failed: %s\n", pcsc_stringify_error(rv)); + return -1; + } + return 0; +} + +int sc_unlock(struct sc_card *card) +{ + SC_FUNC_CALLED(card->ctx, 2); + pthread_mutex_unlock(&card->mutex); + SC_FUNC_RETURN(card->ctx, 2, _sc_unlock_int(card)); +} + +int sc_list_files(struct sc_card *card, u8 *buf, int buflen) +{ + struct sc_apdu apdu; + int r; + + SC_FUNC_CALLED(card->ctx, 2); + sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xAA, 0, 0); + apdu.resp = buf; + apdu.resplen = buflen; + apdu.le = 0; + r = sc_transmit_apdu(card, &apdu); + SC_TEST_RET(card->ctx, r, "APDU transmit failed"); + if (apdu.resplen == 0) + return sc_sw_to_errorcode(card, apdu.sw1, apdu.sw2); + return apdu.resplen; +} + +static int construct_fci(const struct sc_file *file, u8 *out, int *outlen) +{ + u8 *p = out; + u8 buf[32]; + + *p++ = 0x6F; + p++; + + buf[0] = (file->size >> 8) & 0xFF; + buf[1] = file->size & 0xFF; + sc_asn1_put_tag(0x81, buf, 2, p, 16, &p); + buf[0] = file->shareable ? 0x40 : 0; + buf[0] |= (file->type & 7) << 3; + buf[0] |= file->ef_structure & 7; + sc_asn1_put_tag(0x82, buf, 1, p, 16, &p); + buf[0] = (file->id >> 8) & 0xFF; + buf[1] = file->id & 0xFF; + sc_asn1_put_tag(0x83, buf, 2, p, 16, &p); + /* 0x84 = DF name */ + if (file->prop_attr_len) { + memcpy(buf, file->prop_attr, file->prop_attr_len); + sc_asn1_put_tag(0x85, buf, file->prop_attr_len, p, 18, &p); + } + if (file->sec_attr_len) { + memcpy(buf, file->sec_attr, file->sec_attr_len); + sc_asn1_put_tag(0x86, buf, file->sec_attr_len, p, 18, &p); + } + *p++ = 0xDE; + *p++ = 0; + *outlen = p - out; + out[1] = p - out - 2; + return 0; +} + +int sc_create_file(struct sc_card *card, const struct sc_file *file) +{ + int r, len; + u8 sbuf[SC_MAX_APDU_BUFFER_SIZE]; + u8 rbuf[SC_MAX_APDU_BUFFER_SIZE]; + struct sc_apdu apdu; + + SC_FUNC_CALLED(card->ctx, 1); + len = SC_MAX_APDU_BUFFER_SIZE; + r = construct_fci(file, sbuf, &len); + SC_TEST_RET(card->ctx, r, "construct_fci() failed"); + + sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xE0, 0x00, 0x00); + apdu.lc = len; + apdu.datalen = len; + apdu.data = sbuf; + apdu.resplen = sizeof(rbuf); + apdu.resp = rbuf; + + r = sc_transmit_apdu(card, &apdu); + SC_TEST_RET(card->ctx, r, "APDU transmit failed"); + SC_FUNC_RETURN(card->ctx, 1, sc_sw_to_errorcode(card, apdu.sw1, apdu.sw2)); +} + +int sc_delete_file(struct sc_card *card, int file_id) +{ + int r; + u8 sbuf[2]; + u8 rbuf[SC_MAX_APDU_BUFFER_SIZE]; + struct sc_apdu apdu; + + SC_FUNC_CALLED(card->ctx, 1); + sbuf[0] = (file_id >> 8) & 0xFF; + sbuf[1] = file_id & 0xFF; + sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xE4, 0x00, 0x00); + apdu.lc = 2; + apdu.datalen = 2; + apdu.data = sbuf; + apdu.resplen = sizeof(rbuf); + apdu.resp = rbuf; + + r = sc_transmit_apdu(card, &apdu); + SC_TEST_RET(card->ctx, r, "APDU transmit failed"); + if (apdu.resplen != 0) + SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_ILLEGAL_RESPONSE); + SC_FUNC_RETURN(card->ctx, 1, sc_sw_to_errorcode(card, apdu.sw1, apdu.sw2)); +} + +int sc_file_valid(const struct sc_file *file) +{ + assert(file != NULL); + + return file->magic == SC_FILE_MAGIC; +} + +int sc_read_binary(struct sc_card *card, unsigned int idx, + unsigned char *buf, size_t count) +{ +#define RB_BUF_SIZE 250 + int r; + + assert(card != NULL && card->ops != NULL && buf != NULL); + if (card->ctx->debug >= 2) + debug(card->ctx, "sc_read_binary: %d bytes at index %d\n", count, idx); + if (count > RB_BUF_SIZE) { + int bytes_read = 0; + unsigned char *p = buf; + + if (card->ops->read_binary_large != NULL) { + r = card->ops->read_binary_large(card, idx, buf, count); + SC_FUNC_RETURN(card->ctx, 2, r); + } + /* no read_binary_large support... */ + while (count > 0) { + int n = count > RB_BUF_SIZE ? RB_BUF_SIZE : count; + r = sc_read_binary(card, idx, p, n); + SC_TEST_RET(card->ctx, r, "sc_read_binary() failed"); + p += r; + idx += r; + bytes_read += r; + count -= r; + if (r == 0) + SC_FUNC_RETURN(card->ctx, 2, bytes_read); + } + SC_FUNC_RETURN(card->ctx, 2, bytes_read); + } + if (card->ops->read_binary == NULL) + SC_FUNC_RETURN(card->ctx, 2, SC_ERROR_NOT_SUPPORTED); + r = card->ops->read_binary(card, idx, buf, count); + SC_FUNC_RETURN(card->ctx, 2, r); +} + +int sc_select_file(struct sc_card *card, + struct sc_file *file, + const struct sc_path *in_path) +{ + int r; + + assert(card != NULL && in_path != NULL); + if (card->ctx->debug >= 2) { + char line[128], *linep = line; + + linep += sprintf(linep, "called with type %d, path ", in_path->type); + for (r = 0; r < in_path->len; r++) { + sprintf(linep, "%02X", in_path->value[r]); + linep += 2; + } + strcpy(linep, "\n"); + debug(card->ctx, line); + } + if (in_path->len > SC_MAX_PATH_SIZE) + SC_FUNC_RETURN(card->ctx, 2, SC_ERROR_INVALID_ARGUMENTS); + if (card->ops->select_file == NULL) + SC_FUNC_RETURN(card->ctx, 2, SC_ERROR_NOT_SUPPORTED); + r = card->ops->select_file(card, file, in_path); + SC_FUNC_RETURN(card->ctx, 2, r); +} + +int sc_get_challenge(struct sc_card *card, u8 *rnd, size_t len) +{ + int r; + + assert(card != NULL); + SC_FUNC_CALLED(card->ctx, 2); + if (card->ops->get_challenge == NULL) + SC_FUNC_RETURN(card->ctx, 2, SC_ERROR_NOT_SUPPORTED); + r = card->ops->get_challenge(card, rnd, len); + SC_FUNC_RETURN(card->ctx, 2, r); +} diff --git a/src/libopensc/defaults.c b/src/libopensc/defaults.c index 573644d1..3c2c2f05 100644 --- a/src/libopensc/defaults.c +++ b/src/libopensc/defaults.c @@ -24,25 +24,10 @@ #include #include -static int fineid_defaults(void *arg) -{ - struct sc_card *card = (struct sc_card *) arg; - - card->cla = 0; - - return 0; -} - -static int multiflex_defaults(void *arg) -{ - struct sc_card *card = (struct sc_card *) arg; - - card->cla = 0xC0; - return 0; -} - +/* const struct sc_defaults sc_card_table[] = { { "3B:9F:94:40:1E:00:67:11:43:46:49:53:45:10:52:66:FF:81:90:00", fineid_defaults }, { "3B:19:14:55:90:01:02:02:00:05:04:B0", multiflex_defaults }, { NULL, NULL } }; +*/ \ No newline at end of file diff --git a/src/libopensc/iso7816.c b/src/libopensc/iso7816.c new file mode 100644 index 00000000..a7ea682a --- /dev/null +++ b/src/libopensc/iso7816.c @@ -0,0 +1,263 @@ +/* + * sc-iso7816-4.c: Functions specified by the ISO 7816-4 standard + * + * Copyright (C) 2001 Juha Yrjölä + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "opensc.h" +#include "sc-asn1.h" +#include "sc-log.h" + +#include +#include + +static int iso7816_read_binary(struct sc_card *card, + unsigned int idx, u8 *buf, 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, 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_sw_to_errorcode(card, apdu.sw1, apdu.sw2)); + memcpy(buf, recvbuf, apdu.resplen); + + SC_FUNC_RETURN(card->ctx, 2, apdu.resplen); +} + +static void process_fci(struct sc_context *ctx, struct sc_file *file, + const u8 *buf, int buflen) +{ + int taglen, len = buflen; + const u8 *tag = NULL, *p = buf; + + if (ctx->debug >= 3) + debug(ctx, "processing FCI bytes\n"); + tag = sc_asn1_find_tag(p, len, 0x83, &taglen); + if (tag != NULL && taglen == 2) { + file->id = (tag[0] << 8) | tag[1]; + if (ctx->debug >= 3) + debug(ctx, " file identifier: 0x%02X%02X\n", tag[0], + tag[1]); + } + tag = sc_asn1_find_tag(p, len, 0x81, &taglen); + if (tag != NULL && taglen >= 2) { + int bytes = (tag[0] << 8) + tag[1]; + if (ctx->debug >= 3) + debug(ctx, " bytes in file: %d\n", bytes); + file->size = bytes; + } + tag = sc_asn1_find_tag(p, len, 0x82, &taglen); + if (tag != NULL) { + if (taglen > 0) { + unsigned char byte = tag[0]; + const char *type; + + file->shareable = byte & 0x40 ? 1 : 0; + if (ctx->debug >= 3) + debug(ctx, " shareable: %s\n", + (byte & 0x40) ? "yes" : "no"); + file->type = (byte >> 3) & 7; + file->ef_structure = byte & 0x07; + if (ctx->debug >= 3) { + switch ((byte >> 3) & 7) { + case 0: + type = "working EF"; + break; + case 1: + type = "internal EF"; + break; + case 7: + type = "DF"; + break; + default: + type = "unknown"; + break; + } + debug(ctx, " type: %s\n", type); + debug(ctx, " EF structure: %d\n", + byte & 0x07); + } + } + } + tag = sc_asn1_find_tag(p, len, 0x84, &taglen); + if (tag != NULL && taglen > 0 && taglen <= 16) { + char name[17]; + int i; + + memcpy(file->name, tag, taglen); + file->namelen = taglen; + + for (i = 0; i < taglen; i++) { + if (isalnum(tag[i]) || ispunct(tag[i]) + || isspace(tag[i])) + name[i] = tag[i]; + else + name[i] = '?'; + } + name[taglen] = 0; + if (ctx->debug >= 3) + debug(ctx, "File name: %s\n", name); + } + tag = sc_asn1_find_tag(p, len, 0x85, &taglen); + if (tag != NULL && taglen && taglen <= SC_MAX_PROP_ATTR_SIZE) { + memcpy(file->prop_attr, tag, taglen); + file->prop_attr_len = taglen; + } else + file->prop_attr_len = 0; + tag = sc_asn1_find_tag(p, len, 0x86, &taglen); + if (tag != NULL && taglen && taglen <= SC_MAX_SEC_ATTR_SIZE) { + memcpy(file->sec_attr, tag, taglen); + file->sec_attr_len = taglen; + } else + file->sec_attr_len = 0; + file->magic = SC_FILE_MAGIC; +} + +static int iso7816_select_file(struct sc_card *card, + struct sc_file *file, + const struct sc_path *in_path) +{ + struct sc_context *ctx; + struct sc_apdu apdu; + char buf[SC_MAX_APDU_BUFFER_SIZE]; + u8 pathbuf[SC_MAX_PATH_SIZE], *path = pathbuf; + int r, pathlen; + + 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, 0, 0); + apdu.resp = buf; + apdu.resplen = sizeof(buf); + + switch (in_path->type) { + case SC_PATH_TYPE_FILE_ID: + apdu.p1 = 0; + if (pathlen != 2) + return SC_ERROR_INVALID_ARGUMENTS; + break; + case SC_PATH_TYPE_DF_NAME: + apdu.p1 = 4; + break; + case SC_PATH_TYPE_PATH: + apdu.p1 = 8; + if (pathlen >= 2 && memcmp(path, "\x3F\x00", 2) == 0) { + if (pathlen == 2) { /* only 3F00 supplied */ + apdu.p1 = 0; + break; + } + path += 2; + pathlen -= 2; + } + break; + default: + SC_FUNC_RETURN(card->ctx, 2, SC_ERROR_INVALID_ARGUMENTS); + } + apdu.p2 = 0; /* record */ + apdu.lc = pathlen; + apdu.data = path; + apdu.datalen = pathlen; + + if (file != NULL) { + memset(file, 0, sizeof(*file)); + memcpy(&file->path.value, path, pathlen); + file->path.len = pathlen; + } + if (file == NULL || sc_file_valid(file)) + apdu.no_response = 1; + r = sc_transmit_apdu(card, &apdu); + SC_TEST_RET(card->ctx, r, "APDU transmit failed"); + + if (apdu.no_response) { + if (apdu.sw1 == 0x61) + SC_FUNC_RETURN(card->ctx, 2, 0); + SC_FUNC_RETURN(card->ctx, 2, sc_sw_to_errorcode(card, apdu.sw1, apdu.sw2)); + } + + r = sc_sw_to_errorcode(card, apdu.sw1, apdu.sw2); + if (r) + SC_FUNC_RETURN(card->ctx, 2, r); + + switch (apdu.resp[0]) { + case 0x6F: + if (file != NULL && apdu.resp[1] <= apdu.resplen) + process_fci(card->ctx, file, apdu.resp+2, apdu.resp[1]); + break; + case 0x00: /* proprietary coding */ + SC_FUNC_RETURN(card->ctx, 2, SC_ERROR_UNKNOWN_REPLY); + default: + SC_FUNC_RETURN(card->ctx, 2, SC_ERROR_UNKNOWN_REPLY); + } + return 0; +} + +static int iso7816_get_challenge(struct sc_card *card, u8 *rnd, size_t len) +{ + int r; + struct sc_apdu apdu; + u8 buf[10]; + + sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, + 0x84, 0x00, 0x00); + apdu.le = 8; + apdu.resp = buf; + apdu.resplen = 8; /* include SW's */ + + while (len > 0) { + int n = len > 8 ? 8 : len; + + r = sc_transmit_apdu(card, &apdu); + SC_TEST_RET(card->ctx, r, "APDU transmit failed"); + if (apdu.resplen != 8) + return sc_sw_to_errorcode(card, apdu.sw1, apdu.sw2); + memcpy(rnd, apdu.resp, n); + len -= n; + rnd += n; + } + return 0; +} + +static struct sc_card_operations iso_ops = { + read_binary: NULL +}; + +static const struct sc_card_driver iso_driver = { + name: "ISO 7816-x reference driver", + ops: &iso_ops +}; + +const struct sc_card_driver * sc_get_iso7816_driver(void) +{ + if (iso_ops.read_binary == NULL) { + memset(&iso_ops, 0, sizeof(iso_ops)); + iso_ops.read_binary = iso7816_read_binary; + iso_ops.select_file = iso7816_select_file; + iso_ops.get_challenge = iso7816_get_challenge; + } + return &iso_driver; +} diff --git a/src/libopensc/opensc-pkcs15.h b/src/libopensc/opensc-pkcs15.h index 1ba331f1..0ff195fd 100644 --- a/src/libopensc/opensc-pkcs15.h +++ b/src/libopensc/opensc-pkcs15.h @@ -161,6 +161,8 @@ struct sc_pkcs15_card { struct sc_file file_aodf[SC_PKCS15_MAX_AODFS]; int aodf_count; struct sc_file file_dodf; + + int use_cache; }; #define SC_PKCS15_CARD_FLAG_READONLY 0x01 @@ -229,9 +231,6 @@ int sc_pkcs15_compare_id(const struct sc_pkcs15_id *id1, void sc_pkcs15_print_id(const struct sc_pkcs15_id *id); int sc_pkcs15_hex_string_to_id(const char *in, struct sc_pkcs15_id *out); -int sc_pkcs15_parse_common_object_attr(struct sc_pkcs15_common_obj_attr *attr, - const u8 * buf, int buflen); - extern const struct sc_pkcs15_defaults sc_pkcs15_card_table[]; #ifdef __cplusplus diff --git a/src/libopensc/opensc.h b/src/libopensc/opensc.h index d032f726..f2c81b50 100644 --- a/src/libopensc/opensc.h +++ b/src/libopensc/opensc.h @@ -59,6 +59,7 @@ extern "C" { #define SC_ERROR_ASN1_OBJECT_NOT_FOUND -1026 #define SC_ERROR_ASN1_END_OF_CONTENTS -1027 #define SC_ERROR_TOO_MANY_OBJECTS -1028 +#define SC_ERROR_INVALID_CARD -1029 #define SC_APDU_CASE_NONE 0 #define SC_APDU_CASE_1 1 @@ -95,6 +96,7 @@ extern "C" { #define SC_FILE_EF_LINEAR_FIXED 0x02 #define SC_FILE_EF_LINEAR_FIXED_TLV 0x03 +#define SC_MAX_CARD_DRIVERS 16 #define SC_MAX_READERS 4 #define SC_MAX_APDU_BUFFER_SIZE 255 #define SC_MAX_PATH_SIZE 16 @@ -111,10 +113,16 @@ struct sc_object_id { int value[SC_ASN1_MAX_OBJECT_ID_OCTETS]; }; +#define SC_PATH_TYPE_FILE_ID 0 +#define SC_PATH_TYPE_DF_NAME 1 +#define SC_PATH_TYPE_PATH 2 + struct sc_path { u8 value[SC_MAX_PATH_SIZE]; size_t len; int index; + + int type; }; struct sc_file { @@ -143,11 +151,36 @@ struct sc_security_env { int key_ref; }; -struct sc_card; +struct sc_card { + int cla; + struct sc_context *ctx; + + SCARDHANDLE pcsc_card; + int reader; + u8 atr[SC_MAX_ATR_SIZE]; + size_t atr_len; + + pthread_mutex_t mutex; + const struct sc_card_operations *ops; + void *ops_data; +}; struct sc_card_operations { + /* Called in sc_connect_card(). Must return 1, if the current + * card can be handled with this driver, or 0 otherwise. ATR + * field of the sc_card struct is filled in before calling + * this function. */ + int (*match_card)(struct sc_card *card); + + /* Called when ATR of the inserted card matches an entry in ATR + * table. May return SC_ERROR_INVALID_CARD to indicate that + * the card cannot be handled with this driver. */ int (*init)(struct sc_card *card); + /* Called when the card object is being freed. finish() has to + * deallocate all possible private data. */ int (*finish)(struct sc_card *card); + + /* ISO 7816-4 functions */ int (*read_binary)(struct sc_card *card, unsigned int idx, u8 * buf, size_t count); @@ -157,6 +190,8 @@ struct sc_card_operations { const u8 * buf, size_t count); int (*erase_binary)(struct sc_card *card, unsigned int idx, size_t count); + /* These may be left NULL. If not present, multiple calls + * to read_binary et al. will be made. */ int (*read_binary_large)(struct sc_card *card, unsigned int idx, u8 * buf, size_t count); int (*write_binary_large)(struct sc_card *card, unsigned int idx, @@ -164,17 +199,30 @@ struct sc_card_operations { int (*update_binary_large)(struct sc_card *card, unsigned int idx, const u8 * buf, size_t count); /* possibly TODO: record handling */ + + /* select_file: Does the equivalent of SELECT FILE command specified + * in ISO7816-4. Stores information about the selected file to + * , if not NULL. */ int (*select_file)(struct sc_card *card, struct sc_file *file, - const struct sc_path *path, int selection_type); + const struct sc_path *path); int (*get_response)(struct sc_card *card, u8 * buf, size_t count); int (*get_challenge)(struct sc_card *card, u8 * buf, size_t count); /* ISO 7816-8 */ int (*verify)(struct sc_card *card, int ref_qualifier, const u8 *data, size_t data_len, int *tries_left); - int (*restore_security_env)(struct sc_card *card, int se_num); + + /* restore_security_env: Restores a previously saved security + * environment, and stores information about the environment to + * , if not NULL. */ + int (*restore_security_env)(struct sc_card *card, int se_num, + struct sc_security_env *env_out); + + /* set_security_env: Initializes the security environment on card + * according to , and stores the environment as on the + * card. If se_num <= 0, the environment will not be stored. */ int (*set_security_env)(struct sc_card *card, - const struct sc_security_env *env); + const struct sc_security_env *env, int se_num); int (*decipher)(struct sc_card *card, const u8 * crgram, size_t crgram_len, u8 * out, size_t outlen); int (*compute_signature)(struct sc_card *card, const u8 * data, @@ -188,16 +236,9 @@ struct sc_card_operations { const u8 *newref, size_t newlen); }; -struct sc_card { - int cla; - struct sc_context *ctx; - - SCARDHANDLE pcsc_card; - int reader; - u8 atr[SC_MAX_ATR_SIZE]; - size_t atr_len; - - pthread_mutex_t mutex; +struct sc_card_driver { + char *libpath; /* NULL, if compiled in */ + char *name; struct sc_card_operations *ops; }; @@ -209,6 +250,7 @@ struct sc_context { int debug; int use_std_output, use_cache; + const struct sc_card_driver *card_drivers[SC_MAX_CARD_DRIVERS]; }; struct sc_apdu { @@ -224,13 +266,6 @@ struct sc_apdu { unsigned int sw1, sw2; }; - -struct sc_defaults { - const char *atr; - int (*defaults_func)(void *); - int (*pkcs15_defaults_func)(void *); -}; - /* Base64 encoding/decoding functions */ int sc_base64_encode(const u8 *in, size_t inlen, u8 *out, size_t outlen, size_t linelength); @@ -263,9 +298,9 @@ int sc_unlock(struct sc_card *card); /* ISO 7816-4 related functions */ int sc_select_file(struct sc_card *card, struct sc_file *file, - const struct sc_path *path, int pathtype); -int sc_read_binary(struct sc_card *card, int idx, u8 * buf, size_t count); -int sc_get_random(struct sc_card *card, u8 * rndout, size_t len); + const struct sc_path *path); +int sc_read_binary(struct sc_card *card, unsigned int idx, u8 * buf, size_t count); +int sc_get_challenge(struct sc_card *card, u8 * rndout, size_t len); /* ISO 7816-8 related functions */ int sc_restore_security_env(struct sc_card *card, int se_num); @@ -297,10 +332,12 @@ int sc_file_valid(const struct sc_file *file); void sc_print_binary(FILE *f, const u8 *buf, int len); int sc_hex_to_bin(const char *in, u8 *out, size_t *outlen); int sc_sw_to_errorcode(struct sc_card *card, int sw1, int sw2); +void sc_format_path(const char *path_in, struct sc_path *path_out); extern const char *sc_version; -extern const struct sc_defaults sc_card_table[]; +extern const struct sc_card_driver *sc_get_iso7816_driver(void); +extern const struct sc_card_driver *sc_get_setec_driver(void); #ifdef __cplusplus } diff --git a/src/libopensc/pkcs15-cert.c b/src/libopensc/pkcs15-cert.c index 6283fd93..22ca9396 100644 --- a/src/libopensc/pkcs15-cert.c +++ b/src/libopensc/pkcs15-cert.c @@ -164,6 +164,8 @@ static int find_cached_cert(struct sc_pkcs15_card *p15card, if (getuid() != geteuid()) /* no caching in SUID processes */ return -1; + if (p15card->use_cache == 0) + return -1; r = generate_cert_filename(p15card, info, fname, sizeof(fname)); if (r) @@ -227,8 +229,7 @@ int sc_pkcs15_read_certificate(struct sc_pkcs15_card *p15card, SC_FUNC_CALLED(p15card->card->ctx, 1); r = find_cached_cert(p15card, info, &data, &len); if (r) { - r = sc_select_file(p15card->card, &file, &info->path, - SC_SELECT_FILE_BY_PATH); + r = sc_select_file(p15card->card, &file, &info->path); if (r) return r; data = malloc(file.size); @@ -321,8 +322,7 @@ static int get_certs_from_file(struct sc_pkcs15_card *card, u8 buf[2048]; const u8 *p = buf; - r = sc_select_file(card->card, file, &file->path, - SC_SELECT_FILE_BY_PATH); + r = sc_select_file(card->card, file, &file->path); if (r) return r; if (file->size > sizeof(buf)) diff --git a/src/libopensc/pkcs15-pin.c b/src/libopensc/pkcs15-pin.c index 5199f221..16d58fde 100644 --- a/src/libopensc/pkcs15-pin.c +++ b/src/libopensc/pkcs15-pin.c @@ -103,8 +103,7 @@ static int get_pins_from_file(struct sc_pkcs15_card *card, u8 buf[2048]; const u8 *p = buf; - r = sc_select_file(card->card, file, &file->path, - SC_SELECT_FILE_BY_PATH); + r = sc_select_file(card->card, file, &file->path); if (r) return r; if (file->size > sizeof(buf)) @@ -170,8 +169,7 @@ int sc_pkcs15_verify_pin(struct sc_pkcs15_card *p15card, if (pinlen > pin->stored_length || pinlen < pin->min_length) return SC_ERROR_INVALID_PIN_LENGTH; card = p15card->card; - r = sc_select_file(card, &file, &pin->path, - SC_SELECT_FILE_BY_PATH); + r = sc_select_file(card, &file, &pin->path); if (r) return r; @@ -205,8 +203,7 @@ int sc_pkcs15_change_pin(struct sc_pkcs15_card *p15card, if ((oldpinlen < pin->min_length) || (newpinlen < pin->min_length)) return SC_ERROR_INVALID_ARGUMENTS; card = p15card->card; - r = sc_select_file(card, &file, &pin->path, - SC_SELECT_FILE_BY_PATH); + r = sc_select_file(card, &file, &pin->path); if (r) return r; diff --git a/src/libopensc/pkcs15-prkey.c b/src/libopensc/pkcs15-prkey.c index 2f090325..4c0a26cc 100644 --- a/src/libopensc/pkcs15-prkey.c +++ b/src/libopensc/pkcs15-prkey.c @@ -98,8 +98,7 @@ static int get_prkeys_from_file(struct sc_pkcs15_card *card, u8 buf[2048]; const u8 *p = buf; - r = sc_select_file(card->card, file, &file->path, - SC_SELECT_FILE_BY_PATH); + r = sc_select_file(card->card, file, &file->path); if (r) return r; if (file->size > sizeof(buf)) diff --git a/src/libopensc/pkcs15-sec.c b/src/libopensc/pkcs15-sec.c index 48f74968..d42a0200 100644 --- a/src/libopensc/pkcs15-sec.c +++ b/src/libopensc/pkcs15-sec.c @@ -42,14 +42,16 @@ int sc_pkcs15_decipher(struct sc_pkcs15_card *p15card, SC_FUNC_CALLED(ctx, 1); r = sc_select_file(p15card->card, &p15card->file_app, - &p15card->file_app.path, SC_SELECT_FILE_BY_PATH); + &p15card->file_app.path); SC_TEST_RET(ctx, r, "sc_select_file() failed"); r = sc_select_file(p15card->card, &p15card->file_app, - &p15card->file_app.path, SC_SELECT_FILE_BY_PATH); + &p15card->file_app.path); SC_TEST_RET(ctx, r, "sc_select_file() failed"); - usleep(100*1000); /* PC/SC Lite quirks */ +#if 0 + /* FIXME! */ r = sc_restore_security_env(p15card->card, 0); /* empty SE */ SC_TEST_RET(ctx, r, "sc_restore_security_env() failed"); +#endif r = sc_set_security_env(p15card->card, &senv); SC_TEST_RET(ctx, r, "sc_set_security_env() failed"); r = sc_decipher(p15card->card, in, inlen, out, outlen); @@ -81,11 +83,13 @@ int sc_pkcs15_compute_signature(struct sc_pkcs15_card *p15card, SC_FUNC_CALLED(ctx, 1); r = sc_select_file(p15card->card, &p15card->file_app, - &p15card->file_app.path, SC_SELECT_FILE_BY_PATH); + &p15card->file_app.path); SC_TEST_RET(ctx, r, "sc_select_file() failed"); - usleep(100*1000); /* PC/SC Lite quirks */ +#if 0 + /* FIXME! */ r = sc_restore_security_env(p15card->card, 0); /* empty SE */ SC_TEST_RET(ctx, r, "sc_restore_security_env() failed"); +#endif r = sc_set_security_env(p15card->card, &senv); SC_TEST_RET(ctx, r, "sc_set_security_env() failed"); r = sc_compute_signature(p15card->card, in, inlen, out, outlen); diff --git a/src/libopensc/pkcs15.c b/src/libopensc/pkcs15.c index e9dd0650..f51df6d7 100644 --- a/src/libopensc/pkcs15.c +++ b/src/libopensc/pkcs15.c @@ -155,6 +155,7 @@ static int parse_dir(const u8 * buf, int buflen, struct sc_pkcs15_card *card) card->label = strdup("(unknown)"); memcpy(card->file_app.path.value, path, path_len); card->file_app.path.len = path_len; + card->file_app.path.type = SC_PATH_TYPE_PATH; return 0; } @@ -185,6 +186,8 @@ static int parse_odf(const u8 * buf, int buflen, struct sc_pkcs15_card *card) return r; switch (r) { case 0: + if (card->file_prkdf.path.len) + error(card->card->ctx, "warning: card has too many PrKDF's\n"); card->file_prkdf.path = path; break; case 1: @@ -197,6 +200,8 @@ static int parse_odf(const u8 * buf, int buflen, struct sc_pkcs15_card *card) card->cdf_count++; break; case 3: + if (card->file_dodf.path.len) + error(card->card->ctx, "warning: card has too many DODF's\n"); card->file_dodf.path = path; break; case 4: @@ -214,6 +219,7 @@ static int parse_odf(const u8 * buf, int buflen, struct sc_pkcs15_card *card) static const struct sc_pkcs15_defaults * find_defaults(u8 *dir, int dirlen) { +#if 0 int i = 0; const struct sc_pkcs15_defaults *match = NULL; @@ -234,6 +240,8 @@ static const struct sc_pkcs15_defaults * find_defaults(u8 *dir, int dirlen) break; } return match; +#endif + return NULL; } int sc_pkcs15_bind(struct sc_card *card, @@ -246,16 +254,15 @@ int sc_pkcs15_bind(struct sc_card *card, const struct sc_pkcs15_defaults *defaults = NULL; assert(card != NULL && p15card_out != NULL); + SC_FUNC_CALLED(card->ctx, 1); p15card = malloc(sizeof(struct sc_pkcs15_card)); if (p15card == NULL) return SC_ERROR_OUT_OF_MEMORY; memset(p15card, 0, sizeof(struct sc_pkcs15_card)); p15card->card = card; - memcpy(tmppath.value, "\x2F\x00", 2); - tmppath.len = 2; - err = sc_select_file(card, &p15card->file_dir, &tmppath, - SC_SELECT_FILE_BY_PATH); + sc_format_path("2F00", &tmppath); + err = sc_select_file(card, &p15card->file_dir, &tmppath); if (err) goto error; err = sc_read_binary(card, 0, buf, p15card->file_dir.size); @@ -270,7 +277,7 @@ int sc_pkcs15_bind(struct sc_card *card, err = SC_ERROR_PKCS15_CARD_NOT_FOUND; goto error; } - if (p15card->card->ctx->use_cache) + if (p15card->use_cache) defaults = find_defaults(buf, err); if (defaults == NULL) { if (p15card->file_odf.path.len == 0) { @@ -279,8 +286,8 @@ int sc_pkcs15_bind(struct sc_card *card, tmppath.len += 2; } else tmppath = p15card->file_odf.path; - err = sc_select_file(card, &p15card->file_odf, &tmppath, - SC_SELECT_FILE_BY_PATH); + + err = sc_select_file(card, &p15card->file_odf, &tmppath); if (err) goto error; err = sc_read_binary(card, 0, buf, p15card->file_odf.size); @@ -305,8 +312,7 @@ int sc_pkcs15_bind(struct sc_card *card, defaults->defaults_func(p15card, defaults->arg); tmppath = p15card->file_tokeninfo.path; } - err = sc_select_file(card, &p15card->file_tokeninfo, &tmppath, - SC_SELECT_FILE_BY_PATH); + err = sc_select_file(card, &p15card->file_tokeninfo, &tmppath); if (err) goto error; err = sc_read_binary(card, 0, buf, p15card->file_tokeninfo.size); @@ -317,6 +323,9 @@ int sc_pkcs15_bind(struct sc_card *card, goto error; } parse_tokeninfo(p15card, buf, err); + + p15card->use_cache = card->ctx->use_cache; + *p15card_out = p15card; return 0; error: @@ -326,6 +335,8 @@ error: int sc_pkcs15_unbind(struct sc_pkcs15_card *p15card) { + assert(p15card != NULL); + SC_FUNC_CALLED(p15card->card->ctx, 1); free(p15card->label); free(p15card->serial_number); free(p15card->manufacturer_id); @@ -333,38 +344,6 @@ int sc_pkcs15_unbind(struct sc_pkcs15_card *p15card) return 0; } -int sc_pkcs15_parse_common_object_attr(struct sc_pkcs15_common_obj_attr *attr, - const u8 * buf, int buflen) -{ - int taglen; - const u8 *tag; - - tag = sc_asn1_find_tag(buf, buflen, 0x0C, &taglen); /* UTF8STRING */ - if (tag != NULL && taglen < SC_PKCS15_MAX_LABEL_SIZE) { - memcpy(attr->label, tag, taglen); - attr->label[taglen] = 0; - } else - attr->label[0] = 0; - tag = sc_asn1_find_tag(buf, buflen, 0x03, &taglen); /* BIT STRING */ - if (tag != NULL) { - if (sc_asn1_decode_bit_string(buf, buflen, &attr->flags, - sizeof(attr->flags)) < 0) - attr->flags = 0; - } else - attr->flags = 0; - tag = sc_asn1_find_tag(buf, buflen, 0x04, &taglen); /* OCTET STRING */ - if (tag != NULL) { - memcpy(attr->auth_id.value, tag, taglen); - attr->auth_id.len = taglen; - } else - attr->auth_id.len = 0; - - /* FIXME: parse rest */ - attr->user_consent = 0; - - return 0; -} - int sc_pkcs15_compare_id(const struct sc_pkcs15_id *id1, const struct sc_pkcs15_id *id2) { diff --git a/src/libopensc/pkcs15.h b/src/libopensc/pkcs15.h index 1ba331f1..0ff195fd 100644 --- a/src/libopensc/pkcs15.h +++ b/src/libopensc/pkcs15.h @@ -161,6 +161,8 @@ struct sc_pkcs15_card { struct sc_file file_aodf[SC_PKCS15_MAX_AODFS]; int aodf_count; struct sc_file file_dodf; + + int use_cache; }; #define SC_PKCS15_CARD_FLAG_READONLY 0x01 @@ -229,9 +231,6 @@ int sc_pkcs15_compare_id(const struct sc_pkcs15_id *id1, void sc_pkcs15_print_id(const struct sc_pkcs15_id *id); int sc_pkcs15_hex_string_to_id(const char *in, struct sc_pkcs15_id *out); -int sc_pkcs15_parse_common_object_attr(struct sc_pkcs15_common_obj_attr *attr, - const u8 * buf, int buflen); - extern const struct sc_pkcs15_defaults sc_pkcs15_card_table[]; #ifdef __cplusplus diff --git a/src/libopensc/sc.c b/src/libopensc/sc.c index bd81ac36..55120f8b 100644 --- a/src/libopensc/sc.c +++ b/src/libopensc/sc.c @@ -1,5 +1,5 @@ /* - * sc.c: General SmartCard functions + * sc.c: General functions * * Copyright (C) 2001 Juha Yrjölä * @@ -37,43 +37,6 @@ const char *sc_version = VERSION; const char *sc_version = "(undef)"; #endif -int sc_sw_to_errorcode(struct sc_card *card, int sw1, int sw2) -{ - switch (sw1) { - case 0x69: - switch (sw2) { - case 0x82: - return SC_ERROR_SECURITY_STATUS_NOT_SATISFIED; - default: - break; - } - break; - case 0x6A: - switch (sw2) { - case 0x81: - return SC_ERROR_NOT_SUPPORTED; - case 0x82: - case 0x83: - return SC_ERROR_FILE_NOT_FOUND; - case 0x86: - case 0x87: - return SC_ERROR_INVALID_ARGUMENTS; - default: - break; - } - break; - case 0x6D: - return SC_ERROR_NOT_SUPPORTED; - case 0x6E: - return SC_ERROR_UNKNOWN_SMARTCARD; - case 0x90: - if (sw2 == 0) - return 0; - } - error(card->ctx, "Unknown SW's: SW1=%02X, SW2=%02X\n", sw1, sw2); - return SC_ERROR_UNKNOWN_REPLY; -} - void sc_print_binary(FILE *f, const u8 *buf, int count) { int i; @@ -120,201 +83,6 @@ int sc_hex_to_bin(const char *in, u8 *out, size_t *outlen) return err; } -int sc_check_apdu(struct sc_context *ctx, const struct sc_apdu *apdu) -{ - switch (apdu->cse) { - case SC_APDU_CASE_1: - if (apdu->datalen > 0) - SC_FUNC_RETURN(ctx, 4, SC_ERROR_INVALID_ARGUMENTS); - break; - case SC_APDU_CASE_2_SHORT: - if (apdu->datalen > 0) - SC_FUNC_RETURN(ctx, 4, SC_ERROR_INVALID_ARGUMENTS); - if (apdu->resplen < apdu->le) - SC_FUNC_RETURN(ctx, 4, SC_ERROR_INVALID_ARGUMENTS); - break; - case SC_APDU_CASE_3_SHORT: - if (apdu->datalen == 0 || apdu->data == NULL) - SC_FUNC_RETURN(ctx, 4, SC_ERROR_INVALID_ARGUMENTS); - break; - case SC_APDU_CASE_4_SHORT: - if (apdu->datalen == 0 || apdu->data == NULL) - SC_FUNC_RETURN(ctx, 4, SC_ERROR_INVALID_ARGUMENTS); - if (apdu->resplen < apdu->le) - SC_FUNC_RETURN(ctx, 4, SC_ERROR_INVALID_ARGUMENTS); - break; - case SC_APDU_CASE_2_EXT: - case SC_APDU_CASE_3_EXT: - case SC_APDU_CASE_4_EXT: - SC_FUNC_RETURN(ctx, 4, SC_ERROR_INVALID_ARGUMENTS); - } - return 0; -} - -static int sc_transceive_t0(struct sc_card *card, struct sc_apdu *apdu) -{ - SCARD_IO_REQUEST sSendPci, sRecvPci; - BYTE s[SC_MAX_APDU_BUFFER_SIZE], r[SC_MAX_APDU_BUFFER_SIZE]; - DWORD dwSendLength, dwRecvLength; - LONG rv; - u8 *data = s; - size_t data_bytes = apdu->lc; - - if (data_bytes == 0) - data_bytes = 256; - *data++ = apdu->cla; - *data++ = apdu->ins; - *data++ = apdu->p1; - *data++ = apdu->p2; - switch (apdu->cse) { - case SC_APDU_CASE_1: - break; - case SC_APDU_CASE_2_SHORT: - *data++ = (u8) apdu->le; - break; - case SC_APDU_CASE_2_EXT: - *data++ = (u8) 0; - *data++ = (u8) (apdu->le >> 8); - *data++ = (u8) (apdu->le & 0xFF); - break; - case SC_APDU_CASE_3_SHORT: - *data++ = (u8) apdu->lc; - if (apdu->datalen != data_bytes) - return SC_ERROR_INVALID_ARGUMENTS; - memcpy(data, apdu->data, data_bytes); - data += data_bytes; - break; - case SC_APDU_CASE_4_SHORT: - *data++ = (u8) apdu->lc; - if (apdu->datalen != data_bytes) - return SC_ERROR_INVALID_ARGUMENTS; - memcpy(data, apdu->data, data_bytes); - data += data_bytes; - *data++ = (u8) apdu->le; - break; - } - - sSendPci.dwProtocol = SCARD_PROTOCOL_T0; - sSendPci.cbPciLength = 0; - sRecvPci.dwProtocol = SCARD_PROTOCOL_T0; - sRecvPci.cbPciLength = 0; - - dwSendLength = data - s; - dwRecvLength = apdu->resplen + 2; - if (dwRecvLength > 255) /* FIXME: PC/SC Lite quirk */ - dwRecvLength = 255; - if (card->ctx->debug >= 5) { - char buf[2048]; - - sc_hex_dump(card->ctx, s, (size_t) dwSendLength, buf, sizeof(buf)); - debug(card->ctx, "Sending %d bytes (resp. %d bytes):\n%s", - dwSendLength, dwRecvLength, buf); - } - rv = SCardTransmit(card->pcsc_card, &sSendPci, s, dwSendLength, - &sRecvPci, r, &dwRecvLength); - if (rv != SCARD_S_SUCCESS) { - switch (rv) { - case SCARD_W_REMOVED_CARD: - return SC_ERROR_CARD_REMOVED; - case SCARD_W_RESET_CARD: - return SC_ERROR_CARD_RESET; - case SCARD_E_NOT_TRANSACTED: - if (sc_detect_card(card->ctx, card->reader) != 1) - return SC_ERROR_CARD_REMOVED; - return SC_ERROR_TRANSMIT_FAILED; - default: - error(card->ctx, "SCardTransmit failed: %s\n", pcsc_stringify_error(rv)); - return SC_ERROR_TRANSMIT_FAILED; - } - } - if (dwRecvLength < 2) - return SC_ERROR_ILLEGAL_RESPONSE; - apdu->sw1 = (unsigned int) r[dwRecvLength-2]; - apdu->sw2 = (unsigned int) r[dwRecvLength-1]; - dwRecvLength -= 2; - if ((size_t) dwRecvLength > apdu->resplen) - dwRecvLength = (DWORD) apdu->resplen; - else - apdu->resplen = (size_t) dwRecvLength; - if (dwRecvLength > 0) - memcpy(apdu->resp, r, (size_t) dwRecvLength); - - return 0; -} - -int sc_transmit_apdu(struct sc_card *card, struct sc_apdu *apdu) -{ - int r; - - SC_FUNC_CALLED(card->ctx, 4); - r = sc_check_apdu(card->ctx, apdu); - SC_TEST_RET(card->ctx, r, "APDU sanity check failed"); - r = sc_transceive_t0(card, apdu); - SC_TEST_RET(card->ctx, r, "transceive_t0() failed"); - if (card->ctx->debug >= 5) { - char buf[2048]; - - buf[0] = '\0'; - if (apdu->resplen > 0) { - sc_hex_dump(card->ctx, apdu->resp, apdu->resplen, - buf, sizeof(buf)); - } - debug(card->ctx, "Received %d bytes (SW1=%02X SW2=%02X)\n%s", - apdu->resplen, apdu->sw1, apdu->sw2, buf); - } - if (apdu->sw1 == 0x61 && apdu->resplen == 0) { - struct sc_apdu rspapdu; - BYTE rsp[SC_MAX_APDU_BUFFER_SIZE]; - - if (apdu->no_response != 0) - return 0; - - sc_format_apdu(card, &rspapdu, SC_APDU_CASE_2_SHORT, - 0xC0, 0, 0); - rspapdu.le = (size_t) apdu->sw2; - rspapdu.resp = rsp; - rspapdu.resplen = (size_t) apdu->sw2; - r = sc_transceive_t0(card, &rspapdu); - if (r != 0) { - error(card->ctx, "error while getting response: %s\n", - sc_strerror(r)); - return r; - } - 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); - } - /* FIXME: Check apdu->resplen */ - memcpy(apdu->resp, rspapdu.resp, rspapdu.resplen); - apdu->resplen = rspapdu.resplen; - apdu->sw1 = rspapdu.sw1; - apdu->sw2 = rspapdu.sw2; - } - return 0; -} - -void sc_format_apdu(struct sc_card *card, struct sc_apdu *apdu, - int cse, int ins, int p1, int p2) -{ - assert(card != NULL && apdu != NULL); - memset(apdu, 0, sizeof(*apdu)); - apdu->cla = (u8) card->cla; - apdu->cse = cse; - apdu->ins = (u8) ins; - apdu->p1 = (u8) p1; - apdu->p2 = (u8) p2; - apdu->no_response = 0; - - return; -} - int sc_detect_card(struct sc_context *ctx, int reader) { LONG ret; @@ -387,6 +155,7 @@ int sc_establish_context(struct sc_context **ctx_out) DWORD reader_buf_size; char *reader_buf, *p; LPCSTR mszGroups = NULL; + int i; assert(ctx_out != NULL); ctx = malloc(sizeof(struct sc_context)); @@ -418,6 +187,15 @@ int sc_establish_context(struct sc_context **ctx_out) break; } while (p < (reader_buf + reader_buf_size - 1)); free(reader_buf); + for (i = 0; i < SC_MAX_CARD_DRIVERS; i++) + ctx->card_drivers[i] = NULL; + i = 0; +#if 1 + ctx->card_drivers[i++] = sc_get_iso7816_driver(); +#endif +#if 1 + ctx->card_drivers[i++] = sc_get_setec_driver(); +#endif *ctx_out = ctx; return 0; @@ -435,100 +213,23 @@ int sc_destroy_context(struct sc_context *ctx) return 0; } -static const struct sc_defaults * find_defaults(const u8 *atr, int atrlen) +void sc_format_path(const char *str, struct sc_path *path) { - int i = 0; - const struct sc_defaults *match = NULL; + int len = 0; + u8 *p = path->value; - while (sc_card_table[i].atr != NULL) { - u8 defatr[SC_MAX_ATR_SIZE]; - int len = sizeof(defatr); - const struct sc_defaults *def = &sc_card_table[i]; - const char *atrp = def->atr; - i++; - - if (atrp == NULL) + while (str) { + int byte; + + if (sscanf(str, "%02X", &byte) != 1) break; - if (sc_hex_to_bin(atrp, defatr, &len)) - continue; - if (len != atrlen) - continue; - if (memcmp(atr, defatr, len) != 0) - continue; - match = def; - break; + *p++ = byte; + len++; + str += 2; } - return match; -} - -int sc_connect_card(struct sc_context *ctx, - int reader, struct sc_card **card_out) -{ - struct sc_card *card; - DWORD active_proto; - SCARDHANDLE card_handle; - SCARD_READERSTATE_A rgReaderStates[SC_MAX_READERS]; - LONG rv; - int i; - const struct sc_defaults *defaults; - - assert(card_out != NULL); - SC_FUNC_CALLED(ctx, 1); - if (reader >= ctx->reader_count || reader < 0) - SC_FUNC_RETURN(ctx, 1, SC_ERROR_OBJECT_NOT_FOUND); - - rgReaderStates[0].szReader = ctx->readers[reader]; - rgReaderStates[0].dwCurrentState = SCARD_STATE_UNAWARE; - rv = SCardGetStatusChange(ctx->pcsc_ctx, 0, rgReaderStates, 1); - if (rv != 0) { - error(ctx, "SCardGetStatusChange failed: %s\n", pcsc_stringify_error(rv)); - SC_FUNC_RETURN(ctx, 1, SC_ERROR_RESOURCE_MANAGER); /* FIXME */ - } - if (!(rgReaderStates[0].dwEventState & SCARD_STATE_PRESENT)) - SC_FUNC_RETURN(ctx, 1, SC_ERROR_CARD_NOT_PRESENT); - - card = malloc(sizeof(struct sc_card)); - if (card == NULL) - SC_FUNC_RETURN(ctx, 1, SC_ERROR_OUT_OF_MEMORY); - memset(card, 0, sizeof(struct sc_card)); - rv = SCardConnect(ctx->pcsc_ctx, ctx->readers[reader], - SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0, - &card_handle, &active_proto); - if (rv != 0) { - error(ctx, "SCardConnect failed: %s\n", pcsc_stringify_error(rv)); - free(card); - return -1; /* FIXME */ - } - card->reader = reader; - card->ctx = ctx; - card->pcsc_card = card_handle; - i = rgReaderStates[0].cbAtr; - if (i >= SC_MAX_ATR_SIZE) - i = SC_MAX_ATR_SIZE; - memcpy(card->atr, rgReaderStates[0].rgbAtr, i); - card->atr_len = i; - - defaults = find_defaults(card->atr, card->atr_len); - if (defaults != NULL && defaults->defaults_func != NULL) { - defaults->defaults_func(card); - } else { - card->cla = 0; /* FIXME */ - } - pthread_mutex_init(&card->mutex, NULL); - *card_out = card; - - SC_FUNC_RETURN(ctx, 1, 0); -} - -int sc_disconnect_card(struct sc_card *card) -{ - struct sc_context *ctx = card->ctx; - assert(card != NULL); - SC_FUNC_CALLED(ctx, 1); - SCardDisconnect(card->pcsc_card, SCARD_LEAVE_CARD); - pthread_mutex_destroy(&card->mutex); - free(card); - SC_FUNC_RETURN(ctx, 1, 0); + path->len = len; + path->type = SC_PATH_TYPE_PATH; + return; } const char *sc_strerror(int error) @@ -574,148 +275,3 @@ const char *sc_strerror(int error) return errors[0]; return errors[error]; } - -int _sc_lock_int(struct sc_card *card) -{ - long rv; - - rv = SCardBeginTransaction(card->pcsc_card); - - if (rv != SCARD_S_SUCCESS) { - error(card->ctx, "SCardBeginTransaction failed: %s\n", pcsc_stringify_error(rv)); - return -1; - } - return 0; -} - -int sc_lock(struct sc_card *card) -{ - SC_FUNC_CALLED(card->ctx, 2); - pthread_mutex_lock(&card->mutex); - SC_FUNC_RETURN(card->ctx, 2, _sc_lock_int(card)); -} - -int _sc_unlock_int(struct sc_card *card) -{ - long rv; - - rv = SCardEndTransaction(card->pcsc_card, SCARD_LEAVE_CARD); - if (rv != SCARD_S_SUCCESS) { - error(card->ctx, "SCardEndTransaction failed: %s\n", pcsc_stringify_error(rv)); - return -1; - } - return 0; -} - -int sc_unlock(struct sc_card *card) -{ - SC_FUNC_CALLED(card->ctx, 2); - pthread_mutex_unlock(&card->mutex); - SC_FUNC_RETURN(card->ctx, 2, _sc_unlock_int(card)); -} - -int sc_list_files(struct sc_card *card, u8 *buf, int buflen) -{ - struct sc_apdu apdu; - int r; - - SC_FUNC_CALLED(card->ctx, 2); - sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xAA, 0, 0); - apdu.resp = buf; - apdu.resplen = buflen; - apdu.le = 0; - r = sc_transmit_apdu(card, &apdu); - SC_TEST_RET(card->ctx, r, "APDU transmit failed"); - if (apdu.resplen == 0) - return sc_sw_to_errorcode(card, apdu.sw1, apdu.sw2); - return apdu.resplen; -} - -static int construct_fci(const struct sc_file *file, u8 *out, int *outlen) -{ - u8 *p = out; - u8 buf[32]; - - *p++ = 0x6F; - p++; - - buf[0] = (file->size >> 8) & 0xFF; - buf[1] = file->size & 0xFF; - sc_asn1_put_tag(0x81, buf, 2, p, 16, &p); - buf[0] = file->shareable ? 0x40 : 0; - buf[0] |= (file->type & 7) << 3; - buf[0] |= file->ef_structure & 7; - sc_asn1_put_tag(0x82, buf, 1, p, 16, &p); - buf[0] = (file->id >> 8) & 0xFF; - buf[1] = file->id & 0xFF; - sc_asn1_put_tag(0x83, buf, 2, p, 16, &p); - /* 0x84 = DF name */ - if (file->prop_attr_len) { - memcpy(buf, file->prop_attr, file->prop_attr_len); - sc_asn1_put_tag(0x85, buf, file->prop_attr_len, p, 18, &p); - } - if (file->sec_attr_len) { - memcpy(buf, file->sec_attr, file->sec_attr_len); - sc_asn1_put_tag(0x86, buf, file->sec_attr_len, p, 18, &p); - } - *p++ = 0xDE; - *p++ = 0; - *outlen = p - out; - out[1] = p - out - 2; - return 0; -} - -int sc_create_file(struct sc_card *card, const struct sc_file *file) -{ - int r, len; - u8 sbuf[SC_MAX_APDU_BUFFER_SIZE]; - u8 rbuf[SC_MAX_APDU_BUFFER_SIZE]; - struct sc_apdu apdu; - - SC_FUNC_CALLED(card->ctx, 1); - len = SC_MAX_APDU_BUFFER_SIZE; - r = construct_fci(file, sbuf, &len); - SC_TEST_RET(card->ctx, r, "construct_fci() failed"); - - sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xE0, 0x00, 0x00); - apdu.lc = len; - apdu.datalen = len; - apdu.data = sbuf; - apdu.resplen = sizeof(rbuf); - apdu.resp = rbuf; - - r = sc_transmit_apdu(card, &apdu); - SC_TEST_RET(card->ctx, r, "APDU transmit failed"); - SC_FUNC_RETURN(card->ctx, 1, sc_sw_to_errorcode(card, apdu.sw1, apdu.sw2)); -} - -int sc_delete_file(struct sc_card *card, int file_id) -{ - int r; - u8 sbuf[2]; - u8 rbuf[SC_MAX_APDU_BUFFER_SIZE]; - struct sc_apdu apdu; - - SC_FUNC_CALLED(card->ctx, 1); - sbuf[0] = (file_id >> 8) & 0xFF; - sbuf[1] = file_id & 0xFF; - sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xE4, 0x00, 0x00); - apdu.lc = 2; - apdu.datalen = 2; - apdu.data = sbuf; - apdu.resplen = sizeof(rbuf); - apdu.resp = rbuf; - - r = sc_transmit_apdu(card, &apdu); - SC_TEST_RET(card->ctx, r, "APDU transmit failed"); - if (apdu.resplen != 0) - SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_ILLEGAL_RESPONSE); - SC_FUNC_RETURN(card->ctx, 1, sc_sw_to_errorcode(card, apdu.sw1, apdu.sw2)); -} - -int sc_file_valid(const struct sc_file *file) -{ - assert(file != NULL); - - return file->magic == SC_FILE_MAGIC; -}