mirror of
git://git.gnupg.org/gnupg.git
synced 2025-03-24 22:09:57 +01:00
(ccid_transceive): Arghhh. The seqno is another
bit in the R-block than in the I block, this was wrong at one place. Fixes bug #419 and hopefully several others.
This commit is contained in:
parent
780331cfcd
commit
bd644c8d45
@ -1,3 +1,21 @@
|
||||
2005-05-20 Werner Koch <wk@g10code.com>
|
||||
|
||||
* ccid-driver.c (ccid_transceive): Arghhh. The seqno is another
|
||||
bit in the R-block than in the I block, this was wrong at one
|
||||
place. Fixes bug #419 and hopefully several others.
|
||||
|
||||
2005-05-19 Werner Koch <wk@g10code.com>
|
||||
|
||||
* app-common.h, app-openpgp.c, tlv.c, tlv.h: Updated from newer
|
||||
version in gnupg 1.9 CVS.
|
||||
|
||||
2005-05-18 Werner Koch <wk@g10code.com>
|
||||
|
||||
* passphrase.c (agent_open): Made global and add arg TRY.
|
||||
(agent_close): Made global.
|
||||
|
||||
* app-common.h (app_t): Add a field to store the Assuan context.
|
||||
|
||||
2005-05-13 David Shaw <dshaw@jabberwocky.com>
|
||||
|
||||
* build-packet.c (do_comment): Removed.
|
||||
|
126
g10/app-common.h
126
g10/app-common.h
@ -1,5 +1,5 @@
|
||||
/* app-common.h - Common declarations for all card applications
|
||||
* Copyright (C) 2003 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2003, 2005 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
@ -23,10 +23,15 @@
|
||||
#ifndef GNUPG_SCD_APP_COMMON_H
|
||||
#define GNUPG_SCD_APP_COMMON_H
|
||||
|
||||
#if GNUPG_MAJOR_VERSION != 1
|
||||
#include <ksba.h>
|
||||
#if GNUPG_MAJOR_VERSION == 1
|
||||
# ifdef ENABLE_AGENT_SUPPORT
|
||||
# include "assuan.h"
|
||||
# endif
|
||||
#else
|
||||
# include <ksba.h>
|
||||
#endif
|
||||
|
||||
|
||||
struct app_local_s; /* Defined by all app-*.c. */
|
||||
|
||||
struct app_ctx_s {
|
||||
@ -35,6 +40,15 @@ struct app_ctx_s {
|
||||
unsupported operations the particular
|
||||
function pointer is set to NULL */
|
||||
int slot; /* Used reader. */
|
||||
|
||||
/* If this is used by GnuPG 1.4 we need to know the assuan context
|
||||
in case we need to divert the operation to an already running
|
||||
agent. This if ASSUAN_CTX is not NULL we take this as indication
|
||||
that all operations are diverted to gpg-agent. */
|
||||
#if GNUPG_MAJOR_VERSION == 1 && defined(ENABLE_AGENT_SUPPORT)
|
||||
assuan_context_t assuan_ctx;
|
||||
#endif /*GNUPG_MAJOR_VERSION == 1*/
|
||||
|
||||
unsigned char *serialno; /* Serialnumber in raw form, allocated. */
|
||||
size_t serialnolen; /* Length in octets of serialnumber. */
|
||||
const char *apptype;
|
||||
@ -46,54 +60,56 @@ struct app_ctx_s {
|
||||
struct app_local_s *app_local; /* Local to the application. */
|
||||
struct {
|
||||
void (*deinit) (app_t app);
|
||||
int (*learn_status) (app_t app, ctrl_t ctrl);
|
||||
int (*readcert) (app_t app, const char *certid,
|
||||
gpg_error_t (*learn_status) (app_t app, ctrl_t ctrl);
|
||||
gpg_error_t (*readcert) (app_t app, const char *certid,
|
||||
unsigned char **cert, size_t *certlen);
|
||||
int (*getattr) (app_t app, ctrl_t ctrl, const char *name);
|
||||
int (*setattr) (app_t app, const char *name,
|
||||
int (*pincb)(void*, const char *, char **),
|
||||
gpg_error_t (*readkey) (app_t app, const char *certid,
|
||||
unsigned char **pk, size_t *pklen);
|
||||
gpg_error_t (*getattr) (app_t app, ctrl_t ctrl, const char *name);
|
||||
gpg_error_t (*setattr) (app_t app, const char *name,
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg,
|
||||
const unsigned char *value, size_t valuelen);
|
||||
int (*sign) (app_t app,
|
||||
gpg_error_t (*sign) (app_t app,
|
||||
const char *keyidstr, int hashalgo,
|
||||
int (pincb)(void*, const char *, char **),
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg,
|
||||
const void *indata, size_t indatalen,
|
||||
unsigned char **outdata, size_t *outdatalen );
|
||||
int (*auth) (app_t app, const char *keyidstr,
|
||||
int (*pincb)(void*, const char *, char **),
|
||||
gpg_error_t (*auth) (app_t app, const char *keyidstr,
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg,
|
||||
const void *indata, size_t indatalen,
|
||||
unsigned char **outdata, size_t *outdatalen);
|
||||
int (*decipher) (app_t app, const char *keyidstr,
|
||||
int (pincb)(void*, const char *, char **),
|
||||
gpg_error_t (*decipher) (app_t app, const char *keyidstr,
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg,
|
||||
const void *indata, size_t indatalen,
|
||||
unsigned char **outdata, size_t *outdatalen);
|
||||
int (*genkey) (app_t app, ctrl_t ctrl,
|
||||
gpg_error_t (*genkey) (app_t app, ctrl_t ctrl,
|
||||
const char *keynostr, unsigned int flags,
|
||||
int (*pincb)(void*, const char *, char **),
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg);
|
||||
int (*change_pin) (app_t app, ctrl_t ctrl,
|
||||
gpg_error_t (*change_pin) (app_t app, ctrl_t ctrl,
|
||||
const char *chvnostr, int reset_mode,
|
||||
int (*pincb)(void*, const char *, char **),
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg);
|
||||
int (*check_pin) (app_t app, const char *keyidstr,
|
||||
int (pincb)(void*, const char *, char **),
|
||||
gpg_error_t (*check_pin) (app_t app, const char *keyidstr,
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg);
|
||||
} fnc;
|
||||
|
||||
};
|
||||
|
||||
#if GNUPG_MAJOR_VERSION == 1
|
||||
int app_select_openpgp (app_t app);
|
||||
int app_get_serial_and_stamp (app_t app, char **serial, time_t *stamp);
|
||||
int app_openpgp_storekey (app_t app, int keyno,
|
||||
gpg_error_t app_select_openpgp (app_t app);
|
||||
gpg_error_t app_get_serial_and_stamp (app_t app, char **serial, time_t *stamp);
|
||||
gpg_error_t app_openpgp_storekey (app_t app, int keyno,
|
||||
unsigned char *template, size_t template_len,
|
||||
time_t created_at,
|
||||
const unsigned char *m, size_t mlen,
|
||||
const unsigned char *e, size_t elen,
|
||||
int (*pincb)(void*, const char *, char **),
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg);
|
||||
#else
|
||||
/*-- app-help.c --*/
|
||||
@ -102,75 +118,79 @@ size_t app_help_read_length_of_cert (int slot, int fid, size_t *r_certoff);
|
||||
|
||||
|
||||
/*-- app.c --*/
|
||||
app_t select_application (ctrl_t ctrl, int slot, const char *name);
|
||||
gpg_error_t select_application (ctrl_t ctrl, int slot, const char *name,
|
||||
app_t *r_app);
|
||||
void release_application (app_t app);
|
||||
int app_munge_serialno (app_t app);
|
||||
int app_get_serial_and_stamp (app_t app, char **serial, time_t *stamp);
|
||||
int app_write_learn_status (app_t app, ctrl_t ctrl);
|
||||
int app_readcert (app_t app, const char *certid,
|
||||
gpg_error_t app_munge_serialno (app_t app);
|
||||
gpg_error_t app_get_serial_and_stamp (app_t app, char **serial, time_t *stamp);
|
||||
gpg_error_t app_write_learn_status (app_t app, ctrl_t ctrl);
|
||||
gpg_error_t app_readcert (app_t app, const char *certid,
|
||||
unsigned char **cert, size_t *certlen);
|
||||
int app_getattr (app_t app, ctrl_t ctrl, const char *name);
|
||||
int app_setattr (app_t app, const char *name,
|
||||
int (*pincb)(void*, const char *, char **),
|
||||
gpg_error_t app_readkey (app_t app, const char *keyid,
|
||||
unsigned char **pk, size_t *pklen);
|
||||
gpg_error_t app_getattr (app_t app, ctrl_t ctrl, const char *name);
|
||||
gpg_error_t app_setattr (app_t app, const char *name,
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg,
|
||||
const unsigned char *value, size_t valuelen);
|
||||
int app_sign (app_t app, const char *keyidstr, int hashalgo,
|
||||
int (pincb)(void*, const char *, char **),
|
||||
gpg_error_t app_sign (app_t app, const char *keyidstr, int hashalgo,
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg,
|
||||
const void *indata, size_t indatalen,
|
||||
unsigned char **outdata, size_t *outdatalen );
|
||||
int app_auth (app_t app, const char *keyidstr,
|
||||
int (*pincb)(void*, const char *, char **),
|
||||
gpg_error_t app_auth (app_t app, const char *keyidstr,
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg,
|
||||
const void *indata, size_t indatalen,
|
||||
unsigned char **outdata, size_t *outdatalen);
|
||||
int app_decipher (app_t app, const char *keyidstr,
|
||||
int (pincb)(void*, const char *, char **),
|
||||
gpg_error_t app_decipher (app_t app, const char *keyidstr,
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg,
|
||||
const void *indata, size_t indatalen,
|
||||
unsigned char **outdata, size_t *outdatalen );
|
||||
int app_genkey (app_t app, ctrl_t ctrl,
|
||||
gpg_error_t app_genkey (app_t app, ctrl_t ctrl,
|
||||
const char *keynostr, unsigned int flags,
|
||||
int (*pincb)(void*, const char *, char **),
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg);
|
||||
int app_get_challenge (app_t app, size_t nbytes, unsigned char *buffer);
|
||||
int app_change_pin (app_t app, ctrl_t ctrl,
|
||||
gpg_error_t app_get_challenge (app_t app, size_t nbytes,
|
||||
unsigned char *buffer);
|
||||
gpg_error_t app_change_pin (app_t app, ctrl_t ctrl,
|
||||
const char *chvnostr, int reset_mode,
|
||||
int (*pincb)(void*, const char *, char **),
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg);
|
||||
int app_check_pin (app_t app, const char *keyidstr,
|
||||
int (*pincb)(void*, const char *, char **),
|
||||
gpg_error_t app_check_pin (app_t app, const char *keyidstr,
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg);
|
||||
|
||||
|
||||
/*-- app-openpgp.c --*/
|
||||
int app_select_openpgp (app_t app);
|
||||
gpg_error_t app_select_openpgp (app_t app);
|
||||
|
||||
int app_openpgp_cardinfo (app_t app,
|
||||
gpg_error_t app_openpgp_cardinfo (app_t app,
|
||||
char **serialno,
|
||||
char **disp_name,
|
||||
char **pubkey_url,
|
||||
unsigned char **fpr1,
|
||||
unsigned char **fpr2,
|
||||
unsigned char **fpr3);
|
||||
int app_openpgp_storekey (app_t app, int keyno,
|
||||
gpg_error_t app_openpgp_storekey (app_t app, int keyno,
|
||||
unsigned char *template, size_t template_len,
|
||||
time_t created_at,
|
||||
const unsigned char *m, size_t mlen,
|
||||
const unsigned char *e, size_t elen,
|
||||
int (*pincb)(void*, const char *, char **),
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg);
|
||||
int app_openpgp_readkey (app_t app, int keyno,
|
||||
gpg_error_t app_openpgp_readkey (app_t app, int keyno,
|
||||
unsigned char **m, size_t *mlen,
|
||||
unsigned char **e, size_t *elen);
|
||||
/*-- app-nks.c --*/
|
||||
int app_select_nks (app_t app);
|
||||
gpg_error_t app_select_nks (app_t app);
|
||||
|
||||
/*-- app-dinsig.c --*/
|
||||
int app_select_dinsig (app_t app);
|
||||
gpg_error_t app_select_dinsig (app_t app);
|
||||
|
||||
/*-- app-p15.c --*/
|
||||
int app_select_p15 (app_t app);
|
||||
gpg_error_t app_select_p15 (app_t app);
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -90,6 +90,7 @@ static struct {
|
||||
};
|
||||
|
||||
|
||||
/* One cache item for DOs. */
|
||||
struct cache_s {
|
||||
struct cache_s *next;
|
||||
int tag;
|
||||
@ -97,8 +98,27 @@ struct cache_s {
|
||||
unsigned char data[1];
|
||||
};
|
||||
|
||||
|
||||
/* Object with application (i.e. OpenPGP card) specific data. */
|
||||
struct app_local_s {
|
||||
/* A linked list with cached DOs. */
|
||||
struct cache_s *cache;
|
||||
|
||||
/* Keep track of the public keys. */
|
||||
struct
|
||||
{
|
||||
int read_done; /* True if we have at least tried to read them. */
|
||||
unsigned char *key; /* This is a malloced buffer with a canonical
|
||||
encoded S-expression encoding a public
|
||||
key. Might be NULL if key is not
|
||||
available. */
|
||||
size_t keylen; /* The length of the above S-expression. Thsi
|
||||
is usullay only required for corss checks
|
||||
because the length of an S-expression is
|
||||
implicitly available. */
|
||||
} pk[3];
|
||||
|
||||
/* Keep track of card capabilities. */
|
||||
struct
|
||||
{
|
||||
unsigned int get_challenge:1;
|
||||
@ -106,6 +126,8 @@ struct app_local_s {
|
||||
unsigned int change_force_chv:1;
|
||||
unsigned int private_dos:1;
|
||||
} extcap;
|
||||
|
||||
/* Flags used to control the application. */
|
||||
struct
|
||||
{
|
||||
unsigned int no_sync:1; /* Do not sync CHV1 and CHV2 */
|
||||
@ -114,10 +136,16 @@ struct app_local_s {
|
||||
};
|
||||
|
||||
|
||||
|
||||
/***** Local prototypes *****/
|
||||
static unsigned long convert_sig_counter_value (const unsigned char *value,
|
||||
size_t valuelen);
|
||||
static unsigned long get_sig_counter (APP app);
|
||||
static unsigned long get_sig_counter (app_t app);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* Deconstructor. */
|
||||
static void
|
||||
do_deinit (app_t app)
|
||||
@ -125,12 +153,19 @@ do_deinit (app_t app)
|
||||
if (app && app->app_local)
|
||||
{
|
||||
struct cache_s *c, *c2;
|
||||
int i;
|
||||
|
||||
for (c = app->app_local->cache; c; c = c2)
|
||||
{
|
||||
c2 = c->next;
|
||||
xfree (c);
|
||||
}
|
||||
|
||||
for (i=0; i < DIM (app->app_local->pk); i++)
|
||||
{
|
||||
xfree (app->app_local->pk[i].key);
|
||||
app->app_local->pk[i].read_done = 0;
|
||||
}
|
||||
xfree (app->app_local);
|
||||
app->app_local = NULL;
|
||||
}
|
||||
@ -278,23 +313,33 @@ flush_cache (app_t app)
|
||||
NULL if not found or a pointer which must be used to release the
|
||||
buffer holding value. */
|
||||
static void *
|
||||
get_one_do (app_t app, int tag, unsigned char **result, size_t *nbytes)
|
||||
get_one_do (app_t app, int tag, unsigned char **result, size_t *nbytes,
|
||||
int *r_rc)
|
||||
{
|
||||
int rc, i;
|
||||
unsigned char *buffer;
|
||||
size_t buflen;
|
||||
unsigned char *value;
|
||||
size_t valuelen;
|
||||
int dummyrc;
|
||||
|
||||
if (!r_rc)
|
||||
r_rc = &dummyrc;
|
||||
|
||||
*result = NULL;
|
||||
*nbytes = 0;
|
||||
*r_rc = 0;
|
||||
for (i=0; data_objects[i].tag && data_objects[i].tag != tag; i++)
|
||||
;
|
||||
|
||||
if (app->card_version > 0x0100 && data_objects[i].get_immediate_in_v11)
|
||||
{
|
||||
if( iso7816_get_data (app->slot, tag, &buffer, &buflen))
|
||||
return NULL;
|
||||
rc = iso7816_get_data (app->slot, tag, &buffer, &buflen);
|
||||
if (rc)
|
||||
{
|
||||
*r_rc = rc;
|
||||
return NULL;
|
||||
}
|
||||
*result = buffer;
|
||||
*nbytes = buflen;
|
||||
return buffer;
|
||||
@ -306,12 +351,13 @@ get_one_do (app_t app, int tag, unsigned char **result, size_t *nbytes)
|
||||
{
|
||||
rc = get_cached_data (app, data_objects[i].get_from,
|
||||
&buffer, &buflen,
|
||||
data_objects[i].get_immediate_in_v11);
|
||||
(data_objects[i].dont_cache
|
||||
|| data_objects[i].get_immediate_in_v11));
|
||||
if (!rc)
|
||||
{
|
||||
const unsigned char *s;
|
||||
|
||||
s = find_tlv (buffer, buflen, tag, &valuelen);
|
||||
s = find_tlv_unchecked (buffer, buflen, tag, &valuelen);
|
||||
if (!s)
|
||||
value = NULL; /* not found */
|
||||
else if (valuelen > buflen - (s - buffer))
|
||||
@ -328,7 +374,8 @@ get_one_do (app_t app, int tag, unsigned char **result, size_t *nbytes)
|
||||
if (!value) /* Not in a constructed DO, try simple. */
|
||||
{
|
||||
rc = get_cached_data (app, tag, &buffer, &buflen,
|
||||
data_objects[i].get_immediate_in_v11);
|
||||
(data_objects[i].dont_cache
|
||||
|| data_objects[i].get_immediate_in_v11));
|
||||
if (!rc)
|
||||
{
|
||||
value = buffer;
|
||||
@ -342,6 +389,7 @@ get_one_do (app_t app, int tag, unsigned char **result, size_t *nbytes)
|
||||
*result = value;
|
||||
return buffer;
|
||||
}
|
||||
*r_rc = rc;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -385,8 +433,8 @@ dump_all_do (int slot)
|
||||
|
||||
if (j==i || data_objects[i].tag != data_objects[j].get_from)
|
||||
continue;
|
||||
value = find_tlv (buffer, buflen,
|
||||
data_objects[j].tag, &valuelen);
|
||||
value = find_tlv_unchecked (buffer, buflen,
|
||||
data_objects[j].tag, &valuelen);
|
||||
if (!value)
|
||||
; /* not found */
|
||||
else if (valuelen > buflen - (value - buffer))
|
||||
@ -460,7 +508,7 @@ parse_login_data (app_t app)
|
||||
app->app_local->flags.def_chv2 = 0;
|
||||
|
||||
/* Read the DO. */
|
||||
relptr = get_one_do (app, 0x005E, &buffer, &buflen);
|
||||
relptr = get_one_do (app, 0x005E, &buffer, &buflen, NULL);
|
||||
if (!relptr)
|
||||
return; /* Ooops. */
|
||||
for (; buflen; buflen--, buffer++)
|
||||
@ -499,7 +547,7 @@ parse_login_data (app_t app)
|
||||
}
|
||||
|
||||
/* Note, that FPR must be at least 20 bytes. */
|
||||
static int
|
||||
static gpg_error_t
|
||||
store_fpr (int slot, int keynumber, u32 timestamp,
|
||||
const unsigned char *m, size_t mlen,
|
||||
const unsigned char *e, size_t elen,
|
||||
@ -623,7 +671,7 @@ send_key_data (ctrl_t ctrl, const char *name,
|
||||
|
||||
/* Implement the GETATTR command. This is similar to the LEARN
|
||||
command but returns just one value via the status interface. */
|
||||
static int
|
||||
static gpg_error_t
|
||||
do_getattr (app_t app, ctrl_t ctrl, const char *name)
|
||||
{
|
||||
static struct {
|
||||
@ -650,7 +698,7 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
|
||||
{ "PRIVATE-DO-4", 0x0104 },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
int idx, i;
|
||||
int idx, i, rc;
|
||||
void *relptr;
|
||||
unsigned char *value;
|
||||
size_t valuelen;
|
||||
@ -695,7 +743,7 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
relptr = get_one_do (app, table[idx].tag, &value, &valuelen);
|
||||
relptr = get_one_do (app, table[idx].tag, &value, &valuelen, &rc);
|
||||
if (relptr)
|
||||
{
|
||||
if (table[idx].special == 1)
|
||||
@ -732,11 +780,395 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
|
||||
|
||||
xfree (relptr);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Retrieve the fingerprint from the card inserted in SLOT and write
|
||||
the according hex representation to FPR. Caller must have provide
|
||||
a buffer at FPR of least 41 bytes. Returns 0 on success or an
|
||||
error code. */
|
||||
#if GNUPG_MAJOR_VERSION > 1
|
||||
static gpg_error_t
|
||||
retrieve_fpr_from_card (app_t app, int keyno, char *fpr)
|
||||
{
|
||||
gpg_error_t err = 0;
|
||||
void *relptr;
|
||||
unsigned char *value;
|
||||
size_t valuelen;
|
||||
int i;
|
||||
|
||||
assert (keyno >=0 && keyno <= 2);
|
||||
|
||||
relptr = get_one_do (app, 0x00C5, &value, &valuelen, NULL);
|
||||
if (relptr && valuelen >= 60)
|
||||
{
|
||||
for (i = 0; i < 20; i++)
|
||||
sprintf (fpr + (i * 2), "%02X", value[(keyno*20)+i]);
|
||||
}
|
||||
else
|
||||
err = gpg_error (GPG_ERR_NOT_FOUND);
|
||||
xfree (relptr);
|
||||
return err;
|
||||
}
|
||||
#endif /*GNUPG_MAJOR_VERSION > 1*/
|
||||
|
||||
|
||||
/* Retrieve the public key material for the RSA key, whose fingerprint
|
||||
is FPR, from gpg output, which can be read through the stream FP.
|
||||
The RSA modulus will be stored at the address of M and MLEN, the
|
||||
public exponent at E and ELEN. Returns zero on success, an error
|
||||
code on failure. Caller must release the allocated buffers at M
|
||||
and E if the function returns success. */
|
||||
#if GNUPG_MAJOR_VERSION > 1
|
||||
static gpg_error_t
|
||||
retrieve_key_material (FILE *fp, const char *hexkeyid,
|
||||
const unsigned char **m, size_t *mlen,
|
||||
const unsigned char **e, size_t *elen)
|
||||
{
|
||||
gcry_error_t err = 0;
|
||||
char *line = NULL; /* read_line() buffer. */
|
||||
size_t line_size = 0; /* Helper for for read_line. */
|
||||
int found_key = 0; /* Helper to find a matching key. */
|
||||
unsigned char *m_new = NULL;
|
||||
unsigned char *e_new = NULL;
|
||||
size_t m_new_n = 0;
|
||||
size_t e_new_n = 0;
|
||||
|
||||
/* Loop over all records until we have found the subkey
|
||||
corresponsing to the fingerprint. Inm general the first record
|
||||
should be the pub record, but we don't rely on that. Given that
|
||||
we only need to look at one key, it is sufficient to compare the
|
||||
keyid so that we don't need to look at "fpr" records. */
|
||||
for (;;)
|
||||
{
|
||||
char *p;
|
||||
char *fields[6];
|
||||
int nfields;
|
||||
size_t max_length;
|
||||
gcry_mpi_t mpi;
|
||||
int i;
|
||||
|
||||
max_length = 4096;
|
||||
i = read_line (fp, &line, &line_size, &max_length);
|
||||
if (!i)
|
||||
break; /* EOF. */
|
||||
if (i < 0)
|
||||
{
|
||||
err = gpg_error_from_errno (errno);
|
||||
goto leave; /* Error. */
|
||||
}
|
||||
if (!max_length)
|
||||
{
|
||||
err = gpg_error (GPG_ERR_TRUNCATED);
|
||||
goto leave; /* Line truncated - we better stop processing. */
|
||||
}
|
||||
|
||||
/* Parse the line into fields. */
|
||||
for (nfields=0, p=line; p && nfields < DIM (fields); nfields++)
|
||||
{
|
||||
fields[nfields] = p;
|
||||
p = strchr (p, ':');
|
||||
if (p)
|
||||
*(p++) = 0;
|
||||
}
|
||||
if (!nfields)
|
||||
continue; /* No fields at all - skip line. */
|
||||
|
||||
if (!found_key)
|
||||
{
|
||||
if ( (!strcmp (fields[0], "sub") || !strcmp (fields[0], "pub") )
|
||||
&& nfields > 4 && !strcmp (fields[4], hexkeyid))
|
||||
found_key = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( !strcmp (fields[0], "sub") || !strcmp (fields[0], "pub") )
|
||||
break; /* Next key - stop. */
|
||||
|
||||
if ( strcmp (fields[0], "pkd") )
|
||||
continue; /* Not a key data record. */
|
||||
i = 0; /* Avoid erroneous compiler warning. */
|
||||
if ( nfields < 4 || (i = atoi (fields[1])) < 0 || i > 1
|
||||
|| (!i && m_new) || (i && e_new))
|
||||
{
|
||||
err = gpg_error (GPG_ERR_GENERAL);
|
||||
goto leave; /* Error: Invalid key data record or not an RSA key. */
|
||||
}
|
||||
|
||||
err = gcry_mpi_scan (&mpi, GCRYMPI_FMT_HEX, fields[3], 0, NULL);
|
||||
if (err)
|
||||
mpi = NULL;
|
||||
else if (!i)
|
||||
err = gcry_mpi_aprint (GCRYMPI_FMT_STD, &m_new, &m_new_n, mpi);
|
||||
else
|
||||
err = gcry_mpi_aprint (GCRYMPI_FMT_STD, &e_new, &e_new_n, mpi);
|
||||
gcry_mpi_release (mpi);
|
||||
if (err)
|
||||
goto leave;
|
||||
}
|
||||
|
||||
if (m_new && e_new)
|
||||
{
|
||||
*m = m_new;
|
||||
*mlen = m_new_n;
|
||||
m_new = NULL;
|
||||
*e = e_new;
|
||||
*elen = e_new_n;
|
||||
e_new = NULL;
|
||||
}
|
||||
else
|
||||
err = gpg_error (GPG_ERR_GENERAL);
|
||||
|
||||
leave:
|
||||
xfree (m_new);
|
||||
xfree (e_new);
|
||||
xfree (line);
|
||||
return err;
|
||||
}
|
||||
#endif /*GNUPG_MAJOR_VERSION > 1*/
|
||||
|
||||
|
||||
/* Get the public key for KEYNO and store it as an S-expresion with
|
||||
the APP handle. On error that field gets cleared. If we already
|
||||
know about the public key we will just return. Note that this does
|
||||
not mean a key is available; this is soley indicated by the
|
||||
presence of the app->app_local->pk[KEYNO-1].key field.
|
||||
|
||||
Note that GnuPG 1.x does not need this and it would be too time
|
||||
consuming to send it just for the fun of it. However, given that we
|
||||
use the same code in gpg 1.4, we can't use the gcry S-expresion
|
||||
here but need to open encode it. */
|
||||
#if GNUPG_MAJOR_VERSION > 1
|
||||
static gpg_error_t
|
||||
get_public_key (app_t app, int keyno)
|
||||
{
|
||||
gpg_error_t err = 0;
|
||||
unsigned char *buffer;
|
||||
const unsigned char *keydata, *m, *e;
|
||||
size_t buflen, keydatalen, mlen, elen;
|
||||
unsigned char *mbuf = NULL;
|
||||
unsigned char *ebuf = NULL;
|
||||
unsigned char *keybuf = NULL;
|
||||
unsigned char *keybuf_p;
|
||||
|
||||
if (keyno < 1 || keyno > 3)
|
||||
return gpg_error (GPG_ERR_INV_ID);
|
||||
keyno--;
|
||||
|
||||
/* Already cached? */
|
||||
if (app->app_local->pk[keyno].read_done)
|
||||
return 0;
|
||||
|
||||
xfree (app->app_local->pk[keyno].key);
|
||||
app->app_local->pk[keyno].key = NULL;
|
||||
app->app_local->pk[keyno].keylen = 0;
|
||||
|
||||
if (app->card_version > 0x0100)
|
||||
{
|
||||
/* We may simply read the public key out of these cards. */
|
||||
err = iso7816_read_public_key (app->slot,
|
||||
keyno == 0? "\xB6" :
|
||||
keyno == 1? "\xB8" : "\xA4",
|
||||
2,
|
||||
&buffer, &buflen);
|
||||
if (err)
|
||||
{
|
||||
log_error (_("reading public key failed: %s\n"), gpg_strerror (err));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
keydata = find_tlv (buffer, buflen, 0x7F49, &keydatalen);
|
||||
if (!keydata)
|
||||
{
|
||||
err = gpg_error (GPG_ERR_CARD);
|
||||
log_error (_("response does not contain the public key data\n"));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
m = find_tlv (keydata, keydatalen, 0x0081, &mlen);
|
||||
if (!m)
|
||||
{
|
||||
err = gpg_error (GPG_ERR_CARD);
|
||||
log_error (_("response does not contain the RSA modulus\n"));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
|
||||
e = find_tlv (keydata, keydatalen, 0x0082, &elen);
|
||||
if (!e)
|
||||
{
|
||||
err = gpg_error (GPG_ERR_CARD);
|
||||
log_error (_("response does not contain the RSA public exponent\n"));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* Prepend numbers with a 0 if needed. */
|
||||
if (mlen && (*m & 0x80))
|
||||
{
|
||||
mbuf = xtrymalloc ( mlen + 1);
|
||||
if (!mbuf)
|
||||
{
|
||||
err = gpg_error_from_errno (errno);
|
||||
goto leave;
|
||||
}
|
||||
*mbuf = 0;
|
||||
memcpy (mbuf+1, m, mlen);
|
||||
mlen++;
|
||||
m = mbuf;
|
||||
}
|
||||
if (elen && (*e & 0x80))
|
||||
{
|
||||
ebuf = xtrymalloc ( elen + 1);
|
||||
if (!ebuf)
|
||||
{
|
||||
err = gpg_error_from_errno (errno);
|
||||
goto leave;
|
||||
}
|
||||
*ebuf = 0;
|
||||
memcpy (ebuf+1, e, elen);
|
||||
elen++;
|
||||
e = ebuf;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Due to a design problem in v1.0 cards we can't get the public
|
||||
key out of these cards without doing a verify on CHV3.
|
||||
Clearly that is not an option and thus we try to locate the
|
||||
key using an external helper.
|
||||
|
||||
The helper we use here is gpg itself, which should know about
|
||||
the key in any case. */
|
||||
|
||||
char fpr[41];
|
||||
char *hexkeyid;
|
||||
char *command = NULL;
|
||||
FILE *fp;
|
||||
int ret;
|
||||
|
||||
buffer = NULL; /* We don't need buffer. */
|
||||
|
||||
err = retrieve_fpr_from_card (app, keyno, fpr);
|
||||
if (err)
|
||||
{
|
||||
log_error ("error while retrieving fpr from card: %s\n",
|
||||
gpg_strerror (err));
|
||||
goto leave;
|
||||
}
|
||||
hexkeyid = fpr + 24;
|
||||
|
||||
ret = asprintf (&command,
|
||||
"gpg --list-keys --with-colons --with-key-data '%s'",
|
||||
fpr);
|
||||
if (ret < 0)
|
||||
{
|
||||
err = gpg_error_from_errno (errno);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
fp = popen (command, "r");
|
||||
free (command);
|
||||
if (!fp)
|
||||
{
|
||||
err = gpg_error_from_errno (errno);
|
||||
log_error ("running gpg failed: %s\n", gpg_strerror (err));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
err = retrieve_key_material (fp, hexkeyid, &m, &mlen, &e, &elen);
|
||||
fclose (fp);
|
||||
if (err)
|
||||
{
|
||||
log_error ("error while retrieving key material through pipe: %s\n",
|
||||
gpg_strerror (err));
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
|
||||
/* Allocate a buffer to construct the S-expression. */
|
||||
/* FIXME: We should provide a generalized S-expression creation
|
||||
mechanism. */
|
||||
keybuf = xtrymalloc (50 + 2*35 + mlen + elen + 1);
|
||||
if (!keybuf)
|
||||
{
|
||||
err = gpg_error_from_errno (errno);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
sprintf (keybuf, "(10:public-key(3:rsa(1:n%u:", (unsigned int) mlen);
|
||||
keybuf_p = keybuf + strlen (keybuf);
|
||||
memcpy (keybuf_p, m, mlen);
|
||||
keybuf_p += mlen;
|
||||
sprintf (keybuf_p, ")(1:e%u:", (unsigned int)elen);
|
||||
keybuf_p += strlen (keybuf_p);
|
||||
memcpy (keybuf_p, e, elen);
|
||||
keybuf_p += elen;
|
||||
strcpy (keybuf_p, ")))");
|
||||
keybuf_p += strlen (keybuf_p);
|
||||
|
||||
app->app_local->pk[keyno].key = keybuf;
|
||||
app->app_local->pk[keyno].keylen = (keybuf_p - keybuf);
|
||||
|
||||
leave:
|
||||
/* Set a flag to indicate that we tried to read the key. */
|
||||
app->app_local->pk[keyno].read_done = 1;
|
||||
|
||||
xfree (buffer);
|
||||
xfree (mbuf);
|
||||
xfree (ebuf);
|
||||
return 0;
|
||||
}
|
||||
#endif /* GNUPG_MAJOR_VERSION > 1 */
|
||||
|
||||
|
||||
|
||||
/* Send the KEYPAIRINFO back. KEYNO needs to be in the range [1,3].
|
||||
This is used by the LEARN command. */
|
||||
static gpg_error_t
|
||||
send_keypair_info (app_t app, ctrl_t ctrl, int keyno)
|
||||
{
|
||||
gpg_error_t err = 0;
|
||||
/* Note that GnuPG 1.x does not need this and it would be too time
|
||||
consuming to send it just for the fun of it. */
|
||||
#if GNUPG_MAJOR_VERSION > 1
|
||||
unsigned char grip[20];
|
||||
char gripstr[41];
|
||||
char idbuf[50];
|
||||
int i;
|
||||
|
||||
err = get_public_key (app, keyno);
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
assert (keyno >= 1 && keyno <= 3);
|
||||
if (!app->app_local->pk[keyno-1].key)
|
||||
goto leave; /* No such key - ignore. */
|
||||
|
||||
err = keygrip_from_canon_sexp (app->app_local->pk[keyno-1].key,
|
||||
app->app_local->pk[keyno-1].keylen,
|
||||
grip);
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
for (i=0; i < 20; i++)
|
||||
sprintf (gripstr+i*2, "%02X", grip[i]);
|
||||
|
||||
sprintf (idbuf, "OPENPGP.%d", keyno);
|
||||
send_status_info (ctrl, "KEYPAIRINFO",
|
||||
gripstr, 40,
|
||||
idbuf, strlen (idbuf),
|
||||
NULL, (size_t)0);
|
||||
|
||||
leave:
|
||||
#endif /* GNUPG_MAJOR_VERSION > 1 */
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
/* Handle the LEARN command for OpenPGP. */
|
||||
static gpg_error_t
|
||||
do_learn_status (app_t app, ctrl_t ctrl)
|
||||
{
|
||||
do_getattr (app, ctrl, "EXTCAP");
|
||||
@ -760,16 +1192,57 @@ do_learn_status (app_t app, ctrl_t ctrl)
|
||||
if (app->did_chv3)
|
||||
do_getattr (app, ctrl, "PRIVATE-DO-4");
|
||||
}
|
||||
|
||||
send_keypair_info (app, ctrl, 1);
|
||||
send_keypair_info (app, ctrl, 2);
|
||||
send_keypair_info (app, ctrl, 3);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Handle the READKEY command for OpenPGP. On success a canonical
|
||||
encoded S-expression with the public key will get stored at PK and
|
||||
its length (for assertions) at PKLEN; the caller must release that
|
||||
buffer. On error PK and PKLEN are not changed and an error code is
|
||||
returned. */
|
||||
static gpg_error_t
|
||||
do_readkey (app_t app, const char *keyid, unsigned char **pk, size_t *pklen)
|
||||
{
|
||||
#if GNUPG_MAJOR_VERSION > 1
|
||||
gpg_error_t err;
|
||||
int keyno;
|
||||
unsigned char *buf;
|
||||
|
||||
if (!strcmp (keyid, "OPENPGP.1"))
|
||||
keyno = 1;
|
||||
else if (!strcmp (keyid, "OPENPGP.2"))
|
||||
keyno = 2;
|
||||
else if (!strcmp (keyid, "OPENPGP.3"))
|
||||
keyno = 3;
|
||||
else
|
||||
return gpg_error (GPG_ERR_INV_ID);
|
||||
|
||||
err = get_public_key (app, keyno);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
buf = app->app_local->pk[keyno-1].key;
|
||||
if (!buf)
|
||||
return gpg_error (GPG_ERR_NO_PUBKEY);
|
||||
*pk = buf;
|
||||
*pklen = app->app_local->pk[keyno-1].keylen;;
|
||||
return 0;
|
||||
#else
|
||||
return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Verify CHV2 if required. Depending on the configuration of the
|
||||
card CHV1 will also be verified. */
|
||||
static int
|
||||
static gpg_error_t
|
||||
verify_chv2 (app_t app,
|
||||
int (*pincb)(void*, const char *, char **),
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg)
|
||||
{
|
||||
int rc = 0;
|
||||
@ -823,9 +1296,9 @@ verify_chv2 (app_t app,
|
||||
}
|
||||
|
||||
/* Verify CHV3 if required. */
|
||||
static int
|
||||
static gpg_error_t
|
||||
verify_chv3 (app_t app,
|
||||
int (*pincb)(void*, const char *, char **),
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg)
|
||||
{
|
||||
int rc = 0;
|
||||
@ -845,7 +1318,7 @@ verify_chv3 (app_t app,
|
||||
unsigned char *value;
|
||||
size_t valuelen;
|
||||
|
||||
relptr = get_one_do (app, 0x00C4, &value, &valuelen);
|
||||
relptr = get_one_do (app, 0x00C4, &value, &valuelen, NULL);
|
||||
if (!relptr || valuelen < 7)
|
||||
{
|
||||
log_error (_("error retrieving CHV status from card\n"));
|
||||
@ -897,9 +1370,9 @@ verify_chv3 (app_t app,
|
||||
|
||||
/* Handle the SETATTR operation. All arguments are already basically
|
||||
checked. */
|
||||
static int
|
||||
static gpg_error_t
|
||||
do_setattr (app_t app, const char *name,
|
||||
int (*pincb)(void*, const char *, char **),
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg,
|
||||
const unsigned char *value, size_t valuelen)
|
||||
{
|
||||
@ -965,9 +1438,9 @@ do_setattr (app_t app, const char *name,
|
||||
|
||||
|
||||
/* Handle the PASSWD command. */
|
||||
static int
|
||||
static gpg_error_t
|
||||
do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr, int reset_mode,
|
||||
int (*pincb)(void*, const char *, char **),
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg)
|
||||
{
|
||||
int rc = 0;
|
||||
@ -1056,9 +1529,9 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr, int reset_mode,
|
||||
|
||||
|
||||
/* Handle the GENKEY command. */
|
||||
static int
|
||||
static gpg_error_t
|
||||
do_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags,
|
||||
int (*pincb)(void*, const char *, char **),
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg)
|
||||
{
|
||||
int rc;
|
||||
@ -1082,6 +1555,13 @@ do_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags,
|
||||
generation. This _might_ help a card to gather more entropy. */
|
||||
flush_cache (app);
|
||||
|
||||
/* Obviously we need to remove the cached public key. */
|
||||
xfree (app->app_local->pk[keyno].key);
|
||||
app->app_local->pk[keyno].key = NULL;
|
||||
app->app_local->pk[keyno].keylen = 0;
|
||||
app->app_local->pk[keyno].read_done = 0;
|
||||
|
||||
/* Check whether a key already exists. */
|
||||
rc = iso7816_get_data (app->slot, 0x006E, &buffer, &buflen);
|
||||
if (rc)
|
||||
{
|
||||
@ -1109,11 +1589,12 @@ do_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags,
|
||||
else
|
||||
log_info (_("generating new key\n"));
|
||||
|
||||
|
||||
|
||||
/* Prepare for key generation by verifying the ADmin PIN. */
|
||||
rc = verify_chv3 (app, pincb, pincb_arg);
|
||||
if (rc)
|
||||
goto leave;
|
||||
|
||||
|
||||
xfree (buffer); buffer = NULL;
|
||||
|
||||
#if 1
|
||||
@ -1206,7 +1687,7 @@ get_sig_counter (app_t app)
|
||||
size_t valuelen;
|
||||
unsigned long ul;
|
||||
|
||||
relptr = get_one_do (app, 0x0093, &value, &valuelen);
|
||||
relptr = get_one_do (app, 0x0093, &value, &valuelen, NULL);
|
||||
if (!relptr)
|
||||
return 0;
|
||||
ul = convert_sig_counter_value (value, valuelen);
|
||||
@ -1214,7 +1695,7 @@ get_sig_counter (app_t app)
|
||||
return ul;
|
||||
}
|
||||
|
||||
static int
|
||||
static gpg_error_t
|
||||
compare_fingerprint (app_t app, int keyno, unsigned char *sha1fpr)
|
||||
{
|
||||
const unsigned char *fpr;
|
||||
@ -1254,7 +1735,7 @@ compare_fingerprint (app_t app, int keyno, unsigned char *sha1fpr)
|
||||
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
|
||||
static gpg_error_t
|
||||
check_against_given_fingerprint (app_t app, const char *fpr, int keyno)
|
||||
{
|
||||
unsigned char tmp[20];
|
||||
@ -1285,9 +1766,9 @@ check_against_given_fingerprint (app_t app, const char *fpr, int keyno)
|
||||
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
|
||||
static gpg_error_t
|
||||
do_sign (app_t app, const char *keyidstr, int hashalgo,
|
||||
int (*pincb)(void*, const char *, char **),
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg,
|
||||
const void *indata, size_t indatalen,
|
||||
unsigned char **outdata, size_t *outdatalen )
|
||||
@ -1308,7 +1789,15 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
|
||||
|
||||
if (!keyidstr || !*keyidstr)
|
||||
return gpg_error (GPG_ERR_INV_VALUE);
|
||||
if (indatalen != 20)
|
||||
if (indatalen == 20)
|
||||
;
|
||||
else if (indatalen == (15 + 20) && hashalgo == GCRY_MD_SHA1
|
||||
&& !memcmp (indata, sha1_prefix, 15))
|
||||
;
|
||||
else if (indatalen == (15 + 20) && hashalgo == GCRY_MD_RMD160
|
||||
&& !memcmp (indata, rmd160_prefix, 15))
|
||||
;
|
||||
else
|
||||
return gpg_error (GPG_ERR_INV_VALUE);
|
||||
|
||||
/* Check whether an OpenPGP card of any version has been requested. */
|
||||
@ -1419,15 +1908,16 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
|
||||
/* 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.
|
||||
fingerprint delimited by a slash. Optionally the id OPENPGP.3 may
|
||||
be given.
|
||||
|
||||
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
|
||||
static gpg_error_t
|
||||
do_auth (app_t app, const char *keyidstr,
|
||||
int (*pincb)(void*, const char *, char **),
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg,
|
||||
const void *indata, size_t indatalen,
|
||||
unsigned char **outdata, size_t *outdatalen )
|
||||
@ -1444,27 +1934,31 @@ do_auth (app_t app, const char *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 (!strcmp (keyidstr, "OPENPGP.3"))
|
||||
;
|
||||
if (n != 32)
|
||||
else if (strlen (keyidstr) < 32 || strncmp (keyidstr, "D27600012401", 12))
|
||||
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; 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);
|
||||
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
|
||||
@ -1484,9 +1978,9 @@ do_auth (app_t app, const char *keyidstr,
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
static gpg_error_t
|
||||
do_decipher (app_t app, const char *keyidstr,
|
||||
int (pincb)(void*, const char *, char **),
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg,
|
||||
const void *indata, size_t indatalen,
|
||||
unsigned char **outdata, size_t *outdatalen )
|
||||
@ -1545,15 +2039,14 @@ do_decipher (app_t app, const char *keyidstr,
|
||||
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.
|
||||
optional fingerprint part will be ignored.
|
||||
|
||||
There is a special mode if the keyidstr is "<serialno>[CHV3]" with
|
||||
the "[CHV3]" being a literal string: The Admin Pin is checked if
|
||||
and only if the retry counter is still at 3.
|
||||
*/
|
||||
static int
|
||||
and only if the retry counter is still at 3. */
|
||||
static gpg_error_t
|
||||
do_check_pin (app_t app, const char *keyidstr,
|
||||
int (pincb)(void*, const char *, char **),
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg)
|
||||
{
|
||||
unsigned char tmp_sn[20];
|
||||
@ -1588,6 +2081,7 @@ do_check_pin (app_t app, const char *keyidstr,
|
||||
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
|
||||
@ -1600,7 +2094,7 @@ do_check_pin (app_t app, const char *keyidstr,
|
||||
size_t valuelen;
|
||||
int count;
|
||||
|
||||
relptr = get_one_do (app, 0x00C4, &value, &valuelen);
|
||||
relptr = get_one_do (app, 0x00C4, &value, &valuelen, NULL);
|
||||
if (!relptr || valuelen < 7)
|
||||
{
|
||||
log_error (_("error retrieving CHV status from card\n"));
|
||||
@ -1634,7 +2128,7 @@ do_check_pin (app_t app, const char *keyidstr,
|
||||
|
||||
/* Select the OpenPGP application on the card in SLOT. This function
|
||||
must be used before any other OpenPGP application functions. */
|
||||
int
|
||||
gpg_error_t
|
||||
app_select_openpgp (app_t app)
|
||||
{
|
||||
static char const aid[] = { 0xD2, 0x76, 0x00, 0x01, 0x24, 0x01 };
|
||||
@ -1685,7 +2179,7 @@ app_select_openpgp (app_t app)
|
||||
goto leave;
|
||||
}
|
||||
|
||||
relptr = get_one_do (app, 0x00C4, &buffer, &buflen);
|
||||
relptr = get_one_do (app, 0x00C4, &buffer, &buflen, NULL);
|
||||
if (!relptr)
|
||||
{
|
||||
log_error (_("can't access %s - invalid OpenPGP card?\n"),
|
||||
@ -1695,7 +2189,7 @@ app_select_openpgp (app_t app)
|
||||
app->force_chv1 = (buflen && *buffer == 0);
|
||||
xfree (relptr);
|
||||
|
||||
relptr = get_one_do (app, 0x00C0, &buffer, &buflen);
|
||||
relptr = get_one_do (app, 0x00C0, &buffer, &buflen, NULL);
|
||||
if (!relptr)
|
||||
{
|
||||
log_error (_("can't access %s - invalid OpenPGP card?\n"),
|
||||
@ -1723,7 +2217,7 @@ app_select_openpgp (app_t app)
|
||||
|
||||
app->fnc.deinit = do_deinit;
|
||||
app->fnc.learn_status = do_learn_status;
|
||||
app->fnc.readcert = NULL;
|
||||
app->fnc.readkey = do_readkey;
|
||||
app->fnc.getattr = do_getattr;
|
||||
app->fnc.setattr = do_setattr;
|
||||
app->fnc.genkey = do_genkey;
|
||||
@ -1747,7 +2241,7 @@ leave:
|
||||
LEARN command returns. All parameters return allocated strings or
|
||||
buffers or NULL if the data object is not available. All returned
|
||||
values are sanitized. */
|
||||
int
|
||||
gpg_error_t
|
||||
app_openpgp_cardinfo (app_t app,
|
||||
char **serialno,
|
||||
char **disp_name,
|
||||
@ -1778,7 +2272,7 @@ app_openpgp_cardinfo (app_t app,
|
||||
if (disp_name)
|
||||
{
|
||||
*disp_name = NULL;
|
||||
relptr = get_one_do (app, 0x005B, &value, &valuelen);
|
||||
relptr = get_one_do (app, 0x005B, &value, &valuelen, NULL);
|
||||
if (relptr)
|
||||
{
|
||||
*disp_name = make_printable_string (value, valuelen, 0);
|
||||
@ -1789,7 +2283,7 @@ app_openpgp_cardinfo (app_t app,
|
||||
if (pubkey_url)
|
||||
{
|
||||
*pubkey_url = NULL;
|
||||
relptr = get_one_do (app, 0x5F50, &value, &valuelen);
|
||||
relptr = get_one_do (app, 0x5F50, &value, &valuelen, NULL);
|
||||
if (relptr)
|
||||
{
|
||||
*pubkey_url = make_printable_string (value, valuelen, 0);
|
||||
@ -1803,7 +2297,7 @@ app_openpgp_cardinfo (app_t app,
|
||||
*fpr2 = NULL;
|
||||
if (fpr3)
|
||||
*fpr3 = NULL;
|
||||
relptr = get_one_do (app, 0x00C5, &value, &valuelen);
|
||||
relptr = get_one_do (app, 0x00C5, &value, &valuelen, NULL);
|
||||
if (relptr && valuelen >= 60)
|
||||
{
|
||||
if (fpr1)
|
||||
@ -1837,13 +2331,13 @@ app_openpgp_cardinfo (app_t app,
|
||||
create the fingerprint. M, MLEN is the RSA modulus and E, ELEN the
|
||||
RSA public exponent. This function silently overwrites an existing
|
||||
key.*/
|
||||
int
|
||||
gpg_error_t
|
||||
app_openpgp_storekey (app_t app, int keyno,
|
||||
unsigned char *template, size_t template_len,
|
||||
time_t created_at,
|
||||
const unsigned char *m, size_t mlen,
|
||||
const unsigned char *e, size_t elen,
|
||||
int (*pincb)(void*, const char *, char **),
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg)
|
||||
{
|
||||
int rc;
|
||||
@ -1859,6 +2353,11 @@ app_openpgp_storekey (app_t app, int keyno,
|
||||
|
||||
flush_cache (app);
|
||||
|
||||
xfree (app->app_local->pk[keyno].key);
|
||||
app->app_local->pk[keyno].key = NULL;
|
||||
app->app_local->pk[keyno].keylen = 0;
|
||||
app->app_local->pk[keyno].read_done = 0;
|
||||
|
||||
rc = iso7816_put_data (app->slot,
|
||||
(app->card_version > 0x0007? 0xE0 : 0xE9) + keyno,
|
||||
template, template_len);
|
||||
@ -1882,7 +2381,7 @@ app_openpgp_storekey (app_t app, int keyno,
|
||||
|
||||
/* Utility function for external tools: Read the public RSA key at
|
||||
KEYNO and return modulus and exponent in (M,MLEN) and (E,ELEN). */
|
||||
int
|
||||
gpg_error_t
|
||||
app_openpgp_readkey (app_t app, int keyno, unsigned char **m, size_t *mlen,
|
||||
unsigned char **e, size_t *elen)
|
||||
{
|
||||
|
418
g10/cardglue.c
418
g10/cardglue.c
@ -43,9 +43,16 @@
|
||||
#include "apdu.h"
|
||||
#include "app-common.h"
|
||||
|
||||
/* If we build w/o agent support, assuan.h won't be included and thus
|
||||
we need to define a repalcement for the assuan error type. */
|
||||
#ifndef ENABLE_AGENT_SUPPORT
|
||||
typedef int assuan_error_t;
|
||||
#endif
|
||||
|
||||
|
||||
struct ctrl_ctx_s
|
||||
{
|
||||
int (*status_cb)(void *opaque, const char *line);
|
||||
assuan_error_t (*status_cb)(void *opaque, const char *line);
|
||||
void *status_cb_arg;
|
||||
};
|
||||
|
||||
@ -57,10 +64,14 @@ struct pincb_parm_s
|
||||
|
||||
|
||||
static char *default_reader_port;
|
||||
static APP current_app;
|
||||
static app_t current_app;
|
||||
|
||||
|
||||
/* Local prototypes. */
|
||||
static assuan_error_t learn_status_cb (void *opaque, const char *line);
|
||||
|
||||
|
||||
|
||||
/* Create a serialno/fpr string from the serial number and the secret
|
||||
key. caller must free the returned string. There is no error
|
||||
return. [Taken from 1.9's keyid.c]*/
|
||||
@ -135,8 +146,12 @@ send_status_info (CTRL ctrl, const char *keyword, ...)
|
||||
}
|
||||
|
||||
|
||||
void gcry_md_hash_buffer (int algo, void *digest,
|
||||
const void *buffer, size_t length)
|
||||
/* Replacement function of the Libgcrypt onewhich is used in gnupg
|
||||
1.9. Thus function computes the digest of ALGO from the data in
|
||||
BUFFER of LENGTH. ALGO must be supported. */
|
||||
void
|
||||
gcry_md_hash_buffer (int algo, void *digest,
|
||||
const void *buffer, size_t length)
|
||||
{
|
||||
MD_HANDLE h = md_open (algo, 0);
|
||||
if (!h)
|
||||
@ -204,7 +219,7 @@ card_set_reader_port (const char *portstr)
|
||||
no update time is available the returned value is 0. Caller must
|
||||
free SERIAL unless the function returns an error. */
|
||||
int
|
||||
app_get_serial_and_stamp (APP app, char **serial, time_t *stamp)
|
||||
app_get_serial_and_stamp (app_t app, char **serial, time_t *stamp)
|
||||
{
|
||||
unsigned char *buf, *p;
|
||||
int i;
|
||||
@ -254,19 +269,91 @@ agent_release_card_info (struct agent_card_info_s *info)
|
||||
}
|
||||
|
||||
|
||||
/* Print an error message for a failed assuan-Transact and return a
|
||||
gpg error code. No error is printed if RC is 0. */
|
||||
static gpg_error_t
|
||||
test_transact (int rc, const char *command)
|
||||
{
|
||||
if (!rc)
|
||||
return 0;
|
||||
log_error ("sending command `%s' to agent failed: %s\n",
|
||||
command, assuan_strerror (rc));
|
||||
return gpg_error (GPG_ERR_CARD);
|
||||
}
|
||||
|
||||
|
||||
/* Try to open a card using an already running agent. Prepare a
|
||||
proper application context and return it. */
|
||||
static app_t
|
||||
open_card_via_agent (int *scd_available)
|
||||
{
|
||||
assuan_context_t ctx;
|
||||
app_t app;
|
||||
struct agent_card_info_s info;
|
||||
int rc;
|
||||
|
||||
*scd_available = 0;
|
||||
ctx = agent_open (1);
|
||||
if (!ctx)
|
||||
return NULL;
|
||||
|
||||
/* Request the serialbnumber of the card. If we get
|
||||
NOT_SUPPORTED or NO_SCDAEMON back, the gpg-agent either has
|
||||
disabled scdaemon or it can't be used. We close the connection
|
||||
in this case and use our own code. This may happen if just the
|
||||
gpg-agent has been installed for the sake of passphrase
|
||||
caching. */
|
||||
memset (&info, 0, sizeof info);
|
||||
rc = assuan_transact (ctx, "SCD SERIALNO openpgp",
|
||||
NULL, NULL, NULL, NULL,
|
||||
learn_status_cb, &info);
|
||||
if (rc)
|
||||
{
|
||||
if ((rc & 0xffff) == 60 || (rc & 0xffff) == 119)
|
||||
; /* No scdaemon available to gpg-agent. */
|
||||
else
|
||||
{
|
||||
write_status_text (STATUS_CARDCTRL, "4");
|
||||
log_info ("selecting openpgp failed: %s\n", assuan_strerror (rc));
|
||||
*scd_available = 1;
|
||||
}
|
||||
agent_release_card_info (&info);
|
||||
agent_close (ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
app = xcalloc (1, sizeof *app);
|
||||
app->assuan_ctx = ctx;
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Open the current card and select the openpgp application. Return
|
||||
an APP context handle to be used for further procesing or NULL on
|
||||
error or if no OpenPGP application exists.*/
|
||||
static APP
|
||||
static app_t
|
||||
open_card (void)
|
||||
{
|
||||
int slot = -1;
|
||||
int rc;
|
||||
APP app;
|
||||
app_t app;
|
||||
int did_shutdown = 0;
|
||||
int scd_available;
|
||||
|
||||
/* First check whether we can contact a gpg-agent and divert all
|
||||
operation to it. This is required because gpg as well as the
|
||||
agent require exclusive access to the reader. */
|
||||
app = open_card_via_agent (&scd_available);
|
||||
if (app)
|
||||
goto ready; /* Yes, there is a agent with a usable card, go that way. */
|
||||
if (scd_available)
|
||||
return NULL; /* agent avilabale but card problem. */
|
||||
|
||||
|
||||
/* No agent or usable agent, thus we do it on our own. */
|
||||
card_close ();
|
||||
|
||||
|
||||
retry:
|
||||
if (did_shutdown)
|
||||
@ -309,6 +396,7 @@ open_card (void)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ready:
|
||||
app->initialized = 1;
|
||||
current_app = app;
|
||||
if (is_status_enabled () )
|
||||
@ -327,15 +415,19 @@ open_card (void)
|
||||
return app;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
card_close (void)
|
||||
{
|
||||
if (current_app)
|
||||
{
|
||||
APP app = current_app;
|
||||
app_t app = current_app;
|
||||
current_app = NULL;
|
||||
|
||||
apdu_close_reader (app->slot);
|
||||
if (app->assuan_ctx)
|
||||
agent_close (app->assuan_ctx);
|
||||
else
|
||||
apdu_close_reader (app->slot);
|
||||
xfree (app);
|
||||
}
|
||||
}
|
||||
@ -382,7 +474,7 @@ format_cacheid (const char *sn)
|
||||
card context will be closed in all cases except for 0 as return
|
||||
value and if it was possible to merely shutdown the reader. */
|
||||
static int
|
||||
check_card_serialno (APP app, const char *serialno)
|
||||
check_card_serialno (app_t app, const char *serialno)
|
||||
{
|
||||
const char *s;
|
||||
int ask = 0;
|
||||
@ -505,7 +597,7 @@ store_serialno (const char *line)
|
||||
|
||||
|
||||
|
||||
static int
|
||||
static assuan_error_t
|
||||
learn_status_cb (void *opaque, const char *line)
|
||||
{
|
||||
struct agent_card_info_s *parm = opaque;
|
||||
@ -644,7 +736,7 @@ learn_status_cb (void *opaque, const char *line)
|
||||
int
|
||||
agent_learn (struct agent_card_info_s *info)
|
||||
{
|
||||
APP app;
|
||||
app_t app;
|
||||
int rc;
|
||||
struct ctrl_ctx_s ctrl;
|
||||
time_t stamp;
|
||||
@ -655,35 +747,68 @@ agent_learn (struct agent_card_info_s *info)
|
||||
return gpg_error (GPG_ERR_CARD);
|
||||
|
||||
memset (info, 0, sizeof *info);
|
||||
memset (&ctrl, 0, sizeof ctrl);
|
||||
ctrl.status_cb = learn_status_cb;
|
||||
ctrl.status_cb_arg = info;
|
||||
|
||||
rc = app_get_serial_and_stamp (app, &serial, &stamp);
|
||||
if (!rc)
|
||||
if (app->assuan_ctx)
|
||||
{
|
||||
send_status_info (&ctrl, "SERIALNO", serial, strlen(serial), NULL, 0);
|
||||
xfree (serial);
|
||||
rc = app->fnc.learn_status (app, &ctrl);
|
||||
rc = assuan_transact (app->assuan_ctx, "SCD LEARN --force",
|
||||
NULL, NULL, NULL, NULL,
|
||||
learn_status_cb, info);
|
||||
rc = test_transact (rc, "SCD LEARN");
|
||||
}
|
||||
else
|
||||
{
|
||||
memset (&ctrl, 0, sizeof ctrl);
|
||||
ctrl.status_cb = learn_status_cb;
|
||||
ctrl.status_cb_arg = info;
|
||||
|
||||
rc = app_get_serial_and_stamp (app, &serial, &stamp);
|
||||
if (!rc)
|
||||
{
|
||||
send_status_info (&ctrl, "SERIALNO",
|
||||
serial, strlen(serial), NULL, 0);
|
||||
xfree (serial);
|
||||
rc = app->fnc.learn_status (app, &ctrl);
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Get an attribite from the card. Make sure info is initialized. */
|
||||
|
||||
/* Get an attribute from the card. Make sure info is initialized. */
|
||||
int
|
||||
agent_scd_getattr (const char *name, struct agent_card_info_s *info)
|
||||
{
|
||||
APP app;
|
||||
int rc;
|
||||
app_t app;
|
||||
struct ctrl_ctx_s ctrl;
|
||||
|
||||
app = current_app? current_app : open_card ();
|
||||
if (!app)
|
||||
return gpg_error (GPG_ERR_CARD);
|
||||
|
||||
ctrl.status_cb = learn_status_cb;
|
||||
ctrl.status_cb_arg = info;
|
||||
return app->fnc.getattr (app, &ctrl, name);
|
||||
if (app->assuan_ctx)
|
||||
{
|
||||
char line[ASSUAN_LINELENGTH];
|
||||
|
||||
/* We assume that NAME does not need escaping. */
|
||||
if (12 + strlen (name) > DIM(line)-1)
|
||||
return gpg_error (GPG_ERR_CARD);
|
||||
stpcpy (stpcpy (line, "SCD GETATTR "), name);
|
||||
|
||||
rc = test_transact (assuan_transact (app->assuan_ctx, line,
|
||||
NULL, NULL, NULL, NULL,
|
||||
learn_status_cb, info),
|
||||
"SCD GETATTR");
|
||||
}
|
||||
else
|
||||
{
|
||||
ctrl.status_cb = learn_status_cb;
|
||||
ctrl.status_cb_arg = info;
|
||||
rc = app->fnc.getattr (app, &ctrl, name);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
@ -797,14 +922,47 @@ int
|
||||
agent_scd_setattr (const char *name,
|
||||
const unsigned char *value, size_t valuelen)
|
||||
{
|
||||
APP app;
|
||||
app_t app;
|
||||
int rc;
|
||||
|
||||
app = current_app? current_app : open_card ();
|
||||
if (!app)
|
||||
return gpg_error (GPG_ERR_CARD);
|
||||
|
||||
rc = app->fnc.setattr (app, name, pin_cb, NULL, value, valuelen);
|
||||
if (app->assuan_ctx)
|
||||
{
|
||||
char line[ASSUAN_LINELENGTH];
|
||||
char *p;
|
||||
|
||||
/* We assume that NAME does not need escaping. */
|
||||
if (12 + strlen (name) > DIM(line)-1)
|
||||
return gpg_error (GPG_ERR_CARD);
|
||||
p = stpcpy (stpcpy (line, "SCD SETATTR "), name);
|
||||
*p++ = ' ';
|
||||
for (; valuelen; value++, valuelen--)
|
||||
{
|
||||
if (p >= line + DIM(line)-5 )
|
||||
return gpg_error (GPG_ERR_CARD);
|
||||
if (*value < ' ' || *value == '+' || *value == '%')
|
||||
{
|
||||
sprintf (p, "%%%02X", *value);
|
||||
p += 3;
|
||||
}
|
||||
else if (*value == ' ')
|
||||
*p++ = '+';
|
||||
else
|
||||
*p++ = *value;
|
||||
}
|
||||
*p = 0;
|
||||
|
||||
rc = test_transact (assuan_transact (app->assuan_ctx, line,
|
||||
NULL, NULL, NULL, NULL, NULL, NULL),
|
||||
"SCD SETATTR");
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = app->fnc.setattr (app, name, pin_cb, NULL, value, valuelen);
|
||||
}
|
||||
|
||||
if (rc)
|
||||
write_status (STATUS_SC_OP_FAILURE);
|
||||
@ -812,7 +970,7 @@ agent_scd_setattr (const char *name,
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
static assuan_error_t
|
||||
genkey_status_cb (void *opaque, const char *line)
|
||||
{
|
||||
struct agent_card_genkey_s *parm = opaque;
|
||||
@ -868,8 +1026,8 @@ genkey_status_cb (void *opaque, const char *line)
|
||||
int
|
||||
agent_scd_genkey (struct agent_card_genkey_s *info, int keyno, int force)
|
||||
{
|
||||
APP app;
|
||||
char keynostr[20];
|
||||
app_t app;
|
||||
char line[ASSUAN_LINELENGTH];
|
||||
struct ctrl_ctx_s ctrl;
|
||||
int rc;
|
||||
|
||||
@ -878,18 +1036,44 @@ agent_scd_genkey (struct agent_card_genkey_s *info, int keyno, int force)
|
||||
return gpg_error (GPG_ERR_CARD);
|
||||
|
||||
memset (info, 0, sizeof *info);
|
||||
sprintf (keynostr, "%d", keyno);
|
||||
ctrl.status_cb = genkey_status_cb;
|
||||
ctrl.status_cb_arg = info;
|
||||
|
||||
rc = app->fnc.genkey (app, &ctrl, keynostr,
|
||||
force? 1:0,
|
||||
pin_cb, NULL);
|
||||
if (app->assuan_ctx)
|
||||
{
|
||||
snprintf (line, DIM(line)-1, "SCD GENKEY %s%d",
|
||||
force? "--force ":"", keyno);
|
||||
line[DIM(line)-1] = 0;
|
||||
rc = test_transact (assuan_transact (app->assuan_ctx, line,
|
||||
NULL, NULL, NULL, NULL,
|
||||
genkey_status_cb, info),
|
||||
"SCD GENKEY");
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf (line, DIM(line)-1, "%d", keyno);
|
||||
ctrl.status_cb = genkey_status_cb;
|
||||
ctrl.status_cb_arg = info;
|
||||
rc = app->fnc.genkey (app, &ctrl, line,
|
||||
force? 1:0,
|
||||
pin_cb, NULL);
|
||||
}
|
||||
|
||||
if (rc)
|
||||
write_status (STATUS_SC_OP_FAILURE);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static assuan_error_t
|
||||
membuf_data_cb (void *opaque, const void *buffer, size_t length)
|
||||
{
|
||||
membuf_t *data = opaque;
|
||||
|
||||
if (buffer)
|
||||
put_membuf (data, buffer, length);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Send a PKSIGN command to the SCdaemon. */
|
||||
int
|
||||
agent_scd_pksign (const char *serialno, int hashalgo,
|
||||
@ -897,7 +1081,7 @@ agent_scd_pksign (const char *serialno, int hashalgo,
|
||||
unsigned char **r_buf, size_t *r_buflen)
|
||||
{
|
||||
struct pincb_parm_s parm;
|
||||
APP app;
|
||||
app_t app;
|
||||
int rc;
|
||||
|
||||
*r_buf = NULL;
|
||||
@ -909,20 +1093,56 @@ agent_scd_pksign (const char *serialno, int hashalgo,
|
||||
if (!app)
|
||||
return gpg_error (GPG_ERR_CARD);
|
||||
|
||||
/* Check that the card's serialnumber is as required.*/
|
||||
rc = check_card_serialno (app, serialno);
|
||||
if (rc == -1)
|
||||
goto retry;
|
||||
if (app->assuan_ctx)
|
||||
{
|
||||
char *p, line[ASSUAN_LINELENGTH];
|
||||
membuf_t data;
|
||||
size_t len;
|
||||
int i;
|
||||
|
||||
if (indatalen*2 + 50 > DIM(line))
|
||||
return gpg_error (GPG_ERR_GENERAL);
|
||||
|
||||
p = stpcpy (line, "SCD SETDATA ");
|
||||
for (i=0; i < indatalen ; i++, p += 2 )
|
||||
sprintf (p, "%02X", indata[i]);
|
||||
rc = test_transact (assuan_transact (app->assuan_ctx, line,
|
||||
NULL, NULL, NULL, NULL, NULL, NULL),
|
||||
"SCD SETDATA");
|
||||
if (!rc)
|
||||
{
|
||||
init_membuf (&data, 1024);
|
||||
snprintf (line, DIM(line)-1, "SCD PKSIGN %s", serialno);
|
||||
line[DIM(line)-1] = 0;
|
||||
rc = test_transact (assuan_transact (app->assuan_ctx, line,
|
||||
membuf_data_cb, &data,
|
||||
NULL, NULL, NULL, NULL),
|
||||
"SCD PKSIGN");
|
||||
if (rc)
|
||||
xfree (get_membuf (&data, &len));
|
||||
else
|
||||
*r_buf = get_membuf (&data, r_buflen);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Check that the card's serialnumber is as required.*/
|
||||
rc = check_card_serialno (app, serialno);
|
||||
if (rc == -1)
|
||||
goto retry;
|
||||
|
||||
if (!rc)
|
||||
rc = app->fnc.sign (app, serialno, hashalgo,
|
||||
pin_cb, &parm,
|
||||
indata, indatalen,
|
||||
r_buf, r_buflen);
|
||||
}
|
||||
|
||||
if (!rc)
|
||||
rc = app->fnc.sign (app, serialno, hashalgo,
|
||||
pin_cb, &parm,
|
||||
indata, indatalen,
|
||||
r_buf, r_buflen);
|
||||
if (rc)
|
||||
{
|
||||
write_status (STATUS_SC_OP_FAILURE);
|
||||
agent_clear_pin_cache (serialno);
|
||||
if (!app->assuan_ctx)
|
||||
agent_clear_pin_cache (serialno);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@ -935,7 +1155,7 @@ agent_scd_pkdecrypt (const char *serialno,
|
||||
unsigned char **r_buf, size_t *r_buflen)
|
||||
{
|
||||
struct pincb_parm_s parm;
|
||||
APP app;
|
||||
app_t app;
|
||||
int rc;
|
||||
|
||||
*r_buf = NULL;
|
||||
@ -947,20 +1167,56 @@ agent_scd_pkdecrypt (const char *serialno,
|
||||
if (!app)
|
||||
return gpg_error (GPG_ERR_CARD);
|
||||
|
||||
/* Check that the card's serialnumber is as required.*/
|
||||
rc = check_card_serialno (app, serialno);
|
||||
if (rc == -1)
|
||||
goto retry;
|
||||
if (app->assuan_ctx)
|
||||
{
|
||||
char *p, line[ASSUAN_LINELENGTH];
|
||||
membuf_t data;
|
||||
size_t len;
|
||||
int i;
|
||||
|
||||
if (indatalen*2 + 50 > DIM(line))
|
||||
return gpg_error (GPG_ERR_GENERAL);
|
||||
|
||||
p = stpcpy (line, "SCD SETDATA ");
|
||||
for (i=0; i < indatalen ; i++, p += 2 )
|
||||
sprintf (p, "%02X", indata[i]);
|
||||
rc = test_transact (assuan_transact (app->assuan_ctx, line,
|
||||
NULL, NULL, NULL, NULL, NULL, NULL),
|
||||
"SCD SETDATA");
|
||||
if (!rc)
|
||||
{
|
||||
init_membuf (&data, 1024);
|
||||
snprintf (line, DIM(line)-1, "SCD PKDECRYPT %s", serialno);
|
||||
line[DIM(line)-1] = 0;
|
||||
rc = test_transact (assuan_transact (app->assuan_ctx, line,
|
||||
membuf_data_cb, &data,
|
||||
NULL, NULL, NULL, NULL),
|
||||
"SCD PKDECRYPT");
|
||||
if (rc)
|
||||
xfree (get_membuf (&data, &len));
|
||||
else
|
||||
*r_buf = get_membuf (&data, r_buflen);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Check that the card's serialnumber is as required.*/
|
||||
rc = check_card_serialno (app, serialno);
|
||||
if (rc == -1)
|
||||
goto retry;
|
||||
|
||||
if (!rc)
|
||||
rc = app->fnc.decipher (app, serialno,
|
||||
pin_cb, &parm,
|
||||
indata, indatalen,
|
||||
r_buf, r_buflen);
|
||||
}
|
||||
|
||||
if (!rc)
|
||||
rc = app->fnc.decipher (app, serialno,
|
||||
pin_cb, &parm,
|
||||
indata, indatalen,
|
||||
r_buf, r_buflen);
|
||||
if (rc)
|
||||
{
|
||||
write_status (STATUS_SC_OP_FAILURE);
|
||||
agent_clear_pin_cache (serialno);
|
||||
if (!app->assuan_ctx)
|
||||
agent_clear_pin_cache (serialno);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@ -969,7 +1225,7 @@ agent_scd_pkdecrypt (const char *serialno,
|
||||
int
|
||||
agent_scd_change_pin (int chvno)
|
||||
{
|
||||
APP app;
|
||||
app_t app;
|
||||
char chvnostr[20];
|
||||
int reset = 0;
|
||||
int rc;
|
||||
@ -981,9 +1237,17 @@ agent_scd_change_pin (int chvno)
|
||||
if (!app)
|
||||
return gpg_error (GPG_ERR_CARD);
|
||||
|
||||
sprintf (chvnostr, "%d", chvno);
|
||||
rc = app->fnc.change_pin (app, NULL, chvnostr, reset,
|
||||
pin_cb, NULL);
|
||||
if (app->assuan_ctx)
|
||||
{
|
||||
rc = gpg_error (GPG_ERR_CARD);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf (chvnostr, "%d", chvno);
|
||||
rc = app->fnc.change_pin (app, NULL, chvnostr, reset,
|
||||
pin_cb, NULL);
|
||||
}
|
||||
|
||||
if (rc)
|
||||
write_status (STATUS_SC_OP_FAILURE);
|
||||
return rc;
|
||||
@ -995,14 +1259,22 @@ agent_scd_change_pin (int chvno)
|
||||
int
|
||||
agent_scd_checkpin (const char *serialnobuf)
|
||||
{
|
||||
APP app;
|
||||
app_t app;
|
||||
int rc;
|
||||
|
||||
app = current_app? current_app : open_card ();
|
||||
if (!app)
|
||||
return gpg_error (GPG_ERR_CARD);
|
||||
|
||||
rc = app->fnc.check_pin (app, serialnobuf, pin_cb, NULL);
|
||||
if (app->assuan_ctx)
|
||||
{
|
||||
rc = gpg_error (GPG_ERR_CARD);
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = app->fnc.check_pin (app, serialnobuf, pin_cb, NULL);
|
||||
}
|
||||
|
||||
if (rc)
|
||||
write_status (STATUS_SC_OP_FAILURE);
|
||||
return rc;
|
||||
@ -1017,16 +1289,24 @@ agent_openpgp_storekey (int keyno,
|
||||
const unsigned char *m, size_t mlen,
|
||||
const unsigned char *e, size_t elen)
|
||||
{
|
||||
APP app;
|
||||
app_t app;
|
||||
int rc;
|
||||
|
||||
app = current_app? current_app : open_card ();
|
||||
if (!app)
|
||||
return gpg_error (GPG_ERR_CARD);
|
||||
|
||||
rc = app_openpgp_storekey (app, keyno, template, template_len,
|
||||
created_at, m, mlen, e, elen,
|
||||
pin_cb, NULL);
|
||||
if (app->assuan_ctx)
|
||||
{
|
||||
rc = gpg_error (GPG_ERR_CARD);
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = app_openpgp_storekey (app, keyno, template, template_len,
|
||||
created_at, m, mlen, e, elen,
|
||||
pin_cb, NULL);
|
||||
}
|
||||
|
||||
if (rc)
|
||||
write_status (STATUS_SC_OP_FAILURE);
|
||||
return rc;
|
||||
|
@ -1814,7 +1814,7 @@ ccid_transceive (ccid_driver_t handle,
|
||||
msg = send_buffer;
|
||||
tpdulen = last_tpdulen;
|
||||
}
|
||||
else if (sending && !!(tpdu[1] & 0x40) == handle->t1_ns)
|
||||
else if (sending && !!(tpdu[1] & 0x10) == handle->t1_ns)
|
||||
{ /* Reponse does not match our sequence number. */
|
||||
DEBUGOUT ("R-block with wrong seqno received on more bit\n");
|
||||
return CCID_DRIVER_ERR_CARD_IO_ERROR;
|
||||
|
@ -26,6 +26,9 @@
|
||||
#include "global.h"
|
||||
#include "packet.h"
|
||||
#include "cipher.h"
|
||||
#ifdef ENABLE_AGENT_SUPPORT
|
||||
#include "assuan.h"
|
||||
#endif
|
||||
|
||||
/* What qualifies as a certification (rather than a signature?) */
|
||||
#define IS_CERT(s) (IS_KEY_SIG(s) || IS_UID_SIG(s) || IS_SUBKEY_SIG(s) \
|
||||
@ -184,6 +187,10 @@ int build_sk_list( STRLIST locusr, SK_LIST *ret_sk_list,
|
||||
int unlock, unsigned use );
|
||||
|
||||
/*-- passphrase.h --*/
|
||||
#ifdef ENABLE_AGENT_SUPPORT
|
||||
assuan_context_t agent_open (int try);
|
||||
void agent_close (assuan_context_t ctx);
|
||||
#endif
|
||||
int have_static_passphrase(void);
|
||||
void read_passphrase_from_fd( int fd );
|
||||
void passphrase_clear_cache ( u32 *keyid, const char *cacheid, int algo );
|
||||
|
@ -275,6 +275,7 @@ void pause_on_sigusr( int which );
|
||||
void block_all_signals(void);
|
||||
void unblock_all_signals(void);
|
||||
|
||||
|
||||
#ifdef ENABLE_CARD_SUPPORT
|
||||
/*-- card-util.c --*/
|
||||
void change_pin (int no, int allow_admin);
|
||||
|
@ -278,12 +278,13 @@ agent_send_all_options (assuan_context_t ctx)
|
||||
|
||||
/*
|
||||
* Open a connection to the agent and initializes the connection.
|
||||
* Returns: -1 on error; on success a file descriptor for that
|
||||
* connection is returned.
|
||||
* Returns: -1 on error; on success an Assuan context for that
|
||||
* connection is returned. With TRY set to true, no error messages
|
||||
* are printed and the use of the agent won't get disabled on failure.
|
||||
*/
|
||||
#ifdef ENABLE_AGENT_SUPPORT
|
||||
static assuan_context_t
|
||||
agent_open (void)
|
||||
assuan_context_t
|
||||
agent_open (int try)
|
||||
{
|
||||
int rc;
|
||||
assuan_context_t ctx;
|
||||
@ -298,8 +299,11 @@ agent_open (void)
|
||||
infostr = getenv ( "GPG_AGENT_INFO" );
|
||||
if (!infostr || !*infostr)
|
||||
{
|
||||
log_error (_("gpg-agent is not available in this session\n"));
|
||||
opt.use_agent = 0;
|
||||
if (!try)
|
||||
{
|
||||
log_error (_("gpg-agent is not available in this session\n"));
|
||||
opt.use_agent = 0;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
infostr = xstrdup ( infostr );
|
||||
@ -307,9 +311,12 @@ agent_open (void)
|
||||
|
||||
if ( !(p = strchr (infostr, PATHSEP_C)) || p == infostr)
|
||||
{
|
||||
log_error ( _("malformed GPG_AGENT_INFO environment variable\n"));
|
||||
if (!try)
|
||||
{
|
||||
log_error ( _("malformed GPG_AGENT_INFO environment variable\n"));
|
||||
opt.use_agent = 0;
|
||||
}
|
||||
xfree (infostr);
|
||||
opt.use_agent = 0;
|
||||
return NULL;
|
||||
}
|
||||
*p++ = 0;
|
||||
@ -319,28 +326,38 @@ agent_open (void)
|
||||
prot = *p? atoi (p+1) : 0;
|
||||
if (prot != 1)
|
||||
{
|
||||
log_error (_("gpg-agent protocol version %d is not supported\n"), prot);
|
||||
if (!try)
|
||||
{
|
||||
log_error (_("gpg-agent protocol version %d is not supported\n"),
|
||||
prot);
|
||||
opt.use_agent = 0;
|
||||
}
|
||||
xfree (infostr);
|
||||
opt.use_agent = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rc = assuan_socket_connect (&ctx, infostr, pid);
|
||||
if (rc)
|
||||
{
|
||||
log_error ( _("can't connect to `%s': %s\n"),
|
||||
infostr, assuan_strerror (rc));
|
||||
if (!try)
|
||||
{
|
||||
log_error ( _("can't connect to `%s': %s\n"),
|
||||
infostr, assuan_strerror (rc));
|
||||
opt.use_agent = 0;
|
||||
}
|
||||
xfree (infostr );
|
||||
opt.use_agent = 0;
|
||||
return NULL;
|
||||
}
|
||||
xfree (infostr);
|
||||
|
||||
if (agent_send_all_options (ctx))
|
||||
{
|
||||
log_error (_("problem with the agent - disabling agent use\n"));
|
||||
if (!try)
|
||||
{
|
||||
log_error (_("problem with the agent - disabling agent use\n"));
|
||||
opt.use_agent = 0;
|
||||
}
|
||||
assuan_disconnect (ctx);
|
||||
opt.use_agent = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -350,7 +367,7 @@ agent_open (void)
|
||||
|
||||
|
||||
#ifdef ENABLE_AGENT_SUPPORT
|
||||
static void
|
||||
void
|
||||
agent_close (assuan_context_t ctx)
|
||||
{
|
||||
assuan_disconnect (ctx);
|
||||
@ -474,7 +491,7 @@ agent_get_passphrase ( u32 *keyid, int mode, const char *cacheid,
|
||||
}
|
||||
#endif
|
||||
|
||||
if ( !(ctx = agent_open ()) )
|
||||
if ( !(ctx = agent_open (0)) )
|
||||
goto failure;
|
||||
|
||||
if (custom_description)
|
||||
@ -672,7 +689,7 @@ passphrase_clear_cache ( u32 *keyid, const char *cacheid, int algo )
|
||||
else
|
||||
pk = NULL;
|
||||
|
||||
if ( !(ctx = agent_open ()) )
|
||||
if ( !(ctx = agent_open (0)) )
|
||||
goto failure;
|
||||
|
||||
{
|
||||
|
28
g10/tlv.c
28
g10/tlv.c
@ -1,5 +1,5 @@
|
||||
/* tlv.c - Tag-Length-Value Utilities
|
||||
* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
@ -25,9 +25,8 @@
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "errors.h"
|
||||
#include "util.h"
|
||||
#include "packet.h"
|
||||
#include <gpg-error.h>
|
||||
|
||||
#include "tlv.h"
|
||||
|
||||
static const unsigned char *
|
||||
@ -114,17 +113,32 @@ do_find_tlv (const unsigned char *buffer, size_t length,
|
||||
|
||||
/* Locate a TLV encoded data object in BUFFER of LENGTH and
|
||||
return a pointer to value as well as its length in NBYTES. Return
|
||||
NULL if it was not found. Note, that the function does not check
|
||||
whether the value fits into the provided buffer. */
|
||||
NULL if it was not found or if the object does not fit into the buffer. */
|
||||
const unsigned char *
|
||||
find_tlv (const unsigned char *buffer, size_t length,
|
||||
int tag, size_t *nbytes)
|
||||
{
|
||||
return do_find_tlv (buffer, length, tag, nbytes, 0);
|
||||
const unsigned char *p;
|
||||
|
||||
p = do_find_tlv (buffer, length, tag, nbytes, 0);
|
||||
if (p && *nbytes > (length - (p-buffer)))
|
||||
p = NULL; /* Object longer than buffer. */
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Locate a TLV encoded data object in BUFFER of LENGTH and
|
||||
return a pointer to value as well as its length in NBYTES. Return
|
||||
NULL if it was not found. Note, that the function does not check
|
||||
whether the value fits into the provided buffer. */
|
||||
const unsigned char *
|
||||
find_tlv_unchecked (const unsigned char *buffer, size_t length,
|
||||
int tag, size_t *nbytes)
|
||||
{
|
||||
return do_find_tlv (buffer, length, tag, nbytes, 0);
|
||||
}
|
||||
|
||||
|
||||
/* ASN.1 BER parser: Parse BUFFER of length SIZE and return the tag
|
||||
and the length part from the TLV triplet. Update BUFFER and SIZE
|
||||
|
13
g10/tlv.h
13
g10/tlv.h
@ -21,8 +21,6 @@
|
||||
#ifndef SCD_TLV_H
|
||||
#define SCD_TLV_H 1
|
||||
|
||||
#include "types.h"
|
||||
#include "cardglue.h"
|
||||
|
||||
enum tlv_tag_class {
|
||||
CLASS_UNIVERSAL = 0,
|
||||
@ -64,13 +62,20 @@ enum tlv_tag_type {
|
||||
};
|
||||
|
||||
|
||||
/* Locate a TLV encoded data object in BUFFER of LENGTH and return a
|
||||
pointer to value as well as its length in NBYTES. Return NULL if
|
||||
it was not found or if the object does not fit into the buffer. */
|
||||
const unsigned char *find_tlv (const unsigned char *buffer, size_t length,
|
||||
int tag, size_t *nbytes);
|
||||
|
||||
|
||||
/* Locate a TLV encoded data object in BUFFER of LENGTH and return a
|
||||
pointer to value as well as its length in NBYTES. Return NULL if
|
||||
it was not found. Note, that the function does not check whether
|
||||
the value fits into the provided buffer.*/
|
||||
const unsigned char *find_tlv (const unsigned char *buffer, size_t length,
|
||||
int tag, size_t *nbytes);
|
||||
const unsigned char *find_tlv_unchecked (const unsigned char *buffer,
|
||||
size_t length,
|
||||
int tag, size_t *nbytes);
|
||||
|
||||
|
||||
/* ASN.1 BER parser: Parse BUFFER of length SIZE and return the tag
|
||||
|
Loading…
x
Reference in New Issue
Block a user