1
0
mirror of git://git.gnupg.org/gnupg.git synced 2025-02-01 16:33:02 +01:00

agent: Create and use Token entries to track the display s/n.

* agent/divert-scd.c (linefeed_to_percent0A): New.
(ask_for_card): Add arg grip.  Read Token and Label items and use
them.
(divert_pksign, divert_pkdecrypt): Pass down grip.
* agent/findkey.c (write_extended_private_key): Add args serialno,
keyref, and dispserialno.  Writen Token item.
(agent_write_private_key): Add args serialno, keyref, and
dispserialno.
(read_key_file): Add arg r_keymeta.
(agent_keymeta_from_file): New.
(agent_write_shadow_key): Remove leading spaces from serialno and keyid.
* agent/protect-tool.c (agent_write_private_key): Ditto.
* agent/learncard.c (agent_handle_learn): Get DISPSERIALNO and pass to
agent_write_shadow_key.
* agent/command-ssh.c (card_key_available): Ditto.
--

GnuPG-bug-id: 6135

This patch backports some changes from master but also adds the
Display-S/N tracking.
This commit is contained in:
Werner Koch 2022-08-15 12:49:56 +02:00
parent 706adf6691
commit dc9b242628
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
10 changed files with 272 additions and 36 deletions

View File

@ -36,6 +36,7 @@
#include "../common/sysutils.h" /* (gnupg_fd_t) */ #include "../common/sysutils.h" /* (gnupg_fd_t) */
#include "../common/session-env.h" #include "../common/session-env.h"
#include "../common/shareddefs.h" #include "../common/shareddefs.h"
#include "../common/name-value.h"
/* To convey some special hash algorithms we use algorithm numbers /* To convey some special hash algorithms we use algorithm numbers
reserved for application use. */ reserved for application use. */
@ -429,7 +430,9 @@ gpg_error_t agent_modify_description (const char *in, const char *comment,
const gcry_sexp_t key, char **result); const gcry_sexp_t key, char **result);
int agent_write_private_key (const unsigned char *grip, 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,
time_t timestamp); time_t timestamp,
const char *serialno, const char *keyref,
const char *dispserialno);
gpg_error_t agent_key_from_file (ctrl_t ctrl, gpg_error_t agent_key_from_file (ctrl_t ctrl,
const char *cache_nonce, const char *cache_nonce,
const char *desc_text, const char *desc_text,
@ -441,6 +444,8 @@ gpg_error_t agent_key_from_file (ctrl_t ctrl,
char **r_passphrase); char **r_passphrase);
gpg_error_t agent_raw_key_from_file (ctrl_t ctrl, const unsigned char *grip, gpg_error_t agent_raw_key_from_file (ctrl_t ctrl, const unsigned char *grip,
gcry_sexp_t *result); gcry_sexp_t *result);
gpg_error_t agent_keymeta_from_file (ctrl_t ctrl, const unsigned char *grip,
nvc_t *r_keymeta);
gpg_error_t agent_public_key_from_file (ctrl_t ctrl, gpg_error_t agent_public_key_from_file (ctrl_t ctrl,
const unsigned char *grip, const unsigned char *grip,
gcry_sexp_t *result); gcry_sexp_t *result);
@ -549,7 +554,8 @@ gpg_error_t s2k_hash_passphrase (const char *passphrase, int hashalgo,
unsigned char *key, size_t keylen); unsigned char *key, size_t keylen);
gpg_error_t agent_write_shadow_key (const unsigned char *grip, gpg_error_t agent_write_shadow_key (const unsigned char *grip,
const char *serialno, const char *keyid, const char *serialno, const char *keyid,
const unsigned char *pkbuf, int force); const unsigned char *pkbuf, int force,
const char *dispserialno);
/*-- trustlist.c --*/ /*-- trustlist.c --*/

View File

@ -2495,8 +2495,13 @@ card_key_available (ctrl_t ctrl, gcry_sexp_t *r_pk, char **cardsn)
if ( agent_key_available (grip) ) if ( agent_key_available (grip) )
{ {
char *dispserialno;
/* (Shadow)-key is not available in our key storage. */ /* (Shadow)-key is not available in our key storage. */
err = agent_write_shadow_key (grip, serialno, authkeyid, pkbuf, 0); agent_card_getattr (ctrl, "$DISPSERIALNO", &dispserialno);
err = agent_write_shadow_key (grip, serialno, authkeyid, pkbuf, 0,
dispserialno);
xfree (dispserialno);
if (err) if (err)
{ {
xfree (pkbuf); xfree (pkbuf);
@ -3154,7 +3159,8 @@ 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 /* Store this key to our key storage. We do not store a creation
* timestamp because we simply do not know. */ * timestamp because we simply do not know. */
err = agent_write_private_key (key_grip_raw, buffer, buffer_n, 0, 0); err = agent_write_private_key (key_grip_raw, buffer, buffer_n, 0, 0,
NULL, NULL, NULL);
if (err) if (err)
goto out; goto out;

View File

@ -1040,7 +1040,12 @@ cmd_readkey (assuan_context_t ctx, char *line)
if (agent_key_available (grip)) if (agent_key_available (grip))
{ {
/* (Shadow)-key is not available in our key storage. */ /* (Shadow)-key is not available in our key storage. */
rc = agent_write_shadow_key (grip, serialno, keyid, pkbuf, 0); char *dispserialno;
agent_card_getattr (ctrl, "$DISPSERIALNO", &dispserialno);
rc = agent_write_shadow_key (grip, serialno, keyid, pkbuf, 0,
dispserialno);
xfree (dispserialno);
if (rc) if (rc)
goto leave; goto leave;
} }
@ -2425,11 +2430,11 @@ cmd_import_key (assuan_context_t ctx, char *line)
ctrl->s2k_count, -1); ctrl->s2k_count, -1);
if (!err) if (!err)
err = agent_write_private_key (grip, finalkey, finalkeylen, force, err = agent_write_private_key (grip, finalkey, finalkeylen, force,
opt_timestamp); opt_timestamp, NULL, NULL, NULL);
} }
else else
err = agent_write_private_key (grip, key, realkeylen, force, err = agent_write_private_key (grip, key, realkeylen, force,
opt_timestamp); opt_timestamp, NULL, NULL, NULL);
leave: leave:
gcry_sexp_release (openpgp_sexp); gcry_sexp_release (openpgp_sexp);

View File

@ -1069,7 +1069,8 @@ convert_from_openpgp_native (ctrl_t ctrl,
if (!agent_protect (*r_key, passphrase, if (!agent_protect (*r_key, passphrase,
&protectedkey, &protectedkeylen, &protectedkey, &protectedkeylen,
ctrl->s2k_count, -1)) ctrl->s2k_count, -1))
agent_write_private_key (grip, protectedkey, protectedkeylen, 1, 0); agent_write_private_key (grip, protectedkey, protectedkeylen,
1, 0, NULL, NULL, NULL);
xfree (protectedkey); xfree (protectedkey);
} }
else else
@ -1078,7 +1079,7 @@ convert_from_openpgp_native (ctrl_t ctrl,
agent_write_private_key (grip, agent_write_private_key (grip,
*r_key, *r_key,
gcry_sexp_canon_len (*r_key, 0, NULL,NULL), gcry_sexp_canon_len (*r_key, 0, NULL,NULL),
1, 0); 1, 0, NULL, NULL, NULL);
} }
} }

View File

@ -31,16 +31,51 @@
#include "../common/i18n.h" #include "../common/i18n.h"
#include "../common/sexp-parse.h" #include "../common/sexp-parse.h"
/* Replace 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;
}
/* Ask for the card using SHADOW_INFO. If GRIP is not NULL, the
* function also tries to find additional information from the shadow
* key file. */
static int static int
ask_for_card (ctrl_t ctrl, const unsigned char *shadow_info, char **r_kid) ask_for_card (ctrl_t ctrl, const unsigned char *shadow_info,
const unsigned char *grip, char **r_kid)
{ {
int rc, i; int rc, i;
char *serialno; char *serialno;
int no_card = 0; int no_card = 0;
char *desc; char *desc;
char *want_sn, *want_kid, *want_sn_disp; char *want_sn, *want_kid, *want_sn_disp;
int got_sn_disp_from_meta = 0;
int len; int len;
char *comment = NULL;
*r_kid = NULL; *r_kid = NULL;
@ -53,11 +88,62 @@ ask_for_card (ctrl_t ctrl, const unsigned char *shadow_info, char **r_kid)
rc = gpg_error_from_syserror (); rc = gpg_error_from_syserror ();
xfree (want_sn); xfree (want_sn);
xfree (want_kid); xfree (want_kid);
xfree (comment);
return rc; return rc;
} }
if (grip)
{
nvc_t keymeta;
const char *s;
size_t snlen;
nve_t item;
char **tokenfields = NULL;
rc = agent_keymeta_from_file (ctrl, grip, &keymeta);
if (!rc)
{
snlen = strlen (want_sn);
s = NULL;
for (item = nvc_lookup (keymeta, "Token:");
item;
item = nve_next_value (item, "Token:"))
if ((s = nve_value (item)) && !strncmp (s, want_sn, snlen))
break;
if (s && (tokenfields = strtokenize (s, " \t\n")))
{
if (tokenfields[0] && tokenfields[1] && tokenfields[2]
&& tokenfields[3] && strlen (tokenfields[3]) > 1)
{
xfree (want_sn_disp);
want_sn_disp = percent_plus_unescape (tokenfields[3], 0xff);
if (!want_sn_disp)
{
rc = gpg_error_from_syserror ();
xfree (tokenfields);
nvc_release (keymeta);
xfree (want_sn);
xfree (want_kid);
xfree (comment);
return rc;
}
got_sn_disp_from_meta = 1;
}
xfree (tokenfields);
}
if ((s = nvc_get_string (keymeta, "Label:")))
comment = linefeed_to_percent0A (s);
nvc_release (keymeta);
}
}
len = strlen (want_sn_disp); len = strlen (want_sn_disp);
if (len == 32 && !strncmp (want_sn_disp, "D27600012401", 12)) if (got_sn_disp_from_meta)
; /* We got the the display S/N from the key file. */
else if (len == 32 && !strncmp (want_sn_disp, "D27600012401", 12))
{ {
/* This is an OpenPGP card - reformat */ /* This is an OpenPGP card - reformat */
memmove (want_sn_disp, want_sn_disp+16, 4); memmove (want_sn_disp, want_sn_disp+16, 4);
@ -87,6 +173,7 @@ ask_for_card (ctrl_t ctrl, const unsigned char *shadow_info, char **r_kid)
{ {
xfree (want_sn_disp); xfree (want_sn_disp);
xfree (want_sn); xfree (want_sn);
xfree (comment);
*r_kid = want_kid; *r_kid = want_kid;
return 0; /* yes, we have the correct card */ return 0; /* yes, we have the correct card */
} }
@ -112,12 +199,13 @@ ask_for_card (ctrl_t ctrl, const unsigned char *shadow_info, char **r_kid)
{ {
if (asprintf (&desc, if (asprintf (&desc,
"%s:%%0A%%0A" "%s:%%0A%%0A"
" %s%%0A"
" %s", " %s",
no_card no_card
? L_("Please insert the card with serial number") ? L_("Please insert the card with serial number")
: L_("Please remove the current card and " : L_("Please remove the current card and "
"insert the one with serial number"), "insert the one with serial number"),
want_sn_disp) < 0) want_sn_disp, comment? comment:"") < 0)
{ {
rc = out_of_core (); rc = out_of_core ();
} }
@ -136,6 +224,7 @@ ask_for_card (ctrl_t ctrl, const unsigned char *shadow_info, char **r_kid)
xfree (want_sn_disp); xfree (want_sn_disp);
xfree (want_sn); xfree (want_sn);
xfree (want_kid); xfree (want_kid);
xfree (comment);
return rc; return rc;
} }
} }
@ -447,7 +536,7 @@ divert_pksign (ctrl_t ctrl, const char *desc_text,
(void)desc_text; (void)desc_text;
rc = ask_for_card (ctrl, shadow_info, &kid); rc = ask_for_card (ctrl, shadow_info, grip, &kid);
if (rc) if (rc)
return rc; return rc;
@ -599,7 +688,7 @@ divert_pkdecrypt (ctrl_t ctrl, const char *desc_text,
ciphertext = s; ciphertext = s;
ciphertextlen = n; ciphertextlen = n;
rc = ask_for_card (ctrl, shadow_info, &kid); rc = ask_for_card (ctrl, shadow_info, grip, &kid);
if (rc) if (rc)
return rc; return rc;

View File

@ -55,12 +55,16 @@ struct try_unprotect_arg_s
/* Note: Ownership of FNAME and FP are moved to this function. */ /* Note: Ownership of FNAME and FP are moved to this function. */
static gpg_error_t static gpg_error_t
write_extended_private_key (char *fname, estream_t fp, int update, int newkey, write_extended_private_key (char *fname, estream_t fp, int update, int newkey,
const void *buf, size_t len, time_t timestamp) const void *buf, size_t len, time_t timestamp,
const char *serialno, const char *keyref,
const char *dispserialno)
{ {
gpg_error_t err; gpg_error_t err;
nvc_t pk = NULL; nvc_t pk = NULL;
gcry_sexp_t key = NULL; gcry_sexp_t key = NULL;
int remove = 0; int remove = 0;
char *token0 = NULL;
char *token = NULL;
if (update) if (update)
{ {
@ -106,6 +110,59 @@ write_extended_private_key (char *fname, estream_t fp, int update, int newkey,
goto leave; goto leave;
} }
/* If requested write a Token line. */
if (serialno && keyref)
{
nve_t item;
const char *s;
size_t token0len;
char *tmpdistsn = NULL;
if (dispserialno)
{
tmpdistsn = percent_plus_escape (dispserialno);
if (!tmpdistsn)
{
err = gpg_error_from_syserror ();
goto leave;
}
}
token0 = strconcat (serialno, " ", keyref, NULL);
if (token0)
token = strconcat (token0, " - ", tmpdistsn? tmpdistsn:"-", NULL);
xfree (tmpdistsn);
if (!token0 || !token)
{
err = gpg_error_from_syserror ();
goto leave;
}
token0len = strlen (token0);
for (item = nvc_lookup (pk, "Token:");
item;
item = nve_next_value (item, "Token:"))
if ((s = nve_value (item)) && !strncmp (s, token0, token0len))
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;
}
else
{
/* Token exists: Update the display s/n. It may have
* changed due to changes in a newer software version. */
err = nve_set (item, token);
if (err)
goto leave;
}
}
err = es_fseek (fp, 0, SEEK_SET); err = es_fseek (fp, 0, SEEK_SET);
if (err) if (err)
goto leave; goto leave;
@ -145,6 +202,8 @@ write_extended_private_key (char *fname, estream_t fp, int update, int newkey,
if (remove) if (remove)
gnupg_remove (fname); gnupg_remove (fname);
xfree (fname); xfree (fname);
xfree (token);
xfree (token0);
gcry_sexp_release (key); gcry_sexp_release (key);
nvc_release (pk); nvc_release (pk);
return err; return err;
@ -153,11 +212,14 @@ write_extended_private_key (char *fname, estream_t fp, int update, int newkey,
/* Write an S-expression formatted key to our key storage. With FORCE /* Write an S-expression formatted key to our key storage. With FORCE
* passed as true an existing key with the given GRIP will get * passed as true an existing key with the given GRIP will get
* overwritten. If TIMESTAMP is not zero and the key does not yet * overwritten. If TIMESTAMP is not zero and the key does not yet
* exists it will be recorded as creation date. */ * exists it will be recorded as creation date. If SERIALNO, KEYREF,
* of DISPSERIALNO are not NULL they will be recorded as well. */
int int
agent_write_private_key (const unsigned char *grip, agent_write_private_key (const unsigned char *grip,
const void *buffer, size_t length, const void *buffer, size_t length,
int force, time_t timestamp) int force, time_t timestamp,
const char *serialno, const char *keyref,
const char *dispserialno)
{ {
char *fname; char *fname;
estream_t fp; estream_t fp;
@ -226,19 +288,22 @@ agent_write_private_key (const unsigned char *grip,
{ {
/* Key is already in the extended format. */ /* Key is already in the extended format. */
return write_extended_private_key (fname, fp, 1, 0, buffer, length, return write_extended_private_key (fname, fp, 1, 0, buffer, length,
timestamp); timestamp, serialno, keyref,
dispserialno);
} }
if (first == '(' && opt.enable_extended_key_format) if (first == '(' && opt.enable_extended_key_format)
{ {
/* Key is in the old format - but we want the extended format. */ /* Key is in the old format - but we want the extended format. */
return write_extended_private_key (fname, fp, 0, 0, buffer, length, return write_extended_private_key (fname, fp, 0, 0, buffer, length,
timestamp); timestamp, serialno, keyref,
dispserialno);
} }
} }
if (opt.enable_extended_key_format) if (opt.enable_extended_key_format)
return write_extended_private_key (fname, fp, 0, 1, buffer, length, return write_extended_private_key (fname, fp, 0, 1, buffer, length,
timestamp); timestamp, serialno, keyref,
dispserialno);
if (es_fwrite (buffer, length, 1, fp) != 1) if (es_fwrite (buffer, length, 1, fp) != 1)
{ {
@ -715,10 +780,12 @@ unprotect (ctrl_t ctrl, const char *cache_nonce, const char *desc_text,
/* Read the key identified by GRIP from the private key directory and /* Read the key identified by GRIP from the private key directory and
return it as an gcrypt S-expression object in RESULT. On failure * return it as an gcrypt S-expression object in RESULT. If R_KEYMETA
returns an error code and stores NULL at RESULT. */ * 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. */
static gpg_error_t 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; gpg_error_t err;
char *fname; char *fname;
@ -731,6 +798,8 @@ read_key_file (const unsigned char *grip, gcry_sexp_t *result)
char first; char first;
*result = NULL; *result = NULL;
if (r_keymeta)
*r_keymeta = NULL;
bin2hex (grip, 20, hexgrip); bin2hex (grip, 20, hexgrip);
strcpy (hexgrip+40, ".key"); strcpy (hexgrip+40, ".key");
@ -781,12 +850,17 @@ read_key_file (const unsigned char *grip, gcry_sexp_t *result)
else else
{ {
err = nvc_get_private_key (pk, result); err = nvc_get_private_key (pk, result);
nvc_release (pk);
if (err) if (err)
log_error ("error getting private key from '%s': %s\n", log_error ("error getting private key from '%s': %s\n",
fname, gpg_strerror (err)); fname, gpg_strerror (err));
else
nvc_delete_named (pk, "Key:");
} }
if (!err && r_keymeta)
*r_keymeta = pk;
else
nvc_release (pk);
xfree (fname); xfree (fname);
return err; return err;
} }
@ -893,7 +967,7 @@ agent_key_from_file (ctrl_t ctrl, const char *cache_nonce,
if (r_passphrase) if (r_passphrase)
*r_passphrase = NULL; *r_passphrase = NULL;
err = read_key_file (grip, &s_skey); err = read_key_file (grip, &s_skey, NULL);
if (err) if (err)
{ {
if (gpg_err_code (err) == GPG_ERR_ENOENT) if (gpg_err_code (err) == GPG_ERR_ENOENT)
@ -1223,13 +1297,28 @@ agent_raw_key_from_file (ctrl_t ctrl, const unsigned char *grip,
*result = NULL; *result = NULL;
err = read_key_file (grip, &s_skey); err = read_key_file (grip, &s_skey, NULL);
if (!err) if (!err)
*result = s_skey; *result = s_skey;
return err; return err;
} }
gpg_error_t
agent_keymeta_from_file (ctrl_t ctrl, const unsigned char *grip,
nvc_t *r_keymeta)
{
gpg_error_t err;
gcry_sexp_t s_skey;
(void)ctrl;
err = read_key_file (grip, &s_skey, r_keymeta);
gcry_sexp_release (s_skey);
return err;
}
/* Return the public key for the keygrip GRIP. The result is stored /* Return the public key for the keygrip GRIP. The result is stored
at RESULT. This function extracts the public key from the private at RESULT. This function extracts the public key from the private
key database. On failure an error code is returned and NULL stored key database. On failure an error code is returned and NULL stored
@ -1262,7 +1351,7 @@ agent_public_key_from_file (ctrl_t ctrl,
*result = NULL; *result = NULL;
err = read_key_file (grip, &s_skey); err = read_key_file (grip, &s_skey, NULL);
if (err) if (err)
return err; return err;
@ -1409,7 +1498,7 @@ agent_key_info_from_file (ctrl_t ctrl, const unsigned char *grip,
{ {
gcry_sexp_t sexp; gcry_sexp_t sexp;
err = read_key_file (grip, &sexp); err = read_key_file (grip, &sexp, NULL);
if (err) if (err)
{ {
if (gpg_err_code (err) == GPG_ERR_ENOENT) if (gpg_err_code (err) == GPG_ERR_ENOENT)
@ -1493,7 +1582,7 @@ agent_delete_key (ctrl_t ctrl, const char *desc_text,
char *default_desc = NULL; char *default_desc = NULL;
int key_type; 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) if (gpg_err_code (err) == GPG_ERR_ENOENT)
err = gpg_error (GPG_ERR_NO_SECKEY); err = gpg_error (GPG_ERR_NO_SECKEY);
if (err) if (err)
@ -1592,17 +1681,27 @@ agent_delete_key (ctrl_t ctrl, const char *desc_text,
/* Write an S-expression formatted shadow key to our key storage. /* Write an S-expression formatted shadow key to our key storage.
Shadow key is created by an S-expression public key in PKBUF and Shadow key is created by an S-expression public key in PKBUF and
card's SERIALNO and the IDSTRING. With FORCE passed as true an card's SERIALNO and the IDSTRING. With FORCE passed as true an
existing key with the given GRIP will get overwritten. */ existing key with the given GRIP will get overwritten. If
DISPSERIALNO is not NULL the human readable s/n will also be
recorded in the key file. */
gpg_error_t gpg_error_t
agent_write_shadow_key (const unsigned char *grip, agent_write_shadow_key (const unsigned char *grip,
const char *serialno, const char *keyid, 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; gpg_error_t err;
unsigned char *shadow_info; unsigned char *shadow_info;
unsigned char *shdkey; unsigned char *shdkey;
size_t len; 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); shadow_info = make_shadow_info (serialno, keyid);
if (!shadow_info) if (!shadow_info)
return gpg_error_from_syserror (); return gpg_error_from_syserror ();
@ -1616,7 +1715,8 @@ agent_write_shadow_key (const unsigned char *grip,
} }
len = gcry_sexp_canon_len (shdkey, 0, NULL, NULL); len = gcry_sexp_canon_len (shdkey, 0, NULL, NULL);
err = agent_write_private_key (grip, shdkey, len, force, 0); err = agent_write_private_key (grip, shdkey, len, force, 0,
serialno, keyid, dispserialno);
xfree (shdkey); xfree (shdkey);
if (err) if (err)
log_error ("error writing key: %s\n", gpg_strerror (err)); log_error ("error writing key: %s\n", gpg_strerror (err));

View File

@ -69,7 +69,8 @@ store_key (gcry_sexp_t private, const char *passphrase, int force,
buf = p; buf = p;
} }
rc = agent_write_private_key (grip, buf, len, force, timestamp); rc = agent_write_private_key (grip, buf, len, force, timestamp,
NULL, NULL, NULL);
xfree (buf); xfree (buf);
return rc; return rc;
} }

View File

@ -78,7 +78,7 @@ of a continuation line encodes a newline.
Lines containing only whitespace, and lines starting with whitespace Lines containing only whitespace, and lines starting with whitespace
followed by '#' are considered to be comments and are ignored. followed by '#' are considered to be comments and are ignored.
** Well defined names ** Well known names
*** Description *** Description
This is a human readable string describing the key. This is a human readable string describing the key.
@ -108,6 +108,22 @@ This takes a base64 encoded string wrapped so that this
key file can be easily edited with a standard editor. Several of such key file can be easily edited with a standard editor. Several of such
items can be used. 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
similar to 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 or "-".
- The human readable serial number of a card. This is usually what is
printed on the actual card. This value is taken directly from the
card but when asking to insert a card it is useful to have this
value available. GnuPG takes care of creating and possibly updating
this entry. This is percent-plus-escaped.
*** Use-for-ssh *** Use-for-ssh
If given and the value is "yes" or "1" the key is allowed for use by 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 gpg-agent's ssh-agent implementation. This is thus the same as

View File

@ -409,7 +409,14 @@ agent_handle_learn (ctrl_t ctrl, int send, void *assuan_context, int force)
goto leave; goto leave;
} }
rc = agent_write_shadow_key (grip, serialno, item->id, pubkey, force); {
char *dispserialno;
agent_card_getattr (ctrl, "$DISPSERIALNO", &dispserialno);
rc = agent_write_shadow_key (grip, serialno, item->id, pubkey, force,
dispserialno);
xfree (dispserialno);
}
xfree (pubkey); xfree (pubkey);
if (rc) if (rc)
goto leave; goto leave;

View File

@ -810,13 +810,18 @@ agent_askpin (ctrl_t ctrl,
int int
agent_write_private_key (const unsigned char *grip, agent_write_private_key (const unsigned char *grip,
const void *buffer, size_t length, int force, const void *buffer, size_t length, int force,
time_t timestamp) time_t timestamp,
const char *serialno, const char *keyref,
const char *dispserialno)
{ {
char hexgrip[40+4+1]; char hexgrip[40+4+1];
char *p; char *p;
(void)force; (void)force;
(void)timestamp; (void)timestamp;
(void)serialno;
(void)keyref;
(void)dispserialno;
bin2hex (grip, 20, hexgrip); bin2hex (grip, 20, hexgrip);
strcpy (hexgrip+40, ".key"); strcpy (hexgrip+40, ".key");