mirror of
git://git.gnupg.org/gnupg.git
synced 2025-07-03 22:56:33 +02:00
* g10.c (main): New commands --card-edit, --card-status and
--change-pin. New options --ctapi-driver, --pcsc-driver and --disable-ccid * options.h (DBG_CARD_IO): New. * cardglue.c, cardclue.h: Enhanced. * card-util.c: New. Taken from current the gnupg 1.9 branch. * app-common.h, app-openpgp.c, iso7816.c, iso7816.h, apdu.c * apdu.h, ccid-driver.c, ccid-driver.h: New. Takem from the current gnupg 1.9 branch withy minor changes to include directives. * Makefile.am: Added these files.
This commit is contained in:
parent
20ed53942a
commit
e369270a65
15 changed files with 5576 additions and 2 deletions
433
g10/cardglue.c
433
g10/cardglue.c
|
@ -30,6 +30,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "options.h"
|
||||
|
@ -42,6 +43,17 @@
|
|||
#include "i18n.h"
|
||||
|
||||
#include "cardglue.h"
|
||||
#include "apdu.h"
|
||||
#include "app-common.h"
|
||||
|
||||
struct ctrl_ctx_s {
|
||||
int (*status_cb)(void *opaque, const char *line);
|
||||
void *status_cb_arg;
|
||||
};
|
||||
|
||||
|
||||
static char *default_reader_port;
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -70,12 +82,433 @@ serialno_and_fpr_from_sk (const unsigned char *sn, size_t snlen,
|
|||
}
|
||||
|
||||
|
||||
/* Send a line with status information via assuan and escape all given
|
||||
buffers. The variable elements are pairs of (char *, size_t),
|
||||
terminated with a (NULL, 0). */
|
||||
void
|
||||
send_status_info (CTRL ctrl, const char *keyword, ...)
|
||||
{
|
||||
va_list arg_ptr;
|
||||
const unsigned char *value;
|
||||
size_t valuelen;
|
||||
char buf[950], *p;
|
||||
size_t n;
|
||||
|
||||
va_start (arg_ptr, keyword);
|
||||
|
||||
p = buf;
|
||||
n = 0;
|
||||
valuelen = strlen (keyword);
|
||||
for ( ; valuelen && n < DIM (buf)-2; n++, valuelen--, keyword++)
|
||||
*p++ = *keyword;
|
||||
|
||||
while ( (value = va_arg (arg_ptr, const unsigned char *)) )
|
||||
{
|
||||
valuelen = va_arg (arg_ptr, size_t);
|
||||
if (!valuelen)
|
||||
continue; /* empty buffer */
|
||||
if (n)
|
||||
{
|
||||
*p++ = ' ';
|
||||
n++;
|
||||
}
|
||||
for ( ; valuelen && n < DIM (buf)-2; n++, valuelen--, value++)
|
||||
{
|
||||
if (*value < ' ' || *value == '+')
|
||||
{
|
||||
sprintf (p, "%%%02X", *value);
|
||||
p += 3;
|
||||
}
|
||||
else if (*value == ' ')
|
||||
*p++ = '+';
|
||||
else
|
||||
*p++ = *value;
|
||||
}
|
||||
}
|
||||
*p = 0;
|
||||
ctrl->status_cb (ctrl->status_cb_arg, buf);
|
||||
|
||||
va_end (arg_ptr);
|
||||
}
|
||||
|
||||
|
||||
void gcry_md_hash_buffer (int algo, void *digest,
|
||||
const void *buffer, size_t length)
|
||||
{
|
||||
MD_HANDLE h = md_open (algo, 0);
|
||||
if (!h)
|
||||
BUG();
|
||||
md_write (h, (byte *) buffer, length);
|
||||
md_final (h);
|
||||
memcpy (digest, md_read (h, algo), md_digest_length (algo));
|
||||
md_close (h);
|
||||
}
|
||||
|
||||
|
||||
/* This is a limited version of the one in 1.9 but it should be
|
||||
sufficient here. */
|
||||
void
|
||||
log_printf (const char *fmt, ...)
|
||||
{
|
||||
va_list arg_ptr;
|
||||
|
||||
va_start (arg_ptr, fmt);
|
||||
vfprintf (log_stream (), fmt, arg_ptr);
|
||||
va_end (arg_ptr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Print a hexdump of BUFFER. With TEXT of NULL print just the raw
|
||||
dump, with TEXT just an empty string, print a trailing linefeed,
|
||||
otherwise print an entire debug line. */
|
||||
void
|
||||
log_printhex (const char *text, const void *buffer, size_t length)
|
||||
{
|
||||
if (text && *text)
|
||||
log_debug ("%s ", text);
|
||||
if (length)
|
||||
{
|
||||
const unsigned char *p = buffer;
|
||||
log_printf ("%02X", *p);
|
||||
for (length--, p++; length--; p++)
|
||||
log_printf (" %02X", *p);
|
||||
}
|
||||
if (text)
|
||||
log_printf ("\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
app_set_default_reader_port (const char *portstr)
|
||||
{
|
||||
xfree (default_reader_port);
|
||||
default_reader_port = portstr? xstrdup (portstr): NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Retrieve the serial number and the time of the last update of the
|
||||
card. The serial number is returned as a malloced string (hex
|
||||
encoded) in SERIAL and the time of update is returned in STAMP. If
|
||||
no update time is available the returned value is 0. Caller must
|
||||
free SERIAL unless the function returns an error. */
|
||||
int
|
||||
app_get_serial_and_stamp (APP app, char **serial, time_t *stamp)
|
||||
{
|
||||
unsigned char *buf, *p;
|
||||
int i;
|
||||
|
||||
if (!app || !serial || !stamp)
|
||||
return gpg_error (GPG_ERR_INV_VALUE);
|
||||
|
||||
*serial = NULL;
|
||||
*stamp = 0; /* not available */
|
||||
|
||||
buf = xtrymalloc (app->serialnolen * 2 + 1);
|
||||
if (!buf)
|
||||
return gpg_error_from_errno (errno);
|
||||
for (p=buf, i=0; i < app->serialnolen; p +=2, i++)
|
||||
sprintf (p, "%02X", app->serialno[i]);
|
||||
*p = 0;
|
||||
*serial = buf;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* Release the card info structure. */
|
||||
void
|
||||
agent_release_card_info (struct agent_card_info_s *info)
|
||||
{
|
||||
if (!info)
|
||||
return;
|
||||
|
||||
xfree (info->serialno); info->serialno = NULL;
|
||||
xfree (info->disp_name); info->disp_name = NULL;
|
||||
xfree (info->disp_lang); info->disp_lang = NULL;
|
||||
xfree (info->pubkey_url); info->pubkey_url = NULL;
|
||||
xfree (info->login_data); info->login_data = NULL;
|
||||
info->fpr1valid = info->fpr2valid = info->fpr3valid = 0;
|
||||
}
|
||||
|
||||
|
||||
/* Open the current card and select the openpgp application. Return
|
||||
an APP context handle to be used for further procesing or NULL on
|
||||
error or if no OpenPGP application exists.*/
|
||||
static APP
|
||||
open_card (void)
|
||||
{
|
||||
int slot;
|
||||
int rc;
|
||||
APP app;
|
||||
|
||||
slot = apdu_open_reader (default_reader_port);
|
||||
if (slot == -1)
|
||||
{
|
||||
log_error ("card reader not available\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
app = xcalloc (1, sizeof *app);
|
||||
app->slot = slot;
|
||||
rc = app_select_openpgp (app, &app->serialno, &app->serialnolen);
|
||||
if (rc)
|
||||
{
|
||||
/* apdu_close_reader (slot); */
|
||||
log_info ("selecting openpgp failed: %s\n", gpg_strerror (rc));
|
||||
xfree (app);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
app->initialized = 1;
|
||||
return app;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Return a new malloced string by unescaping the string S. Escaping
|
||||
is percent escaping and '+'/space mapping. A binary nul will
|
||||
silently be replaced by a 0xFF. Function returns NULL to indicate
|
||||
an out of memory status. */
|
||||
static char *
|
||||
unescape_status_string (const unsigned char *s)
|
||||
{
|
||||
char *buffer, *d;
|
||||
|
||||
buffer = d = xmalloc (strlen (s)+1);
|
||||
while (*s)
|
||||
{
|
||||
if (*s == '%' && s[1] && s[2])
|
||||
{
|
||||
s++;
|
||||
*d = xtoi_2 (s);
|
||||
if (!*d)
|
||||
*d = '\xff';
|
||||
d++;
|
||||
s += 2;
|
||||
}
|
||||
else if (*s == '+')
|
||||
{
|
||||
*d++ = ' ';
|
||||
s++;
|
||||
}
|
||||
else
|
||||
*d++ = *s++;
|
||||
}
|
||||
*d = 0;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/* Take a 20 byte hexencoded string and put it into the the provided
|
||||
20 byte buffer FPR in binary format. */
|
||||
static int
|
||||
unhexify_fpr (const char *hexstr, unsigned char *fpr)
|
||||
{
|
||||
const char *s;
|
||||
int n;
|
||||
|
||||
for (s=hexstr, n=0; hexdigitp (s); s++, n++)
|
||||
;
|
||||
if (*s || (n != 40))
|
||||
return 0; /* no fingerprint (invalid or wrong length). */
|
||||
n /= 2;
|
||||
for (s=hexstr, n=0; *s; s += 2, n++)
|
||||
fpr[n] = xtoi_2 (s);
|
||||
return 1; /* okay */
|
||||
}
|
||||
|
||||
/* Take the serial number from LINE and return it verbatim in a newly
|
||||
allocated string. We make sure that only hex characters are
|
||||
returned. */
|
||||
static char *
|
||||
store_serialno (const char *line)
|
||||
{
|
||||
const char *s;
|
||||
char *p;
|
||||
|
||||
for (s=line; hexdigitp (s); s++)
|
||||
;
|
||||
p = xmalloc (s + 1 - line);
|
||||
memcpy (p, line, s-line);
|
||||
p[s-line] = 0;
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int
|
||||
learn_status_cb (void *opaque, const char *line)
|
||||
{
|
||||
struct agent_card_info_s *parm = opaque;
|
||||
const char *keyword = line;
|
||||
int keywordlen;
|
||||
int i;
|
||||
|
||||
for (keywordlen=0; *line && !spacep (line); line++, keywordlen++)
|
||||
;
|
||||
while (spacep (line))
|
||||
line++;
|
||||
|
||||
if (keywordlen == 8 && !memcmp (keyword, "SERIALNO", keywordlen))
|
||||
{
|
||||
parm->serialno = store_serialno (line);
|
||||
}
|
||||
else if (keywordlen == 9 && !memcmp (keyword, "DISP-NAME", keywordlen))
|
||||
{
|
||||
parm->disp_name = unescape_status_string (line);
|
||||
}
|
||||
else if (keywordlen == 9 && !memcmp (keyword, "DISP-LANG", keywordlen))
|
||||
{
|
||||
parm->disp_lang = unescape_status_string (line);
|
||||
}
|
||||
else if (keywordlen == 8 && !memcmp (keyword, "DISP-SEX", keywordlen))
|
||||
{
|
||||
parm->disp_sex = *line == '1'? 1 : *line == '2' ? 2: 0;
|
||||
}
|
||||
else if (keywordlen == 10 && !memcmp (keyword, "PUBKEY-URL", keywordlen))
|
||||
{
|
||||
parm->pubkey_url = unescape_status_string (line);
|
||||
}
|
||||
else if (keywordlen == 10 && !memcmp (keyword, "LOGIN-DATA", keywordlen))
|
||||
{
|
||||
parm->login_data = unescape_status_string (line);
|
||||
}
|
||||
else if (keywordlen == 11 && !memcmp (keyword, "SIG-COUNTER", keywordlen))
|
||||
{
|
||||
parm->sig_counter = strtoul (line, NULL, 0);
|
||||
}
|
||||
else if (keywordlen == 10 && !memcmp (keyword, "CHV-STATUS", keywordlen))
|
||||
{
|
||||
char *p, *buf;
|
||||
|
||||
buf = p = unescape_status_string (line);
|
||||
if (buf)
|
||||
{
|
||||
while (spacep (p))
|
||||
p++;
|
||||
parm->chv1_cached = atoi (p);
|
||||
while (!spacep (p))
|
||||
p++;
|
||||
while (spacep (p))
|
||||
p++;
|
||||
for (i=0; *p && i < 3; i++)
|
||||
{
|
||||
parm->chvmaxlen[i] = atoi (p);
|
||||
while (!spacep (p))
|
||||
p++;
|
||||
while (spacep (p))
|
||||
p++;
|
||||
}
|
||||
for (i=0; *p && i < 3; i++)
|
||||
{
|
||||
parm->chvretry[i] = atoi (p);
|
||||
while (!spacep (p))
|
||||
p++;
|
||||
while (spacep (p))
|
||||
p++;
|
||||
}
|
||||
xfree (buf);
|
||||
}
|
||||
}
|
||||
else if (keywordlen == 7 && !memcmp (keyword, "KEY-FPR", keywordlen))
|
||||
{
|
||||
int no = atoi (line);
|
||||
while (!spacep (line))
|
||||
line++;
|
||||
while (spacep (line))
|
||||
line++;
|
||||
if (no == 1)
|
||||
parm->fpr1valid = unhexify_fpr (line, parm->fpr1);
|
||||
else if (no == 2)
|
||||
parm->fpr2valid = unhexify_fpr (line, parm->fpr2);
|
||||
else if (no == 3)
|
||||
parm->fpr3valid = unhexify_fpr (line, parm->fpr3);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Return card info. */
|
||||
int
|
||||
agent_learn (struct agent_card_info_s *info)
|
||||
{
|
||||
APP app;
|
||||
int rc;
|
||||
struct ctrl_ctx_s ctrl;
|
||||
time_t stamp;
|
||||
char *serial;
|
||||
|
||||
app = open_card ();
|
||||
if (!app)
|
||||
return gpg_error (GPG_ERR_CARD);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* Send a SETATTR command to the SCdaemon. */
|
||||
int
|
||||
agent_scd_setattr (const char *name,
|
||||
const unsigned char *value, size_t valuelen)
|
||||
{
|
||||
|
||||
return gpg_error (GPG_ERR_CARD);
|
||||
}
|
||||
|
||||
/* Send a GENKEY command to the SCdaemon. */
|
||||
int
|
||||
agent_scd_genkey (struct agent_card_genkey_s *info, int keyno, int force)
|
||||
{
|
||||
|
||||
return gpg_error (GPG_ERR_CARD);
|
||||
}
|
||||
|
||||
/* Send a PKSIGN command to the SCdaemon. */
|
||||
int
|
||||
agent_scd_pksign (const char *keyid, int hashalgo,
|
||||
const unsigned char *indata, size_t indatalen,
|
||||
char **r_buf, size_t *r_buflen)
|
||||
{
|
||||
|
||||
return gpg_error (GPG_ERR_CARD);
|
||||
}
|
||||
|
||||
|
||||
/* Send a PKDECRYPT command to the SCdaemon. */
|
||||
int
|
||||
agent_scd_pkdecrypt (const char *serialno,
|
||||
const unsigned char *indata, size_t indatalen,
|
||||
char **r_buf, size_t *r_buflen)
|
||||
{
|
||||
|
||||
return gpg_error (GPG_ERR_CARD);
|
||||
}
|
||||
|
||||
/* Change the PIN of an OpenPGP card or reset the retry counter. */
|
||||
int
|
||||
agent_scd_change_pin (int chvno)
|
||||
{
|
||||
|
||||
return gpg_error (GPG_ERR_CARD);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#endif /*ENABLE_CARD_SUPPORT*/
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue