- Fixed error when testing pace without card

- Testing pace allows now to choose the type of the secret (mrz, pin, can, puk).
  The secret can be given as commandline option or interactively.
- Cleaned prompt for getting the password
- Fixed error when inserting an empty password
- When PACE is successfully finished, APDUs for testing can be given
  interactively


git-svn-id: https://vsmartcard.svn.sourceforge.net/svnroot/vsmartcard@73 96b47cad-a561-4643-ad3b-153ac7d7599c
This commit is contained in:
frankmorgner
2010-04-15 07:37:32 +00:00
parent b798a6e3a2
commit 35f75abe1d
8 changed files with 248 additions and 140 deletions

View File

@@ -23,6 +23,32 @@ INSTALLATION
See file INSTALL. See file INSTALL.
HINTS ON GADGETFS
-----------------
To create an USB Gadget in both USB host and USB client mode, you need to load
the kernel module gadgetfs. A guide focused on Debian based systems to run and
compile gadgetfs, you can find here:
http://wiki.openmoko.org/wiki/Building_Gadget_USB_Module
On OpenMoko it is likely, that you need to patch your kernel (see
http://docs.openmoko.org/trac/ticket/2206). If you also want to switch multiple
times between gadgetfs and g_ether an other patch is needed (see
https://docs.openmoko.org/trac/ticket/2240).
USAGE
-----
When testing PACE with either PIN, CAN, MRZ or PUK, the program will be in
interactive mode. Here you can enter APDUs which are to be converted according
to the secure messaging parameter and to be sent to the card. Herefor insert
the APDU in hex with a colon to separate the bytes or without it. So to read
the current selected file both of these forms would be valid:
00:b0:02:00:00
00B0020000
QUESTIONS QUESTIONS
--------- ---------

View File

@@ -171,7 +171,7 @@ void ccid_shutdown()
sc_release_context(ctx); sc_release_context(ctx);
} }
static int build_apdu(const __u8 *buf, size_t len, sc_apdu_t *apdu) int build_apdu(const __u8 *buf, size_t len, sc_apdu_t *apdu)
{ {
const __u8 *p; const __u8 *p;
size_t len0; size_t len0;
@@ -230,7 +230,7 @@ static int build_apdu(const __u8 *buf, size_t len, sc_apdu_t *apdu)
apdu->flags = SC_APDU_FLAGS_NO_GET_RESP|SC_APDU_FLAGS_NO_RETRY_WL; apdu->flags = SC_APDU_FLAGS_NO_GET_RESP|SC_APDU_FLAGS_NO_RETRY_WL;
sc_error(ctx, "APDU, %d byte(s):\tins=%02x p1=%02x p2=%02x", sc_debug(ctx, "APDU, %d bytes:\tins=%02x p1=%02x p2=%02x",
(unsigned int) len0, apdu->ins, apdu->p1, apdu->p2); (unsigned int) len0, apdu->ins, apdu->p1, apdu->p2);
SC_FUNC_RETURN(ctx, SC_LOG_TYPE_VERBOSE, SC_SUCCESS); SC_FUNC_RETURN(ctx, SC_LOG_TYPE_VERBOSE, SC_SUCCESS);
@@ -269,8 +269,9 @@ static int get_rapdu(sc_apdu_t *apdu, size_t slot, __u8 **buf, size_t *resplen)
*buf = apdu->resp; *buf = apdu->resp;
*resplen = apdu->resplen + sizeof(__u8) + sizeof(__u8); *resplen = apdu->resplen + sizeof(__u8) + sizeof(__u8);
sc_debug(ctx, "R-APDU, %d byte(s):\tsw1=%02x sw2=%02x", sc_debug(ctx, "R-APDU, %d byte%s:\tsw1=%02x sw2=%02x",
(unsigned int) *resplen, apdu->sw1, apdu->sw2); (unsigned int) *resplen, !*resplen ? "" : "s",
apdu->sw1, apdu->sw2);
SC_FUNC_RETURN(ctx, SC_LOG_TYPE_VERBOSE, SC_SUCCESS); SC_FUNC_RETURN(ctx, SC_LOG_TYPE_VERBOSE, SC_SUCCESS);
@@ -1296,19 +1297,19 @@ int ccid_state_changed(RDR_to_PC_NotifySlotChange_t **slotchange, int timeout)
return 0; return 0;
} }
int ccid_testpace() int ccid_testpace(u8 pin_id, const char *pin, size_t pinlen)
{ {
int i; int i;
for (i = 0; i < sizeof *card_in_slot; i++) { for (i = 0; i < sizeof *card_in_slot; i++) {
if (!card_in_slot[i] if (sc_detect_card_presence(reader, 0) & SC_SLOT_CARD_PRESENT) {
&& (sc_detect_card_presence(reader, 0) & SC_SLOT_CARD_PRESENT)) { if (!card_in_slot[i] || !sc_card_valid(card_in_slot[i])) {
sc_connect_card(reader, i, &card_in_slot[i]); sc_connect_card(reader, i, &card_in_slot[i]);
} }
return pace_test(card_in_slot[i], pin_id, pin, pinlen);
if (sc_card_valid(card_in_slot[i])) {
return pace_test(card_in_slot[i]);
} }
} }
sc_error(ctx, "No card found.");
return SC_ERROR_SLOT_NOT_FOUND; return SC_ERROR_SLOT_NOT_FOUND;
} }

View File

@@ -20,6 +20,7 @@
#define _CCID_H #define _CCID_H
#include <linux/usb/ch9.h> #include <linux/usb/ch9.h>
#include <opensc/opensc.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@@ -270,7 +271,9 @@ void ccid_shutdown();
int ccid_parse_bulkin(const __u8* inbuf, __u8** outbuf); int ccid_parse_bulkin(const __u8* inbuf, __u8** outbuf);
int ccid_parse_control(struct usb_ctrlrequest *setup, __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_state_changed(RDR_to_PC_NotifySlotChange_t **slotchange, int timeout);
int ccid_testpace(); int ccid_testpace(u8 pin_id, const char *pin, size_t pinlen);
int build_apdu(const __u8 *buf, size_t len, sc_apdu_t *apdu);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@@ -18,6 +18,8 @@
*/ */
#include "pace.h" #include "pace.h"
#include "sm.h" #include "sm.h"
#include "ccid.h"
#include <stdio.h>
#include <opensc/log.h> #include <opensc/log.h>
#include <openssl/evp.h> #include <openssl/evp.h>
#include <openssl/asn1.h> #include <openssl/asn1.h>
@@ -139,14 +141,18 @@ IMPLEMENT_ASN1_FUNCTIONS(PACE_GEN_AUTH_R)
#ifdef NO_PACE #ifdef NO_PACE
inline int GetReadersPACECapabilities(sc_card_t *card, inline int GetReadersPACECapabilities(sc_card_t *card,
const __u8 *in, __u8 **out, size_t *outlen) { const __u8 *in, __u8 **out, size_t *outlen)
{
SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_ERROR, SC_ERROR_NOT_SUPPORTED); SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_ERROR, SC_ERROR_NOT_SUPPORTED);
} }
inline int EstablishPACEChannel(sc_card_t *card, const __u8 *in, inline int EstablishPACEChannel(sc_card_t *card, const __u8 *in,
__u8 **out, size_t *outlen, struct sm_ctx *sm_ctx) { __u8 **out, size_t *outlen, struct sm_ctx *sm_ctx)
{
SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_ERROR, SC_ERROR_NOT_SUPPORTED); SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_ERROR, SC_ERROR_NOT_SUPPORTED);
} }
int pace_test(sc_card_t *card) { int pace_test(sc_card_t *card,
enum s_type pin_id, const char *pin, size_t pinlen)
{
SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_ERROR, SC_ERROR_NOT_SUPPORTED); SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_ERROR, SC_ERROR_NOT_SUPPORTED);
} }
int pace_sm_encrypt(sc_card_t *card, struct *sm_ctx, int pace_sm_encrypt(sc_card_t *card, struct *sm_ctx,
@@ -567,9 +573,10 @@ 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, u8 pin_id)
{ {
sc_ui_hints_t hints; sc_ui_hints_t hints;
char *p; char *p = NULL;
PACE_SEC *r; PACE_SEC *r;
int sc_result; int sc_result;
size_t len;
if (pin && length_pin) if (pin && length_pin)
return PACE_SEC_new(pin, length_pin, pin_id); return PACE_SEC_new(pin, length_pin, pin_id);
@@ -577,22 +584,8 @@ get_psec(sc_card_t *card, const char *pin, size_t length_pin, u8 pin_id)
memset(&hints, 0, sizeof(hints)); memset(&hints, 0, sizeof(hints));
hints.dialog_name = "ccid.PACE"; hints.dialog_name = "ccid.PACE";
hints.card = card; hints.card = card;
switch (pin_id) { hints.prompt = NULL;
case PACE_MRZ: hints.obj_label = pace_secret_name(pin_id);
hints.prompt = "Enter MRZ";
break;
case PACE_CAN:
hints.prompt = "Enter CAN";
break;
case PACE_PIN:
hints.prompt = "Enter PIN";
break;
case PACE_PUK:
hints.prompt = "Enter PUK";
break;
default:
return NULL;
}
hints.usage = SC_UI_USAGE_OTHER; hints.usage = SC_UI_USAGE_OTHER;
sc_result = sc_ui_get_pin(&hints, &p); sc_result = sc_ui_get_pin(&hints, &p);
if (sc_result < 0) { if (sc_result < 0) {
@@ -601,9 +594,12 @@ get_psec(sc_card_t *card, const char *pin, size_t length_pin, u8 pin_id)
return NULL; return NULL;
} }
r = PACE_SEC_new(p, strlen(p), pin_id); len = strlen(p);
r = PACE_SEC_new(p, len, pin_id);
OPENSSL_cleanse(p, strlen(p)); if (len) {
OPENSSL_cleanse(p, len);
}
free(p); free(p);
return r; return r;
@@ -838,11 +834,33 @@ err:
SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_DEBUG, r); SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_DEBUG, r);
} }
int pace_test(sc_card_t *card) static const char *MRZ_name = "MRZ";
static const char *PIN_name = "PIN";
static const char *PUK_name = "PUK";
static const char *CAN_name = "CAN";
static const char *UNDEF_name = "UNDEF";
const char *pace_secret_name(enum s_type pin_id) {
switch (pin_id) {
case PACE_MRZ:
return MRZ_name;
case PACE_PUK:
return PUK_name;
case PACE_PIN:
return PIN_name;
case PACE_CAN:
return CAN_name;
default:
return UNDEF_name;
}
}
int pace_test(sc_card_t *card,
enum s_type pin_id, const char *pin, size_t pinlen)
{ {
__u8 in[16], buf[SC_MAX_APDU_BUFFER_SIZE - 2]; u8 buf[0xff + 5];
char *read = NULL;
__u8 *out = NULL; __u8 *out = NULL;
size_t outlen; size_t outlen, readlen = 0, linelen, apdulen;
struct sm_ctx sctx; struct sm_ctx sctx;
sc_apdu_t apdu; sc_apdu_t apdu;
int r; int r;
@@ -850,68 +868,76 @@ int pace_test(sc_card_t *card)
memset(&sctx, 0, sizeof(sctx)); memset(&sctx, 0, sizeof(sctx));
memset(&apdu, 0, sizeof(apdu)); memset(&apdu, 0, sizeof(apdu));
in[0] = PACE_CAN; // pin_id switch (pin_id) {
in[1] = 0; // length_chat case PACE_MRZ:
in[2] = 6; // length_pin case PACE_CAN:
in[3] = '8'; case PACE_PIN:
in[4] = '4'; case PACE_PUK:
in[5] = '0'; break;
in[6] = '1'; default:
in[7] = '7'; sc_error(card->ctx, "Type of secret not supported");
in[8] = '9'; return SC_ERROR_INVALID_ARGUMENTS;
in[9] = 0; // length_cert_desc }
in[10]= 0; // length_cert_desc
SC_TEST_RET(card->ctx, EstablishPACEChannel(card, in, &out, &outlen, &sctx), if (pinlen > sizeof(buf) - 5) {
sc_error(card->ctx, "%s too long (maximal %u bytes supported)",
pace_secret_name(pin_id),
sizeof(buf) - 5);
}
buf[0] = pin_id;
buf[1] = 0; // length_chat
buf[2] = pinlen; // length_pin
memcpy(&buf[3], pin, pinlen);
buf[3 + pinlen] = 0; // length_cert_desc
buf[4 + pinlen]= 0; // length_cert_desc
SC_TEST_RET(card->ctx,
EstablishPACEChannel(card, buf, &out, &outlen, &sctx),
"Could not establish PACE channel."); "Could not establish PACE channel.");
/* select CardSecurity */ while (1) {
apdu.cla = 0x00; printf("Enter unencrypted APDU (empty line to exit)\n");
apdu.ins = 0xA4;
apdu.p1 = 0x08;
apdu.p2 = 0x00;
in[0] = 0x01;
in[1] = 0x1D;
apdu.data = in;
apdu.datalen = 2;
apdu.lc = apdu.datalen;
apdu.le = 0x00;
apdu.resp = buf;
apdu.resplen = sizeof buf;
apdu.cse = SC_APDU_CASE_4_SHORT;
r = pace_transmit_apdu(&sctx, card, &apdu);
if (r < 0)
sc_error(card->ctx, "Could not select EF.CardSecurity: %s",
sc_strerror(r));
/* read CardSecurity */ linelen = getline(&read, &readlen, stdin);
apdu.cla = 0x00; if (linelen <= 1) {
apdu.ins = 0xB0; if (linelen < 0) {
apdu.p1 = 0x02; r = SC_ERROR_INTERNAL;
apdu.p2 = 0x00; sc_error(card->ctx, "Could not read line");
apdu.le = 0x00; } else {
apdu.resp = buf; r = SC_SUCCESS;
apdu.resplen = sizeof buf; printf("Thanks for flying with ccid\n");
apdu.cse = SC_APDU_CASE_2_SHORT; }
r = pace_transmit_apdu(&sctx, card, &apdu); break;
if (r < 0) }
sc_error(card->ctx, "Could not read EF.CardSecurity: %s",
sc_strerror(r));
/* reset retry counter */ read[linelen - 1] = 0;
apdu.cla = 0x00; if (sc_hex_to_bin(read, buf, &apdulen) < 0) {
apdu.ins = 0x2C; sc_error(card->ctx, "Could not format binary string");
apdu.p1 = 0x03; }
apdu.p2 = 0x02;
apdu.resp = buf;
apdu.resplen = sizeof buf;
apdu.cse = SC_APDU_CASE_1;
r = pace_transmit_apdu(&sctx, card, &apdu);
if (r < 0)
sc_error(card->ctx, "Could not reset retry counter of CAN: %s",
sc_strerror(r));
return SC_SUCCESS; r = build_apdu(buf, apdulen, &apdu);
if (r < 0) {
sc_error(card->ctx, "Could not format APDU");
continue;
}
apdu.resp = buf;
apdu.resplen = sizeof(buf);
r = pace_transmit_apdu(&sctx, card, &apdu);
if (r < 0) {
sc_error(card->ctx, "Could not send APDU: %s", sc_strerror(r));
continue;
}
printf("Decrypted APDU sw1=%02x sw2=%02x\n", apdu.sw1, apdu.sw2);
bin_print(stdout, "Decrypted APDU response data", apdu.resp, apdu.resplen);
}
if (read)
free(read);
SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_ERROR, r);
} }
static int static int

View File

@@ -62,6 +62,8 @@ int increment_ssc(struct pace_sm_ctx *psmctx);
int decrement_ssc(struct pace_sm_ctx *psmctx); int decrement_ssc(struct pace_sm_ctx *psmctx);
int reset_ssc(struct pace_sm_ctx *psmctx); int reset_ssc(struct pace_sm_ctx *psmctx);
const char *pace_secret_name(enum s_type pin_id);
int pace_sm_encrypt(sc_card_t *card, const struct sm_ctx *ctx, int pace_sm_encrypt(sc_card_t *card, const struct sm_ctx *ctx,
const u8 *data, size_t datalen, u8 **enc); const u8 *data, size_t datalen, u8 **enc);
int pace_sm_decrypt(sc_card_t *card, const struct sm_ctx *ctx, int pace_sm_decrypt(sc_card_t *card, const struct sm_ctx *ctx,
@@ -76,7 +78,8 @@ int GetReadersPACECapabilities(sc_card_t *card, const __u8
*in, __u8 **out, size_t *outlen); *in, __u8 **out, size_t *outlen);
int EstablishPACEChannel(sc_card_t *card, const __u8 *in, int EstablishPACEChannel(sc_card_t *card, const __u8 *in,
__u8 **out, size_t *outlen, struct sm_ctx *ctx); __u8 **out, size_t *outlen, struct sm_ctx *ctx);
int pace_test(sc_card_t *card); int pace_test(sc_card_t *card,
enum s_type pin_id, const char *pin, size_t pinlen);
int pace_transmit_apdu(struct sm_ctx *sctx, sc_card_t *card, int pace_transmit_apdu(struct sm_ctx *sctx, sc_card_t *card,
sc_apdu_t *apdu); sc_apdu_t *apdu);

View File

@@ -45,15 +45,22 @@ static const struct sc_asn1_entry c_sm_rapdu[] = {
}; };
void _bin_log(sc_context_t *ctx, int type, const char *file, int line, void _bin_log(sc_context_t *ctx, int type, const char *file, int line,
const char *func, const char *label, const u8 *data, size_t len) const char *func, const char *label, const u8 *data, size_t len,
FILE *f)
{ {
char buf[1024]; char buf[1024];
sc_hex_dump(ctx, data, len, buf, sizeof buf); sc_hex_dump(ctx, data, len, buf, sizeof buf);
sc_do_log(ctx, type, file, line, func, if (!f) {
"\n%s (%u byte%s):\n%s" sc_do_log(ctx, type, file, line, func,
"======================================================================", "\n%s (%u byte%s):\n%s"
label, len, len==1?"":"s", buf); "======================================================================",
label, len, len==1?"":"s", buf);
} else {
fprintf(f, "%s (%u byte%s):\n%s"
"======================================================================\n",
label, len, len==1?"":"s", buf);
}
} }
int int

View File

@@ -53,10 +53,13 @@ int add_iso_pad(const u8 *data, size_t datalen, int block_size, u8 **padded);
int add_padding(const struct sm_ctx *ctx, const u8 *data, size_t datalen, int add_padding(const struct sm_ctx *ctx, const u8 *data, size_t datalen,
u8 **padded); u8 **padded);
#define bin_print(file, label, data, len) \
_bin_log(NULL, 0, NULL, 0, NULL, label, data, len, file)
#define bin_log(ctx, label, data, len) \ #define bin_log(ctx, label, data, len) \
_bin_log(ctx, SC_LOG_TYPE_DEBUG, __FILE__, __LINE__, __FUNCTION__, label, data, len) _bin_log(ctx, SC_LOG_TYPE_DEBUG, __FILE__, __LINE__, __FUNCTION__, label, data, len, NULL)
void _bin_log(sc_context_t *ctx, int type, const char *file, int line, void _bin_log(sc_context_t *ctx, int type, const char *file, int line,
const char *func, const char *label, const u8 *data, size_t len); const char *func, const char *label, const u8 *data, size_t len,
FILE *f);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@@ -47,7 +47,7 @@
#include "usbstring.h" #include "usbstring.h"
#include "ccid.h" #include "ccid.h"
#include "pace.h"
#define DRIVER_VENDOR_NUM 0x0D46 /* KOBIL Systems */ #define DRIVER_VENDOR_NUM 0x0D46 /* KOBIL Systems */
#define DRIVER_PRODUCT_NUM 0x3010 /* KOBIL Class 3 Reader */ #define DRIVER_PRODUCT_NUM 0x3010 /* KOBIL Class 3 Reader */
@@ -57,31 +57,51 @@ static int verbose = 0;
static int debug = 0; static int debug = 0;
static int dohid = 0; static int dohid = 0;
static int doint = 0; static int doint = 0;
static int dotest = 0; static u8 dopacetest = 0;
static int usb_reader_num = -1; static int usb_reader_num = -1;
static const char *pin;
#define OPT_HELP 'h'
#define OPT_INTERRUPT 'n'
#define OPT_READER 'r'
#define OPT_SERIAL 's'
#define OPT_PIN 'i'
#define OPT_PUK 'u'
#define OPT_CAN 'a'
#define OPT_MRZ 'z'
#define OPT_PRODUCT 'p'
#define OPT_VENDOR 'e'
#define OPT_VERBOSE 'v'
#define OPT_VERSION 'o'
static const struct option options[] = { static const struct option options[] = {
/*{ "hid", no_argument, &dohid, 1 },*/ /*{ "hid", no_argument, &dohid, 1 },*/
{ "help", no_argument, NULL, 'h' }, { "help", no_argument, NULL, OPT_HELP },
{ "interrupt", no_argument, &doint, 'n' }, { "reader", required_argument, NULL, OPT_READER },
{ "reader", required_argument, NULL, 'r' }, { "test-pin", optional_argument, NULL, OPT_PIN },
{ "serial", required_argument, NULL, 's' }, { "test-puk", optional_argument, NULL, OPT_PUK },
{ "test-pace", no_argument, &dotest, 't' }, { "test-can", optional_argument, NULL, OPT_CAN },
{ "product", required_argument, NULL, 'p' }, { "test-mrz", optional_argument, NULL, OPT_MRZ },
{ "vendor", required_argument, NULL, 'e' }, { "serial", required_argument, NULL, OPT_SERIAL },
{ "verbose", no_argument, NULL, 'v' }, { "product", required_argument, NULL, OPT_PRODUCT },
{ "version", no_argument, NULL, 'i' }, { "vendor", required_argument, NULL, OPT_VENDOR },
{ "interrupt", no_argument, &doint, OPT_INTERRUPT },
{ "verbose", no_argument, NULL, OPT_VERBOSE },
{ "version", no_argument, NULL, OPT_VERSION },
{ NULL, 0, NULL, 0 } { NULL, 0, NULL, 0 }
}; };
static const char *option_help[] = { static const char *option_help[] = {
/*"Emulate HID device",*/ /*"Emulate HID device",*/
"Print help and exit", "Print help and exit",
"Number of reader to use (default: auto-detect)",
"Run PACE with PIN",
"Run PACE with PUK",
"Run PACE with CAN",
"Run PACE with MRZ",
"USB serial number (default: random)",
"USB product ID (default: 0x3010)",
"USB vendor ID (default: 0x0D46)",
"Add interrupt pipe for CCID", "Add interrupt pipe for CCID",
"Number of the reader to use (default: auto-detect)",
"Serial number (max 56 bytes) of gadget (default: random)",
"test PACE implementation",
"USB product ID (default: 0x3010)",
"USB vendor ID (0default: x0D46)",
"Use (several times) to be more verbose", "Use (several times) to be more verbose",
"Print version and exit.", "Print version and exit.",
}; };
@@ -1081,7 +1101,6 @@ error:
static void *hid (void *param) static void *hid (void *param)
{ {
printf("%s:%d\n", __FILE__, __LINE__);
char **names = (char **) param; char **names = (char **) param;
char *status_name = names[0]; char *status_name = names[0];
int result = 0; int result = 0;
@@ -1718,11 +1737,11 @@ void print_usage(const char *app_name, const struct option options[],
break; break;
} }
sprintf(buf, "--%s%s%s", options[i].name, tmp, arg_str); sprintf(buf, "--%s%s%s", options[i].name, tmp, arg_str);
if (strlen(buf) > 20) { if (strlen(buf) > 22) {
printf(" %s\n", buf); printf(" %s\n", buf);
buf[0] = '\0'; buf[0] = '\0';
} }
printf(" %-20s %s\n", buf, option_help[i]); printf(" %-22s %s\n", buf, option_help[i]);
i++; i++;
} }
} }
@@ -1749,41 +1768,72 @@ main (int argc, char **argv)
} }
while (1) { while (1) {
c = getopt_long(argc, argv, "r:s:p:e:vih", options, &long_optind); c = getopt_long(argc, argv, "hnr:s:i::u::a::z::p:e:vo", options, &long_optind);
if (c == -1) if (c == -1)
break; break;
if (c == '?' || c == 'h') { if (c == '?' || c == OPT_HELP) {
print_usage(argv[0] , options, option_help); print_usage(argv[0] , options, option_help);
exit(0); exit(0);
} }
switch (c) { switch (c) {
case 'r': case OPT_READER:
if (sscanf(optarg, "%d", &usb_reader_num) != 1) if (sscanf(optarg, "%d", &usb_reader_num) != 1)
parse_error(argv[0], optarg, long_optind); parse_error(argv[0], optarg, long_optind);
break; break;
case 's': case OPT_SERIAL:
if (sscanf(optarg, "%56s", serial) != 1) if (sscanf(optarg, "%56s", serial) != 1)
parse_error(argv[0], optarg, long_optind); parse_error(argv[0], optarg, long_optind);
break; break;
case 'p': case OPT_PRODUCT:
if (sscanf(optarg, "%x", &productid) != 1) if (sscanf(optarg, "%x", &productid) != 1)
parse_error(argv[0], optarg, long_optind); parse_error(argv[0], optarg, long_optind);
break; break;
case 'e': case OPT_VENDOR:
if (sscanf(optarg, "%x", &vendorid) != 1) if (sscanf(optarg, "%x", &vendorid) != 1)
parse_error(argv[0], optarg, long_optind); parse_error(argv[0], optarg, long_optind);
break; break;
case 'v': case OPT_VERBOSE:
verbose++; verbose++;
break; break;
case 'i': case OPT_VERSION:
fprintf(stderr, "%s 0.9 written by Frank Morgner.\n" , fprintf(stderr, "%s 0.9 written by Frank Morgner.\n" ,
argv[0]); argv[0]);
exit(0); exit(0);
break; break;
case OPT_PUK:
/* PACE_PIN from openssl/pace.h */
dopacetest = 4;
pin = optarg;
break;
case OPT_PIN:
/* PACE_PIN from openssl/pace.h */
dopacetest = 3;
pin = optarg;
break;
case OPT_CAN:
/* PACE_PIN from openssl/pace.h */
dopacetest = 2;
pin = optarg;
break;
case OPT_MRZ:
/* PACE_PIN from openssl/pace.h */
dopacetest = 1;
pin = optarg;
break;
} }
} }
if (ccid_initialize(usb_reader_num, verbose) < 0) {
perror("Can't initialize ccid");
return 1;
}
if (dopacetest) {
i = ccid_testpace(dopacetest, pin, !pin ? 0 : strlen(pin));
ccid_shutdown();
return i;
}
if (verbose) if (verbose)
fprintf (stderr, "serial=\"%s\"\n", serial); fprintf (stderr, "serial=\"%s\"\n", serial);
@@ -1792,17 +1842,6 @@ main (int argc, char **argv)
return 1; return 1;
} }
if (ccid_initialize(usb_reader_num, verbose) < 0) {
perror("can't initialize ccid");
return 1;
}
if (dotest) {
i = ccid_testpace();
ccid_shutdown();
return i;
}
fd = init_device (); fd = init_device ();
if (fd < 0) if (fd < 0)
return 1; return 1;