1
0
mirror of git://git.gnupg.org/gnupg.git synced 2025-01-03 12:11:33 +01:00

agent: Allow to pass a timestamp to genkey and import.

* agent/command.c (cmd_genkey): Add option --timestamp.
(cmd_import_key): Ditto.
* agent/genkey.c (store_key): Add arg timestamp and change callers.
(agent_genkey): Ditto.
* agent/findkey.c (write_extended_private_key): Add args timestamp and
newkey to write a Created line.
(agent_write_private_key): Add arg timestamp.
(agent_write_shadow_key): Ditto.
* agent/protect-tool.c (agent_write_private_key): Ditto as dummy arg.
--

Signed-off-by: Werner Koch <wk@gnupg.org>
Backported-from-master: 0da923a1240ac78d60c92cdd8488c4e405c3243b
Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
Werner Koch 2020-08-17 14:21:00 +02:00
parent 5b927b7b27
commit 051830d7b4
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
8 changed files with 138 additions and 35 deletions

View File

@ -413,7 +413,8 @@ void start_command_handler_ssh (ctrl_t, gnupg_fd_t);
gpg_error_t agent_modify_description (const char *in, const char *comment, 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);
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,
@ -493,7 +494,7 @@ int check_passphrase_constraints (ctrl_t ctrl, const char *pw, int no_empty,
char **failed_constraint); char **failed_constraint);
gpg_error_t agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt, gpg_error_t agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt,
char **r_passphrase); char **r_passphrase);
int agent_genkey (ctrl_t ctrl, const char *cache_nonce, int agent_genkey (ctrl_t ctrl, const char *cache_nonce, time_t timestamp,
const char *keyparam, size_t keyparmlen, const char *keyparam, size_t keyparmlen,
int no_protection, const char *override_passphrase, int no_protection, const char *override_passphrase,
int preset, membuf_t *outbuf); int preset, membuf_t *outbuf);

View File

@ -3136,8 +3136,9 @@ ssh_identity_register (ctrl_t ctrl, ssh_key_type_spec_t *spec,
if (err) if (err)
goto out; goto out;
/* Store this key to our key storage. */ /* Store this key to our key storage. We do not store a creation
err = agent_write_private_key (key_grip_raw, buffer, buffer_n, 0); * timestamp because we simply do not know. */
err = agent_write_private_key (key_grip_raw, buffer, buffer_n, 0, 0);
if (err) if (err)
goto out; goto out;

View File

@ -835,8 +835,8 @@ cmd_pkdecrypt (assuan_context_t ctx, char *line)
static const char hlp_genkey[] = static const char hlp_genkey[] =
"GENKEY [--no-protection] [--preset] [--inq-passwd]\n" "GENKEY [--no-protection] [--preset] [--timestamp=<isodate>]\n"
" [--passwd-nonce=<s>] [<cache_nonce>]\n" " [--inq-passwd] [--passwd-nonce=<s>] [<cache_nonce>]\n"
"\n" "\n"
"Generate a new key, store the secret part and return the public\n" "Generate a new key, store the secret part and return the public\n"
"part. Here is an example transaction:\n" "part. Here is an example transaction:\n"
@ -849,11 +849,13 @@ static const char hlp_genkey[] =
" S: D (rsa (n 326487324683264) (e 10001)))\n" " S: D (rsa (n 326487324683264) (e 10001)))\n"
" S: OK key created\n" " S: OK key created\n"
"\n" "\n"
"When the --preset option is used the passphrase for the generated\n" "If the --preset option is used the passphrase for the generated\n"
"key will be added to the cache. When --inq-passwd is used an inquire\n" "key will be added to the cache. If --inq-passwd is used an inquire\n"
"with the keyword NEWPASSWD is used to request the passphrase for the\n" "with the keyword NEWPASSWD is used to request the passphrase for the\n"
"new key. When a --passwd-nonce is used, the corresponding cached\n" "new key. If a --passwd-nonce is used, the corresponding cached\n"
"passphrase is used to protect the new key."; "passphrase is used to protect the new key. If --timestamp is given\n"
"its value is recorded as the key's creation time; the value is\n"
"expected in ISO format (e.g. \"20030316T120000\").";
static gpg_error_t static gpg_error_t
cmd_genkey (assuan_context_t ctx, char *line) cmd_genkey (assuan_context_t ctx, char *line)
{ {
@ -870,6 +872,8 @@ cmd_genkey (assuan_context_t ctx, char *line)
int opt_inq_passwd; int opt_inq_passwd;
size_t n; size_t n;
char *p, *pend; char *p, *pend;
const char *s;
time_t opt_timestamp;
int c; int c;
if (ctrl->restricted) if (ctrl->restricted)
@ -893,6 +897,22 @@ cmd_genkey (assuan_context_t ctx, char *line)
goto leave; goto leave;
} }
} }
if ((s=has_option_name (line, "--timestamp")))
{
if (*s != '=')
{
rc = set_error (GPG_ERR_ASS_PARAMETER, "missing value for option");
goto leave;
}
opt_timestamp = isotime2epoch (s+1);
if (opt_timestamp < 1)
{
rc = set_error (GPG_ERR_ASS_PARAMETER, "invalid time value");
goto leave;
}
}
else
opt_timestamp = 0;
line = skip_options (line); line = skip_options (line);
for (p=line; *p && *p != ' ' && *p != '\t'; p++) for (p=line; *p && *p != ' ' && *p != '\t'; p++)
@ -932,7 +952,8 @@ cmd_genkey (assuan_context_t ctx, char *line)
else if (passwd_nonce) else if (passwd_nonce)
newpasswd = agent_get_cache (ctrl, passwd_nonce, CACHE_MODE_NONCE); newpasswd = agent_get_cache (ctrl, passwd_nonce, CACHE_MODE_NONCE);
rc = agent_genkey (ctrl, cache_nonce, (char*)value, valuelen, no_protection, rc = agent_genkey (ctrl, cache_nonce, opt_timestamp,
(char*)value, valuelen, no_protection,
newpasswd, opt_preset, &outbuf); newpasswd, opt_preset, &outbuf);
leave: leave:
@ -2176,7 +2197,8 @@ cmd_keywrap_key (assuan_context_t ctx, char *line)
static const char hlp_import_key[] = static const char hlp_import_key[] =
"IMPORT_KEY [--unattended] [--force] [<cache_nonce>]\n" "IMPORT_KEY [--unattended] [--force] [--timestamp=<isodate>]\n"
" [<cache_nonce>]\n"
"\n" "\n"
"Import a secret key into the key store. The key is expected to be\n" "Import a secret key into the key store. The key is expected to be\n"
"encrypted using the current session's key wrapping key (cf. command\n" "encrypted using the current session's key wrapping key (cf. command\n"
@ -2184,13 +2206,16 @@ static const char hlp_import_key[] =
"no arguments but uses the inquiry \"KEYDATA\" to ask for the actual\n" "no arguments but uses the inquiry \"KEYDATA\" to ask for the actual\n"
"key data. The unwrapped key must be a canonical S-expression. The\n" "key data. The unwrapped key must be a canonical S-expression. The\n"
"option --unattended tries to import the key as-is without any\n" "option --unattended tries to import the key as-is without any\n"
"re-encryption. Existing key can be overwritten with --force."; "re-encryption. An existing key can be overwritten with --force.\n"
"If --timestamp is given its value is recorded as the key's creation\n"
"time; the value is expected in ISO format (e.g. \"20030316T120000\").";
static gpg_error_t static gpg_error_t
cmd_import_key (assuan_context_t ctx, char *line) cmd_import_key (assuan_context_t ctx, char *line)
{ {
ctrl_t ctrl = assuan_get_pointer (ctx); ctrl_t ctrl = assuan_get_pointer (ctx);
gpg_error_t err; gpg_error_t err;
int opt_unattended; int opt_unattended;
time_t opt_timestamp;
int force; int force;
unsigned char *wrappedkey = NULL; unsigned char *wrappedkey = NULL;
size_t wrappedkeylen; size_t wrappedkeylen;
@ -2204,6 +2229,7 @@ cmd_import_key (assuan_context_t ctx, char *line)
gcry_sexp_t openpgp_sexp = NULL; gcry_sexp_t openpgp_sexp = NULL;
char *cache_nonce = NULL; char *cache_nonce = NULL;
char *p; char *p;
const char *s;
if (ctrl->restricted) if (ctrl->restricted)
return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN)); return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
@ -2216,6 +2242,22 @@ cmd_import_key (assuan_context_t ctx, char *line)
opt_unattended = has_option (line, "--unattended"); opt_unattended = has_option (line, "--unattended");
force = has_option (line, "--force"); force = has_option (line, "--force");
if ((s=has_option_name (line, "--timestamp")))
{
if (*s != '=')
{
err = set_error (GPG_ERR_ASS_PARAMETER, "missing value for option");
goto leave;
}
opt_timestamp = isotime2epoch (s+1);
if (opt_timestamp < 1)
{
err = set_error (GPG_ERR_ASS_PARAMETER, "invalid time value");
goto leave;
}
}
else
opt_timestamp = 0;
line = skip_options (line); line = skip_options (line);
for (p=line; *p && *p != ' ' && *p != '\t'; p++) for (p=line; *p && *p != ' ' && *p != '\t'; p++)
@ -2287,7 +2329,6 @@ cmd_import_key (assuan_context_t ctx, char *line)
goto leave; /* Note that ERR is still set. */ goto leave; /* Note that ERR is still set. */
} }
if (openpgp_sexp) if (openpgp_sexp)
{ {
/* In most cases the key is encrypted and thus the conversion /* In most cases the key is encrypted and thus the conversion
@ -2351,10 +2392,12 @@ cmd_import_key (assuan_context_t ctx, char *line)
err = agent_protect (key, passphrase, &finalkey, &finalkeylen, err = agent_protect (key, passphrase, &finalkey, &finalkeylen,
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);
} }
else else
err = agent_write_private_key (grip, key, realkeylen, force); err = agent_write_private_key (grip, key, realkeylen, force,
opt_timestamp);
leave: leave:
gcry_sexp_release (openpgp_sexp); gcry_sexp_release (openpgp_sexp);

View File

@ -1067,7 +1067,7 @@ 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); agent_write_private_key (grip, protectedkey, protectedkeylen, 1, 0);
xfree (protectedkey); xfree (protectedkey);
} }
else else
@ -1076,7 +1076,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); 1, 0);
} }
} }

View File

@ -54,8 +54,8 @@ 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, write_extended_private_key (char *fname, estream_t fp, int update, int newkey,
const void *buf, size_t len) const void *buf, size_t len, time_t timestamp)
{ {
gpg_error_t err; gpg_error_t err;
nvc_t pk = NULL; nvc_t pk = NULL;
@ -93,6 +93,19 @@ write_extended_private_key (char *fname, estream_t fp, int update,
if (err) if (err)
goto leave; goto leave;
/* If a timestamp has been supplied and the key is new write a
* creation timestamp. (We double check that there is no Created
* item yet.)*/
if (timestamp && newkey && !nvc_lookup (pk, "Created:"))
{
gnupg_isotime_t timebuf;
epoch2isotime (timebuf, timestamp);
err = nvc_add (pk, "Created:", timebuf);
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;
@ -136,11 +149,13 @@ write_extended_private_key (char *fname, estream_t fp, int update,
} }
/* 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. */ * overwritten. If TIMESTAMP is not zero and the key does not yet
* exists it will be recorded as creation date. */
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)
{ {
char *fname; char *fname;
estream_t fp; estream_t fp;
@ -208,17 +223,20 @@ agent_write_private_key (const unsigned char *grip,
if (first != '(') if (first != '(')
{ {
/* Key is already in the extended format. */ /* Key is already in the extended format. */
return write_extended_private_key (fname, fp, 1, buffer, length); return write_extended_private_key (fname, fp, 1, 0, buffer, length,
timestamp);
} }
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, buffer, length); return write_extended_private_key (fname, fp, 0, 0, buffer, length,
timestamp);
} }
} }
if (opt.enable_extended_key_format) if (opt.enable_extended_key_format)
return write_extended_private_key (fname, fp, 0, buffer, length); return write_extended_private_key (fname, fp, 0, 1, buffer, length,
timestamp);
if (es_fwrite (buffer, length, 1, fp) != 1) if (es_fwrite (buffer, length, 1, fp) != 1)
{ {
@ -1596,7 +1614,7 @@ 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); err = agent_write_private_key (grip, shdkey, len, force, 0);
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

@ -33,7 +33,7 @@
static int static int
store_key (gcry_sexp_t private, const char *passphrase, int force, store_key (gcry_sexp_t private, const char *passphrase, int force,
unsigned long s2k_count) unsigned long s2k_count, time_t timestamp)
{ {
int rc; int rc;
unsigned char *buf; unsigned char *buf;
@ -68,7 +68,7 @@ store_key (gcry_sexp_t private, const char *passphrase, int force,
buf = p; buf = p;
} }
rc = agent_write_private_key (grip, buf, len, force); rc = agent_write_private_key (grip, buf, len, force, timestamp);
xfree (buf); xfree (buf);
return rc; return rc;
} }
@ -441,9 +441,11 @@ agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt,
KEYPARAM. If CACHE_NONCE is given first try to lookup a passphrase KEYPARAM. If CACHE_NONCE is given first try to lookup a passphrase
using the cache nonce. If NO_PROTECTION is true the key will not using the cache nonce. If NO_PROTECTION is true the key will not
be protected by a passphrase. If OVERRIDE_PASSPHRASE is true that be protected by a passphrase. If OVERRIDE_PASSPHRASE is true that
passphrase will be used for the new key. */ passphrase will be used for the new key. If TIMESTAMP is not zero
it will be recorded as creation date of the key (unless extended
format is disabled) . */
int int
agent_genkey (ctrl_t ctrl, const char *cache_nonce, agent_genkey (ctrl_t ctrl, const char *cache_nonce, time_t timestamp,
const char *keyparam, size_t keyparamlen, int no_protection, const char *keyparam, size_t keyparamlen, int no_protection,
const char *override_passphrase, int preset, membuf_t *outbuf) const char *override_passphrase, int preset, membuf_t *outbuf)
{ {
@ -517,7 +519,7 @@ agent_genkey (ctrl_t ctrl, const char *cache_nonce,
/* store the secret key */ /* store the secret key */
if (DBG_CRYPTO) if (DBG_CRYPTO)
log_debug ("storing private key\n"); log_debug ("storing private key\n");
rc = store_key (s_private, passphrase, 0, ctrl->s2k_count); rc = store_key (s_private, passphrase, 0, ctrl->s2k_count, timestamp);
if (!rc) if (!rc)
{ {
if (!cache_nonce) if (!cache_nonce)
@ -591,7 +593,7 @@ agent_protect_and_store (ctrl_t ctrl, gcry_sexp_t s_skey,
{ {
/* Take an empty string as request not to protect the key. */ /* Take an empty string as request not to protect the key. */
err = store_key (s_skey, **passphrase_addr? *passphrase_addr:NULL, 1, err = store_key (s_skey, **passphrase_addr? *passphrase_addr:NULL, 1,
ctrl->s2k_count); ctrl->s2k_count, 0);
} }
else else
{ {
@ -606,7 +608,7 @@ agent_protect_and_store (ctrl_t ctrl, gcry_sexp_t s_skey,
L_("Please enter the new passphrase"), L_("Please enter the new passphrase"),
&pass); &pass);
if (!err) if (!err)
err = store_key (s_skey, pass, 1, ctrl->s2k_count); err = store_key (s_skey, pass, 1, ctrl->s2k_count, 0);
if (!err && passphrase_addr) if (!err && passphrase_addr)
*passphrase_addr = pass; *passphrase_addr = pass;
else else

View File

@ -79,6 +79,42 @@ 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
*** Description
This is a human readable string describing the key.
*** Key
The name "Key" is special in that it is mandatory and must occur only
once. The associated value holds the actual S-expression with the
cryptographic key. The S-expression is formatted using the 'Advanced
Format' (GCRYSEXP_FMT_ADVANCED) that avoids non-printable characters
so that the file can be easily inspected and edited. See section
'Private Key Format' below for details.
*** Created
The UTC time the key was created in ISO compressed format
(yyyymmddThhmmss). This informarion can be used to re-create an
OpenPGP key.
*** Label
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 as present
in the S-expression of the "Key" item.
*** OpenSSH-cert
This takes a base64 encoded string wrapped so that this
key file can be easily edited with a standard editor. Several of such
items can be used.
*** Use-for-ssh
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
putting the keygrip into the 'sshcontrol' file. Only one such item
should exist.
* Private Key Format * Private Key Format
** Unprotected Private Key Format ** Unprotected Private Key Format

View File

@ -805,12 +805,14 @@ agent_askpin (ctrl_t ctrl,
* to stdout. */ * to stdout. */
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)
{ {
char hexgrip[40+4+1]; char hexgrip[40+4+1];
char *p; char *p;
(void)force; (void)force;
(void)timestamp;
bin2hex (grip, 20, hexgrip); bin2hex (grip, 20, hexgrip);
strcpy (hexgrip+40, ".key"); strcpy (hexgrip+40, ".key");