implemented npa_pin_cmd
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* card-npa.c: Recognize known German identity cards
|
* card-npa.c: Recognize known German identity cards
|
||||||
*
|
*
|
||||||
* Copyright (C) 2011-2012 Frank Morgner <morgner@informatik.hu-berlin.de>
|
* Copyright (C) 2011-2014 Frank Morgner <morgner@informatik.hu-berlin.de>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
@@ -20,6 +20,8 @@
|
|||||||
|
|
||||||
#include "iso-sm-internal.h"
|
#include "iso-sm-internal.h"
|
||||||
#include "libopensc/internal.h"
|
#include "libopensc/internal.h"
|
||||||
|
#include "libopensc/pace.h"
|
||||||
|
#include <npa/npa.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#ifndef HAVE_SC_APDU_GET_OCTETS
|
#ifndef HAVE_SC_APDU_GET_OCTETS
|
||||||
@@ -47,7 +49,6 @@ static struct sc_card_driver npa_drv = {
|
|||||||
NULL, 0, NULL
|
NULL, 0, NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static int npa_match_card(sc_card_t * card)
|
static int npa_match_card(sc_card_t * card)
|
||||||
{
|
{
|
||||||
if (_sc_match_atr(card, npa_atrs, &card->type) < 0)
|
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->drv_data = NULL;
|
||||||
card->caps |= SC_CARD_CAP_APDU_EXT | SC_CARD_CAP_RNG;
|
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;
|
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)
|
static struct sc_card_driver *npa_get_driver(void)
|
||||||
{
|
{
|
||||||
struct sc_card_driver *iso_drv = sc_get_iso7816_driver();
|
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 = *iso_drv->ops;
|
||||||
npa_ops.match_card = npa_match_card;
|
npa_ops.match_card = npa_match_card;
|
||||||
npa_ops.init = npa_init;
|
npa_ops.init = npa_init;
|
||||||
|
npa_ops.pin_cmd = npa_pin_cmd;
|
||||||
|
|
||||||
return &npa_drv;
|
return &npa_drv;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,8 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef ENABLE_SM
|
||||||
|
|
||||||
#include "iso-sm-internal.h"
|
#include "iso-sm-internal.h"
|
||||||
#include <libopensc/asn1.h>
|
#include <libopensc/asn1.h>
|
||||||
#include <libopensc/log.h>
|
#include <libopensc/log.h>
|
||||||
@@ -731,3 +733,36 @@ int sm_stop(struct sc_card *card)
|
|||||||
|
|
||||||
return r;
|
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
|
||||||
|
|||||||
@@ -94,6 +94,8 @@ extern "C" {
|
|||||||
#define MAX_PIN_LEN 6
|
#define MAX_PIN_LEN 6
|
||||||
/** @brief Minimum length of PIN */
|
/** @brief Minimum length of PIN */
|
||||||
#define MIN_PIN_LEN 6
|
#define MIN_PIN_LEN 6
|
||||||
|
/** @brief Length of CAN */
|
||||||
|
#define CAN_LEN 6
|
||||||
/** @brief Minimum length of MRZ */
|
/** @brief Minimum length of MRZ */
|
||||||
#define MAX_MRZ_LEN 128
|
#define MAX_MRZ_LEN 128
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user