- pace debug output of libccid is shown by default in pcscd's log
- made establishpacechannel input independant from any byte order conversion. little endian handling is done by the ccid-part. git-svn-id: https://vsmartcard.svn.sourceforge.net/svnroot/vsmartcard@209 96b47cad-a561-4643-ad3b-153ac7d7599c
This commit is contained in:
@@ -1,3 +1,3 @@
|
|||||||
EXTRA_DIST = ccid-1.3.11.patch ccid-1.3.13.patch \
|
EXTRA_DIST = ccid-1.3.11.patch ccid-1.3.13.patch \
|
||||||
pcsc-lite-1.5.5.patch pcsc-lite-1.6.1.patch \
|
pcsc-lite-1.5.5.patch pcsc-lite-1.6.1.patch \
|
||||||
pcsclite_trunk_r4993.patch
|
pcsclite_trunk_r5063.patch
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
Index: src/ifdhandler.c
|
Index: ccid-1.3.11/src/ifdhandler.c
|
||||||
===================================================================
|
===================================================================
|
||||||
--- src/ifdhandler.c (Revision 4347)
|
--- ccid-1.3.11/src/ifdhandler.c (Revision 4347)
|
||||||
+++ src/ifdhandler.c (Arbeitskopie)
|
+++ ccid-1.3.11/src/ifdhandler.c (Arbeitskopie)
|
||||||
@@ -1266,6 +1266,16 @@
|
@@ -1266,6 +1266,16 @@
|
||||||
iBytesReturned += sizeof(PCSC_TLV_STRUCTURE);
|
iBytesReturned += sizeof(PCSC_TLV_STRUCTURE);
|
||||||
}
|
}
|
||||||
@@ -63,10 +63,10 @@ Index: src/ifdhandler.c
|
|||||||
if (IFD_SUCCESS != return_value)
|
if (IFD_SUCCESS != return_value)
|
||||||
*pdwBytesReturned = 0;
|
*pdwBytesReturned = 0;
|
||||||
|
|
||||||
Index: src/commands.c
|
Index: ccid-1.3.11/src/commands.c
|
||||||
===================================================================
|
===================================================================
|
||||||
--- src/commands.c (Revision 4347)
|
--- ccid-1.3.11/src/commands.c (Revision 4347)
|
||||||
+++ src/commands.c (Arbeitskopie)
|
+++ ccid-1.3.11/src/commands.c (Arbeitskopie)
|
||||||
@@ -68,7 +68,19 @@
|
@@ -68,7 +68,19 @@
|
||||||
unsigned int tx_length, unsigned char tx_buffer[], unsigned int *rx_length,
|
unsigned int tx_length, unsigned char tx_buffer[], unsigned int *rx_length,
|
||||||
unsigned char rx_buffer[]);
|
unsigned char rx_buffer[]);
|
||||||
@@ -106,15 +106,15 @@ Index: src/commands.c
|
|||||||
+ }
|
+ }
|
||||||
+ switch (input[parsed]) {
|
+ switch (input[parsed]) {
|
||||||
+ case 0x01:
|
+ case 0x01:
|
||||||
+ DEBUG_COMM("Initiating PACE with MRZ");
|
+ DEBUG_INFO("Initiating PACE with MRZ");
|
||||||
+ case 0x02:
|
+ case 0x02:
|
||||||
+ DEBUG_COMM("Initiating PACE with CAN");
|
+ DEBUG_INFO("Initiating PACE with CAN");
|
||||||
+ case 0x03:
|
+ case 0x03:
|
||||||
+ DEBUG_COMM("Initiating PACE with PIN");
|
+ DEBUG_INFO("Initiating PACE with PIN");
|
||||||
+ case 0x04:
|
+ case 0x04:
|
||||||
+ DEBUG_COMM("Initiating PACE with PUK");
|
+ DEBUG_INFO("Initiating PACE with PUK");
|
||||||
+ default:
|
+ default:
|
||||||
+ DEBUG_COMM("Initiating PACE with unknown PACE secret type");
|
+ DEBUG_INFO("Initiating PACE with unknown PACE secret type");
|
||||||
+ }
|
+ }
|
||||||
+ parsed += 1;
|
+ parsed += 1;
|
||||||
+
|
+
|
||||||
@@ -186,7 +186,7 @@ Index: src/commands.c
|
|||||||
+ DEBUG_CRITICAL("Malformed Establish PACE Channel output data.");
|
+ DEBUG_CRITICAL("Malformed Establish PACE Channel output data.");
|
||||||
+ return IFD_COMMUNICATION_ERROR;
|
+ return IFD_COMMUNICATION_ERROR;
|
||||||
+ }
|
+ }
|
||||||
+ DEBUG_COMM3("MSE:Set AT Statusbytes: %02X %02X",
|
+ DEBUG_INFO3("MSE:Set AT Statusbytes: %02X %02X",
|
||||||
+ output[parsed+0], output[parsed+1]);
|
+ output[parsed+0], output[parsed+1]);
|
||||||
+ parsed += 2;
|
+ parsed += 2;
|
||||||
+
|
+
|
||||||
@@ -403,10 +403,10 @@ Index: src/commands.c
|
|||||||
+ buffer[1] = (value >> 8) & 0xFF;
|
+ buffer[1] = (value >> 8) & 0xFF;
|
||||||
+} /* i2w */
|
+} /* i2w */
|
||||||
+
|
+
|
||||||
Index: src/commands.h
|
Index: ccid-1.3.11/src/commands.h
|
||||||
===================================================================
|
===================================================================
|
||||||
--- src/commands.h (Revision 4347)
|
--- ccid-1.3.11/src/commands.h (Revision 4347)
|
||||||
+++ src/commands.h (Arbeitskopie)
|
+++ ccid-1.3.11/src/commands.h (Arbeitskopie)
|
||||||
@@ -37,6 +37,14 @@
|
@@ -37,6 +37,14 @@
|
||||||
unsigned char TxBuffer[], unsigned int TxLength,
|
unsigned char TxBuffer[], unsigned int TxLength,
|
||||||
unsigned char RxBuffer[], unsigned int *RxLength);
|
unsigned char RxBuffer[], unsigned int *RxLength);
|
||||||
@@ -422,10 +422,10 @@ Index: src/commands.h
|
|||||||
RESPONSECODE CmdEscape(unsigned int reader_index,
|
RESPONSECODE CmdEscape(unsigned int reader_index,
|
||||||
const unsigned char TxBuffer[], unsigned int TxLength,
|
const unsigned char TxBuffer[], unsigned int TxLength,
|
||||||
unsigned char RxBuffer[], unsigned int *RxLength);
|
unsigned char RxBuffer[], unsigned int *RxLength);
|
||||||
Index: src/ccid.h
|
Index: ccid-1.3.11/src/ccid.h
|
||||||
===================================================================
|
===================================================================
|
||||||
--- src/ccid.h (Revision 4347)
|
--- ccid-1.3.11/src/ccid.h (Revision 4347)
|
||||||
+++ src/ccid.h (Arbeitskopie)
|
+++ ccid-1.3.11/src/ccid.h (Arbeitskopie)
|
||||||
@@ -137,8 +137,10 @@
|
@@ -137,8 +137,10 @@
|
||||||
#define CCID_CLASS_EXCHANGE_MASK 0x00070000
|
#define CCID_CLASS_EXCHANGE_MASK 0x00070000
|
||||||
|
|
||||||
@@ -448,10 +448,10 @@ Index: src/ccid.h
|
|||||||
|
|
||||||
/* all the data rates specified by ISO 7816-3 Fi/Di tables */
|
/* all the data rates specified by ISO 7816-3 Fi/Di tables */
|
||||||
#define ISO_DATA_RATES 10753, 14337, 15625, 17204, \
|
#define ISO_DATA_RATES 10753, 14337, 15625, 17204, \
|
||||||
Index: src/ccid_ifdhandler.h
|
Index: ccid-1.3.11/src/ccid_ifdhandler.h
|
||||||
===================================================================
|
===================================================================
|
||||||
--- src/ccid_ifdhandler.h (Revision 4347)
|
--- ccid-1.3.11/src/ccid_ifdhandler.h (Revision 4347)
|
||||||
+++ src/ccid_ifdhandler.h (Arbeitskopie)
|
+++ ccid-1.3.11/src/ccid_ifdhandler.h (Arbeitskopie)
|
||||||
@@ -38,6 +38,8 @@
|
@@ -38,6 +38,8 @@
|
||||||
#define IOCTL_FEATURE_IFD_PIN_PROPERTIES \
|
#define IOCTL_FEATURE_IFD_PIN_PROPERTIES \
|
||||||
SCARD_CTL_CODE(FEATURE_IFD_PIN_PROPERTIES + CLASS2_IOCTL_MAGIC)
|
SCARD_CTL_CODE(FEATURE_IFD_PIN_PROPERTIES + CLASS2_IOCTL_MAGIC)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
Index: src/ifdhandler.c
|
Index: ccid-1.3.13/src/ifdhandler.c
|
||||||
===================================================================
|
===================================================================
|
||||||
--- src/ifdhandler.c (Revision 4979)
|
--- ccid-1.3.13/src/ifdhandler.c (Revision 4979)
|
||||||
+++ src/ifdhandler.c (Arbeitskopie)
|
+++ ccid-1.3.13/src/ifdhandler.c (Arbeitskopie)
|
||||||
@@ -1384,6 +1384,16 @@
|
@@ -1384,6 +1384,16 @@
|
||||||
iBytesReturned += sizeof(PCSC_TLV_STRUCTURE);
|
iBytesReturned += sizeof(PCSC_TLV_STRUCTURE);
|
||||||
}
|
}
|
||||||
@@ -63,10 +63,10 @@ Index: src/ifdhandler.c
|
|||||||
if (IFD_SUCCESS != return_value)
|
if (IFD_SUCCESS != return_value)
|
||||||
*pdwBytesReturned = 0;
|
*pdwBytesReturned = 0;
|
||||||
|
|
||||||
Index: src/commands.c
|
Index: ccid-1.3.13/src/commands.c
|
||||||
===================================================================
|
===================================================================
|
||||||
--- src/commands.c (Revision 4979)
|
--- ccid-1.3.13/src/commands.c (Revision 4979)
|
||||||
+++ src/commands.c (Arbeitskopie)
|
+++ ccid-1.3.13/src/commands.c (Arbeitskopie)
|
||||||
@@ -68,7 +68,19 @@
|
@@ -68,7 +68,19 @@
|
||||||
unsigned int tx_length, unsigned char tx_buffer[], unsigned int *rx_length,
|
unsigned int tx_length, unsigned char tx_buffer[], unsigned int *rx_length,
|
||||||
unsigned char rx_buffer[]);
|
unsigned char rx_buffer[]);
|
||||||
@@ -106,15 +106,15 @@ Index: src/commands.c
|
|||||||
+ }
|
+ }
|
||||||
+ switch (input[parsed]) {
|
+ switch (input[parsed]) {
|
||||||
+ case 0x01:
|
+ case 0x01:
|
||||||
+ DEBUG_COMM("Initiating PACE with MRZ");
|
+ DEBUG_INFO("Initiating PACE with MRZ");
|
||||||
+ case 0x02:
|
+ case 0x02:
|
||||||
+ DEBUG_COMM("Initiating PACE with CAN");
|
+ DEBUG_INFO("Initiating PACE with CAN");
|
||||||
+ case 0x03:
|
+ case 0x03:
|
||||||
+ DEBUG_COMM("Initiating PACE with PIN");
|
+ DEBUG_INFO("Initiating PACE with PIN");
|
||||||
+ case 0x04:
|
+ case 0x04:
|
||||||
+ DEBUG_COMM("Initiating PACE with PUK");
|
+ DEBUG_INFO("Initiating PACE with PUK");
|
||||||
+ default:
|
+ default:
|
||||||
+ DEBUG_COMM("Initiating PACE with unknown PACE secret type");
|
+ DEBUG_INFO("Initiating PACE with unknown PACE secret type");
|
||||||
+ }
|
+ }
|
||||||
+ parsed += 1;
|
+ parsed += 1;
|
||||||
+
|
+
|
||||||
@@ -186,7 +186,7 @@ Index: src/commands.c
|
|||||||
+ DEBUG_CRITICAL("Malformed Establish PACE Channel output data.");
|
+ DEBUG_CRITICAL("Malformed Establish PACE Channel output data.");
|
||||||
+ return IFD_COMMUNICATION_ERROR;
|
+ return IFD_COMMUNICATION_ERROR;
|
||||||
+ }
|
+ }
|
||||||
+ DEBUG_COMM3("MSE:Set AT Statusbytes: %02X %02X",
|
+ DEBUG_INFO3("MSE:Set AT Statusbytes: %02X %02X",
|
||||||
+ output[parsed+0], output[parsed+1]);
|
+ output[parsed+0], output[parsed+1]);
|
||||||
+ parsed += 2;
|
+ parsed += 2;
|
||||||
+
|
+
|
||||||
@@ -403,10 +403,10 @@ Index: src/commands.c
|
|||||||
+ buffer[1] = (value >> 8) & 0xFF;
|
+ buffer[1] = (value >> 8) & 0xFF;
|
||||||
+} /* i2w */
|
+} /* i2w */
|
||||||
+
|
+
|
||||||
Index: src/commands.h
|
Index: ccid-1.3.13/src/commands.h
|
||||||
===================================================================
|
===================================================================
|
||||||
--- src/commands.h (Revision 4979)
|
--- ccid-1.3.13/src/commands.h (Revision 4979)
|
||||||
+++ src/commands.h (Arbeitskopie)
|
+++ ccid-1.3.13/src/commands.h (Arbeitskopie)
|
||||||
@@ -37,6 +37,14 @@
|
@@ -37,6 +37,14 @@
|
||||||
unsigned char TxBuffer[], unsigned int TxLength,
|
unsigned char TxBuffer[], unsigned int TxLength,
|
||||||
unsigned char RxBuffer[], unsigned int *RxLength);
|
unsigned char RxBuffer[], unsigned int *RxLength);
|
||||||
@@ -422,10 +422,10 @@ Index: src/commands.h
|
|||||||
RESPONSECODE CmdEscape(unsigned int reader_index,
|
RESPONSECODE CmdEscape(unsigned int reader_index,
|
||||||
const unsigned char TxBuffer[], unsigned int TxLength,
|
const unsigned char TxBuffer[], unsigned int TxLength,
|
||||||
unsigned char RxBuffer[], unsigned int *RxLength);
|
unsigned char RxBuffer[], unsigned int *RxLength);
|
||||||
Index: src/ccid.h
|
Index: ccid-1.3.13/src/ccid.h
|
||||||
===================================================================
|
===================================================================
|
||||||
--- src/ccid.h (Revision 4979)
|
--- ccid-1.3.13/src/ccid.h (Revision 4979)
|
||||||
+++ src/ccid.h (Arbeitskopie)
|
+++ ccid-1.3.13/src/ccid.h (Arbeitskopie)
|
||||||
@@ -142,8 +142,10 @@
|
@@ -142,8 +142,10 @@
|
||||||
#define CCID_CLASS_EXCHANGE_MASK 0x00070000
|
#define CCID_CLASS_EXCHANGE_MASK 0x00070000
|
||||||
|
|
||||||
@@ -448,10 +448,10 @@ Index: src/ccid.h
|
|||||||
|
|
||||||
/* all the data rates specified by ISO 7816-3 Fi/Di tables */
|
/* all the data rates specified by ISO 7816-3 Fi/Di tables */
|
||||||
#define ISO_DATA_RATES 10753, 14337, 15625, 17204, \
|
#define ISO_DATA_RATES 10753, 14337, 15625, 17204, \
|
||||||
Index: src/ccid_ifdhandler.h
|
Index: ccid-1.3.13/src/ccid_ifdhandler.h
|
||||||
===================================================================
|
===================================================================
|
||||||
--- src/ccid_ifdhandler.h (Revision 4979)
|
--- ccid-1.3.13/src/ccid_ifdhandler.h (Revision 4979)
|
||||||
+++ src/ccid_ifdhandler.h (Arbeitskopie)
|
+++ ccid-1.3.13/src/ccid_ifdhandler.h (Arbeitskopie)
|
||||||
@@ -37,6 +37,8 @@
|
@@ -37,6 +37,8 @@
|
||||||
SCARD_CTL_CODE(FEATURE_IFD_PIN_PROPERTIES + CLASS2_IOCTL_MAGIC)
|
SCARD_CTL_CODE(FEATURE_IFD_PIN_PROPERTIES + CLASS2_IOCTL_MAGIC)
|
||||||
#define IOCTL_FEATURE_GET_TLV_PROPERTIES \
|
#define IOCTL_FEATURE_GET_TLV_PROPERTIES \
|
||||||
|
|||||||
@@ -779,7 +779,10 @@ perform_PC_to_RDR_Secure(const __u8 *in, size_t inlen, __u8** out, size_t *outle
|
|||||||
const __u8* abData = in + sizeof *request;
|
const __u8* abData = in + sizeof *request;
|
||||||
size_t abDatalen = inlen - sizeof *request;
|
size_t abDatalen = inlen - sizeof *request;
|
||||||
u8 *abDataOut = NULL;
|
u8 *abDataOut = NULL;
|
||||||
size_t resplen = 0;
|
size_t resplen = 0, parsed;
|
||||||
|
__le16 word;
|
||||||
|
struct establish_pace_channel_input pace_input;
|
||||||
|
struct establish_pace_channel_output pace_output;
|
||||||
RDR_to_PC_DataBlock_t *result;
|
RDR_to_PC_DataBlock_t *result;
|
||||||
|
|
||||||
if (!in || !out || !outlen)
|
if (!in || !out || !outlen)
|
||||||
@@ -793,6 +796,8 @@ perform_PC_to_RDR_Secure(const __u8 *in, size_t inlen, __u8** out, size_t *outle
|
|||||||
|
|
||||||
memset(&curr_pin, 0, sizeof(curr_pin));
|
memset(&curr_pin, 0, sizeof(curr_pin));
|
||||||
memset(&new_pin, 0, sizeof(new_pin));
|
memset(&new_pin, 0, sizeof(new_pin));
|
||||||
|
memset(&pace_input, 0, sizeof(pace_input));
|
||||||
|
memset(&pace_output, 0, sizeof(pace_output));
|
||||||
|
|
||||||
if (request->bSlot > sizeof *card_in_slot) {
|
if (request->bSlot > sizeof *card_in_slot) {
|
||||||
sc_error(ctx, "Received request to invalid slot (bSlot=0x%02x)", request->bSlot);
|
sc_error(ctx, "Received request to invalid slot (bSlot=0x%02x)", request->bSlot);
|
||||||
@@ -865,15 +870,69 @@ perform_PC_to_RDR_Secure(const __u8 *in, size_t inlen, __u8** out, size_t *outle
|
|||||||
goto err;
|
goto err;
|
||||||
break;
|
break;
|
||||||
case 0x20:
|
case 0x20:
|
||||||
|
parsed = 1;
|
||||||
|
|
||||||
if (abDatalen < 1) {
|
if (abDatalen < parsed+1) {
|
||||||
sc_error(ctx, "Not enough data for input of EstablishPACEChannel");
|
sc_error(ctx, "Buffer too small, could not get PinID");
|
||||||
sc_result = SC_ERROR_INVALID_DATA;
|
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
pace_input.pin_id = abData[parsed];
|
||||||
|
parsed++;
|
||||||
|
|
||||||
|
if (abDatalen < parsed+1) {
|
||||||
|
sc_error(ctx, "Buffer too small, could not get lengthCHAT");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
pace_input.chat_length = abData[parsed];
|
||||||
|
parsed++;
|
||||||
|
|
||||||
|
if (abDatalen < parsed+pace_input.chat_length) {
|
||||||
|
sc_error(ctx, "Buffer too small, could not get CHAT");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
pace_input.chat = &abData[parsed];
|
||||||
|
parsed += pace_input.chat_length;
|
||||||
|
/* XXX make this human readable */
|
||||||
|
if (pace_input.chat_length)
|
||||||
|
bin_log(ctx, "Card holder authorization template",
|
||||||
|
pace_input.chat, pace_input.chat_length);
|
||||||
|
|
||||||
|
if (abDatalen < parsed+1) {
|
||||||
|
sc_error(ctx, "Buffer too small, could not get lengthPIN");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
pace_input.pin_length = abData[parsed];
|
||||||
|
parsed++;
|
||||||
|
|
||||||
|
if (abDatalen < parsed+pace_input.pin_length) {
|
||||||
|
sc_error(ctx, "Buffer too small, could not get PIN");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
pace_input.pin = &abData[parsed];
|
||||||
|
parsed += pace_input.pin_length;
|
||||||
|
|
||||||
|
if (abDatalen < parsed+sizeof(word)) {
|
||||||
|
sc_error(ctx, "Buffer too small, could not get lengthCertificateDescription");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
memcpy(&word, &abData[parsed], sizeof word);
|
||||||
|
pace_input.certificate_description_length = __le16_to_cpu(word);
|
||||||
|
parsed += sizeof word;
|
||||||
|
|
||||||
|
if (abDatalen < parsed+pace_input.certificate_description_length) {
|
||||||
|
sc_error(ctx, "Buffer too small, could not get CertificateDescription");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
pace_input.certificate_description = &abData[parsed];
|
||||||
|
parsed+= pace_input.certificate_description_length;
|
||||||
|
/* XXX make this human readable */
|
||||||
|
if (pace_input.certificate_description_length)
|
||||||
|
bin_log(ctx, "Certificate description",
|
||||||
|
pace_input.certificate_description,
|
||||||
|
pace_input.certificate_description_length);
|
||||||
|
|
||||||
sc_result = EstablishPACEChannel(NULL,
|
sc_result = EstablishPACEChannel(NULL,
|
||||||
card_in_slot[request->bSlot], abData + 1, abDatalen-1,
|
card_in_slot[request->bSlot], pace_input,
|
||||||
&abDataOut, &resplen, &sctx);
|
&abDataOut, &resplen, &sctx);
|
||||||
goto err;
|
goto err;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -30,7 +30,6 @@
|
|||||||
|
|
||||||
static int verbose = 0;
|
static int verbose = 0;
|
||||||
static int doinfo = 0;
|
static int doinfo = 0;
|
||||||
static u8 pin_id = 0;
|
|
||||||
static u8 dochangepin = 0;
|
static u8 dochangepin = 0;
|
||||||
static u8 doresumepin = 0;
|
static u8 doresumepin = 0;
|
||||||
static u8 dounblock = 0;
|
static u8 dounblock = 0;
|
||||||
@@ -46,9 +45,7 @@ static u8 usecan = 0;
|
|||||||
static const char *mrz = NULL;
|
static const char *mrz = NULL;
|
||||||
static u8 usemrz = 0;
|
static u8 usemrz = 0;
|
||||||
static u8 chat[0xff];
|
static u8 chat[0xff];
|
||||||
static size_t chatlen = 0;
|
|
||||||
static u8 desc[0xffff];
|
static u8 desc[0xffff];
|
||||||
static size_t desclen = 0;
|
|
||||||
static const char *cdriver = NULL;
|
static const char *cdriver = NULL;
|
||||||
|
|
||||||
static sc_context_t *ctx = NULL;
|
static sc_context_t *ctx = NULL;
|
||||||
@@ -107,62 +104,6 @@ static const char *option_help[] = {
|
|||||||
"Print version, available readers and drivers.",
|
"Print version, available readers and drivers.",
|
||||||
};
|
};
|
||||||
|
|
||||||
int pace_get_channel(struct sm_ctx *oldpacectx, sc_card_t *card,
|
|
||||||
enum s_type pin_id, const char *pin, size_t pinlen,
|
|
||||||
const char *chat, size_t chatlen, const char *desc, size_t desclen,
|
|
||||||
__u8 **out, size_t *outlen, struct sm_ctx *sctx)
|
|
||||||
{
|
|
||||||
u8 buf[0xff + 0xff + 0xffff + 5];
|
|
||||||
__le16 word;
|
|
||||||
|
|
||||||
switch (pin_id) {
|
|
||||||
case PACE_MRZ:
|
|
||||||
case PACE_CAN:
|
|
||||||
case PACE_PIN:
|
|
||||||
case PACE_PUK:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
sc_error(card->ctx, "Type of secret not supported");
|
|
||||||
return SC_ERROR_INVALID_ARGUMENTS;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pinlen > 0xff) {
|
|
||||||
sc_error(card->ctx, "%s "
|
|
||||||
"too long (maximal %u bytes supported)",
|
|
||||||
pace_secret_name(pin_id),
|
|
||||||
0xff);
|
|
||||||
return SC_ERROR_INVALID_ARGUMENTS;
|
|
||||||
}
|
|
||||||
if (chatlen > 0xff) {
|
|
||||||
sc_error(card->ctx, "CHAT "
|
|
||||||
"too long (maximal %u bytes supported)",
|
|
||||||
0xff);
|
|
||||||
return SC_ERROR_INVALID_ARGUMENTS;
|
|
||||||
}
|
|
||||||
if (desclen > 0xffff) {
|
|
||||||
sc_error(card->ctx, "Certificate description "
|
|
||||||
"too long (maximal %u bytes supported)",
|
|
||||||
0xffff);
|
|
||||||
return SC_ERROR_INVALID_ARGUMENTS;
|
|
||||||
}
|
|
||||||
|
|
||||||
buf[0] = pin_id;
|
|
||||||
|
|
||||||
buf[1] = chatlen;
|
|
||||||
memcpy(&buf[2], chat, chatlen);
|
|
||||||
|
|
||||||
buf[2 + chatlen] = pinlen;
|
|
||||||
memcpy(&buf[3 + chatlen], pin, pinlen);
|
|
||||||
|
|
||||||
word = __cpu_to_le16(desclen);
|
|
||||||
memcpy(&buf[3 + chatlen + pinlen], &word, sizeof word);
|
|
||||||
memcpy(&buf[3 + chatlen + pinlen + sizeof word],
|
|
||||||
desc, desclen);
|
|
||||||
|
|
||||||
return EstablishPACEChannel(oldpacectx, card, buf,
|
|
||||||
1+1+chatlen+1+pinlen+sizeof(word)+desclen, out, outlen, sctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
int pace_translate_apdus(struct sm_ctx *sctx, sc_card_t *card)
|
int pace_translate_apdus(struct sm_ctx *sctx, sc_card_t *card)
|
||||||
{
|
{
|
||||||
u8 buf[0xff + 5];
|
u8 buf[0xff + 5];
|
||||||
@@ -228,10 +169,14 @@ main (int argc, char **argv)
|
|||||||
__u8 *channeldata = NULL;
|
__u8 *channeldata = NULL;
|
||||||
size_t channeldatalen;
|
size_t channeldatalen;
|
||||||
struct sm_ctx sctx, tmpctx;
|
struct sm_ctx sctx, tmpctx;
|
||||||
|
struct establish_pace_channel_input pace_input;
|
||||||
time_t t_start, t_end;
|
time_t t_start, t_end;
|
||||||
|
u8 *out = NULL;
|
||||||
|
size_t outlen;
|
||||||
|
|
||||||
memset(&sctx, 0, sizeof(sctx));
|
memset(&sctx, 0, sizeof(sctx));
|
||||||
memset(&tmpctx, 0, sizeof(tmpctx));
|
memset(&tmpctx, 0, sizeof(tmpctx));
|
||||||
|
memset(&pace_input, 0, sizeof(pace_input));
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
i = getopt_long(argc, argv, "hr:i::u::a::z::C:D:N::RUtvoc:", options, &oindex);
|
i = getopt_long(argc, argv, "hr:i::u::a::z::C:D:N::RUtvoc:", options, &oindex);
|
||||||
@@ -282,15 +227,19 @@ main (int argc, char **argv)
|
|||||||
can = getenv("MRZ");
|
can = getenv("MRZ");
|
||||||
break;
|
break;
|
||||||
case OPT_CHAT:
|
case OPT_CHAT:
|
||||||
chatlen = sizeof chat;
|
pace_input.chat = chat;
|
||||||
if (sc_hex_to_bin(optarg, chat, &chatlen) < 0) {
|
pace_input.chat_length = sizeof chat;
|
||||||
|
if (sc_hex_to_bin(optarg, (u8 *) pace_input.chat,
|
||||||
|
&pace_input.chat_length) < 0) {
|
||||||
parse_error(argv[0], options, option_help, optarg, oindex);
|
parse_error(argv[0], options, option_help, optarg, oindex);
|
||||||
exit(2);
|
exit(2);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case OPT_CERTDESC:
|
case OPT_CERTDESC:
|
||||||
desclen = sizeof desc;
|
pace_input.certificate_description = desc;
|
||||||
if (sc_hex_to_bin(optarg, desc, &desclen) < 0) {
|
pace_input.certificate_description_length = sizeof desc;
|
||||||
|
if (sc_hex_to_bin(optarg, (u8 *) pace_input.certificate_description,
|
||||||
|
&pace_input.certificate_description_length) < 0) {
|
||||||
parse_error(argv[0], options, option_help, optarg, oindex);
|
parse_error(argv[0], options, option_help, optarg, oindex);
|
||||||
exit(2);
|
exit(2);
|
||||||
}
|
}
|
||||||
@@ -353,37 +302,56 @@ main (int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (doresumepin) {
|
if (doresumepin) {
|
||||||
|
pace_input.pin_id = PACE_CAN;
|
||||||
|
if (can) {
|
||||||
|
pace_input.pin = can;
|
||||||
|
pace_input.pin_length = strlen(can);
|
||||||
|
} else {
|
||||||
|
pace_input.pin = NULL;
|
||||||
|
pace_input.pin_length = 0;
|
||||||
|
}
|
||||||
t_start = time(NULL);
|
t_start = time(NULL);
|
||||||
i = pace_get_channel(NULL, card,
|
i = EstablishPACEChannel(NULL, card, pace_input, &out, &outlen,
|
||||||
PACE_CAN, can, can ? strlen(can) : 0,
|
&tmpctx);
|
||||||
chat, chatlen, desc, desclen,
|
t_end = time(NULL);
|
||||||
&channeldata, &channeldatalen, &tmpctx);
|
|
||||||
if (i < 0)
|
if (i < 0)
|
||||||
goto err;
|
goto err;
|
||||||
t_end = time(NULL);
|
|
||||||
printf("Established PACE channel with CAN in %.0fs.\n",
|
printf("Established PACE channel with CAN in %.0fs.\n",
|
||||||
difftime(t_end, t_start));
|
difftime(t_end, t_start));
|
||||||
|
|
||||||
i = pace_get_channel(&tmpctx, card,
|
pace_input.pin_id = PACE_PIN;
|
||||||
PACE_PIN, pin, pin ? strlen(pin) : 0,
|
if (pin) {
|
||||||
chat, chatlen, desc, desclen,
|
pace_input.pin = pin;
|
||||||
&channeldata, &channeldatalen, &sctx);
|
pace_input.pin_length = strlen(pin);
|
||||||
|
} else {
|
||||||
|
pace_input.pin = NULL;
|
||||||
|
pace_input.pin_length = 0;
|
||||||
|
}
|
||||||
|
t_start = time(NULL);
|
||||||
|
i = EstablishPACEChannel(&tmpctx, card, pace_input, &out, &outlen,
|
||||||
|
&sctx);
|
||||||
|
t_end = time(NULL);
|
||||||
if (i < 0)
|
if (i < 0)
|
||||||
goto err;
|
goto err;
|
||||||
t_start = time(NULL);
|
|
||||||
printf("Established PACE channel with PIN in %.0fs. PIN resumed.\n",
|
printf("Established PACE channel with PIN in %.0fs. PIN resumed.\n",
|
||||||
difftime(t_start, t_end));
|
difftime(t_end, t_start));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dounblock) {
|
if (dounblock) {
|
||||||
|
pace_input.pin_id = PACE_PUK;
|
||||||
|
if (puk) {
|
||||||
|
pace_input.pin = puk;
|
||||||
|
pace_input.pin_length = strlen(puk);
|
||||||
|
} else {
|
||||||
|
pace_input.pin = NULL;
|
||||||
|
pace_input.pin_length = 0;
|
||||||
|
}
|
||||||
t_start = time(NULL);
|
t_start = time(NULL);
|
||||||
i = pace_get_channel(NULL, card,
|
i = EstablishPACEChannel(NULL, card, pace_input, &out, &outlen,
|
||||||
PACE_PUK, puk, puk ? strlen(puk) : 0,
|
&sctx);
|
||||||
chat, chatlen, desc, desclen,
|
t_end = time(NULL);
|
||||||
&channeldata, &channeldatalen, &sctx);
|
|
||||||
if (i < 0)
|
if (i < 0)
|
||||||
goto err;
|
goto err;
|
||||||
t_end = time(NULL);
|
|
||||||
printf("Established PACE channel with PUK in %.0fs.\n",
|
printf("Established PACE channel with PUK in %.0fs.\n",
|
||||||
difftime(t_end, t_start));
|
difftime(t_end, t_start));
|
||||||
|
|
||||||
@@ -394,14 +362,20 @@ main (int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (dochangepin) {
|
if (dochangepin) {
|
||||||
|
pace_input.pin_id = PACE_PIN;
|
||||||
|
if (pin) {
|
||||||
|
pace_input.pin = pin;
|
||||||
|
pace_input.pin_length = strlen(pin);
|
||||||
|
} else {
|
||||||
|
pace_input.pin = NULL;
|
||||||
|
pace_input.pin_length = 0;
|
||||||
|
}
|
||||||
t_start = time(NULL);
|
t_start = time(NULL);
|
||||||
i = pace_get_channel(NULL, card,
|
i = EstablishPACEChannel(NULL, card, pace_input, &out, &outlen,
|
||||||
PACE_PIN, pin, pin ? strlen(pin) : 0,
|
&sctx);
|
||||||
chat, chatlen, desc, desclen,
|
t_end = time(NULL);
|
||||||
&channeldata, &channeldatalen, &sctx);
|
|
||||||
if (i < 0)
|
if (i < 0)
|
||||||
goto err;
|
goto err;
|
||||||
t_end = time(NULL);
|
|
||||||
printf("Established PACE channel with PIN in %.0fs.\n",
|
printf("Established PACE channel with PIN in %.0fs.\n",
|
||||||
difftime(t_end, t_start));
|
difftime(t_end, t_start));
|
||||||
|
|
||||||
@@ -412,20 +386,32 @@ main (int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (dotranslate || (!doresumepin && !dochangepin && !dounblock)) {
|
if (dotranslate || (!doresumepin && !dochangepin && !dounblock)) {
|
||||||
enum s_type id;
|
pace_input.pin = NULL;
|
||||||
const char *s;
|
pace_input.pin_length = 0;
|
||||||
if (usepin) {
|
if (usepin) {
|
||||||
id = PACE_PIN;
|
pace_input.pin_id = PACE_PIN;
|
||||||
s = pin;
|
if (pin) {
|
||||||
|
pace_input.pin = pin;
|
||||||
|
pace_input.pin_length = strlen(pin);
|
||||||
|
}
|
||||||
} else if (usecan) {
|
} else if (usecan) {
|
||||||
id = PACE_CAN;
|
pace_input.pin_id = PACE_CAN;
|
||||||
s = can;
|
if (can) {
|
||||||
|
pace_input.pin = can;
|
||||||
|
pace_input.pin_length = strlen(can);
|
||||||
|
}
|
||||||
} else if (usemrz) {
|
} else if (usemrz) {
|
||||||
id = PACE_MRZ;
|
pace_input.pin_id = PACE_MRZ;
|
||||||
s = mrz;
|
if (mrz) {
|
||||||
|
pace_input.pin = mrz;
|
||||||
|
pace_input.pin_length = strlen(mrz);
|
||||||
|
}
|
||||||
} else if (usepuk) {
|
} else if (usepuk) {
|
||||||
id = PACE_PUK;
|
pace_input.pin_id = PACE_PUK;
|
||||||
s = puk;
|
if (puk) {
|
||||||
|
pace_input.pin = puk;
|
||||||
|
pace_input.pin_length = strlen(puk);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Please specify whether to do PACE with "
|
fprintf(stderr, "Please specify whether to do PACE with "
|
||||||
"PIN, CAN, MRZ or PUK.");
|
"PIN, CAN, MRZ or PUK.");
|
||||||
@@ -433,14 +419,13 @@ main (int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
t_start = time(NULL);
|
t_start = time(NULL);
|
||||||
i = pace_get_channel(NULL, card, id, s, s ? strlen(s) : 0,
|
i = EstablishPACEChannel(NULL, card, pace_input, &out, &outlen,
|
||||||
chat, chatlen, desc, desclen,
|
&sctx);
|
||||||
&channeldata, &channeldatalen, &sctx);
|
t_end = time(NULL);
|
||||||
if (i < 0)
|
if (i < 0)
|
||||||
goto err;
|
goto err;
|
||||||
t_end = time(NULL);
|
|
||||||
printf("Established PACE channel with %s in %.0fs.\n",
|
printf("Established PACE channel with %s in %.0fs.\n",
|
||||||
pace_secret_name(id), difftime(t_end, t_start));
|
pace_secret_name(pace_input.pin_id), difftime(t_end, t_start));
|
||||||
|
|
||||||
if (dotranslate) {
|
if (dotranslate) {
|
||||||
i = pace_translate_apdus(&sctx, card);
|
i = pace_translate_apdus(&sctx, card);
|
||||||
|
|||||||
@@ -958,14 +958,12 @@ void ssl_error(sc_context_t *ctx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int EstablishPACEChannel(const struct sm_ctx *oldpacectx, sc_card_t *card,
|
int EstablishPACEChannel(const struct sm_ctx *oldpacectx, sc_card_t *card,
|
||||||
const __u8 *in, size_t inlen, __u8 **out, size_t *outlen, struct sm_ctx *sctx)
|
struct establish_pace_channel_input pace_input,
|
||||||
|
__u8 **out, size_t *outlen, struct sm_ctx *sctx)
|
||||||
{
|
{
|
||||||
__u8 pin_id;
|
size_t length_ef_cardaccess, recent_car_len, prev_car_len;
|
||||||
size_t length_chat, length_pin, length_cert_desc, length_ef_cardaccess, recent_car_len, prev_car_len;
|
|
||||||
const __u8 *chat, *pin, *certificate_description;
|
|
||||||
__u8 *ef_cardaccess = NULL, *p = NULL, *recent_car = NULL, *prev_car = NULL;
|
__u8 *ef_cardaccess = NULL, *p = NULL, *recent_car = NULL, *prev_car = NULL;
|
||||||
PACEInfo *info = NULL;
|
PACEInfo *info = NULL;
|
||||||
__le16 word;
|
|
||||||
PACEDomainParameterInfo *static_dp = NULL, *eph_dp = NULL;
|
PACEDomainParameterInfo *static_dp = NULL, *eph_dp = NULL;
|
||||||
BUF_MEM *enc_nonce = NULL, *nonce = NULL, *mdata = NULL, *mdata_opp = NULL,
|
BUF_MEM *enc_nonce = NULL, *nonce = NULL, *mdata = NULL, *mdata_opp = NULL,
|
||||||
*k_enc = NULL, *k_mac = NULL, *token_opp = NULL,
|
*k_enc = NULL, *k_mac = NULL, *token_opp = NULL,
|
||||||
@@ -973,67 +971,13 @@ int EstablishPACEChannel(const struct sm_ctx *oldpacectx, sc_card_t *card,
|
|||||||
PACE_SEC *sec = NULL;
|
PACE_SEC *sec = NULL;
|
||||||
PACE_CTX *pctx = NULL;
|
PACE_CTX *pctx = NULL;
|
||||||
int r;
|
int r;
|
||||||
|
__le16 word;
|
||||||
|
|
||||||
if (!card)
|
if (!card)
|
||||||
return SC_ERROR_CARD_NOT_PRESENT;
|
return SC_ERROR_CARD_NOT_PRESENT;
|
||||||
if (!in || !out || !outlen)
|
if (!out || !outlen)
|
||||||
return SC_ERROR_INVALID_ARGUMENTS;
|
return SC_ERROR_INVALID_ARGUMENTS;
|
||||||
|
|
||||||
if (inlen < 1) {
|
|
||||||
sc_error(card->ctx, "Buffer too small, could not get PinID");
|
|
||||||
SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_DEBUG, SC_ERROR_INVALID_DATA);
|
|
||||||
}
|
|
||||||
pin_id = *in;
|
|
||||||
in++;
|
|
||||||
|
|
||||||
if (inlen < 1+1) {
|
|
||||||
sc_error(card->ctx, "Buffer too small, could not get lengthCHAT");
|
|
||||||
SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_DEBUG, SC_ERROR_INVALID_DATA);
|
|
||||||
}
|
|
||||||
length_chat = *in;
|
|
||||||
in++;
|
|
||||||
if (inlen < 1+1+length_chat) {
|
|
||||||
sc_error(card->ctx, "Buffer too small, could not get CHAT");
|
|
||||||
SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_DEBUG, SC_ERROR_INVALID_DATA);
|
|
||||||
}
|
|
||||||
chat = in;
|
|
||||||
in += length_chat;
|
|
||||||
/* XXX make this human readable */
|
|
||||||
if (length_chat)
|
|
||||||
bin_log(card->ctx, "Card holder authorization template",
|
|
||||||
chat, length_chat);
|
|
||||||
|
|
||||||
if (inlen < 1+1+length_chat+1) {
|
|
||||||
sc_error(card->ctx, "Buffer too small, could not get lengthPIN");
|
|
||||||
SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_DEBUG, SC_ERROR_INVALID_DATA);
|
|
||||||
}
|
|
||||||
length_pin = *in;
|
|
||||||
in++;
|
|
||||||
if (inlen < 1+1+length_chat+1+length_pin) {
|
|
||||||
sc_error(card->ctx, "Buffer too small, could not get PIN");
|
|
||||||
SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_DEBUG, SC_ERROR_INVALID_DATA);
|
|
||||||
}
|
|
||||||
pin = in;
|
|
||||||
in += length_pin;
|
|
||||||
|
|
||||||
if (inlen < 1+1+length_chat+1+length_pin+sizeof(word)) {
|
|
||||||
sc_error(card->ctx, "Buffer too small, could not get lengthCertificateDescription");
|
|
||||||
SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_DEBUG, SC_ERROR_INVALID_DATA);
|
|
||||||
}
|
|
||||||
memcpy(&word, in, sizeof word);
|
|
||||||
length_cert_desc = __le16_to_cpu(word);
|
|
||||||
in += sizeof word;
|
|
||||||
if (inlen < 1+1+length_chat+1+length_pin+sizeof(word)+length_cert_desc) {
|
|
||||||
sc_error(card->ctx, "Buffer too small, could not get CertificateDescription");
|
|
||||||
SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_DEBUG, SC_ERROR_INVALID_DATA);
|
|
||||||
}
|
|
||||||
certificate_description = in;
|
|
||||||
/* XXX make this human readable */
|
|
||||||
if (length_cert_desc)
|
|
||||||
bin_log(card->ctx, "Certificate description",
|
|
||||||
certificate_description, length_cert_desc);
|
|
||||||
|
|
||||||
|
|
||||||
if (!oldpacectx) {
|
if (!oldpacectx) {
|
||||||
/* PACE is executed the first time */
|
/* PACE is executed the first time */
|
||||||
r = get_ef_card_access(card, &ef_cardaccess, &length_ef_cardaccess);
|
r = get_ef_card_access(card, &ef_cardaccess, &length_ef_cardaccess);
|
||||||
@@ -1069,7 +1013,8 @@ int EstablishPACEChannel(const struct sm_ctx *oldpacectx, sc_card_t *card,
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = pace_mse_set_at(oldpacectx, card, info->protocol, pin_id, chat, length_chat, *out, (*out)+1);
|
r = pace_mse_set_at(oldpacectx, card, info->protocol, pace_input.pin_id,
|
||||||
|
pace_input.chat, pace_input.chat_length, *out, (*out)+1);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
sc_error(card->ctx, "Could not select protocol proberties "
|
sc_error(card->ctx, "Could not select protocol proberties "
|
||||||
"(MSE: Set AT).");
|
"(MSE: Set AT).");
|
||||||
@@ -1091,7 +1036,8 @@ int EstablishPACEChannel(const struct sm_ctx *oldpacectx, sc_card_t *card,
|
|||||||
bin_log(card->ctx, "Encrypted nonce from MRTD", (u8 *)enc_nonce->data, enc_nonce->length);
|
bin_log(card->ctx, "Encrypted nonce from MRTD", (u8 *)enc_nonce->data, enc_nonce->length);
|
||||||
enc_nonce->max = enc_nonce->length;
|
enc_nonce->max = enc_nonce->length;
|
||||||
|
|
||||||
sec = get_psec(card, (char *) pin, length_pin, pin_id);
|
sec = get_psec(card, (char *) pace_input.pin, pace_input.pin_length,
|
||||||
|
pace_input.pin_id);
|
||||||
if (!sec) {
|
if (!sec) {
|
||||||
sc_error(card->ctx, "Could not encode PACE secret.");
|
sc_error(card->ctx, "Could not encode PACE secret.");
|
||||||
ssl_error(card->ctx);
|
ssl_error(card->ctx);
|
||||||
|
|||||||
@@ -66,10 +66,42 @@ int pace_sm_pre_transmit(sc_card_t *card, const struct sm_ctx *ctx,
|
|||||||
int pace_sm_post_transmit(sc_card_t *card, const struct sm_ctx *ctx,
|
int pace_sm_post_transmit(sc_card_t *card, const struct sm_ctx *ctx,
|
||||||
sc_apdu_t *sm_apdu);
|
sc_apdu_t *sm_apdu);
|
||||||
|
|
||||||
|
|
||||||
|
struct establish_pace_channel_input {
|
||||||
|
unsigned char pin_id;
|
||||||
|
|
||||||
|
size_t chat_length;
|
||||||
|
const unsigned char *chat;
|
||||||
|
|
||||||
|
size_t pin_length;
|
||||||
|
const unsigned char *pin;
|
||||||
|
|
||||||
|
size_t certificate_description_length;
|
||||||
|
const unsigned char *certificate_description;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct establish_pace_channel_output {
|
||||||
|
unsigned char mse_set_at_sw1;
|
||||||
|
unsigned char mse_set_at_sw2;
|
||||||
|
|
||||||
|
size_t ef_cardaccess_length;
|
||||||
|
unsigned char *ef_cardaccess;
|
||||||
|
|
||||||
|
size_t recent_car_length;
|
||||||
|
unsigned char *recent_car;
|
||||||
|
|
||||||
|
size_t previous_car_length;
|
||||||
|
unsigned char *previous_car;
|
||||||
|
|
||||||
|
size_t id_icc_length;
|
||||||
|
unsigned char *id_icc;
|
||||||
|
};
|
||||||
|
|
||||||
int GetReadersPACECapabilities(sc_card_t *card, const unsigned char *in,
|
int GetReadersPACECapabilities(sc_card_t *card, const unsigned char *in,
|
||||||
size_t inlen, unsigned char **out, size_t *outlen);
|
size_t inlen, unsigned char **out, size_t *outlen);
|
||||||
int EstablishPACEChannel(const struct sm_ctx *oldpacectx, sc_card_t *card,
|
int EstablishPACEChannel(const struct sm_ctx *oldpacectx, sc_card_t *card,
|
||||||
const unsigned char *in, size_t inlen, unsigned char **out, size_t *outlen, struct sm_ctx *sctx);
|
struct establish_pace_channel_input pace_input,
|
||||||
|
unsigned char **out, size_t *outlen, struct sm_ctx *sctx);
|
||||||
|
|
||||||
int pace_reset_retry_counter(struct sm_ctx *ctx, sc_card_t *card,
|
int pace_reset_retry_counter(struct sm_ctx *ctx, sc_card_t *card,
|
||||||
enum s_type pin_id, int ask_for_secret,
|
enum s_type pin_id, int ask_for_secret,
|
||||||
|
|||||||
Reference in New Issue
Block a user