diff --git a/npa/src/card-npa.c b/npa/src/card-npa.c index bb4e79f..f699f6a 100644 --- a/npa/src/card-npa.c +++ b/npa/src/card-npa.c @@ -1,7 +1,7 @@ /* * card-npa.c: Recognize known German identity cards * - * Copyright (C) 2011-2012 Frank Morgner + * Copyright (C) 2011-2014 Frank Morgner * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,6 +20,8 @@ #include "iso-sm-internal.h" #include "libopensc/internal.h" +#include "libopensc/pace.h" +#include #include #ifndef HAVE_SC_APDU_GET_OCTETS @@ -47,7 +49,6 @@ static struct sc_card_driver npa_drv = { NULL, 0, NULL }; - static int npa_match_card(sc_card_t * card) { if (_sc_match_atr(card, npa_atrs, &card->type) < 0) @@ -60,14 +61,96 @@ static int npa_init(sc_card_t * card) card->drv_data = NULL; card->caps |= SC_CARD_CAP_APDU_EXT | SC_CARD_CAP_RNG; -#ifdef ENABLE_SM - card->sm_ctx.ops.get_sm_apdu = iso_get_sm_apdu; - card->sm_ctx.ops.free_sm_apdu = iso_free_sm_apdu; -#endif - return SC_SUCCESS; } +static int npa_pin_cmd(struct sc_card *card, struct sc_pin_cmd_data *data, int *tries_left) +{ + struct establish_pace_channel_input pace_input; + struct establish_pace_channel_output pace_output; + int r; + + memset(&pace_input, 0, sizeof pace_input); + memset(&pace_output, 0, sizeof pace_output); + + if (!data) { + r = SC_ERROR_INVALID_ARGUMENTS; + goto err; + } + + if (data->pin_type != SC_AC_CHV) { + r = SC_ERROR_NOT_SUPPORTED; + goto err; + } + + if (tries_left) + *tries_left = -1; + + if (data->cmd != SC_PIN_CMD_UNBLOCK + && data->cmd != SC_PIN_CMD_VERIFY + && data->cmd != SC_PIN_CMD_CHANGE) { + /* TODO support SC_PIN_CMD_GET_INFO */ + r = SC_ERROR_NOT_SUPPORTED; + goto err; + } + + pace_input.pin_id = data->pin_reference; + pace_input.pin = data->pin1.data; + pace_input.pin_length = data->pin1.len; + + if (data->cmd == SC_PIN_CMD_UNBLOCK) { + /* FIXME SC_PIN_CMD_UNBLOCK is currently overloaded with the resume + * command. Iff the first secret has the length of a CAN (6) we are + * resuming the PIN with the CAN. Otherwise we will unblock the PIN + * with PUK. */ + if (pace_input.pin_length == CAN_LEN) { + /* Try to resume the PIN with the CAN. */ + pace_input.pin_id = PACE_PIN_ID_CAN; + r = perform_pace(card, pace_input, &pace_output, 2); + if (r != SC_SUCCESS) + goto err; + + /* Initialize pace_input for usage with the intended PIN */ + pace_input.pin_id = data->pin_reference; + pace_input.pin = data->pin2.data; + pace_input.pin_length = data->pin2.len; + } else { + /* Initialize pace_input for usage with the PUK */ + pace_input.pin_id = PACE_PIN_ID_PUK; + } + } + + r = perform_pace(card, pace_input, &pace_output, 2); + if (r != SC_SUCCESS) + goto err; + + if (pace_output.mse_set_at_sw1 == 0x63) { + if ((pace_output.mse_set_at_sw2 & 0xF0) == 0xC0 && tries_left != NULL) + *tries_left = pace_output.mse_set_at_sw2 & 0x0F; + if (*tries_left > 0 && r != SC_SUCCESS) + *tries_left = *tries_left - 1; + } + + switch (data->cmd) { + case SC_PIN_CMD_UNBLOCK: + if (pace_input.pin_length != CAN_LEN) { + r = npa_unblock_pin(card); + if (r != SC_SUCCESS) + goto err; + } + break; + case SC_PIN_CMD_CHANGE: + r = npa_reset_retry_counter(card, data->pin_reference, 1, + (const char *) data->pin2.data, data->pin2.len); + if (r != SC_SUCCESS) + goto err; + break; + } + +err: + SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r); +} + static struct sc_card_driver *npa_get_driver(void) { struct sc_card_driver *iso_drv = sc_get_iso7816_driver(); @@ -75,6 +158,7 @@ static struct sc_card_driver *npa_get_driver(void) npa_ops = *iso_drv->ops; npa_ops.match_card = npa_match_card; npa_ops.init = npa_init; + npa_ops.pin_cmd = npa_pin_cmd; return &npa_drv; } diff --git a/npa/src/iso-sm.c b/npa/src/iso-sm.c index 4d12f50..da1bd7f 100644 --- a/npa/src/iso-sm.c +++ b/npa/src/iso-sm.c @@ -20,6 +20,8 @@ #include "config.h" #endif +#ifdef ENABLE_SM + #include "iso-sm-internal.h" #include #include @@ -731,3 +733,36 @@ int sm_stop(struct sc_card *card) return r; } + +#else + +int iso_sm_close(struct sc_card *card) +{ + return SC_ERROR_NOT_SUPPORTED; +} + +int iso_get_sm_apdu(struct sc_card *card, struct sc_apdu *apdu, struct sc_apdu **sm_apdu) +{ + return SC_ERROR_NOT_SUPPORTED; +} + +struct iso_sm_ctx *iso_sm_ctx_create(void) +{ + return NULL; +} + +void iso_sm_ctx_clear_free(struct iso_sm_ctx *sctx) +{ +} + +int iso_sm_start(struct sc_card *card, struct iso_sm_ctx *sctx) +{ + return SC_ERROR_NOT_SUPPORTED; +} + +int sm_stop(struct sc_card *card) +{ + return SC_ERROR_NOT_SUPPORTED; +} + +#endif diff --git a/npa/src/npa/npa.h b/npa/src/npa/npa.h index d1a64d3..a2eba16 100644 --- a/npa/src/npa/npa.h +++ b/npa/src/npa/npa.h @@ -94,6 +94,8 @@ extern "C" { #define MAX_PIN_LEN 6 /** @brief Minimum length of PIN */ #define MIN_PIN_LEN 6 +/** @brief Length of CAN */ +#define CAN_LEN 6 /** @brief Minimum length of MRZ */ #define MAX_MRZ_LEN 128