mirror of
git://git.gnupg.org/gnupg.git
synced 2025-03-28 22:49:59 +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>
|
2005-05-13 David Shaw <dshaw@jabberwocky.com>
|
||||||
|
|
||||||
* build-packet.c (do_comment): Removed.
|
* 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
|
/* 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.
|
* This file is part of GnuPG.
|
||||||
*
|
*
|
||||||
@ -23,10 +23,15 @@
|
|||||||
#ifndef GNUPG_SCD_APP_COMMON_H
|
#ifndef GNUPG_SCD_APP_COMMON_H
|
||||||
#define GNUPG_SCD_APP_COMMON_H
|
#define GNUPG_SCD_APP_COMMON_H
|
||||||
|
|
||||||
#if GNUPG_MAJOR_VERSION != 1
|
#if GNUPG_MAJOR_VERSION == 1
|
||||||
#include <ksba.h>
|
# ifdef ENABLE_AGENT_SUPPORT
|
||||||
|
# include "assuan.h"
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# include <ksba.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
struct app_local_s; /* Defined by all app-*.c. */
|
struct app_local_s; /* Defined by all app-*.c. */
|
||||||
|
|
||||||
struct app_ctx_s {
|
struct app_ctx_s {
|
||||||
@ -35,6 +40,15 @@ struct app_ctx_s {
|
|||||||
unsupported operations the particular
|
unsupported operations the particular
|
||||||
function pointer is set to NULL */
|
function pointer is set to NULL */
|
||||||
int slot; /* Used reader. */
|
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. */
|
unsigned char *serialno; /* Serialnumber in raw form, allocated. */
|
||||||
size_t serialnolen; /* Length in octets of serialnumber. */
|
size_t serialnolen; /* Length in octets of serialnumber. */
|
||||||
const char *apptype;
|
const char *apptype;
|
||||||
@ -46,54 +60,56 @@ struct app_ctx_s {
|
|||||||
struct app_local_s *app_local; /* Local to the application. */
|
struct app_local_s *app_local; /* Local to the application. */
|
||||||
struct {
|
struct {
|
||||||
void (*deinit) (app_t app);
|
void (*deinit) (app_t app);
|
||||||
int (*learn_status) (app_t app, ctrl_t ctrl);
|
gpg_error_t (*learn_status) (app_t app, ctrl_t ctrl);
|
||||||
int (*readcert) (app_t app, const char *certid,
|
gpg_error_t (*readcert) (app_t app, const char *certid,
|
||||||
unsigned char **cert, size_t *certlen);
|
unsigned char **cert, size_t *certlen);
|
||||||
int (*getattr) (app_t app, ctrl_t ctrl, const char *name);
|
gpg_error_t (*readkey) (app_t app, const char *certid,
|
||||||
int (*setattr) (app_t app, const char *name,
|
unsigned char **pk, size_t *pklen);
|
||||||
int (*pincb)(void*, const char *, char **),
|
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,
|
void *pincb_arg,
|
||||||
const unsigned char *value, size_t valuelen);
|
const unsigned char *value, size_t valuelen);
|
||||||
int (*sign) (app_t app,
|
gpg_error_t (*sign) (app_t app,
|
||||||
const char *keyidstr, int hashalgo,
|
const char *keyidstr, int hashalgo,
|
||||||
int (pincb)(void*, const char *, char **),
|
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||||
void *pincb_arg,
|
void *pincb_arg,
|
||||||
const void *indata, size_t indatalen,
|
const void *indata, size_t indatalen,
|
||||||
unsigned char **outdata, size_t *outdatalen );
|
unsigned char **outdata, size_t *outdatalen );
|
||||||
int (*auth) (app_t app, const char *keyidstr,
|
gpg_error_t (*auth) (app_t app, const char *keyidstr,
|
||||||
int (*pincb)(void*, const char *, char **),
|
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||||
void *pincb_arg,
|
void *pincb_arg,
|
||||||
const void *indata, size_t indatalen,
|
const void *indata, size_t indatalen,
|
||||||
unsigned char **outdata, size_t *outdatalen);
|
unsigned char **outdata, size_t *outdatalen);
|
||||||
int (*decipher) (app_t app, const char *keyidstr,
|
gpg_error_t (*decipher) (app_t app, const char *keyidstr,
|
||||||
int (pincb)(void*, const char *, char **),
|
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||||
void *pincb_arg,
|
void *pincb_arg,
|
||||||
const void *indata, size_t indatalen,
|
const void *indata, size_t indatalen,
|
||||||
unsigned char **outdata, size_t *outdatalen);
|
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,
|
const char *keynostr, unsigned int flags,
|
||||||
int (*pincb)(void*, const char *, char **),
|
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||||
void *pincb_arg);
|
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,
|
const char *chvnostr, int reset_mode,
|
||||||
int (*pincb)(void*, const char *, char **),
|
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||||
void *pincb_arg);
|
void *pincb_arg);
|
||||||
int (*check_pin) (app_t app, const char *keyidstr,
|
gpg_error_t (*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);
|
void *pincb_arg);
|
||||||
} fnc;
|
} fnc;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#if GNUPG_MAJOR_VERSION == 1
|
#if GNUPG_MAJOR_VERSION == 1
|
||||||
int app_select_openpgp (app_t app);
|
gpg_error_t app_select_openpgp (app_t app);
|
||||||
int app_get_serial_and_stamp (app_t app, char **serial, time_t *stamp);
|
gpg_error_t 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_openpgp_storekey (app_t app, int keyno,
|
||||||
unsigned char *template, size_t template_len,
|
unsigned char *template, size_t template_len,
|
||||||
time_t created_at,
|
time_t created_at,
|
||||||
const unsigned char *m, size_t mlen,
|
const unsigned char *m, size_t mlen,
|
||||||
const unsigned char *e, size_t elen,
|
const unsigned char *e, size_t elen,
|
||||||
int (*pincb)(void*, const char *, char **),
|
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||||
void *pincb_arg);
|
void *pincb_arg);
|
||||||
#else
|
#else
|
||||||
/*-- app-help.c --*/
|
/*-- 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.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);
|
void release_application (app_t app);
|
||||||
int app_munge_serialno (app_t app);
|
gpg_error_t app_munge_serialno (app_t app);
|
||||||
int app_get_serial_and_stamp (app_t app, char **serial, time_t *stamp);
|
gpg_error_t app_get_serial_and_stamp (app_t app, char **serial, time_t *stamp);
|
||||||
int app_write_learn_status (app_t app, ctrl_t ctrl);
|
gpg_error_t app_write_learn_status (app_t app, ctrl_t ctrl);
|
||||||
int app_readcert (app_t app, const char *certid,
|
gpg_error_t app_readcert (app_t app, const char *certid,
|
||||||
unsigned char **cert, size_t *certlen);
|
unsigned char **cert, size_t *certlen);
|
||||||
int app_getattr (app_t app, ctrl_t ctrl, const char *name);
|
gpg_error_t app_readkey (app_t app, const char *keyid,
|
||||||
int app_setattr (app_t app, const char *name,
|
unsigned char **pk, size_t *pklen);
|
||||||
int (*pincb)(void*, const char *, char **),
|
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,
|
void *pincb_arg,
|
||||||
const unsigned char *value, size_t valuelen);
|
const unsigned char *value, size_t valuelen);
|
||||||
int app_sign (app_t app, const char *keyidstr, int hashalgo,
|
gpg_error_t app_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,
|
void *pincb_arg,
|
||||||
const void *indata, size_t indatalen,
|
const void *indata, size_t indatalen,
|
||||||
unsigned char **outdata, size_t *outdatalen );
|
unsigned char **outdata, size_t *outdatalen );
|
||||||
int app_auth (app_t app, const char *keyidstr,
|
gpg_error_t app_auth (app_t app, const char *keyidstr,
|
||||||
int (*pincb)(void*, const char *, char **),
|
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||||
void *pincb_arg,
|
void *pincb_arg,
|
||||||
const void *indata, size_t indatalen,
|
const void *indata, size_t indatalen,
|
||||||
unsigned char **outdata, size_t *outdatalen);
|
unsigned char **outdata, size_t *outdatalen);
|
||||||
int app_decipher (app_t app, const char *keyidstr,
|
gpg_error_t app_decipher (app_t app, const char *keyidstr,
|
||||||
int (pincb)(void*, const char *, char **),
|
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||||
void *pincb_arg,
|
void *pincb_arg,
|
||||||
const void *indata, size_t indatalen,
|
const void *indata, size_t indatalen,
|
||||||
unsigned char **outdata, size_t *outdatalen );
|
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,
|
const char *keynostr, unsigned int flags,
|
||||||
int (*pincb)(void*, const char *, char **),
|
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||||
void *pincb_arg);
|
void *pincb_arg);
|
||||||
int app_get_challenge (app_t app, size_t nbytes, unsigned char *buffer);
|
gpg_error_t app_get_challenge (app_t app, size_t nbytes,
|
||||||
int app_change_pin (app_t app, ctrl_t ctrl,
|
unsigned char *buffer);
|
||||||
|
gpg_error_t app_change_pin (app_t app, ctrl_t ctrl,
|
||||||
const char *chvnostr, int reset_mode,
|
const char *chvnostr, int reset_mode,
|
||||||
int (*pincb)(void*, const char *, char **),
|
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||||
void *pincb_arg);
|
void *pincb_arg);
|
||||||
int app_check_pin (app_t app, const char *keyidstr,
|
gpg_error_t app_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);
|
void *pincb_arg);
|
||||||
|
|
||||||
|
|
||||||
/*-- app-openpgp.c --*/
|
/*-- 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 **serialno,
|
||||||
char **disp_name,
|
char **disp_name,
|
||||||
char **pubkey_url,
|
char **pubkey_url,
|
||||||
unsigned char **fpr1,
|
unsigned char **fpr1,
|
||||||
unsigned char **fpr2,
|
unsigned char **fpr2,
|
||||||
unsigned char **fpr3);
|
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,
|
unsigned char *template, size_t template_len,
|
||||||
time_t created_at,
|
time_t created_at,
|
||||||
const unsigned char *m, size_t mlen,
|
const unsigned char *m, size_t mlen,
|
||||||
const unsigned char *e, size_t elen,
|
const unsigned char *e, size_t elen,
|
||||||
int (*pincb)(void*, const char *, char **),
|
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||||
void *pincb_arg);
|
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 **m, size_t *mlen,
|
||||||
unsigned char **e, size_t *elen);
|
unsigned char **e, size_t *elen);
|
||||||
/*-- app-nks.c --*/
|
/*-- app-nks.c --*/
|
||||||
int app_select_nks (app_t app);
|
gpg_error_t app_select_nks (app_t app);
|
||||||
|
|
||||||
/*-- app-dinsig.c --*/
|
/*-- app-dinsig.c --*/
|
||||||
int app_select_dinsig (app_t app);
|
gpg_error_t app_select_dinsig (app_t app);
|
||||||
|
|
||||||
/*-- app-p15.c --*/
|
/*-- app-p15.c --*/
|
||||||
int app_select_p15 (app_t app);
|
gpg_error_t app_select_p15 (app_t app);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -90,6 +90,7 @@ static struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* One cache item for DOs. */
|
||||||
struct cache_s {
|
struct cache_s {
|
||||||
struct cache_s *next;
|
struct cache_s *next;
|
||||||
int tag;
|
int tag;
|
||||||
@ -97,8 +98,27 @@ struct cache_s {
|
|||||||
unsigned char data[1];
|
unsigned char data[1];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* Object with application (i.e. OpenPGP card) specific data. */
|
||||||
struct app_local_s {
|
struct app_local_s {
|
||||||
|
/* A linked list with cached DOs. */
|
||||||
struct cache_s *cache;
|
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
|
struct
|
||||||
{
|
{
|
||||||
unsigned int get_challenge:1;
|
unsigned int get_challenge:1;
|
||||||
@ -106,6 +126,8 @@ struct app_local_s {
|
|||||||
unsigned int change_force_chv:1;
|
unsigned int change_force_chv:1;
|
||||||
unsigned int private_dos:1;
|
unsigned int private_dos:1;
|
||||||
} extcap;
|
} extcap;
|
||||||
|
|
||||||
|
/* Flags used to control the application. */
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
unsigned int no_sync:1; /* Do not sync CHV1 and CHV2 */
|
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,
|
static unsigned long convert_sig_counter_value (const unsigned char *value,
|
||||||
size_t valuelen);
|
size_t valuelen);
|
||||||
static unsigned long get_sig_counter (APP app);
|
static unsigned long get_sig_counter (app_t app);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Deconstructor. */
|
/* Deconstructor. */
|
||||||
static void
|
static void
|
||||||
do_deinit (app_t app)
|
do_deinit (app_t app)
|
||||||
@ -125,12 +153,19 @@ do_deinit (app_t app)
|
|||||||
if (app && app->app_local)
|
if (app && app->app_local)
|
||||||
{
|
{
|
||||||
struct cache_s *c, *c2;
|
struct cache_s *c, *c2;
|
||||||
|
int i;
|
||||||
|
|
||||||
for (c = app->app_local->cache; c; c = c2)
|
for (c = app->app_local->cache; c; c = c2)
|
||||||
{
|
{
|
||||||
c2 = c->next;
|
c2 = c->next;
|
||||||
xfree (c);
|
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);
|
xfree (app->app_local);
|
||||||
app->app_local = NULL;
|
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
|
NULL if not found or a pointer which must be used to release the
|
||||||
buffer holding value. */
|
buffer holding value. */
|
||||||
static void *
|
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;
|
int rc, i;
|
||||||
unsigned char *buffer;
|
unsigned char *buffer;
|
||||||
size_t buflen;
|
size_t buflen;
|
||||||
unsigned char *value;
|
unsigned char *value;
|
||||||
size_t valuelen;
|
size_t valuelen;
|
||||||
|
int dummyrc;
|
||||||
|
|
||||||
|
if (!r_rc)
|
||||||
|
r_rc = &dummyrc;
|
||||||
|
|
||||||
*result = NULL;
|
*result = NULL;
|
||||||
*nbytes = 0;
|
*nbytes = 0;
|
||||||
|
*r_rc = 0;
|
||||||
for (i=0; data_objects[i].tag && data_objects[i].tag != tag; i++)
|
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 (app->card_version > 0x0100 && data_objects[i].get_immediate_in_v11)
|
||||||
{
|
{
|
||||||
if( iso7816_get_data (app->slot, tag, &buffer, &buflen))
|
rc = iso7816_get_data (app->slot, tag, &buffer, &buflen);
|
||||||
return NULL;
|
if (rc)
|
||||||
|
{
|
||||||
|
*r_rc = rc;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
*result = buffer;
|
*result = buffer;
|
||||||
*nbytes = buflen;
|
*nbytes = buflen;
|
||||||
return buffer;
|
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,
|
rc = get_cached_data (app, data_objects[i].get_from,
|
||||||
&buffer, &buflen,
|
&buffer, &buflen,
|
||||||
data_objects[i].get_immediate_in_v11);
|
(data_objects[i].dont_cache
|
||||||
|
|| data_objects[i].get_immediate_in_v11));
|
||||||
if (!rc)
|
if (!rc)
|
||||||
{
|
{
|
||||||
const unsigned char *s;
|
const unsigned char *s;
|
||||||
|
|
||||||
s = find_tlv (buffer, buflen, tag, &valuelen);
|
s = find_tlv_unchecked (buffer, buflen, tag, &valuelen);
|
||||||
if (!s)
|
if (!s)
|
||||||
value = NULL; /* not found */
|
value = NULL; /* not found */
|
||||||
else if (valuelen > buflen - (s - buffer))
|
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. */
|
if (!value) /* Not in a constructed DO, try simple. */
|
||||||
{
|
{
|
||||||
rc = get_cached_data (app, tag, &buffer, &buflen,
|
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)
|
if (!rc)
|
||||||
{
|
{
|
||||||
value = buffer;
|
value = buffer;
|
||||||
@ -342,6 +389,7 @@ get_one_do (app_t app, int tag, unsigned char **result, size_t *nbytes)
|
|||||||
*result = value;
|
*result = value;
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
*r_rc = rc;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -385,8 +433,8 @@ dump_all_do (int slot)
|
|||||||
|
|
||||||
if (j==i || data_objects[i].tag != data_objects[j].get_from)
|
if (j==i || data_objects[i].tag != data_objects[j].get_from)
|
||||||
continue;
|
continue;
|
||||||
value = find_tlv (buffer, buflen,
|
value = find_tlv_unchecked (buffer, buflen,
|
||||||
data_objects[j].tag, &valuelen);
|
data_objects[j].tag, &valuelen);
|
||||||
if (!value)
|
if (!value)
|
||||||
; /* not found */
|
; /* not found */
|
||||||
else if (valuelen > buflen - (value - buffer))
|
else if (valuelen > buflen - (value - buffer))
|
||||||
@ -460,7 +508,7 @@ parse_login_data (app_t app)
|
|||||||
app->app_local->flags.def_chv2 = 0;
|
app->app_local->flags.def_chv2 = 0;
|
||||||
|
|
||||||
/* Read the DO. */
|
/* Read the DO. */
|
||||||
relptr = get_one_do (app, 0x005E, &buffer, &buflen);
|
relptr = get_one_do (app, 0x005E, &buffer, &buflen, NULL);
|
||||||
if (!relptr)
|
if (!relptr)
|
||||||
return; /* Ooops. */
|
return; /* Ooops. */
|
||||||
for (; buflen; buflen--, buffer++)
|
for (; buflen; buflen--, buffer++)
|
||||||
@ -499,7 +547,7 @@ parse_login_data (app_t app)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Note, that FPR must be at least 20 bytes. */
|
/* Note, that FPR must be at least 20 bytes. */
|
||||||
static int
|
static gpg_error_t
|
||||||
store_fpr (int slot, int keynumber, u32 timestamp,
|
store_fpr (int slot, int keynumber, u32 timestamp,
|
||||||
const unsigned char *m, size_t mlen,
|
const unsigned char *m, size_t mlen,
|
||||||
const unsigned char *e, size_t elen,
|
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
|
/* Implement the GETATTR command. This is similar to the LEARN
|
||||||
command but returns just one value via the status interface. */
|
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)
|
do_getattr (app_t app, ctrl_t ctrl, const char *name)
|
||||||
{
|
{
|
||||||
static struct {
|
static struct {
|
||||||
@ -650,7 +698,7 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
|
|||||||
{ "PRIVATE-DO-4", 0x0104 },
|
{ "PRIVATE-DO-4", 0x0104 },
|
||||||
{ NULL, 0 }
|
{ NULL, 0 }
|
||||||
};
|
};
|
||||||
int idx, i;
|
int idx, i, rc;
|
||||||
void *relptr;
|
void *relptr;
|
||||||
unsigned char *value;
|
unsigned char *value;
|
||||||
size_t valuelen;
|
size_t valuelen;
|
||||||
@ -695,7 +743,7 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
|
|||||||
return 0;
|
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 (relptr)
|
||||||
{
|
{
|
||||||
if (table[idx].special == 1)
|
if (table[idx].special == 1)
|
||||||
@ -732,11 +780,395 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
|
|||||||
|
|
||||||
xfree (relptr);
|
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;
|
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_learn_status (app_t app, ctrl_t ctrl)
|
||||||
{
|
{
|
||||||
do_getattr (app, ctrl, "EXTCAP");
|
do_getattr (app, ctrl, "EXTCAP");
|
||||||
@ -760,16 +1192,57 @@ do_learn_status (app_t app, ctrl_t ctrl)
|
|||||||
if (app->did_chv3)
|
if (app->did_chv3)
|
||||||
do_getattr (app, ctrl, "PRIVATE-DO-4");
|
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;
|
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
|
/* Verify CHV2 if required. Depending on the configuration of the
|
||||||
card CHV1 will also be verified. */
|
card CHV1 will also be verified. */
|
||||||
static int
|
static gpg_error_t
|
||||||
verify_chv2 (app_t app,
|
verify_chv2 (app_t app,
|
||||||
int (*pincb)(void*, const char *, char **),
|
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||||
void *pincb_arg)
|
void *pincb_arg)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
@ -823,9 +1296,9 @@ verify_chv2 (app_t app,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Verify CHV3 if required. */
|
/* Verify CHV3 if required. */
|
||||||
static int
|
static gpg_error_t
|
||||||
verify_chv3 (app_t app,
|
verify_chv3 (app_t app,
|
||||||
int (*pincb)(void*, const char *, char **),
|
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||||
void *pincb_arg)
|
void *pincb_arg)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
@ -845,7 +1318,7 @@ verify_chv3 (app_t app,
|
|||||||
unsigned char *value;
|
unsigned char *value;
|
||||||
size_t valuelen;
|
size_t valuelen;
|
||||||
|
|
||||||
relptr = get_one_do (app, 0x00C4, &value, &valuelen);
|
relptr = get_one_do (app, 0x00C4, &value, &valuelen, NULL);
|
||||||
if (!relptr || valuelen < 7)
|
if (!relptr || valuelen < 7)
|
||||||
{
|
{
|
||||||
log_error (_("error retrieving CHV status from card\n"));
|
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
|
/* Handle the SETATTR operation. All arguments are already basically
|
||||||
checked. */
|
checked. */
|
||||||
static int
|
static gpg_error_t
|
||||||
do_setattr (app_t app, const char *name,
|
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,
|
void *pincb_arg,
|
||||||
const unsigned char *value, size_t valuelen)
|
const unsigned char *value, size_t valuelen)
|
||||||
{
|
{
|
||||||
@ -965,9 +1438,9 @@ do_setattr (app_t app, const char *name,
|
|||||||
|
|
||||||
|
|
||||||
/* Handle the PASSWD command. */
|
/* 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,
|
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)
|
void *pincb_arg)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
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. */
|
/* Handle the GENKEY command. */
|
||||||
static int
|
static gpg_error_t
|
||||||
do_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags,
|
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)
|
void *pincb_arg)
|
||||||
{
|
{
|
||||||
int rc;
|
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. */
|
generation. This _might_ help a card to gather more entropy. */
|
||||||
flush_cache (app);
|
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);
|
rc = iso7816_get_data (app->slot, 0x006E, &buffer, &buflen);
|
||||||
if (rc)
|
if (rc)
|
||||||
{
|
{
|
||||||
@ -1109,11 +1589,12 @@ do_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags,
|
|||||||
else
|
else
|
||||||
log_info (_("generating new key\n"));
|
log_info (_("generating new key\n"));
|
||||||
|
|
||||||
|
|
||||||
|
/* Prepare for key generation by verifying the ADmin PIN. */
|
||||||
rc = verify_chv3 (app, pincb, pincb_arg);
|
rc = verify_chv3 (app, pincb, pincb_arg);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto leave;
|
goto leave;
|
||||||
|
|
||||||
xfree (buffer); buffer = NULL;
|
xfree (buffer); buffer = NULL;
|
||||||
|
|
||||||
#if 1
|
#if 1
|
||||||
@ -1206,7 +1687,7 @@ get_sig_counter (app_t app)
|
|||||||
size_t valuelen;
|
size_t valuelen;
|
||||||
unsigned long ul;
|
unsigned long ul;
|
||||||
|
|
||||||
relptr = get_one_do (app, 0x0093, &value, &valuelen);
|
relptr = get_one_do (app, 0x0093, &value, &valuelen, NULL);
|
||||||
if (!relptr)
|
if (!relptr)
|
||||||
return 0;
|
return 0;
|
||||||
ul = convert_sig_counter_value (value, valuelen);
|
ul = convert_sig_counter_value (value, valuelen);
|
||||||
@ -1214,7 +1695,7 @@ get_sig_counter (app_t app)
|
|||||||
return ul;
|
return ul;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static gpg_error_t
|
||||||
compare_fingerprint (app_t app, int keyno, unsigned char *sha1fpr)
|
compare_fingerprint (app_t app, int keyno, unsigned char *sha1fpr)
|
||||||
{
|
{
|
||||||
const unsigned char *fpr;
|
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
|
the key on the card has been replaced but the shadow information
|
||||||
known to gpg was not updated. If there is no fingerprint we
|
known to gpg was not updated. If there is no fingerprint we
|
||||||
assume that this is okay. */
|
assume that this is okay. */
|
||||||
static int
|
static gpg_error_t
|
||||||
check_against_given_fingerprint (app_t app, const char *fpr, int keyno)
|
check_against_given_fingerprint (app_t app, const char *fpr, int keyno)
|
||||||
{
|
{
|
||||||
unsigned char tmp[20];
|
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
|
GPG_ERR_WRONG_CARD to indicate that the card currently present does
|
||||||
not match the one required for the requested action (e.g. the
|
not match the one required for the requested action (e.g. the
|
||||||
serial number does not match). */
|
serial number does not match). */
|
||||||
static int
|
static gpg_error_t
|
||||||
do_sign (app_t app, const char *keyidstr, int hashalgo,
|
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,
|
void *pincb_arg,
|
||||||
const void *indata, size_t indatalen,
|
const void *indata, size_t indatalen,
|
||||||
unsigned char **outdata, size_t *outdatalen )
|
unsigned char **outdata, size_t *outdatalen )
|
||||||
@ -1308,7 +1789,15 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
|
|||||||
|
|
||||||
if (!keyidstr || !*keyidstr)
|
if (!keyidstr || !*keyidstr)
|
||||||
return gpg_error (GPG_ERR_INV_VALUE);
|
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);
|
return gpg_error (GPG_ERR_INV_VALUE);
|
||||||
|
|
||||||
/* Check whether an OpenPGP card of any version has been requested. */
|
/* 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
|
/* Compute a digital signature using the INTERNAL AUTHENTICATE command
|
||||||
on INDATA which is expected to be the raw message digest. For this
|
on INDATA which is expected to be the raw message digest. For this
|
||||||
application the KEYIDSTR consists of the serialnumber and the
|
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
|
Note that this fucntion may return the error code
|
||||||
GPG_ERR_WRONG_CARD to indicate that the card currently present does
|
GPG_ERR_WRONG_CARD to indicate that the card currently present does
|
||||||
not match the one required for the requested action (e.g. the
|
not match the one required for the requested action (e.g. the
|
||||||
serial number does not match). */
|
serial number does not match). */
|
||||||
static int
|
static gpg_error_t
|
||||||
do_auth (app_t app, const char *keyidstr,
|
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,
|
void *pincb_arg,
|
||||||
const void *indata, size_t indatalen,
|
const void *indata, size_t indatalen,
|
||||||
unsigned char **outdata, size_t *outdatalen )
|
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);
|
return gpg_error (GPG_ERR_INV_VALUE);
|
||||||
|
|
||||||
/* Check whether an OpenPGP card of any version has been requested. */
|
/* Check whether an OpenPGP card of any version has been requested. */
|
||||||
if (strlen (keyidstr) < 32 || strncmp (keyidstr, "D27600012401", 12))
|
if (!strcmp (keyidstr, "OPENPGP.3"))
|
||||||
return gpg_error (GPG_ERR_INV_ID);
|
|
||||||
|
|
||||||
for (s=keyidstr, n=0; hexdigitp (s); s++, n++)
|
|
||||||
;
|
;
|
||||||
if (n != 32)
|
else if (strlen (keyidstr) < 32 || strncmp (keyidstr, "D27600012401", 12))
|
||||||
return gpg_error (GPG_ERR_INV_ID);
|
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
|
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++)
|
for (s=keyidstr, n=0; n < 16; s += 2, n++)
|
||||||
tmp_sn[n] = xtoi_2 (s);
|
tmp_sn[n] = xtoi_2 (s);
|
||||||
|
|
||||||
if (app->serialnolen != 16)
|
if (app->serialnolen != 16)
|
||||||
return gpg_error (GPG_ERR_INV_CARD);
|
return gpg_error (GPG_ERR_INV_CARD);
|
||||||
if (memcmp (app->serialno, tmp_sn, 16))
|
if (memcmp (app->serialno, tmp_sn, 16))
|
||||||
return gpg_error (GPG_ERR_WRONG_CARD);
|
return gpg_error (GPG_ERR_WRONG_CARD);
|
||||||
|
}
|
||||||
|
|
||||||
/* If a fingerprint has been specified check it against the one on
|
/* 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 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,
|
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,
|
void *pincb_arg,
|
||||||
const void *indata, size_t indatalen,
|
const void *indata, size_t indatalen,
|
||||||
unsigned char **outdata, size_t *outdatalen )
|
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
|
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
|
entry system, only the regular CHV will get blocked and not the
|
||||||
dangerous CHV3. KEYIDSTR is the usual card's serial number; an
|
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
|
There is a special mode if the keyidstr is "<serialno>[CHV3]" with
|
||||||
the "[CHV3]" being a literal string: The Admin Pin is checked if
|
the "[CHV3]" being a literal string: The Admin Pin is checked if
|
||||||
and only if the retry counter is still at 3.
|
and only if the retry counter is still at 3. */
|
||||||
*/
|
static gpg_error_t
|
||||||
static int
|
|
||||||
do_check_pin (app_t app, const char *keyidstr,
|
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)
|
void *pincb_arg)
|
||||||
{
|
{
|
||||||
unsigned char tmp_sn[20];
|
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);
|
return gpg_error (GPG_ERR_INV_CARD);
|
||||||
if (memcmp (app->serialno, tmp_sn, 16))
|
if (memcmp (app->serialno, tmp_sn, 16))
|
||||||
return gpg_error (GPG_ERR_WRONG_CARD);
|
return gpg_error (GPG_ERR_WRONG_CARD);
|
||||||
|
|
||||||
/* Yes, there is a race conditions: The user might pull the 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
|
right here and we won't notice that. However this is not a
|
||||||
problem and the check above is merely for a graceful failure
|
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;
|
size_t valuelen;
|
||||||
int count;
|
int count;
|
||||||
|
|
||||||
relptr = get_one_do (app, 0x00C4, &value, &valuelen);
|
relptr = get_one_do (app, 0x00C4, &value, &valuelen, NULL);
|
||||||
if (!relptr || valuelen < 7)
|
if (!relptr || valuelen < 7)
|
||||||
{
|
{
|
||||||
log_error (_("error retrieving CHV status from card\n"));
|
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
|
/* Select the OpenPGP application on the card in SLOT. This function
|
||||||
must be used before any other OpenPGP application functions. */
|
must be used before any other OpenPGP application functions. */
|
||||||
int
|
gpg_error_t
|
||||||
app_select_openpgp (app_t app)
|
app_select_openpgp (app_t app)
|
||||||
{
|
{
|
||||||
static char const aid[] = { 0xD2, 0x76, 0x00, 0x01, 0x24, 0x01 };
|
static char const aid[] = { 0xD2, 0x76, 0x00, 0x01, 0x24, 0x01 };
|
||||||
@ -1685,7 +2179,7 @@ app_select_openpgp (app_t app)
|
|||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
relptr = get_one_do (app, 0x00C4, &buffer, &buflen);
|
relptr = get_one_do (app, 0x00C4, &buffer, &buflen, NULL);
|
||||||
if (!relptr)
|
if (!relptr)
|
||||||
{
|
{
|
||||||
log_error (_("can't access %s - invalid OpenPGP card?\n"),
|
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);
|
app->force_chv1 = (buflen && *buffer == 0);
|
||||||
xfree (relptr);
|
xfree (relptr);
|
||||||
|
|
||||||
relptr = get_one_do (app, 0x00C0, &buffer, &buflen);
|
relptr = get_one_do (app, 0x00C0, &buffer, &buflen, NULL);
|
||||||
if (!relptr)
|
if (!relptr)
|
||||||
{
|
{
|
||||||
log_error (_("can't access %s - invalid OpenPGP card?\n"),
|
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.deinit = do_deinit;
|
||||||
app->fnc.learn_status = do_learn_status;
|
app->fnc.learn_status = do_learn_status;
|
||||||
app->fnc.readcert = NULL;
|
app->fnc.readkey = do_readkey;
|
||||||
app->fnc.getattr = do_getattr;
|
app->fnc.getattr = do_getattr;
|
||||||
app->fnc.setattr = do_setattr;
|
app->fnc.setattr = do_setattr;
|
||||||
app->fnc.genkey = do_genkey;
|
app->fnc.genkey = do_genkey;
|
||||||
@ -1747,7 +2241,7 @@ leave:
|
|||||||
LEARN command returns. All parameters return allocated strings or
|
LEARN command returns. All parameters return allocated strings or
|
||||||
buffers or NULL if the data object is not available. All returned
|
buffers or NULL if the data object is not available. All returned
|
||||||
values are sanitized. */
|
values are sanitized. */
|
||||||
int
|
gpg_error_t
|
||||||
app_openpgp_cardinfo (app_t app,
|
app_openpgp_cardinfo (app_t app,
|
||||||
char **serialno,
|
char **serialno,
|
||||||
char **disp_name,
|
char **disp_name,
|
||||||
@ -1778,7 +2272,7 @@ app_openpgp_cardinfo (app_t app,
|
|||||||
if (disp_name)
|
if (disp_name)
|
||||||
{
|
{
|
||||||
*disp_name = NULL;
|
*disp_name = NULL;
|
||||||
relptr = get_one_do (app, 0x005B, &value, &valuelen);
|
relptr = get_one_do (app, 0x005B, &value, &valuelen, NULL);
|
||||||
if (relptr)
|
if (relptr)
|
||||||
{
|
{
|
||||||
*disp_name = make_printable_string (value, valuelen, 0);
|
*disp_name = make_printable_string (value, valuelen, 0);
|
||||||
@ -1789,7 +2283,7 @@ app_openpgp_cardinfo (app_t app,
|
|||||||
if (pubkey_url)
|
if (pubkey_url)
|
||||||
{
|
{
|
||||||
*pubkey_url = NULL;
|
*pubkey_url = NULL;
|
||||||
relptr = get_one_do (app, 0x5F50, &value, &valuelen);
|
relptr = get_one_do (app, 0x5F50, &value, &valuelen, NULL);
|
||||||
if (relptr)
|
if (relptr)
|
||||||
{
|
{
|
||||||
*pubkey_url = make_printable_string (value, valuelen, 0);
|
*pubkey_url = make_printable_string (value, valuelen, 0);
|
||||||
@ -1803,7 +2297,7 @@ app_openpgp_cardinfo (app_t app,
|
|||||||
*fpr2 = NULL;
|
*fpr2 = NULL;
|
||||||
if (fpr3)
|
if (fpr3)
|
||||||
*fpr3 = NULL;
|
*fpr3 = NULL;
|
||||||
relptr = get_one_do (app, 0x00C5, &value, &valuelen);
|
relptr = get_one_do (app, 0x00C5, &value, &valuelen, NULL);
|
||||||
if (relptr && valuelen >= 60)
|
if (relptr && valuelen >= 60)
|
||||||
{
|
{
|
||||||
if (fpr1)
|
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
|
create the fingerprint. M, MLEN is the RSA modulus and E, ELEN the
|
||||||
RSA public exponent. This function silently overwrites an existing
|
RSA public exponent. This function silently overwrites an existing
|
||||||
key.*/
|
key.*/
|
||||||
int
|
gpg_error_t
|
||||||
app_openpgp_storekey (app_t app, int keyno,
|
app_openpgp_storekey (app_t app, int keyno,
|
||||||
unsigned char *template, size_t template_len,
|
unsigned char *template, size_t template_len,
|
||||||
time_t created_at,
|
time_t created_at,
|
||||||
const unsigned char *m, size_t mlen,
|
const unsigned char *m, size_t mlen,
|
||||||
const unsigned char *e, size_t elen,
|
const unsigned char *e, size_t elen,
|
||||||
int (*pincb)(void*, const char *, char **),
|
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||||
void *pincb_arg)
|
void *pincb_arg)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
@ -1859,6 +2353,11 @@ app_openpgp_storekey (app_t app, int keyno,
|
|||||||
|
|
||||||
flush_cache (app);
|
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,
|
rc = iso7816_put_data (app->slot,
|
||||||
(app->card_version > 0x0007? 0xE0 : 0xE9) + keyno,
|
(app->card_version > 0x0007? 0xE0 : 0xE9) + keyno,
|
||||||
template, template_len);
|
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
|
/* Utility function for external tools: Read the public RSA key at
|
||||||
KEYNO and return modulus and exponent in (M,MLEN) and (E,ELEN). */
|
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,
|
app_openpgp_readkey (app_t app, int keyno, unsigned char **m, size_t *mlen,
|
||||||
unsigned char **e, size_t *elen)
|
unsigned char **e, size_t *elen)
|
||||||
{
|
{
|
||||||
|
418
g10/cardglue.c
418
g10/cardglue.c
@ -43,9 +43,16 @@
|
|||||||
#include "apdu.h"
|
#include "apdu.h"
|
||||||
#include "app-common.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
|
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;
|
void *status_cb_arg;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -57,10 +64,14 @@ struct pincb_parm_s
|
|||||||
|
|
||||||
|
|
||||||
static char *default_reader_port;
|
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
|
/* Create a serialno/fpr string from the serial number and the secret
|
||||||
key. caller must free the returned string. There is no error
|
key. caller must free the returned string. There is no error
|
||||||
return. [Taken from 1.9's keyid.c]*/
|
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,
|
/* Replacement function of the Libgcrypt onewhich is used in gnupg
|
||||||
const void *buffer, size_t length)
|
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);
|
MD_HANDLE h = md_open (algo, 0);
|
||||||
if (!h)
|
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
|
no update time is available the returned value is 0. Caller must
|
||||||
free SERIAL unless the function returns an error. */
|
free SERIAL unless the function returns an error. */
|
||||||
int
|
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;
|
unsigned char *buf, *p;
|
||||||
int i;
|
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
|
/* Open the current card and select the openpgp application. Return
|
||||||
an APP context handle to be used for further procesing or NULL on
|
an APP context handle to be used for further procesing or NULL on
|
||||||
error or if no OpenPGP application exists.*/
|
error or if no OpenPGP application exists.*/
|
||||||
static APP
|
static app_t
|
||||||
open_card (void)
|
open_card (void)
|
||||||
{
|
{
|
||||||
int slot = -1;
|
int slot = -1;
|
||||||
int rc;
|
int rc;
|
||||||
APP app;
|
app_t app;
|
||||||
int did_shutdown = 0;
|
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 ();
|
card_close ();
|
||||||
|
|
||||||
|
|
||||||
retry:
|
retry:
|
||||||
if (did_shutdown)
|
if (did_shutdown)
|
||||||
@ -309,6 +396,7 @@ open_card (void)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ready:
|
||||||
app->initialized = 1;
|
app->initialized = 1;
|
||||||
current_app = app;
|
current_app = app;
|
||||||
if (is_status_enabled () )
|
if (is_status_enabled () )
|
||||||
@ -327,15 +415,19 @@ open_card (void)
|
|||||||
return app;
|
return app;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
card_close (void)
|
card_close (void)
|
||||||
{
|
{
|
||||||
if (current_app)
|
if (current_app)
|
||||||
{
|
{
|
||||||
APP app = current_app;
|
app_t app = current_app;
|
||||||
current_app = NULL;
|
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);
|
xfree (app);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -382,7 +474,7 @@ format_cacheid (const char *sn)
|
|||||||
card context will be closed in all cases except for 0 as return
|
card context will be closed in all cases except for 0 as return
|
||||||
value and if it was possible to merely shutdown the reader. */
|
value and if it was possible to merely shutdown the reader. */
|
||||||
static int
|
static int
|
||||||
check_card_serialno (APP app, const char *serialno)
|
check_card_serialno (app_t app, const char *serialno)
|
||||||
{
|
{
|
||||||
const char *s;
|
const char *s;
|
||||||
int ask = 0;
|
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)
|
learn_status_cb (void *opaque, const char *line)
|
||||||
{
|
{
|
||||||
struct agent_card_info_s *parm = opaque;
|
struct agent_card_info_s *parm = opaque;
|
||||||
@ -644,7 +736,7 @@ learn_status_cb (void *opaque, const char *line)
|
|||||||
int
|
int
|
||||||
agent_learn (struct agent_card_info_s *info)
|
agent_learn (struct agent_card_info_s *info)
|
||||||
{
|
{
|
||||||
APP app;
|
app_t app;
|
||||||
int rc;
|
int rc;
|
||||||
struct ctrl_ctx_s ctrl;
|
struct ctrl_ctx_s ctrl;
|
||||||
time_t stamp;
|
time_t stamp;
|
||||||
@ -655,35 +747,68 @@ agent_learn (struct agent_card_info_s *info)
|
|||||||
return gpg_error (GPG_ERR_CARD);
|
return gpg_error (GPG_ERR_CARD);
|
||||||
|
|
||||||
memset (info, 0, sizeof *info);
|
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 (app->assuan_ctx)
|
||||||
if (!rc)
|
|
||||||
{
|
{
|
||||||
send_status_info (&ctrl, "SERIALNO", serial, strlen(serial), NULL, 0);
|
rc = assuan_transact (app->assuan_ctx, "SCD LEARN --force",
|
||||||
xfree (serial);
|
NULL, NULL, NULL, NULL,
|
||||||
rc = app->fnc.learn_status (app, &ctrl);
|
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;
|
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
|
int
|
||||||
agent_scd_getattr (const char *name, struct agent_card_info_s *info)
|
agent_scd_getattr (const char *name, struct agent_card_info_s *info)
|
||||||
{
|
{
|
||||||
APP app;
|
int rc;
|
||||||
|
app_t app;
|
||||||
struct ctrl_ctx_s ctrl;
|
struct ctrl_ctx_s ctrl;
|
||||||
|
|
||||||
app = current_app? current_app : open_card ();
|
app = current_app? current_app : open_card ();
|
||||||
if (!app)
|
if (!app)
|
||||||
return gpg_error (GPG_ERR_CARD);
|
return gpg_error (GPG_ERR_CARD);
|
||||||
|
|
||||||
ctrl.status_cb = learn_status_cb;
|
if (app->assuan_ctx)
|
||||||
ctrl.status_cb_arg = info;
|
{
|
||||||
return app->fnc.getattr (app, &ctrl, name);
|
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,
|
agent_scd_setattr (const char *name,
|
||||||
const unsigned char *value, size_t valuelen)
|
const unsigned char *value, size_t valuelen)
|
||||||
{
|
{
|
||||||
APP app;
|
app_t app;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
app = current_app? current_app : open_card ();
|
app = current_app? current_app : open_card ();
|
||||||
if (!app)
|
if (!app)
|
||||||
return gpg_error (GPG_ERR_CARD);
|
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)
|
if (rc)
|
||||||
write_status (STATUS_SC_OP_FAILURE);
|
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)
|
genkey_status_cb (void *opaque, const char *line)
|
||||||
{
|
{
|
||||||
struct agent_card_genkey_s *parm = opaque;
|
struct agent_card_genkey_s *parm = opaque;
|
||||||
@ -868,8 +1026,8 @@ genkey_status_cb (void *opaque, const char *line)
|
|||||||
int
|
int
|
||||||
agent_scd_genkey (struct agent_card_genkey_s *info, int keyno, int force)
|
agent_scd_genkey (struct agent_card_genkey_s *info, int keyno, int force)
|
||||||
{
|
{
|
||||||
APP app;
|
app_t app;
|
||||||
char keynostr[20];
|
char line[ASSUAN_LINELENGTH];
|
||||||
struct ctrl_ctx_s ctrl;
|
struct ctrl_ctx_s ctrl;
|
||||||
int rc;
|
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);
|
return gpg_error (GPG_ERR_CARD);
|
||||||
|
|
||||||
memset (info, 0, sizeof *info);
|
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,
|
if (app->assuan_ctx)
|
||||||
force? 1:0,
|
{
|
||||||
pin_cb, NULL);
|
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)
|
if (rc)
|
||||||
write_status (STATUS_SC_OP_FAILURE);
|
write_status (STATUS_SC_OP_FAILURE);
|
||||||
return rc;
|
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. */
|
/* Send a PKSIGN command to the SCdaemon. */
|
||||||
int
|
int
|
||||||
agent_scd_pksign (const char *serialno, int hashalgo,
|
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)
|
unsigned char **r_buf, size_t *r_buflen)
|
||||||
{
|
{
|
||||||
struct pincb_parm_s parm;
|
struct pincb_parm_s parm;
|
||||||
APP app;
|
app_t app;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
*r_buf = NULL;
|
*r_buf = NULL;
|
||||||
@ -909,20 +1093,56 @@ agent_scd_pksign (const char *serialno, int hashalgo,
|
|||||||
if (!app)
|
if (!app)
|
||||||
return gpg_error (GPG_ERR_CARD);
|
return gpg_error (GPG_ERR_CARD);
|
||||||
|
|
||||||
/* Check that the card's serialnumber is as required.*/
|
if (app->assuan_ctx)
|
||||||
rc = check_card_serialno (app, serialno);
|
{
|
||||||
if (rc == -1)
|
char *p, line[ASSUAN_LINELENGTH];
|
||||||
goto retry;
|
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)
|
if (rc)
|
||||||
{
|
{
|
||||||
write_status (STATUS_SC_OP_FAILURE);
|
write_status (STATUS_SC_OP_FAILURE);
|
||||||
agent_clear_pin_cache (serialno);
|
if (!app->assuan_ctx)
|
||||||
|
agent_clear_pin_cache (serialno);
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@ -935,7 +1155,7 @@ agent_scd_pkdecrypt (const char *serialno,
|
|||||||
unsigned char **r_buf, size_t *r_buflen)
|
unsigned char **r_buf, size_t *r_buflen)
|
||||||
{
|
{
|
||||||
struct pincb_parm_s parm;
|
struct pincb_parm_s parm;
|
||||||
APP app;
|
app_t app;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
*r_buf = NULL;
|
*r_buf = NULL;
|
||||||
@ -947,20 +1167,56 @@ agent_scd_pkdecrypt (const char *serialno,
|
|||||||
if (!app)
|
if (!app)
|
||||||
return gpg_error (GPG_ERR_CARD);
|
return gpg_error (GPG_ERR_CARD);
|
||||||
|
|
||||||
/* Check that the card's serialnumber is as required.*/
|
if (app->assuan_ctx)
|
||||||
rc = check_card_serialno (app, serialno);
|
{
|
||||||
if (rc == -1)
|
char *p, line[ASSUAN_LINELENGTH];
|
||||||
goto retry;
|
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)
|
if (rc)
|
||||||
{
|
{
|
||||||
write_status (STATUS_SC_OP_FAILURE);
|
write_status (STATUS_SC_OP_FAILURE);
|
||||||
agent_clear_pin_cache (serialno);
|
if (!app->assuan_ctx)
|
||||||
|
agent_clear_pin_cache (serialno);
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@ -969,7 +1225,7 @@ agent_scd_pkdecrypt (const char *serialno,
|
|||||||
int
|
int
|
||||||
agent_scd_change_pin (int chvno)
|
agent_scd_change_pin (int chvno)
|
||||||
{
|
{
|
||||||
APP app;
|
app_t app;
|
||||||
char chvnostr[20];
|
char chvnostr[20];
|
||||||
int reset = 0;
|
int reset = 0;
|
||||||
int rc;
|
int rc;
|
||||||
@ -981,9 +1237,17 @@ agent_scd_change_pin (int chvno)
|
|||||||
if (!app)
|
if (!app)
|
||||||
return gpg_error (GPG_ERR_CARD);
|
return gpg_error (GPG_ERR_CARD);
|
||||||
|
|
||||||
sprintf (chvnostr, "%d", chvno);
|
if (app->assuan_ctx)
|
||||||
rc = app->fnc.change_pin (app, NULL, chvnostr, reset,
|
{
|
||||||
pin_cb, NULL);
|
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)
|
if (rc)
|
||||||
write_status (STATUS_SC_OP_FAILURE);
|
write_status (STATUS_SC_OP_FAILURE);
|
||||||
return rc;
|
return rc;
|
||||||
@ -995,14 +1259,22 @@ agent_scd_change_pin (int chvno)
|
|||||||
int
|
int
|
||||||
agent_scd_checkpin (const char *serialnobuf)
|
agent_scd_checkpin (const char *serialnobuf)
|
||||||
{
|
{
|
||||||
APP app;
|
app_t app;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
app = current_app? current_app : open_card ();
|
app = current_app? current_app : open_card ();
|
||||||
if (!app)
|
if (!app)
|
||||||
return gpg_error (GPG_ERR_CARD);
|
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)
|
if (rc)
|
||||||
write_status (STATUS_SC_OP_FAILURE);
|
write_status (STATUS_SC_OP_FAILURE);
|
||||||
return rc;
|
return rc;
|
||||||
@ -1017,16 +1289,24 @@ agent_openpgp_storekey (int keyno,
|
|||||||
const unsigned char *m, size_t mlen,
|
const unsigned char *m, size_t mlen,
|
||||||
const unsigned char *e, size_t elen)
|
const unsigned char *e, size_t elen)
|
||||||
{
|
{
|
||||||
APP app;
|
app_t app;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
app = current_app? current_app : open_card ();
|
app = current_app? current_app : open_card ();
|
||||||
if (!app)
|
if (!app)
|
||||||
return gpg_error (GPG_ERR_CARD);
|
return gpg_error (GPG_ERR_CARD);
|
||||||
|
|
||||||
rc = app_openpgp_storekey (app, keyno, template, template_len,
|
if (app->assuan_ctx)
|
||||||
created_at, m, mlen, e, elen,
|
{
|
||||||
pin_cb, NULL);
|
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)
|
if (rc)
|
||||||
write_status (STATUS_SC_OP_FAILURE);
|
write_status (STATUS_SC_OP_FAILURE);
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -1814,7 +1814,7 @@ ccid_transceive (ccid_driver_t handle,
|
|||||||
msg = send_buffer;
|
msg = send_buffer;
|
||||||
tpdulen = last_tpdulen;
|
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. */
|
{ /* Reponse does not match our sequence number. */
|
||||||
DEBUGOUT ("R-block with wrong seqno received on more bit\n");
|
DEBUGOUT ("R-block with wrong seqno received on more bit\n");
|
||||||
return CCID_DRIVER_ERR_CARD_IO_ERROR;
|
return CCID_DRIVER_ERR_CARD_IO_ERROR;
|
||||||
|
@ -26,6 +26,9 @@
|
|||||||
#include "global.h"
|
#include "global.h"
|
||||||
#include "packet.h"
|
#include "packet.h"
|
||||||
#include "cipher.h"
|
#include "cipher.h"
|
||||||
|
#ifdef ENABLE_AGENT_SUPPORT
|
||||||
|
#include "assuan.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
/* What qualifies as a certification (rather than a signature?) */
|
/* 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) \
|
#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 );
|
int unlock, unsigned use );
|
||||||
|
|
||||||
/*-- passphrase.h --*/
|
/*-- 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);
|
int have_static_passphrase(void);
|
||||||
void read_passphrase_from_fd( int fd );
|
void read_passphrase_from_fd( int fd );
|
||||||
void passphrase_clear_cache ( u32 *keyid, const char *cacheid, int algo );
|
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 block_all_signals(void);
|
||||||
void unblock_all_signals(void);
|
void unblock_all_signals(void);
|
||||||
|
|
||||||
|
|
||||||
#ifdef ENABLE_CARD_SUPPORT
|
#ifdef ENABLE_CARD_SUPPORT
|
||||||
/*-- card-util.c --*/
|
/*-- card-util.c --*/
|
||||||
void change_pin (int no, int allow_admin);
|
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.
|
* Open a connection to the agent and initializes the connection.
|
||||||
* Returns: -1 on error; on success a file descriptor for that
|
* Returns: -1 on error; on success an Assuan context for that
|
||||||
* connection is returned.
|
* 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
|
#ifdef ENABLE_AGENT_SUPPORT
|
||||||
static assuan_context_t
|
assuan_context_t
|
||||||
agent_open (void)
|
agent_open (int try)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
assuan_context_t ctx;
|
assuan_context_t ctx;
|
||||||
@ -298,8 +299,11 @@ agent_open (void)
|
|||||||
infostr = getenv ( "GPG_AGENT_INFO" );
|
infostr = getenv ( "GPG_AGENT_INFO" );
|
||||||
if (!infostr || !*infostr)
|
if (!infostr || !*infostr)
|
||||||
{
|
{
|
||||||
log_error (_("gpg-agent is not available in this session\n"));
|
if (!try)
|
||||||
opt.use_agent = 0;
|
{
|
||||||
|
log_error (_("gpg-agent is not available in this session\n"));
|
||||||
|
opt.use_agent = 0;
|
||||||
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
infostr = xstrdup ( infostr );
|
infostr = xstrdup ( infostr );
|
||||||
@ -307,9 +311,12 @@ agent_open (void)
|
|||||||
|
|
||||||
if ( !(p = strchr (infostr, PATHSEP_C)) || p == infostr)
|
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);
|
xfree (infostr);
|
||||||
opt.use_agent = 0;
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
*p++ = 0;
|
*p++ = 0;
|
||||||
@ -319,28 +326,38 @@ agent_open (void)
|
|||||||
prot = *p? atoi (p+1) : 0;
|
prot = *p? atoi (p+1) : 0;
|
||||||
if (prot != 1)
|
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);
|
xfree (infostr);
|
||||||
opt.use_agent = 0;
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = assuan_socket_connect (&ctx, infostr, pid);
|
rc = assuan_socket_connect (&ctx, infostr, pid);
|
||||||
if (rc)
|
if (rc)
|
||||||
{
|
{
|
||||||
log_error ( _("can't connect to `%s': %s\n"),
|
if (!try)
|
||||||
infostr, assuan_strerror (rc));
|
{
|
||||||
|
log_error ( _("can't connect to `%s': %s\n"),
|
||||||
|
infostr, assuan_strerror (rc));
|
||||||
|
opt.use_agent = 0;
|
||||||
|
}
|
||||||
xfree (infostr );
|
xfree (infostr );
|
||||||
opt.use_agent = 0;
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
xfree (infostr);
|
xfree (infostr);
|
||||||
|
|
||||||
if (agent_send_all_options (ctx))
|
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);
|
assuan_disconnect (ctx);
|
||||||
opt.use_agent = 0;
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -350,7 +367,7 @@ agent_open (void)
|
|||||||
|
|
||||||
|
|
||||||
#ifdef ENABLE_AGENT_SUPPORT
|
#ifdef ENABLE_AGENT_SUPPORT
|
||||||
static void
|
void
|
||||||
agent_close (assuan_context_t ctx)
|
agent_close (assuan_context_t ctx)
|
||||||
{
|
{
|
||||||
assuan_disconnect (ctx);
|
assuan_disconnect (ctx);
|
||||||
@ -474,7 +491,7 @@ agent_get_passphrase ( u32 *keyid, int mode, const char *cacheid,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if ( !(ctx = agent_open ()) )
|
if ( !(ctx = agent_open (0)) )
|
||||||
goto failure;
|
goto failure;
|
||||||
|
|
||||||
if (custom_description)
|
if (custom_description)
|
||||||
@ -672,7 +689,7 @@ passphrase_clear_cache ( u32 *keyid, const char *cacheid, int algo )
|
|||||||
else
|
else
|
||||||
pk = NULL;
|
pk = NULL;
|
||||||
|
|
||||||
if ( !(ctx = agent_open ()) )
|
if ( !(ctx = agent_open (0)) )
|
||||||
goto failure;
|
goto failure;
|
||||||
|
|
||||||
{
|
{
|
||||||
|
28
g10/tlv.c
28
g10/tlv.c
@ -1,5 +1,5 @@
|
|||||||
/* tlv.c - Tag-Length-Value Utilities
|
/* 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.
|
* This file is part of GnuPG.
|
||||||
*
|
*
|
||||||
@ -25,9 +25,8 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
#include "errors.h"
|
#include <gpg-error.h>
|
||||||
#include "util.h"
|
|
||||||
#include "packet.h"
|
|
||||||
#include "tlv.h"
|
#include "tlv.h"
|
||||||
|
|
||||||
static const unsigned char *
|
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
|
/* Locate a TLV encoded data object in BUFFER of LENGTH and
|
||||||
return a pointer to value as well as its length in NBYTES. Return
|
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
|
NULL if it was not found or if the object does not fit into the buffer. */
|
||||||
whether the value fits into the provided buffer. */
|
|
||||||
const unsigned char *
|
const unsigned char *
|
||||||
find_tlv (const unsigned char *buffer, size_t length,
|
find_tlv (const unsigned char *buffer, size_t length,
|
||||||
int tag, size_t *nbytes)
|
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
|
/* 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
|
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
|
#ifndef SCD_TLV_H
|
||||||
#define SCD_TLV_H 1
|
#define SCD_TLV_H 1
|
||||||
|
|
||||||
#include "types.h"
|
|
||||||
#include "cardglue.h"
|
|
||||||
|
|
||||||
enum tlv_tag_class {
|
enum tlv_tag_class {
|
||||||
CLASS_UNIVERSAL = 0,
|
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
|
/* 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
|
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
|
it was not found. Note, that the function does not check whether
|
||||||
the value fits into the provided buffer.*/
|
the value fits into the provided buffer.*/
|
||||||
const unsigned char *find_tlv (const unsigned char *buffer, size_t length,
|
const unsigned char *find_tlv_unchecked (const unsigned char *buffer,
|
||||||
int tag, size_t *nbytes);
|
size_t length,
|
||||||
|
int tag, size_t *nbytes);
|
||||||
|
|
||||||
|
|
||||||
/* ASN.1 BER parser: Parse BUFFER of length SIZE and return the tag
|
/* ASN.1 BER parser: Parse BUFFER of length SIZE and return the tag
|
||||||
|
Loading…
x
Reference in New Issue
Block a user