diff --git a/agent/agent.h b/agent/agent.h index 3b53ba45d..01e675b52 100644 --- a/agent/agent.h +++ b/agent/agent.h @@ -124,6 +124,9 @@ struct passphrase change. */ int enable_passphrase_history; + /* If set the extended key format is used for new keys. */ + int enable_extended_key_format; + int running_detached; /* We are running detached from the tty. */ /* If this global option is true, the passphrase cache is ignored diff --git a/agent/findkey.c b/agent/findkey.c index 4429b7a17..0b2ddf1f9 100644 --- a/agent/findkey.c +++ b/agent/findkey.c @@ -52,23 +52,38 @@ struct try_unprotect_arg_s }; +/* Note: Ownership of FNAME and FP are moved to this function. */ static gpg_error_t -write_extended_private_key (char *fname, estream_t fp, +write_extended_private_key (char *fname, estream_t fp, int update, const void *buf, size_t len) { gpg_error_t err; nvc_t pk = NULL; gcry_sexp_t key = NULL; int remove = 0; - int line; - err = nvc_parse_private_key (&pk, &line, fp); - if (err) + if (update) { - log_error ("error parsing '%s' line %d: %s\n", - fname, line, gpg_strerror (err)); - goto leave; + int line; + + err = nvc_parse_private_key (&pk, &line, fp); + if (err && gpg_err_code (err) != GPG_ERR_ENOENT) + { + log_error ("error parsing '%s' line %d: %s\n", + fname, line, gpg_strerror (err)); + goto leave; + } } + else + { + pk = nvc_new_private_key (); + if (!pk) + { + err = gpg_error_from_syserror (); + goto leave; + } + } + es_clearerr (fp); err = gcry_sexp_sscan (&key, NULL, buf, len); if (err) @@ -111,8 +126,7 @@ write_extended_private_key (char *fname, estream_t fp, bump_key_eventcounter (); leave: - if (fp) - es_fclose (fp); + es_fclose (fp); if (remove) gnupg_remove (fname); xfree (fname); @@ -193,11 +207,19 @@ agent_write_private_key (const unsigned char *grip, if (first != '(') { - /* Key is in extended format. */ - return write_extended_private_key (fname, fp, buffer, length); + /* Key is already in the extended format. */ + return write_extended_private_key (fname, fp, 1, buffer, length); + } + 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); } } + if (opt.enable_extended_key_format) + return write_extended_private_key (fname, fp, 0, buffer, length); + if (es_fwrite (buffer, length, 1, fp) != 1) { gpg_error_t tmperr = gpg_error_from_syserror (); diff --git a/agent/gpg-agent.c b/agent/gpg-agent.c index c84dce731..49b10c1ef 100644 --- a/agent/gpg-agent.c +++ b/agent/gpg-agent.c @@ -111,6 +111,7 @@ enum cmd_and_opt_values oCheckPassphrasePattern, oMaxPassphraseDays, oEnablePassphraseHistory, + oEnableExtendedKeyFormat, oUseStandardSocket, oNoUseStandardSocket, oExtraSocket, @@ -238,6 +239,7 @@ static ARGPARSE_OPTS opts[] = { /* */ "@" #endif ), + ARGPARSE_s_n (oEnableExtendedKeyFormat, "enable-extended-key-format", "@"), /* Dummy options for backward compatibility. */ ARGPARSE_o_s (oWriteEnvFile, "write-env-file", "@"), @@ -790,6 +792,7 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread) opt.check_passphrase_pattern = NULL; opt.max_passphrase_days = MAX_PASSPHRASE_DAYS; opt.enable_passphrase_history = 0; + opt.enable_extended_key_format = 0; opt.ignore_cache_for_signing = 0; opt.allow_mark_trusted = 1; opt.allow_external_cache = 1; @@ -859,6 +862,10 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread) opt.enable_passphrase_history = 1; break; + case oEnableExtendedKeyFormat: + opt.enable_extended_key_format = 1; + break; + case oIgnoreCacheForSigning: opt.ignore_cache_for_signing = 1; break; case oAllowMarkTrusted: opt.allow_mark_trusted = 1; break; diff --git a/doc/gpg-agent.texi b/doc/gpg-agent.texi index b72892c2a..ca9d469fd 100644 --- a/doc/gpg-agent.texi +++ b/doc/gpg-agent.texi @@ -571,6 +571,15 @@ local gpg-agent and use its private keys. This enables decrypting or signing data on a remote machine without exposing the private keys to the remote machine. +@anchor{option --enable-extended-key-format} +@item --enable-extended-key-format +@opindex enable-extended-key-format +This option creates keys in the extended private key format. Changing +the passphrase of a key will also convert the key to that new format. +Using this option makes the private keys unreadable for gpg-agent +versions before 2.1.12. The advantage of the extended private key +format is that it is text based and can carry additional meta data. + @anchor{option --enable-ssh-support} @item --enable-ssh-support