diff options
Diffstat (limited to '')
-rw-r--r-- | g10/cardglue.c | 1432 |
1 files changed, 0 insertions, 1432 deletions
diff --git a/g10/cardglue.c b/g10/cardglue.c deleted file mode 100644 index 1bfb9e413..000000000 --- a/g10/cardglue.c +++ /dev/null @@ -1,1432 +0,0 @@ -/* cardglue.c - mainly dispatcher for card related functions. - * Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc. - * - * 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 - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -#include <config.h> -#ifndef ENABLE_CARD_SUPPORT -#error not configured for card support. -#endif -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> -#include <stdarg.h> -#include <assert.h> -#include "options.h" -#include "packet.h" -#include "errors.h" -#include "memory.h" -#include "util.h" -#include "main.h" -#include "status.h" -#include "ttyio.h" -#include "i18n.h" - -#include "cardglue.h" -#include "apdu.h" -#include "app-common.h" - - - -struct ctrl_ctx_s -{ - assuan_error_t (*status_cb)(void *opaque, const char *line); - void *status_cb_arg; -}; - - -struct pincb_parm_s -{ - const char *sn; -}; - - -struct writekey_parm_s -{ - assuan_context_t ctx; - const unsigned char *keydata; - size_t keydatalen; -}; - - - -static char *default_reader_port; -static app_t current_app; - - -/* Local prototypes. */ -static assuan_error_t learn_status_cb (void *opaque, const char *line); - - -/* 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 -agent_open (int try, const char *orig_codeset) -{ - 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*/ - - -/* 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; -} - - -/* 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_t 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; - if (ctrl && ctrl->status_cb) - ctrl->status_cb (ctrl->status_cb_arg, buf); - - va_end (arg_ptr); -} - - -/* Replacement function of the Libgcrypt onewhich is used in gnupg - 1.9. Thus function computes the digest of ALGO from the data in - BUFFER of LENGTH. ALGO must be supported. */ -void -gcry_md_hash_buffer (int algo, void *digest, - const void *buffer, size_t length) -{ - MD_HANDLE h = md_open (algo, 0); - if (!h) - 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; -} - - -void -card_set_reader_port (const char *portstr) -{ - app_set_default_reader_port (portstr); -} - - -/* 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_t 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) -{ - int i; - - 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; - info->cafpr1valid = info->cafpr2valid = info->cafpr3valid = 0; - for (i=0; i < 4; i++) - { - xfree (info->private_do[i]); - info->private_do[i] = NULL; - } -} - - -/* 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, NULL); - if (!ctx) - return NULL; - - /* Request the serialbnumber of the card. If we get - NOT_SUPPORTED or NO_SCDAEMON back, the gpg-agent either has - disabled scdaemon or it can't be used. We close the connection - in this case and use our own code. This may happen if just the - gpg-agent has been installed for the sake of passphrase - caching. */ - memset (&info, 0, sizeof info); - rc = assuan_transact (ctx, "SCD SERIALNO openpgp", - NULL, NULL, NULL, NULL, - learn_status_cb, &info); - if (rc) - { - if ((rc & 0xffff) == 60 || (rc & 0xffff) == 119) - ; /* No scdaemon available to gpg-agent. */ - else - { - write_status_text (STATUS_CARDCTRL, "4"); - log_info ("selecting openpgp failed: %s\n", assuan_strerror (rc)); - *scd_available = 1; - } - agent_release_card_info (&info); - agent_close (ctx); - return NULL; - } - - app = xcalloc (1, sizeof *app); - app->assuan_ctx = ctx; - - return app; -} - - - -/* Open the current card and select the openpgp application. Return - an APP context handle to be used for further procesing or NULL on - error or if no OpenPGP application exists.*/ -static app_t -open_card (void) -{ - int slot = -1; - int rc; - app_t app; - int did_shutdown = 0; - int retry_count = 0; - - /* 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. */ - 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. */ - } - - - /* No agent or usable agent, thus we do it on our own. */ - card_close (); - - retry: - if (did_shutdown) - apdu_reset (slot); - else - { - slot = apdu_open_reader (default_reader_port); - if (slot == -1) - { - write_status_text (STATUS_CARDCTRL, "5"); - log_error (_("card reader not available\n")); - return NULL; - } - } - - app = xcalloc (1, sizeof *app); - app->slot = slot; - rc = app_select_openpgp (app); - if (opt.limit_card_insert_tries - && ++retry_count >= opt.limit_card_insert_tries) - ; - else if (rc && !opt.batch) - { - write_status_text (STATUS_CARDCTRL, "1"); - - did_shutdown = !!apdu_shutdown_reader (slot); - - if ( cpr_get_answer_okay_cancel ("cardctrl.insert_card.okay", - _("Please insert the card and hit return or enter 'c' to cancel: "), - 1) ) - { - if (!did_shutdown) - apdu_close_reader (slot); - xfree (app); - goto retry; - } - } - if (rc) - { - write_status_text (STATUS_CARDCTRL, "4"); - log_info (_("selecting openpgp failed: %s\n"), gpg_strerror (rc)); - apdu_close_reader (slot); - xfree (app); - return NULL; - } - - ready: - app->initialized = 1; - current_app = app; - 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); - } - - return app; -} - - -void -card_close (void) -{ - if (current_app) - { - app_t app = current_app; - current_app = NULL; - - if (app->assuan_ctx) - agent_close (app->assuan_ctx); - else - apdu_close_reader (app->slot); - xfree (app); - } -} - - -/* 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; -} - - -/* 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); -} - - -/* 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 returnd 0 if 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 - value and if it was possible to merely shutdown the reader. */ -static int -check_card_serialno (app_t app, const char *serialno) -{ - const char *s; - int ask = 0; - int n; - - 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]; - int did_shutdown = 0; - - if (current_app && !apdu_shutdown_reader (current_app->slot)) - did_shutdown = 1; - else - card_close (); - - if (!opt.batch) - tty_printf (_("Please remove the current card and " - "insert the one with serial number:\n" - " %.*s\n"), 32, serialno); - - sprintf (buf, "1 %.32s", serialno); - write_status_text (STATUS_CARDCTRL, buf); - - if ( !opt.batch - && cpr_get_answer_okay_cancel ("cardctrl.change_card.okay", - _("Hit return when ready " - "or enter 'c' to cancel: "), - 1) ) - { - card_close (); - return -1; - } - if (did_shutdown) - apdu_reset (current_app->slot); - else - card_close (); - return gpg_error (GPG_ERR_INV_ID); - } - return 0; -} - - -/* 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 assuan_error_t -learn_status_cb (void *opaque, const char *line) -{ - struct agent_card_info_s *parm = opaque; - const char *keyword = line; - int keywordlen; - int i; - -/* log_debug ("got status line `%s'\n", line); */ - for (keywordlen=0; *line && !spacep (line); line++, keywordlen++) - ; - while (spacep (line)) - line++; - - if (keywordlen == 8 && !memcmp (keyword, "SERIALNO", keywordlen)) - { - xfree (parm->serialno); - parm->serialno = store_serialno (line); - } - else if (keywordlen == 9 && !memcmp (keyword, "DISP-NAME", keywordlen)) - { - xfree (parm->disp_name); - parm->disp_name = unescape_percent_string (line); - } - else if (keywordlen == 9 && !memcmp (keyword, "DISP-LANG", keywordlen)) - { - xfree (parm->disp_lang); - parm->disp_lang = unescape_percent_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)) - { - xfree (parm->pubkey_url); - parm->pubkey_url = unescape_percent_string (line); - } - else if (keywordlen == 10 && !memcmp (keyword, "LOGIN-DATA", keywordlen)) - { - xfree (parm->login_data); - parm->login_data = unescape_percent_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_percent_string (line); - if (buf) - { - while (spacep (p)) - p++; - parm->chv1_cached = atoi (p); - while (*p && !spacep (p)) - p++; - while (spacep (p)) - p++; - for (i=0; *p && i < 3; i++) - { - parm->chvmaxlen[i] = atoi (p); - while (*p && !spacep (p)) - p++; - while (spacep (p)) - p++; - } - for (i=0; *p && i < 3; i++) - { - parm->chvretry[i] = atoi (p); - while (*p && !spacep (p)) - p++; - while (spacep (p)) - p++; - } - xfree (buf); - } - } - else if (keywordlen == 7 && !memcmp (keyword, "KEY-FPR", keywordlen)) - { - int no = atoi (line); - while (* line && !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); - } - 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); - } - 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); - } - 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]); - parm->private_do[no] = unescape_percent_string (line); - } - - return 0; -} - - -/* Return card info. */ -int -agent_learn (struct agent_card_info_s *info) -{ - app_t app; - int rc; - struct ctrl_ctx_s ctrl; - time_t stamp; - char *serial; - - app = current_app? current_app : open_card (); - if (!app) - return gpg_error (GPG_ERR_CARD); - - memset (info, 0, sizeof *info); - - if (app->assuan_ctx) - { - rc = assuan_transact (app->assuan_ctx, "SCD LEARN --force", - NULL, NULL, NULL, NULL, - learn_status_cb, info); - rc = test_transact (rc, "SCD LEARN"); - } - else - { - memset (&ctrl, 0, sizeof ctrl); - ctrl.status_cb = learn_status_cb; - ctrl.status_cb_arg = info; - - rc = app_get_serial_and_stamp (app, &serial, &stamp); - if (!rc) - { - send_status_info (&ctrl, "SERIALNO", - serial, strlen(serial), NULL, 0); - xfree (serial); - rc = app->fnc.learn_status (app, &ctrl); - } - } - - return rc; -} - - -/* Get an attribute from the card. Make sure info is initialized. */ -int -agent_scd_getattr (const char *name, struct agent_card_info_s *info) -{ - int rc; - app_t app; - struct ctrl_ctx_s ctrl; - - app = current_app? current_app : open_card (); - if (!app) - return gpg_error (GPG_ERR_CARD); - - 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; -} - - - -static int -pin_cb (void *opaque, const char *info, char **retstr) -{ - struct pincb_parm_s *parm = opaque; - char *value; - int canceled; - int isadmin = 0; - int newpin = 0; - const char *again_text = NULL; - const char *ends, *s; - char *cacheid = NULL; - - *retstr = NULL; - /* log_debug ("asking for PIN '%s'\n", info); */ - - /* We use a special prefix to check whether the Admin PIN has been - requested. */ - if (info && *info =='|' && (ends=strchr (info+1, '|'))) - { - for (s=info+1; s < ends; s++) - { - if (*s == 'A') - isadmin = 1; - else if (*s == 'N') - newpin = 1; - } - info = ends+1; - } - else if (info && *info == '|') - log_debug ("pin_cb called without proper PIN info hack\n"); - - /* 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); - } - - - again: - if (is_status_enabled()) - { - 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"); - } - - value = ask_passphrase (info, again_text, - 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: ") : - isadmin? _("Enter Admin PIN: ") - : _("Enter PIN: "), - cacheid, - &canceled); - xfree (cacheid); - cacheid = NULL; - again_text = NULL; - if (!value && canceled) - return G10ERR_CANCELED; - else if (!value) - return G10ERR_GENERAL; - - if (newpin) - { - char *value2; - - value2 = ask_passphrase (info, NULL, - "passphrase.pin.repeat", - _("Repeat this PIN: "), - NULL, - &canceled); - if (!value2 && canceled) - { - xfree (value); - return G10ERR_CANCELED; - } - else if (!value2) - { - 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); - } - - *retstr = value; - return 0; -} - - - -/* Send a SETATTR command to the SCdaemon. */ -int -agent_scd_setattr (const char *name, - const unsigned char *value, size_t valuelen, - const char *serialno) -{ - app_t app; - int rc; - struct pincb_parm_s parm; - - memset (&parm, 0, sizeof parm); - parm.sn = serialno; - - app = current_app? current_app : open_card (); - if (!app) - return gpg_error (GPG_ERR_CARD); - - 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, &parm, value, valuelen); - } - - status_sc_op_failure (rc); - return rc; -} - - -/* 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 -agent_scd_writekey (int keyno, const char *serialno, - const unsigned char *keydata, size_t keydatalen) -{ - app_t app; - int rc; - char line[ASSUAN_LINELENGTH]; - struct pincb_parm_s parm; - - memset (&parm, 0, sizeof parm); - parm.sn = serialno; - - 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, - pin_cb, &parm, - keydata, keydatalen); - } - - status_sc_op_failure (rc); - return rc; -} - - - -static assuan_error_t -genkey_status_cb (void *opaque, const char *line) -{ - struct agent_card_genkey_s *parm = opaque; - const char *keyword = line; - int keywordlen; - -/* log_debug ("got status line `%s'\n", line); */ - 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; - - while (*line && !spacep (line)) - 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; -} - -/* Send a GENKEY command to the SCdaemon. */ -int -agent_scd_genkey (struct agent_card_genkey_s *info, int keyno, int force, - const char *serialno) -{ - app_t app; - char line[ASSUAN_LINELENGTH]; - struct ctrl_ctx_s ctrl; - int rc; - struct pincb_parm_s parm; - - memset (&parm, 0, sizeof parm); - parm.sn = serialno; - - app = current_app? current_app : open_card (); - if (!app) - return gpg_error (GPG_ERR_CARD); - - memset (info, 0, sizeof *info); - - if (app->assuan_ctx) - { - snprintf (line, DIM(line)-1, "SCD GENKEY %s%d", - force? "--force ":"", keyno); - line[DIM(line)-1] = 0; - rc = test_transact (assuan_transact (app->assuan_ctx, line, - NULL, NULL, NULL, NULL, - genkey_status_cb, info), - "SCD GENKEY"); - } - else - { - snprintf (line, DIM(line)-1, "%d", keyno); - ctrl.status_cb = genkey_status_cb; - ctrl.status_cb_arg = info; - rc = app->fnc.genkey (app, &ctrl, line, - force? 1:0, - pin_cb, &parm); - } - - status_sc_op_failure (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. */ -int -agent_scd_pksign (const char *serialno, int hashalgo, - const unsigned char *indata, size_t indatalen, - unsigned char **r_buf, size_t *r_buflen) -{ - struct pincb_parm_s parm; - app_t app; - int rc; - - *r_buf = NULL; - *r_buflen = 0; - memset (&parm, 0, sizeof parm); - parm.sn = serialno; - retry: - app = current_app? current_app : open_card (); - if (!app) - return gpg_error (GPG_ERR_CARD); - - 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%s", - hashalgo == GCRY_MD_RMD160? "--hash=rmd160 ": "", - 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) - { - status_sc_op_failure (rc); - if (!app->assuan_ctx) - agent_clear_pin_cache (serialno); - } - return rc; -} - - -/* Send a PKDECRYPT command to the SCdaemon. */ -int -agent_scd_pkdecrypt (const char *serialno, - const unsigned char *indata, size_t indatalen, - unsigned char **r_buf, size_t *r_buflen) -{ - struct pincb_parm_s parm; - app_t app; - int rc; - - *r_buf = NULL; - *r_buflen = 0; - memset (&parm, 0, sizeof parm); - parm.sn = serialno; - retry: - app = current_app? current_app : open_card (); - if (!app) - return gpg_error (GPG_ERR_CARD); - - if (app->assuan_ctx) - { - char *p, line[ASSUAN_LINELENGTH]; - membuf_t data; - size_t len; - int i; - - if (indatalen*2 + 50 > DIM(line)) - return gpg_error (GPG_ERR_GENERAL); - - p = stpcpy (line, "SCD SETDATA "); - for (i=0; i < indatalen ; i++, p += 2 ) - sprintf (p, "%02X", indata[i]); - rc = test_transact (assuan_transact (app->assuan_ctx, line, - NULL, NULL, NULL, NULL, NULL, NULL), - "SCD SETDATA"); - if (!rc) - { - init_membuf (&data, 1024); - snprintf (line, DIM(line)-1, "SCD PKDECRYPT %s", serialno); - line[DIM(line)-1] = 0; - rc = test_transact (assuan_transact (app->assuan_ctx, line, - membuf_data_cb, &data, - NULL, NULL, NULL, NULL), - "SCD PKDECRYPT"); - if (rc) - xfree (get_membuf (&data, &len)); - else - *r_buf = get_membuf (&data, r_buflen); - } - } - else - { - /* Check that the card's serialnumber is as required.*/ - rc = check_card_serialno (app, serialno); - if (rc == -1) - goto retry; - - if (!rc) - rc = app->fnc.decipher (app, serialno, - pin_cb, &parm, - indata, indatalen, - r_buf, r_buflen); - } - - if (rc) - { - status_sc_op_failure (rc); - if (!app->assuan_ctx) - agent_clear_pin_cache (serialno); - } - return rc; -} - -/* 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. */ -int -agent_scd_change_pin (int chvno, const char *serialno) -{ - app_t app; - int reset = 0; - int rc; - struct pincb_parm_s parm; - - memset (&parm, 0, sizeof parm); - parm.sn = serialno; - - reset = (chvno >= 100); - chvno %= 100; - - app = current_app? current_app : open_card (); - if (!app) - return gpg_error (GPG_ERR_CARD); - - if (app->assuan_ctx) - { - 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"); - } - else - { - char chvnostr[50]; - - sprintf (chvnostr, "%d", chvno); - rc = app->fnc.change_pin (app, NULL, chvnostr, reset, - pin_cb, &parm); - } - - status_sc_op_failure (rc); - return rc; -} - -/* Perform a CHECKPIN operation. SERIALNO should be the serial - number of the card - optionally followed by the fingerprint; - however the fingerprint is ignored here. */ -int -agent_scd_checkpin (const char *serialnobuf) -{ - app_t app; - int rc; - struct pincb_parm_s parm; - - memset (&parm, 0, sizeof parm); - parm.sn = serialnobuf; - - app = current_app? current_app : open_card (); - if (!app) - return gpg_error (GPG_ERR_CARD); - - if (app->assuan_ctx) - { - 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"); - } - else - { - rc = app->fnc.check_pin (app, serialnobuf, pin_cb, &parm); - } - - status_sc_op_failure (rc); - return rc; -} - - - -void -agent_clear_pin_cache (const char *sn) -{ - char *cacheid = format_cacheid (sn); - if (cacheid) - { - passphrase_clear_cache (NULL, cacheid, 0); - xfree (cacheid); - } -} |