diff options
author | Werner Koch <wk@gnupg.org> | 2024-01-26 09:41:00 +0100 |
---|---|---|
committer | Werner Koch <wk@gnupg.org> | 2024-01-26 09:41:00 +0100 |
commit | dfa60c09f5cd992515df5fdb275dbee7f8f23b71 (patch) | |
tree | e68215d4b947727fa98eb8c95244b8819b058b1e /tools | |
parent | gpg: Clean up pk_ecdh_decrypt function. (diff) | |
parent | Post release updates (diff) | |
download | gnupg2-dfa60c09f5cd992515df5fdb275dbee7f8f23b71.tar.xz gnupg2-dfa60c09f5cd992515df5fdb275dbee7f8f23b71.zip |
Merge branch 'STABLE-BRANCH-2-4'
--
Fixed conflicts:
NEWS
configure.ac
doc/gpg.texi
Diffstat (limited to 'tools')
-rw-r--r-- | tools/card-call-scd.c | 92 | ||||
-rw-r--r-- | tools/gpg-card.c | 142 | ||||
-rw-r--r-- | tools/gpg-card.h | 2 | ||||
-rw-r--r-- | tools/gpgconf.c | 128 |
4 files changed, 309 insertions, 55 deletions
diff --git a/tools/card-call-scd.c b/tools/card-call-scd.c index 17815c61b..f8557e32b 100644 --- a/tools/card-call-scd.c +++ b/tools/card-call-scd.c @@ -1530,14 +1530,16 @@ scd_readkey (const char *keyrefstr, int create_shadow, gcry_sexp_t *r_result) unsigned char *buf; size_t len, buflen; - *r_result = NULL; + if (r_result) + *r_result = NULL; err = start_agent (0); if (err) return err; init_membuf (&data, 1024); if (create_shadow) - snprintf (line, DIM(line), "READKEY --card -- %s", keyrefstr); + snprintf (line, DIM(line), "READKEY %s--card -- %s", + r_result? "" : "--no-data ", keyrefstr); else snprintf (line, DIM(line), "SCD READKEY %s", keyrefstr); err = assuan_transact (agent_ctx, line, @@ -1553,7 +1555,7 @@ scd_readkey (const char *keyrefstr, int create_shadow, gcry_sexp_t *r_result) if (!buf) return gpg_error_from_syserror (); - err = gcry_sexp_new (r_result, buf, buflen, 0); + err = r_result ? gcry_sexp_new (r_result, buf, buflen, 0) : 0; xfree (buf); return err; @@ -1770,6 +1772,90 @@ agent_get_s2k_count (void) } + +struct havekey_status_parm_s +{ + char *string; +}; + +static gpg_error_t +havekey_status_cb (void *opaque, const char *line) +{ + struct havekey_status_parm_s *parm = opaque; + const char *s; + char *p; + + if ((s = has_leading_keyword (line, "KEYFILEINFO"))) + { + xfree (parm->string); + parm->string = xtrystrdup (s); + if (!parm->string) + return gpg_error_from_syserror (); + p = strchr (parm->string, ' '); + if (p) + *p = 0; + } + + return 0; +} + + +/* Run the HAVEKEY --info command and stores the retrieved string at + * R_RESULT. Caller must free that string. If an error is returned + * R_RESULT is set to NULL. */ +gpg_error_t +scd_havekey_info (const unsigned char *grip, char **r_result) +{ + gpg_error_t err; + char line[ASSUAN_LINELENGTH]; + struct havekey_status_parm_s parm = {NULL}; + + *r_result = NULL; + + err = start_agent (0); + if (err) + return err; + + snprintf (line, sizeof line, "HAVEKEY --info "); + log_assert (ASSUAN_LINELENGTH > strlen(line) + 2*KEYGRIP_LEN + 10); + bin2hex (grip, KEYGRIP_LEN, line+strlen(line)); + + err = assuan_transact (agent_ctx, line, + NULL, NULL, NULL, NULL, + havekey_status_cb, &parm); + if (err) + xfree (parm.string); + else + *r_result = parm.string; + return err; +} + + +/* Run the DELETE_KEY command. If FORCE is given the user will not be + * asked for confirmation. */ +gpg_error_t +scd_delete_key (const unsigned char *grip, int force) +{ + gpg_error_t err; + char line[ASSUAN_LINELENGTH]; + struct default_inq_parm_s dfltparm = {NULL}; + + err = start_agent (0); + if (err) + return err; + dfltparm.ctx = agent_ctx; + + snprintf (line, sizeof line, "DELETE_KEY%s ", force?" --force":""); + log_assert (ASSUAN_LINELENGTH > strlen(line) + 2*KEYGRIP_LEN + 10); + bin2hex (grip, KEYGRIP_LEN, line+strlen(line)); + + err = assuan_transact (agent_ctx, line, + NULL, NULL, default_inq_cb, &dfltparm, NULL, NULL); + return err; +} + + + /* Return a malloced string describing the statusword SW. On error * NULL is returned. */ char * diff --git a/tools/gpg-card.c b/tools/gpg-card.c index e66348232..056cdca66 100644 --- a/tools/gpg-card.c +++ b/tools/gpg-card.c @@ -582,13 +582,14 @@ print_shax_fpr (estream_t fp, const unsigned char *fpr, unsigned int fprlen) /* Print the keygrip GRP. */ static void -print_keygrip (estream_t fp, const unsigned char *grp) +print_keygrip (estream_t fp, const unsigned char *grp, int with_lf) { int i; for (i=0; i < 20 ; i++, grp++) tty_fprintf (fp, "%02X", *grp); - tty_fprintf (fp, "\n"); + if (with_lf) + tty_fprintf (fp, "\n"); } @@ -700,7 +701,7 @@ list_one_kinfo (card_info_t info, key_info_t kinfo, goto leave; } - print_keygrip (fp, kinfo->grip); + print_keygrip (fp, kinfo->grip, 1); tty_fprintf (fp, " keyref .....: %s", kinfo->keyref); if (kinfo->usage) { @@ -1376,6 +1377,137 @@ cmd_list (card_info_t info, char *argstr) } + +/* The CHECKKEYS command. */ +static gpg_error_t +cmd_checkkeys (card_info_t callerinfo, char *argstr) +{ + gpg_error_t err; + estream_t fp = opt.interactive? NULL : es_stdout; + strlist_t cards = NULL; + strlist_t sl; + int opt_ondisk; + int opt_delete_clear; + int opt_delete_protected; + int delete_count = 0; + struct card_info_s info_buffer = { 0 }; + card_info_t info = &info_buffer; + key_info_t kinfo; + + + if (!callerinfo) + return print_help + ("CHECKKEYS [--ondisk] [--delete-clear-copy] [--delete-protected-copy]" + "\n\n" + "Print a list of keys on all inserted cards. With --ondisk only\n" + "keys are listed which also have a copy on disk. Missing shadow\n" + "keys are created. With --delete-clear-copy, copies of keys also\n" + "stored on disk without any protection will be deleted.\n" + , 0); + + + opt_ondisk = has_leading_option (argstr, "--ondisk"); + opt_delete_clear = has_leading_option (argstr, "--delete-clear-copy"); + opt_delete_protected = has_leading_option (argstr, "--delete-protected-copy"); + argstr = skip_options (argstr); + + if (*argstr) + { + /* No args expected */ + err = gpg_error (GPG_ERR_INV_ARG); + goto leave; + } + + if (!callerinfo->serialno) + { + /* This is probably the first call We need to send a SERIALNO + * command to scdaemon so that our session knows all cards. */ + err = scd_serialno (NULL, NULL); + if (err) + goto leave; + } + + /* Get the list of all cards. */ + err = scd_cardlist (&cards); + if (err) + goto leave; + + /* Loop over all cards. We use our own info buffer here. */ + for (sl = cards; sl; sl = sl->next) + { + err = scd_switchcard (sl->d); + if (err) + { + log_error ("Error switching to card %s: %s\n", + sl->d, gpg_strerror (err)); + continue; + } + release_card_info (info); + err = scd_learn (info, 0); + if (err) + { + log_error ("Error getting infos from card %s: %s\n", + sl->d, gpg_strerror (err)); + continue; + } + + for (kinfo = info->kinfo; kinfo; kinfo = kinfo->next) + { + char *infostr; + + err = scd_havekey_info (kinfo->grip, &infostr); + if (gpg_err_code (err) == GPG_ERR_NOT_FOUND) + { + /* Create a shadow key and try again. */ + scd_readkey (kinfo->keyref, 1, NULL); + err = scd_havekey_info (kinfo->grip, &infostr); + } + if (err && gpg_err_code (err) != GPG_ERR_NOT_FOUND) + log_error ("Error getting infos for a key: %s\n", + gpg_strerror (err)); + + if (gpg_err_code (err) == GPG_ERR_NOT_FOUND) + ; /* does not make sense to show this. */ + else if (opt_ondisk && infostr && !strcmp (infostr, "shadowed")) + ; /* Don't print this one. */ + else + { + tty_fprintf (fp, "%s %s ", + nullnone (info->serialno), + app_type_string (info->apptype)); + print_keygrip (fp, kinfo->grip, 0); + tty_fprintf (fp, " %s %s\n", + kinfo->keyref, infostr? infostr: "error"); + } + if (infostr + && ((opt_delete_clear && !strcmp (infostr, "clear")) + || (opt_delete_protected && !strcmp (infostr, "protected")))) + { + err = scd_delete_key (kinfo->grip, 0); + if (err) + log_error ("Error deleting a key copy: %s\n", + gpg_strerror (err)); + else + delete_count++; + } + xfree (infostr); + } + } + es_fflush (es_stdout); + if (delete_count) + log_info ("Number of deleted key copies: %d\n", delete_count); + + err = 0; + + leave: + release_card_info (info); + free_strlist (cards); + /* Better reset to the original card. */ + scd_learn (callerinfo, 0); + return err; +} + + /* The VERIFY command. */ static gpg_error_t @@ -3728,6 +3860,7 @@ enum cmdids cmdFORCESIG, cmdGENERATE, cmdPASSWD, cmdPRIVATEDO, cmdWRITECERT, cmdREADCERT, cmdWRITEKEY, cmdUNBLOCK, cmdFACTRST, cmdKDFSETUP, cmdUIF, cmdAUTH, cmdYUBIKEY, cmdAPDU, cmdGPG, cmdGPGSM, cmdHISTORY, + cmdCHECKKEYS, cmdINVCMD }; @@ -3767,6 +3900,7 @@ static struct { "readcert", cmdREADCERT, N_("read a certificate from a data object")}, { "writecert", cmdWRITECERT, N_("store a certificate to a data object")}, { "writekey", cmdWRITEKEY, N_("store a private key to a data object")}, + { "checkkeys", cmdCHECKKEYS, N_("run various checks on the keys")}, { "yubikey", cmdYUBIKEY, N_("Yubikey management commands")}, { "gpg", cmdGPG, NULL}, { "gpgsm", cmdGPGSM, NULL}, @@ -3903,6 +4037,7 @@ dispatch_command (card_info_t info, const char *orig_command) case cmdGPG: err = cmd_gpg (info, argstr, 0); break; case cmdGPGSM: err = cmd_gpg (info, argstr, 1); break; case cmdHISTORY: err = 0; break; /* Only used in interactive mode. */ + case cmdCHECKKEYS: err = cmd_checkkeys (info, argstr); break; case cmdINVCMD: default: @@ -4162,6 +4297,7 @@ interactive_loop (void) case cmdGPG: err = cmd_gpg (info, argstr, 0); break; case cmdGPGSM: err = cmd_gpg (info, argstr, 1); break; case cmdHISTORY: err = cmd_history (info, argstr); break; + case cmdCHECKKEYS: err = cmd_checkkeys (info, argstr); break; case cmdINVCMD: default: diff --git a/tools/gpg-card.h b/tools/gpg-card.h index 86b63cda0..5b49ef31e 100644 --- a/tools/gpg-card.h +++ b/tools/gpg-card.h @@ -246,6 +246,8 @@ gpg_error_t scd_cardlist (strlist_t *result); gpg_error_t scd_applist (strlist_t *result, int all); gpg_error_t scd_change_pin (const char *pinref, int reset_mode, int nullpin); gpg_error_t scd_checkpin (const char *serialno); +gpg_error_t scd_havekey_info (const unsigned char *grip, char **r_result); +gpg_error_t scd_delete_key (const unsigned char *grip, int force); unsigned long agent_get_s2k_count (void); diff --git a/tools/gpgconf.c b/tools/gpgconf.c index 83b4bca21..22569a870 100644 --- a/tools/gpgconf.c +++ b/tools/gpgconf.c @@ -86,30 +86,31 @@ enum cmd_and_opt_values /* The list of commands and options. */ static gpgrt_opt_t opts[] = { - { 300, NULL, 0, N_("@Commands:\n ") }, - - { aListComponents, "list-components", 256, N_("list all components") }, - { aCheckPrograms, "check-programs", 256, N_("check all programs") }, - { aListOptions, "list-options", 256, N_("|COMPONENT|list options") }, - { aChangeOptions, "change-options", 256, N_("|COMPONENT|change options") }, - { aCheckOptions, "check-options", 256, N_("|COMPONENT|check options") }, - { aApplyDefaults, "apply-defaults", 256, - N_("apply global default values") }, - { aApplyProfile, "apply-profile", 256, - N_("|FILE|update configuration files using FILE") }, - { aListDirs, "list-dirs", 256, - N_("get the configuration directories for @GPGCONF@") }, - { aListConfig, "list-config", 256, - N_("list global configuration file") }, - { aCheckConfig, "check-config", 256, - N_("check global configuration file") }, - { aQuerySWDB, "query-swdb", 256, - N_("query the software version database") }, - { aReload, "reload", 256, N_("reload all or a given component")}, - { aLaunch, "launch", 256, N_("launch a given component")}, - { aKill, "kill", 256, N_("kill a given component")}, - { aCreateSocketDir, "create-socketdir", 256, "@"}, - { aRemoveSocketDir, "remove-socketdir", 256, "@"}, + ARGPARSE_group (300, N_("@Commands:\n ")), + + ARGPARSE_c (aListComponents, "list-components", N_("list all components")), + ARGPARSE_c (aCheckPrograms, "check-programs", N_("check all programs")), + ARGPARSE_c (aListOptions, "list-options", N_("|COMPONENT|list options")), + ARGPARSE_c (aChangeOptions, "change-options", + N_("|COMPONENT|change options")), + ARGPARSE_c (aCheckOptions, "check-options", N_("|COMPONENT|check options")), + ARGPARSE_c (aApplyDefaults, "apply-defaults", + N_("apply global default values")), + ARGPARSE_c (aApplyProfile, "apply-profile", + N_("|FILE|update configuration files using FILE")), + ARGPARSE_c (aListDirs, "list-dirs", + N_("get the configuration directories for @GPGCONF@")), + ARGPARSE_c (aListConfig, "list-config", + N_("list global configuration file")), + ARGPARSE_c (aCheckConfig, "check-config", + N_("check global configuration file")), + ARGPARSE_c (aQuerySWDB, "query-swdb", + N_("query the software version database")), + ARGPARSE_c (aReload, "reload", N_("reload all or a given component")), + ARGPARSE_c (aLaunch, "launch", N_("launch a given component")), + ARGPARSE_c (aKill, "kill", N_("kill a given component")), + ARGPARSE_c (aCreateSocketDir, "create-socketdir", "@"), + ARGPARSE_c (aRemoveSocketDir, "remove-socketdir", "@"), ARGPARSE_c (aShowVersions, "show-versions", ""), ARGPARSE_c (aShowConfigs, "show-configs", ""), /* hidden commands: for debugging */ @@ -117,24 +118,25 @@ static gpgrt_opt_t opts[] = ARGPARSE_c (aDotlockLock, "lock", "@"), ARGPARSE_c (aDotlockUnlock, "unlock", "@"), - { 301, NULL, 0, N_("@\nOptions:\n ") }, + ARGPARSE_header (NULL, N_("@\nOptions:\n ")), - { oOutput, "output", 2, N_("use as output file") }, - { oVerbose, "verbose", 0, N_("verbose") }, - { oQuiet, "quiet", 0, N_("quiet") }, - { oDryRun, "dry-run", 0, N_("do not make any changes") }, - { oRuntime, "runtime", 0, N_("activate changes at runtime, if possible") }, + ARGPARSE_s_s (oOutput, "output", N_("use as output file")), + ARGPARSE_s_n (oVerbose, "verbose", N_("verbose")), + ARGPARSE_s_n (oQuiet, "quiet", N_("quiet")), + ARGPARSE_s_n (oDryRun, "dry-run", N_("do not make any changes")), + ARGPARSE_s_n (oRuntime, "runtime", + N_("activate changes at runtime, if possible")), ARGPARSE_s_i (oStatusFD, "status-fd", N_("|FD|write status info to this FD")), /* hidden options */ - { oHomedir, "homedir", 2, "@" }, - { oBuilddir, "build-prefix", 2, "@" }, - { oNull, "null", 0, "@" }, - { oNoVerbose, "no-verbose", 0, "@"}, + ARGPARSE_s_s (oHomedir, "homedir", "@"), + ARGPARSE_s_s (oBuilddir, "build-prefix", "@"), + ARGPARSE_s_n (oNull, "null", "@"), + ARGPARSE_s_n (oNoVerbose, "no-verbose", "@"), ARGPARSE_s_n (oShowSocket, "show-socket", "@"), ARGPARSE_s_s (oChUid, "chuid", "@"), - ARGPARSE_end(), + ARGPARSE_end () }; @@ -1072,12 +1074,12 @@ main (int argc, char **argv) #if !defined(HAVE_W32_SYSTEM) if (!fname) { - es_fprintf (es_stderr, "usage: %s [options] lock|unlock NAME", - GPGCONF_NAME); + es_fprintf (es_stderr, "usage: %s --%slock NAME", + GPGCONF_NAME, cmd==aDotlockUnlock?"un":""); es_putc ('\n', es_stderr); - es_fputs (_("Need one NAME argument"), es_stderr); + es_fputs ("Need name of file protected by the lock", es_stderr); es_putc ('\n', es_stderr); - gpgconf_failure (GPG_ERR_USER_2); + gpgconf_failure (GPG_ERR_SYNTAX); } else { @@ -1151,10 +1153,12 @@ get_revision_from_blurb (const char *blurb, int *r_len) static void show_version_gnupg (estream_t fp, const char *prefix) { - char *fname, *p; + char *fname, *p, *p0; size_t n; estream_t verfp; - char line[100]; + char *line = NULL; + size_t line_len = 0; + ssize_t length; es_fprintf (fp, "%s%sGnuPG %s (%s)\n%s%s\n", prefix, *prefix?"":"* ", gpgrt_strusage (13), BUILD_REVISION, prefix, gpgrt_strusage (17)); @@ -1173,20 +1177,46 @@ show_version_gnupg (estream_t fp, const char *prefix) verfp = es_fopen (fname, "r"); if (!verfp) es_fprintf (fp, "%s[VERSION file not found]\n", prefix); - else if (!es_fgets (line, sizeof line, verfp)) - es_fprintf (fp, "%s[VERSION file is empty]\n", prefix); else { - trim_spaces (line); - for (p=line; *p; p++) - if (*p < ' ' || *p > '~' || *p == '[') - *p = '?'; - es_fprintf (fp, "%s%s\n", prefix, line); + int lnr = 0; + + p0 = NULL; + while ((length = es_read_line (verfp, &line, &line_len, NULL))>0) + { + lnr++; + trim_spaces (line); + if (lnr == 1 && *line != '[') + { + /* Old file format where we look only at the + * first line. */ + p0 = line; + break; + } + else if (!strncmp (line, "version=", 8)) + { + p0 = line + 8; + break; + } + } + if (length < 0 || es_ferror (verfp)) + es_fprintf (fp, "%s[VERSION file read error]\n", prefix); + else if (p0) + { + for (p=p0; *p; p++) + if (*p < ' ' || *p > '~' || *p == '[') + *p = '?'; + es_fprintf (fp, "%s%s\n", prefix, p0); + } + else + es_fprintf (fp, "%s[VERSION file is empty]\n", prefix); + + es_fclose (verfp); } - es_fclose (verfp); } xfree (fname); } + xfree (line); #ifdef HAVE_W32_SYSTEM { |