diff --git a/g10/ChangeLog b/g10/ChangeLog index e0d19d79a..be759ba91 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,3 +1,24 @@ +2004-12-09 Werner Koch + + * passphrase.c (agent_get_passphrase): New args CUSTOM_PROMPT and + CUSTOM_DESCRIPTION. Changed all callers. + + * app-openpgp.c (do_getattr, do_learn_status, do_setattr): Support + the new private DOs. + (do_change_pin): Add a "N" prefix to the strings so that the + callback can act accordingly for a new PIN. Unfortunately this + breaks existing translations but I see no wother way to overvome + this. + + * cardglue.c (learn_status_cb): Ditto. + (agent_release_card_info): Ditto. + (struct pin_cb_info_s): Removed and changed all users. + (pin_cb): Reworked. + + * card-util.c (card_status): Print them + (card_edit): New command PRIVATEDO. + (change_private_do): New. + 2004-12-09 David Shaw * keygen.c (ask_algo): Add a choose-your-own-capabilities option diff --git a/g10/app-openpgp.c b/g10/app-openpgp.c index 163974cab..24fe61649 100644 --- a/g10/app-openpgp.c +++ b/g10/app-openpgp.c @@ -81,6 +81,10 @@ static struct { { 0x00C6, 0, 0x6E, 1, 0, 0, 0, "CA Fingerprints" }, { 0x007A, 1, 0, 1, 0, 0, 0, "Security Support Template" }, { 0x0093, 0, 0x7A, 1, 1, 0, 0, "Digital Signature Counter" }, + { 0x0101, 0, 0, 0, 0, 0, 0, "Private DO 1"}, + { 0x0102, 0, 0, 0, 0, 0, 0, "Private DO 2"}, + { 0x0103, 0, 0, 0, 0, 0, 0, "Private DO 3"}, + { 0x0104, 0, 0, 0, 0, 0, 0, "Private DO 4"}, { 0 } }; @@ -613,6 +617,10 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name) { "SERIALNO", 0x004F, -1 }, { "AID", 0x004F }, { "EXTCAP", 0x0000, -2 }, + { "PRIVATE-DO-1", 0x0101 }, + { "PRIVATE-DO-2", 0x0102 }, + { "PRIVATE-DO-3", 0x0103 }, + { "PRIVATE-DO-4", 0x0104 }, { NULL, 0 } }; int idx, i; @@ -708,6 +716,15 @@ do_learn_status (app_t app, ctrl_t ctrl) do_getattr (app, ctrl, "CA-FPR"); do_getattr (app, ctrl, "CHV-STATUS"); do_getattr (app, ctrl, "SIG-COUNTER"); + if (app->app_local->extcap.private_dos) + { + do_getattr (app, ctrl, "PRIVATE-DO-1"); + do_getattr (app, ctrl, "PRIVATE-DO-2"); + if (app->did_chv2) + do_getattr (app, ctrl, "PRIVATE-DO-3"); + if (app->did_chv3) + do_getattr (app, ctrl, "PRIVATE-DO-4"); + } return 0; } @@ -867,17 +884,22 @@ do_setattr (app_t app, const char *name, static struct { const char *name; int tag; + int need_chv; int special; } table[] = { - { "DISP-NAME", 0x005B }, - { "LOGIN-DATA", 0x005E, 2 }, - { "DISP-LANG", 0x5F2D }, - { "DISP-SEX", 0x5F35 }, - { "PUBKEY-URL", 0x5F50 }, - { "CHV-STATUS-1", 0x00C4, 1 }, - { "CA-FPR-1", 0x00CA }, - { "CA-FPR-2", 0x00CB }, - { "CA-FPR-3", 0x00CC }, + { "DISP-NAME", 0x005B, 3 }, + { "LOGIN-DATA", 0x005E, 3, 2 }, + { "DISP-LANG", 0x5F2D, 3 }, + { "DISP-SEX", 0x5F35, 3 }, + { "PUBKEY-URL", 0x5F50, 3 }, + { "CHV-STATUS-1", 0x00C4, 3, 1 }, + { "CA-FPR-1", 0x00CA, 3 }, + { "CA-FPR-2", 0x00CB, 3 }, + { "CA-FPR-3", 0x00CC, 3 }, + { "PRIVATE-DO-1", 0x0101, 2 }, + { "PRIVATE-DO-2", 0x0102, 3 }, + { "PRIVATE-DO-3", 0x0103, 2 }, + { "PRIVATE-DO-4", 0x0104, 3 }, { NULL, 0 } }; @@ -887,7 +909,17 @@ do_setattr (app_t app, const char *name, if (!table[idx].name) return gpg_error (GPG_ERR_INV_NAME); - rc = verify_chv3 (app, pincb, pincb_arg); + switch (table[idx].need_chv) + { + case 2: + rc = verify_chv2 (app, pincb, pincb_arg); + break; + case 3: + rc = verify_chv3 (app, pincb, pincb_arg); + break; + default: + rc = 0; + } if (rc) return rc; @@ -956,10 +988,10 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr, int reset_mode, else app->did_chv1 = app->did_chv2 = 0; - /* Note to translators: Do not translate the "|A|" prefix but + /* Note to translators: Do not translate the "|*|" prefixes but keep it at the start of the string. We need this elsewhere to get some infos on the string. */ - rc = pincb (pincb_arg, chvno == 3? _("|A|New Admin PIN") : _("New PIN"), + rc = pincb (pincb_arg, chvno == 3? _("|AN|New Admin PIN") : _("|N|New PIN"), &pinvalue); if (rc) { diff --git a/g10/card-util.c b/g10/card-util.c index 066db0c3a..031d59127 100644 --- a/g10/card-util.c +++ b/g10/card-util.c @@ -377,6 +377,14 @@ card_status (FILE *fp, char *serialno, size_t serialnobuflen) info.disp_sex == 2? _("female") : _("unspecified")); print_name (fp, "URL of public key : ", info.pubkey_url); print_name (fp, "Login data .......: ", info.login_data); + if (info.private_do[0]) + print_name (fp, "Private DO 1 .....: ", info.private_do[0]); + if (info.private_do[1]) + print_name (fp, "Private DO 2 .....: ", info.private_do[1]); + if (info.private_do[2]) + print_name (fp, "Private DO 3 .....: ", info.private_do[2]); + if (info.private_do[3]) + print_name (fp, "Private DO 4 .....: ", info.private_do[3]); if (info.cafpr1valid) { tty_fprintf (fp, "CA fingerprint %d .:", 1); @@ -631,6 +639,75 @@ change_login (const char *args) return rc; } +static int +change_private_do (const char *args, int nr) +{ + char do_name[] = "PRIVATE-DO-X"; + char *data; + int n; + int rc; + + assert (nr >= 1 && nr <= 4); + do_name[11] = '0' + nr; + + if (args && (args = strchr (args, '<'))) /* Read it from a file */ + { + FILE *fp; + + /* Fixme: Factor this duplicated code out. */ + for (args++; spacep (args); args++) + ; + fp = fopen (args, "rb"); +#if GNUPG_MAJOR_VERSION == 1 + if (fp && is_secured_file (fileno (fp))) + { + fclose (fp); + fp = NULL; + errno = EPERM; + } +#endif + if (!fp) + { + tty_printf (_("can't open `%s': %s\n"), args, strerror (errno)); + return -1; + } + + data = xmalloc (254); + n = fread (data, 1, 254, fp); + fclose (fp); + if (n < 0) + { + tty_printf (_("error reading `%s': %s\n"), args, strerror (errno)); + xfree (data); + return -1; + } + } + else + { + data = cpr_get ("cardedit.change_private_do", + _("Private DO data: ")); + if (!data) + return -1; + trim_spaces (data); + cpr_kill_prompt (); + n = strlen (data); + } + + if (n > 254 ) + { + tty_printf (_("Error: Private DO too long " + "(limit is %d characters).\n"), 254); + xfree (data); + return -1; + } + + rc = agent_scd_setattr (do_name, data, n ); + if (rc) + log_error ("error setting private DO: %s\n", gpg_strerror (rc)); + xfree (data); + return rc; +} + static int change_lang (void) { @@ -1149,7 +1226,7 @@ card_edit (STRLIST commands) cmdNOP = 0, cmdQUIT, cmdADMIN, cmdHELP, cmdLIST, cmdDEBUG, cmdNAME, cmdURL, cmdFETCH, cmdLOGIN, cmdLANG, cmdSEX, cmdCAFPR, - cmdFORCESIG, cmdGENERATE, cmdPASSWD, + cmdFORCESIG, cmdGENERATE, cmdPASSWD, cmdPRIVATEDO, cmdINVCMD }; @@ -1180,6 +1257,8 @@ card_edit (STRLIST commands) { N_("generate"), cmdGENERATE, 1, N_("generate new keys") }, { N_("passwd"), cmdPASSWD, 0, N_("menu to change or unblock the PIN") }, + /* Note, that we do not announce this command yet. */ + { N_("privatedo"), cmdPRIVATEDO, 0, NULL }, { NULL, cmdINVCMD, 0, NULL } }; @@ -1335,6 +1414,14 @@ card_edit (STRLIST commands) change_cafpr (arg_number); break; + case cmdPRIVATEDO: + if ( arg_number < 1 || arg_number > 4 ) + tty_printf ("usage: privatedo N\n" + " 1 <= N <= 4\n"); + else + change_private_do (arg_string, arg_number); + break; + case cmdFORCESIG: toggle_forcesig (); break; diff --git a/g10/cardglue.c b/g10/cardglue.c index 1b57b79d9..48991633c 100644 --- a/g10/cardglue.c +++ b/g10/cardglue.c @@ -49,12 +49,6 @@ struct ctrl_ctx_s { }; -struct pin_cb_info_s -{ - int repeat; -}; - - static char *default_reader_port; static APP current_app; @@ -233,6 +227,8 @@ app_get_serial_and_stamp (APP app, char **serial, time_t *stamp) void agent_release_card_info (struct agent_card_info_s *info) { + int i; + if (!info) return; @@ -243,6 +239,11 @@ agent_release_card_info (struct agent_card_info_s *info) 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; + } } @@ -471,6 +472,7 @@ learn_status_cb (void *opaque, const char *line) int keywordlen; int i; +/* log_debug ("got status line `%s'\n", line); */ for (keywordlen=0; *line && !spacep (line); line++, keywordlen++) ; while (spacep (line)) @@ -570,7 +572,15 @@ learn_status_cb (void *opaque, const char *line) 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_status_string (line); + } + return 0; } @@ -626,21 +636,28 @@ agent_scd_getattr (const char *name, struct agent_card_info_s *info) static int pin_cb (void *opaque, const char *info, char **retstr) { - struct pin_cb_info_s *parm = opaque; char *value; int canceled; int isadmin = 0; + int newpin = 0; const char *again_text = NULL; + const char *ends, *s; *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 && !strncmp (info, "|A|", 3)) + if (info && *info =='|' && (ends=strchr (info+1, '|'))) { - isadmin = 1; - info += 3; + for (s=info+1; s < ends; s++) + { + if (*s == 'A') + isadmin = 1; + else if (*s == 'N') + newpin = 1; + } + info = ends+1; } again: @@ -649,8 +666,12 @@ pin_cb (void *opaque, const char *info, char **retstr) isadmin? "OPENPGP 3" : "OPENPGP 1"); value = ask_passphrase (info, again_text, - isadmin? "passphrase.adminpin.ask" - : "passphrase.pin.ask", + 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: "), &canceled); @@ -660,7 +681,7 @@ pin_cb (void *opaque, const char *info, char **retstr) else if (!value) return G10ERR_GENERAL; - if (parm->repeat) + if (newpin) { char *value2; @@ -701,15 +722,12 @@ agent_scd_setattr (const char *name, const unsigned char *value, size_t valuelen) { APP app; - struct pin_cb_info_s parm; - - memset (&parm, 0, sizeof parm); app = current_app? current_app : open_card (); if (!app) return gpg_error (GPG_ERR_CARD); - return app->fnc.setattr (app, name, pin_cb, &parm, value, valuelen); + return app->fnc.setattr (app, name, pin_cb, NULL, value, valuelen); } @@ -772,9 +790,6 @@ agent_scd_genkey (struct agent_card_genkey_s *info, int keyno, int force) APP app; char keynostr[20]; struct ctrl_ctx_s ctrl; - struct pin_cb_info_s parm; - - memset (&parm, 0, sizeof parm); app = current_app? current_app : open_card (); if (!app) @@ -787,7 +802,7 @@ agent_scd_genkey (struct agent_card_genkey_s *info, int keyno, int force) return app->fnc.genkey (app, &ctrl, keynostr, force? 1:0, - pin_cb, &parm); + pin_cb, NULL); } /* Send a PKSIGN command to the SCdaemon. */ @@ -798,9 +813,6 @@ agent_scd_pksign (const char *serialno, int hashalgo, { APP app; int rc; - struct pin_cb_info_s parm; - - memset (&parm, 0, sizeof parm); *r_buf = NULL; *r_buflen = 0; @@ -817,7 +829,7 @@ agent_scd_pksign (const char *serialno, int hashalgo, return rc; return app->fnc.sign (app, serialno, hashalgo, - pin_cb, &parm, + pin_cb, NULL, indata, indatalen, r_buf, r_buflen); } @@ -831,9 +843,6 @@ agent_scd_pkdecrypt (const char *serialno, { APP app; int rc; - struct pin_cb_info_s parm; - - memset (&parm, 0, sizeof parm); *r_buf = NULL; *r_buflen = 0; @@ -850,7 +859,7 @@ agent_scd_pkdecrypt (const char *serialno, return rc; return app->fnc.decipher (app, serialno, - pin_cb, &parm, + pin_cb, NULL, indata, indatalen, r_buf, r_buflen); } @@ -862,10 +871,6 @@ agent_scd_change_pin (int chvno) APP app; char chvnostr[20]; int reset = 0; - struct pin_cb_info_s parm; - - memset (&parm, 0, sizeof parm); - parm.repeat = 1; reset = (chvno >= 100); chvno %= 100; @@ -876,7 +881,7 @@ agent_scd_change_pin (int chvno) sprintf (chvnostr, "%d", chvno); return app->fnc.change_pin (app, NULL, chvnostr, reset, - pin_cb, &parm); + pin_cb, NULL); } /* Perform a CHECKPIN operation. SERIALNO should be the serial @@ -886,15 +891,12 @@ int agent_scd_checkpin (const char *serialnobuf) { APP app; - struct pin_cb_info_s parm; - - memset (&parm, 0, sizeof parm); app = current_app? current_app : open_card (); if (!app) return gpg_error (GPG_ERR_CARD); - return app->fnc.check_pin (app, serialnobuf, pin_cb, &parm); + return app->fnc.check_pin (app, serialnobuf, pin_cb, NULL); } @@ -907,9 +909,6 @@ agent_openpgp_storekey (int keyno, const unsigned char *e, size_t elen) { APP app; - struct pin_cb_info_s parm; - - memset (&parm, 0, sizeof parm); app = current_app? current_app : open_card (); if (!app) @@ -917,5 +916,5 @@ agent_openpgp_storekey (int keyno, return app_openpgp_storekey (app, keyno, template, template_len, created_at, m, mlen, e, elen, - pin_cb, &parm); + pin_cb, NULL); } diff --git a/g10/cardglue.h b/g10/cardglue.h index 812d44e2e..1160b32ed 100644 --- a/g10/cardglue.h +++ b/g10/cardglue.h @@ -37,6 +37,7 @@ struct agent_card_info_s { int disp_sex; /* 0 = unspecified, 1 = male, 2 = female */ char *pubkey_url; /* malloced. */ char *login_data; /* malloced. */ + char *private_do[4]; /* malloced. */ char cafpr1valid; char cafpr2valid; char cafpr3valid; diff --git a/g10/passphrase.c b/g10/passphrase.c index d63ba6719..3b1491878 100644 --- a/g10/passphrase.c +++ b/g10/passphrase.c @@ -630,7 +630,8 @@ agent_close ( int fd ) */ static char * agent_get_passphrase ( u32 *keyid, int mode, const char *tryagain_text, - int *canceled) + const char *custom_description, + const char *custom_prompt, int *canceled) { #if defined(__riscos__) return NULL; @@ -648,6 +649,7 @@ agent_get_passphrase ( u32 *keyid, int mode, const char *tryagain_text, int prot; char *orig_codeset = NULL; + log_debug ("agent_get_passphrase tryagin='%s' prompt='%s'\n", tryagain_text, custom_prompt); if (canceled) *canceled = 0; @@ -663,7 +665,7 @@ agent_get_passphrase ( u32 *keyid, int mode, const char *tryagain_text, } #ifdef ENABLE_NLS - /* The Assuan agent protol requires us to trasnmit utf-8 strings */ + /* The Assuan agent protol requires us to transmit utf-8 strings */ orig_codeset = bind_textdomain_codeset (PACKAGE, NULL); #ifdef HAVE_LANGINFO_CODESET if (!orig_codeset) @@ -680,7 +682,9 @@ agent_get_passphrase ( u32 *keyid, int mode, const char *tryagain_text, if ( (fd = agent_open (&prot)) == -1 ) goto failure; - if ( !mode && pk && keyid ) + if (custom_description) + atext = native_to_utf8 (custom_description); + else if ( !mode && pk && keyid ) { char *uid; size_t uidlen; @@ -818,9 +822,12 @@ agent_get_passphrase ( u32 *keyid, int mode, const char *tryagain_text, tryagain_text = _(tryagain_text); /* We allocate 2 time the needed space for atext so that there - is nenough space for escaping */ + is enough space for escaping */ line = m_alloc (15 + 46 - + 3*strlen (tryagain_text) + 3*strlen (atext) + 2); + + 3*strlen (tryagain_text) + + 3*strlen (atext) + + 3*strlen (custom_prompt? custom_prompt:"") + + 2); strcpy (line, "GET_PASSPHRASE "); p = line+15; if (!mode && have_fpr) @@ -844,7 +851,28 @@ agent_get_passphrase ( u32 *keyid, int mode, const char *tryagain_text, *p++ = *s; } *p++ = ' '; - *p++ = 'X'; /* Use the standard prompt */ + + /* The prompt. */ + if (custom_prompt) + { + char *tmp = native_to_utf8 (custom_prompt); + for (i=0, s=tmp; *s; s++) + { + if (*s < ' ' || *s == '+') + { + sprintf (p, "%%%02X", *s); + p += 3; + } + else if (*s == ' ') + *p++ = '+'; + else + *p++ = *s; + } + xfree (tmp); + } + else + *p++ = 'X'; /* Use the standard prompt */ + *p++ = ' '; /* copy description */ for (i=0, s= atext; *s; s++) @@ -1047,7 +1075,7 @@ ask_passphrase (const char *description, if ( opt.use_agent ) { pw = agent_get_passphrase (NULL, 0, - tryagain_text? tryagain_text :description, + tryagain_text, description, prompt, canceled ); if (!pw) { @@ -1188,9 +1216,9 @@ passphrase_to_dek( u32 *keyid, int pubkey_algo, next_pw = NULL; } else if ( opt.use_agent ) { - /* Divert to teh gpg-agent. */ + /* Divert to the gpg-agent. */ pw = agent_get_passphrase ( keyid, mode == 2? 1: 0, - tryagain_text, canceled ); + tryagain_text, NULL, NULL, canceled ); if (!pw) { if (!opt.use_agent) @@ -1198,7 +1226,8 @@ passphrase_to_dek( u32 *keyid, int pubkey_algo, pw = m_strdup (""); } if( *pw && mode == 2 ) { - char *pw2 = agent_get_passphrase ( keyid, 2, NULL, canceled ); + char *pw2 = agent_get_passphrase ( keyid, 2, NULL, NULL, + NULL, canceled ); if (!pw2) { if (!opt.use_agent)