mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-21 14:47:03 +01:00
* command.c (cmd_pkauth): New.
(cmd_setdata): Check whether data was given at all to avoid passing 0 to malloc. * app.c (app_auth): New. * app-openpgp.c (do_auth): New.
This commit is contained in:
parent
fbdee01db9
commit
b8becef1cf
@ -1,3 +1,39 @@
|
||||
2003-07-23 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* command.c (cmd_pkauth): New.
|
||||
(cmd_setdata): Check whether data was given at all to avoid
|
||||
passing 0 to malloc.
|
||||
|
||||
* app.c (app_auth): New.
|
||||
* app-openpgp.c (do_auth): New.
|
||||
|
||||
2003-07-22 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* command.c (cmd_passwd): New.
|
||||
* app.c (app_change_pin): New.
|
||||
* app-openpgp.c (do_change_pin): New.
|
||||
* iso7816.c (iso7816_reset_retry_counter): Implemented.
|
||||
|
||||
* sc-investigate.c (main): New option --gen-random.
|
||||
* iso7816.c (iso7816_get_challenge): Don't create APDUs with a
|
||||
length larger than 255.
|
||||
|
||||
2003-07-17 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* command.c (cmd_random): New command RANDOM.
|
||||
|
||||
* iso7816.c (map_sw): New. Use it in this file to return
|
||||
meaningful error messages. Changed all public fucntions to return
|
||||
a gpg_error_t.
|
||||
(iso7816_change_reference_data): New.
|
||||
* apdu.c (apdu_open_reader): Use faked status words for soem
|
||||
system errors.
|
||||
|
||||
2003-07-16 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* apdu.c (apdu_send_simple): Use apdu_send_le so that we can
|
||||
specify not to send Le as it should be.
|
||||
|
||||
2003-07-15 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* Makefile.am: Add sc-copykeys program.
|
||||
|
32
scd/apdu.c
32
scd/apdu.c
@ -213,7 +213,7 @@ ct_activate_card (int reader)
|
||||
|
||||
/* Open a reader and return an internal handle for it. PORT is a
|
||||
non-negative value with the port number of the reader. USB readers
|
||||
do habe port numbers starting at 32769. */
|
||||
do have port numbers starting at 32769. */
|
||||
static int
|
||||
open_ct_reader (int port)
|
||||
{
|
||||
@ -244,7 +244,7 @@ open_ct_reader (int port)
|
||||
}
|
||||
|
||||
|
||||
/* Actuall 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
|
||||
set to BUFLEN. Returns: CT API error code. */
|
||||
static int
|
||||
@ -356,9 +356,9 @@ send_apdu (int slot, unsigned char *apdu, size_t apdulen,
|
||||
#ifdef HAVE_CTAPI
|
||||
return ct_send_apdu (slot, apdu, apdulen, buffer, buflen);
|
||||
#elif defined(HAVE_PCSC)
|
||||
return -1;
|
||||
return SW_HOST_NO_DRIVER;
|
||||
#else
|
||||
return -1;
|
||||
return SW_HOST_NO_DRIVER;
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -369,7 +369,7 @@ send_apdu (int slot, unsigned char *apdu, size_t apdulen,
|
||||
or -1 for an invalid SLOT or other non card related error. If
|
||||
RETBUF is not NULL, it will receive an allocated buffer with the
|
||||
returned data. The length of that data will be put into
|
||||
*RETBUFLEN. The caller is reposnible for releasing the buffer even
|
||||
*RETBUFLEN. The caller is reponsible for releasing the buffer even
|
||||
in case of errors. */
|
||||
int
|
||||
apdu_send_le(int slot, int class, int ins, int p0, int p1,
|
||||
@ -391,7 +391,7 @@ apdu_send_le(int slot, int class, int ins, int p0, int p1,
|
||||
if (le != -1 && (le > 256 || le < 1))
|
||||
return SW_WRONG_LENGTH;
|
||||
if ((!data && lc != -1) || (data && lc == -1))
|
||||
return -1;
|
||||
return SW_HOST_INV_VALUE;
|
||||
|
||||
apdulen = 0;
|
||||
apdu[apdulen++] = class;
|
||||
@ -414,7 +414,7 @@ apdu_send_le(int slot, int class, int ins, int p0, int p1,
|
||||
{
|
||||
log_error ("apdu_send_simple(%d) failed: %s\n",
|
||||
slot, error_string (slot, rc));
|
||||
return -1;
|
||||
return SW_HOST_INCOMPLETE_CARD_RESPONSE;
|
||||
}
|
||||
sw = (result[resultlen-2] << 8) | result[resultlen-1];
|
||||
/* store away the returned data but strip the statusword. */
|
||||
@ -432,7 +432,7 @@ apdu_send_le(int slot, int class, int ins, int p0, int p1,
|
||||
{
|
||||
*retbuf = xtrymalloc (resultlen? resultlen : 1);
|
||||
if (!*retbuf)
|
||||
return -1; /* fixme: this is actually out of core. */
|
||||
return SW_HOST_OUT_OF_CORE;
|
||||
*retbuflen = resultlen;
|
||||
memcpy (*retbuf, result, resultlen);
|
||||
}
|
||||
@ -448,7 +448,7 @@ apdu_send_le(int slot, int class, int ins, int p0, int p1,
|
||||
{
|
||||
*retbuf = p = xtrymalloc (bufsize);
|
||||
if (!*retbuf)
|
||||
return -1; /* fixme: this is actually out of core. */
|
||||
return SW_HOST_OUT_OF_CORE;
|
||||
assert (resultlen < bufsize);
|
||||
memcpy (p, result, resultlen);
|
||||
p += resultlen;
|
||||
@ -472,7 +472,7 @@ apdu_send_le(int slot, int class, int ins, int p0, int p1,
|
||||
{
|
||||
log_error ("apdu_send_simple(%d) for get response failed: %s\n",
|
||||
slot, error_string (slot, rc));
|
||||
return -1;
|
||||
return SW_HOST_INCOMPLETE_CARD_RESPONSE;
|
||||
}
|
||||
sw = (result[resultlen-2] << 8) | result[resultlen-1];
|
||||
resultlen -= 2;
|
||||
@ -492,7 +492,7 @@ apdu_send_le(int slot, int class, int ins, int p0, int p1,
|
||||
bufsize += resultlen > 4096? resultlen: 4096;
|
||||
tmp = xtryrealloc (*retbuf, bufsize);
|
||||
if (!tmp)
|
||||
return -1; /* fixme: actually this is out of core */
|
||||
return SW_HOST_OUT_OF_CORE;
|
||||
p = tmp + (p - *retbuf);
|
||||
*retbuf = tmp;
|
||||
}
|
||||
@ -531,8 +531,8 @@ apdu_send_le(int slot, int class, int ins, int p0, int p1,
|
||||
caller is reponsible for releasing the buffer even in case of
|
||||
errors. */
|
||||
int
|
||||
apdu_send(int slot, int class, int ins, int p0, int p1,
|
||||
int lc, const char *data, unsigned char **retbuf, size_t *retbuflen)
|
||||
apdu_send (int slot, int class, int ins, int p0, int p1,
|
||||
int lc, const char *data, unsigned char **retbuf, size_t *retbuflen)
|
||||
{
|
||||
return apdu_send_le (slot, class, ins, p0, p1, lc, data, 256,
|
||||
retbuf, retbuflen);
|
||||
@ -548,5 +548,9 @@ int
|
||||
apdu_send_simple (int slot, int class, int ins, int p0, int p1,
|
||||
int lc, const char *data)
|
||||
{
|
||||
return apdu_send (slot, class, ins, p0, p1, lc, data, NULL, NULL);
|
||||
return apdu_send_le (slot, class, ins, p0, p1, lc, data, -1, NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
19
scd/apdu.h
19
scd/apdu.h
@ -22,7 +22,7 @@
|
||||
#define APDU_H
|
||||
|
||||
/* ISO 7816 values for the statusword are defined here because they
|
||||
should not be visible to the users of the actual iso command
|
||||
should not be visible to the users of the actual ISO command
|
||||
API. */
|
||||
enum {
|
||||
SW_MORE_DATA = 0x6100, /* Note: that the low byte must be
|
||||
@ -32,19 +32,31 @@ enum {
|
||||
SW_CHV_WRONG = 0x6982,
|
||||
SW_CHV_BLOCKED = 0x6983,
|
||||
SW_USE_CONDITIONS = 0x6985,
|
||||
SW_NOT_SUPPORTED = 0x6a81,
|
||||
SW_BAD_PARAMETER = 0x6a80, /* (in the data field) */
|
||||
SW_REF_NOT_FOUND = 0x6a88,
|
||||
SW_BAD_P0_P1 = 0x6b00,
|
||||
SW_INS_NOT_SUP = 0x6d00,
|
||||
SW_CLA_NOT_SUP = 0x6e00,
|
||||
SW_SUCCESS = 0x9000
|
||||
SW_SUCCESS = 0x9000,
|
||||
|
||||
/* The follwoing statuswords are no real ones but used to map host
|
||||
OS errors into status words. A status word is 16 bit so that
|
||||
those values can't be issued by a card. */
|
||||
SW_HOST_OUT_OF_CORE = 0x10001, /* No way yet to differentiate
|
||||
between errnos on a failed malloc. */
|
||||
SW_HOST_INV_VALUE = 0x10002,
|
||||
SW_HOST_INCOMPLETE_CARD_RESPONSE = 0x10003,
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* Note , that apdu_open_reader returns no status word but -1 on error. */
|
||||
int apdu_open_reader (int port);
|
||||
unsigned char *apdu_get_atr (int slot, size_t *atrlen);
|
||||
|
||||
|
||||
/* The apdu send functions do return status words. */
|
||||
int apdu_send_simple (int slot, int class, int ins, int p0, int p1,
|
||||
int lc, const char *data);
|
||||
int apdu_send (int slot, int class, int ins, int p0, int p1,
|
||||
@ -56,3 +68,6 @@ int apdu_send_le (int slot, int class, int ins, int p0, int p1,
|
||||
|
||||
|
||||
#endif /*APDU_H*/
|
||||
|
||||
|
||||
|
||||
|
@ -44,6 +44,11 @@ struct app_ctx_s {
|
||||
void *pincb_arg,
|
||||
const void *indata, size_t indatalen,
|
||||
unsigned char **outdata, size_t *outdatalen );
|
||||
int (*auth) (APP app, const char *keyidstr,
|
||||
int (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg,
|
||||
const void *indata, size_t indatalen,
|
||||
unsigned char **outdata, size_t *outdatalen);
|
||||
int (*decipher) (APP app, const char *keyidstr,
|
||||
int (pincb)(void*, const char *, char **),
|
||||
void *pincb_arg,
|
||||
@ -53,6 +58,10 @@ struct app_ctx_s {
|
||||
const char *keynostr, unsigned int flags,
|
||||
int (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg);
|
||||
int (*change_pin) (APP app, CTRL ctrl,
|
||||
const char *chvnostr, int reset_mode,
|
||||
int (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg);
|
||||
} fnc;
|
||||
|
||||
|
||||
@ -71,6 +80,11 @@ int app_sign (APP app, const char *keyidstr, int hashalgo,
|
||||
void *pincb_arg,
|
||||
const void *indata, size_t indatalen,
|
||||
unsigned char **outdata, size_t *outdatalen );
|
||||
int app_auth (APP app, const char *keyidstr,
|
||||
int (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg,
|
||||
const void *indata, size_t indatalen,
|
||||
unsigned char **outdata, size_t *outdatalen);
|
||||
int app_decipher (APP app, const char *keyidstr,
|
||||
int (pincb)(void*, const char *, char **),
|
||||
void *pincb_arg,
|
||||
@ -79,6 +93,11 @@ int app_decipher (APP app, const char *keyidstr,
|
||||
int app_genkey (APP app, CTRL ctrl, const char *keynostr, unsigned int flags,
|
||||
int (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg);
|
||||
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);
|
||||
|
||||
|
||||
/*-- app-openpgp.c --*/
|
||||
int app_select_openpgp (APP app, unsigned char **sn, size_t *snlen);
|
||||
|
@ -561,6 +561,100 @@ do_setattr (APP app, const char *name,
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Handle the PASSWD command. */
|
||||
static int
|
||||
do_change_pin (APP app, CTRL ctrl, const char *chvnostr, int reset_mode,
|
||||
int (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg)
|
||||
{
|
||||
int rc = 0;
|
||||
int chvno = atoi (chvnostr);
|
||||
char *pinvalue;
|
||||
|
||||
if (reset_mode && chvno == 3)
|
||||
{
|
||||
rc = gpg_error (GPG_ERR_INV_ID);
|
||||
goto leave;
|
||||
}
|
||||
else if (reset_mode || chvno == 3)
|
||||
{
|
||||
rc = pincb (pincb_arg, "Admin PIN", &pinvalue);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("error getting PIN: %s\n", gpg_strerror (rc));
|
||||
goto leave;
|
||||
}
|
||||
rc = iso7816_verify (app->slot, 0x83, pinvalue, strlen (pinvalue));
|
||||
xfree (pinvalue);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("verify CHV3 failed: rc=%04X\n", rc);
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
else if (chvno == 1)
|
||||
{
|
||||
rc = pincb (pincb_arg, "Signature PIN", &pinvalue);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("error getting PIN: %s\n", gpg_strerror (rc));
|
||||
goto leave;
|
||||
}
|
||||
rc = iso7816_verify (app->slot, 0x81, pinvalue, strlen (pinvalue));
|
||||
xfree (pinvalue);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("verify CHV1 failed: rc=%04X\n", rc);
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
else if (chvno == 2)
|
||||
{
|
||||
rc = pincb (pincb_arg, "Decryption PIN", &pinvalue);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("error getting PIN: %s\n", gpg_strerror (rc));
|
||||
goto leave;
|
||||
}
|
||||
rc = iso7816_verify (app->slot, 0x82, pinvalue, strlen (pinvalue));
|
||||
xfree (pinvalue);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("verify CHV2 failed: rc=%04X\n", rc);
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = gpg_error (GPG_ERR_INV_ID);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
|
||||
rc = pincb (pincb_arg, chvno == 1? "New Signature PIN" :
|
||||
chvno == 2? "New Decryption PIN" :
|
||||
chvno == 3? "New Admin PIN" : "?", &pinvalue);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("error getting new PIN: %s\n", gpg_strerror (rc));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
if (reset_mode)
|
||||
rc = iso7816_reset_retry_counter (app->slot, 0x80 + chvno,
|
||||
pinvalue, strlen (pinvalue));
|
||||
else
|
||||
rc = iso7816_change_reference_data (app->slot, 0x80 + chvno,
|
||||
NULL, 0,
|
||||
pinvalue, strlen (pinvalue));
|
||||
xfree (pinvalue);
|
||||
|
||||
|
||||
leave:
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Handle the GENKEY command. */
|
||||
static int
|
||||
@ -630,7 +724,7 @@ do_genkey (APP app, CTRL ctrl, const char *keynostr, unsigned int flags,
|
||||
}
|
||||
|
||||
xfree (buffer); buffer = NULL;
|
||||
#if 0
|
||||
#if 1
|
||||
log_info ("please wait while key is being generated ...\n");
|
||||
start_at = time (NULL);
|
||||
rc = iso7816_generate_keypair
|
||||
@ -816,7 +910,7 @@ do_sign (APP app, const char *keyidstr, int hashalgo,
|
||||
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, gpg
|
||||
will detect the bodus signature anyway die to the
|
||||
will detect a bogus signature anyway due to the
|
||||
verify-after-signing feature. */
|
||||
if (fpr)
|
||||
{
|
||||
@ -883,6 +977,107 @@ do_sign (APP app, const char *keyidstr, int hashalgo,
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Compute a digital signature using the INTERNAL AUTHENTICATE command
|
||||
on INDATA which is expected to be the raw message digest. For this
|
||||
application the KEYIDSTR consists of the serialnumber and the
|
||||
fingerprint delimited by a slash.
|
||||
|
||||
Note that this fucntion may return the error code
|
||||
GPG_ERR_WRONG_CARD to indicate that the card currently present does
|
||||
not match the one required for the requested action (e.g. the
|
||||
serial number does not match). */
|
||||
static int
|
||||
do_auth (APP app, const char *keyidstr,
|
||||
int (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg,
|
||||
const void *indata, size_t indatalen,
|
||||
unsigned char **outdata, size_t *outdatalen )
|
||||
{
|
||||
int rc;
|
||||
unsigned char tmp_sn[20]; /* actually 16 but we use it also for the fpr. */
|
||||
const char *s;
|
||||
int n;
|
||||
const char *fpr = NULL;
|
||||
|
||||
if (!keyidstr || !*keyidstr)
|
||||
return gpg_error (GPG_ERR_INV_VALUE);
|
||||
if (indatalen > 50) /* For a 1024 bit key. */
|
||||
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 == '/')
|
||||
fpr = s + 1;
|
||||
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);
|
||||
|
||||
/* 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, 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;
|
||||
}
|
||||
|
||||
if (!app->did_chv2)
|
||||
{
|
||||
char *pinvalue;
|
||||
|
||||
rc = pincb (pincb_arg, "Authentication/Decryption PIN", &pinvalue);
|
||||
if (rc)
|
||||
{
|
||||
log_info ("PIN callback returned error: %s\n", gpg_strerror (rc));
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = iso7816_verify (app->slot, 0x82, pinvalue, strlen (pinvalue));
|
||||
xfree (pinvalue);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("verify CHV2 failed\n");
|
||||
rc = gpg_error (GPG_ERR_GENERAL);
|
||||
return rc;
|
||||
}
|
||||
app->did_chv2 = 1;
|
||||
}
|
||||
|
||||
rc = iso7816_internal_authenticate (app->slot, indata, indatalen,
|
||||
outdata, outdatalen);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
do_decipher (APP app, const char *keyidstr,
|
||||
@ -1017,7 +1212,9 @@ app_select_openpgp (APP app, unsigned char **sn, size_t *snlen)
|
||||
app->fnc.setattr = do_setattr;
|
||||
app->fnc.genkey = do_genkey;
|
||||
app->fnc.sign = do_sign;
|
||||
app->fnc.auth = do_auth;
|
||||
app->fnc.decipher = do_decipher;
|
||||
app->fnc.change_pin = do_change_pin;
|
||||
}
|
||||
|
||||
leave:
|
||||
|
70
scd/app.c
70
scd/app.c
@ -28,6 +28,7 @@
|
||||
#include "scdaemon.h"
|
||||
#include "app-common.h"
|
||||
#include "apdu.h"
|
||||
#include "iso7816.h"
|
||||
|
||||
/* The select the best fitting application and return a context.
|
||||
Returns NULL if no application was found or no card is present. */
|
||||
@ -157,6 +158,34 @@ app_sign (APP app, const char *keyidstr, int hashalgo,
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Create the signature using the INTERNAL AUTHENTICATE command and
|
||||
return the allocated result in OUTDATA. If a PIN is required the
|
||||
PINCB will be used to ask for the PIN; it should return the PIN in
|
||||
an allocated buffer and put it into PIN. */
|
||||
int
|
||||
app_auth (APP app, const char *keyidstr,
|
||||
int (pincb)(void*, const char *, char **),
|
||||
void *pincb_arg,
|
||||
const void *indata, size_t indatalen,
|
||||
unsigned char **outdata, size_t *outdatalen )
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (!app || !indata || !indatalen || !outdata || !outdatalen || !pincb)
|
||||
return gpg_error (GPG_ERR_INV_VALUE);
|
||||
if (!app->initialized)
|
||||
return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
|
||||
if (!app->fnc.auth)
|
||||
return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
|
||||
rc = app->fnc.auth (app, keyidstr,
|
||||
pincb, pincb_arg,
|
||||
indata, indatalen,
|
||||
outdata, outdatalen);
|
||||
if (opt.verbose)
|
||||
log_info ("operation auth result: %s\n", gpg_strerror (rc));
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/* Decrypt the data in INDATA and return the allocated result in OUTDATA.
|
||||
If a PIN is required the PINCB will be used to ask for the PIN; it
|
||||
@ -206,3 +235,44 @@ app_genkey (APP app, CTRL ctrl, const char *keynostr, unsigned int flags,
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/* Perform a GET CHALLENGE operation. This fucntion is special as it
|
||||
directly accesses the card without any application specific
|
||||
wrapper. */
|
||||
int
|
||||
app_get_challenge (APP app, size_t nbytes, unsigned char *buffer)
|
||||
{
|
||||
if (!app || !nbytes || !buffer)
|
||||
return gpg_error (GPG_ERR_INV_VALUE);
|
||||
if (!app->initialized)
|
||||
return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
|
||||
return iso7816_get_challenge (app->slot, nbytes, buffer);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Perform a CHANGE REFERENCE DATA or RESET RETRY COUNTER operation. */
|
||||
int
|
||||
app_change_pin (APP app, CTRL ctrl, const char *chvnostr, int reset_mode,
|
||||
int (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (!app || !chvnostr || !*chvnostr || !pincb)
|
||||
return gpg_error (GPG_ERR_INV_VALUE);
|
||||
if (!app->initialized)
|
||||
return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
|
||||
if (!app->fnc.change_pin)
|
||||
return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
|
||||
rc = app->fnc.change_pin (app, ctrl, chvnostr, reset_mode, pincb, pincb_arg);
|
||||
if (opt.verbose)
|
||||
log_info ("operation change_pin result: %s\n", gpg_strerror (rc));
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
130
scd/command.c
130
scd/command.c
@ -507,6 +507,8 @@ cmd_setdata (ASSUAN_CONTEXT ctx, char *line)
|
||||
;
|
||||
if (*p)
|
||||
return set_error (Parameter_Error, "invalid hexstring");
|
||||
if (!n)
|
||||
return set_error (Parameter_Error, "no data given");
|
||||
if ((n&1))
|
||||
return set_error (Parameter_Error, "odd number of digits");
|
||||
n /= 2;
|
||||
@ -607,6 +609,52 @@ cmd_pksign (ASSUAN_CONTEXT ctx, char *line)
|
||||
return map_to_assuan_status (rc);
|
||||
}
|
||||
|
||||
/* PKAUTH <hexified_id>
|
||||
|
||||
*/
|
||||
static int
|
||||
cmd_pkauth (ASSUAN_CONTEXT ctx, char *line)
|
||||
{
|
||||
CTRL ctrl = assuan_get_pointer (ctx);
|
||||
int rc;
|
||||
unsigned char *outdata;
|
||||
size_t outdatalen;
|
||||
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 = strdup (line);
|
||||
if (!keyidstr)
|
||||
return ASSUAN_Out_Of_Core;
|
||||
|
||||
rc = app_auth (ctrl->app_ctx,
|
||||
keyidstr,
|
||||
pin_cb, ctx,
|
||||
ctrl->in_data.value, ctrl->in_data.valuelen,
|
||||
&outdata, &outdatalen);
|
||||
free (keyidstr);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("app_auth_sign failed: %s\n", gpg_strerror (rc));
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = assuan_send_data (ctx, outdata, outdatalen);
|
||||
xfree (outdata);
|
||||
if (rc)
|
||||
return rc; /* that is already an assuan error code */
|
||||
}
|
||||
|
||||
return map_to_assuan_status (rc);
|
||||
}
|
||||
|
||||
/* PKDECRYPT <hexified_id>
|
||||
|
||||
*/
|
||||
@ -746,6 +794,85 @@ cmd_genkey (ASSUAN_CONTEXT ctx, char *line)
|
||||
}
|
||||
|
||||
|
||||
/* RANDOM <nbytes>
|
||||
|
||||
Get NBYTES of random from the card and send them back as data.
|
||||
*/
|
||||
static int
|
||||
cmd_random (ASSUAN_CONTEXT ctx, char *line)
|
||||
{
|
||||
CTRL ctrl = assuan_get_pointer (ctx);
|
||||
int rc;
|
||||
size_t nbytes;
|
||||
unsigned char *buffer;
|
||||
|
||||
if (!*line)
|
||||
return set_error (Parameter_Error, "number of requested bytes missing");
|
||||
nbytes = strtoul (line, NULL, 0);
|
||||
|
||||
if ((rc = open_card (ctrl)))
|
||||
return rc;
|
||||
|
||||
if (!ctrl->app_ctx)
|
||||
return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
|
||||
|
||||
buffer = xtrymalloc (nbytes);
|
||||
if (!buffer)
|
||||
return ASSUAN_Out_Of_Core;
|
||||
|
||||
rc = app_get_challenge (ctrl->app_ctx, nbytes, buffer);
|
||||
if (!rc)
|
||||
{
|
||||
rc = assuan_send_data (ctx, buffer, nbytes);
|
||||
xfree (buffer);
|
||||
return rc; /* that is already an assuan error code */
|
||||
}
|
||||
xfree (buffer);
|
||||
|
||||
return map_to_assuan_status (rc);
|
||||
}
|
||||
|
||||
|
||||
/* PASSWD [--reset] <chvno>
|
||||
|
||||
Change the PIN or reset thye retry counter of the card holder
|
||||
verfication vector CHVNO. */
|
||||
static int
|
||||
cmd_passwd (ASSUAN_CONTEXT ctx, char *line)
|
||||
{
|
||||
CTRL ctrl = assuan_get_pointer (ctx);
|
||||
int rc;
|
||||
char *chvnostr;
|
||||
int reset_mode = has_option (line, "--reset");
|
||||
|
||||
/* Skip over options. */
|
||||
while (*line == '-' && line[1] == '-')
|
||||
{
|
||||
while (!spacep (line))
|
||||
line++;
|
||||
while (spacep (line))
|
||||
line++;
|
||||
}
|
||||
if (!*line)
|
||||
return set_error (Parameter_Error, "no CHV number given");
|
||||
chvnostr = line;
|
||||
while (!spacep (line))
|
||||
line++;
|
||||
*line = 0;
|
||||
|
||||
if ((rc = open_card (ctrl)))
|
||||
return rc;
|
||||
|
||||
if (!ctrl->app_ctx)
|
||||
return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
|
||||
|
||||
rc = app_change_pin (ctrl->app_ctx, ctrl, chvnostr, reset_mode, pin_cb, ctx
|
||||
);
|
||||
if (rc)
|
||||
log_error ("command passwd failed: %s\n", gpg_strerror (rc));
|
||||
return map_to_assuan_status (rc);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@ -763,11 +890,14 @@ register_commands (ASSUAN_CONTEXT ctx)
|
||||
{ "READKEY", cmd_readkey },
|
||||
{ "SETDATA", cmd_setdata },
|
||||
{ "PKSIGN", cmd_pksign },
|
||||
{ "PKAUTH", cmd_pkauth },
|
||||
{ "PKDECRYPT", cmd_pkdecrypt },
|
||||
{ "INPUT", NULL },
|
||||
{ "OUTPUT", NULL },
|
||||
{ "SETATTR", cmd_setattr },
|
||||
{ "GENKEY", cmd_genkey },
|
||||
{ "RANDOM", cmd_random },
|
||||
{ "PASSWD", cmd_passwd },
|
||||
{ NULL }
|
||||
};
|
||||
int i, rc;
|
||||
|
148
scd/iso7816.c
148
scd/iso7816.c
@ -31,6 +31,8 @@
|
||||
|
||||
#define CMD_SELECT_FILE 0xA4
|
||||
#define CMD_VERIFY 0x20
|
||||
#define CMD_CHANGE_REFERENCE_DATA 0x24
|
||||
#define CMD_RESET_RETRY_COUNTER 0x2C
|
||||
#define CMD_GET_DATA 0xCA
|
||||
#define CMD_PUT_DATA 0xDA
|
||||
#define CMD_PSO 0x2A
|
||||
@ -38,6 +40,40 @@
|
||||
#define CMD_GENERATE_KEYPAIR 0x47
|
||||
#define CMD_GET_CHALLENGE 0x84
|
||||
|
||||
static gpg_error_t
|
||||
map_sw (int sw)
|
||||
{
|
||||
gpg_err_code_t ec;
|
||||
|
||||
switch (sw)
|
||||
{
|
||||
case SW_EEPROM_FAILURE: ec = GPG_ERR_HARDWARE; break;
|
||||
case SW_WRONG_LENGTH: ec = GPG_ERR_INV_VALUE; break;
|
||||
case SW_CHV_WRONG: ec = GPG_ERR_BAD_PIN; break;
|
||||
case SW_CHV_BLOCKED: ec = GPG_ERR_PIN_BLOCKED; break;
|
||||
case SW_USE_CONDITIONS: ec = GPG_ERR_USE_CONDITIONS; break;
|
||||
case SW_NOT_SUPPORTED: ec = GPG_ERR_NOT_SUPPORTED; break;
|
||||
case SW_BAD_PARAMETER: ec = GPG_ERR_INV_VALUE; break;
|
||||
case SW_REF_NOT_FOUND: ec = GPG_ERR_NO_OBJ; break;
|
||||
case SW_BAD_P0_P1: ec = GPG_ERR_INV_VALUE; break;
|
||||
case SW_INS_NOT_SUP: ec = GPG_ERR_CARD; break;
|
||||
case SW_CLA_NOT_SUP: ec = GPG_ERR_CARD; break;
|
||||
case SW_SUCCESS: ec = 0; break;
|
||||
|
||||
case SW_HOST_OUT_OF_CORE: ec = GPG_ERR_ENOMEM; break;
|
||||
case SW_HOST_INV_VALUE: ec = GPG_ERR_INV_VALUE; break;
|
||||
case SW_HOST_INCOMPLETE_CARD_RESPONSE: ec = GPG_ERR_CARD; break;
|
||||
default:
|
||||
if ((sw & 0x010000))
|
||||
ec = GPG_ERR_GENERAL; /* Should not happen. */
|
||||
else if ((sw & 0xff00) == SW_MORE_DATA)
|
||||
ec = 0; /* This should actually never been seen here. */
|
||||
else
|
||||
ec = GPG_ERR_CARD;
|
||||
}
|
||||
return gpg_error (ec);
|
||||
}
|
||||
|
||||
/* This function is specialized version of the SELECT FILE command.
|
||||
SLOT is the card and reader as created for example by
|
||||
apdu_open_reader (), AID is a buffer of size AIDLEN holding the
|
||||
@ -45,37 +81,78 @@
|
||||
AIDs and won't return the AID on success. The return value is 0
|
||||
for okay or GNUPG error code. Note that ISO error codes are
|
||||
internally mapped. */
|
||||
int
|
||||
gpg_error_t
|
||||
iso7816_select_application (int slot, const char *aid, size_t aidlen)
|
||||
{
|
||||
int sw;
|
||||
|
||||
sw = apdu_send_simple (slot, 0x00, CMD_SELECT_FILE, 4, 0, aidlen, aid);
|
||||
if (sw == SW_SUCCESS)
|
||||
return 0;
|
||||
else
|
||||
return -1; /* Fixme: we need a real error code. */
|
||||
return map_sw (sw);
|
||||
}
|
||||
|
||||
|
||||
/* Perform a VERIFY command on SLOT using the card holder verification
|
||||
vector CHVNO with a CHV of lenght CHVLEN. Returns 0 on success. */
|
||||
int
|
||||
gpg_error_t
|
||||
iso7816_verify (int slot, int chvno, const char *chv, size_t chvlen)
|
||||
{
|
||||
int sw;
|
||||
|
||||
sw = apdu_send_simple (slot, 0x00, CMD_VERIFY, 0, chvno, chvlen, chv);
|
||||
if (sw == SW_SUCCESS)
|
||||
return 0;
|
||||
else
|
||||
return -1; /* Fixme: we need a real error code. */
|
||||
return map_sw (sw);
|
||||
}
|
||||
|
||||
/* Perform a CHANGE_REFERENCE_DATA command on SLOT for the card holder
|
||||
verification vector CHVNO. If the OLDCHV is NULL (and OLDCHVLEN
|
||||
0), a "change reference data" is done, otherwise an "exchange
|
||||
reference data". The new reference data is expected in NEWCHV of
|
||||
length NEWCHVLEN. */
|
||||
gpg_error_t
|
||||
iso7816_change_reference_data (int slot, int chvno,
|
||||
const char *oldchv, size_t oldchvlen,
|
||||
const char *newchv, size_t newchvlen)
|
||||
{
|
||||
int sw;
|
||||
char *buf;
|
||||
|
||||
if ((!oldchv && oldchvlen)
|
||||
|| (oldchv && !oldchvlen)
|
||||
|| !newchv || !newchvlen )
|
||||
return gpg_error (GPG_ERR_INV_VALUE);
|
||||
|
||||
buf = xtrymalloc (oldchvlen + newchvlen);
|
||||
if (!buf)
|
||||
return out_of_core ();
|
||||
if (oldchvlen)
|
||||
memcpy (buf, oldchv, oldchvlen);
|
||||
memcpy (buf+oldchvlen, newchv, newchvlen);
|
||||
|
||||
sw = apdu_send_simple (slot, 0x00, CMD_CHANGE_REFERENCE_DATA,
|
||||
oldchvlen? 0 : 1, chvno, oldchvlen+newchvlen, buf);
|
||||
xfree (buf);
|
||||
return map_sw (sw);
|
||||
|
||||
}
|
||||
|
||||
gpg_error_t
|
||||
iso7816_reset_retry_counter (int slot, int chvno,
|
||||
const char *newchv, size_t newchvlen)
|
||||
{
|
||||
int sw;
|
||||
|
||||
if (!newchv || !newchvlen )
|
||||
return gpg_error (GPG_ERR_INV_VALUE);
|
||||
|
||||
sw = apdu_send_simple (slot, 0x00, CMD_RESET_RETRY_COUNTER,
|
||||
2, chvno, newchvlen, newchv);
|
||||
return map_sw (sw);
|
||||
}
|
||||
|
||||
|
||||
/* Perform a GET DATA command requesting TAG and storing the result in
|
||||
a newly allocated buffer at the address passed by RESULT. Return
|
||||
the length of this data at the address of RESULTLEN. */
|
||||
int
|
||||
gpg_error_t
|
||||
iso7816_get_data (int slot, int tag,
|
||||
unsigned char **result, size_t *resultlen)
|
||||
{
|
||||
@ -95,7 +172,7 @@ iso7816_get_data (int slot, int tag,
|
||||
xfree (*result);
|
||||
*result = NULL;
|
||||
*resultlen = 0;
|
||||
return -1; /* FIXME: Map error codes. */
|
||||
return map_sw (sw);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -104,7 +181,7 @@ iso7816_get_data (int slot, int tag,
|
||||
|
||||
/* Perform a PUT DATA command on card in SLOT. Write DATA of length
|
||||
DATALEN to TAG. */
|
||||
int
|
||||
gpg_error_t
|
||||
iso7816_put_data (int slot, int tag,
|
||||
const unsigned char *data, size_t datalen)
|
||||
{
|
||||
@ -113,10 +190,7 @@ iso7816_put_data (int slot, int tag,
|
||||
sw = apdu_send_simple (slot, 0x00, CMD_PUT_DATA,
|
||||
((tag >> 8) & 0xff), (tag & 0xff),
|
||||
datalen, data);
|
||||
if (sw == SW_SUCCESS)
|
||||
return 0;
|
||||
else
|
||||
return -1; /* Fixme: we need a real error code. */
|
||||
return map_sw (sw);
|
||||
}
|
||||
|
||||
|
||||
@ -124,7 +198,7 @@ iso7816_put_data (int slot, int tag,
|
||||
success 0 is returned and the data is availavle in a newly
|
||||
allocated buffer stored at RESULT with its length stored at
|
||||
RESULTLEN. */
|
||||
int
|
||||
gpg_error_t
|
||||
iso7816_compute_ds (int slot, const unsigned char *data, size_t datalen,
|
||||
unsigned char **result, size_t *resultlen)
|
||||
{
|
||||
@ -143,7 +217,7 @@ iso7816_compute_ds (int slot, const unsigned char *data, size_t datalen,
|
||||
xfree (*result);
|
||||
*result = NULL;
|
||||
*resultlen = 0;
|
||||
return -1; /* FIXME: Map error codes. */
|
||||
return map_sw (sw);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -154,7 +228,7 @@ iso7816_compute_ds (int slot, const unsigned char *data, size_t datalen,
|
||||
success 0 is returned and the plaintext is available in a newly
|
||||
allocated buffer stored at RESULT with its length stored at
|
||||
RESULTLEN. */
|
||||
int
|
||||
gpg_error_t
|
||||
iso7816_decipher (int slot, const unsigned char *data, size_t datalen,
|
||||
unsigned char **result, size_t *resultlen)
|
||||
{
|
||||
@ -181,14 +255,14 @@ iso7816_decipher (int slot, const unsigned char *data, size_t datalen,
|
||||
xfree (*result);
|
||||
*result = NULL;
|
||||
*resultlen = 0;
|
||||
return -1; /* FIXME: Map error codes. */
|
||||
return map_sw (sw);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
gpg_error_t
|
||||
iso7816_internal_authenticate (int slot,
|
||||
const unsigned char *data, size_t datalen,
|
||||
unsigned char **result, size_t *resultlen)
|
||||
@ -208,14 +282,14 @@ iso7816_internal_authenticate (int slot,
|
||||
xfree (*result);
|
||||
*result = NULL;
|
||||
*resultlen = 0;
|
||||
return -1; /* FIXME: Map error codes. */
|
||||
return map_sw (sw);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
static gpg_error_t
|
||||
generate_keypair (int slot, int readonly,
|
||||
const unsigned char *data, size_t datalen,
|
||||
unsigned char **result, size_t *resultlen)
|
||||
@ -235,14 +309,14 @@ generate_keypair (int slot, int readonly,
|
||||
xfree (*result);
|
||||
*result = NULL;
|
||||
*resultlen = 0;
|
||||
return -1; /* FIXME: Map error codes. */
|
||||
return map_sw (sw);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
gpg_error_t
|
||||
iso7816_generate_keypair (int slot,
|
||||
const unsigned char *data, size_t datalen,
|
||||
unsigned char **result, size_t *resultlen)
|
||||
@ -251,7 +325,7 @@ iso7816_generate_keypair (int slot,
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
gpg_error_t
|
||||
iso7816_read_public_key (int slot,
|
||||
const unsigned char *data, size_t datalen,
|
||||
unsigned char **result, size_t *resultlen)
|
||||
@ -261,12 +335,12 @@ iso7816_read_public_key (int slot,
|
||||
|
||||
|
||||
|
||||
int
|
||||
iso1816_get_challenge (int slot, int length, unsigned char *buffer)
|
||||
gpg_error_t
|
||||
iso7816_get_challenge (int slot, int length, unsigned char *buffer)
|
||||
{
|
||||
int sw;
|
||||
unsigned char *result;
|
||||
size_t resultlen;
|
||||
size_t resultlen, n;
|
||||
|
||||
if (!buffer || length < 1)
|
||||
return gpg_error (GPG_ERR_INV_VALUE);
|
||||
@ -274,26 +348,24 @@ iso1816_get_challenge (int slot, int length, unsigned char *buffer)
|
||||
do
|
||||
{
|
||||
result = NULL;
|
||||
n = length > 254? 254 : length;
|
||||
sw = apdu_send_le (slot, 0x00, CMD_GET_CHALLENGE, 0, 0, -1, NULL,
|
||||
length,
|
||||
n,
|
||||
&result, &resultlen);
|
||||
if (sw != SW_SUCCESS)
|
||||
{
|
||||
/* Make sure that pending buffers are released. */
|
||||
xfree (result);
|
||||
return -1; /* FIXME: Map error codes. */
|
||||
return map_sw (sw);
|
||||
}
|
||||
if (resultlen > length)
|
||||
resultlen = length;
|
||||
if (resultlen > n)
|
||||
resultlen = n;
|
||||
memcpy (buffer, result, resultlen);
|
||||
buffer += resultlen;
|
||||
length -= length;
|
||||
length -= resultlen;
|
||||
xfree (result);
|
||||
}
|
||||
while (length > 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -21,28 +21,36 @@
|
||||
#ifndef ISO7816_H
|
||||
#define ISO7816_H
|
||||
|
||||
int iso7816_select_application (int slot, const char *aid, size_t aidlen);
|
||||
int iso7816_verify (int slot, int chvno, const char *chv, size_t chvlen);
|
||||
int iso7816_get_data (int slot, int tag,
|
||||
unsigned char **result, size_t *resultlen);
|
||||
int iso7816_put_data (int slot, int tag,
|
||||
const unsigned char *data, size_t datalen);
|
||||
int iso7816_compute_ds (int slot,
|
||||
const unsigned char *data, size_t datalen,
|
||||
unsigned char **result, size_t *resultlen);
|
||||
int iso7816_decipher (int slot,
|
||||
const unsigned char *data, size_t datalen,
|
||||
unsigned char **result, size_t *resultlen);
|
||||
int iso7816_internal_authenticate (int slot,
|
||||
const unsigned char *data, size_t datalen,
|
||||
unsigned char **result, size_t *resultlen);
|
||||
int iso7816_generate_keypair (int slot,
|
||||
gpg_error_t iso7816_select_application (int slot,
|
||||
const char *aid, size_t aidlen);
|
||||
gpg_error_t iso7816_verify (int slot,
|
||||
int chvno, const char *chv, size_t chvlen);
|
||||
gpg_error_t iso7816_change_reference_data (int slot, int chvno,
|
||||
const char *oldchv, size_t oldchvlen,
|
||||
const char *newchv, size_t newchvlen);
|
||||
gpg_error_t iso7816_reset_retry_counter (int slot, int chvno,
|
||||
const char *newchv, size_t newchvlen);
|
||||
gpg_error_t iso7816_get_data (int slot, int tag,
|
||||
unsigned char **result, size_t *resultlen);
|
||||
gpg_error_t iso7816_put_data (int slot, int tag,
|
||||
const unsigned char *data, size_t datalen);
|
||||
gpg_error_t iso7816_compute_ds (int slot,
|
||||
const unsigned char *data, size_t datalen,
|
||||
unsigned char **result, size_t *resultlen);
|
||||
gpg_error_t iso7816_decipher (int slot,
|
||||
const unsigned char *data, size_t datalen,
|
||||
unsigned char **result, size_t *resultlen);
|
||||
int iso7816_read_public_key (int slot,
|
||||
const unsigned char *data, size_t datalen,
|
||||
unsigned char **result, size_t *resultlen);
|
||||
int iso1816_get_challenge (int slot, int length, unsigned char *buffer);
|
||||
gpg_error_t iso7816_internal_authenticate (int slot,
|
||||
const unsigned char *data, size_t datalen,
|
||||
unsigned char **result, size_t *resultlen);
|
||||
gpg_error_t iso7816_generate_keypair (int slot,
|
||||
const unsigned char *data, size_t datalen,
|
||||
unsigned char **result, size_t *resultlen);
|
||||
gpg_error_t iso7816_read_public_key (int slot,
|
||||
const unsigned char *data, size_t datalen,
|
||||
unsigned char **result, size_t *resultlen);
|
||||
gpg_error_t iso7816_get_challenge (int slot,
|
||||
int length, unsigned char *buffer);
|
||||
|
||||
|
||||
#endif /*ISO7816_H*/
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define JNLIB_NEED_LOG_LOGV
|
||||
#include "scdaemon.h"
|
||||
@ -41,6 +42,8 @@ enum cmd_and_opt_values
|
||||
oDebug,
|
||||
oDebugAll,
|
||||
|
||||
oGenRandom,
|
||||
|
||||
aTest };
|
||||
|
||||
|
||||
@ -52,6 +55,7 @@ static ARGPARSE_OPTS opts[] = {
|
||||
{ oReaderPort, "reader-port", 1, "|N|connect to reader at port N"},
|
||||
{ oDebug, "debug" ,4|16, "set debugging flags"},
|
||||
{ oDebugAll, "debug-all" ,0, "enable full debugging"},
|
||||
{ oGenRandom, "gen-random", 4, "|N|generate N bytes of random"},
|
||||
{0}
|
||||
};
|
||||
|
||||
@ -106,6 +110,7 @@ main (int argc, char **argv )
|
||||
int slot, rc;
|
||||
int reader_port = 32768; /* First USB reader. */
|
||||
struct app_ctx_s appbuf;
|
||||
unsigned long gen_random = 0;
|
||||
|
||||
memset (&appbuf, 0, sizeof appbuf);
|
||||
|
||||
@ -134,6 +139,7 @@ main (int argc, char **argv )
|
||||
case oVerbose: opt.verbose++; break;
|
||||
case oDebug: opt.debug |= pargs.r.ret_ulong; break;
|
||||
case oDebugAll: opt.debug = ~0; break;
|
||||
case oGenRandom: gen_random = pargs.r.ret_ulong; break;
|
||||
default : pargs.err = 2; break;
|
||||
}
|
||||
}
|
||||
@ -149,20 +155,49 @@ main (int argc, char **argv )
|
||||
slot = apdu_open_reader (reader_port);
|
||||
if (slot == -1)
|
||||
exit (1);
|
||||
|
||||
rc = atr_dump (slot, stdout);
|
||||
if (rc)
|
||||
log_error ("can't dump ATR: %s\n", gpg_strerror (rc));
|
||||
|
||||
if (!gen_random)
|
||||
{
|
||||
rc = atr_dump (slot, stdout);
|
||||
if (rc)
|
||||
log_error ("can't dump ATR: %s\n", gpg_strerror (rc));
|
||||
}
|
||||
|
||||
appbuf.slot = slot;
|
||||
rc = app_select_openpgp (&appbuf, NULL, NULL);
|
||||
if (rc)
|
||||
log_error ("selecting openpgp failed: %s\n", gpg_strerror (rc));
|
||||
else
|
||||
log_info ("openpgp application selected\n");
|
||||
{
|
||||
appbuf.initialized = 1;
|
||||
log_info ("openpgp application selected\n");
|
||||
|
||||
if (gen_random)
|
||||
{
|
||||
size_t nbytes;
|
||||
unsigned char *buffer;
|
||||
|
||||
buffer = xmalloc (4096);
|
||||
do
|
||||
{
|
||||
nbytes = gen_random > 4096? 4096 : gen_random;
|
||||
rc = app_get_challenge (&appbuf, nbytes, buffer);
|
||||
if (rc)
|
||||
log_error ("app_get_challenge failed: %s\n",gpg_strerror (rc));
|
||||
else
|
||||
{
|
||||
if (fwrite (buffer, nbytes, 1, stdout) != 1)
|
||||
log_error ("writing to stdout failed: %s\n",
|
||||
strerror (errno));
|
||||
gen_random -= nbytes;
|
||||
}
|
||||
}
|
||||
while (gen_random && !log_get_errorcount (0));
|
||||
xfree (buffer);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return log_get_errorcount (0)? 2:0;
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user