2003-09-27 19:37:53 +00:00
|
|
|
|
/* cardglue.c - mainly dispatcher for card related functions.
|
2005-03-07 13:59:59 +00:00
|
|
|
|
* Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
|
2003-09-27 19:37:53 +00:00
|
|
|
|
*
|
|
|
|
|
* This file is part of GnuPG.
|
|
|
|
|
*
|
|
|
|
|
* GnuPG is free software; you can redistribute it and/or modify
|
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
|
* (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* GnuPG is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with this program; if not, write to the Free Software
|
2005-05-31 08:39:18 +00:00
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
|
|
|
|
* USA.
|
2003-09-27 19:37:53 +00:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <config.h>
|
2003-10-02 10:20:12 +00:00
|
|
|
|
#ifndef ENABLE_CARD_SUPPORT
|
2003-10-29 10:07:44 +00:00
|
|
|
|
#error not configured for card support.
|
2003-10-02 10:20:12 +00:00
|
|
|
|
#endif
|
2003-09-27 19:37:53 +00:00
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <errno.h>
|
2003-09-28 13:41:58 +00:00
|
|
|
|
#include <stdarg.h>
|
2003-09-27 19:37:53 +00:00
|
|
|
|
#include <assert.h>
|
|
|
|
|
|
|
|
|
|
#include "options.h"
|
|
|
|
|
#include "packet.h"
|
|
|
|
|
#include "errors.h"
|
|
|
|
|
#include "memory.h"
|
|
|
|
|
#include "util.h"
|
|
|
|
|
#include "main.h"
|
|
|
|
|
#include "status.h"
|
2003-10-29 10:07:44 +00:00
|
|
|
|
#include "ttyio.h"
|
2003-09-27 19:37:53 +00:00
|
|
|
|
#include "i18n.h"
|
|
|
|
|
|
|
|
|
|
#include "cardglue.h"
|
2003-09-28 13:41:58 +00:00
|
|
|
|
#include "apdu.h"
|
|
|
|
|
#include "app-common.h"
|
|
|
|
|
|
2005-05-20 20:37:08 +00:00
|
|
|
|
|
|
|
|
|
|
2005-05-03 22:27:07 +00:00
|
|
|
|
struct ctrl_ctx_s
|
|
|
|
|
{
|
2005-05-20 20:37:08 +00:00
|
|
|
|
assuan_error_t (*status_cb)(void *opaque, const char *line);
|
2003-09-28 13:41:58 +00:00
|
|
|
|
void *status_cb_arg;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2005-05-03 22:27:07 +00:00
|
|
|
|
struct pincb_parm_s
|
|
|
|
|
{
|
|
|
|
|
const char *sn;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2005-05-21 14:04:32 +00:00
|
|
|
|
struct writekey_parm_s
|
|
|
|
|
{
|
|
|
|
|
assuan_context_t ctx;
|
|
|
|
|
const unsigned char *keydata;
|
|
|
|
|
size_t keydatalen;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-09-28 13:41:58 +00:00
|
|
|
|
static char *default_reader_port;
|
2005-05-20 20:37:08 +00:00
|
|
|
|
static app_t current_app;
|
2003-09-27 19:37:53 +00:00
|
|
|
|
|
|
|
|
|
|
2005-05-20 20:37:08 +00:00
|
|
|
|
/* Local prototypes. */
|
|
|
|
|
static assuan_error_t learn_status_cb (void *opaque, const char *line);
|
2003-09-27 19:37:53 +00:00
|
|
|
|
|
2005-05-20 20:37:08 +00:00
|
|
|
|
|
2005-05-31 10:11:01 +00:00
|
|
|
|
/* To avoid cluttering the code with bunches of ifdefs we use a few
|
|
|
|
|
dummy functions instead and defines. */
|
|
|
|
|
#ifndef ENABLE_AGENT_SUPPORT
|
|
|
|
|
|
|
|
|
|
#define ASSUAN_LINELENGTH 100
|
|
|
|
|
|
|
|
|
|
static assuan_context_t
|
2005-07-26 19:08:11 +00:00
|
|
|
|
agent_open (int try, const char *orig_codeset)
|
2005-05-31 10:11:01 +00:00
|
|
|
|
{
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
agent_close (assuan_context_t ctx)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char *
|
|
|
|
|
assuan_strerror (assuan_error_t err)
|
|
|
|
|
{
|
|
|
|
|
return "no Assuan support";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assuan_error_t
|
|
|
|
|
assuan_transact (assuan_context_t ctx,
|
|
|
|
|
const char *command,
|
|
|
|
|
assuan_error_t (*data_cb)(void *, const void *, size_t),
|
|
|
|
|
void *data_cb_arg,
|
|
|
|
|
assuan_error_t (*inquire_cb)(void*, const char *),
|
|
|
|
|
void *inquire_cb_arg,
|
|
|
|
|
assuan_error_t (*status_cb)(void*, const char *),
|
|
|
|
|
void *status_cb_arg)
|
|
|
|
|
{
|
|
|
|
|
return 100; /* ASSUAN_NOT_IMPLEMENTED */
|
|
|
|
|
}
|
|
|
|
|
assuan_error_t
|
|
|
|
|
assuan_send_data (assuan_context_t ctx, const void *buffer, size_t length)
|
|
|
|
|
{
|
|
|
|
|
return 100; /* ASSUAN_NOT_IMPLEMENTED */
|
|
|
|
|
}
|
|
|
|
|
#endif /*!ENABLE_AGENT_SUPPORT*/
|
|
|
|
|
|
2005-05-20 20:37:08 +00:00
|
|
|
|
|
2003-09-27 19:37:53 +00:00
|
|
|
|
/* Create a serialno/fpr string from the serial number and the secret
|
|
|
|
|
key. caller must free the returned string. There is no error
|
|
|
|
|
return. [Taken from 1.9's keyid.c]*/
|
|
|
|
|
char *
|
|
|
|
|
serialno_and_fpr_from_sk (const unsigned char *sn, size_t snlen,
|
|
|
|
|
PKT_secret_key *sk)
|
|
|
|
|
{
|
|
|
|
|
unsigned char fpr[MAX_FINGERPRINT_LEN];
|
|
|
|
|
size_t fprlen;
|
|
|
|
|
char *buffer, *p;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
fingerprint_from_sk (sk, fpr, &fprlen);
|
|
|
|
|
buffer = p = xmalloc (snlen*2 + 1 + fprlen*2 + 1);
|
|
|
|
|
for (i=0; i < snlen; i++, p+=2)
|
|
|
|
|
sprintf (p, "%02X", sn[i]);
|
|
|
|
|
*p++ = '/';
|
|
|
|
|
for (i=0; i < fprlen; i++, p+=2)
|
|
|
|
|
sprintf (p, "%02X", fpr[i]);
|
|
|
|
|
*p = 0;
|
|
|
|
|
return buffer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2003-09-28 13:41:58 +00:00
|
|
|
|
/* 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
|
2005-05-21 14:04:32 +00:00
|
|
|
|
send_status_info (ctrl_t ctrl, const char *keyword, ...)
|
2003-09-28 13:41:58 +00:00
|
|
|
|
{
|
|
|
|
|
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;
|
2005-05-21 14:04:32 +00:00
|
|
|
|
if (ctrl && ctrl->status_cb)
|
|
|
|
|
ctrl->status_cb (ctrl->status_cb_arg, buf);
|
2003-09-28 13:41:58 +00:00
|
|
|
|
|
|
|
|
|
va_end (arg_ptr);
|
|
|
|
|
}
|
2003-09-27 19:37:53 +00:00
|
|
|
|
|
|
|
|
|
|
2005-05-20 20:37:08 +00:00
|
|
|
|
/* Replacement function of the Libgcrypt onewhich is used in gnupg
|
|
|
|
|
1.9. Thus function computes the digest of ALGO from the data in
|
|
|
|
|
BUFFER of LENGTH. ALGO must be supported. */
|
|
|
|
|
void
|
|
|
|
|
gcry_md_hash_buffer (int algo, void *digest,
|
|
|
|
|
const void *buffer, size_t length)
|
2003-09-28 13:41:58 +00:00
|
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2003-10-08 15:21:20 +00:00
|
|
|
|
void
|
|
|
|
|
card_set_reader_port (const char *portstr)
|
|
|
|
|
{
|
|
|
|
|
app_set_default_reader_port (portstr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2003-09-28 13:41:58 +00:00
|
|
|
|
/* 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
|
2005-05-20 20:37:08 +00:00
|
|
|
|
app_get_serial_and_stamp (app_t app, char **serial, time_t *stamp)
|
2003-09-28 13:41:58 +00:00
|
|
|
|
{
|
|
|
|
|
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)
|
|
|
|
|
{
|
2004-12-09 16:57:30 +00:00
|
|
|
|
int i;
|
|
|
|
|
|
2003-09-28 13:41:58 +00:00
|
|
|
|
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;
|
* README: Doc --disable-card-support and --without-readline.
* configure.ac: Check for readline. Make enable-card-support the
default. New option --without-readline. Allow the use of either
the development or the stable libusb.
* cardglue.h: Add members for CA fingerprints.
* cardglue.c (agent_release_card_info): Invalid them.
(learn_status_cb): Store them.
* app-common.h, app-openpgp.c, iso7816.c, iso7816.h
* apdu.c, apdu.h, ccid-driver.c, ccid-driver.h
* card-util.c: Updated from current gnupg-1.9.
* ccid-driver.h (CCID_DRIVER_ERR_ABORTED): New.
* ccid-driver.c (ccid_open_reader): Support the stable 0.1 version
of libusb.
(ccid_get_atr): Handle short messages.
* apdu.c (my_rapdu_get_status): Implemented.
* apdu.c: Include <signal.h>.
* apdu.c (reader_table_s): Add function pointers for the backends.
(apdu_close_reader, apdu_get_status, apdu_activate)
(send_apdu): Make use of them.
(new_reader_slot): Intialize them to NULL.
(dump_ccid_reader_status, ct_dump_reader_status): New.
(dump_pcsc_reader_status): New.
(open_ct_reader, open_pcsc_reader, open_ccid_reader)
(open_osc_reader, open_rapdu_reader): Intialize function pointers.
(ct_activate_card, ct_send_apdu, pcsc_send_apdu, osc_send_apdu)
(error_string): Removed. Replaced by apdu_strerror.
(get_ccid_error_string): Removed.
(ct_activate_card): Remove the unused loop.
(reset_ct_reader): Implemented.
(ct_send_apdu): Activate the card if not yet done.
(pcsc_send_apdu): Ditto.
* ccid-driver.h: Add error codes.
* ccid-driver.c: Implement more or less proper error codes all
over the place.
* apdu.c (apdu_send_direct): New.
(get_ccid_error_string): Add some error code mappings.
(send_apdu): Pass error codes along for drivers already supporting
them.
(host_sw_string): New.
(get_ccid_error_string): Use above.
(send_apdu_ccid): Reset the reader if it has not yet been done.
(open_ccid_reader): Don't care if the ATR can't be read.
(apdu_activate_card): New.
(apdu_strerror): New.
(dump_reader_status): Only enable it with opt.VERBOSE.
* iso7816.c (map_sw): Add mappings for the new error codes.
* apdu.c (open_ct_reader, open_pcsc_reader, open_ccid_reader)
(reset_ccid_reader, open_osc_reader): Call dump_reader_status only
in verbose mode.
* app-openpgp.c (do_getattr): Fix for sending CA-FPR.
* app-openpgp.c (app_openpgp_readkey): Fixed check for valid
exponent.
* app-openpgp.c (do_setattr): Sync FORCE_CHV1.
* card-util.c (change_login): Kludge to allow reading data from a
file.
(card_edit): Pass ARG_STRING to change_login.
(card_status): Print CA fingerprints.
(change_cafpr): New.
(card_edit): New command CAFPR.
* errors.h (G10ERR_NO_CARD, G10ERR_CANCELED): New error codes.
* errors.c (g10_errstr): New error codes G10ERR_NO_CARD,
G10ERR_CANCELED.
2004-09-09 18:18:36 +00:00
|
|
|
|
info->cafpr1valid = info->cafpr2valid = info->cafpr3valid = 0;
|
2004-12-09 16:57:30 +00:00
|
|
|
|
for (i=0; i < 4; i++)
|
|
|
|
|
{
|
|
|
|
|
xfree (info->private_do[i]);
|
|
|
|
|
info->private_do[i] = NULL;
|
|
|
|
|
}
|
2003-09-28 13:41:58 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2005-05-31 10:11:01 +00:00
|
|
|
|
/* Print an error message for a failed assuan_transact and return a
|
2005-05-20 20:37:08 +00:00
|
|
|
|
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;
|
2005-07-26 19:08:11 +00:00
|
|
|
|
ctx = agent_open (1, NULL);
|
2005-05-20 20:37:08 +00:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-09-28 13:41:58 +00:00
|
|
|
|
/* 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.*/
|
2005-05-20 20:37:08 +00:00
|
|
|
|
static app_t
|
2003-09-28 13:41:58 +00:00
|
|
|
|
open_card (void)
|
|
|
|
|
{
|
2004-09-20 13:15:37 +00:00
|
|
|
|
int slot = -1;
|
2003-09-28 13:41:58 +00:00
|
|
|
|
int rc;
|
2005-05-20 20:37:08 +00:00
|
|
|
|
app_t app;
|
2004-09-20 13:15:37 +00:00
|
|
|
|
int did_shutdown = 0;
|
2005-07-19 12:14:39 +00:00
|
|
|
|
int retry_count = 0;
|
2005-05-20 20:37:08 +00:00
|
|
|
|
|
|
|
|
|
/* 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. */
|
2005-05-23 14:38:05 +00:00
|
|
|
|
if (opt.use_agent)
|
|
|
|
|
{
|
|
|
|
|
int scd_available;
|
|
|
|
|
|
|
|
|
|
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. */
|
|
|
|
|
}
|
2003-09-28 13:41:58 +00:00
|
|
|
|
|
2003-10-29 10:07:44 +00:00
|
|
|
|
|
2005-05-20 20:37:08 +00:00
|
|
|
|
/* No agent or usable agent, thus we do it on our own. */
|
|
|
|
|
card_close ();
|
2004-09-20 13:15:37 +00:00
|
|
|
|
|
2003-10-29 10:07:44 +00:00
|
|
|
|
retry:
|
2004-09-20 13:15:37 +00:00
|
|
|
|
if (did_shutdown)
|
|
|
|
|
apdu_reset (slot);
|
|
|
|
|
else
|
2003-09-28 13:41:58 +00:00
|
|
|
|
{
|
2004-09-20 13:15:37 +00:00
|
|
|
|
slot = apdu_open_reader (default_reader_port);
|
|
|
|
|
if (slot == -1)
|
|
|
|
|
{
|
2005-06-18 11:49:50 +00:00
|
|
|
|
write_status_text (STATUS_CARDCTRL, "5");
|
2004-09-20 13:15:37 +00:00
|
|
|
|
log_error ("card reader not available\n");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2003-09-28 13:41:58 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
app = xcalloc (1, sizeof *app);
|
|
|
|
|
app->slot = slot;
|
2004-04-27 08:23:45 +00:00
|
|
|
|
rc = app_select_openpgp (app);
|
2005-07-19 12:14:39 +00:00
|
|
|
|
if (opt.limit_card_insert_tries
|
|
|
|
|
&& ++retry_count >= opt.limit_card_insert_tries)
|
|
|
|
|
;
|
|
|
|
|
else if (rc && !opt.batch)
|
2003-10-29 10:07:44 +00:00
|
|
|
|
{
|
|
|
|
|
write_status_text (STATUS_CARDCTRL, "1");
|
|
|
|
|
|
2004-09-20 13:15:37 +00:00
|
|
|
|
did_shutdown = !!apdu_shutdown_reader (slot);
|
|
|
|
|
|
2003-10-29 10:07:44 +00:00
|
|
|
|
if ( cpr_get_answer_okay_cancel ("cardctrl.insert_card.okay",
|
|
|
|
|
_("Please insert the card and hit return or enter 'c' to cancel: "),
|
|
|
|
|
1) )
|
|
|
|
|
{
|
2004-09-20 13:15:37 +00:00
|
|
|
|
if (!did_shutdown)
|
|
|
|
|
apdu_close_reader (slot);
|
2003-10-29 10:07:44 +00:00
|
|
|
|
xfree (app);
|
|
|
|
|
goto retry;
|
|
|
|
|
}
|
|
|
|
|
}
|
2003-09-28 13:41:58 +00:00
|
|
|
|
if (rc)
|
|
|
|
|
{
|
2005-01-20 18:25:25 +00:00
|
|
|
|
write_status_text (STATUS_CARDCTRL, "4");
|
2003-09-28 13:41:58 +00:00
|
|
|
|
log_info ("selecting openpgp failed: %s\n", gpg_strerror (rc));
|
2003-10-29 10:07:44 +00:00
|
|
|
|
apdu_close_reader (slot);
|
2003-09-28 13:41:58 +00:00
|
|
|
|
xfree (app);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2005-05-20 20:37:08 +00:00
|
|
|
|
ready:
|
2003-09-28 13:41:58 +00:00
|
|
|
|
app->initialized = 1;
|
2003-09-30 08:00:08 +00:00
|
|
|
|
current_app = app;
|
2003-10-29 10:07:44 +00:00
|
|
|
|
if (is_status_enabled () )
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
char *p, *buf;
|
|
|
|
|
|
|
|
|
|
buf = xmalloc (5 + app->serialnolen * 2 + 1);
|
|
|
|
|
p = stpcpy (buf, "3 ");
|
|
|
|
|
for (i=0; i < app->serialnolen; p +=2, i++)
|
|
|
|
|
sprintf (p, "%02X", app->serialno[i]);
|
|
|
|
|
write_status_text (STATUS_CARDCTRL, buf);
|
|
|
|
|
xfree (buf);
|
|
|
|
|
}
|
|
|
|
|
|
2003-09-28 13:41:58 +00:00
|
|
|
|
return app;
|
|
|
|
|
}
|
2003-09-27 19:37:53 +00:00
|
|
|
|
|
2005-05-20 20:37:08 +00:00
|
|
|
|
|
2003-10-10 15:12:02 +00:00
|
|
|
|
void
|
|
|
|
|
card_close (void)
|
|
|
|
|
{
|
|
|
|
|
if (current_app)
|
|
|
|
|
{
|
2005-05-20 20:37:08 +00:00
|
|
|
|
app_t app = current_app;
|
2003-10-10 15:12:02 +00:00
|
|
|
|
current_app = NULL;
|
|
|
|
|
|
2005-05-20 20:37:08 +00:00
|
|
|
|
if (app->assuan_ctx)
|
|
|
|
|
agent_close (app->assuan_ctx);
|
|
|
|
|
else
|
|
|
|
|
apdu_close_reader (app->slot);
|
2003-10-10 15:12:02 +00:00
|
|
|
|
xfree (app);
|
|
|
|
|
}
|
|
|
|
|
}
|
2003-09-27 19:37:53 +00:00
|
|
|
|
|
|
|
|
|
|
2005-05-03 22:27:07 +00:00
|
|
|
|
/* Format a cache ID from the serialnumber in SN and return it as an
|
|
|
|
|
allocated string. In case of an error NULL is returned. */
|
|
|
|
|
static char *
|
|
|
|
|
format_cacheid (const char *sn)
|
|
|
|
|
{
|
|
|
|
|
const char *s;
|
|
|
|
|
size_t snlen;
|
|
|
|
|
char *cacheid = NULL;
|
|
|
|
|
|
|
|
|
|
/* The serialnumber we use for a card is "CARDSN:serialno". Where
|
|
|
|
|
serialno is the BCD string (i.e. hex string) with the full
|
|
|
|
|
number. The serial number expect here constsis of hexdigits
|
|
|
|
|
followed by other characters, we cut off these other
|
|
|
|
|
characters. */
|
|
|
|
|
if (sn)
|
|
|
|
|
{
|
|
|
|
|
for (s=sn,snlen=0; hexdigitp (s); s++, snlen++)
|
|
|
|
|
;
|
|
|
|
|
if (snlen == 32)
|
|
|
|
|
{
|
|
|
|
|
/* Yes, this looks indeed like an OpenPGP card S/N. */
|
|
|
|
|
cacheid = xtrymalloc (7+snlen+1);
|
|
|
|
|
if (cacheid)
|
|
|
|
|
{
|
|
|
|
|
memcpy (cacheid, "CARDSN:", 7);
|
|
|
|
|
memcpy (cacheid+7, sn, snlen);
|
|
|
|
|
cacheid[7+snlen] = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return cacheid;
|
|
|
|
|
}
|
|
|
|
|
|
2005-10-18 17:41:20 +00:00
|
|
|
|
|
|
|
|
|
/* If RC is not 0, write an appropriate status message. */
|
|
|
|
|
static void
|
|
|
|
|
status_sc_op_failure (int rc)
|
|
|
|
|
{
|
|
|
|
|
if (rc == G10ERR_CANCELED)
|
|
|
|
|
write_status_text (STATUS_SC_OP_FAILURE, "1");
|
|
|
|
|
else if (rc == G10ERR_BAD_PASS)
|
|
|
|
|
write_status_text (STATUS_SC_OP_FAILURE, "2");
|
|
|
|
|
else if (rc)
|
|
|
|
|
write_status (STATUS_SC_OP_FAILURE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2003-10-29 10:07:44 +00:00
|
|
|
|
/* Check that the serial number of the current card (as described by
|
|
|
|
|
APP) matches SERIALNO. If there is no match and we are not in
|
|
|
|
|
batch mode, present a prompt to insert the desired card. The
|
|
|
|
|
function return 0 is the present card is okay, -1 if the user
|
|
|
|
|
selected to insert a new card or an error value. Note that the
|
|
|
|
|
card context will be closed in all cases except for 0 as return
|
2004-09-20 13:15:37 +00:00
|
|
|
|
value and if it was possible to merely shutdown the reader. */
|
2003-10-29 10:07:44 +00:00
|
|
|
|
static int
|
2005-05-20 20:37:08 +00:00
|
|
|
|
check_card_serialno (app_t app, const char *serialno)
|
2003-10-29 10:07:44 +00:00
|
|
|
|
{
|
|
|
|
|
const char *s;
|
|
|
|
|
int ask = 0;
|
|
|
|
|
int n;
|
2005-08-04 09:53:21 +00:00
|
|
|
|
|
2003-10-29 10:07:44 +00:00
|
|
|
|
for (s = serialno, n=0; *s != '/' && hexdigitp (s); s++, n++)
|
|
|
|
|
;
|
|
|
|
|
if (n != 32)
|
|
|
|
|
{
|
|
|
|
|
log_error ("invalid serial number in keyring detected\n");
|
|
|
|
|
return gpg_error (GPG_ERR_INV_ID);
|
|
|
|
|
}
|
|
|
|
|
if (app->serialnolen != 16)
|
|
|
|
|
ask = 1;
|
|
|
|
|
for (s = serialno, n=0; !ask && n < 16; s += 2, n++)
|
|
|
|
|
if (app->serialno[n] != xtoi_2 (s))
|
|
|
|
|
ask = 1;
|
|
|
|
|
if (ask)
|
|
|
|
|
{
|
|
|
|
|
char buf[5+32+1];
|
2004-09-20 13:15:37 +00:00
|
|
|
|
int did_shutdown = 0;
|
2003-10-29 10:07:44 +00:00
|
|
|
|
|
2004-09-20 13:15:37 +00:00
|
|
|
|
if (current_app && !apdu_shutdown_reader (current_app->slot))
|
|
|
|
|
did_shutdown = 1;
|
|
|
|
|
else
|
|
|
|
|
card_close ();
|
2003-10-29 10:07:44 +00:00
|
|
|
|
tty_printf (_("Please remove the current card and "
|
* main.h: Create S2K_DIGEST_ALGO macro so we do not need to always set
opt.s2k_digest_algo. This helps fix a problem with PGP 2.x encrypted
symmetric messages. Change all callers (encode.c, g10.c, keyedit.c,
keygen.c, passphrase.c, sign.c).
* armor.c, cardglue.c, getkey.c, import.c, keygen.c: Be consistent in some
more quoted strings. Always use 'user ID', not 'user id', "quotes" for
user IDs, etc.
2004-09-24 20:34:38 +00:00
|
|
|
|
"insert the one with serial number:\n"
|
2003-10-29 10:07:44 +00:00
|
|
|
|
" %.*s\n"), 32, serialno);
|
|
|
|
|
|
|
|
|
|
sprintf (buf, "1 %.32s", serialno);
|
|
|
|
|
write_status_text (STATUS_CARDCTRL, buf);
|
|
|
|
|
|
|
|
|
|
if ( cpr_get_answer_okay_cancel ("cardctrl.change_card.okay",
|
|
|
|
|
_("Hit return when ready "
|
|
|
|
|
"or enter 'c' to cancel: "),
|
|
|
|
|
1) )
|
2004-09-20 13:15:37 +00:00
|
|
|
|
{
|
|
|
|
|
card_close ();
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
if (did_shutdown)
|
|
|
|
|
apdu_reset (current_app->slot);
|
|
|
|
|
else
|
|
|
|
|
card_close ();
|
2003-10-29 10:07:44 +00:00
|
|
|
|
return gpg_error (GPG_ERR_INV_ID);
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2003-09-28 13:41:58 +00:00
|
|
|
|
/* 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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2005-05-20 20:37:08 +00:00
|
|
|
|
static assuan_error_t
|
2003-09-28 13:41:58 +00:00
|
|
|
|
learn_status_cb (void *opaque, const char *line)
|
|
|
|
|
{
|
|
|
|
|
struct agent_card_info_s *parm = opaque;
|
|
|
|
|
const char *keyword = line;
|
|
|
|
|
int keywordlen;
|
|
|
|
|
int i;
|
|
|
|
|
|
2004-12-09 16:57:30 +00:00
|
|
|
|
/* log_debug ("got status line `%s'\n", line); */
|
2003-09-28 13:41:58 +00:00
|
|
|
|
for (keywordlen=0; *line && !spacep (line); line++, keywordlen++)
|
|
|
|
|
;
|
|
|
|
|
while (spacep (line))
|
|
|
|
|
line++;
|
|
|
|
|
|
|
|
|
|
if (keywordlen == 8 && !memcmp (keyword, "SERIALNO", keywordlen))
|
|
|
|
|
{
|
2003-10-02 10:20:12 +00:00
|
|
|
|
xfree (parm->serialno);
|
2003-09-28 13:41:58 +00:00
|
|
|
|
parm->serialno = store_serialno (line);
|
|
|
|
|
}
|
|
|
|
|
else if (keywordlen == 9 && !memcmp (keyword, "DISP-NAME", keywordlen))
|
|
|
|
|
{
|
2003-10-02 10:20:12 +00:00
|
|
|
|
xfree (parm->disp_name);
|
2005-05-24 12:39:42 +00:00
|
|
|
|
parm->disp_name = unescape_percent_string (line);
|
2003-09-28 13:41:58 +00:00
|
|
|
|
}
|
|
|
|
|
else if (keywordlen == 9 && !memcmp (keyword, "DISP-LANG", keywordlen))
|
|
|
|
|
{
|
2003-10-02 10:20:12 +00:00
|
|
|
|
xfree (parm->disp_lang);
|
2005-05-24 12:39:42 +00:00
|
|
|
|
parm->disp_lang = unescape_percent_string (line);
|
2003-09-28 13:41:58 +00:00
|
|
|
|
}
|
|
|
|
|
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))
|
|
|
|
|
{
|
2003-10-02 10:20:12 +00:00
|
|
|
|
xfree (parm->pubkey_url);
|
2005-05-24 12:39:42 +00:00
|
|
|
|
parm->pubkey_url = unescape_percent_string (line);
|
2003-09-28 13:41:58 +00:00
|
|
|
|
}
|
|
|
|
|
else if (keywordlen == 10 && !memcmp (keyword, "LOGIN-DATA", keywordlen))
|
|
|
|
|
{
|
2003-10-02 10:20:12 +00:00
|
|
|
|
xfree (parm->login_data);
|
2005-05-24 12:39:42 +00:00
|
|
|
|
parm->login_data = unescape_percent_string (line);
|
2003-09-28 13:41:58 +00:00
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
|
2005-05-24 12:39:42 +00:00
|
|
|
|
buf = p = unescape_percent_string (line);
|
2003-09-28 13:41:58 +00:00
|
|
|
|
if (buf)
|
|
|
|
|
{
|
|
|
|
|
while (spacep (p))
|
|
|
|
|
p++;
|
|
|
|
|
parm->chv1_cached = atoi (p);
|
2003-10-25 14:17:24 +00:00
|
|
|
|
while (*p && !spacep (p))
|
2003-09-28 13:41:58 +00:00
|
|
|
|
p++;
|
|
|
|
|
while (spacep (p))
|
|
|
|
|
p++;
|
|
|
|
|
for (i=0; *p && i < 3; i++)
|
|
|
|
|
{
|
|
|
|
|
parm->chvmaxlen[i] = atoi (p);
|
2003-10-25 14:17:24 +00:00
|
|
|
|
while (*p && !spacep (p))
|
2003-09-28 13:41:58 +00:00
|
|
|
|
p++;
|
|
|
|
|
while (spacep (p))
|
|
|
|
|
p++;
|
|
|
|
|
}
|
|
|
|
|
for (i=0; *p && i < 3; i++)
|
|
|
|
|
{
|
|
|
|
|
parm->chvretry[i] = atoi (p);
|
2003-10-25 14:17:24 +00:00
|
|
|
|
while (*p && !spacep (p))
|
2003-09-28 13:41:58 +00:00
|
|
|
|
p++;
|
|
|
|
|
while (spacep (p))
|
|
|
|
|
p++;
|
|
|
|
|
}
|
|
|
|
|
xfree (buf);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (keywordlen == 7 && !memcmp (keyword, "KEY-FPR", keywordlen))
|
|
|
|
|
{
|
|
|
|
|
int no = atoi (line);
|
2003-10-25 14:17:24 +00:00
|
|
|
|
while (* line && !spacep (line))
|
2003-09-28 13:41:58 +00:00
|
|
|
|
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);
|
|
|
|
|
}
|
2004-12-10 10:49:14 +00:00
|
|
|
|
else if (keywordlen == 8 && !memcmp (keyword, "KEY-TIME", keywordlen))
|
|
|
|
|
{
|
|
|
|
|
int no = atoi (line);
|
|
|
|
|
while (* line && !spacep (line))
|
|
|
|
|
line++;
|
|
|
|
|
while (spacep (line))
|
|
|
|
|
line++;
|
|
|
|
|
if (no == 1)
|
|
|
|
|
parm->fpr1time = strtoul (line, NULL, 10);
|
|
|
|
|
else if (no == 2)
|
|
|
|
|
parm->fpr2time = strtoul (line, NULL, 10);
|
|
|
|
|
else if (no == 3)
|
|
|
|
|
parm->fpr3time = strtoul (line, NULL, 10);
|
|
|
|
|
}
|
* README: Doc --disable-card-support and --without-readline.
* configure.ac: Check for readline. Make enable-card-support the
default. New option --without-readline. Allow the use of either
the development or the stable libusb.
* cardglue.h: Add members for CA fingerprints.
* cardglue.c (agent_release_card_info): Invalid them.
(learn_status_cb): Store them.
* app-common.h, app-openpgp.c, iso7816.c, iso7816.h
* apdu.c, apdu.h, ccid-driver.c, ccid-driver.h
* card-util.c: Updated from current gnupg-1.9.
* ccid-driver.h (CCID_DRIVER_ERR_ABORTED): New.
* ccid-driver.c (ccid_open_reader): Support the stable 0.1 version
of libusb.
(ccid_get_atr): Handle short messages.
* apdu.c (my_rapdu_get_status): Implemented.
* apdu.c: Include <signal.h>.
* apdu.c (reader_table_s): Add function pointers for the backends.
(apdu_close_reader, apdu_get_status, apdu_activate)
(send_apdu): Make use of them.
(new_reader_slot): Intialize them to NULL.
(dump_ccid_reader_status, ct_dump_reader_status): New.
(dump_pcsc_reader_status): New.
(open_ct_reader, open_pcsc_reader, open_ccid_reader)
(open_osc_reader, open_rapdu_reader): Intialize function pointers.
(ct_activate_card, ct_send_apdu, pcsc_send_apdu, osc_send_apdu)
(error_string): Removed. Replaced by apdu_strerror.
(get_ccid_error_string): Removed.
(ct_activate_card): Remove the unused loop.
(reset_ct_reader): Implemented.
(ct_send_apdu): Activate the card if not yet done.
(pcsc_send_apdu): Ditto.
* ccid-driver.h: Add error codes.
* ccid-driver.c: Implement more or less proper error codes all
over the place.
* apdu.c (apdu_send_direct): New.
(get_ccid_error_string): Add some error code mappings.
(send_apdu): Pass error codes along for drivers already supporting
them.
(host_sw_string): New.
(get_ccid_error_string): Use above.
(send_apdu_ccid): Reset the reader if it has not yet been done.
(open_ccid_reader): Don't care if the ATR can't be read.
(apdu_activate_card): New.
(apdu_strerror): New.
(dump_reader_status): Only enable it with opt.VERBOSE.
* iso7816.c (map_sw): Add mappings for the new error codes.
* apdu.c (open_ct_reader, open_pcsc_reader, open_ccid_reader)
(reset_ccid_reader, open_osc_reader): Call dump_reader_status only
in verbose mode.
* app-openpgp.c (do_getattr): Fix for sending CA-FPR.
* app-openpgp.c (app_openpgp_readkey): Fixed check for valid
exponent.
* app-openpgp.c (do_setattr): Sync FORCE_CHV1.
* card-util.c (change_login): Kludge to allow reading data from a
file.
(card_edit): Pass ARG_STRING to change_login.
(card_status): Print CA fingerprints.
(change_cafpr): New.
(card_edit): New command CAFPR.
* errors.h (G10ERR_NO_CARD, G10ERR_CANCELED): New error codes.
* errors.c (g10_errstr): New error codes G10ERR_NO_CARD,
G10ERR_CANCELED.
2004-09-09 18:18:36 +00:00
|
|
|
|
else if (keywordlen == 6 && !memcmp (keyword, "CA-FPR", keywordlen))
|
|
|
|
|
{
|
|
|
|
|
int no = atoi (line);
|
|
|
|
|
while (*line && !spacep (line))
|
|
|
|
|
line++;
|
|
|
|
|
while (spacep (line))
|
|
|
|
|
line++;
|
|
|
|
|
if (no == 1)
|
|
|
|
|
parm->cafpr1valid = unhexify_fpr (line, parm->cafpr1);
|
|
|
|
|
else if (no == 2)
|
|
|
|
|
parm->cafpr2valid = unhexify_fpr (line, parm->cafpr2);
|
|
|
|
|
else if (no == 3)
|
|
|
|
|
parm->cafpr3valid = unhexify_fpr (line, parm->cafpr3);
|
|
|
|
|
}
|
2004-12-09 16:57:30 +00:00
|
|
|
|
else if (keywordlen == 12 && !memcmp (keyword, "PRIVATE-DO-", 11)
|
|
|
|
|
&& strchr ("1234", keyword[11]))
|
|
|
|
|
{
|
|
|
|
|
int no = keyword[11] - '1';
|
|
|
|
|
assert (no >= 0 && no <= 3);
|
|
|
|
|
xfree (parm->private_do[no]);
|
2005-05-24 12:39:42 +00:00
|
|
|
|
parm->private_do[no] = unescape_percent_string (line);
|
2004-12-09 16:57:30 +00:00
|
|
|
|
}
|
|
|
|
|
|
2003-09-28 13:41:58 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Return card info. */
|
|
|
|
|
int
|
|
|
|
|
agent_learn (struct agent_card_info_s *info)
|
|
|
|
|
{
|
2005-05-20 20:37:08 +00:00
|
|
|
|
app_t app;
|
2003-09-28 13:41:58 +00:00
|
|
|
|
int rc;
|
|
|
|
|
struct ctrl_ctx_s ctrl;
|
|
|
|
|
time_t stamp;
|
|
|
|
|
char *serial;
|
|
|
|
|
|
2003-09-30 08:00:08 +00:00
|
|
|
|
app = current_app? current_app : open_card ();
|
2003-09-28 13:41:58 +00:00
|
|
|
|
if (!app)
|
|
|
|
|
return gpg_error (GPG_ERR_CARD);
|
|
|
|
|
|
2003-10-02 10:20:12 +00:00
|
|
|
|
memset (info, 0, sizeof *info);
|
2003-09-28 13:41:58 +00:00
|
|
|
|
|
2005-05-20 20:37:08 +00:00
|
|
|
|
if (app->assuan_ctx)
|
2003-09-28 13:41:58 +00:00
|
|
|
|
{
|
2005-05-20 20:37:08 +00:00
|
|
|
|
rc = assuan_transact (app->assuan_ctx, "SCD LEARN --force",
|
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
|
learn_status_cb, info);
|
|
|
|
|
rc = test_transact (rc, "SCD LEARN");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
memset (&ctrl, 0, sizeof ctrl);
|
|
|
|
|
ctrl.status_cb = learn_status_cb;
|
|
|
|
|
ctrl.status_cb_arg = info;
|
|
|
|
|
|
|
|
|
|
rc = app_get_serial_and_stamp (app, &serial, &stamp);
|
|
|
|
|
if (!rc)
|
|
|
|
|
{
|
|
|
|
|
send_status_info (&ctrl, "SERIALNO",
|
|
|
|
|
serial, strlen(serial), NULL, 0);
|
|
|
|
|
xfree (serial);
|
|
|
|
|
rc = app->fnc.learn_status (app, &ctrl);
|
|
|
|
|
}
|
2003-09-28 13:41:58 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
2005-05-20 20:37:08 +00:00
|
|
|
|
|
|
|
|
|
/* Get an attribute from the card. Make sure info is initialized. */
|
2003-10-02 10:20:12 +00:00
|
|
|
|
int
|
|
|
|
|
agent_scd_getattr (const char *name, struct agent_card_info_s *info)
|
|
|
|
|
{
|
2005-05-20 20:37:08 +00:00
|
|
|
|
int rc;
|
|
|
|
|
app_t app;
|
2003-10-02 10:20:12 +00:00
|
|
|
|
struct ctrl_ctx_s ctrl;
|
|
|
|
|
|
|
|
|
|
app = current_app? current_app : open_card ();
|
|
|
|
|
if (!app)
|
|
|
|
|
return gpg_error (GPG_ERR_CARD);
|
|
|
|
|
|
2005-05-20 20:37:08 +00:00
|
|
|
|
if (app->assuan_ctx)
|
|
|
|
|
{
|
|
|
|
|
char line[ASSUAN_LINELENGTH];
|
|
|
|
|
|
|
|
|
|
/* We assume that NAME does not need escaping. */
|
|
|
|
|
if (12 + strlen (name) > DIM(line)-1)
|
|
|
|
|
return gpg_error (GPG_ERR_CARD);
|
|
|
|
|
stpcpy (stpcpy (line, "SCD GETATTR "), name);
|
|
|
|
|
|
|
|
|
|
rc = test_transact (assuan_transact (app->assuan_ctx, line,
|
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
|
learn_status_cb, info),
|
|
|
|
|
"SCD GETATTR");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ctrl.status_cb = learn_status_cb;
|
|
|
|
|
ctrl.status_cb_arg = info;
|
|
|
|
|
rc = app->fnc.getattr (app, &ctrl, name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return rc;
|
2003-10-02 10:20:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-09-30 08:00:08 +00:00
|
|
|
|
static int
|
|
|
|
|
pin_cb (void *opaque, const char *info, char **retstr)
|
|
|
|
|
{
|
2005-05-03 22:27:07 +00:00
|
|
|
|
struct pincb_parm_s *parm = opaque;
|
2003-09-30 08:00:08 +00:00
|
|
|
|
char *value;
|
|
|
|
|
int canceled;
|
2004-11-17 16:04:21 +00:00
|
|
|
|
int isadmin = 0;
|
2004-12-09 16:57:30 +00:00
|
|
|
|
int newpin = 0;
|
2004-11-17 16:04:21 +00:00
|
|
|
|
const char *again_text = NULL;
|
2004-12-09 16:57:30 +00:00
|
|
|
|
const char *ends, *s;
|
2005-05-03 22:27:07 +00:00
|
|
|
|
char *cacheid = NULL;
|
2003-09-30 08:00:08 +00:00
|
|
|
|
|
|
|
|
|
*retstr = NULL;
|
2005-03-14 19:19:21 +00:00
|
|
|
|
/* log_debug ("asking for PIN '%s'\n", info); */
|
2003-09-30 08:00:08 +00:00
|
|
|
|
|
2004-11-17 16:04:21 +00:00
|
|
|
|
/* We use a special prefix to check whether the Admin PIN has been
|
|
|
|
|
requested. */
|
2004-12-09 16:57:30 +00:00
|
|
|
|
if (info && *info =='|' && (ends=strchr (info+1, '|')))
|
2004-11-17 16:04:21 +00:00
|
|
|
|
{
|
2004-12-09 16:57:30 +00:00
|
|
|
|
for (s=info+1; s < ends; s++)
|
|
|
|
|
{
|
|
|
|
|
if (*s == 'A')
|
|
|
|
|
isadmin = 1;
|
|
|
|
|
else if (*s == 'N')
|
|
|
|
|
newpin = 1;
|
|
|
|
|
}
|
|
|
|
|
info = ends+1;
|
2004-11-17 16:04:21 +00:00
|
|
|
|
}
|
2005-05-03 22:27:07 +00:00
|
|
|
|
else if (info && *info == '|')
|
2005-03-30 10:39:13 +00:00
|
|
|
|
log_debug ("pin_cb called without proper PIN info hack\n");
|
2004-11-17 16:04:21 +00:00
|
|
|
|
|
2005-05-03 22:27:07 +00:00
|
|
|
|
/* If we are not requesting a new PIN and we are not requesting an
|
|
|
|
|
AdminPIN, compute a string to be used as the cacheID for
|
|
|
|
|
gpg-agent. */
|
|
|
|
|
if (!newpin && !isadmin && parm)
|
|
|
|
|
{
|
|
|
|
|
cacheid = format_cacheid (parm->sn);
|
|
|
|
|
}
|
|
|
|
|
else if (newpin && parm)
|
|
|
|
|
{
|
|
|
|
|
/* Make really sure that it is not cached anymore. */
|
|
|
|
|
agent_clear_pin_cache (parm->sn);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2004-11-17 16:04:21 +00:00
|
|
|
|
again:
|
2004-10-15 13:16:58 +00:00
|
|
|
|
if (is_status_enabled())
|
2005-10-18 17:41:20 +00:00
|
|
|
|
{
|
|
|
|
|
if (parm && parm->sn && *parm->sn)
|
|
|
|
|
{
|
|
|
|
|
char *buf = xmalloc ( 10 + strlen (parm->sn) + 1);
|
|
|
|
|
strcpy (stpcpy (buf, isadmin? "OPENPGP 3 ":"OPENPGP 1 "), parm->sn);
|
|
|
|
|
write_status_text (STATUS_NEED_PASSPHRASE_PIN, buf);
|
|
|
|
|
xfree (buf);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
write_status_text (STATUS_NEED_PASSPHRASE_PIN,
|
|
|
|
|
isadmin? "OPENPGP 3" : "OPENPGP 1");
|
|
|
|
|
}
|
2004-10-15 13:16:58 +00:00
|
|
|
|
|
2004-11-17 16:04:21 +00:00
|
|
|
|
value = ask_passphrase (info, again_text,
|
2004-12-09 16:57:30 +00:00
|
|
|
|
newpin && isadmin? "passphrase.adminpin.new.ask" :
|
|
|
|
|
newpin? "passphrase.pin.new.ask" :
|
|
|
|
|
isadmin? "passphrase.adminpin.ask" :
|
|
|
|
|
"passphrase.pin.ask",
|
|
|
|
|
newpin && isadmin? _("Enter New Admin PIN: ") :
|
|
|
|
|
newpin? _("Enter New PIN: ") :
|
2004-11-17 16:04:21 +00:00
|
|
|
|
isadmin? _("Enter Admin PIN: ")
|
|
|
|
|
: _("Enter PIN: "),
|
2005-05-03 22:27:07 +00:00
|
|
|
|
cacheid,
|
2003-10-08 15:21:20 +00:00
|
|
|
|
&canceled);
|
2005-05-03 22:27:07 +00:00
|
|
|
|
xfree (cacheid);
|
|
|
|
|
cacheid = NULL;
|
2004-11-17 16:04:21 +00:00
|
|
|
|
again_text = NULL;
|
2003-09-30 08:00:08 +00:00
|
|
|
|
if (!value && canceled)
|
2005-10-18 17:41:20 +00:00
|
|
|
|
return G10ERR_CANCELED;
|
2003-09-30 08:00:08 +00:00
|
|
|
|
else if (!value)
|
|
|
|
|
return G10ERR_GENERAL;
|
|
|
|
|
|
2004-12-09 16:57:30 +00:00
|
|
|
|
if (newpin)
|
2004-11-17 16:04:21 +00:00
|
|
|
|
{
|
|
|
|
|
char *value2;
|
|
|
|
|
|
2005-10-18 17:41:20 +00:00
|
|
|
|
value2 = ask_passphrase (info, NULL,
|
2004-11-17 16:04:21 +00:00
|
|
|
|
"passphrase.pin.repeat",
|
|
|
|
|
_("Repeat this PIN: "),
|
2005-10-18 17:41:20 +00:00
|
|
|
|
NULL,
|
|
|
|
|
&canceled);
|
|
|
|
|
if (!value2 && canceled)
|
2004-11-17 16:04:21 +00:00
|
|
|
|
{
|
|
|
|
|
xfree (value);
|
2005-10-18 17:41:20 +00:00
|
|
|
|
return G10ERR_CANCELED;
|
2004-11-17 16:04:21 +00:00
|
|
|
|
}
|
2005-10-18 17:41:20 +00:00
|
|
|
|
else if (!value2)
|
2004-11-17 16:04:21 +00:00
|
|
|
|
{
|
|
|
|
|
xfree (value);
|
|
|
|
|
return G10ERR_GENERAL;
|
|
|
|
|
}
|
|
|
|
|
if (strcmp (value, value2))
|
|
|
|
|
{
|
|
|
|
|
again_text = N_("PIN not correctly repeated; try again");
|
|
|
|
|
xfree (value2);
|
|
|
|
|
xfree (value);
|
|
|
|
|
value = NULL;
|
|
|
|
|
goto again;
|
|
|
|
|
}
|
|
|
|
|
xfree (value2);
|
|
|
|
|
}
|
|
|
|
|
|
2003-09-30 08:00:08 +00:00
|
|
|
|
*retstr = value;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-09-28 13:41:58 +00:00
|
|
|
|
/* Send a SETATTR command to the SCdaemon. */
|
|
|
|
|
int
|
|
|
|
|
agent_scd_setattr (const char *name,
|
2005-10-18 17:41:20 +00:00
|
|
|
|
const unsigned char *value, size_t valuelen,
|
|
|
|
|
const char *serialno)
|
2003-09-28 13:41:58 +00:00
|
|
|
|
{
|
2005-05-20 20:37:08 +00:00
|
|
|
|
app_t app;
|
2005-03-07 13:59:59 +00:00
|
|
|
|
int rc;
|
2005-10-18 17:41:20 +00:00
|
|
|
|
struct pincb_parm_s parm;
|
|
|
|
|
|
|
|
|
|
memset (&parm, 0, sizeof parm);
|
|
|
|
|
parm.sn = serialno;
|
2003-09-28 13:41:58 +00:00
|
|
|
|
|
2003-09-30 08:00:08 +00:00
|
|
|
|
app = current_app? current_app : open_card ();
|
|
|
|
|
if (!app)
|
|
|
|
|
return gpg_error (GPG_ERR_CARD);
|
|
|
|
|
|
2005-05-20 20:37:08 +00:00
|
|
|
|
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
|
|
|
|
|
{
|
2005-10-18 17:41:20 +00:00
|
|
|
|
rc = app->fnc.setattr (app, name, pin_cb, &parm, value, valuelen);
|
2005-05-20 20:37:08 +00:00
|
|
|
|
}
|
2005-03-07 13:59:59 +00:00
|
|
|
|
|
2005-10-18 17:41:20 +00:00
|
|
|
|
status_sc_op_failure (rc);
|
2005-03-07 13:59:59 +00:00
|
|
|
|
return rc;
|
2003-09-28 13:41:58 +00:00
|
|
|
|
}
|
|
|
|
|
|
2003-10-08 15:21:20 +00:00
|
|
|
|
|
2005-05-21 14:04:32 +00:00
|
|
|
|
/* Handle a KEYDATA inquiry. Note, we only send the data,
|
|
|
|
|
assuan_transact takes care of flushing and writing the end */
|
|
|
|
|
static assuan_error_t
|
|
|
|
|
inq_writekey_parms (void *opaque, const char *keyword)
|
|
|
|
|
{
|
|
|
|
|
struct writekey_parm_s *parm = opaque;
|
|
|
|
|
|
|
|
|
|
return assuan_send_data (parm->ctx, parm->keydata, parm->keydatalen);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Send a WRITEKEY command to the SCdaemon. */
|
|
|
|
|
int
|
2005-10-18 17:41:20 +00:00
|
|
|
|
agent_scd_writekey (int keyno, const char *serialno,
|
|
|
|
|
const unsigned char *keydata, size_t keydatalen)
|
2005-05-21 14:04:32 +00:00
|
|
|
|
{
|
|
|
|
|
app_t app;
|
|
|
|
|
int rc;
|
|
|
|
|
char line[ASSUAN_LINELENGTH];
|
2005-10-18 17:41:20 +00:00
|
|
|
|
struct pincb_parm_s parm;
|
|
|
|
|
|
|
|
|
|
memset (&parm, 0, sizeof parm);
|
|
|
|
|
parm.sn = serialno;
|
|
|
|
|
|
2005-05-21 14:04:32 +00:00
|
|
|
|
app = current_app? current_app : open_card ();
|
|
|
|
|
if (!app)
|
|
|
|
|
return gpg_error (GPG_ERR_CARD);
|
|
|
|
|
|
|
|
|
|
if (app->assuan_ctx)
|
|
|
|
|
{
|
|
|
|
|
struct writekey_parm_s parms;
|
|
|
|
|
|
|
|
|
|
snprintf (line, DIM(line)-1, "SCD WRITEKEY --force OPENPGP.%d", keyno);
|
|
|
|
|
line[DIM(line)-1] = 0;
|
|
|
|
|
parms.ctx = app->assuan_ctx;
|
|
|
|
|
parms.keydata = keydata;
|
|
|
|
|
parms.keydatalen = keydatalen;
|
|
|
|
|
rc = test_transact (assuan_transact (app->assuan_ctx, line,
|
|
|
|
|
NULL, NULL,
|
|
|
|
|
inq_writekey_parms, &parms,
|
|
|
|
|
NULL, NULL),
|
|
|
|
|
"SCD WRITEKEY");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
snprintf (line, DIM(line)-1, "OPENPGP.%d", keyno);
|
|
|
|
|
line[DIM(line)-1] = 0;
|
|
|
|
|
rc = app->fnc.writekey (app, NULL, line, 0x0001,
|
2005-10-18 17:41:20 +00:00
|
|
|
|
pin_cb, &parm,
|
2005-05-21 14:04:32 +00:00
|
|
|
|
keydata, keydatalen);
|
|
|
|
|
}
|
|
|
|
|
|
2005-10-18 17:41:20 +00:00
|
|
|
|
status_sc_op_failure (rc);
|
2005-05-21 14:04:32 +00:00
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2005-05-20 20:37:08 +00:00
|
|
|
|
static assuan_error_t
|
2003-10-08 15:21:20 +00:00
|
|
|
|
genkey_status_cb (void *opaque, const char *line)
|
|
|
|
|
{
|
|
|
|
|
struct agent_card_genkey_s *parm = opaque;
|
|
|
|
|
const char *keyword = line;
|
|
|
|
|
int keywordlen;
|
|
|
|
|
|
2004-11-17 16:04:21 +00:00
|
|
|
|
/* log_debug ("got status line `%s'\n", line); */
|
2003-10-08 15:21:20 +00:00
|
|
|
|
for (keywordlen=0; *line && !spacep (line); line++, keywordlen++)
|
|
|
|
|
;
|
|
|
|
|
while (spacep (line))
|
|
|
|
|
line++;
|
|
|
|
|
|
|
|
|
|
if (keywordlen == 7 && !memcmp (keyword, "KEY-FPR", keywordlen))
|
|
|
|
|
{
|
|
|
|
|
parm->fprvalid = unhexify_fpr (line, parm->fpr);
|
|
|
|
|
}
|
|
|
|
|
if (keywordlen == 8 && !memcmp (keyword, "KEY-DATA", keywordlen))
|
|
|
|
|
{
|
|
|
|
|
MPI a;
|
|
|
|
|
const char *name = line;
|
|
|
|
|
char *buf;
|
|
|
|
|
|
2003-10-25 14:17:24 +00:00
|
|
|
|
while (*line && !spacep (line))
|
2003-10-08 15:21:20 +00:00
|
|
|
|
line++;
|
|
|
|
|
while (spacep (line))
|
|
|
|
|
line++;
|
|
|
|
|
|
|
|
|
|
buf = xmalloc ( 2 + strlen (line) + 1);
|
|
|
|
|
strcpy (stpcpy (buf, "0x"), line);
|
|
|
|
|
a = mpi_alloc (300);
|
|
|
|
|
if( mpi_fromstr (a, buf) )
|
|
|
|
|
log_error ("error parsing received key data\n");
|
|
|
|
|
else if (*name == 'n' && spacep (name+1))
|
|
|
|
|
parm->n = a;
|
|
|
|
|
else if (*name == 'e' && spacep (name+1))
|
|
|
|
|
parm->e = a;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
log_info ("unknown parameter name in received key data\n");
|
|
|
|
|
mpi_free (a);
|
|
|
|
|
}
|
|
|
|
|
xfree (buf);
|
|
|
|
|
}
|
|
|
|
|
else if (keywordlen == 14 && !memcmp (keyword,"KEY-CREATED-AT", keywordlen))
|
|
|
|
|
{
|
|
|
|
|
parm->created_at = (u32)strtoul (line, NULL, 10);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2003-09-28 13:41:58 +00:00
|
|
|
|
/* Send a GENKEY command to the SCdaemon. */
|
|
|
|
|
int
|
2005-10-18 17:41:20 +00:00
|
|
|
|
agent_scd_genkey (struct agent_card_genkey_s *info, int keyno, int force,
|
|
|
|
|
const char *serialno)
|
2003-09-28 13:41:58 +00:00
|
|
|
|
{
|
2005-05-20 20:37:08 +00:00
|
|
|
|
app_t app;
|
|
|
|
|
char line[ASSUAN_LINELENGTH];
|
2003-10-08 15:21:20 +00:00
|
|
|
|
struct ctrl_ctx_s ctrl;
|
2005-03-07 13:59:59 +00:00
|
|
|
|
int rc;
|
2005-10-18 17:41:20 +00:00
|
|
|
|
struct pincb_parm_s parm;
|
|
|
|
|
|
|
|
|
|
memset (&parm, 0, sizeof parm);
|
|
|
|
|
parm.sn = serialno;
|
2003-09-28 13:41:58 +00:00
|
|
|
|
|
2003-10-08 15:21:20 +00:00
|
|
|
|
app = current_app? current_app : open_card ();
|
|
|
|
|
if (!app)
|
|
|
|
|
return gpg_error (GPG_ERR_CARD);
|
|
|
|
|
|
|
|
|
|
memset (info, 0, sizeof *info);
|
|
|
|
|
|
2005-05-20 20:37:08 +00:00
|
|
|
|
if (app->assuan_ctx)
|
|
|
|
|
{
|
|
|
|
|
snprintf (line, DIM(line)-1, "SCD GENKEY %s%d",
|
|
|
|
|
force? "--force ":"", keyno);
|
|
|
|
|
line[DIM(line)-1] = 0;
|
|
|
|
|
rc = test_transact (assuan_transact (app->assuan_ctx, line,
|
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
|
genkey_status_cb, info),
|
|
|
|
|
"SCD GENKEY");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
snprintf (line, DIM(line)-1, "%d", keyno);
|
|
|
|
|
ctrl.status_cb = genkey_status_cb;
|
|
|
|
|
ctrl.status_cb_arg = info;
|
|
|
|
|
rc = app->fnc.genkey (app, &ctrl, line,
|
|
|
|
|
force? 1:0,
|
2005-10-18 17:41:20 +00:00
|
|
|
|
pin_cb, &parm);
|
2005-05-20 20:37:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
2005-10-18 17:41:20 +00:00
|
|
|
|
status_sc_op_failure (rc);
|
2005-03-07 13:59:59 +00:00
|
|
|
|
return rc;
|
2003-09-28 13:41:58 +00:00
|
|
|
|
}
|
|
|
|
|
|
2005-05-20 20:37:08 +00:00
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2003-09-28 13:41:58 +00:00
|
|
|
|
/* Send a PKSIGN command to the SCdaemon. */
|
|
|
|
|
int
|
2003-09-30 08:00:08 +00:00
|
|
|
|
agent_scd_pksign (const char *serialno, int hashalgo,
|
2003-09-28 13:41:58 +00:00
|
|
|
|
const unsigned char *indata, size_t indatalen,
|
2003-10-08 15:21:20 +00:00
|
|
|
|
unsigned char **r_buf, size_t *r_buflen)
|
2003-09-28 13:41:58 +00:00
|
|
|
|
{
|
2005-05-03 22:27:07 +00:00
|
|
|
|
struct pincb_parm_s parm;
|
2005-05-20 20:37:08 +00:00
|
|
|
|
app_t app;
|
2003-10-29 10:07:44 +00:00
|
|
|
|
int rc;
|
2003-09-28 13:41:58 +00:00
|
|
|
|
|
2003-09-30 08:00:08 +00:00
|
|
|
|
*r_buf = NULL;
|
|
|
|
|
*r_buflen = 0;
|
2005-05-03 22:27:07 +00:00
|
|
|
|
memset (&parm, 0, sizeof parm);
|
|
|
|
|
parm.sn = serialno;
|
2003-10-29 10:07:44 +00:00
|
|
|
|
retry:
|
2003-09-30 08:00:08 +00:00
|
|
|
|
app = current_app? current_app : open_card ();
|
|
|
|
|
if (!app)
|
|
|
|
|
return gpg_error (GPG_ERR_CARD);
|
|
|
|
|
|
2005-05-20 20:37:08 +00:00
|
|
|
|
if (app->assuan_ctx)
|
|
|
|
|
{
|
|
|
|
|
char *p, line[ASSUAN_LINELENGTH];
|
|
|
|
|
membuf_t data;
|
|
|
|
|
size_t len;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
if (indatalen*2 + 50 > DIM(line))
|
|
|
|
|
return gpg_error (GPG_ERR_GENERAL);
|
|
|
|
|
|
|
|
|
|
p = stpcpy (line, "SCD SETDATA ");
|
|
|
|
|
for (i=0; i < indatalen ; i++, p += 2 )
|
|
|
|
|
sprintf (p, "%02X", indata[i]);
|
|
|
|
|
rc = test_transact (assuan_transact (app->assuan_ctx, line,
|
|
|
|
|
NULL, NULL, NULL, NULL, NULL, NULL),
|
|
|
|
|
"SCD SETDATA");
|
|
|
|
|
if (!rc)
|
|
|
|
|
{
|
|
|
|
|
init_membuf (&data, 1024);
|
|
|
|
|
snprintf (line, DIM(line)-1, "SCD PKSIGN %s", serialno);
|
|
|
|
|
line[DIM(line)-1] = 0;
|
|
|
|
|
rc = test_transact (assuan_transact (app->assuan_ctx, line,
|
|
|
|
|
membuf_data_cb, &data,
|
|
|
|
|
NULL, NULL, NULL, NULL),
|
|
|
|
|
"SCD PKSIGN");
|
|
|
|
|
if (rc)
|
|
|
|
|
xfree (get_membuf (&data, &len));
|
|
|
|
|
else
|
|
|
|
|
*r_buf = get_membuf (&data, r_buflen);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* Check that the card's serialnumber is as required.*/
|
|
|
|
|
rc = check_card_serialno (app, serialno);
|
|
|
|
|
if (rc == -1)
|
|
|
|
|
goto retry;
|
|
|
|
|
|
|
|
|
|
if (!rc)
|
|
|
|
|
rc = app->fnc.sign (app, serialno, hashalgo,
|
|
|
|
|
pin_cb, &parm,
|
|
|
|
|
indata, indatalen,
|
|
|
|
|
r_buf, r_buflen);
|
|
|
|
|
}
|
2003-09-30 08:00:08 +00:00
|
|
|
|
|
2005-03-07 13:59:59 +00:00
|
|
|
|
if (rc)
|
2005-05-03 22:27:07 +00:00
|
|
|
|
{
|
2005-10-18 17:41:20 +00:00
|
|
|
|
status_sc_op_failure (rc);
|
2005-05-20 20:37:08 +00:00
|
|
|
|
if (!app->assuan_ctx)
|
|
|
|
|
agent_clear_pin_cache (serialno);
|
2005-05-03 22:27:07 +00:00
|
|
|
|
}
|
2005-03-07 13:59:59 +00:00
|
|
|
|
return rc;
|
2003-09-28 13:41:58 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Send a PKDECRYPT command to the SCdaemon. */
|
|
|
|
|
int
|
|
|
|
|
agent_scd_pkdecrypt (const char *serialno,
|
|
|
|
|
const unsigned char *indata, size_t indatalen,
|
2003-10-09 15:08:12 +00:00
|
|
|
|
unsigned char **r_buf, size_t *r_buflen)
|
2003-09-28 13:41:58 +00:00
|
|
|
|
{
|
2005-05-03 22:27:07 +00:00
|
|
|
|
struct pincb_parm_s parm;
|
2005-05-20 20:37:08 +00:00
|
|
|
|
app_t app;
|
2003-10-29 10:07:44 +00:00
|
|
|
|
int rc;
|
2003-10-09 15:08:12 +00:00
|
|
|
|
|
|
|
|
|
*r_buf = NULL;
|
|
|
|
|
*r_buflen = 0;
|
2005-05-03 22:27:07 +00:00
|
|
|
|
memset (&parm, 0, sizeof parm);
|
|
|
|
|
parm.sn = serialno;
|
2003-10-29 10:07:44 +00:00
|
|
|
|
retry:
|
2003-10-09 15:08:12 +00:00
|
|
|
|
app = current_app? current_app : open_card ();
|
|
|
|
|
if (!app)
|
|
|
|
|
return gpg_error (GPG_ERR_CARD);
|
|
|
|
|
|
2005-05-20 20:37:08 +00:00
|
|
|
|
if (app->assuan_ctx)
|
|
|
|
|
{
|
|
|
|
|
char *p, line[ASSUAN_LINELENGTH];
|
|
|
|
|
membuf_t data;
|
|
|
|
|
size_t len;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
if (indatalen*2 + 50 > DIM(line))
|
|
|
|
|
return gpg_error (GPG_ERR_GENERAL);
|
|
|
|
|
|
|
|
|
|
p = stpcpy (line, "SCD SETDATA ");
|
|
|
|
|
for (i=0; i < indatalen ; i++, p += 2 )
|
|
|
|
|
sprintf (p, "%02X", indata[i]);
|
|
|
|
|
rc = test_transact (assuan_transact (app->assuan_ctx, line,
|
|
|
|
|
NULL, NULL, NULL, NULL, NULL, NULL),
|
|
|
|
|
"SCD SETDATA");
|
|
|
|
|
if (!rc)
|
|
|
|
|
{
|
|
|
|
|
init_membuf (&data, 1024);
|
|
|
|
|
snprintf (line, DIM(line)-1, "SCD PKDECRYPT %s", serialno);
|
|
|
|
|
line[DIM(line)-1] = 0;
|
|
|
|
|
rc = test_transact (assuan_transact (app->assuan_ctx, line,
|
|
|
|
|
membuf_data_cb, &data,
|
|
|
|
|
NULL, NULL, NULL, NULL),
|
|
|
|
|
"SCD PKDECRYPT");
|
|
|
|
|
if (rc)
|
|
|
|
|
xfree (get_membuf (&data, &len));
|
|
|
|
|
else
|
|
|
|
|
*r_buf = get_membuf (&data, r_buflen);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* Check that the card's serialnumber is as required.*/
|
|
|
|
|
rc = check_card_serialno (app, serialno);
|
|
|
|
|
if (rc == -1)
|
|
|
|
|
goto retry;
|
|
|
|
|
|
|
|
|
|
if (!rc)
|
|
|
|
|
rc = app->fnc.decipher (app, serialno,
|
|
|
|
|
pin_cb, &parm,
|
|
|
|
|
indata, indatalen,
|
|
|
|
|
r_buf, r_buflen);
|
|
|
|
|
}
|
2003-10-29 10:07:44 +00:00
|
|
|
|
|
2005-03-07 13:59:59 +00:00
|
|
|
|
if (rc)
|
2005-05-03 22:27:07 +00:00
|
|
|
|
{
|
2005-10-18 17:41:20 +00:00
|
|
|
|
status_sc_op_failure (rc);
|
2005-05-20 20:37:08 +00:00
|
|
|
|
if (!app->assuan_ctx)
|
|
|
|
|
agent_clear_pin_cache (serialno);
|
2005-05-03 22:27:07 +00:00
|
|
|
|
}
|
2005-03-07 13:59:59 +00:00
|
|
|
|
return rc;
|
2003-09-28 13:41:58 +00:00
|
|
|
|
}
|
|
|
|
|
|
2005-10-18 17:41:20 +00:00
|
|
|
|
/* Change the PIN of an OpenPGP card or reset the retry
|
|
|
|
|
counter. SERIALNO may be NULL or a hex string finally passed to the
|
|
|
|
|
passphrase callback. */
|
2003-09-28 13:41:58 +00:00
|
|
|
|
int
|
2005-10-18 17:41:20 +00:00
|
|
|
|
agent_scd_change_pin (int chvno, const char *serialno)
|
2003-09-28 13:41:58 +00:00
|
|
|
|
{
|
2005-05-20 20:37:08 +00:00
|
|
|
|
app_t app;
|
2003-10-10 15:45:11 +00:00
|
|
|
|
int reset = 0;
|
2005-03-07 13:59:59 +00:00
|
|
|
|
int rc;
|
2005-10-18 17:41:20 +00:00
|
|
|
|
struct pincb_parm_s parm;
|
|
|
|
|
|
|
|
|
|
memset (&parm, 0, sizeof parm);
|
|
|
|
|
parm.sn = serialno;
|
2003-10-10 15:45:11 +00:00
|
|
|
|
|
|
|
|
|
reset = (chvno >= 100);
|
|
|
|
|
chvno %= 100;
|
|
|
|
|
|
|
|
|
|
app = current_app? current_app : open_card ();
|
|
|
|
|
if (!app)
|
|
|
|
|
return gpg_error (GPG_ERR_CARD);
|
2003-09-28 13:41:58 +00:00
|
|
|
|
|
2005-05-20 20:37:08 +00:00
|
|
|
|
if (app->assuan_ctx)
|
|
|
|
|
{
|
2005-05-23 20:16:21 +00:00
|
|
|
|
char line[ASSUAN_LINELENGTH];
|
|
|
|
|
|
|
|
|
|
snprintf (line, DIM(line)-1, "SCD PASSWD%s %d",
|
|
|
|
|
reset? " --reset":"", chvno);
|
|
|
|
|
line[DIM(line)-1] = 0;
|
|
|
|
|
rc = test_transact (assuan_transact (app->assuan_ctx, line,
|
|
|
|
|
NULL, NULL, NULL, NULL, NULL, NULL),
|
|
|
|
|
"SCD PASSWD");
|
2005-05-20 20:37:08 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2005-05-23 20:16:21 +00:00
|
|
|
|
char chvnostr[50];
|
|
|
|
|
|
2005-05-20 20:37:08 +00:00
|
|
|
|
sprintf (chvnostr, "%d", chvno);
|
|
|
|
|
rc = app->fnc.change_pin (app, NULL, chvnostr, reset,
|
2005-10-18 17:41:20 +00:00
|
|
|
|
pin_cb, &parm);
|
2005-05-20 20:37:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
2005-10-18 17:41:20 +00:00
|
|
|
|
status_sc_op_failure (rc);
|
2005-03-07 13:59:59 +00:00
|
|
|
|
return rc;
|
2003-09-28 13:41:58 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-09-20 18:38:39 +00:00
|
|
|
|
/* Perform a CHECKPIN operation. SERIALNO should be the serial
|
|
|
|
|
number of the card - optionally followed by the fingerprint;
|
2003-10-21 18:22:21 +00:00
|
|
|
|
however the fingerprint is ignored here. */
|
|
|
|
|
int
|
|
|
|
|
agent_scd_checkpin (const char *serialnobuf)
|
|
|
|
|
{
|
2005-05-20 20:37:08 +00:00
|
|
|
|
app_t app;
|
2005-03-07 13:59:59 +00:00
|
|
|
|
int rc;
|
2005-10-18 17:41:20 +00:00
|
|
|
|
struct pincb_parm_s parm;
|
|
|
|
|
|
|
|
|
|
memset (&parm, 0, sizeof parm);
|
|
|
|
|
parm.sn = serialnobuf;
|
2003-10-21 18:22:21 +00:00
|
|
|
|
|
|
|
|
|
app = current_app? current_app : open_card ();
|
|
|
|
|
if (!app)
|
|
|
|
|
return gpg_error (GPG_ERR_CARD);
|
|
|
|
|
|
2005-05-20 20:37:08 +00:00
|
|
|
|
if (app->assuan_ctx)
|
|
|
|
|
{
|
2005-05-23 20:16:21 +00:00
|
|
|
|
char line[ASSUAN_LINELENGTH];
|
|
|
|
|
|
|
|
|
|
if (15 + strlen (serialnobuf) > DIM(line)-1)
|
|
|
|
|
return gpg_error (GPG_ERR_CARD);
|
|
|
|
|
stpcpy (stpcpy (line, "SCD CHECKPIN "), serialnobuf);
|
|
|
|
|
rc = test_transact (assuan_transact (app->assuan_ctx, line,
|
|
|
|
|
NULL, NULL, NULL, NULL, NULL, NULL),
|
|
|
|
|
"SCD CHECKPIN");
|
2005-05-20 20:37:08 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2005-10-18 17:41:20 +00:00
|
|
|
|
rc = app->fnc.check_pin (app, serialnobuf, pin_cb, &parm);
|
2005-05-20 20:37:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
2005-10-18 17:41:20 +00:00
|
|
|
|
status_sc_op_failure (rc);
|
2005-03-07 13:59:59 +00:00
|
|
|
|
return rc;
|
2003-10-21 18:22:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-09-23 13:32:31 +00:00
|
|
|
|
|
2005-05-03 22:27:07 +00:00
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
agent_clear_pin_cache (const char *sn)
|
|
|
|
|
{
|
|
|
|
|
char *cacheid = format_cacheid (sn);
|
|
|
|
|
if (cacheid)
|
|
|
|
|
{
|
|
|
|
|
passphrase_clear_cache (NULL, cacheid, 0);
|
|
|
|
|
xfree (cacheid);
|
|
|
|
|
}
|
|
|
|
|
}
|