From 26da47ae53d51e16ae6867cd419ddbf124a94933 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 21 Sep 2020 14:47:53 +0200 Subject: [PATCH] scd: Extend KEYPAIRINFO with an algorithm string. * scd/app-openpgp.c (send_keypair_info): Emit the algo string as part of a KEYPAIRINFO. * scd/command.c (do_readkey): Ditto. * scd/app-piv.c (do_readkey): Ditto. * scd/app-nks.c (do_learn_status_core): Ditto. (struct fid_cache_s): Add field algostr. (flush_fid_cache): Release it. (keygripstr_from_pk_file): Fill it and add it to the cache. Use a single exit label. * scd/app-help.c (app_help_get_keygrip_string_pk): Add new arg r_algostr. Change all callers. -- This is helpful so that callers do not need to parse the key for this basic information. Use "scd readkey --info-only" to return the info status line instead of the key material; using just --info returns the info in addition to the key material. Signed-off-by: Werner Koch --- agent/call-scd.c | 2 +- doc/DETAILS | 9 ++++---- scd/app-common.h | 2 +- scd/app-help.c | 21 ++++++++++++++--- scd/app-nks.c | 57 ++++++++++++++++++++++++++++++++++++----------- scd/app-openpgp.c | 23 +++++++++++++++++-- scd/app-piv.c | 7 +++++- scd/command.c | 10 +++++++-- 8 files changed, 104 insertions(+), 27 deletions(-) diff --git a/agent/call-scd.c b/agent/call-scd.c index c58199539..3ede33c1d 100644 --- a/agent/call-scd.c +++ b/agent/call-scd.c @@ -677,7 +677,7 @@ readkey_status_cb (void *opaque, const char *line) && !parm->keyref) { /* The format of such a line is: - * KEYPAIRINFO [usage] [keytime] + * KEYPAIRINFO [usage] [keytime] [algostr] * * Here we only need the keyref. We use only the first received * KEYPAIRINFO; it is possible to receive several if there are diff --git a/doc/DETAILS b/doc/DETAILS index 728239e19..98f4af511 100644 --- a/doc/DETAILS +++ b/doc/DETAILS @@ -2,7 +2,7 @@ #+TITLE: GnuPG Details # Globally disable superscripts and subscripts: #+OPTIONS: ^:{} -# +#+STARTUP: showall # Note: This file uses org-mode; it should be easy to read as plain # text but be aware of some markup peculiarities: Verbatim code is @@ -1183,7 +1183,7 @@ pkd:0:1024:B665B1435F4C2 .... FF26ABB: byte is either '-' for standard key or 'e' for an ephemeral key. The second byte is either '-' or 'r' for a known revoked key. -*** KEYPAIRINFO [] [] +*** KEYPAIRINFO [] [] [] This status is emitted by scdaemon and gpg-agent to convey brief information about keypairs stored on tokens. is the @@ -1195,8 +1195,9 @@ pkd:0:1024:B665B1435F4C2 .... FF26ABB: encryption, 's' for signing, 'a' for authentication). A '-' can be used to tell that usage flags are not conveyed. is used by OpenPGP cards for the stored key creation time. A '-' means no - info available. The format is the usual ISO string are a number - with the seconds since Epoch. + info available. The format is the usual ISO string or a number + with the seconds since Epoch. is the algorithm or curve + this key uses (e.g. "rsa2048") or a "-" if not known. *** MANUFACTURER [] This status returns the Manufactorer ID as the unsigned number N. diff --git a/scd/app-common.h b/scd/app-common.h index cab82fbb6..d245b8b0a 100644 --- a/scd/app-common.h +++ b/scd/app-common.h @@ -220,7 +220,7 @@ 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, gcry_sexp_t *r_pkey, - int *r_algo); + int *r_algo, char **r_algostr); gpg_error_t app_help_get_keygrip_string (ksba_cert_t cert, char *hexkeygrip, gcry_sexp_t *r_pkey, int *r_algo); gpg_error_t app_help_pubkey_from_cert (const void *cert, size_t certlen, diff --git a/scd/app-help.c b/scd/app-help.c index f2b592399..b599add71 100644 --- a/scd/app-help.c +++ b/scd/app-help.c @@ -57,10 +57,12 @@ app_help_count_bits (const unsigned char *a, size_t len) * function succeeded, the S-expression representing the key is stored * there. The caller needs to call gcry_sexp_release on that. If * R_ALGO is not NULL the public key algorithm id of Libgcrypt is - * stored there. */ + * stored there. If R_ALGOSTR is not NULL and the function succeeds a + * newly allocated algo string (e.g. "rsa2048") is stored there. */ gpg_error_t app_help_get_keygrip_string_pk (const void *pk, size_t pklen, char *hexkeygrip, - gcry_sexp_t *r_pkey, int *r_algo) + gcry_sexp_t *r_pkey, int *r_algo, + char **r_algostr) { gpg_error_t err; gcry_sexp_t s_pkey; @@ -68,6 +70,8 @@ app_help_get_keygrip_string_pk (const void *pk, size_t pklen, char *hexkeygrip, if (r_pkey) *r_pkey = NULL; + if (r_algostr) + *r_algostr = NULL; err = gcry_sexp_sscan (&s_pkey, NULL, pk, pklen); if (err) @@ -81,6 +85,17 @@ app_help_get_keygrip_string_pk (const void *pk, size_t pklen, char *hexkeygrip, if (r_algo) *r_algo = get_pk_algo_from_key (s_pkey); + if (r_algostr) + { + *r_algostr = pubkey_algo_string (s_pkey, NULL); + if (!*r_algostr) + { + err = gpg_error_from_syserror (); + gcry_sexp_release (s_pkey); + return err; + } + } + if (r_pkey) *r_pkey = s_pkey; else @@ -116,7 +131,7 @@ app_help_get_keygrip_string (ksba_cert_t cert, char *hexkeygrip, if (!n) return gpg_error (GPG_ERR_INV_SEXP); err = app_help_get_keygrip_string_pk ((void*)p, n, hexkeygrip, - r_pkey, r_algo); + r_pkey, r_algo, NULL); ksba_free (p); return err; } diff --git a/scd/app-nks.c b/scd/app-nks.c index 5d326cb37..47be7cd85 100644 --- a/scd/app-nks.c +++ b/scd/app-nks.c @@ -178,6 +178,7 @@ struct fid_cache_s { int fid; /* Zero for an unused slot. */ unsigned int got_keygrip:1; /* The keygrip and algo are valid. */ int algo; + char *algostr; /* malloced. */ char keygripstr[2*KEYGRIP_LEN+1]; }; @@ -217,6 +218,8 @@ flush_fid_cache (app_t app) while (app->app_local->fid_cache) { struct fid_cache_s *next = app->app_local->fid_cache->next; + if (app->app_local->fid_cache) + xfree (app->app_local->fid_cache->algostr); xfree (app->app_local->fid_cache); app->app_local->fid_cache = next; } @@ -270,10 +273,12 @@ get_dispserialno (app_t app) * all the ECC parameters required, we don't do that but rely that the * corresponding certificate at CFID is already available and get the * public key from there. If R_ALGO is not NULL the public key - * algorithm for the returned KEYGRIP is stored there. */ + * algorithm for the returned KEYGRIP is stored there. If R_ALGOSTR + * is not NULL the public key algo string (e.g. "rsa2048") is stored + * there. */ static gpg_error_t keygripstr_from_pk_file (app_t app, int pkfid, int cfid, char *r_gripstr, - int *r_algo) + int *r_algo, char **r_algostr) { gpg_error_t err; unsigned char grip[20]; @@ -281,6 +286,7 @@ keygripstr_from_pk_file (app_t app, int pkfid, int cfid, char *r_gripstr, size_t buflen[2]; gcry_sexp_t sexp = NULL; int algo = 0; /* Public key algo. */ + char *algostr = NULL; /* Public key algo string. */ int i; int offset[2] = { 0, 0 }; struct fid_cache_s *ci; @@ -290,9 +296,17 @@ keygripstr_from_pk_file (app_t app, int pkfid, int cfid, char *r_gripstr, { if (!ci->got_keygrip) return gpg_error (GPG_ERR_NOT_FOUND); + if (r_algostr && !ci->algostr) + break; /* Not in the cache - try w/o cache. */ memcpy (r_gripstr, ci->keygripstr, 2*KEYGRIP_LEN+1); if (r_algo) *r_algo = ci->algo; + if (r_algostr) + { + *r_algostr = xtrystrdup (ci->algostr); + if (!*r_algostr) + return gpg_error_from_syserror (); + } return 0; /* Found in cache. */ } @@ -308,7 +322,7 @@ keygripstr_from_pk_file (app_t app, int pkfid, int cfid, char *r_gripstr, { log_error ("nks: error reading certificate %04X: %s\n", cfid, gpg_strerror (err)); - return err; + goto leave; } err = app_help_pubkey_from_cert (cert, certlen, &pk, &pklen); @@ -317,10 +331,11 @@ keygripstr_from_pk_file (app_t app, int pkfid, int cfid, char *r_gripstr, { log_error ("nks: error parsing certificate %04X: %s\n", cfid, gpg_strerror (err)); - return err; + goto leave; } - err = app_help_get_keygrip_string_pk (pk, pklen, r_gripstr, NULL, &algo); + err = app_help_get_keygrip_string_pk (pk, pklen, r_gripstr, NULL, + &algo, &algostr); xfree (pk); if (err) log_error ("nks: error getting keygrip for certificate %04X: %s\n", @@ -331,17 +346,17 @@ keygripstr_from_pk_file (app_t app, int pkfid, int cfid, char *r_gripstr, err = iso7816_select_file (app_get_slot (app), pkfid, 0); if (err) - return err; + goto leave; err = iso7816_read_record (app_get_slot (app), 1, 1, 0, &buffer[0], &buflen[0]); if (err) - return err; + goto leave; err = iso7816_read_record (app_get_slot (app), 2, 1, 0, &buffer[1], &buflen[1]); if (err) { xfree (buffer[0]); - return err; + goto leave; } if (app->appversion < 3) @@ -391,7 +406,8 @@ keygripstr_from_pk_file (app_t app, int pkfid, int cfid, char *r_gripstr, { xfree (buffer[0]); xfree (buffer[1]); - return gpg_error_from_syserror (); + err = gpg_error_from_syserror (); + goto leave; } newbuf[0] = 0; memcpy (newbuf+1, buffer[i]+offset[i], buflen[i] - offset[i]); @@ -430,6 +446,12 @@ keygripstr_from_pk_file (app_t app, int pkfid, int cfid, char *r_gripstr, leave: if (!err) { + if (r_algostr) + { + *r_algostr = algostr; + algostr = NULL; + } + /* FIXME: We need to implement not_found caching. */ for (ci = app->app_local->fid_cache; ci; ci = ci->next) if (ci->fid && ci->fid == pkfid) @@ -437,6 +459,8 @@ keygripstr_from_pk_file (app_t app, int pkfid, int cfid, char *r_gripstr, /* Update the keygrip. */ memcpy (ci->keygripstr, r_gripstr, 2*KEYGRIP_LEN+1); ci->algo = algo; + xfree (ci->algostr); + ci->algostr = algostr? xtrystrdup (algostr) : NULL; ci->got_keygrip = 1; break; } @@ -461,6 +485,7 @@ keygripstr_from_pk_file (app_t app, int pkfid, int cfid, char *r_gripstr, } } gcry_sexp_release (sexp); + xfree (algostr); return err; } @@ -526,7 +551,7 @@ find_fid_by_keyref (app_t app, const char *keyref, int *r_idx, int *r_algo) err = keygripstr_from_pk_file (app, filelist[idx].fid, filelist[idx].iskeypair, - keygripstr, r_algo); + keygripstr, r_algo, NULL); if (err) { log_info ("nks: no keygrip for FID 0x%04X: %s - ignored\n", @@ -595,7 +620,7 @@ find_fid_by_keyref (app_t app, const char *keyref, int *r_idx, int *r_algo) /* We need to get the public key algo. */ err = keygripstr_from_pk_file (app, filelist[idx].fid, filelist[idx].iskeypair, - keygripstr, r_algo); + keygripstr, r_algo, NULL); if (err) log_error ("nks: no keygrip for FID 0x%04X: %s\n", filelist[idx].fid, gpg_strerror (err)); @@ -822,9 +847,11 @@ do_learn_status_core (app_t app, ctrl_t ctrl, unsigned int flags, char gripstr[40+1]; char usagebuf[5]; int usageidx = 0; + char *algostr = NULL; err = keygripstr_from_pk_file (app, filelist[i].fid, - filelist[i].iskeypair, gripstr, NULL); + filelist[i].iskeypair, gripstr, + NULL, &algostr); if (err) log_error ("can't get keygrip from FID 0x%04X: %s\n", filelist[i].fid, gpg_strerror (err)); @@ -843,8 +870,11 @@ do_learn_status_core (app_t app, ctrl_t ctrl, unsigned int flags, gripstr, 40, id_buf, strlen (id_buf), usagebuf, strlen (usagebuf), + "-", (size_t)1, + algostr, strlen (algostr), NULL, (size_t)0); } + xfree (algostr); } } } @@ -2073,7 +2103,8 @@ do_with_keygrip (app_t app, ctrl_t ctrl, int action, } err = keygripstr_from_pk_file (app, filelist[idx].fid, - filelist[idx].iskeypair, keygripstr, NULL); + filelist[idx].iskeypair, keygripstr, + NULL, NULL); if (err) { log_error ("can't get keygrip from FID 0x%04X: %s\n", diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 465819adc..c631383c0 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -2049,6 +2049,7 @@ send_keypair_info (app_t app, ctrl_t ctrl, int key) gpg_error_t err = 0; const char *usage; u32 fprtime; + char *algostr = NULL; err = get_public_key (app, keyno); if (err) @@ -2069,11 +2070,29 @@ send_keypair_info (app_t app, ctrl_t ctrl, int key) if (retrieve_fprtime_from_card (app, keyno, &fprtime)) fprtime = 0; - err = send_status_printf (ctrl, "KEYPAIRINFO", "%s OPENPGP.%d %s %lu", + { + gcry_sexp_t s_pkey; + if (gcry_sexp_new (&s_pkey, app->app_local->pk[keyno].key, + app->app_local->pk[keyno].keylen, 0)) + algostr = xtrystrdup ("?"); + else + { + algostr = pubkey_algo_string (s_pkey, NULL); + gcry_sexp_release (s_pkey); + } + } + if (!algostr) + { + err = gpg_error_from_syserror (); + goto leave; + } + + err = send_status_printf (ctrl, "KEYPAIRINFO", "%s OPENPGP.%d %s %lu %s", app->app_local->pk[keyno].keygrip_str, - keyno+1, usage, (unsigned long)fprtime); + keyno+1, usage, (unsigned long)fprtime, algostr); leave: + xfree (algostr); return err; } diff --git a/scd/app-piv.c b/scd/app-piv.c index 816c909cf..8ab778532 100644 --- a/scd/app-piv.c +++ b/scd/app-piv.c @@ -1538,8 +1538,10 @@ do_readkey (app_t app, ctrl_t ctrl, const char *keyrefstr, unsigned int flags, char keygripstr[KEYGRIP_LEN*2+1]; char idbuf[50]; const char *usage; + char *algostr; - err = app_help_get_keygrip_string_pk (pk, pklen, keygripstr, NULL, NULL); + err = app_help_get_keygrip_string_pk (pk, pklen, keygripstr, + NULL, NULL, &algostr); if (err) { log_error ("app_help_get_keygrip_string_pk failed: %s\n", @@ -1553,7 +1555,10 @@ do_readkey (app_t app, ctrl_t ctrl, const char *keyrefstr, unsigned int flags, keygripstr, strlen (keygripstr), idbuf, strlen (idbuf), usage, strlen (usage), + "-", (size_t)1, + algostr, strlen (algostr), NULL, (size_t)0); + xfree (algostr); } if (r_pk && r_pklen) diff --git a/scd/command.c b/scd/command.c index e2d366d47..56d422a4a 100644 --- a/scd/command.c +++ b/scd/command.c @@ -433,7 +433,7 @@ static const char hlp_learn[] = "or a \"CANCEL\" to force the function to terminate with a Cancel\n" "error message.\n" "\n" - "With the option --keypairinfo only KEYPARIINFO status lines are\n" + "With the option --keypairinfo only KEYPAIRINFO status lines are\n" "returned.\n" "\n" "The response of this command is a list of status lines formatted as\n" @@ -650,9 +650,11 @@ do_readkey (card_t card, ctrl_t ctrl, const char *line, if (opt_info) { char keygripstr[KEYGRIP_LEN*2+1]; + char *algostr; rc = app_help_get_keygrip_string_pk (*pk_p, *pklen_p, - keygripstr, NULL, NULL); + keygripstr, NULL, NULL, + &algostr); if (rc) { log_error ("app_help_get_keygrip_string failed: %s\n", @@ -665,7 +667,11 @@ do_readkey (card_t card, ctrl_t ctrl, const char *line, send_status_info (ctrl, "KEYPAIRINFO", keygripstr, strlen (keygripstr), line, strlen (line), + "-", (size_t)1, + "-", (size_t)1, + algostr, strlen (algostr), NULL, (size_t)0); + xfree (algostr); } } else