mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-23 15:07:03 +01:00
* command.c (cmd_checkpin): New.
(register_commands): Add command CHECKPIN. * app.c (app_check_pin): New. * app-openpgp.c (check_against_given_fingerprint): New. Factored out that code elsewhere. (do_check_pin): New.
This commit is contained in:
parent
99277d21c1
commit
21be16dba9
@ -1,3 +1,20 @@
|
|||||||
|
2003-10-20 Werner Koch <wk@gnupg.org>
|
||||||
|
|
||||||
|
* command.c (cmd_checkpin): New.
|
||||||
|
(register_commands): Add command CHECKPIN.
|
||||||
|
* app.c (app_check_pin): New.
|
||||||
|
* app-openpgp.c (check_against_given_fingerprint): New. Factored
|
||||||
|
out that code elsewhere.
|
||||||
|
(do_check_pin): New.
|
||||||
|
|
||||||
|
2003-10-10 Werner Koch <wk@gnupg.org>
|
||||||
|
|
||||||
|
* ccid-driver.c (ccid_close_reader): New.
|
||||||
|
|
||||||
|
* apdu.c (close_ccid_reader, close_ct_reader, close_csc_reader)
|
||||||
|
(close_osc_reader, apdu_close_reader): New. Not all are properly
|
||||||
|
implemented yet.
|
||||||
|
|
||||||
2003-10-09 Werner Koch <wk@gnupg.org>
|
2003-10-09 Werner Koch <wk@gnupg.org>
|
||||||
|
|
||||||
* ccid-driver.c (ccid_transceive): Add T=1 chaining for sending.
|
* ccid-driver.c (ccid_transceive): Add T=1 chaining for sending.
|
||||||
|
137
scd/apdu.c
137
scd/apdu.c
@ -51,6 +51,13 @@
|
|||||||
insertion of the card (1 = don't wait). */
|
insertion of the card (1 = don't wait). */
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define DLSTDCALL __stdcall
|
||||||
|
#else
|
||||||
|
#define DLSTDCALL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* A structure to collect information pertaining to one reader
|
/* A structure to collect information pertaining to one reader
|
||||||
slot. */
|
slot. */
|
||||||
struct reader_table_s {
|
struct reader_table_s {
|
||||||
@ -84,12 +91,12 @@ static struct reader_table_s reader_table[MAX_READER];
|
|||||||
|
|
||||||
|
|
||||||
/* ct API function pointer. */
|
/* ct API function pointer. */
|
||||||
static char (*CT_init) (unsigned short ctn, unsigned short Pn);
|
static char (* DLSTDCALL CT_init) (unsigned short ctn, unsigned short Pn);
|
||||||
static char (*CT_data) (unsigned short ctn, unsigned char *dad,
|
static char (* DLSTDCALL CT_data) (unsigned short ctn, unsigned char *dad,
|
||||||
unsigned char *sad, unsigned short lc,
|
unsigned char *sad, unsigned short lc,
|
||||||
unsigned char *cmd, unsigned short *lr,
|
unsigned char *cmd, unsigned short *lr,
|
||||||
unsigned char *rsp);
|
unsigned char *rsp);
|
||||||
static char (*CT_close) (unsigned short ctn);
|
static char (* DLSTDCALL CT_close) (unsigned short ctn);
|
||||||
|
|
||||||
/* PC/SC constants and function pointer. */
|
/* PC/SC constants and function pointer. */
|
||||||
#define PCSC_SCOPE_USER 0
|
#define PCSC_SCOPE_USER 0
|
||||||
@ -117,34 +124,38 @@ struct pcsc_io_request_s {
|
|||||||
|
|
||||||
typedef struct pcsc_io_request_s *pcsc_io_request_t;
|
typedef struct pcsc_io_request_s *pcsc_io_request_t;
|
||||||
|
|
||||||
long (*pcsc_establish_context) (unsigned long scope,
|
long (* DLSTDCALL pcsc_establish_context) (unsigned long scope,
|
||||||
const void *reserved1,
|
const void *reserved1,
|
||||||
const void *reserved2,
|
const void *reserved2,
|
||||||
unsigned long *r_context);
|
unsigned long *r_context);
|
||||||
long (*pcsc_release_context) (unsigned long context);
|
long (* DLSTDCALL pcsc_release_context) (unsigned long context);
|
||||||
long (*pcsc_list_readers) (unsigned long context, const char *groups,
|
long (* DLSTDCALL pcsc_list_readers) (unsigned long context,
|
||||||
char *readers, unsigned long *readerslen);
|
const char *groups,
|
||||||
long (*pcsc_connect) (unsigned long context,
|
char *readers, unsigned long*readerslen);
|
||||||
const char *reader,
|
long (* DLSTDCALL pcsc_connect) (unsigned long context,
|
||||||
unsigned long share_mode,
|
const char *reader,
|
||||||
unsigned long preferred_protocols,
|
unsigned long share_mode,
|
||||||
unsigned long *r_card,
|
unsigned long preferred_protocols,
|
||||||
unsigned long *r_active_protocol);
|
unsigned long *r_card,
|
||||||
long (*pcsc_disconnect) (unsigned long card, unsigned long disposition);
|
unsigned long *r_active_protocol);
|
||||||
long (*pcsc_status) (unsigned long card,
|
long (* DLSTDCALL pcsc_disconnect) (unsigned long card,
|
||||||
char *reader, unsigned long *readerlen,
|
unsigned long disposition);
|
||||||
unsigned long *r_state, unsigned long *r_protocol,
|
long (* DLSTDCALL pcsc_status) (unsigned long card,
|
||||||
unsigned char *atr, unsigned long *atrlen);
|
char *reader, unsigned long *readerlen,
|
||||||
long (*pcsc_begin_transaction) (unsigned long card);
|
unsigned long *r_state,
|
||||||
long (*pcsc_end_transaction) (unsigned long card);
|
unsigned long *r_protocol,
|
||||||
long (*pcsc_transmit) (unsigned long card,
|
unsigned char *atr, unsigned long *atrlen);
|
||||||
const pcsc_io_request_t send_pci,
|
long (* DLSTDCALL pcsc_begin_transaction) (unsigned long card);
|
||||||
const unsigned char *send_buffer,
|
long (* DLSTDCALL pcsc_end_transaction) (unsigned long card);
|
||||||
unsigned long send_len,
|
long (* DLSTDCALL pcsc_transmit) (unsigned long card,
|
||||||
pcsc_io_request_t recv_pci,
|
const pcsc_io_request_t send_pci,
|
||||||
unsigned char *recv_buffer,
|
const unsigned char *send_buffer,
|
||||||
unsigned long *recv_len);
|
unsigned long send_len,
|
||||||
long (*pcsc_set_timeout) (unsigned long context, unsigned long timeout);
|
pcsc_io_request_t recv_pci,
|
||||||
|
unsigned char *recv_buffer,
|
||||||
|
unsigned long *recv_len);
|
||||||
|
long (* DLSTDCALL pcsc_set_timeout) (unsigned long context,
|
||||||
|
unsigned long timeout);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -347,6 +358,14 @@ open_ct_reader (int port)
|
|||||||
return reader;
|
return reader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
close_ct_reader (int slot)
|
||||||
|
{
|
||||||
|
/* FIXME: Implement. */
|
||||||
|
reader_table[slot].used = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Actually send the APDU of length APDULEN to SLOT and return a
|
/* Actually send the APDU of length APDULEN to SLOT and return a
|
||||||
maximum of *BUFLEN data in BUFFER, the actual retruned size will be
|
maximum of *BUFLEN data in BUFFER, the actual retruned size will be
|
||||||
@ -570,6 +589,17 @@ pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
|
|||||||
return err? -1:0; /* FIXME: Return appropriate error code. */
|
return err? -1:0; /* FIXME: Return appropriate error code. */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
close_pcsc_reader (int slot)
|
||||||
|
{
|
||||||
|
/* FIXME: Implement. */
|
||||||
|
reader_table[slot].used = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef HAVE_LIBUSB
|
#ifdef HAVE_LIBUSB
|
||||||
/*
|
/*
|
||||||
@ -609,6 +639,15 @@ open_ccid_reader (void)
|
|||||||
return slot;
|
return slot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
close_ccid_reader (int slot)
|
||||||
|
{
|
||||||
|
ccid_close_reader (reader_table[slot].ccid.handle);
|
||||||
|
reader_table[slot].used = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Actually send the APDU of length APDULEN to SLOT and return a
|
/* Actually send the APDU of length APDULEN to SLOT and return a
|
||||||
maximum of *BUFLEN data in BUFFER, the actual returned size will be
|
maximum of *BUFLEN data in BUFFER, the actual returned size will be
|
||||||
@ -738,6 +777,16 @@ open_osc_reader (int portno)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
close_osc_reader (int slot)
|
||||||
|
{
|
||||||
|
/* FIXME: Implement. */
|
||||||
|
reader_table[slot].used = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Actually send the APDU of length APDULEN to SLOT and return a
|
/* Actually send the APDU of length APDULEN to SLOT and return a
|
||||||
maximum of *BUFLEN data in BUFFER, the actual returned size will be
|
maximum of *BUFLEN data in BUFFER, the actual returned size will be
|
||||||
set to BUFLEN. Returns: OpenSC error code. */
|
set to BUFLEN. Returns: OpenSC error code. */
|
||||||
@ -940,6 +989,26 @@ apdu_open_reader (const char *portstr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
apdu_close_reader (int slot)
|
||||||
|
{
|
||||||
|
if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
|
||||||
|
return SW_HOST_NO_DRIVER;
|
||||||
|
if (reader_table[slot].is_ctapi)
|
||||||
|
return close_ct_reader (slot);
|
||||||
|
#ifdef HAVE_LIBUSB
|
||||||
|
else if (reader_table[slot].is_ccid)
|
||||||
|
return close_ccid_reader (slot);
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_OPENSC
|
||||||
|
else if (reader_table[slot].is_osc)
|
||||||
|
return close_osc_reader (slot);
|
||||||
|
#endif
|
||||||
|
else
|
||||||
|
return close_pcsc_reader (slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
unsigned char *
|
unsigned char *
|
||||||
apdu_get_atr (int slot, size_t *atrlen)
|
apdu_get_atr (int slot, size_t *atrlen)
|
||||||
{
|
{
|
||||||
|
@ -54,6 +54,7 @@ enum {
|
|||||||
|
|
||||||
/* Note , that apdu_open_reader returns no status word but -1 on error. */
|
/* Note , that apdu_open_reader returns no status word but -1 on error. */
|
||||||
int apdu_open_reader (const char *portstr);
|
int apdu_open_reader (const char *portstr);
|
||||||
|
int apdu_close_reader (int slot);
|
||||||
unsigned char *apdu_get_atr (int slot, size_t *atrlen);
|
unsigned char *apdu_get_atr (int slot, size_t *atrlen);
|
||||||
|
|
||||||
|
|
||||||
|
@ -65,6 +65,9 @@ struct app_ctx_s {
|
|||||||
const char *chvnostr, int reset_mode,
|
const char *chvnostr, int reset_mode,
|
||||||
int (*pincb)(void*, const char *, char **),
|
int (*pincb)(void*, const char *, char **),
|
||||||
void *pincb_arg);
|
void *pincb_arg);
|
||||||
|
int (*check_pin) (APP app, const char *keyidstr,
|
||||||
|
int (pincb)(void*, const char *, char **),
|
||||||
|
void *pincb_arg);
|
||||||
} fnc;
|
} fnc;
|
||||||
|
|
||||||
|
|
||||||
@ -106,6 +109,9 @@ int app_get_challenge (APP app, size_t nbytes, unsigned char *buffer);
|
|||||||
int app_change_pin (APP app, CTRL ctrl, const char *chvnostr, int reset_mode,
|
int app_change_pin (APP app, CTRL ctrl, const char *chvnostr, int reset_mode,
|
||||||
int (*pincb)(void*, const char *, char **),
|
int (*pincb)(void*, const char *, char **),
|
||||||
void *pincb_arg);
|
void *pincb_arg);
|
||||||
|
int app_check_pin (APP app, const char *keyidstr,
|
||||||
|
int (*pincb)(void*, const char *, char **),
|
||||||
|
void *pincb_arg);
|
||||||
|
|
||||||
|
|
||||||
/*-- app-openpgp.c --*/
|
/*-- app-openpgp.c --*/
|
||||||
|
@ -912,6 +912,33 @@ compare_fingerprint (APP app, int keyno, unsigned char *sha1fpr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* If a fingerprint has been specified check it against the one on
|
||||||
|
the card. This is allows for a meaningful error message in case
|
||||||
|
the key on the card has been replaced but the shadow information
|
||||||
|
known to gpg was not updated. If there is no fingerprint we
|
||||||
|
assume that this is okay. */
|
||||||
|
static int
|
||||||
|
check_against_given_fingerprint (APP app, const char *fpr, int keyno)
|
||||||
|
{
|
||||||
|
unsigned char tmp[20];
|
||||||
|
const char *s;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
for (s=fpr, n=0; hexdigitp (s); s++, n++)
|
||||||
|
;
|
||||||
|
if (n != 40)
|
||||||
|
return gpg_error (GPG_ERR_INV_ID);
|
||||||
|
else if (!*s)
|
||||||
|
; /* okay */
|
||||||
|
else
|
||||||
|
return gpg_error (GPG_ERR_INV_ID);
|
||||||
|
|
||||||
|
for (s=fpr, n=0; n < 20; s += 2, n++)
|
||||||
|
tmp[n] = xtoi_2 (s);
|
||||||
|
return compare_fingerprint (app, keyno, tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Compute a digital signature on INDATA which is expected to be the
|
/* Compute a digital signature on INDATA which is expected to be the
|
||||||
raw message digest. For this application the KEYIDSTR consists of
|
raw message digest. For this application the KEYIDSTR consists of
|
||||||
@ -976,23 +1003,9 @@ do_sign (APP app, const char *keyidstr, int hashalgo,
|
|||||||
known to gpg was not updated. If there is no fingerprint, gpg
|
known to gpg was not updated. If there is no fingerprint, gpg
|
||||||
will detect a bogus signature anyway due to the
|
will detect a bogus signature anyway due to the
|
||||||
verify-after-signing feature. */
|
verify-after-signing feature. */
|
||||||
if (fpr)
|
rc = fpr? check_against_given_fingerprint (app, fpr, 1) : 0;
|
||||||
{
|
if (rc)
|
||||||
for (s=fpr, n=0; hexdigitp (s); s++, n++)
|
return rc;
|
||||||
;
|
|
||||||
if (n != 40)
|
|
||||||
return gpg_error (GPG_ERR_INV_ID);
|
|
||||||
else if (!*s)
|
|
||||||
; /* okay */
|
|
||||||
else
|
|
||||||
return gpg_error (GPG_ERR_INV_ID);
|
|
||||||
|
|
||||||
for (s=fpr, n=0; n < 20; s += 2, n++)
|
|
||||||
tmp_sn[n] = xtoi_2 (s);
|
|
||||||
rc = compare_fingerprint (app, 1, tmp_sn);
|
|
||||||
if (rc)
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hashalgo == GCRY_MD_SHA1)
|
if (hashalgo == GCRY_MD_SHA1)
|
||||||
memcpy (data, sha1_prefix, 15);
|
memcpy (data, sha1_prefix, 15);
|
||||||
@ -1107,23 +1120,9 @@ do_auth (APP app, const char *keyidstr,
|
|||||||
known to gpg was not updated. If there is no fingerprint, gpg
|
known to gpg was not updated. If there is no fingerprint, gpg
|
||||||
will detect a bogus signature anyway due to the
|
will detect a bogus signature anyway due to the
|
||||||
verify-after-signing feature. */
|
verify-after-signing feature. */
|
||||||
if (fpr)
|
rc = fpr? check_against_given_fingerprint (app, fpr, 3) : 0;
|
||||||
{
|
if (rc)
|
||||||
for (s=fpr, n=0; hexdigitp (s); s++, n++)
|
return rc;
|
||||||
;
|
|
||||||
if (n != 40)
|
|
||||||
return gpg_error (GPG_ERR_INV_ID);
|
|
||||||
else if (!*s)
|
|
||||||
; /* okay */
|
|
||||||
else
|
|
||||||
return gpg_error (GPG_ERR_INV_ID);
|
|
||||||
|
|
||||||
for (s=fpr, n=0; n < 20; s += 2, n++)
|
|
||||||
tmp_sn[n] = xtoi_2 (s);
|
|
||||||
rc = compare_fingerprint (app, 3, tmp_sn);
|
|
||||||
if (rc)
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = verify_chv2 (app, pincb, pincb_arg);
|
rc = verify_chv2 (app, pincb, pincb_arg);
|
||||||
if (!rc)
|
if (!rc)
|
||||||
@ -1177,23 +1176,9 @@ do_decipher (APP app, const char *keyidstr,
|
|||||||
the key on the card has been replaced but the shadow information
|
the key on the card has been replaced but the shadow information
|
||||||
known to gpg was not updated. If there is no fingerprint, the
|
known to gpg was not updated. If there is no fingerprint, the
|
||||||
decryption will won't produce the right plaintext anyway. */
|
decryption will won't produce the right plaintext anyway. */
|
||||||
if (fpr)
|
rc = fpr? check_against_given_fingerprint (app, fpr, 2) : 0;
|
||||||
{
|
if (rc)
|
||||||
for (s=fpr, n=0; hexdigitp (s); s++, n++)
|
return rc;
|
||||||
;
|
|
||||||
if (n != 40)
|
|
||||||
return gpg_error (GPG_ERR_INV_ID);
|
|
||||||
else if (!*s)
|
|
||||||
; /* okay */
|
|
||||||
else
|
|
||||||
return gpg_error (GPG_ERR_INV_ID);
|
|
||||||
|
|
||||||
for (s=fpr, n=0; n < 20; s += 2, n++)
|
|
||||||
tmp_sn[n] = xtoi_2 (s);
|
|
||||||
rc = compare_fingerprint (app, 2, tmp_sn);
|
|
||||||
if (rc)
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = verify_chv2 (app, pincb, pincb_arg);
|
rc = verify_chv2 (app, pincb, pincb_arg);
|
||||||
if (!rc)
|
if (!rc)
|
||||||
@ -1202,6 +1187,55 @@ do_decipher (APP app, const char *keyidstr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Perform a simple verify operation for CHV1 and CHV2, so that
|
||||||
|
further operations won't ask for CHV2 and it is possible to do a
|
||||||
|
cheap check on the PIN: If there is something wrong with the PIN
|
||||||
|
entry system, only the regular CHV will get blocked and not the
|
||||||
|
dangerous CHV3. KEYIDSTR is the usual card's serial number; an
|
||||||
|
optional fingerprint part will be ignored. */
|
||||||
|
static int
|
||||||
|
do_check_pin (APP app, const char *keyidstr,
|
||||||
|
int (pincb)(void*, const char *, char **),
|
||||||
|
void *pincb_arg)
|
||||||
|
{
|
||||||
|
unsigned char tmp_sn[20];
|
||||||
|
const char *s;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
if (!keyidstr || !*keyidstr)
|
||||||
|
return gpg_error (GPG_ERR_INV_VALUE);
|
||||||
|
|
||||||
|
/* Check whether an OpenPGP card of any version has been requested. */
|
||||||
|
if (strlen (keyidstr) < 32 || strncmp (keyidstr, "D27600012401", 12))
|
||||||
|
return gpg_error (GPG_ERR_INV_ID);
|
||||||
|
|
||||||
|
for (s=keyidstr, n=0; hexdigitp (s); s++, n++)
|
||||||
|
;
|
||||||
|
if (n != 32)
|
||||||
|
return gpg_error (GPG_ERR_INV_ID);
|
||||||
|
else if (!*s)
|
||||||
|
; /* No fingerprint given: we allow this for now. */
|
||||||
|
else if (*s == '/')
|
||||||
|
; /* We ignore a fingerprint. */
|
||||||
|
else
|
||||||
|
return gpg_error (GPG_ERR_INV_ID);
|
||||||
|
|
||||||
|
for (s=keyidstr, n=0; n < 16; s += 2, n++)
|
||||||
|
tmp_sn[n] = xtoi_2 (s);
|
||||||
|
|
||||||
|
if (app->serialnolen != 16)
|
||||||
|
return gpg_error (GPG_ERR_INV_CARD);
|
||||||
|
if (memcmp (app->serialno, tmp_sn, 16))
|
||||||
|
return gpg_error (GPG_ERR_WRONG_CARD);
|
||||||
|
/* Yes, there is a race conditions: The user might pull the card
|
||||||
|
right here and we won't notice that. However this is not a
|
||||||
|
problem and the check above is merely for a graceful failure
|
||||||
|
between operations. */
|
||||||
|
|
||||||
|
return verify_chv2 (app, pincb, pincb_arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Select the OpenPGP application on the card in SLOT. This function
|
/* Select the OpenPGP application on the card in SLOT. This function
|
||||||
@ -1262,6 +1296,7 @@ app_select_openpgp (APP app, unsigned char **sn, size_t *snlen)
|
|||||||
app->fnc.auth = do_auth;
|
app->fnc.auth = do_auth;
|
||||||
app->fnc.decipher = do_decipher;
|
app->fnc.decipher = do_decipher;
|
||||||
app->fnc.change_pin = do_change_pin;
|
app->fnc.change_pin = do_change_pin;
|
||||||
|
app->fnc.check_pin = do_check_pin;
|
||||||
}
|
}
|
||||||
|
|
||||||
leave:
|
leave:
|
||||||
|
23
scd/app.c
23
scd/app.c
@ -295,6 +295,29 @@ app_change_pin (APP app, CTRL ctrl, const char *chvnostr, int reset_mode,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Perform a VERIFY operation without doing anything lese. This may
|
||||||
|
be used to initialze a the PION cache for long lasting other
|
||||||
|
operations. Its use is highly application dependent. */
|
||||||
|
int
|
||||||
|
app_check_pin (APP app, const char *keyidstr,
|
||||||
|
int (*pincb)(void*, const char *, char **),
|
||||||
|
void *pincb_arg)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (!app || !keyidstr || !*keyidstr || !pincb)
|
||||||
|
return gpg_error (GPG_ERR_INV_VALUE);
|
||||||
|
if (!app->initialized)
|
||||||
|
return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
|
||||||
|
if (!app->fnc.check_pin)
|
||||||
|
return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
|
||||||
|
rc = app->fnc.check_pin (app, keyidstr, pincb, pincb_arg);
|
||||||
|
if (opt.verbose)
|
||||||
|
log_info ("operation check_pin result: %s\n", gpg_strerror (rc));
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -174,6 +174,12 @@ struct ccid_driver_s {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static int bulk_out (ccid_driver_t handle, unsigned char *msg, size_t msglen);
|
||||||
|
static int bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
|
||||||
|
size_t *nread, int expected_type, int seqno);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Convert a little endian stored 4 byte value into an unsigned
|
/* Convert a little endian stored 4 byte value into an unsigned
|
||||||
integer. */
|
integer. */
|
||||||
static unsigned int
|
static unsigned int
|
||||||
@ -182,6 +188,16 @@ convert_le_u32 (const unsigned char *buf)
|
|||||||
return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
|
return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
set_msg_len (unsigned char *msg, unsigned int length)
|
||||||
|
{
|
||||||
|
msg[1] = length;
|
||||||
|
msg[2] = length >> 8;
|
||||||
|
msg[3] = length >> 16;
|
||||||
|
msg[4] = length >> 24;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Parse a CCID descriptor, optionally print all available features
|
/* Parse a CCID descriptor, optionally print all available features
|
||||||
@ -482,6 +498,41 @@ ccid_open_reader (ccid_driver_t *handle, int readerno)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Close the reader HANDLE. */
|
||||||
|
int
|
||||||
|
ccid_close_reader (ccid_driver_t handle)
|
||||||
|
{
|
||||||
|
if (!handle || !handle->idev)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
unsigned char msg[100];
|
||||||
|
size_t msglen;
|
||||||
|
unsigned char seqno;
|
||||||
|
|
||||||
|
msg[0] = PC_to_RDR_IccPowerOff;
|
||||||
|
msg[5] = 0; /* slot */
|
||||||
|
msg[6] = seqno = handle->seqno++;
|
||||||
|
msg[7] = 0; /* RFU */
|
||||||
|
msg[8] = 0; /* RFU */
|
||||||
|
msg[9] = 0; /* RFU */
|
||||||
|
set_msg_len (msg, 0);
|
||||||
|
msglen = 10;
|
||||||
|
|
||||||
|
rc = bulk_out (handle, msg, msglen);
|
||||||
|
if (!rc)
|
||||||
|
bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_SlotStatus, seqno);
|
||||||
|
}
|
||||||
|
|
||||||
|
usb_release_interface (handle->idev, 0);
|
||||||
|
usb_close (handle->idev);
|
||||||
|
handle->idev = NULL;
|
||||||
|
free (handle);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Return False if a card is present and powered. */
|
/* Return False if a card is present and powered. */
|
||||||
int
|
int
|
||||||
ccid_check_card_presence (ccid_driver_t handle)
|
ccid_check_card_presence (ccid_driver_t handle)
|
||||||
@ -491,16 +542,6 @@ ccid_check_card_presence (ccid_driver_t handle)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
set_msg_len (unsigned char *msg, unsigned int length)
|
|
||||||
{
|
|
||||||
msg[1] = length;
|
|
||||||
msg[2] = length >> 8;
|
|
||||||
msg[3] = length >> 16;
|
|
||||||
msg[4] = length >> 24;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Write a MSG of length MSGLEN to the designated bulk out endpoint.
|
/* Write a MSG of length MSGLEN to the designated bulk out endpoint.
|
||||||
Returns 0 on success. */
|
Returns 0 on success. */
|
||||||
static int
|
static int
|
||||||
|
@ -60,6 +60,7 @@ struct ccid_driver_s;
|
|||||||
typedef struct ccid_driver_s *ccid_driver_t;
|
typedef struct ccid_driver_s *ccid_driver_t;
|
||||||
|
|
||||||
int ccid_open_reader (ccid_driver_t *handle, int readerno);
|
int ccid_open_reader (ccid_driver_t *handle, int readerno);
|
||||||
|
int ccid_close_reader (ccid_driver_t handle);
|
||||||
int ccid_get_atr (ccid_driver_t handle,
|
int ccid_get_atr (ccid_driver_t handle,
|
||||||
unsigned char *atr, size_t maxatrlen, size_t *atrlen);
|
unsigned char *atr, size_t maxatrlen, size_t *atrlen);
|
||||||
int ccid_transceive (ccid_driver_t handle,
|
int ccid_transceive (ccid_driver_t handle,
|
||||||
|
@ -923,6 +923,41 @@ cmd_passwd (ASSUAN_CONTEXT ctx, char *line)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* CHECKPIN <hexified_id>
|
||||||
|
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
cmd_checkpin (ASSUAN_CONTEXT ctx, char *line)
|
||||||
|
{
|
||||||
|
CTRL ctrl = assuan_get_pointer (ctx);
|
||||||
|
int rc;
|
||||||
|
char *keyidstr;
|
||||||
|
|
||||||
|
if ((rc = open_card (ctrl)))
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
if (!ctrl->app_ctx)
|
||||||
|
return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
|
||||||
|
|
||||||
|
/* We have to use a copy of the key ID because the function may use
|
||||||
|
the pin_cb which in turn uses the assuan line buffer and thus
|
||||||
|
overwriting the original line with the keyid. */
|
||||||
|
keyidstr = xtrystrdup (line);
|
||||||
|
if (!keyidstr)
|
||||||
|
return ASSUAN_Out_Of_Core;
|
||||||
|
|
||||||
|
rc = app_check_pin (ctrl->app_ctx,
|
||||||
|
keyidstr,
|
||||||
|
pin_cb, ctx);
|
||||||
|
xfree (keyidstr);
|
||||||
|
if (rc)
|
||||||
|
log_error ("app_check_pin failed: %s\n", gpg_strerror (rc));
|
||||||
|
|
||||||
|
return map_to_assuan_status (rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Tell the assuan library about our commands */
|
/* Tell the assuan library about our commands */
|
||||||
@ -948,6 +983,7 @@ register_commands (ASSUAN_CONTEXT ctx)
|
|||||||
{ "GENKEY", cmd_genkey },
|
{ "GENKEY", cmd_genkey },
|
||||||
{ "RANDOM", cmd_random },
|
{ "RANDOM", cmd_random },
|
||||||
{ "PASSWD", cmd_passwd },
|
{ "PASSWD", cmd_passwd },
|
||||||
|
{ "CHECKPIN", cmd_checkpin },
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
int i, rc;
|
int i, rc;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user