From 13013ec1c0d308b5d22f176f3850840cbbf21f05 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 26 May 2023 11:59:46 +0200 Subject: [PATCH] agent: Create and use Token entries to track the display s/n. * agent/findkey.c (agent_write_private_key): Add arg dispserialno and update the token. (agent_write_shadow_key): Add arg dispserialno and adjust all callers. -- GnuPG-bug-id: 6135 Note that this has been forward ported from 2.2 --- agent/agent.h | 13 ++++++---- agent/command-ssh.c | 9 +++++-- agent/command.c | 15 ++++++++--- agent/cvt-openpgp.c | 4 +-- agent/divert-tpm2.c | 2 +- agent/findkey.c | 61 ++++++++++++++++++++++++++++++++++++-------- agent/genkey.c | 3 ++- agent/learncard.c | 10 +++++++- agent/pksign.c | 9 ++++++- agent/protect-tool.c | 5 ++-- 10 files changed, 102 insertions(+), 29 deletions(-) diff --git a/agent/agent.h b/agent/agent.h index 4e7452eee..531fad210 100644 --- a/agent/agent.h +++ b/agent/agent.h @@ -452,10 +452,12 @@ void start_command_handler_ssh (ctrl_t, gnupg_fd_t); /*-- findkey.c --*/ 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 char *serialno, const char *keyref, - time_t timestamp); +gpg_error_t agent_write_private_key (const unsigned char *grip, + const void *buffer, size_t length, + int force, + const char *serialno, const char *keyref, + const char *dispserialno, + time_t timestamp); gpg_error_t agent_key_from_file (ctrl_t ctrl, const char *cache_nonce, const char *desc_text, @@ -587,7 +589,8 @@ gpg_error_t s2k_hash_passphrase (const char *passphrase, int hashalgo, unsigned char *key, size_t keylen); gpg_error_t agent_write_shadow_key (const unsigned char *grip, const char *serialno, const char *keyid, - const unsigned char *pkbuf, int force); + const unsigned char *pkbuf, int force, + const char *dispserialno); /*-- trustlist.c --*/ diff --git a/agent/command-ssh.c b/agent/command-ssh.c index 51111a60d..ca3993321 100644 --- a/agent/command-ssh.c +++ b/agent/command-ssh.c @@ -2432,9 +2432,14 @@ card_key_available (ctrl_t ctrl, const struct card_key_info_s *keyinfo, hex2bin (keyinfo->keygrip, grip, sizeof (grip)); if ( agent_key_available (grip) ) { + char *dispserialno; + /* (Shadow)-key is not available in our key storage. */ + agent_card_getattr (ctrl, "$DISPSERIALNO", &dispserialno, + keyinfo->keygrip); err = agent_write_shadow_key (grip, keyinfo->serialno, - keyinfo->idstr, pkbuf, 0); + keyinfo->idstr, pkbuf, 0, dispserialno); + xfree (dispserialno); if (err) { xfree (pkbuf); @@ -3282,7 +3287,7 @@ ssh_identity_register (ctrl_t ctrl, ssh_key_type_spec_t *spec, /* Store this key to our key storage. We do not store a creation * timestamp because we simply do not know. */ err = agent_write_private_key (key_grip_raw, buffer, buffer_n, 0, - NULL, NULL, 0); + NULL, NULL, NULL, 0); if (err) goto out; diff --git a/agent/command.c b/agent/command.c index dd7cb5e57..b7a71cbe5 100644 --- a/agent/command.c +++ b/agent/command.c @@ -1359,7 +1359,14 @@ cmd_readkey (assuan_context_t ctx, char *line) if (agent_key_available (grip)) { /* (Shadow)-key is not available in our key storage. */ - rc = agent_write_shadow_key (grip, serialno, keyid, pkbuf, 0); + char *dispserialno; + char hexgrip[40+1]; + + bin2hex (grip, 20, hexgrip); + agent_card_getattr (ctrl, "$DISPSERIALNO", &dispserialno, hexgrip); + rc = agent_write_shadow_key (grip, serialno, keyid, pkbuf, 0, + dispserialno); + xfree (dispserialno); if (rc) goto leave; } @@ -2916,11 +2923,11 @@ cmd_import_key (assuan_context_t ctx, char *line) ctrl->s2k_count); if (!err) err = agent_write_private_key (grip, finalkey, finalkeylen, force, - NULL, NULL, opt_timestamp); + NULL, NULL, NULL, opt_timestamp); } else - err = agent_write_private_key (grip, key, realkeylen, force, NULL, NULL, - opt_timestamp); + err = agent_write_private_key (grip, key, realkeylen, force, + NULL, NULL, NULL, opt_timestamp); leave: gcry_sexp_release (openpgp_sexp); diff --git a/agent/cvt-openpgp.c b/agent/cvt-openpgp.c index 9bb815ff8..6aad35bff 100644 --- a/agent/cvt-openpgp.c +++ b/agent/cvt-openpgp.c @@ -1148,7 +1148,7 @@ convert_from_openpgp_native (ctrl_t ctrl, &protectedkey, &protectedkeylen, ctrl->s2k_count)) agent_write_private_key (grip, protectedkey, protectedkeylen, 1, - NULL, NULL, 0); + NULL, NULL, NULL, 0); xfree (protectedkey); } else @@ -1157,7 +1157,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, NULL, NULL, 0); + 1, NULL, NULL, NULL, 0); } } diff --git a/agent/divert-tpm2.c b/agent/divert-tpm2.c index 4cae66218..b2f884f93 100644 --- a/agent/divert-tpm2.c +++ b/agent/divert-tpm2.c @@ -50,7 +50,7 @@ agent_write_tpm2_shadow_key (ctrl_t ctrl, const unsigned char *grip, len = gcry_sexp_canon_len (shdkey, 0, NULL, NULL); err = agent_write_private_key (grip, shdkey, len, 1 /*force*/, - NULL, NULL, 0); + NULL, NULL, NULL, 0); xfree (shdkey); if (err) log_error ("error writing key: %s\n", gpg_strerror (err)); diff --git a/agent/findkey.c b/agent/findkey.c index 098d5224f..a9cb96a0c 100644 --- a/agent/findkey.c +++ b/agent/findkey.c @@ -84,12 +84,13 @@ linefeed_to_percent0A (const char *string) * storage. With FORCE passed as true an existing key with the given * GRIP will get overwritten. If SERIALNO and KEYREF are given a * Token line is added to the key if the extended format is used. If - * TIMESTAMP is not zero and the key doies not yet exists it will be + * TIMESTAMP is not zero and the key does not yet exists it will be * recorded as creation date. */ -int +gpg_error_t agent_write_private_key (const unsigned char *grip, const void *buffer, size_t length, int force, const char *serialno, const char *keyref, + const char *dispserialno, time_t timestamp) { gpg_error_t err; @@ -100,7 +101,10 @@ agent_write_private_key (const unsigned char *grip, nvc_t pk = NULL; gcry_sexp_t key = NULL; int remove = 0; + char *token0 = NULL; char *token = NULL; + char *dispserialno_buffer = NULL; + char **tokenfields = NULL; bin2hex (grip, 20, hexgrip); strcpy (hexgrip+40, ".key"); @@ -225,19 +229,34 @@ agent_write_private_key (const unsigned char *grip, { nve_t item; const char *s; + size_t token0len; - token = strconcat (serialno, " ", keyref, NULL); - if (!token) + if (dispserialno) + { + /* Escape the DISPSERIALNO. */ + dispserialno_buffer = percent_plus_escape (dispserialno); + if (!dispserialno_buffer) + { + err = gpg_error_from_syserror (); + goto leave; + } + dispserialno = dispserialno_buffer; + } + + token0 = strconcat (serialno, " ", keyref, NULL); + if (token0) + token = strconcat (token0, " - ", dispserialno? dispserialno:"-", NULL); + if (!token0 || !token) { err = gpg_error_from_syserror (); goto leave; } - /* fixme: the strcmp should compare only the first two strings. */ + token0len = strlen (token0); for (item = nvc_lookup (pk, "Token:"); item; item = nve_next_value (item, "Token:")) - if ((s = nve_value (item)) && !strcmp (s, token)) + if ((s = nve_value (item)) && !strncmp (s, token0, token0len)) break; if (!item) { @@ -248,6 +267,23 @@ agent_write_private_key (const unsigned char *grip, if (err) goto leave; } + else + { + /* Token exists: Update the display s/n. It may have + * changed due to changes in a newer software version. */ + if (s && (tokenfields = strtokenize (s, " \t\n")) + && tokenfields[0] && tokenfields[1] && tokenfields[2] + && tokenfields[3] + && !strcmp (tokenfields[3], dispserialno)) + ; /* No need to update Token entry. */ + else + { + err = nve_set (item, token); + if (err) + goto leave; + } + } + } /* If a timestamp has been supplied and the key is new, write a @@ -300,12 +336,15 @@ agent_write_private_key (const unsigned char *grip, leave: es_fclose (fp); - if (remove) + if (remove && fname) gnupg_remove (fname); xfree (fname); + xfree (token); + xfree (token0); + xfree (dispserialno_buffer); + xfree (tokenfields); gcry_sexp_release (key); nvc_release (pk); - xfree (token); return err; } @@ -1794,7 +1833,8 @@ agent_delete_key (ctrl_t ctrl, const char *desc_text, gpg_error_t agent_write_shadow_key (const unsigned char *grip, const char *serialno, const char *keyid, - const unsigned char *pkbuf, int force) + const unsigned char *pkbuf, int force, + const char *dispserialno) { gpg_error_t err; unsigned char *shadow_info; @@ -1821,7 +1861,8 @@ 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, serialno, keyid, 0); + err = agent_write_private_key (grip, shdkey, len, force, + serialno, keyid, dispserialno, 0); 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 7660443ca..741c05f4f 100644 --- a/agent/genkey.c +++ b/agent/genkey.c @@ -67,7 +67,8 @@ store_key (gcry_sexp_t private, const char *passphrase, int force, buf = p; } - rc = agent_write_private_key (grip, buf, len, force, NULL, NULL, timestamp); + rc = agent_write_private_key (grip, buf, len, force, + NULL, NULL, NULL, timestamp); xfree (buf); return rc; } diff --git a/agent/learncard.c b/agent/learncard.c index 678ff9b96..8d80b809d 100644 --- a/agent/learncard.c +++ b/agent/learncard.c @@ -408,7 +408,15 @@ agent_handle_learn (ctrl_t ctrl, int send, void *assuan_context, int force) goto leave; } - rc = agent_write_shadow_key (grip, serialno, item->id, pubkey, force); + { + char *dispserialno; + + agent_card_getattr (ctrl, "$DISPSERIALNO", &dispserialno, + item->hexgrip); + rc = agent_write_shadow_key (grip, serialno, item->id, pubkey, force, + dispserialno); + xfree (dispserialno); + } xfree (pubkey); if (rc) goto leave; diff --git a/agent/pksign.c b/agent/pksign.c index dfed0e398..a7b5c579f 100644 --- a/agent/pksign.c +++ b/agent/pksign.c @@ -372,8 +372,15 @@ agent_pksign_do (ctrl_t ctrl, const char *cache_nonce, } if (keyref) - agent_write_shadow_key (ctrl->keygrip, serialno, keyref, pkbuf, 0); + { + char *dispserialno; + agent_card_getattr (ctrl, "$DISPSERIALNO", &dispserialno, + hexgrip); + agent_write_shadow_key (ctrl->keygrip, serialno, keyref, pkbuf, + 0, dispserialno); + xfree (dispserialno); + } algo = get_pk_algo_from_key (s_pkey); xfree (serialno); diff --git a/agent/protect-tool.c b/agent/protect-tool.c index 87cf36814..17f6fd559 100644 --- a/agent/protect-tool.c +++ b/agent/protect-tool.c @@ -813,11 +813,11 @@ agent_askpin (ctrl_t ctrl, /* Replacement for the function in findkey.c. Here we write the key * to stdout. */ -int +gpg_error_t agent_write_private_key (const unsigned char *grip, const void *buffer, size_t length, int force, const char *serialno, const char *keyref, - time_t timestamp) + const char *dispserialno, time_t timestamp) { char hexgrip[40+4+1]; char *p; @@ -826,6 +826,7 @@ agent_write_private_key (const unsigned char *grip, (void)serialno; (void)keyref; (void)timestamp; + (void)dispserialno; bin2hex (grip, 20, hexgrip); strcpy (hexgrip+40, ".key");