From 2b5a2eb2d2a04d27dd4fa79bb24254f56f684388 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 4 Aug 2011 14:57:35 +0200 Subject: [PATCH] New option --ssh-fpr for the agent:KEYINFO command Also added the option --data. Hwoever we don't list the other itehms 2.1. does; instead we print dashes. --- .gitignore | 1 + NEWS | 3 +- agent/ChangeLog | 3 + agent/command.c | 194 ++++++++++++++++++++++++++++++------------------ 4 files changed, 126 insertions(+), 75 deletions(-) diff --git a/.gitignore b/.gitignore index 92c467445..eb3806e9c 100644 --- a/.gitignore +++ b/.gitignore @@ -31,6 +31,7 @@ agent/gpg-agent agent/gpg-preset-passphrase agent/gpg-protect-tool agent/t-protect +agent/t-ssh-utils common/libcommon.a common/libcommonpth.a common/libgpgrl.a diff --git a/NEWS b/NEWS index a4dbff251..efa83450a 100644 --- a/NEWS +++ b/NEWS @@ -5,7 +5,8 @@ Noteworthy changes in version 2.0.18 (unreleased) * Bug fix for newer versions of Libgcrypt. - * Support the SSH confirm flag. + * Support the SSH confirm flag and show SSH fingerprint in ssh + related pinentries. * Improved dirmngr/gpgsm interaction for OCSP. diff --git a/agent/ChangeLog b/agent/ChangeLog index 9060a4980..09e60262a 100644 --- a/agent/ChangeLog +++ b/agent/ChangeLog @@ -1,5 +1,8 @@ 2011-08-04 Werner Koch + * command.c (cmd_keyinfo, do_one_keyinfo): Support options --data + and --ssh-fpr. + * command-ssh.c (ssh_identity_register): Display the ssh fingerprint in the prompt. (add_control_entry): Add arg FMTFPR and use it as comment in diff --git a/agent/command.c b/agent/command.c index c300fe59d..97cf507fb 100644 --- a/agent/command.c +++ b/agent/command.c @@ -37,6 +37,7 @@ #include "agent.h" #include #include "i18n.h" +#include "../common/ssh-utils.h" /* maximum allowed size of the inquired ciphertext */ #define MAXLEN_CIPHERTEXT 4096 @@ -72,7 +73,7 @@ struct putval_item_s struct putval_item_s *next; size_t off; /* Offset to the value into DATA. */ size_t len; /* Length of the value. */ - char d[1]; /* Key | Nul | value. */ + char d[1]; /* Key | Nul | value. */ }; @@ -86,14 +87,14 @@ static struct putval_item_s *putval_list; integers and there should be no problem if they are overflowing as callers need to check only whether a counter changed. The actual values are not meaningful. */ -struct +struct { /* Incremented if any of the other counters below changed. */ unsigned int any; /* Incremented if a key is added or removed from the internal privat key database. */ - unsigned int key; + unsigned int key; /* Incremented if a change of the card readers stati has been detected. */ @@ -291,7 +292,7 @@ agent_write_status (ctrl_t ctrl, const char *keyword, ...) va_start (arg_ptr, keyword); - p = buf; + p = buf; n = 0; while ( (text = va_arg (arg_ptr, const char *)) ) { @@ -332,7 +333,7 @@ agent_inq_pinentry_launched (ctrl_t ctrl, unsigned long pid) { char line[100]; - if (!ctrl || !ctrl->server_local + if (!ctrl || !ctrl->server_local || !ctrl->server_local->allow_pinentry_notify) return 0; snprintf (line, DIM(line)-1, "PINENTRY_LAUNCHED %lu", pid); @@ -341,7 +342,7 @@ agent_inq_pinentry_launched (ctrl_t ctrl, unsigned long pid) -static const char hlp_geteventcounter[] = +static const char hlp_geteventcounter[] = "GETEVENTCOUNTER\n" "\n" "Return a a status line named EVENTCOUNTER with the current values\n" @@ -399,7 +400,7 @@ bump_card_eventcounter (void) -static const char hlp_istrusted[] = +static const char hlp_istrusted[] = "ISTRUSTED \n" "\n" "Return OK when we have an entry with this fingerprint in our\n" @@ -439,7 +440,7 @@ cmd_istrusted (assuan_context_t ctx, char *line) } -static const char hlp_listtrusted[] = +static const char hlp_listtrusted[] = "LISTTRUSTED\n" "\n" "List all entries from the trustlist."; @@ -447,7 +448,7 @@ static gpg_error_t cmd_listtrusted (assuan_context_t ctx, char *line) { int rc; - + (void)line; rc = agent_listtrusted (ctx); @@ -457,7 +458,7 @@ cmd_listtrusted (assuan_context_t ctx, char *line) } -static const char hlp_martrusted[] = +static const char hlp_martrusted[] = "MARKTRUSTED \n" "\n" "Store a new key in into the trustlist."; @@ -484,7 +485,7 @@ cmd_marktrusted (assuan_context_t ctx, char *line) for (p=line; i < 40; p++, i++) fpr[i] = *p >= 'a'? (*p & 0xdf): *p; fpr[i] = 0; - + while (spacep (p)) p++; flag = *p++; @@ -542,7 +543,7 @@ cmd_sigkey (assuan_context_t ctx, char *line) } -static const char hlp_setkeydesc[] = +static const char hlp_setkeydesc[] = "SETKEYDESC plus_percent_escaped_string\n" "\n" "Set a description to be used for the next PKSIGN or PKDECRYPT\n" @@ -629,7 +630,7 @@ cmd_sethash (assuan_context_t ctx, char *line) algo = 0; line = skip_options (line); - + if (!algo) { /* No hash option has been given: require an algo number instead */ @@ -649,7 +650,7 @@ cmd_sethash (assuan_context_t ctx, char *line) n /= 2; if (algo == MD_USER_TLS_MD5SHA1 && n == 36) ; - else if (n != 16 && n != 20 && n != 24 + else if (n != 16 && n != 20 && n != 24 && n != 28 && n != 32 && n != 48 && n != 64) return set_error (GPG_ERR_ASS_PARAMETER, "unsupported length of hash"); @@ -666,7 +667,7 @@ cmd_sethash (assuan_context_t ctx, char *line) } -static const char hlp_pksign[] = +static const char hlp_pksign[] = "PKSIGN [options]\n" "\n" "Perform the actual sign operation. Neither input nor output are\n" @@ -678,9 +679,9 @@ cmd_pksign (assuan_context_t ctx, char *line) cache_mode_t cache_mode = CACHE_MODE_NORMAL; ctrl_t ctrl = assuan_get_pointer (ctx); membuf_t outbuf; - + (void)line; - + if (opt.ignore_cache_for_signing) cache_mode = CACHE_MODE_IGNORE; else if (!ctrl->server_local->use_cache_for_signing) @@ -702,7 +703,7 @@ cmd_pksign (assuan_context_t ctx, char *line) } -static const char hlp_pkdecrypt[] = +static const char hlp_pkdecrypt[] = "PKDECRYPT \n" "\n" "Perform the actual decrypt operation. Input is not\n" @@ -741,7 +742,7 @@ cmd_pkdecrypt (assuan_context_t ctx, char *line) } -static const char hlp_genkey[] = +static const char hlp_genkey[] = "GENKEY\n" "\n" "Generate a new key, store the secret part and return the public\n" @@ -787,7 +788,7 @@ cmd_genkey (assuan_context_t ctx, char *line) -static const char hlp_readkey[] = +static const char hlp_readkey[] = "READKEY \n" "\n" "Return the public key for the given keygrip."; @@ -831,16 +832,16 @@ cmd_readkey (assuan_context_t ctx, char *line) -static const char hlp_keyinfo[] = - "KEYINFO [--list] \n" +static const char hlp_keyinfo[] = + "KEYINFO [--list] [--data] [--ssh-fpr] \n" "\n" "Return information about the key specified by the KEYGRIP. If the\n" "key is not available GPG_ERR_NOT_FOUND is returned. If the option\n" "--list is given the keygrip is ignored and information about all\n" "available keys are returned. The information is returned as a\n" - "status line with this format:\n" + "status line unless --data was specified, with this format:\n" "\n" - " KEYINFO \n" + " KEYINFO - - \n" "\n" "KEYGRIP is the keygrip.\n" "\n" @@ -856,12 +857,18 @@ static const char hlp_keyinfo[] = "IDSTR is the IDSTR used to distinguish keys on a smartcard. If it\n" " is not known a dash is used instead.\n" "\n" + "FPR returns the formatted ssh-style fingerprint of the key. It is only\n" + " print if the option --ssh-fpr has been used. '-' is printed if the\n" + " fingerprint is not available.\n" + "\n" "More information may be added in the future."; static gpg_error_t -do_one_keyinfo (ctrl_t ctrl, const unsigned char *grip) +do_one_keyinfo (ctrl_t ctrl, const unsigned char *grip, assuan_context_t ctx, + int data, int with_ssh_fpr) { gpg_error_t err; char hexgrip[40+1]; + char *fpr = NULL; int keytype; unsigned char *shadow_info = NULL; char *serialno = NULL; @@ -874,29 +881,65 @@ do_one_keyinfo (ctrl_t ctrl, const unsigned char *grip) /* Reformat the grip so that we use uppercase as good style. */ bin2hex (grip, 20, hexgrip); - - if (keytype == PRIVATE_KEY_CLEAR + + if (keytype == PRIVATE_KEY_CLEAR || keytype == PRIVATE_KEY_PROTECTED) keytypestr = "D"; else if (keytype == PRIVATE_KEY_SHADOWED) keytypestr = "T"; - else + else keytypestr = "-"; - + + /* Compute the ssh fingerprint if requested. */ + if (with_ssh_fpr) + { + gcry_sexp_t key; + + if (!agent_raw_key_from_file (ctrl, grip, &key)) + { + ssh_get_fingerprint_string (key, &fpr); + gcry_sexp_release (key); + } + } + if (shadow_info) { err = parse_shadow_info (shadow_info, &serialno, &idstr); if (err) goto leave; } - - err = agent_write_status (ctrl, "KEYINFO", - hexgrip, - keytypestr, - serialno? serialno : "-", - idstr? idstr : "-", - NULL); + + /* Note that we don't support the CACHED and PROTECTION values as + gnupg 2.1 does. We print '-' instead. However we support the + ssh fingerprint. */ + if (!data) + err = agent_write_status (ctrl, "KEYINFO", + hexgrip, + keytypestr, + serialno? serialno : "-", + idstr? idstr : "-", + "-", + "-", + fpr? fpr : "-", + NULL); + else + { + char *string; + + string = xtryasprintf ("%s %s %s %s - - %s\n", + hexgrip, keytypestr, + serialno? serialno : "-", + idstr? idstr : "-", + fpr? fpr : "-"); + if (!string) + err = gpg_error_from_syserror (); + else + err = assuan_send_data (ctx, string, strlen(string)); + xfree (string); + } + leave: + xfree (fpr); xfree (shadow_info); xfree (serialno); xfree (idstr); @@ -912,8 +955,11 @@ cmd_keyinfo (assuan_context_t ctx, char *line) unsigned char grip[20]; DIR *dir = NULL; int list_mode; + int opt_data, opt_ssh_fpr; list_mode = has_option (line, "--list"); + opt_data = has_option (line, "--data"); + opt_ssh_fpr = has_option (line, "--ssh-fpr"); line = skip_options (line); if (list_mode) @@ -921,7 +967,7 @@ cmd_keyinfo (assuan_context_t ctx, char *line) char *dirname; struct dirent *dir_entry; char hexgrip[41]; - + dirname = make_filename_try (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, NULL); if (!dirname) { @@ -948,7 +994,7 @@ cmd_keyinfo (assuan_context_t ctx, char *line) if ( hex2bin (hexgrip, grip, 20) < 0 ) continue; /* Bad hex string. */ - err = do_one_keyinfo (ctrl, grip); + err = do_one_keyinfo (ctrl, grip, ctx, opt_data, opt_ssh_fpr); if (err) goto leave; } @@ -959,9 +1005,9 @@ cmd_keyinfo (assuan_context_t ctx, char *line) err = parse_keygrip (ctx, line, grip); if (err) goto leave; - err = do_one_keyinfo (ctrl, grip); + err = do_one_keyinfo (ctrl, grip, ctx, opt_data, opt_ssh_fpr); } - + leave: if (dir) closedir (dir); @@ -998,7 +1044,7 @@ send_back_passphrase (assuan_context_t ctx, int via_data, const char *pw) } -static const char hlp_get_passphrase[] = +static const char hlp_get_passphrase[] = "GET_PASSPHRASE [--data] [--check] [--no-ask] [--repeat[=N]]\n" " [--qualitybar] \n" " [ ]\n" @@ -1119,8 +1165,8 @@ cmd_get_passphrase (assuan_context_t ctx, char *line) plus_to_blank (desc); next_try: - rc = agent_get_passphrase (ctrl, &response, desc, prompt, - repeat_errtext? repeat_errtext:errtext, + rc = agent_get_passphrase (ctrl, &response, desc, prompt, + repeat_errtext? repeat_errtext:errtext, opt_qualbar); xfree (repeat_errtext); repeat_errtext = NULL; @@ -1145,7 +1191,7 @@ cmd_get_passphrase (assuan_context_t ctx, char *line) { xfree (response2); xfree (response); - repeat_errtext = try_percent_escape + repeat_errtext = try_percent_escape (_("does not match - try again"), NULL); if (!repeat_errtext) { @@ -1172,7 +1218,7 @@ cmd_get_passphrase (assuan_context_t ctx, char *line) } -static const char hlp_clear_passphrase[] = +static const char hlp_clear_passphrase[] = "CLEAR_PASSPHRASE \n" "\n" "may be used to invalidate the cache entry for a passphrase. The\n" @@ -1198,7 +1244,7 @@ cmd_clear_passphrase (assuan_context_t ctx, char *line) } -static const char hlp_get_confirmation[] = +static const char hlp_get_confirmation[] = "GET_CONFIRMATION \n" "\n" "This command may be used to ask for a simple confirmation.\n" @@ -1265,7 +1311,7 @@ cmd_learn (assuan_context_t ctx, char *line) -static const char hlp_passwd[] = +static const char hlp_passwd[] = "PASSWD \n" "\n" "Change the passphrase/PIN for the key identified by keygrip in LINE."; @@ -1284,7 +1330,7 @@ cmd_passwd (assuan_context_t ctx, char *line) ctrl->in_passwd++; rc = agent_key_from_file (ctrl, ctrl->server_local->keydesc, - grip, &shadow_info, CACHE_MODE_IGNORE, NULL, + grip, &shadow_info, CACHE_MODE_IGNORE, NULL, &s_skey); if (rc) ; @@ -1309,7 +1355,7 @@ cmd_passwd (assuan_context_t ctx, char *line) } -static const char hlp_preset_passphrase[] = +static const char hlp_preset_passphrase[] = "PRESET_PASSPHRASE \n" "\n" "Set the cached passphrase/PIN for the key identified by the keygrip\n" @@ -1338,7 +1384,7 @@ cmd_preset_passphrase (assuan_context_t ctx, char *line) line++; while (*line && (*line == ' ' || *line == '\t')) line++; - + /* Currently, only infinite timeouts are allowed. */ ttl = -1; if (line[0] != '-' || line[1] != '1') @@ -1378,7 +1424,7 @@ cmd_preset_passphrase (assuan_context_t ctx, char *line) -static const char hlp_scd[] = +static const char hlp_scd[] = "SCD \n" " \n" "This is a general quote command to redirect everything to the\n" @@ -1396,7 +1442,7 @@ cmd_scd (assuan_context_t ctx, char *line) -static const char hlp_getval[] = +static const char hlp_getval[] = "GETVAL \n" "\n" "Return the value for KEY from the special environment as created by\n" @@ -1415,7 +1461,7 @@ cmd_getval (assuan_context_t ctx, char *line) p = strchr (key, ' '); if (p) { - *p++ = 0; + *p++ = 0; for (; *p == ' '; p++) ; if (*p) @@ -1440,7 +1486,7 @@ cmd_getval (assuan_context_t ctx, char *line) } -static const char hlp_putval[] = +static const char hlp_putval[] = "PUTVAL []\n" "\n" "The gpg-agent maintains a kind of environment which may be used to\n" @@ -1474,7 +1520,7 @@ cmd_putval (assuan_context_t ctx, char *line) p = strchr (key, ' '); if (p) { - *p++ = 0; + *p++ = 0; for (; *p == ' '; p++) ; if (*p) @@ -1503,7 +1549,7 @@ cmd_putval (assuan_context_t ctx, char *line) xfree (vl); } - if (valuelen) /* Add entry. */ + if (valuelen) /* Add entry. */ { vl = xtrymalloc (sizeof *vl + strlen (key) + valuelen); if (!vl) @@ -1527,7 +1573,7 @@ cmd_putval (assuan_context_t ctx, char *line) -static const char hlp_updatestartuptty[] = +static const char hlp_updatestartuptty[] = "UPDATESTARTUPTTY\n" "\n" "Set startup TTY and X11 DISPLAY variables to the values of this\n" @@ -1537,7 +1583,7 @@ static const char hlp_updatestartuptty[] = static gpg_error_t cmd_updatestartuptty (assuan_context_t ctx, char *line) { - static const char *names[] = + static const char *names[] = { "GPG_TTY", "DISPLAY", "TERM", "XAUTHORITY", "PINENTRY_USER_DATA", NULL }; ctrl_t ctrl = assuan_get_pointer (ctx); gpg_error_t err = 0; @@ -1545,7 +1591,7 @@ cmd_updatestartuptty (assuan_context_t ctx, char *line) int idx; char *lc_ctype = NULL; char *lc_messages = NULL; - + (void)line; se = session_env_new (); @@ -1559,14 +1605,14 @@ cmd_updatestartuptty (assuan_context_t ctx, char *line) err = session_env_setenv (se, names[idx], value); } - if (!err && ctrl->lc_ctype) + if (!err && ctrl->lc_ctype) if (!(lc_ctype = xtrystrdup (ctrl->lc_ctype))) err = gpg_error_from_syserror (); if (!err && ctrl->lc_messages) if (!(lc_messages = xtrystrdup (ctrl->lc_messages))) err = gpg_error_from_syserror (); - + if (err) { session_env_release (se); @@ -1599,7 +1645,7 @@ cmd_killagent (assuan_context_t ctx, char *line) ctrl_t ctrl = assuan_get_pointer (ctx); (void)line; - + if (!opt.use_standard_socket) return set_error (GPG_ERR_NOT_SUPPORTED, "no --use-standard-socket"); @@ -1625,7 +1671,7 @@ cmd_reloadagent (assuan_context_t ctx, char *line) -static const char hlp_getinfo[] = +static const char hlp_getinfo[] = "GETINFO \n" "\n" "Multipurpose function to return a variety of information.\n" @@ -1693,15 +1739,15 @@ cmd_getinfo (assuan_context_t ctx, char *line) int iterator; const char *name, *value; char *string; - - iterator = 0; + + iterator = 0; while ((name = session_env_list_stdenvnames (&iterator, NULL))) { value = session_env_getenv_or_default (line[5] == 't'? opt.startup_env:ctrl->session_env, name, NULL); if (value) { - string = xtryasprintf ("%s=%s", name, value); + string = xtryasprintf ("%s=%s", name, value); if (!string) rc = gpg_error_from_syserror (); else @@ -1827,7 +1873,7 @@ static void post_cmd_notify (assuan_context_t ctx, gpg_error_t err) { ctrl_t ctrl = assuan_get_pointer (ctx); - + (void)err; /* Switch off any I/O monitor controlled logging pausing. */ @@ -1844,7 +1890,7 @@ io_monitor (assuan_context_t ctx, void *hook, int direction, const char *line, size_t linelen) { ctrl_t ctrl = assuan_get_pointer (ctx); - + (void) hook; /* Note that we only check for the uppercase name. This allows to @@ -1871,7 +1917,7 @@ command_has_option (const char *cmd, const char *cmdopt) if (!strcmp (cmdopt, "repeat")) return 1; } - + return 0; } @@ -1905,8 +1951,8 @@ register_commands (assuan_context_t ctx) { "MARKTRUSTED", cmd_marktrusted, hlp_martrusted }, { "LEARN", cmd_learn, hlp_learn }, { "PASSWD", cmd_passwd, hlp_passwd }, - { "INPUT", NULL }, - { "OUTPUT", NULL }, + { "INPUT", NULL }, + { "OUTPUT", NULL }, { "SCD", cmd_scd, hlp_scd }, { "GETVAL", cmd_getval, hlp_getval }, { "PUTVAL", cmd_putval, hlp_putval }, @@ -1924,7 +1970,7 @@ register_commands (assuan_context_t ctx) table[i].help); if (rc) return rc; - } + } assuan_register_post_cmd_notify (ctx, post_cmd_notify); assuan_register_reset_notify (ctx, reset_notify); assuan_register_option_handler (ctx, option_handler); @@ -1963,7 +2009,7 @@ start_command_handler (ctrl_t ctrl, gnupg_fd_t listen_fd, gnupg_fd_t fd) /* FIXME: Need to call assuan_sock_set_nonce for Windows. But this branch is currently not used. */ } - else + else { rc = assuan_init_socket_server (ctx, fd, ASSUAN_SOCKET_SERVER_ACCEPTED); } @@ -2002,7 +2048,7 @@ start_command_handler (ctrl_t ctrl, gnupg_fd_t listen_fd, gnupg_fd_t fd) log_info ("Assuan accept problem: %s\n", gpg_strerror (rc)); break; } - + rc = assuan_process (ctx); if (rc) {