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>
|
||||
|
||||
* 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). */
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
#define DLSTDCALL __stdcall
|
||||
#else
|
||||
#define DLSTDCALL
|
||||
#endif
|
||||
|
||||
|
||||
/* A structure to collect information pertaining to one reader
|
||||
slot. */
|
||||
struct reader_table_s {
|
||||
@ -84,12 +91,12 @@ static struct reader_table_s reader_table[MAX_READER];
|
||||
|
||||
|
||||
/* ct API function pointer. */
|
||||
static char (*CT_init) (unsigned short ctn, unsigned short Pn);
|
||||
static char (*CT_data) (unsigned short ctn, unsigned char *dad,
|
||||
unsigned char *sad, unsigned short lc,
|
||||
unsigned char *cmd, unsigned short *lr,
|
||||
unsigned char *rsp);
|
||||
static char (*CT_close) (unsigned short ctn);
|
||||
static char (* DLSTDCALL CT_init) (unsigned short ctn, unsigned short Pn);
|
||||
static char (* DLSTDCALL CT_data) (unsigned short ctn, unsigned char *dad,
|
||||
unsigned char *sad, unsigned short lc,
|
||||
unsigned char *cmd, unsigned short *lr,
|
||||
unsigned char *rsp);
|
||||
static char (* DLSTDCALL CT_close) (unsigned short ctn);
|
||||
|
||||
/* PC/SC constants and function pointer. */
|
||||
#define PCSC_SCOPE_USER 0
|
||||
@ -117,34 +124,38 @@ struct pcsc_io_request_s {
|
||||
|
||||
typedef struct pcsc_io_request_s *pcsc_io_request_t;
|
||||
|
||||
long (*pcsc_establish_context) (unsigned long scope,
|
||||
const void *reserved1,
|
||||
const void *reserved2,
|
||||
unsigned long *r_context);
|
||||
long (*pcsc_release_context) (unsigned long context);
|
||||
long (*pcsc_list_readers) (unsigned long context, const char *groups,
|
||||
char *readers, unsigned long *readerslen);
|
||||
long (*pcsc_connect) (unsigned long context,
|
||||
const char *reader,
|
||||
unsigned long share_mode,
|
||||
unsigned long preferred_protocols,
|
||||
unsigned long *r_card,
|
||||
unsigned long *r_active_protocol);
|
||||
long (*pcsc_disconnect) (unsigned long card, unsigned long disposition);
|
||||
long (*pcsc_status) (unsigned long card,
|
||||
char *reader, unsigned long *readerlen,
|
||||
unsigned long *r_state, unsigned long *r_protocol,
|
||||
unsigned char *atr, unsigned long *atrlen);
|
||||
long (*pcsc_begin_transaction) (unsigned long card);
|
||||
long (*pcsc_end_transaction) (unsigned long card);
|
||||
long (*pcsc_transmit) (unsigned long card,
|
||||
const pcsc_io_request_t send_pci,
|
||||
const unsigned char *send_buffer,
|
||||
unsigned long send_len,
|
||||
pcsc_io_request_t recv_pci,
|
||||
unsigned char *recv_buffer,
|
||||
unsigned long *recv_len);
|
||||
long (*pcsc_set_timeout) (unsigned long context, unsigned long timeout);
|
||||
long (* DLSTDCALL pcsc_establish_context) (unsigned long scope,
|
||||
const void *reserved1,
|
||||
const void *reserved2,
|
||||
unsigned long *r_context);
|
||||
long (* DLSTDCALL pcsc_release_context) (unsigned long context);
|
||||
long (* DLSTDCALL pcsc_list_readers) (unsigned long context,
|
||||
const char *groups,
|
||||
char *readers, unsigned long*readerslen);
|
||||
long (* DLSTDCALL pcsc_connect) (unsigned long context,
|
||||
const char *reader,
|
||||
unsigned long share_mode,
|
||||
unsigned long preferred_protocols,
|
||||
unsigned long *r_card,
|
||||
unsigned long *r_active_protocol);
|
||||
long (* DLSTDCALL pcsc_disconnect) (unsigned long card,
|
||||
unsigned long disposition);
|
||||
long (* DLSTDCALL pcsc_status) (unsigned long card,
|
||||
char *reader, unsigned long *readerlen,
|
||||
unsigned long *r_state,
|
||||
unsigned long *r_protocol,
|
||||
unsigned char *atr, unsigned long *atrlen);
|
||||
long (* DLSTDCALL pcsc_begin_transaction) (unsigned long card);
|
||||
long (* DLSTDCALL pcsc_end_transaction) (unsigned long card);
|
||||
long (* DLSTDCALL pcsc_transmit) (unsigned long card,
|
||||
const pcsc_io_request_t send_pci,
|
||||
const unsigned char *send_buffer,
|
||||
unsigned long send_len,
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
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. */
|
||||
}
|
||||
|
||||
static int
|
||||
close_pcsc_reader (int slot)
|
||||
{
|
||||
/* FIXME: Implement. */
|
||||
reader_table[slot].used = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef HAVE_LIBUSB
|
||||
/*
|
||||
@ -609,6 +639,15 @@ open_ccid_reader (void)
|
||||
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
|
||||
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
|
||||
maximum of *BUFLEN data in BUFFER, the actual returned size will be
|
||||
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 *
|
||||
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. */
|
||||
int apdu_open_reader (const char *portstr);
|
||||
int apdu_close_reader (int slot);
|
||||
unsigned char *apdu_get_atr (int slot, size_t *atrlen);
|
||||
|
||||
|
||||
|
@ -65,6 +65,9 @@ struct app_ctx_s {
|
||||
const char *chvnostr, int reset_mode,
|
||||
int (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg);
|
||||
int (*check_pin) (APP app, const char *keyidstr,
|
||||
int (pincb)(void*, const char *, char **),
|
||||
void *pincb_arg);
|
||||
} 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 (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg);
|
||||
int app_check_pin (APP app, const char *keyidstr,
|
||||
int (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg);
|
||||
|
||||
|
||||
/*-- 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
|
||||
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
|
||||
will detect a bogus signature anyway due to the
|
||||
verify-after-signing feature. */
|
||||
if (fpr)
|
||||
{
|
||||
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_sn[n] = xtoi_2 (s);
|
||||
rc = compare_fingerprint (app, 1, tmp_sn);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
rc = fpr? check_against_given_fingerprint (app, fpr, 1) : 0;
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (hashalgo == GCRY_MD_SHA1)
|
||||
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
|
||||
will detect a bogus signature anyway due to the
|
||||
verify-after-signing feature. */
|
||||
if (fpr)
|
||||
{
|
||||
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_sn[n] = xtoi_2 (s);
|
||||
rc = compare_fingerprint (app, 3, tmp_sn);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
rc = fpr? check_against_given_fingerprint (app, fpr, 3) : 0;
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = verify_chv2 (app, pincb, pincb_arg);
|
||||
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
|
||||
known to gpg was not updated. If there is no fingerprint, the
|
||||
decryption will won't produce the right plaintext anyway. */
|
||||
if (fpr)
|
||||
{
|
||||
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_sn[n] = xtoi_2 (s);
|
||||
rc = compare_fingerprint (app, 2, tmp_sn);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
rc = fpr? check_against_given_fingerprint (app, fpr, 2) : 0;
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = verify_chv2 (app, pincb, pincb_arg);
|
||||
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
|
||||
@ -1262,6 +1296,7 @@ app_select_openpgp (APP app, unsigned char **sn, size_t *snlen)
|
||||
app->fnc.auth = do_auth;
|
||||
app->fnc.decipher = do_decipher;
|
||||
app->fnc.change_pin = do_change_pin;
|
||||
app->fnc.check_pin = do_check_pin;
|
||||
}
|
||||
|
||||
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
|
||||
integer. */
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
@ -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. */
|
||||
int
|
||||
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.
|
||||
Returns 0 on success. */
|
||||
static int
|
||||
|
@ -60,6 +60,7 @@ struct ccid_driver_s;
|
||||
typedef struct ccid_driver_s *ccid_driver_t;
|
||||
|
||||
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,
|
||||
unsigned char *atr, size_t maxatrlen, size_t *atrlen);
|
||||
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 */
|
||||
@ -948,6 +983,7 @@ register_commands (ASSUAN_CONTEXT ctx)
|
||||
{ "GENKEY", cmd_genkey },
|
||||
{ "RANDOM", cmd_random },
|
||||
{ "PASSWD", cmd_passwd },
|
||||
{ "CHECKPIN", cmd_checkpin },
|
||||
{ NULL }
|
||||
};
|
||||
int i, rc;
|
||||
|
Loading…
x
Reference in New Issue
Block a user