gpg: Support dual keygrips.

* g10/keyid.c (keygrip_from_pk): Add arg get_second to support dual
algos.  Implement for Kyber.
(hexkeygrip_from_pk): Extend for dual algos.
* g10/call-agent.c (agent_keytotpm): Bail out for dual algos.
(agent_keytocard): Ditto.
(agent_probe_secret_key): Handle dual algos.
(agent_probe_any_secret_key): Ditto.
(agent_get_keyinfo): Allow for dual algos but take only the first key.
* g10/export.c (do_export_one_keyblock): Bail out for dual algos.
--

This also adds some fixmes which we eventually need to address.

GnuPG-bug-id: 6815
This commit is contained in:
Werner Koch 2024-04-05 12:02:32 +02:00
parent ce8b25270b
commit 53c6b1e858
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
10 changed files with 181 additions and 46 deletions

View File

@ -169,10 +169,11 @@ described here.
(the colon is quoted =\x3a=). For a "pub" record this field is
not used on --fixed-list-mode. A "uat" record puts the attribute
subpacket count here, a space, and then the total attribute
subpacket size. In gpgsm the issuer name comes here. The FPR and FP2
records store the fingerprints here. The fingerprint of a
subpacket size. In gpgsm the issuer name comes here. The FPR and
FP2 records store the fingerprints here. The fingerprint of a
revocation key is also stored here. A "grp" records puts the
keygrip here.
keygrip here; for combined algorithms the keygrips are delimited
by comma.
*** Field 11 - Signature class
@ -186,9 +187,6 @@ described here.
"rev" and "rvs" may be followed by a comma and a 2 digit hexnumber
with the revocation reason.
In a "grp" record the second keygrip for combined algorithms is
given here.
*** Field 12 - Key capabilities
The defined capabilities are:
@ -248,7 +246,7 @@ described here.
For pub, sub, sec, ssb, crt, and crs records this field is used
for the ECC curve name. For combined algorithms the first and the
second algorithm name, delimited by a '+', are put here.
second algorithm name, delimited by an underscore are put here.
*** Field 18 - Compliance flags

View File

@ -1080,6 +1080,12 @@ agent_keytotpm (ctrl_t ctrl, const char *hexgrip)
snprintf(line, DIM(line), "KEYTOTPM %s\n", hexgrip);
if (strchr (hexgrip, ','))
{
log_error ("storing a part of a dual key is not yet supported\n");
return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
}
rc = start_agent (ctrl, 0);
if (rc)
return rc;
@ -1109,6 +1115,13 @@ agent_keytocard (const char *hexgrip, int keyno, int force,
memset (&parm, 0, sizeof parm);
if (strchr (hexgrip, ','))
{
log_error ("storing a part of a dual key is not yet supported\n");
return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
}
snprintf (line, DIM(line), "KEYTOCARD %s%s %s OPENPGP.%d %s%s%s",
force?"--force ": "", hexgrip, serialno, keyno, timestamp,
ecdh_param_str? " ":"", ecdh_param_str? ecdh_param_str:"");
@ -2240,9 +2253,9 @@ agent_probe_secret_key (ctrl_t ctrl, PKT_public_key *pk)
{
gpg_error_t err;
char line[ASSUAN_LINELENGTH];
char *hexgrip;
char *hexgrip, *p;
struct keyinfo_data_parm_s keyinfo;
int result, result2;
memset (&keyinfo, 0, sizeof keyinfo);
@ -2253,28 +2266,64 @@ agent_probe_secret_key (ctrl_t ctrl, PKT_public_key *pk)
err = hexkeygrip_from_pk (pk, &hexgrip);
if (err)
return 0;
if ((p=strchr (hexgrip, ',')))
*p++ = 0;
snprintf (line, sizeof line, "KEYINFO %s", hexgrip);
xfree (hexgrip);
err = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL,
keyinfo_status_cb, &keyinfo);
xfree (keyinfo.serialno);
if (err)
return 0;
result = 0;
else if (keyinfo.card_available)
result = 4;
else if (keyinfo.passphrase_cached)
result = 3;
else if (keyinfo.is_smartcard)
result = 2;
else
result = 1;
if (keyinfo.card_available)
return 4;
if (!p)
{
xfree (hexgrip);
return result; /* Not a dual algo - we are ready. */
}
if (keyinfo.passphrase_cached)
return 3;
/* Now check the second keygrip. */
memset (&keyinfo, 0, sizeof keyinfo);
snprintf (line, sizeof line, "KEYINFO %s", p);
if (keyinfo.is_smartcard)
return 2;
err = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL,
keyinfo_status_cb, &keyinfo);
xfree (keyinfo.serialno);
if (err)
result2 = 0;
else if (keyinfo.card_available)
result2 = 4;
else if (keyinfo.passphrase_cached)
result2 = 3;
else if (keyinfo.is_smartcard)
result2 = 2;
else
result2 = 1;
return 1;
xfree (hexgrip);
if (result == result2)
return result; /* Both keys have the same status. */
else if (!result && result2)
return 0; /* Only first key available - return no key. */
else if (result && !result2)
return 0; /* Only second key not availabale - return no key. */
else if (result == 4 || result == 2)
return result; /* First key on card - don't care where the second is. */
else
return result;
}
/* Ask the agent whether a secret key is available for any of the
keys (primary or sub) in KEYBLOCK. Returns 0 if available. */
gpg_error_t
@ -2286,6 +2335,8 @@ agent_probe_any_secret_key (ctrl_t ctrl, kbnode_t keyblock)
kbnode_t kbctx, node;
int nkeys; /* (always zero in secret_keygrips mode) */
unsigned char grip[KEYGRIP_LEN];
unsigned char grip2[KEYGRIP_LEN];
int grip2_valid;
const unsigned char *s;
unsigned int n;
@ -2320,8 +2371,9 @@ agent_probe_any_secret_key (ctrl_t ctrl, kbnode_t keyblock)
}
if (err)
{
log_info ("problem with fast path key listing: %s - ignored\n",
gpg_strerror (err));
if (opt.quiet)
log_info ("problem with fast path key listing: %s - ignored\n",
gpg_strerror (err));
err = 0;
}
/* We want to do this only once. */
@ -2340,22 +2392,30 @@ agent_probe_any_secret_key (ctrl_t ctrl, kbnode_t keyblock)
if (ctrl && ctrl->secret_keygrips)
{
/* We got an array with all secret keygrips. Check this. */
err = keygrip_from_pk (node->pkt->pkt.public_key, grip);
err = keygrip_from_pk (node->pkt->pkt.public_key, grip, 0);
if (err)
return err;
err = keygrip_from_pk (node->pkt->pkt.public_key, grip2, 1);
if (err && gpg_err_code (err) != GPG_ERR_FALSE)
return err;
grip2_valid = !err;
for (s=ctrl->secret_keygrips, n = 0;
n < ctrl->secret_keygrips_len;
s += 20, n += 20)
{
if (!memcmp (s, grip, 20))
return 0;
if (grip2_valid && !memcmp (s, grip2, 20))
return 0;
}
err = gpg_error (GPG_ERR_NO_SECKEY);
/* Keep on looping over the keyblock. Never bump nkeys. */
}
else
{
if (nkeys && ((p - line) + 41) > (ASSUAN_LINELENGTH - 2))
if (nkeys
&& ((p - line) + 4*KEYGRIP_LEN+1+1) > (ASSUAN_LINELENGTH - 2))
{
err = assuan_transact (agent_ctx, line,
NULL, NULL, NULL, NULL, NULL, NULL);
@ -2365,13 +2425,24 @@ agent_probe_any_secret_key (ctrl_t ctrl, kbnode_t keyblock)
nkeys = 0;
}
err = keygrip_from_pk (node->pkt->pkt.public_key, grip);
err = keygrip_from_pk (node->pkt->pkt.public_key, grip, 0);
if (err)
return err;
*p++ = ' ';
bin2hex (grip, 20, p);
p += 40;
nkeys++;
err = keygrip_from_pk (node->pkt->pkt.public_key, grip2, 1);
if (err && gpg_err_code (err) != GPG_ERR_FALSE)
return err;
if (!err) /* Add the second keygrip from dual algos. */
{
*p++ = ' ';
bin2hex (grip2, 20, p);
p += 40;
nkeys++;
}
}
}
@ -2398,6 +2469,7 @@ agent_get_keyinfo (ctrl_t ctrl, const char *hexkeygrip,
gpg_error_t err;
char line[ASSUAN_LINELENGTH];
struct keyinfo_data_parm_s keyinfo;
char *s;
memset (&keyinfo, 0,sizeof keyinfo);
@ -2407,10 +2479,20 @@ agent_get_keyinfo (ctrl_t ctrl, const char *hexkeygrip,
if (err)
return err;
if (!hexkeygrip || strlen (hexkeygrip) != 40)
/* FIXME: Support dual keys. Maybe under the assumption that the
* first key might be on a card. */
if (!hexkeygrip)
return gpg_error (GPG_ERR_INV_VALUE);
s = strchr (hexkeygrip, ',');
if (!s)
s = hexkeygrip + strlen (hexkeygrip);
if (s - hexkeygrip != 40)
return gpg_error (GPG_ERR_INV_VALUE);
snprintf (line, DIM(line), "KEYINFO %s", hexkeygrip);
/* Note that for a dual algo we only get info for the first key.
* FIXME: We need to see how we can show the status of the second
* key in a key listing. */
snprintf (line, DIM(line), "KEYINFO %.40s", hexkeygrip);
err = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL,
keyinfo_status_cb, &keyinfo);
@ -3174,6 +3256,7 @@ agent_delete_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
return err;
}
/* FIXME: Shall we add support to DELETE_KEY for dual keys? */
snprintf (line, DIM(line), "DELETE_KEY%s %s",
force? " --force":"", hexkeygrip);
err = assuan_transact (agent_ctx, line, NULL, NULL,

View File

@ -1961,6 +1961,11 @@ do_export_one_keyblock (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid,
err = 0;
continue;
}
if (strchr (hexgrip, ','))
{
log_error ("exporting a secret dual key is not yet supported\n");
return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
}
xfree (serialno);
serialno = NULL;

View File

@ -578,7 +578,8 @@ char *hexfingerprint (PKT_public_key *pk, char *buffer, size_t buflen);
char *v5hexfingerprint (PKT_public_key *pk, char *buffer, size_t buflen);
char *format_hexfingerprint (const char *fingerprint,
char *buffer, size_t buflen);
gpg_error_t keygrip_from_pk (PKT_public_key *pk, unsigned char *array);
gpg_error_t keygrip_from_pk (PKT_public_key *pk, unsigned char *array,
int get_second);
gpg_error_t hexkeygrip_from_pk (PKT_public_key *pk, char **r_grip);
char *ecdh_param_str_from_pk (PKT_public_key *pk);

View File

@ -1103,6 +1103,7 @@ change_passphrase (ctrl_t ctrl, kbnode_t keyblock)
err = hexkeygrip_from_pk (pk, &hexgrip);
if (err)
goto leave;
/* FIXME: Handle dual keys. */
err = agent_get_keyinfo (ctrl, hexgrip, &serialno, NULL);
if (!err && serialno)
; /* Key on card. */

View File

@ -6308,6 +6308,8 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock, const char *algostr,
err = hexkeygrip_from_pk (pri_psk, &hexgrip);
if (err)
goto leave;
/* FIXME: Right now the primary key won't be a dual key. But this
* will change */
if (agent_get_keyinfo (NULL, hexgrip, &serialno, NULL))
{
if (interactive)

View File

@ -1293,16 +1293,22 @@ format_hexfingerprint (const char *fingerprint, char *buffer, size_t buflen)
/* Return the so called KEYGRIP which is the SHA-1 hash of the public
key parameters expressed as an canonical encoded S-Exp. ARRAY must
be 20 bytes long. Returns 0 on success or an error code. */
* key parameters expressed as an canonical encoded S-Exp. ARRAY must
* be 20 bytes long. Returns 0 on success or an error code. If
* GET_SECOND Is one and PK has dual algorithm, the keygrip of the
* second algorithm is return; GPG_ERR_FALSE is returned if the algo
* is not a dual algorithm. */
gpg_error_t
keygrip_from_pk (PKT_public_key *pk, unsigned char *array)
keygrip_from_pk (PKT_public_key *pk, unsigned char *array, int get_second)
{
gpg_error_t err;
gcry_sexp_t s_pkey;
if (DBG_PACKET)
log_debug ("get_keygrip for public key\n");
log_debug ("get_keygrip for public key%s\n", get_second?" (second)":"");
if (get_second && pk->pubkey_algo != PUBKEY_ALGO_KYBER)
return gpg_error (GPG_ERR_FALSE);
switch (pk->pubkey_algo)
{
@ -1351,14 +1357,30 @@ keygrip_from_pk (PKT_public_key *pk, unsigned char *array)
break;
case PUBKEY_ALGO_KYBER:
{
char tmpname[15];
if (get_second)
{
char tmpname[15];
snprintf (tmpname, sizeof tmpname, "kyber%u", nbits_from_pk (pk));
err = gcry_sexp_build (&s_pkey, NULL,
"(public-key(%s(p%m)))",
tmpname, pk->pkey[2]);
}
snprintf (tmpname, sizeof tmpname, "kyber%u", nbits_from_pk (pk));
err = gcry_sexp_build (&s_pkey, NULL,
"(public-key(%s(p%m)))",
tmpname, pk->pkey[2]);
}
else
{
char *curve = openpgp_oid_to_str (pk->pkey[0]);
if (!curve)
err = gpg_error_from_syserror ();
else
{
err = gcry_sexp_build (&s_pkey, NULL,
openpgp_oid_is_cv25519 (pk->pkey[0])
? "(public-key(ecc(curve%s)(flags djb-tweak)(q%m)))"
: "(public-key(ecc(curve%s)(q%m)))",
curve, pk->pkey[1]);
xfree (curve);
}
}
break;
default:
@ -1393,26 +1415,45 @@ keygrip_from_pk (PKT_public_key *pk, unsigned char *array)
/* Store an allocated buffer with the keygrip of PK encoded as a
hexstring at r_GRIP. Returns 0 on success. */
* hexstring at r_GRIP. Returns 0 on success. For dual algorithms
* the keygrips are delimited by a comma. */
gpg_error_t
hexkeygrip_from_pk (PKT_public_key *pk, char **r_grip)
{
gpg_error_t err;
char *buf;
unsigned char grip[KEYGRIP_LEN];
unsigned char grip2[KEYGRIP_LEN];
*r_grip = NULL;
err = keygrip_from_pk (pk, grip);
err = keygrip_from_pk (pk, grip, 0);
if (!err)
{
char * buf = xtrymalloc (KEYGRIP_LEN * 2 + 1);
if (!buf)
err = gpg_error_from_syserror ();
else
if (pk->pubkey_algo == PUBKEY_ALGO_KYBER)
{
bin2hex (grip, KEYGRIP_LEN, buf);
*r_grip = buf;
err = keygrip_from_pk (pk, grip2, 1);
if (err)
goto leave;
buf = xtrymalloc (2 * KEYGRIP_LEN * 2 + 1 + 1);
}
else
buf = xtrymalloc (KEYGRIP_LEN * 2 + 1);
if (!buf)
{
err = gpg_error_from_syserror ();
goto leave;
}
bin2hex (grip, KEYGRIP_LEN, buf);
if (pk->pubkey_algo == PUBKEY_ALGO_KYBER)
{
buf[2*KEYGRIP_LEN] = ',';
bin2hex (grip2, KEYGRIP_LEN, buf+2*KEYGRIP_LEN+1);
}
*r_grip = buf;
}
leave:
return err;
}

View File

@ -1148,7 +1148,7 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
if (need_keyid)
keyid_from_pk (pk, aki);
if (need_grip)
keygrip_from_pk (pk, grip);
keygrip_from_pk (pk, grip, 0);
if (use_key_present_hash
&& !key_present_hash_ready

View File

@ -248,6 +248,8 @@ get_it (ctrl_t ctrl,
/* Decrypt. */
desc = gpg_format_keydesc (ctrl, sk, FORMAT_KEYDESC_NORMAL, 1);
/*FIXME: Support dual keys. */
err = agent_pkdecrypt (NULL, keygrip,
desc, sk->keyid, sk->main_keyid, sk->pubkey_algo,
s_data, &frame, &nframe, &padding);

View File

@ -495,6 +495,7 @@ do_sign (ctrl_t ctrl, PKT_public_key *pksk, PKT_signature *sig,
gcry_sexp_t s_sigval;
desc = gpg_format_keydesc (ctrl, pksk, FORMAT_KEYDESC_NORMAL, 1);
/* FIXME: Eventually support dual keys. */
err = agent_pksign (NULL/*ctrl*/, cache_nonce, hexgrip, desc,
pksk->keyid, pksk->main_keyid, pksk->pubkey_algo,
dp, gcry_md_get_algo_dlen (mdalgo), mdalgo,
@ -580,6 +581,7 @@ openpgp_card_v1_p (PKT_public_key *pk)
{
char *hexgrip;
/* Note: No need to care about dual keys for non-RSA keys. */
err = hexkeygrip_from_pk (pk, &hexgrip);
if (err)
{