no 'pace' in common part

'PACE' is extremely card specific protocol and has not to be ostensibly
present in the common part of OpenSC:
 * currently in OpenSC there is no card driver that supports or uses this protocol;
 * amazing content of the common 'sc_perform_pace' -- beside the verbose logs
   the only substantial action is to call the card/reader specific handler.
   According to the current sources and the pull request 83
   this 'common' procedure is called by the card driver or
   card specific tool/operation.
 * currently the 'PACE' can be thouroghly tested only by one person (Frank Morgner),
   and only using the OpenSSL patched with the PACE specific patch.
   So, at least a dedicated configuration option could be introduced when comiting PACE to the common part.
 * common 'sc_perfom_pace' has the same role as the 'initialize-SM' handler of the existing SM framework
   and can be implemented as card specific SM, as the others cards do.
   This confirmed by Frank Morgner, the author of PACE commits and nPA card driver, himself.
   (https://github.com/OpenSC/OpenSC/pull/83)
This commit is contained in:
Viktor Tarasov 2012-08-26 11:16:30 +02:00
parent 7c39aeefb9
commit 41861e42b0
8 changed files with 124 additions and 199 deletions

View File

@ -475,22 +475,6 @@
</listitem>
</varlistentry>
<varlistentry>
<term>
<command>pace</command> <replaceable>secret-type</replaceable> [<replaceable>secret</replaceable>]
</term>
<listitem><para>Perform PACE with the card. <replaceable>secret-type</replaceable>
can be one of pin, can, puk or mrz. <replaceable>secret</replaceable> is the secret to be verified as string.
</para>
<para>
If <replaceable>secret</replaceable> is omitted, the secret will be verified with the PIN-Pad.
</para>
<para>
Example: pace can 123456
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
</refsect1>

View File

@ -10,7 +10,8 @@ noinst_HEADERS = cards.h ctbcs.h internal.h esteid.h muscle.h muscle-filesystem.
opensc.h pkcs15.h \
cardctl.h asn1.h log.h \
errors.h types.h compression.h itacns.h iso7816.h \
authentic.h iasecc.h iasecc-sdo.h sm.h card-sc-hsm.h
authentic.h iasecc.h iasecc-sdo.h sm.h card-sc-hsm.h \
pace.h
AM_CPPFLAGS = -DOPENSC_CONF_PATH=\"$(sysconfdir)/opensc.conf\"
AM_CFLAGS = $(OPTIONAL_OPENSSL_CFLAGS) $(OPTIONAL_OPENCT_CFLAGS) \

View File

@ -302,7 +302,6 @@ sc_remote_data_init
sc_crc32
sc_pkcs15_convert_prkey
sc_pkcs15_convert_pubkey
sc_perform_pace
iasecc_sdo_encode_update_field
iasecc_sm_create_file
iasecc_sm_delete_file

View File

@ -330,7 +330,7 @@ struct sc_pin_cmd_pin {
u8 pad_char;
size_t offset; /* PIN offset in the APDU */
size_t length_offset; /* Effective PIN length offset in the APDU */
int max_tries; /* Used for signaling back from SC_PIN_CMD_GET_INFO */
int tries_left; /* Used for signaling back from SC_PIN_CMD_GET_INFO */
@ -349,7 +349,7 @@ struct sc_pin_cmd_data {
struct sc_apdu *apdu; /* APDU of the PIN command */
};
#if 0
#define PACE_PIN_ID_MRZ 0x01
#define PACE_PIN_ID_CAN 0x02
#define PACE_PIN_ID_PIN 0x03
@ -414,6 +414,7 @@ struct establish_pace_channel_output {
/** PCD identifier */
unsigned char *id_pcd;
};
#endif
struct sc_reader_operations {
/* Called during sc_establish_context(), when the driver
@ -442,11 +443,12 @@ struct sc_reader_operations {
int (*display_message)(struct sc_reader *, const char *);
int (*perform_verify)(struct sc_reader *, struct sc_pin_cmd_data *);
int (*perform_pace)(struct sc_reader *reader,
struct establish_pace_channel_input *,
struct establish_pace_channel_output *);
void *establish_pace_channel_input,
void *establish_pace_channel_output);
/* Wait for an event */
int (*wait_for_event)(struct sc_context *ctx, unsigned int event_mask, sc_reader_t **event_reader, unsigned int *event,
int (*wait_for_event)(struct sc_context *ctx, unsigned int event_mask,
sc_reader_t **event_reader, unsigned int *event,
int timeout, void **reader_states);
/* Reset a reader */
int (*reset)(struct sc_reader *, int);
@ -1294,10 +1296,6 @@ extern const char *sc_get_version(void);
extern sc_card_driver_t *sc_get_iso7816_driver(void);
int sc_perform_pace(sc_card_t *card,
struct establish_pace_channel_input *pace_input,
struct establish_pace_channel_output *pace_output);
#ifdef __cplusplus
}
#endif

107
src/libopensc/pace.h Normal file
View File

@ -0,0 +1,107 @@
/*
* opensc.h: PACE library header file
*
* Copyright (C) ???? Frank Morgner <morgner@informatik.hu-berlin.de>
*
* 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
*/
#ifndef _PACE_H
#define _PACE_H
#include <stdio.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
#include "libopensc/opensc.h"
#ifdef ENABLE_SM
#include "libopensc/sm.h"
#endif
#define PACE_PIN_ID_MRZ 0x01
#define PACE_PIN_ID_CAN 0x02
#define PACE_PIN_ID_PIN 0x03
#define PACE_PIN_ID_PUK 0x04
/**
* Input data for EstablishPACEChannel()
*/
struct establish_pace_channel_input {
/** Type of secret (CAN, MRZ, PIN or PUK). */
unsigned char pin_id;
/** Length of \a chat */
size_t chat_length;
/** Card holder authorization template */
const unsigned char *chat;
/** Length of \a pin */
size_t pin_length;
/** Secret */
const unsigned char *pin;
/** Length of \a certificate_description */
size_t certificate_description_length;
/** Certificate description */
const unsigned char *certificate_description;
};
/**
* Output data for EstablishPACEChannel()
*/
struct establish_pace_channel_output {
/** PACE result (TR-03119) */
unsigned int result;
/** MSE: Set AT status byte */
unsigned char mse_set_at_sw1;
/** MSE: Set AT status byte */
unsigned char mse_set_at_sw2;
/** Length of \a ef_cardaccess */
size_t ef_cardaccess_length;
/** EF.CardAccess */
unsigned char *ef_cardaccess;
/** Length of \a recent_car */
size_t recent_car_length;
/** Most recent certificate authority reference */
unsigned char *recent_car;
/** Length of \a previous_car */
size_t previous_car_length;
/** Previous certificate authority reference */
unsigned char *previous_car;
/** Length of \a id_icc */
size_t id_icc_length;
/** ICC identifier */
unsigned char *id_icc;
/** Length of \a id_pcd */
size_t id_pcd_length;
/** PCD identifier */
unsigned char *id_pcd;
};
#ifdef __cplusplus
}
#endif
#endif

View File

@ -37,6 +37,8 @@
#include "internal.h"
#include "internal-winscard.h"
#include "pace.h"
/* Logging */
#define PCSC_TRACE(reader, desc, rv) do { sc_log(reader->ctx, "%s:" desc ": 0x%08lx\n", reader->name, rv); } while (0)
#define PCSC_LOG(ctx, desc, rv) do { sc_log(ctx, desc ": 0x%08lx\n", rv); } while (0)
@ -1898,13 +1900,15 @@ static int transform_pace_output(u8 *rbuf, size_t rbuflen,
return SC_SUCCESS;
}
static int pcsc_perform_pace(struct sc_reader *reader,
struct establish_pace_channel_input *pace_input,
struct establish_pace_channel_output *pace_output)
static int
pcsc_perform_pace(struct sc_reader *reader, void *input_pace, void *output_pace)
{
struct establish_pace_channel_input *pace_input = (struct establish_pace_channel_input *) input_pace;
struct establish_pace_channel_output *pace_output = (struct establish_pace_channel_output *) output_pace;
struct pcsc_private_data *priv;
u8 rbuf[SC_MAX_EXT_APDU_BUFFER_SIZE], sbuf[SC_MAX_EXT_APDU_BUFFER_SIZE];
size_t rcount = sizeof rbuf, scount = sizeof sbuf;
size_t rcount = sizeof rbuf, scount = sizeof sbuf;
if (!reader || !reader->capabilities & SC_READER_CAP_PACE_GENERIC)
return SC_ERROR_INVALID_ARGUMENTS;

View File

@ -279,127 +279,3 @@ int sc_build_pin(u8 *buf, size_t buflen, struct sc_pin_cmd_pin *pin, int pad)
return i;
}
int sc_perform_pace(sc_card_t *card,
struct establish_pace_channel_input *pace_input,
struct establish_pace_channel_output *pace_output)
{
int r = SC_ERROR_NOT_SUPPORTED;
u8 buf[0xffff];
assert(card != NULL && pace_input != NULL && pace_output != NULL);
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_NORMAL);
switch (pace_input->pin_id) {
case PACE_PIN_ID_MRZ:
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Initiating PACE with MRZ");
break;
case PACE_PIN_ID_CAN:
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Initiating PACE with CAN");
break;
case PACE_PIN_ID_PIN:
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Initiating PACE with PIN");
break;
case PACE_PIN_ID_PUK:
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Initiating PACE with PUK");
break;
default:
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Initiating PACE with unknown PACE secret type");
break;
}
if (pace_input->chat_length) {
sc_hex_dump(card->ctx, SC_LOG_DEBUG_NORMAL,
pace_input->chat,
pace_input->chat_length, buf, sizeof buf);
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,
"CHAT (%d bytes):\n%s",
pace_input->chat_length, buf);
} else {
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,
"CHAT (0 bytes)");
}
if (pace_input->certificate_description_length) {
sc_hex_dump(card->ctx, SC_LOG_DEBUG_NORMAL,
pace_input->certificate_description,
pace_input->certificate_description_length, buf, sizeof buf);
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,
"Certificate description (%d bytes):\n%s",
pace_input->certificate_description_length, buf);
} else {
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,
"Certificate description (0 bytes)");
}
if (card->reader
&& card->reader->ops
&& card->reader->ops->perform_pace
&& card->reader->capabilities & SC_READER_CAP_PACE_GENERIC) {
r = card->reader->ops->perform_pace(card->reader, pace_input,
pace_output);
} else {
/* TODO Add EstablishPACEChannel using a normal reader here */
/* see for example http://vsmartcard.sourceforge.net/npa/README.html */
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "PACE currently only supported via reader.");
}
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE,
"EstablishPACEChannel Result is 0x%08X",
pace_output->result);
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,
"MSE:Set AT Statusbytes: %02X %02X",
pace_output->mse_set_at_sw1, pace_output->mse_set_at_sw2);
if (pace_output->ef_cardaccess_length) {
sc_hex_dump(card->ctx, SC_LOG_DEBUG_NORMAL,
pace_output->ef_cardaccess,
pace_output->ef_cardaccess_length, buf, sizeof buf);
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,
"EF.CardAccess (%d bytes):\n%s",
pace_output->ef_cardaccess_length, buf);
} else {
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,
"EF.CardAccess (0 bytes)");
}
if (pace_output->recent_car_length) {
sc_hex_dump(card->ctx, SC_LOG_DEBUG_NORMAL,
pace_output->recent_car,
pace_output->recent_car_length, buf, sizeof buf);
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,
"Most recent certificate authority reference (%d bytes):\n%s",
pace_output->recent_car_length, buf);
} else {
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,
"Most recent certificate authority reference (0 bytes)");
}
if (pace_output->previous_car_length) {
sc_hex_dump(card->ctx, SC_LOG_DEBUG_NORMAL,
pace_output->previous_car,
pace_output->previous_car_length, buf, sizeof buf);
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,
"Previous certificate authority reference (%d bytes):\n%s",
pace_output->previous_car_length, buf);
} else {
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,
"Previous certificate authority reference (0 bytes)");
}
if (pace_output->id_icc_length) {
sc_hex_dump(card->ctx, SC_LOG_DEBUG_NORMAL,
pace_output->id_icc,
pace_output->id_icc_length, buf, sizeof buf);
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,
"Ephemeral PACE public key of the ICC (ID ICC, %d bytes):\n%s",
pace_output->id_icc_length, buf);
} else {
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,
"Ephemeral PACE public key of the ICC (ID ICC, 0 bytes)");
}
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
}

View File

@ -92,7 +92,6 @@ static int do_create(int argc, char **argv);
static int do_mkdir(int argc, char **argv);
static int do_delete(int argc, char **argv);
static int do_verify(int argc, char **argv);
static int do_pace(int argc, char **argv);
static int do_change(int argc, char **argv);
static int do_unblock(int argc, char **argv);
static int do_get(int argc, char **argv);
@ -151,9 +150,6 @@ static struct command cmds[] = {
{ do_verify,
"verify", "{CHV|KEY|AUT|PRO}<key ref> [<pin>]",
"present a PIN or key to the card" },
{ do_pace,
"pace", "{pin|can|puk|mrz} [<secret>]",
"Establish a PACE channel" },
{ do_change,
"change", "CHV<pin ref> [[<old pin>] <new pin>]",
"change a PIN" },
@ -1032,46 +1028,6 @@ static int do_verify(int argc, char **argv)
return 0;
}
static int do_pace(int argc, char **argv)
{
int r;
struct establish_pace_channel_input pace_input;
struct establish_pace_channel_output pace_output;
memset(&pace_input, 0, sizeof(pace_input));
memset(&pace_output, 0, sizeof(pace_output));
switch (argc) {
case 2:
pace_input.pin = (unsigned char *) argv[1];
/* fall through */
case 1:
if (strcasecmp(argv[0], "pin") == 0)
pace_input.pin_id = PACE_PIN_ID_PIN;
else if (strcasecmp(argv[0], "puk") == 0)
pace_input.pin_id = PACE_PIN_ID_PUK;
else if (strcasecmp(argv[0], "can") == 0)
pace_input.pin_id = PACE_PIN_ID_CAN;
else if (strcasecmp(argv[0], "mrz") == 0)
pace_input.pin_id = PACE_PIN_ID_MRZ;
else
return usage(do_pace);
break;
default:
return usage(do_pace);
}
r = sc_perform_pace(card, &pace_input, &pace_output);
if (r) {
printf("PACE failed: %s\n", sc_strerror(r));
return -1;
}
printf("Established PACE channel.\n");
return 0;
}
static int do_change(int argc, char **argv)
{
int ref, r, tries_left = -1;