aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2020-08-17 12:21:00 +0000
committerWerner Koch <[email protected]>2020-08-17 13:05:49 +0000
commit0da923a1240ac78d60c92cdd8488c4e405c3243b (patch)
tree106ce6faa60a206478752cb21096cc29b4e90d15
parentAdd --chuid to gpg, gpg-card, and gpg-connect-agent. (diff)
downloadgnupg-0da923a1240ac78d60c92cdd8488c4e405c3243b.tar.gz
gnupg-0da923a1240ac78d60c92cdd8488c4e405c3243b.zip
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 new key 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 <[email protected]>
-rw-r--r--agent/agent.h5
-rw-r--r--agent/command-ssh.c6
-rw-r--r--agent/command.c66
-rw-r--r--agent/cvt-openpgp.c4
-rw-r--r--agent/findkey.c41
-rw-r--r--agent/genkey.c16
-rw-r--r--agent/keyformat.txt5
-rw-r--r--agent/protect-tool.c4
8 files changed, 109 insertions, 38 deletions
diff --git a/agent/agent.h b/agent/agent.h
index 7f18eb601..25d9e2d29 100644
--- a/agent/agent.h
+++ b/agent/agent.h
@@ -442,7 +442,8 @@ gpg_error_t agent_modify_description (const char *in, const char *comment,
const gcry_sexp_t key, char **result);
int agent_write_private_key (const unsigned char *grip,
const void *buffer, size_t length, int force,
- const char *serialno, const char *keyref);
+ const char *serialno, const char *keyref,
+ time_t timestamp);
gpg_error_t agent_key_from_file (ctrl_t ctrl,
const char *cache_nonce,
const char *desc_text,
@@ -522,7 +523,7 @@ int check_passphrase_constraints (ctrl_t ctrl, const char *pw, int no_empty,
char **failed_constraint);
gpg_error_t agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt,
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,
int no_protection, const char *override_passphrase,
int preset, membuf_t *outbuf);
diff --git a/agent/command-ssh.c b/agent/command-ssh.c
index 664bd0d30..9081f6f89 100644
--- a/agent/command-ssh.c
+++ b/agent/command-ssh.c
@@ -3036,8 +3036,10 @@ ssh_identity_register (ctrl_t ctrl, ssh_key_type_spec_t *spec,
if (err)
goto out;
- /* Store this key to our key storage. */
- err = agent_write_private_key (key_grip_raw, buffer, buffer_n, 0, NULL, NULL);
+ /* Store this key to our key storage. We do not store a creation
+ * timestamp because we simply do not know. */
+ err = agent_write_private_key (key_grip_raw, buffer, buffer_n, 0,
+ NULL, NULL, 0);
if (err)
goto out;
diff --git a/agent/command.c b/agent/command.c
index 6efde5e28..b2bb72ace 100644
--- a/agent/command.c
+++ b/agent/command.c
@@ -928,8 +928,8 @@ cmd_pkdecrypt (assuan_context_t ctx, char *line)
static const char hlp_genkey[] =
- "GENKEY [--no-protection] [--preset] [--inq-passwd]\n"
- " [--passwd-nonce=<s>] [<cache_nonce>]\n"
+ "GENKEY [--no-protection] [--preset] [--timestamp=<isodate>]\n"
+ " [--inq-passwd] [--passwd-nonce=<s>] [<cache_nonce>]\n"
"\n"
"Generate a new key, store the secret part and return the public\n"
"part. Here is an example transaction:\n"
@@ -942,11 +942,13 @@ static const char hlp_genkey[] =
" S: D (rsa (n 326487324683264) (e 10001)))\n"
" S: OK key created\n"
"\n"
- "When 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"
+ "If the --preset option is used the passphrase for the generated\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"
- "new key. When a --passwd-nonce is used, the corresponding cached\n"
- "passphrase is used to protect the new key.";
+ "new key. If a --passwd-nonce is used, the corresponding cached\n"
+ "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
cmd_genkey (assuan_context_t ctx, char *line)
{
@@ -963,6 +965,8 @@ cmd_genkey (assuan_context_t ctx, char *line)
int opt_inq_passwd;
size_t n;
char *p, *pend;
+ const char *s;
+ time_t opt_timestamp;
int c;
if (ctrl->restricted)
@@ -986,6 +990,22 @@ cmd_genkey (assuan_context_t ctx, char *line)
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);
for (p=line; *p && *p != ' ' && *p != '\t'; p++)
@@ -1027,7 +1047,8 @@ cmd_genkey (assuan_context_t ctx, char *line)
else if (passwd_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);
leave:
@@ -2321,7 +2342,8 @@ cmd_keywrap_key (assuan_context_t ctx, char *line)
static const char hlp_import_key[] =
- "IMPORT_KEY [--unattended] [--force] [<cache_nonce>]\n"
+ "IMPORT_KEY [--unattended] [--force] [--timestamp=<isodate>]\n"
+ " [<cache_nonce>]\n"
"\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"
@@ -2329,13 +2351,16 @@ static const char hlp_import_key[] =
"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"
"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
cmd_import_key (assuan_context_t ctx, char *line)
{
ctrl_t ctrl = assuan_get_pointer (ctx);
gpg_error_t err;
int opt_unattended;
+ time_t opt_timestamp;
int force;
unsigned char *wrappedkey = NULL;
size_t wrappedkeylen;
@@ -2349,6 +2374,7 @@ cmd_import_key (assuan_context_t ctx, char *line)
gcry_sexp_t openpgp_sexp = NULL;
char *cache_nonce = NULL;
char *p;
+ const char *s;
if (ctrl->restricted)
return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
@@ -2361,6 +2387,22 @@ cmd_import_key (assuan_context_t ctx, char *line)
opt_unattended = has_option (line, "--unattended");
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);
for (p=line; *p && *p != ' ' && *p != '\t'; p++)
@@ -2434,7 +2476,6 @@ cmd_import_key (assuan_context_t ctx, char *line)
goto leave; /* Note that ERR is still set. */
}
-
if (openpgp_sexp)
{
/* In most cases the key is encrypted and thus the conversion
@@ -2499,10 +2540,11 @@ cmd_import_key (assuan_context_t ctx, char *line)
ctrl->s2k_count, -1);
if (!err)
err = agent_write_private_key (grip, finalkey, finalkeylen, force,
- NULL, NULL);
+ NULL, NULL, opt_timestamp);
}
else
- err = agent_write_private_key (grip, key, realkeylen, force, NULL, NULL);
+ err = agent_write_private_key (grip, key, realkeylen, force, NULL, NULL,
+ opt_timestamp);
leave:
gcry_sexp_release (openpgp_sexp);
diff --git a/agent/cvt-openpgp.c b/agent/cvt-openpgp.c
index 5d60b66f3..c43809f90 100644
--- a/agent/cvt-openpgp.c
+++ b/agent/cvt-openpgp.c
@@ -1114,7 +1114,7 @@ convert_from_openpgp_native (ctrl_t ctrl,
&protectedkey, &protectedkeylen,
ctrl->s2k_count, -1))
agent_write_private_key (grip, protectedkey, protectedkeylen, 1,
- NULL, NULL);
+ NULL, NULL, 0);
xfree (protectedkey);
}
else
@@ -1123,7 +1123,7 @@ convert_from_openpgp_native (ctrl_t ctrl,
agent_write_private_key (grip,
*r_key,
gcry_sexp_canon_len (*r_key, 0, NULL,NULL),
- 1, NULL, NULL);
+ 1, NULL, NULL, 0);
}
}
diff --git a/agent/findkey.c b/agent/findkey.c
index 0951a754e..a9a8fb851 100644
--- a/agent/findkey.c
+++ b/agent/findkey.c
@@ -82,9 +82,10 @@ linefeed_to_percent0A (const char *string)
/* 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,
+write_extended_private_key (char *fname, estream_t fp, int update, int newkey,
const void *buf, size_t len,
- const char *serialno, const char *keyref)
+ const char *serialno, const char *keyref,
+ time_t timestamp)
{
gpg_error_t err;
nvc_t pk = NULL;
@@ -153,6 +154,19 @@ write_extended_private_key (char *fname, estream_t fp, int update,
}
}
+ /* If a timestamp has been supplied and the key is new write a
+ * creation timestamp. (We douple 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);
if (err)
@@ -199,12 +213,15 @@ write_extended_private_key (char *fname, estream_t fp, int update,
/* Write an S-expression formatted key to our key storage. With FORCE
* passed as true an existing key with the given GRIP will get
- * overwritten. If SERIALNO and KEYREF are given a Token line is added to
- * the key if the extended format is used. */
+ * overwritten. If SERIALNO and KEYREF are given a Token line is
+ * added to the key if the extended format is used. If TIMESTAMP is
+ * not zero and the key doies not yet exists it will be recorded as
+ * creation date. */
int
agent_write_private_key (const unsigned char *grip,
const void *buffer, size_t length, int force,
- const char *serialno, const char *keyref)
+ const char *serialno, const char *keyref,
+ time_t timestamp)
{
char *fname;
estream_t fp;
@@ -272,20 +289,20 @@ agent_write_private_key (const unsigned char *grip,
if (first != '(')
{
/* Key is already in the extended format. */
- return write_extended_private_key (fname, fp, 1, buffer, length,
- serialno, keyref);
+ return write_extended_private_key (fname, fp, 1, 0, buffer, length,
+ serialno, keyref, timestamp);
}
if (first == '(' && opt.enable_extended_key_format)
{
/* Key is in the old format - but we want the extended format. */
- return write_extended_private_key (fname, fp, 0, buffer, length,
- serialno, keyref);
+ return write_extended_private_key (fname, fp, 0, 0, buffer, length,
+ serialno, keyref, timestamp);
}
}
if (opt.enable_extended_key_format)
- return write_extended_private_key (fname, fp, 0, buffer, length,
- serialno, keyref);
+ return write_extended_private_key (fname, fp, 0, 1, buffer, length,
+ serialno, keyref, timestamp);
if (es_fwrite (buffer, length, 1, fp) != 1)
{
@@ -1552,7 +1569,7 @@ agent_write_shadow_key (const unsigned char *grip,
}
len = gcry_sexp_canon_len (shdkey, 0, NULL, NULL);
- err = agent_write_private_key (grip, shdkey, len, force, serialno, keyid);
+ err = agent_write_private_key (grip, shdkey, len, force, serialno, keyid, 0);
xfree (shdkey);
if (err)
log_error ("error writing key: %s\n", gpg_strerror (err));
diff --git a/agent/genkey.c b/agent/genkey.c
index 970876ba1..9b47f0fac 100644
--- a/agent/genkey.c
+++ b/agent/genkey.c
@@ -32,7 +32,7 @@
static int
store_key (gcry_sexp_t private, const char *passphrase, int force,
- unsigned long s2k_count)
+ unsigned long s2k_count, time_t timestamp)
{
int rc;
unsigned char *buf;
@@ -67,7 +67,7 @@ store_key (gcry_sexp_t private, const char *passphrase, int force,
buf = p;
}
- rc = agent_write_private_key (grip, buf, len, force, NULL, NULL);
+ rc = agent_write_private_key (grip, buf, len, force, NULL, NULL, timestamp);
xfree (buf);
return rc;
}
@@ -423,9 +423,11 @@ agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt,
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
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
-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 *override_passphrase, int preset, membuf_t *outbuf)
{
@@ -499,7 +501,7 @@ agent_genkey (ctrl_t ctrl, const char *cache_nonce,
/* store the secret key */
if (DBG_CRYPTO)
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 (!cache_nonce)
@@ -573,7 +575,7 @@ agent_protect_and_store (ctrl_t ctrl, gcry_sexp_t s_skey,
{
/* Take an empty string as request not to protect the key. */
err = store_key (s_skey, **passphrase_addr? *passphrase_addr:NULL, 1,
- ctrl->s2k_count);
+ ctrl->s2k_count, 0);
}
else
{
@@ -588,7 +590,7 @@ agent_protect_and_store (ctrl_t ctrl, gcry_sexp_t s_skey,
L_("Please enter the new passphrase"),
&pass);
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)
*passphrase_addr = pass;
else
diff --git a/agent/keyformat.txt b/agent/keyformat.txt
index e2ca05c84..7e1b9613d 100644
--- a/agent/keyformat.txt
+++ b/agent/keyformat.txt
@@ -86,6 +86,11 @@ 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
diff --git a/agent/protect-tool.c b/agent/protect-tool.c
index a95f418e6..8325f2564 100644
--- a/agent/protect-tool.c
+++ b/agent/protect-tool.c
@@ -816,7 +816,8 @@ agent_askpin (ctrl_t ctrl,
int
agent_write_private_key (const unsigned char *grip,
const void *buffer, size_t length, int force,
- const char *serialno, const char *keyref)
+ const char *serialno, const char *keyref,
+ time_t timestamp)
{
char hexgrip[40+4+1];
char *p;
@@ -824,6 +825,7 @@ agent_write_private_key (const unsigned char *grip,
(void)force;
(void)serialno;
(void)keyref;
+ (void)timestamp;
bin2hex (grip, 20, hexgrip);
strcpy (hexgrip+40, ".key");