From 0b0104ce472047118c2e7c72f29a092d9ecd8b76 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 20 Mar 2019 09:16:46 +0100 Subject: [PATCH 001/169] tests: Add a first v5 sample key -- --- tests/openpgp/samplekeys/README | 2 ++ tests/openpgp/samplekeys/v5-sample-1-pub.asc | 19 ++++++++++++++++++ tests/openpgp/samplekeys/v5-sample-1-sec.asc | 21 ++++++++++++++++++++ 3 files changed, 42 insertions(+) create mode 100644 tests/openpgp/samplekeys/v5-sample-1-pub.asc create mode 100644 tests/openpgp/samplekeys/v5-sample-1-sec.asc diff --git a/tests/openpgp/samplekeys/README b/tests/openpgp/samplekeys/README index f8a7e9ed7..74635c702 100644 --- a/tests/openpgp/samplekeys/README +++ b/tests/openpgp/samplekeys/README @@ -20,6 +20,8 @@ ed25519-cv25519-sample-1.asc Ed25519+CV25519 sample key (no passphrase) silent-running.asc Collection of sample secret keys (no passphrases) rsa-primary-auth-only.pub.asc rsa2408 primary only, usage: cert,auth rsa-primary-auth-only.sec.asc Ditto but the secret keyblock. +v5-sample-1-pub.asc A version 5 key (ed25519/cert,sign,v5+cv25519/v5) +v5-sample-1-sec.asc Ditto, but the secret keyblock (unprotected). Notes: diff --git a/tests/openpgp/samplekeys/v5-sample-1-pub.asc b/tests/openpgp/samplekeys/v5-sample-1-pub.asc new file mode 100644 index 000000000..9f7147130 --- /dev/null +++ b/tests/openpgp/samplekeys/v5-sample-1-pub.asc @@ -0,0 +1,19 @@ +pub ed25519 2019-03-20 [SC] + 19347BC9872464025F99DF3EC2E0000ED9884892E1F7B3EA4C94009159569B54 +uid emma.goldman@example.net +sub cv25519 2019-03-20 [E] + E4557C2B02FFBF4B04F87401EC336AF7133D0F85BE7FD09BAEFD9CAEB8C93965 + +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mDcFXJH05BYAAAAtCSsGAQQB2kcPAQEHQFhZlVcVVtwf+21xNQPX+ecMJJBL0MPd +fj75iux+my8QtBhlbW1hLmdvbGRtYW5AZXhhbXBsZS5uZXSIlgUTFggASCIhBRk0 +e8mHJGQCX5nfPsLgAA7ZiEiS4fez6kyUAJFZVptUBQJckfTkAhsDBQsJCAcCAyIC +AQYVCgkICwIEFgIDAQIeBwIXgAAA9cAA/jiR3yMsZMeEQ40u6uzEoXa6UXeV/S3w +wJAXRJy9M8s0AP9vuL/7AyTfFXwwzSjDnYmzS0qAhbLDQ643N+MXGBJ2Bbg8BVyR +9OQSAAAAMgorBgEEAZdVAQUBAQdA+nysrzml2UCweAqtpDuncSPlvrcBWKU0yfU0 +YvYWWAoDAQgHiHoFGBYIACwiIQUZNHvJhyRkAl+Z3z7C4AAO2YhIkuH3s+pMlACR +WVabVAUCXJH05AIbDAAAOSQBAP4BOOIR/sGLNMOfeb5fPs/02QMieoiSjIBnijho +b2U5AQC+RtOHCHx7TcIYl5/Uyoi+FOvPLcNw4hOv2nwUzSSVAw== +=WYfO +-----END PGP PUBLIC KEY BLOCK----- diff --git a/tests/openpgp/samplekeys/v5-sample-1-sec.asc b/tests/openpgp/samplekeys/v5-sample-1-sec.asc new file mode 100644 index 000000000..b5463c93f --- /dev/null +++ b/tests/openpgp/samplekeys/v5-sample-1-sec.asc @@ -0,0 +1,21 @@ +sec ed25519 2019-03-20 [SC] + 19347BC9872464025F99DF3EC2E0000ED9884892E1F7B3EA4C94009159569B54 +uid emma.goldman@example.net +ssb cv25519 2019-03-20 [E] + E4557C2B02FFBF4B04F87401EC336AF7133D0F85BE7FD09BAEFD9CAEB8C93965 + +-----BEGIN PGP PRIVATE KEY BLOCK----- + +lGEFXJH05BYAAAAtCSsGAQQB2kcPAQEHQFhZlVcVVtwf+21xNQPX+ecMJJBL0MPd +fj75iux+my8QAAAAAAAiAQCHZ1SnSUmWqxEsoI6facIVZQu6mph3cBFzzTvcm5lA +Ng5ctBhlbW1hLmdvbGRtYW5AZXhhbXBsZS5uZXSIlgUTFggASCIhBRk0e8mHJGQC +X5nfPsLgAA7ZiEiS4fez6kyUAJFZVptUBQJckfTkAhsDBQsJCAcCAyICAQYVCgkI +CwIEFgIDAQIeBwIXgAAA9cAA/jiR3yMsZMeEQ40u6uzEoXa6UXeV/S3wwJAXRJy9 +M8s0AP9vuL/7AyTfFXwwzSjDnYmzS0qAhbLDQ643N+MXGBJ2BZxmBVyR9OQSAAAA +MgorBgEEAZdVAQUBAQdA+nysrzml2UCweAqtpDuncSPlvrcBWKU0yfU0YvYWWAoD +AQgHAAAAAAAiAP9OdAPppjU1WwpqjIItkxr+VPQRT8Zm/Riw7U3F6v3OiBFHiHoF +GBYIACwiIQUZNHvJhyRkAl+Z3z7C4AAO2YhIkuH3s+pMlACRWVabVAUCXJH05AIb +DAAAOSQBAP4BOOIR/sGLNMOfeb5fPs/02QMieoiSjIBnijhob2U5AQC+RtOHCHx7 +TcIYl5/Uyoi+FOvPLcNw4hOv2nwUzSSVAw== +=IiS2 +-----END PGP PRIVATE KEY BLOCK----- From 393269948c883afb770bb536f03045254d13b911 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 22 Mar 2019 09:44:04 +0100 Subject: [PATCH 002/169] scd: Refactor the app selection code. * scd/app.c (app_priority_list): New. Signed-off-by: Werner Koch --- scd/app.c | 52 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/scd/app.c b/scd/app.c index 2ee104d9e..81218f411 100644 --- a/scd/app.c +++ b/scd/app.c @@ -33,6 +33,31 @@ static npth_mutex_t app_list_lock; static app_t app_top; + + +/* The list of application names and there select function. Of no + * specfic application is selected the first available application on + * a card is selected. */ +struct app_priority_list_s +{ + char const *name; + gpg_error_t (*select_func)(app_t); +}; + +static struct app_priority_list_s app_priority_list[] = + {{ "openpgp", app_select_openpgp }, + { "piv", app_select_piv }, + { "nks", app_select_nks }, + { "p15", app_select_p15 }, + { "geldkarte", app_select_geldkarte }, + { "dinsig", app_select_dinsig }, + { "sc-hsm", app_select_sc_hsm }, + { NULL, NULL } + }; + + + + static void print_progress_line (void *opaque, const char *what, int pc, int cur, int tot) @@ -179,6 +204,7 @@ app_new_register (int slot, ctrl_t ctrl, const char *name, unsigned char *result = NULL; size_t resultlen; int want_undefined; + int i; /* Need to allocate a new one. */ app = xtrycalloc (1, sizeof *app); @@ -330,26 +356,18 @@ app_new_register (int slot, ctrl_t ctrl, const char *name, goto leave; /* Set a default error so that we run through the application - * selecion chain. */ + * selection chain. */ err = gpg_error (GPG_ERR_NOT_FOUND); } - if (err && is_app_allowed ("openpgp") - && (!name || !strcmp (name, "openpgp"))) - err = app_select_openpgp (app); - if (err && is_app_allowed ("piv") && (!name || !strcmp (name, "piv"))) - err = app_select_piv (app); - if (err && is_app_allowed ("nks") && (!name || !strcmp (name, "nks"))) - err = app_select_nks (app); - if (err && is_app_allowed ("p15") && (!name || !strcmp (name, "p15"))) - err = app_select_p15 (app); - if (err && is_app_allowed ("geldkarte") - && (!name || !strcmp (name, "geldkarte"))) - err = app_select_geldkarte (app); - if (err && is_app_allowed ("dinsig") && (!name || !strcmp (name, "dinsig"))) - err = app_select_dinsig (app); - if (err && is_app_allowed ("sc-hsm") && (!name || !strcmp (name, "sc-hsm"))) - err = app_select_sc_hsm (app); + /* Find the first available app if NAME is NULL or the one matching + * NAME but only if that application is also enabled. */ + for (i=0; err && app_priority_list[i].name; i++) + { + if (is_app_allowed (app_priority_list[i].name) + && (!name || !strcmp (name, app_priority_list[i].name))) + err = app_priority_list[i].select_func (app); + } if (err && name && gpg_err_code (err) != GPG_ERR_OBJ_TERM_STATE) err = gpg_error (GPG_ERR_NOT_SUPPORTED); From e847cf1df7aa55ac2af7efd39ca05882258acbfe Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 22 Mar 2019 11:40:01 +0100 Subject: [PATCH 003/169] wkd: New command --print-wkd-hash for gpg-wks-client. * tools/gpg-wks-client.c (aPrintWKDHash): New. (opts) : Add "--print-wkd-hash". (main): Implement that command. (proc_userid_from_stdin): New. * tools/wks-util.c (wks_fname_from_userid): Add option HASH_ONLY. (wks_cmd_print_wkd_hash): New. -- GnuPG-bug-id: 4418 Signed-off-by: Werner Koch --- doc/wks.texi | 4 ++ tools/gpg-wks-client.c | 85 +++++++++++++++++++++++++++++++++++++++++- tools/gpg-wks-server.c | 2 +- tools/gpg-wks.h | 3 +- tools/wks-util.c | 47 +++++++++++++++++++---- 5 files changed, 129 insertions(+), 12 deletions(-) diff --git a/doc/wks.texi b/doc/wks.texi index f132b3186..0ebd3db3f 100644 --- a/doc/wks.texi +++ b/doc/wks.texi @@ -101,6 +101,10 @@ fingerprint and the mailbox separated by a space. The command @option{--remove-key} removes a key from that directory, its only argument is a user-id. +The command @option{--print-wkd-hash} prints a WKD user id identifier +and the corresponding mailbox from the user-ids given on the command +line or via stdin (one user-id per line). + @command{gpg-wks-client} is not commonly invoked directly and thus it is not installed in the bin directory. Here is an example how it can be invoked manually to check for a Web Key Directory entry for diff --git a/tools/gpg-wks-client.c b/tools/gpg-wks-client.c index 0f08737c4..2c40d7e17 100644 --- a/tools/gpg-wks-client.c +++ b/tools/gpg-wks-client.c @@ -61,6 +61,7 @@ enum cmd_and_opt_values aRead, aInstallKey, aRemoveKey, + aPrintWKDHash, oGpgProgram, oSend, @@ -90,6 +91,8 @@ static ARGPARSE_OPTS opts[] = { "install a key into a directory"), ARGPARSE_c (aRemoveKey, "remove-key", "remove a key from a directory"), + ARGPARSE_c (aPrintWKDHash, "print-wkd-hash", + "Print the WKD identifier for the given user ids"), ARGPARSE_group (301, ("@\nOptions:\n ")), @@ -129,6 +132,8 @@ const char *fake_submission_addr; static void wrong_args (const char *text) GPGRT_ATTR_NORETURN; +static gpg_error_t proc_userid_from_stdin (gpg_error_t (*func)(const char *), + const char *text); static gpg_error_t command_supported (char *userid); static gpg_error_t command_check (char *userid); static gpg_error_t command_send (const char *fingerprint, const char *userid); @@ -230,6 +235,7 @@ parse_arguments (ARGPARSE_ARGS *pargs, ARGPARSE_OPTS *popts) case aCheck: case aInstallKey: case aRemoveKey: + case aPrintWKDHash: cmd = pargs->r_opt; break; @@ -246,7 +252,7 @@ parse_arguments (ARGPARSE_ARGS *pargs, ARGPARSE_OPTS *popts) int main (int argc, char **argv) { - gpg_error_t err; + gpg_error_t err, delayed_err; ARGPARSE_ARGS pargs; enum cmd_and_opt_values cmd; @@ -377,6 +383,28 @@ main (int argc, char **argv) err = wks_cmd_remove_key (*argv); break; + case aPrintWKDHash: + if (!argc) + err = proc_userid_from_stdin (wks_cmd_print_wkd_hash, "printing hash"); + else + { + for (err = delayed_err = 0; !err && argc; argc--, argv++) + { + err = wks_cmd_print_wkd_hash (*argv); + if (gpg_err_code (err) == GPG_ERR_INV_USER_ID) + { + /* Diagnostic already printed. */ + delayed_err = err; + err = 0; + } + else if (err) + log_error ("printing hash failed: %s\n", gpg_strerror (err)); + } + if (!err) + err = delayed_err; + } + break; + default: usage (1); err = 0; @@ -390,10 +418,63 @@ main (int argc, char **argv) wks_write_status (STATUS_FAILURE, "- %u", GPG_ERR_GENERAL); else wks_write_status (STATUS_SUCCESS, NULL); - return log_get_errorcount (0)? 1:0; + return (err || log_get_errorcount (0))? 1:0; } +/* Read user ids from stdin and call FUNC for each user id. TEXT is + * used for error messages. */ +static gpg_error_t +proc_userid_from_stdin (gpg_error_t (*func)(const char *), const char *text) +{ + gpg_error_t err = 0; + gpg_error_t delayed_err = 0; + char line[2048]; + size_t n = 0; + + /* If we are on a terminal disable buffering to get direct response. */ + if (gnupg_isatty (es_fileno (es_stdin)) + && gnupg_isatty (es_fileno (es_stdout))) + { + es_setvbuf (es_stdin, NULL, _IONBF, 0); + es_setvbuf (es_stdout, NULL, _IOLBF, 0); + } + + while (es_fgets (line, sizeof line - 1, es_stdin)) + { + n = strlen (line); + if (!n || line[n-1] != '\n') + { + err = gpg_error (*line? GPG_ERR_LINE_TOO_LONG + : GPG_ERR_INCOMPLETE_LINE); + log_error ("error reading stdin: %s\n", gpg_strerror (err)); + break; + } + trim_spaces (line); + err = func (line); + if (gpg_err_code (err) == GPG_ERR_INV_USER_ID) + { + delayed_err = err; + err = 0; + } + else if (err) + log_error ("%s failed: %s\n", text, gpg_strerror (err)); + } + if (es_ferror (es_stdin)) + { + err = gpg_error_from_syserror (); + log_error ("error reading stdin: %s\n", gpg_strerror (err)); + goto leave; + } + + leave: + if (!err) + err = delayed_err; + return err; +} + + + /* Add the user id UID to the key identified by FINGERPRINT. */ static gpg_error_t diff --git a/tools/gpg-wks-server.c b/tools/gpg-wks-server.c index f83ef6528..2082fb87d 100644 --- a/tools/gpg-wks-server.c +++ b/tools/gpg-wks-server.c @@ -1939,7 +1939,7 @@ command_check_key (const char *userid) char *addrspec = NULL; char *fname = NULL; - err = wks_fname_from_userid (userid, &fname, &addrspec); + err = wks_fname_from_userid (userid, 0, &fname, &addrspec); if (err) goto leave; diff --git a/tools/gpg-wks.h b/tools/gpg-wks.h index e36943090..99969c1ef 100644 --- a/tools/gpg-wks.h +++ b/tools/gpg-wks.h @@ -98,11 +98,12 @@ gpg_error_t wks_parse_policy (policy_flags_t flags, estream_t stream, int ignore_unknown); void wks_free_policy (policy_flags_t policy); -gpg_error_t wks_fname_from_userid (const char *userid, +gpg_error_t wks_fname_from_userid (const char *userid, int hash_only, char **r_fname, char **r_addrspec); gpg_error_t wks_compute_hu_fname (char **r_fname, const char *addrspec); gpg_error_t wks_cmd_install_key (const char *fname, const char *userid); gpg_error_t wks_cmd_remove_key (const char *userid); +gpg_error_t wks_cmd_print_wkd_hash (const char *userid); /*-- wks-receive.c --*/ diff --git a/tools/wks-util.c b/tools/wks-util.c index 1459045ef..d5cfcd874 100644 --- a/tools/wks-util.c +++ b/tools/wks-util.c @@ -749,9 +749,12 @@ write_to_file (estream_t src, const char *fname) /* Return the filename and optionally the addrspec for USERID at - * R_FNAME and R_ADDRSPEC. R_ADDRSPEC might also be set on error. */ + * R_FNAME and R_ADDRSPEC. R_ADDRSPEC might also be set on error. If + * HASH_ONLY is set only the has is returned at R_FNAME and no file is + * created. */ gpg_error_t -wks_fname_from_userid (const char *userid, char **r_fname, char **r_addrspec) +wks_fname_from_userid (const char *userid, int hash_only, + char **r_fname, char **r_addrspec) { gpg_error_t err; char *addrspec = NULL; @@ -767,7 +770,7 @@ wks_fname_from_userid (const char *userid, char **r_fname, char **r_addrspec) addrspec = mailbox_from_userid (userid, 0); if (!addrspec) { - if (opt.verbose) + if (opt.verbose || hash_only) log_info ("\"%s\" is not a proper mail address\n", userid); err = gpg_error (GPG_ERR_INV_USER_ID); goto leave; @@ -788,11 +791,20 @@ wks_fname_from_userid (const char *userid, char **r_fname, char **r_addrspec) goto leave; } - *r_fname = make_filename_try (opt.directory, domain, "hu", hash, NULL); - if (!*r_fname) - err = gpg_error_from_syserror (); + if (hash_only) + { + *r_fname = hash; + hash = NULL; + err = 0; + } else - err = 0; + { + *r_fname = make_filename_try (opt.directory, domain, "hu", hash, NULL); + if (!*r_fname) + err = gpg_error_from_syserror (); + else + err = 0; + } leave: if (r_addrspec && addrspec) @@ -1061,7 +1073,7 @@ wks_cmd_remove_key (const char *userid) char *addrspec = NULL; char *fname = NULL; - err = wks_fname_from_userid (userid, &fname, &addrspec); + err = wks_fname_from_userid (userid, 0, &fname, &addrspec); if (err) goto leave; @@ -1089,3 +1101,22 @@ wks_cmd_remove_key (const char *userid) xfree (addrspec); return err; } + + +/* Print the WKD hash for the user ids to stdout. */ +gpg_error_t +wks_cmd_print_wkd_hash (const char *userid) +{ + gpg_error_t err; + char *addrspec, *fname; + + err = wks_fname_from_userid (userid, 1, &fname, &addrspec); + if (err) + return err; + + es_printf ("%s %s\n", fname, addrspec); + + xfree (fname); + xfree (addrspec); + return err; +} From 5a96db65e582889fc4383443934495651c969fd6 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 22 Mar 2019 12:29:02 +0100 Subject: [PATCH 004/169] doc: Add a spec comment to app-piv.c -- --- scd/app-piv.c | 1 + 1 file changed, 1 insertion(+) diff --git a/scd/app-piv.c b/scd/app-piv.c index 5748c70b8..41fd7b7c5 100644 --- a/scd/app-piv.c +++ b/scd/app-piv.c @@ -19,6 +19,7 @@ /* Some notes: * - Specs for PIV are at http://dx.doi.org/10.6028/NIST.SP.800-73-4 + * - https://developers.yubico.com/PIV/Introduction/PIV_attestation.html * * - Access control matrix: * | Action | 9B | PIN | PUK | | From b30528f48780c9917ec8ba3b3d163fba5c740d92 Mon Sep 17 00:00:00 2001 From: Daniel Kahn Gillmor Date: Fri, 22 Mar 2019 23:49:03 +0100 Subject: [PATCH 005/169] doc: fix formatting error Signed-off-by: Daniel Kahn Gillmor --- doc/gpg.texi | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/gpg.texi b/doc/gpg.texi index e6829b911..123abed4c 100644 --- a/doc/gpg.texi +++ b/doc/gpg.texi @@ -2334,7 +2334,8 @@ opposite meaning. The options are: can be used to update only the subkeys or other non-user id related information. - @item repair-keys. After import, fix various problems with the + @item repair-keys + After import, fix various problems with the keys. For example, this reorders signatures, and strips duplicate signatures. Defaults to yes. From 8d1b5982138c104f3c50663738892fa110193059 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Mon, 25 Mar 2019 19:39:44 +0900 Subject: [PATCH 006/169] libdns: Don't use _[A-Z] which are reserved names. * dirmngr/dns.c: Use the identifiers of "*_instance" instead of reserved "_[A-Z]". -- GnuPG-bug-id: 4420 Signed-off-by: NIIBE Yutaka --- dirmngr/dns.c | 80 +++++++++++++++++++++++++-------------------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/dirmngr/dns.c b/dirmngr/dns.c index fa5e5283d..142e8d2c1 100644 --- a/dirmngr/dns.c +++ b/dirmngr/dns.c @@ -2217,8 +2217,8 @@ static void dns_p_dump3(struct dns_packet *P, struct dns_rr_i *I, FILE *fp) { void dns_p_dump(struct dns_packet *P, FILE *fp) { - struct dns_rr_i _I = { 0 }; - dns_p_dump3(P, &_I, fp); + struct dns_rr_i I_instance = { 0 }; + dns_p_dump3(P, &I_instance, fp); } /* dns_p_dump() */ @@ -5275,8 +5275,8 @@ error: struct dns_packet *dns_hosts_query(struct dns_hosts *hosts, struct dns_packet *Q, int *error_) { - union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } _P = { 0 }; - struct dns_packet *P = dns_p_init(&_P.p, 512); + union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } P_instance = { 0 }; + struct dns_packet *P = dns_p_init(&P_instance.p, 512); struct dns_packet *A = 0; struct dns_rr rr; struct dns_hosts_entry *ent; @@ -6837,7 +6837,7 @@ unsigned dns_hints_grep(struct sockaddr **sa, socklen_t *sa_len, unsigned lim, s struct dns_packet *dns_hints_query(struct dns_hints *hints, struct dns_packet *Q, int *error_) { - union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } _P = { 0 }; + union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } P_instance = { 0 }; struct dns_packet *A, *P; struct dns_rr rr; char zone[DNS_D_MAXNAME + 1]; @@ -6846,11 +6846,11 @@ struct dns_packet *dns_hints_query(struct dns_hints *hints, struct dns_packet *Q struct sockaddr *sa; socklen_t slen; int error; - struct dns_rr_i _I = { 0 }; + struct dns_rr_i I_instance = { 0 }; - _I.section = DNS_S_QUESTION; + I_instance.section = DNS_S_QUESTION; - if (!dns_rr_grep(&rr, 1, &_I, Q, &error)) + if (!dns_rr_grep(&rr, 1, &I_instance, Q, &error)) goto error; if (!(zlen = dns_d_expand(zone, sizeof zone, rr.dn.p, Q, &error))) @@ -6858,7 +6858,7 @@ struct dns_packet *dns_hints_query(struct dns_hints *hints, struct dns_packet *Q else if (zlen >= sizeof zone) goto toolong; - P = dns_p_init(&_P.p, 512); + P = dns_p_init(&P_instance.p, 512); dns_header(P)->qr = 1; if ((error = dns_rr_copy(P, &rr, Q))) @@ -8463,8 +8463,8 @@ error: static struct dns_packet *dns_res_glue(struct dns_resolver *R, struct dns_packet *Q) { - union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } _P = { 0 }; - struct dns_packet *P = dns_p_init(&_P.p, 512); + union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } P_instance = { 0 }; + struct dns_packet *P = dns_p_init(&P_instance.p, 512); char qname[DNS_D_MAXNAME + 1]; size_t qlen; enum dns_type qtype; @@ -8537,20 +8537,20 @@ static int dns_res_nameserv_cmp(struct dns_rr *a, struct dns_rr *b, struct dns_r int cmp, error; if (!(error = dns_ns_parse(&ns, a, P))) { - struct dns_rr_i _I = { 0 }; + struct dns_rr_i I_instance = { 0 }; - _I.section = (DNS_S_ALL & ~DNS_S_QD); - _I.name = ns.host; - _I.type = DNS_T_A; - glued[0] = !!dns_rr_grep(&x, 1, &_I, P, &error); + I_instance.section = (DNS_S_ALL & ~DNS_S_QD); + I_instance.name = ns.host; + I_instance.type = DNS_T_A; + glued[0] = !!dns_rr_grep(&x, 1, &I_instance, P, &error); } if (!(error = dns_ns_parse(&ns, b, P))) { - struct dns_rr_i _I = { 0 }; + struct dns_rr_i I_instance = { 0 }; - _I.section = (DNS_S_ALL & ~DNS_S_QD); - _I.name = ns.host; - _I.type = DNS_T_A; - glued[1] = !!dns_rr_grep(&y, 1, &_I, P, &error); + I_instance.section = (DNS_S_ALL & ~DNS_S_QD); + I_instance.name = ns.host; + I_instance.type = DNS_T_A; + glued[1] = !!dns_rr_grep(&y, 1, &I_instance, P, &error); } if ((cmp = glued[1] - glued[0])) { return cmp; @@ -9916,13 +9916,13 @@ exec: return dns_ai_setent(ent, &any, rr.type, ai); case DNS_AI_S_SUBMIT_G: { - struct dns_rr_i _I = { 0 }; + struct dns_rr_i I_instance = { 0 }; - _I.section = DNS_S_QD; - _I.name = ai->g.name; - _I.type = ai->g.type; + I_instance.section = DNS_S_QD; + I_instance.name = ai->g.name; + I_instance.type = ai->g.type; /* skip if already queried */ - if (dns_rr_grep(&rr, 1, &_I, ai->glue, &error)) + if (dns_rr_grep(&rr, 1, &I_instance, ai->glue, &error)) dns_ai_goto(DNS_AI_S_FOREACH_I); /* skip if we recursed (CNAME chains should have been handled in the resolver) */ if (++ai->g_depth > 1) @@ -10598,7 +10598,7 @@ static struct dns_trace *trace(const char *mode) { static void print_packet(struct dns_packet *P, FILE *fp) { - struct dns_rr_i _I = { 0 }; + struct dns_rr_i I_instance = { 0 }; I.sort = MAIN.sort; dns_p_dump3(P, &I, fp); @@ -10608,10 +10608,10 @@ static void print_packet(struct dns_packet *P, FILE *fp) { static int parse_packet(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) { - union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } _P = { 0 }; - union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } _Q = { 0 }; - struct dns_packet *P = dns_p_init(&_P.p, 512); - struct dns_packet *Q = dns_p_init(&_Q.p, 512); + union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } P_instance = { 0 }; + union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } Q_instance = { 0 }; + struct dns_packet *P = dns_p_init(&P_instance.p, 512); + struct dns_packet *Q = dns_p_init(&Q_instance.p, 512); enum dns_section section; struct dns_rr rr; int error; @@ -10655,7 +10655,7 @@ static int parse_packet(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) { const char *dn = "ns8.yahoo.com"; char *_name = dns_d_init(_p, sizeof _p, dn, strlen (dn), DNS_D_ANCHOR); struct dns_rr rrset[32]; - struct dns_rr_i _I = { 0 }; + struct dns_rr_i I_instance = { 0 }; struct dns_rr_i *rri = &I; unsigned rrcount = dns_rr_grep(rrset, lengthof(rrset), rri, Q, &error); @@ -10818,8 +10818,8 @@ static int show_hosts(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) { static int query_hosts(int argc, char *argv[]) { - union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } _Q = { 0 }; - struct dns_packet *Q = dns_p_init(&_Q.p, 512); + union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } Q_instance = { 0 }; + struct dns_packet *Q = dns_p_init(&Q_instance.p, 512); struct dns_packet *A; char qname[DNS_D_MAXNAME + 1]; size_t qlen; @@ -10937,8 +10937,8 @@ static int dump_random(int argc, char *argv[]) { static int send_query(int argc, char *argv[]) { - union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } _Q = { 0 }; - struct dns_packet *A, *Q = dns_p_init(&_Q.p, 512); + union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } Q_instance = { 0 }; + struct dns_packet *A, *Q = dns_p_init(&Q_instance.p, 512); char host[INET6_ADDRSTRLEN + 1]; struct sockaddr_storage ss; struct dns_socket *so; @@ -11033,10 +11033,10 @@ static int show_hints(int argc, char *argv[]) { if (0 == strcmp(how, "plain")) { dns_hints_dump(hints, stdout); } else { - union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } _P = { 0 }; + union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } P_instance = { 0 }; struct dns_packet *query, *answer; - query = dns_p_init(&_P.p, 512); + query = dns_p_init(&P_instance.p, 512); if ((error = dns_p_push(query, DNS_S_QUESTION, who, strlen(who), DNS_T_A, DNS_C_IN, 0, 0))) panic("%s: %s", who, dns_strerror(error)); @@ -11199,8 +11199,8 @@ static int echo_port(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) { panic("127.0.0.1:5353: %s", dns_strerror(errno)); for (;;) { - union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } _P = { 0 }; - struct dns_packet *pkt = dns_p_init(&_P.p, 512); + union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } P_instance = { 0 }; + struct dns_packet *pkt = dns_p_init(&P_instance.p, 512); struct sockaddr_storage ss; socklen_t slen = sizeof ss; ssize_t count; From e4e0804ed123516fa00f8a876a862b2c6d34ba5c Mon Sep 17 00:00:00 2001 From: Andre Heinecke Date: Mon, 25 Mar 2019 14:05:52 +0100 Subject: [PATCH 007/169] sm, w32: Translate logger and status fd to handles * sm/gpgsm.c (main): Call translate_sys2libc_fd_int to convert the FDs. -- This is required to actually pass gpgsm an fd on windows and not a windows handle. For the passphrase-fd this was already done. --- sm/gpgsm.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sm/gpgsm.c b/sm/gpgsm.c index 2f9e5bfd2..70964512c 100644 --- a/sm/gpgsm.c +++ b/sm/gpgsm.c @@ -1283,8 +1283,12 @@ main ( int argc, char **argv) case oDebugNoChainValidation: opt.no_chain_validation = 1; break; case oDebugIgnoreExpiration: opt.ignore_expiration = 1; break; - case oStatusFD: ctrl.status_fd = pargs.r.ret_int; break; - case oLoggerFD: log_set_fd (pargs.r.ret_int ); break; + case oStatusFD: + ctrl.status_fd = translate_sys2libc_fd_int (pargs.r.ret_int, 1); + break; + case oLoggerFD: + log_set_fd (translate_sys2libc_fd_int (pargs.r.ret_int, 1)); + break; case oWithMD5Fingerprint: opt.with_md5_fingerprint=1; /*fall through*/ case oWithFingerprint: From 2fc9a517516f5dc00811d96e6b04f8116d8eac28 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 25 Mar 2019 14:47:31 +0100 Subject: [PATCH 008/169] doc: Clarify option --no-keyring. -- GnuPG-bug-id: 4424 Signed-off-by: Werner Koch --- doc/gpg.texi | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/gpg.texi b/doc/gpg.texi index 123abed4c..d3b7be598 100644 --- a/doc/gpg.texi +++ b/doc/gpg.texi @@ -3289,7 +3289,8 @@ secret keyrings. @item --no-keyring @opindex no-keyring -Do not add use any keyrings even if specified as options. +Do not use any keyring at all. This overrides the default and all +options which specify keyrings. @item --skip-verify @opindex skip-verify From 70c97a862aa586c314a64190d1e489a272e552ea Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 25 Mar 2019 15:13:59 +0100 Subject: [PATCH 009/169] wkd: New command --print-wkd-url for gpg-wks-client. * tools/gpg-wks-client.c (aPrintWKDURL): New. (opts): Add option. (main): Implement. * tools/wks-util.c (wks_cmd_print_wkd_url): New. Signed-off-by: Werner Koch --- doc/wks.texi | 8 ++++++-- tools/gpg-wks-client.c | 19 +++++++++++++++++-- tools/gpg-wks.h | 1 + tools/wks-util.c | 27 ++++++++++++++++++++++++++- 4 files changed, 50 insertions(+), 5 deletions(-) diff --git a/doc/wks.texi b/doc/wks.texi index 0ebd3db3f..9f1fff2a8 100644 --- a/doc/wks.texi +++ b/doc/wks.texi @@ -101,10 +101,14 @@ fingerprint and the mailbox separated by a space. The command @option{--remove-key} removes a key from that directory, its only argument is a user-id. -The command @option{--print-wkd-hash} prints a WKD user id identifier -and the corresponding mailbox from the user-ids given on the command +The command @option{--print-wkd-hash} prints the WKD user-id identifiers +and the corresponding mailboxes from the user-ids given on the command line or via stdin (one user-id per line). +The command @option{--print-wkd-url} prints the URLs used to fetch the +key for the given user-ids from WKD. The meanwhile preferred format +with sub-domains is used here. + @command{gpg-wks-client} is not commonly invoked directly and thus it is not installed in the bin directory. Here is an example how it can be invoked manually to check for a Web Key Directory entry for diff --git a/tools/gpg-wks-client.c b/tools/gpg-wks-client.c index 2c40d7e17..861a1fc61 100644 --- a/tools/gpg-wks-client.c +++ b/tools/gpg-wks-client.c @@ -62,6 +62,7 @@ enum cmd_and_opt_values aInstallKey, aRemoveKey, aPrintWKDHash, + aPrintWKDURL, oGpgProgram, oSend, @@ -93,6 +94,8 @@ static ARGPARSE_OPTS opts[] = { "remove a key from a directory"), ARGPARSE_c (aPrintWKDHash, "print-wkd-hash", "Print the WKD identifier for the given user ids"), + ARGPARSE_c (aPrintWKDURL, "print-wkd-url", + "Print the WKD URL for the given user id"), ARGPARSE_group (301, ("@\nOptions:\n ")), @@ -236,6 +239,7 @@ parse_arguments (ARGPARSE_ARGS *pargs, ARGPARSE_OPTS *popts) case aInstallKey: case aRemoveKey: case aPrintWKDHash: + case aPrintWKDURL: cmd = pargs->r_opt; break; @@ -384,13 +388,24 @@ main (int argc, char **argv) break; case aPrintWKDHash: + case aPrintWKDURL: if (!argc) - err = proc_userid_from_stdin (wks_cmd_print_wkd_hash, "printing hash"); + { + if (cmd == aPrintWKDHash) + err = proc_userid_from_stdin (wks_cmd_print_wkd_hash, + "printing WKD hash"); + else + err = proc_userid_from_stdin (wks_cmd_print_wkd_url, + "printing WKD URL"); + } else { for (err = delayed_err = 0; !err && argc; argc--, argv++) { - err = wks_cmd_print_wkd_hash (*argv); + if (cmd == aPrintWKDHash) + err = wks_cmd_print_wkd_hash (*argv); + else + err = wks_cmd_print_wkd_url (*argv); if (gpg_err_code (err) == GPG_ERR_INV_USER_ID) { /* Diagnostic already printed. */ diff --git a/tools/gpg-wks.h b/tools/gpg-wks.h index 99969c1ef..9acd7c37f 100644 --- a/tools/gpg-wks.h +++ b/tools/gpg-wks.h @@ -104,6 +104,7 @@ gpg_error_t wks_compute_hu_fname (char **r_fname, const char *addrspec); gpg_error_t wks_cmd_install_key (const char *fname, const char *userid); gpg_error_t wks_cmd_remove_key (const char *userid); gpg_error_t wks_cmd_print_wkd_hash (const char *userid); +gpg_error_t wks_cmd_print_wkd_url (const char *userid); /*-- wks-receive.c --*/ diff --git a/tools/wks-util.c b/tools/wks-util.c index d5cfcd874..1c1ac8c0b 100644 --- a/tools/wks-util.c +++ b/tools/wks-util.c @@ -1103,7 +1103,7 @@ wks_cmd_remove_key (const char *userid) } -/* Print the WKD hash for the user ids to stdout. */ +/* Print the WKD hash for the user id to stdout. */ gpg_error_t wks_cmd_print_wkd_hash (const char *userid) { @@ -1120,3 +1120,28 @@ wks_cmd_print_wkd_hash (const char *userid) xfree (addrspec); return err; } + + +/* Print the WKD URL for the user id to stdout. */ +gpg_error_t +wks_cmd_print_wkd_url (const char *userid) +{ + gpg_error_t err; + char *addrspec, *fname; + char *domain; + + err = wks_fname_from_userid (userid, 1, &fname, &addrspec); + if (err) + return err; + + domain = strchr (addrspec, '@'); + if (domain) + *domain++ = 0; + + es_printf ("https://openpgpkey.%s/.well-known/openpgpkey/%s/hu/%s?l=%s\n", + domain, domain, fname, addrspec); + + xfree (fname); + xfree (addrspec); + return err; +} From e1a86a1fdfeb32d384bff29e92eeb050e3136512 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 25 Mar 2019 15:39:18 +0100 Subject: [PATCH 010/169] doc: Add relevant NEWS items from 2.2. -- --- NEWS | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/NEWS b/NEWS index cf096b66e..e4599c2bd 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,102 @@ Noteworthy changes in version 2.3.0 (unreleased) ------------------------------------------------ + Changes also found in 2.2.14: + + * gpg: Allow import of PGP desktop exported secret keys. Also avoid + importing secret keys if the secret keyblock is not valid. [#4392] + + * gpg: Make invalid primary key algo obvious in key listings. + + * sm: Do not mark a certificate in a key listing as de-vs compliant + if its use for a signature will not be possible. + + * sm: Fix certificate creation with key on card. + + * sm: Create rsa3072 bit certificates by default. + + * sm: Print Yubikey attestation extensions with --dump-cert. + + * agent: Fix cancellation handling for scdaemon. + + * agent: Support --mode=ssh option for CLEAR_PASSPHRASE. [#4340] + + * scd: Fix flushing of the CA-FPR DOs in app-openpgp. + + * scd: Avoid a conflict error with the "undefined" app. + + * dirmngr: Add CSRF protection exception for protonmail. + + * dirmngr: Fix build problems with gcc 9 in libdns. + + * gpgconf: New option --show-socket for use with --launch. + + * gpgtar: Make option -C work for archive creation. + + Release-info: https://dev.gnupg.org/T4412 + See-also: gnupg-announce/2019q1/000435.html + + Changes also found in 2.2.13: + + * gpg: Implement key lookup via keygrip (using the & prefix). + + * gpg: Allow generating Ed25519 key from existing key. + + * gpg: Emit an ERROR status line if no key was found with -k. + + * gpg: Stop early when trying to create a primary Elgamal key. [#4329] + + * gpgsm: Print the card's key algorithms along with their keygrips + in interactive key generation. + + * agent: Clear bogus pinentry cache in the error case. [#4348] + + * scd: Support "acknowledge button" feature. + + * scd: Fix for USB INTERRUPT transfer. [#4308] + + * wks: Do no use compression for the the encrypted challenge and + response. + + Release-info: https://dev.gnupg.org/T4290 + See-also: gnupg-announce/2019q1/000434.html + + Changes also found in 2.2.12: + + * tools: New commands --install-key and --remove-key for + gpg-wks-client. This allows to prepare a Web Key Directory on a + local file system for later upload to a web server. + + * gpg: New --list-option "show-only-fpr-mbox". This makes the use + of the new gpg-wks-client --install-key command easier on Windows. + + * gpg: Improve processing speed when --skip-verify is used. + + * gpg: Fix a bug where a LF was accidentally written to the console. + + * gpg: --card-status now shows whether a card has the new KDF + feature enabled. + + * agent: New runtime option --s2k-calibration=MSEC. New configure + option --with-agent-s2k-calibration=MSEC. [#3399] + + * dirmngr: Try another keyserver from the pool on receiving a 502, + 503, or 504 error. [#4175] + + * dirmngr: Avoid possible CSRF attacks via http redirects. A HTTP + query will not anymore follow a 3xx redirect unless the Location + header gives the same host. If the host is different only the + host and port is taken from the Location header and the original + path and query parts are kept. + + * dirmngr: New command FLUSHCRL to flush all CRLS from disk and + memory. [#3967] + + * New simplified Chinese translation (zh_CN). + + Release-info: https://dev.gnupg.org/T4289 + See-also: gnupg-announce/2018q4/000433.html + Changes also found in 2.2.11: * gpgsm: Fix CRL loading when intermediate certicates are not yet @@ -388,6 +484,9 @@ Noteworthy changes in version 2.3.0 (unreleased) Version 2.2.9 (2018-07-12) Version 2.2.10 (2018-08-30) Version 2.2.11 (2018-11-06) + Version 2.2.12 (2018-12-14) + Version 2.2.13 (2019-02-12) + Version 2.2.14 (2019-03-19) Noteworthy changes in version 2.2.0 (2017-08-28) From 3c7a1f3aea7f6e8137a93ef2166ff329688f5445 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 26 Mar 2019 09:02:19 +0100 Subject: [PATCH 011/169] agent: Allow other ssh fingerprint algos in KEYINFO. * agent/command.c (cmd_keyinfo): Allow for --ssh-fpr=ALGO. Default to the standard algo. Signed-off-by: Werner Koch --- agent/command.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/agent/command.c b/agent/command.c index 5e2b6df2b..082ed4144 100644 --- a/agent/command.c +++ b/agent/command.c @@ -1075,7 +1075,7 @@ cmd_readkey (assuan_context_t ctx, char *line) static const char hlp_keyinfo[] = - "KEYINFO [--[ssh-]list] [--data] [--ssh-fpr] [--with-ssh] \n" + "KEYINFO [--[ssh-]list] [--data] [--ssh-fpr[=algo]] [--with-ssh] \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" @@ -1111,7 +1111,9 @@ static const char hlp_keyinfo[] = " '-' - Unknown protection.\n" "\n" "FPR returns the formatted ssh-style fingerprint of the key. It is only\n" - " printed if the option --ssh-fpr has been used. It defaults to '-'.\n" + " printed if the option --ssh-fpr has been used. If ALGO is not given\n" + " to that option the default ssh fingerprint algo is used. Without the\n" + " option a '-' is printed.\n" "\n" "TTL is the TTL in seconds for that key or '-' if n/a.\n" "\n" @@ -1198,7 +1200,7 @@ do_one_keyinfo (ctrl_t ctrl, const unsigned char *grip, assuan_context_t ctx, if (!agent_raw_key_from_file (ctrl, grip, &key)) { - ssh_get_fingerprint_string (key, GCRY_MD_MD5, &fpr); + ssh_get_fingerprint_string (key, with_ssh_fpr, &fpr); gcry_sexp_release (key); } } @@ -1279,7 +1281,21 @@ cmd_keyinfo (assuan_context_t ctx, char *line) else list_mode = has_option (line, "--list"); opt_data = has_option (line, "--data"); - opt_ssh_fpr = has_option (line, "--ssh-fpr"); + + if (has_option_name (line, "--ssh-fpr")) + { + if (has_option (line, "--ssh-fpr=md5")) + opt_ssh_fpr = GCRY_MD_MD5; + else if (has_option (line, "--ssh-fpr=sha1")) + opt_ssh_fpr = GCRY_MD_SHA1; + else if (has_option (line, "--ssh-fpr=sha256")) + opt_ssh_fpr = GCRY_MD_SHA256; + else + opt_ssh_fpr = opt.ssh_fingerprint_digest; + } + else + opt_ssh_fpr = 0; + opt_with_ssh = has_option (line, "--with-ssh"); line = skip_options (line); From aa58d2a49b3d416d9d6a0691a89f2bc8bc8649ad Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 26 Mar 2019 13:31:06 +0100 Subject: [PATCH 012/169] sm: Allow decryption even if expired other keys are configured. * sm/gpgsm.c (main): Add special handling for bad keys in decrypt mode. -- The problem can easily be tested by adding --encrypt-to EXPIRED_KEY to a decryption command. With that patch the errors are printed but decryption continues and the process returns success unless other errors occur. GnuPG-bug-id: 4431 Signed-off-by: Werner Koch --- sm/gpgsm.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/sm/gpgsm.c b/sm/gpgsm.c index 70964512c..020072a50 100644 --- a/sm/gpgsm.c +++ b/sm/gpgsm.c @@ -1742,6 +1742,8 @@ main ( int argc, char **argv) if (!do_not_setup_keys) { + int errcount = log_get_errorcount (0); + for (sl = locusr; sl ; sl = sl->next) { int rc = gpgsm_add_to_certlist (&ctrl, sl->d, 1, &signerlist, 0); @@ -1770,6 +1772,15 @@ main ( int argc, char **argv) if ((sl->flags & 1)) do_add_recipient (&ctrl, sl->d, &recplist, 1, recp_required); } + + /* We do not require a recipient for decryption but because + * recipients and signers are always checked and log_error is + * sometimes used (for failed signing keys or due to a failed + * CRL checking) that would have bumbed up the error counter. + * We clear the counter in the decryption case because there is + * no reason to force decryption to fail. */ + if (cmd == aDecrypt && !errcount) + log_get_errorcount (1); /* clear counter */ } if (log_get_errorcount(0)) From 4324560b2c0bb76a1769535c383424a042e505ae Mon Sep 17 00:00:00 2001 From: Trevor Bentley Date: Mon, 25 Mar 2019 15:19:47 +0100 Subject: [PATCH 013/169] gpg: Don't use EdDSA algo ID for ECDSA curves. * g10/keygen.c (ask_curve): Change algo ID to ECDSA if it changed from an EdDSA curve. -- This change matters when it is called from ask_card_keyattr. Some-comments-by: NIIBE Yutaka --- g10/keygen.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/g10/keygen.c b/g10/keygen.c index 64fefd231..943b40110 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -2507,14 +2507,25 @@ ask_curve (int *algo, int *subkey_algo, const char *current) else { /* If the user selected a signing algorithm and Curve25519 - we need to set the algo to EdDSA and update the curve name. */ - if ((*algo == PUBKEY_ALGO_ECDSA || *algo == PUBKEY_ALGO_EDDSA) - && curves[idx].eddsa_curve) + we need to set the algo to EdDSA and update the curve name. + If switching away from EdDSA, we need to set the algo back + to ECDSA. */ + if (*algo == PUBKEY_ALGO_ECDSA || *algo == PUBKEY_ALGO_EDDSA) { - if (subkey_algo && *subkey_algo == PUBKEY_ALGO_ECDSA) - *subkey_algo = PUBKEY_ALGO_EDDSA; - *algo = PUBKEY_ALGO_EDDSA; - result = curves[idx].eddsa_curve; + if (curves[idx].eddsa_curve) + { + if (subkey_algo && *subkey_algo == PUBKEY_ALGO_ECDSA) + *subkey_algo = PUBKEY_ALGO_EDDSA; + *algo = PUBKEY_ALGO_EDDSA; + result = curves[idx].eddsa_curve; + } + else + { + if (subkey_algo && *subkey_algo == PUBKEY_ALGO_EDDSA) + *subkey_algo = PUBKEY_ALGO_ECDSA; + *algo = PUBKEY_ALGO_ECDSA; + result = curves[idx].name; + } } else result = curves[idx].name; From 5a3055eb722e61126748e83564e1bba42807d722 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 27 Mar 2019 17:34:50 +0100 Subject: [PATCH 014/169] scd: Support reading the Yubikey 4 firmware version. * scd/app.c (app_new_register): Detect yk4 version numbers. -- Having the version of the yubikey is important to select which other methods can be used with a Yubikey. Note that we do not detect the formfactor of a Yubikey 4 and instead use 0 for our serial number prefix. This does not affect app-openpgp becuase there we use the app specific serial number. Signed-off-by: Werner Koch --- scd/app.c | 59 +++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 21 deletions(-) diff --git a/scd/app.c b/scd/app.c index 81218f411..f0f6d7ecb 100644 --- a/scd/app.c +++ b/scd/app.c @@ -247,9 +247,12 @@ app_new_register (int slot, ctrl_t ctrl, const char *name, * config. */ static char const yk_aid[] = { 0xA0, 0x00, 0x00, 0x05, 0x27, 0x47, 0x11, 0x17 }; /*MGR*/ + static char const otp_aid[] = + { 0xA0, 0x00, 0x00, 0x05, 0x27, 0x20, 0x01 }; /*OTP*/ unsigned char *buf; size_t buflen; - const unsigned char *s0, *s1; + const unsigned char *s0; + unsigned char formfactor; size_t n; if (!iso7816_select_application (slot, yk_aid, sizeof yk_aid, @@ -269,29 +272,43 @@ app_new_register (int slot, ctrl_t ctrl, const char *name, if (buflen > 1) { s0 = find_tlv (buf+1, buflen-1, 0x04, &n); /* Form factor */ - if (s0 && n == 1) + formfactor = (s0 && n == 1)? *s0 : 0; + + s0 = find_tlv (buf+1, buflen-1, 0x02, &n); /* Serial */ + if (s0 && n >= 4) { - s1 = find_tlv (buf+1, buflen-1, 0x02, &n); /* Serial */ - if (s1 && n >= 4) + app->serialno = xtrymalloc (3 + 1 + n); + if (app->serialno) { - app->serialno = xtrymalloc (3 + 1 + n); - if (app->serialno) - { - app->serialnolen = 3 + 1 + n; - app->serialno[0] = 0xff; - app->serialno[1] = 0x02; - app->serialno[2] = 0x0; - app->serialno[3] = *s0; - memcpy (app->serialno + 4, s1, n); - /* Note that we do not clear the error - * so that no further serial number - * testing is done. After all we just - * set the serial number. */ - } + app->serialnolen = 3 + 1 + n; + app->serialno[0] = 0xff; + app->serialno[1] = 0x02; + app->serialno[2] = 0x0; + app->serialno[3] = formfactor; + memcpy (app->serialno + 4, s0, n); + /* Note that we do not clear the error + * so that no further serial number + * testing is done. After all we just + * set the serial number. */ } - s1 = find_tlv (buf+1, buflen-1, 0x05, &n); /* version */ - if (s1 && n == 3) - app->cardversion = ((s1[0]<<16)|(s1[1]<<8)|s1[2]); + } + + s0 = find_tlv (buf+1, buflen-1, 0x05, &n); /* version */ + if (s0 && n == 3) + app->cardversion = ((s0[0]<<16)|(s0[1]<<8)|s0[2]); + else if (!s0) + { + /* No version - this is not a Yubikey 5. We now + * switch to the OTP app and take the first + * three bytes of the reponse as version + * number. */ + xfree (buf); + buf = NULL; + if (!iso7816_select_application_ext (slot, + otp_aid, sizeof otp_aid, + 1, &buf, &buflen) + && buflen > 3) + app->cardversion = ((buf[0]<<16)|(buf[1]<<8)|buf[2]); } } xfree (buf); From 2f761251c5730a9ad113fa58466addc9c2372da8 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 28 Mar 2019 10:56:28 +0100 Subject: [PATCH 015/169] card: Allow "yubikey disable" only for Yubikey-5 and later. * tools/card-yubikey.c (yubikey_commands): Add new arg INFO and test for Yubikey-5. * tools/gpg-card.c (cmd_yubikey): Pass info to yubikey_commands. -- The configuration can be read from a Yubikey-4 but not be written. The mode command is also not useful because it allows only the selection of transports. It does not allow to disable single applications based on one transport (like OPGP and PIV). Thsi patch shows an appropriate error message. Signed-off-by: Werner Koch --- tools/card-yubikey.c | 10 +++++++++- tools/gpg-card.c | 2 +- tools/gpg-card.h | 3 ++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/tools/card-yubikey.c b/tools/card-yubikey.c index f9d130988..fff669cc0 100644 --- a/tools/card-yubikey.c +++ b/tools/card-yubikey.c @@ -310,7 +310,7 @@ yk_enable_disable (struct ykapps_s *yk, struct iface_s *iface, * stream to output information. This function must only be called on * Yubikeys. */ gpg_error_t -yubikey_commands (estream_t fp, int argc, char *argv[]) +yubikey_commands (card_info_t info, estream_t fp, int argc, char *argv[]) { gpg_error_t err; enum {ykLIST, ykENABLE, ykDISABLE } cmd; @@ -336,6 +336,14 @@ yubikey_commands (estream_t fp, int argc, char *argv[]) goto leave; } + if (info->cardversion < 0x050000 && cmd != ykLIST) + { + log_info ("Sub-command '%s' is only support by Yubikey-5 and later\n", + argv[0]); + err = gpg_error (GPG_ERR_NOT_SUPPORTED); + goto leave; + } + /* Parse interface if needed. */ if (cmd == ykLIST) iface.usb = iface.nfc = 1; diff --git a/tools/gpg-card.c b/tools/gpg-card.c index e2d728dab..a3113c9c5 100644 --- a/tools/gpg-card.c +++ b/tools/gpg-card.c @@ -2988,7 +2988,7 @@ cmd_yubikey (card_info_t info, char *argstr) /* Note that we always do a learn to get a chance to the card back * into a usable state. */ - err = yubikey_commands (fp, nwords, words); + err = yubikey_commands (info, fp, nwords, words); err2 = scd_learn (info); if (err2) log_error ("Error re-reading card: %s\n", gpg_strerror (err)); diff --git a/tools/gpg-card.h b/tools/gpg-card.h index 099ea5448..35db14d25 100644 --- a/tools/gpg-card.h +++ b/tools/gpg-card.h @@ -224,7 +224,8 @@ gpg_error_t scd_checkpin (const char *serialno); unsigned long agent_get_s2k_count (void); /*-- card-yubikey.c --*/ -gpg_error_t yubikey_commands (estream_t fp, int argc, char *argv[]); +gpg_error_t yubikey_commands (card_info_t info, + estream_t fp, int argc, char *argv[]); #endif /*GNUPG_GPG_CARD_H*/ From 80c069b5e1ad6fbd547de59f332eb3fabb68c572 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 28 Mar 2019 14:46:05 +0100 Subject: [PATCH 016/169] card: For passwd add a PIV menu and make the OpenPGP menu optional. * tools/gpg-card.c (get_selection): New. (cmd_passwd): Reworked. Signed-off-by: Werner Koch --- tools/gpg-card.c | 183 ++++++++++++++++++++++++++--------------------- 1 file changed, 102 insertions(+), 81 deletions(-) diff --git a/tools/gpg-card.c b/tools/gpg-card.c index a3113c9c5..7b3f8a3f6 100644 --- a/tools/gpg-card.c +++ b/tools/gpg-card.c @@ -429,6 +429,24 @@ put_data_to_file (const char *fname, const void *buffer, size_t length) } +/* Return a malloced string with the number opf the menu PROMPT. + * Control-D is mapped to "Q". */ +static char * +get_selection (const char *prompt) +{ + char *answer; + + tty_printf ("\n"); + tty_printf ("%s", prompt); + tty_printf ("\n"); + answer = tty_get (_("Your selection? ")); + tty_kill_prompt (); + if (*answer == CONTROL_D) + strcpy (answer, "q"); + return answer; +} + + /* Simply prints TEXT to the output. Returns 0 as a convenience. * This is a separate fucntion so that it can be extended to run @@ -2097,21 +2115,23 @@ cmd_generate (card_info_t info, char *argstr) -/* Sub-menu to change a PIN. */ +/* Change a PIN. */ static gpg_error_t cmd_passwd (card_info_t info, char *argstr) { - gpg_error_t err; + gpg_error_t err = 0; char *answer = NULL; - const char *pinref; + const char *pinref = NULL; + int reset_mode = 0; + int menu_used = 0; if (!info) return print_help ("PASSWD [PINREF]\n\n" - "Menu to change or unblock the PINs. Note that the\n" - "presented menu options depend on the type of card\n" - "and whether the admin mode is enabled. For OpenPGP\n" - "and PIV cards defaults for PINREF are available.", + "Change or unblock the PINs. Note that in interactive mode\n" + "and without a PINREF a menu is presented for certain cards;\n" + "in non-interactive and without a PINREF a default value is\n" + "used for these cards.", 0); if (opt.interactive || opt.verbose) @@ -2119,92 +2139,93 @@ cmd_passwd (card_info_t info, char *argstr) app_type_string (info->apptype), info->dispserialno? info->dispserialno : info->serialno); - if (!*argstr && info->apptype == APP_TYPE_OPENPGP) + if (*argstr) + pinref = argstr; + else if (opt.interactive && info->apptype == APP_TYPE_OPENPGP) { - /* For an OpenPGP card we present the well known menu if no - * argument is given. */ - for (;;) + menu_used = 1; + while (!pinref) { - tty_printf ("\n"); - tty_printf ("1 - change PIN\n" - "2 - unblock and set new PIN\n" - "3 - change Admin PIN\n" - "4 - set the Reset Code\n" - "Q - quit\n"); - tty_printf ("\n"); - - err = 0; xfree (answer); - answer = tty_get (_("Your selection? ")); - tty_kill_prompt (); - if (*answer == CONTROL_D) - break; /* Quit. */ + answer = get_selection ("1 - change the PIN\n" + "2 - unblock and set new a PIN\n" + "3 - change the Admin PIN\n" + "4 - set the Reset Code\n" + "Q - quit\n"); if (strlen (answer) != 1) continue; - if (*answer == 'q' || *answer == 'Q') - break; /* Quit. */ - - if (*answer == '1') - { - /* Change PIN (same as the direct thing in non-admin mode). */ - err = scd_change_pin ("OPENPGP.1", 0); - if (err) - log_error ("Error changing the PIN: %s\n", gpg_strerror (err)); - else - log_info ("PIN changed.\n"); - } + else if (*answer == 'q' || *answer == 'Q') + goto leave; + else if (*answer == '1') + pinref = "OPENPGP.1"; else if (*answer == '2') - { - /* Unblock PIN by setting a new PIN. */ - err = scd_change_pin ("OPENPGP.1", 1); - if (err) - log_error ("Error unblocking the PIN: %s\n", gpg_strerror(err)); - else - log_info ("PIN unblocked and new PIN set.\n"); - } + { pinref = "OPENPGP.1"; reset_mode = 1; } else if (*answer == '3') - { - /* Change Admin PIN. */ - err = scd_change_pin ("OPENPGP.3", 0); - if (err) - log_error ("Error changing the PIN: %s\n", gpg_strerror (err)); - else - log_info ("PIN changed.\n"); - } + pinref = "OPENPGP.3"; else if (*answer == '4') - { - /* Set a new Reset Code. */ - err = scd_change_pin ("OPENPGP.2", 1); - if (err) - log_error ("Error setting the Reset Code: %s\n", - gpg_strerror (err)); - else - log_info ("Reset Code set.\n"); - } + { pinref = "OPENPGP.2"; reset_mode = 1; } + } + } + else if (info->apptype == APP_TYPE_OPENPGP) + pinref = "OPENPGP.1"; + else if (opt.interactive && info->apptype == APP_TYPE_PIV) + { + menu_used = 1; + while (!pinref) + { + xfree (answer); + answer = get_selection ("1 - change the PIN\n" + "2 - change the PUK\n" + "3 - change the Global PIN\n" + "Q - quit\n"); + if (strlen (answer) != 1) + ; + else if (*answer == 'q' || *answer == 'Q') + goto leave; + else if (*answer == '1') + pinref = "PIV.80"; + else if (*answer == '2') + pinref = "PIV.81"; + else if (*answer == '3') + pinref = "PIV.00"; + } + } + else if (info->apptype == APP_TYPE_PIV) + pinref = "PIV.80"; + else + { + err = gpg_error (GPG_ERR_MISSING_VALUE); + goto leave; + } - } /*end for loop*/ + err = scd_change_pin (pinref, reset_mode); + if (err) + { + if (!opt.interactive && !menu_used && !opt.verbose) + ; + else if (!ascii_strcasecmp (pinref, "PIV.81")) + log_error ("Error changing the PUK.\n"); + else if (!ascii_strcasecmp (pinref, "OPENPGP.1") && reset_mode) + log_error ("Error unblocking the PIN.\n"); + else if (!ascii_strcasecmp (pinref, "OPENPGP.2") && reset_mode) + log_error ("Error setting the Reset Code.\n"); + else if (!ascii_strcasecmp (pinref, "OPENPGP.3")) + log_error ("Error changing the Admin PIN.\n"); + else + log_error ("Error changing the PIN.\n"); } else { - if (*argstr) - pinref = argstr; - else if (info->apptype == APP_TYPE_PIV) - pinref = "PIV.80"; - else - { - /* Note that we do not have a default value for OpenPGP - * because we want to be mostly compatible to "gpg - * --card-edit" and show a menu in that case (above). */ - err = gpg_error (GPG_ERR_MISSING_VALUE); - goto leave; - } - err = scd_change_pin (pinref, 0); - if (err) - goto leave; - - if (info->apptype == APP_TYPE_PIV - && !ascii_strcasecmp (pinref, "PIV.81")) + if (!opt.interactive && !opt.verbose) + ; + else if (!ascii_strcasecmp (pinref, "PIV.81")) log_info ("PUK changed.\n"); + else if (!ascii_strcasecmp (pinref, "OPENPGP.1") && reset_mode) + log_info ("PIN unblocked and new PIN set.\n"); + else if (!ascii_strcasecmp (pinref, "OPENPGP.2") && reset_mode) + log_info ("Reset Code set.\n"); + else if (!ascii_strcasecmp (pinref, "OPENPGP.3")) + log_info ("Admin PIN changed.\n"); else log_info ("PIN changed.\n"); } @@ -2261,7 +2282,7 @@ cmd_unblock (card_info_t info) } else { - log_info ("Unblocking not yet supported for '%s'\n", + log_info ("Unblocking not supported for '%s'.\n", app_type_string (info->apptype)); err = gpg_error (GPG_ERR_NOT_IMPLEMENTED); } From 97feef8ee94a5e1cb9daba82f108eb62122c7910 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 28 Mar 2019 17:05:20 +0100 Subject: [PATCH 017/169] scd: New option --application-priority. * scd/scdaemon.c (oApplicationPriority): New. (opts): Add "application_priority". (main): Process option. * scd/app.c (app_update_priority_list): New. (get_supported_applications): Take apps from global list. * tools/gpgconf-comp.c (gc_options_scdaemon): Add option. Signed-off-by: Werner Koch --- doc/scdaemon.texi | 16 +++++++++- scd/app-common.h | 1 + scd/app.c | 76 ++++++++++++++++++++++++++++++++++---------- scd/scdaemon.c | 12 +++++++ tools/gpgconf-comp.c | 4 +++ 5 files changed, 91 insertions(+), 18 deletions(-) diff --git a/doc/scdaemon.texi b/doc/scdaemon.texi index 81af28105..0c984162c 100644 --- a/doc/scdaemon.texi +++ b/doc/scdaemon.texi @@ -332,6 +332,21 @@ This option disables the use of the card application named @var{name}. This is mainly useful for debugging or if a application with lower priority should be used by default. +@item --application-priority @var{namelist} +@opindex application-priority +This option allows to change the order in which applications of a card +a tried if no specific application was requested. @var{namelist} is a +space or comma delimited list of application names. Unknown names are +simply skipped. Applications not mentioned in the list are put in the +former order at the end of the new priority list. + +To get the list of current active applications, use +@cartouche +@smallexample + gpg-connect-agent 'scd getinfo app_list' /bye +@end smallexample +@end cartouche + @end table All the long options may also be given in the configuration file after @@ -767,4 +782,3 @@ length up to N bytes. If N is not given a default value is used @command{gpg2}(1) @end ifset @include see-also-note.texi - diff --git a/scd/app-common.h b/scd/app-common.h index 3df896228..c53bf06ca 100644 --- a/scd/app-common.h +++ b/scd/app-common.h @@ -133,6 +133,7 @@ size_t app_help_read_length_of_cert (int slot, int fid, size_t *r_certoff); /*-- app.c --*/ +void app_update_priority_list (const char *arg); void app_send_card_list (ctrl_t ctrl); char *app_get_serialno (app_t app); diff --git a/scd/app.c b/scd/app.c index f0f6d7ecb..59a8880db 100644 --- a/scd/app.c +++ b/scd/app.c @@ -59,6 +59,59 @@ static struct app_priority_list_s app_priority_list[] = +/* Initialization function to change the default app_priority_list. + * LIST is a list of comma or space separated strings with application + * names. Unknown names will only result in warning message. + * Application not mentioned in LIST are used in their original order + * after the given once. */ +void +app_update_priority_list (const char *arg) +{ + struct app_priority_list_s save; + char **names; + int i, j, idx; + + names = strtokenize (arg, ", "); + if (!names) + log_fatal ("strtokenize failed: %s\n", + gpg_strerror (gpg_error_from_syserror ())); + + idx = 0; + for (i=0; names[i]; i++) + { + ascii_strlwr (names[i]); + for (j=0; j < i; j++) + if (!strcmp (names[j], names[i])) + break; + if (j < i) + { + log_info ("warning: duplicate application '%s' in priority list\n", + names[i]); + continue; + } + + for (j=idx; app_priority_list[j].name; j++) + if (!strcmp (names[i], app_priority_list[j].name)) + break; + if (!app_priority_list[j].name) + { + log_info ("warning: unknown application '%s' in priority list\n", + names[i]); + continue; + } + save = app_priority_list[idx]; + app_priority_list[idx] = app_priority_list[j]; + app_priority_list[j] = save; + idx++; + } + log_assert (idx < DIM (app_priority_list)); + + xfree (names); + for (i=0; app_priority_list[i].name; i++) + log_info ("app priority %d: %s\n", i, app_priority_list[i].name); +} + + static void print_progress_line (void *opaque, const char *what, int pc, int cur, int tot) { @@ -511,32 +564,21 @@ select_application (ctrl_t ctrl, const char *name, app_t *r_app, char * get_supported_applications (void) { - const char *list[] = { - "openpgp", - "piv", - "nks", - "p15", - "geldkarte", - "dinsig", - "sc-hsm", - /* Note: "undefined" is not listed here because it needs special - treatment by the client. */ - NULL - }; int idx; size_t nbytes; char *buffer, *p; + const char *s; - for (nbytes=1, idx=0; list[idx]; idx++) - nbytes += strlen (list[idx]) + 1 + 1; + for (nbytes=1, idx=0; (s=app_priority_list[idx].name); idx++) + nbytes += strlen (s) + 1 + 1; buffer = xtrymalloc (nbytes); if (!buffer) return NULL; - for (p=buffer, idx=0; list[idx]; idx++) - if (is_app_allowed (list[idx])) - p = stpcpy (stpcpy (p, list[idx]), ":\n"); + for (p=buffer, idx=0; (s=app_priority_list[idx].name); idx++) + if (is_app_allowed (s)) + p = stpcpy (stpcpy (p, s), ":\n"); *p = 0; return buffer; diff --git a/scd/scdaemon.c b/scd/scdaemon.c index 507108db0..42efb4c37 100644 --- a/scd/scdaemon.c +++ b/scd/scdaemon.c @@ -98,6 +98,7 @@ enum cmd_and_opt_values oAllowAdmin, oDenyAdmin, oDisableApplication, + oApplicationPriority, oEnablePinpadVarlen, oListenBacklog }; @@ -154,6 +155,8 @@ static ARGPARSE_OPTS opts[] = { ARGPARSE_s_n (oDenyAdmin, "deny-admin", N_("deny the use of admin card commands")), ARGPARSE_s_s (oDisableApplication, "disable-application", "@"), + ARGPARSE_s_s (oApplicationPriority, "application-priority", + N_("|LIST|Change the application priority to LIST")), ARGPARSE_s_n (oEnablePinpadVarlen, "enable-pinpad-varlen", N_("use variable length input for pinpad")), ARGPARSE_s_s (oHomedir, "homedir", "@"), @@ -436,6 +439,7 @@ main (int argc, char **argv ) struct assuan_malloc_hooks malloc_hooks; int res; npth_t pipecon_handler; + const char *application_priority = NULL; early_system_init (); set_strusage (my_strusage); @@ -616,6 +620,10 @@ main (int argc, char **argv ) add_to_strlist (&opt.disabled_applications, pargs.r.ret_str); break; + case oApplicationPriority: + application_priority = pargs.r.ret_str; + break; + case oEnablePinpadVarlen: opt.enable_pinpad_varlen = 1; break; case oListenBacklog: @@ -720,6 +728,7 @@ main (int argc, char **argv ) es_printf ("disable-pinpad:%lu:\n", GC_OPT_FLAG_NONE ); es_printf ("card-timeout:%lu:%d:\n", GC_OPT_FLAG_DEFAULT, 0); es_printf ("enable-pinpad-varlen:%lu:\n", GC_OPT_FLAG_NONE ); + es_printf ("application-priority:%lu:\n", GC_OPT_FLAG_NONE ); scd_exit (0); } @@ -739,6 +748,9 @@ main (int argc, char **argv ) log_debug ("... okay\n"); } + if (application_priority) + app_update_priority_list (application_priority); + if (pipe_server) { /* This is the simple pipe based server */ diff --git a/tools/gpgconf-comp.c b/tools/gpgconf-comp.c index 2ae79d91d..272b7571e 100644 --- a/tools/gpgconf-comp.c +++ b/tools/gpgconf-comp.c @@ -653,6 +653,10 @@ static gc_option_t gc_options_scdaemon[] = { "card-timeout", GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME, GC_LEVEL_BASIC, "gnupg", "|N|disconnect the card after N seconds of inactivity", GC_ARG_TYPE_UINT32, GC_BACKEND_SCDAEMON }, + { "application-priority", + GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME, GC_LEVEL_ADVANCED, + "gnupg", "|LIST|Change the application priority to LIST", + GC_ARG_TYPE_STRING, GC_BACKEND_SCDAEMON }, { "Debug", GC_OPT_FLAG_GROUP, GC_LEVEL_ADVANCED, From 21b674097442a54ae889a90d708639b257ba43db Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 29 Mar 2019 14:20:47 +0100 Subject: [PATCH 018/169] dirmngr: Better for error code for http status 413. * dirmngr/ks-engine-hkp.c (send_request): New case for 413. * dirmngr/ks-engine-http.c (ks_http_fetch): Ditto. * dirmngr/ocsp.c (do_ocsp_request): Ditto. -- Signed-off-by: Werner Koch --- dirmngr/ks-engine-hkp.c | 4 ++++ dirmngr/ks-engine-http.c | 4 ++++ dirmngr/ocsp.c | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/dirmngr/ks-engine-hkp.c b/dirmngr/ks-engine-hkp.c index 4d660b87e..0a360f09f 100644 --- a/dirmngr/ks-engine-hkp.c +++ b/dirmngr/ks-engine-hkp.c @@ -1313,6 +1313,10 @@ send_request (ctrl_t ctrl, const char *request, const char *hostportstr, err = gpg_error (GPG_ERR_NOT_IMPLEMENTED); goto leave; + case 413: /* Payload too large */ + err = gpg_error (GPG_ERR_TOO_LARGE); + goto leave; + default: log_error (_("error accessing '%s': http status %u\n"), request, http_get_status_code (http)); diff --git a/dirmngr/ks-engine-http.c b/dirmngr/ks-engine-http.c index 0f3e2db4a..a84a3a1ea 100644 --- a/dirmngr/ks-engine-http.c +++ b/dirmngr/ks-engine-http.c @@ -174,6 +174,10 @@ ks_http_fetch (ctrl_t ctrl, const char *url, unsigned int flags, } goto once_more; + case 413: /* Payload too large */ + err = gpg_error (GPG_ERR_TOO_LARGE); + goto leave; + default: log_error (_("error accessing '%s': http status %u\n"), url, http_get_status_code (http)); diff --git a/dirmngr/ocsp.c b/dirmngr/ocsp.c index 79c252d87..dbd8c97bc 100644 --- a/dirmngr/ocsp.c +++ b/dirmngr/ocsp.c @@ -238,6 +238,10 @@ do_ocsp_request (ctrl_t ctrl, ksba_ocsp_t ocsp, gcry_md_hd_t md, } break; + case 413: /* Payload too large */ + err = gpg_error (GPG_ERR_TOO_LARGE); + break; + default: log_error (_("error accessing '%s': http status %u\n"), url, http_get_status_code (http)); From 3a4534d82682f69788da3cf4a445e38fbaf6b98e Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 1 Apr 2019 18:12:35 +0200 Subject: [PATCH 019/169] gpg: Remove unused arg in a card related function. * g10/call-agent.c (agent_scd_setattr): Remove unused arg serialno. Signed-off-by: Werner Koch --- g10/call-agent.c | 33 +++++++++++++++++---------------- g10/call-agent.h | 5 ++--- g10/card-util.c | 27 +++++++++++++-------------- g10/getkey.c | 2 +- 4 files changed, 33 insertions(+), 34 deletions(-) diff --git a/g10/call-agent.c b/g10/call-agent.c index 83777534e..797faf572 100644 --- a/g10/call-agent.c +++ b/g10/call-agent.c @@ -726,7 +726,10 @@ learn_status_cb (void *opaque, const char *line) return 0; } -/* Call the scdaemon to learn about a smartcard */ + +/* Call the scdaemon to learn about a smartcard. Note that in + * contradiction to the function's name, gpg-agent's LEARN command is + * used and not the low-level "SCD LEARN". */ int agent_scd_learn (struct agent_card_info_s *info, int force) { @@ -876,23 +879,21 @@ agent_scd_getattr (const char *name, struct agent_card_info_s *info) } -/* Send an setattr command to the SCdaemon. SERIALNO is not actually - used here but required by gpg 1.4's implementation of this code in - cardglue.c. */ -int -agent_scd_setattr (const char *name, - const unsigned char *value, size_t valuelen, - const char *serialno) +/* Send an setattr command to the SCdaemon. + * Used by: + * card-util.c + */ +gpg_error_t +agent_scd_setattr (const char *name, const void *value_arg, size_t valuelen) { - int rc; + gpg_error_t err; + const unsigned char *value = value_arg; char line[ASSUAN_LINELENGTH]; char *p; struct default_inq_parm_s parm; memset (&parm, 0, sizeof parm); - (void)serialno; - if (!*name || !valuelen) return gpg_error (GPG_ERR_INV_VALUE); @@ -918,16 +919,16 @@ agent_scd_setattr (const char *name, } *p = 0; - rc = start_agent (NULL, 1); - if (!rc) + err = start_agent (NULL, 1); + if (!err) { parm.ctx = agent_ctx; - rc = assuan_transact (agent_ctx, line, NULL, NULL, + err = assuan_transact (agent_ctx, line, NULL, NULL, default_inq_cb, &parm, NULL, NULL); } - status_sc_op_failure (rc); - return rc; + status_sc_op_failure (err); + return err; } diff --git a/g10/call-agent.h b/g10/call-agent.h index 8619a34f8..4c4fb2d4d 100644 --- a/g10/call-agent.h +++ b/g10/call-agent.h @@ -101,9 +101,8 @@ int agent_keytocard (const char *hexgrip, int keyno, int force, const char *serialno, const char *timestamp); /* Send a SETATTR command to the SCdaemon. */ -int agent_scd_setattr (const char *name, - const unsigned char *value, size_t valuelen, - const char *serialno); +gpg_error_t agent_scd_setattr (const char *name, + const void *value, size_t valuelen); /* Send a WRITECERT command to the SCdaemon. */ int agent_scd_writecert (const char *certidstr, diff --git a/g10/card-util.c b/g10/card-util.c index 08844bae3..f4054a9fd 100644 --- a/g10/card-util.c +++ b/g10/card-util.c @@ -816,7 +816,7 @@ change_name (void) return -1; } - rc = agent_scd_setattr ("DISP-NAME", isoname, strlen (isoname), NULL ); + rc = agent_scd_setattr ("DISP-NAME", isoname, strlen (isoname)); if (rc) log_error ("error setting Name: %s\n", gpg_strerror (rc)); @@ -837,7 +837,7 @@ change_url (void) trim_spaces (url); cpr_kill_prompt (); - rc = agent_scd_setattr ("PUBKEY-URL", url, strlen (url), NULL ); + rc = agent_scd_setattr ("PUBKEY-URL", url, strlen (url)); if (rc) log_error ("error setting URL: %s\n", gpg_strerror (rc)); xfree (url); @@ -995,7 +995,7 @@ change_login (const char *args) n = strlen (data); } - rc = agent_scd_setattr ("LOGIN-DATA", data, n, NULL ); + rc = agent_scd_setattr ("LOGIN-DATA", data, n); if (rc) log_error ("error setting login data: %s\n", gpg_strerror (rc)); xfree (data); @@ -1033,7 +1033,7 @@ change_private_do (const char *args, int nr) n = strlen (data); } - rc = agent_scd_setattr (do_name, data, n, NULL ); + rc = agent_scd_setattr (do_name, data, n); if (rc) log_error ("error setting private DO: %s\n", gpg_strerror (rc)); xfree (data); @@ -1132,7 +1132,7 @@ change_lang (void) return -1; } - rc = agent_scd_setattr ("DISP-LANG", data, strlen (data), NULL ); + rc = agent_scd_setattr ("DISP-LANG", data, strlen (data)); if (rc) log_error ("error setting lang: %s\n", gpg_strerror (rc)); xfree (data); @@ -1168,7 +1168,7 @@ change_sex (void) return -1; } - rc = agent_scd_setattr ("DISP-SEX", str, 1, NULL ); + rc = agent_scd_setattr ("DISP-SEX", str, 1); if (rc) log_error ("error setting salutation: %s\n", gpg_strerror (rc)); xfree (data); @@ -1216,7 +1216,7 @@ change_cafpr (int fprno) rc = agent_scd_setattr (fprno==1?"CA-FPR-1": fprno==2?"CA-FPR-2": - fprno==3?"CA-FPR-3":"x", fpr, fprlen, NULL ); + fprno==3?"CA-FPR-3":"x", fpr, fprlen); if (rc) log_error ("error setting cafpr: %s\n", gpg_strerror (rc)); write_sc_op_status (rc); @@ -1242,7 +1242,7 @@ toggle_forcesig (void) newstate = !info.chv1_cached; agent_release_card_info (&info); - rc = agent_scd_setattr ("CHV-STATUS-1", newstate? "\x01":"", 1, NULL); + rc = agent_scd_setattr ("CHV-STATUS-1", newstate? "\x01":"", 1); if (rc) log_error ("error toggling signature PIN flag: %s\n", gpg_strerror (rc)); write_sc_op_status (rc); @@ -1292,7 +1292,7 @@ check_pin_for_key_operation (struct agent_card_info_s *info, int *forced_chv1) { /* Switch off 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, info->serialno); + rc = agent_scd_setattr ("CHV-STATUS-1", "\x01", 1); if (rc) { log_error ("error clearing forced signature PIN flag: %s\n", @@ -1323,7 +1323,7 @@ restore_forced_chv1 (int *forced_chv1) if (*forced_chv1) { /* Switch back to forced state. */ - rc = agent_scd_setattr ("CHV-STATUS-1", "", 1, NULL); + rc = agent_scd_setattr ("CHV-STATUS-1", "", 1); if (rc) { log_error ("error setting forced signature PIN flag: %s\n", @@ -1570,7 +1570,7 @@ do_change_keyattr (int keyno, const struct key_attr *key_attr) return gpg_error (GPG_ERR_PUBKEY_ALGO); } - err = agent_scd_setattr ("KEY-ATTR", args, strlen (args), NULL); + err = agent_scd_setattr ("KEY-ATTR", args, strlen (args)); if (err) log_error (_("error changing key attribute for key %d: %s\n"), keyno+1, gpg_strerror (err)); @@ -2116,8 +2116,7 @@ kdf_setup (const char *args) goto leave_error; err = agent_scd_setattr ("KDF", kdf_data, - single ? KDF_DATA_LENGTH_MIN : KDF_DATA_LENGTH_MAX, - NULL); + single ? KDF_DATA_LENGTH_MIN : KDF_DATA_LENGTH_MAX); if (err) goto leave_error; @@ -2169,7 +2168,7 @@ uif (int arg_number, const char *arg_rest) data[1] = 0x20; - err = agent_scd_setattr (name, data, 2, NULL); + err = agent_scd_setattr (name, data, 2); if (err) log_error (_("error for setup UIF: %s\n"), gpg_strerror (err)); } diff --git a/g10/getkey.c b/g10/getkey.c index 9dae879d2..b15fbc13a 100644 --- a/g10/getkey.c +++ b/g10/getkey.c @@ -1315,7 +1315,7 @@ subkey_is_ok (const PKT_public_key *sub) /* Return true if KEYBLOCK has only expired encryption subkyes. Note * that the function returns false if the key has no encryption - * subkeys at all or the subkecys are revoked. */ + * subkeys at all or the subkeys are revoked. */ static int only_expired_enc_subkeys (kbnode_t keyblock) { From 334b16b868e771b983263ed20c200869e7e51198 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 1 Apr 2019 18:34:19 +0200 Subject: [PATCH 020/169] gpg: Remove two unused card related functions. * g10/call-agent.c (inq_writekey_parms): Remove. (agent_scd_writekey): Remove. (agent_clear_pin_cache): Remove this stub. --- g10/call-agent.c | 162 ++++++++++++++++++++++------------------------- g10/call-agent.h | 8 --- g10/card-util.c | 4 -- 3 files changed, 76 insertions(+), 98 deletions(-) diff --git a/g10/call-agent.c b/g10/call-agent.c index 797faf572..0416218df 100644 --- a/g10/call-agent.c +++ b/g10/call-agent.c @@ -352,7 +352,7 @@ start_agent (ctrl_t ctrl, int flag_for_card) break; default: write_status_text (STATUS_CARDCTRL, "4"); - log_info ("selecting openpgp failed: %s\n", gpg_strerror (rc)); + log_info ("selecting card failed: %s\n", gpg_strerror (rc)); break; } } @@ -729,7 +729,12 @@ learn_status_cb (void *opaque, const char *line) /* Call the scdaemon to learn about a smartcard. Note that in * contradiction to the function's name, gpg-agent's LEARN command is - * used and not the low-level "SCD LEARN". */ + * used and not the low-level "SCD LEARN". + * Used by: + * card-util.c + * keyedit_menu + * card_store_key_with_backup (Woth force to remove secret key data) + */ int agent_scd_learn (struct agent_card_info_s *info, int force) { @@ -819,6 +824,10 @@ agent_scd_apdu (const char *hexapdu, unsigned int *r_sw) } +/* Used by: + * card_store_subkey + * card_store_key_with_backup + */ int agent_keytocard (const char *hexgrip, int keyno, int force, const char *serialno, const char *timestamp) @@ -848,8 +857,18 @@ agent_keytocard (const char *hexgrip, int keyno, int force, /* Call the agent to retrieve a data object. This function returns - the data in the same structure as used by the learn command. It is - allowed to update such a structure using this command. */ + * the data in the same structure as used by the learn command. It is + * allowed to update such a structure using this command. + * + * Used by: + * build_sk_list + * enum_secret_keys + * get_signature_count + * card-util.c + * generate_keypair (KEY-ATTR) + * card_store_key_with_backup (SERIALNO) + * generate_card_subkeypair (KEY-ATTR) + */ int agent_scd_getattr (const char *name, struct agent_card_info_s *info) { @@ -878,6 +897,7 @@ agent_scd_getattr (const char *name, struct agent_card_info_s *info) return rc; } + /* Send an setattr command to the SCdaemon. * Used by: @@ -954,7 +974,10 @@ inq_writecert_parms (void *opaque, const char *line) } -/* Send a WRITECERT command to the SCdaemon. */ +/* Send a WRITECERT command to the SCdaemon. + * Used by: + * card-util.c + */ int agent_scd_writecert (const char *certidstr, const unsigned char *certdata, size_t certdatalen) @@ -985,60 +1008,6 @@ agent_scd_writecert (const char *certidstr, } - -/* Handle a KEYDATA inquiry. Note, we only send the data, - assuan_transact takes care of flushing and writing the end */ -static gpg_error_t -inq_writekey_parms (void *opaque, const char *line) -{ - int rc; - struct writekey_parm_s *parm = opaque; - - if (has_leading_keyword (line, "KEYDATA")) - { - rc = assuan_send_data (parm->dflt->ctx, parm->keydata, parm->keydatalen); - } - else - rc = default_inq_cb (parm->dflt, line); - - return rc; -} - - -/* Send a WRITEKEY command to the SCdaemon. */ -int -agent_scd_writekey (int keyno, const char *serialno, - const unsigned char *keydata, size_t keydatalen) -{ - int rc; - char line[ASSUAN_LINELENGTH]; - struct writekey_parm_s parms; - struct default_inq_parm_s dfltparm; - - memset (&dfltparm, 0, sizeof dfltparm); - - (void)serialno; - - rc = start_agent (NULL, 1); - if (rc) - return rc; - - memset (&parms, 0, sizeof parms); - - snprintf (line, DIM(line), "SCD WRITEKEY --force OPENPGP.%d", keyno); - dfltparm.ctx = agent_ctx; - parms.dflt = &dfltparm; - parms.keydata = keydata; - parms.keydatalen = keydatalen; - - rc = assuan_transact (agent_ctx, line, NULL, NULL, - inq_writekey_parms, &parms, NULL, NULL); - - status_sc_op_failure (rc); - return rc; -} - - /* Status callback for the SCD GENKEY command. */ static gpg_error_t @@ -1066,10 +1035,13 @@ scd_genkey_cb (void *opaque, const char *line) } /* Send a GENKEY command to the SCdaemon. If *CREATETIME is not 0, - the value will be passed to SCDAEMON with --timestamp option so that - the key is created with this. Otherwise, timestamp was generated by - SCDEAMON. On success, creation time is stored back to - CREATETIME. */ + * the value will be passed to SCDAEMON with --timestamp option so that + * the key is created with this. Otherwise, timestamp was generated by + * SCDEAMON. On success, creation time is stored back to + * CREATETIME. + * Used by: + * gen_card_key + */ int agent_scd_genkey (int keyno, int force, u32 *createtime) { @@ -1102,9 +1074,17 @@ agent_scd_genkey (int keyno, int force, u32 *createtime) status_sc_op_failure (rc); return rc; } + + /* Return the serial number of the card or an appropriate error. The - serial number is returned as a hexstring. */ + * serial number is returned as a hexstring. With DEMAND the active + * card is switched to the card with that serialno. + * Used by: + * card-util.c + * build_sk_list + * enum_secret_keys + */ int agent_scd_serialno (char **r_serialno, const char *demand) { @@ -1112,7 +1092,7 @@ agent_scd_serialno (char **r_serialno, const char *demand) char *serialno = NULL; char line[ASSUAN_LINELENGTH]; - err = start_agent (NULL, 1 | FLAG_FOR_CARD_SUPPRESS_ERRORS); + err = start_agent (NULL, (1 | FLAG_FOR_CARD_SUPPRESS_ERRORS)); if (err) return err; @@ -1133,8 +1113,13 @@ agent_scd_serialno (char **r_serialno, const char *demand) *r_serialno = serialno; return 0; } + + -/* Send a READCERT command to the SCdaemon. */ +/* Send a READCERT command to the SCdaemon. + * Used by: + * card-util.c + */ int agent_scd_readcert (const char *certidstr, void **r_buf, size_t *r_buflen) @@ -1172,6 +1157,8 @@ agent_scd_readcert (const char *certidstr, return 0; } + + struct card_cardlist_parm_s { int error; @@ -1209,7 +1196,12 @@ card_cardlist_cb (void *opaque, const char *line) return 0; } -/* Return cardlist. */ + +/* Return a list of currently available cards. + * Used by: + * card-util.c + * skclist.c + */ int agent_scd_cardlist (strlist_t *result) { @@ -1238,16 +1230,20 @@ agent_scd_cardlist (strlist_t *result) return 0; } + + /* Change the PIN of an OpenPGP card or reset the retry counter. - CHVNO 1: Change the PIN - 2: For v1 cards: Same as 1. - For v2 cards: Reset the PIN using the Reset Code. - 3: Change the admin PIN - 101: Set a new PIN and reset the retry counter - 102: For v1 cars: Same as 101. - For v2 cards: Set a new Reset Code. - SERIALNO is not used. + * CHVNO 1: Change the PIN + * 2: For v1 cards: Same as 1. + * For v2 cards: Reset the PIN using the Reset Code. + * 3: Change the admin PIN + * 101: Set a new PIN and reset the retry counter + * 102: For v1 cars: Same as 101. + * For v2 cards: Set a new Reset Code. + * SERIALNO is not used. + * Used by: + * card-util.c */ int agent_scd_change_pin (int chvno, const char *serialno) @@ -1281,8 +1277,11 @@ agent_scd_change_pin (int chvno, const char *serialno) /* Perform a CHECKPIN operation. SERIALNO should be the serial - number of the card - optionally followed by the fingerprint; - however the fingerprint is ignored here. */ + * number of the card - optionally followed by the fingerprint; + * however the fingerprint is ignored here. + * Used by: + * card-util.c + */ int agent_scd_checkpin (const char *serialno) { @@ -1307,15 +1306,6 @@ agent_scd_checkpin (const char *serialno) } -/* Dummy function, only used by the gpg 1.4 implementation. */ -void -agent_clear_pin_cache (const char *sn) -{ - (void)sn; -} - - - /* Note: All strings shall be UTF-8. On success the caller needs to free the string stored at R_PASSPHRASE. On error NULL will be diff --git a/g10/call-agent.h b/g10/call-agent.h index 4c4fb2d4d..86ee8a170 100644 --- a/g10/call-agent.h +++ b/g10/call-agent.h @@ -108,10 +108,6 @@ gpg_error_t agent_scd_setattr (const char *name, int agent_scd_writecert (const char *certidstr, const unsigned char *certdata, size_t certdatalen); -/* Send a WRITEKEY command to the SCdaemon. */ -int agent_scd_writekey (int keyno, const char *serialno, - const unsigned char *keydata, size_t keydatalen); - /* Send a GENKEY command to the SCdaemon. */ int agent_scd_genkey (int keyno, int force, u32 *createtime); @@ -125,10 +121,6 @@ int agent_scd_change_pin (int chvno, const char *serialno); /* Send the CHECKPIN command to the SCdaemon. */ int agent_scd_checkpin (const char *serialno); -/* Dummy function, only implemented by gpg 1.4. */ -void agent_clear_pin_cache (const char *sn); - - /* Send the GET_PASSPHRASE command to the agent. */ gpg_error_t agent_get_passphrase (const char *cache_id, const char *err_msg, diff --git a/g10/card-util.c b/g10/card-util.c index f4054a9fd..f9cce33ee 100644 --- a/g10/card-util.c +++ b/g10/card-util.c @@ -91,8 +91,6 @@ change_pin (int unblock_v2, int allow_admin) log_info (_("OpenPGP card no. %s detected\n"), info.serialno? info.serialno : "[none]"); - agent_clear_pin_cache (info.serialno); - if (opt.batch) { agent_release_card_info (&info); @@ -1285,8 +1283,6 @@ check_pin_for_key_operation (struct agent_card_info_s *info, int *forced_chv1) { int rc = 0; - agent_clear_pin_cache (info->serialno); - *forced_chv1 = !info->chv1_cached; if (*forced_chv1) { /* Switch off the forced mode so that during key generation we From 0fad61de159acf39e38a04f28f162f0beb0e77d6 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 1 Apr 2019 18:37:02 +0200 Subject: [PATCH 021/169] gpg: New card function agent_scd_keypairinfo. * g10/call-agent.c (scd_keypairinfo_status_cb) (agent_scd_keypairinfo): New. Taken from gpgsm. Signed-off-by: Werner Koch --- g10/call-agent.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++-- g10/call-agent.h | 3 ++ 2 files changed, 82 insertions(+), 3 deletions(-) diff --git a/g10/call-agent.c b/g10/call-agent.c index 0416218df..e5d5877ed 100644 --- a/g10/call-agent.c +++ b/g10/call-agent.c @@ -767,10 +767,86 @@ agent_scd_learn (struct agent_card_info_s *info, int force) } + +/* Callback for the agent_scd_keypairinfo function. */ +static gpg_error_t +scd_keypairinfo_status_cb (void *opaque, const char *line) +{ + strlist_t *listaddr = opaque; + const char *keyword = line; + int keywordlen; + strlist_t sl; + char *p; + + for (keywordlen=0; *line && !spacep (line); line++, keywordlen++) + ; + while (spacep (line)) + line++; + + if (keywordlen == 11 && !memcmp (keyword, "KEYPAIRINFO", keywordlen)) + { + sl = append_to_strlist (listaddr, line); + p = sl->d; + /* Make sure that we only have two tokens so that future + * extensions of the format won't change the format expected by + * the caller. */ + while (*p && !spacep (p)) + p++; + if (*p) + { + while (spacep (p)) + p++; + while (*p && !spacep (p)) + p++; + *p = 0; + } + } + + return 0; +} + + +/* Read the keypairinfo lines of the current card directly from + * scdaemon. The list is returned as a string made up of the keygrip, + * a space and the keyref. */ +gpg_error_t +agent_scd_keypairinfo (ctrl_t ctrl, strlist_t *r_list) +{ + gpg_error_t err; + strlist_t list = NULL; + struct default_inq_parm_s inq_parm; + + *r_list = NULL; + err= start_agent (ctrl, 1); + if (err) + return err; + memset (&inq_parm, 0, sizeof inq_parm); + inq_parm.ctx = agent_ctx; + + err = assuan_transact (agent_ctx, "SCD LEARN --force", + NULL, NULL, + default_inq_cb, &inq_parm, + scd_keypairinfo_status_cb, &list); + if (!err && !list) + err = gpg_error (GPG_ERR_NO_DATA); + if (err) + { + free_strlist (list); + return err; + } + *r_list = list; + return 0; +} + + + /* Send an APDU to the current card. On success the status word is - stored at R_SW. With HEXAPDU being NULL only a RESET command is - send to scd. With HEXAPDU being the string "undefined" the command - "SERIALNO undefined" is send to scd. */ + * stored at R_SW. With HEXAPDU being NULL only a RESET command is + * send to scd. With HEXAPDU being the string "undefined" the command + * "SERIALNO undefined" is send to scd. + * Used by: + * card-util.c + */ gpg_error_t agent_scd_apdu (const char *hexapdu, unsigned int *r_sw) { diff --git a/g10/call-agent.h b/g10/call-agent.h index 86ee8a170..0a545b22e 100644 --- a/g10/call-agent.h +++ b/g10/call-agent.h @@ -84,6 +84,9 @@ void agent_release_card_info (struct agent_card_info_s *info); /* Return card info. */ int agent_scd_learn (struct agent_card_info_s *info, int force); +/* Get the keypariinfo directly from scdaemon. */ +gpg_error_t agent_scd_keypairinfo (ctrl_t ctrl, strlist_t *r_list); + /* Return list of cards. */ int agent_scd_cardlist (strlist_t *result); From e47524c34a2a9f53c2507f67a0b41b460cee78b7 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 1 Apr 2019 19:24:33 +0200 Subject: [PATCH 022/169] gpg: Prepare card code to allow other than OpenPGP cards. * g10/call-agent.c (start_agent): Use card app auto selection. * g10/card-util.c (current_card_status): Print the Application type. (card_status): Put empty line between card listings. Signed-off-by: Werner Koch --- g10/call-agent.c | 2 +- g10/card-util.c | 44 +++++++++++++++++++++++++++++--------------- 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/g10/call-agent.c b/g10/call-agent.c index e5d5877ed..b02d6c68f 100644 --- a/g10/call-agent.c +++ b/g10/call-agent.c @@ -336,7 +336,7 @@ start_agent (ctrl_t ctrl, int flag_for_card) if (!(flag_for_card & FLAG_FOR_CARD_SUPPRESS_ERRORS)) rc = warn_version_mismatch (agent_ctx, SCDAEMON_NAME, 2); if (!rc) - rc = assuan_transact (agent_ctx, "SCD SERIALNO openpgp", + rc = assuan_transact (agent_ctx, "SCD SERIALNO", NULL, NULL, NULL, NULL, learn_status_cb, &info); if (rc && !(flag_for_card & FLAG_FOR_CARD_SUPPRESS_ERRORS)) diff --git a/g10/card-util.c b/g10/card-util.c index f9cce33ee..7e329bb6b 100644 --- a/g10/card-util.c +++ b/g10/card-util.c @@ -419,36 +419,43 @@ current_card_status (ctrl_t ctrl, estream_t fp, if (!info.serialno || strncmp (info.serialno, "D27600012401", 12) || strlen (info.serialno) != 32 ) { + const char *name1, *name2; if (info.apptype && !strcmp (info.apptype, "NKS")) { - if (opt.with_colons) - es_fputs ("netkey-card:\n", fp); - log_info ("this is a NetKey card\n"); + name1 = "netkey"; + name2 = "NetKey"; } else if (info.apptype && !strcmp (info.apptype, "DINSIG")) { - if (opt.with_colons) - es_fputs ("dinsig-card:\n", fp); - log_info ("this is a DINSIG compliant card\n"); + name1 = "dinsig"; + name2 = "DINSIG"; } else if (info.apptype && !strcmp (info.apptype, "P15")) { - if (opt.with_colons) - es_fputs ("pkcs15-card:\n", fp); - log_info ("this is a PKCS#15 compliant card\n"); + name1 = "pkcs15"; + name2 = "PKCS#15"; } else if (info.apptype && !strcmp (info.apptype, "GELDKARTE")) { - if (opt.with_colons) - es_fputs ("geldkarte-card:\n", fp); - log_info ("this is a Geldkarte compliant card\n"); + name1 = "geldkarte"; + name2 = "Geldkarte"; + } + else if (info.apptype && !strcmp (info.apptype, "PIV")) + { + name1 = "piv"; + name2 = "PIV"; } else { - if (opt.with_colons) - es_fputs ("unknown:\n", fp); + name1 = "unknown"; + name2 = "Unknown"; } - log_info ("not an OpenPGP card\n"); + + if (opt.with_colons) + es_fprintf (fp, "%s-card:\n", name1); + else + tty_fprintf (fp, "Application type .: %s\n", name2); + agent_release_card_info (&info); xfree (pk); return; @@ -463,6 +470,8 @@ current_card_status (ctrl_t ctrl, estream_t fp, if (opt.with_colons) es_fputs ("openpgp-card:\n", fp); + else + tty_fprintf (fp, "Application type .: %s\n", "OpenPGP"); if (opt.with_colons) @@ -695,6 +704,7 @@ card_status (ctrl_t ctrl, estream_t fp, const char *serialno) strlist_t card_list, sl; char *serialno0, *serialno1; int all_cards = 0; + int any_card = 0; if (serialno == NULL) { @@ -722,6 +732,10 @@ card_status (ctrl_t ctrl, estream_t fp, const char *serialno) if (!all_cards && strcmp (serialno, sl->d)) continue; + if (any_card && !opt.with_colons) + tty_fprintf (fp, "\n"); + any_card = 1; + err = agent_scd_serialno (&serialno1, sl->d); if (err) { From 9ed1aa56c4bbf44e00b731d6807ada9e95c91bd7 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 1 Apr 2019 19:58:33 +0200 Subject: [PATCH 023/169] sm: Show the usage flags when generating a key from a card. * g10/call-agent.c (scd_keypairinfo_status_cb): Also store the usage flags. * sm/call-agent.c (scd_keypairinfo_status_cb): Ditto. * sm/certreqgen-ui.c (gpgsm_gencertreq_tty): Print the usage flags. Signed-off-by: Werner Koch --- g10/call-agent.c | 20 ++++++++++++++++++-- sm/call-agent.c | 25 ++++++++++++++++++++----- sm/certreqgen-ui.c | 24 +++++++++++++++++++++++- 3 files changed, 61 insertions(+), 8 deletions(-) diff --git a/g10/call-agent.c b/g10/call-agent.c index b02d6c68f..83ca921a7 100644 --- a/g10/call-agent.c +++ b/g10/call-agent.c @@ -798,7 +798,22 @@ scd_keypairinfo_status_cb (void *opaque, const char *line) p++; while (*p && !spacep (p)) p++; - *p = 0; + if (*p) + { + *p++ = 0; + while (spacep (p)) + p++; + while (*p && !spacep (p)) + { + switch (*p++) + { + case 'c': sl->flags |= GCRY_PK_USAGE_CERT; break; + case 's': sl->flags |= GCRY_PK_USAGE_SIGN; break; + case 'e': sl->flags |= GCRY_PK_USAGE_ENCR; break; + case 'a': sl->flags |= GCRY_PK_USAGE_AUTH; break; + } + } + } } } @@ -808,7 +823,8 @@ scd_keypairinfo_status_cb (void *opaque, const char *line) /* Read the keypairinfo lines of the current card directly from * scdaemon. The list is returned as a string made up of the keygrip, - * a space and the keyref. */ + * a space and the keyref. The flags of the string carry the usage + * bits. */ gpg_error_t agent_scd_keypairinfo (ctrl_t ctrl, strlist_t *r_list) { diff --git a/sm/call-agent.c b/sm/call-agent.c index 4f2b83f56..4c3eecb10 100644 --- a/sm/call-agent.c +++ b/sm/call-agent.c @@ -785,9 +785,9 @@ scd_keypairinfo_status_cb (void *opaque, const char *line) { sl = append_to_strlist (listaddr, line); p = sl->d; - /* Make sure that we only have two tokes so that future - extensions of the format won't change the format expected by - the caller. */ + /* Make sure that we only have two tokens so that future + * extensions of the format won't change the format expected by + * the caller. */ while (*p && !spacep (p)) p++; if (*p) @@ -796,7 +796,22 @@ scd_keypairinfo_status_cb (void *opaque, const char *line) p++; while (*p && !spacep (p)) p++; - *p = 0; + if (*p) + { + *p++ = 0; + while (spacep (p)) + p++; + while (*p && !spacep (p)) + { + switch (*p++) + { + case 'c': sl->flags |= GCRY_PK_USAGE_CERT; break; + case 's': sl->flags |= GCRY_PK_USAGE_SIGN; break; + case 'e': sl->flags |= GCRY_PK_USAGE_ENCR; break; + case 'a': sl->flags |= GCRY_PK_USAGE_AUTH; break; + } + } + } } } @@ -806,7 +821,7 @@ scd_keypairinfo_status_cb (void *opaque, const char *line) /* Call the agent to read the keypairinfo lines of the current card. The list is returned as a string made up of the keygrip, a space - and the keyid. */ + and the keyid. The flags of the string carry the usage bits. */ int gpgsm_agent_scd_keypairinfo (ctrl_t ctrl, strlist_t *r_list) { diff --git a/sm/certreqgen-ui.c b/sm/certreqgen-ui.c index 70e5739e8..6f822bdbc 100644 --- a/sm/certreqgen-ui.c +++ b/sm/certreqgen-ui.c @@ -249,6 +249,7 @@ gpgsm_gencertreq_tty (ctrl_t ctrl, estream_t output_stream) gcry_sexp_t s_pkey; char *algostr = NULL; const char *keyref; + int any = 0; keyref = strchr (sl->d, ' '); if (keyref) @@ -262,7 +263,28 @@ gpgsm_gencertreq_tty (ctrl_t ctrl, estream_t output_stream) } xfree (pkey); } - tty_printf (" (%d) %s %s\n", count, sl->d, algostr); + tty_printf (" (%d) %s %s", count, sl->d, algostr); + if ((sl->flags & GCRY_PK_USAGE_CERT)) + { + tty_printf ("%scert", any?",":" ("); + any = 1; + } + if ((sl->flags & GCRY_PK_USAGE_SIGN)) + { + tty_printf ("%ssign", any?",":" ("); + any = 1; + } + if ((sl->flags & GCRY_PK_USAGE_AUTH)) + { + tty_printf ("%sauth", any?",":" ("); + any = 1; + } + if ((sl->flags & GCRY_PK_USAGE_ENCR)) + { + tty_printf ("%sencr", any?",":" ("); + any = 1; + } + tty_printf ("%s\n", any?")":""); xfree (algostr); } xfree (answer); From e100ace7f8a729bbe30d9f4ed157a7a229a04eb0 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 2 Apr 2019 13:22:32 +0200 Subject: [PATCH 024/169] dirmngr: Improve domaininfo cache update algorithm. * dirmngr/domaininfo.c (struct domaininfo_s): Add field keepmark. (insert_or_update): Implement new update algorithm. -- The old algorithm limited the length of a bucket chain by purging the last 50% or the entries. Thus the first domains entered into the cache were never purged. The new algorithm is a bit better: It also limits the chain length on overflow to 50% but tries to keep the entries indicating that a WKD is available in the cache. If there is still space to keep more, those which clearly do not support WKD are also kept. Signed-off-by: Werner Koch --- dirmngr/domaininfo.c | 125 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 106 insertions(+), 19 deletions(-) diff --git a/dirmngr/domaininfo.c b/dirmngr/domaininfo.c index f6263b06d..b41aef366 100644 --- a/dirmngr/domaininfo.c +++ b/dirmngr/domaininfo.c @@ -47,6 +47,7 @@ struct domaininfo_s unsigned int wkd_not_found:1; /* A WKD query failed. */ unsigned int wkd_supported:1; /* One WKD entry was found. */ unsigned int wkd_not_supported:1; /* Definitely does not support WKD. */ + unsigned int keepmark:1; /* Private to insert_or_update(). */ char name[1]; }; typedef struct domaininfo_s *domaininfo_t; @@ -143,7 +144,10 @@ insert_or_update (const char *domain, { domaininfo_t di; domaininfo_t di_new; - domaininfo_t di_cut; + domaininfo_t drop = NULL; + domaininfo_t drop_extra = NULL; + int nkept = 0; + int ndropped = 0; u32 hash; int count; @@ -162,7 +166,6 @@ insert_or_update (const char *domain, /* Need to do another lookup because the malloc is a system call and * thus the hash array may have been changed by another thread. */ - di_cut = NULL; for (count=0, di = domainbuckets[hash]; di; di = di->next, count++) if (!strcmp (di->name, domain)) { @@ -172,16 +175,89 @@ insert_or_update (const char *domain, } /* Before we insert we need to check whether the chain gets too long. */ - di_cut = NULL; if (count >= MAX_DOMAINBUCKET_LEN) { - for (count=0, di = domainbuckets[hash]; di; di = di->next, count++) - if (count >= MAX_DOMAINBUCKET_LEN/2) - { - di_cut = di->next; - di->next = NULL; - break; - } + domaininfo_t bucket; + domaininfo_t *array; + int narray, idx; + domaininfo_t keep = NULL; + + /* Unlink from the global list before doing a syscall. */ + bucket = domainbuckets[hash]; + domainbuckets[hash] = NULL; + + array = xtrycalloc (count, sizeof *array); + if (!array) + { + /* That's bad; give up the entire bucket. */ + log_error ("domaininfo: error allocating helper array: %s\n", + gpg_strerror (gpg_err_code_from_syserror ())); + drop_extra = bucket; + goto leave; + } + narray = 0; + + /* Move all items into an array for easier processing. */ + for (di = bucket; di; di = di->next) + array[narray++] = di; + log_assert (narray == count); + + /* Mark all item in the array which are flagged to support wkd + * but not more than half of the maximum. This way we will at + * the end drop half of the items. */ + count = 0; + for (idx=0; idx < narray; idx++) + { + di = array[idx]; + di->keepmark = 0; /* Clear flag here on the first pass. */ + if (di->wkd_supported && count < MAX_DOMAINBUCKET_LEN/2) + { + di->keepmark = 1; + count++; + } + } + /* Now mark those which are marked as not found. */ + /* FIXME: we should use an LRU algorithm here. */ + for (idx=0; idx < narray; idx++) + { + di = array[idx]; + if (!di->keepmark + && di->wkd_not_supported && count < MAX_DOMAINBUCKET_LEN/2) + { + di->keepmark = 1; + count++; + } + } + + /* Build a bucket list and a second list for later freeing the + * items (we can't do it directly because a free is a system + * call and we want to avoid locks in this module. Note that + * the kept items will be reversed order which does not matter. */ + for (idx=0; idx < narray; idx++) + { + di = array[idx]; + if (di->keepmark) + { + di->next = keep; + keep = di; + nkept++; + } + else + { + di->next = drop; + drop = di; + ndropped++; + } + } + + /* In case another thread added new stuff to the domain list we + * simply drop them instead all. It would also be possible to + * append them to our list but then we can't guarantee that a + * bucket list is almost all of the time limited to + * MAX_DOMAINBUCKET_LEN. Not sure whether this is really a + * sensible strategy. */ + drop_extra = domainbuckets[hash]; + domainbuckets[hash] = keep; } /* Insert */ @@ -190,17 +266,28 @@ insert_or_update (const char *domain, di->next = domainbuckets[hash]; domainbuckets[hash] = di; - /* Remove the rest of the cutted chain. */ - while (di_cut) + if (opt.verbose && (nkept || ndropped)) + log_info ("domaininfo: bucket=%lu kept=%d purged=%d\n", + (unsigned long)hash, nkept, ndropped); + + leave: + /* Remove the dropped items. */ + while (drop) { - di = di_cut->next; - xfree (di_cut); - di_cut = di; + di = drop->next; + xfree (drop); + drop = di; + } + while (drop_extra) + { + di = drop_extra->next; + xfree (drop_extra); + drop_extra = di; } } -/* Helper for domaininfo_set_no_name. */ +/* Helper for domaininfo_set_no_name. May not do any syscalls. */ static void set_no_name_cb (domaininfo_t di, int insert_mode) { @@ -224,7 +311,7 @@ domaininfo_set_no_name (const char *domain) } -/* Helper for domaininfo_set_wkd_supported. */ +/* Helper for domaininfo_set_wkd_supported. May not do any syscalls. */ static void set_wkd_supported_cb (domaininfo_t di, int insert_mode) { @@ -245,7 +332,7 @@ domaininfo_set_wkd_supported (const char *domain) } -/* Helper for domaininfo_set_wkd_not_supported. */ +/* Helper for domaininfo_set_wkd_not_supported. May not do any syscalls. */ static void set_wkd_not_supported_cb (domaininfo_t di, int insert_mode) { @@ -265,7 +352,7 @@ domaininfo_set_wkd_not_supported (const char *domain) -/* Helper for domaininfo_set_wkd_not_found. */ +/* Helper for domaininfo_set_wkd_not_found. May not do any syscalls. */ static void set_wkd_not_found_cb (domaininfo_t di, int insert_mode) { From f952226043824cbbeb8517126b5266926121c4e8 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 2 Apr 2019 18:49:51 +0200 Subject: [PATCH 025/169] common: Extend function pubkey_algo_string. * common/sexputil.c (pubkey_algo_string): Add arg R_ALGOID. * sm/certreqgen-ui.c (gpgsm_gencertreq_tty): Adjust. * tools/gpg-card.c (list_one_kinfo): Ditto. Signed-off-by: Werner Koch --- common/sexputil.c | 9 +++++++-- common/util.h | 2 +- sm/certreqgen-ui.c | 2 +- tools/gpg-card.c | 2 +- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/common/sexputil.c b/common/sexputil.c index d3020e169..f99bc3b18 100644 --- a/common/sexputil.c +++ b/common/sexputil.c @@ -581,9 +581,9 @@ get_pk_algo_from_canon_sexp (const unsigned char *keydata, size_t keydatalen) /* Given the public key S_PKEY, return a new buffer with a descriptive * string for its algorithm. This function may return NULL on memory - * error. */ + * error. If R_ALGOID is not NULL the gcrypt algo id is stored there. */ char * -pubkey_algo_string (gcry_sexp_t s_pkey) +pubkey_algo_string (gcry_sexp_t s_pkey, enum gcry_pk_algos *r_algoid) { const char *prefix; gcry_sexp_t l1; @@ -591,6 +591,9 @@ pubkey_algo_string (gcry_sexp_t s_pkey) int algo; char *result; + if (r_algoid) + *r_algoid = 0; + l1 = gcry_sexp_find_token (s_pkey, "public-key", 0); if (!l1) return xtrystrdup ("E_no_key"); @@ -632,6 +635,8 @@ pubkey_algo_string (gcry_sexp_t s_pkey) else result = xtryasprintf ("X_algo_%d", algo); + if (r_algoid) + *r_algoid = algo; xfree (algoname); return result; } diff --git a/common/util.h b/common/util.h index 8895137ec..bd6cd1ff5 100644 --- a/common/util.h +++ b/common/util.h @@ -192,7 +192,7 @@ gpg_error_t get_rsa_pk_from_canon_sexp (const unsigned char *keydata, int get_pk_algo_from_key (gcry_sexp_t key); int get_pk_algo_from_canon_sexp (const unsigned char *keydata, size_t keydatalen); -char *pubkey_algo_string (gcry_sexp_t s_pkey); +char *pubkey_algo_string (gcry_sexp_t s_pkey, enum gcry_pk_algos *r_algoid); /*-- convert.c --*/ int hex2bin (const char *string, void *buffer, size_t length); diff --git a/sm/certreqgen-ui.c b/sm/certreqgen-ui.c index 6f822bdbc..ae9ec35d0 100644 --- a/sm/certreqgen-ui.c +++ b/sm/certreqgen-ui.c @@ -258,7 +258,7 @@ gpgsm_gencertreq_tty (ctrl_t ctrl, estream_t output_stream) if (!gpgsm_agent_readkey (ctrl, 1, keyref, &pkey)) { if (!gcry_sexp_new (&s_pkey, pkey, 0, 0)) - algostr = pubkey_algo_string (s_pkey); + algostr = pubkey_algo_string (s_pkey, NULL); gcry_sexp_release (s_pkey); } xfree (pkey); diff --git a/tools/gpg-card.c b/tools/gpg-card.c index 7b3f8a3f6..d98a545ff 100644 --- a/tools/gpg-card.c +++ b/tools/gpg-card.c @@ -673,7 +673,7 @@ list_one_kinfo (key_info_t firstkinfo, key_info_t kinfo, if (!scd_readkey (kinfo->keyref, &s_pkey)) { - char *tmp = pubkey_algo_string (s_pkey); + char *tmp = pubkey_algo_string (s_pkey, NULL); tty_fprintf (fp, " algorithm ..: %s\n", tmp); xfree (tmp); gcry_sexp_release (s_pkey); From a480182f9d7ec316648cb64248f7a0cc8f681bc3 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 2 Apr 2019 18:57:09 +0200 Subject: [PATCH 026/169] gpg: Allow direct key generation from card with --full-gen-key. * g10/call-agent.c (agent_scd_readkey): New. * g10/keygen.c (ask_key_flags): Factor code out to .. (ask_key_flags_with_mask): new. (ask_algo): New mode 14. -- Note that this new menu 14 is always displayed. The usage flags can be changed only in --expert mode, though. Creating and using signing keys works but decryption does not yet work; we will need to tweak a couple of other places for that. Tested with a Yubikey's PIV app. Signed-off-by: Werner Koch --- doc/DETAILS | 1 + doc/gpg-card.texi | 14 ++-- g10/call-agent.c | 43 +++++++++++ g10/call-agent.h | 5 +- g10/keygen.c | 178 ++++++++++++++++++++++++++++++++++++++++------ 5 files changed, 213 insertions(+), 28 deletions(-) diff --git a/doc/DETAILS b/doc/DETAILS index 74a63ef00..3046523da 100644 --- a/doc/DETAILS +++ b/doc/DETAILS @@ -1572,6 +1572,7 @@ Description of some debug flags: | ecc/* | 11 | ECC (set your own capabilities) | | ecc/e | 12 | ECC (encrypt only) | | keygrip | 13 | Existing key | + | cardkey | 14 | Existing key from card | If one of the "foo/*" names are used a "keygen.flags" prompt needs to be answered as well. Instead of toggling the predefined flags, diff --git a/doc/gpg-card.texi b/doc/gpg-card.texi index aa49f81e7..92379aa19 100644 --- a/doc/gpg-card.texi +++ b/doc/gpg-card.texi @@ -210,7 +210,7 @@ Key management ...: [none] keyref .....: PIV.9D @end example -Note that the ``Displayed s/sn'' is printed on the token and also +Note that the ``Displayed s/n'' is printed on the token and also shown in Pinentry prompts asking for the PIN. The four standard key slots are always shown, if other key slots are initialized they are shown as well. The @emph{PIV authentication} key (internal reference @@ -231,11 +231,11 @@ which needs to be provided only once so that decryption operations can then be done until the card is reset or removed from the reader or USB port. -We now generate tree of the four keys. Note that GnuPG does currently -not use the the @emph{Card authentication} key but because it is -mandatory by the specs we create it anyway. Key generation requires -that we authenticate to the card. This can be done either on the -command line (which would reveal the key): +We now generate three of the four keys. Note that GnuPG does +currently not use the the @emph{Card authentication} key; however, +that key is mandatory by the PIV standard and thus we create it too. +Key generation requires that we authenticate to the card. This can be +done either on the command line (which would reveal the key): @example gpg/card> auth 010203040506070801020304050607080102030405060708 @@ -360,7 +360,7 @@ gpgsm: total number processed: 1 gpgsm: imported: 1 @end example -Note the last steps which imported the created certificate. If you +Note the last step which imported the created certificate. If you you instead created a certificate signing request (CSR) instead of a self-signed certificate and sent this off to a CA you would do the same import step with the certificate received from the CA. Take note diff --git a/g10/call-agent.c b/g10/call-agent.c index 83ca921a7..a0c5f811f 100644 --- a/g10/call-agent.c +++ b/g10/call-agent.c @@ -1251,6 +1251,49 @@ agent_scd_readcert (const char *certidstr, } +/* This is a variant of agent_readkey which sends a READKEY command + * directly Scdaemon. On success a new s-expression is stored at + * R_RESULT. */ +gpg_error_t +agent_scd_readkey (const char *keyrefstr, gcry_sexp_t *r_result) +{ + gpg_error_t err; + char line[ASSUAN_LINELENGTH]; + membuf_t data; + unsigned char *buf; + size_t len, buflen; + struct default_inq_parm_s dfltparm; + + memset (&dfltparm, 0, sizeof dfltparm); + dfltparm.ctx = agent_ctx; + + *r_result = NULL; + err = start_agent (NULL, 1); + if (err) + return err; + + init_membuf (&data, 1024); + snprintf (line, DIM(line), "SCD READKEY %s", keyrefstr); + err = assuan_transact (agent_ctx, line, + put_membuf_cb, &data, + default_inq_cb, &dfltparm, + NULL, NULL); + if (err) + { + xfree (get_membuf (&data, &len)); + return err; + } + buf = get_membuf (&data, &buflen); + if (!buf) + return gpg_error_from_syserror (); + + err = gcry_sexp_new (r_result, buf, buflen, 0); + xfree (buf); + + return err; +} + + struct card_cardlist_parm_s { int error; diff --git a/g10/call-agent.h b/g10/call-agent.h index 0a545b22e..cb874fdad 100644 --- a/g10/call-agent.h +++ b/g10/call-agent.h @@ -114,10 +114,13 @@ int agent_scd_writecert (const char *certidstr, /* Send a GENKEY command to the SCdaemon. */ int agent_scd_genkey (int keyno, int force, u32 *createtime); -/* Send a READKEY command to the SCdaemon. */ +/* Send a READCERT command to the SCdaemon. */ int agent_scd_readcert (const char *certidstr, void **r_buf, size_t *r_buflen); +/* Send a READKEY command to the SCdaemon. */ +gpg_error_t agent_scd_readkey (const char *keyrefstr, gcry_sexp_t *r_result); + /* Change the PIN of an OpenPGP card or reset the retry counter. */ int agent_scd_change_pin (int chvno, const char *serialno); diff --git a/g10/keygen.c b/g10/keygen.c index 943b40110..6ea4e72c6 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -1881,24 +1881,26 @@ print_key_flags(int flags) /* Ask for the key flags and return them. CURRENT gives the current - * usage which should normally be given as 0. */ + * usage which should normally be given as 0. MASK gives the allowed + * flags. */ unsigned int -ask_key_flags (int algo, int subkey, unsigned int current) +ask_key_flags_with_mask (int algo, int subkey, unsigned int current, + unsigned int mask) { /* TRANSLATORS: Please use only plain ASCII characters for the - translation. If this is not possible use single digits. The - string needs to 8 bytes long. Here is a description of the - functions: - - s = Toggle signing capability - e = Toggle encryption capability - a = Toggle authentication capability - q = Finish - */ + * translation. If this is not possible use single digits. The + * string needs to 8 bytes long. Here is a description of the + * functions: + * + * s = Toggle signing capability + * e = Toggle encryption capability + * a = Toggle authentication capability + * q = Finish + */ const char *togglers = _("SsEeAaQq"); char *answer = NULL; const char *s; - unsigned int possible = openpgp_pk_algo_usage(algo); + unsigned int possible; if ( strlen(togglers) != 8 ) { @@ -1907,22 +1909,26 @@ ask_key_flags (int algo, int subkey, unsigned int current) togglers = "11223300"; } - /* Only primary keys may certify. */ - if(subkey) - possible&=~PUBKEY_USAGE_CERT; + /* Mask the possible usage flags. This is for example used for a + * card based key. */ + possible = (openpgp_pk_algo_usage (algo) & mask); - /* Preload the current set with the possible set, minus - authentication if CURRENT has been given as 0. If CURRENT has - been has non-zero we mask with all possible usages. */ + /* However, only primary keys may certify. */ + if (subkey) + possible &= ~PUBKEY_USAGE_CERT; + + /* Preload the current set with the possible set, without + * authentication if CURRENT is 0. If CURRENT is non-zero we mask + * with all possible usages. */ if (current) current &= possible; else current = (possible&~PUBKEY_USAGE_AUTH); - for(;;) + for (;;) { tty_printf("\n"); - tty_printf(_("Possible actions for a %s key: "), + tty_printf(_("Possible actions for this %s key: "), (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_EDDSA) ? "ECDSA/EdDSA" : openpgp_pk_algo_name (algo)); @@ -2009,6 +2015,13 @@ ask_key_flags (int algo, int subkey, unsigned int current) } +unsigned int +ask_key_flags (int algo, int subkey, unsigned int current) +{ + return ask_key_flags_with_mask (algo, subkey, current, ~0); +} + + /* Check whether we have a key for the key with HEXGRIP. Returns 0 if there is no such key or the OpenPGP algo number for the key. */ static int @@ -2047,10 +2060,12 @@ static int ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage, char **r_keygrip) { + gpg_error_t err; char *keygrip = NULL; char *answer = NULL; int algo; int dummy_algo; + char *p; if (!r_subkey_algo) r_subkey_algo = &dummy_algo; @@ -2101,6 +2116,8 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage, if (opt.expert && r_keygrip) tty_printf (_(" (%d) Existing key\n"), 13 ); + if (r_keygrip) + tty_printf (_(" (%d) Existing key from card\n"), 14 ); for (;;) { @@ -2221,9 +2238,130 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage, *r_usage = ask_key_flags (algo, addmode, 0); break; } + else if ((algo == 14 || !strcmp (answer, "cardkey")) && r_keygrip) + { + char *serialno; + strlist_t keypairlist, sl; + int count, selection; + + err = agent_scd_serialno (&serialno, NULL); + if (err) + { + tty_printf (_("error reading the card: %s\n"), + gpg_strerror (err)); + goto ask_again; + } + tty_printf (_("Serial number of the card: %s\n"), serialno); + xfree (serialno); + + err = agent_scd_keypairinfo (ctrl, &keypairlist); + if (err) + { + tty_printf (_("error reading the card: %s\n"), + gpg_strerror (err)); + goto ask_again; + } + + do + { + tty_printf (_("Available keys:\n")); + for (count=1,sl=keypairlist; sl; sl = sl->next, count++) + { + gcry_sexp_t s_pkey; + char *algostr = NULL; + enum gcry_pk_algos algoid = 0; + const char *keyref; + int any = 0; + + keyref = strchr (sl->d, ' '); + if (keyref) + { + keyref++; + if (!agent_scd_readkey (keyref, &s_pkey)) + { + algostr = pubkey_algo_string (s_pkey, &algoid); + gcry_sexp_release (s_pkey); + } + } + /* We use the flags also encode the algo for use + * below. We need to tweak the algo in case + * GCRY_PK_ECC is returned becuase pubkey_algo_string + * is not aware of the OpenPGP algo mapping. + * FIXME: This is an ugly hack. */ + sl->flags &= 0xff; + if (algoid == GCRY_PK_ECC + && algostr && !strncmp (algostr, "nistp", 5) + && !(sl->flags & GCRY_PK_USAGE_ENCR)) + sl->flags |= (PUBKEY_ALGO_ECDSA << 8); + else + sl->flags |= (map_pk_gcry_to_openpgp (algoid) << 8); + + tty_printf (" (%d) %s %s", count, sl->d, algostr); + if ((sl->flags & GCRY_PK_USAGE_CERT)) + { + tty_printf ("%scert", any?",":" ("); + any = 1; + } + if ((sl->flags & GCRY_PK_USAGE_SIGN)) + { + tty_printf ("%ssign", any?",":" ("); + any = 1; + } + if ((sl->flags & GCRY_PK_USAGE_AUTH)) + { + tty_printf ("%sauth", any?",":" ("); + any = 1; + } + if ((sl->flags & GCRY_PK_USAGE_ENCR)) + { + tty_printf ("%sencr", any?",":" ("); + any = 1; + } + tty_printf ("%s\n", any?")":""); + xfree (algostr); + } + + xfree (answer); + answer = cpr_get ("keygen.cardkey", _("Your selection? ")); + cpr_kill_prompt (); + trim_spaces (answer); + selection = atoi (answer); + } + while (!(selection > 0 && selection < count)); + + for (count=1,sl=keypairlist; sl; sl = sl->next, count++) + if (count == selection) + break; + if (!sl) + { + /* Just in case COUNT is zero (no keys). */ + free_strlist (keypairlist); + goto ask_again; + } + + xfree (keygrip); + keygrip = xstrdup (sl->d); + if ((p = strchr (keygrip, ' '))) + *p = 0; + algo = (sl->flags >>8); + if (opt.expert) + *r_usage = ask_key_flags_with_mask (algo, addmode, + (sl->flags & 0xff), + (sl->flags & 0xff)); + else + { + *r_usage = (sl->flags & 0xff); + if (addmode) + *r_usage &= ~GCRY_PK_USAGE_CERT; + } + free_strlist (keypairlist); + break; + } else tty_printf (_("Invalid selection.\n")); + ask_again: + ; } xfree(answer); From 2d3392c147a24e49ee4658d4a50fafd68599fba3 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 3 Apr 2019 09:04:49 +0200 Subject: [PATCH 027/169] gpg: Print modern style key info for non-decryptable keys. * g10/mainproc.c (print_pkenc_list): Simplify. -- This changes the output from # ------------------------ >8 ------------------------ gpg: encrypted with 2048-bit RSA key, ID D20073D46DF6C97D, created 2019-04-02 "Test with PIV card" to gpg: encrypted with rsa2048 key, ID D20073D46DF6C97D, created 2019-04-02 "Test with PIV card" Signed-off-by: Werner Koch # ------------------------ 8< ------------------------ --- g10/keyid.c | 2 +- g10/mainproc.c | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/g10/keyid.c b/g10/keyid.c index aa77b47e2..45454f056 100644 --- a/g10/keyid.c +++ b/g10/keyid.c @@ -68,7 +68,7 @@ pubkey_letter( int algo ) } /* Return a string describing the public key algorithm and the - keysize. For elliptic curves the functions prints the name of the + keysize. For elliptic curves the function prints the name of the curve because the keysize is a property of the curve. The string is copied to the supplied buffer up a length of BUFSIZE-1. Examples for the output are: diff --git a/g10/mainproc.c b/g10/mainproc.c index 7acf67b1e..d99ac4386 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -506,19 +506,18 @@ print_pkenc_list (ctrl_t ctrl, struct pubkey_enc_list *list) for (; list; list = list->next) { PKT_public_key *pk; - const char *algstr; + char pkstrbuf[PUBKEY_STRING_SIZE]; + char *p; - algstr = openpgp_pk_algo_name (list->pubkey_algo); pk = xmalloc_clear (sizeof *pk); - if (!algstr) - algstr = "[?]"; pk->pubkey_algo = list->pubkey_algo; if (!get_pubkey (ctrl, pk, list->keyid)) { - char *p; - log_info (_("encrypted with %u-bit %s key, ID %s, created %s\n"), - nbits_from_pk (pk), algstr, keystr_from_pk(pk), + pubkey_string (pk, pkstrbuf, sizeof pkstrbuf); + + log_info (_("encrypted with %s key, ID %s, created %s\n"), + pkstrbuf, keystr_from_pk (pk), strtimestamp (pk->timestamp)); p = get_user_id_native (ctrl, list->keyid); log_printf (_(" \"%s\"\n"), p); @@ -526,7 +525,8 @@ print_pkenc_list (ctrl_t ctrl, struct pubkey_enc_list *list) } else log_info (_("encrypted with %s key, ID %s\n"), - algstr, keystr(list->keyid)); + openpgp_pk_algo_name (list->pubkey_algo), + keystr(list->keyid)); free_public_key (pk); } From bcca3acb87c36213fef9311236ea949d006f759c Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 3 Apr 2019 10:27:08 +0200 Subject: [PATCH 028/169] card: Allow card selection with LIST. * tools/card-call-scd.c (start_agent): Request serialno only whean started. (scd_serialno): Allow NULL for r_serialno. * tools/gpg-card.c (cmd_factoryreset): Use changed scd_serialno. (cmd_list): New. (dispatch_command): Use cmd_list for cmdLIST. (interactive_loop): Ditto. Signed-off-by: Werner Koch --- tools/card-call-scd.c | 13 +++-- tools/gpg-card.c | 114 ++++++++++++++++++++++++++++++------------ 2 files changed, 90 insertions(+), 37 deletions(-) diff --git a/tools/card-call-scd.c b/tools/card-call-scd.c index 0a01bf5ca..c2580bf5c 100644 --- a/tools/card-call-scd.c +++ b/tools/card-call-scd.c @@ -310,11 +310,13 @@ static gpg_error_t start_agent (unsigned int flags) { gpg_error_t err; + int started = 0; if (agent_ctx) err = 0; else { + started = 1; err = start_new_gpg_agent (&agent_ctx, GPG_ERR_SOURCE_DEFAULT, opt.agent_program, @@ -347,7 +349,7 @@ start_agent (unsigned int flags) } } - if (!err && !(flags & START_AGENT_NO_STARTUP_CMDS)) + if (started && !err && !(flags & START_AGENT_NO_STARTUP_CMDS)) { /* Request the serial number of the card for an early test. */ struct card_info_s info; @@ -990,7 +992,7 @@ learn_status_cb (void *opaque, const char *line) /* Call the scdaemon to learn about a smartcard. This fills INFO - * wioth data from the card. */ + * with data from the card. */ gpg_error_t scd_learn (card_info_t info) { @@ -1268,7 +1270,7 @@ scd_genkey (const char *keyref, int force, const char *algo, u32 *createtime) /* Return the serial number of the card or an appropriate error. The * serial number is returned as a hexstring. If DEMAND is not NULL - * the reader with the a card of the serilanumber DEMAND is + * the reader with the a card of the serial number DEMAND is * requested. */ gpg_error_t scd_serialno (char **r_serialno, const char *demand) @@ -1295,7 +1297,10 @@ scd_serialno (char **r_serialno, const char *demand) return err; } - *r_serialno = serialno; + if (r_serialno) + *r_serialno = serialno; + else + xfree (serialno); return 0; } diff --git a/tools/gpg-card.c b/tools/gpg-card.c index d98a545ff..ddc4d12bf 100644 --- a/tools/gpg-card.c +++ b/tools/gpg-card.c @@ -999,6 +999,81 @@ list_card (card_info_t info) } + +/* The LIST command. This also updates INFO. */ +static gpg_error_t +cmd_list (card_info_t info, char *argstr) +{ + gpg_error_t err; + int opt_cards; + strlist_t cards = NULL; + strlist_t sl; + estream_t fp = opt.interactive? NULL : es_stdout; + int cardno, count; + + + if (!info) + return print_help + ("LIST [--cards] [N]\n\n" + "Show the content of the current card or with N given the N-th card.\n" + "Option --cards lists available cards.", + 0); + + opt_cards = has_leading_option (argstr, "--cards"); + argstr = skip_options (argstr); + + + if (digitp (argstr)) + { + cardno = atoi (argstr); + while (digitp (argstr)) + argstr++; + while (spacep (argstr)) + argstr++; + } + else + cardno = -1; + + + if (opt_cards) + { + err = scd_cardlist (&cards); + if (err) + goto leave; + for (count = 0, sl = cards; sl; sl = sl->next, count++) + tty_fprintf (fp, "%d %s\n", count, sl->d); + } + else + { + if (cardno != -1) + { + err = scd_cardlist (&cards); + if (err) + goto leave; + for (count = 0, sl = cards; sl; sl = sl->next, count++) + if (count == cardno) + break; + if (!sl) + { + err = gpg_error (GPG_ERR_INV_INDEX); + goto leave; + } + err = scd_serialno (NULL, sl->d); + if (err) + goto leave; + } + + err = scd_learn (info); + if (!err) + list_card (info); + } + + leave: + free_strlist (cards); + return err; +} + + /* The VERIFY command. */ static gpg_error_t @@ -2478,9 +2553,8 @@ cmd_factoryreset (card_info_t info) if (err) goto leave; - /* Then, connect the card again (answer used as a dummy). */ - xfree (answer); answer = NULL; - err = scd_serialno (&answer, NULL); + /* Then, connect the card again. */ + err = scd_serialno (NULL, NULL); leave: if (err && any_apdu && !is_yubikey) @@ -3158,20 +3232,6 @@ dispatch_command (card_info_t info, const char *orig_command) } break; - case cmdLIST: - if (!info) - print_help ("LIST\n\n" - "Show content of the card.", 0); - else - { - err = scd_learn (info); - if (err) - log_error ("Error reading card: %s\n", gpg_strerror (err)); - else - list_card (info); - } - break; - case cmdRESET: if (!info) print_help ("RESET\n\n" @@ -3183,6 +3243,7 @@ dispatch_command (card_info_t info, const char *orig_command) } break; + case cmdLIST: err = cmd_list (info, argstr); break; case cmdVERIFY: err = cmd_verify (info, argstr); break; case cmdAUTH: err = cmd_authenticate (info, argstr); break; case cmdNAME: err = cmd_name (info, argstr); break; @@ -3268,14 +3329,11 @@ interactive_loop (void) } else if (redisplay) { - err = scd_learn (info); + err = cmd_list (info, ""); if (err) - { - log_error ("Error reading card: %s\n", gpg_strerror (err)); - } + log_error ("Error reading card: %s\n", gpg_strerror (err)); else { - list_card (info); tty_printf("\n"); redisplay = 0; } @@ -3388,17 +3446,6 @@ interactive_loop (void) } break; - case cmdLIST: - if (!info) - print_help ("LIST\n\n" - "Show content of the card.", 0); - else - { - /* Actual work is done by the redisplay code block. */ - redisplay = 1; - } - break; - case cmdRESET: if (!info) print_help ("RESET\n\n" @@ -3410,6 +3457,7 @@ interactive_loop (void) } break; + case cmdLIST: err = cmd_list (info, argstr); break; case cmdVERIFY: err = cmd_verify (info, argstr); if (!err) From 1f688e0d1dba4dd7a311d416d06d654ed7b4290d Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 3 Apr 2019 11:26:14 +0200 Subject: [PATCH 029/169] gpg: Avoid endless loop if a card's serial number can't be read. * g10/skclist.c (enum_secret_keys): Move list forward on error. -- The error is not easy to reproduce but may occur if a card is removed at the wrong time. Tested by changing the code. Signed-off-by: Werner Koch --- g10/skclist.c | 1 + 1 file changed, 1 insertion(+) diff --git a/g10/skclist.c b/g10/skclist.c index c9c41d0d9..ebbaba254 100644 --- a/g10/skclist.c +++ b/g10/skclist.c @@ -423,6 +423,7 @@ enum_secret_keys (ctrl_t ctrl, void **context, PKT_public_key *sk) if (opt.verbose) log_info (_("error getting serial number of card: %s\n"), gpg_strerror (err)); + c->sl = c->sl->next; continue; } From 2b1135cf920cf3d863813d60f032d476dcccfb58 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 3 Apr 2019 13:16:22 +0200 Subject: [PATCH 030/169] scd: New standard attributes $ENCRKEYID and $SIGNKEYID. * g10/call-agent.c (agent_scd_keypairinfo): Use --keypairinfo. * sm/call-agent.c (gpgsm_agent_scd_keypairinfo): Ditto. * scd/app-openpgp.c (do_getattr): Add attributes "$ENCRKEYID" and "$SIGNKEYID". * scd/app-piv.c (do_getattr): Ditto. -- We already have $AUTHKEYID to locate the keyref of the key to be used with ssh. It will also be useful to have default keyref for encryption and signing. For example, this will allow us to repalce the use of "OPENPGP.2" by a app type specific keyref. Signed-off-by: Werner Koch --- g10/call-agent.c | 2 +- scd/app-openpgp.c | 14 ++++++++++++++ scd/app-piv.c | 14 +++++++++++++- sm/call-agent.c | 2 +- 4 files changed, 29 insertions(+), 3 deletions(-) diff --git a/g10/call-agent.c b/g10/call-agent.c index a0c5f811f..3b4882b53 100644 --- a/g10/call-agent.c +++ b/g10/call-agent.c @@ -839,7 +839,7 @@ agent_scd_keypairinfo (ctrl_t ctrl, strlist_t *r_list) memset (&inq_parm, 0, sizeof inq_parm); inq_parm.ctx = agent_ctx; - err = assuan_transact (agent_ctx, "SCD LEARN --force", + err = assuan_transact (agent_ctx, "SCD LEARN --keypairinfo", NULL, NULL, default_inq_cb, &inq_parm, scd_keypairinfo_status_cb, &list); diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 1e904b578..c5ca063f7 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -987,6 +987,8 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name) { "PRIVATE-DO-3", 0x0103 }, { "PRIVATE-DO-4", 0x0104 }, { "$AUTHKEYID", 0x0000, -3 }, + { "$ENCRKEYID", 0x0000, -6 }, + { "$SIGNKEYID", 0x0000, -7 }, { "$DISPSERIALNO",0x0000, -4 }, { "UIF-1", 0x00D6, 0 }, { "UIF-2", 0x00D7, 0 }, @@ -1071,6 +1073,18 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name) send_key_attr (ctrl, app, table[idx].name, i); return 0; } + if (table[idx].special == -6) + { + char const tmp[] = "OPENPGP.2"; + send_status_info (ctrl, table[idx].name, tmp, strlen (tmp), NULL, 0); + return 0; + } + if (table[idx].special == -7) + { + char const tmp[] = "OPENPGP.1"; + send_status_info (ctrl, table[idx].name, tmp, strlen (tmp), NULL, 0); + return 0; + } relptr = get_one_do (app, table[idx].tag, &value, &valuelen, &rc); if (relptr) diff --git a/scd/app-piv.c b/scd/app-piv.c index 41fd7b7c5..addc22c17 100644 --- a/scd/app-piv.c +++ b/scd/app-piv.c @@ -812,7 +812,9 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name) int special; } table[] = { { "SERIALNO", 0x0000, -1 }, - { "$AUTHKEYID", 0x0000, -2 }, /* Default key for ssh. */ + { "$AUTHKEYID", 0x0000, -2 }, /* Default ssh key. */ + { "$ENCRKEYID", 0x0000, -6 }, /* Default encryption key. */ + { "$SIGNKEYID", 0x0000, -7 }, /* Default signing key. */ { "$DISPSERIALNO",0x0000, -3 }, { "CHV-STATUS", 0x0000, -4 }, { "CHV-USAGE", 0x007E, -5 } @@ -883,6 +885,16 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name) xfree (relptr); } } + else if (table[idx].special == -6) + { + char const tmp[] = "PIV.9D"; /* Key Management. */ + send_status_info (ctrl, table[idx].name, tmp, strlen (tmp), NULL, 0); + } + else if (table[idx].special == -7) + { + char const tmp[] = "PIV.9C"; /* Digital Signature. */ + send_status_info (ctrl, table[idx].name, tmp, strlen (tmp), NULL, 0); + } else { relptr = get_one_do (app, table[idx].tag, &value, &valuelen, &err); diff --git a/sm/call-agent.c b/sm/call-agent.c index 4c3eecb10..1fbb449bc 100644 --- a/sm/call-agent.c +++ b/sm/call-agent.c @@ -836,7 +836,7 @@ gpgsm_agent_scd_keypairinfo (ctrl_t ctrl, strlist_t *r_list) inq_parm.ctrl = ctrl; inq_parm.ctx = agent_ctx; - rc = assuan_transact (agent_ctx, "SCD LEARN --force", + rc = assuan_transact (agent_ctx, "SCD LEARN --keypairinfo", NULL, NULL, default_inq_cb, &inq_parm, scd_keypairinfo_status_cb, &list); From ec6a6779236a89d4784a6bb7de0def9cc0f9e8a4 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 3 Apr 2019 15:30:10 +0200 Subject: [PATCH 031/169] gpg: Allow decryption using PIV cards. * g10/call-agent.c (struct getattr_one_parm_s): New. (getattr_one_status_cb): New. (agent_scd_getattr_one): New. * g10/pubkey-enc.c (get_it): Allow the standard leading zero byte from pkcs#1. * g10/skclist.c (enum_secret_keys): Handle non-OpenPGP cards. Signed-off-by: Werner Koch --- g10/call-agent.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++ g10/call-agent.h | 3 ++ g10/pubkey-enc.c | 10 ++++++ g10/skclist.c | 61 +++++++++++++++++++++++++++++++----- 4 files changed, 146 insertions(+), 8 deletions(-) diff --git a/g10/call-agent.c b/g10/call-agent.c index 3b4882b53..f603d491a 100644 --- a/g10/call-agent.c +++ b/g10/call-agent.c @@ -947,6 +947,86 @@ agent_keytocard (const char *hexgrip, int keyno, int force, } + +/* Object used with the agent_scd_getattr_one. */ +struct getattr_one_parm_s { + const char *keyword; /* Keyword to look for. */ + char *data; /* Malloced and unescaped data. */ + gpg_error_t err; /* Error code or 0 on success. */ +}; + + +/* Callback for agent_scd_getattr_one. */ +static gpg_error_t +getattr_one_status_cb (void *opaque, const char *line) +{ + struct getattr_one_parm_s *parm = opaque; + const char *s; + + if (parm->data) + return 0; /* We want only the first occurrence. */ + + if ((s=has_leading_keyword (line, parm->keyword))) + { + parm->data = percent_plus_unescape (s, 0xff); + if (!parm->data) + parm->err = gpg_error_from_syserror (); + } + + return 0; +} + + +/* Simplified version of agent_scd_getattr. This function returns + * only the first occurance of the attribute NAME and stores it at + * R_VALUE. A nul in the result is silennly replaced by 0xff. On + * error NULL is stored at R_VALUE. */ +gpg_error_t +agent_scd_getattr_one (const char *name, char **r_value) +{ + gpg_error_t err; + char line[ASSUAN_LINELENGTH]; + struct default_inq_parm_s inqparm; + struct getattr_one_parm_s parm; + + *r_value = NULL; + + if (!*name) + return gpg_error (GPG_ERR_INV_VALUE); + + memset (&inqparm, 0, sizeof inqparm); + inqparm.ctx = agent_ctx; + + memset (&parm, 0, sizeof parm); + parm.keyword = name; + + /* We assume that NAME does not need escaping. */ + if (12 + strlen (name) > DIM(line)-1) + return gpg_error (GPG_ERR_TOO_LARGE); + stpcpy (stpcpy (line, "SCD GETATTR "), name); + + err = start_agent (NULL, 1); + if (err) + return err; + + err = assuan_transact (agent_ctx, line, + NULL, NULL, + default_inq_cb, &inqparm, + getattr_one_status_cb, &parm); + if (!err && parm.err) + err = parm.err; + else if (!err && !parm.data) + err = gpg_error (GPG_ERR_NO_DATA); + + if (!err) + *r_value = parm.data; + else + xfree (parm.data); + + return err; +} + + /* Call the agent to retrieve a data object. This function returns * the data in the same structure as used by the learn command. It is diff --git a/g10/call-agent.h b/g10/call-agent.h index cb874fdad..c0018a595 100644 --- a/g10/call-agent.h +++ b/g10/call-agent.h @@ -96,6 +96,9 @@ int agent_scd_serialno (char **r_serialno, const char *demand); /* Send an APDU to the card. */ gpg_error_t agent_scd_apdu (const char *hexapdu, unsigned int *r_sw); +/* Get attribute NAME from the card and store at R_VALUE. */ +gpg_error_t agent_scd_getattr_one (const char *name, char **r_value); + /* Update INFO with the attribute NAME. */ int agent_scd_getattr (const char *name, struct agent_card_info_s *info); diff --git a/g10/pubkey-enc.c b/g10/pubkey-enc.c index 055c39b8f..f61fa7abe 100644 --- a/g10/pubkey-enc.c +++ b/g10/pubkey-enc.c @@ -319,6 +319,16 @@ get_it (ctrl_t ctrl, err = gpg_error (GPG_ERR_WRONG_SECKEY); goto leave; } + + /* FIXME: Actually the leading zero is required but due to + * the way we encode the output in libgcrypt as an MPI we + * are not able to encode that leading zero. However, when + * using a Smartcard we are doing it the right way and + * therefore we have to skip the zero. This should be fixed + * in gpg-agent of course. */ + if (!frame[n]) + n++; + if (frame[n] == 1 && frame[nframe - 1] == 2) { log_info (_("old encoding of the DEK is not supported\n")); diff --git a/g10/skclist.c b/g10/skclist.c index ebbaba254..b4f83ea1a 100644 --- a/g10/skclist.c +++ b/g10/skclist.c @@ -340,6 +340,10 @@ enum_secret_keys (ctrl_t ctrl, void **context, PKT_public_key *sk) SK_LIST results; } *c = *context; +#if MAX_FINGERPRINT_LEN < KEYGRIP_LEN +# error buffer too short for this configuration +#endif + if (!c) { /* Make a new context. */ @@ -430,17 +434,58 @@ enum_secret_keys (ctrl_t ctrl, void **context, PKT_public_key *sk) xfree (serialno); c->info.fpr2len = 0; err = agent_scd_getattr ("KEY-FPR", &c->info); + if (!err) + { + if (c->info.fpr2len) + { + c->fpr2[0] = '0'; + c->fpr2[1] = 'x'; + bin2hex (c->info.fpr2, sizeof c->info.fpr2, + c->fpr2 + 2); + name = c->fpr2; + } + } + else if (gpg_err_code (err) == GPG_ERR_INV_NAME) + { + /* KEY-FPR not supported by the card - get + * the key using the keygrip. */ + char *keyref; + strlist_t kplist, sl; + const char *s; + int i; + + err = agent_scd_getattr_one ("$ENCRKEYID", &keyref); + if (!err) + { + err = agent_scd_keypairinfo (ctrl, &kplist); + if (!err) + { + for (sl = kplist; sl; sl = sl->next) + if ((s = strchr (sl->d, ' ')) + && !strcmp (s+1, keyref)) + break; + if (sl) + { + c->fpr2[0] = '&'; + for (i=1, s=sl->d; + (*s && *s != ' ' + && i < sizeof c->fpr2 - 3); + s++, i++) + c->fpr2[i] = *s; + c->fpr2[i] = 0; + name = c->fpr2; + } + else /* Restore error. */ + err = gpg_error (GPG_ERR_INV_NAME); + free_strlist (kplist); + } + } + xfree (keyref); + } if (err) - log_error ("error retrieving key fingerprint from card: %s\n", + log_error ("error retrieving key from card: %s\n", gpg_strerror (err)); - if (c->info.fpr2len) - { - c->fpr2[0] = '0'; - c->fpr2[1] = 'x'; - bin2hex (c->info.fpr2, sizeof c->info.fpr2,c->fpr2+2); - name = c->fpr2; - } c->sl = c->sl->next; } else From 679b8f1c045476bd6e0a1f1565379263143994ee Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 3 Apr 2019 17:31:09 +0200 Subject: [PATCH 032/169] scd: New options --info and --info-only for READKEY. * scd/command.c (cmd_readkey): New options --info and --info-only. * scd/app.c (app_readkey): New arg 'flags'. * scd/app-common.h (APP_READKEY_FLAG_INFO): New. (struct app_ctx_s): New args 'ctrl' and 'flags' for member readkey. Change all implementers. * scd/app-nks.c (do_readkey): Stub implementation of APP_READKEY_FLAG_INFO. * scd/app-openpgp.c (do_readkey): Implement APP_READKEY_FLAG_INFO. * scd/app-piv.c (do_readkey): Ditto. -- This feature allows to quickly get the keygrip and in most cases also the usage flags for one specific keyref. Example: <- readkey --info-only PIV.9D -> S KEYPAIRINFO FC6061FB457224370B85C6F34DD56CD29E669620 PIV.9D e -> OK Signed-off-by: Werner Koch --- scd/app-common.h | 14 +++++++++++--- scd/app-help.c | 45 +++++++++++++++++++++++++++++---------------- scd/app-nks.c | 13 +++++++++++-- scd/app-openpgp.c | 27 +++++++++++++++++++-------- scd/app-piv.c | 36 +++++++++++++++++++++++++++++++----- scd/app.c | 19 ++++++++++--------- scd/command.c | 43 ++++++++++++++++++++++++++++++++++++------- 7 files changed, 147 insertions(+), 50 deletions(-) diff --git a/scd/app-common.h b/scd/app-common.h index c53bf06ca..6bb8eba50 100644 --- a/scd/app-common.h +++ b/scd/app-common.h @@ -36,10 +36,14 @@ /* Flags used with app_writekey. */ #define APP_WRITEKEY_FLAG_FORCE 1 /* Force overwriting existing key. */ +/* Flags used with app_readkey. */ +#define APP_READKEY_FLAG_INFO 1 /* Send also a KEYPAIRINFO line. */ + /* Bit flags set by the decipher function into R_INFO. */ #define APP_DECIPHER_INFO_NOPAD 1 /* Padding has been removed. */ + struct app_local_s; /* Defined by all app-*.c. */ struct app_ctx_s { @@ -75,8 +79,9 @@ struct app_ctx_s { gpg_error_t (*learn_status) (app_t app, ctrl_t ctrl, unsigned int flags); gpg_error_t (*readcert) (app_t app, const char *certid, unsigned char **cert, size_t *certlen); - gpg_error_t (*readkey) (app_t app, const char *certid, - unsigned char **pk, size_t *pklen); + gpg_error_t (*readkey) (app_t app, ctrl_t ctrl, + const char *certid, unsigned int flags, + unsigned char **pk, size_t *pklen); gpg_error_t (*getattr) (app_t app, ctrl_t ctrl, const char *name); gpg_error_t (*setattr) (app_t app, const char *name, gpg_error_t (*pincb)(void*, const char *, char **), @@ -126,6 +131,8 @@ struct app_ctx_s { /*-- app-help.c --*/ unsigned int app_help_count_bits (const unsigned char *a, size_t len); +gpg_error_t app_help_get_keygrip_string_pk (const void *pk, size_t pklen, + char *hexkeygrip); gpg_error_t app_help_get_keygrip_string (ksba_cert_t cert, char *hexkeygrip); gpg_error_t app_help_pubkey_from_cert (const void *cert, size_t certlen, unsigned char **r_pk, size_t *r_pklen); @@ -152,7 +159,8 @@ gpg_error_t app_write_learn_status (app_t app, ctrl_t ctrl, gpg_error_t app_readcert (app_t app, ctrl_t ctrl, const char *certid, unsigned char **cert, size_t *certlen); gpg_error_t app_readkey (app_t app, ctrl_t ctrl, - const char *keyid, unsigned char **pk, size_t *pklen); + const char *keyid, unsigned int flags, + unsigned char **pk, size_t *pklen); gpg_error_t app_getattr (app_t app, ctrl_t ctrl, const char *name); gpg_error_t app_setattr (app_t app, ctrl_t ctrl, const char *name, gpg_error_t (*pincb)(void*, const char *, char **), diff --git a/scd/app-help.c b/scd/app-help.c index f0f551c55..59221ea9c 100644 --- a/scd/app-help.c +++ b/scd/app-help.c @@ -52,26 +52,17 @@ app_help_count_bits (const unsigned char *a, size_t len) } -/* Return the KEYGRIP for the certificate CERT as an hex encoded - string in the user provided buffer HEXKEYGRIP which must be of at - least 41 bytes. */ +/* Return the KEYGRIP for the canonical encoded public key (PK,PKLEN) + * as an hex encoded string in the user provided buffer HEXKEYGRIP + * which must be of at least 41 bytes. */ gpg_error_t -app_help_get_keygrip_string (ksba_cert_t cert, char *hexkeygrip) +app_help_get_keygrip_string_pk (const void *pk, size_t pklen, char *hexkeygrip) { gpg_error_t err; gcry_sexp_t s_pkey; - ksba_sexp_t p; - size_t n; - unsigned char array[20]; + unsigned char array[KEYGRIP_LEN]; - p = ksba_cert_get_public_key (cert); - if (!p) - return gpg_error (GPG_ERR_BUG); - n = gcry_sexp_canon_len (p, 0, NULL, NULL); - if (!n) - return gpg_error (GPG_ERR_INV_SEXP); - err = gcry_sexp_sscan (&s_pkey, NULL, (char*)p, n); - xfree (p); + err = gcry_sexp_sscan (&s_pkey, NULL, pk, pklen); if (err) return err; /* Can't parse that S-expression. */ if (!gcry_pk_get_keygrip (s_pkey, array)) @@ -81,12 +72,34 @@ app_help_get_keygrip_string (ksba_cert_t cert, char *hexkeygrip) } gcry_sexp_release (s_pkey); - bin2hex (array, 20, hexkeygrip); + bin2hex (array, KEYGRIP_LEN, hexkeygrip); return 0; } +/* Return the KEYGRIP for the certificate CERT as an hex encoded + string in the user provided buffer HEXKEYGRIP which must be of at + least 41 bytes. */ +gpg_error_t +app_help_get_keygrip_string (ksba_cert_t cert, char *hexkeygrip) +{ + gpg_error_t err; + ksba_sexp_t p; + size_t n; + + p = ksba_cert_get_public_key (cert); + if (!p) + return gpg_error (GPG_ERR_BUG); + n = gcry_sexp_canon_len (p, 0, NULL, NULL); + if (!n) + return gpg_error (GPG_ERR_INV_SEXP); + err = app_help_get_keygrip_string_pk ((void*)p, n, hexkeygrip); + ksba_free (p); + return err; +} + + gpg_error_t app_help_pubkey_from_cert (const void *cert, size_t certlen, unsigned char **r_pk, size_t *r_pklen) diff --git a/scd/app-nks.c b/scd/app-nks.c index 40c941616..2785ad014 100644 --- a/scd/app-nks.c +++ b/scd/app-nks.c @@ -618,7 +618,8 @@ do_readcert (app_t app, const char *certid, certificate parsing code in commands.c:cmd_readkey. For internal use PK and PKLEN may be NULL to just check for an existing key. */ static gpg_error_t -do_readkey (app_t app, const char *keyid, unsigned char **pk, size_t *pklen) +do_readkey (app_t app, ctrl_t ctrl, const char *keyid, unsigned int flags, + unsigned char **pk, size_t *pklen) { gpg_error_t err; unsigned char *buffer[2]; @@ -653,6 +654,14 @@ do_readkey (app_t app, const char *keyid, unsigned char **pk, size_t *pklen) return err; } + if ((flags & APP_READKEY_FLAG_INFO)) + { + /* Not yet implemented but we won't get here for any regular + * keyrefs anyway, thus the top layer will provide the + * keypairinfo from the certificate. */ + (void)ctrl; + } + if (pk && pklen) { *pk = make_canon_sexp_from_rsa_pk (buffer[0], buflen[0], @@ -698,7 +707,7 @@ do_writekey (app_t app, ctrl_t ctrl, else return gpg_error (GPG_ERR_INV_ID); - if (!force && !do_readkey (app, keyid, NULL, NULL)) + if (!force && !do_readkey (app, ctrl, keyid, 0, NULL, NULL)) return gpg_error (GPG_ERR_EEXIST); /* Parse the S-expression. */ diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index c5ca063f7..1a537127c 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -1889,7 +1889,8 @@ do_learn_status (app_t app, ctrl_t ctrl, unsigned int flags) buffer. On error PK and PKLEN are not changed and an error code is returned. */ static gpg_error_t -do_readkey (app_t app, const char *keyid, unsigned char **pk, size_t *pklen) +do_readkey (app_t app, ctrl_t ctrl, const char *keyid, unsigned int flags, + unsigned char **pk, size_t *pklen) { gpg_error_t err; int keyno; @@ -1912,15 +1913,25 @@ do_readkey (app_t app, const char *keyid, unsigned char **pk, size_t *pklen) if (!buf) return gpg_error (GPG_ERR_NO_PUBKEY); - *pklen = app->app_local->pk[keyno].keylen; - *pk = xtrymalloc (*pklen); - if (!*pk) + if ((flags & APP_READKEY_FLAG_INFO)) { - err = gpg_error_from_syserror (); - *pklen = 0; - return err; + err = send_keypair_info (app, ctrl, keyno+1); + if (err) + return err; + } + + if (pk && pklen) + { + *pklen = app->app_local->pk[keyno].keylen; + *pk = xtrymalloc (*pklen); + if (!*pk) + { + err = gpg_error_from_syserror (); + *pklen = 0; + return err; + } + memcpy (*pk, buf, *pklen); } - memcpy (*pk, buf, *pklen); return 0; } diff --git a/scd/app-piv.c b/scd/app-piv.c index addc22c17..3dd3fb151 100644 --- a/scd/app-piv.c +++ b/scd/app-piv.c @@ -1465,7 +1465,7 @@ do_readcert (app_t app, const char *certid, * returned. */ static gpg_error_t -do_readkey (app_t app, const char *keyrefstr, +do_readkey (app_t app, ctrl_t ctrl, const char *keyrefstr, unsigned int flags, unsigned char **r_pk, size_t *r_pklen) { gpg_error_t err; @@ -1517,9 +1517,35 @@ do_readkey (app_t app, const char *keyrefstr, goto leave; } - *r_pk = pk; - pk = NULL; - *r_pklen = pklen; + if ((flags & APP_READKEY_FLAG_INFO)) + { + char keygripstr[KEYGRIP_LEN*2+1]; + char idbuf[50]; + const char *usage; + + err = app_help_get_keygrip_string_pk (pk, pklen, keygripstr); + if (err) + { + log_error ("app_help_get_keygrip_string_pk failed: %s\n", + gpg_strerror (err)); + goto leave; + } + usage = dobj->usage? dobj->usage : ""; + + snprintf (idbuf, sizeof idbuf, "PIV.%s", dobj->keyref); + send_status_info (ctrl, "KEYPAIRINFO", + keygripstr, strlen (keygripstr), + idbuf, strlen (idbuf), + usage, strlen (usage), + NULL, (size_t)0); + } + + if (r_pk && r_pklen) + { + *r_pk = pk; + pk = NULL; + *r_pklen = pklen; + } leave: gcry_sexp_release (s_pkey); @@ -3218,7 +3244,7 @@ do_writecert (app_t app, ctrl_t ctrl, * GPG_ERR_NO_PUBKEY). We enforce this because otherwise the only * way to detect whether a key exists is by trying to use that * key. */ - err = do_readkey (app, certrefstr, &orig_pk, &orig_pklen); + err = do_readkey (app, ctrl, certrefstr, 0, &orig_pk, &orig_pklen); if (err) { if (gpg_err_code (err) == GPG_ERR_NOT_FOUND) diff --git a/scd/app.c b/scd/app.c index 59a8880db..1f3808fd4 100644 --- a/scd/app.c +++ b/scd/app.c @@ -772,14 +772,15 @@ app_readcert (app_t app, ctrl_t ctrl, const char *certid, /* Read the key with ID KEYID. On success a canonical encoded - S-expression with the public key will get stored at PK and its - length (for assertions) at PKLEN; the caller must release that - buffer. On error NULL will be stored at PK and PKLEN and an error - code returned. - - This function might not be supported by all applications. */ + * S-expression with the public key will get stored at PK and its + * length (for assertions) at PKLEN; the caller must release that + * buffer. On error NULL will be stored at PK and PKLEN and an error + * code returned. If the key is not required NULL may be passed for + * PK; this makse send if the APP_READKEY_FLAG_INFO has also been set. + * + * This function might not be supported by all applications. */ gpg_error_t -app_readkey (app_t app, ctrl_t ctrl, const char *keyid, +app_readkey (app_t app, ctrl_t ctrl, const char *keyid, unsigned int flags, unsigned char **pk, size_t *pklen) { gpg_error_t err; @@ -789,7 +790,7 @@ app_readkey (app_t app, ctrl_t ctrl, const char *keyid, if (pklen) *pklen = 0; - if (!app || !keyid || !pk || !pklen) + if (!app || !keyid) return gpg_error (GPG_ERR_INV_VALUE); if (!app->ref_count) return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); @@ -798,7 +799,7 @@ app_readkey (app_t app, ctrl_t ctrl, const char *keyid, err = lock_app (app, ctrl); if (err) return err; - err= app->fnc.readkey (app, keyid, pk, pklen); + err= app->fnc.readkey (app, ctrl, keyid, flags, pk, pklen); unlock_app (app); return err; } diff --git a/scd/command.c b/scd/command.c index 0d1a5cd3f..28c739d93 100644 --- a/scd/command.c +++ b/scd/command.c @@ -502,19 +502,20 @@ cmd_readcert (assuan_context_t ctx, char *line) static const char hlp_readkey[] = - "READKEY [--advanced] |\n" + "READKEY [--advanced] [--info[-only]] |\n" "\n" "Return the public key for the given cert or key ID as a standard\n" - "S-expression.\n" - "In --advanced mode it returns the S-expression in advanced format.\n" - "\n" - "Note that this function may even be used on a locked card."; + "S-expression. With --advanced the S-expression is returned in\n" + "advanced format. With --info a KEYPAIRINFO status line is also\n" + "emitted; with --info-only the regular output is suppressed."; static gpg_error_t cmd_readkey (assuan_context_t ctx, char *line) { ctrl_t ctrl = assuan_get_pointer (ctx); int rc; int advanced = 0; + int opt_info = 0; + int opt_nokey = 0; unsigned char *cert = NULL; unsigned char *pk = NULL; size_t ncert, pklen; @@ -524,6 +525,10 @@ cmd_readkey (assuan_context_t ctx, char *line) if (has_option (line, "--advanced")) advanced = 1; + if (has_option (line, "--info")) + opt_info = 1; + if (has_option (line, "--info-only")) + opt_info = opt_nokey = 1; line = skip_options (line); line = xstrdup (line); /* Need a copy of the line. */ @@ -531,7 +536,9 @@ cmd_readkey (assuan_context_t ctx, char *line) /* If the application supports the READKEY function we use that. Otherwise we use the old way by extracting it from the certificate. */ - rc = app_readkey (ctrl->app_ctx, ctrl, line, &pk, &pklen); + rc = app_readkey (ctrl->app_ctx, ctrl, line, + opt_info? APP_READKEY_FLAG_INFO : 0, + opt_nokey? NULL : &pk, &pklen); if (!rc) ; /* Okay, got that key. */ else if (gpg_err_code (rc) == GPG_ERR_UNSUPPORTED_OPERATION @@ -551,6 +558,26 @@ cmd_readkey (assuan_context_t ctx, char *line) gpg_strerror (rc)); goto leave; } + + if (opt_info) + { + char keygripstr[KEYGRIP_LEN*2+1]; + + rc = app_help_get_keygrip_string_pk (pk, pklen, keygripstr); + if (rc) + { + log_error ("app_help_get_keygrip_string failed: %s\n", + gpg_strerror (rc)); + goto leave; + } + + /* FIXME: Using LINE is not correct because it might be an + * OID and has not been canonicalized (i.e. uppercased). */ + send_status_info (ctrl, "KEYPAIRINFO", + keygripstr, strlen (keygripstr), + line, strlen (line), + NULL, (size_t)0); + } } else { @@ -558,7 +585,9 @@ cmd_readkey (assuan_context_t ctx, char *line) goto leave; } - if (advanced) + if (opt_nokey) + ; + else if (advanced) { gcry_sexp_t s_key; unsigned char *pkadv; From 2c9b68f28de1ce9a6a18d091caba01ddd4707774 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 3 Apr 2019 17:45:35 +0200 Subject: [PATCH 033/169] gpg: Improve the code to decrypt using PIV cards. * g10/call-agent.c (agent_scd_keypairinfo): Add arg 'keyref'. * g10/keygen.c (ask_algo): Adjust. * g10/skclist.c (enum_secret_keys): Request the keyref directly. -- This improves commit ec6a6779236a89d4784a6bb7de0def9cc0f9e8a4 to avoid looping over all keypairinfos. This way scdaemon does not need to compute all the keypairinfos for all keys of a card. This patch is possible due the enhanced READKEY command in scdaemon. Signed-off-by: Werner Koch --- g10/call-agent.c | 13 ++++++++++--- g10/call-agent.h | 3 ++- g10/keygen.c | 2 +- g10/skclist.c | 33 +++++++++++++-------------------- 4 files changed, 26 insertions(+), 25 deletions(-) diff --git a/g10/call-agent.c b/g10/call-agent.c index f603d491a..f6c7d3951 100644 --- a/g10/call-agent.c +++ b/g10/call-agent.c @@ -824,13 +824,15 @@ scd_keypairinfo_status_cb (void *opaque, const char *line) /* Read the keypairinfo lines of the current card directly from * scdaemon. The list is returned as a string made up of the keygrip, * a space and the keyref. The flags of the string carry the usage - * bits. */ + * bits. If KEYREF is not NULL, only a single string is returned + * which matches the given keyref. */ gpg_error_t -agent_scd_keypairinfo (ctrl_t ctrl, strlist_t *r_list) +agent_scd_keypairinfo (ctrl_t ctrl, const char *keyref, strlist_t *r_list) { gpg_error_t err; strlist_t list = NULL; struct default_inq_parm_s inq_parm; + char line[ASSUAN_LINELENGTH]; *r_list = NULL; err= start_agent (ctrl, 1); @@ -839,7 +841,12 @@ agent_scd_keypairinfo (ctrl_t ctrl, strlist_t *r_list) memset (&inq_parm, 0, sizeof inq_parm); inq_parm.ctx = agent_ctx; - err = assuan_transact (agent_ctx, "SCD LEARN --keypairinfo", + if (keyref) + snprintf (line, DIM(line), "SCD READKEY --info-only %s", keyref); + else + snprintf (line, DIM(line), "SCD LEARN --keypairinfo"); + + err = assuan_transact (agent_ctx, line, NULL, NULL, default_inq_cb, &inq_parm, scd_keypairinfo_status_cb, &list); diff --git a/g10/call-agent.h b/g10/call-agent.h index c0018a595..c4d0a9de1 100644 --- a/g10/call-agent.h +++ b/g10/call-agent.h @@ -85,7 +85,8 @@ void agent_release_card_info (struct agent_card_info_s *info); int agent_scd_learn (struct agent_card_info_s *info, int force); /* Get the keypariinfo directly from scdaemon. */ -gpg_error_t agent_scd_keypairinfo (ctrl_t ctrl, strlist_t *r_list); +gpg_error_t agent_scd_keypairinfo (ctrl_t ctrl, const char *keyref, + strlist_t *r_list); /* Return list of cards. */ int agent_scd_cardlist (strlist_t *result); diff --git a/g10/keygen.c b/g10/keygen.c index 6ea4e72c6..22ac6f0b5 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -2254,7 +2254,7 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage, tty_printf (_("Serial number of the card: %s\n"), serialno); xfree (serialno); - err = agent_scd_keypairinfo (ctrl, &keypairlist); + err = agent_scd_keypairinfo (ctrl, NULL, &keypairlist); if (err) { tty_printf (_("error reading the card: %s\n"), diff --git a/g10/skclist.c b/g10/skclist.c index b4f83ea1a..c13566e2b 100644 --- a/g10/skclist.c +++ b/g10/skclist.c @@ -450,38 +450,31 @@ enum_secret_keys (ctrl_t ctrl, void **context, PKT_public_key *sk) /* KEY-FPR not supported by the card - get * the key using the keygrip. */ char *keyref; - strlist_t kplist, sl; + strlist_t kplist; const char *s; int i; err = agent_scd_getattr_one ("$ENCRKEYID", &keyref); if (!err) { - err = agent_scd_keypairinfo (ctrl, &kplist); + err = agent_scd_keypairinfo (ctrl, keyref, + &kplist); if (!err) { - for (sl = kplist; sl; sl = sl->next) - if ((s = strchr (sl->d, ' ')) - && !strcmp (s+1, keyref)) - break; - if (sl) - { - c->fpr2[0] = '&'; - for (i=1, s=sl->d; - (*s && *s != ' ' - && i < sizeof c->fpr2 - 3); - s++, i++) - c->fpr2[i] = *s; - c->fpr2[i] = 0; - name = c->fpr2; - } - else /* Restore error. */ - err = gpg_error (GPG_ERR_INV_NAME); + c->fpr2[0] = '&'; + for (i=1, s=kplist->d; + (*s && *s != ' ' + && i < sizeof c->fpr2 - 3); + s++, i++) + c->fpr2[i] = *s; + c->fpr2[i] = 0; + name = c->fpr2; free_strlist (kplist); } + xfree (keyref); } - xfree (keyref); } + if (err) log_error ("error retrieving key from card: %s\n", gpg_strerror (err)); From f1cf799a37f320d33cae445c74f3fc1936dd9995 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Thu, 4 Apr 2019 15:58:21 +0900 Subject: [PATCH 034/169] scd: Better handling of timeout and time extension. * scd/ccid-driver.c (CCID_CMD_TIMEOUT_LONGER): Remove. (ccid_transceive): Don't use x4 blindly for bBWI, but use dynamically determined value. Use value from variable wait_more for bulk_in. Set wait_more by the value of time extension request. Signed-off-by: NIIBE Yutaka --- scd/ccid-driver.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/scd/ccid-driver.c b/scd/ccid-driver.c index 69df17355..dca8340ba 100644 --- a/scd/ccid-driver.c +++ b/scd/ccid-driver.c @@ -110,8 +110,6 @@ /* CCID command timeout. */ #define CCID_CMD_TIMEOUT (5*1000) -/* OpenPGPcard v2.1 requires huge timeout for key generation. */ -#define CCID_CMD_TIMEOUT_LONGER (60*1000) /* Depending on how this source is used we either define our error output to go to stderr or to the GnuPG based logging functions. We @@ -3094,7 +3092,7 @@ ccid_transceive (ccid_driver_t handle, msg[0] = PC_to_RDR_XfrBlock; msg[5] = 0; /* slot */ msg[6] = seqno = handle->seqno++; - msg[7] = 4; /* bBWI */ + msg[7] = (wait_more ? wait_more : 1); /* bBWI */ msg[8] = 0; /* RFU */ msg[9] = 0; /* RFU */ set_msg_len (msg, tpdulen); @@ -3120,7 +3118,7 @@ ccid_transceive (ccid_driver_t handle, msg = recv_buffer; rc = bulk_in (handle, msg, sizeof recv_buffer, &msglen, via_escape? RDR_to_PC_Escape : RDR_to_PC_DataBlock, seqno, - wait_more? CCID_CMD_TIMEOUT_LONGER: CCID_CMD_TIMEOUT, 0); + (wait_more ? wait_more : 1) * CCID_CMD_TIMEOUT, 0); if (rc) return rc; @@ -3150,6 +3148,7 @@ ccid_transceive (ccid_driver_t handle, (!(msg[pcboff] & 0x80) && (msg[pcboff] & 0x20)? " [more]":"")); + wait_more = 0; if (!(tpdu[1] & 0x80)) { /* This is an I-block. */ retries = 0; @@ -3295,9 +3294,7 @@ ccid_transceive (ccid_driver_t handle, /* Wait time extension request. */ unsigned char bwi = tpdu[3]; - /* Check if it's unusual value which can't be expressed in ATR. */ - if (bwi > 15) - wait_more = 1; + wait_more = bwi; msg = send_buffer; tpdu = msg + hdrlen; From 310944aa37974a4817204a16ba9893feae564f5a Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 4 Apr 2019 12:49:06 +0200 Subject: [PATCH 035/169] doc: Minor change to the included yat2m. -- Getting the rendering of man pages is not really easy; let's see whether this is better. The change has also been done upstream. Signed-off-by: Werner Koch --- doc/gpg-card.texi | 157 ++++++++++++++++++++++++++++++++++++++++++---- doc/yat2m.c | 3 +- 2 files changed, 148 insertions(+), 12 deletions(-) diff --git a/doc/gpg-card.texi b/doc/gpg-card.texi index 92379aa19..fcc1792f1 100644 --- a/doc/gpg-card.texi +++ b/doc/gpg-card.texi @@ -8,9 +8,9 @@ @node Smart Card Tool @chapter Smart Card Tool -GnuPG comes with tool to administrate smart cards and USB tokens. This -tool is an extension of the @option{--edit-key} command available with -@command{gpg}. +GnuPG comes with a tool to administrate smart cards and USB tokens. +This tool is an enhanced version of the @option{--edit-key} command +available with @command{gpg}. @menu * gpg-card:: Administrate smart cards. @@ -135,7 +135,7 @@ featuring the PIV application (requires Yubikey-5). We assume that the credentials have not yet been changed and thus are: @table @asis @item Authentication key -This is a 24 byte key described by the hex string +This is a 24 byte key described by the hex string @* @code{010203040506070801020304050607080102030405060708}. @item PIV Application PIN This is the string @code{123456}. @@ -164,11 +164,13 @@ Version ..........: 2.1 [...] @end example -It can be seen by the ``Application type'' line that GnuPG selected the -OpenPGP application of the Yubikey. This is because GnuPG assigns the -highest priority to the OpenPGP application. To use the PIV -application of the Yubikey, the OpenPGP application needs to be -disabled: +It can be seen by the ``Application type'' line that GnuPG selected +the OpenPGP application of the Yubikey. This is because GnuPG assigns +the highest priority to the OpenPGP application. To use the PIV +application of the Yubikey several methods can be used: + +With a Yubikey 5 or later the OpenPGP application on the Yubikey can +be disabled: @example gpg/card> yubikey disable all opgp @@ -186,8 +188,32 @@ gpg/card> reset The @code{reset} is required so that the GnuPG system rereads the card. Note that disabled applications keep all their data and can at -any time be re-enabled (see @emph{help yubikey}). Now a @emph{list} -command shows this: +any time be re-enabled (use @kbd{help yubikey}). + +Another option, which works for all Yubikey versions, is to disable +the support for OpenPGP cards in scdaemon. This is done by adding the +line + +@smallexample +disable-application openpgp +@end smallexample + +to @file{~/.gnupg/scdaemon.conf} and by restarting scdaemon, either by +killing the process or by using @kbd{gpgconf --kill scdaemon}. Finally +the default order in which card applications are tried by scdaemon can +be changed. For example to prefer PIV over OpenPGP it is sufficient +to add + +@smallexample +application-priority piv +@end smallexample + +to @file{~/.gnupg/scdaemon.conf} and to restart @command{scdaemon}. +This has an effect only on tokens which support both, PIV and OpenPGP, +but does not hamper the use of OpenPGP only tokens. + +With one of these methods employed the @code{list} command of +@command{gpg-card} shows this: @example gpg/card> list @@ -210,6 +236,11 @@ Key management ...: [none] keyref .....: PIV.9D @end example +In case several tokens are plugged into the computer, gpg-card will +show only one. To show another token the number of the token (0, 1, +2, ...) can be given as an argument to the @code{list} command. The +command @kbd{list --cards} prints a list of all inserted tokens. + Note that the ``Displayed s/n'' is printed on the token and also shown in Pinentry prompts asking for the PIN. The four standard key slots are always shown, if other key slots are initialized they are @@ -507,7 +538,111 @@ As usual use ssh-add with the uppercase @samp{-L} to list the public ssh key. To use the certificates with Thunderbird or Mozilla, please consult the Scute manual for details. +If you want to use the same PIV keys also for OpenPGP (for example on +a Yubikey to avoid switching between OpenPGP and PIV), this is also +possible: +@example +$ gpgsm --learn +$ gpg --full-gen-key +Please select what kind of key you want: + (1) RSA and RSA (default) + (2) DSA and Elgamal + (3) DSA (sign only) + (4) RSA (sign only) + (14) Existing key from card +Your selection? 14 +Serial number of the card: FF020001008A77C1 +Available keys: + (1) 213D1825FDE0F8240CB4E4229F01AF90AC658C2E PIV.9A nistp384 (auth) + (2) 7A53E6CFFE7220A0E646B4632EE29E5A7104499C PIV.9E nistp256 (auth) + (3) 32A6C6FAFCB8421878608AAB452D5470DD3223ED PIV.9C rsa2048 (cert,sign) + (4) 34798AAFE0A7565088101CC4AE31C5C8C74461CB PIV.9D rsa2048 (encr) +Your selection? 3 +Please specify how long the key should be valid. + 0 = key does not expire + = key expires in n days + w = key expires in n weeks + m = key expires in n months + y = key expires in n years +Key is valid for? (0) +Key does not expire at all +Is this correct? (y/N) y + +GnuPG needs to construct a user ID to identify your key. + +Real name: +Email address: otto@@example.net +Comment: +You selected this USER-ID: + "otto@@example.net" + +Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? o +gpg: key C3AFA9ED971BB365 marked as ultimately trusted +gpg: revocation certificate stored as '[...]D971BB365.rev' +public and secret key created and signed. + +Note that this key cannot be used for encryption. You may want to use +the command "--edit-key" to generate a subkey for this purpose. +pub rsa2048 2019-04-04 [SC] + 7F899AE2FB73159DD68A1B20C3AFA9ED971BB365 +uid otto@@example.net +@end example + +Note that you will be asked two times to enter the PIN of your PIV +card. If you run @command{gpg} in @option{--expert} mode you will +also ge given the option to change the usage flags of the key. The next +typescript shows how to add the encryption subkey: + +@example +$ gpg --edit-key 7F899AE2FB73159DD68A1B20C3AFA9ED971BB365 +Secret key is available. + +sec rsa2048/C3AFA9ED971BB365 + created: 2019-04-04 expires: never usage: SC + card-no: FF020001008A77C1 + trust: ultimate validity: ultimate +[ultimate] (1). otto@@example.net +gpg> addkey +Secret parts of primary key are stored on-card. +Please select what kind of key you want: + (3) DSA (sign only) + (4) RSA (sign only) + (5) Elgamal (encrypt only) + (6) RSA (encrypt only) + (14) Existing key from card +Your selection? 14 +Serial number of the card: FF020001008A77C1 +Available keys: + (1) 213D1825FDE0F8240CB4E4229F01AF90AC658C2E PIV.9A nistp384 (auth) + (2) 7A53E6CFFE7220A0E646B4632EE29E5A7104499C PIV.9E nistp256 (auth) + (3) 32A6C6FAFCB8421878608AAB452D5470DD3223ED PIV.9C rsa2048 (cert,sign) + (4) 34798AAFE0A7565088101CC4AE31C5C8C74461CB PIV.9D rsa2048 (encr) +Your selection? 4 +Please specify how long the key should be valid. + 0 = key does not expire + = key expires in n days + w = key expires in n weeks + m = key expires in n months + y = key expires in n years +Key is valid for? (0) +Key does not expire at all +Is this correct? (y/N) y +Really create? (y/N) y + +sec rsa2048/C3AFA9ED971BB365 + created: 2019-04-04 expires: never usage: SC + card-no: FF020001008A77C1 + trust: ultimate validity: ultimate +ssb rsa2048/7067860A98FCE6E1 + created: 2019-04-04 expires: never usage: E + card-no: FF020001008A77C1 +[ultimate] (1). otto@@example.net + +gpg> save +@end example + +Now you can use your PIV card also with @command{gpg}. @c @mansect examples diff --git a/doc/yat2m.c b/doc/yat2m.c index be0ef17fd..2d6f54ea2 100644 --- a/doc/yat2m.c +++ b/doc/yat2m.c @@ -724,7 +724,8 @@ proc_texi_cmd (FILE *fp, const char *command, const char *rest, size_t len, { "url", 0, "\\fB", "\\fR" }, { "sc", 0, "\\fB", "\\fR" }, { "var", 0, "\\fI", "\\fR" }, - { "samp", 0, "\\(aq", "\\(aq" }, + { "samp", 0, "\\(oq", "\\(cq" }, + { "kbd", 0, "\\(oq", "\\(cq" }, { "file", 0, "\\(oq\\fI","\\fR\\(cq" }, { "env", 0, "\\(oq\\fI","\\fR\\(cq" }, { "acronym", 0 }, From 958172cc3acb7172bc5e1fa76efafe26695ed402 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 4 Apr 2019 12:51:21 +0200 Subject: [PATCH 036/169] scd:piv: Fix RSA decryption. * scd/app-piv.c (do_decipher): Fixup leading zero byte. -- Signed-off-by: Werner Koch --- scd/app-piv.c | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/scd/app-piv.c b/scd/app-piv.c index 3dd3fb151..f13ef52ee 100644 --- a/scd/app-piv.c +++ b/scd/app-piv.c @@ -2434,15 +2434,34 @@ do_decipher (app_t app, const char *keyidstr, /* Check that the ciphertext has the right length; due to internal * convey mechanism using MPIs leading zero bytes might have been - * lost. Adjust for this. Note that for ECC this actually - * superfluous because the first octet is always '04' to indicate an + * lost. Adjust for this. Unfortunately the ciphertext might have + * also been prefixed with a leading zero to make it a positive + * number; that may be a too long frame and we need to adjust for + * this too. Note that for ECC thoses fixes are not reqquired + * because the first octet is always '04' to indicate an * uncompressed point. */ if (indatalen > framelen) { - err = gpg_error (GPG_ERR_INV_VALUE); - log_error ("piv: input of %zu octets too large for mechanism %d\n", - indatalen, mechanism); - goto leave; + if (mechanism == PIV_ALGORITHM_RSA + && indatalen == framelen + 1 && !*indata) + { + indata_buffer = xtrycalloc (1, framelen); + if (!indata_buffer) + { + err = gpg_error_from_syserror (); + goto leave; + } + memcpy (indata_buffer, indata+1, framelen); + indata = indata_buffer; + indatalen = framelen; + } + else + { + err = gpg_error (GPG_ERR_INV_VALUE); + log_error ("piv: input of %zu octets too large for mechanism %d\n", + indatalen, mechanism); + goto leave; + } } if (indatalen < framelen) { From ea32842d5c2e2d262d32791130d7eae5c8c3edcf Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 5 Apr 2019 17:02:43 +0200 Subject: [PATCH 037/169] gpg: Fix printing of the user id during import. * g10/getkey.c (struct keyid_list): Add field fprlen. (cache_user_id): Set and test it. (get_user_id_byfpr): Make static, add arg fprlen and use it. (get_user_id_byfpr_native): Add arg fprlen and change all callers. -- This was a regression in the 2.3 base. GnuPG-bug-id: 3801 Signed-off-by: Werner Koch --- g10/getkey.c | 22 +++++++++++++--------- g10/import.c | 6 +++--- g10/keydb.h | 3 +-- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/g10/getkey.c b/g10/getkey.c index b15fbc13a..49e237add 100644 --- a/g10/getkey.c +++ b/g10/getkey.c @@ -112,6 +112,7 @@ static struct typedef struct keyid_list { struct keyid_list *next; + byte fprlen; char fpr[MAX_FINGERPRINT_LEN]; u32 keyid[2]; } *keyid_list_t; @@ -311,6 +312,7 @@ cache_user_id (KBNODE keyblock) size_t uidlen; keyid_list_t keyids = NULL; KBNODE k; + size_t n; for (k = keyblock; k; k = k->next) { @@ -320,7 +322,8 @@ cache_user_id (KBNODE keyblock) keyid_list_t a = xmalloc_clear (sizeof *a); /* Hmmm: For a long list of keyids it might be an advantage * to append the keys. */ - fingerprint_from_pk (k->pkt->pkt.public_key, a->fpr, NULL); + fingerprint_from_pk (k->pkt->pkt.public_key, a->fpr, &n); + a->fprlen = n; keyid_from_pk (k->pkt->pkt.public_key, a->keyid); /* First check for duplicates. */ for (r = user_id_db; r; r = r->next) @@ -329,7 +332,8 @@ cache_user_id (KBNODE keyblock) for (b = r->keyids; b; b = b->next) { - if (!memcmp (b->fpr, a->fpr, MAX_FINGERPRINT_LEN)) + if (b->fprlen == a->fprlen + && !memcmp (b->fpr, a->fpr, a->fprlen)) { if (DBG_CACHE) log_debug ("cache_user_id: already in cache\n"); @@ -1637,7 +1641,7 @@ get_pubkey_fromfile (ctrl_t ctrl, PKT_public_key *pk, const char *fname) * * FPRINT is a byte array whose contents is the fingerprint to use as * the search term. FPRINT_LEN specifies the length of the - * fingerprint (in bytes). Currently, only 16 and 20-byte + * fingerprint (in bytes). Currently, only 16, 20, and 32-byte * fingerprints are supported. * * FIXME: We should replace this with the _byname function. This can @@ -3943,8 +3947,8 @@ get_user_id_native (ctrl_t ctrl, u32 *keyid) returned string, which must be freed using xfree, may not be NUL terminated. To determine the length of the string, you must use *RN. */ -char * -get_user_id_byfpr (ctrl_t ctrl, const byte *fpr, size_t *rn) +static char * +get_user_id_byfpr (ctrl_t ctrl, const byte *fpr, size_t fprlen, size_t *rn) { user_id_db_t r; char *p; @@ -3958,7 +3962,7 @@ get_user_id_byfpr (ctrl_t ctrl, const byte *fpr, size_t *rn) keyid_list_t a; for (a = r->keyids; a; a = a->next) { - if (!memcmp (a->fpr, fpr, MAX_FINGERPRINT_LEN)) + if (a->fprlen == fprlen && !memcmp (a->fpr, fpr, fprlen)) { /* An empty string as user id is possible. Make sure that the malloc allocates one byte and does @@ -3972,7 +3976,7 @@ get_user_id_byfpr (ctrl_t ctrl, const byte *fpr, size_t *rn) } } while (++pass < 2 - && !get_pubkey_byfprint (ctrl, NULL, NULL, fpr, MAX_FINGERPRINT_LEN)); + && !get_pubkey_byfprint (ctrl, NULL, NULL, fpr, fprlen)); p = xstrdup (user_id_not_found_utf8 ()); *rn = strlen (p); return p; @@ -3982,10 +3986,10 @@ get_user_id_byfpr (ctrl_t ctrl, const byte *fpr, size_t *rn) encoding. The returned string needs to be freed. Unlike get_user_id_byfpr, the returned string is NUL terminated. */ char * -get_user_id_byfpr_native (ctrl_t ctrl, const byte *fpr) +get_user_id_byfpr_native (ctrl_t ctrl, const byte *fpr, size_t fprlen) { size_t rn; - char *p = get_user_id_byfpr (ctrl, fpr, &rn); + char *p = get_user_id_byfpr (ctrl, fpr, fprlen, &rn); char *p2 = utf8_to_native (p, rn, 0); xfree (p); return p2; diff --git a/g10/import.c b/g10/import.c index c2a1dd033..6c8a37785 100644 --- a/g10/import.c +++ b/g10/import.c @@ -2028,7 +2028,7 @@ import_one (ctrl_t ctrl, /* We are ready. */ if (!opt.quiet && !silent) { - char *p = get_user_id_byfpr_native (ctrl, fpr2); + char *p = get_user_id_byfpr_native (ctrl, fpr2, fpr2len); log_info (_("key %s: public key \"%s\" imported\n"), keystr(keyid), p); xfree(p); @@ -2114,7 +2114,7 @@ import_one (ctrl_t ctrl, /* We are ready. */ if (!opt.quiet && !silent) { - char *p = get_user_id_byfpr_native (ctrl, fpr2); + char *p = get_user_id_byfpr_native (ctrl, fpr2, fpr2len); if (n_uids == 1 ) log_info( _("key %s: \"%s\" 1 new user ID\n"), keystr(keyid),p); @@ -2175,7 +2175,7 @@ import_one (ctrl_t ctrl, if (!opt.quiet && !silent) { - char *p = get_user_id_byfpr_native (ctrl, fpr2); + char *p = get_user_id_byfpr_native (ctrl, fpr2, fpr2len); log_info( _("key %s: \"%s\" not changed\n"),keystr(keyid),p); xfree(p); } diff --git a/g10/keydb.h b/g10/keydb.h index 7cdfe9bbf..54c1f6823 100644 --- a/g10/keydb.h +++ b/g10/keydb.h @@ -436,8 +436,7 @@ char *get_user_id_string_native (ctrl_t ctrl, u32 *keyid); char *get_long_user_id_string (ctrl_t ctrl, u32 *keyid); char *get_user_id (ctrl_t ctrl, u32 *keyid, size_t *rn, int *r_nouid); char *get_user_id_native (ctrl_t ctrl, u32 *keyid); -char *get_user_id_byfpr (ctrl_t ctrl, const byte *fpr, size_t *rn); -char *get_user_id_byfpr_native (ctrl_t ctrl, const byte *fpr); +char *get_user_id_byfpr_native (ctrl_t ctrl, const byte *fpr, size_t fprlen); void release_akl(void); int parse_auto_key_locate(const char *options); From b30351496dd3056462c8db25c03fed6d2aa00e9b Mon Sep 17 00:00:00 2001 From: Andre Heinecke Date: Thu, 11 Apr 2019 08:37:46 +0200 Subject: [PATCH 038/169] speedo,w32: Install gpg-card.exe * build-aux/speedo/w32/inst.nsi: Install gpg-card.exe --- build-aux/speedo/w32/inst.nsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build-aux/speedo/w32/inst.nsi b/build-aux/speedo/w32/inst.nsi index fb452d513..f130a4eda 100644 --- a/build-aux/speedo/w32/inst.nsi +++ b/build-aux/speedo/w32/inst.nsi @@ -624,6 +624,7 @@ Section "GnuPG" SEC_gnupg File "bin/gpgsm.exe" File "bin/gpgconf.exe" File "bin/gpg-connect-agent.exe" + File "bin/gpg-card.exe" File "bin/gpgtar.exe" File "libexec/dirmngr_ldap.exe" File "libexec/gpg-preset-passphrase.exe" @@ -1313,6 +1314,7 @@ Section "-un.gnupg" Delete "$INSTDIR\bin\gpgconf.exe" Delete "$INSTDIR\bin\gpg-connect-agent.exe" Delete "$INSTDIR\bin\gpgtar.exe" + Delete "$INSTDIR\bin\gpg-card.exe" Delete "$INSTDIR\bin\dirmngr_ldap.exe" Delete "$INSTDIR\bin\gpg-preset-passphrase.exe" Delete "$INSTDIR\bin\gpg-wks-client.exe" From 40595b57936e39ee2a4d58b1dd19edea7537a471 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 11 Apr 2019 09:43:33 +0200 Subject: [PATCH 039/169] gpg: Set a limit of 5 to the number of keys imported from the WKD. * g10/import.c (import): Limit the number of considered keys to 5. (import_one): Return the first fingerprint in case of WKD. -- The Web Key Directory should carry only one key. However, some providers like to put old or expired keys also into the WKD. I don't thunk that this is a good idea but I heard claims that this is needed for them to migrate existing key data bases. This patch puts a limit on 5 on it (we had none right now) and also fixes the issue that gpg could not work immediately with the requested key because the code uses the fingerprint of the key to use the imported key. Now the first key is used. On a second try (w/o accessing the WKD) the regular key selection mechanism would be in effect. I think this is the most conservative approach. Let's see whether it helps. Signed-off-by: Werner Koch --- g10/import.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/g10/import.c b/g10/import.c index 6c8a37785..565086773 100644 --- a/g10/import.c +++ b/g10/import.c @@ -669,6 +669,18 @@ import (ctrl_t ctrl, IOBUF inp, const char* fname,struct import_stats_s *stats, if (!(++stats->count % 100) && !opt.quiet) log_info (_("%lu keys processed so far\n"), stats->count ); + + if (origin == KEYORG_WKD && stats->count >= 5) + { + /* We limit the number of keys _received_ from the WKD to 5. + * In fact there should be only one key but some sites want + * to store a few expired keys there also. gpg's key + * selection will later figure out which key to use. Note + * that for WKD we always return the fingerprint of the + * first imported key. */ + log_info ("import from WKD stopped after %d keys\n", 5); + break; + } } stats->v3keys += v3keys; if (rc == -1) @@ -2203,14 +2215,19 @@ import_one (ctrl_t ctrl, fingerprint of the key in all cases. */ if (fpr) { - xfree (*fpr); /* Note that we need to compare against 0 here because COUNT gets only incremented after returning from this function. */ if (!stats->count) - *fpr = fingerprint_from_pk (pk, NULL, fpr_len); - else - *fpr = NULL; + { + xfree (*fpr); + *fpr = fingerprint_from_pk (pk, NULL, fpr_len); + } + else if (origin != KEYORG_WKD) + { + xfree (*fpr); + *fpr = NULL; + } } } From 1b1f649deaeba963ed7240b27f848004db0b051f Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 11 Apr 2019 09:54:28 +0200 Subject: [PATCH 040/169] gpg: Accept also armored data from the WKD. * g10/keyserver.c (keyserver_import_wkd): Clear NO_ARMOR. -- We may even adjust the specs to allow that. It should not be a problem for any OpenPGP implementation because armored keys are very common and de-armoring code is de-facto a mandatory feature. Signed-off-by: Werner Koch --- g10/keyserver.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/g10/keyserver.c b/g10/keyserver.c index 66900f7a9..04802d1a5 100644 --- a/g10/keyserver.c +++ b/g10/keyserver.c @@ -2051,8 +2051,9 @@ keyserver_import_wkd (ctrl_t ctrl, const char *name, int quick, int armor_status = opt.no_armor; import_filter_t save_filt; - /* Keys returned via WKD are in binary format. */ - opt.no_armor = 1; + /* Keys returned via WKD are in binary format. However, we + * relax that requirement and allow also for armored data. */ + opt.no_armor = 0; save_filt = save_and_clear_import_filter (); if (!save_filt) err = gpg_error_from_syserror (); From 60f384592144de53c9a5f5e11d7f73ce863aa94f Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 12 Apr 2019 11:11:09 +0200 Subject: [PATCH 041/169] gpg: Cache a once computed fingerprint in PKT_public_key. * g10/packet.h (PKT_public_key): Add fields fpr and fprlen. * g10/keyid.c (do_fingerprint_md): Remove. (compute_fingerprint): New. (keyid_from_pk): Simplify. (fingerprint_from_pk): Simplify. (hexfingerprint): Avoid using extra array. -- This is similar to what we are doing with the keyid for a long time. Signed-off-by: Werner Koch --- g10/keyid.c | 118 ++++++++++++++++++++------------------------------- g10/packet.h | 3 ++ 2 files changed, 50 insertions(+), 71 deletions(-) diff --git a/g10/keyid.c b/g10/keyid.c index 45454f056..7605cb386 100644 --- a/g10/keyid.c +++ b/g10/keyid.c @@ -253,20 +253,6 @@ hash_public_key (gcry_md_hd_t md, PKT_public_key *pk) } -static gcry_md_hd_t -do_fingerprint_md( PKT_public_key *pk ) -{ - gcry_md_hd_t md; - - if (gcry_md_open (&md, pk->version == 5 ? GCRY_MD_SHA256 : GCRY_MD_SHA1, 0)) - BUG (); - hash_public_key (md,pk); - gcry_md_final (md); - - return md; -} - - /* fixme: Check whether we can replace this function or if not describe why we need it. */ u32 @@ -520,6 +506,37 @@ keystr_from_desc(KEYDB_SEARCH_DESC *desc) } +/* Compute the fingerprint and keyid and store it in PK. */ +static void +compute_fingerprint (PKT_public_key *pk) +{ + const byte *dp; + gcry_md_hd_t md; + size_t len; + + if (gcry_md_open (&md, pk->version == 5 ? GCRY_MD_SHA256 : GCRY_MD_SHA1, 0)) + BUG (); + hash_public_key (md, pk); + gcry_md_final (md); + dp = gcry_md_read (md, 0); + len = gcry_md_get_algo_dlen (gcry_md_get_algo (md)); + log_assert (len <= MAX_FINGERPRINT_LEN); + memcpy (pk->fpr, dp, len); + pk->fprlen = len; + if (pk->version == 5) + { + pk->keyid[0] = buf32_to_u32 (dp); + pk->keyid[1] = buf32_to_u32 (dp+4); + } + else + { + pk->keyid[0] = buf32_to_u32 (dp+12); + pk->keyid[1] = buf32_to_u32 (dp+16); + } + gcry_md_close( md); +} + + /* * Get the keyid from the public key PK and store it at KEYID unless * this is NULL. Returns the 32 bit short keyid. @@ -532,37 +549,11 @@ keyid_from_pk (PKT_public_key *pk, u32 *keyid) if (!keyid) keyid = dummy_keyid; - if( pk->keyid[0] || pk->keyid[1] ) - { - keyid[0] = pk->keyid[0]; - keyid[1] = pk->keyid[1]; - } - else - { - const byte *dp; - gcry_md_hd_t md; + if (!pk->fprlen) + compute_fingerprint (pk); - md = do_fingerprint_md(pk); - if(md) - { - dp = gcry_md_read ( md, 0 ); - if (pk->version == 5) - { - keyid[0] = buf32_to_u32 (dp); - keyid[1] = buf32_to_u32 (dp+4); - } - else - { - keyid[0] = buf32_to_u32 (dp+12); - keyid[1] = buf32_to_u32 (dp+16); - } - gcry_md_close (md); - pk->keyid[0] = keyid[0]; - pk->keyid[1] = keyid[1]; - } - else - pk->keyid[0] = pk->keyid[1] = keyid[0]= keyid[1] = 0xFFFFFFFF; - } + keyid[0] = pk->keyid[0]; + keyid[1] = pk->keyid[1]; return keyid[1]; /*FIXME:shortkeyid ist different for v5*/ } @@ -805,6 +796,7 @@ colon_expirestr_from_sig (PKT_signature *sig) } + /* * Return a byte array with the fingerprint for the given PK/SK * The length of the array is returned in ret_len. Caller must free @@ -813,31 +805,15 @@ colon_expirestr_from_sig (PKT_signature *sig) byte * fingerprint_from_pk (PKT_public_key *pk, byte *array, size_t *ret_len) { - const byte *dp; - size_t len; - gcry_md_hd_t md; + if (!pk->fprlen) + compute_fingerprint (pk); - md = do_fingerprint_md (pk); - dp = gcry_md_read (md, 0); - len = gcry_md_get_algo_dlen (gcry_md_get_algo (md)); - log_assert (len <= MAX_FINGERPRINT_LEN); if (!array) - array = xmalloc ( len ); - memcpy (array, dp, len ); - if (pk->version == 5) - { - pk->keyid[0] = buf32_to_u32 (dp); - pk->keyid[1] = buf32_to_u32 (dp+4); - } - else - { - pk->keyid[0] = buf32_to_u32 (dp+12); - pk->keyid[1] = buf32_to_u32 (dp+16); - } - gcry_md_close( md); + array = xmalloc (pk->fprlen); + memcpy (array, pk->fpr, pk->fprlen); if (ret_len) - *ret_len = len; + *ret_len = pk->fprlen; return array; } @@ -852,19 +828,19 @@ fingerprint_from_pk (PKT_public_key *pk, byte *array, size_t *ret_len) char * hexfingerprint (PKT_public_key *pk, char *buffer, size_t buflen) { - unsigned char fpr[MAX_FINGERPRINT_LEN]; - size_t len; + if (!pk->fprlen) + compute_fingerprint (pk); - fingerprint_from_pk (pk, fpr, &len); if (!buffer) { - buffer = xtrymalloc (2 * len + 1); + buffer = xtrymalloc (2 * pk->fprlen + 1); if (!buffer) return NULL; } - else if (buflen < 2*len+1) + else if (buflen < 2 * pk->fprlen + 1) log_fatal ("%s: buffer too short (%zu)\n", __func__, buflen); - bin2hex (fpr, len, buffer); + + bin2hex (pk->fpr, pk->fprlen, buffer); return buffer; } diff --git a/g10/packet.h b/g10/packet.h index 41dd1a95a..d05a8f0f2 100644 --- a/g10/packet.h +++ b/g10/packet.h @@ -394,6 +394,7 @@ typedef struct byte pubkey_algo; byte pubkey_usage; /* for now only used to pass it to getkey() */ byte req_usage; /* hack to pass a request to getkey() */ + byte fprlen; /* 0 or length of FPR. */ u32 has_expired; /* set to the expiration date if expired */ /* keyid of the primary key. Never access this value directly. Instead, use pk_main_keyid(). */ @@ -401,6 +402,8 @@ typedef struct /* keyid of this key. Never access this value directly! Instead, use pk_keyid(). */ u32 keyid[2]; + /* Fingerprint of the key. Only valid if FPRLEN is not 0. */ + byte fpr[MAX_FINGERPRINT_LEN]; prefitem_t *prefs; /* list of preferences (may be NULL) */ struct { From 64a5fd37271a3e454c0d59ac3500e1a1b232e4f7 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Sat, 13 Apr 2019 11:48:58 +0200 Subject: [PATCH 042/169] gpg: New caching functions. * g10/objcache.c: New. * g10/objcache.h: New. * g10/Makefile.am (common_source): Add them. * g10/gpg.c: Include objcache.h. (g10_exit): Call objcache_dump_stats. * g10/getkey.c: Include objcache.h. (get_primary_uid, release_keyid_list): Remove. (cache_user_id): Remove. (finish_lookup): Call the new cache_put_keyblock instead of cache_user_id. (get_user_id_string): Remove code for mode 2. (get_user_id): Implement using cache_get_uid_bykid. -- This generic caching module is better than the ad-hoc code we used in getkey.c. More cleanup in getkey is still required but it is a start. There is also a small performance increase with the new cache: With a large keyring and --list-sigs I get these numbers: | | before | after | |------+------------+------------| | real | 14m1.028s | 12m16.186s | | user | 2m18.484s | 1m36.040s | | sys | 11m42.420s | 10m40.044s | Note the speedup in the user time which is due to the improved cache algorithm. This is obvious, because the old cache was just a long linked list; the new cache are two hash tables. Signed-off-by: Werner Koch --- g10/Makefile.am | 1 + g10/getkey.c | 148 +++-------- g10/gpg.c | 2 + g10/objcache.c | 642 ++++++++++++++++++++++++++++++++++++++++++++++++ g10/objcache.h | 28 +++ 5 files changed, 702 insertions(+), 119 deletions(-) create mode 100644 g10/objcache.c create mode 100644 g10/objcache.h diff --git a/g10/Makefile.am b/g10/Makefile.am index 3b4464364..884b4749b 100644 --- a/g10/Makefile.am +++ b/g10/Makefile.am @@ -121,6 +121,7 @@ common_source = \ sig-check.c \ keylist.c \ pkglue.c pkglue.h \ + objcache.c objcache.h \ ecdh.c gpg_sources = server.c \ diff --git a/g10/getkey.c b/g10/getkey.c index 49e237add..34bc4bf0e 100644 --- a/g10/getkey.c +++ b/g10/getkey.c @@ -36,6 +36,7 @@ #include "../common/i18n.h" #include "keyserver-internal.h" #include "call-agent.h" +#include "objcache.h" #include "../common/host2net.h" #include "../common/mbox-util.h" #include "../common/status.h" @@ -141,7 +142,6 @@ typedef struct user_id_db char name[1]; } *user_id_db_t; static user_id_db_t user_id_db; -static int uid_cache_entries; /* Number of entries in uid cache. */ static void merge_selfsigs (ctrl_t ctrl, kbnode_t keyblock); static int lookup (ctrl_t ctrl, getkey_ctx_t ctx, int want_secret, @@ -263,115 +263,6 @@ user_id_not_found_utf8 (void) -/* Return the user ID from the given keyblock. - * We use the primary uid flag which has been set by the merge_selfsigs - * function. The returned value is only valid as long as the given - * keyblock is not changed. */ -static const char * -get_primary_uid (KBNODE keyblock, size_t * uidlen) -{ - KBNODE k; - const char *s; - - for (k = keyblock; k; k = k->next) - { - if (k->pkt->pkttype == PKT_USER_ID - && !k->pkt->pkt.user_id->attrib_data - && k->pkt->pkt.user_id->flags.primary) - { - *uidlen = k->pkt->pkt.user_id->len; - return k->pkt->pkt.user_id->name; - } - } - s = user_id_not_found_utf8 (); - *uidlen = strlen (s); - return s; -} - - -static void -release_keyid_list (keyid_list_t k) -{ - while (k) - { - keyid_list_t k2 = k->next; - xfree (k); - k = k2; - } -} - -/**************** - * Store the association of keyid and userid - * Feed only public keys to this function. - */ -static void -cache_user_id (KBNODE keyblock) -{ - user_id_db_t r; - const char *uid; - size_t uidlen; - keyid_list_t keyids = NULL; - KBNODE k; - size_t n; - - for (k = keyblock; k; k = k->next) - { - if (k->pkt->pkttype == PKT_PUBLIC_KEY - || k->pkt->pkttype == PKT_PUBLIC_SUBKEY) - { - keyid_list_t a = xmalloc_clear (sizeof *a); - /* Hmmm: For a long list of keyids it might be an advantage - * to append the keys. */ - fingerprint_from_pk (k->pkt->pkt.public_key, a->fpr, &n); - a->fprlen = n; - keyid_from_pk (k->pkt->pkt.public_key, a->keyid); - /* First check for duplicates. */ - for (r = user_id_db; r; r = r->next) - { - keyid_list_t b; - - for (b = r->keyids; b; b = b->next) - { - if (b->fprlen == a->fprlen - && !memcmp (b->fpr, a->fpr, a->fprlen)) - { - if (DBG_CACHE) - log_debug ("cache_user_id: already in cache\n"); - release_keyid_list (keyids); - xfree (a); - return; - } - } - } - /* Now put it into the cache. */ - a->next = keyids; - keyids = a; - } - } - if (!keyids) - BUG (); /* No key no fun. */ - - - uid = get_primary_uid (keyblock, &uidlen); - - if (uid_cache_entries >= MAX_UID_CACHE_ENTRIES) - { - /* fixme: use another algorithm to free some cache slots */ - r = user_id_db; - user_id_db = r->next; - release_keyid_list (r->keyids); - xfree (r); - uid_cache_entries--; - } - r = xmalloc (sizeof *r + uidlen - 1); - r->keyids = keyids; - r->len = uidlen; - memcpy (r->name, uid, r->len); - r->next = user_id_db; - user_id_db = r; - uid_cache_entries++; -} - /* Disable and drop the public key cache (which is filled by cache_public_key and get_pubkey). Note: there is currently no way @@ -3627,7 +3518,7 @@ finish_lookup (kbnode_t keyblock, unsigned int req_usage, int want_exact, xfree (tempkeystr); } - cache_user_id (keyblock); + cache_put_keyblock (keyblock); return latest_key ? latest_key : keyblock; /* Found. */ } @@ -3848,6 +3739,7 @@ get_user_id_string (ctrl_t ctrl, u32 * keyid, int mode, size_t *r_len, int pass = 0; char *p; + log_assert (mode != 2); if (r_nouid) *r_nouid = 0; @@ -3862,13 +3754,7 @@ get_user_id_string (ctrl_t ctrl, u32 * keyid, int mode, size_t *r_len, { if (mode == 2) { - /* An empty string as user id is possible. Make - sure that the malloc allocates one byte and - does not bail out. */ - p = xmalloc (r->len? r->len : 1); - memcpy (p, r->name, r->len); - if (r_len) - *r_len = r->len; + BUG (); } else { @@ -3926,7 +3812,31 @@ get_long_user_id_string (ctrl_t ctrl, u32 * keyid) char * get_user_id (ctrl_t ctrl, u32 *keyid, size_t *rn, int *r_nouid) { - return get_user_id_string (ctrl, keyid, 2, rn, r_nouid); + char *name; + unsigned int namelen; + + if (r_nouid) + *r_nouid = 0; + + name = cache_get_uid_bykid (keyid, &namelen); + if (!name) + { + /* Get it so that the cache will be filled. */ + if (!get_pubkey (ctrl, NULL, keyid)) + name = cache_get_uid_bykid (keyid, &namelen); + } + + if (!name) + { + name = xstrdup (user_id_not_found_utf8 ()); + namelen = strlen (name); + if (r_nouid) + *r_nouid = 1; + } + + if (rn && name) + *rn = namelen; + return name; } diff --git a/g10/gpg.c b/g10/gpg.c index 1ab7b0497..b46d22690 100644 --- a/g10/gpg.c +++ b/g10/gpg.c @@ -59,6 +59,7 @@ #include "../common/asshelp.h" #include "call-dirmngr.h" #include "tofu.h" +#include "objcache.h" #include "../common/init.h" #include "../common/mbox-util.h" #include "../common/shareddefs.h" @@ -5223,6 +5224,7 @@ g10_exit( int rc ) { keydb_dump_stats (); sig_check_dump_stats (); + objcache_dump_stats (); gcry_control (GCRYCTL_DUMP_MEMORY_STATS); gcry_control (GCRYCTL_DUMP_RANDOM_STATS); } diff --git a/g10/objcache.c b/g10/objcache.c new file mode 100644 index 000000000..7eb92cd0d --- /dev/null +++ b/g10/objcache.c @@ -0,0 +1,642 @@ +/* objcache.c - Caching functions for keys and user ids. + * Copyright (C) 2019 g10 Code GmbH + * + * 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 3 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, see . + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#include +#include +#include +#include + +#include "gpg.h" +#include "../common/util.h" +#include "packet.h" +#include "keydb.h" +#include "options.h" +#include "objcache.h" + +/* Note that max value for uid_items is actually a the threshold when + * we start to look for ietms which can be removed. */ +#define NO_OF_UID_ITEM_BUCKETS 107 +#define MAX_UID_ITEMS_PER_BUCKET 20 + +#define NO_OF_KEY_ITEM_BUCKETS 383 +#define MAX_KEY_ITEMS_PER_BUCKET 20 + + +/* An object to store a user id. This describes an item in the linked + * lists of a bucket in hash table. The reference count will + * eventually be used to remove items from the table. */ +typedef struct uid_item_s +{ + struct uid_item_s *next; + unsigned int refcount; /* The reference count for this item. */ + unsigned int namelen; /* The length of the UID sans the nul. */ + char name[1]; +} *uid_item_t; + +static uid_item_t *uid_table; /* Hash table for with user ids. */ +static size_t uid_table_size; /* Number of allocated buckets. */ +static unsigned int uid_table_max; /* Max. # of items in a bucket. */ +static unsigned int uid_table_added; /* # of items added. */ +static unsigned int uid_table_dropped;/* # of items dropped. */ + + +/* An object to store properties of a key. Note that this can be used + * for a primary or a subkey. The key is linked to a user if that + * exists. */ +typedef struct key_item_s +{ + struct key_item_s *next; + unsigned int usecount; + byte fprlen; + char fpr[MAX_FINGERPRINT_LEN]; + u32 keyid[2]; + uid_item_t ui; /* NULL of a ref'ed user id item. */ +} *key_item_t; + +static key_item_t *key_table; /* Hash table with the keys. */ +static size_t key_table_size; /* Number of allocated buckents. */ +static unsigned int key_table_max; /* Max. # of items in a bucket. */ +static unsigned int key_table_added; /* # of items added. */ +static unsigned int key_table_dropped;/* # of items dropped. */ +static key_item_t key_item_attic; /* List of freed items. */ + + + +/* Dump stats. */ +void +objcache_dump_stats (void) +{ + unsigned int idx; + int len, minlen, maxlen; + unsigned int count, attic, empty; + key_item_t ki; + uid_item_t ui; + + count = empty = 0; + minlen = -1; + maxlen = 0; + for (idx = 0; idx < key_table_size; idx++) + { + len = 0; + for (ki = key_table[idx]; ki; ki = ki->next) + { + count++; + len++; + /* log_debug ("key bucket %u: kid=%08lX used=%u ui=%p\n", */ + /* idx, (ulong)ki->keyid[0], ki->usecount, ki->ui); */ + } + if (len > maxlen) + maxlen = len; + + if (!len) + empty++; + else if (minlen == -1 || len < minlen) + minlen = len; + } + for (attic=0, ki = key_item_attic; ki; ki = ki->next) + attic++; + log_info ("objcache: keys=%u/%u/%u chains=%u,%d..%d buckets=%zu/%u" + " attic=%u\n", + count, key_table_added, key_table_dropped, + empty, minlen > 0? minlen : 0, maxlen, + key_table_size, key_table_max, attic); + + count = empty = 0; + minlen = -1; + maxlen = 0; + for (idx = 0; idx < uid_table_size; idx++) + { + len = 0; + for (ui = uid_table[idx]; ui; ui = ui->next) + { + count++; + len++; + /* log_debug ("uid bucket %u: %p ref=%u l=%u (%.20s)\n", */ + /* idx, ui, ui->refcount, ui->namelen, ui->name); */ + } + if (len > maxlen) + maxlen = len; + + if (!len) + empty++; + else if (minlen == -1 || len < minlen) + minlen = len; + } + log_info ("objcache: uids=%u/%u/%u chains=%u,%d..%d buckets=%zu/%u\n", + count, uid_table_added, uid_table_dropped, + empty, minlen > 0? minlen : 0, maxlen, + uid_table_size, uid_table_max); +} + + + +/* The hash function we use for the uid_table. Must not call a system + * function. */ +static inline unsigned int +uid_table_hasher (const char *name, unsigned namelen) +{ + const unsigned char *s = (const unsigned char*)name; + unsigned int hashval = 0; + unsigned int carry; + + for (; namelen; namelen--, s++) + { + hashval = (hashval << 4) + *s; + if ((carry = (hashval & 0xf0000000))) + { + hashval ^= (carry >> 24); + hashval ^= carry; + } + } + + return hashval % uid_table_size; +} + + +/* Run time allocation of the uid table. This allows us to eventually + * add an option to gpg to control the size. */ +static void +uid_table_init (void) +{ + if (uid_table) + return; + uid_table_size = NO_OF_UID_ITEM_BUCKETS; + uid_table_max = MAX_UID_ITEMS_PER_BUCKET; + uid_table = xcalloc (uid_table_size, sizeof *uid_table); +} + + +static uid_item_t +uid_item_ref (uid_item_t ui) +{ + if (ui) + ui->refcount++; + return ui; +} + +static void +uid_item_unref (uid_item_t uid) +{ + if (!uid) + return; + if (!uid->refcount) + log_fatal ("too many unrefs for uid_item\n"); + + uid->refcount--; + /* We do not release the item here because that would require that + * we locate the head of the list which has this item. This will + * take too long and thus the item is removed when we need to purge + * some items for the list during uid_item_put. */ +} + + +/* Put (NAME,NAMELEN) into the UID_TABLE and return the item. The + * reference count for that item is incremented. NULL is return on an + * allocation error. The caller should release the returned item + * using uid_item_unref. */ +static uid_item_t +uid_table_put (const char *name, unsigned int namelen) +{ + unsigned int hash; + uid_item_t ui; + unsigned int count; + + if (!uid_table) + uid_table_init (); + + hash = uid_table_hasher (name, namelen); + for (ui = uid_table[hash], count = 0; ui; ui = ui->next, count++) + if (ui->namelen == namelen && !memcmp (ui->name, name, namelen)) + return uid_item_ref (ui); /* Found. */ + + /* If the bucket is full remove all unrefed items. */ + if (count >= uid_table_max) + { + uid_item_t ui_next, ui_prev, list_head, drop_head; + + /* No syscalls from here .. */ + list_head = uid_table[hash]; + drop_head = NULL; + while (list_head && !list_head->refcount) + { + ui = list_head; + list_head = ui->next; + ui->next = drop_head; + drop_head = ui; + } + if ((ui_prev = list_head)) + for (ui = ui_prev->next; ui; ui = ui_next) + { + ui_next = ui->next; + if (!ui->refcount) + { + ui->next = drop_head; + drop_head = ui; + ui_prev->next = ui_next; + } + else + ui_prev = ui; + } + uid_table[hash] = list_head; + /* ... to here */ + + for (ui = drop_head; ui; ui = ui_next) + { + ui_next = ui->next; + xfree (ui); + uid_table_dropped++; + } + } + + count = uid_table_added + uid_table_dropped; + ui = xtrycalloc (1, sizeof *ui + namelen); + if (!ui) + return NULL; /* Out of core. */ + if (count != uid_table_added + uid_table_dropped) + { + /* During the malloc another thread added an item. Thus we need + * to check again. */ + uid_item_t ui_new = ui; + for (ui = uid_table[hash]; ui; ui = ui->next) + if (ui->namelen == namelen && !memcmp (ui->name, name, namelen)) + { + /* Found. */ + xfree (ui_new); + return uid_item_ref (ui); + } + ui = ui_new; + } + + memcpy (ui->name, name, namelen); + ui->name[namelen] = 0; /* Extra Nul so we can use it as a string. */ + ui->namelen = namelen; + ui->refcount = 1; + ui->next = uid_table[hash]; + uid_table[hash] = ui; + uid_table_added++; + return ui; +} + + + +/* The hash function we use for the key_table. Must not call a system + * function. */ +static inline unsigned int +key_table_hasher (u32 *keyid) +{ + /* A fingerprint could be used directly as a hash value. However, + * we use the keyid here because it is used in encrypted packets and + * older signatures to identify a key. Since v4 keys the keyid is + * anyway a part of the fingerprint so it quickly extracted from a + * fingerprint. Note that v3 keys are not supported by gpg. */ + return keyid[0] % key_table_size; +} + + +/* Run time allocation of the key table. This allows us to eventually + * add an option to gpg to control the size. */ +static void +key_table_init (void) +{ + if (key_table) + return; + key_table_size = NO_OF_KEY_ITEM_BUCKETS; + key_table_max = MAX_KEY_ITEMS_PER_BUCKET; + key_table = xcalloc (key_table_size, sizeof *key_table); +} + + +static void +key_item_free (key_item_t ki) +{ + if (!ki) + return; + uid_item_unref (ki->ui); + ki->ui = NULL; + ki->next = key_item_attic; + key_item_attic = ki; +} + + +/* Get a key item from PK or if that is NULL from KEYID. The + * reference count for that item is incremented. NULL is return if it + * was not found. */ +static key_item_t +key_table_get (PKT_public_key *pk, u32 *keyid) +{ + unsigned int hash; + key_item_t ki, ki2; + + if (!key_table) + key_table_init (); + + if (pk) + { + byte fpr[MAX_FINGERPRINT_LEN]; + size_t fprlen; + u32 tmpkeyid[2]; + + fingerprint_from_pk (pk, fpr, &fprlen); + keyid_from_pk (pk, tmpkeyid); + hash = key_table_hasher (tmpkeyid); + for (ki = key_table[hash]; ki; ki = ki->next) + if (ki->fprlen == fprlen && !memcmp (ki->fpr, fpr, fprlen)) + return ki; /* Found */ + } + else if (keyid) + { + hash = key_table_hasher (keyid); + for (ki = key_table[hash]; ki; ki = ki->next) + if (ki->keyid[0] == keyid[0] && ki->keyid[1] == keyid[1]) + { + /* Found. We need to check for dups. */ + for (ki2 = ki->next; ki2; ki2 = ki2->next) + if (ki2->keyid[0] == keyid[0] && ki2->keyid[1] == keyid[1]) + return NULL; /* Duplicated keyid - retrun NULL. */ + + /* This is the only one - return it. */ + return ki; + } + } + return NULL; +} + + +/* Helper for the qsort in key_table_put. */ +static int +compare_key_items (const void *arg_a, const void *arg_b) +{ + const key_item_t a = *(const key_item_t *)arg_a; + const key_item_t b = *(const key_item_t *)arg_b; + + /* Reverse sort on the usecount. */ + if (a->usecount > b->usecount) + return -1; + else if (a->usecount == b->usecount) + return 0; + else + return 1; +} + + +/* Put PK into the KEY_TABLE and return a key item. The reference + * count for that item is incremented. If UI is given it is put into + * the entry. NULL is return on an allocation error. */ +static key_item_t +key_table_put (PKT_public_key *pk, uid_item_t ui) +{ + unsigned int hash; + key_item_t ki; + u32 keyid[2]; + byte fpr[MAX_FINGERPRINT_LEN]; + size_t fprlen; + unsigned int count, n; + + if (!key_table) + key_table_init (); + + fingerprint_from_pk (pk, fpr, &fprlen); + keyid_from_pk (pk, keyid); + hash = key_table_hasher (keyid); + for (ki = key_table[hash], count=0; ki; ki = ki->next, count++) + if (ki->fprlen == fprlen && !memcmp (ki->fpr, fpr, fprlen)) + return ki; /* Found */ + + /* If the bucket is full remove a couple of items. */ + if (count >= key_table_max) + { + key_item_t list_head, *list_tailp, ki_next; + key_item_t *array; + int narray, idx; + + /* Unlink from the global list so that other threads don't + * disturb us. If another thread adds or removes something only + * one will be the winner. Bad luck for the drooped cache items + * but after all it is just a cache. */ + list_head = key_table[hash]; + key_table[hash] = NULL; + + /* Put all items into an array for sorting. */ + array = xtrycalloc (count, sizeof *array); + if (!array) + { + /* That's bad; give up all items of the bucket. */ + log_info ("Note: malloc failed while purging from the key_tabe: %s\n", + gpg_strerror (gpg_error_from_syserror ())); + goto leave_drop; + } + narray = 0; + for (ki = list_head; ki; ki = ki_next) + { + ki_next = ki->next; + array[narray++] = ki; + ki->next = NULL; + } + log_assert (narray == count); + + /* Sort the array and put half of it onto a new list. */ + qsort (array, narray, sizeof *array, compare_key_items); + list_head = NULL; + list_tailp = &list_head; + for (idx=0; idx < narray/2; idx++) + { + *list_tailp = array[idx]; + list_tailp = &array[idx]->next; + } + + /* Put the new list into the bucket. */ + ki = key_table[hash]; + key_table[hash] = list_head; + list_head = ki; + + /* Free the remaining items and the array. */ + for (; idx < narray; idx++) + { + key_item_free (array[idx]); + key_table_dropped++; + } + xfree (array); + + leave_drop: + /* Free any items added in the meantime by other threads. This + * is also used in case of a malloc problem (which won't update + * the counters, though). */ + for ( ; list_head; list_head = ki_next) + { + ki_next = list_head->next; + key_item_free (list_head); + } + } + + /* Add an item to the bucket. We allocate a whole block of items + * for cache performace reasons. */ + if (!key_item_attic) + { + key_item_t kiblock; + int kiblocksize = 256; + + kiblock = xtrymalloc (kiblocksize * sizeof *kiblock); + if (!kiblock) + return NULL; /* Out of core. */ + for (n = 0; n < kiblocksize; n++) + { + ki = kiblock + n; + ki->next = key_item_attic; + key_item_attic = ki; + } + + /* During the malloc another thread may have changed the bucket. + * Thus we need to check again. */ + for (ki = key_table[hash]; ki; ki = ki->next) + if (ki->fprlen == fprlen && !memcmp (ki->fpr, fpr, fprlen)) + return ki; /* Found */ + } + + /* We now know that there is an item in the attic. */ + ki = key_item_attic; + key_item_attic = ki->next; + ki->next = NULL; + + memcpy (ki->fpr, fpr, fprlen); + ki->fprlen = fprlen; + ki->keyid[0] = keyid[0]; + ki->keyid[1] = keyid[1]; + ki->ui = uid_item_ref (ui); + ki->usecount = 0; + ki->next = key_table[hash]; + key_table[hash] = ki; + key_table_added++; + return ki; +} + + + +/* Return the user ID from the given keyblock. We use the primary uid + * flag which should have already been set. The returned value is + * only valid as long as the given keyblock is not changed. */ +static const char * +primary_uid_from_keyblock (kbnode_t keyblock, size_t *uidlen) +{ + kbnode_t k; + + for (k = keyblock; k; k = k->next) + { + if (k->pkt->pkttype == PKT_USER_ID + && !k->pkt->pkt.user_id->attrib_data + && k->pkt->pkt.user_id->flags.primary) + { + *uidlen = k->pkt->pkt.user_id->len; + return k->pkt->pkt.user_id->name; + } + } + return NULL; +} + + +/* Store the associations of keyid/fingerprint and userid. Only + * public keys should be fed to this function. */ +void +cache_put_keyblock (kbnode_t keyblock) +{ + uid_item_t ui = NULL; + kbnode_t k; + + restart: + for (k = keyblock; k; k = k->next) + { + if (k->pkt->pkttype == PKT_PUBLIC_KEY + || k->pkt->pkttype == PKT_PUBLIC_SUBKEY) + { + if (!ui) + { + /* Initially we just test for an entry to avoid the need + * to create a user id item for a put. Only if we miss + * key in the cache we create a user id and restart. */ + if (!key_table_get (k->pkt->pkt.public_key, NULL)) + { + const char *uid; + size_t uidlen; + + uid = primary_uid_from_keyblock (keyblock, &uidlen); + if (uid) + { + ui = uid_table_put (uid, uidlen); + if (!ui) + { + log_info ("Note: failed to cache a user id: %s\n", + gpg_strerror (gpg_error_from_syserror ())); + goto leave; + } + goto restart; + } + } + } + else /* With a UID we use the update cache mode. */ + { + if (!key_table_put (k->pkt->pkt.public_key, ui)) + { + log_info ("Note: failed to cache a key: %s\n", + gpg_strerror (gpg_error_from_syserror ())); + goto leave; + } + } + } + } + + leave: + uid_item_unref (ui); +} + + +/* Return the user id string for KEYID. If a user id is not found (or + * on malloc error) NULL is returned. If R_LENGTH is not NULL the + * length of the user id is stored there; this does not included the + * always appended nul. Note that a user id may include an internal + * nul which can be detected by the caller by comparing to the + * returned length. */ +char * +cache_get_uid_bykid (u32 *keyid, unsigned int *r_length) +{ + key_item_t ki; + char *p; + + if (r_length) + *r_length = 0; + + ki = key_table_get (NULL, keyid); + if (!ki) + return NULL; /* Not found or duplicate keyid. */ + + if (!ki->ui) + p = NULL; /* No user id known for key. */ + else + { + p = xtrymalloc (ki->ui->namelen + 1); + if (p) + { + memcpy (p, ki->ui->name, ki->ui->namelen + 1); + if (r_length) + *r_length = ki->ui->namelen; + ki->usecount++; + } + } + + return p; +} diff --git a/g10/objcache.h b/g10/objcache.h new file mode 100644 index 000000000..e92679168 --- /dev/null +++ b/g10/objcache.h @@ -0,0 +1,28 @@ +/* objcache.h - Caching functions for keys and user ids. + * Copyright (C) 2019 g10 Code GmbH + * + * 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 3 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, see . + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#ifndef GNUPG_G10_OBJCACHE_H +#define GNUPG_G10_OBJCACHE_H + +void objcache_dump_stats (void); +void cache_put_keyblock (kbnode_t keyblock); +char *cache_get_uid_bykid (u32 *keyid, unsigned int *r_length); + +#endif /*GNUPG_G10_OBJCACHE_H*/ From b6f0b0efa19e0434024bc16e246032b613fd448a Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Tue, 16 Apr 2019 13:24:10 +0900 Subject: [PATCH 043/169] common: Fix AWK portability. * common/Makefile.am: Use pkg_namespace. * common/mkstrtable.awk: Use pkg_namespace. Regexp fix. -- GnuPG-bug-Bug: 4459 Signed-off-by: NIIBE Yutaka --- common/Makefile.am | 4 ++-- common/mkstrtable.awk | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/common/Makefile.am b/common/Makefile.am index b6a6605f1..9e0f10917 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -149,13 +149,13 @@ if MAINTAINER_MODE audit-events.h: Makefile.am mkstrtable.awk exaudit.awk audit.h $(AWK) -f $(srcdir)/exaudit.awk $(srcdir)/audit.h \ | $(AWK) -f $(srcdir)/mkstrtable.awk -v textidx=3 -v nogettext=1 \ - -v namespace=eventstr_ > $(srcdir)/audit-events.h + -v pkg_namespace=eventstr_ > $(srcdir)/audit-events.h # Create the status-codes.h include file from status.h status-codes.h: Makefile.am mkstrtable.awk exstatus.awk status.h $(AWK) -f $(srcdir)/exstatus.awk $(srcdir)/status.h \ | $(AWK) -f $(srcdir)/mkstrtable.awk -v textidx=3 -v nogettext=1 \ - -v namespace=statusstr_ > $(srcdir)/status-codes.h + -v pkg_namespace=statusstr_ > $(srcdir)/status-codes.h endif # diff --git a/common/mkstrtable.awk b/common/mkstrtable.awk index b5d4ef07a..60efce8a3 100644 --- a/common/mkstrtable.awk +++ b/common/mkstrtable.awk @@ -76,7 +76,7 @@ # # The variable prefix can be used to prepend a string to each message. # -# The variable namespace can be used to prepend a string to each +# The variable pkg_namespace can be used to prepend a string to each # variable and macro name. BEGIN { @@ -101,7 +101,7 @@ header { print "/* The purpose of this complex string table is to produce"; print " optimal code with a minimum of relocations. */"; print ""; - print "static const char " namespace "msgstr[] = "; + print "static const char " pkg_namespace "msgstr[] = "; header = 0; } else @@ -109,7 +109,7 @@ header { } !header { - sub (/\#.+/, ""); + sub (/#.+/, ""); sub (/[ ]+$/, ""); # Strip trailing space and tab characters. if (/^$/) @@ -149,14 +149,14 @@ END { else print " gettext_noop (\"" prefix last_msgstr "\");"; print ""; - print "static const int " namespace "msgidx[] ="; + print "static const int " pkg_namespace "msgidx[] ="; print " {"; for (i = 0; i < coded_msgs; i++) print " " pos[i] ","; print " " pos[coded_msgs]; print " };"; print ""; - print "#define " namespace "msgidxof(code) (0 ? -1 \\"; + print "#define " pkg_namespace "msgidxof(code) (0 ? -1 \\"; # Gather the ranges. skip = code[0]; From a861f9343d6e6d18064e4e54aeb914c5a10b2095 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Wed, 17 Apr 2019 09:58:07 +0900 Subject: [PATCH 044/169] g10: Fix a memory leak. * g10/import.c (import): Care PNDING_PKT on error. -- GnuPG-bug-id: 4461 Reported-by: Philippe Antoine Signed-off-by: NIIBE Yutaka --- g10/import.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/g10/import.c b/g10/import.c index 565086773..00bc47cc1 100644 --- a/g10/import.c +++ b/g10/import.c @@ -689,6 +689,13 @@ import (ctrl_t ctrl, IOBUF inp, const char* fname,struct import_stats_s *stats, log_error (_("error reading '%s': %s\n"), fname, gpg_strerror (rc)); release_kbnode (secattic); + + /* When read_block loop was stopped by error, we have PENDING_PKT left. */ + if (pending_pkt) + { + free_packet (pending_pkt, NULL); + xfree (pending_pkt); + } return rc; } From e57954ed278cb5e6e725005b1ecaf7ce70006ce0 Mon Sep 17 00:00:00 2001 From: Andre Heinecke Date: Thu, 18 Apr 2019 13:19:05 +0200 Subject: [PATCH 045/169] g10: Fix double free when locating by mbox * g10/getkey.c (get_best_pubkey_byname): Set new.uid always to NULL after use. -- pubkey_cmp is not guranteed to set new.uid. So if the diff < 0 case is reached best is set to new. If then diff > 0 is reached without modifying new.uid e.g. if the key has no matching mboxes. new.uid is free'd even though the uid is still referenced in best. GnuPG-Bug-Id: T4462 --- g10/getkey.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/g10/getkey.c b/g10/getkey.c index 34bc4bf0e..1e7334307 100644 --- a/g10/getkey.c +++ b/g10/getkey.c @@ -1388,15 +1388,14 @@ get_best_pubkey_byname (ctrl_t ctrl, GETKEY_CTX *retctx, PKT_public_key *pk, /* Old key is better. */ release_public_key_parts (&new.key); free_user_id (new.uid); - new.uid = NULL; } else { /* A tie. Keep the old key. */ release_public_key_parts (&new.key); free_user_id (new.uid); - new.uid = NULL; } + new.uid = NULL; } getkey_end (ctrl, ctx); ctx = NULL; From ea7d85ff658c000f5f469e0a869af0e512e8c59f Mon Sep 17 00:00:00 2001 From: Daniel Kahn Gillmor Date: Fri, 19 Apr 2019 11:03:24 -0400 Subject: [PATCH 046/169] gpgconf: correct capitalization of "Tor" * tools/gpgconf-comp.cb (gc_options_dirmngr): correct capitalization of Tor. -- https://www.torproject.org/docs/faq.html.en#WhyCalledTor says: > Note: even though it originally came from an acronym, Tor is not > spelled "TOR". Only the first letter is capitalized. In fact, we can > usually spot people who haven't read any of our website (and have > instead learned everything they know about Tor from news articles) by > the fact that they spell it wrong. Signed-off-by: Daniel Kahn Gillmor --- tools/gpgconf-comp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/gpgconf-comp.c b/tools/gpgconf-comp.c index 272b7571e..a55d89874 100644 --- a/tools/gpgconf-comp.c +++ b/tools/gpgconf-comp.c @@ -971,7 +971,7 @@ static gc_option_t gc_options_dirmngr[] = GC_OPT_FLAG_GROUP, GC_LEVEL_BASIC, "gnupg", N_("Options controlling the use of Tor") }, { "use-tor", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC, - "dirmngr", "route all network traffic via TOR", + "dirmngr", "route all network traffic via Tor", GC_ARG_TYPE_NONE, GC_BACKEND_DIRMNGR }, { "Keyserver", From b0f0791e4ade845b2a0e2a94dbda4f3bf1ceb039 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Mon, 22 Apr 2019 20:34:36 +0900 Subject: [PATCH 047/169] scd: Factor out a function to check keyidstr. * scd/app-openpgp.c (check_keyidstr): New. (do_sign, do_auth, do_decipher, do_check_pin): Use check_keyidstr. Signed-off-by: NIIBE Yutaka --- scd/app-openpgp.c | 185 +++++++++++++++------------------------------- 1 file changed, 59 insertions(+), 126 deletions(-) diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 1a537127c..25ec834c8 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -4294,6 +4294,50 @@ check_against_given_fingerprint (app_t app, const char *fpr, int key) } +static int +check_keyidstr (app_t app, const char *keyidstr, int keyno) +{ + int rc; + const char *s; + int n; + const char *fpr = NULL; + unsigned char tmp_sn[20]; /* Actually 16 bytes but also for the fpr. */ + + if (strlen (keyidstr) < 32 || strncmp (keyidstr, "D27600012401", 12)) + return gpg_error (GPG_ERR_INV_ID); + else + { + for (s=keyidstr, n=0; hexdigitp (s); s++, n++) + ; + if (n != 32) + return gpg_error (GPG_ERR_INV_ID); + else if (!*s) + ; /* no fingerprint given: we allow this for now. */ + else if (*s == '/') + fpr = s + 1; + else + return gpg_error (GPG_ERR_INV_ID); + + for (s=keyidstr, n=0; n < 16; s += 2, n++) + tmp_sn[n] = xtoi_2 (s); + + if (app->serialnolen != 16) + return gpg_error (GPG_ERR_INV_CARD); + if (memcmp (app->serialno, tmp_sn, 16)) + return gpg_error (GPG_ERR_WRONG_CARD); + } + + /* If a fingerprint has been specified check it against the one on + the card. This is allows for a meaningful error message in case + the key on the card has been replaced but the shadow information + known to gpg was not updated. If there is no fingerprint, gpg + will detect a bogus signature anyway due to the + verify-after-signing feature. */ + rc = (fpr&&keyno)? check_against_given_fingerprint (app, fpr, keyno) : 0; + + return rc; +} + /* Compute a digital signature on INDATA which is expected to be the raw message digest. For this application the KEYIDSTR consists of @@ -4339,10 +4383,6 @@ do_sign (app_t app, const char *keyidstr, int hashalgo, int rc; unsigned char data[19+64]; size_t datalen; - unsigned char tmp_sn[20]; /* Actually 16 bytes but also for the fpr. */ - const char *s; - int n; - const char *fpr = NULL; unsigned long sigcount; int use_auth = 0; int exmode, le_value; @@ -4387,40 +4427,13 @@ do_sign (app_t app, const char *keyidstr, int hashalgo, ; else if (!strcmp (keyidstr, "OPENPGP.3")) use_auth = 1; - else if (strlen (keyidstr) < 32 || strncmp (keyidstr, "D27600012401", 12)) - return gpg_error (GPG_ERR_INV_ID); else { - for (s=keyidstr, n=0; hexdigitp (s); s++, n++) - ; - if (n != 32) - return gpg_error (GPG_ERR_INV_ID); - else if (!*s) - ; /* no fingerprint given: we allow this for now. */ - else if (*s == '/') - fpr = s + 1; - else - return gpg_error (GPG_ERR_INV_ID); - - for (s=keyidstr, n=0; n < 16; s += 2, n++) - tmp_sn[n] = xtoi_2 (s); - - if (app->serialnolen != 16) - return gpg_error (GPG_ERR_INV_CARD); - if (memcmp (app->serialno, tmp_sn, 16)) - return gpg_error (GPG_ERR_WRONG_CARD); + rc = check_keyidstr (app, keyidstr, 1); + if (rc) + return rc; } - /* If a fingerprint has been specified check it against the one on - the card. This is allows for a meaningful error message in case - the key on the card has been replaced but the shadow information - known to gpg was not updated. If there is no fingerprint, gpg - will detect a bogus signature anyway due to the - verify-after-signing feature. */ - rc = fpr? check_against_given_fingerprint (app, fpr, 1) : 0; - if (rc) - return rc; - /* Concatenate prefix and digest. */ #define X(a,b,d) \ if (hashalgo == GCRY_MD_ ## a && (d) ) \ @@ -4537,10 +4550,6 @@ do_auth (app_t app, const char *keyidstr, unsigned char **outdata, size_t *outdatalen ) { int rc; - unsigned char tmp_sn[20]; /* Actually 16 but we use it also for the fpr. */ - const char *s; - int n; - const char *fpr = NULL; if (!keyidstr || !*keyidstr) return gpg_error (GPG_ERR_INV_VALUE); @@ -4568,40 +4577,13 @@ do_auth (app_t app, const char *keyidstr, /* Check whether an OpenPGP card of any version has been requested. */ if (!strcmp (keyidstr, "OPENPGP.3")) ; - else if (strlen (keyidstr) < 32 || strncmp (keyidstr, "D27600012401", 12)) - return gpg_error (GPG_ERR_INV_ID); else { - for (s=keyidstr, n=0; hexdigitp (s); s++, n++) - ; - if (n != 32) - return gpg_error (GPG_ERR_INV_ID); - else if (!*s) - ; /* no fingerprint given: we allow this for now. */ - else if (*s == '/') - fpr = s + 1; - else - return gpg_error (GPG_ERR_INV_ID); - - for (s=keyidstr, n=0; n < 16; s += 2, n++) - tmp_sn[n] = xtoi_2 (s); - - if (app->serialnolen != 16) - return gpg_error (GPG_ERR_INV_CARD); - if (memcmp (app->serialno, tmp_sn, 16)) - return gpg_error (GPG_ERR_WRONG_CARD); + rc = check_keyidstr (app, keyidstr, 3); + if (rc) + return rc; } - /* If a fingerprint has been specified check it against the one on - the card. This is allows for a meaningful error message in case - the key on the card has been replaced but the shadow information - known to gpg was not updated. If there is no fingerprint, gpg - will detect a bogus signature anyway due to the - verify-after-signing feature. */ - rc = fpr? check_against_given_fingerprint (app, fpr, 3) : 0; - if (rc) - return rc; - rc = verify_chv2 (app, pincb, pincb_arg); if (!rc) { @@ -4637,11 +4619,8 @@ do_decipher (app_t app, const char *keyidstr, unsigned char **outdata, size_t *outdatalen, unsigned int *r_info) { - int rc; - unsigned char tmp_sn[20]; /* actually 16 but we use it also for the fpr. */ - const char *s; int n; - const char *fpr = NULL; + int rc; int exmode, le_value; unsigned char *fixbuf = NULL; int padind = 0; @@ -4653,39 +4632,13 @@ do_decipher (app_t app, const char *keyidstr, /* Check whether an OpenPGP card of any version has been requested. */ if (!strcmp (keyidstr, "OPENPGP.2")) ; - else if (strlen (keyidstr) < 32 || strncmp (keyidstr, "D27600012401", 12)) - return gpg_error (GPG_ERR_INV_ID); else { - for (s=keyidstr, n=0; hexdigitp (s); s++, n++) - ; - if (n != 32) - return gpg_error (GPG_ERR_INV_ID); - else if (!*s) - ; /* no fingerprint given: we allow this for now. */ - else if (*s == '/') - fpr = s + 1; - else - return gpg_error (GPG_ERR_INV_ID); - - for (s=keyidstr, n=0; n < 16; s += 2, n++) - tmp_sn[n] = xtoi_2 (s); - - if (app->serialnolen != 16) - return gpg_error (GPG_ERR_INV_CARD); - if (memcmp (app->serialno, tmp_sn, 16)) - return gpg_error (GPG_ERR_WRONG_CARD); + rc = check_keyidstr (app, keyidstr, 2); + if (rc) + return rc; } - /* If a fingerprint has been specified check it against the one on - the card. This is allows for a meaningful error message in case - the key on the card has been replaced but the shadow information - known to gpg was not updated. If there is no fingerprint, the - decryption won't produce the right plaintext anyway. */ - rc = fpr? check_against_given_fingerprint (app, fpr, 2) : 0; - if (rc) - return rc; - rc = verify_chv2 (app, pincb, pincb_arg); if (rc) return rc; @@ -4901,38 +4854,18 @@ do_check_pin (app_t app, const char *keyidstr, gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg) { - unsigned char tmp_sn[20]; - const char *s; - int n; int admin_pin = 0; + int rc; if (!keyidstr || !*keyidstr) return gpg_error (GPG_ERR_INV_VALUE); - /* Check whether an OpenPGP card of any version has been requested. */ - if (strlen (keyidstr) < 32 || strncmp (keyidstr, "D27600012401", 12)) - return gpg_error (GPG_ERR_INV_ID); + rc = check_keyidstr (app, keyidstr, 0); + if (rc) + return rc; - for (s=keyidstr, n=0; hexdigitp (s); s++, n++) - ; - if (n != 32) - return gpg_error (GPG_ERR_INV_ID); - else if (!*s) - ; /* No fingerprint given: we allow this for now. */ - else if (*s == '/') - ; /* We ignore a fingerprint. */ - else if (!strcmp (s, "[CHV3]") ) + if (strlen (keyidstr) >= 32+6 && !strcmp (keyidstr+32, "[CHV3]")) admin_pin = 1; - else - return gpg_error (GPG_ERR_INV_ID); - - for (s=keyidstr, n=0; n < 16; s += 2, n++) - tmp_sn[n] = xtoi_2 (s); - - if (app->serialnolen != 16) - return gpg_error (GPG_ERR_INV_CARD); - if (memcmp (app->serialno, tmp_sn, 16)) - return gpg_error (GPG_ERR_WRONG_CARD); /* Yes, there is a race conditions: The user might pull the card right here and we won't notice that. However this is not a From e769609cd3c12d2e26955538399172016f78d2d4 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Tue, 23 Apr 2019 10:51:01 +0900 Subject: [PATCH 048/169] scd: Allow KEYGRIP as KEYIDSTR. * scd/app-openpgp.c (struct app_local_s): Add keygrip_str. (store_keygrip): New. (read_public_key): Call store_keygrip to hold keygrip. (get_public_key): Likewise. (send_keypair_info): Use stored keygrip_str. (check_keyidstr): Allow use of KEYGRIP. (do_check_pin): Allow use of KEYGRIP of signing slot. Signed-off-by: NIIBE Yutaka --- scd/app-openpgp.c | 67 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 52 insertions(+), 15 deletions(-) diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 25ec834c8..02d388695 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -176,6 +176,7 @@ struct app_local_s { is usually only required for cross checks because the length of an S-expression is implicitly available. */ + unsigned char keygrip_str[41]; /* The keygrip, null terminated */ } pk[3]; unsigned char status_indicator; /* The card status indicator. */ @@ -1575,6 +1576,23 @@ ecc_read_pubkey (app_t app, ctrl_t ctrl, u32 created_at, int keyno, } +static gpg_error_t +store_keygrip (app_t app, int keyno) +{ + gpg_error_t err; + unsigned char grip[20]; + + err = keygrip_from_canon_sexp (app->app_local->pk[keyno].key, + app->app_local->pk[keyno].keylen, + grip); + if (err) + return err; + + bin2hex (grip, 20, app->app_local->pk[keyno].keygrip_str); + return 0; +} + + /* Parse tag-length-value data for public key in BUFFER of BUFLEN length. Key of KEYNO in APP is updated with an S-expression of public key. When CTRL is not NULL, fingerprint is computed with @@ -1626,6 +1644,8 @@ read_public_key (app_t app, ctrl_t ctrl, u32 created_at, int keyno, app->app_local->pk[keyno].key = keybuf; /* Decrement for trailing '\0' */ app->app_local->pk[keyno].keylen = len - 1; + + err = store_keygrip (app, keyno); } return err; @@ -1773,11 +1793,13 @@ get_public_key (app_t app, int keyno) app->app_local->pk[keyno].key = (unsigned char*)keybuf; /* Decrement for trailing '\0' */ app->app_local->pk[keyno].keylen = len - 1; + err = store_keygrip (app, keyno); } leave: /* Set a flag to indicate that we tried to read the key. */ - app->app_local->pk[keyno].read_done = 1; + if (!err) + app->app_local->pk[keyno].read_done = 1; xfree (buffer); return err; @@ -1796,8 +1818,6 @@ send_keypair_info (app_t app, ctrl_t ctrl, int key) /* Note that GnuPG 1.x does not need this and it would be too time consuming to send it just for the fun of it. */ #if GNUPG_MAJOR_VERSION > 1 - unsigned char grip[20]; - char gripstr[41]; char idbuf[50]; const char *usage; @@ -1809,14 +1829,6 @@ send_keypair_info (app_t app, ctrl_t ctrl, int key) if (!app->app_local->pk[keyno].key) goto leave; /* No such key - ignore. */ - err = keygrip_from_canon_sexp (app->app_local->pk[keyno].key, - app->app_local->pk[keyno].keylen, - grip); - if (err) - goto leave; - - bin2hex (grip, 20, gripstr); - switch (keyno) { case 0: usage = "sc"; break; @@ -1827,7 +1839,7 @@ send_keypair_info (app_t app, ctrl_t ctrl, int key) sprintf (idbuf, "OPENPGP.%d", keyno+1); send_status_info (ctrl, "KEYPAIRINFO", - gripstr, 40, + app->app_local->pk[keyno].keygrip_str, 40, idbuf, strlen (idbuf), usage, strlen (usage), NULL, (size_t)0); @@ -4294,6 +4306,17 @@ check_against_given_fingerprint (app_t app, const char *fpr, int key) } +/* Check KEYIDSTR, if it's valid. + When KEYNO is 0, it means it's for PIN check. + Otherwise, KEYNO corresponds to the slot (signing, decipher and auth). + KEYIDSTR is either: + (1) Serial number + (2) Serial number "/" fingerprint + (3) keygrip + + When KEYNO is 0 and KEYIDSTR is for a keygrip, the keygrip should + be to be compared is the first one (keygrip for signing). + */ static int check_keyidstr (app_t app, const char *keyidstr, int keyno) { @@ -4303,13 +4326,26 @@ check_keyidstr (app_t app, const char *keyidstr, int keyno) const char *fpr = NULL; unsigned char tmp_sn[20]; /* Actually 16 bytes but also for the fpr. */ - if (strlen (keyidstr) < 32 || strncmp (keyidstr, "D27600012401", 12)) + if (strlen (keyidstr) < 32) return gpg_error (GPG_ERR_INV_ID); else { for (s=keyidstr, n=0; hexdigitp (s); s++, n++) ; - if (n != 32) + + /* Check if it's a keygrip */ + if (n == 40) + { + const unsigned char *keygrip_str; + + keygrip_str = app->app_local->pk[keyno?keyno-1:0].keygrip_str; + if (!strncmp (keygrip_str, keyidstr, 40)) + return 0; + else + return gpg_error (GPG_ERR_INV_ID); + } + + if (n != 32 || strncmp (keyidstr, "D27600012401", 12)) return gpg_error (GPG_ERR_INV_ID); else if (!*s) ; /* no fingerprint given: we allow this for now. */ @@ -4864,7 +4900,8 @@ do_check_pin (app_t app, const char *keyidstr, if (rc) return rc; - if (strlen (keyidstr) >= 32+6 && !strcmp (keyidstr+32, "[CHV3]")) + if ((strlen (keyidstr) >= 32+6 && !strcmp (keyidstr+32, "[CHV3]")) + || (strlen (keyidstr) >= 40+6 && !strcmp (keyidstr+40, "[CHV3]"))) admin_pin = 1; /* Yes, there is a race conditions: The user might pull the card From d5443b918dd3b8ccb3c4fdd8fe9d70d84aa312ff Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Tue, 23 Apr 2019 11:57:56 +0900 Subject: [PATCH 049/169] po: Update Japanese Translation. Signed-off-by: NIIBE Yutaka --- po/ja.po | 416 +++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 267 insertions(+), 149 deletions(-) diff --git a/po/ja.po b/po/ja.po index d2b4c7e8c..f4f39a091 100644 --- a/po/ja.po +++ b/po/ja.po @@ -8,9 +8,9 @@ # msgid "" msgstr "" -"Project-Id-Version: gnupg 2.2.6\n" +"Project-Id-Version: gnupg 2.2.13\n" "Report-Msgid-Bugs-To: translations@gnupg.org\n" -"PO-Revision-Date: 2018-04-12 10:51+0900\n" +"PO-Revision-Date: 2019-04-23 11:50+0900\n" "Last-Translator: NIIBE Yutaka \n" "Language-Team: none\n" "Language: ja\n" @@ -23,12 +23,12 @@ msgstr "" msgid "failed to acquire the pinentry lock: %s\n" msgstr "pinentryのロックの獲得に失敗しました: %s\n" -#. TRANSLATORS: These are labels for buttons etc used in -#. Pinentries. An underscore indicates that the next letter -#. should be used as an accelerator. Double the underscore for -#. a literal one. The actual to be translated text starts after -#. the second vertical bar. Note that gpg-agent has been set to -#. utf-8 so that the strings are in the expected encoding. +#. TRANSLATORS: These are labels for buttons etc as used in +#. * Pinentries. In your translation copy the text before the +#. * second vertical bar verbatim; translate only the following +#. * text. An underscore indicates that the next letter should be +#. * used as an accelerator. Double the underscore to have +#. * pinentry display a literal underscore. msgid "|pinentry-label|_OK" msgstr "|pinentry-label|_OK" @@ -203,9 +203,11 @@ msgstr "PUK" msgid "Reset Code" msgstr "リセット・コード" -#, c-format -msgid "%s%%0A%%0AUse the reader's pinpad for input." -msgstr "%s%%0A%%0Aリーダーのピンパッドを入力に使ってください。" +msgid "Push ACK button on card/token." +msgstr "カード/トークンのACKボタンを押してください。" + +msgid "Use the reader's pinpad for input." +msgstr "リーダーのピンパッドを入力に使ってください。" msgid "Repeat this Reset Code" msgstr "このリセット・コードをもう一度入力してください" @@ -813,30 +815,30 @@ msgid "unknown debug flag '%s' ignored\n" msgstr "未知のdebugフラグ'%s'は無視されました\n" #, c-format -msgid "no running gpg-agent - starting '%s'\n" -msgstr "gpg-agentが実行されていません - '%s'を開始します\n" +msgid "waiting for the dirmngr to come up ... (%ds)\n" +msgstr "dirmngrの起動のため、%d秒待ちます\n" #, c-format msgid "waiting for the agent to come up ... (%ds)\n" msgstr "agentの起動のため、%d秒待ちます\n" -msgid "connection to agent established\n" +msgid "connection to the dirmngr established\n" +msgstr "dirmngrへの接続が確立しました\n" + +msgid "connection to the agent established\n" msgstr "エージェントへの接続が確立しました。\n" -msgid "connection to agent is in restricted mode\n" +#, c-format +msgid "no running gpg-agent - starting '%s'\n" +msgstr "gpg-agentが実行されていません - '%s'を開始します\n" + +msgid "connection to the agent is in restricted mode\n" msgstr "エージェントへの接続は制限モードです。\n" #, c-format -msgid "no running Dirmngr - starting '%s'\n" +msgid "no running dirmngr - starting '%s'\n" msgstr "dirmngrが動いていません - 開始します'%s'\n" -#, c-format -msgid "waiting for the dirmngr to come up ... (%ds)\n" -msgstr "dirmngrの起動のため、%d秒待ちます\n" - -msgid "connection to the dirmngr established\n" -msgstr "dirmngrへの接続が確立しました\n" - #. TRANSLATORS: Copy the prefix between the vertical bars #. verbatim. It will not be printed. msgid "|audit-log-result|Good" @@ -1128,7 +1130,7 @@ msgid "CRC error; %06lX - %06lX\n" msgstr "CRCエラー。%06lX - %06lX\n" msgid "premature eof (in trailer)\n" -msgstr "ファイル末尾が早すぎます (後尾部の中にあります)\n" +msgstr "ファイル終端が早すぎます (後尾部の中にあります)\n" msgid "error in trailer line\n" msgstr "後尾の行にエラーがあります\n" @@ -1205,6 +1207,10 @@ msgstr "注意: \"%s\"コマンドを使って再起動してください。\n" msgid "%s is not compliant with %s mode\n" msgstr "%sは%sモードに準拠しません\n" +#, c-format +msgid "problem with the agent: %s\n" +msgstr "エージェントに問題: %s\n" + #, c-format msgid "OpenPGP card not available: %s\n" msgstr "OpenPGPカードが利用できません: %s\n" @@ -1228,14 +1234,11 @@ msgstr "あなたの選択は? " msgid "[not set]" msgstr "[未設定]" -msgid "male" -msgstr "男" +msgid "Mr." +msgstr "Mr." -msgid "female" -msgstr "女" - -msgid "unspecified" -msgstr "無指定" +msgid "Mrs." +msgstr "Mrs" msgid "not forced" msgstr "強制なし" @@ -1288,8 +1291,8 @@ msgstr "エラー: 優先指定の文字列の長さが無効です。\n" msgid "Error: invalid characters in preference string.\n" msgstr "エラー: 優先指定の文字列に無効な文字があります。\n" -msgid "Sex ((M)ale, (F)emale or space): " -msgstr "性別 ((M)男、(F)女、または空白): " +msgid "Salutation (M = Mr., F = Mrs., or space): " +msgstr "敬称 (M = Mr., F = Mrs, あるいは空白): " msgid "Error: invalid response.\n" msgstr "エラー: 無効な応答。\n" @@ -1315,13 +1318,15 @@ msgid "Replace existing key? (y/N) " msgstr "既存の鍵を置き換えしますか? (y/N) " msgid "" -"Note: There is no guarantee that the card supports the requested size.\n" -" If the key generation does not succeed, please check the\n" -" documentation of your card to see what sizes are allowed.\n" +"Note: There is no guarantee that the card supports the requested\n" +" key type or size. If the key generation does not succeed,\n" +" please check the documentation of your card to see which\n" +" key types and sizes are supported.\n" msgstr "" -"注意: カードが要求された鍵長をサポートしているという保証はありません。\n" -" 鍵生成が成功しない場合、あなたのカードに関する技術文書を確認し、\n" -" 利用できる鍵長について確認ください。\n" +"注意: カードが要求された鍵のタイプもしくは鍵長をサポートしている保証は\n" +" ありません。鍵生成が成功しない場合、あなたのカードに関する技術文書を\n" +" 確認し、どの鍵のタイプと鍵長がサポートされているかについて確認して\n" +" ください。\n" #, c-format msgid "What keysize do you want? (%u) " @@ -1432,6 +1437,10 @@ msgstr "工場出荷リセットを行いますか? (本当なら \"yes\" と入 msgid "error for setup KDF: %s\n" msgstr "KDF設定のエラー: %s\n" +#, c-format +msgid "error for setup UIF: %s\n" +msgstr "UIF設定のエラー: %s\n" + msgid "quit this menu" msgstr "このメニューを終了" @@ -1459,8 +1468,8 @@ msgstr "ログイン名の変更" msgid "change the language preferences" msgstr "言語の優先指定の変更" -msgid "change card holder's sex" -msgstr "カード所有者の性別の変更" +msgid "change card holder's salutation" +msgstr "カード所有者の敬称の変更" msgid "change a CA fingerprint" msgstr "CAフィンガープリントの変更" @@ -1489,6 +1498,9 @@ msgstr "PIN認証のKDFを設定する" msgid "change the key attribute" msgstr "鍵の属性の変更" +msgid "change the User Interaction Flag" +msgstr "ユーザ・インタラクション・フラグの変更" + msgid "gpg/card> " msgstr "gpg/card> " @@ -1527,7 +1539,7 @@ msgid "(unless you specify the key by fingerprint)\n" msgstr "(フィンガー・プリントで鍵を指定してない限り)\n" msgid "can't do this in batch mode without \"--yes\"\n" -msgstr "\"--yes\"なしでバッチ・モードではできません\n" +msgstr "これは\"--yes\"なしでバッチ・モードではできません\n" msgid "Delete this key from the keyring? (y/N) " msgstr "この鍵を鍵リングから削除しますか? (y/N) " @@ -1567,8 +1579,8 @@ msgid "can't use a symmetric ESK packet due to the S2K mode\n" msgstr "S2Kモードのため、共通鍵ESKパケットを使えません\n" #, c-format -msgid "using cipher %s\n" -msgstr "暗号方式 %s を使います\n" +msgid "using cipher %s.%s\n" +msgstr "暗号方式 %s.%s を使います\n" #, c-format msgid "'%s' already compressed\n" @@ -1608,16 +1620,16 @@ msgid "forcing symmetric cipher %s (%d) violates recipient preferences\n" msgstr "共通鍵暗号方式 %s (%d) の強制が、受取人の優先指定をそむきます\n" #, c-format -msgid "%s/%s encrypted for: \"%s\"\n" -msgstr "%s/%s暗号化 受信者:\"%s\"\n" +msgid "%s/%s.%s encrypted for: \"%s\"\n" +msgstr "%s/%s.%s 暗号化 受信者:\"%s\"\n" #, c-format msgid "option '%s' may not be used in %s mode\n" msgstr "オプション'%s'を%sモードで使うことはできません\n" #, c-format -msgid "%s encrypted data\n" -msgstr "%s暗号化済みデータ\n" +msgid "%s.%s encrypted data\n" +msgstr "%s.%s 暗号化データ\n" #, c-format msgid "encrypted with unknown algorithm %d\n" @@ -1688,6 +1700,9 @@ msgstr "エクスポートの際、利用できない部分を除去する" msgid "remove as much as possible from key during export" msgstr "エクスポートの際、できるだけ除去する" +msgid "Do not export user id or attribute packets" +msgstr "ユーザIDもしくは属性パケットをエクスポートしない" + msgid "use the GnuPG key backup format" msgstr "GnuPGの鍵のバックアップフォーマットを使います" @@ -1719,22 +1734,6 @@ msgstr "'%s'の作成エラー: %s\n" msgid "[User ID not found]" msgstr "[ユーザIDが見つかりません]" -#, c-format -msgid "(check argument of option '%s')\n" -msgstr "(オプション'%s'の引数を確認ください)\n" - -#, c-format -msgid "Warning: '%s' should be a long key ID or a fingerprint\n" -msgstr "警告: '%s'は長い鍵IDかフィンガープリントであるべきです。\n" - -#, c-format -msgid "error looking up: %s\n" -msgstr "検索のエラー: %s\n" - -#, c-format -msgid "Warning: %s appears in the keyring %d times\n" -msgstr "警告: %sは鍵リングに%d回出現します\n" - #, c-format msgid "automatically retrieved '%s' via %s\n" msgstr "'%s'を %s から自動取得\n" @@ -1746,10 +1745,18 @@ msgstr "'%s'を %s から取得する際のエラー: %s\n" msgid "No fingerprint" msgstr "フィンガープリントがありません" +#, c-format +msgid "checking for a fresh copy of an expired key via %s\n" +msgstr "%s から失効した鍵の新しいコピーを確認します。\n" + #, c-format msgid "secret key \"%s\" not found: %s\n" msgstr "秘密鍵\"%s\"が見つかりません: %s\n" +#, c-format +msgid "(check argument of option '%s')\n" +msgstr "(オプション'%s'の引数を確認ください)\n" + #, c-format msgid "Warning: not using '%s' as default key: %s\n" msgstr "警告: デフォルトの秘密鍵として '%s' を用いません: %s\n" @@ -2225,7 +2232,10 @@ msgid "will not run with insecure memory due to %s\n" msgstr "%s のため、セキュアでないメモリで実行しません\n" msgid "selected cipher algorithm is invalid\n" -msgstr "選択された暗号アルゴリズムは、無効です\n" +msgstr "選択された暗号アルゴリズムは無効です\n" + +msgid "selected AEAD algorithm is invalid\n" +msgstr "選択された AEAD アルゴリズムは無効です\n" msgid "selected compression algorithm is invalid\n" msgstr "選択された圧縮アルゴリズムは、無効です\n" @@ -2260,16 +2270,27 @@ msgstr "無効なデフォルトの優先指定\n" msgid "invalid personal cipher preferences\n" msgstr "無効な個人用暗号方式の優先指定\n" +msgid "invalid personal AEAD preferences\n" +msgstr "無効な個人用 AEAD 方式の優先指定\n" + msgid "invalid personal digest preferences\n" msgstr "無効な個人用ダイジェストの優先指定\n" msgid "invalid personal compress preferences\n" msgstr "無効な個人用圧縮の優先指定\n" +#, c-format +msgid "chunk size invalid - using %d\n" +msgstr "無効なチャンク長です - %dにします\n" + #, c-format msgid "%s does not yet work with %s\n" msgstr "%sは%sではまだ機能しません\n" +#, c-format +msgid "AEAD algorithm '%s' may not be used in %s mode\n" +msgstr "AEAD アルゴリズム'%s'を%sモードで使うことはできません\n" + #, c-format msgid "digest algorithm '%s' may not be used in %s mode\n" msgstr "ダイジェスト・アルゴリズム'%s'を%sモードで使うことはできません\n" @@ -2417,6 +2438,9 @@ msgstr "インポート後、利用できない部分を鍵から除去します msgid "remove as much as possible from key after import" msgstr "インポート後、できるだけ除去します" +msgid "Do not import user id or attribute packets" +msgstr "ユーザIDもしくは属性パケットをインポートしない" + msgid "run import filters and export key immediately" msgstr "インポート・フィルタを実行し鍵をすぐにエクスポートします" @@ -2510,6 +2534,10 @@ msgstr "" msgid " \"%s\": preference for cipher algorithm %s\n" msgstr " \"%s\": 暗号アルゴリズムの優先指定 %s\n" +#, c-format +msgid " \"%s\": preference for AEAD algorithm %s\n" +msgstr " \"%s\": AEADアルゴリズムの優先指定 %s\n" + #, c-format msgid " \"%s\": preference for digest algorithm %s\n" msgstr " \"%s\": ダイジェスト・アルゴリズムの優先指定 %s\n" @@ -2634,6 +2662,18 @@ msgstr "鍵 %s: 秘密鍵はもうあります\n" msgid "key %s: error sending to agent: %s\n" msgstr "鍵 %s: エージェントへの送信エラー: %s\n" +#. TRANSLATORS: For a smartcard, each private key on host has a +#. * reference (stub) to a smartcard and actual private key data +#. * is stored on the card. A single smartcard can have up to +#. * three private key data. Importing private key stub is always +#. * skipped in 2.1, and it returns GPG_ERR_NOT_PROCESSED. +#. * Instead, user should be suggested to run 'gpg --card-status', +#. * then, references to a card will be automatically created +#. * again. +#, c-format +msgid "To migrate '%s', with each smartcard, run: %s\n" +msgstr "'%s'の移行には、スマードカードそれぞれで、以下を実行してください: %s\n" + #, c-format msgid "secret key %s: %s\n" msgstr "秘密鍵 %s: %s\n" @@ -2645,19 +2685,26 @@ msgstr "秘密鍵のインポートは禁止です\n" msgid "key %s: secret key with invalid cipher %d - skipped\n" msgstr "鍵%s: 無効な暗号方式%dの秘密鍵です - スキップします\n" -#. TRANSLATORS: For smartcard, each private key on -#. host has a reference (stub) to a smartcard and -#. actual private key data is stored on the card. A -#. single smartcard can have up to three private key -#. data. Importing private key stub is always -#. skipped in 2.1, and it returns -#. GPG_ERR_NOT_PROCESSED. Instead, user should be -#. suggested to run 'gpg --card-status', then, -#. references to a card will be automatically -#. created again. -#, c-format -msgid "To migrate '%s', with each smartcard, run: %s\n" -msgstr "'%s'の移行には、スマードカードそれぞれで、以下を実行してください: %s\n" +msgid "No reason specified" +msgstr "理由は指定されていません" + +msgid "Key is superseded" +msgstr "鍵がとりかわっています" + +msgid "Key has been compromised" +msgstr "鍵(の信頼性)が損なわれています" + +msgid "Key is no longer used" +msgstr "鍵はもはや使われていません" + +msgid "User ID is no longer valid" +msgstr "ユーザIDがもはや有効でありません" + +msgid "reason for revocation: " +msgstr "失効理由: " + +msgid "revocation comment: " +msgstr "失効のコメント: " #, c-format msgid "key %s: no public key - can't apply revocation certificate\n" @@ -3269,12 +3316,15 @@ msgstr "'%s'は、有効な有効期限ではありません\n" #, c-format msgid "\"%s\" is not a proper fingerprint\n" -msgstr "\"%s\"はフ正しいィンガープリントではありません\n" +msgstr "\"%s\"は正しいフィンガープリントではありません\n" #, c-format msgid "subkey \"%s\" not found\n" msgstr "副鍵\"%s\"が見つかりません\n" +msgid "AEAD: " +msgstr "AEAD: " + msgid "Digest: " msgstr "ダイジェスト: " @@ -3607,6 +3657,9 @@ msgstr "ダイジェストの優先指定が多すぎます\n" msgid "too many compression preferences\n" msgstr "圧縮の優先指定が多すぎます\n" +msgid "too many AEAD preferences\n" +msgstr "AEAD方式の優先指定が多すぎます\n" + #, c-format msgid "invalid item '%s' in preference string\n" msgstr "優先指定の文字列に無効な項目'%s'があります\n" @@ -3647,21 +3700,21 @@ msgid "Authenticate" msgstr "Authenticate" #. TRANSLATORS: Please use only plain ASCII characters for the -#. translation. If this is not possible use single digits. The -#. string needs to 8 bytes long. Here is a description of the -#. functions: -#. -#. s = Toggle signing capability -#. e = Toggle encryption capability -#. a = Toggle authentication capability -#. q = Finish +#. * translation. If this is not possible use single digits. The +#. * string needs to 8 bytes long. Here is a description of the +#. * functions: +#. * +#. * s = Toggle signing capability +#. * e = Toggle encryption capability +#. * a = Toggle authentication capability +#. * q = Finish #. msgid "SsEeAaQq" msgstr "SsEeAaQq" #, c-format -msgid "Possible actions for a %s key: " -msgstr "鍵%sに認められた操作: " +msgid "Possible actions for this %s key: " +msgstr "この鍵%sにありうる操作: " msgid "Current allowed actions: " msgstr "現在の認められた操作: " @@ -3734,6 +3787,10 @@ msgstr " (%d) ECC (暗号化のみ)\n" msgid " (%d) Existing key\n" msgstr " (%d) 既存の鍵\n" +#, c-format +msgid " (%d) Existing key from card\n" +msgstr " (%d) カードに存在する鍵\n" + msgid "Enter the keygrip: " msgstr "keygripを入力: " @@ -3743,6 +3800,17 @@ msgstr "有効なkeygrip (40桁の16進数字)ではありません\n" msgid "No key with this keygrip\n" msgstr "このkeygripの鍵はありません\n" +#, c-format +msgid "error reading the card: %s\n" +msgstr "カードの読み込みエラー: %s\n" + +#, c-format +msgid "Serial number of the card: %s\n" +msgstr "カードのシリアル番号: %s\n" + +msgid "Available keys:\n" +msgstr "利用可能な鍵:\n" + #, c-format msgid "rounded to %u bits\n" msgstr "%uビットに切り上げます\n" @@ -4196,11 +4264,15 @@ msgstr "*警告*: URI %s からデータを取れません: %s\n" #, c-format msgid "weird size for an encrypted session key (%d)\n" -msgstr "変な長さの暗号化済みセッション鍵 (%d)\n" +msgstr "変な長さの暗号化セッション鍵 (%d)\n" #, c-format -msgid "%s encrypted session key\n" -msgstr "%s 暗号化済みセッション鍵\n" +msgid "%s.%s encrypted session key\n" +msgstr "%s.%s 暗号化セッション鍵\n" + +#, c-format +msgid "encrypted with unknown algorithm %d.%s\n" +msgstr "不明のアルゴリズム%d.%sによる暗号化\n" #, c-format msgid "passphrase generated with unknown digest algorithm %d\n" @@ -4210,12 +4282,9 @@ msgstr "不明のダイジェスト・アルゴリズムで生成されたパス msgid "public key is %s\n" msgstr "公開鍵は%sです\n" -msgid "public key encrypted data: good DEK\n" -msgstr "公開鍵による暗号化済みデータ: 正しいDEKです\n" - #, c-format -msgid "encrypted with %u-bit %s key, ID %s, created %s\n" -msgstr "%u-ビット%s鍵, ID %s, 日付%sに暗号化されました\n" +msgid "encrypted with %s key, ID %s, created %s\n" +msgstr "%s鍵, ID %s, 作成日付%s により暗号化されました\n" #, c-format msgid " \"%s\"\n" @@ -4225,9 +4294,8 @@ msgstr " \"%s\"\n" msgid "encrypted with %s key, ID %s\n" msgstr "%s鍵, ID %sで暗号化されました\n" -#, c-format -msgid "public key decryption failed: %s\n" -msgstr "公開鍵の復号に失敗しました: %s\n" +msgid "WARNING: multiple plaintexts seen\n" +msgstr "*警告*: 複数のプレインテクストが見られます\n" #, c-format msgid "encrypted with %lu passphrases\n" @@ -4237,8 +4305,14 @@ msgid "encrypted with 1 passphrase\n" msgstr "1 個のパスフレーズで暗号化\n" #, c-format +msgid "public key decryption failed: %s\n" +msgstr "公開鍵の復号に失敗しました: %s\n" + +msgid "public key encrypted data: good DEK\n" +msgstr "公開鍵による暗号化データ: 正しいDEKです\n" + msgid "assuming %s encrypted data\n" -msgstr "%s暗号化済みデータを仮定\n" +msgstr "%s暗号化データを仮定\n" #, c-format msgid "IDEA cipher unavailable, optimistically attempting to use %s instead\n" @@ -4247,6 +4321,22 @@ msgstr "IDEA暗号方式は利用不能なので、楽天的ですが%sで代用 msgid "WARNING: message was not integrity protected\n" msgstr "*警告*: メッセージの完全性は保護されていません\n" +msgid "" +"Hint: If this message was created before the year 2003 it is\n" +"likely that this message is legitimate. This is because back\n" +"then integrity protection was not widely used.\n" +msgstr "" +"ヒント: もし、このメッセージが2003年以前に作成されたのであれば、\n" +"このメッセージはおそらく正当でしょう。当時、整合性の保護機能は\n" +"広く使われてはいなかったためです。\n" + +#, c-format +msgid "Use the option '%s' to decrypt anyway.\n" +msgstr "それでも復号するにはオプション '%s' を使います。\n" + +msgid "decryption forced to fail!\n" +msgstr "復号は強制的に失敗とされました!\n" + msgid "decryption okay\n" msgstr "復号に成功\n" @@ -4264,9 +4354,6 @@ msgstr "注意: 送信者は\"極秘とする\"ように求めています\n" msgid "original file name='%.*s'\n" msgstr "元のファイル名='%.*s'\n" -msgid "WARNING: multiple plaintexts seen\n" -msgstr "*警告*: 複数のプレインテクストが見られます\n" - msgid "standalone revocation - use \"gpg --import\" to apply\n" msgstr "スタンドアロン失効 - \"gpg --import\"を使って適用してください\n" @@ -4493,14 +4580,13 @@ msgstr "公開鍵のアルゴリズム%dは、取り扱えません\n" msgid "WARNING: potentially insecure symmetrically encrypted session key\n" msgstr "*警告*: 潜在的にセキュアでない共通鍵暗号化セッション鍵です\n" +msgid "Unknown critical signature notation: " +msgstr "不明なクリティカルな署名注釈: " + #, c-format msgid "subpacket of type %d has critical bit set\n" msgstr "型%dの下位パケットにクリティカル・ビットを発見\n" -#, c-format -msgid "problem with the agent: %s\n" -msgstr "エージェントに問題: %s\n" - msgid "Enter passphrase\n" msgstr "パスフレーズを入力\n" @@ -4581,27 +4667,6 @@ msgstr "この写真は正しいですか (y/N/q)? " msgid "unable to display photo ID!\n" msgstr "フォトIDが表示不能!\n" -msgid "No reason specified" -msgstr "理由は指定されていません" - -msgid "Key is superseded" -msgstr "鍵がとりかわっています" - -msgid "Key has been compromised" -msgstr "鍵(の信頼性)が損なわれています" - -msgid "Key is no longer used" -msgstr "鍵はもはや使われていません" - -msgid "User ID is no longer valid" -msgstr "ユーザIDがもはや有効でありません" - -msgid "reason for revocation: " -msgstr "失効理由: " - -msgid "revocation comment: " -msgstr "失効のコメント: " - #. TRANSLATORS: These are the allowed answers in lower and #. uppercase. Below you will find the matching strings which #. should be translated accordingly and the letter changed to @@ -5080,6 +5145,10 @@ msgstr "注意: 鍵 %s は失効済みです\n" msgid "bad key signature from key %s: %s (0x%02x, 0x%x)\n" msgstr "鍵%sによる不正な鍵への署名: %s (0x%02x, 0x%x)\n" +#, c-format +msgid "bad data signature from key %s: %s (0x%02x, 0x%x)\n" +msgstr "鍵%sによる不正なデータへの署名: %s (0x%02x, 0x%x)\n" + #, c-format msgid "assuming bad signature from key %s due to an unknown critical bit\n" msgstr "不明のクリティカル・ビットのため、鍵%sによる署名を不正とみなします\n" @@ -5122,8 +5191,8 @@ msgid "signing:" msgstr "署名:" #, c-format -msgid "%s encryption will be used\n" -msgstr "%s暗号化を使用します\n" +msgid "%s.%s encryption will be used\n" +msgstr "%s.%s 暗号化を使用します\n" msgid "key is not flagged as insecure - can't use it with the faked RNG!\n" msgstr "" @@ -5751,6 +5820,13 @@ msgstr "入力の%u行目が長すぎるか、LFがないようです\n" msgid "can't open fd %d: %s\n" msgstr "fd %dが開けません: %s\n" +msgid "WARNING: encrypting without integrity protection is dangerous\n" +msgstr "*警告*: 完全性保護なしでの暗号化は危険です\n" + +#, c-format +msgid "Hint: Do not use option %s\n" +msgstr "ヒント: オプション %s を使わない\n" + msgid "set debugging flags" msgstr "デバッグ・フラグを設定" @@ -6030,6 +6106,9 @@ msgstr "リーダのピンパッドを使わない" msgid "deny the use of admin card commands" msgstr "管理カード・コマンドの使用を拒否" +msgid "|LIST|Change the application priority to LIST" +msgstr "|LIST|アプリケーションの優先順位をLISTに変更します" + msgid "use variable length input for pinpad" msgstr "ピンパッドの可変長入力を使う" @@ -6385,17 +6464,6 @@ msgstr " (%d) 既存の鍵\n" msgid " (%d) Existing key from card\n" msgstr " (%d) カードに存在する鍵\n" -#, c-format -msgid "error reading the card: %s\n" -msgstr "カードの読み込みエラー: %s\n" - -#, c-format -msgid "Serial number of the card: %s\n" -msgstr "カードのシリアル番号: %s\n" - -msgid "Available keys:\n" -msgstr "利用可能な鍵:\n" - #, c-format msgid "Possible actions for a %s key:\n" msgstr "%s鍵に可能な操作:\n" @@ -7641,6 +7709,17 @@ msgstr "'%s' は無効なLDAP URLです\n" msgid "error accessing '%s': http status %u\n" msgstr "'%s'へアクセスのエラー: httpステイタス %u\n" +#, c-format +msgid "URL '%s' redirected to '%s' (%u)\n" +msgstr "URL'%s' は '%s' (%u) へリダイレクトされました\n" + +msgid "too many redirections\n" +msgstr "リダイレクトが多すぎます\n" + +#, c-format +msgid "redirection changed to '%s'\n" +msgstr "リダイレクトが'%s'に変更されました\n" + #, c-format msgid "error allocating memory: %s\n" msgstr "メモリの確保のエラー: %s\n" @@ -7736,13 +7815,6 @@ msgstr "'%s'の接続エラー: %s\n" msgid "error reading HTTP response for '%s': %s\n" msgstr "'%s'のHTTP応答の読み込みエラー: %s\n" -#, c-format -msgid "URL '%s' redirected to '%s' (%u)\n" -msgstr "URL'%s' は '%s' (%u) へリダイレクトされました\n" - -msgid "too many redirections\n" -msgstr "リダイレクトが多すぎます\n" - #, c-format msgid "error parsing OCSP response for '%s': %s\n" msgstr "'%s'に対するOCSP応答構文解析エラー: %s\n" @@ -8332,6 +8404,52 @@ msgstr "" "形式: gpg-check-pattern [オプション] パターンファイル\n" "パターンファイルに対して標準入力のパスフレーズを確認する\n" +#, c-format +msgid "%s card no. %s detected\n" +msgstr "%s カード番号 %sを検出しました\n" + +msgid "authenticate to the card" +msgstr "カードに対して認証します" + +msgid "send a reset to the card daemon" +msgstr "リセットをカードデーモンに送ります" + +msgid "change a private data object" +msgstr "プライベート・データオブジェクトを変更します" + +msgid "read a certificate from a data object" +msgstr "証明書をデータオブジェクトから読み出します" + +msgid "store a certificate to a data object" +msgstr "証明書をデータオブジェクトに保管します" + +msgid "store a private key to a data object" +msgstr "プライベート鍵をデータオブジェクトに保管します" + +msgid "Yubikey management commands" +msgstr "Yubikey管理コマンド" + +#~ msgid "male" +#~ msgstr "男" + +#~ msgid "female" +#~ msgstr "女" + +#~ msgid "unspecified" +#~ msgstr "無指定" + +#~ msgid "Sex ((M)ale, (F)emale or space): " +#~ msgstr "性別 ((M)男、(F)女、または空白): " + +#~ msgid "Warning: '%s' should be a long key ID or a fingerprint\n" +#~ msgstr "警告: '%s'は長い鍵IDかフィンガープリントであるべきです。\n" + +#~ msgid "error looking up: %s\n" +#~ msgstr "検索のエラー: %s\n" + +#~ msgid "Warning: %s appears in the keyring %d times\n" +#~ msgstr "警告: %sは鍵リングに%d回出現します\n" + #~ msgid "using \"http\" instead of \"https\"\n" #~ msgstr "\"http\" を \"https\" の代わりに使います\n" From 874bc970ba6ec243ff474ef090242e0f7be6a7bc Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Thu, 25 Apr 2019 14:49:49 +0900 Subject: [PATCH 050/169] scd: Add new command: KEYINFO. * scd/app-common.h (struct app_ctx_s): Add with_keygrip function. * scd/app-openpgp.c (do_with_keygrip): New. * scd/app.c (app_do_with_keygrip): New. * scd/command.c (cmd_keyinfo): New. (send_keyinfo): New. -- KEYGRIP_ACTION_LOOKUP is not yet used. It will be used for directly asking PK* action to determine an APP. Signed-off-by: NIIBE Yutaka --- scd/app-common.h | 10 +++++++ scd/app-openpgp.c | 54 +++++++++++++++++++++++++++++++++++ scd/app.c | 21 ++++++++++++++ scd/command.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++- scd/scdaemon.h | 2 ++ 5 files changed, 159 insertions(+), 1 deletion(-) diff --git a/scd/app-common.h b/scd/app-common.h index 6bb8eba50..8a25cda55 100644 --- a/scd/app-common.h +++ b/scd/app-common.h @@ -126,9 +126,18 @@ struct app_ctx_s { gpg_error_t (*check_pin) (app_t app, const char *keyidstr, gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg); + int (*with_keygrip) (app_t app, ctrl_t ctrl, int action, + const char *keygrip_str); } fnc; }; +enum + { + KEYGRIP_ACTION_SEND_DATA, + KEYGRIP_ACTION_WRITE_STATUS, + KEYGRIP_ACTION_LOOKUP + }; + /*-- app-help.c --*/ unsigned int app_help_count_bits (const unsigned char *a, size_t len); gpg_error_t app_help_get_keygrip_string_pk (const void *pk, size_t pklen, @@ -206,6 +215,7 @@ gpg_error_t app_change_pin (app_t app, ctrl_t ctrl, gpg_error_t app_check_pin (app_t app, ctrl_t ctrl, const char *keyidstr, gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg); +app_t app_do_with_keygrip (ctrl_t ctrl, int action, const char *keygrip_str); /*-- app-openpgp.c --*/ diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 02d388695..c1c90350b 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -4945,6 +4945,59 @@ do_check_pin (app_t app, const char *keyidstr, return verify_chv2 (app, pincb, pincb_arg); } +static int +do_with_keygrip (app_t app, ctrl_t ctrl, int action, const char *keygrip_str) +{ + int i; + + if (action == KEYGRIP_ACTION_LOOKUP) + { + if (keygrip_str == NULL) + return 1; + + for (i = 0; i < 3; i++) + if (app->app_local->pk[i].read_done + && !strcmp (keygrip_str, app->app_local->pk[i].keygrip_str)) + return 0; /* Found */ + + return 1; + } + else + { + char idbuf[50]; + char buf[65]; + int data = (action == KEYGRIP_ACTION_SEND_DATA); + + if (DIM (buf) < 2 * app->serialnolen + 1) + return 0; + + bin2hex (app->serialno, app->serialnolen, buf); + + if (keygrip_str == NULL) + { + for (i = 0; i < 3; i++) + if (app->app_local->pk[i].read_done) + { + sprintf (idbuf, "OPENPGP.%d", i+1); + send_keyinfo (ctrl, data, + app->app_local->pk[i].keygrip_str,buf, idbuf); + } + } + else + { + for (i = 0; i < 3; i++) + if (app->app_local->pk[i].read_done + && !strcmp (keygrip_str, app->app_local->pk[i].keygrip_str)) + { + sprintf (idbuf, "OPENPGP.%d", i+1); + send_keyinfo (ctrl, data, keygrip_str, buf, idbuf); + return 0; + } + } + + return 1; + } +} /* Show information about card capabilities. */ static void @@ -5327,6 +5380,7 @@ app_select_openpgp (app_t app) app->fnc.decipher = do_decipher; app->fnc.change_pin = do_change_pin; app->fnc.check_pin = do_check_pin; + app->fnc.with_keygrip = do_with_keygrip; } leave: diff --git a/scd/app.c b/scd/app.c index 1f3808fd4..4fe60cbbb 100644 --- a/scd/app.c +++ b/scd/app.c @@ -1290,3 +1290,24 @@ app_send_card_list (ctrl_t ctrl) } npth_mutex_unlock (&app_list_lock); } + +/* Execute an action for each app. ACTION can be one of: + KEYGRIP_ACTION_SEND_DATA: send data if KEYGRIP_STR matches + KEYGRIP_ACTION_WRITE_STATUS: write status if KEYGRIP_STR matches + KEYGRIP_ACTION_LOOKUP: Return matching APP + */ +app_t +app_do_with_keygrip (ctrl_t ctrl, int action, const char *keygrip_str) +{ + app_t a; + + npth_mutex_lock (&app_list_lock); + + for (a = app_top; a; a = a->next) + if (a->fnc.with_keygrip + && !a->fnc.with_keygrip (a, ctrl, action, keygrip_str)) + break; + + npth_mutex_unlock (&app_list_lock); + return a; +} diff --git a/scd/command.c b/scd/command.c index 28c739d93..33e1985b3 100644 --- a/scd/command.c +++ b/scd/command.c @@ -424,7 +424,7 @@ cmd_learn (assuan_context_t ctx, char *line) serial = app_get_serialno (ctrl->app_ctx); if (!serial) - return gpg_error (GPG_ERR_INV_VALUE); + return gpg_error (GPG_ERR_INV_VALUE); rc = assuan_write_status (ctx, "SERIALNO", serial); if (rc < 0) @@ -1757,6 +1757,76 @@ cmd_killscd (assuan_context_t ctx, char *line) } +static const char hlp_keyinfo[] = + "KEYINFO [--list] [--data] \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. Unless --data is given, the\n" + "information is returned as a status line using the format:\n" + "\n" + " KEYINFO T \n" + "\n" + "KEYGRIP is the keygrip.\n" + "\n" + "SERIALNO is an ASCII string with the serial number of the\n" + " smartcard. If the serial number is not known a single\n" + " dash '-' is used instead.\n" + "\n" + "IDSTR is the IDSTR used to distinguish keys on a smartcard. If it\n" + " is not known a dash is used instead.\n" + "\n" + "More information may be added in the future."; +static gpg_error_t +cmd_keyinfo (assuan_context_t ctx, char *line) +{ + int list_mode; + int opt_data; + int action; + char *keygrip_str; + ctrl_t ctrl = assuan_get_pointer (ctx); + + list_mode = has_option (line, "--list"); + opt_data = has_option (line, "--data"); + line = skip_options (line); + + if (list_mode) + keygrip_str = NULL; + else + keygrip_str = line; + + if (opt_data) + action = KEYGRIP_ACTION_SEND_DATA; + else + action = KEYGRIP_ACTION_WRITE_STATUS; + + app_do_with_keygrip (ctrl, action, keygrip_str); + + return 0; +} + +void +send_keyinfo (ctrl_t ctrl, int data, const char *keygrip_str, + const char *serialno, const char *idstr) +{ + char *string; + assuan_context_t ctx = ctrl->server_local->assuan_ctx; + + string = xtryasprintf ("%s T %s %s\n", keygrip_str, + serialno? serialno : "-", + idstr? idstr : "-"); + if (!string) + return; + + if (!data) + assuan_write_status (ctx, "KEYINFO", string); + else + assuan_send_data (ctx, string, strlen (string)); + + xfree (string); + return; +} /* Tell the assuan library about our commands */ static int @@ -1792,6 +1862,7 @@ register_commands (assuan_context_t ctx) { "DISCONNECT", cmd_disconnect,hlp_disconnect }, { "APDU", cmd_apdu, hlp_apdu }, { "KILLSCD", cmd_killscd, hlp_killscd }, + { "KEYINFO", cmd_keyinfo, hlp_keyinfo }, { NULL } }; int i, rc; diff --git a/scd/scdaemon.h b/scd/scdaemon.h index 73589ade8..230653b11 100644 --- a/scd/scdaemon.h +++ b/scd/scdaemon.h @@ -125,6 +125,8 @@ void send_status_info (ctrl_t ctrl, const char *keyword, ...) void send_status_direct (ctrl_t ctrl, const char *keyword, const char *args); gpg_error_t send_status_printf (ctrl_t ctrl, const char *keyword, const char *format, ...) GPGRT_ATTR_PRINTF(3,4); +void send_keyinfo (ctrl_t ctrl, int data, const char *keygrip_str, + const char *serialno, const char *idstr); void popup_prompt (void *opaque, int on); void send_client_notifications (app_t app, int removal); From 03df28b18b92b3fd3d2ba1000903c088dc5b0fcf Mon Sep 17 00:00:00 2001 From: Andre Heinecke Date: Mon, 29 Apr 2019 08:54:39 +0200 Subject: [PATCH 051/169] common,w32: Breakaway detached childs when in job * common/exechelp-w32.c (gnupg_spawn_process_detached): Add CREATE_BREAKAWAY_FROM_JOB creation flag if required. -- When the gpg process is assigned to a W32 "Job" the child processes are killed once the Job is finished. As we want our detached processes to linger e.g. gpg-agent the breakaway flag is required in that case. GnuPG-Bug-Id: T4333 Thanks to Jan Echternach for reporting this and providing a patch. Signed-off-by: Andre Heinecke --- common/exechelp-w32.c | 45 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/common/exechelp-w32.c b/common/exechelp-w32.c index 86b1d6869..ea158a33f 100644 --- a/common/exechelp-w32.c +++ b/common/exechelp-w32.c @@ -856,6 +856,7 @@ gnupg_spawn_process_detached (const char *pgmname, const char *argv[], STARTUPINFO si; int cr_flags; char *cmdline; + BOOL in_job = FALSE; /* We don't use ENVP. */ @@ -884,6 +885,50 @@ gnupg_spawn_process_detached (const char *pgmname, const char *argv[], | GetPriorityClass (GetCurrentProcess ()) | CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS); + + /* Check if we were spawned as part of a Job. + * In a job we need to add CREATE_BREAKAWAY_FROM_JOB + * to the cr_flags, otherwise our child processes + * are killed when we terminate. */ + if (!IsProcessInJob (GetCurrentProcess(), NULL, &in_job)) + { + log_error ("IsProcessInJob() failed: %s\n", w32_strerror (-1)); + in_job = FALSE; + } + + if (in_job) + { + /* Only try to break away from job if it is allowed, otherwise + * CreateProcess() would fail with an "Access is denied" error. */ + JOBOBJECT_EXTENDED_LIMIT_INFORMATION info; + if (!QueryInformationJobObject (NULL, JobObjectExtendedLimitInformation, + &info, sizeof info, NULL)) + { + log_error ("QueryInformationJobObject() failed: %s\n", + w32_strerror (-1)); + } + else if ((info.BasicLimitInformation.LimitFlags & + JOB_OBJECT_LIMIT_BREAKAWAY_OK)) + { + log_debug ("Using CREATE_BREAKAWAY_FROM_JOB flag\n"); + cr_flags |= CREATE_BREAKAWAY_FROM_JOB; + } + else if ((info.BasicLimitInformation.LimitFlags & + JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK)) + { + /* The child process should automatically detach from the job. */ + log_debug ("Not using CREATE_BREAKAWAY_FROM_JOB flag; " + "JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK is set\n"); + } + else + { + /* It seems that the child process must remain in the job. + * This is not necessarily an error, although it can cause premature + * termination of the child process when the job is closed. */ + log_debug ("Not using CREATE_BREAKAWAY_FROM_JOB flag\n"); + } + } + /* log_debug ("CreateProcess(detached), path='%s' cmdline='%s'\n", */ /* pgmname, cmdline); */ if (!CreateProcess (pgmname, /* Program to start. */ From 5f3864fb647237f862bbe7e26763dffa0e945202 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 30 Apr 2019 08:25:59 +0200 Subject: [PATCH 052/169] sm: Add yet inactive options to support authenticode * sm/gpgsm.c (opts): New options --authenticode and --attribute. * sm/gpgsm.h (opt): Add vars authenticode and attribute_list. * sm/sign.c (add_signed_attribute): New but inactive. (gpgsm_sign): Use new options. -- Because libksba 1.4 is not yet ready the new code is not yet active. Signed-off-by: Werner Koch --- g10/sig-check.c | 2 +- sm/gpgsm.c | 10 ++++ sm/gpgsm.h | 15 ++++++ sm/sign.c | 118 +++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 142 insertions(+), 3 deletions(-) diff --git a/g10/sig-check.c b/g10/sig-check.c index e7f97de65..4c172d692 100644 --- a/g10/sig-check.c +++ b/g10/sig-check.c @@ -1076,7 +1076,7 @@ check_signature_over_key_or_uid (ctrl_t ctrl, PKT_public_key *signer, * signature packet's data structure. * * TODO: add r_revoked here as well. It has the same problems as - * r_expiredate and r_expired and the cache. */ + * r_expiredate and r_expired and the cache [nw]. Which problems [wk]? */ int check_key_signature2 (ctrl_t ctrl, kbnode_t root, kbnode_t node, PKT_public_key *check_pk, diff --git a/sm/gpgsm.c b/sm/gpgsm.c index 020072a50..b9694b2e9 100644 --- a/sm/gpgsm.c +++ b/sm/gpgsm.c @@ -192,6 +192,8 @@ enum cmd_and_opt_values { oNoRandomSeedFile, oNoCommonCertsImport, oIgnoreCertExtension, + oAuthenticode, + oAttribute, oNoAutostart }; @@ -402,6 +404,8 @@ static ARGPARSE_OPTS opts[] = { ARGPARSE_s_n (oNoCommonCertsImport, "no-common-certs-import", "@"), ARGPARSE_s_s (oIgnoreCertExtension, "ignore-cert-extension", "@"), ARGPARSE_s_n (oNoAutostart, "no-autostart", "@"), + ARGPARSE_s_n (oAuthenticode, "authenticode", "@"), + ARGPARSE_s_s (oAttribute, "attribute", "@"), /* Command aliases. */ ARGPARSE_c (aListKeys, "list-key", "@"), @@ -1460,6 +1464,12 @@ main ( int argc, char **argv) add_to_strlist (&opt.ignored_cert_extensions, pargs.r.ret_str); break; + case oAuthenticode: opt.authenticode = 1; break; + + case oAttribute: + add_to_strlist (&opt.attributes, pargs.r.ret_str); + break; + case oNoAutostart: opt.autostart = 0; break; case oCompliance: diff --git a/sm/gpgsm.h b/sm/gpgsm.h index 7a5e4917d..c15d8dc4f 100644 --- a/sm/gpgsm.h +++ b/sm/gpgsm.h @@ -149,6 +149,21 @@ struct strlist_t ignored_cert_extensions; enum gnupg_compliance_mode compliance; + + /* Enable creation of authenticode signatures. */ + int authenticode; + + /* A list of extra attributes put into a signed data object. For a + * signed each attribute each string has the format: + * :s: + * and for an unsigned attribute + * :u: + * The OID is in the usual dotted decimal for. The HEX_OR_FILENAME + * is either a list of hex digits or a filename with the DER encoded + * value. A filename is detected by the presence of a slash in the + * HEX_OR_FILENAME. The actual value needs to be encoded as a SET OF + * attribute values. */ + strlist_t attributes; } opt; /* Debug values and macros. */ diff --git a/sm/sign.c b/sm/sign.c index 24ecad3d7..0604642b4 100644 --- a/sm/sign.c +++ b/sm/sign.c @@ -302,6 +302,99 @@ add_certificate_list (ctrl_t ctrl, ksba_cms_t cms, ksba_cert_t cert) } +#if KSBA_VERSION_NUMBER >= 0x010400 && 0 /* 1.4.0 */ +static gpg_error_t +add_signed_attribute (ksba_cms_t cms, const char *attrstr) +{ + gpg_error_t err; + char **fields = NULL; + const char *s; + int i; + unsigned char *der = NULL; + size_t derlen; + + fields = strtokenize (attrstr, ":"); + if (!fields) + { + err = gpg_error_from_syserror (); + log_error ("strtokenize failed: %s\n", gpg_strerror (err)); + goto leave; + } + + for (i=0; fields[i]; i++) + ; + if (i != 3) + { + err = gpg_error (GPG_ERR_SYNTAX); + log_error ("invalid attribute specification '%s': %s\n", + attrstr, i < 3 ? "not enough fields":"too many fields"); + goto leave; + } + if (!ascii_strcasecmp (fields[1], "u")) + { + err = 0; + goto leave; /* Skip unsigned attruibutes. */ + } + if (ascii_strcasecmp (fields[1], "s")) + { + err = gpg_error (GPG_ERR_SYNTAX); + log_error ("invalid attribute specification '%s': %s\n", + attrstr, "type is not 's' or 'u'"); + goto leave; + } + /* Check that the OID is valid. */ + err = ksba_oid_from_str (fields[0], &der, &derlen); + if (err) + { + log_error ("invalid attribute specification '%s': %s\n", + attrstr, gpg_strerror (err)); + goto leave; + } + xfree (der); + der = NULL; + + if (strchr (fields[2], '/')) + { + /* FIXME: read from file. */ + } + else /* Directly given in hex. */ + { + for (i=0, s = fields[2]; hexdigitp (s); s++, i++) + ; + if (*s || !i || (i&1)) + { + log_error ("invalid attribute specification '%s': %s\n", + attrstr, "invalid hex encoding of the data"); + err = gpg_error (GPG_ERR_SYNTAX); + goto leave; + } + der = xtrystrdup (fields[2]); + if (!der) + { + err = gpg_error_from_syserror (); + log_error ("malloc failed: %s\n", gpg_strerror (err)); + goto leave; + } + for (s=fields[2], derlen=0; s[0] && s[1]; s += 2) + der[derlen++] = xtoi_2 (s); + } + + /* Store the data in the CMS object for all signers. */ + err = ksba_cms_add_attribute (cms, -1, fields[0], 0, der, derlen); + if (err) + { + log_error ("invalid attribute specification '%s': %s\n", + attrstr, gpg_strerror (err)); + goto leave; + } + + leave: + xfree (der); + xfree (fields); + return err; +} +#endif /*ksba >= 1.4.0 */ + /* Perform a sign operation. @@ -377,10 +470,17 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, goto leave; } - /* We are going to create signed data with data as encap. content */ + /* We are going to create signed data with data as encap. content. + * In authenticode mode we use spcIndirectDataContext instead. */ err = ksba_cms_set_content_type (cms, 0, KSBA_CT_SIGNED_DATA); if (!err) - err = ksba_cms_set_content_type (cms, 1, KSBA_CT_DATA); + err = ksba_cms_set_content_type + (cms, 1, +#if KSBA_VERSION_NUMBER >= 0x010400 && 0 + opt.authenticode? KSBA_CT_SPC_IND_DATA_CTX : +#endif + KSBA_CT_DATA + ); if (err) { log_debug ("ksba_cms_set_content_type failed: %s\n", @@ -643,6 +743,20 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, } } + /* We can add signed attributes only when build against libksba 1.4. */ +#if KSBA_VERSION_NUMBER >= 0x010400 && 0 /* 1.4.0 */ + { + strlist_t sl; + + for (sl = opt.attributes; sl; sl = sl->next) + if ((err = add_signed_attribute (cms, sl->d))) + goto leave; + } +#else + log_info ("Note: option --attribute is ignored by this version\n"); +#endif /*ksba >= 1.4.0 */ + + /* We need to write at least a minimal list of our capabilities to try to convince some MUAs to use 3DES and not the crippled RC2. Our list is: From 5ed227589288503db6dee6c4eeb36bc73b79d0de Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 30 Apr 2019 08:26:59 +0200 Subject: [PATCH 053/169] tools: Some changes to the ccidmon.c debug helper. -- --- tools/ccidmon.c | 47 +++++++++++++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/tools/ccidmon.c b/tools/ccidmon.c index d61bb3c64..4e99da54d 100644 --- a/tools/ccidmon.c +++ b/tools/ccidmon.c @@ -64,9 +64,10 @@ static int any_error; struct { int is_bi; + char timestamp[20]; char address[50]; int count; - char data[2000]; + char data[16000]; } databuffer; @@ -576,7 +577,10 @@ flush_data (void) return; if (verbose) - printf ("Address: %s\n", databuffer.address); + { + printf ("Timestamp: %s\n", databuffer.timestamp); + printf ("Address..: %s\n", databuffer.address); + } if (databuffer.is_bi) { print_r2p (databuffer.data, databuffer.count); @@ -590,7 +594,8 @@ flush_data (void) } static void -collect_data (char *hexdata, const char *address, unsigned int lineno) +collect_data (char *hexdata, const char *timestamp, + const char *address, unsigned int lineno) { size_t length; int is_bi; @@ -602,6 +607,9 @@ collect_data (char *hexdata, const char *address, unsigned int lineno) if (databuffer.is_bi != is_bi || strcmp (databuffer.address, address)) flush_data (); databuffer.is_bi = is_bi; + if (strlen (timestamp) >= sizeof databuffer.timestamp) + die ("timestamp field too long"); + strcpy (databuffer.timestamp, timestamp); if (strlen (address) >= sizeof databuffer.address) die ("address field too long"); strcpy (databuffer.address, address); @@ -627,7 +635,7 @@ collect_data (char *hexdata, const char *address, unsigned int lineno) if (length >= sizeof (databuffer.data)) { - err ("too much data at line %u - can handle only up to % bytes", + err ("too much data at line %u - can handle only up to %zu bytes", lineno, sizeof (databuffer.data)); break; } @@ -641,43 +649,50 @@ static void parse_line (char *line, unsigned int lineno) { char *p; - char *event_type, *address, *data, *status, *datatag; + char *timestamp, *event_type, *address, *data, *status, *datatag; + + if (*line == '#' || !*line) + return; if (debug) printf ("line[%u] ='%s'\n", lineno, line); p = strtok (line, " "); if (!p) - die ("invalid line %d (no URB)"); - p = strtok (NULL, " "); - if (!p) - die ("invalid line %d (no timestamp)"); + die ("invalid line %d (no URB)", lineno); + timestamp = strtok (NULL, " "); + if (!timestamp) + die ("invalid line %d (no timestamp)", lineno); event_type = strtok (NULL, " "); if (!event_type) - die ("invalid line %d (no event type)"); + die ("invalid line %d (no event type)", lineno); address = strtok (NULL, " "); if (!address) - die ("invalid line %d (no address"); + die ("invalid line %d (no address", lineno); if (usb_bus || usb_dev) { int bus, dev; p = strchr (address, ':'); if (!p) - die ("invalid line %d (invalid address"); + die ("invalid line %d (invalid address", lineno); p++; bus = atoi (p); p = strchr (p, ':'); if (!p) - die ("invalid line %d (invalid address"); + die ("invalid line %d (invalid address", lineno); p++; dev = atoi (p); if ((usb_bus && usb_bus != bus) || (usb_dev && usb_dev != dev)) return; /* We don't want that one. */ } - if (*address != 'B' || (address[1] != 'o' && address[1] != 'i')) - return; /* We only want block in and block out. */ + if (*address == 'B' && (address[1] == 'o' || address[1] == 'i')) + ; /* We want block ind and out. */ + else if (*address == 'C' && (address[1] == 'o' || address[1] == 'i')) + ; /* We want control ind and out. */ + else + return; /* But nothing else. */ status = strtok (NULL, " "); if (!status) return; @@ -692,7 +707,7 @@ parse_line (char *line, unsigned int lineno) if (datatag && *datatag == '=') { data = strtok (NULL, ""); - collect_data (data?data:"", address, lineno); + collect_data (data?data:"", timestamp, address, lineno); } } From bd6ecbb8f8e92fe4a7fed40fcf470eb83bda0927 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 3 May 2019 10:53:34 +0200 Subject: [PATCH 054/169] gpg: Use just the addrspec from the Signer's UID. * g10/parse-packet.c (parse_signature): Take only rthe addrspec from a Signer's UID subpacket. -- This is to address a problem in the currentr OpenKeychain which put the entire UID into the subpacket. For example our Tofu code can only use the addrspec and not the entire UID. Reported-by: Wiktor Kwapisiewicz Signed-off-by: Werner Koch --- g10/parse-packet.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/g10/parse-packet.c b/g10/parse-packet.c index 5b4b1c900..f67edc547 100644 --- a/g10/parse-packet.c +++ b/g10/parse-packet.c @@ -35,6 +35,7 @@ #include "main.h" #include "../common/i18n.h" #include "../common/host2net.h" +#include "../common/mbox-util.h" /* Maximum length of packets to avoid excessive memory allocation. */ @@ -2118,12 +2119,20 @@ parse_signature (IOBUF inp, int pkttype, unsigned long pktlen, p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_SIGNERS_UID, &len); if (p && len) { + char *mbox; + sig->signers_uid = try_make_printable_string (p, len, 0); if (!sig->signers_uid) { rc = gpg_error_from_syserror (); goto leave; } + mbox = mailbox_from_userid (sig->signers_uid, 0); + if (mbox) + { + xfree (sig->signers_uid); + sig->signers_uid = mbox; + } } p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_NOTATION, NULL); From c9fa28bfad297b17e76341ffb40383ce92da5d44 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 3 May 2019 14:24:07 +0200 Subject: [PATCH 055/169] common: In private key mode write "Key:" always last in name-value. * common/name-value.c (nvc_write): Take care of Key. Factor some code out to ... (write_one_entry): new. -- The key item is in general not manual editable thus we put it at the end of a file. Signed-off-by: Werner Koch --- common/name-value.c | 51 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 39 insertions(+), 12 deletions(-) diff --git a/common/name-value.c b/common/name-value.c index 5094acd03..89fd060c8 100644 --- a/common/name-value.c +++ b/common/name-value.c @@ -778,29 +778,56 @@ nvc_parse_private_key (nvc_t *result, int *errlinep, estream_t stream) } +/* Helper fpr nvc_write. */ +static gpg_error_t +write_one_entry (nve_t entry, estream_t stream) +{ + gpg_error_t err; + strlist_t sl; + + if (entry->name) + es_fputs (entry->name, stream); + + err = assert_raw_value (entry); + if (err) + return err; + + for (sl = entry->raw_value; sl; sl = sl->next) + es_fputs (sl->d, stream); + + if (es_ferror (stream)) + return my_error_from_syserror (); + + return 0; +} + + /* Write a representation of PK to STREAM. */ gpg_error_t nvc_write (nvc_t pk, estream_t stream) { - gpg_error_t err; + gpg_error_t err = 0; nve_t entry; - strlist_t s; + nve_t keyentry = NULL; for (entry = pk->first; entry; entry = entry->next) { - if (entry->name) - es_fputs (entry->name, stream); + if (pk->private_key_mode + && entry->name && !ascii_strcasecmp (entry->name, "Key:")) + { + if (!keyentry) + keyentry = entry; + continue; + } - err = assert_raw_value (entry); + err = write_one_entry (entry, stream); if (err) return err; - - for (s = entry->raw_value; s; s = s->next) - es_fputs (s->d, stream); - - if (es_ferror (stream)) - return my_error_from_syserror (); } - return 0; + /* In private key mode we write the Key always last. */ + if (keyentry) + err = write_one_entry (keyentry, stream); + + return err; } From bdf252e76ada0056bec2ee7940255f32552328c5 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 3 May 2019 15:54:54 +0200 Subject: [PATCH 056/169] agent: Put Token lines into the key files. * agent/findkey.c (write_extended_private_key): Add args serialno and keyref. Write a Token line if that does not yet exist. (agent_write_private_key): Add args serialno and keyref and change all callers. (agent_write_shadow_key): Skip leading spaces. * agent/keyformat.txt: Improve extended key format docs. -- Noet that the extended key forma is the defaqult in 2.3. This patch is a first step to better handle tokens which carray the same key. Signed-off-by: Werner Koch --- agent/agent.h | 3 +- agent/command-ssh.c | 2 +- agent/command.c | 5 ++-- agent/cvt-openpgp.c | 5 ++-- agent/findkey.c | 62 +++++++++++++++++++++++++++++++++++------ agent/genkey.c | 2 +- agent/keyformat.txt | 66 ++++++++++++++++++++++++++++++++++---------- agent/protect-tool.c | 5 +++- agent/protect.c | 3 +- 9 files changed, 121 insertions(+), 32 deletions(-) diff --git a/agent/agent.h b/agent/agent.h index 0f804cd8b..b7eacf471 100644 --- a/agent/agent.h +++ b/agent/agent.h @@ -414,7 +414,8 @@ void start_command_handler_ssh (ctrl_t, gnupg_fd_t); gpg_error_t agent_modify_description (const char *in, const char *comment, const gcry_sexp_t key, char **result); int agent_write_private_key (const unsigned char *grip, - const void *buffer, size_t length, int force); + const void *buffer, size_t length, int force, + const char *serialno, const char *keyref); gpg_error_t agent_key_from_file (ctrl_t ctrl, const char *cache_nonce, const char *desc_text, diff --git a/agent/command-ssh.c b/agent/command-ssh.c index ebd28ab5a..727bb9b94 100644 --- a/agent/command-ssh.c +++ b/agent/command-ssh.c @@ -3142,7 +3142,7 @@ ssh_identity_register (ctrl_t ctrl, ssh_key_type_spec_t *spec, goto out; /* Store this key to our key storage. */ - err = agent_write_private_key (key_grip_raw, buffer, buffer_n, 0); + err = agent_write_private_key (key_grip_raw, buffer, buffer_n, 0, NULL, NULL); if (err) goto out; diff --git a/agent/command.c b/agent/command.c index 082ed4144..9bb6fa306 100644 --- a/agent/command.c +++ b/agent/command.c @@ -2255,10 +2255,11 @@ cmd_import_key (assuan_context_t ctx, char *line) err = agent_protect (key, passphrase, &finalkey, &finalkeylen, ctrl->s2k_count, -1); if (!err) - err = agent_write_private_key (grip, finalkey, finalkeylen, force); + err = agent_write_private_key (grip, finalkey, finalkeylen, force, + NULL, NULL); } else - err = agent_write_private_key (grip, key, realkeylen, force); + err = agent_write_private_key (grip, key, realkeylen, force, NULL, NULL); leave: gcry_sexp_release (openpgp_sexp); diff --git a/agent/cvt-openpgp.c b/agent/cvt-openpgp.c index 06cd1c840..42052d48e 100644 --- a/agent/cvt-openpgp.c +++ b/agent/cvt-openpgp.c @@ -1067,7 +1067,8 @@ convert_from_openpgp_native (ctrl_t ctrl, if (!agent_protect (*r_key, passphrase, &protectedkey, &protectedkeylen, ctrl->s2k_count, -1)) - agent_write_private_key (grip, protectedkey, protectedkeylen, 1); + agent_write_private_key (grip, protectedkey, protectedkeylen, 1, + NULL, NULL); xfree (protectedkey); } else @@ -1076,7 +1077,7 @@ convert_from_openpgp_native (ctrl_t ctrl, agent_write_private_key (grip, *r_key, gcry_sexp_canon_len (*r_key, 0, NULL,NULL), - 1); + 1, NULL, NULL); } } diff --git a/agent/findkey.c b/agent/findkey.c index 89a18fa9e..157870e17 100644 --- a/agent/findkey.c +++ b/agent/findkey.c @@ -55,12 +55,14 @@ struct try_unprotect_arg_s /* Note: Ownership of FNAME and FP are moved to this function. */ static gpg_error_t write_extended_private_key (char *fname, estream_t fp, int update, - const void *buf, size_t len) + const void *buf, size_t len, + const char *serialno, const char *keyref) { gpg_error_t err; nvc_t pk = NULL; gcry_sexp_t key = NULL; int remove = 0; + char *token = NULL; if (update) { @@ -93,6 +95,37 @@ write_extended_private_key (char *fname, estream_t fp, int update, if (err) goto leave; + /* If requested write a Token line. */ + if (serialno && keyref) + { + nve_t item; + const char *s; + + token = strconcat (serialno, " ", keyref, NULL); + if (!token) + { + err = gpg_error_from_syserror (); + goto leave; + } + + /* fixme: the strcmp should compare only the first two strings. */ + for (item = nvc_lookup (pk, "Token:"); + item; + item = nve_next_value (item, "Token:")) + if ((s = nve_value (item)) && !strcmp (s, token)) + break; + if (!item) + { + /* No token or no token with that value exists. Add a new + * one so that keys which have been stored on several cards + * are well supported. */ + err = nvc_add (pk, "Token:", token); + if (err) + goto leave; + } + } + + err = es_fseek (fp, 0, SEEK_SET); if (err) goto leave; @@ -132,15 +165,18 @@ write_extended_private_key (char *fname, estream_t fp, int update, xfree (fname); gcry_sexp_release (key); nvc_release (pk); + xfree (token); return err; } /* Write an S-expression formatted key to our key storage. With FORCE - passed as true an existing key with the given GRIP will get - overwritten. */ + * passed as true an existing key with the given GRIP will get + * overwritten. If SERIALNO and KEYREF are give an a Token line is added to + * th key if the extended format ist used. */ int agent_write_private_key (const unsigned char *grip, - const void *buffer, size_t length, int force) + const void *buffer, size_t length, int force, + const char *serialno, const char *keyref) { char *fname; estream_t fp; @@ -208,17 +244,20 @@ agent_write_private_key (const unsigned char *grip, if (first != '(') { /* Key is already in the extended format. */ - return write_extended_private_key (fname, fp, 1, buffer, length); + return write_extended_private_key (fname, fp, 1, buffer, length, + serialno, keyref); } if (first == '(' && opt.enable_extended_key_format) { /* Key is in the old format - but we want the extended format. */ - return write_extended_private_key (fname, fp, 0, buffer, length); + return write_extended_private_key (fname, fp, 0, buffer, length, + serialno, keyref); } } if (opt.enable_extended_key_format) - return write_extended_private_key (fname, fp, 0, buffer, length); + return write_extended_private_key (fname, fp, 0, buffer, length, + serialno, keyref); if (es_fwrite (buffer, length, 1, fp) != 1) { @@ -1580,6 +1619,13 @@ agent_write_shadow_key (const unsigned char *grip, unsigned char *shdkey; size_t len; + /* Just in case some caller did not parse the stuff correctly, skip + * leading spaces. */ + while (spacep (serialno)) + serialno++; + while (spacep (keyid)) + keyid++; + shadow_info = make_shadow_info (serialno, keyid); if (!shadow_info) return gpg_error_from_syserror (); @@ -1593,7 +1639,7 @@ agent_write_shadow_key (const unsigned char *grip, } len = gcry_sexp_canon_len (shdkey, 0, NULL, NULL); - err = agent_write_private_key (grip, shdkey, len, force); + err = agent_write_private_key (grip, shdkey, len, force, serialno, keyid); xfree (shdkey); if (err) log_error ("error writing key: %s\n", gpg_strerror (err)); diff --git a/agent/genkey.c b/agent/genkey.c index d5c80d0aa..84342f9ea 100644 --- a/agent/genkey.c +++ b/agent/genkey.c @@ -68,7 +68,7 @@ store_key (gcry_sexp_t private, const char *passphrase, int force, buf = p; } - rc = agent_write_private_key (grip, buf, len, force); + rc = agent_write_private_key (grip, buf, len, force, NULL, NULL); xfree (buf); return rc; } diff --git a/agent/keyformat.txt b/agent/keyformat.txt index c7426db9d..058fb0143 100644 --- a/agent/keyformat.txt +++ b/agent/keyformat.txt @@ -18,7 +18,8 @@ hexadecimal representation of the keygrip[2] and suffixed with ".key". * Extended Private Key Format -GnuPG 2.3+ will use a new format to store private keys that is both +** Overview +GnuPG 2.3+ uses a new format to store private keys that is both more flexible and easier to read and edit by human beings. The new format stores name,value-pairs using the common mail and http header convention. Example (here indented with two spaces): @@ -28,6 +29,8 @@ convention. Example (here indented with two spaces): Use-for-ssh: yes OpenSSH-cert: long base64 encoded string wrapped so that this key file can be easily edited with a standard editor. + Token: D2760001240102000005000011730000 OPENPGP.1 + Token: FF020001008A77C1 PIV.9C Key: (shadowed-private-key (rsa (n #00AA1AD2A55FD8C8FDE9E1941772D9CC903FA43B268CB1B5A1BAFDC900 @@ -52,33 +55,66 @@ Keys in the extended format can be recognized by looking at the first byte of the file. If it starts with a '(' it is a naked S-expression, otherwise it is a key in extended format. -** Names - +*** Names A name must start with a letter and end with a colon. Valid characters are all ASCII letters, numbers and the hyphen. Comparison of names is done case insensitively. Names may be used several times -to represent an array of values. - -The name "Key:" is special in that it may occur only once and the -associated value holds the actual S-expression with the cryptographic -key. The S-expression is formatted using the 'Advanced Format' -(GCRYSEXP_FMT_ADVANCED) that avoids non-printable characters so that -the file can be easily inspected and edited. See section 'Private Key -Format' below for details. - -** Values +to represent an array of values. Note that the name "Key" is special +in that it is madandory must occur only once. +*** Values Values are UTF-8 encoded strings. Values can be wrapped at any point, and continued in the next line indicated by leading whitespace. A continuation line with one leading space does not introduce a blank so that the lines can be effectively concatenated. A blank line as part of a continuation line encodes a newline. -** Comments - +*** Comments Lines containing only whitespace, and lines starting with whitespace followed by '#' are considered to be comments and are ignored. +** Well defined names + +*** Description +This is a human readable string describing the key. + +*** Key +The name "Key" is special in that it is mandatory and must occur only +once. The associated value holds the actual S-expression with the +cryptographic key. The S-expression is formatted using the 'Advanced +Format' (GCRYSEXP_FMT_ADVANCED) that avoids non-printable characters +so that the file can be easily inspected and edited. See section +'Private Key Format' below for details. + +*** Label +This is a short human readable description for the key which can be +used by the software to describe the key in a user interface. For +example as part of the description in a prompt for a PIN or +passphrase. It is often used instead of a comment element preent in +the S-expression of the "Key" item. + +*** OpenSSH-cert +This takes a base64 encoded string wrapped so that this +key file can be easily edited with a standard editor. Several of such +items can be used. + +*** Token +If such an item exists it overrides the info given by the "shadow" +parameter in the S-expression. Using this item makes it possible to +describe a key which is stored on several tokens and also makes it +easy to update this info using a standard editor. The syntax is the +same as with the "shadow" parameter: + +- Serialnumber of the token +- Key reference from the token in full format (e.g. "OpenPGP.2") +- An optional fixed length of the PIN. + +*** Use-for-ssh +If given and the value is "yes" or "1" the key is allowed for use by +gpg-agent's ssh-agent implementation. This is thus the same as +putting the keygrip into the 'sshcontrol' file. Only one such item +should exist. + * Private Key Format ** Unprotected Private Key Format diff --git a/agent/protect-tool.c b/agent/protect-tool.c index ec7b47695..30d78cd43 100644 --- a/agent/protect-tool.c +++ b/agent/protect-tool.c @@ -799,12 +799,15 @@ agent_askpin (ctrl_t ctrl, * to stdout. */ int agent_write_private_key (const unsigned char *grip, - const void *buffer, size_t length, int force) + const void *buffer, size_t length, int force, + const char *serialno, const char *keyref) { char hexgrip[40+4+1]; char *p; (void)force; + (void)serialno; + (void)keyref; bin2hex (grip, 20, hexgrip); strcpy (hexgrip+40, ".key"); diff --git a/agent/protect.c b/agent/protect.c index 61fb8f45d..c7fb773e1 100644 --- a/agent/protect.c +++ b/agent/protect.c @@ -1667,7 +1667,8 @@ agent_get_shadow_info (const unsigned char *shadowkey, R_HEXSN and the Id string as a malloced string at R_IDSTR. On error an error code is returned and NULL is stored at the result parameters addresses. If the serial number or the ID string is not - required, NULL may be passed for them. */ + required, NULL may be passed for them. Note that R_PINLEN is + currently not used by any caller. */ gpg_error_t parse_shadow_info (const unsigned char *shadow_info, char **r_hexsn, char **r_idstr, int *r_pinlen) From f43560a4d6cd44824654989ae043b346910e7a43 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 3 May 2019 16:15:04 +0200 Subject: [PATCH 057/169] doc: Minor doc fix to dirmngr. -- Reported-by: dkg --- doc/dirmngr.texi | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/doc/dirmngr.texi b/doc/dirmngr.texi index f5910a884..eb49ad96c 100644 --- a/doc/dirmngr.texi +++ b/doc/dirmngr.texi @@ -251,7 +251,7 @@ The option @option{--use-tor} switches Dirmngr and thus GnuPG into ``Tor mode'' to route all network access via Tor (an anonymity network). Certain other features are disabled in this mode. The effect of @option{--use-tor} cannot be overridden by any other command -or even be reloading gpg-agent. The use of @option{--no-use-tor} +or even by reloading dirmngr. The use of @option{--no-use-tor} disables the use of Tor. The default is to use Tor if it is available on startup or after reloading dirmngr. @@ -1178,5 +1178,3 @@ as a binary blob. @c used for this. The first one starts a search and the second one is @c used to retrieve certificate after certificate. @c - - From c856ee7312c9eeb7d79a30189a49f70986420364 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Tue, 7 May 2019 09:41:14 +0900 Subject: [PATCH 058/169] scd: Support direct use of app with PKSIGN/PKAUTH/PKDECRYPT. * scd/command.c (cmd_pksign, cmd_pkauth, cmd_pkdecrypt): When length of keyidstr is 40, it is considered as a keygrip for direct use. Signed-off-by: NIIBE Yutaka --- scd/command.c | 87 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 76 insertions(+), 11 deletions(-) diff --git a/scd/command.c b/scd/command.c index 33e1985b3..3bfc1a5db 100644 --- a/scd/command.c +++ b/scd/command.c @@ -757,6 +757,8 @@ cmd_pksign (assuan_context_t ctx, char *line) size_t outdatalen; char *keyidstr; int hash_algo; + app_t app; + int direct = 0; if (has_option (line, "--hash=rmd160")) hash_algo = GCRY_MD_RMD160; @@ -789,11 +791,30 @@ cmd_pksign (assuan_context_t ctx, char *line) if (!keyidstr) return out_of_core (); - rc = app_sign (ctrl->app_ctx, ctrl, - keyidstr, hash_algo, - pin_cb, ctx, - ctrl->in_data.value, ctrl->in_data.valuelen, - &outdata, &outdatalen); + /* When it's a keygrip, we directly use APP, with no change of + ctrl->app_ctx. */ + if (strlen (keyidstr) == 40) + { + app = app_do_with_keygrip (ctrl, KEYGRIP_ACTION_LOOKUP, keyidstr); + direct = 1; + } + else + app = ctrl->app_ctx; + + if (app) + { + if (direct) + app->ref_count++; + rc = app_sign (app, ctrl, + keyidstr, hash_algo, + pin_cb, ctx, + ctrl->in_data.value, ctrl->in_data.valuelen, + &outdata, &outdatalen); + if (direct) + app->ref_count--; + } + else + rc = gpg_error (GPG_ERR_NO_SECKEY); xfree (keyidstr); if (rc) @@ -822,6 +843,8 @@ cmd_pkauth (assuan_context_t ctx, char *line) unsigned char *outdata; size_t outdatalen; char *keyidstr; + app_t app; + int direct = 0; if ((rc = open_card (ctrl))) return rc; @@ -836,9 +859,29 @@ cmd_pkauth (assuan_context_t ctx, char *line) if (!keyidstr) return out_of_core (); - rc = app_auth (ctrl->app_ctx, ctrl, keyidstr, pin_cb, ctx, - ctrl->in_data.value, ctrl->in_data.valuelen, - &outdata, &outdatalen); + /* When it's a keygrip, we directly use APP, with no change of + ctrl->app_ctx. */ + if (strlen (keyidstr) == 40) + { + app = app_do_with_keygrip (ctrl, KEYGRIP_ACTION_LOOKUP, keyidstr); + direct = 1; + } + else + app = ctrl->app_ctx; + + if (app) + { + if (direct) + app->ref_count++; + rc = app_auth (app, ctrl, keyidstr, pin_cb, ctx, + ctrl->in_data.value, ctrl->in_data.valuelen, + &outdata, &outdatalen); + if (direct) + app->ref_count--; + } + else + rc = gpg_error (GPG_ERR_NO_SECKEY); + xfree (keyidstr); if (rc) { @@ -867,6 +910,8 @@ cmd_pkdecrypt (assuan_context_t ctx, char *line) size_t outdatalen; char *keyidstr; unsigned int infoflags; + app_t app; + int direct = 0; if ((rc = open_card (ctrl))) return rc; @@ -874,9 +919,29 @@ cmd_pkdecrypt (assuan_context_t ctx, char *line) keyidstr = xtrystrdup (line); if (!keyidstr) return out_of_core (); - rc = app_decipher (ctrl->app_ctx, ctrl, keyidstr, pin_cb, ctx, - ctrl->in_data.value, ctrl->in_data.valuelen, - &outdata, &outdatalen, &infoflags); + + /* When it's a keygrip, we directly use APP, with no change of + ctrl->app_ctx. */ + if (strlen (keyidstr) == 40) + { + app = app_do_with_keygrip (ctrl, KEYGRIP_ACTION_LOOKUP, keyidstr); + direct = 1; + } + else + app = ctrl->app_ctx; + + if (app) + { + if (direct) + app->ref_count++; + rc = app_decipher (ctrl->app_ctx, ctrl, keyidstr, pin_cb, ctx, + ctrl->in_data.value, ctrl->in_data.valuelen, + &outdata, &outdatalen, &infoflags); + if (direct) + app->ref_count--; + } + else + rc = gpg_error (GPG_ERR_NO_SECKEY); xfree (keyidstr); if (rc) From b5985d0ca21ca376f22c050857bfda05592cebef Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 7 May 2019 11:01:15 +0200 Subject: [PATCH 059/169] common: New functions nvc_delete_named and nvc_get_string. * common/name-value.c (nvc_delete_named): New. (nvc_get_string): New. Signed-off-by: Werner Koch --- common/name-value.c | 34 ++++++++++++++++++++++++++++++++++ common/name-value.h | 6 ++++++ common/t-name-value.c | 25 +++++++++++++++++++++++++ 3 files changed, 65 insertions(+) diff --git a/common/name-value.c b/common/name-value.c index 89fd060c8..989a5b111 100644 --- a/common/name-value.c +++ b/common/name-value.c @@ -514,6 +514,21 @@ nvc_delete (nvc_t pk, nve_t entry) nve_release (entry, pk->private_key_mode); } + +/* Delete the entries with NAME from PK. */ +void +nvc_delete_named (nvc_t pk, const char *name) +{ + nve_t e; + + if (!valid_name (name)) + return; + + while ((e = nvc_lookup (pk, name))) + nvc_delete (pk, e); +} + + /* Lookup and iteration. */ @@ -563,6 +578,25 @@ nve_next_value (nve_t entry, const char *name) return NULL; } + +/* Return the string for the first entry in NVC with NAME. If an + * entry with NAME is missing in NVC or its value is the empty string + * NULL is returned. Note that the The returned string is a pointer + * into NVC. */ +const char * +nvc_get_string (nvc_t nvc, const char *name) +{ + nve_t item; + + if (!nvc) + return NULL; + item = nvc_lookup (nvc, name); + if (!item) + return NULL; + return nve_value (item); +} + + /* Private key handling. */ diff --git a/common/name-value.h b/common/name-value.h index 5c24b8db1..a6283a649 100644 --- a/common/name-value.h +++ b/common/name-value.h @@ -72,6 +72,9 @@ nve_t nve_next (nve_t entry); /* Get the next entry with the given name. */ nve_t nve_next_value (nve_t entry, const char *name); +/* Return the string for the first entry in NVC with NAME or NULL. */ +const char *nvc_get_string (nvc_t nvc, const char *name); + /* Adding and modifying values. */ @@ -88,6 +91,9 @@ gpg_error_t nvc_set (nvc_t pk, const char *name, const char *value); /* Delete the given entry from PK. */ void nvc_delete (nvc_t pk, nve_t pke); +/* Delete the entries with NAME from PK. */ +void nvc_delete_named (nvc_t pk, const char *name); + /* Private key handling. */ diff --git a/common/t-name-value.c b/common/t-name-value.c index 57f685ffb..13a383ddb 100644 --- a/common/t-name-value.c +++ b/common/t-name-value.c @@ -292,6 +292,7 @@ run_modification_tests (void) { gpg_error_t err; nvc_t pk; + nve_t e; gcry_sexp_t key; char *buf; @@ -344,6 +345,30 @@ run_modification_tests (void) assert (strcmp (buf, "") == 0); xfree (buf); + /* Test whether we can delete an entry by name. */ + err = nvc_add (pk, "Key:", "(3:foo)"); + assert (!err); + e = nvc_lookup (pk, "Key:"); + assert (e); + nvc_delete_named (pk, "Kez:"); /* Delete an inexistant name. */ + e = nvc_lookup (pk, "Key:"); + assert (e); + nvc_delete_named (pk, "Key:"); + e = nvc_lookup (pk, "Key:"); + assert (!e); + + /* Ditto but now whether it deletes all entries with that name. We + * don't use "Key" because that name is special in private key mode. */ + err = nvc_add (pk, "AKey:", "A-value"); + assert (!err); + err = nvc_add (pk, "AKey:", "B-value"); + assert (!err); + e = nvc_lookup (pk, "AKey:"); + assert (e); + nvc_delete_named (pk, "AKey:"); + e = nvc_lookup (pk, "AKey:"); + assert (!e); + nvc_set (pk, "Foo:", "A really long value spanning across multiple lines" " that has to be wrapped at a convenient space."); buf = nvc_to_string (pk); From 5388537806411c19ea84db8c4419f410be9ac616 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 7 May 2019 11:08:26 +0200 Subject: [PATCH 060/169] agent: Allow the use of "Label:" in a key file. * agent/findkey.c (linefeed_to_percent0A): New. (read_key_file): Add optional arg 'keymeta' and change all callers. (agent_key_from_file): Prefer "Label:" over the comment for protected keys. -- If in the extended key format an item Label: This is my key is found, "This is my key" will be displayed instead of the comment intially recorded in the s-expression. This is pretty useful for the ssh keys because often there is only the original file name recorded in the comment. If no Label is found or it is empty the S-expression comment is used. To show more than one line, the standard name-value syntax can be used, for example: Label: The Ssh key I registered on fencepost. Signed-off-by: Werner Koch --- agent/findkey.c | 103 ++++++++++++++++++++++++++++++++++---------- agent/keyformat.txt | 4 +- 2 files changed, 82 insertions(+), 25 deletions(-) diff --git a/agent/findkey.c b/agent/findkey.c index 157870e17..5699a215e 100644 --- a/agent/findkey.c +++ b/agent/findkey.c @@ -1,7 +1,7 @@ /* findkey.c - Locate the secret key * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, * 2010, 2011 Free Software Foundation, Inc. - * Copyright (C) 2014 Werner Koch + * Copyright (C) 2014, 2019 Werner Koch * * This file is part of GnuPG. * @@ -52,6 +52,36 @@ struct try_unprotect_arg_s }; +/* Repalce all linefeeds in STRING by "%0A" and return a new malloced + * string. May return NULL on memory error. */ +static char * +linefeed_to_percent0A (const char *string) +{ + const char *s; + size_t n; + char *buf, *p; + + for (n=0, s=string; *s; s++) + if (*s == '\n') + n += 3; + else + n++; + p = buf = xtrymalloc (n+1); + if (!buf) + return NULL; + for (s=string; *s; s++) + if (*s == '\n') + { + memcpy (p, "%0A", 3); + p += 3; + } + else + *p++ = *s; + *p = 0; + return buf; +} + + /* Note: Ownership of FNAME and FP are moved to this function. */ static gpg_error_t write_extended_private_key (char *fname, estream_t fp, int update, @@ -734,10 +764,13 @@ unprotect (ctrl_t ctrl, const char *cache_nonce, const char *desc_text, /* Read the key identified by GRIP from the private key directory and - return it as an gcrypt S-expression object in RESULT. On failure - returns an error code and stores NULL at RESULT. */ + * return it as an gcrypt S-expression object in RESULT. If R_KEYMETA + * is not NULl and the extended key format is used, the meta data + * items are stored there. However the "Key:" item is removed from + * it. On failure returns an error code and stores NULL at RESULT and + * R_KEYMETA. */ static gpg_error_t -read_key_file (const unsigned char *grip, gcry_sexp_t *result) +read_key_file (const unsigned char *grip, gcry_sexp_t *result, nvc_t *r_keymeta) { gpg_error_t err; char *fname; @@ -750,6 +783,8 @@ read_key_file (const unsigned char *grip, gcry_sexp_t *result) char first; *result = NULL; + if (r_keymeta) + *r_keymeta = NULL; bin2hex (grip, 20, hexgrip); strcpy (hexgrip+40, ".key"); @@ -788,7 +823,7 @@ read_key_file (const unsigned char *grip, gcry_sexp_t *result) if (first != '(') { /* Key is in extended format. */ - nvc_t pk; + nvc_t pk = NULL; int line; err = nvc_parse_private_key (&pk, &line, fp); @@ -800,12 +835,17 @@ read_key_file (const unsigned char *grip, gcry_sexp_t *result) else { err = nvc_get_private_key (pk, result); - nvc_release (pk); if (err) log_error ("error getting private key from '%s': %s\n", fname, gpg_strerror (err)); + else + nvc_delete_named (pk, "Key:"); } + if (!err && r_keymeta) + *r_keymeta = pk; + else + nvc_release (pk); xfree (fname); return err; } @@ -905,6 +945,7 @@ agent_key_from_file (ctrl_t ctrl, const char *cache_nonce, unsigned char *buf; size_t len, buflen, erroff; gcry_sexp_t s_skey; + nvc_t keymeta = NULL; *result = NULL; if (shadow_info) @@ -912,7 +953,7 @@ agent_key_from_file (ctrl_t ctrl, const char *cache_nonce, if (r_passphrase) *r_passphrase = NULL; - err = read_key_file (grip, &s_skey); + err = read_key_file (grip, &s_skey, &keymeta); if (err) { if (gpg_err_code (err) == GPG_ERR_ENOENT) @@ -925,7 +966,10 @@ agent_key_from_file (ctrl_t ctrl, const char *cache_nonce, now. */ err = make_canon_sexp (s_skey, &buf, &len); if (err) - return err; + { + nvc_release (keymeta); + return err; + } switch (agent_private_key_type (buf)) { @@ -950,25 +994,35 @@ agent_key_from_file (ctrl_t ctrl, const char *cache_nonce, case PRIVATE_KEY_PROTECTED: { char *desc_text_final; - char *comment = NULL; + char *comment_buffer = NULL; + const char *comment = NULL; /* Note, that we will take the comment as a C string for - display purposes; i.e. all stuff beyond a Nul character is - ignored. */ - { - gcry_sexp_t comment_sexp; + * display purposes; i.e. all stuff beyond a Nul character is + * ignored. If a "Label" entry is available in the meta data + * this is used instead of the s-ecpression comment. */ + if (keymeta && (comment = nvc_get_string (keymeta, "Label:"))) + { + if (strchr (comment, '\n') + && (comment_buffer = linefeed_to_percent0A (comment))) + comment = comment_buffer; + } + else + { + gcry_sexp_t comment_sexp; - comment_sexp = gcry_sexp_find_token (s_skey, "comment", 0); - if (comment_sexp) - comment = gcry_sexp_nth_string (comment_sexp, 1); - gcry_sexp_release (comment_sexp); - } + comment_sexp = gcry_sexp_find_token (s_skey, "comment", 0); + if (comment_sexp) + comment_buffer = gcry_sexp_nth_string (comment_sexp, 1); + gcry_sexp_release (comment_sexp); + comment = comment_buffer; + } desc_text_final = NULL; if (desc_text) err = agent_modify_description (desc_text, comment, s_skey, &desc_text_final); - gcry_free (comment); + gcry_free (comment_buffer); if (!err) { @@ -1023,6 +1077,7 @@ agent_key_from_file (ctrl_t ctrl, const char *cache_nonce, xfree (*r_passphrase); *r_passphrase = NULL; } + nvc_release (keymeta); return err; } @@ -1039,10 +1094,12 @@ agent_key_from_file (ctrl_t ctrl, const char *cache_nonce, xfree (*r_passphrase); *r_passphrase = NULL; } + nvc_release (keymeta); return err; } *result = s_skey; + nvc_release (keymeta); return 0; } @@ -1242,7 +1299,7 @@ agent_raw_key_from_file (ctrl_t ctrl, const unsigned char *grip, *result = NULL; - err = read_key_file (grip, &s_skey); + err = read_key_file (grip, &s_skey, NULL); if (!err) *result = s_skey; return err; @@ -1280,7 +1337,7 @@ agent_public_key_from_file (ctrl_t ctrl, *result = NULL; - err = read_key_file (grip, &s_skey); + err = read_key_file (grip, &s_skey, NULL); if (err) return err; @@ -1425,7 +1482,7 @@ agent_key_info_from_file (ctrl_t ctrl, const unsigned char *grip, { gcry_sexp_t sexp; - err = read_key_file (grip, &sexp); + err = read_key_file (grip, &sexp, NULL); if (err) { if (gpg_err_code (err) == GPG_ERR_ENOENT) @@ -1509,7 +1566,7 @@ agent_delete_key (ctrl_t ctrl, const char *desc_text, char *default_desc = NULL; int key_type; - err = read_key_file (grip, &s_skey); + err = read_key_file (grip, &s_skey, NULL); if (gpg_err_code (err) == GPG_ERR_ENOENT) err = gpg_error (GPG_ERR_NO_SECKEY); if (err) diff --git a/agent/keyformat.txt b/agent/keyformat.txt index 058fb0143..e2ca05c84 100644 --- a/agent/keyformat.txt +++ b/agent/keyformat.txt @@ -90,8 +90,8 @@ so that the file can be easily inspected and edited. See section This is a short human readable description for the key which can be used by the software to describe the key in a user interface. For example as part of the description in a prompt for a PIN or -passphrase. It is often used instead of a comment element preent in -the S-expression of the "Key" item. +passphrase. It is often used instead of a comment element as present +in the S-expression of the "Key" item. *** OpenSSH-cert This takes a base64 encoded string wrapped so that this From 69e0b080f06b66eee96327617c6fbffe8a88d586 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 7 May 2019 11:50:38 +0200 Subject: [PATCH 061/169] agent: If a Label is make sure that label is part of the prompt. * agent/findkey.c (has_comment_expando): New. (agent_key_from_file): Modify DESC_TEXT. -- A Label entry in the keyfile is always set manually and thus we can assume that the user wants to have this label in the prompt. In case the prompt template does not demand a comment this patch appends a comment to thhe template. This is a common case for on-disk keys used by gpg. Signed-off-by: Werner Koch --- agent/findkey.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/agent/findkey.c b/agent/findkey.c index 5699a215e..755a90be1 100644 --- a/agent/findkey.c +++ b/agent/findkey.c @@ -401,6 +401,33 @@ try_unprotect_cb (struct pin_entry_info_s *pi) } +/* Return true if the STRING has an %C or %c expando. */ +static int +has_comment_expando (const char *string) +{ + const char *s; + int percent = 0; + + if (!string) + return 0; + + for (s = string; *s; s++) + { + if (percent) + { + if (*s == 'c' || *s == 'C') + return 1; + percent = 0; + } + else if (*s == '%') + percent = 1; + } + return 0; +} + + + + /* Modify a Key description, replacing certain special format characters. List of currently supported replacements: @@ -946,6 +973,7 @@ agent_key_from_file (ctrl_t ctrl, const char *cache_nonce, size_t len, buflen, erroff; gcry_sexp_t s_skey; nvc_t keymeta = NULL; + char *desc_text_buffer = NULL; /* Used in case we extend DESC_TEXT. */ *result = NULL; if (shadow_info) @@ -968,6 +996,7 @@ agent_key_from_file (ctrl_t ctrl, const char *cache_nonce, if (err) { nvc_release (keymeta); + xfree (desc_text_buffer); return err; } @@ -1006,6 +1035,14 @@ agent_key_from_file (ctrl_t ctrl, const char *cache_nonce, if (strchr (comment, '\n') && (comment_buffer = linefeed_to_percent0A (comment))) comment = comment_buffer; + /* In case DESC_TEXT has no escape pattern for a comment + * we append one. */ + if (desc_text && !has_comment_expando (desc_text)) + { + desc_text_buffer = strconcat (desc_text, "%0A%C", NULL); + if (desc_text_buffer) + desc_text = desc_text_buffer; + } } else { @@ -1078,6 +1115,7 @@ agent_key_from_file (ctrl_t ctrl, const char *cache_nonce, *r_passphrase = NULL; } nvc_release (keymeta); + xfree (desc_text_buffer); return err; } @@ -1095,11 +1133,13 @@ agent_key_from_file (ctrl_t ctrl, const char *cache_nonce, *r_passphrase = NULL; } nvc_release (keymeta); + xfree (desc_text_buffer); return err; } *result = s_skey; nvc_release (keymeta); + xfree (desc_text_buffer); return 0; } From 7098e4ce198d70361fb160fabeced7453c76e6b2 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 9 May 2019 14:49:59 +0200 Subject: [PATCH 062/169] dirmngr: Add a CSRF expection for pm.me -- Also comment typo fix. --- agent/command.c | 4 ++-- dirmngr/http.c | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/agent/command.c b/agent/command.c index 9bb6fa306..6efd1bff2 100644 --- a/agent/command.c +++ b/agent/command.c @@ -1258,8 +1258,8 @@ do_one_keyinfo (ctrl_t ctrl, const unsigned char *grip, assuan_context_t ctx, } -/* Entry int for the command KEYINFO. This function handles the - command option processing. For details see hlp_keyinfo above. */ +/* Entry into the command KEYINFO. This function handles the + * command option processing. For details see hlp_keyinfo above. */ static gpg_error_t cmd_keyinfo (assuan_context_t ctx, char *line) { diff --git a/dirmngr/http.c b/dirmngr/http.c index d6856fe05..32c0fb181 100644 --- a/dirmngr/http.c +++ b/dirmngr/http.c @@ -3536,7 +3536,8 @@ same_host_p (parsed_uri_t a, parsed_uri_t b) { "protonmail.com", "api.protonmail.com" }, { NULL, "api.protonmail.ch" }, { "protonmail.ch", "api.protonmail.com" }, - { NULL, "api.protonmail.ch" } + { NULL, "api.protonmail.ch" }, + { "pm.me", "api.protonmail.ch" } }; int i; const char *from; From 9662538be6afc8beee0f2654f9a8f234c5dac016 Mon Sep 17 00:00:00 2001 From: Daniel Kahn Gillmor Date: Fri, 10 May 2019 12:39:45 -0400 Subject: [PATCH 063/169] doc: correct documentation for gpgconf --kill * doc/tools.texi(gpgconf): Correct documentation for gpgconf --kill. Signed-off-by: Daniel Kahn Gillmor --- doc/tools.texi | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/doc/tools.texi b/doc/tools.texi index 119f698d6..ba63506f3 100644 --- a/doc/tools.texi +++ b/doc/tools.texi @@ -352,11 +352,12 @@ may use this command to ensure that they are started. Using "all" for @item --kill [@var{component}] @opindex kill -Kill the given component. Components which support killing are -@command{gpg-agent} and @command{scdaemon}. Components which don't -support reloading are ignored. Using "all" for @var{component} kills -all components running as daemons. Note that as of now reload and -kill have the same effect for @command{scdaemon}. +Kill the given component that runs as a daemon, including +@command{gpg-agent}, @command{dirmngr}, and @command{scdaemon}. A +@command{component} which does not run as a daemon will be ignored. +Using "all" for @var{component} kills all components running as +daemons. Note that as of now reload and kill have the same effect for +@command{scdaemon}. @item --create-socketdir @opindex create-socketdir From 1cd2aca03b8807c6f8e4929ace462bb606dcd53f Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Mon, 13 May 2019 15:15:29 +0900 Subject: [PATCH 064/169] build: Update m4/iconv.m4. * m4/iconv.m4: Update from gettext 0.20.1. -- This includes fixes of file descriptor leaks. GnuPG-bug-id: 4504 Signed-off-by: NIIBE Yutaka --- m4/iconv.m4 | 222 ++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 165 insertions(+), 57 deletions(-) diff --git a/m4/iconv.m4 b/m4/iconv.m4 index 66bc76f48..a285e9daa 100644 --- a/m4/iconv.m4 +++ b/m4/iconv.m4 @@ -1,5 +1,6 @@ -# iconv.m4 serial AM6 (gettext-0.17) -dnl Copyright (C) 2000-2002, 2007 Free Software Foundation, Inc. +# iconv.m4 serial 21 +dnl Copyright (C) 2000-2002, 2007-2014, 2016-2019 Free Software Foundation, +dnl Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. @@ -30,61 +31,118 @@ AC_DEFUN([AM_ICONV_LINK], dnl Add $INCICONV to CPPFLAGS before performing the following checks, dnl because if the user has installed libiconv and not disabled its use dnl via --without-libiconv-prefix, he wants to use it. The first - dnl AC_TRY_LINK will then fail, the second AC_TRY_LINK will succeed. + dnl AC_LINK_IFELSE will then fail, the second AC_LINK_IFELSE will succeed. am_save_CPPFLAGS="$CPPFLAGS" AC_LIB_APPENDTOVAR([CPPFLAGS], [$INCICONV]) - AC_CACHE_CHECK([for iconv], am_cv_func_iconv, [ + AC_CACHE_CHECK([for iconv], [am_cv_func_iconv], [ am_cv_func_iconv="no, consider installing GNU libiconv" am_cv_lib_iconv=no - AC_TRY_LINK([#include -#include ], - [iconv_t cd = iconv_open("",""); - iconv(cd,NULL,NULL,NULL,NULL); - iconv_close(cd);], - am_cv_func_iconv=yes) + AC_LINK_IFELSE( + [AC_LANG_PROGRAM( + [[ +#include +#include + ]], + [[iconv_t cd = iconv_open("",""); + iconv(cd,NULL,NULL,NULL,NULL); + iconv_close(cd);]])], + [am_cv_func_iconv=yes]) if test "$am_cv_func_iconv" != yes; then am_save_LIBS="$LIBS" LIBS="$LIBS $LIBICONV" - AC_TRY_LINK([#include -#include ], - [iconv_t cd = iconv_open("",""); - iconv(cd,NULL,NULL,NULL,NULL); - iconv_close(cd);], - am_cv_lib_iconv=yes - am_cv_func_iconv=yes) + AC_LINK_IFELSE( + [AC_LANG_PROGRAM( + [[ +#include +#include + ]], + [[iconv_t cd = iconv_open("",""); + iconv(cd,NULL,NULL,NULL,NULL); + iconv_close(cd);]])], + [am_cv_lib_iconv=yes] + [am_cv_func_iconv=yes]) LIBS="$am_save_LIBS" fi ]) if test "$am_cv_func_iconv" = yes; then - AC_CACHE_CHECK([for working iconv], am_cv_func_iconv_works, [ - dnl This tests against bugs in AIX 5.1 and HP-UX 11.11. + AC_CACHE_CHECK([for working iconv], [am_cv_func_iconv_works], [ + dnl This tests against bugs in AIX 5.1, AIX 6.1..7.1, HP-UX 11.11, + dnl Solaris 10. am_save_LIBS="$LIBS" if test $am_cv_lib_iconv = yes; then LIBS="$LIBS $LIBICONV" fi - AC_TRY_RUN([ + am_cv_func_iconv_works=no + for ac_iconv_const in '' 'const'; do + AC_RUN_IFELSE( + [AC_LANG_PROGRAM( + [[ #include #include -int main () -{ + +#ifndef ICONV_CONST +# define ICONV_CONST $ac_iconv_const +#endif + ]], + [[int result = 0; /* Test against AIX 5.1 bug: Failures are not distinguishable from successful returns. */ { iconv_t cd_utf8_to_88591 = iconv_open ("ISO8859-1", "UTF-8"); if (cd_utf8_to_88591 != (iconv_t)(-1)) { - static const char input[] = "\342\202\254"; /* EURO SIGN */ + static ICONV_CONST char input[] = "\342\202\254"; /* EURO SIGN */ char buf[10]; - const char *inptr = input; + ICONV_CONST char *inptr = input; size_t inbytesleft = strlen (input); char *outptr = buf; size_t outbytesleft = sizeof (buf); size_t res = iconv (cd_utf8_to_88591, - (char **) &inptr, &inbytesleft, + &inptr, &inbytesleft, &outptr, &outbytesleft); if (res == 0) - return 1; + result |= 1; + iconv_close (cd_utf8_to_88591); + } + } + /* Test against Solaris 10 bug: Failures are not distinguishable from + successful returns. */ + { + iconv_t cd_ascii_to_88591 = iconv_open ("ISO8859-1", "646"); + if (cd_ascii_to_88591 != (iconv_t)(-1)) + { + static ICONV_CONST char input[] = "\263"; + char buf[10]; + ICONV_CONST char *inptr = input; + size_t inbytesleft = strlen (input); + char *outptr = buf; + size_t outbytesleft = sizeof (buf); + size_t res = iconv (cd_ascii_to_88591, + &inptr, &inbytesleft, + &outptr, &outbytesleft); + if (res == 0) + result |= 2; + iconv_close (cd_ascii_to_88591); + } + } + /* Test against AIX 6.1..7.1 bug: Buffer overrun. */ + { + iconv_t cd_88591_to_utf8 = iconv_open ("UTF-8", "ISO-8859-1"); + if (cd_88591_to_utf8 != (iconv_t)(-1)) + { + static ICONV_CONST char input[] = "\304"; + static char buf[2] = { (char)0xDE, (char)0xAD }; + ICONV_CONST char *inptr = input; + size_t inbytesleft = 1; + char *outptr = buf; + size_t outbytesleft = 1; + size_t res = iconv (cd_88591_to_utf8, + &inptr, &inbytesleft, + &outptr, &outbytesleft); + if (res != (size_t)(-1) || outptr - buf > 1 || buf[1] != (char)0xAD) + result |= 4; + iconv_close (cd_88591_to_utf8); } } #if 0 /* This bug could be worked around by the caller. */ @@ -93,37 +151,53 @@ int main () iconv_t cd_88591_to_utf8 = iconv_open ("utf8", "iso88591"); if (cd_88591_to_utf8 != (iconv_t)(-1)) { - static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337"; + static ICONV_CONST char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337"; char buf[50]; - const char *inptr = input; + ICONV_CONST char *inptr = input; size_t inbytesleft = strlen (input); char *outptr = buf; size_t outbytesleft = sizeof (buf); size_t res = iconv (cd_88591_to_utf8, - (char **) &inptr, &inbytesleft, + &inptr, &inbytesleft, &outptr, &outbytesleft); if ((int)res > 0) - return 1; + result |= 8; + iconv_close (cd_88591_to_utf8); } } #endif /* Test against HP-UX 11.11 bug: No converter from EUC-JP to UTF-8 is provided. */ - if (/* Try standardized names. */ - iconv_open ("UTF-8", "EUC-JP") == (iconv_t)(-1) - /* Try IRIX, OSF/1 names. */ - && iconv_open ("UTF-8", "eucJP") == (iconv_t)(-1) - /* Try AIX names. */ - && iconv_open ("UTF-8", "IBM-eucJP") == (iconv_t)(-1) - /* Try HP-UX names. */ - && iconv_open ("utf8", "eucJP") == (iconv_t)(-1)) - return 1; - return 0; -}], [am_cv_func_iconv_works=yes], [am_cv_func_iconv_works=no], - [case "$host_os" in - aix* | hpux*) am_cv_func_iconv_works="guessing no" ;; - *) am_cv_func_iconv_works="guessing yes" ;; - esac]) + { + /* Try standardized names. */ + iconv_t cd1 = iconv_open ("UTF-8", "EUC-JP"); + /* Try IRIX, OSF/1 names. */ + iconv_t cd2 = iconv_open ("UTF-8", "eucJP"); + /* Try AIX names. */ + iconv_t cd3 = iconv_open ("UTF-8", "IBM-eucJP"); + /* Try HP-UX names. */ + iconv_t cd4 = iconv_open ("utf8", "eucJP"); + if (cd1 == (iconv_t)(-1) && cd2 == (iconv_t)(-1) + && cd3 == (iconv_t)(-1) && cd4 == (iconv_t)(-1)) + result |= 16; + if (cd1 != (iconv_t)(-1)) + iconv_close (cd1); + if (cd2 != (iconv_t)(-1)) + iconv_close (cd2); + if (cd3 != (iconv_t)(-1)) + iconv_close (cd3); + if (cd4 != (iconv_t)(-1)) + iconv_close (cd4); + } + return result; +]])], + [am_cv_func_iconv_works=yes], , + [case "$host_os" in + aix* | hpux*) am_cv_func_iconv_works="guessing no" ;; + *) am_cv_func_iconv_works="guessing yes" ;; + esac]) + test "$am_cv_func_iconv_works" = no || break + done LIBS="$am_save_LIBS" ]) case "$am_cv_func_iconv_works" in @@ -134,7 +208,7 @@ int main () am_func_iconv=no am_cv_lib_iconv=no fi if test "$am_func_iconv" = yes; then - AC_DEFINE(HAVE_ICONV, 1, + AC_DEFINE([HAVE_ICONV], [1], [Define if you have the iconv() function and it works.]) fi if test "$am_cv_lib_iconv" = yes; then @@ -147,34 +221,68 @@ int main () LIBICONV= LTLIBICONV= fi - AC_SUBST(LIBICONV) - AC_SUBST(LTLIBICONV) + AC_SUBST([LIBICONV]) + AC_SUBST([LTLIBICONV]) ]) -AC_DEFUN([AM_ICONV], +dnl Define AM_ICONV using AC_DEFUN_ONCE for Autoconf >= 2.64, in order to +dnl avoid warnings like +dnl "warning: AC_REQUIRE: `AM_ICONV' was expanded before it was required". +dnl This is tricky because of the way 'aclocal' is implemented: +dnl - It requires defining an auxiliary macro whose name ends in AC_DEFUN. +dnl Otherwise aclocal's initial scan pass would miss the macro definition. +dnl - It requires a line break inside the AC_DEFUN_ONCE and AC_DEFUN expansions. +dnl Otherwise aclocal would emit many "Use of uninitialized value $1" +dnl warnings. +m4_define([gl_iconv_AC_DEFUN], + m4_version_prereq([2.64], + [[AC_DEFUN_ONCE( + [$1], [$2])]], + [m4_ifdef([gl_00GNULIB], + [[AC_DEFUN_ONCE( + [$1], [$2])]], + [[AC_DEFUN( + [$1], [$2])]])])) +gl_iconv_AC_DEFUN([AM_ICONV], [ AM_ICONV_LINK if test "$am_cv_func_iconv" = yes; then AC_MSG_CHECKING([for iconv declaration]) - AC_CACHE_VAL(am_cv_proto_iconv, [ - AC_TRY_COMPILE([ + AC_CACHE_VAL([am_cv_proto_iconv], [ + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [[ #include #include extern #ifdef __cplusplus "C" #endif -#if defined(__STDC__) || defined(__cplusplus) +#if defined(__STDC__) || defined(_MSC_VER) || defined(__cplusplus) size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft); #else size_t iconv(); #endif -], [], am_cv_proto_iconv_arg1="", am_cv_proto_iconv_arg1="const") + ]], + [[]])], + [am_cv_proto_iconv_arg1=""], + [am_cv_proto_iconv_arg1="const"]) am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);"]) am_cv_proto_iconv=`echo "[$]am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'` - AC_MSG_RESULT([$]{ac_t:- - }[$]am_cv_proto_iconv) - AC_DEFINE_UNQUOTED(ICONV_CONST, $am_cv_proto_iconv_arg1, - [Define as const if the declaration of iconv() needs const.]) + AC_MSG_RESULT([ + $am_cv_proto_iconv]) + else + dnl When compiling GNU libiconv on a system that does not have iconv yet, + dnl pick the POSIX compliant declaration without 'const'. + am_cv_proto_iconv_arg1="" fi + AC_DEFINE_UNQUOTED([ICONV_CONST], [$am_cv_proto_iconv_arg1], + [Define as const if the declaration of iconv() needs const.]) + dnl Also substitute ICONV_CONST in the gnulib generated . + m4_ifdef([gl_ICONV_H_DEFAULTS], + [AC_REQUIRE([gl_ICONV_H_DEFAULTS]) + if test -n "$am_cv_proto_iconv_arg1"; then + ICONV_CONST="const" + fi + ]) ]) From d07666412d4317460c6f03b3ffd03edf4a715ef7 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 13 May 2019 12:38:32 +0200 Subject: [PATCH 065/169] gpg: Cleanup use of make_keysig_packet. * g10/sign.c (make_keysig_packet): Remove obsolete arg diegst_algo which was always passed as 0. Change all callers. * g10/gpgcompose.c (signature): Warn when trying to set a digest algo. -- Signed-off-by: Werner Koch --- doc/gpg.texi | 12 ++++++++---- g10/gpgcompose.c | 9 ++++++++- g10/keyedit.c | 19 ++++++++++--------- g10/keygen.c | 8 ++++---- g10/packet.h | 2 +- g10/revoke.c | 4 ++-- g10/sign.c | 38 +++++++++++++++----------------------- 7 files changed, 48 insertions(+), 44 deletions(-) diff --git a/doc/gpg.texi b/doc/gpg.texi index d3b7be598..df807fafc 100644 --- a/doc/gpg.texi +++ b/doc/gpg.texi @@ -3081,10 +3081,14 @@ the same thing. @opindex cert-digest-algo Use @var{name} as the message digest algorithm used when signing a key. Running the program with the command @option{--version} yields a -list of supported algorithms. Be aware that if you choose an algorithm -that GnuPG supports but other OpenPGP implementations do not, then some -users will not be able to use the key signatures you make, or quite -possibly your entire key. +list of supported algorithms. Be aware that if you choose an +algorithm that GnuPG supports but other OpenPGP implementations do +not, then some users will not be able to use the key signatures you +make, or quite possibly your entire key. Note also that a public key +algorithm must be compatible with the specified digest algorithm; thus +selecting an arbitrary digest algorithm may result in error messages +from lower crypto layers or lead to security flaws. + @item --disable-cipher-algo @var{name} @opindex disable-cipher-algo diff --git a/g10/gpgcompose.c b/g10/gpgcompose.c index e882fa8e3..9e6d51a57 100644 --- a/g10/gpgcompose.c +++ b/g10/gpgcompose.c @@ -1799,12 +1799,19 @@ signature (const char *option, int argc, char *argv[], void *cookie) keyid_copy (si.issuer_pk->keyid, pk_keyid (pripk)); } + /* The reuse of core gpg stuff by this tool is questionable when it + * requires adding extra code to the actual gpg code. It does not + * make sense to pass an extra parameter and in particular not given + * that gpg already has opt.cert_digest_algo to override it. */ + if (si.digest_algo) + log_info ("note: digest algo can't be passed to make_keysig_packet\n"); + /* Changing the issuer's key id is fragile. Check to make sure make_keysig_packet didn't recompute the keyid. */ keyid_copy (keyid, si.issuer_pk->keyid); err = make_keysig_packet (global_ctrl, &sig, si.pk, si.uid, si.sk, si.issuer_pk, - si.class, si.digest_algo, + si.class, si.timestamp, si.expiration, mksubpkt_callback, &si, NULL); log_assert (keyid_cmp (keyid, si.issuer_pk->keyid) == 0); diff --git a/g10/keyedit.c b/g10/keyedit.c index c28a565b1..7f4c5a509 100644 --- a/g10/keyedit.c +++ b/g10/keyedit.c @@ -1012,7 +1012,8 @@ sign_uids (ctrl_t ctrl, estream_t fp, node->pkt->pkt.user_id, NULL, pk, - 0x13, 0, 0, 0, + 0x13, + 0, 0, keygen_add_std_prefs, primary_pk, NULL); else @@ -1020,7 +1021,7 @@ sign_uids (ctrl_t ctrl, estream_t fp, node->pkt->pkt.user_id, NULL, pk, - class, 0, + class, timestamp, duration, sign_mk_attrib, &attrib, NULL); @@ -3991,7 +3992,7 @@ menu_adduid (ctrl_t ctrl, kbnode_t pub_keyblock, return 0; } - err = make_keysig_packet (ctrl, &sig, pk, uid, NULL, pk, 0x13, 0, 0, 0, + err = make_keysig_packet (ctrl, &sig, pk, uid, NULL, pk, 0x13, 0, 0, keygen_add_std_prefs, pk, NULL); if (err) { @@ -4374,7 +4375,7 @@ menu_addrevoker (ctrl_t ctrl, kbnode_t pub_keyblock, int sensitive) break; } - rc = make_keysig_packet (ctrl, &sig, pk, NULL, NULL, pk, 0x1F, 0, 0, 0, + rc = make_keysig_packet (ctrl, &sig, pk, NULL, NULL, pk, 0x1F, 0, 0, keygen_add_revkey, &revkey, NULL); if (rc) { @@ -5898,7 +5899,7 @@ reloop: /* (must use this, because we are modifying the list) */ } rc = make_keysig_packet (ctrl, &sig, primary_pk, unode->pkt->pkt.user_id, - NULL, signerkey, 0x30, 0, 0, 0, + NULL, signerkey, 0x30, 0, 0, sign_mk_attrib, &attrib, NULL); free_public_key (signerkey); if (rc) @@ -5977,11 +5978,11 @@ core_revuid (ctrl_t ctrl, kbnode_t keyblock, KBNODE node, memset (&attrib, 0, sizeof attrib); /* should not need to cast away const here; but revocation_reason_build_cb needs to take a non-const - void* in order to meet the function signtuare for the + void* in order to meet the function signutare for the mksubpkt argument to make_keysig_packet */ attrib.reason = (struct revocation_reason_info *)reason; - rc = make_keysig_packet (ctrl, &sig, pk, uid, NULL, pk, 0x30, 0, + rc = make_keysig_packet (ctrl, &sig, pk, uid, NULL, pk, 0x30, timestamp, 0, sign_mk_attrib, &attrib, NULL); if (rc) @@ -6111,7 +6112,7 @@ menu_revkey (ctrl_t ctrl, kbnode_t pub_keyblock) return 0; rc = make_keysig_packet (ctrl, &sig, pk, NULL, NULL, pk, - 0x20, 0, 0, 0, + 0x20, 0, 0, revocation_reason_build_cb, reason, NULL); if (rc) { @@ -6173,7 +6174,7 @@ menu_revsubkey (ctrl_t ctrl, kbnode_t pub_keyblock) node->flag &= ~NODFLG_SELKEY; rc = make_keysig_packet (ctrl, &sig, mainpk, NULL, subpk, mainpk, - 0x28, 0, 0, 0, sign_mk_attrib, &attrib, + 0x28, 0, 0, sign_mk_attrib, &attrib, NULL); if (rc) { diff --git a/g10/keygen.c b/g10/keygen.c index 22ac6f0b5..ac6bcc890 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -1022,7 +1022,7 @@ make_backsig (ctrl_t ctrl, PKT_signature *sig, PKT_public_key *pk, cache_public_key (sub_pk); err = make_keysig_packet (ctrl, &backsig, pk, NULL, sub_pk, sub_psk, 0x19, - 0, timestamp, 0, NULL, NULL, cache_nonce); + timestamp, 0, NULL, NULL, cache_nonce); if (err) log_error ("make_keysig_packet failed for backsig: %s\n", gpg_strerror (err)); @@ -1130,7 +1130,7 @@ write_direct_sig (ctrl_t ctrl, kbnode_t root, PKT_public_key *psk, /* Make the signature. */ err = make_keysig_packet (ctrl, &sig, pk, NULL,NULL, psk, 0x1F, - 0, timestamp, 0, + timestamp, 0, keygen_add_revkey, revkey, cache_nonce); if (err) { @@ -1185,7 +1185,7 @@ write_selfsigs (ctrl_t ctrl, kbnode_t root, PKT_public_key *psk, /* Make the signature. */ err = make_keysig_packet (ctrl, &sig, pk, uid, NULL, psk, 0x13, - 0, timestamp, 0, + timestamp, 0, keygen_add_std_prefs, pk, cache_nonce); if (err) { @@ -1245,7 +1245,7 @@ write_keybinding (ctrl_t ctrl, kbnode_t root, oduap.usage = use; oduap.pk = sub_pk; err = make_keysig_packet (ctrl, &sig, pri_pk, NULL, sub_pk, pri_psk, 0x18, - 0, timestamp, 0, + timestamp, 0, keygen_add_key_flags_and_expire, &oduap, cache_nonce); if (err) diff --git a/g10/packet.h b/g10/packet.h index d05a8f0f2..d787bde9e 100644 --- a/g10/packet.h +++ b/g10/packet.h @@ -931,7 +931,7 @@ int ask_for_detached_datafile( gcry_md_hd_t md, gcry_md_hd_t md2, int make_keysig_packet (ctrl_t ctrl, PKT_signature **ret_sig, PKT_public_key *pk, PKT_user_id *uid, PKT_public_key *subpk, - PKT_public_key *pksk, int sigclass, int digest_algo, + PKT_public_key *pksk, int sigclass, u32 timestamp, u32 duration, int (*mksubpkt)(PKT_signature *, void *), void *opaque, diff --git a/g10/revoke.c b/g10/revoke.c index e8ce3544c..e63060cb9 100644 --- a/g10/revoke.c +++ b/g10/revoke.c @@ -343,7 +343,7 @@ gen_desig_revoke (ctrl_t ctrl, const char *uname, strlist_t locusr) push_armor_filter (afx, out); /* create it */ - rc = make_keysig_packet (ctrl, &sig, pk, NULL, NULL, pk2, 0x20, 0, + rc = make_keysig_packet (ctrl, &sig, pk, NULL, NULL, pk2, 0x20, 0, 0, revocation_reason_build_cb, reason, NULL); @@ -474,7 +474,7 @@ create_revocation (ctrl_t ctrl, afx->hdrlines = "Comment: This is a revocation certificate\n"; push_armor_filter (afx, out); - rc = make_keysig_packet (ctrl, &sig, psk, NULL, NULL, psk, 0x20, 0, + rc = make_keysig_packet (ctrl, &sig, psk, NULL, NULL, psk, 0x20, 0, 0, revocation_reason_build_cb, reason, cache_nonce); if (rc) diff --git a/g10/sign.c b/g10/sign.c index 176940bff..132b94101 100644 --- a/g10/sign.c +++ b/g10/sign.c @@ -1593,7 +1593,7 @@ make_keysig_packet (ctrl_t ctrl, PKT_signature **ret_sig, PKT_public_key *pk, PKT_user_id *uid, PKT_public_key *subpk, PKT_public_key *pksk, - int sigclass, int digest_algo, + int sigclass, u32 timestamp, u32 duration, int (*mksubpkt)(PKT_signature *, void *), void *opaque, const char *cache_nonce) @@ -1601,6 +1601,7 @@ make_keysig_packet (ctrl_t ctrl, PKT_signature *sig; int rc = 0; int sigversion; + int digest_algo; gcry_md_hd_t md; log_assert ((sigclass >= 0x10 && sigclass <= 0x13) || sigclass == 0x1F @@ -1612,31 +1613,22 @@ make_keysig_packet (ctrl_t ctrl, else sigversion = 4; - if (!digest_algo) + /* Select the digest algo to use. */ + if (opt.cert_digest_algo) /* Forceful override by the user. */ + digest_algo = opt.cert_digest_algo; + else if (pksk->pubkey_algo == PUBKEY_ALGO_DSA) /* Meet DSA requirements. */ + digest_algo = match_dsa_hash (gcry_mpi_get_nbits (pksk->pkey[1])/8); + else if (pksk->pubkey_algo == PUBKEY_ALGO_ECDSA /* Meet ECDSA requirements. */ + || pksk->pubkey_algo == PUBKEY_ALGO_EDDSA) { - /* Basically, this means use SHA1 always unless the user - * specified something (use whatever they said), or it's DSA - * (use the best match). They still can't pick an inappropriate - * hash for DSA or the signature will fail. Note that this - * still allows the caller of make_keysig_packet to override the - * user setting if it must. */ - - if (opt.cert_digest_algo) - digest_algo = opt.cert_digest_algo; - else if (pksk->pubkey_algo == PUBKEY_ALGO_DSA) - digest_algo = match_dsa_hash (gcry_mpi_get_nbits (pksk->pkey[1])/8); - else if (pksk->pubkey_algo == PUBKEY_ALGO_ECDSA - || pksk->pubkey_algo == PUBKEY_ALGO_EDDSA) - { - if (openpgp_oid_is_ed25519 (pksk->pkey[0])) - digest_algo = DIGEST_ALGO_SHA256; - else - digest_algo = match_dsa_hash - (ecdsa_qbits_from_Q (gcry_mpi_get_nbits (pksk->pkey[1]))/8); - } + if (openpgp_oid_is_ed25519 (pksk->pkey[0])) + digest_algo = DIGEST_ALGO_SHA256; else - digest_algo = DEFAULT_DIGEST_ALGO; + digest_algo = match_dsa_hash + (ecdsa_qbits_from_Q (gcry_mpi_get_nbits (pksk->pkey[1]))/8); } + else /* Use the default. */ + digest_algo = DEFAULT_DIGEST_ALGO; if (gcry_md_open (&md, digest_algo, 0)) BUG (); From 484d6ba5896acfa3dcf73d9536bcf5e006579b5f Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 13 May 2019 19:01:28 +0200 Subject: [PATCH 066/169] gpg: Change update_keysig_packet to replace SHA-1 by SHA-256. * g10/sign.c (update_keysig_packet): Convert digest algo when needed. -- Several gpg commands try to keep most properties of a key signature when updating (i.e. creating a new version of a key signature). This included the use of the current hash-algorithm. This patch changes this so that SHA-1 or RMD160 are replaced by SHA-256 if possible (i.e. for RSA signatures). Affected commands are for example --quick-set-expire and --quick-set-primary-uid. GnuPG-bug-id: 4508 Signed-off-by: Werner Koch --- g10/sign.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/g10/sign.c b/g10/sign.c index 132b94101..d71580639 100644 --- a/g10/sign.c +++ b/g10/sign.c @@ -1714,8 +1714,19 @@ update_keysig_packet (ctrl_t ctrl, || (orig_sig->sig_class == 0x18 && !subpk)) return GPG_ERR_GENERAL; + /* Either use the override digest algo or in the normal case the + * original digest algorithm. However, iff the original digest + * algorithms is SHA-1 and we are in gnupg or de-vs compliance mode + * we switch to SHA-256 (done by the macro). */ if (opt.cert_digest_algo) digest_algo = opt.cert_digest_algo; + else if (pksk->pubkey_algo == PUBKEY_ALGO_DSA + || pksk->pubkey_algo == PUBKEY_ALGO_ECDSA + || pksk->pubkey_algo == PUBKEY_ALGO_EDDSA) + digest_algo = orig_sig->digest_algo; + else if (orig_sig->digest_algo == DIGEST_ALGO_SHA1 + || orig_sig->digest_algo == DIGEST_ALGO_RMD160) + digest_algo = DEFAULT_DIGEST_ALGO; else digest_algo = orig_sig->digest_algo; From 802a2aa300bad3d4385d17a2deeb0966da4e737d Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Tue, 14 May 2019 11:20:07 +0900 Subject: [PATCH 067/169] g10: Fix possible null dereference. * g10/armor.c (armor_filter): Access ->d in the internal loop. -- GnuPG-bug-id: 4494 Signed-off-by: NIIBE Yutaka --- g10/armor.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/g10/armor.c b/g10/armor.c index 972766503..eb2d28bca 100644 --- a/g10/armor.c +++ b/g10/armor.c @@ -1394,10 +1394,10 @@ armor_filter( void *opaque, int control, } /* write the comment strings */ - for(s=comment->d;comment;comment=comment->next,s=comment->d) + for(;comment;comment=comment->next) { iobuf_writestr(a, "Comment: " ); - for( ; *s; s++ ) + for( s=comment->d; *s; s++ ) { if( *s == '\n' ) iobuf_writestr(a, "\\n" ); From 7102d9b798b0985412007d3bf8b954959e4adec7 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 14 May 2019 07:56:10 +0200 Subject: [PATCH 068/169] gpg: Do not print a hint to use the deprecated --keyserver option. * g10/keyserver.c (keyserver_search): Remove a specialized error message. -- Dirmngr comes with a default keyserver and the suggestion to use gpg --keyserver is not good because that option is deprecated. An error message "No keyserver available" is sufficient. GnuPG-bug-id: 4512 Signed-off-by: Werner Koch --- g10/keyserver.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/g10/keyserver.c b/g10/keyserver.c index 04802d1a5..3a6fe69a8 100644 --- a/g10/keyserver.c +++ b/g10/keyserver.c @@ -1519,9 +1519,7 @@ keyserver_search (ctrl_t ctrl, strlist_t tokens) log_info (_("key not found on keyserver\n")); } - if (gpg_err_code (err) == GPG_ERR_NO_KEYSERVER) - log_error (_("no keyserver known (use option --keyserver)\n")); - else if (gpg_err_code (err) == GPG_ERR_NO_DATA) + if (gpg_err_code (err) == GPG_ERR_NO_DATA) err = gpg_error (GPG_ERR_NOT_FOUND); else if (err) log_error ("error searching keyserver: %s\n", gpg_strerror (err)); From 3c2198e907c6e37ef227370b3ec95cc9198cf400 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 14 May 2019 10:07:06 +0200 Subject: [PATCH 069/169] doc: Minor edit for a gpg option. -- GnuPG-bug-id: 4507 --- doc/gpg.texi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/gpg.texi b/doc/gpg.texi index df807fafc..ddbac0edc 100644 --- a/doc/gpg.texi +++ b/doc/gpg.texi @@ -1330,8 +1330,8 @@ give the opposite meaning. The options are: @item show-only-fpr-mbox @opindex list-options:show-only-fpr-mbox - For each valid user-id which also has a valid mail address print - only the fingerprint and the mail address. + For each user-id which has a valid mail address print + only the fingerprint followed by the mail address. @end table @item --verify-options @var{parameters} From 5651b2c460a7898027c1765c2063c302606b5f85 Mon Sep 17 00:00:00 2001 From: Daniel Kahn Gillmor Date: Tue, 14 May 2019 00:05:42 -0400 Subject: [PATCH 070/169] agent: correct length for uri and comment on 64-bit big-endian platforms * agent/findkey.c (agent_public_key_from_file): pass size_t as int to gcry_sexp_build_array's %b. -- This is only a problem on big-endian systems where size_t is not the same size as an int. It was causing failures on debian's s390x, powerpc64, and sparc64 platforms. There may well be other failures with %b on those platforms in the codebase, and it probably needs an audit. Once you have a key in private-keys-v1.d/$KEYGRIP.key with a comment or a uri of reasonable length associated with it, this fix can be tested with: gpg-agent --server <<<"READKEY $KEYGRIP" On the failing platforms, the printed comment will be of length 0. Gnupg-bug-id: 4501 Signed-off-by: Daniel Kahn Gillmor --- agent/findkey.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/agent/findkey.c b/agent/findkey.c index 755a90be1..20c9dc56a 100644 --- a/agent/findkey.c +++ b/agent/findkey.c @@ -1366,6 +1366,7 @@ agent_public_key_from_file (ctrl_t ctrl, gcry_sexp_t uri_sexp, comment_sexp; const char *uri, *comment; size_t uri_length, comment_length; + int uri_intlen, comment_intlen; char *format, *p; void *args[2+7+2+2+1]; /* Size is 2 + max. # of elements + 2 for uri + 2 for comment + end-of-list. */ @@ -1447,14 +1448,16 @@ agent_public_key_from_file (ctrl_t ctrl, { p = stpcpy (p, "(uri %b)"); assert (argidx+1 < DIM (args)); - args[argidx++] = (void *)&uri_length; + uri_intlen = (int)uri_length; + args[argidx++] = (void *)&uri_intlen; args[argidx++] = (void *)&uri; } if (comment) { p = stpcpy (p, "(comment %b)"); assert (argidx+1 < DIM (args)); - args[argidx++] = (void *)&comment_length; + comment_intlen = (int)comment_length; + args[argidx++] = (void *)&comment_intlen; args[argidx++] = (void*)&comment; } *p++ = ')'; From 54e96c6fd262bd0090fec836c97d7fdb04bd6129 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 14 May 2019 10:31:46 +0200 Subject: [PATCH 071/169] agent: Replace most assert by log_assert. -- --- agent/cache.c | 1 - agent/call-pinentry.c | 1 - agent/call-scd.c | 1 - agent/command-ssh.c | 5 ++--- agent/command.c | 3 +-- agent/cvt-openpgp.c | 9 ++++----- agent/findkey.c | 20 +++++++++----------- agent/genkey.c | 11 +++++------ agent/gpg-agent.c | 3 +-- agent/learncard.c | 1 - agent/pkdecrypt.c | 5 ++--- agent/pksign.c | 6 ++---- agent/preset-passphrase.c | 1 - agent/protect-tool.c | 17 ++++++++--------- agent/protect.c | 14 +++++++------- agent/trans.c | 1 - agent/trustlist.c | 3 +-- 17 files changed, 42 insertions(+), 60 deletions(-) diff --git a/agent/cache.c b/agent/cache.c index 799d595ab..4a3e5a547 100644 --- a/agent/cache.c +++ b/agent/cache.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include "agent.h" diff --git a/agent/call-pinentry.c b/agent/call-pinentry.c index 34dde3744..5b4713f41 100644 --- a/agent/call-pinentry.c +++ b/agent/call-pinentry.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #ifndef HAVE_W32_SYSTEM diff --git a/agent/call-scd.c b/agent/call-scd.c index b2266225e..b52c6c8eb 100644 --- a/agent/call-scd.c +++ b/agent/call-scd.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #ifdef HAVE_SIGNAL_H # include diff --git a/agent/command-ssh.c b/agent/command-ssh.c index 727bb9b94..5f7884b1f 100644 --- a/agent/command-ssh.c +++ b/agent/command-ssh.c @@ -41,7 +41,6 @@ #include #include #include -#include #ifndef HAVE_W32_SYSTEM #include #include @@ -1030,7 +1029,7 @@ search_control_file (ssh_control_file_t cf, const char *hexgrip, { gpg_error_t err; - assert (strlen (hexgrip) == 40 ); + log_assert (strlen (hexgrip) == 40 ); if (r_disabled) *r_disabled = 0; @@ -2646,7 +2645,7 @@ ssh_handler_request_identities (ctrl_t ctrl, continue; /* Should not happen. */ if (cf->item.disabled) continue; - assert (strlen (cf->item.hexgrip) == 40); + log_assert (strlen (cf->item.hexgrip) == 40); hex2bin (cf->item.hexgrip, grip, sizeof (grip)); err = agent_public_key_from_file (ctrl, grip, &key_public); diff --git a/agent/command.c b/agent/command.c index 6efd1bff2..c056eb3f0 100644 --- a/agent/command.c +++ b/agent/command.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include @@ -2212,7 +2211,7 @@ cmd_import_key (assuan_context_t ctx, char *line) goto leave; /* Invalid canonical encoded S-expression. */ if (passphrase) { - assert (!opt_unattended); + log_assert (!opt_unattended); if (!cache_nonce) { char buf[12]; diff --git a/agent/cvt-openpgp.c b/agent/cvt-openpgp.c index 42052d48e..003402956 100644 --- a/agent/cvt-openpgp.c +++ b/agent/cvt-openpgp.c @@ -22,7 +22,6 @@ #include #include #include -#include #include "agent.h" #include "../common/i18n.h" @@ -571,7 +570,7 @@ do_unprotect (const char *passphrase, } skey[i] = NULL; skeylen = i; - assert (skeylen <= skeysize); + log_assert (skeylen <= skeysize); /* Note: at this point NDATA should be 2 for a simple checksum or 20 for the sha1 digest. */ @@ -1105,8 +1104,8 @@ apply_protection (gcry_mpi_t *array, int npkey, int nskey, int ndata; unsigned char *p, *data; - assert (npkey < nskey); - assert (nskey < DIM (bufarr)); + log_assert (npkey < nskey); + log_assert (nskey < DIM (bufarr)); /* Collect only the secret key parameters into BUFARR et al and compute the required size of the data buffer. */ @@ -1143,7 +1142,7 @@ apply_protection (gcry_mpi_t *array, int npkey, int nskey, xfree (bufarr[i]); bufarr[i] = NULL; } - assert (p == data + ndata - 20); + log_assert (p == data + ndata - 20); /* Append a hash of the secret key parameters. */ gcry_md_hash_buffer (GCRY_MD_SHA1, p, data, ndata - 20); diff --git a/agent/findkey.c b/agent/findkey.c index 20c9dc56a..370050d8b 100644 --- a/agent/findkey.c +++ b/agent/findkey.c @@ -26,10 +26,8 @@ #include #include #include -#include #include #include -#include #include /* (we use pth_sleep) */ #include "agent.h" @@ -336,7 +334,7 @@ try_unprotect_cb (struct pin_entry_info_s *pi) gnupg_isotime_t now, protected_at, tmptime; char *desc = NULL; - assert (!arg->unprotected_key); + log_assert (!arg->unprotected_key); arg->change_required = 0; err = agent_unprotect (ctrl, arg->protected_key, pi->pin, protected_at, @@ -740,7 +738,7 @@ unprotect (ctrl_t ctrl, const char *cache_nonce, const char *desc_text, } else { - assert (arg.unprotected_key); + log_assert (arg.unprotected_key); if (arg.change_required) { /* The callback told as that the user should change their @@ -748,7 +746,7 @@ unprotect (ctrl_t ctrl, const char *cache_nonce, const char *desc_text, size_t canlen, erroff; gcry_sexp_t s_skey; - assert (arg.unprotected_key); + log_assert (arg.unprotected_key); canlen = gcry_sexp_canon_len (arg.unprotected_key, 0, NULL, NULL); rc = gcry_sexp_sscan (&s_skey, &erroff, (char*)arg.unprotected_key, canlen); @@ -1415,7 +1413,7 @@ agent_public_key_from_file (ctrl_t ctrl, such a task. After all that is what we do in protect.c. Need to find common patterns and write a straightformward API to use them. */ - assert (sizeof (size_t) <= sizeof (void*)); + log_assert (sizeof (size_t) <= sizeof (void*)); format = xtrymalloc (15+4+7*npkey+10+15+1+1); if (!format) @@ -1440,14 +1438,14 @@ agent_public_key_from_file (ctrl_t ctrl, *p++ = '('; *p++ = *s++; p = stpcpy (p, " %m)"); - assert (argidx < DIM (args)); + log_assert (argidx < DIM (args)); args[argidx++] = &array[idx]; } *p++ = ')'; if (uri) { p = stpcpy (p, "(uri %b)"); - assert (argidx+1 < DIM (args)); + log_assert (argidx+1 < DIM (args)); uri_intlen = (int)uri_length; args[argidx++] = (void *)&uri_intlen; args[argidx++] = (void *)&uri; @@ -1455,14 +1453,14 @@ agent_public_key_from_file (ctrl_t ctrl, if (comment) { p = stpcpy (p, "(comment %b)"); - assert (argidx+1 < DIM (args)); + log_assert (argidx+1 < DIM (args)); comment_intlen = (int)comment_length; args[argidx++] = (void *)&comment_intlen; args[argidx++] = (void*)&comment; } *p++ = ')'; *p = 0; - assert (argidx < DIM (args)); + log_assert (argidx < DIM (args)); args[argidx] = NULL; err = gcry_sexp_build_array (&list, NULL, format, args); @@ -1559,7 +1557,7 @@ agent_key_info_from_file (ctrl_t ctrl, const unsigned char *grip, if (!err) { n = gcry_sexp_canon_len (s, 0, NULL, NULL); - assert (n); + log_assert (n); *r_shadow_info = xtrymalloc (n); if (!*r_shadow_info) err = gpg_error_from_syserror (); diff --git a/agent/genkey.c b/agent/genkey.c index 84342f9ea..46a772eda 100644 --- a/agent/genkey.c +++ b/agent/genkey.c @@ -24,7 +24,6 @@ #include #include #include -#include #include "agent.h" #include "../common/i18n.h" @@ -47,12 +46,12 @@ store_key (gcry_sexp_t private, const char *passphrase, int force, } len = gcry_sexp_sprint (private, GCRYSEXP_FMT_CANON, NULL, 0); - assert (len); + log_assert (len); buf = gcry_malloc_secure (len); if (!buf) return out_of_core (); len = gcry_sexp_sprint (private, GCRYSEXP_FMT_CANON, buf, len); - assert (len); + log_assert (len); if (passphrase) { @@ -127,7 +126,7 @@ check_passphrase_pattern (ctrl_t ctrl, const char *pw) argv[i++] = "--", argv[i++] = opt.check_passphrase_pattern, argv[i] = NULL; - assert (i < sizeof argv); + log_assert (i < sizeof argv); if (gnupg_spawn_process_fd (pgmname, argv, fileno (infp), -1, -1, &pid)) result = 1; /* Execute error - assume password should no be used. */ @@ -557,7 +556,7 @@ agent_genkey (ctrl_t ctrl, const char *cache_nonce, if (DBG_CRYPTO) log_debug ("returning public key\n"); len = gcry_sexp_sprint (s_public, GCRYSEXP_FMT_CANON, NULL, 0); - assert (len); + log_assert (len); buf = xtrymalloc (len); if (!buf) { @@ -567,7 +566,7 @@ agent_genkey (ctrl_t ctrl, const char *cache_nonce, return tmperr; } len = gcry_sexp_sprint (s_public, GCRYSEXP_FMT_CANON, buf, len); - assert (len); + log_assert (len); put_membuf (outbuf, buf, len); gcry_sexp_release (s_public); xfree (buf); diff --git a/agent/gpg-agent.c b/agent/gpg-agent.c index d9e2bbf25..d3fe7fe56 100644 --- a/agent/gpg-agent.c +++ b/agent/gpg-agent.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -1952,7 +1951,7 @@ agent_set_progress_cb (void (*cb)(ctrl_t ctrl, const char *what, static void agent_init_default_ctrl (ctrl_t ctrl) { - assert (ctrl->session_env); + log_assert (ctrl->session_env); /* Note we ignore malloc errors because we can't do much about it and the request will fail anyway shortly after this diff --git a/agent/learncard.c b/agent/learncard.c index f3219ed8f..f40f5ac4d 100644 --- a/agent/learncard.c +++ b/agent/learncard.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include diff --git a/agent/pkdecrypt.c b/agent/pkdecrypt.c index 06a8e0b6f..a0ced2f55 100644 --- a/agent/pkdecrypt.c +++ b/agent/pkdecrypt.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include @@ -119,10 +118,10 @@ agent_pkdecrypt (ctrl_t ctrl, const char *desc_text, gcry_sexp_dump (s_plain); } len = gcry_sexp_sprint (s_plain, GCRYSEXP_FMT_CANON, NULL, 0); - assert (len); + log_assert (len); buf = xmalloc (len); len = gcry_sexp_sprint (s_plain, GCRYSEXP_FMT_CANON, buf, len); - assert (len); + log_assert (len); if (*buf == '(') put_membuf (outbuf, buf, len); else diff --git a/agent/pksign.c b/agent/pksign.c index 828e63f58..bc8d7336a 100644 --- a/agent/pksign.c +++ b/agent/pksign.c @@ -24,8 +24,6 @@ #include #include #include -#include -#include #include #include "agent.h" @@ -250,13 +248,13 @@ do_encode_raw_pkcs1 (const byte *md, size_t mdlen, unsigned int nbits, frame[n++] = 0; frame[n++] = 1; /* Block type. */ i = nframe - mdlen - 3 ; - assert (i >= 8); /* At least 8 bytes of padding. */ + log_assert (i >= 8); /* At least 8 bytes of padding. */ memset (frame+n, 0xff, i ); n += i; frame[n++] = 0; memcpy (frame+n, md, mdlen ); n += mdlen; - assert (n == nframe); + log_assert (n == nframe); /* Create the S-expression. */ rc = gcry_sexp_build (&hash, NULL, diff --git a/agent/preset-passphrase.c b/agent/preset-passphrase.c index 7a9ea1b44..e22e9d58d 100644 --- a/agent/preset-passphrase.c +++ b/agent/preset-passphrase.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #ifdef HAVE_LOCALE_H diff --git a/agent/protect-tool.c b/agent/protect-tool.c index 30d78cd43..059a9bdbd 100644 --- a/agent/protect-tool.c +++ b/agent/protect-tool.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #ifdef HAVE_LOCALE_H @@ -198,10 +197,10 @@ make_canonical (const char *fname, const char *buf, size_t buflen) return NULL; } len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_CANON, NULL, 0); - assert (len); + log_assert (len); result = xmalloc (len); len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_CANON, result, len); - assert (len); + log_assert (len); gcry_sexp_release (sexp); return result; } @@ -222,10 +221,10 @@ make_advanced (const unsigned char *buf, size_t buflen) return NULL; } len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_ADVANCED, NULL, 0); - assert (len); + log_assert (len); result = xmalloc (len); len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_ADVANCED, result, len); - assert (len); + log_assert (len); gcry_sexp_release (sexp); return result; } @@ -433,7 +432,7 @@ read_and_shadow (const char *fname) return; } resultlen = gcry_sexp_canon_len (result, 0, NULL,NULL); - assert (resultlen); + log_assert (resultlen); if (opt_armor) { @@ -469,7 +468,7 @@ show_shadow_info (const char *fname) return; } infolen = gcry_sexp_canon_len (info, 0, NULL,NULL); - assert (infolen); + log_assert (infolen); if (opt_armor) { @@ -496,7 +495,7 @@ show_file (const char *fname) return; keylen = gcry_sexp_canon_len (key, 0, NULL,NULL); - assert (keylen); + log_assert (keylen); if (opt_canonical) { @@ -723,7 +722,7 @@ get_passphrase (int promptno) gpg_strerror (err)); agent_exit (0); } - assert (pw); + log_assert (pw); return pw; } diff --git a/agent/protect.c b/agent/protect.c index c7fb773e1..e3bbf3ed5 100644 --- a/agent/protect.c +++ b/agent/protect.c @@ -528,7 +528,7 @@ do_encryption (const unsigned char *hashbegin, size_t hashlen, memcpy (p, iv+blklen, blklen); /* Add padding. */ p += blklen; } - assert ( p - outbuf == outlen); + log_assert ( p - outbuf == outlen); if (use_ocb) { gcry_cipher_final (hd); @@ -718,11 +718,11 @@ agent_protect (const unsigned char *plainkey, const char *passphrase, hash_end = s; s++; /* Skip to the end of the S-expression. */ - assert (depth == 1); + log_assert (depth == 1); rc = sskip (&s, &depth); if (rc) return rc; - assert (!depth); + log_assert (!depth); real_end = s-1; rc = do_encryption (hash_begin, hash_end - hash_begin + 1, @@ -760,7 +760,7 @@ agent_protect (const unsigned char *plainkey, const char *passphrase, memcpy (p, prot_end+1, real_end - prot_end); p += real_end - prot_end; - assert ( p - *result == *resultlen); + log_assert ( p - *result == *resultlen); xfree (protected); return 0; @@ -999,7 +999,7 @@ merge_lists (const unsigned char *protectedkey, /* Skip over the protected list element in the original list. */ s = protectedkey + replacepos; - assert (*s == '('); + log_assert (*s == '('); s++; i = 1; rc = sskip (&s, &i); @@ -1026,7 +1026,7 @@ merge_lists (const unsigned char *protectedkey, rc = sskip (&s, &i); if (rc) goto failure; - assert (s[-1] == ')'); + log_assert (s[-1] == ')'); endpos = s; /* one behind the end of the list */ /* Append the rest. */ @@ -1571,7 +1571,7 @@ agent_shadow_key (const unsigned char *pubkey, point = s; /* insert right before the point */ depth--; s++; - assert (depth == 1); + log_assert (depth == 1); /* Calculate required length by taking in account: the "shadowed-" prefix, the "shadowed", "t1-v1" as well as some parenthesis */ diff --git a/agent/trans.c b/agent/trans.c index ff1a34e68..9d090ff86 100644 --- a/agent/trans.c +++ b/agent/trans.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include diff --git a/agent/trustlist.c b/agent/trustlist.c index af177b2e2..d91e92e07 100644 --- a/agent/trustlist.c +++ b/agent/trustlist.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include @@ -550,7 +549,7 @@ insert_colons (const char *string) } } *p = 0; - assert (strlen (buffer) <= nnew); + log_assert (strlen (buffer) <= nnew); return buffer; } From 22e274f839f9a6c9a511648f29cae497f6492c97 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 14 May 2019 13:36:08 +0200 Subject: [PATCH 072/169] sm: Change keydb code to use the keybox locking. * kbx/keybox-init.c (keybox_lock): New arg TIMEOUT. Change all callers to pass -1 when locking. * sm/keydb.c (struct resource_item): Remove LOCKANDLE. (struct keydb_handle): Add KEEP_LOCK. (keydb_add_resource): Use keybox locking instead of a separate dotlock for testing whether we can run a compress. (keydb_release): Reset KEEP_LOCK. (keydb_lock): Set KEEP_LOCK. (unlock_all): Take care of KEEP_LOCK. (lock_all): Use keybox_lock instead of dotlock fucntions. (keydb_delete): Remove arg UNLOCK. * sm/delete.c (delete_one): Adjust keydb_delete. Due to the KEEP_LOCK the keydb_release takes care of unlocking. -- This aligns the code more with g10/keydb.c and avoids the separate calls to dotlock_take. GnuPG-bug-id: 4505 Signed-off-by: Werner Koch --- g10/keydb.c | 8 +++--- kbx/keybox-init.c | 13 ++++++--- kbx/keybox.h | 2 +- sm/delete.c | 5 ++-- sm/keydb.c | 72 +++++++++++++++++++++++------------------------ sm/keydb.h | 2 +- 6 files changed, 53 insertions(+), 49 deletions(-) diff --git a/g10/keydb.c b/g10/keydb.c index 8c067e1df..45eb4aa34 100644 --- a/g10/keydb.c +++ b/g10/keydb.c @@ -1,6 +1,6 @@ /* keydb.c - key database dispatcher * Copyright (C) 2001-2013 Free Software Foundation, Inc. - * Coyrright (C) 2001-2015 Werner Koch + * Copyright (C) 2001-2015 Werner Koch * * This file is part of GnuPG. * @@ -1076,7 +1076,7 @@ lock_all (KEYDB_HANDLE hd) rc = keyring_lock (hd->active[i].u.kr, 1); break; case KEYDB_RESOURCE_TYPE_KEYBOX: - rc = keybox_lock (hd->active[i].u.kb, 1); + rc = keybox_lock (hd->active[i].u.kb, 1, -1); break; } } @@ -1094,7 +1094,7 @@ lock_all (KEYDB_HANDLE hd) keyring_lock (hd->active[i].u.kr, 0); break; case KEYDB_RESOURCE_TYPE_KEYBOX: - keybox_lock (hd->active[i].u.kb, 0); + keybox_lock (hd->active[i].u.kb, 0, 0); break; } } @@ -1127,7 +1127,7 @@ unlock_all (KEYDB_HANDLE hd) keyring_lock (hd->active[i].u.kr, 0); break; case KEYDB_RESOURCE_TYPE_KEYBOX: - keybox_lock (hd->active[i].u.kb, 0); + keybox_lock (hd->active[i].u.kb, 0, 0); break; } } diff --git a/kbx/keybox-init.c b/kbx/keybox-init.c index 6a83f7162..9a65c1345 100644 --- a/kbx/keybox-init.c +++ b/kbx/keybox-init.c @@ -261,10 +261,12 @@ _keybox_close_file (KEYBOX_HANDLE hd) /* - * Lock the keybox at handle HD, or unlock if YES is false. + * Lock the keybox at handle HD, or unlock if YES is false. TIMEOUT + * is the value used for dotlock_take. In general -1 should be used + * when taking a lock; use 0 when releasing a lock. */ gpg_error_t -keybox_lock (KEYBOX_HANDLE hd, int yes) +keybox_lock (KEYBOX_HANDLE hd, int yes, long timeout) { gpg_error_t err = 0; KB_NAME kb = hd->kb; @@ -302,10 +304,13 @@ keybox_lock (KEYBOX_HANDLE hd, int yes) hd->fp = NULL; } #endif /*HAVE_W32_SYSTEM*/ - if (dotlock_take (kb->lockhd, -1)) + if (dotlock_take (kb->lockhd, timeout)) { err = gpg_error_from_syserror (); - log_info ("can't lock '%s'\n", kb->fname ); + if (!timeout && gpg_err_code (err) == GPG_ERR_EACCES) + ; /* No diagnostic if we only tried to lock. */ + else + log_info ("can't lock '%s'\n", kb->fname ); } else kb->is_locked = 1; diff --git a/kbx/keybox.h b/kbx/keybox.h index 665b05fc0..4d941571e 100644 --- a/kbx/keybox.h +++ b/kbx/keybox.h @@ -76,7 +76,7 @@ void keybox_pop_found_state (KEYBOX_HANDLE hd); const char *keybox_get_resource_name (KEYBOX_HANDLE hd); int keybox_set_ephemeral (KEYBOX_HANDLE hd, int yes); -gpg_error_t keybox_lock (KEYBOX_HANDLE hd, int yes); +gpg_error_t keybox_lock (KEYBOX_HANDLE hd, int yes, long timeout); /*-- keybox-file.c --*/ /* Fixme: This function does not belong here: Provide a better diff --git a/sm/delete.c b/sm/delete.c index f359cc595..b370406de 100644 --- a/sm/delete.c +++ b/sm/delete.c @@ -113,7 +113,8 @@ delete_one (ctrl_t ctrl, const char *username) goto leave; } - /* We need to search again to get back to the right position. */ + /* We need to search again to get back to the right position. Neo + * that the lock is kept until the KH is released. */ rc = keydb_lock (kh); if (rc) { @@ -132,7 +133,7 @@ delete_one (ctrl_t ctrl, const char *username) goto leave; } - rc = keydb_delete (kh, duplicates ? 0 : 1); + rc = keydb_delete (kh); if (rc) goto leave; if (opt.verbose) diff --git a/sm/keydb.c b/sm/keydb.c index f66a5766d..0144a8189 100644 --- a/sm/keydb.c +++ b/sm/keydb.c @@ -47,7 +47,6 @@ struct resource_item { KEYBOX_HANDLE kr; } u; void *token; - dotlock_t lockhandle; }; static struct resource_item all_resources[MAX_KEYDB_RESOURCES]; @@ -58,7 +57,14 @@ static int any_registered; struct keydb_handle { + + /* If this flag is set the resources is locked. */ int locked; + + /* If this flag is set a lock will only be released by + * keydb_release. */ + int keep_lock; + int found; int saved_found; int current; @@ -346,26 +352,20 @@ keydb_add_resource (ctrl_t ctrl, const char *url, int force, int *auto_created) err = gpg_error (GPG_ERR_RESOURCE_LIMIT); else { + KEYBOX_HANDLE kbxhd; + all_resources[used_resources].type = rt; all_resources[used_resources].u.kr = NULL; /* Not used here */ all_resources[used_resources].token = token; - all_resources[used_resources].lockhandle - = dotlock_create (filename, 0); - if (!all_resources[used_resources].lockhandle) - log_fatal ( _("can't create lock for '%s'\n"), filename); - - /* Do a compress run if needed and the file is not locked. */ - if (!dotlock_take (all_resources[used_resources].lockhandle, 0)) + /* Do a compress run if needed and the keybox is not locked. */ + kbxhd = keybox_new_x509 (token, 0); + if (kbxhd) { - KEYBOX_HANDLE kbxhd = keybox_new_x509 (token, 0); + if (!keybox_lock (kbxhd, 1, 0)) + keybox_compress (kbxhd); - if (kbxhd) - { - keybox_compress (kbxhd); - keybox_release (kbxhd); - } - dotlock_release (all_resources[used_resources].lockhandle); + keybox_release (kbxhd); } used_resources++; @@ -415,7 +415,6 @@ keydb_new (void) case KEYDB_RESOURCE_TYPE_KEYBOX: hd->active[j].type = all_resources[i].type; hd->active[j].token = all_resources[i].token; - hd->active[j].lockhandle = all_resources[i].lockhandle; hd->active[j].u.kr = keybox_new_x509 (all_resources[i].token, 0); if (!hd->active[j].u.kr) { @@ -442,6 +441,7 @@ keydb_release (KEYDB_HANDLE hd) assert (active_handles > 0); active_handles--; + hd->keep_lock = 0; unlock_all (hd); for (i=0; i < hd->used; i++) { @@ -526,17 +526,22 @@ keydb_set_ephemeral (KEYDB_HANDLE hd, int yes) /* If the keyring has not yet been locked, lock it now. This - operation is required before any update operation; it is optional - for an insert operation. The lock is released with - keydb_released. */ + * operation is required before any update operation; it is optional + * for an insert operation. The lock is kept until a keydb_release so + * that internal unlock_all calls have no effect. */ gpg_error_t keydb_lock (KEYDB_HANDLE hd) { + gpg_error_t err; + if (!hd) return gpg_error (GPG_ERR_INV_HANDLE); - if (hd->locked) - return 0; /* Already locked. */ - return lock_all (hd); + + err = lock_all (hd); + if (!err) + hd->keep_lock = 1; + + return err; } @@ -556,8 +561,7 @@ lock_all (KEYDB_HANDLE hd) case KEYDB_RESOURCE_TYPE_NONE: break; case KEYDB_RESOURCE_TYPE_KEYBOX: - if (hd->active[i].lockhandle) - rc = dotlock_take (hd->active[i].lockhandle, -1); + rc = keybox_lock (hd->active[i].u.kr, 1, -1); break; } if (rc) @@ -566,7 +570,7 @@ lock_all (KEYDB_HANDLE hd) if (rc) { - /* revert the already set locks */ + /* Revert the already set locks. */ for (i--; i >= 0; i--) { switch (hd->active[i].type) @@ -574,8 +578,7 @@ lock_all (KEYDB_HANDLE hd) case KEYDB_RESOURCE_TYPE_NONE: break; case KEYDB_RESOURCE_TYPE_KEYBOX: - if (hd->active[i].lockhandle) - dotlock_release (hd->active[i].lockhandle); + keybox_lock (hd->active[i].u.kr, 0, 0); break; } } @@ -583,10 +586,7 @@ lock_all (KEYDB_HANDLE hd) else hd->locked = 1; - /* make_dotlock () does not yet guarantee that errno is set, thus - we can't rely on the error reason and will simply use - EACCES. */ - return rc? gpg_error (GPG_ERR_EACCES) : 0; + return rc; } static void @@ -594,7 +594,7 @@ unlock_all (KEYDB_HANDLE hd) { int i; - if (!hd->locked) + if (!hd->locked || hd->keep_lock) return; for (i=hd->used-1; i >= 0; i--) @@ -604,8 +604,7 @@ unlock_all (KEYDB_HANDLE hd) case KEYDB_RESOURCE_TYPE_NONE: break; case KEYDB_RESOURCE_TYPE_KEYBOX: - if (hd->active[i].lockhandle) - dotlock_release (hd->active[i].lockhandle); + keybox_lock (hd->active[i].u.kr, 0, 0); break; } } @@ -840,7 +839,7 @@ keydb_update_cert (KEYDB_HANDLE hd, ksba_cert_t cert) * The current keyblock or cert will be deleted. */ int -keydb_delete (KEYDB_HANDLE hd, int unlock) +keydb_delete (KEYDB_HANDLE hd) { int rc = -1; @@ -866,8 +865,7 @@ keydb_delete (KEYDB_HANDLE hd, int unlock) break; } - if (unlock) - unlock_all (hd); + unlock_all (hd); return rc; } diff --git a/sm/keydb.h b/sm/keydb.h index 623462553..20dcdbe4d 100644 --- a/sm/keydb.h +++ b/sm/keydb.h @@ -49,7 +49,7 @@ int keydb_get_cert (KEYDB_HANDLE hd, ksba_cert_t *r_cert); int keydb_insert_cert (KEYDB_HANDLE hd, ksba_cert_t cert); int keydb_update_cert (KEYDB_HANDLE hd, ksba_cert_t cert); -int keydb_delete (KEYDB_HANDLE hd, int unlock); +int keydb_delete (KEYDB_HANDLE hd); int keydb_locate_writable (KEYDB_HANDLE hd, const char *reserved); void keydb_rebuild_caches (void); From 49b236af0ecbb6df67513feb4b63851f2e159ea2 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 14 May 2019 19:05:58 +0200 Subject: [PATCH 073/169] kbx: Fix deadlock in gpgsm on Windows due to a sharing violation. * kbx/keybox-init.c (keybox_lock) [W32]: Use _keybox_close_file instead of fclose so that a close is done if the file is opened by another handle. * kbx/keybox-search.c (keybox_search): Remember the last offset and use that in NEXT search mode if we had to re-open the file. -- GnuPG-bug-id: 4505 Signed-off-by: Werner Koch --- kbx/keybox-init.c | 20 ++++++++------------ kbx/keybox-search.c | 34 +++++++++++++++++++++++++++++++++- kbx/keybox-update.c | 2 +- 3 files changed, 42 insertions(+), 14 deletions(-) diff --git a/kbx/keybox-init.c b/kbx/keybox-init.c index 9a65c1345..2223f4d15 100644 --- a/kbx/keybox-init.c +++ b/kbx/keybox-init.c @@ -291,18 +291,14 @@ keybox_lock (KEYBOX_HANDLE hd, int yes, long timeout) if (!kb->is_locked) { #ifdef HAVE_W32_SYSTEM - /* Under Windows we need to close the file before we try - * to lock it. This is because another process might have - * taken the lock and is using keybox_file_rename to - * rename the base file. How if our dotlock_take below is - * waiting for the lock but we have the base file still - * open, keybox_file_rename will never succeed as we are - * in a deadlock. */ - if (hd->fp) - { - fclose (hd->fp); - hd->fp = NULL; - } + /* Under Windows we need to close the file before we try + * to lock it. This is because another process might have + * taken the lock and is using keybox_file_rename to + * rename the base file. Now if our dotlock_take below is + * waiting for the lock but we have the base file still + * open, keybox_file_rename will never succeed as we are + * in a deadlock. */ + _keybox_close_file (hd); #endif /*HAVE_W32_SYSTEM*/ if (dotlock_take (kb->lockhd, timeout)) { diff --git a/kbx/keybox-search.c b/kbx/keybox-search.c index 101e1b5ea..1600861a8 100644 --- a/kbx/keybox-search.c +++ b/kbx/keybox-search.c @@ -873,16 +873,21 @@ keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc, KEYBOXBLOB blob = NULL; struct sn_array_s *sn_array = NULL; int pk_no, uid_no; + off_t lastfoundoff; if (!hd) return gpg_error (GPG_ERR_INV_VALUE); - /* clear last found result */ + /* Clear last found result but reord the offset of the last found + * blob which we may need later. */ if (hd->found.blob) { + lastfoundoff = _keybox_get_blob_fileoffset (hd->found.blob); _keybox_release_blob (hd->found.blob); hd->found.blob = NULL; } + else + lastfoundoff = 0; if (hd->error) return hd->error; /* still in error state */ @@ -901,6 +906,7 @@ keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc, case KEYDB_SEARCH_MODE_FIRST: /* always restart the search in this mode */ keybox_search_reset (hd); + lastfoundoff = 0; break; default: break; @@ -925,6 +931,32 @@ keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc, xfree (sn_array); return rc; } + /* log_debug ("%s: re-opened file\n", __func__); */ + if (ndesc && desc[0].mode == KEYDB_SEARCH_MODE_NEXT && lastfoundoff) + { + /* Search mode is next and the last search operation + * returned a blob which also was not the first one. We now + * need to skip over that blob and hope that the file has + * not changed. */ + if (fseeko (hd->fp, lastfoundoff, SEEK_SET)) + { + rc = gpg_error_from_syserror (); + log_debug ("%s: seeking to last found offset failed: %s\n", + __func__, gpg_strerror (rc)); + xfree (sn_array); + return gpg_error (GPG_ERR_NOTHING_FOUND); + } + /* log_debug ("%s: re-opened file and sought to last offset\n", */ + /* __func__); */ + rc = _keybox_read_blob (NULL, hd->fp, NULL); + if (rc) + { + log_debug ("%s: skipping last found blob failed: %s\n", + __func__, gpg_strerror (rc)); + xfree (sn_array); + return gpg_error (GPG_ERR_NOTHING_FOUND); + } + } } /* Kludge: We need to convert an SN given as hexstring to its binary diff --git a/kbx/keybox-update.c b/kbx/keybox-update.c index 580330f52..e09fefc41 100644 --- a/kbx/keybox-update.c +++ b/kbx/keybox-update.c @@ -423,7 +423,7 @@ keybox_update_keyblock (KEYBOX_HANDLE hd, const void *image, size_t imagelen) if (off == (off_t)-1) return gpg_error (GPG_ERR_GENERAL); - /* Close this the file so that we do no mess up the position for a + /* Close the file so that we do no mess up the position for a next search. */ _keybox_close_file (hd); From 62c29af63203400947569c5965a8cf05a22fcd4c Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Wed, 15 May 2019 15:44:32 +0900 Subject: [PATCH 074/169] scd: Fix return value for KEYINFO command. * scd/command.c (cmd_keyinfo): Return GPG_ERR_NOT_FOUND if none. Signed-off-by: NIIBE Yutaka --- scd/command.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/scd/command.c b/scd/command.c index 3bfc1a5db..6b80341e4 100644 --- a/scd/command.c +++ b/scd/command.c @@ -1851,6 +1851,7 @@ cmd_keyinfo (assuan_context_t ctx, char *line) int action; char *keygrip_str; ctrl_t ctrl = assuan_get_pointer (ctx); + app_t a; list_mode = has_option (line, "--list"); opt_data = has_option (line, "--data"); @@ -1866,8 +1867,10 @@ cmd_keyinfo (assuan_context_t ctx, char *line) else action = KEYGRIP_ACTION_WRITE_STATUS; - app_do_with_keygrip (ctrl, action, keygrip_str); + a = app_do_with_keygrip (ctrl, action, keygrip_str); + if (!list_mode && !a) + return gpg_error (GPG_ERR_NOT_FOUND); return 0; } From 6e041b7b356c3adba714e98f4ecf0dd007375390 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 14 May 2019 20:03:44 +0200 Subject: [PATCH 075/169] sm: Add a couple of debug calls to the keydb module. * sm/gpgsm.h (DBG_CLOCK_VALUE, DBG_CLOCK): New. (DBG_LOOKUP_VALUE, DBG_LOOKUP): New. * sm/gpgsm.c: new debug flags "lookup" and "clock" * sm/keydb.c: Add log_clock calls to most functions. (keydb_search_desc_dump): New. (keydb_search) [DBG_LOOKUP]: Print descrh decription. * sm/keylist.c (list_cert_std): Flush FP in debug mode to better syncronize the output with the debug output -- Signed-off-by: Werner Koch --- sm/gpgsm.c | 2 + sm/gpgsm.h | 4 + sm/keydb.c | 260 ++++++++++++++++++++++++++++++++++++++++++--------- sm/keydb.h | 6 +- sm/keylist.c | 2 + 5 files changed, 229 insertions(+), 45 deletions(-) diff --git a/sm/gpgsm.c b/sm/gpgsm.c index b9694b2e9..f5837079d 100644 --- a/sm/gpgsm.c +++ b/sm/gpgsm.c @@ -430,6 +430,8 @@ static struct debug_flags_s debug_flags [] = { DBG_MEMSTAT_VALUE, "memstat" }, { DBG_HASHING_VALUE, "hashing" }, { DBG_IPC_VALUE , "ipc" }, + { DBG_CLOCK_VALUE , "clock" }, + { DBG_LOOKUP_VALUE , "lookup" }, { 0, NULL } }; diff --git a/sm/gpgsm.h b/sm/gpgsm.h index c15d8dc4f..4ad0afb29 100644 --- a/sm/gpgsm.h +++ b/sm/gpgsm.h @@ -175,6 +175,8 @@ struct #define DBG_MEMSTAT_VALUE 128 /* show memory statistics */ #define DBG_HASHING_VALUE 512 /* debug hashing operations */ #define DBG_IPC_VALUE 1024 /* debug assuan communication */ +#define DBG_CLOCK_VALUE 4096 +#define DBG_LOOKUP_VALUE 8192 /* debug the key lookup */ #define DBG_X509 (opt.debug & DBG_X509_VALUE) #define DBG_CRYPTO (opt.debug & DBG_CRYPTO_VALUE) @@ -182,6 +184,8 @@ struct #define DBG_CACHE (opt.debug & DBG_CACHE_VALUE) #define DBG_HASHING (opt.debug & DBG_HASHING_VALUE) #define DBG_IPC (opt.debug & DBG_IPC_VALUE) +#define DBG_CLOCK (opt.debug & DBG_CLOCK_VALUE) +#define DBG_LOOKUP (opt.debug & DBG_LOOKUP_VALUE) /* Forward declaration for an object defined in server.c */ struct server_local_s; diff --git a/sm/keydb.c b/sm/keydb.c index 0144a8189..53e3cf887 100644 --- a/sm/keydb.c +++ b/sm/keydb.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include @@ -401,11 +400,14 @@ keydb_new (void) KEYDB_HANDLE hd; int i, j; + if (DBG_CLOCK) + log_clock ("%s: enter\n", __func__); + hd = xcalloc (1, sizeof *hd); hd->found = -1; hd->saved_found = -1; - assert (used_resources <= MAX_KEYDB_RESOURCES); + log_assert (used_resources <= MAX_KEYDB_RESOURCES); for (i=j=0; i < used_resources; i++) { switch (all_resources[i].type) @@ -428,6 +430,8 @@ keydb_new (void) hd->used = j; active_handles++; + if (DBG_CLOCK) + log_clock ("%s: leave (hd=%p)\n", __func__, hd); return hd; } @@ -438,7 +442,11 @@ keydb_release (KEYDB_HANDLE hd) if (!hd) return; - assert (active_handles > 0); + + if (DBG_CLOCK) + log_clock ("%s: enter (hd=%p)\n", __func__, hd); + + log_assert (active_handles > 0); active_handles--; hd->keep_lock = 0; @@ -455,7 +463,9 @@ keydb_release (KEYDB_HANDLE hd) } } - xfree (hd); + xfree (hd); + if (DBG_CLOCK) + log_clock ("%s: leave\n", __func__); } @@ -537,10 +547,14 @@ keydb_lock (KEYDB_HANDLE hd) if (!hd) return gpg_error (GPG_ERR_INV_HANDLE); + if (DBG_CLOCK) + log_clock ("%s: enter (hd=%p)\n", __func__, hd); err = lock_all (hd); if (!err) hd->keep_lock = 1; + if (DBG_CLOCK) + log_clock ("%s: leave (err=%s)\n", __func__, gpg_strerror (err)); return err; } @@ -637,6 +651,8 @@ keydb_push_found_state (KEYDB_HANDLE hd) hd->saved_found = hd->found; hd->found = -1; + if (DBG_CLOCK) + log_clock ("%s: done (hd=%p)\n", __func__, hd); } @@ -660,6 +676,8 @@ keydb_pop_found_state (KEYDB_HANDLE hd) keybox_pop_found_state (hd->active[hd->found].u.kr); break; } + if (DBG_CLOCK) + log_clock ("%s: done (hd=%p)\n", __func__, hd); } @@ -677,9 +695,16 @@ keydb_get_cert (KEYDB_HANDLE hd, ksba_cert_t *r_cert) if (!hd) return gpg_error (GPG_ERR_INV_VALUE); - if ( hd->found < 0 || hd->found >= hd->used) - return -1; /* nothing found */ + if (DBG_CLOCK) + log_clock ("%s: enter (hd=%p)\n", __func__, hd); + if ( hd->found < 0 || hd->found >= hd->used) + { + rc = -1; /* nothing found */ + goto leave; + } + + rc = GPG_ERR_BUG; switch (hd->active[hd->found].type) { case KEYDB_RESOURCE_TYPE_NONE: @@ -690,9 +715,13 @@ keydb_get_cert (KEYDB_HANDLE hd, ksba_cert_t *r_cert) break; } + leave: + if (DBG_CLOCK) + log_clock ("%s: leave (rc=%d)\n", __func__, rc); return rc; } + /* Return a flag of the last found object. WHICH is the flag requested; it should be one of the KEYBOX_FLAG_ values. If the operation is successful, the flag value will be stored at the address given by @@ -700,14 +729,21 @@ keydb_get_cert (KEYDB_HANDLE hd, ksba_cert_t *r_cert) gpg_error_t keydb_get_flags (KEYDB_HANDLE hd, int which, int idx, unsigned int *value) { - int err = 0; + gpg_error_t err; if (!hd) return gpg_error (GPG_ERR_INV_VALUE); - if ( hd->found < 0 || hd->found >= hd->used) - return gpg_error (GPG_ERR_NOTHING_FOUND); + if (DBG_CLOCK) + log_clock ("%s: enter (hd=%p)\n", __func__, hd); + if ( hd->found < 0 || hd->found >= hd->used) + { + err = gpg_error (GPG_ERR_NOTHING_FOUND); + goto leave; + } + + err = gpg_error (GPG_ERR_BUG); switch (hd->active[hd->found].type) { case KEYDB_RESOURCE_TYPE_NONE: @@ -718,9 +754,13 @@ keydb_get_flags (KEYDB_HANDLE hd, int which, int idx, unsigned int *value) break; } + leave: + if (DBG_CLOCK) + log_clock ("%s: leave (err=%s)\n", __func__, gpg_strerror (err)); return err; } + /* Set a flag of the last found object. WHICH is the flag to be set; it should be one of the KEYBOX_FLAG_ values. If the operation is successful, the flag value will be stored in the keybox. Note, @@ -730,16 +770,25 @@ keydb_get_flags (KEYDB_HANDLE hd, int which, int idx, unsigned int *value) gpg_error_t keydb_set_flags (KEYDB_HANDLE hd, int which, int idx, unsigned int value) { - int err = 0; + gpg_error_t err = 0; if (!hd) return gpg_error (GPG_ERR_INV_VALUE); + if (DBG_CLOCK) + log_clock ("%s: enter (hd=%p)\n", __func__, hd); + if ( hd->found < 0 || hd->found >= hd->used) - return gpg_error (GPG_ERR_NOTHING_FOUND); + { + err = gpg_error (GPG_ERR_NOTHING_FOUND); + goto leave; + } if (!hd->locked) - return gpg_error (GPG_ERR_NOT_LOCKED); + { + err = gpg_error (GPG_ERR_NOT_LOCKED); + goto leave; + } switch (hd->active[hd->found].type) { @@ -751,16 +800,19 @@ keydb_set_flags (KEYDB_HANDLE hd, int which, int idx, unsigned int value) break; } + leave: + if (DBG_CLOCK) + log_clock ("%s: leave (err=%s)\n", __func__, gpg_strerror (err)); return err; } /* * Insert a new Certificate into one of the resources. */ -int +gpg_error_t keydb_insert_cert (KEYDB_HANDLE hd, ksba_cert_t cert) { - int rc = -1; + gpg_error_t err; int idx; unsigned char digest[20]; @@ -770,103 +822,136 @@ keydb_insert_cert (KEYDB_HANDLE hd, ksba_cert_t cert) if (opt.dry_run) return 0; + if (DBG_CLOCK) + log_clock ("%s: enter (hd=%p)\n", __func__, hd); + if ( hd->found >= 0 && hd->found < hd->used) idx = hd->found; else if ( hd->current >= 0 && hd->current < hd->used) idx = hd->current; else - return gpg_error (GPG_ERR_GENERAL); + { + err = gpg_error (GPG_ERR_GENERAL); + goto leave; + } if (!hd->locked) - return gpg_error (GPG_ERR_NOT_LOCKED); + { + err = gpg_error (GPG_ERR_NOT_LOCKED); + goto leave; + } gpgsm_get_fingerprint (cert, GCRY_MD_SHA1, digest, NULL); /* kludge*/ + err = gpg_error (GPG_ERR_BUG); switch (hd->active[idx].type) { case KEYDB_RESOURCE_TYPE_NONE: - rc = gpg_error (GPG_ERR_GENERAL); + err = gpg_error (GPG_ERR_GENERAL); break; case KEYDB_RESOURCE_TYPE_KEYBOX: - rc = keybox_insert_cert (hd->active[idx].u.kr, cert, digest); + err = keybox_insert_cert (hd->active[idx].u.kr, cert, digest); break; } unlock_all (hd); - return rc; + + leave: + if (DBG_CLOCK) + log_clock ("%s: leave (err=%s)\n", __func__, gpg_strerror (err)); + return err; } /* Update the current keyblock with KB. */ -int +/* Note: This function is currently not called. */ +gpg_error_t keydb_update_cert (KEYDB_HANDLE hd, ksba_cert_t cert) { - int rc = 0; + gpg_error_t err; unsigned char digest[20]; if (!hd) return gpg_error (GPG_ERR_INV_VALUE); if ( hd->found < 0 || hd->found >= hd->used) - return -1; /* nothing found */ + return gpg_error (GPG_ERR_NOT_FOUND); if (opt.dry_run) return 0; - rc = lock_all (hd); - if (rc) - return rc; + if (DBG_CLOCK) + log_clock ("%s: enter (hd=%p)\n", __func__, hd); + + err = lock_all (hd); + if (err) + goto leave; gpgsm_get_fingerprint (cert, GCRY_MD_SHA1, digest, NULL); /* kludge*/ + err = gpg_error (GPG_ERR_BUG); switch (hd->active[hd->found].type) { case KEYDB_RESOURCE_TYPE_NONE: - rc = gpg_error (GPG_ERR_GENERAL); /* oops */ + err = gpg_error (GPG_ERR_GENERAL); /* oops */ break; case KEYDB_RESOURCE_TYPE_KEYBOX: - rc = keybox_update_cert (hd->active[hd->found].u.kr, cert, digest); + err = keybox_update_cert (hd->active[hd->found].u.kr, cert, digest); break; } unlock_all (hd); - return rc; + leave: + if (DBG_CLOCK) + log_clock ("%s: leave (err=%s)\n", __func__, gpg_strerror (err)); + return err; } /* * The current keyblock or cert will be deleted. */ -int +gpg_error_t keydb_delete (KEYDB_HANDLE hd) { - int rc = -1; + gpg_error_t err; if (!hd) return gpg_error (GPG_ERR_INV_VALUE); if ( hd->found < 0 || hd->found >= hd->used) - return -1; /* nothing found */ + return gpg_error (GPG_ERR_NOT_FOUND); - if( opt.dry_run ) + if (opt.dry_run) return 0; - if (!hd->locked) - return gpg_error (GPG_ERR_NOT_LOCKED); + if (DBG_CLOCK) + log_clock ("%s: enter (hd=%p)\n", __func__, hd); + if (!hd->locked) + { + err = gpg_error (GPG_ERR_NOT_LOCKED); + goto leave; + } + + err = gpg_error (GPG_ERR_BUG); switch (hd->active[hd->found].type) { case KEYDB_RESOURCE_TYPE_NONE: - rc = gpg_error (GPG_ERR_GENERAL); + err = gpg_error (GPG_ERR_GENERAL); break; case KEYDB_RESOURCE_TYPE_KEYBOX: - rc = keybox_delete (hd->active[hd->found].u.kr); + err = keybox_delete (hd->active[hd->found].u.kr); break; } unlock_all (hd); - return rc; + + leave: + if (DBG_CLOCK) + log_clock ("%s: leave (err=%s)\n", __func__, gpg_strerror (err)); + return err; } @@ -939,29 +1024,92 @@ keydb_rebuild_caches (void) gpg_error_t keydb_search_reset (KEYDB_HANDLE hd) { + gpg_error_t err = 0; int i; - gpg_error_t rc = 0; if (!hd) return gpg_error (GPG_ERR_INV_VALUE); + if (DBG_CLOCK) + log_clock ("%s: enter (hd=%p)\n", __func__, hd); + hd->current = 0; hd->found = -1; /* and reset all resources */ - for (i=0; !rc && i < hd->used; i++) + for (i=0; !err && i < hd->used; i++) { switch (hd->active[i].type) { case KEYDB_RESOURCE_TYPE_NONE: break; case KEYDB_RESOURCE_TYPE_KEYBOX: - rc = keybox_search_reset (hd->active[i].u.kr); + err = keybox_search_reset (hd->active[i].u.kr); break; } } - return rc; + + if (DBG_CLOCK) + log_clock ("%s: leave (err=%s)\n", __func__, gpg_strerror (err)); + return err; } + +char * +keydb_search_desc_dump (struct keydb_search_desc *desc) +{ + char *fpr; + char *result; + + switch (desc->mode) + { + case KEYDB_SEARCH_MODE_EXACT: + return xasprintf ("EXACT: '%s'", desc->u.name); + case KEYDB_SEARCH_MODE_SUBSTR: + return xasprintf ("SUBSTR: '%s'", desc->u.name); + case KEYDB_SEARCH_MODE_MAIL: + return xasprintf ("MAIL: '%s'", desc->u.name); + case KEYDB_SEARCH_MODE_MAILSUB: + return xasprintf ("MAILSUB: '%s'", desc->u.name); + case KEYDB_SEARCH_MODE_MAILEND: + return xasprintf ("MAILEND: '%s'", desc->u.name); + case KEYDB_SEARCH_MODE_WORDS: + return xasprintf ("WORDS: '%s'", desc->u.name); + case KEYDB_SEARCH_MODE_SHORT_KID: + return xasprintf ("SHORT_KID: '%08lX'", (ulong)desc->u.kid[1]); + case KEYDB_SEARCH_MODE_LONG_KID: + return xasprintf ("LONG_KID: '%08lX%08lX'", + (ulong)desc->u.kid[0], (ulong)desc->u.kid[1]); + case KEYDB_SEARCH_MODE_FPR: + fpr = bin2hexcolon (desc->u.fpr, desc->fprlen, NULL); + result = xasprintf ("FPR%02d: '%s'", desc->fprlen, fpr); + xfree (fpr); + return result; + case KEYDB_SEARCH_MODE_ISSUER: + return xasprintf ("ISSUER: '%s'", desc->u.name); + case KEYDB_SEARCH_MODE_ISSUER_SN: + return xasprintf ("ISSUER_SN: '%*s'", + (int) (desc->snlen == -1 + ? strlen (desc->sn) : desc->snlen), + desc->sn); + case KEYDB_SEARCH_MODE_SN: + return xasprintf ("SN: '%*s'", + (int) (desc->snlen == -1 + ? strlen (desc->sn) : desc->snlen), + desc->sn); + case KEYDB_SEARCH_MODE_SUBJECT: + return xasprintf ("SUBJECT: '%s'", desc->u.name); + case KEYDB_SEARCH_MODE_KEYGRIP: + return xasprintf ("KEYGRIP: %s", desc->u.grip); + case KEYDB_SEARCH_MODE_FIRST: + return xasprintf ("FIRST"); + case KEYDB_SEARCH_MODE_NEXT: + return xasprintf ("NEXT"); + default: + return xasprintf ("Bad search mode (%d)", desc->mode); + } +} + + /* * Search through all keydb resources, starting at the current position, * for a keyblock which contains one of the keys described in the DESC array. @@ -972,6 +1120,7 @@ keydb_search (ctrl_t ctrl, KEYDB_HANDLE hd, { int rc = -1; unsigned long skipped; + int i; if (!hd) return gpg_error (GPG_ERR_INV_VALUE); @@ -983,7 +1132,22 @@ keydb_search (ctrl_t ctrl, KEYDB_HANDLE hd, return gpg_error (GPG_ERR_NOT_FOUND); } - while (rc == -1 && hd->current >= 0 && hd->current < hd->used) + if (DBG_CLOCK) + log_clock ("%s: enter (hd=%p)\n", __func__, hd); + + if (DBG_LOOKUP) + { + log_debug ("%s: %zd search description(s):\n", __func__, ndesc); + for (i = 0; i < ndesc; i ++) + { + char *t = keydb_search_desc_dump (&desc[i]); + log_debug ("%s: %d: %s\n", __func__, i, t); + xfree (t); + } + } + + while ((rc == -1 || gpg_err_code (rc) == GPG_ERR_EOF) + && hd->current >= 0 && hd->current < hd->used) { switch (hd->active[hd->current].type) { @@ -996,6 +1160,15 @@ keydb_search (ctrl_t ctrl, KEYDB_HANDLE hd, NULL, &skipped); break; } + + if (DBG_LOOKUP) + log_debug ("%s: searched %s (resource %d of %d) => %s\n", + __func__, + hd->active[hd->current].type == KEYDB_RESOURCE_TYPE_KEYBOX + ? "keybox" : "unknown type", + hd->current, hd->used, + rc == -1 ? "EOF" : gpg_strerror (rc)); + if (rc == -1 || gpg_err_code (rc) == GPG_ERR_EOF) { /* EOF -> switch to next resource */ hd->current++; @@ -1004,6 +1177,9 @@ keydb_search (ctrl_t ctrl, KEYDB_HANDLE hd, hd->found = hd->current; } + + if (DBG_CLOCK) + log_clock ("%s: leave (rc=%d)\n", __func__, rc); return rc; } diff --git a/sm/keydb.h b/sm/keydb.h index 20dcdbe4d..1ab94a2c2 100644 --- a/sm/keydb.h +++ b/sm/keydb.h @@ -46,10 +46,10 @@ gpg_error_t keydb_set_flags (KEYDB_HANDLE hd, int which, int idx, void keydb_push_found_state (KEYDB_HANDLE hd); void keydb_pop_found_state (KEYDB_HANDLE hd); int keydb_get_cert (KEYDB_HANDLE hd, ksba_cert_t *r_cert); -int keydb_insert_cert (KEYDB_HANDLE hd, ksba_cert_t cert); -int keydb_update_cert (KEYDB_HANDLE hd, ksba_cert_t cert); +gpg_error_t keydb_insert_cert (KEYDB_HANDLE hd, ksba_cert_t cert); +gpg_error_t keydb_update_cert (KEYDB_HANDLE hd, ksba_cert_t cert); -int keydb_delete (KEYDB_HANDLE hd); +gpg_error_t keydb_delete (KEYDB_HANDLE hd); int keydb_locate_writable (KEYDB_HANDLE hd, const char *reserved); void keydb_rebuild_caches (void); diff --git a/sm/keylist.c b/sm/keylist.c index e242310be..4eecb8720 100644 --- a/sm/keylist.c +++ b/sm/keylist.c @@ -1373,6 +1373,8 @@ list_cert_std (ctrl_t ctrl, ksba_cert_t cert, estream_t fp, int have_secret, else es_fprintf (fp, " [certificate is bad: %s]\n", gpg_strerror (err)); } + if (opt.debug) + es_fflush (fp); } From a4be077abdbf286e3dcdeb0553ba0e74b7e2df5f Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 15 May 2019 08:50:15 +0200 Subject: [PATCH 076/169] gpgconf: Support --homedir for --launch. * tools/gpgconf-comp.c (gpg_agent_runtime_change): Simplify because gnupg_homedir already returns abd absolute name. (scdaemon_runtime_change): Ditto. (dirmngr_runtime_change): Ditto. (gc_component_launch): Support --homedir. -- GnuPG-bug-id: 4496 Signed-off-by: Werner Koch --- doc/tools.texi | 2 ++ tools/gpgconf-comp.c | 25 +++++++++---------------- 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/doc/tools.texi b/doc/tools.texi index ba63506f3..7dcd84e2f 100644 --- a/doc/tools.texi +++ b/doc/tools.texi @@ -393,6 +393,8 @@ extends numerical field values by human-readable descriptions. @opindex quiet Try to be as quiet as possible. +@include opt-homedir.texi + @item -n @itemx --dry-run Do not actually change anything. This is currently only implemented diff --git a/tools/gpgconf-comp.c b/tools/gpgconf-comp.c index a55d89874..a308c1c83 100644 --- a/tools/gpgconf-comp.c +++ b/tools/gpgconf-comp.c @@ -1156,12 +1156,8 @@ gpg_agent_runtime_change (int killflag) pgmname = gnupg_module_name (GNUPG_MODULE_NAME_CONNECT_AGENT); if (!gnupg_default_homedir_p ()) { - abs_homedir = make_absfilename_try (gnupg_homedir (), NULL); - if (!abs_homedir) - err = gpg_error_from_syserror (); - argv[i++] = "--homedir"; - argv[i++] = abs_homedir; + argv[i++] = gnupg_homedir (); } argv[i++] = "--no-autostart"; argv[i++] = killflag? "KILLAGENT" : "RELOADAGENT"; @@ -1199,12 +1195,8 @@ scdaemon_runtime_change (int killflag) pgmname = gnupg_module_name (GNUPG_MODULE_NAME_CONNECT_AGENT); if (!gnupg_default_homedir_p ()) { - abs_homedir = make_absfilename_try (gnupg_homedir (), NULL); - if (!abs_homedir) - err = gpg_error_from_syserror (); - argv[i++] = "--homedir"; - argv[i++] = abs_homedir; + argv[i++] = gnupg_homedir (); } argv[i++] = "-s"; argv[i++] = "--no-autostart"; @@ -1243,12 +1235,8 @@ dirmngr_runtime_change (int killflag) argv[3] = NULL; else { - abs_homedir = make_absfilename_try (gnupg_homedir (), NULL); - if (!abs_homedir) - err = gpg_error_from_syserror (); - argv[3] = "--homedir"; - argv[4] = abs_homedir; + argv[4] = gnupg_homedir (); argv[5] = NULL; } @@ -1270,7 +1258,7 @@ gc_component_launch (int component) { gpg_error_t err; const char *pgmname; - const char *argv[3]; + const char *argv[5]; int i; pid_t pid; @@ -1292,6 +1280,11 @@ gc_component_launch (int component) pgmname = gnupg_module_name (GNUPG_MODULE_NAME_CONNECT_AGENT); i = 0; + if (!gnupg_default_homedir_p ()) + { + argv[i++] = "--homedir"; + argv[i++] = gnupg_homedir (); + } if (component == GC_COMPONENT_DIRMNGR) argv[i++] = "--dirmngr"; argv[i++] = "NOP"; From 392e59a3d487e174edcea570e69a0f946c55a19a Mon Sep 17 00:00:00 2001 From: Daniel Kahn Gillmor Date: Mon, 13 May 2019 21:22:38 -0400 Subject: [PATCH 077/169] gpg: enable OpenPGP export of cleartext keys with comments * g10/export.c (cleartext_secret_key_to_openpgp): ignore trailing sublists in private-key S-expression. -- When gpg-agent learns about a private key from its ssh-agent interface, it stores its S-expression with the comment attached. The export mechanism for OpenPGP keys already in cleartext was too brittle because it would choke on these comments. This change lets it ignore any additional trailing sublists. Signed-off-by: Daniel Kahn Gillmor Gnupg-Bug-Id: 4490 --- g10/export.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/g10/export.c b/g10/export.c index 4f6c9137e..b12da9cdb 100644 --- a/g10/export.c +++ b/g10/export.c @@ -596,7 +596,10 @@ cleartext_secret_key_to_openpgp (gcry_sexp_t s_key, PKT_public_key *pk) top_list = gcry_sexp_find_token (s_key, "private-key", 0); if (!top_list) goto bad_seckey; - if (gcry_sexp_length(top_list) != 2) + + /* ignore all S-expression after the first sublist -- we assume that + they are comments or otherwise irrelevant to OpenPGP */ + if (gcry_sexp_length(top_list) < 2) goto bad_seckey; key = gcry_sexp_nth (top_list, 1); if (!key) From 42adb56e660a2e8533ae23cb432037485c2c1022 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 15 May 2019 09:18:28 +0200 Subject: [PATCH 078/169] doc: Do not mention gpg's deprecated --keyserver option. -- GnuPG-bug-id: 4466 --- doc/gpg.texi | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/doc/gpg.texi b/doc/gpg.texi index ddbac0edc..6181ee536 100644 --- a/doc/gpg.texi +++ b/doc/gpg.texi @@ -434,9 +434,8 @@ file given with option @option{--output}. Use together with @item --send-keys @var{keyIDs} @opindex send-keys Similar to @option{--export} but sends the keys to a keyserver. -Fingerprints may be used instead of key IDs. Option -@option{--keyserver} must be used to give the name of this -keyserver. Don't send your complete keyring to a keyserver --- select +Fingerprints may be used instead of key IDs. +Don't send your complete keyring to a keyserver --- select only those keys which are new or changed by you. If no @var{keyIDs} are given, @command{@gpgname} does nothing. @@ -491,27 +490,25 @@ signatures, user-IDs and subkeys. @opindex receive-keys @itemx --recv-keys @var{keyIDs} @opindex recv-keys -Import the keys with the given @var{keyIDs} from a keyserver. Option -@option{--keyserver} must be used to give the name of this keyserver. +Import the keys with the given @var{keyIDs} from a keyserver. @item --refresh-keys @opindex refresh-keys Request updates from a keyserver for keys that already exist on the local keyring. This is useful for updating a key with the latest signatures, user IDs, etc. Calling this with no arguments will refresh -the entire keyring. Option @option{--keyserver} must be used to give the -name of the keyserver for all keys that do not have preferred keyservers -set (see @option{--keyserver-options honor-keyserver-url}). +the entire keyring. @item --search-keys @var{names} @opindex search-keys -Search the keyserver for the given @var{names}. Multiple names given here will -be joined together to create the search string for the keyserver. -Option @option{--keyserver} must be used to give the name of this -keyserver. Keyservers that support different search methods allow using -the syntax specified in "How to specify a user ID" below. Note that -different keyserver types support different search methods. Currently -only LDAP supports them all. +Search the keyserver for the given @var{names}. Multiple names given +here will be joined together to create the search string for the +keyserver. Note that keyservers search for @var{names} in a different +and simpler way than gpg does. The best choice is to use a mail +address. Due to data privacy reasons keyservers may even not even +allow searching by user id or mail address and thus may only return +results when being used with the @option{--recv-key} command to +search by key fingerprint or keyid. @item --fetch-keys @var{URIs} @opindex fetch-keys @@ -1766,12 +1763,11 @@ list. The default is "local,wkd". PGP Universal method of checking @samp{ldap://keys.(thedomain)}. @item keyserver - Locate a key using whatever keyserver is defined using the - @option{--keyserver} option. + Locate a key using a keyserver. @item keyserver-URL - In addition, a keyserver URL as used in the @option{--keyserver} option - may be used here to query that particular keyserver. + In addition, a keyserver URL as used in the @command{dirmngr} + configuration may be used here to query that particular keyserver. @item local Locate the key using the local keyrings. This mechanism allows the user to From 01730529f20882cd98882a61408e9bee960c86f1 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Wed, 15 May 2019 17:12:23 +0900 Subject: [PATCH 079/169] scd: Don't put newline at the end of status. * scd/command.c (send_keyinfo): Remove newline. Signed-off-by: NIIBE Yutaka --- scd/command.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scd/command.c b/scd/command.c index 6b80341e4..9173a6843 100644 --- a/scd/command.c +++ b/scd/command.c @@ -1881,7 +1881,7 @@ send_keyinfo (ctrl_t ctrl, int data, const char *keygrip_str, char *string; assuan_context_t ctx = ctrl->server_local->assuan_ctx; - string = xtryasprintf ("%s T %s %s\n", keygrip_str, + string = xtryasprintf ("%s T %s %s", keygrip_str, serialno? serialno : "-", idstr? idstr : "-"); if (!string) From 1091f22511e1a8259eb5c998f5c207ee95723a4a Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Wed, 15 May 2019 15:53:35 +0900 Subject: [PATCH 080/169] agent: Support scdaemon operation using KEYGRIP. * agent/agent.h (struct card_key_info_s): New. (divert_pksign, divert_pkdecrypt): New API. * agent/call-scd.c (card_keyinfo_cb): New. (agent_card_free_keyinfo, agent_card_keyinfo): New. * agent/divert-scd.c (ask_for_card): Having GRIP argument, ask scdaemon with agent_card_keyinfo. (divert_pksign, divert_pkdecrypt): Ditto. * agent/pkdecrypt.c (agent_pkdecrypt): Supply GRIP. * agent/pksign.c (agent_pksign_do): Ditto. -- We are going to relax the requirment for SERIALNO of card. It's OK, when a card doesn't have recorded SERIALNO. If a card has a key with GRIP, it can be used. GnuPG-bug-id: 2291, 4301 Signed-off-by: NIIBE Yutaka --- agent/agent.h | 14 ++++ agent/call-scd.c | 164 +++++++++++++++++++++++++++++++++++++++++++-- agent/divert-scd.c | 66 +++++++++++------- agent/pkdecrypt.c | 4 +- agent/pksign.c | 1 + 5 files changed, 215 insertions(+), 34 deletions(-) diff --git a/agent/agent.h b/agent/agent.h index b7eacf471..77672bd50 100644 --- a/agent/agent.h +++ b/agent/agent.h @@ -361,6 +361,15 @@ typedef int (*lookup_ttl_t)(const char *hexgrip); #endif +/* Information from scdaemon for card keys. */ +struct card_key_info_s +{ + struct card_key_info_s *next; + char keygrip[40]; + char *serialno; + char *idstr; +}; + /*-- gpg-agent.c --*/ void agent_exit (int rc) GPGRT_ATTR_NORETURN; /* Also implemented in other tools */ @@ -544,10 +553,12 @@ void agent_reload_trustlist (void); /*-- divert-scd.c --*/ int divert_pksign (ctrl_t ctrl, const char *desc_text, + const unsigned char *grip, const unsigned char *digest, size_t digestlen, int algo, const unsigned char *shadow_info, unsigned char **r_sig, size_t *r_siglen); int divert_pkdecrypt (ctrl_t ctrl, const char *desc_text, + const unsigned char *grip, const unsigned char *cipher, const unsigned char *shadow_info, char **r_buf, size_t *r_len, int *r_padding); @@ -604,6 +615,9 @@ int agent_card_scd (ctrl_t ctrl, const char *cmdline, int (*getpin_cb)(void *, const char *, const char *, char*, size_t), void *getpin_cb_arg, void *assuan_context); +void agent_card_free_keyinfo (struct card_key_info_s *l); +gpg_error_t agent_card_keyinfo (ctrl_t ctrl, const char *keygrip, + struct card_key_info_s **result); /*-- learncard.c --*/ diff --git a/agent/call-scd.c b/agent/call-scd.c index b52c6c8eb..5b53b0223 100644 --- a/agent/call-scd.c +++ b/agent/call-scd.c @@ -329,13 +329,13 @@ start_scd (ctrl_t ctrl) { ctrl->scd_local = xtrycalloc (1, sizeof *ctrl->scd_local); if (!ctrl->scd_local) - { - err = gpg_error_from_syserror (); - rc = npth_mutex_unlock (&start_scd_lock); - if (rc) - log_error ("failed to release the start_scd lock: %s\n", strerror (rc)); - return err; - } + { + err = gpg_error_from_syserror (); + rc = npth_mutex_unlock (&start_scd_lock); + if (rc) + log_error ("failed to release the start_scd lock: %s\n", strerror (rc)); + return err; + } ctrl->scd_local->next_local = scd_local_list; scd_local_list = ctrl->scd_local; } @@ -1281,6 +1281,156 @@ agent_card_cardlist (ctrl_t ctrl, strlist_t *result) } +struct card_keyinfo_parm_s { + int error; + struct card_key_info_s *list; +}; + +/* Callback function for agent_card_keylist. */ +static gpg_error_t +card_keyinfo_cb (void *opaque, const char *line) +{ + struct card_keyinfo_parm_s *parm = opaque; + const char *keyword = line; + int keywordlen; + + for (keywordlen=0; *line && !spacep (line); line++, keywordlen++) + ; + while (spacep (line)) + line++; + + if (keywordlen == 7 && !memcmp (keyword, "KEYINFO", keywordlen)) + { + const char *s; + int n; + struct card_key_info_s *keyinfo; + struct card_key_info_s **l_p = &parm->list; + + while ((*l_p)) + l_p = &(*l_p)->next; + + keyinfo = xtrycalloc (1, sizeof *keyinfo); + if (!keyinfo) + { + alloc_error: + if (!parm->error) + parm->error = gpg_error_from_syserror (); + return 0; + } + + for (n=0,s=line; hexdigitp (s); s++, n++) + ; + + if (n != 40) + { + parm_error: + if (!parm->error) + parm->error = gpg_error (GPG_ERR_ASS_PARAMETER); + return 0; + } + + memcpy (keyinfo->keygrip, line, 40); + + line = s; + + if (!*line) + goto parm_error; + + while (spacep (line)) + line++; + + if (*line++ != 'T') + goto parm_error; + + if (!*line) + goto parm_error; + + while (spacep (line)) + line++; + + for (n=0,s=line; hexdigitp (s); s++, n++) + ; + + if (!n) + goto parm_error; + + keyinfo->serialno = xtrymalloc (n+1); + if (!keyinfo->serialno) + goto alloc_error; + + memcpy (keyinfo->serialno, line, n); + keyinfo->serialno[n] = 0; + + line = s; + + if (!*line) + goto parm_error; + + while (spacep (line)) + line++; + + if (!*line) + goto parm_error; + + keyinfo->idstr = xtrystrdup (line); + if (!keyinfo->idstr) + goto alloc_error; + + *l_p = keyinfo; + } + + return 0; +} + + +void +agent_card_free_keyinfo (struct card_key_info_s *l) +{ + struct card_key_info_s *l_next; + + for (; l; l = l_next) + { + l_next = l->next; + free (l->serialno); + free (l->idstr); + free (l); + } +} + +/* Call the scdaemon to check if a key of KEYGRIP is available, or + retrieve list of available keys on cards. On success the allocated + structure is stored at RESULT. On error an error code is returned + and NULL is stored at RESULT. */ +gpg_error_t +agent_card_keyinfo (ctrl_t ctrl, const char *keygrip, + struct card_key_info_s **result) +{ + int err; + struct card_keyinfo_parm_s parm; + char line[ASSUAN_LINELENGTH]; + + *result = NULL; + + memset (&parm, 0, sizeof parm); + snprintf (line, sizeof line, "KEYINFO %s", keygrip ? keygrip : "--list"); + + err = start_scd (ctrl); + if (err) + return err; + + err = assuan_transact (ctrl->scd_local->ctx, line, + NULL, NULL, NULL, NULL, + card_keyinfo_cb, &parm); + if (!err && parm.error) + err = parm.error; + + if (!err) + *result = parm.list; + else + agent_card_free_keyinfo (parm.list); + + return unlock_scd (ctrl, err); +} static gpg_error_t pass_status_thru (void *opaque, const char *line) diff --git a/agent/divert-scd.c b/agent/divert-scd.c index e89c74a19..a6ffba75f 100644 --- a/agent/divert-scd.c +++ b/agent/divert-scd.c @@ -32,28 +32,43 @@ #include "../common/sexp-parse.h" -static int -ask_for_card (ctrl_t ctrl, const unsigned char *shadow_info, char **r_kid) +static gpg_error_t +ask_for_card (ctrl_t ctrl, const unsigned char *shadow_info, + const unsigned char *grip, char **r_kid) { - int rc, i; + int i; char *serialno; int no_card = 0; char *desc; char *want_sn, *want_kid, *want_sn_disp; int len; + struct card_key_info_s *keyinfo; + gpg_error_t err; + char hexgrip[41]; *r_kid = NULL; - rc = parse_shadow_info (shadow_info, &want_sn, &want_kid, NULL); - if (rc) - return rc; + bin2hex (grip, 20, hexgrip); + err = agent_card_keyinfo (ctrl, hexgrip, &keyinfo); + if (!err) + { + agent_card_free_keyinfo (keyinfo); + if ((*r_kid = xtrystrdup (hexgrip))) + return 0; + else + return gpg_error_from_syserror (); + } + + err = parse_shadow_info (shadow_info, &want_sn, &want_kid, NULL); + if (err) + return err; want_sn_disp = xtrystrdup (want_sn); if (!want_sn_disp) { - rc = gpg_error_from_syserror (); + err = gpg_error_from_syserror (); xfree (want_sn); xfree (want_kid); - return rc; + return err; } len = strlen (want_sn_disp); @@ -76,8 +91,8 @@ ask_for_card (ctrl_t ctrl, const unsigned char *shadow_info, char **r_kid) for (;;) { - rc = agent_card_serialno (ctrl, &serialno, want_sn); - if (!rc) + err = agent_card_serialno (ctrl, &serialno, want_sn); + if (!err) { log_debug ("detected card with S/N %s\n", serialno); i = strcmp (serialno, want_sn); @@ -91,24 +106,24 @@ ask_for_card (ctrl_t ctrl, const unsigned char *shadow_info, char **r_kid) return 0; /* yes, we have the correct card */ } } - else if (gpg_err_code (rc) == GPG_ERR_ENODEV) + else if (gpg_err_code (err) == GPG_ERR_ENODEV) { log_debug ("no device present\n"); - rc = 0; + err = 0; no_card = 1; } - else if (gpg_err_code (rc) == GPG_ERR_CARD_NOT_PRESENT) + else if (gpg_err_code (err) == GPG_ERR_CARD_NOT_PRESENT) { log_debug ("no card present\n"); - rc = 0; + err = 0; no_card = 2; } else { - log_error ("error accessing card: %s\n", gpg_strerror (rc)); + log_error ("error accessing card: %s\n", gpg_strerror (err)); } - if (!rc) + if (!err) { if (asprintf (&desc, "%s:%%0A%%0A" @@ -119,24 +134,24 @@ ask_for_card (ctrl_t ctrl, const unsigned char *shadow_info, char **r_kid) "insert the one with serial number"), want_sn_disp) < 0) { - rc = out_of_core (); + err = out_of_core (); } else { - rc = agent_get_confirmation (ctrl, desc, NULL, NULL, 0); + err = agent_get_confirmation (ctrl, desc, NULL, NULL, 0); if (ctrl->pinentry_mode == PINENTRY_MODE_LOOPBACK && - gpg_err_code (rc) == GPG_ERR_NO_PIN_ENTRY) - rc = gpg_error (GPG_ERR_CARD_NOT_PRESENT); + gpg_err_code (err) == GPG_ERR_NO_PIN_ENTRY) + err = gpg_error (GPG_ERR_CARD_NOT_PRESENT); xfree (desc); } } - if (rc) + if (err) { xfree (want_sn_disp); xfree (want_sn); xfree (want_kid); - return rc; + return err; } } } @@ -434,7 +449,7 @@ getpin_cb (void *opaque, const char *desc_text, const char *info, * * FIXME: Explain the other args. */ int -divert_pksign (ctrl_t ctrl, const char *desc_text, +divert_pksign (ctrl_t ctrl, const char *desc_text, const unsigned char *grip, const unsigned char *digest, size_t digestlen, int algo, const unsigned char *shadow_info, unsigned char **r_sig, size_t *r_siglen) @@ -446,7 +461,7 @@ divert_pksign (ctrl_t ctrl, const char *desc_text, (void)desc_text; - rc = ask_for_card (ctrl, shadow_info, &kid); + rc = ask_for_card (ctrl, shadow_info, grip, &kid); if (rc) return rc; @@ -490,6 +505,7 @@ divert_pksign (ctrl_t ctrl, const char *desc_text, R_PADDING with -1 for not known. */ int divert_pkdecrypt (ctrl_t ctrl, const char *desc_text, + const unsigned char *grip, const unsigned char *cipher, const unsigned char *shadow_info, char **r_buf, size_t *r_len, int *r_padding) @@ -581,7 +597,7 @@ divert_pkdecrypt (ctrl_t ctrl, const char *desc_text, ciphertext = s; ciphertextlen = n; - rc = ask_for_card (ctrl, shadow_info, &kid); + rc = ask_for_card (ctrl, shadow_info, grip, &kid); if (rc) return rc; diff --git a/agent/pkdecrypt.c b/agent/pkdecrypt.c index a0ced2f55..ec23daf83 100644 --- a/agent/pkdecrypt.c +++ b/agent/pkdecrypt.c @@ -85,8 +85,8 @@ agent_pkdecrypt (ctrl_t ctrl, const char *desc_text, goto leave; } - rc = divert_pkdecrypt (ctrl, desc_text, ciphertext, shadow_info, - &buf, &len, r_padding); + rc = divert_pkdecrypt (ctrl, desc_text, ctrl->keygrip, ciphertext, + shadow_info, &buf, &len, r_padding); if (rc) { log_error ("smartcard decryption failed: %s\n", gpg_strerror (rc)); diff --git a/agent/pksign.c b/agent/pksign.c index bc8d7336a..d9519d1bd 100644 --- a/agent/pksign.c +++ b/agent/pksign.c @@ -352,6 +352,7 @@ agent_pksign_do (ctrl_t ctrl, const char *cache_nonce, agent_modify_description (desc_text, NULL, s_skey, &desc2); err = divert_pksign (ctrl, desc2? desc2 : desc_text, + ctrl->keygrip, data, datalen, ctrl->digest.algo, shadow_info, &buf, &len); From dc35b25195e564affdea7969a7c4ea4e200ab45f Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Thu, 16 May 2019 10:09:41 +0900 Subject: [PATCH 081/169] agent,scd: Scan and load all public keys for availability. * agent/divert-scd.c (ask_for_card): Scan by SERIALNO command. * scd/app-openpgp.c (do_with_keygrip): Make sure to load pubkey. Signed-off-by: NIIBE Yutaka --- agent/divert-scd.c | 21 ++++++++++++++------- scd/app-openpgp.c | 4 ++++ 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/agent/divert-scd.c b/agent/divert-scd.c index a6ffba75f..cfa2347c7 100644 --- a/agent/divert-scd.c +++ b/agent/divert-scd.c @@ -48,15 +48,22 @@ ask_for_card (ctrl_t ctrl, const unsigned char *shadow_info, *r_kid = NULL; - bin2hex (grip, 20, hexgrip); - err = agent_card_keyinfo (ctrl, hexgrip, &keyinfo); + /* Scan device(s), and check if key for GRIP is available. */ + err = agent_card_serialno (ctrl, &serialno, NULL); if (!err) { - agent_card_free_keyinfo (keyinfo); - if ((*r_kid = xtrystrdup (hexgrip))) - return 0; - else - return gpg_error_from_syserror (); + xfree (serialno); + bin2hex (grip, 20, hexgrip); + err = agent_card_keyinfo (ctrl, hexgrip, &keyinfo); + if (!err) + { + /* Key for GRIP found, use it directly. */ + agent_card_free_keyinfo (keyinfo); + if ((*r_kid = xtrystrdup (hexgrip))) + return 0; + else + return gpg_error_from_syserror (); + } } err = parse_shadow_info (shadow_info, &want_sn, &want_kid, NULL); diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index c1c90350b..95df43828 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -4950,6 +4950,10 @@ do_with_keygrip (app_t app, ctrl_t ctrl, int action, const char *keygrip_str) { int i; + /* Make sure we have load the public keys. */ + for (i = 0; i < 3; i++) + get_public_key (app, i); + if (action == KEYGRIP_ACTION_LOOKUP) { if (keygrip_str == NULL) From 79c99921e35921140c83d7c101829d95f038f3da Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 16 May 2019 08:24:29 +0200 Subject: [PATCH 082/169] scd: Remove unused cruft from GnuPG 1.x * scd/apdu.c: Remove code used only by GnuPG 1. * scd/app-openpgp.c: Ditto. * scd/ccid-driver.c: Ditto. * scd/iso7816.c: Ditto. Signed-off-by: Werner Koch --- scd/apdu.c | 22 ++++++---------------- scd/app-openpgp.c | 33 --------------------------------- scd/ccid-driver.c | 20 ++++---------------- scd/iso7816.c | 17 ++++------------- 4 files changed, 14 insertions(+), 78 deletions(-) diff --git a/scd/apdu.c b/scd/apdu.c index 816938ac5..ffa28c689 100644 --- a/scd/apdu.c +++ b/scd/apdu.c @@ -43,22 +43,12 @@ #endif /*USE_G10CODE_RAPDU*/ #if defined(GNUPG_SCD_MAIN_HEADER) -#include GNUPG_SCD_MAIN_HEADER -#elif GNUPG_MAJOR_VERSION == 1 -/* This is used with GnuPG version < 1.9. The code has been source - copied from the current GnuPG >= 1.9 and is maintained over - there. */ -#include "../common/options.h" -#include "errors.h" -#include "memory.h" -#include "../common/util.h" -#include "../common/i18n.h" -#include "dynload.h" -#include "cardglue.h" -#else /* GNUPG_MAJOR_VERSION != 1 */ -#include "scdaemon.h" -#include "../common/exechelp.h" -#endif /* GNUPG_MAJOR_VERSION != 1 */ +# include GNUPG_SCD_MAIN_HEADER +#else /*!GNUPG_SCD_MAIN_HEADER*/ +# include "scdaemon.h" +# include "../common/exechelp.h" +#endif /*!GNUPG_SCD_MAIN_HEADER*/ + #include "../common/host2net.h" #include "iso7816.h" diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 95df43828..aa21529c6 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -50,18 +50,7 @@ #include #include -#if GNUPG_MAJOR_VERSION == 1 -/* This is used with GnuPG version < 1.9. The code has been source - copied from the current GnuPG >= 1.9 and is maintained over - there. */ -#include "options.h" -#include "errors.h" -#include "memory.h" -#include "cardglue.h" -#else /* GNUPG_MAJOR_VERSION != 1 */ #include "scdaemon.h" -#endif /* GNUPG_MAJOR_VERSION != 1 */ - #include "../common/util.h" #include "../common/i18n.h" #include "iso7816.h" @@ -1229,7 +1218,6 @@ get_remaining_tries (app_t app, int adminpw) the according hex representation to FPR. Caller must have provide a buffer at FPR of least 41 bytes. Returns 0 on success or an error code. */ -#if GNUPG_MAJOR_VERSION > 1 static gpg_error_t retrieve_fpr_from_card (app_t app, int keyno, char *fpr) { @@ -1248,7 +1236,6 @@ retrieve_fpr_from_card (app_t app, int keyno, char *fpr) xfree (relptr); return err; } -#endif /*GNUPG_MAJOR_VERSION > 1*/ /* Retrieve the public key material for the RSA key, whose fingerprint @@ -1257,7 +1244,6 @@ retrieve_fpr_from_card (app_t app, int keyno, char *fpr) public exponent at E and ELEN. Returns zero on success, an error code on failure. Caller must release the allocated buffers at M and E if the function returns success. */ -#if GNUPG_MAJOR_VERSION > 1 static gpg_error_t retrieve_key_material (FILE *fp, const char *hexkeyid, const unsigned char **m, size_t *mlen, @@ -1362,7 +1348,6 @@ retrieve_key_material (FILE *fp, const char *hexkeyid, xfree (line); return err; } -#endif /*GNUPG_MAJOR_VERSION > 1*/ static gpg_error_t @@ -1662,7 +1647,6 @@ read_public_key (app_t app, ctrl_t ctrl, u32 created_at, int keyno, consuming to send it just for the fun of it. However, given that we use the same code in gpg 1.4, we can't use the gcry S-expression here but need to open encode it. */ -#if GNUPG_MAJOR_VERSION > 1 static gpg_error_t get_public_key (app_t app, int keyno) { @@ -1804,8 +1788,6 @@ get_public_key (app_t app, int keyno) xfree (buffer); return err; } -#endif /* GNUPG_MAJOR_VERSION > 1 */ - /* Send the KEYPAIRINFO back. KEY needs to be in the range [1,3]. @@ -1815,9 +1797,6 @@ send_keypair_info (app_t app, ctrl_t ctrl, int key) { int keyno = key - 1; gpg_error_t err = 0; - /* Note that GnuPG 1.x does not need this and it would be too time - consuming to send it just for the fun of it. */ -#if GNUPG_MAJOR_VERSION > 1 char idbuf[50]; const char *usage; @@ -1845,8 +1824,6 @@ send_keypair_info (app_t app, ctrl_t ctrl, int key) NULL, (size_t)0); leave: -#endif /* GNUPG_MAJOR_VERSION > 1 */ - return err; } @@ -1956,7 +1933,6 @@ static gpg_error_t do_readcert (app_t app, const char *certid, unsigned char **cert, size_t *certlen) { -#if GNUPG_MAJOR_VERSION > 1 gpg_error_t err; unsigned char *buffer; size_t buflen; @@ -1985,9 +1961,6 @@ do_readcert (app_t app, const char *certid, } xfree (relptr); return err; -#else - return gpg_error (GPG_ERR_NOT_IMPLEMENTED); -#endif } @@ -2374,13 +2347,11 @@ verify_chv3 (app_t app, { int rc = 0; -#if GNUPG_MAJOR_VERSION != 1 if (!opt.allow_admin) { log_info (_("access to admin commands is not configured\n")); return gpg_error (GPG_ERR_EACCES); } -#endif if (!app->did_chv3) { @@ -2569,7 +2540,6 @@ do_writecert (app_t app, ctrl_t ctrl, const unsigned char *certdata, size_t certdatalen) { (void)ctrl; -#if GNUPG_MAJOR_VERSION > 1 if (strcmp (certidstr, "OPENPGP.3")) return gpg_error (GPG_ERR_INV_ID); if (!certdata || !certdatalen) @@ -2579,9 +2549,6 @@ do_writecert (app_t app, ctrl_t ctrl, if (certdatalen > app->app_local->extcap.max_certlen_3) return gpg_error (GPG_ERR_TOO_LARGE); return do_setattr (app, "CERT-3", pincb, pincb_arg, certdata, certdatalen); -#else - return gpg_error (GPG_ERR_NOT_IMPLEMENTED); -#endif } diff --git a/scd/ccid-driver.c b/scd/ccid-driver.c index dca8340ba..657766e30 100644 --- a/scd/ccid-driver.c +++ b/scd/ccid-driver.c @@ -112,22 +112,10 @@ #define CCID_CMD_TIMEOUT (5*1000) /* Depending on how this source is used we either define our error - output to go to stderr or to the GnuPG based logging functions. We - use the latter when GNUPG_MAJOR_VERSION or GNUPG_SCD_MAIN_HEADER - are defined. */ -#if defined(GNUPG_MAJOR_VERSION) || defined(GNUPG_SCD_MAIN_HEADER) - + * output to go to stderr or to the GnuPG based logging functions. We + * use the latter when GNUPG_SCD_MAIN_HEADER is defined. */ #if defined(GNUPG_SCD_MAIN_HEADER) -# include GNUPG_SCD_MAIN_HEADER -#elif GNUPG_MAJOR_VERSION == 1 /* GnuPG Version is < 1.9. */ -# include "options.h" -# include "util.h" -# include "memory.h" -# include "cardglue.h" -# else /* This is the modularized GnuPG 1.9 or later. */ -# include "scdaemon.h" -#endif - +# include GNUPG_SCD_MAIN_HEADER # define DEBUGOUT(t) do { if (debug_level) \ log_debug (DRVNAME t); } while (0) @@ -173,7 +161,7 @@ # define DEBUGOUT_LF() do { if (debug_level) \ putc ('\n', stderr); } while (0) -#endif /* This source not used by scdaemon. */ +#endif /* This source is not used by scdaemon. */ #ifndef EAGAIN diff --git a/scd/iso7816.c b/scd/iso7816.c index d9f3336c7..b09354f16 100644 --- a/scd/iso7816.c +++ b/scd/iso7816.c @@ -24,19 +24,10 @@ #include #if defined(GNUPG_SCD_MAIN_HEADER) -#include GNUPG_SCD_MAIN_HEADER -#elif GNUPG_MAJOR_VERSION == 1 -/* This is used with GnuPG version < 1.9. The code has been source - copied from the current GnuPG >= 1.9 and is maintained over - there. */ -#include "options.h" -#include "errors.h" -#include "memory.h" -#include "../common/util.h" -#include "../common/i18n.h" -#else /* GNUPG_MAJOR_VERSION != 1 */ -#include "scdaemon.h" -#endif /* GNUPG_MAJOR_VERSION != 1 */ +# include GNUPG_SCD_MAIN_HEADER +#else +# include "scdaemon.h" +#endif /*!GNUPG_SCD_MAIN_HEADER*/ #include "iso7816.h" #include "apdu.h" From 50c2f76ae65d4ee793876865011fa97c85f38ac2 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 16 May 2019 12:24:08 +0200 Subject: [PATCH 083/169] gpgconf: Before --launch check that the config file is fine. * tools/gpgconf-comp.c (gc_component_launch): Check the conf file. * tools/gpgconf.c (gpgconf_failure): Call log_flush. -- GnuPG-bug-id: 4497 Signed-off-by: Werner Koch --- tools/gpgconf-comp.c | 18 ++++++++++++++---- tools/gpgconf.c | 1 + 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/tools/gpgconf-comp.c b/tools/gpgconf-comp.c index a308c1c83..110f88975 100644 --- a/tools/gpgconf-comp.c +++ b/tools/gpgconf-comp.c @@ -1273,8 +1273,17 @@ gc_component_launch (int component) if (!(component == GC_COMPONENT_GPG_AGENT || component == GC_COMPONENT_DIRMNGR)) { - es_fputs (_("Component not suitable for launching"), es_stderr); - es_putc ('\n', es_stderr); + log_error ("%s\n", _("Component not suitable for launching")); + gpgconf_failure (0); + } + + if (gc_component_check_options (component, NULL, NULL)) + { + log_error (_("Configuration file of component %s is broken\n"), + gc_component[component].name); + if (!opt.quiet) + log_info (_("Note: Use the command \"%s%s\" to get details.\n"), + "gpgconf --check-options ", gc_component[component].name); gpgconf_failure (0); } @@ -1685,8 +1694,9 @@ collect_error_output (estream_t fp, const char *tag) } -/* Check the options of a single component. Returns 0 if everything - is OK. */ +/* Check the options of a single component. If CONF_FILE is NULL the + * standard config file is used. If OUT is not NULL the output is + * written to that stream. Returns 0 if everything is OK. */ int gc_component_check_options (int component, estream_t out, const char *conf_file) { diff --git a/tools/gpgconf.c b/tools/gpgconf.c index b67125b89..a0cd97f60 100644 --- a/tools/gpgconf.c +++ b/tools/gpgconf.c @@ -900,6 +900,7 @@ main (int argc, char **argv) void gpgconf_failure (gpg_error_t err) { + log_flush (); if (!err) err = gpg_error (GPG_ERR_GENERAL); gpgconf_write_status From 6fc5df1e10129f3171d80cf731f310b9e8d97c26 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 16 May 2019 13:57:04 +0200 Subject: [PATCH 084/169] kbx: Fix an endless loop under Windows due to an incomplete fix. * kbx/keybox-search.c (keybox_search): We need to seek to the last position in all cases not just when doing a NEXT. -- This is because search from the beginning needs a keybox_search_reset. We can only make an exception for KEYDB_SEARCH_MODE_FIRST.. Fixes-commit: 49b236af0ecbb6df67513feb4b63851f2e159ea2 Signed-off-by: Werner Koch --- kbx/keybox-search.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kbx/keybox-search.c b/kbx/keybox-search.c index 1600861a8..77469a24c 100644 --- a/kbx/keybox-search.c +++ b/kbx/keybox-search.c @@ -932,9 +932,9 @@ keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc, return rc; } /* log_debug ("%s: re-opened file\n", __func__); */ - if (ndesc && desc[0].mode == KEYDB_SEARCH_MODE_NEXT && lastfoundoff) + if (ndesc && desc[0].mode != KEYDB_SEARCH_MODE_FIRST && lastfoundoff) { - /* Search mode is next and the last search operation + /* Search mode is not first and the last search operation * returned a blob which also was not the first one. We now * need to skip over that blob and hope that the file has * not changed. */ From 7e5847da0f3d715cb59d05adcd9107b460b6411b Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 17 May 2019 12:31:11 +0200 Subject: [PATCH 085/169] gpg: Improve the photo image viewer selection. * g10/exec.c (w32_system): Add "!ShellExecute" special. * g10/photoid.c (get_default_photo_command): Use the new ShellExecute under Windows and fallbac to 'display' and 'xdg-open' in the Unix case. (show_photos): Flush stdout so that the output is shown before the image pops up. -- For Unix this basically syncs the code with what we have in gpg 1.4. Note that xdg-open may not be used when running as root which we support here. For Windows we now use ShellExecute as this seems to be preferred over "cmd /c start"; however this does not solve the actual problem we had in the bug report. To solve that problem we resort to a wait parameter which defaults to 400ms. This works on my Windows-10 virtualized test box. If we can figure out which simple viewers are commonly installed on Windows we should enhance this patch to test for them. GnuPG-bug-id: 4334 Signed-off-by: Werner Koch --- doc/gpg.texi | 23 ++++++----- g10/exec.c | 110 +++++++++++++++++++++++++++++++++++++++----------- g10/photoid.c | 16 ++++++-- 3 files changed, 113 insertions(+), 36 deletions(-) diff --git a/doc/gpg.texi b/doc/gpg.texi index 6181ee536..ddfa2f27f 100644 --- a/doc/gpg.texi +++ b/doc/gpg.texi @@ -1426,19 +1426,24 @@ viewed (e.g. "f"), "%V" for the calculated validity as a string (e.g. and "%%" for an actual percent sign. If neither %i or %I are present, then the photo will be supplied to the viewer on standard input. -The default viewer is "xloadimage -fork -quiet -title 'KeyID 0x%k' -STDIN". Note that if your image viewer program is not secure, then -executing it from GnuPG does not make it secure. +On Unix the default viewer is +@code{xloadimage -fork -quiet -title 'KeyID 0x%k' STDIN} +with a fallback to +@code{display -title 'KeyID 0x%k' %i} +and finally to +@code{xdg-open %i}. +On Windows +@code{!ShellExecute 400 %i} is used; here the command is a meta +command to use that API call followed by a wait time in milliseconds +which is used to give the viewer time to read the temporary image file +before gpg deletes it again. Note that if your image viewer program +is not secure, then executing it from gpg does not make it secure. @item --exec-path @var{string} @opindex exec-path @efindex PATH -Sets a list of directories to search for photo viewers and keyserver -helpers. If not provided, keyserver helpers use the compiled-in -default directory, and photo viewers use the @code{PATH} environment -variable. -Note, that on W32 system this value is ignored when searching for -keyserver helpers. +Sets a list of directories to search for photo viewers If not provided +photo viewers use the @code{PATH} environment variable. @item --keyring @var{file} @opindex keyring diff --git a/g10/exec.c b/g10/exec.c index 74a83970e..3e5dc278b 100644 --- a/g10/exec.c +++ b/g10/exec.c @@ -77,37 +77,99 @@ set_exec_path(const char *path) { return GPG_ERR_GENERAL; } static int w32_system(const char *command) { -#ifdef HAVE_W32CE_SYSTEM -#warning Change this code to use common/exechelp.c -#else - PROCESS_INFORMATION pi; - STARTUPINFO si; - char *string; + if (!strncmp (command, "!ShellExecute ", 14)) + { + SHELLEXECUTEINFOW see; + wchar_t *wname; + int waitms; - /* We must use a copy of the command as CreateProcess modifies this - argument. */ - string=xstrdup(command); + command = command + 14; + while (spacep (command)) + command++; + waitms = atoi (command); + if (waitms < 0) + waitms = 0; + else if (waitms > 60*1000) + waitms = 60000; + while (*command && !spacep (command)) + command++; + while (spacep (command)) + command++; - memset(&pi,0,sizeof(pi)); - memset(&si,0,sizeof(si)); - si.cb=sizeof(si); + wname = utf8_to_wchar (command); + if (!wname) + return -1; - if(!CreateProcess(NULL,string,NULL,NULL,FALSE, - DETACHED_PROCESS, - NULL,NULL,&si,&pi)) - return -1; + memset (&see, 0, sizeof see); + see.cbSize = sizeof see; + see.fMask = (SEE_MASK_NOCLOSEPROCESS + | SEE_MASK_NOASYNC + | SEE_MASK_FLAG_NO_UI + | SEE_MASK_NO_CONSOLE); + see.lpVerb = L"open"; + see.lpFile = (LPCWSTR)wname; + see.nShow = SW_SHOW; - /* Wait for the child to exit */ - WaitForSingleObject(pi.hProcess,INFINITE); + if (DBG_EXTPROG) + log_debug ("running ShellExecuteEx(open,'%s')\n", command); + if (!ShellExecuteExW (&see)) + { + if (DBG_EXTPROG) + log_debug ("ShellExecuteEx failed: rc=%d\n", (int)GetLastError ()); + xfree (wname); + return -1; + } + if (DBG_EXTPROG) + log_debug ("ShellExecuteEx succeeded (hProcess=%p,hInstApp=%d)\n", + see.hProcess, (int)see.hInstApp); - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); - xfree(string); + if (!see.hProcess) + { + gnupg_usleep (waitms*1000); + if (DBG_EXTPROG) + log_debug ("ShellExecuteEx ready (wait=%dms)\n", waitms); + } + else + { + WaitForSingleObject (see.hProcess, INFINITE); + if (DBG_EXTPROG) + log_debug ("ShellExecuteEx ready\n"); + } + CloseHandle (see.hProcess); + + xfree (wname); + } + else + { + char *string; + PROCESS_INFORMATION pi; + STARTUPINFO si; + + /* We must use a copy of the command as CreateProcess modifies + * this argument. */ + string = xstrdup (command); + + memset (&pi, 0, sizeof(pi)); + memset (&si, 0, sizeof(si)); + si.cb = sizeof (si); + + if (!CreateProcess (NULL, string, NULL, NULL, FALSE, + DETACHED_PROCESS, + NULL, NULL, &si, &pi)) + return -1; + + /* Wait for the child to exit */ + WaitForSingleObject (pi.hProcess, INFINITE); + + CloseHandle (pi.hProcess); + CloseHandle (pi.hThread); + xfree (string); + } return 0; -#endif } -#endif +#endif /*_W32*/ + /* Replaces current $PATH */ int @@ -508,7 +570,7 @@ exec_read(struct exec_info *info) if(info->flags.use_temp_files) { if(DBG_EXTPROG) - log_debug("system() command is %s\n",info->command); + log_debug ("running command: %s\n",info->command); #if defined (_WIN32) info->progreturn=w32_system(info->command); diff --git a/g10/photoid.c b/g10/photoid.c index bcea64fbf..f9720d329 100644 --- a/g10/photoid.c +++ b/g10/photoid.c @@ -262,7 +262,8 @@ char *image_type_to_string(byte type,int style) } #if !defined(FIXED_PHOTO_VIEWER) && !defined(DISABLE_PHOTO_VIEWER) -static const char *get_default_photo_command(void) +static const char * +get_default_photo_command(void) { #if defined(_WIN32) OSVERSIONINFO osvi; @@ -274,14 +275,21 @@ static const char *get_default_photo_command(void) if(osvi.dwPlatformId==VER_PLATFORM_WIN32_WINDOWS) return "start /w %i"; else - return "cmd /c start /w %i"; + return "!ShellExecute 400 %i"; #elif defined(__APPLE__) /* OS X. This really needs more than just __APPLE__. */ return "open %I"; #elif defined(__riscos__) return "Filer_Run %I"; #else - return "xloadimage -fork -quiet -title 'KeyID 0x%k' stdin"; + if (!path_access ("xloadimage", X_OK)) + return "xloadimage -fork -quiet -title 'KeyID 0x%k' stdin"; + else if (!path_access ("display",X_OK)) + return "display -title 'KeyID 0x%k' %i"; + else if (getuid () && !path_access ("xdg-open", X_OK)) + return "xdg-open %i"; + else + return "/bin/true"; #endif } #endif @@ -312,6 +320,8 @@ show_photos (ctrl_t ctrl, const struct user_attribute *attrs, int count, if (pk) keyid_from_pk (pk, kid); + es_fflush (es_stdout); + for(i=0;i Date: Fri, 17 May 2019 13:40:24 +0200 Subject: [PATCH 086/169] gpg: Fix using --decrypt along with --use-embedded-filename. * g10/options.h (opt): Add flags.dummy_outfile. * g10/decrypt.c (decrypt_message): Set this global flag instead of the fucntion local flag. * g10/plaintext.c (get_output_file): Ignore opt.output if that was used as a dummy option aslong with --use-embedded-filename. -- The problem here was that an explicit specified --decrypt, as meanwhile suggested, did not work with that dangerous --use-embedded-filename. In contrast it worked when gpg decrypted as a side-effect of parsing the data. GnuPG-bug-id: 4500 Signed-off-by: Werner Koch --- doc/gpg.texi | 3 ++- g10/decrypt.c | 7 ++++--- g10/options.h | 2 ++ g10/plaintext.c | 3 ++- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/doc/gpg.texi b/doc/gpg.texi index ddfa2f27f..fd7dcddf0 100644 --- a/doc/gpg.texi +++ b/doc/gpg.texi @@ -3023,7 +3023,8 @@ to display the message. This option overrides @option{--set-filename}. @itemx --no-use-embedded-filename @opindex use-embedded-filename Try to create a file with a name as embedded in the data. This can be -a dangerous option as it enables overwriting files. Defaults to no. +a dangerous option as it enables overwriting files. Defaults to no. +Note that the option @option{--output} overrides this option. @item --cipher-algo @var{name} @opindex cipher-algo diff --git a/g10/decrypt.c b/g10/decrypt.c index 4d6734d40..9589aff58 100644 --- a/g10/decrypt.c +++ b/g10/decrypt.c @@ -48,7 +48,6 @@ decrypt_message (ctrl_t ctrl, const char *filename) armor_filter_context_t *afx = NULL; progress_filter_context_t *pfx; int rc; - int no_out = 0; pfx = new_progress_context (); @@ -82,11 +81,13 @@ decrypt_message (ctrl_t ctrl, const char *filename) if (!opt.outfile) { - no_out = 1; opt.outfile = "-"; + opt.flags.dummy_outfile = 1; } + else + opt.flags.dummy_outfile = 0; rc = proc_encryption_packets (ctrl, NULL, fp ); - if (no_out) + if (opt.flags.dummy_outfile) opt.outfile = NULL; iobuf_close (fp); diff --git a/g10/options.h b/g10/options.h index 8adf09f08..b26cea0db 100644 --- a/g10/options.h +++ b/g10/options.h @@ -249,6 +249,8 @@ struct unsigned int disable_signer_uid:1; /* Flag to enable experimental features from RFC4880bis. */ unsigned int rfc4880bis:1; + /* Hack: --output is not given but OUTFILE was temporary set to "-". */ + unsigned int dummy_outfile:1; } flags; /* Linked list of ways to find a key if the key isn't on the local diff --git a/g10/plaintext.c b/g10/plaintext.c index c5d1ddb7f..f9e0a4296 100644 --- a/g10/plaintext.c +++ b/g10/plaintext.c @@ -70,7 +70,8 @@ get_output_file (const byte *embedded_name, int embedded_namelen, goto leave; } } - else if (opt.outfile) + else if (opt.outfile + && !(opt.flags.use_embedded_filename && opt.flags.dummy_outfile)) { fname = xtrystrdup (opt.outfile); if (!fname) From 110a4550179fd1faeee8d2f17a33ed7807a397ae Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 20 May 2019 12:31:55 +0200 Subject: [PATCH 087/169] gpg: Do not delete any keys if --dry-run is passed. * g10/delkey.c (do_delete_key): Don't delete the keyblock on dry runs. Do not clear the ownertrust. Do not let the agent delete the key. -- Co-authored-by: Matheus Afonso Martins Moreira Signed-off-by: Werner Koch --- g10/delkey.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/g10/delkey.c b/g10/delkey.c index cc5673846..276080532 100644 --- a/g10/delkey.c +++ b/g10/delkey.c @@ -188,7 +188,7 @@ do_delete_key (ctrl_t ctrl, const char *username, int secret, int force, * pre-caution is that since 2.1 the secret key may also * be used for other protocols and thus deleting it from * the gpg would also delete the key for other tools. */ - if (!err) + if (!err && !opt.dry_run) err = agent_delete_key (NULL, hexgrip, prompt, opt.answer_yes); xfree (prompt); @@ -219,7 +219,7 @@ do_delete_key (ctrl_t ctrl, const char *username, int secret, int force, } else { - err = keydb_delete_keyblock (hd); + err = opt.dry_run? 0 : keydb_delete_keyblock (hd); if (err) { log_error (_("deleting keyblock failed: %s\n"), @@ -232,7 +232,7 @@ do_delete_key (ctrl_t ctrl, const char *username, int secret, int force, revalidation_mark(). This makes sense - only deleting keys that have ownertrust set should trigger this. */ - if (!secret && pk && clear_ownertrusts (ctrl, pk)) + if (!secret && pk && !opt.dry_run && clear_ownertrusts (ctrl, pk)) { if (opt.verbose) log_info (_("ownertrust information cleared\n")); From 479f7bf31ce405e558d844c3eb576b463a8697e5 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Tue, 21 May 2019 15:50:28 +0900 Subject: [PATCH 088/169] agent: For SSH key, don't put NUL-byte at the end. * agent/command-ssh.c (ssh_key_to_protected_buffer): Update the length by the second call of gcry_sexp_sprint. -- GnuPG-bug-id: 4502 Signed-off-by: NIIBE Yutaka --- agent/command-ssh.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/agent/command-ssh.c b/agent/command-ssh.c index 5f7884b1f..0849a06fc 100644 --- a/agent/command-ssh.c +++ b/agent/command-ssh.c @@ -3007,8 +3007,8 @@ ssh_key_to_protected_buffer (gcry_sexp_t key, const char *passphrase, goto out; } - gcry_sexp_sprint (key, GCRYSEXP_FMT_CANON, buffer_new, buffer_new_n); - /* FIXME: guarantee? */ + buffer_new_n = gcry_sexp_sprint (key, GCRYSEXP_FMT_CANON, + buffer_new, buffer_new_n); if (*passphrase) err = agent_protect (buffer_new, passphrase, buffer, buffer_n, 0, -1); From 1eb93d9229c54baa5f1b7ccf7d105d3692c51a4d Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Tue, 21 May 2019 16:18:36 +0900 Subject: [PATCH 089/169] scd: Fix for SCARD_IO_REQUEST structure. * scd/apdu.c (struct pcsc_io_request_s): Use pcsc_dword_t for Windows. -- This fix is for correctness and for the future when we will support 64-bit Windows. GnuPG-bug-id: 4454 Suggested-by: Juris Ozols Signed-off-by: NIIBE Yutaka --- scd/apdu.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/scd/apdu.c b/scd/apdu.c index ffa28c689..254c74101 100644 --- a/scd/apdu.c +++ b/scd/apdu.c @@ -256,8 +256,13 @@ static npth_mutex_t reader_table_lock; struct pcsc_io_request_s { +#if defined(_WIN32) || defined(__CYGWIN__) + pcsc_dword_t protocol; + pcsc_dword_t pci_len; +#else unsigned long protocol; unsigned long pci_len; +#endif }; typedef struct pcsc_io_request_s *pcsc_io_request_t; From 126caa34bbdb36f40514643b9d6f5ead3240c735 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 21 May 2019 12:54:47 +0200 Subject: [PATCH 090/169] gpg: Unify the the use of the print_pubkey_info functions. * g10/keylist.c (format_seckey_info): Remove. (print_pubkey_info, print_seckey_info): Remove. (format_key_info): New. (print_key_info): New. (print_key_info_log): New. * g10/card-util.c (current_card_status): Use print_key_info and remove the useless condition on KEYBLOCK. * g10/delkey.c (do_delete_key): Replace print_pubkey_info and print_seckey_info by print_key_info. * g10/keyedit.c (menu_addrevoker): Replace print_pubkey_info by print_key_info. * g10/pkclist.c (do_we_trust_pre): Ditto. * g10/revoke.c (gen_desig_revoke): Ditto. (gen_revoke): Ditto. Also use print_key_info_log instead of separate functions. Signed-off-by: Werner Koch --- g10/card-util.c | 5 ++- g10/delkey.c | 5 +-- g10/keyedit.c | 2 +- g10/keylist.c | 96 +++++++++++++++++++++++++++++-------------------- g10/main.h | 7 ++-- g10/pkclist.c | 2 +- g10/revoke.c | 22 +++++------- 7 files changed, 75 insertions(+), 64 deletions(-) diff --git a/g10/card-util.c b/g10/card-util.c index 7e329bb6b..1b9461e0a 100644 --- a/g10/card-util.c +++ b/g10/card-util.c @@ -680,9 +680,8 @@ current_card_status (ctrl_t ctrl, estream_t fp, if ( thefpr && !fpr_is_ff (thefpr, thefprlen) && !get_pubkey_byfprint (ctrl, pk, &keyblock, thefpr, thefprlen)) { - print_pubkey_info (ctrl, fp, pk); - if (keyblock) - print_card_key_info (fp, keyblock); + print_key_info (ctrl, fp, 0, pk, 0); + print_card_key_info (fp, keyblock); } else tty_fprintf (fp, "[none]\n"); diff --git a/g10/delkey.c b/g10/delkey.c index 276080532..6f816080e 100644 --- a/g10/delkey.c +++ b/g10/delkey.c @@ -135,10 +135,7 @@ do_delete_key (ctrl_t ctrl, const char *username, int secret, int force, } else { - if (secret) - print_seckey_info (ctrl, pk); - else - print_pubkey_info (ctrl, NULL, pk ); + print_key_info (ctrl, NULL, 0, pk, secret); tty_printf( "\n" ); yes = cpr_get_answer_is_yes diff --git a/g10/keyedit.c b/g10/keyedit.c index 7f4c5a509..cb05914e1 100644 --- a/g10/keyedit.c +++ b/g10/keyedit.c @@ -4356,7 +4356,7 @@ menu_addrevoker (ctrl_t ctrl, kbnode_t pub_keyblock, int sensitive) continue; } - print_pubkey_info (ctrl, NULL, revoker_pk); + print_key_info (ctrl, NULL, 0, revoker_pk, 0); print_fingerprint (ctrl, NULL, revoker_pk, 2); tty_printf ("\n"); diff --git a/g10/keylist.c b/g10/keylist.c index 8d5b2e0b9..50625d0b7 100644 --- a/g10/keylist.c +++ b/g10/keylist.c @@ -165,43 +165,15 @@ secret_key_list (ctrl_t ctrl, strlist_t list) list_one (ctrl, list, 1, 0); } -char * -format_seckey_info (ctrl_t ctrl, PKT_public_key *pk) -{ - u32 keyid[2]; - char *p; - char pkstrbuf[PUBKEY_STRING_SIZE]; - char *info; - - keyid_from_pk (pk, keyid); - p = get_user_id_native (ctrl, keyid); - - info = xtryasprintf ("sec %s/%s %s %s", - pubkey_string (pk, pkstrbuf, sizeof pkstrbuf), - keystr (keyid), datestr_from_pk (pk), p); - - xfree (p); - - return info; -} - -void -print_seckey_info (ctrl_t ctrl, PKT_public_key *pk) -{ - char *p = format_seckey_info (ctrl, pk); - tty_printf ("\n%s\n", p); - xfree (p); -} - -/* Print information about the public key. With FP passed as NULL, - the tty output interface is used, otherwise output is directed to - the given stream. */ -void -print_pubkey_info (ctrl_t ctrl, estream_t fp, PKT_public_key *pk) + +/* Helper for print_key_info and print_key_info_log. */ +static char * +format_key_info (ctrl_t ctrl, PKT_public_key *pk, int secret) { u32 keyid[2]; char *p; char pkstrbuf[PUBKEY_STRING_SIZE]; + char *result; keyid_from_pk (pk, keyid); @@ -212,13 +184,59 @@ print_pubkey_info (ctrl_t ctrl, estream_t fp, PKT_public_key *pk) else p = get_user_id_native (ctrl, keyid); - if (!fp) - tty_printf ("\n"); - tty_fprintf (fp, "%s %s/%s %s %s\n", - pk->flags.primary? "pub":"sub", - pubkey_string (pk, pkstrbuf, sizeof pkstrbuf), - keystr (keyid), datestr_from_pk (pk), p); + result = xtryasprintf ("%s %s/%s %s %s", + secret? (pk->flags.primary? "sec":"ssb") + /* */ : (pk->flags.primary? "pub":"sub"), + pubkey_string (pk, pkstrbuf, sizeof pkstrbuf), + keystr (keyid), datestr_from_pk (pk), p); xfree (p); + return result; +} + + +/* Print basic information about a public or secret key. With FP + * passed as NULL, the tty output interface is used, otherwise output + * is directed to the given stream. INDENT gives the requested + * indentation; if that is a negative value indentation is suppressed + * for the first line. SECRET tells that the PK has a secret part. + * FIXME: This is similar in use to print_key_line and thus both + * functions should eventually be united. + */ +void +print_key_info (ctrl_t ctrl, estream_t fp, + int indent, PKT_public_key *pk, int secret) +{ + int indentabs = indent >= 0? indent : -indent; + char *info; + + /* Note: Negative values for INDENT are not yet needed. */ + + info = format_key_info (ctrl, pk, secret); + + if (!fp && indent >= 0) + tty_printf ("\n"); /* (Backward compatibility to old code) */ + tty_fprintf (fp, "%*s%s\n", indentabs, "", + info? info : "[Ooops - out of core]"); + + xfree (info); +} + + +/* Same as print_key_info put print using the log functions at + * LOGLEVEL. */ +void +print_key_info_log (ctrl_t ctrl, int loglevel, + int indent, PKT_public_key *pk, int secret) +{ + int indentabs = indent >= 0? indent : -indent; + char *info; + + info = format_key_info (ctrl, pk, secret); + + log_log (loglevel, "%*s%s\n", indentabs, "", + info? info : "[Ooops - out of core]"); + + xfree (info); } diff --git a/g10/main.h b/g10/main.h index 34a932b16..134d8b950 100644 --- a/g10/main.h +++ b/g10/main.h @@ -470,9 +470,10 @@ void show_keyserver_url(PKT_signature *sig,int indent,int mode); void show_notation(PKT_signature *sig,int indent,int mode,int which); void dump_attribs (const PKT_user_id *uid, PKT_public_key *pk); void set_attrib_fd(int fd); -char *format_seckey_info (ctrl_t ctrl, PKT_public_key *pk); -void print_seckey_info (ctrl_t ctrl, PKT_public_key *pk); -void print_pubkey_info (ctrl_t ctrl, estream_t fp, PKT_public_key *pk); +void print_key_info (ctrl_t ctrl, estream_t fp, int indent, + PKT_public_key *pk, int secret); +void print_key_info_log (ctrl_t ctrl, int loglevel, int indent, + PKT_public_key *pk, int secret); void print_card_key_info (estream_t fp, KBNODE keyblock); void print_key_line (ctrl_t ctrl, estream_t fp, PKT_public_key *pk, int secret); diff --git a/g10/pkclist.c b/g10/pkclist.c index 46258bf85..20eb00cea 100644 --- a/g10/pkclist.c +++ b/g10/pkclist.c @@ -475,7 +475,7 @@ do_we_trust_pre (ctrl_t ctrl, PKT_public_key *pk, unsigned int trustlevel ) if( !opt.batch && !rc ) { - print_pubkey_info (ctrl, NULL,pk); + print_key_info (ctrl, NULL, 0, pk, 0); print_fingerprint (ctrl, NULL, pk, 2); tty_printf("\n"); diff --git a/g10/revoke.c b/g10/revoke.c index e63060cb9..0a93c31f9 100644 --- a/g10/revoke.c +++ b/g10/revoke.c @@ -305,11 +305,11 @@ gen_desig_revoke (ctrl_t ctrl, const char *uname, strlist_t locusr) any = 1; - print_pubkey_info (ctrl, NULL, pk); + print_key_info (ctrl, NULL, 0, pk, 0); tty_printf ("\n"); tty_printf (_("To be revoked by:\n")); - print_seckey_info (ctrl, pk2); + print_key_info (ctrl, NULL, 0, pk2, 1); if(pk->revkey[i].class&0x40) tty_printf(_("(This is a sensitive revocation key)\n")); @@ -669,30 +669,26 @@ gen_revoke (ctrl_t ctrl, const char *uname) rc = keydb_search (kdbhd, &desc, 1, NULL); if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND) - /* Not ambiguous. */ { + /* Not ambiguous. */ } else if (rc == 0) - /* Ambiguous. */ { - char *info; - + /* Ambiguous. */ /* TRANSLATORS: The %s prints a key specification which for example has been given at the command line. Several lines lines with secret key infos are printed after this message. */ log_error (_("'%s' matches multiple secret keys:\n"), uname); - info = format_seckey_info (ctrl, keyblock->pkt->pkt.public_key); - log_error (" %s\n", info); - xfree (info); + print_key_info_log (ctrl, GPGRT_LOGLVL_ERROR, 2, + keyblock->pkt->pkt.public_key, 1); release_kbnode (keyblock); rc = keydb_get_keyblock (kdbhd, &keyblock); while (! rc) { - info = format_seckey_info (ctrl, keyblock->pkt->pkt.public_key); - log_info (" %s\n", info); - xfree (info); + print_key_info_log (ctrl, GPGRT_LOGLVL_INFO, 2, + keyblock->pkt->pkt.public_key, 1); release_kbnode (keyblock); keyblock = NULL; @@ -726,7 +722,7 @@ gen_revoke (ctrl_t ctrl, const char *uname) } keyid_from_pk (psk, keyid ); - print_seckey_info (ctrl, psk); + print_key_info (ctrl, NULL, 0, psk, 1); tty_printf("\n"); if (!cpr_get_answer_is_yes ("gen_revoke.okay", From 156788a43c20e38cd52f4f725395aff2c72142ff Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 21 May 2019 16:25:56 +0200 Subject: [PATCH 091/169] gpg: Do not allow creation of user ids larger than our parser allows. * g10/parse-packet.c: Move max packet lengths constants to ... * g10/packet.h: ... here. * g10/build-packet.c (do_user_id): Return an error if too data is too large. * g10/keygen.c (write_uid): Return an error for too large data. -- This can lead to keyring corruption becuase we expect that our parser is abale to parse packts created by us. Test case is gpg --batch --passphrase 'abc' -v \ --quick-gen-key $(yes 'a'| head -4000|tr -d '\n') GnuPG-bug-id: 4532 Signed-off-by: Werner Koch --- g10/build-packet.c | 8 +++++++- g10/keygen.c | 33 +++++++++++++++++++-------------- g10/packet.h | 5 +++++ g10/parse-packet.c | 6 ------ 4 files changed, 31 insertions(+), 21 deletions(-) diff --git a/g10/build-packet.c b/g10/build-packet.c index 07fccb099..2a95df694 100644 --- a/g10/build-packet.c +++ b/g10/build-packet.c @@ -447,15 +447,21 @@ do_user_id( IOBUF out, int ctb, PKT_user_id *uid ) * Without forcing HDRLEN to 2 in this case an indeterminate length * packet would be written which is not allowed. Note that we are * always called with a CTB indicating an old packet header format, - * so that forcing a 2 octet header works. */ + * so that forcing a 2 octet header works. We also check for the + * maximum allowed packet size by the parser using an arbitrary + * extra 10 bytes for header data. */ if (uid->attrib_data) { + if (uid->attrib_len > MAX_ATTR_PACKET_LENGTH - 10) + return gpg_error (GPG_ERR_TOO_LARGE); hdrlen = uid->attrib_len? 0 : 2; write_header2 (out, ctb, uid->attrib_len, hdrlen); rc = iobuf_write( out, uid->attrib_data, uid->attrib_len ); } else { + if (uid->len > MAX_UID_PACKET_LENGTH - 10) + return gpg_error (GPG_ERR_TOO_LARGE); hdrlen = uid->len? 0 : 2; write_header2 (out, ctb, uid->len, hdrlen); rc = iobuf_write( out, uid->name, uid->len ); diff --git a/g10/keygen.c b/g10/keygen.c index ac6bcc890..d9037d29d 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -227,18 +227,22 @@ print_status_key_not_created (const char *handle) -static void -write_uid( KBNODE root, const char *s ) +static gpg_error_t +write_uid (kbnode_t root, const char *s) { - PACKET *pkt = xmalloc_clear(sizeof *pkt ); - size_t n = strlen(s); + PACKET *pkt = xmalloc_clear (sizeof *pkt); + size_t n = strlen (s); - pkt->pkttype = PKT_USER_ID; - pkt->pkt.user_id = xmalloc_clear (sizeof *pkt->pkt.user_id + n); - pkt->pkt.user_id->len = n; - pkt->pkt.user_id->ref = 1; - strcpy(pkt->pkt.user_id->name, s); - add_kbnode( root, new_kbnode( pkt ) ); + if (n > MAX_UID_PACKET_LENGTH - 10) + return gpg_error (GPG_ERR_INV_USER_ID); + + pkt->pkttype = PKT_USER_ID; + pkt->pkt.user_id = xmalloc_clear (sizeof *pkt->pkt.user_id + n); + pkt->pkt.user_id->len = n; + pkt->pkt.user_id->ref = 1; + strcpy (pkt->pkt.user_id->name, s); + add_kbnode (root, new_kbnode (pkt)); + return 0; } static void @@ -5092,10 +5096,11 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para, if (!err && (s = get_parameter_value (para, pUSERID))) { - write_uid (pub_root, s ); - err = write_selfsigs (ctrl, pub_root, pri_psk, - get_parameter_uint (para, pKEYUSAGE), timestamp, - cache_nonce); + err = write_uid (pub_root, s ); + if (!err) + err = write_selfsigs (ctrl, pub_root, pri_psk, + get_parameter_uint (para, pKEYUSAGE), timestamp, + cache_nonce); } /* Write the auth key to the card before the encryption key. This diff --git a/g10/packet.h b/g10/packet.h index d787bde9e..479f25044 100644 --- a/g10/packet.h +++ b/g10/packet.h @@ -33,6 +33,11 @@ #define DEBUG_PARSE_PACKET 1 +/* Maximum length of packets to avoid excessive memory allocation. */ +#define MAX_KEY_PACKET_LENGTH (256 * 1024) +#define MAX_UID_PACKET_LENGTH ( 2 * 1024) +#define MAX_COMMENT_PACKET_LENGTH ( 64 * 1024) +#define MAX_ATTR_PACKET_LENGTH ( 16 * 1024*1024) /* Constants to allocate static MPI arrays. */ #define PUBKEY_MAX_NPKEY OPENPGP_MAX_NPKEY diff --git a/g10/parse-packet.c b/g10/parse-packet.c index f67edc547..ab82d475a 100644 --- a/g10/parse-packet.c +++ b/g10/parse-packet.c @@ -38,12 +38,6 @@ #include "../common/mbox-util.h" -/* Maximum length of packets to avoid excessive memory allocation. */ -#define MAX_KEY_PACKET_LENGTH (256 * 1024) -#define MAX_UID_PACKET_LENGTH ( 2 * 1024) -#define MAX_COMMENT_PACKET_LENGTH ( 64 * 1024) -#define MAX_ATTR_PACKET_LENGTH ( 16 * 1024*1024) - static int mpi_print_mode; static int list_mode; static estream_t listfp; From 4c7d63cd5b02ebfd09933bebd1312e01958b3e20 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 21 May 2019 17:27:42 +0200 Subject: [PATCH 092/169] gpg: Do not bail on an invalid packet in the local keyring. * g10/keydb.c (parse_keyblock_image): Treat invalid packet special. -- This is in particular useful to run --list-keys on a keyring with corrupted packets. The extra flush is to keep the diagnostic close to the regular --list-key output. Signed-off-by: Werner Koch --- g10/keydb.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/g10/keydb.c b/g10/keydb.c index 45eb4aa34..a7691bbe2 100644 --- a/g10/keydb.c +++ b/g10/keydb.c @@ -1242,8 +1242,15 @@ parse_keyblock_image (iobuf_t iobuf, int pk_no, int uid_no, } if (err) { + es_fflush (es_stdout); log_error ("parse_keyblock_image: read error: %s\n", gpg_strerror (err)); + if (gpg_err_code (err) == GPG_ERR_INV_PACKET) + { + free_packet (pkt, &parsectx); + init_packet (pkt); + continue; + } err = gpg_error (GPG_ERR_INV_KEYRING); break; } From 265e6d670682e661cec89657c3330b0b388ca0a7 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Thu, 23 May 2019 09:40:01 +0900 Subject: [PATCH 093/169] g10: Copy expiredate from primary key when marked expired. * g10/getkey.c (merge_selfsigs): Update ->expiredate of subkey. -- GnuPG-bug-id: 3343 Signed-off-by: NIIBE Yutaka --- g10/getkey.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/g10/getkey.c b/g10/getkey.c index 1e7334307..bb8486bb4 100644 --- a/g10/getkey.c +++ b/g10/getkey.c @@ -3185,7 +3185,11 @@ merge_selfsigs (ctrl_t ctrl, kbnode_t keyblock) memcpy (&pk->revoked, &rinfo, sizeof (rinfo)); } if (main_pk->has_expired) - pk->has_expired = main_pk->has_expired; + { + pk->has_expired = main_pk->has_expired; + if (!pk->expiredate || pk->expiredate > main_pk->expiredate) + pk->expiredate = main_pk->expiredate; + } } } return; From 7158a5696dc84e1ebd2b523ab83a43a32423181d Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Thu, 23 May 2019 10:15:18 +0900 Subject: [PATCH 094/169] agent: Stop scdaemon after reload when disable_scdaemon. * agent/call-scd.c (agent_card_killscd): New. * agent/gpg-agent.c (agent_sighup_action): Call agent_card_killscd. -- GnuPG-bug-id: 4326 Signed-off-by: NIIBE Yutaka --- agent/agent.h | 1 + agent/call-scd.c | 9 +++++++++ agent/gpg-agent.c | 3 +++ 3 files changed, 13 insertions(+) diff --git a/agent/agent.h b/agent/agent.h index 77672bd50..ec8370c4b 100644 --- a/agent/agent.h +++ b/agent/agent.h @@ -618,6 +618,7 @@ int agent_card_scd (ctrl_t ctrl, const char *cmdline, void agent_card_free_keyinfo (struct card_key_info_s *l); gpg_error_t agent_card_keyinfo (ctrl_t ctrl, const char *keygrip, struct card_key_info_s **result); +void agent_card_killscd (void); /*-- learncard.c --*/ diff --git a/agent/call-scd.c b/agent/call-scd.c index 5b53b0223..a96f5b783 100644 --- a/agent/call-scd.c +++ b/agent/call-scd.c @@ -1515,3 +1515,12 @@ agent_card_scd (ctrl_t ctrl, const char *cmdline, return unlock_scd (ctrl, 0); } + +void +agent_card_killscd (void) +{ + if (primary_scd_ctx == NULL) + return; + assuan_transact (primary_scd_ctx, "KILLSCD", + NULL, NULL, NULL, NULL, NULL, NULL); +} diff --git a/agent/gpg-agent.c b/agent/gpg-agent.c index d3fe7fe56..57d5a459c 100644 --- a/agent/gpg-agent.c +++ b/agent/gpg-agent.c @@ -2441,6 +2441,9 @@ agent_sighup_action (void) "pinentry" binary that one can be used in case the "pinentry-basic" fallback was in use. */ gnupg_module_name_flush_some (); + + if (opt.disable_scdaemon) + agent_card_killscd (); } From cc6069ac6ecd57dcbb808f28d54fd9f89dc55014 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 27 May 2019 10:40:38 +0200 Subject: [PATCH 095/169] gpg: Allow deletion of subkeys with --delete-[secret-]key. * common/userids.c (classify_user_id): Do not set the EXACT flag in the default case. * g10/export.c (exact_subkey_match_p): Make static, * g10/delkey.c (do_delete_key): Implement subkey only deleting. -- GnuPG-bug-id: 4457 --- common/userids.c | 7 ++-- doc/gpg.texi | 10 ++++- g10/delkey.c | 104 +++++++++++++++++++++++++++++++++++++++++++---- g10/export.c | 4 +- g10/main.h | 2 + 5 files changed, 113 insertions(+), 14 deletions(-) diff --git a/common/userids.c b/common/userids.c index 181b48866..55bd85546 100644 --- a/common/userids.c +++ b/common/userids.c @@ -380,8 +380,10 @@ classify_user_id (const char *name, KEYDB_SEARCH_DESC *desc, int openpgp_hack) } else if (!hexprefix) { - /* The fingerprint in an X.509 listing is often delimited by - colons, so we try to single this case out. */ + /* The fingerprint of an X.509 listing is often delimited by + * colons, so we try to single this case out. Note that the + * OpenPGP bang suffix is not supported here. */ + desc->exact = 0; mode = 0; hexlength = strspn (s, ":0123456789abcdefABCDEF"); if (hexlength == 59 && (!s[hexlength] || spacep (s+hexlength))) @@ -454,7 +456,6 @@ classify_user_id (const char *name, KEYDB_SEARCH_DESC *desc, int openpgp_hack) } if (!mode) /* Default to substring search. */ { - desc->exact = 0; desc->u.name = s; mode = KEYDB_SEARCH_MODE_SUBSTR; } diff --git a/doc/gpg.texi b/doc/gpg.texi index fd7dcddf0..c9262c66a 100644 --- a/doc/gpg.texi +++ b/doc/gpg.texi @@ -404,7 +404,10 @@ functionality is also available as the subcommand "passwd" with the @opindex delete-keys Remove key from the public keyring. In batch mode either @option{--yes} is required or the key must be specified by fingerprint. This is a -safeguard against accidental deletion of multiple keys. +safeguard against accidental deletion of multiple keys. If the +exclamation mark syntax is used with the fingerprint of a subkey only +that subkey is deleted; if the exclamation mark is used with the +fingerprint of the primary key the entire public key is deleted. @item --delete-secret-keys @var{name} @opindex delete-secret-keys @@ -413,7 +416,10 @@ specified by fingerprint. The option @option{--yes} can be used to advice gpg-agent not to request a confirmation. This extra pre-caution is done because @command{@gpgname} can't be sure that the secret key (as controlled by gpg-agent) is only used for the given -OpenPGP public key. +OpenPGP public key. If the exclamation mark syntax is used with the +fingerprint of a subkey only the secret part of that subkey is +deleted; if the exclamation mark is used with the fingerprint of the +primary key only the secret part of the primary key is deleted. @item --delete-secret-and-public-key @var{name} diff --git a/g10/delkey.c b/g10/delkey.c index 6f816080e..b5ab47434 100644 --- a/g10/delkey.c +++ b/g10/delkey.c @@ -1,7 +1,7 @@ /* delkey.c - delete keys * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, * 2005, 2006 Free Software Foundation, Inc. - * Copyright (C) 2014 Werner Koch + * Copyright (C) 2014, 2019 Werner Koch * * This file is part of GnuPG. * @@ -53,13 +53,15 @@ do_delete_key (ctrl_t ctrl, const char *username, int secret, int force, gpg_error_t err; kbnode_t keyblock = NULL; kbnode_t node, kbctx; + kbnode_t targetnode; KEYDB_HANDLE hd; PKT_public_key *pk = NULL; u32 keyid[2]; int okay=0; int yes; KEYDB_SEARCH_DESC desc; - int exactmatch; + int exactmatch; /* True if key was found by fingerprint. */ + int thiskeyonly; /* 0 = false, 1 = is primary key, 2 = is a subkey. */ *r_sec_avail = 0; @@ -70,6 +72,7 @@ do_delete_key (ctrl_t ctrl, const char *username, int secret, int force, /* Search the userid. */ err = classify_user_id (username, &desc, 1); exactmatch = (desc.mode == KEYDB_SEARCH_MODE_FPR); + thiskeyonly = desc.exact; if (!err) err = keydb_search (hd, &desc, 1, NULL); if (err) @@ -95,7 +98,35 @@ do_delete_key (ctrl_t ctrl, const char *username, int secret, int force, err = gpg_error (GPG_ERR_GENERAL); goto leave; } - pk = node->pkt->pkt.public_key; + + /* If an operation only on a subkey is requested, find that subkey + * now. */ + if (thiskeyonly) + { + kbnode_t tmpnode; + + for (kbctx=NULL; (tmpnode = walk_kbnode (keyblock, &kbctx, 0)); ) + { + if (!(tmpnode->pkt->pkttype == PKT_PUBLIC_KEY + || tmpnode->pkt->pkttype == PKT_PUBLIC_SUBKEY)) + continue; + if (exact_subkey_match_p (&desc, tmpnode)) + break; + } + if (!tmpnode) + { + log_error ("Oops; requested subkey not found anymore!\n"); + err = gpg_error (GPG_ERR_GENERAL); + goto leave; + } + /* Set NODE to this specific subkey or primary key. */ + thiskeyonly = node == tmpnode? 1 : 2; + targetnode = tmpnode; + } + else + targetnode = node; + + pk = targetnode->pkt->pkt.public_key; keyid_from_pk (pk, keyid); if (!secret && !force) @@ -136,7 +167,32 @@ do_delete_key (ctrl_t ctrl, const char *username, int secret, int force, else { print_key_info (ctrl, NULL, 0, pk, secret); - tty_printf( "\n" ); + tty_printf ("\n"); + if (thiskeyonly == 1 && !secret) + { + /* We need to delete the entire public key despite the use + * of the thiskeyonly request. */ + tty_printf (_("Note: The public primary key and all its subkeys" + " will be deleted.\n")); + } + else if (thiskeyonly == 2 && !secret) + { + tty_printf (_("Note: Only the shown public subkey" + " will be deleted.\n")); + } + if (thiskeyonly == 1 && secret) + { + tty_printf (_("Note: Only the secret part of the shown primary" + " key will be deleted.\n")); + } + else if (thiskeyonly == 2 && secret) + { + tty_printf (_("Note: Only the secret part of the shown subkey" + " will be deleted.\n")); + } + + if (thiskeyonly) + tty_printf ("\n"); yes = cpr_get_answer_is_yes (secret? "delete_key.secret.okay": "delete_key.okay", @@ -173,6 +229,9 @@ do_delete_key (ctrl_t ctrl, const char *username, int secret, int force, || node->pkt->pkttype == PKT_PUBLIC_SUBKEY)) continue; + if (thiskeyonly && targetnode != node) + continue; + if (agent_probe_secret_key (NULL, node->pkt->pkt.public_key)) continue; /* No secret key for that public (sub)key. */ @@ -214,9 +273,38 @@ do_delete_key (ctrl_t ctrl, const char *username, int secret, int force, if (firsterr) goto leave; } + else if (thiskeyonly == 2) + { + int selected = 0; + + /* Delete the specified public subkey. */ + for (kbctx=NULL; (node = walk_kbnode (keyblock, &kbctx, 0)); ) + { + if (thiskeyonly && targetnode != node) + continue; + + if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) + { + selected = targetnode == node; + if (selected) + delete_kbnode (node); + } + else if (selected && node->pkt->pkttype == PKT_SIGNATURE) + delete_kbnode (node); + else + selected = 0; + } + commit_kbnode (&keyblock); + err = keydb_update_keyblock (ctrl, hd, keyblock); + if (err) + { + log_error (_("update failed: %s\n"), gpg_strerror (err)); + goto leave; + } + } else { - err = opt.dry_run? 0 : keydb_delete_keyblock (hd); + err = keydb_delete_keyblock (hd); if (err) { log_error (_("deleting keyblock failed: %s\n"), @@ -229,7 +317,8 @@ do_delete_key (ctrl_t ctrl, const char *username, int secret, int force, revalidation_mark(). This makes sense - only deleting keys that have ownertrust set should trigger this. */ - if (!secret && pk && !opt.dry_run && clear_ownertrusts (ctrl, pk)) + if (!secret && pk && !opt.dry_run && thiskeyonly != 2 + && clear_ownertrusts (ctrl, pk)) { if (opt.verbose) log_info (_("ownertrust information cleared\n")); @@ -242,7 +331,8 @@ do_delete_key (ctrl_t ctrl, const char *username, int secret, int force, return err; } -/**************** + +/* * Delete a public or secret key from a keyring. */ gpg_error_t diff --git a/g10/export.c b/g10/export.c index b12da9cdb..9be7d137e 100644 --- a/g10/export.c +++ b/g10/export.c @@ -436,8 +436,8 @@ new_subkey_list_item (KBNODE node) (keyID or fingerprint) and does match the one at NODE. It is assumed that the packet at NODE is either a public or secret subkey. */ -static int -exact_subkey_match_p (KEYDB_SEARCH_DESC *desc, KBNODE node) +int +exact_subkey_match_p (KEYDB_SEARCH_DESC *desc, kbnode_t node) { u32 kid[2]; byte fpr[MAX_FINGERPRINT_LEN]; diff --git a/g10/main.h b/g10/main.h index 134d8b950..67d7e8060 100644 --- a/g10/main.h +++ b/g10/main.h @@ -414,6 +414,8 @@ void export_print_stats (export_stats_t stats); int parse_export_options(char *str,unsigned int *options,int noisy); gpg_error_t parse_and_set_export_filter (const char *string); +int exact_subkey_match_p (KEYDB_SEARCH_DESC *desc, kbnode_t node); + int export_pubkeys (ctrl_t ctrl, strlist_t users, unsigned int options, export_stats_t stats); int export_seckeys (ctrl_t ctrl, strlist_t users, unsigned int options, From b6289af9738ddbc533defba0aefd950a9ca21ff1 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 27 May 2019 12:52:58 +0200 Subject: [PATCH 096/169] gpg: Fixed i18n markup of some strings. * g10/tofu.c: Removed some translation markups which either make no sense or are not possble. -- Error message which are not helpful for the user but indicate a problem of the installation or the code do not need a translation. The translator may not understand them correctly and the use support can't immediately locate the problem because it needs to be reverse translated. There is also one case where certain grammar constructs are assumed (concatenating parts of a sentence at runtime). Better do not translate that than getting weird sentences. --- g10/tofu.c | 32 ++++++++++++-------------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/g10/tofu.c b/g10/tofu.c index 44f354512..e78da15c1 100644 --- a/g10/tofu.c +++ b/g10/tofu.c @@ -534,7 +534,7 @@ check_utks (sqlite3 *db) NULL, NULL, &err); if (rc) { - log_error (_("error creating 'ultimately_trusted_keys' TOFU table: %s\n"), + log_error ("error creating 'ultimately_trusted_keys' TOFU table: %s\n", err); sqlite3_free (err); goto out; @@ -840,7 +840,7 @@ initdb (sqlite3 *db) NULL, NULL, &err); if (rc) { - log_error (_("error creating 'encryptions' TOFU table: %s\n"), + log_error ("error creating 'encryptions' TOFU table: %s\n", err); sqlite3_free (err); } @@ -870,7 +870,7 @@ initdb (sqlite3 *db) * safely ignore. */ rc = 0; else - log_error (_("adding column effective_policy to bindings DB: %s\n"), + log_error ("adding column effective_policy to bindings DB: %s\n", err); sqlite3_free (err); } @@ -2146,8 +2146,7 @@ build_conflict_set (ctrl_t ctrl, tofu_dbs_t dbs, rc = keydb_search_reset (hd); if (rc) { - log_error (_("resetting keydb: %s\n"), - gpg_strerror (rc)); + log_error ("resetting keydb failed: %s\n", gpg_strerror (rc)); continue; } @@ -2614,8 +2613,8 @@ get_policy (ctrl_t ctrl, tofu_dbs_t dbs, PKT_public_key *pk, if (record_binding (dbs, fingerprint, email, user_id, policy == TOFU_POLICY_NONE ? TOFU_POLICY_AUTO : policy, effective_policy, conflict, 1, 0, now) != 0) - log_error (_("error setting TOFU binding's policy" - " to %s\n"), tofu_policy_str (policy)); + log_error ("error setting TOFU binding's policy" + " to %s\n", tofu_policy_str (policy)); } /* If the caller wants the set of conflicts, return it. */ @@ -3152,14 +3151,10 @@ show_statistics (tofu_dbs_t dbs, es_fprintf (fp, _("%s: Verified 0 signatures."), email); else { - /* TRANSLATORS: The final %s is replaced by a string like - "7~months". */ + /* Note: Translation not possible with that wording. */ char *ago_str = time_ago_str (now - signature_first_seen); es_fprintf - (fp, - ngettext("%s: Verified %ld~signature in the past %s.", - "%s: Verified %ld~signatures in the past %s.", - signature_count), + (fp, "%s: Verified %ld~signatures in the past %s.", email, signature_count, ago_str); xfree (ago_str); } @@ -3172,12 +3167,9 @@ show_statistics (tofu_dbs_t dbs, { char *ago_str = time_ago_str (now - encryption_first_done); - /* TRANSLATORS: The final %s is replaced by a string like - "7~months". */ - es_fprintf (fp, - ngettext("Encrypted %ld~message in the past %s.", - "Encrypted %ld~messages in the past %s.", - encryption_count), + /* Note: Translation not possible with this kind of + * composition. */ + es_fprintf (fp, "Encrypted %ld~messages in the past %s.", encryption_count, ago_str); xfree (ago_str); } @@ -3944,7 +3936,7 @@ tofu_set_policy (ctrl_t ctrl, kbnode_t kb, enum tofu_policy policy) policy, TOFU_POLICY_NONE, NULL, 0, 1, now); if (err) { - log_error (_("error setting policy for key %s, user id \"%s\": %s"), + log_error ("error setting policy for key %s, user id \"%s\": %s", fingerprint, email, gpg_strerror (err)); xfree (email); break; From 521e7d4644ed365ab2de3dfaa6c3728ca10ba79b Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 27 May 2019 15:44:16 +0200 Subject: [PATCH 097/169] sm: Avoid confusing diagnostic for the default key. * sm/certlist.c (cert_usage_p): Add arg 'silent' and change all callers. (gpgsm_cert_use_sign_p): Add arg 'silent' and pass to cert_usage_p. Change all callers. * sm/sign.c (gpgsm_get_default_cert): Set SILENT when calling gpgsm_cert_use_sign_p -- GnuPG-bug-id: 4535 Signed-off-by: Werner Koch --- sm/certlist.c | 45 +++++++++++++++++++++++++-------------------- sm/gpgsm.h | 2 +- sm/sign.c | 6 +++--- 3 files changed, 29 insertions(+), 24 deletions(-) diff --git a/sm/certlist.c b/sm/certlist.c index 12a492518..0847c169b 100644 --- a/sm/certlist.c +++ b/sm/certlist.c @@ -48,7 +48,7 @@ static const char oid_kp_ocspSigning[] = "1.3.6.1.5.5.7.3.9"; debugging). MODE 4 is for certificate signing, MODE for COSP response signing. */ static int -cert_usage_p (ksba_cert_t cert, int mode) +cert_usage_p (ksba_cert_t cert, int mode, int silent) { gpg_error_t err; unsigned int use; @@ -118,7 +118,7 @@ cert_usage_p (ksba_cert_t cert, int mode) if (gpg_err_code (err) == GPG_ERR_NO_DATA) { err = 0; - if (opt.verbose && mode < 2) + if (opt.verbose && mode < 2 && !silent) log_info (_("no key usage specified - assuming all usages\n")); use = ~0; } @@ -139,8 +139,9 @@ cert_usage_p (ksba_cert_t cert, int mode) { if ((use & (KSBA_KEYUSAGE_KEY_CERT_SIGN))) return 0; - log_info (_("certificate should not have " - "been used for certification\n")); + if (!silent) + log_info (_("certificate should not have " + "been used for certification\n")); return gpg_error (GPG_ERR_WRONG_KEY_USAGE); } @@ -151,8 +152,9 @@ cert_usage_p (ksba_cert_t cert, int mode) || (use & (KSBA_KEYUSAGE_KEY_CERT_SIGN |KSBA_KEYUSAGE_CRL_SIGN)))) return 0; - log_info (_("certificate should not have " - "been used for OCSP response signing\n")); + if (!silent) + log_info (_("certificate should not have " + "been used for OCSP response signing\n")); return gpg_error (GPG_ERR_WRONG_KEY_USAGE); } @@ -162,19 +164,22 @@ cert_usage_p (ksba_cert_t cert, int mode) ) return 0; - log_info (mode==3? _("certificate should not have been used for encryption\n"): - mode==2? _("certificate should not have been used for signing\n"): - mode==1? _("certificate is not usable for encryption\n"): - _("certificate is not usable for signing\n")); + if (!silent) + log_info + (mode==3? _("certificate should not have been used for encryption\n"): + mode==2? _("certificate should not have been used for signing\n"): + mode==1? _("certificate is not usable for encryption\n"): + /**/ _("certificate is not usable for signing\n")); + return gpg_error (GPG_ERR_WRONG_KEY_USAGE); } /* Return 0 if the cert is usable for signing */ int -gpgsm_cert_use_sign_p (ksba_cert_t cert) +gpgsm_cert_use_sign_p (ksba_cert_t cert, int silent) { - return cert_usage_p (cert, 0); + return cert_usage_p (cert, 0, silent); } @@ -182,31 +187,31 @@ gpgsm_cert_use_sign_p (ksba_cert_t cert) int gpgsm_cert_use_encrypt_p (ksba_cert_t cert) { - return cert_usage_p (cert, 1); + return cert_usage_p (cert, 1, 0); } int gpgsm_cert_use_verify_p (ksba_cert_t cert) { - return cert_usage_p (cert, 2); + return cert_usage_p (cert, 2, 0); } int gpgsm_cert_use_decrypt_p (ksba_cert_t cert) { - return cert_usage_p (cert, 3); + return cert_usage_p (cert, 3, 0); } int gpgsm_cert_use_cert_p (ksba_cert_t cert) { - return cert_usage_p (cert, 4); + return cert_usage_p (cert, 4, 0); } int gpgsm_cert_use_ocsp_p (ksba_cert_t cert) { - return cert_usage_p (cert, 5); + return cert_usage_p (cert, 5, 0); } @@ -341,7 +346,7 @@ gpgsm_add_to_certlist (ctrl_t ctrl, const char *name, int secret, first_subject = ksba_cert_get_subject (cert, 0); first_issuer = ksba_cert_get_issuer (cert, 0); } - rc = secret? gpgsm_cert_use_sign_p (cert) + rc = secret? gpgsm_cert_use_sign_p (cert, 0) : gpgsm_cert_use_encrypt_p (cert); if (gpg_err_code (rc) == GPG_ERR_WRONG_KEY_USAGE) { @@ -403,8 +408,8 @@ gpgsm_add_to_certlist (ctrl_t ctrl, const char *name, int secret, first_issuer, cert2) && ((gpg_err_code ( - secret? gpgsm_cert_use_sign_p (cert2) - : gpgsm_cert_use_encrypt_p (cert2) + secret? gpgsm_cert_use_sign_p (cert2,0) + : gpgsm_cert_use_encrypt_p (cert2) ) ) == GPG_ERR_WRONG_KEY_USAGE)); if (tmp) diff --git a/sm/gpgsm.h b/sm/gpgsm.h index 4ad0afb29..65fff853a 100644 --- a/sm/gpgsm.h +++ b/sm/gpgsm.h @@ -337,7 +337,7 @@ int gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert, int gpgsm_basic_cert_check (ctrl_t ctrl, ksba_cert_t cert); /*-- certlist.c --*/ -int gpgsm_cert_use_sign_p (ksba_cert_t cert); +int gpgsm_cert_use_sign_p (ksba_cert_t cert, int silent); int gpgsm_cert_use_encrypt_p (ksba_cert_t cert); int gpgsm_cert_use_verify_p (ksba_cert_t cert); int gpgsm_cert_use_decrypt_p (ksba_cert_t cert); diff --git a/sm/sign.c b/sm/sign.c index 0604642b4..341d8cf68 100644 --- a/sm/sign.c +++ b/sm/sign.c @@ -161,7 +161,7 @@ gpgsm_get_default_cert (ctrl_t ctrl, ksba_cert_t *r_cert) return rc; } - if (!gpgsm_cert_use_sign_p (cert)) + if (!gpgsm_cert_use_sign_p (cert, 1)) { p = gpgsm_get_keygrip_hexstring (cert); if (p) @@ -504,7 +504,7 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, /* Although we don't check for ambiguous specification we will check that the signer's certificate is usable and valid. */ - rc = gpgsm_cert_use_sign_p (cert); + rc = gpgsm_cert_use_sign_p (cert, 0); if (!rc) rc = gpgsm_validate_chain (ctrl, cert, "", NULL, 0, NULL, 0, NULL); if (rc) @@ -613,7 +613,7 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, /* Gather certificates of signers and store them in the CMS object. */ for (cl=signerlist; cl; cl = cl->next) { - rc = gpgsm_cert_use_sign_p (cl->cert); + rc = gpgsm_cert_use_sign_p (cl->cert, 0); if (rc) goto leave; From 19415a265253a5ab72e79493d2f40c7e4441d81e Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Tue, 28 May 2019 11:29:25 +0900 Subject: [PATCH 098/169] agent: Remove unused agent_show_message. * agent/call-pinentry.c (agent_show_message): Remove. * agent/genkey.c (take_this_one_anyway): Rename from take_this_one_anyway2. Remove a dead path calling agent_show_message. (check_passphrase_constraints): Use take_this_one_anyway. -- Fixes-commit: 2778c6f8f40d73272075ce04c07097f65c94054e Signed-off-by: NIIBE Yutaka --- agent/call-pinentry.c | 49 ------------------------------------------- agent/genkey.c | 29 ++++++------------------- 2 files changed, 6 insertions(+), 72 deletions(-) diff --git a/agent/call-pinentry.c b/agent/call-pinentry.c index 5b4713f41..487b21e81 100644 --- a/agent/call-pinentry.c +++ b/agent/call-pinentry.c @@ -1454,55 +1454,6 @@ agent_get_confirmation (ctrl_t ctrl, -/* Pop up the PINentry, display the text DESC and a button with the - text OK_BTN (which may be NULL to use the default of "OK") and wait - for the user to hit this button. The return value is not - relevant. */ -int -agent_show_message (ctrl_t ctrl, const char *desc, const char *ok_btn) -{ - int rc; - char line[ASSUAN_LINELENGTH]; - - if (ctrl->pinentry_mode != PINENTRY_MODE_ASK) - return gpg_error (GPG_ERR_CANCELED); - - rc = start_pinentry (ctrl); - if (rc) - return rc; - - if (desc) - build_cmd_setdesc (line, DIM(line), desc); - else - snprintf (line, DIM(line), "RESET"); - rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); - /* Most pinentries out in the wild return the old Assuan error code - for canceled which gets translated to an assuan Cancel error and - not to the code for a user cancel. Fix this here. */ - if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED) - rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED); - - if (rc) - return unlock_pinentry (ctrl, rc); - - if (ok_btn) - { - snprintf (line, DIM(line), "SETOK %s", ok_btn); - rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, - NULL, NULL, NULL); - if (rc) - return unlock_pinentry (ctrl, rc); - } - - rc = assuan_transact (entry_ctx, "CONFIRM --one-button", NULL, NULL, NULL, - NULL, NULL, NULL); - if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED) - rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED); - - return unlock_pinentry (ctrl, rc); -} - - /* The thread running the popup message. */ static void * popup_message_thread (void *arg) diff --git a/agent/genkey.c b/agent/genkey.c index 46a772eda..0d2038016 100644 --- a/agent/genkey.c +++ b/agent/genkey.c @@ -148,27 +148,10 @@ check_passphrase_pattern (ctrl_t ctrl, const char *pw) static int -take_this_one_anyway2 (ctrl_t ctrl, const char *desc, const char *anyway_btn) +take_this_one_anyway (ctrl_t ctrl, const char *desc, const char *anyway_btn) { - gpg_error_t err; - - if (opt.enforce_passphrase_constraints) - { - err = agent_show_message (ctrl, desc, L_("Enter new passphrase")); - if (!err) - err = gpg_error (GPG_ERR_CANCELED); - } - else - err = agent_get_confirmation (ctrl, desc, - anyway_btn, L_("Enter new passphrase"), 0); - return err; -} - - -static int -take_this_one_anyway (ctrl_t ctrl, const char *desc) -{ - return take_this_one_anyway2 (ctrl, desc, L_("Take this one anyway")); + return agent_get_confirmation (ctrl, desc, + anyway_btn, L_("Enter new passphrase"), 0); } @@ -211,8 +194,8 @@ check_passphrase_constraints (ctrl_t ctrl, const char *pw, if (opt.enforce_passphrase_constraints) *failed_constraint = xstrdup (desc); else - err = take_this_one_anyway2 (ctrl, desc, - L_("Yes, protection is not needed")); + err = take_this_one_anyway (ctrl, desc, + L_("Yes, protection is not needed")); } goto leave; @@ -310,7 +293,7 @@ check_passphrase_constraints (ctrl_t ctrl, const char *pw, *failed_constraint = msg; else { - err = take_this_one_anyway (ctrl, msg); + err = take_this_one_anyway (ctrl, msg, L_("Take this one anyway")); xfree (msg); } } From a2a90717466a88756bbdc6b11577cfee061fc1a8 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 28 May 2019 12:13:27 +0200 Subject: [PATCH 099/169] agent: Make an MD encoding function more robust. * agent/pksign.c (do_encode_md): Use ascii_tolower and avoid uninitalized TMP in the error case. -- This is just in case libgcrypt ever returns an algorithm name longer than 15 bytes. Signed-off-by: Werner Koch --- agent/pksign.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/agent/pksign.c b/agent/pksign.c index d9519d1bd..4a43b09de 100644 --- a/agent/pksign.c +++ b/agent/pksign.c @@ -44,16 +44,21 @@ do_encode_md (const byte * md, size_t mdlen, int algo, gcry_sexp_t * r_hash, int i; s = gcry_md_algo_name (algo); - if (s && strlen (s) < 16) + if (!s || strlen (s) >= 16) + { + hash = NULL; + rc = gpg_error (GPG_ERR_DIGEST_ALGO); + } + else { - for (i=0; i < strlen (s); i++) - tmp[i] = tolower (s[i]); + for (i=0; s[i]; i++) + tmp[i] = ascii_tolower (s[i]); tmp[i] = '\0'; - } - rc = gcry_sexp_build (&hash, NULL, - "(data (flags pkcs1) (hash %s %b))", - tmp, (int)mdlen, md); + rc = gcry_sexp_build (&hash, NULL, + "(data (flags pkcs1) (hash %s %b))", + tmp, (int)mdlen, md); + } } else { From 4699e294cc9e59f35262adca26ca291927acca9e Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 28 May 2019 12:22:39 +0200 Subject: [PATCH 100/169] dirmngr: Improve finding OCSP cert. * dirmngr/certcache.c (find_cert_bysubject): Add better debug output and try to locate by keyid. -- This chnages was suggested in GnuPG-bug-id: 4536 but we do not have any test cases for this. Signed-off-by: Werner Koch --- dirmngr/certcache.c | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/dirmngr/certcache.c b/dirmngr/certcache.c index adb005ec8..5486997b6 100644 --- a/dirmngr/certcache.c +++ b/dirmngr/certcache.c @@ -1471,6 +1471,9 @@ find_cert_bysubject (ctrl_t ctrl, const char *subject_dn, ksba_sexp_t keyid) { ksba_cert_ref (ci->cert); release_cache_lock (); + if (DBG_LOOKUP) + log_debug ("%s: certificate found in the cache" + " via ocsp_certs\n", __func__); return ci->cert; /* We use this certificate. */ } release_cache_lock (); @@ -1478,7 +1481,7 @@ find_cert_bysubject (ctrl_t ctrl, const char *subject_dn, ksba_sexp_t keyid) log_debug ("find_cert_bysubject: certificate not in ocsp_certs\n"); } - /* No check whether the certificate is cached. */ + /* Now check whether the certificate is cached. */ for (seq=0; (cert = get_cert_bysubject (subject_dn, seq)); seq++) { if (!keyid) @@ -1487,6 +1490,9 @@ find_cert_bysubject (ctrl_t ctrl, const char *subject_dn, ksba_sexp_t keyid) && !cmp_simple_canon_sexp (keyid, subj)) { xfree (subj); + if (DBG_LOOKUP) + log_debug ("%s: certificate found in the cache" + " via subject DN\n", __func__); break; /* Found matching cert. */ } xfree (subj); @@ -1495,6 +1501,34 @@ find_cert_bysubject (ctrl_t ctrl, const char *subject_dn, ksba_sexp_t keyid) if (cert) return cert; /* Done. */ + /* If we do not have a subject DN but have a keyid, try to locate it + * by keyid. */ + if (!subject_dn && keyid) + { + int i; + cert_item_t ci; + ksba_sexp_t ski; + + acquire_cache_read_lock (); + for (i=0; i < 256; i++) + for (ci=cert_cache[i]; ci; ci = ci->next) + if (ci->cert && !ksba_cert_get_subj_key_id (ci->cert, NULL, &ski)) + { + if (!cmp_simple_canon_sexp (keyid, ski)) + { + ksba_free (ski); + ksba_cert_ref (ci->cert); + release_cache_lock (); + if (DBG_LOOKUP) + log_debug ("%s: certificate found in the cache" + " via ski\n", __func__); + return ci->cert; + } + ksba_free (ski); + } + release_cache_lock (); + } + if (DBG_LOOKUP) log_debug ("find_cert_bysubject: certificate not in cache\n"); From 405f41007c35ef52bf85c7c2686dab01fdf2c950 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 28 May 2019 12:27:00 +0200 Subject: [PATCH 101/169] dirmngr: Allow for other hash algorithms than SHA-1 in OCSP. * dirmngr/ocsp.c (do_ocsp_request): Remove arg md. Add args r_sigval, r_produced_at, and r_md. Get the hash algo from the signature and create the context here. (check_signature): Allow any hash algo. Print a diagnostic if the signature does not verify. -- GnuPG-bug-id: 3966 Signed-off-by: Werner Koch --- dirmngr/ocsp.c | 105 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 80 insertions(+), 25 deletions(-) diff --git a/dirmngr/ocsp.c b/dirmngr/ocsp.c index dbd8c97bc..e19779c59 100644 --- a/dirmngr/ocsp.c +++ b/dirmngr/ocsp.c @@ -116,10 +116,15 @@ read_response (estream_t fp, unsigned char **r_buffer, size_t *r_buflen) /* Construct an OCSP request, send it to the configured OCSP responder and parse the response. On success the OCSP context may be used to - further process the response. */ + further process the response. The signature value and the + production date are returned at R_SIGVAL and R_PRODUCED_AT; they + may be NULL or an empty string if not available. A new hash + context is returned at R_MD. */ static gpg_error_t -do_ocsp_request (ctrl_t ctrl, ksba_ocsp_t ocsp, gcry_md_hd_t md, - const char *url, ksba_cert_t cert, ksba_cert_t issuer_cert) +do_ocsp_request (ctrl_t ctrl, ksba_ocsp_t ocsp, + const char *url, ksba_cert_t cert, ksba_cert_t issuer_cert, + ksba_sexp_t *r_sigval, ksba_isotime_t r_produced_at, + gcry_md_hd_t *r_md) { gpg_error_t err; unsigned char *request, *response; @@ -132,6 +137,10 @@ do_ocsp_request (ctrl_t ctrl, ksba_ocsp_t ocsp, gcry_md_hd_t md, (void)ctrl; + *r_sigval = NULL; + *r_produced_at = 0; + *r_md = NULL; + if (dirmngr_use_tor ()) { /* For now we do not allow OCSP via Tor due to possible privacy @@ -263,6 +272,7 @@ do_ocsp_request (ctrl_t ctrl, ksba_ocsp_t ocsp, gcry_md_hd_t md, xfree (free_this); return err; } + /* log_printhex (response, responselen, "ocsp response"); */ err = ksba_ocsp_parse_response (ocsp, response, responselen, &response_status); @@ -290,11 +300,34 @@ do_ocsp_request (ctrl_t ctrl, ksba_ocsp_t ocsp, gcry_md_hd_t md, } if (response_status == KSBA_OCSP_RSPSTATUS_SUCCESS) { + int hash_algo; + if (opt.verbose) log_info (_("OCSP responder at '%s' status: %s\n"), url, t); + /* Get the signature value now because we can all this fucntion + * only once. */ + *r_sigval = ksba_ocsp_get_sig_val (ocsp, r_produced_at); + + hash_algo = hash_algo_from_sigval (*r_sigval); + if (!hash_algo) + { + if (opt.verbose) + log_info ("ocsp: using SHA-256 as fallback hash algo.\n"); + hash_algo = GCRY_MD_SHA256; + } + err = gcry_md_open (r_md, hash_algo, 0); + if (err) + { + log_error (_("failed to establish a hashing context for OCSP: %s\n"), + gpg_strerror (err)); + goto leave; + } + if (DBG_HASHING) + gcry_md_debug (*r_md, "ocsp"); + err = ksba_ocsp_hash_response (ocsp, response, responselen, - HASH_FNC, md); + HASH_FNC, *r_md); if (err) log_error (_("hashing the OCSP response for '%s' failed: %s\n"), url, gpg_strerror (err)); @@ -305,8 +338,17 @@ do_ocsp_request (ctrl_t ctrl, ksba_ocsp_t ocsp, gcry_md_hd_t md, err = gpg_error (GPG_ERR_GENERAL); } + leave: xfree (response); xfree (free_this); + if (err) + { + xfree (*r_sigval); + *r_sigval = NULL; + *r_produced_at = 0; + gcry_md_close (*r_md); + *r_md = NULL; + } return err; } @@ -391,7 +433,7 @@ check_signature_core (ctrl_t ctrl, ksba_cert_t cert, gcry_sexp_t s_sig, /* We simply ignore all errors. */ gcry_sexp_release (s_pkey); - return -1; + return err; } @@ -410,18 +452,27 @@ check_signature (ctrl_t ctrl, int algo, cert_idx; gcry_sexp_t s_hash; ksba_cert_t cert; + const char *s; /* Create a suitable S-expression with the hash value of our response. */ gcry_md_final (md); algo = gcry_md_get_algo (md); - if (algo != GCRY_MD_SHA1 ) + s = gcry_md_algo_name (algo); + if (algo && s && strlen (s) < 16) { - log_error (_("only SHA-1 is supported for OCSP responses\n")); - return gpg_error (GPG_ERR_DIGEST_ALGO); + char hashalgostr[16+1]; + int i; + + for (i=0; s[i]; i++) + hashalgostr[i] = ascii_tolower (s[i]); + hashalgostr[i] = 0; + err = gcry_sexp_build (&s_hash, NULL, "(data(flags pkcs1)(hash %s %b))", + hashalgostr, + (int)gcry_md_get_algo_dlen (algo), + gcry_md_read (md, algo)); } - err = gcry_sexp_build (&s_hash, NULL, "(data(flags pkcs1)(hash sha1 %b))", - gcry_md_get_algo_dlen (algo), - gcry_md_read (md, algo)); + else + err = gpg_error (GPG_ERR_DIGEST_ALGO); if (err) { log_error (_("creating S-expression failed: %s\n"), gcry_strerror (err)); @@ -465,6 +516,7 @@ check_signature (ctrl_t ctrl, { cert_ref_t cref; + /* dump_cert ("from ocsp response", cert); */ cref = xtrymalloc (sizeof *cref); if (!cref) log_error (_("allocating list item failed: %s\n"), @@ -500,8 +552,6 @@ check_signature (ctrl_t ctrl, } log_printf ("not found\n"); } - ksba_free (name); - ksba_free (keyid); if (cert) { @@ -510,10 +560,24 @@ check_signature (ctrl_t ctrl, ksba_cert_release (cert); if (!err) { + ksba_free (name); + ksba_free (keyid); gcry_sexp_release (s_hash); return 0; /* Successfully verified the signature. */ } + log_error ("responder certificate "); + if (name) + log_printf ("'/%s' ", name); + if (keyid) + { + log_printf ("{"); + dump_serial (keyid); + log_printf ("} "); + } + log_printf ("did not verify: %s\n", gpg_strerror (err)); } + ksba_free (name); + ksba_free (keyid); } gcry_sexp_release (s_hash); @@ -588,8 +652,6 @@ ocsp_isvalid (ctrl_t ctrl, ksba_cert_t cert, const char *cert_fpr, goto leave; } - - /* Figure out the OCSP responder to use. 1. Try to get the reponder from the certificate. We do only take http and https style URIs into account. @@ -646,14 +708,8 @@ ocsp_isvalid (ctrl_t ctrl, ksba_cert_t cert, const char *cert_fpr, } /* Ask the OCSP responder. */ - err = gcry_md_open (&md, GCRY_MD_SHA1, 0); - if (err) - { - log_error (_("failed to establish a hashing context for OCSP: %s\n"), - gpg_strerror (err)); - goto leave; - } - err = do_ocsp_request (ctrl, ocsp, md, url, cert, issuer_cert); + err = do_ocsp_request (ctrl, ocsp, url, cert, issuer_cert, + &sigval, produced_at, &md); if (err) goto leave; @@ -685,8 +741,7 @@ ocsp_isvalid (ctrl_t ctrl, ksba_cert_t cert, const char *cert_fpr, } /* We got a useful answer, check that the answer has a valid signature. */ - sigval = ksba_ocsp_get_sig_val (ocsp, produced_at); - if (!sigval || !*produced_at) + if (!sigval || !*produced_at || !md) { err = gpg_error (GPG_ERR_INV_OBJ); goto leave; From 6b06fb3cc550c61921ac239cbe637d934827dd20 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 28 May 2019 18:09:13 +0200 Subject: [PATCH 102/169] Add changes from 2.2 to NEWS. -- --- NEWS | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/NEWS b/NEWS index e4599c2bd..5eab68ef0 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,88 @@ Noteworthy changes in version 2.3.0 (unreleased) ------------------------------------------------ + Changes also found in 2.2.16: + + * gpg,gpgsm: Fix deadlock on Windows due to a keybox sharing + violation. [#4505] + + * gpg: Allow deletion of subkeys with --delete-key. This finally + makes the bang-suffix work as expected for that command. [#4457] + + * gpg: Replace SHA-1 by SHA-256 in self-signatures when updating + them with --quick-set-expire or --quick-set-primary-uid. [#4508] + + * gpg: Improve the photo image viewer selection. [#4334] + + * gpg: Fix decryption with --use-embedded-filename. [#4500] + + * gpg: Remove hints on using the --keyserver option. [#4512] + + * gpg: Fix export of certain secret keys with comments. [#4490] + + * gpg: Reject too long user-ids in --quick-gen-key. [#4532] + + * gpg: Fix a double free in the best key selection code. [#4462] + + * gpg: Fix the key generation dialog for switching back from EdDSA + to ECDSA. + + * gpg: Use AES-192 with SHA-384 to comply with RFC-6637. + + * gpg: Use only the addrspec from the Signer's UID subpacket to + mitigate a problem with another implementation. + + * gpg: Skip invalid packets during a keyring listing and sync + diagnostics with the output. + + * gpgsm: Avoid confusing diagnostic when signing with the default + key. [#4535] + + * agent: Do not delete any secret key in --dry-run mode. + + * agent: Fix failures on 64 bit big-endian boxes related to URIs in + a keyfile. [#4501] + + * agent: Stop scdaemon after a reload with disable-scdaemon newly + configured. [#4326] + + * dirmngr: Improve caching algorithm for WKD domains. + + * dirmngr: Support other hash algorithms than SHA-1 for OCSP. [#3966] + + * gpgconf: Make --homedir work for --launch. [#4496] + + * gpgconf: Before --launch check for a valid config file. [#4497] + + * wkd: Do not import more than 5 keys from one WKD address. + + * wkd: Accept keys which are stored in armored format in the + directory. + + * The installer for Windows now comes with signed binaries. + + Release-info: https://dev.gnupg.org/T4509 + See-also: gnupg-announce/2019q2/000438.html + + Changes also found in 2.2.15: + + * sm: Fix --logger-fd and --status-fd on Windows for non-standard + file descriptors. + + * sm: Allow decryption even if expired keys are configured. [#4431] + + * agent: Change command KEYINFO to print ssh fingerprints with other + hash algos. + + * dirmngr: Fix build problems on Solaris due to the use of reserved + symbol names. [#4420] + + * wkd: New commands --print-wkd-hash and --print-wkd-url for + gpg-wks-client. + + Release-info: https://dev.gnupg.org/T4434 + See-also: gnupg-announce/2019q1/000436.html + Changes also found in 2.2.14: * gpg: Allow import of PGP desktop exported secret keys. Also avoid @@ -487,6 +569,8 @@ Noteworthy changes in version 2.3.0 (unreleased) Version 2.2.12 (2018-12-14) Version 2.2.13 (2019-02-12) Version 2.2.14 (2019-03-19) + Version 2.2.15 (2019-03-26) + Version 2.2.16 (2019-05-28) Noteworthy changes in version 2.2.0 (2017-08-28) From 6790eaf9529209e36099d9520821a3b8ad02ccef Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Wed, 29 May 2019 16:19:46 +0900 Subject: [PATCH 103/169] agent: Add A-flag for KEYINFO output for card. * agent/command.c (do_one_keyinfo): Add ON_CARD argument to put A-flag. (cmd_keyinfo): Call agent_card_keyinfo to offer additional information if it's on card. -- This is a modification in gpg-agent, intended for better enum_secret_keys in gpg frontend. GnuPG-bug-id: 4244 Signed-off-by: NIIBE Yutaka --- agent/command.c | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/agent/command.c b/agent/command.c index c056eb3f0..460aa1dec 100644 --- a/agent/command.c +++ b/agent/command.c @@ -1120,13 +1120,14 @@ static const char hlp_keyinfo[] = " 'D' - The key has been disabled,\n" " 'S' - The key is listed in sshcontrol (requires --with-ssh),\n" " 'c' - Use of the key needs to be confirmed,\n" + " 'A' - The key is available on card,\n" " '-' - No flags given.\n" "\n" "More information may be added in the future."; static gpg_error_t do_one_keyinfo (ctrl_t ctrl, const unsigned char *grip, assuan_context_t ctx, int data, int with_ssh_fpr, int in_ssh, - int ttl, int disabled, int confirm) + int ttl, int disabled, int confirm, int on_card) { gpg_error_t err; char hexgrip[40+1]; @@ -1167,6 +1168,8 @@ do_one_keyinfo (ctrl_t ctrl, const unsigned char *grip, assuan_context_t ctx, strcat (flagsbuf, "S"); if (confirm) strcat (flagsbuf, "c"); + if (on_card) + strcat (flagsbuf, "A"); if (!*flagsbuf) strcpy (flagsbuf, "-"); @@ -1271,6 +1274,9 @@ cmd_keyinfo (assuan_context_t ctx, char *line) ssh_control_file_t cf = NULL; char hexgrip[41]; int disabled, ttl, confirm, is_ssh; + struct card_key_info_s *keyinfo_on_cards; + struct card_key_info_s *l; + int on_card; if (ctrl->restricted) return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN)); @@ -1301,6 +1307,8 @@ cmd_keyinfo (assuan_context_t ctx, char *line) if (opt_with_ssh || list_mode == 2) cf = ssh_open_control_file (); + agent_card_keyinfo (ctrl, NULL, &keyinfo_on_cards); + if (list_mode == 2) { if (cf) @@ -1310,8 +1318,14 @@ cmd_keyinfo (assuan_context_t ctx, char *line) { if (hex2bin (hexgrip, grip, 20) < 0 ) continue; /* Bad hex string. */ + + on_card = 0; + for (l = keyinfo_on_cards; l; l = l->next) + if (!memcmp (l->keygrip, hexgrip, 40)) + on_card = 1; + err = do_one_keyinfo (ctrl, grip, ctx, opt_data, opt_ssh_fpr, 1, - ttl, disabled, confirm); + ttl, disabled, confirm, on_card); if (err) goto leave; } @@ -1361,8 +1375,13 @@ cmd_keyinfo (assuan_context_t ctx, char *line) goto leave; } + on_card = 0; + for (l = keyinfo_on_cards; l; l = l->next) + if (!memcmp (l->keygrip, hexgrip, 40)) + on_card = 1; + err = do_one_keyinfo (ctrl, grip, ctx, opt_data, opt_ssh_fpr, is_ssh, - ttl, disabled, confirm); + ttl, disabled, confirm, on_card); if (err) goto leave; } @@ -1384,11 +1403,17 @@ cmd_keyinfo (assuan_context_t ctx, char *line) goto leave; } + on_card = 0; + for (l = keyinfo_on_cards; l; l = l->next) + if (!memcmp (l->keygrip, line, 40)) + on_card = 1; + err = do_one_keyinfo (ctrl, grip, ctx, opt_data, opt_ssh_fpr, is_ssh, - ttl, disabled, confirm); + ttl, disabled, confirm, on_card); } leave: + agent_card_free_keyinfo (keyinfo_on_cards); ssh_close_control_file (cf); if (dir) closedir (dir); From f2ac6742d403a5a95d84ac7cdcf8913c39297bcb Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 3 Jun 2019 16:31:58 +0200 Subject: [PATCH 104/169] Return better error code for some getinfo IPC commands. * agent/command.c (cmd_getinfo): Return GPG_ERR_FALSE as boolean False. * g13/server.c (cmd_getinfo): Ditto. * sm/server.c (cmd_getinfo): Ditto. -- GPG_ERR_FALSE was introduced with libgpg-error 1.21 and we now require a later version for gnupg 2. Thus we can switch to this more descriptive code. Signed-off-by: Werner Koch --- agent/command.c | 6 +++--- g13/server.c | 2 +- sm/server.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/agent/command.c b/agent/command.c index 460aa1dec..3c2da183c 100644 --- a/agent/command.c +++ b/agent/command.c @@ -3110,7 +3110,7 @@ cmd_getinfo (assuan_context_t ctx, char *line) { cmdopt = line; if (!command_has_option (cmd, cmdopt)) - rc = gpg_error (GPG_ERR_GENERAL); + rc = gpg_error (GPG_ERR_FALSE); } } } @@ -3124,7 +3124,7 @@ cmd_getinfo (assuan_context_t ctx, char *line) } else if (!strcmp (line, "restricted")) { - rc = ctrl->restricted? 0 : gpg_error (GPG_ERR_GENERAL); + rc = ctrl->restricted? 0 : gpg_error (GPG_ERR_FALSE); } else if (ctrl->restricted) { @@ -3158,7 +3158,7 @@ cmd_getinfo (assuan_context_t ctx, char *line) } else if (!strcmp (line, "scd_running")) { - rc = agent_scd_check_running ()? 0 : gpg_error (GPG_ERR_GENERAL); + rc = agent_scd_check_running ()? 0 : gpg_error (GPG_ERR_FALSE); } else if (!strcmp (line, "std_env_names")) { diff --git a/g13/server.c b/g13/server.c index defde6c02..780295214 100644 --- a/g13/server.c +++ b/g13/server.c @@ -530,7 +530,7 @@ cmd_getinfo (assuan_context_t ctx, char *line) { cmdopt = line; if (!command_has_option (cmd, cmdopt)) - err = gpg_error (GPG_ERR_GENERAL); + err = gpg_error (GPG_ERR_FALSE); } } } diff --git a/sm/server.c b/sm/server.c index 98505e26d..77ec07fc0 100644 --- a/sm/server.c +++ b/sm/server.c @@ -1162,14 +1162,14 @@ cmd_getinfo (assuan_context_t ctx, char *line) { cmdopt = line; if (!command_has_option (cmd, cmdopt)) - rc = gpg_error (GPG_ERR_GENERAL); + rc = gpg_error (GPG_ERR_FALSE); } } } } else if (!strcmp (line, "offline")) { - rc = ctrl->offline? 0 : gpg_error (GPG_ERR_GENERAL); + rc = ctrl->offline? 0 : gpg_error (GPG_ERR_FALSE); } else rc = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT"); From eaf3b89d11156cc055644fc50761e1692e791e84 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Mon, 3 Jun 2019 11:57:08 +0900 Subject: [PATCH 105/169] doc: Add a section for gpg-check-pattern. * doc/Makefile.am: Add gpg-check-pattern.1. * doc/tools.texi (GPG-CHECK-PATTERN): New. -- GnuPG-bug-id: 4031 Signed-off-by: NIIBE Yutaka --- doc/Makefile.am | 2 +- doc/tools.texi | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/doc/Makefile.am b/doc/Makefile.am index 0720dd366..cef9ff29f 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -95,7 +95,7 @@ myman_pages = gpgsm.1 gpg-agent.1 dirmngr.8 scdaemon.1 \ watchgnupg.1 gpgconf.1 addgnupghome.8 gpg-preset-passphrase.1 \ gpg-connect-agent.1 gpgparsemail.1 symcryptrun.1 gpgtar.1 \ applygnupgdefaults.8 gpg-wks-client.1 gpg-wks-server.1 \ - dirmngr-client.1 gpg-card.1 + dirmngr-client.1 gpg-card.1 gpg-check-pattern.1 if USE_GPG2_HACK myman_pages += gpg2.1 gpgv2.1 else diff --git a/doc/tools.texi b/doc/tools.texi index 7dcd84e2f..460030038 100644 --- a/doc/tools.texi +++ b/doc/tools.texi @@ -21,6 +21,7 @@ GnuPG comes with a couple of smaller tools: * gpgparsemail:: Parse a mail message into an annotated format * symcryptrun:: Call a simple symmetric encryption tool. * gpgtar:: Encrypt or sign files into an archive. +* gpg-check-pattern:: Check a passphrase on stdin against the patternfile. @end menu @c @@ -2110,3 +2111,50 @@ gpgtar --list-archive test1 @command{tar}(1), @end ifset @include see-also-note.texi + +@c +@c GPG-CHECK-PATTERN +@c +@manpage gpg-check-pattern.1 +@node gpg-check-pattern +@section Check a passphrase on stdin against the patternfile +@ifset manverb +.B gpg-check-pattern +\- Check a passphrase on stdin against the patternfile +@end ifset + +@mansect synopsis +@ifset manverb +.B gpg\-check\-pattern +.RI [ options ] +.I patternfile +@end ifset + +@mansect description +@command{gpg-check-pattern} checks a passphrase given on stdin against +a specified pattern file. + +@mansect options +@noindent + +@table @gnupgtabopt + +@item --verbose +@opindex verbose +Enable extra informational output. + +@item --check +@opindex check +Run only a syntax check on the patternfile. + +@item --null +@opindex null +Input is expected to be null delimited. + +@end table + +@mansect see also +@ifset isman +@command{gpg}(1), +@end ifset +@include see-also-note.texi From 20acc7c0226550530085a674ef1bb41ebfa39408 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Tue, 4 Jun 2019 09:17:21 +0900 Subject: [PATCH 106/169] g10,agent: Support CONFIRM for --delete-key. * agent/call-pinentry.c (agent_get_confirmation): Add call of pinentry_loopback_confirm. (agent_popup_message_start): Likewise. (agent_popup_message_stop): Return if it's loopback mode. * agent/command.c (pinentry_loopback_confirm): New. * g10/call-agent.c (default_inq_cb): Support "CONFIRM" inquery when PINENTRY_MODE_LOOPBACK mode. (confirm_status_cb): New. (agent_delete_key): Supply confirm_status_cb to set the description string for confirmation. -- In the Assuan communication, we introduce new interaction: [gpg] [gpg-agent] --- CMD: PKDECRYPT --> <-- STATUS: SETDESC "..." <-- STATUS: SETOK "..." <-- STATUS: SETNOTOK "..." <-- INQUERY: CONFIRM 0/1 (0 for display, 1 for user query) --- INQUERY-result: --> <-- RESULT: ... GnuPG-bug-id: 3465 Signed-off-by: NIIBE Yutaka --- agent/call-pinentry.c | 16 ++++++++++- agent/command.c | 23 +++++++++++++++ g10/call-agent.c | 66 +++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 102 insertions(+), 3 deletions(-) diff --git a/agent/call-pinentry.c b/agent/call-pinentry.c index 487b21e81..c2105cd6e 100644 --- a/agent/call-pinentry.c +++ b/agent/call-pinentry.c @@ -1391,6 +1391,9 @@ agent_get_confirmation (ctrl_t ctrl, if (ctrl->pinentry_mode == PINENTRY_MODE_CANCEL) return gpg_error (GPG_ERR_CANCELED); + if (ctrl->pinentry_mode == PINENTRY_MODE_LOOPBACK) + return pinentry_loopback_confirm (ctrl, desc, 1, ok, notok); + return gpg_error (GPG_ERR_NO_PIN_ENTRY); } @@ -1486,7 +1489,15 @@ agent_popup_message_start (ctrl_t ctrl, const char *desc, const char *ok_btn) int err; if (ctrl->pinentry_mode != PINENTRY_MODE_ASK) - return gpg_error (GPG_ERR_CANCELED); + { + if (ctrl->pinentry_mode == PINENTRY_MODE_CANCEL) + return gpg_error (GPG_ERR_CANCELED); + + if (ctrl->pinentry_mode == PINENTRY_MODE_LOOPBACK) + return pinentry_loopback_confirm (ctrl, desc, 0, ok_btn, NULL); + + return gpg_error (GPG_ERR_NO_PIN_ENTRY); + } rc = start_pinentry (ctrl); if (rc) @@ -1537,6 +1548,9 @@ agent_popup_message_stop (ctrl_t ctrl) (void)ctrl; + if (ctrl->pinentry_mode == PINENTRY_MODE_LOOPBACK) + return; + if (!popup_tid || !entry_ctx) { log_debug ("agent_popup_message_stop called with no active popup\n"); diff --git a/agent/command.c b/agent/command.c index 3c2da183c..b59532ce5 100644 --- a/agent/command.c +++ b/agent/command.c @@ -3680,3 +3680,26 @@ pinentry_loopback(ctrl_t ctrl, const char *keyword, assuan_end_confidential (ctx); return rc; } + +/* Helper for the pinentry loopback mode to ask confirmation + or just to show message. */ +gpg_error_t +pinentry_loopback_confirm (ctrl_t ctrl, const char *desc, + int ask_confirmation, + const char *ok, const char *notok) +{ + gpg_error_t err = 0; + assuan_context_t ctx = ctrl->server_local->assuan_ctx; + + if (desc) + err = print_assuan_status (ctx, "SETDESC", "%s", desc); + if (!err && ok) + err = print_assuan_status (ctx, "SETOK", "%s", ok); + if (!err && notok) + err = print_assuan_status (ctx, "SETNOTOK", "%s", notok); + + if (!err) + err = assuan_inquire (ctx, ask_confirmation ? "CONFIRM 1" : "CONFIRM 0", + NULL, NULL, 0); + return err; +} diff --git a/g10/call-agent.c b/g10/call-agent.c index f6c7d3951..19deb73d7 100644 --- a/g10/call-agent.c +++ b/g10/call-agent.c @@ -41,6 +41,7 @@ #include "../common/status.h" #include "../common/shareddefs.h" #include "../common/host2net.h" +#include "../common/ttyio.h" #define CONTROL_D ('D' - 'A' + 1) @@ -48,6 +49,13 @@ static assuan_context_t agent_ctx = NULL; static int did_early_card_test; +struct confirm_parm_s +{ + char *desc; + char *ok; + char *notok; +}; + struct default_inq_parm_s { ctrl_t ctrl; @@ -57,6 +65,7 @@ struct default_inq_parm_s u32 *mainkeyid; int pubkey_algo; } keyinfo; + struct confirm_parm_s *confirm; }; struct cipher_parm_s @@ -136,6 +145,7 @@ default_inq_cb (void *opaque, const char *line) { gpg_error_t err = 0; struct default_inq_parm_s *parm = opaque; + const char *s; if (has_leading_keyword (line, "PINENTRY_LAUNCHED")) { @@ -151,7 +161,7 @@ default_inq_cb (void *opaque, const char *line) { if (have_static_passphrase ()) { - const char *s = get_static_passphrase (); + s = get_static_passphrase (); err = assuan_send_data (parm->ctx, s, strlen (s)); } else @@ -176,6 +186,27 @@ default_inq_cb (void *opaque, const char *line) xfree (pw); } } + else if ((s = has_leading_keyword (line, "CONFIRM")) + && opt.pinentry_mode == PINENTRY_MODE_LOOPBACK + && parm->confirm) + { + int ask = atoi (s); + int yes; + + if (ask) + { + yes = cpr_get_answer_is_yes (NULL, parm->confirm->desc); + if (yes) + err = assuan_send_data (parm->ctx, NULL, 0); + else + err = gpg_error (GPG_ERR_NOT_CONFIRMED); + } + else + { + tty_printf ("%s", parm->confirm->desc); + err = assuan_send_data (parm->ctx, NULL, 0); + } + } else log_debug ("ignoring gpg-agent inquiry '%s'\n", line); @@ -2512,6 +2543,31 @@ agent_export_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc, } +/* Status callback for handling confirmation. */ +static gpg_error_t +confirm_status_cb (void *opaque, const char *line) +{ + struct confirm_parm_s *parm = opaque; + const char *s; + + if ((s = has_leading_keyword (line, "SETDESC"))) + { + xfree (parm->desc); + parm->desc = unescape_status_string (s); + } + else if ((s = has_leading_keyword (line, "SETOK"))) + { + xfree (parm->ok); + parm->ok = unescape_status_string (s); + } + else if ((s = has_leading_keyword (line, "SETNOTOK"))) + { + xfree (parm->notok); + parm->notok = unescape_status_string (s); + } + + return 0; +} /* Ask the agent to delete the key identified by HEXKEYGRIP. If DESC is not NULL, display DESC instead of the default description @@ -2524,9 +2580,12 @@ agent_delete_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc, gpg_error_t err; char line[ASSUAN_LINELENGTH]; struct default_inq_parm_s dfltparm; + struct confirm_parm_s confirm_parm; + memset (&confirm_parm, 0, sizeof confirm_parm); memset (&dfltparm, 0, sizeof dfltparm); dfltparm.ctrl = ctrl; + dfltparm.confirm = &confirm_parm; err = start_agent (ctrl, 0); if (err) @@ -2548,7 +2607,10 @@ agent_delete_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc, force? " --force":"", hexkeygrip); err = assuan_transact (agent_ctx, line, NULL, NULL, default_inq_cb, &dfltparm, - NULL, NULL); + confirm_status_cb, &confirm_parm); + xfree (confirm_parm.desc); + xfree (confirm_parm.ok); + xfree (confirm_parm.notok); return err; } From 4262933ef6f7530b4ad55646250a6763de9bf103 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Tue, 4 Jun 2019 09:45:31 +0900 Subject: [PATCH 107/169] scd: Remove unsupported --card-timeout option. * doc/scdaemon.texi (card-timeout): Remove. * scd/scdaemon.c (main): Remove oCardTimeout handling. -- There was the card-timeout option in GnuPG 2.0, but it was never implemented correctly. The intention of this option was to allow sharing smartcard among multiple applications, but this didn't work well as user's expectation (it only worked with DISCONNECT command). This is because other parts of scdaemon assumes exclusive access. In GnuPG 2.1, the support of the option was removed, improving "DISCONNECT" command always works well without this option. GnuPG-bug-id: 3383 Signed-off-by: NIIBE Yutaka --- doc/scdaemon.texi | 14 -------------- scd/scdaemon.c | 5 ----- 2 files changed, 19 deletions(-) diff --git a/doc/scdaemon.texi b/doc/scdaemon.texi index 0c984162c..575553f35 100644 --- a/doc/scdaemon.texi +++ b/doc/scdaemon.texi @@ -286,20 +286,6 @@ To get a list of available CCID readers you may use this command: @end smallexample @end cartouche -@item --card-timeout @var{n} -@opindex card-timeout -If @var{n} is not 0 and no client is actively using the card, the card -will be powered down after @var{n} seconds. Powering down the card -avoids a potential risk of damaging a card when used with certain -cheap readers. This also allows applications that are not aware of -Scdaemon to access the card. The disadvantage of using a card timeout -is that accessing the card takes longer and that the user needs to -enter the PIN again after the next power up. - -Note that with the current version of Scdaemon the card is powered -down immediately at the next timer tick for any value of @var{n} other -than 0. - @item --enable-pinpad-varlen @opindex enable-pinpad-varlen Please specify this option when the card reader supports variable diff --git a/scd/scdaemon.c b/scd/scdaemon.c index 42efb4c37..12eff755b 100644 --- a/scd/scdaemon.c +++ b/scd/scdaemon.c @@ -89,7 +89,6 @@ enum cmd_and_opt_values oDaemon, oBatch, oReaderPort, - oCardTimeout, octapiDriver, opcscDriver, oDisableCCID, @@ -144,8 +143,6 @@ static ARGPARSE_OPTS opts[] = { "@" #endif /* end --disable-ccid */), - ARGPARSE_s_u (oCardTimeout, "card-timeout", - N_("|N|disconnect the card after N seconds of inactivity")), ARGPARSE_s_n (oDisablePinpad, "disable-pinpad", N_("do not use a reader's pinpad")), @@ -614,8 +611,6 @@ main (int argc, char **argv ) break; case oDenyAdmin: opt.allow_admin = 0; break; - case oCardTimeout: opt.card_timeout = pargs.r.ret_ulong; break; - case oDisableApplication: add_to_strlist (&opt.disabled_applications, pargs.r.ret_str); break; From 3a1bb0081087c0604ed681642114934ffe607fa1 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Tue, 4 Jun 2019 09:59:08 +0900 Subject: [PATCH 108/169] agent: Add pinentry_loopback_confirm declaration. * agent/agent.h (pinentry_loopback_confirm): New. Signed-off-by: NIIBE Yutaka --- agent/agent.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/agent/agent.h b/agent/agent.h index ec8370c4b..84e5e782b 100644 --- a/agent/agent.h +++ b/agent/agent.h @@ -398,8 +398,11 @@ void bump_key_eventcounter (void); void bump_card_eventcounter (void); void start_command_handler (ctrl_t, gnupg_fd_t, gnupg_fd_t); gpg_error_t pinentry_loopback (ctrl_t, const char *keyword, - unsigned char **buffer, size_t *size, - size_t max_length); + unsigned char **buffer, size_t *size, + size_t max_length); +gpg_error_t pinentry_loopback_confirm (ctrl_t ctrl, const char *desc, + int ask_confirmation, + const char *ok, const char *notok); #ifdef HAVE_W32_SYSTEM int serve_mmapped_ssh_request (ctrl_t ctrl, From 0076bef2026a87c4c0e05bad7d322638b1de3f37 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Tue, 4 Jun 2019 11:35:06 +0900 Subject: [PATCH 109/169] agent: Allow TERM="". * agent/call-pinentry.c (start_pinentry): When TERM is none, don't send OPTION ttytype to pinentry. -- GnuPG-bug-id: 4137 Signed-off-by: NIIBE Yutaka --- agent/call-pinentry.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/agent/call-pinentry.c b/agent/call-pinentry.c index c2105cd6e..02ec1c8c8 100644 --- a/agent/call-pinentry.c +++ b/agent/call-pinentry.c @@ -438,7 +438,7 @@ start_pinentry (ctrl_t ctrl) return unlock_pinentry (ctrl, rc); } value = session_env_getenv (ctrl->session_env, "TERM"); - if (value) + if (value && *value) { char *optstr; if (asprintf (&optstr, "OPTION ttytype=%s", value) < 0 ) From 537fbe13af6a70e105982c4b69c1bcc3908ffb08 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Tue, 4 Jun 2019 13:39:46 +0900 Subject: [PATCH 110/169] g10: Block signals in g10_exit. * g10/gpg.c (g10_exit): Block all signals before calling emergency_cleanup. -- There is a race condition here which results crash of the process. When a signal is delivered in emergency_cleanup, it is called again. This change fixes the problem. GnuPG-bug-id: 2747 Signed-off-by: NIIBE Yutaka --- g10/gpg.c | 1 + 1 file changed, 1 insertion(+) diff --git a/g10/gpg.c b/g10/gpg.c index b46d22690..1819c3fe8 100644 --- a/g10/gpg.c +++ b/g10/gpg.c @@ -5231,6 +5231,7 @@ g10_exit( int rc ) if (opt.debug) gcry_control (GCRYCTL_DUMP_SECMEM_STATS ); + gnupg_block_all_signals (); emergency_cleanup (); rc = rc? rc : log_get_errorcount(0)? 2 : g10_errors_seen? 1 : 0; From 9bf650db022b6b65bbfa74c311cdc3e6b73d3b44 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 4 Jun 2019 09:23:27 +0200 Subject: [PATCH 111/169] sm: Print a better diagnostic for encryption certificate selection. * sm/certlist.c (gpgsm_add_to_certlist): Add diagnostic and fold two similar branches. -- Without this patch gpgsm printed: gpgsm[23045]: DBG: chan_6 <- RECIPIENT edward.tester@demo.gnupg.com gpgsm[23045]: certificate is not usable for encryption gpgsm[23045]: certificate is good with this patch a gpgsm[23045]: looking for another certificate is inserted into the log. Signed-off-by: Werner Koch --- sm/certlist.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/sm/certlist.c b/sm/certlist.c index 0847c169b..b3d113bfd 100644 --- a/sm/certlist.c +++ b/sm/certlist.c @@ -352,19 +352,14 @@ gpgsm_add_to_certlist (ctrl_t ctrl, const char *name, int secret, { /* There might be another certificate with the correct usage, so we try again */ - if (!wrong_usage) - { /* save the first match */ - wrong_usage = rc; - ksba_cert_release (cert); - cert = NULL; - goto get_next; - } - else if (same_subject_issuer (first_subject, first_issuer, - cert)) + if (!wrong_usage + || same_subject_issuer (first_subject, first_issuer,cert)) { - wrong_usage = rc; + if (!wrong_usage) + wrong_usage = rc; /* save error of the first match */ ksba_cert_release (cert); cert = NULL; + log_info (_("looking for another certificate\n")); goto get_next; } else From c13e459ffeffb8c5387c44b3c04bb92b7111a75b Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Thu, 6 Jun 2019 09:32:58 +0900 Subject: [PATCH 112/169] gpgparsemail: Die on parse error (not abort). * tools/gpgparsemail.c (parse_message): Don't use ERRNO. * tools/rfc822parse.c (transition_to_body): Return -1. (transition_to_header, insert_header): Likewise. -- GnuPG-bug-id: 1977 Signed-off-by: NIIBE Yutaka --- tools/gpgparsemail.c | 2 +- tools/rfc822parse.c | 16 +++++++++++----- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/tools/gpgparsemail.c b/tools/gpgparsemail.c index b12209755..c5f4e6cd0 100644 --- a/tools/gpgparsemail.c +++ b/tools/gpgparsemail.c @@ -654,7 +654,7 @@ parse_message (FILE *fp) if (rfc822parse_insert (msg, line, length)) - die ("parser failed: %s", strerror (errno)); + die ("parser failed"); if (info.hashing) { diff --git a/tools/rfc822parse.c b/tools/rfc822parse.c index f1e95bd34..0280796fe 100644 --- a/tools/rfc822parse.c +++ b/tools/rfc822parse.c @@ -420,7 +420,9 @@ transition_to_body (rfc822parse_t msg) s = rfc822parse_query_parameter (ctx, "boundary", 0); if (s) { - assert (!msg->current_part->boundary); + if (msg->current_part->boundary) + return -1; + msg->current_part->boundary = malloc (strlen (s) + 1); if (msg->current_part->boundary) { @@ -437,7 +439,8 @@ transition_to_body (rfc822parse_t msg) return -1; } rc = do_callback (msg, RFC822PARSE_LEVEL_DOWN); - assert (!msg->current_part->down); + if (msg->current_part->down) + return -1; msg->current_part->down = part; msg->current_part = part; msg->in_preamble = 1; @@ -458,8 +461,9 @@ transition_to_header (rfc822parse_t msg) { part_t part; - assert (msg->current_part); - assert (!msg->current_part->right); + if (!(msg->current_part + && !msg->current_part->right)) + return -1; part = new_part (); if (!part) @@ -476,7 +480,9 @@ insert_header (rfc822parse_t msg, const unsigned char *line, size_t length) { HDR_LINE hdr; - assert (msg->current_part); + if (!msg->current_part) + return -1; + if (!length) { msg->in_body = 1; From 72fe8d652fce6cb9104bb07ef0fb811cbab3303a Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Thu, 6 Jun 2019 09:55:10 +0900 Subject: [PATCH 113/169] scd: Bring back --card-timeout option as deprecated. * doc/scdaemon.texi (card-timeout): Add. * scd/scdaemon.c (main): Revert the change. -- GnuPG-bug-id: 3383 Fixes-commit: 4262933ef6f7530b4ad55646250a6763de9bf103 Signed-off-by: NIIBE Yutaka --- doc/scdaemon.texi | 6 ++++++ scd/scdaemon.c | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/doc/scdaemon.texi b/doc/scdaemon.texi index 575553f35..21c3fd826 100644 --- a/doc/scdaemon.texi +++ b/doc/scdaemon.texi @@ -286,6 +286,12 @@ To get a list of available CCID readers you may use this command: @end smallexample @end cartouche +@item --card-timeout @var{n} +@opindex card-timeout +This option is deprecated. In GnuPG 2.0, it used to be used for +DISCONNECT command to control timing issue. Since DISCONNECT command +works synchronously, it has no effect. + @item --enable-pinpad-varlen @opindex enable-pinpad-varlen Please specify this option when the card reader supports variable diff --git a/scd/scdaemon.c b/scd/scdaemon.c index 12eff755b..42efb4c37 100644 --- a/scd/scdaemon.c +++ b/scd/scdaemon.c @@ -89,6 +89,7 @@ enum cmd_and_opt_values oDaemon, oBatch, oReaderPort, + oCardTimeout, octapiDriver, opcscDriver, oDisableCCID, @@ -143,6 +144,8 @@ static ARGPARSE_OPTS opts[] = { "@" #endif /* end --disable-ccid */), + ARGPARSE_s_u (oCardTimeout, "card-timeout", + N_("|N|disconnect the card after N seconds of inactivity")), ARGPARSE_s_n (oDisablePinpad, "disable-pinpad", N_("do not use a reader's pinpad")), @@ -611,6 +614,8 @@ main (int argc, char **argv ) break; case oDenyAdmin: opt.allow_admin = 0; break; + case oCardTimeout: opt.card_timeout = pargs.r.ret_ulong; break; + case oDisableApplication: add_to_strlist (&opt.disabled_applications, pargs.r.ret_str); break; From 1e9d61fb95e4813225a40f720231196abdb83992 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Fri, 7 Jun 2019 13:28:07 +0900 Subject: [PATCH 114/169] gpgparsemail: Die on parse error, printing errno thing. * tools/gpgparsemail.c (parse_message): Revert the change. * tools/rfc822parse.c (transition_to_body): Set ERRNO. (transition_to_header, insert_header): Likewise. -- In the comment of rfc822parse_* functions, it explicitly explained setting ERRNO on error. For parser errors, it may not have appropriate ERRNO, in such a case, use ENOENT. Fixes-commit: c13e459ffeffb8c5387c44b3c04bb92b7111a75b Signed-off-by: NIIBE Yutaka --- tools/gpgparsemail.c | 2 +- tools/rfc822parse.c | 20 ++++++++++++++++---- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/tools/gpgparsemail.c b/tools/gpgparsemail.c index c5f4e6cd0..b12209755 100644 --- a/tools/gpgparsemail.c +++ b/tools/gpgparsemail.c @@ -654,7 +654,7 @@ parse_message (FILE *fp) if (rfc822parse_insert (msg, line, length)) - die ("parser failed"); + die ("parser failed: %s", strerror (errno)); if (info.hashing) { diff --git a/tools/rfc822parse.c b/tools/rfc822parse.c index 0280796fe..ac6ecb17c 100644 --- a/tools/rfc822parse.c +++ b/tools/rfc822parse.c @@ -421,7 +421,10 @@ transition_to_body (rfc822parse_t msg) if (s) { if (msg->current_part->boundary) - return -1; + { + errno = ENOENT; + return -1; + } msg->current_part->boundary = malloc (strlen (s) + 1); if (msg->current_part->boundary) @@ -440,7 +443,10 @@ transition_to_body (rfc822parse_t msg) } rc = do_callback (msg, RFC822PARSE_LEVEL_DOWN); if (msg->current_part->down) - return -1; + { + errno = ENOENT; + return -1; + } msg->current_part->down = part; msg->current_part = part; msg->in_preamble = 1; @@ -463,7 +469,10 @@ transition_to_header (rfc822parse_t msg) if (!(msg->current_part && !msg->current_part->right)) - return -1; + { + errno = ENOENT; + return -1; + } part = new_part (); if (!part) @@ -481,7 +490,10 @@ insert_header (rfc822parse_t msg, const unsigned char *line, size_t length) HDR_LINE hdr; if (!msg->current_part) - return -1; + { + errno = ENOENT; + return -1; + } if (!length) { From 6562de7475b21cd03c7b1a83a591fa563c589f5b Mon Sep 17 00:00:00 2001 From: Daniel Kahn Gillmor Date: Sun, 9 Jun 2019 17:33:09 -0400 Subject: [PATCH 115/169] doc/gpgsm: explain what "policy-file" refers to. A new user who sees "policy-file" and searches naively through the documentation to find it again won't be able to tell what this refers to, since "policies.txt" doesn't otherwise match the search string "policy". This gives them a fighting chance at finding the documentation. Signed-off-by: Daniel Kahn Gillmor --- doc/gpgsm.texi | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/gpgsm.texi b/doc/gpgsm.texi index 1736ff111..a8eb93c4a 100644 --- a/doc/gpgsm.texi +++ b/doc/gpgsm.texi @@ -349,7 +349,8 @@ verbose commands to @command{gpgsm}, such as @samp{-vv}. @item --policy-file @var{filename} @opindex policy-file -Change the default name of the policy file to @var{filename}. +Change the default name of the policy file to @var{filename}. The +default name is @{policies.txt}. @item --agent-program @var{file} @opindex agent-program From 6e46862abd2c2e82f245e381c3f08c5829fb61e6 Mon Sep 17 00:00:00 2001 From: Daniel Kahn Gillmor Date: Fri, 14 Jun 2019 16:49:27 +0100 Subject: [PATCH 116/169] fix up 6562de7475b21cd03c7b1a83a591fa563c589f5b Signed-off-by: Daniel Kahn Gillmor --- doc/gpgsm.texi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/gpgsm.texi b/doc/gpgsm.texi index a8eb93c4a..75ccdc3ba 100644 --- a/doc/gpgsm.texi +++ b/doc/gpgsm.texi @@ -350,7 +350,7 @@ verbose commands to @command{gpgsm}, such as @samp{-vv}. @item --policy-file @var{filename} @opindex policy-file Change the default name of the policy file to @var{filename}. The -default name is @{policies.txt}. +default name is @file{policies.txt}. @item --agent-program @var{file} @opindex agent-program From 6260f413182ce1e0fbdae363f2e55f825811d39f Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 17 Jun 2019 09:26:36 +0200 Subject: [PATCH 117/169] note: previous commit 6e46862 fixes another minor doc issue fix. -- Please use useful subjects so that there is no need to lookup what a fix is. A commit fix should be indicated with the keyword "Fixes-commit: xxxxx" From 479c2775d5df64432c1bf64faae7f9abd3042850 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 17 Jun 2019 13:56:13 +0200 Subject: [PATCH 118/169] scd: Use the correct gpg for the v1.0 OpenPGP card hack. * scd/app-openpgp.c (get_public_key): Use gnupg_module_name instead of just "gpg". -- There is no bug report regarding this and it would be very unlikely but we should always use the gpg belonging to our code. Signed-off-by: Werner Koch --- scd/app-openpgp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index aa21529c6..f174e2e2a 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -1731,7 +1731,8 @@ get_public_key (app_t app, int keyno) hexkeyid = fpr + 24; ret = gpgrt_asprintf - (&command, "gpg --list-keys --with-colons --with-key-data '%s'", fpr); + (&command, "%s --list-keys --with-colons --with-key-data '%s'", + gnupg_module_name (GNUPG_MODULE_NAME_GPG), fpr); if (ret < 0) { err = gpg_error_from_syserror (); From 70f7b262877b1e751d8557dc04a09a420e9d8a8f Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 17 Jun 2019 14:35:21 +0200 Subject: [PATCH 119/169] scd: Slight change to app->fnc.do_with_keygrip. * scd/app-openpgp.c (do_with_keygrip): Return a real error code to avoid misinterpretation of the result. Also fix the case for a too small buffer. -- The only real chnage is the case for a too small buffer. That should in general never happen but if so we now return an error instead of success. Signed-off-by: Werner Koch --- scd/app-common.h | 7 +++++-- scd/app-openpgp.c | 18 ++++++++++-------- scd/app.c | 24 +++++++++++++++++++++--- 3 files changed, 36 insertions(+), 13 deletions(-) diff --git a/scd/app-common.h b/scd/app-common.h index 8a25cda55..cf51d26fe 100644 --- a/scd/app-common.h +++ b/scd/app-common.h @@ -126,11 +126,13 @@ struct app_ctx_s { gpg_error_t (*check_pin) (app_t app, const char *keyidstr, gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg); - int (*with_keygrip) (app_t app, ctrl_t ctrl, int action, - const char *keygrip_str); + gpg_error_t (*with_keygrip) (app_t app, ctrl_t ctrl, int action, + const char *keygrip_str); } fnc; }; + +/* Action values for app_do_with_keygrip. */ enum { KEYGRIP_ACTION_SEND_DATA, @@ -138,6 +140,7 @@ enum KEYGRIP_ACTION_LOOKUP }; + /*-- app-help.c --*/ unsigned int app_help_count_bits (const unsigned char *a, size_t len); gpg_error_t app_help_get_keygrip_string_pk (const void *pk, size_t pklen, diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index f174e2e2a..5e67a7b53 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -4913,7 +4913,7 @@ do_check_pin (app_t app, const char *keyidstr, return verify_chv2 (app, pincb, pincb_arg); } -static int +static gpg_error_t do_with_keygrip (app_t app, ctrl_t ctrl, int action, const char *keygrip_str) { int i; @@ -4925,14 +4925,12 @@ do_with_keygrip (app_t app, ctrl_t ctrl, int action, const char *keygrip_str) if (action == KEYGRIP_ACTION_LOOKUP) { if (keygrip_str == NULL) - return 1; + return gpg_error (GPG_ERR_NOT_FOUND); for (i = 0; i < 3; i++) if (app->app_local->pk[i].read_done && !strcmp (keygrip_str, app->app_local->pk[i].keygrip_str)) - return 0; /* Found */ - - return 1; + return 0; /* Found */ } else { @@ -4941,7 +4939,7 @@ do_with_keygrip (app_t app, ctrl_t ctrl, int action, const char *keygrip_str) int data = (action == KEYGRIP_ACTION_SEND_DATA); if (DIM (buf) < 2 * app->serialnolen + 1) - return 0; + return gpg_error (GPG_ERR_BUFFER_TOO_SHORT); bin2hex (app->serialno, app->serialnolen, buf); @@ -4954,6 +4952,10 @@ do_with_keygrip (app_t app, ctrl_t ctrl, int action, const char *keygrip_str) send_keyinfo (ctrl, data, app->app_local->pk[i].keygrip_str,buf, idbuf); } + /* Return an error so that the dispatcher keeps on looping + * over the other applications. Only for clarity we use a + * different error code than for the not_found case. */ + return gpg_error (GPG_ERR_TRUE); } else { @@ -4966,9 +4968,9 @@ do_with_keygrip (app_t app, ctrl_t ctrl, int action, const char *keygrip_str) return 0; } } - - return 1; } + + return gpg_error (GPG_ERR_NOT_FOUND); } /* Show information about card capabilities. */ diff --git a/scd/app.c b/scd/app.c index 4fe60cbbb..9640c8015 100644 --- a/scd/app.c +++ b/scd/app.c @@ -1292,9 +1292,27 @@ app_send_card_list (ctrl_t ctrl) } /* Execute an action for each app. ACTION can be one of: - KEYGRIP_ACTION_SEND_DATA: send data if KEYGRIP_STR matches - KEYGRIP_ACTION_WRITE_STATUS: write status if KEYGRIP_STR matches - KEYGRIP_ACTION_LOOKUP: Return matching APP + * + * - KEYGRIP_ACTION_SEND_DATA + * + * If KEYGRIP_STR matches a public key of any active application + * send information as LF terminated data lines about the public + * key. The format of these lines is + * T + * If a match was found a pointer to the matching application is + * returned. With the KEYGRIP_STR given as NULL, lines for all + * keys will be send and the return value is NULL. + * + * - KEYGRIP_ACTION_WRITE_STATUS + * + * Same as KEYGRIP_ACTION_SEND_DATA but uses status lines instead + * of data lines. + * + * - KEYGRIP_ACTION_LOOKUP + * + * Returns a pointer to the application matching KEYGRIP_STR but + * does not emit any status or data lines. If no key with that + * keygrip is available or KEYGRIP_STR is NULL, NULL is returned. */ app_t app_do_with_keygrip (ctrl_t ctrl, int action, const char *keygrip_str) From c594dcfc93486cd26e193aa5c82bb8a8f30ab57b Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 17 Jun 2019 16:19:22 +0200 Subject: [PATCH 120/169] scd: Add explict functions for 'app' reference counting. * scd/app.c (app_ref): New. (app_unref): New. (release_application): Renamed to ... (app_unref_locked): this and remove arg locked_already. Change callers to use this or app_ref. * scd/command.c (open_card_with_request): (cmd_pksign, cmd_pkauth, cmd_pkdecrypt): Use app_ref and app_unref instead of accessing the counter directly. -- This is better in case we need to debug stuff. There is a real change however: We now lock and unlock the app before changing the reference count. The whole app locking business should be reviewed because we pass pointers along without immediately bumping the refcount. Signed-off-by: Werner Koch --- scd/app-common.h | 6 +++++- scd/app.c | 48 ++++++++++++++++++++++++++++++++++++------------ scd/command.c | 21 +++++++++++---------- scd/scdaemon.h | 3 +++ 4 files changed, 55 insertions(+), 23 deletions(-) diff --git a/scd/app-common.h b/scd/app-common.h index cf51d26fe..8dc43285e 100644 --- a/scd/app-common.h +++ b/scd/app-common.h @@ -164,7 +164,11 @@ gpg_error_t select_application (ctrl_t ctrl, const char *name, app_t *r_app, int scan, const unsigned char *serialno_bin, size_t serialno_bin_len); char *get_supported_applications (void); -void release_application (app_t app, int locked_already); + +app_t app_ref (app_t app); +void app_unref (app_t app); +void app_unref_locked (app_t app); + gpg_error_t app_munge_serialno (app_t app); gpg_error_t app_write_learn_status (app_t app, ctrl_t ctrl, unsigned int flags); diff --git a/scd/app.c b/scd/app.c index 9640c8015..9055c9e8e 100644 --- a/scd/app.c +++ b/scd/app.c @@ -242,7 +242,7 @@ app_reset (app_t app, ctrl_t ctrl, int send_reset) else { ctrl->app_ctx = NULL; - release_application (app, 0); + app_unref (app); } return err; @@ -541,6 +541,7 @@ select_application (ctrl_t ctrl, const char *name, app_t *r_app, err = check_conflict (a, name); if (!err) { + /* Note: We do not use app_ref as we are already locked. */ a->ref_count++; *r_app = a; if (a_prev) @@ -604,7 +605,8 @@ deallocate_app (app_t app) a_prev = a; if (app->ref_count) - log_error ("trying to release context used yet (%d)\n", app->ref_count); + log_error ("trying to release still used app context (%d)\n", + app->ref_count); if (app->fnc.deinit) { @@ -618,13 +620,24 @@ deallocate_app (app_t app) xfree (app); } -/* Free the resources associated with the application APP. APP is - allowed to be NULL in which case this is a no-op. Note that we are - using reference counting to track the users of the application and - actually deferring the deallocation to allow for a later reuse by - a new connection. */ + +/* Increment the reference counter for APP. Returns the APP. */ +app_t +app_ref (app_t app) +{ + lock_app (app, NULL); + ++app->ref_count; + unlock_app (app); + return app; +} + + +/* Decrement the reference counter for APP. Note that we are using + * reference counting to track the users of the application and are + * deferring the actual deallocation to allow for a later reuse by a + * new connection. Using NULL for APP is a no-op. */ void -release_application (app_t app, int locked_already) +app_unref (app_t app) { if (!app) return; @@ -634,15 +647,26 @@ release_application (app_t app, int locked_already) is using the card - this way the PIN cache and other cached data are preserved. */ - if (!locked_already) - lock_app (app, NULL); + lock_app (app, NULL); + if (!app->ref_count) + log_bug ("trying to release an already released context\n"); + --app->ref_count; + unlock_app (app); +} + + +/* This is the same as app_unref but assumes that APP is already + * locked. */ +void +app_unref_locked (app_t app) +{ + if (!app) + return; if (!app->ref_count) log_bug ("trying to release an already released context\n"); --app->ref_count; - if (!locked_already) - unlock_app (app); } diff --git a/scd/command.c b/scd/command.c index 9173a6843..426615c8b 100644 --- a/scd/command.c +++ b/scd/command.c @@ -234,7 +234,7 @@ open_card_with_request (ctrl_t ctrl, const char *apptype, const char *serialno) /* Re-scan USB devices. Release APP, before the scan. */ ctrl->app_ctx = NULL; - release_application (app, 0); + app_unref (app); if (serialno) serialno_bin = hex_to_buffer (serialno, &serialno_bin_len); @@ -804,14 +804,14 @@ cmd_pksign (assuan_context_t ctx, char *line) if (app) { if (direct) - app->ref_count++; + app_ref (app); rc = app_sign (app, ctrl, keyidstr, hash_algo, pin_cb, ctx, ctrl->in_data.value, ctrl->in_data.valuelen, &outdata, &outdatalen); if (direct) - app->ref_count--; + app_unref (app); } else rc = gpg_error (GPG_ERR_NO_SECKEY); @@ -872,12 +872,12 @@ cmd_pkauth (assuan_context_t ctx, char *line) if (app) { if (direct) - app->ref_count++; + app_ref (app); rc = app_auth (app, ctrl, keyidstr, pin_cb, ctx, ctrl->in_data.value, ctrl->in_data.valuelen, &outdata, &outdatalen); if (direct) - app->ref_count--; + app_unref (app); } else rc = gpg_error (GPG_ERR_NO_SECKEY); @@ -933,12 +933,12 @@ cmd_pkdecrypt (assuan_context_t ctx, char *line) if (app) { if (direct) - app->ref_count++; + app_ref (app); rc = app_decipher (ctrl->app_ctx, ctrl, keyidstr, pin_cb, ctx, ctrl->in_data.value, ctrl->in_data.valuelen, &outdata, &outdatalen, &infoflags); if (direct) - app->ref_count--; + app_unref (app); } else rc = gpg_error (GPG_ERR_NO_SECKEY); @@ -1648,7 +1648,7 @@ cmd_restart (assuan_context_t ctx, char *line) if (app) { ctrl->app_ctx = NULL; - release_application (app, 0); + app_unref (app); } if (locked_session && ctrl->server_local == locked_session) { @@ -2169,7 +2169,8 @@ popup_prompt (void *opaque, int on) } -/* Helper to send the clients a status change notification. */ +/* Helper to send the clients a status change notification. Note that + * this fucntion assumes that APP is already locked. */ void send_client_notifications (app_t app, int removal) { @@ -2199,7 +2200,7 @@ send_client_notifications (app_t app, int removal) { sl->ctrl_backlink->app_ctx = NULL; sl->card_removed = 1; - release_application (app, 1); + app_unref_locked (app); } if (!sl->event_signal || !sl->assuan_ctx) diff --git a/scd/scdaemon.h b/scd/scdaemon.h index 230653b11..7eb08a904 100644 --- a/scd/scdaemon.h +++ b/scd/scdaemon.h @@ -129,7 +129,10 @@ void send_keyinfo (ctrl_t ctrl, int data, const char *keygrip_str, const char *serialno, const char *idstr); void popup_prompt (void *opaque, int on); + +/* Take care: this function assumes that APP is locked. */ void send_client_notifications (app_t app, int removal); + void scd_kick_the_loop (void); int get_active_connection_count (void); From e900bf29737b3f7a09f749a271f2c5d7b59c49eb Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 17 Jun 2019 18:04:36 +0200 Subject: [PATCH 121/169] scd:piv: Add the do_with_keygrip feature. * scd/app-piv.c (do_with_keygrip): New. (app_select_piv): Register function. Signed-off-by: Werner Koch --- scd/app-piv.c | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++ scd/command.c | 6 ++++ 2 files changed, 95 insertions(+) diff --git a/scd/app-piv.c b/scd/app-piv.c index f13ef52ee..2ee72e0fc 100644 --- a/scd/app-piv.c +++ b/scd/app-piv.c @@ -3300,6 +3300,94 @@ do_writecert (app_t app, ctrl_t ctrl, } +/* Process the various keygrip based info requests. */ +static gpg_error_t +do_with_keygrip (app_t app, ctrl_t ctrl, int action, + const char *want_keygripstr) +{ + gpg_error_t err; + char *keygripstr = NULL; + char *serialno = NULL; + char idbuf[20]; + int data = 0; + int i, tag, dummy_got_cert; + + /* First a quick check for valid parameters. */ + switch (action) + { + case KEYGRIP_ACTION_LOOKUP: + if (!want_keygripstr) + { + err = gpg_error (GPG_ERR_NOT_FOUND); + goto leave; + } + break; + case KEYGRIP_ACTION_SEND_DATA: + data = 1; + break; + case KEYGRIP_ACTION_WRITE_STATUS: + break; + default: + err = gpg_error (GPG_ERR_INV_ARG); + goto leave; + } + + /* Allocate the s/n string if needed. */ + if (action != KEYGRIP_ACTION_LOOKUP) + { + serialno = app_get_serialno (app); + if (!serialno) + { + err = gpg_error_from_syserror (); + goto leave; + } + } + + for (i = 0; (tag = data_objects[i].tag); i++) + { + if (!data_objects[i].keypair) + continue; + + xfree (keygripstr); + if (get_keygrip_by_tag (app, tag, &keygripstr, &dummy_got_cert)) + continue; + + if (action == KEYGRIP_ACTION_LOOKUP) + { + if (!strcmp (keygripstr, want_keygripstr)) + { + err = 0; /* Found */ + goto leave; + } + } + else if (!want_keygripstr || !strcmp (keygripstr, want_keygripstr)) + { + snprintf (idbuf, sizeof idbuf, "PIV.%s", data_objects[i].keyref); + send_keyinfo (ctrl, data, keygripstr, serialno, idbuf); + if (want_keygripstr) + { + err = 0; /* Found */ + goto leave; + } + } + } + + /* Return an error so that the dispatcher keeps on looping over the + * other applications. For clarity we use a different error code + * when listing all keys. Note that in lookup mode WANT_KEYGRIPSTR + * is not NULL. */ + if (!want_keygripstr) + err = gpg_error (GPG_ERR_TRUE); + else + err = gpg_error (GPG_ERR_NOT_FOUND); + + leave: + xfree (keygripstr); + xfree (serialno); + return err; +} + + /* Select the PIV application on the card in SLOT. This function must * be used before any other PIV application functions. */ gpg_error_t @@ -3398,6 +3486,7 @@ app_select_piv (app_t app) app->fnc.decipher = do_decipher; app->fnc.change_pin = do_change_chv; app->fnc.check_pin = do_check_chv; + app->fnc.with_keygrip = do_with_keygrip; leave: diff --git a/scd/command.c b/scd/command.c index 426615c8b..4f4005458 100644 --- a/scd/command.c +++ b/scd/command.c @@ -1874,6 +1874,10 @@ cmd_keyinfo (assuan_context_t ctx, char *line) return 0; } + +/* Send a keyinfo string as used by the KEYGRIP_ACTION_SEND_DATA. If + * DATA is true the string is emitted as a data line, else as a status + * line. */ void send_keyinfo (ctrl_t ctrl, int data, const char *keygrip_str, const char *serialno, const char *idstr) @@ -1895,6 +1899,8 @@ send_keyinfo (ctrl_t ctrl, int data, const char *keygrip_str, xfree (string); return; } + + /* Tell the assuan library about our commands */ static int From c3dd53a65dc9ea2c4814e24079f0270c2fef14c6 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Tue, 18 Jun 2019 10:13:40 +0900 Subject: [PATCH 122/169] scd: KEYINFO: Send LF for --data. * scd/command.c (send_keyinfo): Send LF for --data. -- Fixes-commit: 01730529f20882cd98882a61408e9bee960c86f1 Signed-off-by: NIIBE Yutaka --- scd/command.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/scd/command.c b/scd/command.c index 4f4005458..1929c33f1 100644 --- a/scd/command.c +++ b/scd/command.c @@ -1885,9 +1885,11 @@ send_keyinfo (ctrl_t ctrl, int data, const char *keygrip_str, char *string; assuan_context_t ctx = ctrl->server_local->assuan_ctx; - string = xtryasprintf ("%s T %s %s", keygrip_str, + string = xtryasprintf ("%s T %s %s%s", keygrip_str, serialno? serialno : "-", - idstr? idstr : "-"); + idstr? idstr : "-", + data? "\n" : ""); + if (!string) return; From 5a5288d051a551a1a8f169225e62572f6ee8cb10 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 19 Jun 2019 08:50:40 +0200 Subject: [PATCH 123/169] scd: Split data structures into app and card related objects. * scd/app-common.h (struct card_ctx_s): New. (struct app_ctx_s): Factor card specific fields out to card_ctx_s. (app_get_slot): New. * scd/scdaemon.h (card_t): New. (struct server_control_s): Rename field app_ctx to card_ctx and change all users. * scd/app-dinsig.c: Use app_get_slot and adjust for chang in card related fields. * scd/app-geldkarte.c: Ditto. * scd/app-nks.c: Ditto. * scd/app-openpgp.c: Ditto. * scd/app-p15.c: Ditto. * scd/app-sc-hsm.c: Ditto. * scd/app.c: Lost of changes to adjust for the changed data structures. Change all callers. (app_list_lock): Rename to card_list_lock. (app_top): Remove. (card_top): New. (lock_app): Rename to lock_card and change arg type. (unlock_app): Rename to unlock_card. (app_dump_state): Print card and app info. (app_reset): Rename to card_reset. (app_new_register): Change for the new data structure. (deallocate_card): Dealloc card and all apps. (app_ref): Rename to card_ref. (app_unref): Rename to card_unref. (app_unref_locked): Rename to card_unref_locked. (card_get_serialno): New. * scd/command.c (cmd_pkdecrypt): Actually use the looked up card and former app object and not the standard one from the context. -- Although quite large, this is a straightforward change to separate card/token related data from card application related data. Before this change there was a one-to-one relation between card and application and no way to represent several applications on a card. The new data structure will allow for such a representation. Signed-off-by: Werner Koch --- scd/app-common.h | 120 +++++--- scd/app-dinsig.c | 25 +- scd/app-geldkarte.c | 14 +- scd/app-nks.c | 61 ++-- scd/app-openpgp.c | 103 ++++--- scd/app-p15.c | 80 ++--- scd/app-piv.c | 65 ++-- scd/app-sc-hsm.c | 44 +-- scd/app.c | 703 ++++++++++++++++++++++++-------------------- scd/command.c | 168 +++++------ scd/scdaemon.h | 8 +- 11 files changed, 774 insertions(+), 617 deletions(-) diff --git a/scd/app-common.h b/scd/app-common.h index 8dc43285e..cdb941283 100644 --- a/scd/app-common.h +++ b/scd/app-common.h @@ -46,29 +46,53 @@ struct app_local_s; /* Defined by all app-*.c. */ -struct app_ctx_s { - struct app_ctx_s *next; + +/* The object describing a card. */ +struct card_ctx_s { + struct card_ctx_s *next; npth_mutex_t lock; - /* Number of connections currently using this application context. - If this is not 0 the application has been initialized and the - function pointers may be used. Note that for unsupported - operations the particular function pointer is set to NULL */ + /* Number of connections currently using this application context. */ unsigned int ref_count; /* Used reader slot. */ int slot; + const char *cardtype; /* NULL or string with the token's type. */ + unsigned int cardversion;/* Firmware version of the token or 0. */ + + unsigned int card_status; + + /* The serial number is associated with the card and not with a + * specific app. If a card uses different serial numbers for its + * applications, our code picks the serial number of a specific + * application and uses that. */ unsigned char *serialno; /* Serialnumber in raw form, allocated. */ size_t serialnolen; /* Length in octets of serialnumber. */ - const char *cardtype; /* NULL or string with the token's type. */ - const char *apptype; - unsigned int cardversion;/* Firmware version of the token or 0. */ - unsigned int appversion; /* Version of the application or 0. */ - unsigned int card_status; + + /* A linked list of applications used on this card. The app at the + * head of the list is the currently active app; To work with the + * other apps, switching to that app might be needed. Switching will + * put the active app at the head of the list. */ + app_t app; + + /* Various flags. */ unsigned int reset_requested:1; unsigned int periodical_check_needed:1; +}; + + +/* The object describing a card's applications. A card may have + * several applications and it is usuallay required to explicity + * switch between applications. */ +struct app_ctx_s { + struct app_ctx_s *next; + + card_t card; /* Link back to the card. */ + + const char *apptype; + unsigned int appversion; /* Version of the application or 0. */ unsigned int did_chv1:1; unsigned int force_chv1:1; /* True if the card does not cache CHV1. */ unsigned int did_chv2:1; @@ -141,6 +165,16 @@ enum }; +/* Helper to get the slot from an APP object. */ +static inline int +app_get_slot (app_t app) +{ + if (app && app->card) + return app->card->slot; + return -1; +} + + /*-- app-help.c --*/ unsigned int app_help_count_bits (const unsigned char *a, size_t len); gpg_error_t app_help_get_keygrip_string_pk (const void *pk, size_t pklen, @@ -154,75 +188,77 @@ size_t app_help_read_length_of_cert (int slot, int fid, size_t *r_certoff); /*-- app.c --*/ void app_update_priority_list (const char *arg); void app_send_card_list (ctrl_t ctrl); +char *card_get_serialno (card_t card); char *app_get_serialno (app_t app); void app_dump_state (void); void application_notify_card_reset (int slot); -gpg_error_t check_application_conflict (const char *name, app_t app); -gpg_error_t app_reset (app_t app, ctrl_t ctrl, int send_reset); -gpg_error_t select_application (ctrl_t ctrl, const char *name, app_t *r_app, +gpg_error_t check_application_conflict (const char *name, card_t card); +gpg_error_t card_reset (card_t card, ctrl_t ctrl, int send_reset); +gpg_error_t select_application (ctrl_t ctrl, const char *name, card_t *r_app, int scan, const unsigned char *serialno_bin, size_t serialno_bin_len); char *get_supported_applications (void); -app_t app_ref (app_t app); -void app_unref (app_t app); -void app_unref_locked (app_t app); +card_t card_ref (card_t card); +void card_unref (card_t card); +void card_unref_locked (card_t card); -gpg_error_t app_munge_serialno (app_t app); -gpg_error_t app_write_learn_status (app_t app, ctrl_t ctrl, +gpg_error_t app_munge_serialno (card_t card); +gpg_error_t app_write_learn_status (card_t card, ctrl_t ctrl, unsigned int flags); -gpg_error_t app_readcert (app_t app, ctrl_t ctrl, const char *certid, +gpg_error_t app_readcert (card_t card, ctrl_t ctrl, const char *certid, unsigned char **cert, size_t *certlen); -gpg_error_t app_readkey (app_t app, ctrl_t ctrl, +gpg_error_t app_readkey (card_t card, ctrl_t ctrl, const char *keyid, unsigned int flags, unsigned char **pk, size_t *pklen); -gpg_error_t app_getattr (app_t app, ctrl_t ctrl, const char *name); -gpg_error_t app_setattr (app_t app, ctrl_t ctrl, const char *name, - gpg_error_t (*pincb)(void*, const char *, char **), - void *pincb_arg, - const unsigned char *value, size_t valuelen); -gpg_error_t app_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo, - gpg_error_t (*pincb)(void*, const char *, char **), - void *pincb_arg, - const void *indata, size_t indatalen, - unsigned char **outdata, size_t *outdatalen ); -gpg_error_t app_auth (app_t app, ctrl_t ctrl, const char *keyidstr, +gpg_error_t app_getattr (card_t card, ctrl_t ctrl, const char *name); +gpg_error_t app_setattr (card_t card, ctrl_t ctrl, const char *name, + gpg_error_t (*pincb)(void*, const char *, char **), + void *pincb_arg, + const unsigned char *value, size_t valuelen); +gpg_error_t app_sign (card_t card, ctrl_t ctrl, + const char *keyidstr, int hashalgo, gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg, const void *indata, size_t indatalen, unsigned char **outdata, size_t *outdatalen); -gpg_error_t app_decipher (app_t app, ctrl_t ctrl, const char *keyidstr, +gpg_error_t app_auth (card_t card, ctrl_t ctrl, const char *keyidstr, + gpg_error_t (*pincb)(void*, const char *, char **), + void *pincb_arg, + const void *indata, size_t indatalen, + unsigned char **outdata, size_t *outdatalen); +gpg_error_t app_decipher (card_t card, ctrl_t ctrl, const char *keyidstr, gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg, const void *indata, size_t indatalen, unsigned char **outdata, size_t *outdatalen, unsigned int *r_info); -gpg_error_t app_writecert (app_t app, ctrl_t ctrl, +gpg_error_t app_writecert (card_t card, ctrl_t ctrl, const char *certidstr, gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg, const unsigned char *keydata, size_t keydatalen); -gpg_error_t app_writekey (app_t app, ctrl_t ctrl, +gpg_error_t app_writekey (card_t card, ctrl_t ctrl, const char *keyidstr, unsigned int flags, gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg, const unsigned char *keydata, size_t keydatalen); -gpg_error_t app_genkey (app_t app, ctrl_t ctrl, +gpg_error_t app_genkey (card_t card, ctrl_t ctrl, const char *keynostr, const char *keytype, unsigned int flags, time_t createtime, gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg); -gpg_error_t app_get_challenge (app_t app, ctrl_t ctrl, size_t nbytes, +gpg_error_t app_get_challenge (card_t card, ctrl_t ctrl, size_t nbytes, unsigned char *buffer); -gpg_error_t app_change_pin (app_t app, ctrl_t ctrl, +gpg_error_t app_change_pin (card_t card, ctrl_t ctrl, const char *chvnostr, unsigned int flags, gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg); -gpg_error_t app_check_pin (app_t app, ctrl_t ctrl, const char *keyidstr, - gpg_error_t (*pincb)(void*, const char *, char **), - void *pincb_arg); -app_t app_do_with_keygrip (ctrl_t ctrl, int action, const char *keygrip_str); +gpg_error_t app_check_pin (card_t card, ctrl_t ctrl, const char *keyidstr, + gpg_error_t (*pincb)(void*, const char *, char **), + void *pincb_arg); +card_t app_do_with_keygrip (ctrl_t ctrl, int action, const char *keygrip_str); /*-- app-openpgp.c --*/ diff --git a/scd/app-dinsig.c b/scd/app-dinsig.c index 983bed6e1..74de30cc5 100644 --- a/scd/app-dinsig.c +++ b/scd/app-dinsig.c @@ -101,7 +101,7 @@ do_learn_status (app_t app, ctrl_t ctrl, unsigned int flags) /* Return the certificate of the card holder. */ fid = 0xC000; - len = app_help_read_length_of_cert (app->slot, fid, &certoff); + len = app_help_read_length_of_cert (app_get_slot (app), fid, &certoff); if (!len) return 0; /* Card has not been personalized. */ @@ -114,7 +114,8 @@ do_learn_status (app_t app, ctrl_t ctrl, unsigned int flags) /* Now we need to read the certificate, so that we can get the public key out of it. */ - err = iso7816_read_binary (app->slot, certoff, len-certoff, &der, &derlen); + err = iso7816_read_binary (app_get_slot (app), certoff, len-certoff, + &der, &derlen); if (err) { log_info ("error reading entire certificate from FID 0x%04X: %s\n", @@ -193,14 +194,14 @@ do_readcert (app_t app, const char *certid, /* Read the entire file. fixme: This could be optimized by first reading the header to figure out how long the certificate actually is. */ - err = iso7816_select_file (app->slot, fid, 0); + err = iso7816_select_file (app_get_slot (app), fid, 0); if (err) { log_error ("error selecting FID 0x%04X: %s\n", fid, gpg_strerror (err)); return err; } - err = iso7816_read_binary (app->slot, 0, 0, &buffer, &buflen); + err = iso7816_read_binary (app_get_slot (app), 0, 0, &buffer, &buflen); if (err) { log_error ("error reading certificate from FID 0x%04X: %s\n", @@ -293,7 +294,7 @@ verify_pin (app_t app, pininfo.maxlen = 8; if (!opt.disable_pinpad - && !iso7816_check_pinpad (app->slot, ISO7816_VERIFY, &pininfo) ) + && !iso7816_check_pinpad (app_get_slot (app), ISO7816_VERIFY, &pininfo) ) { rc = pincb (pincb_arg, _("||Please enter your PIN at the reader's pinpad"), @@ -304,7 +305,7 @@ verify_pin (app_t app, gpg_strerror (rc)); return rc; } - rc = iso7816_verify_kp (app->slot, 0x81, &pininfo); + rc = iso7816_verify_kp (app_get_slot (app), 0x81, &pininfo); /* Dismiss the prompt. */ pincb (pincb_arg, NULL, NULL); } @@ -345,7 +346,8 @@ verify_pin (app_t app, return gpg_error (GPG_ERR_BAD_PIN); } - rc = iso7816_verify (app->slot, 0x81, pinvalue, strlen (pinvalue)); + rc = iso7816_verify (app_get_slot (app), 0x81, + pinvalue, strlen (pinvalue)); if (gpg_err_code (rc) == GPG_ERR_INV_VALUE) { /* We assume that ISO 9564-1 encoding is used and we failed @@ -366,7 +368,8 @@ verify_pin (app_t app, paddedpin[i++] = (((*s - '0') << 4) | 0x0f); while (i < sizeof paddedpin) paddedpin[i++] = 0xff; - rc = iso7816_verify (app->slot, 0x81, paddedpin, sizeof paddedpin); + rc = iso7816_verify (app_get_slot (app), 0x81, + paddedpin, sizeof paddedpin); } xfree (pinvalue); } @@ -482,7 +485,7 @@ do_sign (app_t app, const char *keyidstr, int hashalgo, rc = verify_pin (app, pincb, pincb_arg); if (!rc) - rc = iso7816_compute_ds (app->slot, 0, data, datalen, 0, + rc = iso7816_compute_ds (app_get_slot (app), 0, data, datalen, 0, outdata, outdatalen); return rc; } @@ -532,7 +535,7 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr, return err; } - err = iso7816_change_reference_data (app->slot, 0x81, + err = iso7816_change_reference_data (app_get_slot (app), 0x81, oldpin, oldpinlen, pinvalue, strlen (pinvalue)); xfree (pinvalue); @@ -547,7 +550,7 @@ gpg_error_t app_select_dinsig (app_t app) { static char const aid[] = { 0xD2, 0x76, 0x00, 0x00, 0x66, 0x01 }; - int slot = app->slot; + int slot = app_get_slot (app); int rc; rc = iso7816_select_application (slot, aid, sizeof aid, 0); diff --git a/scd/app-geldkarte.c b/scd/app-geldkarte.c index 85bcedc4f..e126f2adb 100644 --- a/scd/app-geldkarte.c +++ b/scd/app-geldkarte.c @@ -277,7 +277,7 @@ app_select_geldkarte (app_t app) static char const aid[] = { 0xD2, 0x76, 0x00, 0x00, 0x25, 0x45, 0x50, 0x02, 0x00 }; gpg_error_t err; - int slot = app->slot; + int slot = app_get_slot (app); unsigned char *result = NULL; size_t resultlen; struct app_local_s *ld; @@ -316,17 +316,17 @@ app_select_geldkarte (app_t app) app->fnc.deinit = do_deinit; /* If we don't have a serialno yet construct it from the EF_ID. */ - if (!app->serialno) + if (!app->card->serialno) { - app->serialno = xtrymalloc (10); - if (!app->serialno) + app->card->serialno = xtrymalloc (10); + if (!app->card->serialno) { err = gpg_error_from_syserror (); goto leave; } - memcpy (app->serialno, result, 10); - app->serialnolen = 10; - err = app_munge_serialno (app); + memcpy (app->card->serialno, result, 10); + app->card->serialnolen = 10; + err = app_munge_serialno (app->card); if (err) goto leave; } diff --git a/scd/app-nks.c b/scd/app-nks.c index 2785ad014..bc54c016e 100644 --- a/scd/app-nks.c +++ b/scd/app-nks.c @@ -151,13 +151,15 @@ keygripstr_from_pk_file (app_t app, int fid, char *r_gripstr) int i; int offset[2] = { 0, 0 }; - err = iso7816_select_file (app->slot, fid, 0); + err = iso7816_select_file (app_get_slot (app), fid, 0); if (err) return err; - err = iso7816_read_record (app->slot, 1, 1, 0, &buffer[0], &buflen[0]); + err = iso7816_read_record (app_get_slot (app), 1, 1, 0, + &buffer[0], &buflen[0]); if (err) return err; - err = iso7816_read_record (app->slot, 2, 1, 0, &buffer[1], &buflen[1]); + err = iso7816_read_record (app_get_slot (app), 2, 1, 0, + &buffer[1], &buflen[1]); if (err) { xfree (buffer[0]); @@ -272,7 +274,7 @@ get_chv_status (app_t app, int sigg, int pwid) command[2] = 0x00; command[3] = pwid; - if (apdu_send_direct (app->slot, 0, (unsigned char *)command, + if (apdu_send_direct (app_get_slot (app), 0, (unsigned char *)command, 4, 0, NULL, &result, &resultlen)) rc = -1; /* Error. */ else if (resultlen < 2) @@ -406,7 +408,7 @@ do_learn_status_core (app_t app, ctrl_t ctrl, unsigned int flags, int is_sigg) { size_t len; - len = app_help_read_length_of_cert (app->slot, + len = app_help_read_length_of_cert (app_get_slot (app), filelist[i].fid, NULL); if (len) { @@ -528,14 +530,14 @@ do_readcert (app_t app, const char *certid, /* Read the entire file. fixme: This could be optimized by first reading the header to figure out how long the certificate actually is. */ - err = iso7816_select_file (app->slot, fid, 0); + err = iso7816_select_file (app_get_slot (app), fid, 0); if (err) { log_error ("error selecting FID 0x%04X: %s\n", fid, gpg_strerror (err)); return err; } - err = iso7816_read_binary (app->slot, 0, 0, &buffer, &buflen); + err = iso7816_read_binary (app_get_slot (app), 0, 0, &buffer, &buflen); if (err) { log_error ("error reading certificate from FID 0x%04X: %s\n", @@ -633,13 +635,14 @@ do_readkey (app_t app, ctrl_t ctrl, const char *keyid, unsigned int flags, return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); /* Access the KEYD file which is always in the master directory. */ - err = iso7816_select_path (app->slot, path, DIM (path)); + err = iso7816_select_path (app_get_slot (app), path, DIM (path)); if (err) return err; /* Due to the above select we need to re-select our application. */ app->app_local->need_app_select = 1; /* Get the two records. */ - err = iso7816_read_record (app->slot, 5, 1, 0, &buffer[0], &buflen[0]); + err = iso7816_read_record (app_get_slot (app), 5, 1, 0, + &buffer[0], &buflen[0]); if (err) return err; if (all_zero_p (buffer[0], buflen[0])) @@ -647,7 +650,8 @@ do_readkey (app_t app, ctrl_t ctrl, const char *keyid, unsigned int flags, xfree (buffer[0]); return gpg_error (GPG_ERR_NOT_FOUND); } - err = iso7816_read_record (app->slot, 6, 1, 0, &buffer[1], &buflen[1]); + err = iso7816_read_record (app_get_slot (app), 6, 1, 0, + &buffer[1], &buflen[1]); if (err) { xfree (buffer[0]); @@ -760,7 +764,7 @@ do_writekey (app_t app, ctrl_t ctrl, /* mse[10] = 0x82; /\* RSA public exponent of up to 4 bytes. *\/ */ /* mse[12] = rsa_e_len; */ /* memcpy (mse+12, rsa_e, rsa_e_len); */ -/* err = iso7816_manage_security_env (app->slot, 0x81, 0xB6, */ +/* err = iso7816_manage_security_env (app_get_slot (app), 0x81, 0xB6, */ /* mse, sizeof mse); */ leave: @@ -803,7 +807,7 @@ verify_pin (app_t app, int pwid, const char *desc, pininfo.maxlen = 16; if (!opt.disable_pinpad - && !iso7816_check_pinpad (app->slot, ISO7816_VERIFY, &pininfo) ) + && !iso7816_check_pinpad (app_get_slot (app), ISO7816_VERIFY, &pininfo) ) { rc = pincb (pincb_arg, desc, NULL); if (rc) @@ -813,7 +817,7 @@ verify_pin (app_t app, int pwid, const char *desc, return rc; } - rc = iso7816_verify_kp (app->slot, pwid, &pininfo); + rc = iso7816_verify_kp (app_get_slot (app), pwid, &pininfo); pincb (pincb_arg, NULL, NULL); /* Dismiss the prompt. */ } else @@ -834,7 +838,8 @@ verify_pin (app_t app, int pwid, const char *desc, return rc; } - rc = iso7816_verify (app->slot, pwid, pinvalue, strlen (pinvalue)); + rc = iso7816_verify (app_get_slot (app), pwid, + pinvalue, strlen (pinvalue)); xfree (pinvalue); } @@ -972,7 +977,7 @@ do_sign (app_t app, const char *keyidstr, int hashalgo, mse[3] = 0x84; /* Private key reference. */ mse[4] = 1; mse[5] = kid; - rc = iso7816_manage_security_env (app->slot, 0x41, 0xB6, + rc = iso7816_manage_security_env (app_get_slot (app), 0x41, 0xB6, mse, sizeof mse); } /* Verify using PW1.CH. */ @@ -980,7 +985,7 @@ do_sign (app_t app, const char *keyidstr, int hashalgo, rc = verify_pin (app, 0, NULL, pincb, pincb_arg); /* Compute the signature. */ if (!rc) - rc = iso7816_compute_ds (app->slot, 0, data, datalen, 0, + rc = iso7816_compute_ds (app_get_slot (app), 0, data, datalen, 0, outdata, outdatalen); return rc; } @@ -1047,7 +1052,7 @@ do_decipher (app_t app, const char *keyidstr, mse[3] = 0x84; /* Private key reference. */ mse[4] = 1; mse[5] = kid; - rc = iso7816_manage_security_env (app->slot, 0x41, 0xB8, + rc = iso7816_manage_security_env (app_get_slot (app), 0x41, 0xB8, mse, sizeof mse); } else @@ -1057,7 +1062,7 @@ do_decipher (app_t app, const char *keyidstr, 0x80, 1, 0x10, /* Select algorithm RSA. */ 0x84, 1, 0x81 /* Select local secret key 1 for decryption. */ }; - rc = iso7816_manage_security_env (app->slot, 0xC1, 0xB8, + rc = iso7816_manage_security_env (app_get_slot (app), 0xC1, 0xB8, mse, sizeof mse); } @@ -1068,7 +1073,8 @@ do_decipher (app_t app, const char *keyidstr, /* Note that we need to use extended length APDUs for TCOS 3 cards. Command chaining does not work. */ if (!rc) - rc = iso7816_decipher (app->slot, app->app_local->nks_version > 2? 1:0, + rc = iso7816_decipher (app_get_slot (app), + app->app_local->nks_version > 2? 1:0, indata, indatalen, 0, 0x81, outdata, outdatalen); return rc; @@ -1260,13 +1266,13 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *pwidstr, } memcpy (data, oldpin, oldpinlen); memcpy (data+oldpinlen, newpin, newpinlen); - err = iso7816_reset_retry_counter_with_rc (app->slot, pwid, + err = iso7816_reset_retry_counter_with_rc (app_get_slot (app), pwid, data, datalen); wipememory (data, datalen); xfree (data); } else - err = iso7816_change_reference_data (app->slot, pwid, + err = iso7816_change_reference_data (app_get_slot (app), pwid, oldpin, oldpinlen, newpin, newpinlen); leave: @@ -1347,9 +1353,11 @@ switch_application (app_t app, int enable_sigg) log_info ("app-nks: switching to %s\n", enable_sigg? "SigG":"NKS"); if (enable_sigg) - err = iso7816_select_application (app->slot, aid_sigg, sizeof aid_sigg, 0); + err = iso7816_select_application (app_get_slot (app), + aid_sigg, sizeof aid_sigg, 0); else - err = iso7816_select_application (app->slot, aid_nks, sizeof aid_nks, 0); + err = iso7816_select_application (app_get_slot (app), + aid_nks, sizeof aid_nks, 0); if (!err && enable_sigg && app->app_local->nks_version >= 3 && !app->app_local->sigg_msig_checked) @@ -1362,9 +1370,10 @@ switch_application (app_t app, int enable_sigg) app->app_local->sigg_msig_checked = 1; app->app_local->sigg_is_msig = 1; - err = iso7816_select_file (app->slot, 0x5349, 0); + err = iso7816_select_file (app_get_slot (app), 0x5349, 0); if (!err) - err = iso7816_read_record (app->slot, 1, 1, 0, &buffer, &buflen); + err = iso7816_read_record (app_get_slot (app), 1, 1, 0, + &buffer, &buflen); if (!err) { tmpl = find_tlv (buffer, buflen, 0x7a, &tmpllen); @@ -1396,7 +1405,7 @@ switch_application (app_t app, int enable_sigg) gpg_error_t app_select_nks (app_t app) { - int slot = app->slot; + int slot = app_get_slot (app); int rc; rc = iso7816_select_application (slot, aid_nks, sizeof aid_nks, 0); diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 5e67a7b53..4f17a3c44 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -338,7 +338,7 @@ get_cached_data (app_t app, int tag, else exmode = 0; - err = iso7816_get_data (app->slot, exmode, tag, &p, &len); + err = iso7816_get_data (app_get_slot (app), exmode, tag, &p, &len); if (err) return err; if (len) @@ -469,7 +469,7 @@ get_one_do (app_t app, int tag, unsigned char **result, size_t *nbytes, if (app->appversion > 0x0100 && data_objects[i].get_immediate_in_v11) { exmode = 0; - rc = iso7816_get_data (app->slot, exmode, tag, &buffer, &buflen); + rc = iso7816_get_data (app_get_slot (app), exmode, tag, &buffer, &buflen); if (rc) { *r_rc = rc; @@ -811,7 +811,7 @@ store_fpr (app_t app, int keynumber, u32 timestamp, unsigned char *fpr, tag2 = 0xCE + keynumber; flush_cache_item (app, 0xCD); - rc = iso7816_put_data (app->slot, 0, tag, fpr, 20); + rc = iso7816_put_data (app_get_slot (app), 0, tag, fpr, 20); if (rc) log_error (_("failed to store the fingerprint: %s\n"),gpg_strerror (rc)); @@ -824,7 +824,7 @@ store_fpr (app_t app, int keynumber, u32 timestamp, unsigned char *fpr, buf[2] = timestamp >> 8; buf[3] = timestamp; - rc = iso7816_put_data (app->slot, 0, tag2, buf, 4); + rc = iso7816_put_data (app_get_slot (app), 0, tag2, buf, 4); if (rc) log_error (_("failed to store the creation date: %s\n"), gpg_strerror (rc)); @@ -1691,7 +1691,7 @@ get_public_key (app_t app, int keyno) le_value = 256; /* Use legacy value. */ } - err = iso7816_read_public_key (app->slot, exmode, + err = iso7816_read_public_key (app_get_slot (app), exmode, (keyno == 0? "\xB6" : keyno == 1? "\xB8" : "\xA4"), 2, le_value, &buffer, &buflen); @@ -2161,7 +2161,7 @@ verify_a_chv (app_t app, /* Special case for def_chv2 mechanism. */ if (opt.verbose) log_info (_("using default PIN as %s\n"), "CHV2"); - rc = iso7816_verify (app->slot, 0x82, "123456", 6); + rc = iso7816_verify (app_get_slot (app), 0x82, "123456", 6); if (rc) { /* Verification of CHV2 with the default PIN failed, @@ -2194,7 +2194,7 @@ verify_a_chv (app_t app, } if (!opt.disable_pinpad - && !iso7816_check_pinpad (app->slot, ISO7816_VERIFY, &pininfo) + && !iso7816_check_pinpad (app_get_slot (app), ISO7816_VERIFY, &pininfo) && !check_pinpad_request (app, &pininfo, 0)) { /* The reader supports the verify command through the pinpad. @@ -2210,7 +2210,7 @@ verify_a_chv (app_t app, gpg_strerror (rc)); return rc; } - rc = iso7816_verify_kp (app->slot, 0x80+chvno, &pininfo); + rc = iso7816_verify_kp (app_get_slot (app), 0x80+chvno, &pininfo); /* Dismiss the prompt. */ pincb (pincb_arg, NULL, NULL); @@ -2241,7 +2241,8 @@ verify_a_chv (app_t app, rc = pin2hash_if_kdf (app, chvno, *pinvalue, pinlen); if (!rc) - rc = iso7816_verify (app->slot, 0x80+chvno, *pinvalue, *pinlen); + rc = iso7816_verify (app_get_slot (app), + 0x80 + chvno, *pinvalue, *pinlen); } if (rc) @@ -2281,7 +2282,7 @@ verify_chv2 (app_t app, the card is not configured to require a verification before each CHV1 controlled operation (force_chv1) and if we are not using the pinpad (PINVALUE == NULL). */ - rc = iso7816_verify (app->slot, 0x81, pinvalue, pinlen); + rc = iso7816_verify (app_get_slot (app), 0x81, pinvalue, pinlen); if (gpg_err_code (rc) == GPG_ERR_BAD_PIN) rc = gpg_error (GPG_ERR_PIN_NOT_SYNCED); if (rc) @@ -2369,7 +2370,8 @@ verify_chv3 (app_t app, return rc; if (!opt.disable_pinpad - && !iso7816_check_pinpad (app->slot, ISO7816_VERIFY, &pininfo) + && !iso7816_check_pinpad (app_get_slot (app), + ISO7816_VERIFY, &pininfo) && !check_pinpad_request (app, &pininfo, 1)) { /* The reader supports the verify command through the pinpad. */ @@ -2382,7 +2384,7 @@ verify_chv3 (app_t app, gpg_strerror (rc)); return rc; } - rc = iso7816_verify_kp (app->slot, 0x83, &pininfo); + rc = iso7816_verify_kp (app_get_slot (app), 0x83, &pininfo); /* Dismiss the prompt. */ pincb (pincb_arg, NULL, NULL); } @@ -2411,7 +2413,7 @@ verify_chv3 (app_t app, rc = pin2hash_if_kdf (app, 3, pinvalue, &pinlen); if (!rc) - rc = iso7816_verify (app->slot, 0x83, pinvalue, pinlen); + rc = iso7816_verify (app_get_slot (app), 0x83, pinvalue, pinlen); xfree (pinvalue); } @@ -2510,7 +2512,8 @@ do_setattr (app_t app, const char *name, exmode = -254; /* Command chaining with max. 254 bytes. */ else exmode = 0; - rc = iso7816_put_data (app->slot, exmode, table[idx].tag, value, valuelen); + rc = iso7816_put_data (app_get_slot (app), + exmode, table[idx].tag, value, valuelen); if (rc) log_error ("failed to set '%s': %s\n", table[idx].name, gpg_strerror (rc)); @@ -2567,7 +2570,7 @@ clear_chv_status (app_t app, int chvno) apdu[2] = 0xff; apdu[3] = 0x80+chvno; - err = iso7816_apdu_direct (app->slot, apdu, 4, 0, NULL, NULL, NULL); + err = iso7816_apdu_direct (app_get_slot (app), apdu, 4, 0, NULL, NULL, NULL); if (err) { if (gpg_err_code (err) == GPG_ERR_INV_VALUE) @@ -2578,7 +2581,8 @@ clear_chv_status (app_t app, int chvno) if (chvno == 1) { apdu[3]++; - err = iso7816_apdu_direct (app->slot, apdu, 4, 0, NULL, NULL, NULL); + err = iso7816_apdu_direct (app_get_slot (app), + apdu, 4, 0, NULL, NULL, NULL); app->did_chv1 = app->did_chv2 = 0; } else if (chvno == 2) @@ -2689,7 +2693,7 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr, /* Version 2 cards. */ if (!opt.disable_pinpad - && !iso7816_check_pinpad (app->slot, + && !iso7816_check_pinpad (app_get_slot (app), ISO7816_CHANGE_REFERENCE_DATA, &pininfo) && !check_pinpad_request (app, &pininfo, chvno == 3)) use_pinpad = 1; @@ -2832,7 +2836,7 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr, rc = pin2hash_if_kdf (app, 0, buffer+pinlen0, &pinlen); } if (!rc) - rc = iso7816_reset_retry_counter_with_rc (app->slot, 0x81, + rc = iso7816_reset_retry_counter_with_rc (app_get_slot (app), 0x81, buffer, pinlen0+pinlen); wipememory (buffer, pinlen0 + pinlen); xfree (buffer); @@ -2849,31 +2853,37 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr, { rc = pin2hash_if_kdf (app, 0, pinvalue, &pinlen); if (!rc) - rc = iso7816_put_data (app->slot, 0, 0xD3, pinvalue, pinlen); + rc = iso7816_put_data (app_get_slot (app), + 0, 0xD3, pinvalue, pinlen); } } else if (reset_mode) { rc = pin2hash_if_kdf (app, 1, pinvalue, &pinlen); if (!rc) - rc = iso7816_reset_retry_counter (app->slot, 0x81, pinvalue, pinlen); + rc = iso7816_reset_retry_counter (app_get_slot (app), + 0x81, pinvalue, pinlen); if (!rc && !app->app_local->extcap.is_v2) - rc = iso7816_reset_retry_counter (app->slot, 0x82, pinvalue, pinlen); + rc = iso7816_reset_retry_counter (app_get_slot (app), + 0x82, pinvalue, pinlen); } else if (!app->app_local->extcap.is_v2) { /* Version 1 cards. */ if (chvno == 1 || chvno == 2) { - rc = iso7816_change_reference_data (app->slot, 0x81, NULL, 0, + rc = iso7816_change_reference_data (app_get_slot (app), + 0x81, NULL, 0, pinvalue, strlen (pinvalue)); if (!rc) - rc = iso7816_change_reference_data (app->slot, 0x82, NULL, 0, + rc = iso7816_change_reference_data (app_get_slot (app), + 0x82, NULL, 0, pinvalue, strlen (pinvalue)); } else /* CHVNO == 3 */ { - rc = iso7816_change_reference_data (app->slot, 0x80 + chvno, NULL, 0, + rc = iso7816_change_reference_data (app_get_slot (app), + 0x80 + chvno, NULL, 0, pinvalue, strlen (pinvalue)); } } @@ -2894,7 +2904,8 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr, gpg_strerror (rc)); goto leave; } - rc = iso7816_change_reference_data_kp (app->slot, 0x80 + chvno, 0, + rc = iso7816_change_reference_data_kp (app_get_slot (app), + 0x80 + chvno, 0, &pininfo); pincb (pincb_arg, NULL, NULL); /* Dismiss the prompt. */ } @@ -2904,7 +2915,8 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr, if (!rc) rc = pin2hash_if_kdf (app, chvno, pinvalue, &pinlen); if (!rc) - rc = iso7816_change_reference_data (app->slot, 0x80 + chvno, + rc = iso7816_change_reference_data (app_get_slot (app), + 0x80 + chvno, oldpinvalue, pinlen0, pinvalue, pinlen); } @@ -2947,7 +2959,7 @@ does_key_exist (app_t app, int keyidx, int generating, int force) assert (keyidx >=0 && keyidx <= 2); - if (iso7816_get_data (app->slot, 0, 0x006E, &buffer, &buflen)) + if (iso7816_get_data (app_get_slot (app), 0, 0x006E, &buffer, &buflen)) { log_error (_("error reading application data\n")); return gpg_error (GPG_ERR_GENERAL); @@ -3261,7 +3273,7 @@ change_keyattr (app_t app, int keyno, const unsigned char *buf, size_t buflen, return err; /* Change the attribute. */ - err = iso7816_put_data (app->slot, 0, 0xC1+keyno, buf, buflen); + err = iso7816_put_data (app_get_slot (app), 0, 0xC1+keyno, buf, buflen); if (err) log_error ("error changing key attribute (key=%d)\n", keyno+1); else @@ -3653,7 +3665,7 @@ rsa_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **), exmode = -254; else exmode = 0; - err = iso7816_put_data_odd (app->slot, exmode, 0x3fff, + err = iso7816_put_data_odd (app_get_slot (app), exmode, 0x3fff, template, template_len); } else @@ -3703,7 +3715,7 @@ rsa_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **), goto leave; /* Store the key. */ - err = iso7816_put_data (app->slot, 0, + err = iso7816_put_data (app_get_slot (app), 0, (app->appversion > 0x0007? 0xE0:0xE9)+keyno, template, template_len); } @@ -3975,7 +3987,7 @@ ecc_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **), exmode = -254; else exmode = 0; - err = iso7816_put_data_odd (app->slot, exmode, 0x3fff, + err = iso7816_put_data_odd (app_get_slot (app), exmode, 0x3fff, template, template_len); xfree (template); } @@ -4143,7 +4155,7 @@ do_genkey (app_t app, ctrl_t ctrl, const char *keynostr, const char *keytype, log_info (_("please wait while key is being generated ...\n")); start_at = time (NULL); - err = iso7816_generate_keypair (app->slot, exmode, 0x80, 0, + err = iso7816_generate_keypair (app_get_slot (app), exmode, 0x80, 0, (keyno == 0? "\xB6" : keyno == 1? "\xB8" : "\xA4"), 2, le_value, &buffer, &buflen); @@ -4325,9 +4337,9 @@ check_keyidstr (app_t app, const char *keyidstr, int keyno) for (s=keyidstr, n=0; n < 16; s += 2, n++) tmp_sn[n] = xtoi_2 (s); - if (app->serialnolen != 16) + if (app->card->serialnolen != 16) return gpg_error (GPG_ERR_INV_CARD); - if (memcmp (app->serialno, tmp_sn, 16)) + if (memcmp (app->card->serialno, tmp_sn, 16)) return gpg_error (GPG_ERR_WRONG_CARD); } @@ -4485,7 +4497,8 @@ do_sign (app_t app, const char *keyidstr, int hashalgo, char *pinvalue; int pinlen; - rc = verify_a_chv (app, pincb, pincb_arg, 1, sigcount, &pinvalue, &pinlen); + rc = verify_a_chv (app, pincb, pincb_arg, 1, sigcount, + &pinvalue, &pinlen); if (rc) return rc; @@ -4498,7 +4511,7 @@ do_sign (app_t app, const char *keyidstr, int hashalgo, pinpad has been used. */ if (!app->did_chv2 && pinvalue && !app->app_local->extcap.is_v2) { - rc = iso7816_verify (app->slot, 0x82, pinvalue, pinlen); + rc = iso7816_verify (app_get_slot (app), 0x82, pinvalue, pinlen); if (gpg_err_code (rc) == GPG_ERR_BAD_PIN) rc = gpg_error (GPG_ERR_PIN_NOT_SYNCED); if (rc) @@ -4526,7 +4539,7 @@ do_sign (app_t app, const char *keyidstr, int hashalgo, exmode = 0; le_value = 0; } - rc = iso7816_compute_ds (app->slot, exmode, data, datalen, le_value, + rc = iso7816_compute_ds (app_get_slot (app), exmode, data, datalen, le_value, outdata, outdatalen); if (gpg_err_code (rc) == GPG_ERR_TIMEOUT) clear_chv_status (app, 1); @@ -4605,7 +4618,7 @@ do_auth (app_t app, const char *keyidstr, exmode = 0; le_value = 0; } - rc = iso7816_internal_authenticate (app->slot, exmode, + rc = iso7816_internal_authenticate (app_get_slot (app), exmode, indata, indatalen, le_value, outdata, outdatalen); if (gpg_err_code (rc) == GPG_ERR_TIMEOUT) @@ -4800,7 +4813,7 @@ do_decipher (app_t app, const char *keyidstr, else exmode = le_value = 0; - rc = iso7816_decipher (app->slot, exmode, + rc = iso7816_decipher (app_get_slot (app), exmode, indata, indatalen, le_value, padind, outdata, outdatalen); xfree (fixbuf); @@ -4938,10 +4951,10 @@ do_with_keygrip (app_t app, ctrl_t ctrl, int action, const char *keygrip_str) char buf[65]; int data = (action == KEYGRIP_ACTION_SEND_DATA); - if (DIM (buf) < 2 * app->serialnolen + 1) + if (DIM (buf) < 2 * app->card->serialnolen + 1) return gpg_error (GPG_ERR_BUFFER_TOO_SHORT); - bin2hex (app->serialno, app->serialnolen, buf); + bin2hex (app->card->serialno, app->card->serialnolen, buf); if (keygrip_str == NULL) { @@ -5198,7 +5211,7 @@ gpg_error_t app_select_openpgp (app_t app) { static char const aid[] = { 0xD2, 0x76, 0x00, 0x01, 0x24, 0x01 }; - int slot = app->slot; + int slot = app_get_slot (app); int rc; unsigned char *buffer; size_t buflen; @@ -5236,9 +5249,9 @@ app_select_openpgp (app_t app) app->appversion |= buffer[7]; manufacturer = (buffer[8]<<8 | buffer[9]); - xfree (app->serialno); - app->serialno = buffer; - app->serialnolen = buflen; + xfree (app->card->serialno); + app->card->serialno = buffer; + app->card->serialnolen = buflen; buffer = NULL; app->app_local = xtrycalloc (1, sizeof *app->app_local); if (!app->app_local) diff --git a/scd/app-p15.c b/scd/app-p15.c index 190292433..59cc195fb 100644 --- a/scd/app-p15.c +++ b/scd/app-p15.c @@ -443,7 +443,7 @@ select_ef_by_path (app_t app, const unsigned short *path, size_t pathlen) if (app->app_local->direct_path_selection) { - err = iso7816_select_path (app->slot, path+1, pathlen-1); + err = iso7816_select_path (app_get_slot (app), path+1, pathlen-1); if (err) { log_error ("error selecting path "); @@ -461,7 +461,8 @@ select_ef_by_path (app_t app, const unsigned short *path, size_t pathlen) supported by the card. */ for (i=0; i < pathlen; i++) { - err = iso7816_select_file (app->slot, path[i], !(i+1 == pathlen)); + err = iso7816_select_file (app_get_slot (app), + path[i], !(i+1 == pathlen)); if (err) { log_error ("error selecting part %d from path ", i); @@ -612,7 +613,8 @@ read_ef_odf (app_t app, unsigned short odf_fid) unsigned short value; size_t offset; - err = select_and_read_binary (app->slot, odf_fid, "ODF", &buffer, &buflen); + err = select_and_read_binary (app_get_slot (app), odf_fid, "ODF", + &buffer, &buflen); if (err) return err; @@ -826,7 +828,8 @@ read_ef_prkdf (app_t app, unsigned short fid, prkdf_object_t *result) if (!fid) return gpg_error (GPG_ERR_NO_DATA); /* No private keys. */ - err = select_and_read_binary (app->slot, fid, "PrKDF", &buffer, &buflen); + err = select_and_read_binary (app_get_slot (app), fid, "PrKDF", + &buffer, &buflen); if (err) return err; @@ -1282,7 +1285,8 @@ read_ef_cdf (app_t app, unsigned short fid, cdf_object_t *result) if (!fid) return gpg_error (GPG_ERR_NO_DATA); /* No certificates. */ - err = select_and_read_binary (app->slot, fid, "CDF", &buffer, &buflen); + err = select_and_read_binary (app_get_slot (app), fid, "CDF", + &buffer, &buflen); if (err) return err; @@ -1555,7 +1559,8 @@ read_ef_aodf (app_t app, unsigned short fid, aodf_object_t *result) if (!fid) return gpg_error (GPG_ERR_NO_DATA); /* No authentication objects. */ - err = select_and_read_binary (app->slot, fid, "AODF", &buffer, &buflen); + err = select_and_read_binary (app_get_slot (app), fid, "AODF", + &buffer, &buflen); if (err) return err; @@ -2216,7 +2221,7 @@ read_ef_tokeninfo (app_t app) int class, tag, constructed, ndef; unsigned long ul; - err = select_and_read_binary (app->slot, 0x5032, "TokenInfo", + err = select_and_read_binary (app_get_slot (app), 0x5032, "TokenInfo", &buffer, &buflen); if (err) return err; @@ -2294,13 +2299,13 @@ read_p15_info (app_t app) { /* If we don't have a serial number yet but the TokenInfo provides one, use that. */ - if (!app->serialno && app->app_local->serialno) + if (!app->card->serialno && app->app_local->serialno) { - app->serialno = app->app_local->serialno; - app->serialnolen = app->app_local->serialnolen; + app->card->serialno = app->app_local->serialno; + app->card->serialnolen = app->app_local->serialnolen; app->app_local->serialno = NULL; app->app_local->serialnolen = 0; - err = app_munge_serialno (app); + err = app_munge_serialno (app->card); if (err) return err; } @@ -2553,7 +2558,8 @@ readcert_by_cdf (app_t app, cdf_object_t cdf, if (err) goto leave; - err = iso7816_read_binary (app->slot, cdf->off, cdf->len, &buffer, &buflen); + err = iso7816_read_binary (app_get_slot (app), cdf->off, cdf->len, + &buffer, &buflen); if (!err && (!buflen || *buffer == 0xff)) err = gpg_error (GPG_ERR_NOT_FOUND); if (err) @@ -2713,7 +2719,8 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name) err = select_ef_by_path (app, path, DIM(path) ); if (!err) - err = iso7816_read_binary (app->slot, 0, 0, &buffer, &buflen); + err = iso7816_read_binary (app_get_slot (app), 0, 0, + &buffer, &buflen); if (err) { log_error ("error accessing EF(ID): %s\n", gpg_strerror (err)); @@ -2758,7 +2765,7 @@ micardo_mse (app_t app, unsigned short fid) unsigned char msebuf[10]; /* Read the KeyD file containing extra information on keys. */ - err = iso7816_select_file (app->slot, 0x0013, 0); + err = iso7816_select_file (app_get_slot (app), 0x0013, 0); if (err) { log_error ("error reading EF_keyD: %s\n", gpg_strerror (err)); @@ -2772,7 +2779,8 @@ micardo_mse (app_t app, unsigned short fid) size_t n, nn; const unsigned char *p, *pp; - err = iso7816_read_record (app->slot, recno, 1, 0, &buffer, &buflen); + err = iso7816_read_record (app_get_slot (app), recno, 1, 0, + &buffer, &buflen); if (gpg_err_code (err) == GPG_ERR_NOT_FOUND) break; /* ready */ if (err) @@ -2811,7 +2819,8 @@ micardo_mse (app_t app, unsigned short fid) /* Restore the security environment to SE_NUM if needed */ if (se_num) { - err = iso7816_manage_security_env (app->slot, 0xf3, se_num, NULL, 0); + err = iso7816_manage_security_env (app_get_slot (app), + 0xf3, se_num, NULL, 0); if (err) { log_error ("restoring SE to %d failed: %s\n", @@ -2826,7 +2835,7 @@ micardo_mse (app_t app, unsigned short fid) msebuf[2] = 0x80; msebuf[3] = (refdata >> 8); msebuf[4] = refdata; - err = iso7816_manage_security_env (app->slot, 0x41, 0xb6, msebuf, 5); + err = iso7816_manage_security_env (app_get_slot (app), 0x41, 0xb6, msebuf, 5); if (err) { log_error ("setting SE to reference file %04hX failed: %s\n", @@ -2948,7 +2957,7 @@ do_sign (app_t app, const char *keyidstr, int hashalgo, mse[3] = 0x84; /* Private key reference tag. */ mse[4] = prkdf->key_reference_valid? prkdf->key_reference : 0x82; - err = iso7816_manage_security_env (app->slot, + err = iso7816_manage_security_env (app_get_slot (app), 0x41, 0xB6, mse, sizeof mse); no_data_padding = 1; @@ -3101,7 +3110,7 @@ do_sign (app_t app, const char *keyidstr, int hashalgo, else pinvaluelen = strlen (pinvalue); - err = iso7816_verify (app->slot, + err = iso7816_verify (app_get_slot (app), aodf->pin_reference_valid? aodf->pin_reference : 0, pinvalue, pinvaluelen); xfree (pinvalue); @@ -3170,7 +3179,7 @@ do_sign (app_t app, const char *keyidstr, int hashalgo, mse[1] = 1; mse[2] = prkdf->key_reference; - err = iso7816_manage_security_env (app->slot, + err = iso7816_manage_security_env (app_get_slot (app), 0x41, 0xB6, mse, sizeof mse); } @@ -3181,11 +3190,14 @@ do_sign (app_t app, const char *keyidstr, int hashalgo, } if (hashalgo == MD_USER_TLS_MD5SHA1) - err = iso7816_compute_ds (app->slot, 0, data, 36, 0, outdata, outdatalen); + err = iso7816_compute_ds (app_get_slot (app), + 0, data, 36, 0, outdata, outdatalen); else if (no_data_padding) - err = iso7816_compute_ds (app->slot, 0, data+15, 20, 0,outdata,outdatalen); + err = iso7816_compute_ds (app_get_slot (app), + 0, data+15, 20, 0,outdata,outdatalen); else - err = iso7816_compute_ds (app->slot, 0, data, 35, 0, outdata, outdatalen); + err = iso7816_compute_ds (app_get_slot (app), + 0, data, 35, 0, outdata, outdatalen); return err; } @@ -3280,7 +3292,7 @@ read_home_df (int slot, int *r_belpic) gpg_error_t app_select_p15 (app_t app) { - int slot = app->slot; + int slot = app_get_slot (app); int rc; unsigned short def_home_df = 0; card_type_t card_type = CARD_TYPE_UNKNOWN; @@ -3298,7 +3310,7 @@ app_select_p15 (app_t app) Using the 2f02 just works. */ unsigned short path[1] = { 0x2f00 }; - rc = iso7816_select_path (app->slot, path, 1); + rc = iso7816_select_path (app_get_slot (app), path, 1); if (!rc) { direct = 1; @@ -3306,7 +3318,7 @@ app_select_p15 (app_t app) if (def_home_df) { path[0] = def_home_df; - rc = iso7816_select_path (app->slot, path, 1); + rc = iso7816_select_path (app_get_slot (app), path, 1); } } } @@ -3330,7 +3342,7 @@ app_select_p15 (app_t app) size_t atrlen; int i; - atr = apdu_get_atr (app->slot, &atrlen); + atr = apdu_get_atr (app_get_slot (app), &atrlen); if (!atr) rc = gpg_error (GPG_ERR_INV_CARD); else @@ -3381,8 +3393,8 @@ app_select_p15 (app_t app) prototype card right here because we need to access to EF(TokenInfo). We mark such a serial number by the using a prefix of FF0100. */ - if (app->serialnolen == 12 - && !memcmp (app->serialno, "\xD2\x76\0\0\0\0\0\0\0\0\0\0", 12)) + if (app->card->serialnolen == 12 + && !memcmp (app->card->serialno, "\xD2\x76\0\0\0\0\0\0\0\0\0\0", 12)) { /* This is a German card with a silly serial number. Try to get the serial number from the EF(TokenInfo). . */ @@ -3390,16 +3402,16 @@ app_select_p15 (app_t app) /* FIXME: actually get it from EF(TokenInfo). */ - p = xtrymalloc (3 + app->serialnolen); + p = xtrymalloc (3 + app->card->serialnolen); if (!p) rc = gpg_error (gpg_err_code_from_errno (errno)); else { memcpy (p, "\xff\x01", 3); - memcpy (p+3, app->serialno, app->serialnolen); - app->serialnolen += 3; - xfree (app->serialno); - app->serialno = p; + memcpy (p+3, app->card->serialno, app->card->serialnolen); + app->card->serialnolen += 3; + xfree (app->card->serialno); + app->card->serialno = p; } } diff --git a/scd/app-piv.c b/scd/app-piv.c index 2ee72e0fc..4b3868729 100644 --- a/scd/app-piv.c +++ b/scd/app-piv.c @@ -283,7 +283,7 @@ get_cached_data (app_t app, int tag, } } - err = iso7816_get_data_odd (app->slot, 0, tag, &p, &len); + err = iso7816_get_data_odd (app_get_slot (app), 0, tag, &p, &len); if (err) return err; @@ -737,18 +737,18 @@ get_dispserialno (app_t app, int failmode) { char *result; - if (app->serialno && app->serialnolen == 3+1+4 - && !memcmp (app->serialno, "\xff\x02\x00", 3)) + if (app->card && app->card->serialno && app->card->serialnolen == 3+1+4 + && !memcmp (app->card->serialno, "\xff\x02\x00", 3)) { /* This is a 4 byte S/N of a Yubikey which seems to be printed * on the token in decimal. Maybe they will print larger S/N * also in decimal but we can't be sure, thus do it only for * these 32 bit numbers. */ unsigned long sn; - sn = app->serialno[4] * 16777216; - sn += app->serialno[5] * 65536; - sn += app->serialno[6] * 256; - sn += app->serialno[7]; + sn = app->card->serialno[4] * 16777216; + sn += app->card->serialno[5] * 65536; + sn += app->card->serialno[6] * 256; + sn += app->card->serialno[7]; result = xtryasprintf ("yk-%lu", sn); } else if (failmode) @@ -786,7 +786,7 @@ get_chv_status (app_t app, const char *keyrefstr) apdu[1] = ISO7816_VERIFY; apdu[2] = 0x00; apdu[3] = keyref; - if (!iso7816_apdu_direct (app->slot, apdu, 4, 0, &sw, NULL, NULL)) + if (!iso7816_apdu_direct (app_get_slot (app), apdu, 4, 0, &sw, NULL, NULL)) result = -5; /* No need to verification. */ else if (sw == 0x6a88 || sw == 0x6a80) result = -2; /* No such PIN. */ @@ -938,7 +938,7 @@ auth_adm_key (app_t app, const unsigned char *value, size_t valuelen) tmpl[2] = 0x80; tmpl[3] = 0; /* (Empty witness requests a witness.) */ tmpllen = 4; - err = iso7816_general_authenticate (app->slot, 0, + err = iso7816_general_authenticate (app_get_slot (app), 0, PIV_ALGORITHM_3DES_ECB_0, 0x9B, tmpl, tmpllen, 0, &outdata, &outdatalen); @@ -971,7 +971,7 @@ auth_adm_key (app_t app, const unsigned char *value, size_t valuelen) tmpl[23] = 0; tmpllen = 24; xfree (outdata); - err = iso7816_general_authenticate (app->slot, 0, + err = iso7816_general_authenticate (app_get_slot (app), 0, PIV_ALGORITHM_3DES_ECB_0, 0x9B, tmpl, tmpllen, 0, &outdata, &outdatalen); @@ -1045,7 +1045,8 @@ set_adm_key (app_t app, const unsigned char *value, size_t valuelen) apdu[6] = 0x9b; apdu[7] = 24; memcpy (apdu+8, value, 24); - err = iso7816_apdu_direct (app->slot, apdu, 8+24, 0, &sw, NULL, NULL); + err = iso7816_apdu_direct (app_get_slot (app), apdu, 8+24, 0, + &sw, NULL, NULL); wipememory (apdu+8, 24); if (err) log_error ("piv: setting admin key failed; sw=%04x\n", sw); @@ -1426,7 +1427,7 @@ do_readcert (app_t app, const char *certid, apdu[1] = 0xf9; /* Yubikey: Get attestation cert. */ apdu[2] = xtoi_2 (certid+9); apdu[3] = 0; - err = iso7816_apdu_direct (app->slot, apdu, 4, 1, + err = iso7816_apdu_direct (app_get_slot (app), apdu, 4, 1, NULL, &result, &resultlen); if (!err) { @@ -1880,7 +1881,7 @@ verify_chv (app_t app, int keyref, int force, apdu[1] = ISO7816_VERIFY; apdu[2] = 0x00; apdu[3] = keyref; - if (!iso7816_apdu_direct (app->slot, apdu, 4, 0, &sw, NULL, NULL)) + if (!iso7816_apdu_direct (app_get_slot (app), apdu, 4, 0, &sw, NULL, NULL)) { if (!force) /* No need to verification. */ return 0; /* All fine. */ @@ -1896,7 +1897,7 @@ verify_chv (app_t app, int keyref, int force, if (err) return err; - err = iso7816_verify (app->slot, keyref, pin, pinlen); + err = iso7816_verify (app_get_slot (app), keyref, pin, pinlen); wipememory (pin, pinlen); xfree (pin); if (err) @@ -1957,7 +1958,8 @@ do_change_chv (app_t app, ctrl_t ctrl, const char *pwidstr, apdu[1] = ISO7816_VERIFY; apdu[2] = 0xff; apdu[3] = keyref; - err = iso7816_apdu_direct (app->slot, apdu, 4, 0, NULL, NULL, NULL); + err = iso7816_apdu_direct (app_get_slot (app), apdu, 4, 0, + NULL, NULL, NULL); goto leave; } @@ -1979,7 +1981,7 @@ do_change_chv (app_t app, ctrl_t ctrl, const char *pwidstr, apdu[1] = ISO7816_VERIFY; apdu[2] = 0x00; apdu[3] = keyref; - if (!iso7816_apdu_direct (app->slot, apdu, 4, 0, &sw, NULL, NULL)) + if (!iso7816_apdu_direct (app_get_slot (app), apdu, 4, 0, &sw, NULL, NULL)) remaining = -1; /* Already verified, thus full number of tries. */ else if ((sw & 0xfff0) == 0x63C0) remaining = (sw & 0x000f); /* PIN has REMAINING tries left. */ @@ -1996,7 +1998,7 @@ do_change_chv (app_t app, ctrl_t ctrl, const char *pwidstr, * old is wrong. This is not possible for the PUK, though. */ if (keyref != 0x81) { - err = iso7816_verify (app->slot, keyref, oldpin, oldpinlen); + err = iso7816_verify (app_get_slot (app), keyref, oldpin, oldpinlen); if (err) { log_error ("CHV %02X verification failed: %s\n", @@ -2021,7 +2023,8 @@ do_change_chv (app_t app, ctrl_t ctrl, const char *pwidstr, } memcpy (buf, oldpin, oldpinlen); memcpy (buf+oldpinlen, newpin, newpinlen); - err = iso7816_reset_retry_counter_with_rc (app->slot, targetkeyref, + err = iso7816_reset_retry_counter_with_rc (app_get_slot (app), + targetkeyref, buf, oldpinlen+newpinlen); xfree (buf); if (err) @@ -2030,7 +2033,7 @@ do_change_chv (app_t app, ctrl_t ctrl, const char *pwidstr, } else { - err = iso7816_change_reference_data (app->slot, keyref, + err = iso7816_change_reference_data (app_get_slot (app), keyref, oldpin, oldpinlen, newpin, newpinlen); if (err) @@ -2269,7 +2272,7 @@ do_sign (app_t app, const char *keyidstr, int hashalgo, goto leave; /* Note: the -1 requests command chaining. */ - err = iso7816_general_authenticate (app->slot, -1, + err = iso7816_general_authenticate (app_get_slot (app), -1, mechanism, keyref, apdudata, (int)apdudatalen, 0, &outdata, &outdatalen); @@ -2492,7 +2495,7 @@ do_decipher (app_t app, const char *keyidstr, goto leave; /* Note: the -1 requests command chaining. */ - err = iso7816_general_authenticate (app->slot, -1, + err = iso7816_general_authenticate (app_get_slot (app), -1, mechanism, keyref, apdudata, (int)apdudatalen, 0, &outdata, &outdatalen); @@ -2693,7 +2696,7 @@ writekey_rsa (app_t app, data_object_t dobj, int keyref, if (err) goto leave; - err = iso7816_send_apdu (app->slot, + err = iso7816_send_apdu (app_get_slot (app), -1, /* Use command chaining. */ 0, /* Class */ 0xfe, /* Ins: Yubikey Import Asym. Key. */ @@ -2715,7 +2718,7 @@ writekey_rsa (app_t app, data_object_t dobj, int keyref, if (err) goto leave; tmpl[0] = PIV_ALGORITHM_RSA; - err = put_data (app->slot, dobj->tag, + err = put_data (app_get_slot (app), dobj->tag, (int)0x80, (size_t)1, tmpl, (int)0x7f49, (size_t)apdudatalen, apdudata, (int)0, (size_t)0, NULL); @@ -2845,7 +2848,7 @@ writekey_ecc (app_t app, data_object_t dobj, int keyref, if (err) goto leave; - err = iso7816_send_apdu (app->slot, + err = iso7816_send_apdu (app_get_slot (app), -1, /* Use command chaining. */ 0, /* Class */ 0xfe, /* Ins: Yubikey Import Asym. Key. */ @@ -2866,7 +2869,7 @@ writekey_ecc (app_t app, data_object_t dobj, int keyref, if (err) goto leave; tmpl[0] = mechanism; - err = put_data (app->slot, dobj->tag, + err = put_data (app_get_slot (app), dobj->tag, (int)0x80, (size_t)1, tmpl, (int)0x7f49, (size_t)apdudatalen, apdudata, (int)0, (size_t)0, NULL); @@ -2952,7 +2955,7 @@ do_writekey (app_t app, ctrl_t ctrl, /* First clear an existing key. We do this by writing an empty 7f49 * tag. This will return GPG_ERR_NO_PUBKEY on a later read. */ flush_cached_data (app, dobj->tag); - err = put_data (app->slot, dobj->tag, + err = put_data (app_get_slot (app), dobj->tag, (int)0x7f49, (size_t)0, "", (int)0, (size_t)0, NULL); if (err) @@ -3180,7 +3183,7 @@ do_genkey (app_t app, ctrl_t ctrl, const char *keyrefstr, const char *keytype, tmpl[3] = 1; tmpl[4] = mechanism; tmpllen = 5; - err = iso7816_generate_keypair (app->slot, 0, 0, keyref, + err = iso7816_generate_keypair (app_get_slot (app), 0, 0, keyref, tmpl, tmpllen, 0, &buffer, &buflen); if (err) { @@ -3210,7 +3213,7 @@ do_genkey (app_t app, ctrl_t ctrl, const char *keyrefstr, const char *keytype, tmpl[0] = mechanism; flush_cached_data (app, dobj->tag); - err = put_data (app->slot, dobj->tag, + err = put_data (app_get_slot (app), dobj->tag, (int)0x80, (size_t)1, tmpl, (int)0x7f49, (size_t)keydatalen, keydata, (int)0, (size_t)0, NULL); @@ -3281,7 +3284,7 @@ do_writecert (app_t app, ctrl_t ctrl, goto leave; } - err = put_data (app->slot, dobj->tag, + err = put_data (app_get_slot (app), dobj->tag, (int)0x70, (size_t)certlen, cert,/* Certificate */ (int)0x71, (size_t)1, "", /* No compress */ (int)0xfe, (size_t)0, "", /* Empty LRC. */ @@ -3395,7 +3398,7 @@ app_select_piv (app_t app) { static char const aid[] = { 0xA0, 0x00, 0x00, 0x03, 0x08, /* RID=NIST */ 0x00, 0x00, 0x10, 0x00 /* PIX=PIV */ }; - int slot = app->slot; + int slot = app_get_slot (app); gpg_error_t err; unsigned char *apt = NULL; size_t aptlen; @@ -3463,7 +3466,7 @@ app_select_piv (app_t app) goto leave; } - if (app->cardtype && !strcmp (app->cardtype, "yubikey")) + if (app->card->cardtype && !strcmp (app->card->cardtype, "yubikey")) app->app_local->flags.yubikey = 1; diff --git a/scd/app-sc-hsm.c b/scd/app-sc-hsm.c index 8094b2463..a8a792369 100644 --- a/scd/app-sc-hsm.c +++ b/scd/app-sc-hsm.c @@ -484,7 +484,8 @@ read_ef_prkd (app_t app, unsigned short fid, prkdf_object_t *prkdresult, if (!fid) return gpg_error (GPG_ERR_NO_DATA); /* No private keys. */ - err = select_and_read_binary (app->slot, fid, "PrKDF", &buffer, &buflen, 255); + err = select_and_read_binary (app_get_slot (app), + fid, "PrKDF", &buffer, &buflen, 255); if (err) return err; @@ -832,7 +833,7 @@ read_ef_prkd (app_t app, unsigned short fid, prkdf_object_t *prkdresult, xfree (buffer); buffer = NULL; buflen = 0; - err = select_and_read_binary (app->slot, + err = select_and_read_binary (app_get_slot (app), ((SC_HSM_EE_PREFIX << 8) | (fid & 0xFF)), "CertEF", &buffer, &buflen, 1); if (!err && buffer[0] == 0x30) @@ -953,7 +954,8 @@ read_ef_cd (app_t app, unsigned short fid, cdf_object_t *result) if (!fid) return gpg_error (GPG_ERR_NO_DATA); /* No certificates. */ - err = select_and_read_binary (app->slot, fid, "CDF", &buffer, &buflen, 255); + err = select_and_read_binary (app_get_slot (app), fid, "CDF", + &buffer, &buflen, 255); if (err) return err; @@ -1202,7 +1204,7 @@ read_serialno(app_t app) size_t n, objlen, hdrlen, chrlen; int class, tag, constructed, ndef; - err = select_and_read_binary (app->slot, 0x2F02, "EF.C_DevAut", + err = select_and_read_binary (app_get_slot (app), 0x2F02, "EF.C_DevAut", &buffer, &buflen, 512); if (err) return err; @@ -1229,15 +1231,15 @@ read_serialno(app_t app) } chrlen -= 5; - app->serialno = xtrymalloc (chrlen); - if (!app->serialno) + app->card->serialno = xtrymalloc (chrlen); + if (!app->card->serialno) { err = gpg_error_from_syserror (); goto leave; } - app->serialnolen = chrlen; - memcpy (app->serialno, chr, chrlen); + app->card->serialnolen = chrlen; + memcpy (app->card->serialno, chr, chrlen); leave: xfree (buffer); @@ -1260,7 +1262,7 @@ read_meta (app_t app) if (err) return err; - err = list_ef (app->slot, &eflist, &eflistlen); + err = list_ef (app_get_slot (app), &eflist, &eflistlen); if (err) return err; @@ -1454,7 +1456,7 @@ readcert_by_cdf (app_t app, cdf_object_t cdf, return 0; } - err = select_and_read_binary (app->slot, cdf->fid, "CD", + err = select_and_read_binary (app_get_slot (app), cdf->fid, "CD", &buffer, &buflen, 4096); if (err) { @@ -1592,7 +1594,8 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name) } else if (!strcmp (name, "$DISPSERIALNO")) { - send_status_info (ctrl, name, app->serialno, app->serialnolen, NULL, 0); + send_status_info (ctrl, name, + app->card->serialno, app->card->serialnolen, NULL, 0); return 0; } @@ -1693,8 +1696,8 @@ verify_pin (app_t app, gpg_error_t (*pincb)(void*, const char *, char **), char *prompt; int sw; - sw = apdu_send_simple (app->slot, 0, 0x00, ISO7816_VERIFY, 0x00, 0x81, - -1, NULL); + sw = apdu_send_simple (app_get_slot (app), + 0, 0x00, ISO7816_VERIFY, 0x00, 0x81, -1, NULL); if (sw == SW_SUCCESS) return 0; /* PIN already verified */ @@ -1719,7 +1722,7 @@ verify_pin (app_t app, gpg_error_t (*pincb)(void*, const char *, char **), prompt = "||Please enter the PIN"; if (!opt.disable_pinpad - && !iso7816_check_pinpad (app->slot, ISO7816_VERIFY, &pininfo) ) + && !iso7816_check_pinpad (app_get_slot (app), ISO7816_VERIFY, &pininfo) ) { err = pincb (pincb_arg, prompt, NULL); if (err) @@ -1728,7 +1731,7 @@ verify_pin (app_t app, gpg_error_t (*pincb)(void*, const char *, char **), return err; } - err = iso7816_verify_kp (app->slot, 0x81, &pininfo); + err = iso7816_verify_kp (app_get_slot (app), 0x81, &pininfo); pincb (pincb_arg, NULL, NULL); /* Dismiss the prompt. */ } else @@ -1740,7 +1743,8 @@ verify_pin (app_t app, gpg_error_t (*pincb)(void*, const char *, char **), return err; } - err = iso7816_verify (app->slot, 0x81, pinvalue, strlen(pinvalue)); + err = iso7816_verify (app_get_slot (app), + 0x81, pinvalue, strlen(pinvalue)); xfree (pinvalue); } if (err) @@ -1883,7 +1887,8 @@ do_sign (app_t app, const char *keyidstr, int hashalgo, if (err) return err; - sw = apdu_send_le (app->slot, 1, 0x80, 0x68, prkdf->key_reference, algoid, + sw = apdu_send_le (app_get_slot (app), + 1, 0x80, 0x68, prkdf->key_reference, algoid, cdsblklen, cdsblk, 0, outdata, outdatalen); return iso7816_map_sw (sw); } @@ -2018,7 +2023,8 @@ do_decipher (app_t app, const char *keyidstr, if (err) return err; - sw = apdu_send_le (app->slot, 1, 0x80, 0x62, prkdf->key_reference, 0x21, + sw = apdu_send_le (app_get_slot (app), + 1, 0x80, 0x62, prkdf->key_reference, 0x21, p1blklen, p1blk, 0, &rspdata, &rspdatalen); err = iso7816_map_sw (sw); if (err) @@ -2044,7 +2050,7 @@ do_decipher (app_t app, const char *keyidstr, gpg_error_t app_select_sc_hsm (app_t app) { - int slot = app->slot; + int slot = app_get_slot (app); int rc; rc = iso7816_select_application (slot, sc_hsm_aid, sizeof sc_hsm_aid, 0); diff --git a/scd/app.c b/scd/app.c index 9055c9e8e..aa26443f6 100644 --- a/scd/app.c +++ b/scd/app.c @@ -31,8 +31,13 @@ #include "apdu.h" #include "../common/tlv.h" -static npth_mutex_t app_list_lock; -static app_t app_top; +/* Lock to protect the list of cards and its associated + * applications. */ +static npth_mutex_t card_list_lock; + +/* A list of card contexts. A card is a collection of applications + * (described by app_t) on the same physical token. */ +static card_t card_top; /* The list of application names and there select function. Of no @@ -126,59 +131,68 @@ print_progress_line (void *opaque, const char *what, int pc, int cur, int tot) } -/* Lock the reader SLOT. This function shall be used right before - calling any of the actual application functions to serialize access - to the reader. We do this always even if the reader is not - actually used. This allows an actual connection to assume that it - never shares a reader (while performing one command). Returns 0 on - success; only then the unlock_reader function must be called after - returning from the handler. */ +/* Lock the CARD. This function shall be used right before calling + * any of the actual application functions to serialize access to the + * reader. We do this always even if the card is not actually used. + * This allows an actual connection to assume that it never shares a + * card (while performing one command). Returns 0 on success; only + * then the unlock_reader function must be called after returning from + * the handler. Right now we assume a that a reader has just one + * card; this may eventually need refinement. */ static gpg_error_t -lock_app (app_t app, ctrl_t ctrl) +lock_card (card_t card, ctrl_t ctrl) { - if (npth_mutex_lock (&app->lock)) + if (npth_mutex_lock (&card->lock)) { gpg_error_t err = gpg_error_from_syserror (); - log_error ("failed to acquire APP lock for %p: %s\n", - app, gpg_strerror (err)); + log_error ("failed to acquire CARD lock for %p: %s\n", + card, gpg_strerror (err)); return err; } - apdu_set_progress_cb (app->slot, print_progress_line, ctrl); - apdu_set_prompt_cb (app->slot, popup_prompt, ctrl); + apdu_set_progress_cb (card->slot, print_progress_line, ctrl); + apdu_set_prompt_cb (card->slot, popup_prompt, ctrl); return 0; } -/* Release a lock on the reader. See lock_reader(). */ -static void -unlock_app (app_t app) -{ - apdu_set_progress_cb (app->slot, NULL, NULL); - apdu_set_prompt_cb (app->slot, NULL, NULL); - if (npth_mutex_unlock (&app->lock)) +/* Release a lock on a card. See lock_reader(). */ +static void +unlock_card (card_t card) +{ + apdu_set_progress_cb (card->slot, NULL, NULL); + apdu_set_prompt_cb (card->slot, NULL, NULL); + + if (npth_mutex_unlock (&card->lock)) { gpg_error_t err = gpg_error_from_syserror (); - log_error ("failed to release APP lock for %p: %s\n", - app, gpg_strerror (err)); + log_error ("failed to release CARD lock for %p: %s\n", + card, gpg_strerror (err)); } } /* This function may be called to print information pertaining to the - current state of this module to the log. */ + * current state of this module to the log. */ void app_dump_state (void) { + card_t c; app_t a; - npth_mutex_lock (&app_list_lock); - for (a = app_top; a; a = a->next) - log_info ("app_dump_state: app=%p type='%s'\n", a, a->apptype); - npth_mutex_unlock (&app_list_lock); + npth_mutex_lock (&card_list_lock); + for (c = card_top; c; c = c->next) + { + log_info ("app_dump_state: card=%p slot=%d type=%s\n", + c, c->slot, c->cardtype? c->cardtype:"unknown"); + for (a=c->app; a; a = a->next) + log_info ("app_dump_state: app=%p type='%s'\n", a, a->apptype); + } + npth_mutex_unlock (&card_list_lock); } + /* Check whether the application NAME is allowed. This does not mean we have support for it though. */ static int @@ -194,33 +208,40 @@ is_app_allowed (const char *name) static gpg_error_t -check_conflict (app_t app, const char *name) +check_conflict (card_t card, const char *name) { - if (!app || !name || (app->apptype && !ascii_strcasecmp (app->apptype, name))) + if (!card || !name) + return 0; + if (!card->app) + return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); /* Should not happen. */ + + /* FIXME: Needs changes for app switching. */ + if (card->app->apptype && !ascii_strcasecmp (card->app->apptype, name)) return 0; - if (app->apptype && !strcmp (app->apptype, "UNDEFINED")) + if (card->app->apptype && !strcmp (card->app->apptype, "UNDEFINED")) return 0; log_info ("application '%s' in use - can't switch\n", - app->apptype? app->apptype : ""); + card->app->apptype? card->app->apptype : ""); return gpg_error (GPG_ERR_CONFLICT); } + /* This function is used by the serialno command to check for an application conflict which may appear if the serialno command is used to request a specific application and the connection has already done a select_application. */ gpg_error_t -check_application_conflict (const char *name, app_t app) +check_application_conflict (const char *name, card_t card) { - return check_conflict (app, name); + return check_conflict (card, name); } gpg_error_t -app_reset (app_t app, ctrl_t ctrl, int send_reset) +card_reset (card_t card, ctrl_t ctrl, int send_reset) { gpg_error_t err = 0; @@ -228,21 +249,21 @@ app_reset (app_t app, ctrl_t ctrl, int send_reset) { int sw; - lock_app (app, ctrl); - sw = apdu_reset (app->slot); + lock_card (card, ctrl); + sw = apdu_reset (card->slot); if (sw) err = gpg_error (GPG_ERR_CARD_RESET); - app->reset_requested = 1; - unlock_app (app); + card->reset_requested = 1; + unlock_card (card); scd_kick_the_loop (); gnupg_sleep (1); } else { - ctrl->app_ctx = NULL; - app_unref (app); + ctrl->card_ctx = NULL; + card_unref (card); } return err; @@ -253,36 +274,37 @@ app_new_register (int slot, ctrl_t ctrl, const char *name, int periodical_check_needed) { gpg_error_t err = 0; + card_t card = NULL; app_t app = NULL; unsigned char *result = NULL; size_t resultlen; int want_undefined; int i; - /* Need to allocate a new one. */ - app = xtrycalloc (1, sizeof *app); - if (!app) + /* Need to allocate a new card object */ + card = xtrycalloc (1, sizeof *card); + if (!card) { err = gpg_error_from_syserror (); log_info ("error allocating context: %s\n", gpg_strerror (err)); return err; } - app->slot = slot; - app->card_status = (unsigned int)-1; + card->slot = slot; + card->card_status = (unsigned int)-1; - if (npth_mutex_init (&app->lock, NULL)) + if (npth_mutex_init (&card->lock, NULL)) { err = gpg_error_from_syserror (); log_error ("error initializing mutex: %s\n", gpg_strerror (err)); - xfree (app); + xfree (card); return err; } - err = lock_app (app, ctrl); + err = lock_card (card, ctrl); if (err) { - xfree (app); + xfree (card); return err; } @@ -313,7 +335,7 @@ app_new_register (int slot, ctrl_t ctrl, const char *name, && !iso7816_apdu_direct (slot, "\x00\x1d\x00\x00\x00", 5, 0, NULL, &buf, &buflen)) { - app->cardtype = "yubikey"; + card->cardtype = "yubikey"; if (opt.verbose) { log_info ("Yubico: config="); @@ -330,15 +352,15 @@ app_new_register (int slot, ctrl_t ctrl, const char *name, s0 = find_tlv (buf+1, buflen-1, 0x02, &n); /* Serial */ if (s0 && n >= 4) { - app->serialno = xtrymalloc (3 + 1 + n); - if (app->serialno) + card->serialno = xtrymalloc (3 + 1 + n); + if (card->serialno) { - app->serialnolen = 3 + 1 + n; - app->serialno[0] = 0xff; - app->serialno[1] = 0x02; - app->serialno[2] = 0x0; - app->serialno[3] = formfactor; - memcpy (app->serialno + 4, s0, n); + card->serialnolen = 3 + 1 + n; + card->serialno[0] = 0xff; + card->serialno[1] = 0x02; + card->serialno[2] = 0x0; + card->serialno[3] = formfactor; + memcpy (card->serialno + 4, s0, n); /* Note that we do not clear the error * so that no further serial number * testing is done. After all we just @@ -348,7 +370,7 @@ app_new_register (int slot, ctrl_t ctrl, const char *name, s0 = find_tlv (buf+1, buflen-1, 0x05, &n); /* version */ if (s0 && n == 3) - app->cardversion = ((s0[0]<<16)|(s0[1]<<8)|s0[2]); + card->cardversion = ((s0[0]<<16)|(s0[1]<<8)|s0[2]); else if (!s0) { /* No version - this is not a Yubikey 5. We now @@ -361,7 +383,7 @@ app_new_register (int slot, ctrl_t ctrl, const char *name, otp_aid, sizeof otp_aid, 1, &buf, &buflen) && buflen > 3) - app->cardversion = ((buf[0]<<16)|(buf[1]<<8)|buf[2]); + card->cardversion = ((buf[0]<<16)|(buf[1]<<8)|buf[2]); } } xfree (buf); @@ -382,7 +404,7 @@ app_new_register (int slot, ctrl_t ctrl, const char *name, resultlen -= (p-result); if (p && n > resultlen && n == 0x0d && resultlen+1 == n) { - /* The object it does not fit into the buffer. This is an + /* The object does not fit into the buffer. This is an invalid encoding (or the buffer is too short. However, I have some test cards with such an invalid encoding and therefore I use this ugly workaround to return something @@ -396,9 +418,9 @@ app_new_register (int slot, ctrl_t ctrl, const char *name, /* The GDO file is pretty short, thus we simply reuse it for storing the serial number. */ memmove (result, p, n); - app->serialno = result; - app->serialnolen = n; - err = app_munge_serialno (app); + card->serialno = result; + card->serialnolen = n; + err = app_munge_serialno (card); if (err) goto leave; } @@ -408,6 +430,17 @@ app_new_register (int slot, ctrl_t ctrl, const char *name, } } + /* Allocate a new app object. */ + app = xtrycalloc (1, sizeof *app); + if (!app) + { + err = gpg_error_from_syserror (); + log_info ("error allocating app context: %s\n", gpg_strerror (err)); + goto leave; + } + card->app = app; + app->card = card; + /* Figure out the application to use. */ if (want_undefined) { @@ -430,7 +463,7 @@ app_new_register (int slot, ctrl_t ctrl, const char *name, err = gpg_error (GPG_ERR_NOT_FOUND); } - /* Find the first available app if NAME is NULL or the one matching + /* Find the first available app if NAME is NULL or the matching * NAME but only if that application is also enabled. */ for (i=0; err && app_priority_list[i].name; i++) { @@ -450,44 +483,47 @@ app_new_register (int slot, ctrl_t ctrl, const char *name, else log_info ("no supported card application found: %s\n", gpg_strerror (err)); - unlock_app (app); + unlock_card (card); xfree (app); + xfree (card); return err; } - app->periodical_check_needed = periodical_check_needed; - app->next = app_top; - app_top = app; - unlock_app (app); + card->periodical_check_needed = periodical_check_needed; + + card->next = card_top; + card_top = card; + unlock_card (card); return 0; } + /* If called with NAME as NULL, select the best fitting application - and return a context; otherwise select the application with NAME - and return a context. Returns an error code and stores NULL at - R_APP if no application was found or no card is present. */ + * and return its card context; otherwise select the application with + * NAME and return its card context. Returns an error code and stores + * NULL at R_CARD if no application was found or no card is present. */ gpg_error_t -select_application (ctrl_t ctrl, const char *name, app_t *r_app, +select_application (ctrl_t ctrl, const char *name, card_t *r_card, int scan, const unsigned char *serialno_bin, size_t serialno_bin_len) { gpg_error_t err = 0; - app_t a, a_prev = NULL; + card_t card, card_prev = NULL; - *r_app = NULL; + *r_card = NULL; - npth_mutex_lock (&app_list_lock); + npth_mutex_lock (&card_list_lock); - if (scan || !app_top) + if (scan || !card_top) { struct dev_list *l; - int new_app = 0; + int new_card = 0; /* Scan the devices to find new device(s). */ err = apdu_dev_list_start (opt.reader_port, &l); if (err) { - npth_mutex_unlock (&app_list_lock); + npth_mutex_unlock (&card_list_lock); return err; } @@ -496,7 +532,7 @@ select_application (ctrl_t ctrl, const char *name, app_t *r_app, int slot; int periodical_check_needed_this; - slot = apdu_open_reader (l, !app_top); + slot = apdu_open_reader (l, !card_top); if (slot < 0) break; @@ -510,7 +546,7 @@ select_application (ctrl_t ctrl, const char *name, app_t *r_app, { err = app_new_register (slot, ctrl, name, periodical_check_needed_this); - new_app++; + new_card++; } if (err) @@ -520,43 +556,43 @@ select_application (ctrl_t ctrl, const char *name, app_t *r_app, apdu_dev_list_finish (l); /* If new device(s), kick the scdaemon loop. */ - if (new_app) + if (new_card) scd_kick_the_loop (); } - for (a = app_top; a; a = a->next) + for (card = card_top; card; card = card->next) { - lock_app (a, ctrl); + lock_card (card, ctrl); if (serialno_bin == NULL) break; - if (a->serialnolen == serialno_bin_len - && !memcmp (a->serialno, serialno_bin, a->serialnolen)) + if (card->serialnolen == serialno_bin_len + && !memcmp (card->serialno, serialno_bin, card->serialnolen)) break; - unlock_app (a); - a_prev = a; + unlock_card (card); + card_prev = card; } - if (a) + if (card) { - err = check_conflict (a, name); + err = check_conflict (card, name); if (!err) { - /* Note: We do not use app_ref as we are already locked. */ - a->ref_count++; - *r_app = a; - if (a_prev) + /* Note: We do not use card_ref as we are already locked. */ + card->ref_count++; + *r_card = card; + if (card_prev) { - a_prev->next = a->next; - a->next = app_top; - app_top = a; + card_prev->next = card->next; + card->next = card_top; + card_top = card; } } - unlock_app (a); + unlock_card (card); } else err = gpg_error (GPG_ERR_ENODEV); - npth_mutex_unlock (&app_list_lock); + npth_mutex_unlock (&card_list_lock); return err; } @@ -588,85 +624,88 @@ get_supported_applications (void) /* Deallocate the application. */ static void -deallocate_app (app_t app) +deallocate_card (card_t card) { - app_t a, a_prev = NULL; + card_t c, c_prev = NULL; + app_t a, anext; - for (a = app_top; a; a = a->next) - if (a == app) + for (c = card_top; c; c = c->next) + if (c == card) { - if (a_prev == NULL) - app_top = a->next; + if (c_prev == NULL) + card_top = c->next; else - a_prev->next = a->next; + c_prev->next = c->next; break; } else - a_prev = a; + c_prev = c; - if (app->ref_count) - log_error ("trying to release still used app context (%d)\n", - app->ref_count); + if (card->ref_count) + log_error ("releasing still used card context (%d)\n", card->ref_count); - if (app->fnc.deinit) + for (a = card->app; a; a = anext) { - app->fnc.deinit (app); - app->fnc.deinit = NULL; + if (a->fnc.deinit) + { + a->fnc.deinit (a); + a->fnc.deinit = NULL; + } + anext = a->next; + xfree (a); } - xfree (app->serialno); + xfree (card->serialno); - unlock_app (app); - xfree (app); + unlock_card (card); + xfree (card); } -/* Increment the reference counter for APP. Returns the APP. */ -app_t -app_ref (app_t app) +/* Increment the reference counter of CARD. Returns CARD. */ +card_t +card_ref (card_t card) { - lock_app (app, NULL); - ++app->ref_count; - unlock_app (app); - return app; + lock_card (card, NULL); + ++card->ref_count; + unlock_card (card); + return card; } -/* Decrement the reference counter for APP. Note that we are using - * reference counting to track the users of the application and are - * deferring the actual deallocation to allow for a later reuse by a - * new connection. Using NULL for APP is a no-op. */ +/* Decrement the reference counter for CARD. Note that we are using + * reference counting to track the users of the card's application and + * are deferring the actual deallocation to allow for a later reuse by + * a new connection. Using NULL for CARD is a no-op. */ void -app_unref (app_t app) +card_unref (card_t card) { - if (!app) + if (!card) return; - /* We don't deallocate app here. Instead, we keep it. This is + /* We don't deallocate CARD here. Instead, we keep it. This is useful so that a card does not get reset even if only one session is using the card - this way the PIN cache and other cached data are preserved. */ - lock_app (app, NULL); - if (!app->ref_count) - log_bug ("trying to release an already released context\n"); - --app->ref_count; - unlock_app (app); + lock_card (card, NULL); + card_unref_locked (card); + unlock_card (card); } -/* This is the same as app_unref but assumes that APP is already +/* This is the same as card_unref but assumes that CARD is already * locked. */ void -app_unref_locked (app_t app) +card_unref_locked (card_t card) { - if (!app) + if (!card) return; - if (!app->ref_count) - log_bug ("trying to release an already released context\n"); + if (!card->ref_count) + log_bug ("tried to release an already released card context\n"); - --app->ref_count; + --card->ref_count; } @@ -686,30 +725,30 @@ app_unref_locked (app_t app) All other serial number not starting with FF are used as they are. */ gpg_error_t -app_munge_serialno (app_t app) +app_munge_serialno (card_t card) { - if (app->serialnolen && app->serialno[0] == 0xff) + if (card->serialnolen && card->serialno[0] == 0xff) { /* The serial number starts with our special prefix. This requires that we put our default prefix "FF0000" in front. */ - unsigned char *p = xtrymalloc (app->serialnolen + 3); + unsigned char *p = xtrymalloc (card->serialnolen + 3); if (!p) return gpg_error_from_syserror (); memcpy (p, "\xff\0", 3); - memcpy (p+3, app->serialno, app->serialnolen); - app->serialnolen += 3; - xfree (app->serialno); - app->serialno = p; + memcpy (p+3, card->serialno, card->serialnolen); + card->serialnolen += 3; + xfree (card->serialno); + card->serialno = p; } - else if (!app->serialnolen) + else if (!card->serialnolen) { unsigned char *p = xtrymalloc (3); if (!p) return gpg_error_from_syserror (); memcpy (p, "\xff\x7f", 3); - app->serialnolen = 3; - xfree (app->serialno); - app->serialno = p; + card->serialnolen = 3; + xfree (card->serialno); + card->serialno = p; } return 0; } @@ -720,52 +759,66 @@ app_munge_serialno (app_t app) returned as a malloced string (hex encoded) in SERIAL. Caller must free SERIAL unless the function returns an error. */ char * -app_get_serialno (app_t app) +card_get_serialno (card_t card) { char *serial; - if (!app) + if (!card) return NULL; - if (!app->serialnolen) + if (!card->serialnolen) serial = xtrystrdup ("FF7F00"); else - serial = bin2hex (app->serialno, app->serialnolen, NULL); + serial = bin2hex (card->serialno, card->serialnolen, NULL); return serial; } +/* Same as card_get_serialno but takes an APP object. */ +char * +app_get_serialno (app_t app) +{ + if (!app || !app->card) + return NULL; + return card_get_serialno (app->card); +} + /* Write out the application specific status lines for the LEARN command. */ gpg_error_t -app_write_learn_status (app_t app, ctrl_t ctrl, unsigned int flags) +app_write_learn_status (card_t card, ctrl_t ctrl, unsigned int flags) { gpg_error_t err; + app_t app; - if (!app) + if (!card) return gpg_error (GPG_ERR_INV_VALUE); + if (!card->app) + return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); + app = card->app; if (!app->fnc.learn_status) return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); /* We do not send CARD and APPTYPE if only keypairinfo is requested. */ if (!(flags &1)) { - if (app->cardtype) - send_status_direct (ctrl, "CARDTYPE", app->cardtype); - if (app->cardversion) - send_status_printf (ctrl, "CARDVERSION", "%X", app->cardversion); + if (card->cardtype) + send_status_direct (ctrl, "CARDTYPE", card->cardtype); + if (card->cardversion) + send_status_printf (ctrl, "CARDVERSION", "%X", card->cardversion); if (app->apptype) send_status_direct (ctrl, "APPTYPE", app->apptype); if (app->appversion) send_status_printf (ctrl, "APPVERSION", "%X", app->appversion); + /* FIXME: Send infor for the otehr active apps of the card? */ } - err = lock_app (app, ctrl); + err = lock_card (card, ctrl); if (err) return err; - err = app->fnc.learn_status (app, ctrl, flags); - unlock_app (app); + err = app->fnc.learn_status (card->app, ctrl, flags); + unlock_card (card); return err; } @@ -775,22 +828,22 @@ app_write_learn_status (app_t app, ctrl_t ctrl, unsigned int flags) buffer put into CERT and the length of the certificate put into CERTLEN. */ gpg_error_t -app_readcert (app_t app, ctrl_t ctrl, const char *certid, +app_readcert (card_t card, ctrl_t ctrl, const char *certid, unsigned char **cert, size_t *certlen) { gpg_error_t err; - if (!app) + if (!card) return gpg_error (GPG_ERR_INV_VALUE); - if (!app->ref_count) + if (!card->ref_count || !card->app) return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); - if (!app->fnc.readcert) + if (!card->app->fnc.readcert) return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); - err = lock_app (app, ctrl); + err = lock_card (card, ctrl); if (err) return err; - err = app->fnc.readcert (app, certid, cert, certlen); - unlock_app (app); + err = card->app->fnc.readcert (card->app, certid, cert, certlen); + unlock_card (card); return err; } @@ -804,7 +857,7 @@ app_readcert (app_t app, ctrl_t ctrl, const char *certid, * * This function might not be supported by all applications. */ gpg_error_t -app_readkey (app_t app, ctrl_t ctrl, const char *keyid, unsigned int flags, +app_readkey (card_t card, ctrl_t ctrl, const char *keyid, unsigned int flags, unsigned char **pk, size_t *pklen) { gpg_error_t err; @@ -814,47 +867,47 @@ app_readkey (app_t app, ctrl_t ctrl, const char *keyid, unsigned int flags, if (pklen) *pklen = 0; - if (!app || !keyid) + if (!card || !keyid) return gpg_error (GPG_ERR_INV_VALUE); - if (!app->ref_count) + if (!card->ref_count || !card->app) return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); - if (!app->fnc.readkey) + if (!card->app->fnc.readkey) return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); - err = lock_app (app, ctrl); + err = lock_card (card, ctrl); if (err) return err; - err= app->fnc.readkey (app, ctrl, keyid, flags, pk, pklen); - unlock_app (app); + err = card->app->fnc.readkey (card->app, ctrl, keyid, flags, pk, pklen); + unlock_card (card); return err; } /* Perform a GETATTR operation. */ gpg_error_t -app_getattr (app_t app, ctrl_t ctrl, const char *name) +app_getattr (card_t card, ctrl_t ctrl, const char *name) { gpg_error_t err; - if (!app || !name || !*name) + if (!card || !name || !*name) return gpg_error (GPG_ERR_INV_VALUE); - if (!app->ref_count) + if (!card->ref_count || !card->app) return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); - if (app->cardtype && name && !strcmp (name, "CARDTYPE")) + if (card->cardtype && name && !strcmp (name, "CARDTYPE")) { - send_status_direct (ctrl, "CARDTYPE", app->cardtype); + send_status_direct (ctrl, "CARDTYPE", card->cardtype); return 0; } - if (app->apptype && name && !strcmp (name, "APPTYPE")) + if (card->app->apptype && name && !strcmp (name, "APPTYPE")) { - send_status_direct (ctrl, "APPTYPE", app->apptype); + send_status_direct (ctrl, "APPTYPE", card->app->apptype); return 0; } if (name && !strcmp (name, "SERIALNO")) { char *serial; - serial = app_get_serialno (app); + serial = card_get_serialno (card); if (!serial) return gpg_error (GPG_ERR_INV_VALUE); @@ -863,44 +916,47 @@ app_getattr (app_t app, ctrl_t ctrl, const char *name) return 0; } - if (!app->fnc.getattr) + if (!card->app->fnc.getattr) return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); - err = lock_app (app, ctrl); + err = lock_card (card, ctrl); if (err) return err; - err = app->fnc.getattr (app, ctrl, name); - unlock_app (app); + err = card->app->fnc.getattr (card->app, ctrl, name); + unlock_card (card); return err; } + /* Perform a SETATTR operation. */ gpg_error_t -app_setattr (app_t app, ctrl_t ctrl, const char *name, +app_setattr (card_t card, ctrl_t ctrl, const char *name, gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg, const unsigned char *value, size_t valuelen) { gpg_error_t err; - if (!app || !name || !*name || !value) + if (!card || !name || !*name || !value) return gpg_error (GPG_ERR_INV_VALUE); - if (!app->ref_count) + if (!card->ref_count || !card->app) return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); - if (!app->fnc.setattr) + if (!card->app->fnc.setattr) return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); - err = lock_app (app, ctrl); + err = lock_card (card, ctrl); if (err) return err; - err = app->fnc.setattr (app, name, pincb, pincb_arg, value, valuelen); - unlock_app (app); + err = card->app->fnc.setattr (card->app, name, pincb, pincb_arg, + value, valuelen); + unlock_card (card); return err; } + /* Create the signature and return the allocated result in OUTDATA. If a PIN is required the PINCB will be used to ask for the PIN; it should return the PIN in an allocated buffer and put it into PIN. */ gpg_error_t -app_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo, +app_sign (card_t card, ctrl_t ctrl, const char *keyidstr, int hashalgo, gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg, const void *indata, size_t indatalen, @@ -908,31 +964,32 @@ app_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo, { gpg_error_t err; - if (!app || !indata || !indatalen || !outdata || !outdatalen || !pincb) + if (!card || !indata || !indatalen || !outdata || !outdatalen || !pincb) return gpg_error (GPG_ERR_INV_VALUE); - if (!app->ref_count) + if (!card->ref_count || !card->app) return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); - if (!app->fnc.sign) + if (!card->app->fnc.sign) return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); - err = lock_app (app, ctrl); + err = lock_card (card, ctrl); if (err) return err; - err = app->fnc.sign (app, keyidstr, hashalgo, - pincb, pincb_arg, - indata, indatalen, - outdata, outdatalen); - unlock_app (app); + err = card->app->fnc.sign (card->app, keyidstr, hashalgo, + pincb, pincb_arg, + indata, indatalen, + outdata, outdatalen); + unlock_card (card); if (opt.verbose) log_info ("operation sign result: %s\n", gpg_strerror (err)); return err; } + /* Create the signature using the INTERNAL AUTHENTICATE command and return the allocated result in OUTDATA. If a PIN is required the PINCB will be used to ask for the PIN; it should return the PIN in an allocated buffer and put it into PIN. */ gpg_error_t -app_auth (app_t app, ctrl_t ctrl, const char *keyidstr, +app_auth (card_t card, ctrl_t ctrl, const char *keyidstr, gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg, const void *indata, size_t indatalen, @@ -940,20 +997,20 @@ app_auth (app_t app, ctrl_t ctrl, const char *keyidstr, { gpg_error_t err; - if (!app || !indata || !indatalen || !outdata || !outdatalen || !pincb) + if (!card || !indata || !indatalen || !outdata || !outdatalen || !pincb) return gpg_error (GPG_ERR_INV_VALUE); - if (!app->ref_count) + if (!card->ref_count || !card->app) return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); - if (!app->fnc.auth) + if (!card->app->fnc.auth) return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); - err = lock_app (app, ctrl); + err = lock_card (card, ctrl); if (err) return err; - err = app->fnc.auth (app, keyidstr, - pincb, pincb_arg, - indata, indatalen, - outdata, outdatalen); - unlock_app (app); + err = card->app->fnc.auth (card->app, keyidstr, + pincb, pincb_arg, + indata, indatalen, + outdata, outdatalen); + unlock_card (card); if (opt.verbose) log_info ("operation auth result: %s\n", gpg_strerror (err)); return err; @@ -964,7 +1021,7 @@ app_auth (app_t app, ctrl_t ctrl, const char *keyidstr, If a PIN is required the PINCB will be used to ask for the PIN; it should return the PIN in an allocated buffer and put it into PIN. */ gpg_error_t -app_decipher (app_t app, ctrl_t ctrl, const char *keyidstr, +app_decipher (card_t card, ctrl_t ctrl, const char *keyidstr, gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg, const void *indata, size_t indatalen, @@ -975,21 +1032,21 @@ app_decipher (app_t app, ctrl_t ctrl, const char *keyidstr, *r_info = 0; - if (!app || !indata || !indatalen || !outdata || !outdatalen || !pincb) + if (!card || !indata || !indatalen || !outdata || !outdatalen || !pincb) return gpg_error (GPG_ERR_INV_VALUE); - if (!app->ref_count) + if (!card->ref_count || !card->app) return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); - if (!app->fnc.decipher) + if (!card->app->fnc.decipher) return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); - err = lock_app (app, ctrl); + err = lock_card (card, ctrl); if (err) return err; - err = app->fnc.decipher (app, keyidstr, - pincb, pincb_arg, - indata, indatalen, - outdata, outdatalen, - r_info); - unlock_app (app); + err = card->app->fnc.decipher (card->app, keyidstr, + pincb, pincb_arg, + indata, indatalen, + outdata, outdatalen, + r_info); + unlock_card (card); if (opt.verbose) log_info ("operation decipher result: %s\n", gpg_strerror (err)); return err; @@ -998,26 +1055,26 @@ app_decipher (app_t app, ctrl_t ctrl, const char *keyidstr, /* Perform the WRITECERT operation. */ gpg_error_t -app_writecert (app_t app, ctrl_t ctrl, - const char *certidstr, - gpg_error_t (*pincb)(void*, const char *, char **), - void *pincb_arg, - const unsigned char *data, size_t datalen) +app_writecert (card_t card, ctrl_t ctrl, + const char *certidstr, + gpg_error_t (*pincb)(void*, const char *, char **), + void *pincb_arg, + const unsigned char *data, size_t datalen) { gpg_error_t err; - if (!app || !certidstr || !*certidstr || !pincb) + if (!card || !certidstr || !*certidstr || !pincb) return gpg_error (GPG_ERR_INV_VALUE); - if (!app->ref_count) + if (!card->ref_count || !card->app) return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); - if (!app->fnc.writecert) + if (!card->app->fnc.writecert) return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); - err = lock_app (app, ctrl); + err = lock_card (card, ctrl); if (err) return err; - err = app->fnc.writecert (app, ctrl, certidstr, - pincb, pincb_arg, data, datalen); - unlock_app (app); + err = card->app->fnc.writecert (card->app, ctrl, certidstr, + pincb, pincb_arg, data, datalen); + unlock_card (card); if (opt.verbose) log_info ("operation writecert result: %s\n", gpg_strerror (err)); return err; @@ -1026,7 +1083,7 @@ app_writecert (app_t app, ctrl_t ctrl, /* Perform the WRITEKEY operation. */ gpg_error_t -app_writekey (app_t app, ctrl_t ctrl, +app_writekey (card_t card, ctrl_t ctrl, const char *keyidstr, unsigned int flags, gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg, @@ -1034,18 +1091,18 @@ app_writekey (app_t app, ctrl_t ctrl, { gpg_error_t err; - if (!app || !keyidstr || !*keyidstr || !pincb) + if (!card || !keyidstr || !*keyidstr || !pincb) return gpg_error (GPG_ERR_INV_VALUE); - if (!app->ref_count) + if (!card->ref_count || !card->app) return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); - if (!app->fnc.writekey) + if (!card->app->fnc.writekey) return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); - err = lock_app (app, ctrl); + err = lock_card (card, ctrl); if (err) return err; - err = app->fnc.writekey (app, ctrl, keyidstr, flags, - pincb, pincb_arg, keydata, keydatalen); - unlock_app (app); + err = card->app->fnc.writekey (card->app, ctrl, keyidstr, flags, + pincb, pincb_arg, keydata, keydatalen); + unlock_card (card); if (opt.verbose) log_info ("operation writekey result: %s\n", gpg_strerror (err)); return err; @@ -1054,25 +1111,25 @@ app_writekey (app_t app, ctrl_t ctrl, /* Perform a SETATTR operation. */ gpg_error_t -app_genkey (app_t app, ctrl_t ctrl, const char *keynostr, +app_genkey (card_t card, ctrl_t ctrl, const char *keynostr, const char *keytype, unsigned int flags, time_t createtime, gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg) { gpg_error_t err; - if (!app || !keynostr || !*keynostr || !pincb) + if (!card || !keynostr || !*keynostr || !pincb) return gpg_error (GPG_ERR_INV_VALUE); - if (!app->ref_count) + if (!card->ref_count || !card->app) return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); - if (!app->fnc.genkey) + if (!card->app->fnc.genkey) return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); - err = lock_app (app, ctrl); + err = lock_card (card, ctrl); if (err) return err; - err = app->fnc.genkey (app, ctrl, keynostr, keytype, flags, - createtime, pincb, pincb_arg); - unlock_app (app); + err = card->app->fnc.genkey (card->app, ctrl, keynostr, keytype, flags, + createtime, pincb, pincb_arg); + unlock_card (card); if (opt.verbose) log_info ("operation genkey result: %s\n", gpg_strerror (err)); return err; @@ -1083,44 +1140,45 @@ app_genkey (app_t app, ctrl_t ctrl, const char *keynostr, directly accesses the card without any application specific wrapper. */ gpg_error_t -app_get_challenge (app_t app, ctrl_t ctrl, size_t nbytes, unsigned char *buffer) +app_get_challenge (card_t card, ctrl_t ctrl, + size_t nbytes, unsigned char *buffer) { gpg_error_t err; - if (!app || !nbytes || !buffer) + if (!card || !nbytes || !buffer) return gpg_error (GPG_ERR_INV_VALUE); - if (!app->ref_count) + if (!card->ref_count) return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); - err = lock_app (app, ctrl); + err = lock_card (card, ctrl); if (err) return err; - err = iso7816_get_challenge (app->slot, nbytes, buffer); - unlock_app (app); + err = iso7816_get_challenge (card->slot, nbytes, buffer); + unlock_card (card); return err; } - /* Perform a CHANGE REFERENCE DATA or RESET RETRY COUNTER operation. */ gpg_error_t -app_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr, +app_change_pin (card_t card, ctrl_t ctrl, const char *chvnostr, unsigned int flags, gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg) { gpg_error_t err; - if (!app || !chvnostr || !*chvnostr || !pincb) + if (!card || !chvnostr || !*chvnostr || !pincb) return gpg_error (GPG_ERR_INV_VALUE); - if (!app->ref_count) + if (!card->ref_count || !card->app) return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); - if (!app->fnc.change_pin) + if (!card->app->fnc.change_pin) return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); - err = lock_app (app, ctrl); + err = lock_card (card, ctrl); if (err) return err; - err = app->fnc.change_pin (app, ctrl, chvnostr, flags, pincb, pincb_arg); - unlock_app (app); + err = card->app->fnc.change_pin (card->app, ctrl, + chvnostr, flags, pincb, pincb_arg); + unlock_card (card); if (opt.verbose) log_info ("operation change_pin result: %s\n", gpg_strerror (err)); return err; @@ -1131,28 +1189,29 @@ app_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr, be used to initialize a the PIN cache for long lasting other operations. Its use is highly application dependent. */ gpg_error_t -app_check_pin (app_t app, ctrl_t ctrl, const char *keyidstr, +app_check_pin (card_t card, ctrl_t ctrl, const char *keyidstr, gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg) { gpg_error_t err; - if (!app || !keyidstr || !*keyidstr || !pincb) + if (!card || !keyidstr || !*keyidstr || !pincb) return gpg_error (GPG_ERR_INV_VALUE); - if (!app->ref_count) + if (!card->ref_count || !card->app) return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); - if (!app->fnc.check_pin) + if (!card->app->fnc.check_pin) return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); - err = lock_app (app, ctrl); + err = lock_card (card, ctrl); if (err) return err; - err = app->fnc.check_pin (app, keyidstr, pincb, pincb_arg); - unlock_app (app); + err = card->app->fnc.check_pin (card->app, keyidstr, pincb, pincb_arg); + unlock_card (card); if (opt.verbose) log_info ("operation check_pin result: %s\n", gpg_strerror (err)); return err; } + static void report_change (int slot, int old_status, int cur_status) { @@ -1212,26 +1271,27 @@ report_change (int slot, int old_status, int cur_status) xfree (homestr); } + int scd_update_reader_status_file (void) { - app_t a, app_next; + card_t card, card_next; int periodical_check_needed = 0; - npth_mutex_lock (&app_list_lock); - for (a = app_top; a; a = app_next) + npth_mutex_lock (&card_list_lock); + for (card = card_top; card; card = card_next) { int sw; unsigned int status; - lock_app (a, NULL); - app_next = a->next; + lock_card (card, NULL); + card_next = card->next; - if (a->reset_requested) + if (card->reset_requested) status = 0; else { - sw = apdu_get_status (a->slot, 0, &status); + sw = apdu_get_status (card->slot, 0, &status); if (sw == SW_HOST_NO_READER) { /* Most likely the _reader_ has been unplugged. */ @@ -1240,40 +1300,41 @@ scd_update_reader_status_file (void) else if (sw) { /* Get status failed. Ignore that. */ - if (a->periodical_check_needed) + if (card->periodical_check_needed) periodical_check_needed = 1; - unlock_app (a); + unlock_card (card); continue; } } - if (a->card_status != status) + if (card->card_status != status) { - report_change (a->slot, a->card_status, status); - send_client_notifications (a, status == 0); + report_change (card->slot, card->card_status, status); + send_client_notifications (card, status == 0); if (status == 0) { - log_debug ("Removal of a card: %d\n", a->slot); - apdu_close_reader (a->slot); - deallocate_app (a); + log_debug ("Removal of a card: %d\n", card->slot); + apdu_close_reader (card->slot); + deallocate_card (card); } else { - a->card_status = status; - if (a->periodical_check_needed) + card->card_status = status; + if (card->periodical_check_needed) periodical_check_needed = 1; - unlock_app (a); + unlock_card (card); } } else { - if (a->periodical_check_needed) + if (card->periodical_check_needed) periodical_check_needed = 1; - unlock_app (a); + unlock_card (card); } } - npth_mutex_unlock (&app_list_lock); + + npth_mutex_unlock (&card_list_lock); return periodical_check_needed; } @@ -1287,7 +1348,7 @@ initialize_module_command (void) { gpg_error_t err; - if (npth_mutex_init (&app_list_lock, NULL)) + if (npth_mutex_init (&card_list_lock, NULL)) { err = gpg_error_from_syserror (); log_error ("app: error initializing mutex: %s\n", gpg_strerror (err)); @@ -1297,24 +1358,26 @@ initialize_module_command (void) return apdu_init (); } + void app_send_card_list (ctrl_t ctrl) { - app_t a; + card_t c; char buf[65]; - npth_mutex_lock (&app_list_lock); - for (a = app_top; a; a = a->next) + npth_mutex_lock (&card_list_lock); + for (c = card_top; c; c = c->next) { - if (DIM (buf) < 2 * a->serialnolen + 1) + if (DIM (buf) < 2 * c->serialnolen + 1) continue; - bin2hex (a->serialno, a->serialnolen, buf); + bin2hex (c->serialno, c->serialnolen, buf); send_status_direct (ctrl, "SERIALNO", buf); } - npth_mutex_unlock (&app_list_lock); + npth_mutex_unlock (&card_list_lock); } + /* Execute an action for each app. ACTION can be one of: * * - KEYGRIP_ACTION_SEND_DATA @@ -1338,18 +1401,24 @@ app_send_card_list (ctrl_t ctrl) * does not emit any status or data lines. If no key with that * keygrip is available or KEYGRIP_STR is NULL, NULL is returned. */ -app_t +card_t app_do_with_keygrip (ctrl_t ctrl, int action, const char *keygrip_str) { + card_t c; app_t a; - npth_mutex_lock (&app_list_lock); + npth_mutex_lock (&card_list_lock); - for (a = app_top; a; a = a->next) - if (a->fnc.with_keygrip - && !a->fnc.with_keygrip (a, ctrl, action, keygrip_str)) - break; + for (c = card_top; c; c = c->next) + for (a = c->app; a; a = a->next) + if (a->fnc.with_keygrip + && !a->fnc.with_keygrip (a, ctrl, action, keygrip_str)) + break; + /* FIXME: Add app switching logic. The above code assumes that the + * actions can be performend without switching. This needs to be + * checked. For a lookup we also need to reorder the apps so that + * the selected one will be used. */ - npth_mutex_unlock (&app_list_lock); - return a; + npth_mutex_unlock (&card_list_lock); + return c; } diff --git a/scd/command.c b/scd/command.c index 1929c33f1..1c8338446 100644 --- a/scd/command.c +++ b/scd/command.c @@ -145,10 +145,10 @@ hex_to_buffer (const char *string, size_t *r_length) static void do_reset (ctrl_t ctrl, int send_reset) { - app_t app = ctrl->app_ctx; + card_t card = ctrl->card_ctx; - if (app) - app_reset (app, ctrl, IS_LOCKED (ctrl)? 0: send_reset); + if (card) + card_reset (card, ctrl, IS_LOCKED (ctrl)? 0: send_reset); /* If we hold a lock, unlock now. */ if (locked_session && ctrl->server_local == locked_session) @@ -157,6 +157,8 @@ do_reset (ctrl_t ctrl, int send_reset) log_info ("implicitly unlocking due to RESET\n"); } } + + static gpg_error_t reset_notify (assuan_context_t ctx, char *line) @@ -211,10 +213,10 @@ open_card (ctrl_t ctrl) if ( IS_LOCKED (ctrl) ) return gpg_error (GPG_ERR_LOCKED); - if (ctrl->app_ctx) + if (ctrl->card_ctx) return 0; - return select_application (ctrl, NULL, &ctrl->app_ctx, 0, NULL, 0); + return select_application (ctrl, NULL, &ctrl->card_ctx, 0, NULL, 0); } /* Explicitly open a card for a specific use of APPTYPE or SERIALNO. */ @@ -224,22 +226,24 @@ open_card_with_request (ctrl_t ctrl, const char *apptype, const char *serialno) gpg_error_t err; unsigned char *serialno_bin = NULL; size_t serialno_bin_len = 0; - app_t app = ctrl->app_ctx; + card_t card = ctrl->card_ctx; /* If we are already initialized for one specific application we need to check that the client didn't requested a specific application different from the one in use before we continue. */ - if (apptype && ctrl->app_ctx) - return check_application_conflict (apptype, ctrl->app_ctx); + /* FIXME: Extend to allow switching between apps. */ + if (apptype && ctrl->card_ctx) + return check_application_conflict (apptype, ctrl->card_ctx); - /* Re-scan USB devices. Release APP, before the scan. */ - ctrl->app_ctx = NULL; - app_unref (app); + /* Re-scan USB devices. Release CARD, before the scan. */ + /* FIXME: Is a card_unref sufficient or do we need to deallocate? */ + ctrl->card_ctx = NULL; + card_unref (card); if (serialno) serialno_bin = hex_to_buffer (serialno, &serialno_bin_len); - err = select_application (ctrl, apptype, &ctrl->app_ctx, 1, + err = select_application (ctrl, apptype, &ctrl->card_ctx, 1, serialno_bin, serialno_bin_len); xfree (serialno_bin); @@ -313,7 +317,7 @@ cmd_serialno (assuan_context_t ctx, char *line) c->server_local->card_removed = 0; } - serial = app_get_serialno (ctrl->app_ctx); + serial = card_get_serialno (ctrl->card_ctx); if (!serial) return gpg_error (GPG_ERR_INV_VALUE); @@ -411,18 +415,18 @@ cmd_learn (assuan_context_t ctx, char *line) { const char *reader; char *serial; - app_t app = ctrl->app_ctx; + card_t card = ctrl->card_ctx; - if (!app) + if (!card) return gpg_error (GPG_ERR_CARD_NOT_PRESENT); - reader = apdu_get_reader_name (app->slot); + reader = apdu_get_reader_name (card->slot); if (!reader) return out_of_core (); send_status_direct (ctrl, "READER", reader); /* No need to free the string of READER. */ - serial = app_get_serialno (ctrl->app_ctx); + serial = card_get_serialno (ctrl->card_ctx); if (!serial) return gpg_error (GPG_ERR_INV_VALUE); @@ -461,7 +465,7 @@ cmd_learn (assuan_context_t ctx, char *line) /* Let the application print out its collection of useful status information. */ if (!rc) - rc = app_write_learn_status (ctrl->app_ctx, ctrl, only_keypairinfo); + rc = app_write_learn_status (ctrl->card_ctx, ctrl, only_keypairinfo); return rc; } @@ -484,7 +488,7 @@ cmd_readcert (assuan_context_t ctx, char *line) return rc; line = xstrdup (line); /* Need a copy of the line. */ - rc = app_readcert (ctrl->app_ctx, ctrl, line, &cert, &ncert); + rc = app_readcert (ctrl->card_ctx, ctrl, line, &cert, &ncert); if (rc) log_error ("app_readcert failed: %s\n", gpg_strerror (rc)); xfree (line); @@ -536,7 +540,7 @@ cmd_readkey (assuan_context_t ctx, char *line) /* If the application supports the READKEY function we use that. Otherwise we use the old way by extracting it from the certificate. */ - rc = app_readkey (ctrl->app_ctx, ctrl, line, + rc = app_readkey (ctrl->card_ctx, ctrl, line, opt_info? APP_READKEY_FLAG_INFO : 0, opt_nokey? NULL : &pk, &pklen); if (!rc) @@ -545,7 +549,7 @@ cmd_readkey (assuan_context_t ctx, char *line) || gpg_err_code (rc) == GPG_ERR_NOT_FOUND) { /* Fall back to certificate reading. */ - rc = app_readcert (ctrl->app_ctx, ctrl, line, &cert, &ncert); + rc = app_readcert (ctrl->card_ctx, ctrl, line, &cert, &ncert); if (rc) { log_error ("app_readcert failed: %s\n", gpg_strerror (rc)); @@ -757,7 +761,7 @@ cmd_pksign (assuan_context_t ctx, char *line) size_t outdatalen; char *keyidstr; int hash_algo; - app_t app; + card_t card; int direct = 0; if (has_option (line, "--hash=rmd160")) @@ -791,27 +795,27 @@ cmd_pksign (assuan_context_t ctx, char *line) if (!keyidstr) return out_of_core (); - /* When it's a keygrip, we directly use APP, with no change of - ctrl->app_ctx. */ + /* When it's a keygrip, we directly use the card, with no change of + ctrl->card_ctx. */ if (strlen (keyidstr) == 40) { - app = app_do_with_keygrip (ctrl, KEYGRIP_ACTION_LOOKUP, keyidstr); + card = app_do_with_keygrip (ctrl, KEYGRIP_ACTION_LOOKUP, keyidstr); direct = 1; } else - app = ctrl->app_ctx; + card = ctrl->card_ctx; - if (app) + if (card) { if (direct) - app_ref (app); - rc = app_sign (app, ctrl, + card_ref (card); + rc = app_sign (card, ctrl, keyidstr, hash_algo, pin_cb, ctx, ctrl->in_data.value, ctrl->in_data.valuelen, &outdata, &outdatalen); if (direct) - app_unref (app); + card_unref (card); } else rc = gpg_error (GPG_ERR_NO_SECKEY); @@ -843,13 +847,13 @@ cmd_pkauth (assuan_context_t ctx, char *line) unsigned char *outdata; size_t outdatalen; char *keyidstr; - app_t app; + card_t card; int direct = 0; if ((rc = open_card (ctrl))) return rc; - if (!ctrl->app_ctx) + if (!ctrl->card_ctx) return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); /* We have to use a copy of the key ID because the function may use @@ -859,25 +863,25 @@ cmd_pkauth (assuan_context_t ctx, char *line) if (!keyidstr) return out_of_core (); - /* When it's a keygrip, we directly use APP, with no change of - ctrl->app_ctx. */ + /* When it's a keygrip, we directly use CARD, with no change of + ctrl->card_ctx. */ if (strlen (keyidstr) == 40) { - app = app_do_with_keygrip (ctrl, KEYGRIP_ACTION_LOOKUP, keyidstr); + card = app_do_with_keygrip (ctrl, KEYGRIP_ACTION_LOOKUP, keyidstr); direct = 1; } else - app = ctrl->app_ctx; + card = ctrl->card_ctx; - if (app) + if (card) { if (direct) - app_ref (app); - rc = app_auth (app, ctrl, keyidstr, pin_cb, ctx, + card_ref (card); + rc = app_auth (card, ctrl, keyidstr, pin_cb, ctx, ctrl->in_data.value, ctrl->in_data.valuelen, &outdata, &outdatalen); if (direct) - app_unref (app); + card_unref (card); } else rc = gpg_error (GPG_ERR_NO_SECKEY); @@ -910,7 +914,7 @@ cmd_pkdecrypt (assuan_context_t ctx, char *line) size_t outdatalen; char *keyidstr; unsigned int infoflags; - app_t app; + card_t card; int direct = 0; if ((rc = open_card (ctrl))) @@ -920,25 +924,25 @@ cmd_pkdecrypt (assuan_context_t ctx, char *line) if (!keyidstr) return out_of_core (); - /* When it's a keygrip, we directly use APP, with no change of - ctrl->app_ctx. */ + /* When it's a keygrip, we directly use CARD, with no change of + ctrl->card_ctx. */ if (strlen (keyidstr) == 40) { - app = app_do_with_keygrip (ctrl, KEYGRIP_ACTION_LOOKUP, keyidstr); + card = app_do_with_keygrip (ctrl, KEYGRIP_ACTION_LOOKUP, keyidstr); direct = 1; } else - app = ctrl->app_ctx; + card = ctrl->card_ctx; - if (app) + if (card) { if (direct) - app_ref (app); - rc = app_decipher (ctrl->app_ctx, ctrl, keyidstr, pin_cb, ctx, + card_ref (card); + rc = app_decipher (card, ctrl, keyidstr, pin_cb, ctx, ctrl->in_data.value, ctrl->in_data.valuelen, &outdata, &outdatalen, &infoflags); if (direct) - app_unref (app); + card_unref (card); } else rc = gpg_error (GPG_ERR_NO_SECKEY); @@ -999,7 +1003,7 @@ cmd_getattr (assuan_context_t ctx, char *line) /* FIXME: Applications should not return sensitive data if the card is locked. */ - rc = app_getattr (ctrl->app_ctx, ctrl, keyword); + rc = app_getattr (ctrl->card_ctx, ctrl, keyword); return rc; } @@ -1061,7 +1065,7 @@ cmd_setattr (assuan_context_t ctx, char *orig_line) assuan_end_confidential (ctx); if (!err) { - err = app_setattr (ctrl->app_ctx, ctrl, keyword, pin_cb, ctx, + err = app_setattr (ctrl->card_ctx, ctrl, keyword, pin_cb, ctx, value, nbytes); wipememory (value, nbytes); xfree (value); @@ -1071,7 +1075,7 @@ cmd_setattr (assuan_context_t ctx, char *orig_line) else { nbytes = percent_plus_unescape_inplace (line, 0); - err = app_setattr (ctrl->app_ctx, ctrl, keyword, pin_cb, ctx, + err = app_setattr (ctrl->card_ctx, ctrl, keyword, pin_cb, ctx, (const unsigned char*)line, nbytes); } @@ -1112,7 +1116,7 @@ cmd_writecert (assuan_context_t ctx, char *line) if ((rc = open_card (ctrl))) return rc; - if (!ctrl->app_ctx) + if (!ctrl->card_ctx) return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); certid = xtrystrdup (certid); @@ -1129,7 +1133,7 @@ cmd_writecert (assuan_context_t ctx, char *line) } /* Write the certificate to the card. */ - rc = app_writecert (ctrl->app_ctx, ctrl, certid, + rc = app_writecert (ctrl->card_ctx, ctrl, certid, pin_cb, ctx, certdata, certdatalen); xfree (certid); xfree (certdata); @@ -1174,7 +1178,7 @@ cmd_writekey (assuan_context_t ctx, char *line) if ((rc = open_card (ctrl))) return rc; - if (!ctrl->app_ctx) + if (!ctrl->card_ctx) return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); keyid = xtrystrdup (keyid); @@ -1192,7 +1196,7 @@ cmd_writekey (assuan_context_t ctx, char *line) } /* Write the key to the card. */ - rc = app_writekey (ctrl->app_ctx, ctrl, keyid, force? 1:0, + rc = app_writekey (ctrl->card_ctx, ctrl, keyid, force? 1:0, pin_cb, ctx, keydata, keydatalen); xfree (keyid); xfree (keydata); @@ -1266,7 +1270,7 @@ cmd_genkey (assuan_context_t ctx, char *line) if ((err = open_card (ctrl))) goto leave; - if (!ctrl->app_ctx) + if (!ctrl->card_ctx) return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); keyref = keyref_buffer = xtrystrdup (keyref); @@ -1275,7 +1279,7 @@ cmd_genkey (assuan_context_t ctx, char *line) err = gpg_error_from_syserror (); goto leave; } - err = app_genkey (ctrl->app_ctx, ctrl, keyref, opt_algo, + err = app_genkey (ctrl->card_ctx, ctrl, keyref, opt_algo, force? APP_GENKEY_FLAG_FORCE : 0, timestamp, pin_cb, ctx); @@ -1310,14 +1314,14 @@ cmd_random (assuan_context_t ctx, char *line) if ((rc = open_card (ctrl))) return rc; - if (!ctrl->app_ctx) + if (!ctrl->card_ctx) return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); buffer = xtrymalloc (nbytes); if (!buffer) return out_of_core (); - rc = app_get_challenge (ctrl->app_ctx, ctrl, nbytes, buffer); + rc = app_get_challenge (ctrl->card_ctx, ctrl, nbytes, buffer); if (!rc) { rc = assuan_send_data (ctx, buffer, nbytes); @@ -1371,13 +1375,13 @@ cmd_passwd (assuan_context_t ctx, char *line) if ((rc = open_card (ctrl))) return rc; - if (!ctrl->app_ctx) + if (!ctrl->card_ctx) return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); chvnostr = xtrystrdup (chvnostr); if (!chvnostr) return out_of_core (); - rc = app_change_pin (ctrl->app_ctx, ctrl, chvnostr, flags, pin_cb, ctx); + rc = app_change_pin (ctrl->card_ctx, ctrl, chvnostr, flags, pin_cb, ctx); if (rc) log_error ("command passwd failed: %s\n", gpg_strerror (rc)); xfree (chvnostr); @@ -1428,7 +1432,7 @@ cmd_checkpin (assuan_context_t ctx, char *line) if ((rc = open_card (ctrl))) return rc; - if (!ctrl->app_ctx) + if (!ctrl->card_ctx) return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); /* We have to use a copy of the key ID because the function may use @@ -1438,7 +1442,7 @@ cmd_checkpin (assuan_context_t ctx, char *line) if (!idstr) return out_of_core (); - rc = app_check_pin (ctrl->app_ctx, ctrl, idstr, pin_cb, ctx); + rc = app_check_pin (ctrl->card_ctx, ctrl, idstr, pin_cb, ctx); xfree (idstr); if (rc) log_error ("app_check_pin failed: %s\n", gpg_strerror (rc)); @@ -1641,14 +1645,14 @@ static gpg_error_t cmd_restart (assuan_context_t ctx, char *line) { ctrl_t ctrl = assuan_get_pointer (ctx); - app_t app = ctrl->app_ctx; + card_t card = ctrl->card_ctx; (void)line; - if (app) + if (card) { - ctrl->app_ctx = NULL; - app_unref (app); + ctrl->card_ctx = NULL; + card_unref (card); } if (locked_session && ctrl->server_local == locked_session) { @@ -1670,10 +1674,10 @@ cmd_disconnect (assuan_context_t ctx, char *line) (void)line; - if (!ctrl->app_ctx) + if (!ctrl->card_ctx) return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); - apdu_disconnect (ctrl->app_ctx->slot); + apdu_disconnect (ctrl->card_ctx->slot); return 0; } @@ -1702,7 +1706,7 @@ static gpg_error_t cmd_apdu (assuan_context_t ctx, char *line) { ctrl_t ctrl = assuan_get_pointer (ctx); - app_t app; + card_t card; int rc; unsigned char *apdu; size_t apdulen; @@ -1732,8 +1736,8 @@ cmd_apdu (assuan_context_t ctx, char *line) if ((rc = open_card (ctrl))) return rc; - app = ctrl->app_ctx; - if (!app) + card = ctrl->card_ctx; + if (!card) return gpg_error (GPG_ERR_CARD_NOT_PRESENT); if (with_atr) @@ -1742,7 +1746,7 @@ cmd_apdu (assuan_context_t ctx, char *line) size_t atrlen; char hexbuf[400]; - atr = apdu_get_atr (app->slot, &atrlen); + atr = apdu_get_atr (card->slot, &atrlen); if (!atr || atrlen > sizeof hexbuf - 2 ) { rc = gpg_error (GPG_ERR_INV_CARD); @@ -1787,7 +1791,7 @@ cmd_apdu (assuan_context_t ctx, char *line) unsigned char *result = NULL; size_t resultlen; - rc = apdu_send_direct (app->slot, exlen, + rc = apdu_send_direct (card->slot, exlen, apdu, apdulen, handle_more, NULL, &result, &resultlen); if (rc) @@ -1851,7 +1855,7 @@ cmd_keyinfo (assuan_context_t ctx, char *line) int action; char *keygrip_str; ctrl_t ctrl = assuan_get_pointer (ctx); - app_t a; + card_t card; list_mode = has_option (line, "--list"); opt_data = has_option (line, "--data"); @@ -1867,9 +1871,9 @@ cmd_keyinfo (assuan_context_t ctx, char *line) else action = KEYGRIP_ACTION_WRITE_STATUS; - a = app_do_with_keygrip (ctrl, action, keygrip_str); + card = app_do_with_keygrip (ctrl, action, keygrip_str); - if (!list_mode && !a) + if (!list_mode && !card) return gpg_error (GPG_ERR_NOT_FOUND); return 0; } @@ -2180,7 +2184,7 @@ popup_prompt (void *opaque, int on) /* Helper to send the clients a status change notification. Note that * this fucntion assumes that APP is already locked. */ void -send_client_notifications (app_t app, int removal) +send_client_notifications (card_t card, int removal) { struct { pid_t pid; @@ -2195,7 +2199,7 @@ send_client_notifications (app_t app, int removal) struct server_local_s *sl; for (sl=session_list; sl; sl = sl->next_session) - if (sl->ctrl_backlink && sl->ctrl_backlink->app_ctx == app) + if (sl->ctrl_backlink && sl->ctrl_backlink->card_ctx == card) { pid_t pid; #ifdef HAVE_W32_SYSTEM @@ -2206,9 +2210,9 @@ send_client_notifications (app_t app, int removal) if (removal) { - sl->ctrl_backlink->app_ctx = NULL; + sl->ctrl_backlink->card_ctx = NULL; sl->card_removed = 1; - app_unref_locked (app); + card_unref_locked (card); } if (!sl->event_signal || !sl->assuan_ctx) diff --git a/scd/scdaemon.h b/scd/scdaemon.h index 7eb08a904..f4a243703 100644 --- a/scd/scdaemon.h +++ b/scd/scdaemon.h @@ -84,6 +84,7 @@ struct #define DBG_READER (opt.debug & DBG_READER_VALUE) struct server_local_s; +struct card_ctx_s; struct app_ctx_s; struct server_control_s @@ -101,7 +102,7 @@ struct server_control_s associated. Note that this is shared with the other connections: All connections accessing the same reader are using the same application context. */ - struct app_ctx_s *app_ctx; + struct card_ctx_s *card_ctx; /* Helper to store the value we are going to sign */ struct @@ -111,6 +112,7 @@ struct server_control_s } in_data; }; +typedef struct card_ctx_s *card_t; typedef struct app_ctx_s *app_t; /*-- scdaemon.c --*/ @@ -130,8 +132,8 @@ void send_keyinfo (ctrl_t ctrl, int data, const char *keygrip_str, void popup_prompt (void *opaque, int on); -/* Take care: this function assumes that APP is locked. */ -void send_client_notifications (app_t app, int removal); +/* Take care: this function assumes that CARD is locked. */ +void send_client_notifications (card_t card, int removal); void scd_kick_the_loop (void); int get_active_connection_count (void); From d5287f43fd4def68901519a4c1d471b81ee86ed0 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Thu, 20 Jun 2019 11:29:27 +0900 Subject: [PATCH 124/169] tools: Fix error handling for gpg-pair-tool. * tools/gpg-pair-tool.c (read_message): Initialize ERR. Signed-off-by: NIIBE Yutaka --- tools/gpg-pair-tool.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/gpg-pair-tool.c b/tools/gpg-pair-tool.c index 347b29d24..9a781def1 100644 --- a/tools/gpg-pair-tool.c +++ b/tools/gpg-pair-tool.c @@ -976,7 +976,7 @@ read_message (unsigned char **r_msg, size_t *r_msglen, int *r_msgtype, static gpg_error_t display_sas (const unsigned char *hash, size_t hashlen, int wait) { - gpg_error_t err; + gpg_error_t err = 0; unsigned long sas = 0; char sasbuf[12]; From 0ccb5ddef18f04b86855530838af4cbb9b8aa30b Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Thu, 20 Jun 2019 15:10:33 +0900 Subject: [PATCH 125/169] po: Update Japanese Translation. Signed-off-by: NIIBE Yutaka --- po/ja.po | 131 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 74 insertions(+), 57 deletions(-) diff --git a/po/ja.po b/po/ja.po index f4f39a091..26c86eca3 100644 --- a/po/ja.po +++ b/po/ja.po @@ -4,13 +4,13 @@ # IIDA Yosiaki , 1999, 2000, 2002, 2003, 2004. # Yoshihiro Kajiki , 1999. # Takashi P.KATOH, 2002. -# NIIBE Yutaka , 2013, 2014, 2015, 2016, 2017, 2018. +# NIIBE Yutaka , 2013, 2014, 2015, 2016, 2017, 2018, 2019. # msgid "" msgstr "" -"Project-Id-Version: gnupg 2.2.13\n" +"Project-Id-Version: gnupg 2.2.16\n" "Report-Msgid-Bugs-To: translations@gnupg.org\n" -"PO-Revision-Date: 2019-04-23 11:50+0900\n" +"PO-Revision-Date: 2019-06-20 13:57+0900\n" "Last-Translator: NIIBE Yutaka \n" "Language-Team: none\n" "Language: ja\n" @@ -242,9 +242,6 @@ msgstr "一時ファイルの書き込みエラー: %s\n" msgid "Enter new passphrase" msgstr "新しいパスフレーズを入力してください" -msgid "Take this one anyway" -msgstr "それでもこれを使います" - #, c-format msgid "" "You have not entered a passphrase!%0AAn empty passphrase is not allowed." @@ -282,6 +279,9 @@ msgstr "" msgid "Warning: You have entered an insecure passphrase." msgstr "警告: 安全とは言えないパスフレーズが入力されました。" +msgid "Take this one anyway" +msgstr "それでもこれを使います" + #, c-format msgid "Please enter the passphrase to%0Aprotect your new key" msgstr "新しい鍵を保護するために、%0Aパスフレーズを入力してください。" @@ -579,7 +579,7 @@ msgid "error reading '%s', line %d: %s\n" msgstr "'%s'の読み込みエラー(行 %d): %s\n" msgid "error reading list of trusted root certificates\n" -msgstr "信用されたルート証明書のリストの読み込みエラ−\n" +msgstr "信用されたルート証明書のリストの読み込みエラー\n" #. TRANSLATORS: This prompt is shown by the Pinentry #. and has one special property: A "%%0A" is used by @@ -676,7 +676,7 @@ msgid "checking created signature failed: %s\n" msgstr "作成された署名の検査に失敗しました: %s\n" msgid "secret key parts are not available\n" -msgstr "秘密部分が得られません\n" +msgstr "秘密鍵部分が利用できません\n" #, c-format msgid "public key algorithm %d (%s) is not supported\n" @@ -731,7 +731,7 @@ msgid "can't connect to '%s': %s\n" msgstr "'%s'へ接続できません: %s\n" msgid "problem setting the gpg-agent options\n" -msgstr "gpg-agentオプションの設定の問題\n" +msgstr "gpg-agentのオプション設定の問題\n" #, c-format msgid "can't disable core dumps: %s\n" @@ -1541,6 +1541,18 @@ msgstr "(フィンガー・プリントで鍵を指定してない限り)\n" msgid "can't do this in batch mode without \"--yes\"\n" msgstr "これは\"--yes\"なしでバッチ・モードではできません\n" +msgid "Note: The public primary key and all its subkeys will be deleted.\n" +msgstr "注意: 主鍵とすべての副鍵の公開鍵が削除されます。\n" + +msgid "Note: Only the shown public subkey will be deleted.\n" +msgstr "注意: 表示されている副鍵の公開鍵だけが削除されます。\n" + +msgid "Note: Only the secret part of the shown primary key will be deleted.\n" +msgstr "注意: 表示されている主鍵の秘密鍵だけが削除されます。\n" + +msgid "Note: Only the secret part of the shown subkey will be deleted.\n" +msgstr "注意: 表示されている副鍵の秘密鍵だけが削除されます。" + msgid "Delete this key from the keyring? (y/N) " msgstr "この鍵を鍵リングから削除しますか? (y/N) " @@ -1557,6 +1569,10 @@ msgstr "鍵" msgid "subkey" msgstr "副鍵: " +#, c-format +msgid "update failed: %s\n" +msgstr "更新に失敗しました: %s\n" + #, c-format msgid "deleting keyblock failed: %s\n" msgstr "鍵ブロックの削除に失敗しました: %s\n" @@ -3274,10 +3290,6 @@ msgstr "変更を保存しますか? (y/N) " msgid "Quit without saving? (y/N) " msgstr "保存せずに終了しますか? (y/N) " -#, c-format -msgid "update failed: %s\n" -msgstr "更新に失敗しました: %s\n" - msgid "Key not changed so no update needed.\n" msgstr "鍵は無変更なので更新は不要です。\n" @@ -4232,9 +4244,6 @@ msgstr "鍵\"%s\"が鍵サーバに見つかりません\n" msgid "key not found on keyserver\n" msgstr "鍵が鍵サーバに見つかりません\n" -msgid "no keyserver known (use option --keyserver)\n" -msgstr "既知の鍵サーバがありません (オプション--keyserverを使いましょう)\n" - #, c-format msgid "requesting key %s from %s server %s\n" msgstr "鍵%sを%sからサーバ%sに要求\n" @@ -4311,6 +4320,7 @@ msgstr "公開鍵の復号に失敗しました: %s\n" msgid "public key encrypted data: good DEK\n" msgstr "公開鍵による暗号化データ: 正しいDEKです\n" +#, c-format msgid "assuming %s encrypted data\n" msgstr "%s暗号化データを仮定\n" @@ -5375,9 +5385,6 @@ msgid "unsupported TOFU database version: %s\n" msgstr "サポートされていないTOFUデータベースバージョン: %s\n" #, c-format -msgid "error creating 'ultimately_trusted_keys' TOFU table: %s\n" -msgstr "'ultimately_trusted_keys' TOFUテーブル作成エラー: %s\n" - msgid "TOFU DB error" msgstr "TOFU DBエラー" @@ -5393,14 +5400,6 @@ msgstr "TOFUデータベースのバージョン判定エラー: %s\n" msgid "error initializing TOFU database: %s\n" msgstr "TOFUデータベースの初期化エラー: %s\n" -#, c-format -msgid "error creating 'encryptions' TOFU table: %s\n" -msgstr "'encryptions' TOFUデータベースの作成エラー: %s\n" - -#, c-format -msgid "adding column effective_policy to bindings DB: %s\n" -msgstr "バインディングDBにカラムeffective_policyを追加: %s\n" - #, c-format msgid "error opening TOFU database '%s': %s\n" msgstr "TOFUデータベースのオープンでエラー '%s': %s\n" @@ -5539,14 +5538,6 @@ msgstr "不明をデフォルトとします。\n" msgid "TOFU db corruption detected.\n" msgstr "TOFU dbが壊れていることが検出されました。\n" -#, c-format -msgid "resetting keydb: %s\n" -msgstr "keydbをリセット: %s\n" - -#, c-format -msgid "error setting TOFU binding's policy to %s\n" -msgstr "TOFUバインディングのポリシーを %s に設定エラー\n" - #, c-format msgid "error changing TOFU policy: %s\n" msgstr "TOFUポリシーの作成エラー: %s\n" @@ -5594,19 +5585,9 @@ msgstr "%s: 0個の署名を検証、0個のメッセージを暗号化しまし msgid "%s: Verified 0 signatures." msgstr "%s: 0個の署名を検証しました。" -#, c-format -msgid "%s: Verified %ld~signature in the past %s." -msgid_plural "%s: Verified %ld~signatures in the past %s." -msgstr[0] "%s: 署名を%ld個検証しました(これまで %s に)。" - msgid "Encrypted 0 messages." msgstr "0 個のメッセージを暗号化しました。" -#, c-format -msgid "Encrypted %ld~message in the past %s." -msgid_plural "Encrypted %ld~messages in the past %s." -msgstr[0] "メッセージを%ld個暗号化しました(これまで %s に)。" - #, c-format msgid "(policy: %s)" msgstr "(ポリシー: %s)" @@ -5654,10 +5635,6 @@ msgid "WARNING: Encrypting to %s, which has no non-revoked user ids\n" msgstr "" "*警告*: %s に暗号化します。失効していないユーザIDが一つもないものです\n" -#, c-format -msgid "error setting policy for key %s, user id \"%s\": %s" -msgstr "鍵%s, ユーザID \"%s\"のポリシーの設定エラー: %s" - #, c-format msgid "'%s' is not a valid long keyID\n" msgstr "'%s'は、有効な大型鍵IDでありません\n" @@ -5823,7 +5800,7 @@ msgstr "fd %dが開けません: %s\n" msgid "WARNING: encrypting without integrity protection is dangerous\n" msgstr "*警告*: 完全性保護なしでの暗号化は危険です\n" -#, c-format +#, c-format msgid "Hint: Do not use option %s\n" msgstr "ヒント: オプション %s を使わない\n" @@ -6377,6 +6354,9 @@ msgstr "証明書は暗号化のために使えません\n" msgid "certificate is not usable for signing\n" msgstr "証明書は署名のために使えません\n" +msgid "looking for another certificate\n" +msgstr "別の証明書を探索する" + #, c-format msgid "line %d: invalid algorithm\n" msgstr "行 %d: 無効なアルゴリズムです\n" @@ -7823,6 +7803,10 @@ msgstr "'%s'に対するOCSP応答構文解析エラー: %s\n" msgid "OCSP responder at '%s' status: %s\n" msgstr "OSCP応答が '%s' でステイタス: %s\n" +#, c-format +msgid "failed to establish a hashing context for OCSP: %s\n" +msgstr "OCSPのハッシュ・コンテクストを確立するのに失敗しました: %s\n" + #, c-format msgid "hashing the OCSP response for '%s' failed: %s\n" msgstr "'%s'に対するOCSP応答のハッシングに失敗しました: %s\n" @@ -7830,9 +7814,6 @@ msgstr "'%s'に対するOCSP応答のハッシングに失敗しました: %s\n" msgid "not signed by a default OCSP signer's certificate" msgstr "デフォルトOCSP署名者の証明で署名されていません" -msgid "only SHA-1 is supported for OCSP responses\n" -msgstr "SHA-1だけがOCSPレスポンスとしてサポートされています\n" - #, c-format msgid "allocating list item failed: %s\n" msgstr "リスト項目の確保に失敗しました: %s\n" @@ -7876,10 +7857,6 @@ msgstr "デフォルトOCSP応答'%s'を使います\n" msgid "using OCSP responder '%s'\n" msgstr "OCSP応答'%s'を使います\n" -#, c-format -msgid "failed to establish a hashing context for OCSP: %s\n" -msgstr "OCSPのハッシュ・コンテクストを確立するのに失敗しました: %s\n" - #, c-format msgid "error getting OCSP status for target certificate: %s\n" msgstr "対象の証明書のOCSPステイタスの取得エラー: %s\n" @@ -8178,6 +8155,14 @@ msgstr "パスフレーズ入力" msgid "Component not suitable for launching" msgstr "コンポーネントが起動するために適切ではありません" +#, c-format +msgid "Configuration file of component %s is broken\n" +msgstr "コンポーネント%sのコンフィグレーション・ファイルが壊れています\n" + +#, c-format +msgid "Note: Use the command \"%s%s\" to get details.\n" +msgstr "注意: \"%s\"コマンドを使って詳細を得てください。\n" + #, c-format msgid "External verification of component %s failed" msgstr "コンポーネント%sの外部の検証が失敗しました" @@ -8429,6 +8414,38 @@ msgstr "プライベート鍵をデータオブジェクトに保管します" msgid "Yubikey management commands" msgstr "Yubikey管理コマンド" +#~ msgid "no keyserver known (use option --keyserver)\n" +#~ msgstr "既知の鍵サーバがありません (オプション--keyserverを使いましょう)\n" + +#~ msgid "error creating 'ultimately_trusted_keys' TOFU table: %s\n" +#~ msgstr "'ultimately_trusted_keys' TOFUテーブル作成エラー: %s\n" + +#~ msgid "error creating 'encryptions' TOFU table: %s\n" +#~ msgstr "'encryptions' TOFUデータベースの作成エラー: %s\n" + +#~ msgid "adding column effective_policy to bindings DB: %s\n" +#~ msgstr "バインディングDBにカラムeffective_policyを追加: %s\n" + +#~ msgid "resetting keydb: %s\n" +#~ msgstr "keydbをリセット: %s\n" + +#~ msgid "error setting TOFU binding's policy to %s\n" +#~ msgstr "TOFUバインディングのポリシーを %s に設定エラー\n" + +#~ msgid "%s: Verified %ld~signature in the past %s." +#~ msgid_plural "%s: Verified %ld~signatures in the past %s." +#~ msgstr[0] "%s: 署名を%ld個検証しました(これまで %s に)。" + +#~ msgid "Encrypted %ld~message in the past %s." +#~ msgid_plural "Encrypted %ld~messages in the past %s." +#~ msgstr[0] "メッセージを%ld個暗号化しました(これまで %s に)。" + +#~ msgid "error setting policy for key %s, user id \"%s\": %s" +#~ msgstr "鍵%s, ユーザID \"%s\"のポリシーの設定エラー: %s" + +#~ msgid "only SHA-1 is supported for OCSP responses\n" +#~ msgstr "SHA-1だけがOCSPレスポンスとしてサポートされています\n" + #~ msgid "male" #~ msgstr "男" From 9551275857c1f9a75fee5736fa6c3cf361364f22 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 19 Jun 2019 14:30:16 +0200 Subject: [PATCH 126/169] scd: Use enums for cardtype and apptype. * scd/app-common.h (cardtype_t): New. (apptype_t): New. (struct card_ctx_s): Change type of cardtype. (struct app_ctx_s): Change type of apptype. Adjust all users. * scd/app.c (struct app_priority_list_s): Add field apptype. (strcardtype): New. Use as needed. (strapptype): New. Use as needed. -- Using strcmp is lame and we can't use a switch to let the compiler complain about missed cases. Signed-off-by: Werner Koch --- scd/app-common.h | 34 ++++++++++++++++++-- scd/app-dinsig.c | 2 +- scd/app-geldkarte.c | 2 +- scd/app-nks.c | 2 +- scd/app-openpgp.c | 2 +- scd/app-p15.c | 2 +- scd/app-piv.c | 4 +-- scd/app-sc-hsm.c | 2 +- scd/app.c | 78 +++++++++++++++++++++++++++++++-------------- 9 files changed, 94 insertions(+), 34 deletions(-) diff --git a/scd/app-common.h b/scd/app-common.h index cdb941283..d3d8869fa 100644 --- a/scd/app-common.h +++ b/scd/app-common.h @@ -43,7 +43,34 @@ #define APP_DECIPHER_INFO_NOPAD 1 /* Padding has been removed. */ +/* List of supported card types. Generic is the usual ISO7817-4 + * compliant card. More specific card or token versions can be given + * here. Use strcardtype() to map them to a string. */ +typedef enum + { + CARDTYPE_GENERIC = 0, + CARDTYPE_YUBIKEY + } cardtype_t; + +/* List of supported card applications. The source code for each + * application can usually be found in an app-NAME.c file. Use + * strapptype() to map them to a string. */ +typedef enum + { + APPTYPE_NONE = 0, + APPTYPE_UNDEFINED, + APPTYPE_OPENPGP, + APPTYPE_PIV, + APPTYPE_NKS, + APPTYPE_P15, + APPTYPE_GELDKARTE, + APPTYPE_DINSIG, + APPTYPE_SC_HSM + } apptype_t; + + +/* Formeard declararion. */ struct app_local_s; /* Defined by all app-*.c. */ @@ -59,7 +86,7 @@ struct card_ctx_s { /* Used reader slot. */ int slot; - const char *cardtype; /* NULL or string with the token's type. */ + cardtype_t cardtype; /* The token's type. */ unsigned int cardversion;/* Firmware version of the token or 0. */ unsigned int card_status; @@ -91,7 +118,7 @@ struct app_ctx_s { card_t card; /* Link back to the card. */ - const char *apptype; + apptype_t apptype; /* The type of the application. */ unsigned int appversion; /* Version of the application or 0. */ unsigned int did_chv1:1; unsigned int force_chv1:1; /* True if the card does not cache CHV1. */ @@ -186,6 +213,9 @@ size_t app_help_read_length_of_cert (int slot, int fid, size_t *r_certoff); /*-- app.c --*/ +const char *strcardtype (cardtype_t t); +const char *strapptype (apptype_t t); + void app_update_priority_list (const char *arg); void app_send_card_list (ctrl_t ctrl); char *card_get_serialno (card_t card); diff --git a/scd/app-dinsig.c b/scd/app-dinsig.c index 74de30cc5..d02938cb1 100644 --- a/scd/app-dinsig.c +++ b/scd/app-dinsig.c @@ -556,7 +556,7 @@ app_select_dinsig (app_t app) rc = iso7816_select_application (slot, aid, sizeof aid, 0); if (!rc) { - app->apptype = "DINSIG"; + app->apptype = APPTYPE_DINSIG; app->fnc.learn_status = do_learn_status; app->fnc.readcert = do_readcert; diff --git a/scd/app-geldkarte.c b/scd/app-geldkarte.c index e126f2adb..4589f3da6 100644 --- a/scd/app-geldkarte.c +++ b/scd/app-geldkarte.c @@ -312,7 +312,7 @@ app_select_geldkarte (app_t app) goto leave; /* Probably not a Geldkarte. */ } - app->apptype = "GELDKARTE"; + app->apptype = APPTYPE_GELDKARTE; app->fnc.deinit = do_deinit; /* If we don't have a serialno yet construct it from the EF_ID. */ diff --git a/scd/app-nks.c b/scd/app-nks.c index bc54c016e..3f985c24a 100644 --- a/scd/app-nks.c +++ b/scd/app-nks.c @@ -1411,7 +1411,7 @@ app_select_nks (app_t app) rc = iso7816_select_application (slot, aid_nks, sizeof aid_nks, 0); if (!rc) { - app->apptype = "NKS"; + app->apptype = APPTYPE_NKS; app->app_local = xtrycalloc (1, sizeof *app->app_local); if (!app->app_local) diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 4f17a3c44..b93b7b557 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -5224,7 +5224,7 @@ app_select_openpgp (app_t app) { unsigned int manufacturer; - app->apptype = "OPENPGP"; + app->apptype = APPTYPE_OPENPGP; app->did_chv1 = 0; app->did_chv2 = 0; diff --git a/scd/app-p15.c b/scd/app-p15.c index 59cc195fb..3b7233926 100644 --- a/scd/app-p15.c +++ b/scd/app-p15.c @@ -3360,7 +3360,7 @@ app_select_p15 (app_t app) } if (!rc) { - app->apptype = "P15"; + app->apptype = APPTYPE_P15; app->app_local = xtrycalloc (1, sizeof *app->app_local); if (!app->app_local) diff --git a/scd/app-piv.c b/scd/app-piv.c index 4b3868729..331f914bb 100644 --- a/scd/app-piv.c +++ b/scd/app-piv.c @@ -3413,7 +3413,7 @@ app_select_piv (app_t app) if (err) goto leave; - app->apptype = "PIV"; + app->apptype = APPTYPE_PIV; app->did_chv1 = 0; app->did_chv2 = 0; app->did_chv3 = 0; @@ -3466,7 +3466,7 @@ app_select_piv (app_t app) goto leave; } - if (app->card->cardtype && !strcmp (app->card->cardtype, "yubikey")) + if (app->card->cardtype == CARDTYPE_YUBIKEY) app->app_local->flags.yubikey = 1; diff --git a/scd/app-sc-hsm.c b/scd/app-sc-hsm.c index a8a792369..d18a1a737 100644 --- a/scd/app-sc-hsm.c +++ b/scd/app-sc-hsm.c @@ -2056,7 +2056,7 @@ app_select_sc_hsm (app_t app) rc = iso7816_select_application (slot, sc_hsm_aid, sizeof sc_hsm_aid, 0); if (!rc) { - app->apptype = "SC-HSM"; + app->apptype = APPTYPE_SC_HSM; app->app_local = xtrycalloc (1, sizeof *app->app_local); if (!app->app_local) diff --git a/scd/app.c b/scd/app.c index aa26443f6..ef9e993d3 100644 --- a/scd/app.c +++ b/scd/app.c @@ -40,30 +40,58 @@ static npth_mutex_t card_list_lock; static card_t card_top; -/* The list of application names and there select function. Of no - * specfic application is selected the first available application on +/* The list of application names and their select function. If no + * specific application is selected the first available application on * a card is selected. */ struct app_priority_list_s { + apptype_t apptype; char const *name; gpg_error_t (*select_func)(app_t); }; static struct app_priority_list_s app_priority_list[] = - {{ "openpgp", app_select_openpgp }, - { "piv", app_select_piv }, - { "nks", app_select_nks }, - { "p15", app_select_p15 }, - { "geldkarte", app_select_geldkarte }, - { "dinsig", app_select_dinsig }, - { "sc-hsm", app_select_sc_hsm }, - { NULL, NULL } + {{ APPTYPE_OPENPGP , "openpgp", app_select_openpgp }, + { APPTYPE_PIV , "piv", app_select_piv }, + { APPTYPE_NKS , "nks", app_select_nks }, + { APPTYPE_P15 , "p15", app_select_p15 }, + { APPTYPE_GELDKARTE, "geldkarte", app_select_geldkarte }, + { APPTYPE_DINSIG , "dinsig", app_select_dinsig }, + { APPTYPE_SC_HSM , "sc-hsm", app_select_sc_hsm }, + { APPTYPE_NONE , NULL, NULL } + /* APPTYPE_UNDEFINED is special and not listed here. */ }; +/* Map a cardtype to a string. Never returns NULL. */ +const char * +strcardtype (cardtype_t t) +{ + switch (t) + { + case CARDTYPE_GENERIC: return "generic"; + case CARDTYPE_YUBIKEY: return "yubikey"; + } + return "?"; +} + + +/* Map an application type to a string. Never returns NULL. */ +const char * +strapptype (apptype_t t) +{ + int i; + + for (i=0; app_priority_list[i].apptype; i++) + if (app_priority_list[i].apptype == t) + return app_priority_list[i].name; + return t == APPTYPE_UNDEFINED? "undefined" : t? "?" : "none"; +} + + /* Initialization function to change the default app_priority_list. * LIST is a list of comma or space separated strings with application * names. Unknown names will only result in warning message. @@ -185,9 +213,10 @@ app_dump_state (void) for (c = card_top; c; c = c->next) { log_info ("app_dump_state: card=%p slot=%d type=%s\n", - c, c->slot, c->cardtype? c->cardtype:"unknown"); + c, c->slot, strcardtype (c->cardtype)); for (a=c->app; a; a = a->next) - log_info ("app_dump_state: app=%p type='%s'\n", a, a->apptype); + log_info ("app_dump_state: app=%p type='%s'\n", + a, strapptype (a->apptype)); } npth_mutex_unlock (&card_list_lock); } @@ -216,14 +245,15 @@ check_conflict (card_t card, const char *name) return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); /* Should not happen. */ /* FIXME: Needs changes for app switching. */ - if (card->app->apptype && !ascii_strcasecmp (card->app->apptype, name)) + if (!card->app->apptype + || !ascii_strcasecmp (strapptype (card->app->apptype), name)) return 0; - if (card->app->apptype && !strcmp (card->app->apptype, "UNDEFINED")) + if (card->app->apptype == APPTYPE_UNDEFINED) return 0; log_info ("application '%s' in use - can't switch\n", - card->app->apptype? card->app->apptype : ""); + strapptype (card->app->apptype)); return gpg_error (GPG_ERR_CONFLICT); } @@ -335,7 +365,7 @@ app_new_register (int slot, ctrl_t ctrl, const char *name, && !iso7816_apdu_direct (slot, "\x00\x1d\x00\x00\x00", 5, 0, NULL, &buf, &buflen)) { - card->cardtype = "yubikey"; + card->cardtype = CARDTYPE_YUBIKEY; if (opt.verbose) { log_info ("Yubico: config="); @@ -446,7 +476,7 @@ app_new_register (int slot, ctrl_t ctrl, const char *name, { /* We switch to the "undefined" application only if explicitly requested. */ - app->apptype = "UNDEFINED"; + app->apptype = APPTYPE_UNDEFINED; /* Clear the error so that we don't run through the application * selection chain. */ err = 0; @@ -804,14 +834,14 @@ app_write_learn_status (card_t card, ctrl_t ctrl, unsigned int flags) if (!(flags &1)) { if (card->cardtype) - send_status_direct (ctrl, "CARDTYPE", card->cardtype); + send_status_direct (ctrl, "CARDTYPE", strcardtype (card->cardtype)); if (card->cardversion) send_status_printf (ctrl, "CARDVERSION", "%X", card->cardversion); if (app->apptype) - send_status_direct (ctrl, "APPTYPE", app->apptype); + send_status_direct (ctrl, "APPTYPE", strapptype (app->apptype)); if (app->appversion) send_status_printf (ctrl, "APPVERSION", "%X", app->appversion); - /* FIXME: Send infor for the otehr active apps of the card? */ + /* FIXME: Send info for the other active apps of the card? */ } err = lock_card (card, ctrl); @@ -893,14 +923,14 @@ app_getattr (card_t card, ctrl_t ctrl, const char *name) if (!card->ref_count || !card->app) return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); - if (card->cardtype && name && !strcmp (name, "CARDTYPE")) + if (name && !strcmp (name, "CARDTYPE")) { - send_status_direct (ctrl, "CARDTYPE", card->cardtype); + send_status_direct (ctrl, "CARDTYPE", strcardtype (card->cardtype)); return 0; } - if (card->app->apptype && name && !strcmp (name, "APPTYPE")) + if (name && !strcmp (name, "APPTYPE")) { - send_status_direct (ctrl, "APPTYPE", card->app->apptype); + send_status_direct (ctrl, "APPTYPE", strapptype (card->app->apptype)); return 0; } if (name && !strcmp (name, "SERIALNO")) From 4256e9f0f1bf27ed2e93ca3890003ead208ef6df Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 21 Jun 2019 10:09:52 +0200 Subject: [PATCH 127/169] gpg: Very minor code cleanup. * g10/decrypt-data.c (decrypt_data): Remove superfluous test. Signed-off-by: Werner Koch --- g10/decrypt-data.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/g10/decrypt-data.c b/g10/decrypt-data.c index 4d9dc86d9..c73d5fb45 100644 --- a/g10/decrypt-data.c +++ b/g10/decrypt-data.c @@ -471,6 +471,7 @@ decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek) { char *filename = NULL; estream_t fp; + rc = get_output_file ("", 0, ed->buf, &filename, &fp); if (! rc) { @@ -492,8 +493,7 @@ decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek) filename, gpg_strerror (rc)); iobuf_close (output); - if (afx) - release_armor_context (afx); + release_armor_context (afx); } xfree (filename); } From 43dcf93407d6d2b87b6e7db74fd05fd237495bfe Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 21 Jun 2019 10:23:35 +0200 Subject: [PATCH 128/169] scd: Simplify inclusion of app-common.h. * scd/scdaemon.h: Include app-common.h. Remove inclusion of that header from all other files. (card_t, app_t): Move typedef to ... * scd/app-common.h: here. Use them in the defs. -- In another patch we will need apptype_t in the ctrl object and thus we need to reorganize things a bit now. Given that most files need app-common anyway it makes sense to always include it. Signed-off-by: Werner Koch --- scd/app-common.h | 11 ++++++++--- scd/app-dinsig.c | 1 - scd/app-geldkarte.c | 1 - scd/app-help.c | 1 - scd/app-nks.c | 1 - scd/app-openpgp.c | 1 - scd/app-p15.c | 1 - scd/app-piv.c | 1 - scd/app-sc-hsm.c | 1 - scd/app.c | 1 - scd/command.c | 1 - scd/scdaemon.c | 1 - scd/scdaemon.h | 4 ++-- 13 files changed, 10 insertions(+), 16 deletions(-) diff --git a/scd/app-common.h b/scd/app-common.h index d3d8869fa..3925eacf7 100644 --- a/scd/app-common.h +++ b/scd/app-common.h @@ -70,13 +70,18 @@ typedef enum } apptype_t; -/* Formeard declararion. */ +/* Forward declarations. */ +struct card_ctx_s; +struct app_ctx_s; struct app_local_s; /* Defined by all app-*.c. */ +typedef struct card_ctx_s *card_t; +typedef struct app_ctx_s *app_t; + /* The object describing a card. */ struct card_ctx_s { - struct card_ctx_s *next; + card_t next; npth_mutex_t lock; @@ -114,7 +119,7 @@ struct card_ctx_s { * several applications and it is usuallay required to explicity * switch between applications. */ struct app_ctx_s { - struct app_ctx_s *next; + app_t next; card_t card; /* Link back to the card. */ diff --git a/scd/app-dinsig.c b/scd/app-dinsig.c index d02938cb1..16a82ade4 100644 --- a/scd/app-dinsig.c +++ b/scd/app-dinsig.c @@ -81,7 +81,6 @@ #include "../common/i18n.h" #include "iso7816.h" -#include "app-common.h" #include "../common/tlv.h" diff --git a/scd/app-geldkarte.c b/scd/app-geldkarte.c index 4589f3da6..15b38194d 100644 --- a/scd/app-geldkarte.c +++ b/scd/app-geldkarte.c @@ -39,7 +39,6 @@ #include "../common/i18n.h" #include "iso7816.h" -#include "app-common.h" #include "../common/tlv.h" diff --git a/scd/app-help.c b/scd/app-help.c index 59221ea9c..e3ad74434 100644 --- a/scd/app-help.c +++ b/scd/app-help.c @@ -24,7 +24,6 @@ #include #include "scdaemon.h" -#include "app-common.h" #include "iso7816.h" #include "../common/tlv.h" diff --git a/scd/app-nks.c b/scd/app-nks.c index 3f985c24a..0651e5d57 100644 --- a/scd/app-nks.c +++ b/scd/app-nks.c @@ -53,7 +53,6 @@ #include "scdaemon.h" #include "../common/i18n.h" #include "iso7816.h" -#include "app-common.h" #include "../common/tlv.h" #include "apdu.h" #include "../common/host2net.h" diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index b93b7b557..c301f8218 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -54,7 +54,6 @@ #include "../common/util.h" #include "../common/i18n.h" #include "iso7816.h" -#include "app-common.h" #include "../common/tlv.h" #include "../common/host2net.h" #include "../common/openpgpdefs.h" diff --git a/scd/app-p15.c b/scd/app-p15.c index 3b7233926..9cd423ee6 100644 --- a/scd/app-p15.c +++ b/scd/app-p15.c @@ -38,7 +38,6 @@ #include "scdaemon.h" #include "iso7816.h" -#include "app-common.h" #include "../common/tlv.h" #include "apdu.h" /* fixme: we should move the card detection to a separate file */ diff --git a/scd/app-piv.c b/scd/app-piv.c index 331f914bb..c1bc79435 100644 --- a/scd/app-piv.c +++ b/scd/app-piv.c @@ -61,7 +61,6 @@ #include "../common/util.h" #include "../common/i18n.h" #include "iso7816.h" -#include "app-common.h" #include "../common/tlv.h" #include "../common/host2net.h" #include "apdu.h" /* We use apdu_send_direct. */ diff --git a/scd/app-sc-hsm.c b/scd/app-sc-hsm.c index d18a1a737..87e58d984 100644 --- a/scd/app-sc-hsm.c +++ b/scd/app-sc-hsm.c @@ -33,7 +33,6 @@ #include "scdaemon.h" #include "iso7816.h" -#include "app-common.h" #include "../common/tlv.h" #include "apdu.h" diff --git a/scd/app.c b/scd/app.c index ef9e993d3..d9b762994 100644 --- a/scd/app.c +++ b/scd/app.c @@ -26,7 +26,6 @@ #include "scdaemon.h" #include "../common/exechelp.h" -#include "app-common.h" #include "iso7816.h" #include "apdu.h" #include "../common/tlv.h" diff --git a/scd/command.c b/scd/command.c index 1c8338446..3c63ef5fd 100644 --- a/scd/command.c +++ b/scd/command.c @@ -33,7 +33,6 @@ #include "scdaemon.h" #include #include -#include "app-common.h" #include "iso7816.h" #include "apdu.h" /* Required for apdu_*_reader (). */ #include "atr.h" diff --git a/scd/scdaemon.c b/scd/scdaemon.c index 42efb4c37..e89569e5d 100644 --- a/scd/scdaemon.c +++ b/scd/scdaemon.c @@ -46,7 +46,6 @@ #include "../common/i18n.h" #include "../common/sysutils.h" -#include "app-common.h" #include "iso7816.h" #include "apdu.h" #include "ccid-driver.h" diff --git a/scd/scdaemon.h b/scd/scdaemon.h index f4a243703..d9c476d52 100644 --- a/scd/scdaemon.h +++ b/scd/scdaemon.h @@ -30,6 +30,8 @@ #include #include "../common/util.h" #include "../common/sysutils.h" +#include "app-common.h" + /* To convey some special hash algorithms we use algorithm numbers reserved for application use. */ @@ -112,8 +114,6 @@ struct server_control_s } in_data; }; -typedef struct card_ctx_s *card_t; -typedef struct app_ctx_s *app_t; /*-- scdaemon.c --*/ void scd_exit (int rc); From 91e2931caac9b914efa0a4524effaaa5948ebd00 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 21 Jun 2019 10:47:45 +0200 Subject: [PATCH 129/169] scd: Track the currently selected app. * scd/scdaemon.h (struct server_control_s): Add 'current_apptype'. * scd/command.c (scd_clear_current_app): New. * scd/app.c (app_new_register): Set it. (deallocate_card): Clear it. -- Signed-off-by: Werner Koch --- scd/app.c | 9 +++++++-- scd/command.c | 17 ++++++++++++++++- scd/scdaemon.h | 6 ++++++ 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/scd/app.c b/scd/app.c index d9b762994..61ae5c27a 100644 --- a/scd/app.c +++ b/scd/app.c @@ -519,9 +519,13 @@ app_new_register (int slot, ctrl_t ctrl, const char *name, } card->periodical_check_needed = periodical_check_needed; - card->next = card_top; card_top = card; + + /* If no current apptype is known for this session, set it now. */ + if (!ctrl->current_apptype) + ctrl->current_apptype = app->apptype; + unlock_card (card); return 0; } @@ -684,8 +688,9 @@ deallocate_card (card_t card) xfree (a); } - xfree (card->serialno); + scd_clear_current_app (card); + xfree (card->serialno); unlock_card (card); xfree (card); } diff --git a/scd/command.c b/scd/command.c index 3c63ef5fd..c45737376 100644 --- a/scd/command.c +++ b/scd/command.c @@ -2069,6 +2069,21 @@ scd_command_handler (ctrl_t ctrl, int fd) } +/* Clear the current application info for CARD from all sessions. + * This is used while deallocating a card. */ +void +scd_clear_current_app (card_t card) +{ + struct server_local_s *sl; + + for (sl=session_list; sl; sl = sl->next_session) + { + if (sl->ctrl_backlink->card_ctx == card) + sl->ctrl_backlink->current_apptype = APPTYPE_NONE; + } +} + + /* 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). */ @@ -2181,7 +2196,7 @@ popup_prompt (void *opaque, int on) /* Helper to send the clients a status change notification. Note that - * this fucntion assumes that APP is already locked. */ + * this function assumes that APP is already locked. */ void send_client_notifications (card_t card, int removal) { diff --git a/scd/scdaemon.h b/scd/scdaemon.h index d9c476d52..7ebf6b58d 100644 --- a/scd/scdaemon.h +++ b/scd/scdaemon.h @@ -106,6 +106,11 @@ struct server_control_s application context. */ struct card_ctx_s *card_ctx; + /* The currently active application for this context. We need to + * knw this for cards which are abale to swicth on the fly between + * apps. */ + apptype_t current_apptype; + /* Helper to store the value we are going to sign */ struct { @@ -122,6 +127,7 @@ const char *scd_get_socket_name (void); /*-- command.c --*/ gpg_error_t initialize_module_command (void); int scd_command_handler (ctrl_t, int); +void scd_clear_current_app (card_t card); void send_status_info (ctrl_t ctrl, const char *keyword, ...) GPGRT_ATTR_SENTINEL(1); void send_status_direct (ctrl_t ctrl, const char *keyword, const char *args); From 1b78e4951ed7a66ec71ca036e7680148a63143be Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 21 Jun 2019 11:41:58 +0200 Subject: [PATCH 130/169] scd: Add code to check whether app switching is possible. * scd/app.c (check_conflict): Fold into ... (check_application_conflict): this and adjust callers. Return a different error code if it is possible to switch apps. -- Right now this change does nothing visible. Signed-off-by: Werner Koch --- scd/app-common.h | 2 +- scd/app.c | 43 ++++++++++++++++++++++++++++--------------- scd/command.c | 9 +++++---- 3 files changed, 34 insertions(+), 20 deletions(-) diff --git a/scd/app-common.h b/scd/app-common.h index 3925eacf7..a13623fde 100644 --- a/scd/app-common.h +++ b/scd/app-common.h @@ -228,7 +228,7 @@ char *app_get_serialno (app_t app); void app_dump_state (void); void application_notify_card_reset (int slot); -gpg_error_t check_application_conflict (const char *name, card_t card); +gpg_error_t check_application_conflict (card_t card, const char *name); gpg_error_t card_reset (card_t card, ctrl_t ctrl, int send_reset); gpg_error_t select_application (ctrl_t ctrl, const char *name, card_t *r_app, int scan, const unsigned char *serialno_bin, diff --git a/scd/app.c b/scd/app.c index 61ae5c27a..b415668f0 100644 --- a/scd/app.c +++ b/scd/app.c @@ -235,15 +235,23 @@ is_app_allowed (const char *name) } -static gpg_error_t -check_conflict (card_t card, const char *name) +/* This function is mainly used by the serialno command to check for + * an application conflict which may appear if the serialno command is + * used to request a specific application and the connection has + * already done a select_application. Return values are: + * 0 - No conflict + * GPG_ERR_FALSE - Another application is in use but it is possible + * to switch to the requested application. + * other code - Switching is not possible. + */ +gpg_error_t +check_application_conflict (card_t card, const char *name) { if (!card || !name) return 0; if (!card->app) return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); /* Should not happen. */ - /* FIXME: Needs changes for app switching. */ if (!card->app->apptype || !ascii_strcasecmp (strapptype (card->app->apptype), name)) return 0; @@ -251,6 +259,22 @@ check_conflict (card_t card, const char *name) if (card->app->apptype == APPTYPE_UNDEFINED) return 0; + if (card->cardtype == CARDTYPE_YUBIKEY) + { + if (card->app->apptype == APPTYPE_OPENPGP) + { + /* Current app is OpenPGP. */ + if (!ascii_strcasecmp (name, "piv")) + return gpg_error (GPG_ERR_FALSE); /* Switching allowed. */ + } + else if (card->app->apptype == APPTYPE_PIV) + { + /* Current app is PIV. */ + if (!ascii_strcasecmp (name, "openpgp")) + return gpg_error (GPG_ERR_FALSE); /* Switching allowed. */ + } + } + log_info ("application '%s' in use - can't switch\n", strapptype (card->app->apptype)); @@ -258,17 +282,6 @@ check_conflict (card_t card, const char *name) } -/* This function is used by the serialno command to check for an - application conflict which may appear if the serialno command is - used to request a specific application and the connection has - already done a select_application. */ -gpg_error_t -check_application_conflict (const char *name, card_t card) -{ - return check_conflict (card, name); -} - - gpg_error_t card_reset (card_t card, ctrl_t ctrl, int send_reset) { @@ -607,7 +620,7 @@ select_application (ctrl_t ctrl, const char *name, card_t *r_card, if (card) { - err = check_conflict (card, name); + err = check_application_conflict (card, name); if (!err) { /* Note: We do not use card_ref as we are already locked. */ diff --git a/scd/command.c b/scd/command.c index c45737376..3156aa9ef 100644 --- a/scd/command.c +++ b/scd/command.c @@ -220,7 +220,8 @@ open_card (ctrl_t ctrl) /* Explicitly open a card for a specific use of APPTYPE or SERIALNO. */ static gpg_error_t -open_card_with_request (ctrl_t ctrl, const char *apptype, const char *serialno) +open_card_with_request (ctrl_t ctrl, + const char *apptypestr, const char *serialno) { gpg_error_t err; unsigned char *serialno_bin = NULL; @@ -231,8 +232,8 @@ open_card_with_request (ctrl_t ctrl, const char *apptype, const char *serialno) need to check that the client didn't requested a specific application different from the one in use before we continue. */ /* FIXME: Extend to allow switching between apps. */ - if (apptype && ctrl->card_ctx) - return check_application_conflict (apptype, ctrl->card_ctx); + if (apptypestr && ctrl->card_ctx) + return check_application_conflict (ctrl->card_ctx, apptypestr); /* Re-scan USB devices. Release CARD, before the scan. */ /* FIXME: Is a card_unref sufficient or do we need to deallocate? */ @@ -242,7 +243,7 @@ open_card_with_request (ctrl_t ctrl, const char *apptype, const char *serialno) if (serialno) serialno_bin = hex_to_buffer (serialno, &serialno_bin_len); - err = select_application (ctrl, apptype, &ctrl->card_ctx, 1, + err = select_application (ctrl, apptypestr, &ctrl->card_ctx, 1, serialno_bin, serialno_bin_len); xfree (serialno_bin); From 0400a4eb1782e7a4aea5b04492c93939c6b9799a Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 21 Jun 2019 14:01:06 +0200 Subject: [PATCH 131/169] scd: Take the lock earlier in the function dispatchers. * scd/app.c: Chnage all function dispatcher. -- This change will allow us to easier integrate an app swithcing logic. The change should have no user visible effect. The error checking we do now with the card locked will rarely be asserted. It is the correct thing to do anyway. Signed-off-by: Werner Koch --- scd/app.c | 267 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 154 insertions(+), 113 deletions(-) diff --git a/scd/app.c b/scd/app.c index b415668f0..34ed99d57 100644 --- a/scd/app.c +++ b/scd/app.c @@ -841,30 +841,35 @@ app_write_learn_status (card_t card, ctrl_t ctrl, unsigned int flags) if (!card) return gpg_error (GPG_ERR_INV_VALUE); - if (!card->app) - return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); - app = card->app; - if (!app->fnc.learn_status) - return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); - - /* We do not send CARD and APPTYPE if only keypairinfo is requested. */ - if (!(flags &1)) - { - if (card->cardtype) - send_status_direct (ctrl, "CARDTYPE", strcardtype (card->cardtype)); - if (card->cardversion) - send_status_printf (ctrl, "CARDVERSION", "%X", card->cardversion); - if (app->apptype) - send_status_direct (ctrl, "APPTYPE", strapptype (app->apptype)); - if (app->appversion) - send_status_printf (ctrl, "APPVERSION", "%X", app->appversion); - /* FIXME: Send info for the other active apps of the card? */ - } err = lock_card (card, ctrl); if (err) return err; - err = app->fnc.learn_status (card->app, ctrl, flags); + + app = card->app; + if (!app) + err = gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); + else if (!app->fnc.learn_status) + err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); + else + { + /* We do not send CARD and APPTYPE if only keypairinfo is requested. */ + if (!(flags &1)) + { + if (card->cardtype) + send_status_direct (ctrl, "CARDTYPE", strcardtype (card->cardtype)); + if (card->cardversion) + send_status_printf (ctrl, "CARDVERSION", "%X", card->cardversion); + if (app->apptype) + send_status_direct (ctrl, "APPTYPE", strapptype (app->apptype)); + if (app->appversion) + send_status_printf (ctrl, "APPVERSION", "%X", app->appversion); + /* FIXME: Send info for the other active apps of the card? */ + } + + err = app->fnc.learn_status (app, ctrl, flags); + } + unlock_card (card); return err; } @@ -882,14 +887,17 @@ app_readcert (card_t card, ctrl_t ctrl, const char *certid, if (!card) return gpg_error (GPG_ERR_INV_VALUE); - if (!card->ref_count || !card->app) - return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); - if (!card->app->fnc.readcert) - return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); err = lock_card (card, ctrl); if (err) return err; - err = card->app->fnc.readcert (card->app, certid, cert, certlen); + + if (!card->ref_count || !card->app) + err = gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); + else if (!card->app->fnc.readcert) + err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); + else + err = card->app->fnc.readcert (card->app, certid, cert, certlen); + unlock_card (card); return err; } @@ -916,14 +924,17 @@ app_readkey (card_t card, ctrl_t ctrl, const char *keyid, unsigned int flags, if (!card || !keyid) return gpg_error (GPG_ERR_INV_VALUE); - if (!card->ref_count || !card->app) - return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); - if (!card->app->fnc.readkey) - return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); err = lock_card (card, ctrl); if (err) return err; - err = card->app->fnc.readkey (card->app, ctrl, keyid, flags, pk, pklen); + + if (!card->ref_count || !card->app) + err = gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); + else if (!card->app->fnc.readkey) + err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); + else + err = card->app->fnc.readkey (card->app, ctrl, keyid, flags, pk, pklen); + unlock_card (card); return err; } @@ -937,38 +948,38 @@ app_getattr (card_t card, ctrl_t ctrl, const char *name) if (!card || !name || !*name) return gpg_error (GPG_ERR_INV_VALUE); - if (!card->ref_count || !card->app) - return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); + err = lock_card (card, ctrl); + if (err) + return err; - if (name && !strcmp (name, "CARDTYPE")) + if (!card->ref_count || !card->app) + err = gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); + else if (name && !strcmp (name, "CARDTYPE")) { send_status_direct (ctrl, "CARDTYPE", strcardtype (card->cardtype)); - return 0; } - if (name && !strcmp (name, "APPTYPE")) + else if (name && !strcmp (name, "APPTYPE")) { send_status_direct (ctrl, "APPTYPE", strapptype (card->app->apptype)); - return 0; } - if (name && !strcmp (name, "SERIALNO")) + else if (name && !strcmp (name, "SERIALNO")) { char *serial; serial = card_get_serialno (card); if (!serial) - return gpg_error (GPG_ERR_INV_VALUE); - - send_status_direct (ctrl, "SERIALNO", serial); - xfree (serial); - return 0; + err = gpg_error (GPG_ERR_INV_VALUE); + else + { + send_status_direct (ctrl, "SERIALNO", serial); + xfree (serial); + } } + else if (!card->app->fnc.getattr) + err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); + else + err = card->app->fnc.getattr (card->app, ctrl, name); - if (!card->app->fnc.getattr) - return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); - err = lock_card (card, ctrl); - if (err) - return err; - err = card->app->fnc.getattr (card->app, ctrl, name); unlock_card (card); return err; } @@ -985,15 +996,18 @@ app_setattr (card_t card, ctrl_t ctrl, const char *name, if (!card || !name || !*name || !value) return gpg_error (GPG_ERR_INV_VALUE); - if (!card->ref_count || !card->app) - return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); - if (!card->app->fnc.setattr) - return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); err = lock_card (card, ctrl); if (err) return err; - err = card->app->fnc.setattr (card->app, name, pincb, pincb_arg, - value, valuelen); + + if (!card->ref_count || !card->app) + err = gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); + else if (!card->app->fnc.setattr) + err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); + else + err = card->app->fnc.setattr (card->app, name, pincb, pincb_arg, + value, valuelen); + unlock_card (card); return err; } @@ -1013,17 +1027,20 @@ app_sign (card_t card, ctrl_t ctrl, const char *keyidstr, int hashalgo, if (!card || !indata || !indatalen || !outdata || !outdatalen || !pincb) return gpg_error (GPG_ERR_INV_VALUE); - if (!card->ref_count || !card->app) - return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); - if (!card->app->fnc.sign) - return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); err = lock_card (card, ctrl); if (err) return err; - err = card->app->fnc.sign (card->app, keyidstr, hashalgo, - pincb, pincb_arg, - indata, indatalen, - outdata, outdatalen); + + if (!card->ref_count || !card->app) + err = gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); + else if (!card->app->fnc.sign) + err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); + else + err = card->app->fnc.sign (card->app, keyidstr, hashalgo, + pincb, pincb_arg, + indata, indatalen, + outdata, outdatalen); + unlock_card (card); if (opt.verbose) log_info ("operation sign result: %s\n", gpg_strerror (err)); @@ -1046,17 +1063,20 @@ app_auth (card_t card, ctrl_t ctrl, const char *keyidstr, if (!card || !indata || !indatalen || !outdata || !outdatalen || !pincb) return gpg_error (GPG_ERR_INV_VALUE); - if (!card->ref_count || !card->app) - return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); - if (!card->app->fnc.auth) - return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); err = lock_card (card, ctrl); if (err) return err; - err = card->app->fnc.auth (card->app, keyidstr, - pincb, pincb_arg, - indata, indatalen, - outdata, outdatalen); + + if (!card->ref_count || !card->app) + err = gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); + else if (!card->app->fnc.auth) + err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); + else + err = card->app->fnc.auth (card->app, keyidstr, + pincb, pincb_arg, + indata, indatalen, + outdata, outdatalen); + unlock_card (card); if (opt.verbose) log_info ("operation auth result: %s\n", gpg_strerror (err)); @@ -1081,18 +1101,21 @@ app_decipher (card_t card, ctrl_t ctrl, const char *keyidstr, if (!card || !indata || !indatalen || !outdata || !outdatalen || !pincb) return gpg_error (GPG_ERR_INV_VALUE); - if (!card->ref_count || !card->app) - return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); - if (!card->app->fnc.decipher) - return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); err = lock_card (card, ctrl); if (err) return err; - err = card->app->fnc.decipher (card->app, keyidstr, - pincb, pincb_arg, - indata, indatalen, - outdata, outdatalen, - r_info); + + if (!card->ref_count || !card->app) + err = gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); + else if (!card->app->fnc.decipher) + err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); + else + err = card->app->fnc.decipher (card->app, keyidstr, + pincb, pincb_arg, + indata, indatalen, + outdata, outdatalen, + r_info); + unlock_card (card); if (opt.verbose) log_info ("operation decipher result: %s\n", gpg_strerror (err)); @@ -1112,15 +1135,18 @@ app_writecert (card_t card, ctrl_t ctrl, if (!card || !certidstr || !*certidstr || !pincb) return gpg_error (GPG_ERR_INV_VALUE); - if (!card->ref_count || !card->app) - return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); - if (!card->app->fnc.writecert) - return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); err = lock_card (card, ctrl); if (err) return err; - err = card->app->fnc.writecert (card->app, ctrl, certidstr, - pincb, pincb_arg, data, datalen); + + if (!card->ref_count || !card->app) + err = gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); + else if (!card->app->fnc.writecert) + err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); + else + err = card->app->fnc.writecert (card->app, ctrl, certidstr, + pincb, pincb_arg, data, datalen); + unlock_card (card); if (opt.verbose) log_info ("operation writecert result: %s\n", gpg_strerror (err)); @@ -1140,15 +1166,18 @@ app_writekey (card_t card, ctrl_t ctrl, if (!card || !keyidstr || !*keyidstr || !pincb) return gpg_error (GPG_ERR_INV_VALUE); - if (!card->ref_count || !card->app) - return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); - if (!card->app->fnc.writekey) - return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); err = lock_card (card, ctrl); if (err) return err; - err = card->app->fnc.writekey (card->app, ctrl, keyidstr, flags, - pincb, pincb_arg, keydata, keydatalen); + + if (!card->ref_count || !card->app) + err = gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); + else if (!card->app->fnc.writekey) + err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); + else + err = card->app->fnc.writekey (card->app, ctrl, keyidstr, flags, + pincb, pincb_arg, keydata, keydatalen); + unlock_card (card); if (opt.verbose) log_info ("operation writekey result: %s\n", gpg_strerror (err)); @@ -1156,7 +1185,7 @@ app_writekey (card_t card, ctrl_t ctrl, } -/* Perform a SETATTR operation. */ +/* Perform a GENKEY operation. */ gpg_error_t app_genkey (card_t card, ctrl_t ctrl, const char *keynostr, const char *keytype, unsigned int flags, time_t createtime, @@ -1167,15 +1196,18 @@ app_genkey (card_t card, ctrl_t ctrl, const char *keynostr, if (!card || !keynostr || !*keynostr || !pincb) return gpg_error (GPG_ERR_INV_VALUE); - if (!card->ref_count || !card->app) - return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); - if (!card->app->fnc.genkey) - return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); err = lock_card (card, ctrl); if (err) return err; - err = card->app->fnc.genkey (card->app, ctrl, keynostr, keytype, flags, - createtime, pincb, pincb_arg); + + if (!card->ref_count || !card->app) + err = gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); + else if (!card->app->fnc.genkey) + err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); + else + err = card->app->fnc.genkey (card->app, ctrl, keynostr, keytype, flags, + createtime, pincb, pincb_arg); + unlock_card (card); if (opt.verbose) log_info ("operation genkey result: %s\n", gpg_strerror (err)); @@ -1194,12 +1226,15 @@ app_get_challenge (card_t card, ctrl_t ctrl, if (!card || !nbytes || !buffer) return gpg_error (GPG_ERR_INV_VALUE); - if (!card->ref_count) - return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); err = lock_card (card, ctrl); if (err) return err; - err = iso7816_get_challenge (card->slot, nbytes, buffer); + + if (!card->ref_count) + err = gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); + else + err = iso7816_get_challenge (card->slot, nbytes, buffer); + unlock_card (card); return err; } @@ -1216,15 +1251,18 @@ app_change_pin (card_t card, ctrl_t ctrl, const char *chvnostr, if (!card || !chvnostr || !*chvnostr || !pincb) return gpg_error (GPG_ERR_INV_VALUE); - if (!card->ref_count || !card->app) - return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); - if (!card->app->fnc.change_pin) - return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); err = lock_card (card, ctrl); if (err) return err; - err = card->app->fnc.change_pin (card->app, ctrl, - chvnostr, flags, pincb, pincb_arg); + + if (!card->ref_count || !card->app) + err = gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); + else if (!card->app->fnc.change_pin) + err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); + else + err = card->app->fnc.change_pin (card->app, ctrl, + chvnostr, flags, pincb, pincb_arg); + unlock_card (card); if (opt.verbose) log_info ("operation change_pin result: %s\n", gpg_strerror (err)); @@ -1244,14 +1282,17 @@ app_check_pin (card_t card, ctrl_t ctrl, const char *keyidstr, if (!card || !keyidstr || !*keyidstr || !pincb) return gpg_error (GPG_ERR_INV_VALUE); - if (!card->ref_count || !card->app) - return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); - if (!card->app->fnc.check_pin) - return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); err = lock_card (card, ctrl); if (err) return err; - err = card->app->fnc.check_pin (card->app, keyidstr, pincb, pincb_arg); + + if (!card->ref_count || !card->app) + err = gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); + else if (!card->app->fnc.check_pin) + err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); + else + err = card->app->fnc.check_pin (card->app, keyidstr, pincb, pincb_arg); + unlock_card (card); if (opt.verbose) log_info ("operation check_pin result: %s\n", gpg_strerror (err)); @@ -1464,7 +1505,7 @@ app_do_with_keygrip (ctrl_t ctrl, int action, const char *keygrip_str) /* FIXME: Add app switching logic. The above code assumes that the * actions can be performend without switching. This needs to be * checked. For a lookup we also need to reorder the apps so that - * the selected one will be used. */ + * the selected one will be used. */ npth_mutex_unlock (&card_list_lock); return c; From b304c006a3c9ba186fb2510859df7f02a0acad25 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 21 Jun 2019 14:51:55 +0200 Subject: [PATCH 132/169] scd: Take the card look while running app->with_keygrip. * scd/app.c (app_do_with_keygrip): Lock the card. -- Better safe than sorry. We should also review the card reference counting to see whether we better ref the returned card object already here. Signed-off-by: Werner Koch --- scd/app.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/scd/app.c b/scd/app.c index 34ed99d57..ccba75c89 100644 --- a/scd/app.c +++ b/scd/app.c @@ -1492,6 +1492,7 @@ app_send_card_list (ctrl_t ctrl) card_t app_do_with_keygrip (ctrl_t ctrl, int action, const char *keygrip_str) { + gpg_error_t err; card_t c; app_t a; @@ -1499,9 +1500,17 @@ app_do_with_keygrip (ctrl_t ctrl, int action, const char *keygrip_str) for (c = card_top; c; c = c->next) for (a = c->app; a; a = a->next) - if (a->fnc.with_keygrip - && !a->fnc.with_keygrip (a, ctrl, action, keygrip_str)) - break; + if (a->fnc.with_keygrip) + { + if (!lock_card (c, ctrl)) + { + err = a->fnc.with_keygrip (a, ctrl, action, keygrip_str); + unlock_card (c); + if (!err) + break; + } + } + /* FIXME: Add app switching logic. The above code assumes that the * actions can be performend without switching. This needs to be * checked. For a lookup we also need to reorder the apps so that From d7d1ff45574ed935d07642964a529a358b11a1a7 Mon Sep 17 00:00:00 2001 From: Daniel Kahn Gillmor Date: Sun, 23 Jun 2019 20:21:02 -0400 Subject: [PATCH 133/169] spelling: Fix "synchronize" Signed-off-by: Daniel Kahn Gillmor --- g10/cpr.c | 2 +- kbx/keybox-blob.c | 4 ++-- scd/ccid-driver.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/g10/cpr.c b/g10/cpr.c index 3d39d6bda..d502e8b52 100644 --- a/g10/cpr.c +++ b/g10/cpr.c @@ -62,7 +62,7 @@ progress_cb (void *ctx, const char *what, int printchar, /* Return true if the status message NO may currently be issued. We - need this to avoid syncronisation problem while auto retrieving a + need this to avoid synchronization problem while auto retrieving a key. There it may happen that a status NODATA is issued for a non available key and the user may falsely interpret this has a missing signature. */ diff --git a/kbx/keybox-blob.c b/kbx/keybox-blob.c index 0bcd4a323..8ac67afbe 100644 --- a/kbx/keybox-blob.c +++ b/kbx/keybox-blob.c @@ -134,7 +134,7 @@ Note that this value matches TRUST_FLAG_REVOKED - u16 RFU - u32 Recheck_after - - u32 Latest timestamp in the keyblock (useful for KS syncronsiation?) + - u32 Latest timestamp in the keyblock (useful for KS synchronization?) - u32 Blob created at - u32 [NRES] Size of reserved space (not including this field) - bN Reserved space of size NRES for future use. @@ -144,7 +144,7 @@ - bN Space for the keyblock or certificate. - bN RFU. This is the remaining space after keyblock and before the checksum. It is not covered by the checksum. - - b20 SHA-1 checksum (useful for KS syncronisation?) + - b20 SHA-1 checksum (useful for KS synchronization?) Note, that KBX versions before GnuPG 2.1 used an MD5 checksum. However it was only created but never checked. Thus we do not expect problems if we switch to SHA-1. If diff --git a/scd/ccid-driver.c b/scd/ccid-driver.c index 657766e30..e092a2b9a 100644 --- a/scd/ccid-driver.c +++ b/scd/ccid-driver.c @@ -2963,7 +2963,7 @@ ccid_transceive_apdu_level (ccid_driver_t handle, bit 7 1 bit 6 1 bit 5 clear=request,set=response - bit 4..0 0 = resyncronisation request + bit 4..0 0 = resynchronization request 1 = information field size request 2 = abort request 3 = extension of BWT request From d803b3bb3c084b6bce4d2bd161db50dc45442e5b Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 25 Jun 2019 08:30:04 +0200 Subject: [PATCH 134/169] scd: Add an re-select mechanism to switch apps. * scd/app-common.h (struct app_ctx_s): Add func ptr 'reselect'. * scd/app-piv.c (do_reselect): New. (app_select_piv): Move AID constant to file scope. * scd/app-openpgp.c (do_reselect): New. (app_select_openpgp): Move AID constant to file scope. * scd/app.c (apptype_from_name): New. (check_application_conflict): Check against all apps of the card. Always set current_apptype. (select_additional_application): New. (maybe_switch_app): New. (app_write_learn_status, app_readcert, app_readkey, app_getattr) (app_setattr, app_sign, app_auth, app_decipher, app_writecert) (app_writekey, app_genkey, app_change_pin, app_check_pin): Use it here. (app_do_with_keygrip): Force reselect on success. (app_new_register): Move setting of CURRENT_APPTYPE to ... (select_application): here so that it will be set to the requested card. * scd/command.c (open_card_with_request): Select additional application if possible. -- Noet that we will likely need to rework this even more so to get well defined semantics for card access. Signed-off-by: Werner Koch --- scd/app-common.h | 2 + scd/app-dinsig.c | 1 + scd/app-geldkarte.c | 1 + scd/app-nks.c | 1 + scd/app-openpgp.c | 34 ++++++- scd/app-p15.c | 1 + scd/app-piv.c | 34 ++++++- scd/app-sc-hsm.c | 1 + scd/app.c | 234 +++++++++++++++++++++++++++++++++++++------- scd/command.c | 12 ++- scd/scdaemon.h | 2 +- 11 files changed, 274 insertions(+), 49 deletions(-) diff --git a/scd/app-common.h b/scd/app-common.h index a13623fde..97b9b39ef 100644 --- a/scd/app-common.h +++ b/scd/app-common.h @@ -132,6 +132,7 @@ struct app_ctx_s { struct app_local_s *app_local; /* Local to the application. */ struct { void (*deinit) (app_t app); + gpg_error_t (*reselect) (app_t app, ctrl_t ctrl); gpg_error_t (*learn_status) (app_t app, ctrl_t ctrl, unsigned int flags); gpg_error_t (*readcert) (app_t app, const char *certid, unsigned char **cert, size_t *certlen); @@ -233,6 +234,7 @@ gpg_error_t card_reset (card_t card, ctrl_t ctrl, int send_reset); gpg_error_t select_application (ctrl_t ctrl, const char *name, card_t *r_app, int scan, const unsigned char *serialno_bin, size_t serialno_bin_len); +gpg_error_t select_additional_application (ctrl_t ctrl, const char *name); char *get_supported_applications (void); card_t card_ref (card_t card); diff --git a/scd/app-dinsig.c b/scd/app-dinsig.c index 16a82ade4..9993b68ff 100644 --- a/scd/app-dinsig.c +++ b/scd/app-dinsig.c @@ -557,6 +557,7 @@ app_select_dinsig (app_t app) { app->apptype = APPTYPE_DINSIG; + app->fnc.reselect = NULL; app->fnc.learn_status = do_learn_status; app->fnc.readcert = do_readcert; app->fnc.getattr = NULL; diff --git a/scd/app-geldkarte.c b/scd/app-geldkarte.c index 15b38194d..141985932 100644 --- a/scd/app-geldkarte.c +++ b/scd/app-geldkarte.c @@ -313,6 +313,7 @@ app_select_geldkarte (app_t app) app->apptype = APPTYPE_GELDKARTE; app->fnc.deinit = do_deinit; + app->fnc.reselect = NULL; /* If we don't have a serialno yet construct it from the EF_ID. */ if (!app->card->serialno) diff --git a/scd/app-nks.c b/scd/app-nks.c index 0651e5d57..d12720cf6 100644 --- a/scd/app-nks.c +++ b/scd/app-nks.c @@ -1424,6 +1424,7 @@ app_select_nks (app_t app) log_info ("Detected NKS version: %d\n", app->app_local->nks_version); app->fnc.deinit = do_deinit; + app->fnc.reselect = NULL; app->fnc.learn_status = do_learn_status; app->fnc.readcert = do_readcert; app->fnc.readkey = do_readkey; diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index c301f8218..767f29d26 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -59,6 +59,11 @@ #include "../common/openpgpdefs.h" + +/* The AID of this application. */ +static char const openpgp_aid[] = { 0xD2, 0x76, 0x00, 0x01, 0x24, 0x01 }; + + /* A table describing the DOs of the card. */ static struct { int tag; @@ -5204,12 +5209,35 @@ parse_algorithm_attribute (app_t app, int keyno) xfree (relptr); } + +/* Reselect the application. This is used by cards which support + * on-the-fly switching between applications. */ +static gpg_error_t +do_reselect (app_t app, ctrl_t ctrl) +{ + gpg_error_t err; + + (void)ctrl; + + /* An extra check which should not be necessary because the caller + * should have made sure that a re-select is only called for + * approriate cards. */ + if (app->card->cardtype != CARDTYPE_YUBIKEY) + return gpg_error (GPG_ERR_NOT_SUPPORTED); + + /* Note that the card can't cope with P2=0xCO, thus we need to pass + * a special flag value. */ + err = iso7816_select_application (app_get_slot (app), + openpgp_aid, sizeof openpgp_aid, 0x0001); + return err; +} + + /* Select the OpenPGP application on the card in SLOT. This function must be used before any other OpenPGP application functions. */ gpg_error_t app_select_openpgp (app_t app) { - static char const aid[] = { 0xD2, 0x76, 0x00, 0x01, 0x24, 0x01 }; int slot = app_get_slot (app); int rc; unsigned char *buffer; @@ -5218,7 +5246,8 @@ app_select_openpgp (app_t app) /* Note that the card can't cope with P2=0xCO, thus we need to pass a special flag value. */ - rc = iso7816_select_application (slot, aid, sizeof aid, 0x0001); + rc = iso7816_select_application (slot, + openpgp_aid, sizeof openpgp_aid, 0x0001); if (!rc) { unsigned int manufacturer; @@ -5353,6 +5382,7 @@ app_select_openpgp (app_t app) dump_all_do (slot); app->fnc.deinit = do_deinit; + app->fnc.reselect = do_reselect; app->fnc.learn_status = do_learn_status; app->fnc.readcert = do_readcert; app->fnc.readkey = do_readkey; diff --git a/scd/app-p15.c b/scd/app-p15.c index 9cd423ee6..ce82b34a9 100644 --- a/scd/app-p15.c +++ b/scd/app-p15.c @@ -3415,6 +3415,7 @@ app_select_p15 (app_t app) } app->fnc.deinit = do_deinit; + app->fnc.reselect = NULL; app->fnc.learn_status = do_learn_status; app->fnc.readcert = do_readcert; app->fnc.getattr = do_getattr; diff --git a/scd/app-piv.c b/scd/app-piv.c index c1bc79435..3b94a28e4 100644 --- a/scd/app-piv.c +++ b/scd/app-piv.c @@ -81,6 +81,10 @@ #define PIV_ALGORITHM_ECC_P384 0x14 +/* The AID for PIV. */ +static char const piv_aid[] = { 0xA0, 0x00, 0x00, 0x03, 0x08, /* RID=NIST */ + 0x00, 0x00, 0x10, 0x00 /* PIX=PIV */ }; + /* A table describing the DOs of a PIV card. */ struct data_object_s @@ -3390,13 +3394,32 @@ do_with_keygrip (app_t app, ctrl_t ctrl, int action, } +/* Reselect the application. This is used by cards which support + * on-the-fly switching between applications. */ +static gpg_error_t +do_reselect (app_t app, ctrl_t ctrl) +{ + gpg_error_t err; + + (void)ctrl; + + /* An extra check which should not be necessary because the caller + * should have made sure that a re-select is only called for + * approriate cards. */ + if (!app->app_local->flags.yubikey) + return gpg_error (GPG_ERR_NOT_SUPPORTED); + + err = iso7816_select_application (app_get_slot (app), + piv_aid, sizeof piv_aid, 0x0001); + return err; +} + + /* Select the PIV application on the card in SLOT. This function must * be used before any other PIV application functions. */ gpg_error_t app_select_piv (app_t app) { - static char const aid[] = { 0xA0, 0x00, 0x00, 0x03, 0x08, /* RID=NIST */ - 0x00, 0x00, 0x10, 0x00 /* PIX=PIV */ }; int slot = app_get_slot (app); gpg_error_t err; unsigned char *apt = NULL; @@ -3407,7 +3430,7 @@ app_select_piv (app_t app) /* Note that we select using the AID without the 2 octet version * number. This allows for better reporting of future specs. We * need to use the use-zero-for-P2-flag. */ - err = iso7816_select_application_ext (slot, aid, sizeof aid, 0x0001, + err = iso7816_select_application_ext (slot, piv_aid, sizeof piv_aid, 0x0001, &apt, &aptlen); if (err) goto leave; @@ -3427,7 +3450,7 @@ app_select_piv (app_t app) } s = find_tlv (apt, aptlen, 0x4F, &n); - if (!s || n != 6 || memcmp (s, aid+5, 4)) + if (!s || n != 6 || memcmp (s, piv_aid+5, 4)) { /* The PIX does not match. */ log_error ("piv: missing or invalid DO 0x4F in APT\n"); @@ -3450,7 +3473,7 @@ app_select_piv (app_t app) goto leave; } s = find_tlv (s, n, 0x4F, &n); - if (!s || n != 5 || memcmp (s, aid, 5)) + if (!s || n != 5 || memcmp (s, piv_aid, 5)) { /* The RID does not match. */ log_error ("piv: missing or invalid DO 0x79.4F in APT\n"); @@ -3475,6 +3498,7 @@ app_select_piv (app_t app) dump_all_do (slot); app->fnc.deinit = do_deinit; + app->fnc.reselect = do_reselect; app->fnc.learn_status = do_learn_status; app->fnc.readcert = do_readcert; app->fnc.readkey = do_readkey; diff --git a/scd/app-sc-hsm.c b/scd/app-sc-hsm.c index 87e58d984..16d25b581 100644 --- a/scd/app-sc-hsm.c +++ b/scd/app-sc-hsm.c @@ -2069,6 +2069,7 @@ app_select_sc_hsm (app_t app) goto leave; app->fnc.deinit = do_deinit; + app->fnc.reselect = NULL; app->fnc.learn_status = do_learn_status; app->fnc.readcert = do_readcert; app->fnc.getattr = do_getattr; diff --git a/scd/app.c b/scd/app.c index ccba75c89..c568b636b 100644 --- a/scd/app.c +++ b/scd/app.c @@ -91,6 +91,24 @@ strapptype (apptype_t t) } +/* Return the apptype for NAME. */ +static apptype_t +apptype_from_name (const char *name) +{ + int i; + + if (!name) + return APPTYPE_NONE; + + for (i=0; app_priority_list[i].apptype; i++) + if (!ascii_strcasecmp (app_priority_list[i].name, name)) + return app_priority_list[i].apptype; + if (!ascii_strcasecmp ("undefined", name)) + return APPTYPE_UNDEFINED; + return APPTYPE_NONE; +} + + /* Initialization function to change the default app_priority_list. * LIST is a list of comma or space separated strings with application * names. Unknown names will only result in warning message. @@ -247,14 +265,18 @@ is_app_allowed (const char *name) gpg_error_t check_application_conflict (card_t card, const char *name) { + app_t app; + if (!card || !name) return 0; if (!card->app) return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); /* Should not happen. */ - if (!card->app->apptype - || !ascii_strcasecmp (strapptype (card->app->apptype), name)) - return 0; + /* Check whether the requested NAME matches any already selected + * application. */ + for (app = card->app; app; app = app->next) + if (!ascii_strcasecmp (strapptype (app->apptype), name)) + return 0; if (card->app->apptype == APPTYPE_UNDEFINED) return 0; @@ -535,10 +557,6 @@ app_new_register (int slot, ctrl_t ctrl, const char *name, card->next = card_top; card_top = card; - /* If no current apptype is known for this session, set it now. */ - if (!ctrl->current_apptype) - ctrl->current_apptype = app->apptype; - unlock_card (card); return 0; } @@ -632,7 +650,9 @@ select_application (ctrl_t ctrl, const char *name, card_t *r_card, card->next = card_top; card_top = card; } - } + + ctrl->current_apptype = card->app ? card->app->apptype : 0; + } unlock_card (card); } else @@ -644,6 +664,82 @@ select_application (ctrl_t ctrl, const char *name, card_t *r_card, } +/* This function needs to be called with the NAME of the new + * application to be selected on CARD. On success the application is + * added to the list of the card's active applications as currently + * active application. On error no new application is allocated. + * Selecting an already selected application has no effect. */ +gpg_error_t +select_additional_application (ctrl_t ctrl, const char *name) +{ + gpg_error_t err = 0; + apptype_t req_apptype; + card_t card; + app_t app = NULL; + int i; + + req_apptype = apptype_from_name (name); + if (!req_apptype) + err = gpg_error (GPG_ERR_NOT_FOUND); + + card = ctrl->card_ctx; + if (!card) + return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); + + err = lock_card (card, ctrl); + if (err) + return err; + + /* Check that the requested app has not yet been put onto the list. */ + for (app = card->app; app; app = app->next) + if (app->apptype == req_apptype) + { + /* We already got this one. Note that in this case we don't + * make it the current one but it doesn't matter because + * maybe_switch_app will do that anyway. */ + err = 0; + app = NULL; + goto leave; + } + app = NULL; + + /* Allocate a new app object. */ + app = xtrycalloc (1, sizeof *app); + if (!app) + { + err = gpg_error_from_syserror (); + log_info ("error allocating app context: %s\n", gpg_strerror (err)); + goto leave; + } + + /* Find the app and run the select. */ + for (i=0; app_priority_list[i].apptype; i++) + { + if (app_priority_list[i].apptype == req_apptype + && is_app_allowed (app_priority_list[i].name)) + err = app_priority_list[i].select_func (app); + } + if (!app_priority_list[i].apptype + || (err && gpg_err_code (err) != GPG_ERR_OBJ_TERM_STATE)) + err = gpg_error (GPG_ERR_NOT_SUPPORTED); + + if (err) + goto leave; + + /* Add this app. We make it the current one to avoid an extra + * reselect by maybe_switch_app after the select we just did. */ + app->next = card->app; + card->app = app; + ctrl->current_apptype = app->apptype; + log_error ("added app '%s' to the card context\n", strapptype(app->apptype)); + + leave: + unlock_card (card); + xfree (app); + return err; +} + + char * get_supported_applications (void) { @@ -831,6 +927,63 @@ app_get_serialno (app_t app) } +/* Check that the card has been initialized and whether we need to + * switch to another application on the same card. Switching means + * that the new active app will be moved to the head of the list at + * CARD->app. Thus function must be called with the card lock held. */ +static gpg_error_t +maybe_switch_app (ctrl_t ctrl, card_t card) +{ + gpg_error_t err; + app_t app, app_prev; + + if (!card->ref_count || !card->app) + return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); + if (!ctrl->current_apptype) + { + /* For whatever reasons the current apptype has not been set - + * fix that and use the current app. */ + ctrl->current_apptype = card->app->apptype; + return 0; + } + log_debug ("card=%p want=%s card->app=%s\n", + card, strapptype (ctrl->current_apptype), + strapptype (card->app->apptype)); + app_dump_state (); + if (ctrl->current_apptype == card->app->apptype) + return 0; /* No need to switch. */ + app_prev = card->app; + for (app = app_prev->next; app; app_prev = app, app = app->next) + if (app->apptype == ctrl->current_apptype) + break; + if (!app) + return gpg_error (GPG_ERR_WRONG_CARD); + + if (!app->fnc.reselect) + { + log_error ("oops: reselect function missing for '%s'\n", + strapptype(app->apptype)); + return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); + } + err = app->fnc.reselect (app, ctrl); + if (err) + { + log_error ("error re-selecting '%s': %s\n", + strapptype(app->apptype), gpg_strerror (err)); + return err; + } + /* Swap APP with the head of the app list. Note that APP is not the + * head of the list. */ + app_prev->next = app->next; + app->next = card->app; + card->app = app; + ctrl->current_apptype = app->apptype; + log_error ("switched to '%s'\n", strapptype(app->apptype)); + + return 0; +} + + /* Write out the application specific status lines for the LEARN command. */ gpg_error_t @@ -846,13 +999,14 @@ app_write_learn_status (card_t card, ctrl_t ctrl, unsigned int flags) if (err) return err; - app = card->app; - if (!app) - err = gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); - else if (!app->fnc.learn_status) + if ((err = maybe_switch_app (ctrl, card))) + ; + else if (!card->app->fnc.learn_status) err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); else { + app = card->app; + /* We do not send CARD and APPTYPE if only keypairinfo is requested. */ if (!(flags &1)) { @@ -891,8 +1045,8 @@ app_readcert (card_t card, ctrl_t ctrl, const char *certid, if (err) return err; - if (!card->ref_count || !card->app) - err = gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); + if ((err = maybe_switch_app (ctrl, card))) + ; else if (!card->app->fnc.readcert) err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); else @@ -928,8 +1082,8 @@ app_readkey (card_t card, ctrl_t ctrl, const char *keyid, unsigned int flags, if (err) return err; - if (!card->ref_count || !card->app) - err = gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); + if ((err = maybe_switch_app (ctrl, card))) + ; else if (!card->app->fnc.readkey) err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); else @@ -952,8 +1106,8 @@ app_getattr (card_t card, ctrl_t ctrl, const char *name) if (err) return err; - if (!card->ref_count || !card->app) - err = gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); + if ((err = maybe_switch_app (ctrl, card))) + ; else if (name && !strcmp (name, "CARDTYPE")) { send_status_direct (ctrl, "CARDTYPE", strcardtype (card->cardtype)); @@ -1000,8 +1154,8 @@ app_setattr (card_t card, ctrl_t ctrl, const char *name, if (err) return err; - if (!card->ref_count || !card->app) - err = gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); + if ((err = maybe_switch_app (ctrl, card))) + ; else if (!card->app->fnc.setattr) err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); else @@ -1031,8 +1185,8 @@ app_sign (card_t card, ctrl_t ctrl, const char *keyidstr, int hashalgo, if (err) return err; - if (!card->ref_count || !card->app) - err = gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); + if ((err = maybe_switch_app (ctrl, card))) + ; else if (!card->app->fnc.sign) err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); else @@ -1067,8 +1221,8 @@ app_auth (card_t card, ctrl_t ctrl, const char *keyidstr, if (err) return err; - if (!card->ref_count || !card->app) - err = gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); + if ((err = maybe_switch_app (ctrl, card))) + ; else if (!card->app->fnc.auth) err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); else @@ -1105,8 +1259,8 @@ app_decipher (card_t card, ctrl_t ctrl, const char *keyidstr, if (err) return err; - if (!card->ref_count || !card->app) - err = gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); + if ((err = maybe_switch_app (ctrl, card))) + ; else if (!card->app->fnc.decipher) err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); else @@ -1139,8 +1293,8 @@ app_writecert (card_t card, ctrl_t ctrl, if (err) return err; - if (!card->ref_count || !card->app) - err = gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); + if ((err = maybe_switch_app (ctrl, card))) + ; else if (!card->app->fnc.writecert) err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); else @@ -1170,8 +1324,8 @@ app_writekey (card_t card, ctrl_t ctrl, if (err) return err; - if (!card->ref_count || !card->app) - err = gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); + if ((err = maybe_switch_app (ctrl, card))) + ; else if (!card->app->fnc.writekey) err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); else @@ -1200,8 +1354,8 @@ app_genkey (card_t card, ctrl_t ctrl, const char *keynostr, if (err) return err; - if (!card->ref_count || !card->app) - err = gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); + if ((err = maybe_switch_app (ctrl, card))) + ; else if (!card->app->fnc.genkey) err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); else @@ -1255,8 +1409,8 @@ app_change_pin (card_t card, ctrl_t ctrl, const char *chvnostr, if (err) return err; - if (!card->ref_count || !card->app) - err = gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); + if ((err = maybe_switch_app (ctrl, card))) + ; else if (!card->app->fnc.change_pin) err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); else @@ -1286,8 +1440,8 @@ app_check_pin (card_t card, ctrl_t ctrl, const char *keyidstr, if (err) return err; - if (!card->ref_count || !card->app) - err = gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); + if ((err = maybe_switch_app (ctrl, card))) + ; else if (!card->app->fnc.check_pin) err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); else @@ -1513,8 +1667,12 @@ app_do_with_keygrip (ctrl_t ctrl, int action, const char *keygrip_str) /* FIXME: Add app switching logic. The above code assumes that the * actions can be performend without switching. This needs to be - * checked. For a lookup we also need to reorder the apps so that - * the selected one will be used. */ + * checked. */ + + /* Force switching of the app if the selected one is not the current + * one. Changing the current apptype is sufficient to do this. */ + if (c && c->app && c->app->apptype != a->apptype) + ctrl->current_apptype = a->apptype; npth_mutex_unlock (&card_list_lock); return c; diff --git a/scd/command.c b/scd/command.c index 3156aa9ef..2b851c5fd 100644 --- a/scd/command.c +++ b/scd/command.c @@ -231,9 +231,16 @@ open_card_with_request (ctrl_t ctrl, /* If we are already initialized for one specific application we need to check that the client didn't requested a specific application different from the one in use before we continue. */ - /* FIXME: Extend to allow switching between apps. */ if (apptypestr && ctrl->card_ctx) - return check_application_conflict (ctrl->card_ctx, apptypestr); + { + err = check_application_conflict (ctrl->card_ctx, apptypestr); + if (gpg_err_code (err) == GPG_ERR_FALSE) + { + /* Different application but switching is supported. */ + err = select_additional_application (ctrl, apptypestr); + } + return err; + } /* Re-scan USB devices. Release CARD, before the scan. */ /* FIXME: Is a card_unref sufficient or do we need to deallocate? */ @@ -2084,7 +2091,6 @@ scd_clear_current_app (card_t card) } } - /* 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). */ diff --git a/scd/scdaemon.h b/scd/scdaemon.h index 7ebf6b58d..b709b1cbc 100644 --- a/scd/scdaemon.h +++ b/scd/scdaemon.h @@ -107,7 +107,7 @@ struct server_control_s struct card_ctx_s *card_ctx; /* The currently active application for this context. We need to - * knw this for cards which are abale to swicth on the fly between + * know this for cards which are able to switch on the fly between * apps. */ apptype_t current_apptype; From c8e62965bc90eabff5c4b7cb349bd8e41584c01b Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 25 Jun 2019 09:23:38 +0200 Subject: [PATCH 135/169] scd: Return a stable list with "getinfo card_list". * scd/app.c (compare_card_list_items): New. (app_send_card_list): Sort the card objects by slot. -- This is required so that in gpg-card a "list N" command always returns the expected card. Sorting by slot should be sufficient. Signed-off-by: Werner Koch --- scd/app-common.h | 2 +- scd/app.c | 41 +++++++++++++++++++++++++++++++++++++---- scd/command.c | 2 +- 3 files changed, 39 insertions(+), 6 deletions(-) diff --git a/scd/app-common.h b/scd/app-common.h index 97b9b39ef..460046f89 100644 --- a/scd/app-common.h +++ b/scd/app-common.h @@ -223,7 +223,7 @@ const char *strcardtype (cardtype_t t); const char *strapptype (apptype_t t); void app_update_priority_list (const char *arg); -void app_send_card_list (ctrl_t ctrl); +gpg_error_t app_send_card_list (ctrl_t ctrl); char *card_get_serialno (card_t card); char *app_get_serialno (app_t app); diff --git a/scd/app.c b/scd/app.c index c568b636b..1ad6b9ed6 100644 --- a/scd/app.c +++ b/scd/app.c @@ -1601,22 +1601,55 @@ initialize_module_command (void) } -void +/* Sort helper for app_send_card_list. */ +static int +compare_card_list_items (const void *arg_a, const void *arg_b) +{ + const card_t a = *(const card_t *)arg_a; + const card_t b = *(const card_t *)arg_b; + + return a->slot - b->slot; +} + + +/* Send status lines with the serialno of all inserted cards. */ +gpg_error_t app_send_card_list (ctrl_t ctrl) { + gpg_error_t err; card_t c; char buf[65]; + card_t *cardlist = NULL; + int n, ncardlist; npth_mutex_lock (&card_list_lock); - for (c = card_top; c; c = c->next) + for (n=0, c = card_top; c; c = c->next) + n++; + cardlist = xtrycalloc (n, sizeof *cardlist); + if (!cardlist) { - if (DIM (buf) < 2 * c->serialnolen + 1) + err = gpg_error_from_syserror (); + goto leave; + } + for (ncardlist=0, c = card_top; c; c = c->next) + cardlist[ncardlist++] = c; + qsort (cardlist, ncardlist, sizeof *cardlist, compare_card_list_items); + + for (n=0; n < ncardlist; n++) + { + if (DIM (buf) < 2 * cardlist[n]->serialnolen + 1) continue; - bin2hex (c->serialno, c->serialnolen, buf); + bin2hex (cardlist[n]->serialno, cardlist[n]->serialnolen, buf); send_status_direct (ctrl, "SERIALNO", buf); } + + err = 0; + + leave: npth_mutex_unlock (&card_list_lock); + xfree (cardlist); + return err; } diff --git a/scd/command.c b/scd/command.c index 2b851c5fd..f341b6ae2 100644 --- a/scd/command.c +++ b/scd/command.c @@ -1630,7 +1630,7 @@ cmd_getinfo (assuan_context_t ctx, char *line) { ctrl_t ctrl = assuan_get_pointer (ctx); - app_send_card_list (ctrl); + rc = app_send_card_list (ctrl); } else rc = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT"); From 92ba831758cff0262504ac51e5df7a439844327c Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 25 Jun 2019 09:48:18 +0200 Subject: [PATCH 136/169] scd: Do not conflict if a card with another serialno is demanded. * scd/app.c (check_application_conflict): Add args to pass a serialno. * scd/command.c (open_card_with_request): Pass the serialno to check_application_conflict. -- Signed-off-by: Werner Koch --- scd/app-common.h | 4 +++- scd/app.c | 18 +++++++++++++++--- scd/command.c | 14 ++++++++------ 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/scd/app-common.h b/scd/app-common.h index 460046f89..5866c9b32 100644 --- a/scd/app-common.h +++ b/scd/app-common.h @@ -229,7 +229,9 @@ char *app_get_serialno (app_t app); void app_dump_state (void); void application_notify_card_reset (int slot); -gpg_error_t check_application_conflict (card_t card, const char *name); +gpg_error_t check_application_conflict (card_t card, const char *name, + const unsigned char *serialno_bin, + size_t serialno_bin_len); gpg_error_t card_reset (card_t card, ctrl_t ctrl, int send_reset); gpg_error_t select_application (ctrl_t ctrl, const char *name, card_t *r_app, int scan, const unsigned char *serialno_bin, diff --git a/scd/app.c b/scd/app.c index 1ad6b9ed6..ed7adc3a3 100644 --- a/scd/app.c +++ b/scd/app.c @@ -260,10 +260,15 @@ is_app_allowed (const char *name) * 0 - No conflict * GPG_ERR_FALSE - Another application is in use but it is possible * to switch to the requested application. - * other code - Switching is not possible. + * Other code - Switching is not possible. + * + * If SERIALNO_BIN is not NULL a coflict is onl asserted if the + * serialno of the card matches. */ gpg_error_t -check_application_conflict (card_t card, const char *name) +check_application_conflict (card_t card, const char *name, + const unsigned char *serialno_bin, + size_t serialno_bin_len) { app_t app; @@ -272,6 +277,13 @@ check_application_conflict (card_t card, const char *name) if (!card->app) return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); /* Should not happen. */ + if (serialno_bin && card->serialno) + { + if (serialno_bin_len != card->serialnolen + || memcmp (serialno_bin, card->serialno, card->serialnolen)) + return 0; /* The card does not match the requested S/N. */ + } + /* Check whether the requested NAME matches any already selected * application. */ for (app = card->app; app; app = app->next) @@ -638,7 +650,7 @@ select_application (ctrl_t ctrl, const char *name, card_t *r_card, if (card) { - err = check_application_conflict (card, name); + err = check_application_conflict (card, name, NULL, 0); if (!err) { /* Note: We do not use card_ref as we are already locked. */ diff --git a/scd/command.c b/scd/command.c index f341b6ae2..0096ca96d 100644 --- a/scd/command.c +++ b/scd/command.c @@ -228,18 +228,22 @@ open_card_with_request (ctrl_t ctrl, size_t serialno_bin_len = 0; card_t card = ctrl->card_ctx; + if (serialno) + serialno_bin = hex_to_buffer (serialno, &serialno_bin_len); + /* If we are already initialized for one specific application we need to check that the client didn't requested a specific application different from the one in use before we continue. */ if (apptypestr && ctrl->card_ctx) { - err = check_application_conflict (ctrl->card_ctx, apptypestr); + err = check_application_conflict (ctrl->card_ctx, apptypestr, + serialno_bin, serialno_bin_len); if (gpg_err_code (err) == GPG_ERR_FALSE) { /* Different application but switching is supported. */ err = select_additional_application (ctrl, apptypestr); } - return err; + goto leave; } /* Re-scan USB devices. Release CARD, before the scan. */ @@ -247,13 +251,11 @@ open_card_with_request (ctrl_t ctrl, ctrl->card_ctx = NULL; card_unref (card); - if (serialno) - serialno_bin = hex_to_buffer (serialno, &serialno_bin_len); - err = select_application (ctrl, apptypestr, &ctrl->card_ctx, 1, serialno_bin, serialno_bin_len); - xfree (serialno_bin); + leave: + xfree (serialno_bin); return err; } From f05fd37266f50b2a91c318cb78d8721351aeb797 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Thu, 27 Jun 2019 08:30:25 +0900 Subject: [PATCH 137/169] po: Update Japanese Translation. -- Thanks to Philippe. Reported-by: Phillppe Antoine Signed-off-by: NIIBE Yutaka --- po/ja.po | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/po/ja.po b/po/ja.po index 26c86eca3..ccca194bb 100644 --- a/po/ja.po +++ b/po/ja.po @@ -10,7 +10,7 @@ msgid "" msgstr "" "Project-Id-Version: gnupg 2.2.16\n" "Report-Msgid-Bugs-To: translations@gnupg.org\n" -"PO-Revision-Date: 2019-06-20 13:57+0900\n" +"PO-Revision-Date: 2019-06-27 08:29+0900\n" "Last-Translator: NIIBE Yutaka \n" "Language-Team: none\n" "Language: ja\n" @@ -1551,7 +1551,7 @@ msgid "Note: Only the secret part of the shown primary key will be deleted.\n" msgstr "注意: 表示されている主鍵の秘密鍵だけが削除されます。\n" msgid "Note: Only the secret part of the shown subkey will be deleted.\n" -msgstr "注意: 表示されている副鍵の秘密鍵だけが削除されます。" +msgstr "注意: 表示されている副鍵の秘密鍵だけが削除されます。\n" msgid "Delete this key from the keyring? (y/N) " msgstr "この鍵を鍵リングから削除しますか? (y/N) " @@ -6355,7 +6355,7 @@ msgid "certificate is not usable for signing\n" msgstr "証明書は署名のために使えません\n" msgid "looking for another certificate\n" -msgstr "別の証明書を探索する" +msgstr "別の証明書を探索する\n" #, c-format msgid "line %d: invalid algorithm\n" @@ -8161,7 +8161,7 @@ msgstr "コンポーネント%sのコンフィグレーション・ファイル #, c-format msgid "Note: Use the command \"%s%s\" to get details.\n" -msgstr "注意: \"%s\"コマンドを使って詳細を得てください。\n" +msgstr "注意: \"%s%s\"コマンドを使って詳細を得てください。\n" #, c-format msgid "External verification of component %s failed" From 374a0775546b6241ca2dd10836202c50300d8e91 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Fri, 28 Jun 2019 09:33:30 +0900 Subject: [PATCH 138/169] agent: Close a dialog cleanly when gpg/ssh is killed for CONFIRM. * agent/call-pinentry.c (watch_sock_start): Factor out from do_getpin. (watch_sock_end): Likewise. (do_getpin): Use those functions. (agent_get_confirmation): Likewise. (popup_message_thread): Likewise. -- Pinentry's dialog for confirmation should be also closed cleanly, as well as the dialog for pin-input. Signed-off-by: NIIBE Yutaka --- agent/call-pinentry.c | 82 +++++++++++++++++++++++++++++++------------ 1 file changed, 60 insertions(+), 22 deletions(-) diff --git a/agent/call-pinentry.c b/agent/call-pinentry.c index 02ec1c8c8..9271b4ae9 100644 --- a/agent/call-pinentry.c +++ b/agent/call-pinentry.c @@ -948,15 +948,14 @@ build_cmd_setdesc (char *line, size_t linelen, const char *desc) static void * watch_sock (void *arg) { - gnupg_fd_t *p = (gnupg_fd_t *)arg; pid_t pid = assuan_get_pid (entry_ctx); while (1) { int err; - gnupg_fd_t sock = *p; fd_set fdset; struct timeval timeout = { 0, 500000 }; + gnupg_fd_t sock = *(gnupg_fd_t *)arg; if (sock == GNUPG_INVALID_FD) return NULL; @@ -994,18 +993,11 @@ watch_sock (void *arg) } -/* Ask pinentry to get a pin by "GETPIN" command, spawning a thread - detecting the socket's EOF. - */ static gpg_error_t -do_getpin (ctrl_t ctrl, struct entry_parm_s *parm) +watch_sock_start (gnupg_fd_t *sock_p, npth_t *thread_p) { npth_attr_t tattr; - gpg_error_t rc; int err; - npth_t thread; - int saveflag = assuan_get_flag (entry_ctx, ASSUAN_CONFIDENTIAL); - gnupg_fd_t sock_watched = ctrl->thread_startup.fd; err = npth_attr_init (&tattr); if (err) @@ -1015,7 +1007,7 @@ do_getpin (ctrl_t ctrl, struct entry_parm_s *parm) } npth_attr_setdetachstate (&tattr, NPTH_CREATE_JOINABLE); - err = npth_create (&thread, &tattr, watch_sock, (void *)&sock_watched); + err = npth_create (thread_p, &tattr, watch_sock, sock_p); npth_attr_destroy (&tattr); if (err) { @@ -1023,6 +1015,36 @@ do_getpin (ctrl_t ctrl, struct entry_parm_s *parm) return gpg_error_from_errno (err); } + return 0; +} + +static void +watch_sock_end (gnupg_fd_t *sock_p, npth_t *thread_p) +{ + int err; + + *sock_p = GNUPG_INVALID_FD; + err = npth_join (*thread_p, NULL); + if (err) + log_error ("watch_sock_end: error joining thread: %s\n", strerror (err)); +} + + +/* Ask pinentry to get a pin by "GETPIN" command, spawning a thread + detecting the socket's EOF. + */ +static gpg_error_t +do_getpin (ctrl_t ctrl, struct entry_parm_s *parm) +{ + gpg_error_t rc; + int saveflag = assuan_get_flag (entry_ctx, ASSUAN_CONFIDENTIAL); + gnupg_fd_t sock_watched = ctrl->thread_startup.fd; + npth_t thread; + + rc = watch_sock_start (&sock_watched, &thread); + if (rc) + return rc; + assuan_begin_confidential (entry_ctx); rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, parm, inq_quality, entry_ctx, @@ -1039,10 +1061,7 @@ do_getpin (ctrl_t ctrl, struct entry_parm_s *parm) && gpg_err_code (rc) == GPG_ERR_CANCELED) rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_FULLY_CANCELED); - sock_watched = GNUPG_INVALID_FD; - err = npth_join (thread, NULL); - if (err) - log_error ("do_getpin: error joining thread: %s\n", strerror (err)); + watch_sock_end (&sock_watched, &thread); return rc; } @@ -1447,12 +1466,23 @@ agent_get_confirmation (ctrl_t ctrl, return unlock_pinentry (ctrl, rc); } - rc = assuan_transact (entry_ctx, "CONFIRM", - NULL, NULL, NULL, NULL, NULL, NULL); - if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED) - rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED); + { + gnupg_fd_t sock_watched = ctrl->thread_startup.fd; + npth_t thread; - return unlock_pinentry (ctrl, rc); + rc = watch_sock_start (&sock_watched, &thread); + if (rc) + return rc; + + rc = assuan_transact (entry_ctx, "CONFIRM", + NULL, NULL, NULL, NULL, NULL, NULL); + if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED) + rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED); + + watch_sock_end (&sock_watched, &thread); + + return unlock_pinentry (ctrl, rc); + } } @@ -1461,7 +1491,13 @@ agent_get_confirmation (ctrl_t ctrl, static void * popup_message_thread (void *arg) { - (void)arg; + gpg_error_t rc; + gnupg_fd_t sock_watched = *(gnupg_fd_t *)arg; + npth_t thread; + + rc = watch_sock_start (&sock_watched, &thread); + if (rc) + return NULL; /* We use the --one-button hack instead of the MESSAGE command to allow the use of old Pinentries. Those old Pinentries will then @@ -1469,6 +1505,7 @@ popup_message_thread (void *arg) annoyance. */ assuan_transact (entry_ctx, "CONFIRM --one-button", NULL, NULL, NULL, NULL, NULL, NULL); + watch_sock_end (&sock_watched, &thread); popup_finished = 1; return NULL; } @@ -1525,7 +1562,8 @@ agent_popup_message_start (ctrl_t ctrl, const char *desc, const char *ok_btn) npth_attr_setdetachstate (&tattr, NPTH_CREATE_JOINABLE); popup_finished = 0; - err = npth_create (&popup_tid, &tattr, popup_message_thread, NULL); + err = npth_create (&popup_tid, &tattr, popup_message_thread, + &ctrl->thread_startup.fd); npth_attr_destroy (&tattr); if (err) { From 7c877f942a344e7778005840ed7f3e20ace12f4a Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Mon, 1 Jul 2019 13:07:22 +0900 Subject: [PATCH 139/169] tools: gpgconf: Killing order is children-first. * tools/gpgconf-comp.c (gc_component_kill): Reverse the order. -- The order matters in a corner case; On a busy machine, there was a race condition between gpg-agent's running KILLAGENT command and its accepting incoming request on the socket. If a request by gpg-connect-agent was accepted, it resulted an error by sudden shutdown. This change of the order can remove such a race. Here, we know backend=0 is none. GnuPG-bug-id: 4577 Signed-off-by: NIIBE Yutaka --- tools/gpgconf-comp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/gpgconf-comp.c b/tools/gpgconf-comp.c index 110f88975..628ca358f 100644 --- a/tools/gpgconf-comp.c +++ b/tools/gpgconf-comp.c @@ -1343,7 +1343,7 @@ gc_component_kill (int component) } /* Do the restart for the selected backends. */ - for (backend = 0; backend < GC_BACKEND_NR; backend++) + for (backend = GC_BACKEND_NR-1; backend; backend--) { if (runtime[backend] && gc_backend[backend].runtime_change) (*gc_backend[backend].runtime_change) (1); From 894b72d796c826b1c7e1df788e16874cd051e672 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 1 Jul 2019 14:01:08 +0200 Subject: [PATCH 140/169] gpg: Make read_block in import.c more flexible. * g10/import.c: Change arg 'with_meta' to 'options'. Change callers. -- This chnage allows to pass more options to read_block. Signed-off-by: Werner Koch --- g10/import.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/g10/import.c b/g10/import.c index 00bc47cc1..de45755a4 100644 --- a/g10/import.c +++ b/g10/import.c @@ -102,7 +102,7 @@ static int import (ctrl_t ctrl, unsigned char **fpr, size_t *fpr_len, unsigned int options, import_screener_t screener, void *screener_arg, int origin, const char *url); -static int read_block (IOBUF a, int with_meta, +static int read_block (IOBUF a, unsigned int options, PACKET **pending_pkt, kbnode_t *ret_root, int *r_v3keys); static void revocation_present (ctrl_t ctrl, kbnode_t keyblock); static gpg_error_t import_one (ctrl_t ctrl, @@ -589,8 +589,7 @@ import (ctrl_t ctrl, IOBUF inp, const char* fname,struct import_stats_s *stats, release_armor_context (afx); } - while (!(rc = read_block (inp, !!(options & IMPORT_RESTORE), - &pending_pkt, &keyblock, &v3keys))) + while (!(rc = read_block (inp, options, &pending_pkt, &keyblock, &v3keys))) { stats->v3keys += v3keys; if (keyblock->pkt->pkttype == PKT_PUBLIC_KEY) @@ -845,16 +844,16 @@ valid_keyblock_packet (int pkttype) } -/**************** - * Read the next keyblock from stream A. - * Meta data (ring trust packets) are only considered of WITH_META is set. - * PENDING_PKT should be initialized to NULL and not changed by the caller. - * Return: 0 = okay, -1 no more blocks or another errorcode. - * The int at R_V3KEY counts the number of unsupported v3 - * keyblocks. +/* Read the next keyblock from stream A. Meta data (ring trust + * packets) are only considered if OPTIONS has the IMPORT_RESTORE flag + * set. PENDING_PKT should be initialized to NULL and not changed by + * the caller. + * + * Returns 0 for okay, -1 no more blocks, or any other errorcode. The + * integer at R_V3KEY counts the number of unsupported v3 keyblocks. */ static int -read_block( IOBUF a, int with_meta, +read_block( IOBUF a, unsigned int options, PACKET **pending_pkt, kbnode_t *ret_root, int *r_v3keys) { int rc; @@ -877,7 +876,7 @@ read_block( IOBUF a, int with_meta, pkt = xmalloc (sizeof *pkt); init_packet (pkt); init_parse_packet (&parsectx, a); - if (!with_meta) + if (!(options & IMPORT_RESTORE)) parsectx.skip_meta = 1; in_v3key = 0; skip_sigs = 0; From 2e349bb6173789e0e9e42c32873d89c7bc36cea4 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 1 Jul 2019 15:14:59 +0200 Subject: [PATCH 141/169] gpg: New import and keyserver option "self-sigs-only" * g10/options.h (IMPORT_SELF_SIGS_ONLY): New. * g10/import.c (parse_import_options): Add option "self-sigs-only". (read_block): Handle that option. -- This option is intended to help against importing keys with many bogus key-signatures. It has obvious drawbacks and is not a bullet-proof solution because a self-signature can also be faked and would be detected only later. GnuPG-bug-id: 4591 Signed-off-by: Werner Koch --- doc/gpg.texi | 8 ++++++++ g10/import.c | 42 +++++++++++++++++++++++++++++++++++++++--- g10/options.h | 1 + 3 files changed, 48 insertions(+), 3 deletions(-) diff --git a/doc/gpg.texi b/doc/gpg.texi index c9262c66a..4c383f495 100644 --- a/doc/gpg.texi +++ b/doc/gpg.texi @@ -2341,6 +2341,14 @@ opposite meaning. The options are: can be used to update only the subkeys or other non-user id related information. + @item self-sigs-only + Accept only self-signatures while importing a key. All other + key-signatures are skipped at an early import stage. This option + can be used with @code{keyserver-options} to mitigate attempts to + flood a key with bogus signatures from a keyserver. The drawback is + that all other valid key-signatures, as required by the Web of Trust + are also not imported. + @item repair-keys After import, fix various problems with the keys. For example, this reorders signatures, and strips duplicate diff --git a/g10/import.c b/g10/import.c index de45755a4..583c8e66f 100644 --- a/g10/import.c +++ b/g10/import.c @@ -190,7 +190,10 @@ parse_import_options(char *str,unsigned int *options,int noisy) N_("remove as much as possible from key after import")}, {"import-drop-uids", IMPORT_DROP_UIDS, NULL, - N_("Do not import user id or attribute packets")}, + N_("do not import user id or attribute packets")}, + + {"self-sigs-only", IMPORT_SELF_SIGS_ONLY, NULL, + N_("ignore key-signatures which are not self-signatures")}, {"import-export", IMPORT_EXPORT, NULL, N_("run import filters and export key immediately")}, @@ -861,6 +864,8 @@ read_block( IOBUF a, unsigned int options, PACKET *pkt; kbnode_t root = NULL; int in_cert, in_v3key, skip_sigs; + u32 keyid[2]; + unsigned int dropped_nonselfsigs = 0; *r_v3keys = 0; @@ -983,16 +988,43 @@ read_block( IOBUF a, unsigned int options, init_packet(pkt); break; + case PKT_SIGNATURE: + if (!in_cert) + goto x_default; + if (!(options & IMPORT_SELF_SIGS_ONLY)) + goto x_default; + if (pkt->pkt.signature->keyid[0] == keyid[0] + && pkt->pkt.signature->keyid[1] == keyid[1]) + { /* This is likely a self-signature. We import this one. + * Eventually we should use the ISSUER_FPR to compare + * self-signatures, but that will work only for v5 keys + * which are currently not even deployed. + * Note that we do not do any crypto verify here because + * that would defeat this very mitigation of DoS by + * importing a key with a huge amount of faked + * key-signatures. A verification will be done later in + * the processing anyway. Here we want a cheap an early + * way to drop non-self-signatures. */ + goto x_default; + } + /* Skip this signature. */ + dropped_nonselfsigs++; + free_packet (pkt, &parsectx); + init_packet(pkt); + break; + case PKT_PUBLIC_KEY: case PKT_SECRET_KEY: - if (in_cert ) /* Store this packet. */ + if (in_cert) /* Store this packet. */ { *pending_pkt = pkt; pkt = NULL; goto ready; } in_cert = 1; - /* fall through */ + keyid_from_pk (pkt->pkt.public_key, keyid); + goto x_default; + default: x_default: if (in_cert && valid_keyblock_packet (pkt->pkttype)) @@ -1021,6 +1053,10 @@ read_block( IOBUF a, unsigned int options, free_packet (pkt, &parsectx); deinit_parse_packet (&parsectx); xfree( pkt ); + if (!rc && dropped_nonselfsigs && opt.verbose) + log_info ("key %s: number of dropped non-self-signatures: %u\n", + keystr (keyid), dropped_nonselfsigs); + return rc; } diff --git a/g10/options.h b/g10/options.h index b26cea0db..234929b15 100644 --- a/g10/options.h +++ b/g10/options.h @@ -363,6 +363,7 @@ EXTERN_UNLESS_MAIN_MODULE int memory_stat_debug_mode; #define IMPORT_REPAIR_KEYS (1<<11) #define IMPORT_DRY_RUN (1<<12) #define IMPORT_DROP_UIDS (1<<13) +#define IMPORT_SELF_SIGS_ONLY (1<<14) #define EXPORT_LOCAL_SIGS (1<<0) #define EXPORT_ATTRIBUTES (1<<1) From 3a403ab04eeb45f12b34f9d9c421dac93eaf2160 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 1 Jul 2019 21:53:55 +0200 Subject: [PATCH 142/169] gpg: Fallback to import with self-sigs-only on too large keyblocks. * g10/import.c (import_one): Rename to ... (import_one_real): this. Do not print and update stats on keyring write errors. (import_one): New. Add fallback code. -- GnuPG-bug-id: 4591 Signed-off-by: Werner Koch --- g10/import.c | 121 ++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 101 insertions(+), 20 deletions(-) diff --git a/g10/import.c b/g10/import.c index 583c8e66f..ce7602a9f 100644 --- a/g10/import.c +++ b/g10/import.c @@ -129,6 +129,7 @@ static int delete_inv_parts (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid, unsigned int options); static int any_uid_left (kbnode_t keyblock); static int remove_all_uids (kbnode_t *keyblock); +static void remove_all_non_self_sigs (kbnode_t *keyblock, u32 *keyid); static int merge_blocks (ctrl_t ctrl, unsigned int options, kbnode_t keyblock_orig, kbnode_t keyblock, u32 *keyid, @@ -1783,12 +1784,12 @@ update_key_origin (kbnode_t keyblock, u32 curtime, int origin, const char *url) * has valid parts. */ static gpg_error_t -import_one (ctrl_t ctrl, - kbnode_t keyblock, struct import_stats_s *stats, - unsigned char **fpr, size_t *fpr_len, unsigned int options, - int from_sk, int silent, - import_screener_t screener, void *screener_arg, - int origin, const char *url, int *r_valid) +import_one_real (ctrl_t ctrl, + kbnode_t keyblock, struct import_stats_s *stats, + unsigned char **fpr, size_t *fpr_len, unsigned int options, + int from_sk, int silent, + import_screener_t screener, void *screener_arg, + int origin, const char *url, int *r_valid) { gpg_error_t err = 0; PKT_public_key *pk; @@ -1871,6 +1872,13 @@ import_one (ctrl_t ctrl, return 0; } + /* Remove all non-self-sigs if requested. Noe that this is a NOP if + * that option has been globally set but we may also be called + * latter with the already parsed keyblock and a locally changed + * option. This is why we need to remove them here as well. */ + if ((options & IMPORT_SELF_SIGS_ONLY)) + remove_all_non_self_sigs (&keyblock, keyid); + /* Remove or collapse the user ids. */ if ((options & IMPORT_DROP_UIDS)) remove_all_uids (&keyblock); @@ -2080,22 +2088,25 @@ import_one (ctrl_t ctrl, hd = NULL; /* We are ready. */ - if (!opt.quiet && !silent) + if (!err && !opt.quiet && !silent) { char *p = get_user_id_byfpr_native (ctrl, fpr2, fpr2len); log_info (_("key %s: public key \"%s\" imported\n"), keystr(keyid), p); xfree(p); } - if (is_status_enabled()) + if (!err && is_status_enabled()) { char *us = get_long_user_id_string (ctrl, keyid); write_status_text( STATUS_IMPORTED, us ); xfree(us); print_import_ok (pk, 1); } - stats->imported++; - new_key = 1; + if (!err) + { + stats->imported++; + new_key = 1; + } } else /* Key already exists - merge. */ { @@ -2165,8 +2176,10 @@ import_one (ctrl_t ctrl, keydb_release (hd); hd = NULL; - /* We are ready. */ - if (!opt.quiet && !silent) + /* We are ready. Print and update stats if we got no error. + * An error here comes from writing the keyblock and thus + * very likely means that no update happened. */ + if (!err && !opt.quiet && !silent) { char *p = get_user_id_byfpr_native (ctrl, fpr2, fpr2len); if (n_uids == 1 ) @@ -2202,14 +2215,17 @@ import_one (ctrl_t ctrl, xfree(p); } - stats->n_uids +=n_uids; - stats->n_sigs +=n_sigs; - stats->n_subk +=n_subk; - stats->n_sigs_cleaned +=n_sigs_cleaned; - stats->n_uids_cleaned +=n_uids_cleaned; + if (!err) + { + stats->n_uids +=n_uids; + stats->n_sigs +=n_sigs; + stats->n_subk +=n_subk; + stats->n_sigs_cleaned +=n_sigs_cleaned; + stats->n_uids_cleaned +=n_uids_cleaned; - if (is_status_enabled () && !silent) - print_import_ok (pk, ((n_uids?2:0)|(n_sigs?4:0)|(n_subk?8:0))); + if (is_status_enabled () && !silent) + print_import_ok (pk, ((n_uids?2:0)|(n_sigs?4:0)|(n_subk?8:0))); + } } else { @@ -2296,6 +2312,39 @@ import_one (ctrl_t ctrl, } +/* Wrapper around import_one_real to retry the import in some cases. */ +static gpg_error_t +import_one (ctrl_t ctrl, + kbnode_t keyblock, struct import_stats_s *stats, + unsigned char **fpr, size_t *fpr_len, unsigned int options, + int from_sk, int silent, + import_screener_t screener, void *screener_arg, + int origin, const char *url, int *r_valid) +{ + gpg_error_t err; + + err = import_one_real (ctrl, keyblock, stats, fpr, fpr_len, options, + from_sk, silent, screener, screener_arg, + origin, url, r_valid); + if (gpg_err_code (err) == GPG_ERR_TOO_LARGE + && gpg_err_source (err) == GPG_ERR_SOURCE_KEYBOX) + { + /* We hit the maximum image length. Ask the wrapper to do + * everything again but this time with some extra options. */ + u32 keyid[2]; + + keyid_from_pk (keyblock->pkt->pkt.public_key, keyid); + log_info ("key %s: keyblock too large, retrying with self-sigs-only\n", + keystr (keyid)); + options |= IMPORT_SELF_SIGS_ONLY | IMPORT_CLEAN; + err = import_one_real (ctrl, keyblock, stats, fpr, fpr_len, options, + from_sk, silent, screener, screener_arg, + origin, url, r_valid); + } + return err; +} + + /* Transfer all the secret keys in SEC_KEYBLOCK to the gpg-agent. The * function prints diagnostics and returns an error code. If BATCH is * true the secret keys are stored by gpg-agent in the transfer format @@ -2974,7 +3023,7 @@ import_secret_one (ctrl_t ctrl, kbnode_t keyblock, /* The secret keyblock may not have nodes which are deleted in * the public keyblock. Otherwise we would import just the * secret key without having the public key. That would be - * surprising and clutters out private-keys-v1.d. */ + * surprising and clutters our private-keys-v1.d. */ err = resync_sec_with_pub_keyblock (&keyblock, pub_keyblock, &attic); if (err) goto leave; @@ -3823,6 +3872,38 @@ remove_all_uids (kbnode_t *keyblock) } +/* Delete all non-self-sigs from KEYBLOCK. + * Returns: True if the keyblock has changed. */ +static void +remove_all_non_self_sigs (kbnode_t *keyblock, u32 *keyid) +{ + kbnode_t node; + unsigned int dropped = 0; + + for (node = *keyblock; node; node = node->next) + { + if (is_deleted_kbnode (node)) + continue; + + if (node->pkt->pkttype != PKT_SIGNATURE) + continue; + + if (node->pkt->pkt.signature->keyid[0] == keyid[0] + && node->pkt->pkt.signature->keyid[1] == keyid[1]) + continue; + delete_kbnode (node); + dropped++; + } + + if (dropped) + commit_kbnode (keyblock); + + if (dropped && opt.verbose) + log_info ("key %s: number of dropped non-self-signatures: %u\n", + keystr (keyid), dropped); +} + + /* * It may happen that the imported keyblock has duplicated user IDs. * We check this here and collapse those user IDs together with their From cf92f7d96f83e5af7d2c232c8450c2c7d900ade8 Mon Sep 17 00:00:00 2001 From: Peter Lebbing Date: Tue, 2 Jul 2019 10:28:56 +0200 Subject: [PATCH 143/169] Mention --sender in documentation --- doc/gpg.texi | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/gpg.texi b/doc/gpg.texi index 4c383f495..5822dfdd6 100644 --- a/doc/gpg.texi +++ b/doc/gpg.texi @@ -2644,11 +2644,11 @@ legacy non-MDC message is exceptionally required, the option @item --disable-signer-uid @opindex disable-signer-uid -By default the user ID of the signing key is embedded in the data -signature. As of now this is only done if the signing key has been -specified with @option{local-user} using a mail address. This -information can be helpful for verifier to locate the key; see -option @option{--auto-key-retrieve}. +By default the user ID of the signing key is embedded in the data signature. +As of now this is only done if the signing key has been specified with +@option{local-user} using a mail address, or with @option{sender}. This +information can be helpful for verifier to locate the key; see option +@option{--auto-key-retrieve}. @item --personal-cipher-preferences @var{string} @opindex personal-cipher-preferences From 37f0c55c7be3fc4912237f2bc72466aef6f8aa36 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 3 Jul 2019 16:20:00 +0200 Subject: [PATCH 144/169] dirmngr: Do not rewrite the redirection for the "openpgpkey" subdomain. * dirmngr/http.c (same_host_p): Consider certain subdomains to be the same. -- GnuPG-bug-id: 4603 Signed-off-by: Werner Koch --- dirmngr/http.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/dirmngr/http.c b/dirmngr/http.c index 32c0fb181..81b7ba897 100644 --- a/dirmngr/http.c +++ b/dirmngr/http.c @@ -3539,6 +3539,10 @@ same_host_p (parsed_uri_t a, parsed_uri_t b) { NULL, "api.protonmail.ch" }, { "pm.me", "api.protonmail.ch" } }; + static const char *subdomains[] = + { + "openpgpkey." + }; int i; const char *from; @@ -3560,6 +3564,22 @@ same_host_p (parsed_uri_t a, parsed_uri_t b) return 1; } + /* Also consider hosts the same if they differ only in a subdomain; + * in both direction. This allows to have redirection between the + * WKD advanced and direct lookup methods. */ + for (i=0; i < DIM (subdomains); i++) + { + const char *subdom = subdomains[i]; + size_t subdomlen = strlen (subdom); + + if (!ascii_strncasecmp (a->host, subdom, subdomlen) + && !ascii_strcasecmp (a->host + subdomlen, b->host)) + return 1; + if (!ascii_strncasecmp (b->host, subdom, subdomlen) + && !ascii_strcasecmp (b->host + subdomlen, a->host)) + return 1; + } + return 0; } From 8b113bb148f273524682252233b3c65954e1419e Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 3 Jul 2019 17:39:53 +0200 Subject: [PATCH 145/169] dirmngr: Avoid endless loop in case of HTTP error 503. * dirmngr/ks-engine-hkp.c (SEND_REQUEST_EXTRA_RETRIES): New. (handle_send_request_error): Use it for 503 and 504. (ks_hkp_search, ks_hkp_get, ks_hkp_put): Pass a new var for extra_tries. -- This is a pretty stupid fix but one which works without much risk of regressions. We could have used the existing TRIES but in that case the fallback to other host would have been too limited. With the used value we can have several fallbacks to other hosts. Note that the TRIES is still cumulative and not per host. GnuPG-bug-id: 4600 Signed-off-by: Werner Koch --- dirmngr/ks-engine-hkp.c | 43 +++++++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/dirmngr/ks-engine-hkp.c b/dirmngr/ks-engine-hkp.c index 0a360f09f..ef33db229 100644 --- a/dirmngr/ks-engine-hkp.c +++ b/dirmngr/ks-engine-hkp.c @@ -68,6 +68,10 @@ /* Number of retries done for a dead host etc. */ #define SEND_REQUEST_RETRIES 3 +/* Number of retries done in case of transient errors. */ +#define SEND_REQUEST_EXTRA_RETRIES 5 + + enum ks_protocol { KS_PROTOCOL_HKP, KS_PROTOCOL_HKPS, KS_PROTOCOL_MAX }; /* Objects used to maintain information about hosts. */ @@ -1353,10 +1357,12 @@ send_request (ctrl_t ctrl, const char *request, const char *hostportstr, with REQUEST. The function returns true if the caller shall try again. TRIES_LEFT points to a variable to track the number of retries; this function decrements it and won't return true if it is - down to zero. */ + down to zero. EXTRA_TRIES_LEFT does the same but only for + transient http status codes. */ static int handle_send_request_error (ctrl_t ctrl, gpg_error_t err, const char *request, - unsigned int http_status, unsigned int *tries_left) + unsigned int http_status, unsigned int *tries_left, + unsigned int *extra_tries_left) { int retry = 0; @@ -1412,9 +1418,12 @@ handle_send_request_error (ctrl_t ctrl, gpg_error_t err, const char *request, case 503: /* Service Unavailable */ case 504: /* Gateway Timeout */ - log_info ("selecting a different host due to a %u (%s)", - http_status, http_status2string (http_status)); - retry = 1; + if (*extra_tries_left) + { + log_info ("selecting a different host due to a %u (%s)", + http_status, http_status2string (http_status)); + retry = 2; + } break; } } @@ -1424,8 +1433,16 @@ handle_send_request_error (ctrl_t ctrl, gpg_error_t err, const char *request, break; } - if (*tries_left) - --*tries_left; + if (retry == 2) + { + if (*extra_tries_left) + --*extra_tries_left; + } + else + { + if (*tries_left) + --*tries_left; + } return retry; } @@ -1450,6 +1467,7 @@ ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern, char *httphost = NULL; unsigned int http_status; unsigned int tries = SEND_REQUEST_RETRIES; + unsigned int extra_tries = SEND_REQUEST_EXTRA_RETRIES; *r_fp = NULL; @@ -1525,7 +1543,8 @@ ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern, /* Send the request. */ err = send_request (ctrl, request, hostport, httphost, httpflags, NULL, NULL, &fp, &http_status); - if (handle_send_request_error (ctrl, err, request, http_status, &tries)) + if (handle_send_request_error (ctrl, err, request, http_status, + &tries, &extra_tries)) { reselect = 1; goto again; @@ -1595,6 +1614,7 @@ ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp) unsigned int httpflags; unsigned int http_status; unsigned int tries = SEND_REQUEST_RETRIES; + unsigned int extra_tries = SEND_REQUEST_EXTRA_RETRIES; *r_fp = NULL; @@ -1668,7 +1688,8 @@ ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp) /* Send the request. */ err = send_request (ctrl, request, hostport, httphost, httpflags, NULL, NULL, &fp, &http_status); - if (handle_send_request_error (ctrl, err, request, http_status, &tries)) + if (handle_send_request_error (ctrl, err, request, http_status, + &tries, &extra_tries)) { reselect = 1; goto again; @@ -1744,6 +1765,7 @@ ks_hkp_put (ctrl_t ctrl, parsed_uri_t uri, const void *data, size_t datalen) unsigned int httpflags; unsigned int http_status; unsigned int tries = SEND_REQUEST_RETRIES; + unsigned int extra_tries = SEND_REQUEST_EXTRA_RETRIES; parm.datastring = NULL; @@ -1782,7 +1804,8 @@ ks_hkp_put (ctrl_t ctrl, parsed_uri_t uri, const void *data, size_t datalen) /* Send the request. */ err = send_request (ctrl, request, hostport, httphost, 0, put_post_cb, &parm, &fp, &http_status); - if (handle_send_request_error (ctrl, err, request, http_status, &tries)) + if (handle_send_request_error (ctrl, err, request, http_status, + &tries, &extra_tries)) { reselect = 1; goto again; From 9980f81da765f88a65604ab083563bf15ccdb425 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 4 Jul 2019 10:42:48 +0200 Subject: [PATCH 146/169] gpg: Make the get_pubkey_byname interface easier to understand. * g10/keydb.h (enum get_pubkey_modes): New. * g10/getkey.c (get_pubkey_byname): Repalce no_akl by a mode arg and change all callers. -- This change prepares the implementation of GET_PUBKEY_NO_LOCAL. Signed-off-by: Werner Koch --- g10/export.c | 6 +++--- g10/getkey.c | 41 +++++++++++++++++++++++++---------------- g10/gpgcompose.c | 6 ++++-- g10/keydb.h | 13 +++++++++++-- g10/keyedit.c | 9 ++++++--- g10/pkclist.c | 14 ++++++++------ 6 files changed, 57 insertions(+), 32 deletions(-) diff --git a/g10/export.c b/g10/export.c index 9be7d137e..e8bf14cf5 100644 --- a/g10/export.c +++ b/g10/export.c @@ -2174,10 +2174,10 @@ export_ssh_key (ctrl_t ctrl, const char *userid) { getkey_ctx_t getkeyctx; - err = get_pubkey_byname (ctrl, &getkeyctx, NULL, userid, &keyblock, + err = get_pubkey_byname (ctrl, GET_PUBKEY_NO_AKL, + &getkeyctx, NULL, userid, &keyblock, NULL, - 0 /* Only usable keys or given exact. */, - 1 /* No AKL lookup. */); + 0 /* Only usable keys or given exact. */); if (!err) { err = getkey_next (ctrl, getkeyctx, NULL, NULL); diff --git a/g10/getkey.c b/g10/getkey.c index bb8486bb4..f7158c2b6 100644 --- a/g10/getkey.c +++ b/g10/getkey.c @@ -843,11 +843,21 @@ key_byname (ctrl_t ctrl, GETKEY_CTX *retctx, strlist_t namelist, /* Find a public key identified by NAME. * - * If name appears to be a valid RFC822 mailbox (i.e., email - * address) and auto key lookup is enabled (no_akl == 0), then the - * specified auto key lookup methods (--auto-key-lookup) are used to - * import the key into the local keyring. Otherwise, just the local - * keyring is consulted. + * If name appears to be a valid RFC822 mailbox (i.e., email address) + * and auto key lookup is enabled (mode != GET_PUBKEY_NO_AKL), then + * the specified auto key lookup methods (--auto-key-lookup) are used + * to import the key into the local keyring. Otherwise, just the + * local keyring is consulted. + * + * MODE can be one of: + * GET_PUBKEY_NORMAL - The standard mode + * GET_PUBKEY_NO_AKL - The auto key locate functionality is + * disabled and only the local key ring is + * considered. Note: the local key ring is + * consulted even if local is not in the + * auto-key-locate option list! + * GET_PUBKEY_NO_LOCAL - Only the auto key locate functionaly is + * used and no local search is done. * * If RETCTX is not NULL, then the constructed context is returned in * *RETCTX so that getpubkey_next can be used to get subsequent @@ -883,18 +893,14 @@ key_byname (ctrl_t ctrl, GETKEY_CTX *retctx, strlist_t namelist, * documentation for skip_unusable for an exact definition) are * skipped unless they are looked up by key id or by fingerprint. * - * If NO_AKL is set, then the auto key locate functionality is - * disabled and only the local key ring is considered. Note: the - * local key ring is consulted even if local is not in the - * --auto-key-locate option list! - * * This function returns 0 on success. Otherwise, an error code is * returned. In particular, GPG_ERR_NO_PUBKEY or GPG_ERR_NO_SECKEY * (if want_secret is set) is returned if the key is not found. */ int -get_pubkey_byname (ctrl_t ctrl, GETKEY_CTX * retctx, PKT_public_key * pk, +get_pubkey_byname (ctrl_t ctrl, enum get_pubkey_modes mode, + GETKEY_CTX * retctx, PKT_public_key * pk, const char *name, KBNODE * ret_keyblock, - KEYDB_HANDLE * ret_kdbhd, int include_unusable, int no_akl) + KEYDB_HANDLE * ret_kdbhd, int include_unusable) { int rc; strlist_t namelist = NULL; @@ -930,7 +936,7 @@ get_pubkey_byname (ctrl_t ctrl, GETKEY_CTX * retctx, PKT_public_key * pk, * Note: we only save the search context in RETCTX if the local * method is the first method tried (either explicitly or * implicitly). */ - if (!no_akl) + if (mode != GET_PUBKEY_NO_AKL) { /* auto-key-locate is enabled. */ @@ -980,7 +986,9 @@ get_pubkey_byname (ctrl_t ctrl, GETKEY_CTX * retctx, PKT_public_key * pk, /* If the requested name resembles a valid mailbox and automatic retrieval has been enabled, we try to import the key. */ - if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY && !no_akl && is_mbox) + if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY + && mode != GET_PUBKEY_NO_AKL + && is_mbox) { /* NAME wasn't present in the local keyring (or we didn't try * the local keyring). Since the auto key locate feature is @@ -1325,8 +1333,9 @@ get_best_pubkey_byname (ctrl_t ctrl, GETKEY_CTX *retctx, PKT_public_key *pk, getkey_end (ctrl, ctx); ctx = NULL; } - err = get_pubkey_byname (ctrl, &ctx, pk, name, ret_keyblock, - NULL, include_unusable, 0); + err = get_pubkey_byname (ctrl, GET_PUBKEY_NORMAL, + &ctx, pk, name, ret_keyblock, + NULL, include_unusable); if (err) { getkey_end (ctrl, ctx); diff --git a/g10/gpgcompose.c b/g10/gpgcompose.c index 9e6d51a57..7b7e1dc9a 100644 --- a/g10/gpgcompose.c +++ b/g10/gpgcompose.c @@ -1200,7 +1200,8 @@ sig_revocation_key (const char *option, int argc, char *argv[], void *cookie) option, argv[0]); pk.req_usage = PUBKEY_USAGE_SIG; - err = get_pubkey_byname (NULL, NULL, &pk, argv[1], NULL, NULL, 1, 1); + err = get_pubkey_byname (NULL, GET_PUBKEY_NO_AKL, + NULL, &pk, argv[1], NULL, NULL, 1); if (err) log_fatal ("looking up key %s: %s\n", argv[1], gpg_strerror (err)); @@ -2457,7 +2458,8 @@ pk_esk (const char *option, int argc, char *argv[], void *cookie) memset (&pk, 0, sizeof (pk)); pk.req_usage = PUBKEY_USAGE_ENC; - err = get_pubkey_byname (NULL, NULL, &pk, pi.keyid, NULL, NULL, 1, 1); + err = get_pubkey_byname (NULL, GET_PUBKEY_NO_AKL, + NULL, &pk, pi.keyid, NULL, NULL, 1); if (err) log_fatal ("%s: looking up key %s: %s\n", option, pi.keyid, gpg_strerror (err)); diff --git a/g10/keydb.h b/g10/keydb.h index 54c1f6823..19d2523e0 100644 --- a/g10/keydb.h +++ b/g10/keydb.h @@ -345,12 +345,21 @@ typedef struct pubkey_s *pubkey_t; /* Free a list of public keys. */ void pubkeys_free (pubkey_t keys); + +/* Mode flags for get_pubkey_byname. */ +enum get_pubkey_modes + { + GET_PUBKEY_NORMAL = 0, + GET_PUBKEY_NO_AKL = 1, + GET_PUBKEY_NO_LOCAL = 2 + }; + /* Find a public key identified by NAME. */ -int get_pubkey_byname (ctrl_t ctrl, +int get_pubkey_byname (ctrl_t ctrl, enum get_pubkey_modes mode, GETKEY_CTX *retctx, PKT_public_key *pk, const char *name, KBNODE *ret_keyblock, KEYDB_HANDLE *ret_kdbhd, - int include_unusable, int no_akl ); + int include_unusable); /* Likewise, but only return the best match if NAME resembles a mail * address. */ diff --git a/g10/keyedit.c b/g10/keyedit.c index cb05914e1..1bf5de9b2 100644 --- a/g10/keyedit.c +++ b/g10/keyedit.c @@ -1438,7 +1438,8 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr, #endif /* Get the public key */ - err = get_pubkey_byname (ctrl, NULL, NULL, username, &keyblock, &kdbhd, 1, 1); + err = get_pubkey_byname (ctrl, GET_PUBKEY_NO_AKL, + NULL, NULL, username, &keyblock, &kdbhd, 1); if (err) { log_error (_("key \"%s\" not found: %s\n"), username, gpg_strerror (err)); @@ -2571,7 +2572,8 @@ find_by_primary_fpr (ctrl_t ctrl, const char *fpr, err = gpg_error (GPG_ERR_INV_NAME); goto leave; } - err = get_pubkey_byname (ctrl, NULL, NULL, fpr, &keyblock, &kdbhd, 1, 1); + err = get_pubkey_byname (ctrl, GET_PUBKEY_NO_AKL, + NULL, NULL, fpr, &keyblock, &kdbhd, 1); if (err) { log_error (_("key \"%s\" not found: %s\n"), fpr, gpg_strerror (err)); @@ -4290,7 +4292,8 @@ menu_addrevoker (ctrl_t ctrl, kbnode_t pub_keyblock, int sensitive) primary keys only, but some casual testing shows that PGP and GnuPG both can handle a designated revocation from a subkey. */ revoker_pk->req_usage = PUBKEY_USAGE_CERT; - rc = get_pubkey_byname (ctrl, NULL, revoker_pk, answer, NULL, NULL, 1, 1); + rc = get_pubkey_byname (ctrl, GET_PUBKEY_NO_AKL, + NULL, revoker_pk, answer, NULL, NULL, 1); if (rc) { log_error (_("key \"%s\" not found: %s\n"), answer, diff --git a/g10/pkclist.c b/g10/pkclist.c index 20eb00cea..66a1f0655 100644 --- a/g10/pkclist.c +++ b/g10/pkclist.c @@ -975,8 +975,8 @@ build_pk_list (ctrl_t ctrl, strlist_t rcpts, PK_LIST *ret_pk_list) r->pk = xmalloc_clear (sizeof *r->pk); r->pk->req_usage = PUBKEY_USAGE_ENC; - rc = get_pubkey_byname (ctrl, NULL, r->pk, default_key, - NULL, NULL, 0, 1); + rc = get_pubkey_byname (ctrl, GET_PUBKEY_NO_AKL, + NULL, r->pk, default_key, NULL, NULL, 0); if (rc) { xfree (r->pk); @@ -1041,8 +1041,8 @@ build_pk_list (ctrl_t ctrl, strlist_t rcpts, PK_LIST *ret_pk_list) /* We explicitly allow encrypt-to to an disabled key; thus we pass 1 for the second last argument and 1 as the last argument to disable AKL. */ - if ( (rc = get_pubkey_byname (ctrl, - NULL, pk, rov->d, NULL, NULL, 1, 1)) ) + if ((rc = get_pubkey_byname (ctrl, GET_PUBKEY_NO_AKL, + NULL, pk, rov->d, NULL, NULL, 1))) { free_public_key ( pk ); pk = NULL; log_error (_("%s: skipped: %s\n"), rov->d, gpg_strerror (rc) ); @@ -1179,7 +1179,8 @@ build_pk_list (ctrl_t ctrl, strlist_t rcpts, PK_LIST *ret_pk_list) free_public_key (pk); pk = xmalloc_clear( sizeof *pk ); pk->req_usage = PUBKEY_USAGE_ENC; - rc = get_pubkey_byname (ctrl, NULL, pk, answer, NULL, NULL, 0, 0 ); + rc = get_pubkey_byname (ctrl, GET_PUBKEY_NORMAL, + NULL, pk, answer, NULL, NULL, 0); if (rc) tty_printf(_("No such user ID.\n")); else if ( !(rc=openpgp_pk_test_algo2 (pk->pubkey_algo, @@ -1257,7 +1258,8 @@ build_pk_list (ctrl_t ctrl, strlist_t rcpts, PK_LIST *ret_pk_list) /* The default recipient is allowed to be disabled; thus pass 1 as second last argument. We also don't want an AKL. */ - rc = get_pubkey_byname (ctrl, NULL, pk, def_rec, NULL, NULL, 1, 1); + rc = get_pubkey_byname (ctrl, GET_PUBKEY_NO_AKL, + NULL, pk, def_rec, NULL, NULL, 1); if (rc) log_error(_("unknown default recipient \"%s\"\n"), def_rec ); else if ( !(rc=openpgp_pk_test_algo2(pk->pubkey_algo, From d00c8024e58822e0623b3fad99248ce68a8b7725 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 4 Jul 2019 15:13:26 +0200 Subject: [PATCH 147/169] gpg: New command --locate-external-key. * g10/gpg.c (aLocateExtKeys): New. (opts): Add --locate-external-keys. (main): Implement that. * g10/getkey.c (get_pubkey_byname): Implement GET_PUBKEY_NO_LOCAL. (get_best_pubkey_byname): Add arg 'mode' and pass on to get_pubkey_byname. Change callers. * g10/keylist.c (public_key_list): Add arg 'no_local'. (locate_one): Ditto. Pass on to get_best_pubkey_byname. -- This new command is a shortcut for --auto-key-locate nodefault,clear,wkd,... --locate-key and uses the default or configured AKL list but does so without local. See also GnuPG-bug-id: 4599 Signed-off-by: Werner Koch --- doc/gpg.texi | 13 +++++++++---- g10/getkey.c | 48 ++++++++++++++++++++++++++++++++---------------- g10/gpg.c | 8 ++++++-- g10/keydb.h | 2 +- g10/keylist.c | 18 +++++++++++------- g10/main.h | 3 ++- g10/pkclist.c | 3 ++- 7 files changed, 63 insertions(+), 32 deletions(-) diff --git a/doc/gpg.texi b/doc/gpg.texi index 5822dfdd6..8feab8218 100644 --- a/doc/gpg.texi +++ b/doc/gpg.texi @@ -346,12 +346,17 @@ numbers 1-9 or "T" for 10 and above to indicate trust signature levels @item --locate-keys +@itemx --locate-external-keys @opindex locate-keys +@opindex locate-external-keys Locate the keys given as arguments. This command basically uses the -same algorithm as used when locating keys for encryption or signing and -may thus be used to see what keys @command{@gpgname} might use. In -particular external methods as defined by @option{--auto-key-locate} may -be used to locate a key. Only public keys are listed. +same algorithm as used when locating keys for encryption or signing +and may thus be used to see what keys @command{@gpgname} might use. +In particular external methods as defined by +@option{--auto-key-locate} may be used to locate a key. Only public +keys are listed. The variant @option{--locate-external-keys} does not +consider a locally existing key and can thus be used to force the +refresh of a key via the defined external methods. @item --show-keys @opindex show-keys diff --git a/g10/getkey.c b/g10/getkey.c index f7158c2b6..62142772e 100644 --- a/g10/getkey.c +++ b/g10/getkey.c @@ -936,7 +936,9 @@ get_pubkey_byname (ctrl_t ctrl, enum get_pubkey_modes mode, * Note: we only save the search context in RETCTX if the local * method is the first method tried (either explicitly or * implicitly). */ - if (mode != GET_PUBKEY_NO_AKL) + if (mode == GET_PUBKEY_NO_LOCAL) + nodefault = 1; /* Auto-key-locate but ignore "local". */ + else if (mode != GET_PUBKEY_NO_AKL) { /* auto-key-locate is enabled. */ @@ -965,7 +967,13 @@ get_pubkey_byname (ctrl_t ctrl, enum get_pubkey_modes mode, anylocalfirst = 1; } - if (nodefault && is_mbox) + if (mode == GET_PUBKEY_NO_LOCAL) + { + /* Force using the AKL. If IS_MBOX is not set this is the final + * error code. */ + rc = GPG_ERR_NO_PUBKEY; + } + else if (nodefault && is_mbox) { /* Either "nodefault" or "local" (explicitly) appeared in the * auto key locate list and NAME appears to be an email address. @@ -1012,17 +1020,25 @@ get_pubkey_byname (ctrl_t ctrl, enum get_pubkey_modes mode, break; case AKL_LOCAL: - mechanism_string = "Local"; - did_akl_local = 1; - if (retctx) - { - getkey_end (ctrl, *retctx); - *retctx = NULL; - } - add_to_strlist (&namelist, name); - rc = key_byname (ctrl, anylocalfirst ? retctx : NULL, - namelist, pk, 0, - include_unusable, ret_keyblock, ret_kdbhd); + if (mode == GET_PUBKEY_NO_LOCAL) + { + mechanism_string = "None"; + rc = GPG_ERR_NO_PUBKEY; + } + else + { + mechanism_string = "Local"; + did_akl_local = 1; + if (retctx) + { + getkey_end (ctrl, *retctx); + *retctx = NULL; + } + add_to_strlist (&namelist, name); + rc = key_byname (ctrl, anylocalfirst ? retctx : NULL, + namelist, pk, 0, + include_unusable, ret_keyblock, ret_kdbhd); + } break; case AKL_CERT: @@ -1157,7 +1173,6 @@ get_pubkey_byname (ctrl_t ctrl, enum get_pubkey_modes mode, } } - if (rc && retctx) { getkey_end (ctrl, *retctx); @@ -1310,7 +1325,8 @@ pubkey_cmp (ctrl_t ctrl, const char *name, struct pubkey_cmp_cookie *old, * resembles a mail address, the results are ranked and only the best * result is returned. */ gpg_error_t -get_best_pubkey_byname (ctrl_t ctrl, GETKEY_CTX *retctx, PKT_public_key *pk, +get_best_pubkey_byname (ctrl_t ctrl, enum get_pubkey_modes mode, + GETKEY_CTX *retctx, PKT_public_key *pk, const char *name, KBNODE *ret_keyblock, int include_unusable) { @@ -1333,7 +1349,7 @@ get_best_pubkey_byname (ctrl_t ctrl, GETKEY_CTX *retctx, PKT_public_key *pk, getkey_end (ctrl, ctx); ctx = NULL; } - err = get_pubkey_byname (ctrl, GET_PUBKEY_NORMAL, + err = get_pubkey_byname (ctrl, mode, &ctx, pk, name, ret_keyblock, NULL, include_unusable); if (err) diff --git a/g10/gpg.c b/g10/gpg.c index 1819c3fe8..66e47dde5 100644 --- a/g10/gpg.c +++ b/g10/gpg.c @@ -149,6 +149,7 @@ enum cmd_and_opt_values aSendKeys, aRecvKeys, aLocateKeys, + aLocateExtKeys, aSearchKeys, aRefreshKeys, aFetchKeys, @@ -503,6 +504,7 @@ static ARGPARSE_OPTS opts[] = { ARGPARSE_c (aRefreshKeys, "refresh-keys", N_("update all keys from a keyserver")), ARGPARSE_c (aLocateKeys, "locate-keys", "@"), + ARGPARSE_c (aLocateExtKeys, "locate-external-keys", "@"), ARGPARSE_c (aFetchKeys, "fetch-keys" , "@" ), ARGPARSE_c (aShowKeys, "show-keys" , "@" ), ARGPARSE_c (aExportSecret, "export-secret-keys" , "@" ), @@ -2612,6 +2614,7 @@ main (int argc, char **argv) #endif /* ENABLE_CARD_SUPPORT*/ case aListKeys: case aLocateKeys: + case aLocateExtKeys: case aListSigs: case aExportSecret: case aExportSecretSub: @@ -4512,7 +4515,7 @@ main (int argc, char **argv) sl = NULL; for( ; argc; argc--, argv++ ) add_to_strlist2( &sl, *argv, utf8_strings ); - public_key_list (ctrl, sl, 0); + public_key_list (ctrl, sl, 0, 0); free_strlist(sl); break; case aListSecretKeys: @@ -4523,10 +4526,11 @@ main (int argc, char **argv) free_strlist(sl); break; case aLocateKeys: + case aLocateExtKeys: sl = NULL; for (; argc; argc--, argv++) add_to_strlist2( &sl, *argv, utf8_strings ); - public_key_list (ctrl, sl, 1); + public_key_list (ctrl, sl, 1, cmd == aLocateExtKeys); free_strlist (sl); break; diff --git a/g10/keydb.h b/g10/keydb.h index 19d2523e0..6ad8dce4c 100644 --- a/g10/keydb.h +++ b/g10/keydb.h @@ -363,7 +363,7 @@ int get_pubkey_byname (ctrl_t ctrl, enum get_pubkey_modes mode, /* Likewise, but only return the best match if NAME resembles a mail * address. */ -gpg_error_t get_best_pubkey_byname (ctrl_t ctrl, +gpg_error_t get_best_pubkey_byname (ctrl_t ctrl, enum get_pubkey_modes mode, GETKEY_CTX *retctx, PKT_public_key *pk, const char *name, KBNODE *ret_keyblock, int include_unusable); diff --git a/g10/keylist.c b/g10/keylist.c index 50625d0b7..1274775d2 100644 --- a/g10/keylist.c +++ b/g10/keylist.c @@ -51,7 +51,7 @@ static void list_all (ctrl_t, int, int); static void list_one (ctrl_t ctrl, strlist_t names, int secret, int mark_secret); -static void locate_one (ctrl_t ctrl, strlist_t names); +static void locate_one (ctrl_t ctrl, strlist_t names, int no_local); static void print_card_serialno (const char *serialno); struct keylist_context @@ -83,10 +83,11 @@ keylist_context_release (struct keylist_context *listctx) /* List the keys. If list is NULL, all available keys are listed. - With LOCATE_MODE set the locate algorithm is used to find a - key. */ + * With LOCATE_MODE set the locate algorithm is used to find a key; if + * in addition NO_LOCAL is set the locate does not look into the local + * keyring. */ void -public_key_list (ctrl_t ctrl, strlist_t list, int locate_mode) +public_key_list (ctrl_t ctrl, strlist_t list, int locate_mode, int no_local) { #ifndef NO_TRUST_MODELS if (opt.with_colons) @@ -140,7 +141,7 @@ public_key_list (ctrl_t ctrl, strlist_t list, int locate_mode) #endif if (locate_mode) - locate_one (ctrl, list); + locate_one (ctrl, list, no_local); else if (!list) list_all (ctrl, 0, opt.with_secret); else @@ -658,7 +659,7 @@ list_one (ctrl_t ctrl, strlist_t names, int secret, int mark_secret) static void -locate_one (ctrl_t ctrl, strlist_t names) +locate_one (ctrl_t ctrl, strlist_t names, int no_local) { int rc = 0; strlist_t sl; @@ -672,7 +673,10 @@ locate_one (ctrl_t ctrl, strlist_t names) for (sl = names; sl; sl = sl->next) { - rc = get_best_pubkey_byname (ctrl, &ctx, NULL, sl->d, &keyblock, 1); + rc = get_best_pubkey_byname (ctrl, + no_local? GET_PUBKEY_NO_LOCAL + /* */: GET_PUBKEY_NORMAL, + &ctx, NULL, sl->d, &keyblock, 1); if (rc) { if (gpg_err_code (rc) != GPG_ERR_NO_PUBKEY) diff --git a/g10/main.h b/g10/main.h index 67d7e8060..f45b03909 100644 --- a/g10/main.h +++ b/g10/main.h @@ -458,7 +458,8 @@ struct revocation_reason_info * get_default_uid_revocation_reason(void); void release_revocation_reason_info( struct revocation_reason_info *reason ); /*-- keylist.c --*/ -void public_key_list (ctrl_t ctrl, strlist_t list, int locate_mode ); +void public_key_list (ctrl_t ctrl, strlist_t list, + int locate_mode, int no_local); void secret_key_list (ctrl_t ctrl, strlist_t list ); void print_subpackets_colon(PKT_signature *sig); void reorder_keyblock (KBNODE keyblock); diff --git a/g10/pkclist.c b/g10/pkclist.c index 66a1f0655..1fd23a3e4 100644 --- a/g10/pkclist.c +++ b/g10/pkclist.c @@ -834,7 +834,8 @@ find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use, if (from_file) rc = get_pubkey_fromfile (ctrl, pk, name); else - rc = get_best_pubkey_byname (ctrl, NULL, pk, name, &keyblock, 0); + rc = get_best_pubkey_byname (ctrl, GET_PUBKEY_NORMAL, + NULL, pk, name, &keyblock, 0); if (rc) { int code; From 91a6ba32347a21c9029728eec96b8ff80f944629 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 4 Jul 2019 15:21:39 +0200 Subject: [PATCH 148/169] gpg: Avoid printing false AKL error message. * g10/getkey.c (get_pubkey_byname): Add special traeatment for default and skipped-local. -- This change avoids error message like gpg: error retrieving 'foo@example.org' via None: No public key A 'None' mechanism is something internal. Signed-off-by: Werner Koch --- g10/getkey.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/g10/getkey.c b/g10/getkey.c index 62142772e..228042d1a 100644 --- a/g10/getkey.c +++ b/g10/getkey.c @@ -1015,14 +1015,14 @@ get_pubkey_byname (ctrl_t ctrl, enum get_pubkey_modes mode, { case AKL_NODEFAULT: /* This is a dummy mechanism. */ - mechanism_string = "None"; + mechanism_string = ""; rc = GPG_ERR_NO_PUBKEY; break; case AKL_LOCAL: if (mode == GET_PUBKEY_NO_LOCAL) { - mechanism_string = "None"; + mechanism_string = ""; rc = GPG_ERR_NO_PUBKEY; } else @@ -1165,8 +1165,8 @@ get_pubkey_byname (ctrl_t ctrl, enum get_pubkey_modes mode, name, mechanism_string); break; } - if (gpg_err_code (rc) != GPG_ERR_NO_PUBKEY - || opt.verbose || no_fingerprint) + if ((gpg_err_code (rc) != GPG_ERR_NO_PUBKEY + || opt.verbose || no_fingerprint) && *mechanism_string) log_info (_("error retrieving '%s' via %s: %s\n"), name, mechanism_string, no_fingerprint ? _("No fingerprint") : gpg_strerror (rc)); From 23c978640812d123eaffd4108744bdfcf48f7c93 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 4 Jul 2019 15:45:39 +0200 Subject: [PATCH 149/169] gpg: Add "self-sigs-only" and "import-clean" to the keyserver options. * g10/gpg.c (main): Change default. -- Due to the DoS attack on the keyeservers we do not anymore default to import key signatures. That makes the keyserver unsuable for getting keys for the WoT but it still allows to retriev keys - even if that takes long to download the large keyblocks. To revert to the old behavior add keyserver-optiions no-self-sigs-only,no-import-clean to gpg.conf. GnuPG-bug-id: 4607 Signed-off-by: Werner Koch --- doc/gpg.texi | 5 +++++ g10/gpg.c | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/doc/gpg.texi b/doc/gpg.texi index 8feab8218..9513a4e0f 100644 --- a/doc/gpg.texi +++ b/doc/gpg.texi @@ -1917,6 +1917,11 @@ are available for all keyserver types, some common options are: @end table +The default list of options is: "self-sigs-only, import-clean, +repair-keys, repair-pks-subkey-bug, export-attributes, +honor-pka-record". + + @item --completes-needed @var{n} @opindex compliant-needed Number of completely trusted users to introduce a new diff --git a/g10/gpg.c b/g10/gpg.c index 66e47dde5..0bbe72394 100644 --- a/g10/gpg.c +++ b/g10/gpg.c @@ -2424,7 +2424,9 @@ main (int argc, char **argv) opt.import_options = IMPORT_REPAIR_KEYS; opt.export_options = EXPORT_ATTRIBUTES; opt.keyserver_options.import_options = (IMPORT_REPAIR_KEYS - | IMPORT_REPAIR_PKS_SUBKEY_BUG); + | IMPORT_REPAIR_PKS_SUBKEY_BUG + | IMPORT_SELF_SIGS_ONLY + | IMPORT_CLEAN); opt.keyserver_options.export_options = EXPORT_ATTRIBUTES; opt.keyserver_options.options = KEYSERVER_HONOR_PKA_RECORD; opt.verify_options = (LIST_SHOW_UID_VALIDITY From 064aeb14c9b869e114e9ec789526fad8da657230 Mon Sep 17 00:00:00 2001 From: Daniel Kahn Gillmor Date: Tue, 11 Jun 2019 08:25:46 +0100 Subject: [PATCH 150/169] dirmngr: fix handling of HTTPS redirections during HKP * dirmngr/ks-engine-hkp.c (send_request): Reinitialize HTTP session when following a HTTP redirection. -- inspired by patch from Damien Goutte-Gattat GnuPG-Bug_id: 4566 Signed-off-by: Daniel Kahn Gillmor Originally applied to 2.2. Here a minor conflict fix was needed. --- dirmngr/ks-engine-hkp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dirmngr/ks-engine-hkp.c b/dirmngr/ks-engine-hkp.c index ef33db229..f8814ecd0 100644 --- a/dirmngr/ks-engine-hkp.c +++ b/dirmngr/ks-engine-hkp.c @@ -1221,6 +1221,7 @@ send_request (ctrl_t ctrl, const char *request, const char *hostportstr, /* FIXME: I am not sure whey we allow a downgrade for hkp requests. * Needs at least an explanation here.. */ + once_more: err = http_session_new (&session, httphost, ((ctrl->http_no_crl? HTTP_FLAG_NO_CRL : 0) | HTTP_FLAG_TRUST_DEF), @@ -1230,7 +1231,6 @@ send_request (ctrl_t ctrl, const char *request, const char *hostportstr, http_session_set_log_cb (session, cert_log_cb); http_session_set_timeout (session, ctrl->timeout); - once_more: err = http_open (ctrl, &http, post_cb? HTTP_REQ_POST : HTTP_REQ_GET, request, @@ -1310,6 +1310,8 @@ send_request (ctrl_t ctrl, const char *request, const char *hostportstr, request = request_buffer; http_close (http, 0); http = NULL; + http_session_release (session); + session = NULL; } goto once_more; From 6cc4119ec03be61c78189a0bec99372035289b91 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Fri, 5 Jul 2019 15:16:08 +0900 Subject: [PATCH 151/169] gpg: Return the last error for pubkey decryption. * g10/mainproc.c (proc_encrypted): Check ->result against -1. When c->dek == NULL, put GPG_ERR_NO_SECKEY only when not set. * g10/pubkey-enc.c (get_session_key): Set k->result by the result of get_it. When no secret key is available for some reasons, return the last specific error, if any. GnuPG-bug-id: 4561 Signed-off-by: NIIBE Yutaka --- g10/mainproc.c | 7 +++++-- g10/pubkey-enc.c | 36 ++++++++++++++++++++---------------- 2 files changed, 25 insertions(+), 18 deletions(-) diff --git a/g10/mainproc.c b/g10/mainproc.c index d99ac4386..ba03de660 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -583,7 +583,7 @@ proc_encrypted (CTX c, PACKET *pkt) struct pubkey_enc_list *list; for (list = c->pkenc_list; list; list = list->next) - if (list->result == GPG_ERR_NO_SECKEY) + if (list->result != -1) { char buf[20]; snprintf (buf, sizeof buf, "%08lX%08lX", @@ -668,7 +668,10 @@ proc_encrypted (CTX c, PACKET *pkt) } } else if (!c->dek) - result = GPG_ERR_NO_SECKEY; + { + if (!result) + result = GPG_ERR_NO_SECKEY; + } /* Compute compliance with CO_DE_VS. */ if (!result && is_status_enabled () diff --git a/g10/pubkey-enc.c b/g10/pubkey-enc.c index f61fa7abe..fb1b17143 100644 --- a/g10/pubkey-enc.c +++ b/g10/pubkey-enc.c @@ -75,25 +75,21 @@ gpg_error_t get_session_key (ctrl_t ctrl, struct pubkey_enc_list *list, DEK *dek) { PKT_public_key *sk = NULL; - int rc; + gpg_error_t err; void *enum_context = NULL; u32 keyid[2]; int search_for_secret_keys = 1; + struct pubkey_enc_list *k; if (DBG_CLOCK) log_clock ("get_session_key enter"); while (search_for_secret_keys) { - struct pubkey_enc_list *k; - sk = xmalloc_clear (sizeof *sk); - rc = enum_secret_keys (ctrl, &enum_context, sk); - if (rc) - { - rc = GPG_ERR_NO_SECKEY; - break; - } + err = enum_secret_keys (ctrl, &enum_context, sk); + if (err) + break; if (!(sk->pubkey_usage & PUBKEY_USAGE_ENC)) continue; @@ -132,8 +128,6 @@ get_session_key (ctrl_t ctrl, struct pubkey_enc_list *list, DEK *dek) if (openpgp_pk_test_algo2 (k->pubkey_algo, PUBKEY_USAGE_ENC)) continue; - k->result = GPG_ERR_NO_SECKEY; - if (sk->pubkey_algo != k->pubkey_algo) continue; @@ -154,16 +148,16 @@ get_session_key (ctrl_t ctrl, struct pubkey_enc_list *list, DEK *dek) else continue; - rc = get_it (ctrl, k, dek, sk, keyid); - if (!rc) + err = get_it (ctrl, k, dek, sk, keyid); + k->result = err; + if (!err) { - k->result = 0; if (!opt.quiet && !k->keyid[0] && !k->keyid[1]) log_info (_("okay, we are the anonymous recipient.\n")); search_for_secret_keys = 0; break; } - else if (gpg_err_code (rc) == GPG_ERR_FULLY_CANCELED) + else if (gpg_err_code (err) == GPG_ERR_FULLY_CANCELED) { search_for_secret_keys = 0; break; /* Don't try any more secret keys. */ @@ -172,9 +166,19 @@ get_session_key (ctrl_t ctrl, struct pubkey_enc_list *list, DEK *dek) } enum_secret_keys (ctrl, &enum_context, NULL); /* free context */ + if (gpg_err_code (err) == GPG_ERR_EOF) + { + err = gpg_error (GPG_ERR_NO_SECKEY); + + /* Return the last specific error, if any. */ + for (k = list; k; k = k->next) + if (k->result != -1) + err = k->result; + } + if (DBG_CLOCK) log_clock ("get_session_key leave"); - return rc; + return err; } From 38b9da7de3350b1e56b85a058cdb1fdded78cf6d Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Fri, 5 Jul 2019 15:46:19 +0900 Subject: [PATCH 152/169] sm: Return the last error for pubkey decryption. * sm/decrypt.c: Use TMP_RC for ksba_cms_get_issuer_serial, and return the last error when no key is available. Fix the error report with TMP_RC for second call of ksba_cms_get_issuer_serial. GnuPG-bug-id: 4561 Signed-off-by: NIIBE Yutaka --- sm/decrypt.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/sm/decrypt.c b/sm/decrypt.c index b0ab63f00..ec9800840 100644 --- a/sm/decrypt.c +++ b/sm/decrypt.c @@ -397,16 +397,17 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, estream_t out_fp) char *hexkeygrip = NULL; char *desc = NULL; char kidbuf[16+1]; + int tmp_rc; *kidbuf = 0; - rc = ksba_cms_get_issuer_serial (cms, recp, &issuer, &serial); - if (rc == -1 && recp) + tmp_rc = ksba_cms_get_issuer_serial (cms, recp, &issuer, &serial); + if (tmp_rc == -1 && recp) break; /* no more recipients */ audit_log_i (ctrl->audit, AUDIT_NEW_RECP, recp); - if (rc) + if (tmp_rc) log_error ("recp %d - error getting info: %s\n", - recp, gpg_strerror (rc)); + recp, gpg_strerror (tmp_rc)); else { ksba_cert_t cert = NULL; @@ -569,7 +570,7 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, estream_t out_fp) audit_log_i (ctrl->audit, AUDIT_NEW_RECP, recp); if (tmp_rc) log_error ("recp %d - error getting info: %s\n", - recp, gpg_strerror (rc)); + recp, gpg_strerror (tmp_rc)); else { char *tmpstr = gpgsm_format_sn_issuer (serial, issuer); @@ -583,7 +584,8 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, estream_t out_fp) if (!any_key) { - rc = gpg_error (GPG_ERR_NO_SECKEY); + if (!rc) + rc = gpg_error (GPG_ERR_NO_SECKEY); goto leave; } } From b0e8724b102535c27a8c973ec038d340858a8eb8 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 5 Jul 2019 08:41:42 +0200 Subject: [PATCH 153/169] wkd: Change client/server limit back to 64 KiB * tools/wks-receive.c (decrypt_data): Change limit. -- The former limit ~1MiB of was used during development. Signed-off-by: Werner Koch --- tools/wks-receive.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/wks-receive.c b/tools/wks-receive.c index e67da628d..e5d2ed4b2 100644 --- a/tools/wks-receive.c +++ b/tools/wks-receive.c @@ -96,7 +96,7 @@ decrypt_data (receive_ctx_t ctx) /* We limit the output to 64 KiB to avoid DoS using compression * tricks. A regular client will anyway only send a minimal key; * that is one w/o key signatures and attribute packets. */ - ccparray_put (&ccp, "--max-output=0xf0000"); /*FIXME: Change s/F/1/ */ + ccparray_put (&ccp, "--max-output=0x10000"); ccparray_put (&ccp, "--batch"); if (opt.verbose) ccparray_put (&ccp, "--verbose"); From 96bf8f477805bae58cfb77af8ceba418ff8aaad9 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 5 Jul 2019 09:31:58 +0200 Subject: [PATCH 154/169] gpg: With --auto-key-retrieve prefer WKD over keyservers. * g10/mainproc.c (check_sig_and_print): Print a hint on how to make use of the preferred keyserver. Remove keyserver lookup just by the keyid. Try a WKD lookup before a keyserver lookup. -- The use of the the keyid for lookups does not make much sense anymore since for quite some time we do have the fingerprint as part of the signature. GnuPG-bug-id: 4595 Signed-off-by: Werner Koch --- doc/gpg.texi | 24 ++++++++-- g10/keyserver.c | 2 +- g10/mainproc.c | 116 ++++++++++++++++++++++++++---------------------- 3 files changed, 85 insertions(+), 57 deletions(-) diff --git a/doc/gpg.texi b/doc/gpg.texi index 9513a4e0f..80c7f48f5 100644 --- a/doc/gpg.texi +++ b/doc/gpg.texi @@ -1814,10 +1814,26 @@ These options enable or disable the automatic retrieving of keys from a keyserver when verifying signatures made by keys that are not on the local keyring. The default is @option{--no-auto-key-retrieve}. -If the method "wkd" is included in the list of methods given to -@option{auto-key-locate}, the signer's user ID is part of the -signature, and the option @option{--disable-signer-uid} is not used, -the "wkd" method may also be used to retrieve a key. +The order of methods tried to lookup the key is: + +1. If a preferred keyserver is specified in the signature and the +option @option{honor-keyserver-url} is active (which is not the +default), that keyserver is tried. Note that the creator of the +signature uses the option @option{--sig-keyserver-url} to specify the +preferred keyserver for data signatures. + +2. If the signature has the Signer's UID set (e.g. using +@option{--sender} while creating the signature) a Web Key Directory +(WKD) lookup is done. This is the default configuration but can be +disabled by removing WKD from the auto-key-locate list or by using the +option @option{--disable-signer-uid}. + +3. If the option @option{honor-pka-record} is active, the legacy PKA +method is used. + +4. If any keyserver is configured and the Issuer Fingerprint is part +of the signature (since GnuPG 2.1.16), the configured keyservers are +tried. Note that this option makes a "web bug" like behavior possible. Keyserver or Web Key Directory operators can see which keys you diff --git a/g10/keyserver.c b/g10/keyserver.c index 3a6fe69a8..b07afb128 100644 --- a/g10/keyserver.c +++ b/g10/keyserver.c @@ -333,7 +333,7 @@ parse_keyserver_uri (const char *string,int require_scheme) { /* Three slashes means network path with a default host name. This is a hack because it does not crok all possible - combiantions. We should better repalce all code bythe parser + combinations. We should better replace all code by the parser from http.c. */ keyserver->path = xstrdup (uri+2); } diff --git a/g10/mainproc.c b/g10/mainproc.c index ba03de660..f44faf82d 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -1843,7 +1843,6 @@ check_sig_and_print (CTX c, kbnode_t node) int is_revkey = 0; char *issuer_fpr = NULL; PKT_public_key *pk = NULL; /* The public key for the signature or NULL. */ - int tried_ks_by_fpr; const void *extrahash = NULL; size_t extrahashlen = 0; @@ -2002,12 +2001,17 @@ check_sig_and_print (CTX c, kbnode_t node) rc = do_check_sig (c, node, extrahash, extrahashlen, NULL, &is_expkey, &is_revkey, &pk); - /* If the key isn't found, check for a preferred keyserver. */ - if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY && sig->flags.pref_ks) + /* If the key isn't found, check for a preferred keyserver. Note + * that this is only done if honor-keyserver-url has been set. We + * test for this in the loop so that we can show info about the + * preferred keyservers. */ + if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY + && sig->flags.pref_ks) { const byte *p; int seq = 0; size_t n; + int any_pref_ks = 0; while ((p=enum_sig_subpkt (sig->hashed,SIGSUBPKT_PREF_KS,&n,&seq,NULL))) { @@ -2018,9 +2022,10 @@ check_sig_and_print (CTX c, kbnode_t node) log_info(_("Key available at: ") ); print_utf8_buffer (log_get_stream(), p, n); log_printf ("\n"); + any_pref_ks = 1; - if (opt.keyserver_options.options&KEYSERVER_AUTO_KEY_RETRIEVE - && opt.keyserver_options.options&KEYSERVER_HONOR_KEYSERVER_URL) + if ((opt.keyserver_options.options&KEYSERVER_AUTO_KEY_RETRIEVE) + && (opt.keyserver_options.options&KEYSERVER_HONOR_KEYSERVER_URL)) { struct keyserver_spec *spec; @@ -2029,6 +2034,10 @@ check_sig_and_print (CTX c, kbnode_t node) { int res; + if (DBG_LOOKUP) + log_debug ("trying auto-key-retrieve method %s\n", + "Pref-KS"); + free_public_key (pk); pk = NULL; glo_ctrl.in_auto_key_retrieve++; @@ -2037,6 +2046,9 @@ check_sig_and_print (CTX c, kbnode_t node) if (!res) rc = do_check_sig (c, node, extrahash, extrahashlen, NULL, &is_expkey, &is_revkey, &pk); + else if (DBG_LOOKUP) + log_debug ("lookup via %s failed: %s\n", "Pref-KS", + gpg_strerror (res)); free_keyserver_spec (spec); if (!rc) @@ -2044,10 +2056,44 @@ check_sig_and_print (CTX c, kbnode_t node) } } } + + if (any_pref_ks + && (opt.keyserver_options.options&KEYSERVER_AUTO_KEY_RETRIEVE) + && !(opt.keyserver_options.options&KEYSERVER_HONOR_KEYSERVER_URL)) + log_info (_("Note: Use '%s' to make use of this info\n"), + "--keyserver-option honor-keyserver-url"); + } + + /* If the above methods didn't work, our next try is to retrieve the + * key from the WKD. This requires that WKD is in the AKL and the + * Signer's UID is in the signature. */ + if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY + && (opt.keyserver_options.options & KEYSERVER_AUTO_KEY_RETRIEVE) + && !opt.flags.disable_signer_uid + && akl_has_wkd_method () + && sig->signers_uid) + { + int res; + + if (DBG_LOOKUP) + log_debug ("trying auto-key-retrieve method %s\n", "WKD"); + free_public_key (pk); + pk = NULL; + glo_ctrl.in_auto_key_retrieve++; + res = keyserver_import_wkd (c->ctrl, sig->signers_uid, 1, NULL, NULL); + glo_ctrl.in_auto_key_retrieve--; + /* Fixme: If the fingerprint is embedded in the signature, + * compare it to the fingerprint of the returned key. */ + if (!res) + rc = do_check_sig (c, node, extrahash, extrahashlen, + NULL, &is_expkey, &is_revkey, &pk); + else if (DBG_LOOKUP) + log_debug ("lookup via %s failed: %s\n", "WKD", gpg_strerror (res)); } /* If the avove methods didn't work, our next try is to use the URI - * from a DNS PKA record. */ + * from a DNS PKA record. This is a legacy method which will + * eventually be removed. */ if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY && (opt.keyserver_options.options & KEYSERVER_AUTO_KEY_RETRIEVE) && (opt.keyserver_options.options & KEYSERVER_HONOR_PKA_RECORD)) @@ -2064,6 +2110,9 @@ check_sig_and_print (CTX c, kbnode_t node) spec = parse_keyserver_uri (uri, 1); if (spec) { + if (DBG_LOOKUP) + log_debug ("trying auto-key-retrieve method %s\n", "PKA"); + free_public_key (pk); pk = NULL; glo_ctrl.in_auto_key_retrieve++; @@ -2073,16 +2122,16 @@ check_sig_and_print (CTX c, kbnode_t node) if (!res) rc = do_check_sig (c, node, extrahash, extrahashlen, NULL, &is_expkey, &is_revkey, &pk); + else if (DBG_LOOKUP) + log_debug ("lookup via %s failed: %s\n", "PKA", + gpg_strerror (res)); } } } /* If the above methods didn't work, our next try is to locate * the key via its fingerprint from a keyserver. This requires - * that the signers fingerprint is encoded in the signature. We - * favor this over the WKD method (to be tried next), because an - * arbitrary keyserver is less subject to web bug like monitoring. */ - tried_ks_by_fpr = 0; + * that the signers fingerprint is encoded in the signature. */ if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY && (opt.keyserver_options.options&KEYSERVER_AUTO_KEY_RETRIEVE) && keyserver_any_configured (c->ctrl)) @@ -2094,60 +2143,23 @@ check_sig_and_print (CTX c, kbnode_t node) p = issuer_fpr_raw (sig, &n); if (p) { + if (DBG_LOOKUP) + log_debug ("trying auto-key-retrieve method %s\n", "KS"); + /* v4 or v5 packet with a SHA-1/256 fingerprint. */ free_public_key (pk); pk = NULL; glo_ctrl.in_auto_key_retrieve++; res = keyserver_import_fprint (c->ctrl, p, n, opt.keyserver, 1); - tried_ks_by_fpr = 1; glo_ctrl.in_auto_key_retrieve--; if (!res) rc = do_check_sig (c, node, extrahash, extrahashlen, NULL, &is_expkey, &is_revkey, &pk); + else if (DBG_LOOKUP) + log_debug ("lookup via %s failed: %s\n", "KS", gpg_strerror (res)); } } - /* If the above methods didn't work, our next try is to retrieve the - * key from the WKD. */ - if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY - && (opt.keyserver_options.options & KEYSERVER_AUTO_KEY_RETRIEVE) - && !opt.flags.disable_signer_uid - && akl_has_wkd_method () - && sig->signers_uid) - { - int res; - - free_public_key (pk); - pk = NULL; - glo_ctrl.in_auto_key_retrieve++; - res = keyserver_import_wkd (c->ctrl, sig->signers_uid, 1, NULL, NULL); - glo_ctrl.in_auto_key_retrieve--; - /* Fixme: If the fingerprint is embedded in the signature, - * compare it to the fingerprint of the returned key. */ - if (!res) - rc = do_check_sig (c, node, extrahash, extrahashlen, - NULL, &is_expkey, &is_revkey, &pk); - } - - /* If the above methods did't work, our next try is to use a - * keyserver. */ - if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY - && (opt.keyserver_options.options&KEYSERVER_AUTO_KEY_RETRIEVE) - && !tried_ks_by_fpr - && keyserver_any_configured (c->ctrl)) - { - int res; - - free_public_key (pk); - pk = NULL; - glo_ctrl.in_auto_key_retrieve++; - res = keyserver_import_keyid (c->ctrl, sig->keyid, opt.keyserver, 1); - glo_ctrl.in_auto_key_retrieve--; - if (!res) - rc = do_check_sig (c, node, extrahash, extrahashlen, - NULL, &is_expkey, &is_revkey, &pk); - } - if (!rc || gpg_err_code (rc) == GPG_ERR_BAD_SIGNATURE) { kbnode_t un, keyblock; From 39c40e572c5632f836d089dce49224f947244bf2 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Mon, 8 Jul 2019 12:26:51 +0900 Subject: [PATCH 155/169] scd: Fix keygrip search. * scd/app.c (app_do_with_keygrip): Break the entire loop. Fixes-commit: 5a5288d051a551a1a8f169225e62572f6ee8cb10 Signed-off-by: NIIBE Yutaka --- scd/app.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scd/app.c b/scd/app.c index ed7adc3a3..57c4b7743 100644 --- a/scd/app.c +++ b/scd/app.c @@ -1706,10 +1706,12 @@ app_do_with_keygrip (ctrl_t ctrl, int action, const char *keygrip_str) err = a->fnc.with_keygrip (a, ctrl, action, keygrip_str); unlock_card (c); if (!err) - break; + goto leave_the_loop; } } + leave_the_loop: + /* FIXME: Add app switching logic. The above code assumes that the * actions can be performend without switching. This needs to be * checked. */ From c51a5685554a06e00ae1e99070b44613b2f8d417 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Tue, 9 Jul 2019 10:56:09 +0900 Subject: [PATCH 156/169] scd: ccid-driver: Initial getting ATR more robustly. * scd/ccid-driver.c (send_power_off): New. (do_close_reader): Use send_power_off. (ccid_get_atr): Add error recovery. GnuPG-bug-id: 4616 Signed-off-by: NIIBE Yutaka --- scd/ccid-driver.c | 57 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 39 insertions(+), 18 deletions(-) diff --git a/scd/ccid-driver.c b/scd/ccid-driver.c index e092a2b9a..f791c3ad5 100644 --- a/scd/ccid-driver.c +++ b/scd/ccid-driver.c @@ -1717,31 +1717,37 @@ ccid_require_get_status (ccid_driver_t handle) return 1; } - -static void -do_close_reader (ccid_driver_t handle) +static int +send_power_off (ccid_driver_t handle) { int rc; unsigned char msg[100]; size_t msglen; unsigned char seqno; - if (!handle->powered_off) - { - msg[0] = PC_to_RDR_IccPowerOff; - msg[5] = 0; /* slot */ - msg[6] = seqno = handle->seqno++; - msg[7] = 0; /* RFU */ - msg[8] = 0; /* RFU */ - msg[9] = 0; /* RFU */ - set_msg_len (msg, 0); - msglen = 10; + msg[0] = PC_to_RDR_IccPowerOff; + msg[5] = 0; /* slot */ + msg[6] = seqno = handle->seqno++; + msg[7] = 0; /* RFU */ + msg[8] = 0; /* RFU */ + msg[9] = 0; /* RFU */ + set_msg_len (msg, 0); + msglen = 10; - rc = bulk_out (handle, msg, msglen, 0); - if (!rc) - bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_SlotStatus, - seqno, 2000, 0); - } + rc = bulk_out (handle, msg, msglen, 0); + if (!rc) + bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_SlotStatus, + seqno, 2000, 0); + return rc; +} + +static void +do_close_reader (ccid_driver_t handle) +{ + int rc; + + if (!handle->powered_off) + send_power_off (handle); if (handle->transfer) { @@ -2597,6 +2603,21 @@ ccid_get_atr (ccid_driver_t handle, NULL, 0, NULL)) goto again; } + else if (statusbits == 0 && CCID_COMMAND_FAILED (msg)) + { + /* Card was active already, and something went wrong with + PC_to_RDR_IccPowerOn command. It may be baud-rate mismatch + between the card and the reader. To recover from this state, + send PC_to_RDR_IccPowerOff command to reset the card and try + again. + */ + rc = send_power_off (handle); + if (rc) + return rc; + + statusbits = 1; + goto again; + } else if (CCID_COMMAND_FAILED (msg)) return CCID_DRIVER_ERR_CARD_IO_ERROR; From 37d758e5f2b5d07dc937098cf48096cf35ea61e4 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Tue, 9 Jul 2019 16:59:56 +0900 Subject: [PATCH 157/169] sm: Fix card access. * sm/call-agent.c (gpgsm_scd_pksign): Cast to integer for %b. -- This fix is needed on big endian machine where size_t is bigger than integer. Signed-off-by: NIIBE Yutaka --- sm/call-agent.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sm/call-agent.c b/sm/call-agent.c index 1fbb449bc..b37c2e53d 100644 --- a/sm/call-agent.c +++ b/sm/call-agent.c @@ -409,19 +409,19 @@ gpgsm_scd_pksign (ctrl_t ctrl, const char *keyid, const char *desc, { case GCRY_PK_RSA: rc = gcry_sexp_build (&sig, NULL, "(sig-val(rsa(s%b)))", - sigbuflen, sigbuf); + (int)sigbuflen, sigbuf); break; case GCRY_PK_ECC: rc = gcry_sexp_build (&sig, NULL, "(sig-val(ecdsa(r%b)(s%b)))", - sigbuflen/2, sigbuf, - sigbuflen/2, sigbuf + sigbuflen/2); + (int)sigbuflen/2, sigbuf, + (int)sigbuflen/2, sigbuf + sigbuflen/2); break; case GCRY_PK_EDDSA: rc = gcry_sexp_build (&sig, NULL, "(sig-val(eddsa(r%b)(s%b)))", - sigbuflen/2, sigbuf, - sigbuflen/2, sigbuf + sigbuflen/2); + (int)sigbuflen/2, sigbuf, + (int)sigbuflen/2, sigbuf + sigbuflen/2); break; default: From eec150eca78a053193a0994a96482791b5da36be Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 9 Jul 2019 11:07:35 +0200 Subject: [PATCH 158/169] gpg: Fix regression in option "self-sigs-only". * g10/import.c (read_block): Make sure KEYID is availabale also on a pending packet. -- Reported-by: Phil Pennock Fixes-commit: 2e349bb6173789e0e9e42c32873d89c7bc36cea4 Signed-off-by: Werner Koch --- g10/import.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/g10/import.c b/g10/import.c index ce7602a9f..ceba15b68 100644 --- a/g10/import.c +++ b/g10/import.c @@ -866,6 +866,7 @@ read_block( IOBUF a, unsigned int options, kbnode_t root = NULL; int in_cert, in_v3key, skip_sigs; u32 keyid[2]; + int got_keyid = 0; unsigned int dropped_nonselfsigs = 0; *r_v3keys = 0; @@ -874,7 +875,11 @@ read_block( IOBUF a, unsigned int options, { root = new_kbnode( *pending_pkt ); *pending_pkt = NULL; + log_assert (root->pkt->pkttype == PKT_PUBLIC_KEY + || root->pkt->pkttype == PKT_SECRET_KEY); in_cert = 1; + keyid_from_pk (root->pkt->pkt.public_key, keyid); + got_keyid = 1; } else in_cert = 0; @@ -994,6 +999,7 @@ read_block( IOBUF a, unsigned int options, goto x_default; if (!(options & IMPORT_SELF_SIGS_ONLY)) goto x_default; + log_assert (got_keyid); if (pkt->pkt.signature->keyid[0] == keyid[0] && pkt->pkt.signature->keyid[1] == keyid[1]) { /* This is likely a self-signature. We import this one. @@ -1016,6 +1022,11 @@ read_block( IOBUF a, unsigned int options, case PKT_PUBLIC_KEY: case PKT_SECRET_KEY: + if (!got_keyid) + { + keyid_from_pk (pkt->pkt.public_key, keyid); + got_keyid = 1; + } if (in_cert) /* Store this packet. */ { *pending_pkt = pkt; @@ -1023,7 +1034,6 @@ read_block( IOBUF a, unsigned int options, goto ready; } in_cert = 1; - keyid_from_pk (pkt->pkt.public_key, keyid); goto x_default; default: From a29156d5a650702ad79fe11f45782bc4bc159c13 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 9 Jul 2019 11:13:51 +0200 Subject: [PATCH 159/169] gpg: Do not try the import fallback if the options are already used. * g10/import.c (import_one): Check options. Signed-off-by: Werner Koch --- g10/import.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/g10/import.c b/g10/import.c index ceba15b68..32c0f65cb 100644 --- a/g10/import.c +++ b/g10/import.c @@ -2337,7 +2337,9 @@ import_one (ctrl_t ctrl, from_sk, silent, screener, screener_arg, origin, url, r_valid); if (gpg_err_code (err) == GPG_ERR_TOO_LARGE - && gpg_err_source (err) == GPG_ERR_SOURCE_KEYBOX) + && gpg_err_source (err) == GPG_ERR_SOURCE_KEYBOX + && ((options & (IMPORT_SELF_SIGS_ONLY | IMPORT_CLEAN)) + != (IMPORT_SELF_SIGS_ONLY | IMPORT_CLEAN))) { /* We hit the maximum image length. Ask the wrapper to do * everything again but this time with some extra options. */ From a7a043e82555a9da984c6fb01bfec4990d904690 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Wed, 10 Jul 2019 15:06:54 +0900 Subject: [PATCH 160/169] gpg: Fix keyring retrieval. * g10/keyring.c (keyring_get_keyblock): Avoid O(N^2) append. GnuPG-bug-id: 4592 Signed-off-by: NIIBE Yutaka --- g10/keyring.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/g10/keyring.c b/g10/keyring.c index 21791a6ac..5fa499759 100644 --- a/g10/keyring.c +++ b/g10/keyring.c @@ -473,11 +473,14 @@ keyring_get_keyblock (KEYRING_HANDLE hd, KBNODE *ret_kb) } in_cert = 1; - node = lastnode = new_kbnode (pkt); + node = new_kbnode (pkt); if (!keyblock) - keyblock = node; + keyblock = lastnode = node; else - add_kbnode (keyblock, node); + { + lastnode->next = node; + lastnode = node; + } switch (pkt->pkttype) { case PKT_PUBLIC_KEY: From 33c17a8008c3ba3bb740069f9f97c7467f156b54 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Wed, 10 Jul 2019 15:42:07 +0900 Subject: [PATCH 161/169] gpg: Improve import slowness. * g10/import.c (read_block): Avoid O(N^2) append. (sec_to_pub_keyblock): Likewise. Signed-off-by: NIIBE Yutaka --- g10/import.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/g10/import.c b/g10/import.c index 32c0f65cb..c32dbf059 100644 --- a/g10/import.c +++ b/g10/import.c @@ -864,6 +864,7 @@ read_block( IOBUF a, unsigned int options, struct parse_packet_ctx_s parsectx; PACKET *pkt; kbnode_t root = NULL; + kbnode_t lastnode = NULL; int in_cert, in_v3key, skip_sigs; u32 keyid[2]; int got_keyid = 0; @@ -873,7 +874,7 @@ read_block( IOBUF a, unsigned int options, if (*pending_pkt) { - root = new_kbnode( *pending_pkt ); + root = lastnode = new_kbnode( *pending_pkt ); *pending_pkt = NULL; log_assert (root->pkt->pkttype == PKT_PUBLIC_KEY || root->pkt->pkttype == PKT_SECRET_KEY); @@ -1041,9 +1042,12 @@ read_block( IOBUF a, unsigned int options, if (in_cert && valid_keyblock_packet (pkt->pkttype)) { if (!root ) - root = new_kbnode (pkt); + root = lastnode = new_kbnode (pkt); else - add_kbnode (root, new_kbnode (pkt)); + { + lastnode->next = new_kbnode (pkt); + lastnode = lastnode->next; + } pkt = xmalloc (sizeof *pkt); } else @@ -2664,6 +2668,7 @@ sec_to_pub_keyblock (kbnode_t sec_keyblock) kbnode_t pub_keyblock = NULL; kbnode_t ctx = NULL; kbnode_t secnode, pubnode; + kbnode_t lastnode = NULL; unsigned int tag = 0; /* Set a tag to all nodes. */ @@ -2703,9 +2708,12 @@ sec_to_pub_keyblock (kbnode_t sec_keyblock) pubnode->tag = secnode->tag; if (!pub_keyblock) - pub_keyblock = pubnode; + pub_keyblock = lastnode = pubnode; else - add_kbnode (pub_keyblock, pubnode); + { + lastnode->next = pubnode; + lastnode = pubnode; + } } return pub_keyblock; From 29c7fb4053d207c163802642babbdbb6f885727e Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Thu, 11 Jul 2019 12:32:44 +0900 Subject: [PATCH 162/169] gpg: Fix getting User ID. * g10/getkey.c (user_id_db): Remove, as no use anymore. (get_user_id_string): Use cache_get_uid_bykid. (get_user_id_byfpr): Use cache_get_uid_byfpr. * g10/objcache.c (cache_get_uid_byfpr): New. * g10/objcache.h (cache_get_uid_byfpr): New. Fixes-commit: 64a5fd37271a3e454c0d59ac3500e1a1b232e4f7 Signed-off-by: NIIBE Yutaka --- g10/getkey.c | 123 ++++++++++++++++--------------------------------- g10/objcache.c | 47 +++++++++++++++++++ g10/objcache.h | 1 + 3 files changed, 88 insertions(+), 83 deletions(-) diff --git a/g10/getkey.c b/g10/getkey.c index 228042d1a..57617a0a9 100644 --- a/g10/getkey.c +++ b/g10/getkey.c @@ -134,14 +134,6 @@ static int pk_cache_disabled; #if MAX_UID_CACHE_ENTRIES < 5 #error we really need the userid cache #endif -typedef struct user_id_db -{ - struct user_id_db *next; - keyid_list_t keyids; - int len; - char name[1]; -} *user_id_db_t; -static user_id_db_t user_id_db; static void merge_selfsigs (ctrl_t ctrl, kbnode_t keyblock); static int lookup (ctrl_t ctrl, getkey_ctx_t ctx, int want_secret, @@ -3759,62 +3751,40 @@ get_seckey_default_or_card (ctrl_t ctrl, PKT_public_key *pk, * this string must be freed by xfree. If R_NOUID is not NULL it is * set to true if a user id was not found; otherwise to false. */ static char * -get_user_id_string (ctrl_t ctrl, u32 * keyid, int mode, size_t *r_len, - int *r_nouid) +get_user_id_string (ctrl_t ctrl, u32 * keyid, int mode) { - user_id_db_t r; - keyid_list_t a; - int pass = 0; + char *name; + unsigned int namelen; char *p; log_assert (mode != 2); - if (r_nouid) - *r_nouid = 0; - /* Try it two times; second pass reads from the database. */ - do + name = cache_get_uid_bykid (keyid, &namelen); + if (!name) { - for (r = user_id_db; r; r = r->next) - { - for (a = r->keyids; a; a = a->next) - { - if (a->keyid[0] == keyid[0] && a->keyid[1] == keyid[1]) - { - if (mode == 2) - { - BUG (); - } - else - { - if (mode) - p = xasprintf ("%08lX%08lX %.*s", - (ulong) keyid[0], (ulong) keyid[1], - r->len, r->name); - else - p = xasprintf ("%s %.*s", keystr (keyid), - r->len, r->name); - if (r_len) - *r_len = strlen (p); - } - - return p; - } - } - } + /* Get it so that the cache will be filled. */ + if (!get_pubkey (ctrl, NULL, keyid)) + name = cache_get_uid_bykid (keyid, &namelen); } - while (++pass < 2 && !get_pubkey (ctrl, NULL, keyid)); - if (mode == 2) - p = xstrdup (user_id_not_found_utf8 ()); - else if (mode) - p = xasprintf ("%08lX%08lX [?]", (ulong) keyid[0], (ulong) keyid[1]); + if (name) + { + if (mode) + p = xasprintf ("%08lX%08lX %.*s", + (ulong) keyid[0], (ulong) keyid[1], namelen, name); + else + p = xasprintf ("%s %.*s", keystr (keyid), namelen, name); + + xfree (name); + } else - p = xasprintf ("%s [?]", keystr (keyid)); + { + if (mode) + p = xasprintf ("%08lX%08lX [?]", (ulong) keyid[0], (ulong) keyid[1]); + else + p = xasprintf ("%s [?]", keystr (keyid)); + } - if (r_nouid) - *r_nouid = 1; - if (r_len) - *r_len = strlen (p); return p; } @@ -3822,7 +3792,7 @@ get_user_id_string (ctrl_t ctrl, u32 * keyid, int mode, size_t *r_len, char * get_user_id_string_native (ctrl_t ctrl, u32 * keyid) { - char *p = get_user_id_string (ctrl, keyid, 0, NULL, NULL); + char *p = get_user_id_string (ctrl, keyid, 0); char *p2 = utf8_to_native (p, strlen (p), 0); xfree (p); return p2; @@ -3832,7 +3802,7 @@ get_user_id_string_native (ctrl_t ctrl, u32 * keyid) char * get_long_user_id_string (ctrl_t ctrl, u32 * keyid) { - return get_user_id_string (ctrl, keyid, 1, NULL, NULL); + return get_user_id_string (ctrl, keyid, 1); } @@ -3888,36 +3858,23 @@ get_user_id_native (ctrl_t ctrl, u32 *keyid) static char * get_user_id_byfpr (ctrl_t ctrl, const byte *fpr, size_t fprlen, size_t *rn) { - user_id_db_t r; - char *p; - int pass = 0; + char *name; - /* Try it two times; second pass reads from the database. */ - do + name = cache_get_uid_byfpr (fpr, fprlen, rn); + if (!name) { - for (r = user_id_db; r; r = r->next) - { - keyid_list_t a; - for (a = r->keyids; a; a = a->next) - { - if (a->fprlen == fprlen && !memcmp (a->fpr, fpr, fprlen)) - { - /* An empty string as user id is possible. Make - sure that the malloc allocates one byte and does - not bail out. */ - p = xmalloc (r->len? r->len : 1); - memcpy (p, r->name, r->len); - *rn = r->len; - return p; - } - } - } + /* Get it so that the cache will be filled. */ + if (!get_pubkey_byfprint (ctrl, NULL, NULL, fpr, fprlen)) + name = cache_get_uid_byfpr (fpr, fprlen, rn); } - while (++pass < 2 - && !get_pubkey_byfprint (ctrl, NULL, NULL, fpr, fprlen)); - p = xstrdup (user_id_not_found_utf8 ()); - *rn = strlen (p); - return p; + + if (!name) + { + name = xstrdup (user_id_not_found_utf8 ()); + *rn = strlen (name); + } + + return name; } /* Like get_user_id_byfpr, but convert the string to the native diff --git a/g10/objcache.c b/g10/objcache.c index 7eb92cd0d..adb0717d7 100644 --- a/g10/objcache.c +++ b/g10/objcache.c @@ -640,3 +640,50 @@ cache_get_uid_bykid (u32 *keyid, unsigned int *r_length) return p; } + + +/* Return the user id string for FPR with FPRLEN. If a user id is not + * found (or on malloc error) NULL is returned. If R_LENGTH is not + * NULL the length of the user id is stored there; this does not + * included the always appended nul. Note that a user id may include + * an internal nul which can be detected by the caller by comparing to + * the returned length. */ +char * +cache_get_uid_byfpr (const byte *fpr, size_t fprlen, size_t *r_length) +{ + char *p; + unsigned int hash; + u32 keyid[2]; + key_item_t ki; + + if (r_length) + *r_length = 0; + + if (!key_table) + return NULL; + + keyid_from_fingerprint (NULL, fpr, fprlen, keyid); + hash = key_table_hasher (keyid); + for (ki = key_table[hash]; ki; ki = ki->next) + if (ki->fprlen == fprlen && !memcmp (ki->fpr, fpr, fprlen)) + break; /* Found */ + + if (!ki) + return NULL; /* Not found. */ + + if (!ki->ui) + p = NULL; /* No user id known for key. */ + else + { + p = xtrymalloc (ki->ui->namelen + 1); + if (p) + { + memcpy (p, ki->ui->name, ki->ui->namelen + 1); + if (r_length) + *r_length = ki->ui->namelen; + ki->usecount++; + } + } + + return p; +} diff --git a/g10/objcache.h b/g10/objcache.h index e92679168..edf129525 100644 --- a/g10/objcache.h +++ b/g10/objcache.h @@ -24,5 +24,6 @@ void objcache_dump_stats (void); void cache_put_keyblock (kbnode_t keyblock); char *cache_get_uid_bykid (u32 *keyid, unsigned int *r_length); +char *cache_get_uid_byfpr (const byte *fpr, size_t fprlen, size_t *r_length); #endif /*GNUPG_G10_OBJCACHE_H*/ From 2536bf276189a474a3a1ca9716368cf5d991b0d6 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Thu, 11 Jul 2019 13:21:48 +0900 Subject: [PATCH 163/169] scd: Fix debug logging of the internal CCID driver. * scd/ccid-driver.c [GNUPG_MAJOR_VERSION] (DEBUGOUT): Use log_debug. Fixes-commit: 79c99921e35921140c83d7c101829d95f038f3da Signed-off-by: NIIBE Yutaka --- scd/ccid-driver.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/scd/ccid-driver.c b/scd/ccid-driver.c index f791c3ad5..789774606 100644 --- a/scd/ccid-driver.c +++ b/scd/ccid-driver.c @@ -112,10 +112,15 @@ #define CCID_CMD_TIMEOUT (5*1000) /* Depending on how this source is used we either define our error - * output to go to stderr or to the GnuPG based logging functions. We - * use the latter when GNUPG_SCD_MAIN_HEADER is defined. */ -#if defined(GNUPG_SCD_MAIN_HEADER) -# include GNUPG_SCD_MAIN_HEADER + * output to go to the GnuPG based logging functions or to stderr. We + * use the former when GNUPG_MAJOR_VERSION or GNUPG_SCD_MAIN_HEADER is + * defined. */ +#if defined(GNUPG_MAJOR_VERSION) || defined(GNUPG_SCD_MAIN_HEADER) +# if defined(GNUPG_SCD_MAIN_HEADER) +# include GNUPG_SCD_MAIN_HEADER +# else /* This is the modularized GnuPG 1.9 or later. */ +# include "scdaemon.h" +# endif # define DEBUGOUT(t) do { if (debug_level) \ log_debug (DRVNAME t); } while (0) From b31060425226b45deb21915bf5cd8b6ba62bd098 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Thu, 11 Jul 2019 14:37:27 +0900 Subject: [PATCH 164/169] scd: Fix internal CCID driver, so that -DTEST works. * scd/ccid-driver.c: Support a test program by ccid-driver. Signed-off-by: NIIBE Yutaka --- scd/ccid-driver.c | 97 +++++++++++++++++++++++++++-------------------- 1 file changed, 55 insertions(+), 42 deletions(-) diff --git a/scd/ccid-driver.c b/scd/ccid-driver.c index 789774606..45faa05bd 100644 --- a/scd/ccid-driver.c +++ b/scd/ccid-driver.c @@ -951,7 +951,7 @@ get_escaped_usb_string (libusb_device_handle *idev, int idx, rc = libusb_control_transfer (idev, LIBUSB_ENDPOINT_IN, LIBUSB_REQUEST_GET_DESCRIPTOR, (LIBUSB_DT_STRING << 8), 0, - (char*)buf, sizeof buf, 1000 /* ms timeout */); + buf, sizeof buf, 1000 /* ms timeout */); #ifdef USE_NPTH npth_protect (); #endif @@ -966,7 +966,7 @@ get_escaped_usb_string (libusb_device_handle *idev, int idx, rc = libusb_control_transfer (idev, LIBUSB_ENDPOINT_IN, LIBUSB_REQUEST_GET_DESCRIPTOR, (LIBUSB_DT_STRING << 8) + idx, langid, - (char*)buf, sizeof buf, 1000 /* ms timeout */); + buf, sizeof buf, 1000 /* ms timeout */); #ifdef USE_NPTH npth_protect (); #endif @@ -1481,7 +1481,9 @@ intr_cb (struct libusb_transfer *transfer) { DEBUGOUT ("CCID: card removed\n"); handle->powered_off = 1; +#if defined(GNUPG_MAJOR_VERSION) scd_kick_the_loop (); +#endif } else { @@ -1496,7 +1498,9 @@ intr_cb (struct libusb_transfer *transfer) device_removed: DEBUGOUT ("CCID: device removed\n"); handle->powered_off = 1; +#if defined(GNUPG_MAJOR_VERSION) scd_kick_the_loop (); +#endif } } @@ -1904,7 +1908,7 @@ bulk_out (ccid_driver_t handle, unsigned char *msg, size_t msglen, npth_unprotect (); #endif rc = libusb_bulk_transfer (handle->idev, handle->ep_bulk_out, - (char*)msg, msglen, &transferred, + msg, msglen, &transferred, 5000 /* ms timeout */); #ifdef USE_NPTH npth_protect (); @@ -1951,7 +1955,7 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length, npth_unprotect (); #endif rc = libusb_bulk_transfer (handle->idev, handle->ep_bulk_in, - (char*)buffer, length, &msglen, timeout); + buffer, length, &msglen, timeout); #ifdef USE_NPTH npth_protect (); #endif @@ -2071,7 +2075,9 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length, { DEBUGOUT ("CCID: card inactive/removed\n"); handle->powered_off = 1; +#if defined(GNUPG_MAJOR_VERSION) scd_kick_the_loop (); +#endif } } @@ -2085,7 +2091,7 @@ static int abort_cmd (ccid_driver_t handle, int seqno) { int rc; - char dummybuf[8]; + unsigned char dummybuf[8]; unsigned char msg[100]; int msglen; @@ -2136,7 +2142,7 @@ abort_cmd (ccid_driver_t handle, int seqno) npth_unprotect (); #endif rc = libusb_bulk_transfer (handle->idev, handle->ep_bulk_out, - (char*)msg, msglen, &transferred, + msg, msglen, &transferred, 5000 /* ms timeout */); #ifdef USE_NPTH npth_protect (); @@ -2154,7 +2160,7 @@ abort_cmd (ccid_driver_t handle, int seqno) npth_unprotect (); #endif rc = libusb_bulk_transfer (handle->idev, handle->ep_bulk_in, - (char*)msg, sizeof msg, &msglen, + msg, sizeof msg, &msglen, 5000 /*ms timeout*/); #ifdef USE_NPTH npth_protect (); @@ -2275,7 +2281,7 @@ ccid_poll (ccid_driver_t handle) int i, j; rc = libusb_interrupt_transfer (handle->idev, handle->ep_intr, - (char*)msg, sizeof msg, &msglen, + msg, sizeof msg, &msglen, 0 /* ms timeout */ ); if (rc == LIBUSB_ERROR_TIMEOUT) return 0; @@ -3737,7 +3743,7 @@ print_result (int rc, const unsigned char *data, size_t length) int main (int argc, char **argv) { - int rc; + gpg_error_t err; ccid_driver_t ccid; int slotstat; unsigned char result[512]; @@ -3746,6 +3752,8 @@ main (int argc, char **argv) int verify_123456 = 0; int did_verify = 0; int no_poll = 0; + int idx_max; + struct ccid_dev_table *ccid_table; if (argc) { @@ -3789,27 +3797,36 @@ main (int argc, char **argv) break; } - rc = ccid_open_reader (&ccid, argc? *argv:NULL, NULL); - if (rc) + err = ccid_dev_scan (&idx_max, &ccid_table); + if (err) return 1; + if (idx_max == 0) + return 1; + + err = ccid_open_reader (argc? *argv:NULL, 0, ccid_table, &ccid, NULL); + if (err) + return 1; + + ccid_dev_scan_finish (ccid_table, idx_max); + if (!no_poll) ccid_poll (ccid); fputs ("getting ATR ...\n", stderr); - rc = ccid_get_atr (ccid, NULL, 0, NULL); - if (rc) + err = ccid_get_atr (ccid, NULL, 0, NULL); + if (err) { - print_error (rc); + print_error (err); return 1; } if (!no_poll) ccid_poll (ccid); fputs ("getting slot status ...\n", stderr); - rc = ccid_slot_status (ccid, &slotstat, 1); - if (rc) + err = ccid_slot_status (ccid, &slotstat, 1); + if (err) { - print_error (rc); + print_error (err); return 1; } @@ -3820,10 +3837,10 @@ main (int argc, char **argv) { static unsigned char apdu[] = { 0, 0xA4, 4, 0, 6, 0xD2, 0x76, 0x00, 0x01, 0x24, 0x01}; - rc = ccid_transceive (ccid, - apdu, sizeof apdu, - result, sizeof result, &resultlen); - print_result (rc, result, resultlen); + err = ccid_transceive (ccid, + apdu, sizeof apdu, + result, sizeof result, &resultlen); + print_result (err, result, resultlen); } @@ -3833,9 +3850,9 @@ main (int argc, char **argv) fputs ("getting OpenPGP DO 0x65 ....\n", stderr); { static unsigned char apdu[] = { 0, 0xCA, 0, 0x65, 254 }; - rc = ccid_transceive (ccid, apdu, sizeof apdu, - result, sizeof result, &resultlen); - print_result (rc, result, resultlen); + err = ccid_transceive (ccid, apdu, sizeof apdu, + result, sizeof result, &resultlen); + print_result (err, result, resultlen); } if (!no_pinpad) @@ -3845,22 +3862,18 @@ main (int argc, char **argv) if (!no_pinpad) { static unsigned char apdu[] = { 0, 0x20, 0, 0x81 }; + pininfo_t pininfo = { 0, 0, 0 }; - - if (ccid_transceive_secure (ccid, - apdu, sizeof apdu, - 1, 0, 0, 0, + if (ccid_transceive_secure (ccid, apdu, sizeof apdu, &pininfo, NULL, 0, NULL)) fputs ("can't verify using a PIN-Pad reader\n", stderr); else { - fputs ("verifying CHV1 using the PINPad ....\n", stderr); + fputs ("verifying CHV1 using the PINPad ....\n", stderr); - rc = ccid_transceive_secure (ccid, - apdu, sizeof apdu, - 1, 0, 0, 0, - result, sizeof result, &resultlen); - print_result (rc, result, resultlen); + err = ccid_transceive_secure (ccid, apdu, sizeof apdu, &pininfo, + result, sizeof result, &resultlen); + print_result (err, result, resultlen); did_verify = 1; } } @@ -3871,20 +3884,20 @@ main (int argc, char **argv) { static unsigned char apdu[] = {0, 0x20, 0, 0x81, 6, '1','2','3','4','5','6'}; - rc = ccid_transceive (ccid, apdu, sizeof apdu, - result, sizeof result, &resultlen); - print_result (rc, result, resultlen); + err = ccid_transceive (ccid, apdu, sizeof apdu, + result, sizeof result, &resultlen); + print_result (err, result, resultlen); } } - if (!rc) + if (!err) { fputs ("getting OpenPGP DO 0x5E ....\n", stderr); { static unsigned char apdu[] = { 0, 0xCA, 0, 0x5E, 254 }; - rc = ccid_transceive (ccid, apdu, sizeof apdu, - result, sizeof result, &resultlen); - print_result (rc, result, resultlen); + err = ccid_transceive (ccid, apdu, sizeof apdu, + result, sizeof result, &resultlen); + print_result (err, result, resultlen); } } @@ -3895,7 +3908,7 @@ main (int argc, char **argv) /* * Local Variables: - * compile-command: "gcc -DTEST -Wall -I/usr/local/include -lusb -g ccid-driver.c" + * compile-command: "gcc -DTEST -DGPGRT_ENABLE_ES_MACROS -DHAVE_NPTH -DUSE_NPTH -Wall -I/usr/include/libusb-1.0 -I/usr/local/include -lusb-1.0 -g ccid-driver.c -lnpth -lgpg-error" * End: */ #endif /*TEST*/ From 02d8b383833bac0382e910a2058b11b127acfd4d Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Thu, 11 Jul 2019 14:55:28 +0900 Subject: [PATCH 165/169] agent: Relax the handling of pinentry error for keyboard grab. * agent/call-pinentry.c (start_pinentry): It's not fatal when pinentry doesn't support no-grab/grab option. GnuPG-bug-id: 4587 Signed-off-by: NIIBE Yutaka --- agent/call-pinentry.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/agent/call-pinentry.c b/agent/call-pinentry.c index 9271b4ae9..a895a8b8f 100644 --- a/agent/call-pinentry.c +++ b/agent/call-pinentry.c @@ -423,7 +423,17 @@ start_pinentry (ctrl_t ctrl) opt.no_grab? "OPTION no-grab":"OPTION grab", NULL, NULL, NULL, NULL, NULL, NULL); if (rc) - return unlock_pinentry (ctrl, rc); + { + if (gpg_err_code (rc) == GPG_ERR_NOT_SUPPORTED + || gpg_err_code (rc) == GPG_ERR_UNKNOWN_OPTION) + { + if (opt.verbose) + log_info ("Option no-grab/grab is ignored by pinentry.\n"); + /* Keep going even if the feature is not supported. */ + } + else + return unlock_pinentry (ctrl, rc); + } value = session_env_getenv (ctrl->session_env, "GPG_TTY"); if (value) From 89303b9998ea30d87b4c60dd48097dbe5e986a89 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Fri, 12 Jul 2019 09:26:00 +0900 Subject: [PATCH 166/169] gpg: Don't try decryption by session key when NULL. * g10/mainproc.c (proc_encrypted): Only call get_session_key when PKENC_LIST is not NULL. Return GPG_ERR_BAD_KEY, instead of GPG_ERR_NO_SECKEY, when it's encrypted only by symmetric key. Signed-off-by: NIIBE Yutaka --- g10/mainproc.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/g10/mainproc.c b/g10/mainproc.c index f44faf82d..8a9005c21 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -574,7 +574,7 @@ proc_encrypted (CTX c, PACKET *pkt) write_status_error ("pkdecrypt_failed", result); } } - else + else if (c->pkenc_list) { c->dek = xmalloc_secure_clear (sizeof *c->dek); result = get_session_key (c->ctrl, c->pkenc_list, c->dek); @@ -669,8 +669,11 @@ proc_encrypted (CTX c, PACKET *pkt) } else if (!c->dek) { + if (c->symkeys && !c->pkenc_list) + result = gpg_error (GPG_ERR_BAD_KEY); + if (!result) - result = GPG_ERR_NO_SECKEY; + result = gpg_error (GPG_ERR_NO_SECKEY); } /* Compute compliance with CO_DE_VS. */ @@ -783,7 +786,7 @@ proc_encrypted (CTX c, PACKET *pkt) if ((gpg_err_code (result) == GPG_ERR_BAD_KEY || gpg_err_code (result) == GPG_ERR_CHECKSUM || gpg_err_code (result) == GPG_ERR_CIPHER_ALGO) - && *c->dek->s2k_cacheid != '\0') + && c->dek && *c->dek->s2k_cacheid != '\0') { if (opt.debug) log_debug ("cleared passphrase cached with ID: %s\n", From 4e601c7643fcfa3d8babcce58daa4c6c6a42d338 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Fri, 12 Jul 2019 12:11:26 +0900 Subject: [PATCH 167/169] Fix a reference in comment. * common/openpgp-s2k.c: Fix. Signed-off-by: NIIBE Yutaka --- common/openpgp-s2k.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/openpgp-s2k.c b/common/openpgp-s2k.c index 2b0ba604b..69de76329 100644 --- a/common/openpgp-s2k.c +++ b/common/openpgp-s2k.c @@ -39,7 +39,7 @@ #include "openpgpdefs.h" -/* Pack an s2k iteration count into the form specified in RFC-48800. +/* Pack an s2k iteration count into the form specified in RFC-4880. * If we're in between valid values, round up. */ unsigned char encode_s2k_iterations (int iterations) From 58bab1a8784b0dbae70b5d74757cd56484292d1c Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Fri, 12 Jul 2019 17:19:17 +0900 Subject: [PATCH 168/169] doc: Dependencies for figures are only for maintainers. * doc/Makefile.am [MAINTAINER_MODE] (.svg.eps, etc.): Enable only when maintainer-mode. GnuPG-bug-id: 4280 Signed-off-by: NIIBE Yutaka --- doc/Makefile.am | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/Makefile.am b/doc/Makefile.am index cef9ff29f..0c44217d0 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -121,6 +121,7 @@ mkdefsinc: mkdefsinc.c Makefile ../config.h $(CC_FOR_BUILD) -I. -I.. -I$(srcdir) $(AM_CPPFLAGS) \ -o $@ $(srcdir)/mkdefsinc.c +if MAINTAINER_MODE .svg.eps: convert `test -f '$<' || echo '$(srcdir)/'`$< $@ @@ -141,6 +142,7 @@ mkdefsinc: mkdefsinc.c Makefile ../config.h .fig.pdf: fig2dev -L pdf `test -f '$<' || echo '$(srcdir)/'`$< $@ +endif yat2m-stamp: $(myman_sources) defs.inc From fb1c8978f57b8f92e2ea9d10afc1d133656c9706 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 12 Jul 2019 12:49:12 +0200 Subject: [PATCH 169/169] scd: Remove useless GNUPG_SCD_MAIN_HEADER macro. * scd/apdu.c (): Remove never set and useless macro. * scd/ccid-driver.c: Ditto. * scd/iso7816.c: Ditto. -- Signed-off-by: Werner Koch --- scd/apdu.c | 6 ++---- scd/ccid-driver.c | 11 +++-------- scd/iso7816.c | 6 ++---- 3 files changed, 7 insertions(+), 16 deletions(-) diff --git a/scd/apdu.c b/scd/apdu.c index 254c74101..2df113c5e 100644 --- a/scd/apdu.c +++ b/scd/apdu.c @@ -42,12 +42,10 @@ #include "rapdu.h" #endif /*USE_G10CODE_RAPDU*/ -#if defined(GNUPG_SCD_MAIN_HEADER) -# include GNUPG_SCD_MAIN_HEADER -#else /*!GNUPG_SCD_MAIN_HEADER*/ +#if defined(GNUPG_MAJOR_VERSION) # include "scdaemon.h" # include "../common/exechelp.h" -#endif /*!GNUPG_SCD_MAIN_HEADER*/ +#endif /*GNUPG_MAJOR_VERSION*/ #include "../common/host2net.h" diff --git a/scd/ccid-driver.c b/scd/ccid-driver.c index 45faa05bd..d762490c8 100644 --- a/scd/ccid-driver.c +++ b/scd/ccid-driver.c @@ -112,15 +112,10 @@ #define CCID_CMD_TIMEOUT (5*1000) /* Depending on how this source is used we either define our error - * output to go to the GnuPG based logging functions or to stderr. We - * use the former when GNUPG_MAJOR_VERSION or GNUPG_SCD_MAIN_HEADER is - * defined. */ -#if defined(GNUPG_MAJOR_VERSION) || defined(GNUPG_SCD_MAIN_HEADER) -# if defined(GNUPG_SCD_MAIN_HEADER) -# include GNUPG_SCD_MAIN_HEADER -# else /* This is the modularized GnuPG 1.9 or later. */ + * output to go to stderr or to the GnuPG based logging functions. We + * use the latter when GNUPG_MAJOR_VERSION is defined. */ +#if defined(GNUPG_MAJOR_VERSION) # include "scdaemon.h" -# endif # define DEBUGOUT(t) do { if (debug_level) \ log_debug (DRVNAME t); } while (0) diff --git a/scd/iso7816.c b/scd/iso7816.c index b09354f16..954aa3d4a 100644 --- a/scd/iso7816.c +++ b/scd/iso7816.c @@ -23,11 +23,9 @@ #include #include -#if defined(GNUPG_SCD_MAIN_HEADER) -# include GNUPG_SCD_MAIN_HEADER -#else +#if defined(GNUPG_MAJOR_VERSION) # include "scdaemon.h" -#endif /*!GNUPG_SCD_MAIN_HEADER*/ +#endif /*GNUPG_MAJOR_VERSION*/ #include "iso7816.h" #include "apdu.h"