From 7e0b4c15942c50351bf46fa0001cb1e4b119c360 Mon Sep 17 00:00:00 2001 From: frankmorgner Date: Thu, 15 Apr 2010 18:37:03 +0000 Subject: [PATCH] - added information about opensc - using sc_transmit_apdu instead of my_transmit_apdu. fixing the opensc error is the better solution than implementing it twice (see http://www.opensc-project.org/opensc/ticket/209) git-svn-id: https://vsmartcard.svn.sourceforge.net/svnroot/vsmartcard@75 96b47cad-a561-4643-ad3b-153ac7d7599c --- ccid/Makefile | 1 - ccid/README | 15 ++- ccid/apdu.c | 317 -------------------------------------------------- ccid/apdu.h | 20 ---- ccid/pace.c | 3 +- ccid/sm.c | 3 +- 6 files changed, 14 insertions(+), 345 deletions(-) delete mode 100644 ccid/apdu.c delete mode 100644 ccid/apdu.h diff --git a/ccid/Makefile b/ccid/Makefile index 36bc8ea..7872a6a 100644 --- a/ccid/Makefile +++ b/ccid/Makefile @@ -24,7 +24,6 @@ TARGETS = ccid CCID_SRC = ccid.h ccid.c \ sm.c sm.h \ pace.h pace.c pace_lib.c \ - apdu.h apdu.c \ usbstring.c usbstring.h usb.c # top-level rule diff --git a/ccid/README b/ccid/README index 4e29dd4..4afdb7c 100644 --- a/ccid/README +++ b/ccid/README @@ -13,8 +13,9 @@ ccid has support for Password Authenticated Connection Establishment (PACE) using OpenPACE (see http://sourceforge.net/projects/openpace/). PACE is experimental and disabled by default. See file INSTALL how to compile it. -ccid is implemented using GadgetFS. The source code is based on the GadgetFS -example at http://www.linux-usb.org/gadget/. +ccid is implemented using GadgetFS. Some fragments of the source code is based +on the GadgetFS example at http://www.linux-usb.org/gadget/ and on the source +code of the OpenSC tools. INSTALLATION @@ -39,8 +40,17 @@ https://docs.openmoko.org/trac/ticket/2240). If you only use PACE for testing your card, you don't need gadgetfs. +HINTS ON OPENSC +----------------- + +If ccid runs into a checking error, because the Le field of the APDU is 0 (as +set for the General Authenticate APDU during PACE), you need to patch libopensc +(see http://www.opensc-project.org/opensc/ticket/209) + + USAGE ----- + When testing PACE with either PIN, CAN, MRZ or PUK, the program will be in interactive mode. Here you can enter APDUs which are to be converted according to the secure messaging parameter and to be sent to the card. Herefor insert @@ -50,7 +60,6 @@ the current selected file both of these forms would be valid: 00B0020000 - QUESTIONS --------- diff --git a/ccid/apdu.c b/ccid/apdu.c deleted file mode 100644 index e3f4368..0000000 --- a/ccid/apdu.c +++ /dev/null @@ -1,317 +0,0 @@ -/* - * apdu.c: basic APDU handling functions - * - * Copyright (C) 2005 Nils Larsch - * - * 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 "apdu.h" -#include -#include -#include - - -/*********************************************************************/ -/* higher level APDU transfer handling functions */ -/*********************************************************************/ -/* +------------------+ - * | sc_transmit_apdu | - * +------------------+ - * | | - * | | detect APDU cse +--------------------+ - * | +---------------------------------> | sc_detect_apdu_cse | - * | +--------------------+ - * | - * | - * | - * | send single APDU +--------------------+ - * +---------------------------------------> | do_single_transmit | - * ^ +--------------------+ - * | | - * | re-transmit if wrong length | - * | or GET RESPONSE | - * +-------------------------------+ - * | - * v - * card->reader->ops->tranmit - */ - - -#ifndef _WIN32 -#include -#define msleep(t) usleep((t) * 1000) -#else -#define msleep(t) Sleep(t) -#define sleep(t) Sleep((t) * 1000) -#endif - - -/** Tries to determine the APDU type (short or extended) of the supplied - * APDU if one of the SC_APDU_CASE_? types is used. - * @param apdu APDU object - */ -static void sc_detect_apdu_cse(const sc_card_t *card, sc_apdu_t *apdu) -{ - if (apdu->cse == SC_APDU_CASE_2 || apdu->cse == SC_APDU_CASE_3 || - apdu->cse == SC_APDU_CASE_4) { - int btype = apdu->cse & SC_APDU_SHORT_MASK; - /* if either Lc or Le is bigger than the maximun for - * short APDUs and the card supports extended APDUs - * use extended APDUs (unless Lc is greater than - * 255 and command chaining is activated) */ - if ((apdu->le > 256 || (apdu->lc > 255 && (apdu->flags & SC_APDU_FLAGS_CHAINING) == 0)) && - (card->caps & SC_CARD_CAP_APDU_EXT) != 0) - btype |= SC_APDU_EXT; - apdu->cse = btype; - } -} - - -/** Sends a single APDU to the card reader and calls - * GET RESPONSE to get the return data if necessary. - * @param card sc_card_t object for the smartcard - * @param apdu APDU to be send - * @return SC_SUCCESS on success and an error value otherwise - */ -static int do_single_transmit(sc_card_t *card, sc_apdu_t *apdu) -{ - int r; - size_t olen = apdu->resplen; - sc_context_t *ctx = card->ctx; - - /* XXX: insert secure messaging here (?), i.e. something like - if (card->sm_ctx->use_sm != 0) { - r = card->ops->sm_transform(...); - if (r != SC_SUCCESS) - ... - r = sc_check_apdu(...); - if (r != SC_SUCCESS) - ... - } - */ - - /* send APDU to the reader driver */ - if (card->reader->ops->transmit == NULL) - return SC_ERROR_NOT_SUPPORTED; - r = card->reader->ops->transmit(card->reader, card->slot, apdu); - if (r != 0) { - sc_error(ctx, "unable to transmit APDU"); - return r; - } - /* ok, the APDU was successfully transmitted. Now we have two - * special cases: - * 1. the card returned 0x6Cxx: in this case we re-trasmit the APDU - * wit hLe set to SW2 (this is course only possible if the - * response buffer size is larger than the new Le = SW2) - */ - if (apdu->sw1 == 0x6C && (apdu->flags & SC_APDU_FLAGS_NO_RETRY_WL) == 0) { - size_t nlen = apdu->sw2 != 0 ? (size_t)apdu->sw2 : 256; - if (olen >= nlen) { - /* don't try again if it doesn't work this time */ - apdu->flags |= SC_APDU_FLAGS_NO_GET_RESP; - /* set the new expected length */ - apdu->resplen = olen; - apdu->le = nlen; - /* as some reader/smartcards can't handle an immediate - * re-transmit so we optionally need to sleep for - * a while */ - if (card->wait_resend_apdu != 0) - msleep(card->wait_resend_apdu); - /* re-transmit the APDU with new Le length */ - r = card->reader->ops->transmit(card->reader, card->slot, apdu); - if (r != SC_SUCCESS) { - sc_error(ctx, "unable to transmit APDU"); - return r; - } - } else { - /* we cannot re-transmit the APDU with the demanded - * Le value as the buffer is too small => error */ - sc_debug(ctx, "wrong length: required length exceeds resplen"); - return SC_ERROR_WRONG_LENGTH; - } - } - - /* 2. the card returned 0x61xx: more data can be read from the card - * using the GET RESPONSE command (mostly used in the T0 protocol). - * Unless the SC_APDU_FLAGS_NO_GET_RESP is set we try to read as - * much data as possible using GET RESPONSE. - */ - if (apdu->sw1 == 0x61 && (apdu->flags & SC_APDU_FLAGS_NO_GET_RESP) == 0) { - if (apdu->le == 0) { - /* no data is requested => change return value to - * 0x9000 and ignore the remaining data */ - /* FIXME: why not return 0x61xx ? It's not an - * error */ - apdu->sw1 = 0x90; - apdu->sw2 = 0x00; - - } else { - /* call GET RESPONSE until we have read all data - * requested or until the card retuns 0x9000, - * whatever happens first. - */ - size_t le, minlen, buflen; - u8 *buf; - - if (card->ops->get_response == NULL) { - /* this should _never_ happen */ - sc_error(ctx, "no GET RESPONSE command\n"); - return SC_ERROR_NOT_SUPPORTED; - } - - /* if the command already returned some data - * append the new data to the end of the buffer - */ - buf = apdu->resp + apdu->resplen; - - /* read as much data as fits in apdu->resp (i.e. - * max(apdu->resplen, amount of data available)). - */ - buflen = olen - apdu->resplen; - - /* 0x6100 means at least 256 more bytes to read */ - le = apdu->sw2 != 0 ? (size_t)apdu->sw2 : 256; - /* we try to read at least as much as bytes as - * promised in the response bytes */ - minlen = le; - - do { - u8 tbuf[256]; - /* call GET RESPONSE to get more date from - * the card; note: GET RESPONSE returns the - * amount of data left (== SW2) */ - r = card->ops->get_response(card, &le, tbuf); - if (r < 0) - SC_FUNC_RETURN(ctx, 2, r); - - if (buflen < le) - return SC_ERROR_WRONG_LENGTH; - - memcpy(buf, tbuf, le); - buf += le; - buflen -= le; - - minlen -= le; - if (r != 0) - le = minlen = (size_t)r; - else - /* if the card has returned 0x9000 but - * we still expect data ask for more - * until we have read enough bytes */ - le = minlen; - } while (r != 0 || minlen != 0); - /* we've read all data, let's return 0x9000 */ - apdu->resplen = buf - apdu->resp; - apdu->sw1 = 0x90; - apdu->sw2 = 0x00; - } - } - - return SC_SUCCESS; -} - -int my_transmit_apdu(sc_card_t *card, sc_apdu_t *apdu) -{ - int r = SC_SUCCESS; - - if (card == NULL || apdu == NULL) - return SC_ERROR_INVALID_ARGUMENTS; - - SC_FUNC_CALLED(card->ctx, 4); - - /* determine the APDU type if necessary, i.e. to use - * short or extended APDUs */ - sc_detect_apdu_cse(card, apdu); - /* basic APDU consistency check */ - /*r = sc_check_apdu(card, apdu);*/ - if (r != SC_SUCCESS) - return SC_ERROR_INVALID_ARGUMENTS; - - r = sc_lock(card); /* acquire card lock*/ - if (r != SC_SUCCESS) { - sc_error(card->ctx, "unable to acquire lock"); - return r; - } - - if ((apdu->flags & SC_APDU_FLAGS_CHAINING) != 0) { - /* divide et impera: transmit APDU in chunks with Lc < 255 - * bytes using command chaining */ - size_t len = apdu->datalen; - const u8 *buf = apdu->data; - - while (len != 0) { - size_t plen; - sc_apdu_t tapdu; - int last = 0; - - tapdu = *apdu; - /* clear chaining flag */ - tapdu.flags &= ~SC_APDU_FLAGS_CHAINING; - if (len > 255) { - /* adjust APDU case: in case of CASE 4 APDU - * the intermediate APDU are of CASE 3 */ - if ((tapdu.cse & SC_APDU_SHORT_MASK) == SC_APDU_CASE_4_SHORT) - tapdu.cse--; - /* XXX: the chunk size must be adjusted when - * secure messaging is used */ - plen = 255; - tapdu.cla |= 0x10; - tapdu.le = 0; - /* the intermediate APDU don't expect data */ - tapdu.lc = 0; - tapdu.resplen = 0; - tapdu.resp = NULL; - } else { - plen = len; - last = 1; - } - tapdu.data = buf; - tapdu.datalen = tapdu.lc = plen; - - /*r = sc_check_apdu(card, &tapdu);*/ - if (r != SC_SUCCESS) { - sc_error(card->ctx, "inconsistent APDU while chaining"); - break; - } - - r = do_single_transmit(card, &tapdu); - if (r != SC_SUCCESS) - break; - if (last != 0) { - /* in case of the last APDU set the SW1 - * and SW2 bytes in the original APDU */ - apdu->sw1 = tapdu.sw1; - apdu->sw2 = tapdu.sw2; - apdu->resplen = tapdu.resplen; - } else { - /* otherwise check the status bytes */ - r = sc_check_sw(card, tapdu.sw1, tapdu.sw2); - if (r != SC_SUCCESS) - break; - } - len -= plen; - buf += plen; - } - } else - /* transmit single APDU */ - r = do_single_transmit(card, apdu); - /* all done => release lock */ - if (sc_unlock(card) != SC_SUCCESS) - sc_error(card->ctx, "sc_unlock failed"); - - return r; -} - diff --git a/ccid/apdu.h b/ccid/apdu.h deleted file mode 100644 index 178c978..0000000 --- a/ccid/apdu.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef _CCID_APDU_H -#define _CCID_APDU_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -/** Sends a APDU to the card - * @param card sc_card_t object to which the APDU should be send - * @param apdu sc_apdu_t object of the APDU to be send - * @return SC_SUCCESS on succcess and an error code otherwise - */ -int my_transmit_apdu(sc_card_t *card, sc_apdu_t *apdu); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/ccid/pace.c b/ccid/pace.c index ed3f9a5..28858ef 100644 --- a/ccid/pace.c +++ b/ccid/pace.c @@ -188,7 +188,6 @@ int pace_sm_verify_authentication(sc_card_t *card, struct sm_ctx *ctx, #include #include #include -#include "apdu.h" const size_t maxresp = SC_MAX_APDU_BUFFER_SIZE - 2; @@ -452,7 +451,7 @@ static int pace_gen_auth(sc_card_t *card, /* sanity checks in sc_transmit_apdu forbid case 4 apdus with le == 0 */ apdu.resplen = maxresp; apdu.resp = malloc(apdu.resplen); - r = my_transmit_apdu(card, &apdu); + r = sc_transmit_apdu(card, &apdu); if (r < 0) goto err; diff --git a/ccid/sm.c b/ccid/sm.c index c4267c3..1098ef0 100644 --- a/ccid/sm.c +++ b/ccid/sm.c @@ -17,7 +17,6 @@ * ccid. If not, see . */ #include "sm.h" -#include "apdu.h" #include #include #include @@ -575,7 +574,7 @@ int sm_transmit_apdu(const struct sm_ctx *sctx, sc_card_t *card, SC_TEST_RET(card->ctx, sm_encrypt(sctx, card, apdu, &sm_apdu), "Could not encrypt APDU."); - SC_TEST_RET(card->ctx, my_transmit_apdu(card, &sm_apdu), + SC_TEST_RET(card->ctx, sc_transmit_apdu(card, &sm_apdu), "Could not transmit SM APDU."); SC_TEST_RET(card->ctx, sm_decrypt(sctx, card, &sm_apdu, apdu), "Could not decrypt APDU.");