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
  <blank line>
  <space>I registered on fencepost.

Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
Werner Koch 2019-05-07 11:08:26 +02:00
parent b5985d0ca2
commit 5388537806
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
2 changed files with 82 additions and 25 deletions

View File

@ -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)

View File

@ -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