diff options
Diffstat (limited to 'g10/card-util.c')
-rw-r--r-- | g10/card-util.c | 884 |
1 files changed, 0 insertions, 884 deletions
diff --git a/g10/card-util.c b/g10/card-util.c deleted file mode 100644 index c93d028bd..000000000 --- a/g10/card-util.c +++ /dev/null @@ -1,884 +0,0 @@ -/* card-util.c - Utility functions for the OpenPGP card. - * Copyright (C) 2003 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include <config.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> -#include <assert.h> - -#if GNUPG_MAJOR_VERSION != 1 -#include "gpg.h" -#endif -#include "util.h" -#include "i18n.h" -#include "ttyio.h" -#include "status.h" -#include "options.h" -#include "main.h" -#if GNUPG_MAJOR_VERSION == 1 -#include "cardglue.h" -#else -#include "call-agent.h" -#endif - -#define CONTROL_D ('D' - 'A' + 1) - - -/* Change the PIN of a an OpenPGP card. This is an interactive - function. */ -void -change_pin (int chvno) -{ - struct agent_card_info_s info; - int rc; - - rc = agent_learn (&info); - if (rc) - { - log_error (_("OpenPGP card not available: %s\n"), - gpg_strerror (rc)); - return; - } - - log_info (_("OpenPGP card no. %s detected\n"), - info.serialno? info.serialno : "[none]"); - - agent_release_card_info (&info); - - if (opt.batch) - { - log_error (_("sorry, can't do this in batch mode\n")); - return; - } - - for (;;) - { - char *answer; - - tty_printf ("\n"); - tty_printf ("1 - change PIN\n" - "2 - unblock PIN\n" - "3 - change Admin PIN\n" - "Q - quit\n"); - tty_printf ("\n"); - - answer = cpr_get("cardutil.change_pin.menu",_("Your selection? ")); - cpr_kill_prompt(); - if (strlen (answer) != 1) - continue; - - rc = 0; - if (*answer == '1') - { - rc = agent_scd_change_pin (1); - if (rc) - tty_printf ("Error changing the PIN: %s\n", gpg_strerror (rc)); - else - tty_printf ("PIN changed.\n"); - } - else if (*answer == '2') - { - rc = agent_scd_change_pin (101); - if (rc) - tty_printf ("Error unblocking the PIN: %s\n", gpg_strerror (rc)); - else - tty_printf ("PIN unblocked and new PIN set.\n"); - } - else if (*answer == '3') - { - rc = agent_scd_change_pin (3); - if (rc) - tty_printf ("Error changing the PIN: %s\n", gpg_strerror (rc)); - else - tty_printf ("PIN changed.\n"); - } - else if (*answer == 'q' || *answer == 'Q') - { - break; - } - } -} - -static const char * -get_manufacturer (unsigned int no) -{ - /* Note: Make sure that there is no colon or linefeed in the string. */ - switch (no) - { - case 0: - case 0xffff: return "test card"; - case 0x0001: return "PPC Card Systems"; - default: return "unknown"; - } -} - - -static void -print_sha1_fpr (FILE *fp, const unsigned char *fpr) -{ - int i; - - if (fpr) - { - for (i=0; i < 20 ; i+=2, fpr += 2 ) - { - if (i == 10 ) - tty_fprintf (fp, " "); - tty_fprintf (fp, " %02X%02X", *fpr, fpr[1]); - } - } - else - tty_fprintf (fp, " [none]"); - tty_fprintf (fp, "\n"); -} - - -static void -print_sha1_fpr_colon (FILE *fp, const unsigned char *fpr) -{ - int i; - - if (fpr) - { - for (i=0; i < 20 ; i++, fpr++) - fprintf (fp, "%02X", *fpr); - } - putc (':', fp); -} - - -static void -print_name (FILE *fp, const char *text, const char *name) -{ - tty_fprintf (fp, "%s", text); - - /* FIXME: tty_printf_utf8_string2 eats everything after and - including an @ - e.g. when printing an url. */ - if (name && *name) - { - if (fp) - print_utf8_string2 (fp, name, strlen (name), '\n'); - else - tty_print_utf8_string2 (name, strlen (name), 0); - } - else - tty_fprintf (fp, _("[not set]")); - tty_fprintf (fp, "\n"); -} - -static void -print_isoname (FILE *fp, const char *text, const char *tag, const char *name) -{ - if (opt.with_colons) - fprintf (fp, "%s:", tag); - else - tty_fprintf (fp, "%s", text); - - if (name && *name) - { - char *p, *given, *buf = xstrdup (name); - - given = strstr (buf, "<<"); - for (p=buf; *p; p++) - if (*p == '<') - *p = ' '; - if (given && given[2]) - { - *given = 0; - given += 2; - if (opt.with_colons) - print_string (fp, given, strlen (given), ':'); - else if (fp) - print_utf8_string2 (fp, given, strlen (given), '\n'); - else - tty_print_utf8_string2 (given, strlen (given), 0); - - if (opt.with_colons) - putc (':', fp); - else if (*buf) - tty_fprintf (fp, " "); - } - - if (opt.with_colons) - print_string (fp, buf, strlen (buf), ':'); - else if (fp) - print_utf8_string2 (fp, buf, strlen (buf), '\n'); - else - tty_print_utf8_string2 (buf, strlen (buf), 0); - xfree (buf); - } - else - { - if (opt.with_colons) - putc (':', fp); - else - tty_fprintf (fp, _("[not set]")); - } - - if (opt.with_colons) - fputs (":\n", fp); - else - tty_fprintf (fp, "\n"); -} - -/* Return true if the SHA1 fingerprint FPR consists only of zeroes. */ -static int -fpr_is_zero (const char *fpr) -{ - int i; - - for (i=0; i < 20 && !fpr[i]; i++) - ; - return (i == 20); -} - - -/* Print all available information about the current card. */ -void -card_status (FILE *fp, char *serialno, size_t serialnobuflen) -{ - struct agent_card_info_s info; - PKT_public_key *pk = xcalloc (1, sizeof *pk); - int rc; - unsigned int uval; - - if (serialno && serialnobuflen) - *serialno = 0; - - rc = agent_learn (&info); - if (rc) - { - if (opt.with_colons) - fputs ("AID:::\n", fp); - log_error (_("OpenPGP card not available: %s\n"), - gpg_strerror (rc)); - xfree (pk); - return; - } - - if (opt.with_colons) - fprintf (fp, "AID:%s:", info.serialno? info.serialno : ""); - else - tty_fprintf (fp, "Application ID ...: %s\n", - info.serialno? info.serialno : "[none]"); - if (!info.serialno || strncmp (info.serialno, "D27600012401", 12) - || strlen (info.serialno) != 32 ) - { - if (opt.with_colons) - fputs ("unknown:\n", fp); - log_info ("not an OpenPGP card\n"); - agent_release_card_info (&info); - xfree (pk); - return; - } - - if (!serialno) - ; - else if (strlen (serialno)+1 > serialnobuflen) - log_error ("serial number longer than expected\n"); - else - strcpy (serialno, info.serialno); - - if (opt.with_colons) - fputs ("openpgp-card:\n", fp); - - - if (opt.with_colons) - { - fprintf (fp, "version:%.4s:\n", info.serialno+12); - uval = xtoi_2(info.serialno+16)*256 + xtoi_2 (info.serialno+18); - fprintf (fp, "vendor:%04x:%s:\n", uval, get_manufacturer (uval)); - fprintf (fp, "serial:%.8s:\n", info.serialno+20); - - print_isoname (fp, "Name of cardholder: ", "name", info.disp_name); - - fputs ("lang:", fp); - if (info.disp_lang) - print_string (fp, info.disp_lang, strlen (info.disp_lang), ':'); - fputs (":\n", fp); - - fprintf (fp, "sex:%c:\n", (info.disp_sex == 1? 'm': - info.disp_sex == 2? 'f' : 'u')); - - fputs ("url:", fp); - if (info.pubkey_url) - print_string (fp, info.pubkey_url, strlen (info.pubkey_url), ':'); - fputs (":\n", fp); - - fputs ("login:", fp); - if (info.login_data) - print_string (fp, info.login_data, strlen (info.login_data), ':'); - fputs (":\n", fp); - - fprintf (fp, "forcepin:%d:::\n", !info.chv1_cached); - fprintf (fp, "maxpinlen:%d:%d:%d:\n", - info.chvmaxlen[0], info.chvmaxlen[1], info.chvmaxlen[2]); - fprintf (fp, "pinretry:%d:%d:%d:\n", - info.chvretry[0], info.chvretry[1], info.chvretry[2]); - fprintf (fp, "sigcount:%lu:::\n", info.sig_counter); - - fputs ("fpr:", fp); - print_sha1_fpr_colon (fp, info.fpr1valid? info.fpr1:NULL); - print_sha1_fpr_colon (fp, info.fpr2valid? info.fpr2:NULL); - print_sha1_fpr_colon (fp, info.fpr3valid? info.fpr3:NULL); - putc ('\n', fp); - - } - else - { - tty_fprintf (fp, "Version ..........: %.1s%c.%.1s%c\n", - info.serialno[12] == '0'?"":info.serialno+12, - info.serialno[13], - info.serialno[14] == '0'?"":info.serialno+14, - info.serialno[15]); - tty_fprintf (fp, "Manufacturer .....: %s\n", - get_manufacturer (xtoi_2(info.serialno+16)*256 - + xtoi_2 (info.serialno+18))); - tty_fprintf (fp, "Serial number ....: %.8s\n", info.serialno+20); - - print_isoname (fp, "Name of cardholder: ", "name", info.disp_name); - print_name (fp, "Language prefs ...: ", info.disp_lang); - tty_fprintf (fp, "Sex ..............: %s\n", - info.disp_sex == 1? _("male"): - info.disp_sex == 2? _("female") : _("unspecified")); - print_name (fp, "URL of public key : ", info.pubkey_url); - print_name (fp, "Login data .......: ", info.login_data); - tty_fprintf (fp, "Signature PIN ....: %s\n", - info.chv1_cached? _("not forced"): _("forced")); - tty_fprintf (fp, "Max. PIN lengths .: %d %d %d\n", - info.chvmaxlen[0], info.chvmaxlen[1], info.chvmaxlen[2]); - tty_fprintf (fp, "PIN retry counter : %d %d %d\n", - info.chvretry[0], info.chvretry[1], info.chvretry[2]); - tty_fprintf (fp, "Signature counter : %lu\n", info.sig_counter); - tty_fprintf (fp, "Signature key ....:"); - print_sha1_fpr (fp, info.fpr1valid? info.fpr1:NULL); - tty_fprintf (fp, "Encryption key....:"); - print_sha1_fpr (fp, info.fpr2valid? info.fpr2:NULL); - tty_fprintf (fp, "Authentication key:"); - print_sha1_fpr (fp, info.fpr3valid? info.fpr3:NULL); - tty_fprintf (fp, "General key info..: "); - if (info.fpr1valid && !get_pubkey_byfprint (pk, info.fpr1, 20)) - print_pubkey_info (fp, pk); - else - tty_fprintf (fp, "[none]\n"); - } - - free_public_key (pk); - agent_release_card_info (&info); -} - - -static char * -get_one_name (const char *prompt1, const char *prompt2) -{ - char *name; - int i; - - for (;;) - { - name = cpr_get (prompt1, prompt2); - if (!name) - return NULL; - trim_spaces (name); - cpr_kill_prompt (); - for (i=0; name[i] && name[i] >= ' ' && name[i] <= 126; i++) - ; - - /* The name must be in Latin-1 and not UTF-8 - lacking the code - to ensure this we restrict it to ASCII. */ - if (name[i]) - tty_printf (_("Error: Only plain ASCII is currently allowed.\n")); - else if (strchr (name, '<')) - tty_printf (_("Error: The \"<\" character may not be used.\n")); - else if (strstr (name, " ")) - tty_printf (_("Error: Double spaces are not allowed.\n")); - else - return name; - xfree (name); - } -} - - - -static int -change_name (void) -{ - char *surname = NULL, *givenname = NULL; - char *isoname, *p; - int rc; - - surname = get_one_name ("keygen.smartcard.surname", - _("Cardholder's surname: ")); - givenname = get_one_name ("keygen.smartcard.givenname", - _("Cardholder's given name: ")); - if (!surname || !givenname || (!*surname && !*givenname)) - { - xfree (surname); - xfree (givenname); - return -1; /*canceled*/ - } - - isoname = xmalloc ( strlen (surname) + 2 + strlen (givenname) + 1); - strcpy (stpcpy (stpcpy (isoname, surname), "<<"), givenname); - xfree (surname); - xfree (givenname); - for (p=isoname; *p; p++) - if (*p == ' ') - *p = '<'; - - if (strlen (isoname) > 39 ) - { - tty_printf (_("Error: Combined name too long " - "(limit is %d characters).\n"), 39); - xfree (isoname); - return -1; - } - - log_debug ("setting Name to `%s'\n", isoname); - rc = agent_scd_setattr ("DISP-NAME", isoname, strlen (isoname) ); - if (rc) - log_error ("error setting Name: %s\n", gpg_strerror (rc)); - - xfree (isoname); - return rc; -} - - -static int -change_url (void) -{ - char *url; - int rc; - - url = cpr_get ("cardedit.change_url", _("URL to retrieve public key: ")); - if (!url) - return -1; - trim_spaces (url); - cpr_kill_prompt (); - - if (strlen (url) > 254 ) - { - tty_printf (_("Error: URL too long " - "(limit is %d characters).\n"), 254); - xfree (url); - return -1; - } - - rc = agent_scd_setattr ("PUBKEY-URL", url, strlen (url) ); - if (rc) - log_error ("error setting URL: %s\n", gpg_strerror (rc)); - xfree (url); - return rc; -} - -static int -change_login (void) -{ - char *data; - int rc; - - data = cpr_get ("cardedit.change_login", - _("Login data (account name): ")); - if (!data) - return -1; - trim_spaces (data); - cpr_kill_prompt (); - - if (strlen (data) > 254 ) - { - tty_printf (_("Error: Login data too long " - "(limit is %d characters).\n"), 254); - xfree (data); - return -1; - } - - rc = agent_scd_setattr ("LOGIN-DATA", data, strlen (data) ); - if (rc) - log_error ("error setting login data: %s\n", gpg_strerror (rc)); - xfree (data); - return rc; -} - -static int -change_lang (void) -{ - char *data, *p; - int rc; - - data = cpr_get ("cardedit.change_lang", - _("Language preferences: ")); - if (!data) - return -1; - trim_spaces (data); - cpr_kill_prompt (); - - if (strlen (data) > 8 || (strlen (data) & 1)) - { - tty_printf (_("Error: invalid length of preference string.\n")); - xfree (data); - return -1; - } - - for (p=data; *p && *p >= 'a' && *p <= 'z'; p++) - ; - if (*p) - { - tty_printf (_("Error: invalid characters in preference string.\n")); - xfree (data); - return -1; - } - - rc = agent_scd_setattr ("DISP-LANG", data, strlen (data) ); - if (rc) - log_error ("error setting lang: %s\n", gpg_strerror (rc)); - xfree (data); - return rc; -} - - -static int -change_sex (void) -{ - char *data; - const char *str; - int rc; - - data = cpr_get ("cardedit.change_sex", - _("Sex ((M)ale, (F)emale or space): ")); - if (!data) - return -1; - trim_spaces (data); - cpr_kill_prompt (); - - if (!*data) - str = "9"; - else if ((*data == 'M' || *data == 'm') && !data[1]) - str = "1"; - else if ((*data == 'F' || *data == 'f') && !data[1]) - str = "2"; - else - { - tty_printf (_("Error: invalid response.\n")); - xfree (data); - return -1; - } - - rc = agent_scd_setattr ("DISP-SEX", str, 1 ); - if (rc) - log_error ("error setting sex: %s\n", gpg_strerror (rc)); - xfree (data); - return rc; -} - - -static void -toggle_forcesig (void) -{ - struct agent_card_info_s info; - int rc; - int newstate; - - memset (&info, 0, sizeof info); - rc = agent_scd_getattr ("CHV-STATUS", &info); - if (rc) - { - log_error ("error getting current status: %s\n", gpg_strerror (rc)); - return; - } - newstate = !info.chv1_cached; - agent_release_card_info (&info); - - rc = agent_scd_setattr ("CHV-STATUS-1", newstate? "\x01":"", 1); - if (rc) - log_error ("error toggling signature PIN flag: %s\n", gpg_strerror (rc)); -} - - -static void -generate_card_keys (const char *serialno) -{ - struct agent_card_info_s info; - int rc; - int forced_chv1; - - memset (&info, 0, sizeof info); - rc = agent_scd_getattr ("KEY-FPR", &info); - if (!rc) - rc = agent_scd_getattr ("SERIALNO", &info); - if (!rc) - rc = agent_scd_getattr ("CHV-STATUS", &info); - if (!rc) - rc = agent_scd_getattr ("DISP-NAME", &info); - if (rc) - { - log_error ("error getting current key info: %s\n", gpg_strerror (rc)); - return; - } - if ( (info.fpr1valid && !fpr_is_zero (info.fpr1)) - || (info.fpr2valid && !fpr_is_zero (info.fpr2)) - || (info.fpr3valid && !fpr_is_zero (info.fpr3))) - { - tty_printf ("\n"); - log_info ("NOTE: keys are already stored on the card!\n"); - tty_printf ("\n"); - if ( !cpr_get_answer_is_yes( "cardedit.genkeys.replace_keys", - _("Replace existing keys? "))) - { - agent_release_card_info (&info); - return; - } - } - else if (!info.disp_name || !*info.disp_name) - { - tty_printf ("\n"); - tty_printf (_("Please note that the factory settings of the PINs are\n" - " PIN = \"%s\" Admin PIN = \"%s\"\n" - "You should change them using the command --change-pin\n"), - "123456", "12345678"); - tty_printf ("\n"); - } - - forced_chv1 = !info.chv1_cached; - if (forced_chv1) - { /* Switch of the forced mode so that during key generation we - don't get bothered with PIN queries for each - self-signature. */ - rc = agent_scd_setattr ("CHV-STATUS-1", "\x01", 1); - if (rc) - { - log_error ("error clearing forced signature PIN flag: %s\n", - gpg_strerror (rc)); - return; - } - } - - /* Check the PIN now, so that we won't get asked later for each - binding signature. */ - rc = agent_scd_checkpin (serialno); - if (rc) - log_error ("error checking the PIN: %s\n", gpg_strerror (rc)); - else - generate_keypair (NULL, info.serialno); - - agent_release_card_info (&info); - if (forced_chv1) - { /* Switch back to forced state. */ - rc = agent_scd_setattr ("CHV-STATUS-1", "", 1); - if (rc) - { - log_error ("error setting forced signature PIN flag: %s\n", - gpg_strerror (rc)); - return; - } - } -} - -/* Menu to edit all user changeable values on an OpenPGP card. Only - Key creation is not handled here. */ -void -card_edit (STRLIST commands) -{ - enum cmdids { - cmdNOP = 0, - cmdQUIT, cmdHELP, cmdLIST, cmdDEBUG, - cmdNAME, cmdURL, cmdLOGIN, cmdLANG, cmdSEX, - cmdFORCESIG, cmdGENERATE, cmdPASSWD, - cmdINVCMD - }; - - static struct { - const char *name; - enum cmdids id; - const char *desc; - } cmds[] = { - { N_("quit") , cmdQUIT , N_("quit this menu") }, - { N_("q") , cmdQUIT , NULL }, - { N_("help") , cmdHELP , N_("show this help") }, - { "?" , cmdHELP , NULL }, - { N_("list") , cmdLIST , N_("list all available data") }, - { N_("l") , cmdLIST , NULL }, - { N_("debug") , cmdDEBUG , NULL }, - { N_("name") , cmdNAME , N_("change card holder's name") }, - { N_("url") , cmdURL , N_("change URL to retrieve key") }, - { N_("login") , cmdLOGIN , N_("change the login name") }, - { N_("lang") , cmdLANG , N_("change the language preferences") }, - { N_("sex") , cmdSEX , N_("change card holder's sex") }, - { N_("forcesig"), - cmdFORCESIG, N_("toggle the signature force PIN flag") }, - { N_("generate"), - cmdGENERATE, N_("generate new keys") }, - { N_("passwd"), cmdPASSWD, N_("menu to change or unblock the PIN") }, - { NULL, cmdINVCMD } - }; - - enum cmdids cmd = cmdNOP; - int have_commands = !!commands; - int redisplay = 1; - char *answer = NULL; - int did_checkpin = 0; - char serialnobuf[50]; - - - if (opt.command_fd != -1) - ; - else if (opt.batch && !have_commands) - { - log_error(_("can't do that in batchmode\n")); - goto leave; - } - - for (;;) - { - int arg_number; - const char *arg_string = ""; - char *p; - int i; - - tty_printf("\n"); - if (redisplay ) - { - if (opt.with_colons) - { - card_status (stdout, serialnobuf, DIM (serialnobuf)); - fflush (stdout); - } - else - { - card_status (NULL, serialnobuf, DIM (serialnobuf)); - tty_printf("\n"); - } - redisplay = 0; - } - - do - { - xfree (answer); - if (have_commands) - { - if (commands) - { - answer = xstrdup (commands->d); - commands = commands->next; - } - else if (opt.batch) - { - answer = xstrdup ("quit"); - } - else - have_commands = 0; - } - - if (!have_commands) - { - answer = cpr_get_no_help("cardedit.prompt", _("Command> ")); - cpr_kill_prompt(); - } - trim_spaces(answer); - } - while( *answer == '#' ); - - arg_number = 0; /* Yes, here is the init which egcc complains about */ - if (!*answer) - cmd = cmdLIST; /* Default to the list command */ - else if (*answer == CONTROL_D) - cmd = cmdQUIT; - else { - if ((p=strchr (answer,' '))) - { - *p++ = 0; - trim_spaces (answer); - trim_spaces (p); - arg_number = atoi(p); - arg_string = p; - } - - for (i=0; cmds[i].name; i++ ) - if (!ascii_strcasecmp (answer, cmds[i].name )) - break; - - cmd = cmds[i].id; - } - - - switch (cmd) - { - case cmdHELP: - for (i=0; cmds[i].name; i++ ) - if (cmds[i].desc) - tty_printf("%-10s %s\n", cmds[i].name, _(cmds[i].desc) ); - break; - - case cmdLIST: - redisplay = 1; - break; - - case cmdNAME: - change_name (); - break; - - case cmdURL: - change_url (); - break; - - case cmdLOGIN: - change_login (); - break; - - case cmdLANG: - change_lang (); - break; - - case cmdSEX: - change_sex (); - break; - - case cmdFORCESIG: - toggle_forcesig (); - break; - - case cmdGENERATE: - generate_card_keys (serialnobuf); - break; - - case cmdPASSWD: - change_pin (0); - did_checkpin = 0; /* Need to reset it of course. */ - break; - - case cmdQUIT: - goto leave; - - case cmdNOP: - break; - - case cmdINVCMD: - default: - tty_printf ("\n"); - tty_printf (_("Invalid command (try \"help\")\n")); - break; - } /* End command switch. */ - } /* End of main menu loop. */ - - leave: - xfree (answer); -} - |