From 06375ec693c2ad3923f811a648c1f050cf942bc8 Mon Sep 17 00:00:00 2001 From: frankmorgner Date: Wed, 28 Apr 2010 13:14:40 +0000 Subject: [PATCH] added support for changing CAN and PIN for PACE git-svn-id: https://vsmartcard.svn.sourceforge.net/svnroot/vsmartcard@83 96b47cad-a561-4643-ad3b-153ac7d7599c --- ccid/ccid.c | 9 ++-- ccid/ccid.h | 3 +- ccid/pace.c | 117 +++++++++++++++++++++++++++++++++++++++++----------- ccid/pace.h | 9 +++- ccid/usb.c | 23 +++++++++-- 5 files changed, 130 insertions(+), 31 deletions(-) diff --git a/ccid/ccid.c b/ccid/ccid.c index 984f484..f38729f 100644 --- a/ccid/ccid.c +++ b/ccid/ccid.c @@ -1308,14 +1308,16 @@ int ccid_state_changed(RDR_to_PC_NotifySlotChange_t **slotchange, int timeout) } #ifdef NO_PACE -int ccid_testpace(u8 pin_id, const char *pin, size_t pinlen) +int ccid_testpace(u8 pin_id, const char *pin, size_t pinlen, + u8 new_pin_id, const char *new_pin, size_t new_pinlen) { sc_error(ctx, "ccid not compiled with support for PACE."); return SC_ERROR_NOT_SUPPORTED; } #else -int ccid_testpace(u8 pin_id, const char *pin, size_t pinlen) +int ccid_testpace(u8 pin_id, const char *pin, size_t pinlen, + u8 new_pin_id, const char *new_pin, size_t new_pinlen) { int i; for (i = 0; i < sizeof *card_in_slot; i++) { @@ -1323,7 +1325,8 @@ int ccid_testpace(u8 pin_id, const char *pin, size_t pinlen) if (!card_in_slot[i] || !sc_card_valid(card_in_slot[i])) { sc_connect_card(reader, i, &card_in_slot[i]); } - return pace_test(card_in_slot[i], pin_id, pin, pinlen); + return pace_test(card_in_slot[i], pin_id, pin, pinlen, + new_pin_id, new_pin, new_pinlen); } } diff --git a/ccid/ccid.h b/ccid/ccid.h index 321d83b..5a510ad 100644 --- a/ccid/ccid.h +++ b/ccid/ccid.h @@ -272,7 +272,8 @@ void ccid_shutdown(); int ccid_parse_bulkin(const __u8* inbuf, __u8** outbuf); int ccid_parse_control(struct usb_ctrlrequest *setup, __u8 **outbuf); int ccid_state_changed(RDR_to_PC_NotifySlotChange_t **slotchange, int timeout); -int ccid_testpace(u8 pin_id, const char *pin, size_t pinlen); +int ccid_testpace(u8 pin_id, const char *pin, size_t pinlen, + u8 new_pin_id, const char *new_pin, size_t new_pinlen); int build_apdu(const __u8 *buf, size_t len, sc_apdu_t *apdu); diff --git a/ccid/pace.c b/ccid/pace.c index 36baf8e..7492e9d 100644 --- a/ccid/pace.c +++ b/ccid/pace.c @@ -151,7 +151,8 @@ inline int EstablishPACEChannel(sc_card_t *card, const __u8 *in, SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_ERROR, SC_ERROR_NOT_SUPPORTED); } int pace_test(sc_card_t *card, - enum s_type pin_id, const char *pin, size_t pinlen) + enum s_type pin_id, const char *pin, size_t pinlen, + enum s_type new_pin_id, const char *new_pin, size_t new_pinlen) { SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_ERROR, SC_ERROR_NOT_SUPPORTED); } @@ -176,6 +177,11 @@ int pace_sm_verify_authentication(sc_card_t *card, struct sm_ctx *ctx, { SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_ERROR, SC_ERROR_NOT_SUPPORTED); } +int pace_change_p(struct sm_ctx *ctx, sc_card_t *card, enum s_type pin_id, + const char *newp, size_t newplen) +{ + SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_ERROR, SC_ERROR_NOT_SUPPORTED); +} #else #include @@ -568,38 +574,62 @@ err: SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_DEBUG, r); } +static int +pace_reset_retry_counter(struct sm_ctx *ctx, sc_card_t *card, + enum s_type pin_id, const char *new, size_t new_len) +{ + sc_apdu_t apdu; + + apdu.cla = 0; + apdu.ins = 0x2C; + apdu.p2 = pin_id; + apdu.data = (u8 *) new; + apdu.datalen = new_len; + apdu.lc = apdu.datalen; + apdu.flags = SC_APDU_FLAGS_NO_GET_RESP|SC_APDU_FLAGS_NO_RETRY_WL; + + if (new_len) { + apdu.p1 = 0x02; + apdu.cse = SC_APDU_CASE_3_SHORT; + } else { + apdu.p1 = 0x03; + apdu.cse = SC_APDU_CASE_1; + } + + return pace_transmit_apdu(ctx, card, &apdu); +} + static PACE_SEC * -get_psec(sc_card_t *card, const char *pin, size_t length_pin, u8 pin_id) +get_psec(sc_card_t *card, const char *pin, size_t length_pin, enum s_type pin_id) { sc_ui_hints_t hints; char *p = NULL; PACE_SEC *r; int sc_result; - size_t len; - if (pin && length_pin) - return PACE_SEC_new(pin, length_pin, pin_id); - - memset(&hints, 0, sizeof(hints)); - hints.dialog_name = "ccid.PACE"; - hints.card = card; - hints.prompt = NULL; - hints.obj_label = pace_secret_name(pin_id); - hints.usage = SC_UI_USAGE_OTHER; - sc_result = sc_ui_get_pin(&hints, &p); - if (sc_result < 0) { - sc_error(card->ctx, "Could not read PACE secret (%s).\n", - sc_strerror(sc_result)); - return NULL; + if (!length_pin || !pin) { + memset(&hints, 0, sizeof(hints)); + hints.dialog_name = "ccid.PACE"; + hints.card = card; + hints.prompt = NULL; + hints.obj_label = pace_secret_name(pin_id); + hints.usage = SC_UI_USAGE_OTHER; + sc_result = sc_ui_get_pin(&hints, &p); + if (sc_result < 0) { + sc_error(card->ctx, "Could not read PACE secret (%s).\n", + sc_strerror(sc_result)); + return NULL; + } + length_pin = strlen(p); + pin = p; } - len = strlen(p); - r = PACE_SEC_new(p, len, pin_id); + r = PACE_SEC_new(pin, length_pin, pin_id); - if (len) { - OPENSSL_cleanse(p, len); + if (p) { + OPENSSL_cleanse(p, length_pin); + free(p); } - free(p); return r; } @@ -854,7 +884,8 @@ const char *pace_secret_name(enum s_type pin_id) { } int pace_test(sc_card_t *card, - enum s_type pin_id, const char *pin, size_t pinlen) + enum s_type pin_id, const char *pin, size_t pinlen, + enum s_type new_pin_id, const char *new_pin, size_t new_pinlen) { u8 buf[0xff + 5]; char *read = NULL; @@ -894,6 +925,12 @@ int pace_test(sc_card_t *card, EstablishPACEChannel(card, buf, &out, &outlen, &sctx), "Could not establish PACE channel."); + if (new_pin_id) { + SC_TEST_RET(card->ctx, + pace_change_p(&sctx, card, new_pin_id, new_pin, new_pinlen), + "Could not change PACE secret."); + } + while (1) { printf("Enter unencrypted APDU (empty line to exit)\n"); @@ -1332,4 +1369,38 @@ int pace_transmit_apdu(struct sm_ctx *ctx, sc_card_t *card, SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_DEBUG, r); } +int pace_change_p(struct sm_ctx *ctx, sc_card_t *card, enum s_type pin_id, + const char *newp, size_t newplen) +{ + sc_ui_hints_t hints; + char *p = NULL; + int r; + + if (!newplen || !newp) { + memset(&hints, 0, sizeof(hints)); + hints.dialog_name = "ccid.PACE"; + hints.card = card; + hints.prompt = NULL; + hints.obj_label = pace_secret_name(pin_id); + hints.usage = SC_UI_USAGE_NEW_PIN; + r = sc_ui_get_pin(&hints, &p); + if (r < 0) { + sc_error(card->ctx, "Could not read new %s (%s).\n", + hints.obj_label, sc_strerror(r)); + SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_ERROR, r); + } + newplen = strlen(p); + newp = p; + } + + r = pace_reset_retry_counter(ctx, card, pin_id, newp, newplen); + + if (p) { + OPENSSL_cleanse(p, newplen); + free(p); + } + + SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_DEBUG, r); +} + #endif diff --git a/ccid/pace.h b/ccid/pace.h index 0b0e1b0..61b0212 100644 --- a/ccid/pace.h +++ b/ccid/pace.h @@ -64,7 +64,14 @@ int GetReadersPACECapabilities(sc_card_t *card, const __u8 int EstablishPACEChannel(sc_card_t *card, const __u8 *in, __u8 **out, size_t *outlen, struct sm_ctx *ctx); int pace_test(sc_card_t *card, - enum s_type pin_id, const char *pin, size_t pinlen); + enum s_type pin_id, const char *pin, size_t pinlen, + enum s_type new_pin_id, const char *new_pin, size_t new_pinlen); +int pace_change_p(struct sm_ctx *ctx, sc_card_t *card, enum s_type pin_id, + const char *newp, size_t newplen); +#define pace_change_pin(ctx, card, newpin, newpinlen) \ + pace_change_p(ctx, card, PACE_PIN, newpin, newpinlen) +#define pace_change_can(ctx, card, newcan, newcanlen) \ + pace_change_p(ctx, card, PACE_CAN, newcan, newcanlen) int pace_transmit_apdu(struct sm_ctx *sctx, sc_card_t *card, sc_apdu_t *apdu); diff --git a/ccid/usb.c b/ccid/usb.c index 39a66af..d2291c7 100644 --- a/ccid/usb.c +++ b/ccid/usb.c @@ -58,6 +58,8 @@ static int dohid = 0; static int doint = 0; static int doinfo = 0; static u8 dopacetest = 0; +static u8 dochangepin = 0; +static const char *newpin = NULL; static int usb_reader_num = -1; static const char *pin = NULL; static const char *cdriver = NULL; @@ -70,6 +72,8 @@ static const char *cdriver = NULL; #define OPT_PUK 'u' #define OPT_CAN 'a' #define OPT_MRZ 'z' +#define OPT_CHANGE_PIN 'I' +#define OPT_CHANGE_CAN 'A' #define OPT_PRODUCT 'p' #define OPT_VENDOR 'e' #define OPT_VERBOSE 'v' @@ -85,6 +89,8 @@ static const struct option options[] = { { "test-puk", optional_argument, NULL, OPT_PUK }, { "test-can", optional_argument, NULL, OPT_CAN }, { "test-mrz", optional_argument, NULL, OPT_MRZ }, + { "new-pin", optional_argument, NULL, OPT_CHANGE_PIN }, + { "new-can", optional_argument, NULL, OPT_CHANGE_CAN }, { "serial", required_argument, NULL, OPT_SERIAL }, { "product", required_argument, NULL, OPT_PRODUCT }, { "vendor", required_argument, NULL, OPT_VENDOR }, @@ -102,6 +108,8 @@ static const char *option_help[] = { "Run PACE with PUK", "Run PACE with CAN", "Run PACE with MRZ", + "Change PIN when PACE is finished", + "Change CAN when PACE is finished", "USB serial number (default: random)", "USB product ID (default: 0x3010)", "USB vendor ID (default: 0x0D46)", @@ -1772,7 +1780,7 @@ main (int argc, char **argv) } while (1) { - c = getopt_long(argc, argv, "hnr:s:i::u::a::z::p:e:voc:", options, &oindex); + c = getopt_long(argc, argv, "hnr:s:i::u::a::z::I::A::p:e:voc:", options, &oindex); if (c == -1) break; switch (c) { @@ -1821,10 +1829,18 @@ main (int argc, char **argv) pin = optarg; break; case OPT_MRZ: - /* PACE_PIN from openssl/pace.h */ + /* PACE_MRZ from openssl/pace.h */ dopacetest = 1; pin = optarg; break; + case OPT_CHANGE_CAN: + dochangepin = 2; + newpin = optarg; + break; + case OPT_CHANGE_PIN: + dochangepin = 3; + newpin = optarg; + break; case '?': /* fall through */ default: @@ -1855,7 +1871,8 @@ main (int argc, char **argv) } if (dopacetest) { - i = ccid_testpace(dopacetest, pin, !pin ? 0 : strlen(pin)); + i = ccid_testpace(dopacetest, pin, !pin ? 0 : strlen(pin), + dochangepin, newpin, !newpin ? 0 : strlen(newpin)); ccid_shutdown(); return i; }