agent: Make --disable-extended-key-format a dummy option.

* agent/agent.h (opt): Remove enable_extended_key_format.
* agent/gpg-agent.c (enum cmd_and_opt_values): Turn
oDisableExtendedKeyFormat and oEnableExtendedKeyFormat into dummy
options.

* agent/protect.c (do_encryption): Remove arg use_ocb and
corresponding code.
(agent_protect): Ditto.  Change all callers.

* agent/command.c (cmd_readkey): Do not test for key availability here
but defer that agent_write_shadow_key.

* agent/findkey.c (agent_write_private_key): Simplify due to the
removal of disable-extended-key-format.
(write_extended_private_key): Fold into agent_write_private_key.
Remove the maybe_update arg.
(agent_write_shadow_key): Ditto.  Simplify.
--

GnuPG-bug-id: 6386
Backported-from-master: 6d792ae2eb
But with large changes to get 2.2 more aligned with master again.  This
is not finished; in particular the bug is not fixed; this comes wit
the next patch.
This commit is contained in:
Werner Koch 2023-03-13 08:49:49 +01:00
parent db73f17f0c
commit 4f754caad8
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
12 changed files with 227 additions and 449 deletions

View File

@ -132,13 +132,6 @@ struct
passphrase change. */
int enable_passphrase_history;
/* If set the extended key format is used for new keys. Note that
* this may have the value 2 in which case
* --disable-extended-key-format won't have any effect and thus
* effectivley locking it. This is required to support existing
* profiles which lock the use of --enable-extended-key-format. */
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
@ -430,9 +423,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,
time_t timestamp,
const char *serialno, const char *keyref,
const char *dispserialno);
const char *dispserialno, time_t timestamp);
gpg_error_t agent_key_from_file (ctrl_t ctrl,
const char *cache_nonce,
const char *desc_text,
@ -533,7 +525,7 @@ unsigned char get_standard_s2k_count_rfc4880 (void);
unsigned long get_standard_s2k_time (void);
int agent_protect (const unsigned char *plainkey, const char *passphrase,
unsigned char **result, size_t *resultlen,
unsigned long s2k_count, int use_ocb);
unsigned long s2k_count);
gpg_error_t agent_unprotect (ctrl_t ctrl,
const unsigned char *protectedkey, const char *passphrase,
gnupg_isotime_t protected_at,
@ -552,8 +544,7 @@ gpg_error_t s2k_hash_passphrase (const char *passphrase, int hashalgo,
const unsigned char *s2ksalt,
unsigned int s2kcount,
unsigned char *key, size_t keylen);
gpg_error_t agent_write_shadow_key (int maybe_update,
const unsigned char *grip,
gpg_error_t agent_write_shadow_key (const unsigned char *grip,
const char *serialno, const char *keyid,
const unsigned char *pkbuf, int force,
const char *dispserialno);

View File

@ -2499,7 +2499,7 @@ card_key_available (ctrl_t ctrl, gcry_sexp_t *r_pk, char **cardsn)
/* (Shadow)-key is not available in our key storage. */
agent_card_getattr (ctrl, "$DISPSERIALNO", &dispserialno);
err = agent_write_shadow_key (0, grip, serialno, authkeyid, pkbuf, 0,
err = agent_write_shadow_key (grip, serialno, authkeyid, pkbuf, 0,
dispserialno);
xfree (dispserialno);
if (err)
@ -3028,7 +3028,7 @@ ssh_key_to_protected_buffer (gcry_sexp_t key, const char *passphrase,
buffer_new, buffer_new_n);
if (*passphrase)
err = agent_protect (buffer_new, passphrase, buffer, buffer_n, 0, -1);
err = agent_protect (buffer_new, passphrase, buffer, buffer_n, 0);
else
{
/* The key derivation function does not support zero length
@ -3159,8 +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
* timestamp because we simply do not know. */
err = agent_write_private_key (key_grip_raw, buffer, buffer_n, 0, 0,
NULL, NULL, NULL);
err = agent_write_private_key (key_grip_raw, buffer, buffer_n, 0,
NULL, NULL, NULL, 0);
if (err)
goto out;

View File

@ -975,7 +975,6 @@ cmd_genkey (assuan_context_t ctx, char *line)
}
static const char hlp_readkey[] =
"READKEY [--no-data] <hexstring_with_keygrip>\n"
@ -1040,20 +1039,11 @@ cmd_readkey (assuan_context_t ctx, char *line)
}
agent_card_getattr (ctrl, "$DISPSERIALNO", &dispserialno);
if (agent_key_available (grip))
{
/* Shadow-key is not available in our key storage. */
rc = agent_write_shadow_key (0, grip, serialno, keyid, pkbuf, 0,
dispserialno);
}
else
{
/* Shadow-key is available in our key storage but ne check
* whether we need to update it with a new display-s/n or
* whatever. */
rc = agent_write_shadow_key (1, grip, serialno, keyid, pkbuf, 0,
dispserialno);
}
/* Shadow-key is or is not available in our key storage. In
* any case we need to check whether we need to update with
* a new display-s/n or whatever. */
rc = agent_write_shadow_key (grip, serialno, keyid, pkbuf, 0,
dispserialno);
if (rc)
goto leave;
@ -2435,14 +2425,14 @@ cmd_import_key (assuan_context_t ctx, char *line)
if (passphrase)
{
err = agent_protect (key, passphrase, &finalkey, &finalkeylen,
ctrl->s2k_count, -1);
ctrl->s2k_count);
if (!err)
err = agent_write_private_key (grip, finalkey, finalkeylen, force,
opt_timestamp, NULL, NULL, NULL);
NULL, NULL, NULL, opt_timestamp);
}
else
err = agent_write_private_key (grip, key, realkeylen, force,
opt_timestamp, NULL, NULL, NULL);
NULL, NULL, NULL, opt_timestamp);
leave:
gcry_sexp_release (openpgp_sexp);

View File

@ -1068,9 +1068,9 @@ convert_from_openpgp_native (ctrl_t ctrl,
if (!agent_protect (*r_key, passphrase,
&protectedkey, &protectedkeylen,
ctrl->s2k_count, -1))
ctrl->s2k_count))
agent_write_private_key (grip, protectedkey, protectedkeylen,
1, 0, NULL, NULL, NULL);
1/*force*/, NULL, NULL, NULL, 0);
xfree (protectedkey);
}
else
@ -1079,7 +1079,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, 0, NULL, NULL, NULL);
1/*force*/, NULL, NULL, NULL, 0);
}
}

View File

@ -1,7 +1,8 @@
/* 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
* Copyright (C) 2023 g10 Code GmbH
*
* This file is part of GnuPG.
*
@ -67,20 +68,23 @@ fname_from_keygrip (const unsigned char *grip)
}
/* Note: Ownership of FNAME and FP are moved to this function.
* OLD_FORMAT is true if the file exists but is still in the
* non-extended mode format. If MAYBE_UPDATE is set the function
* assumes that the file exists but writes it only if it figures that
* an update is required. */
static gpg_error_t
write_extended_private_key (int maybe_update,
char *fname, estream_t fp,
int old_format, int newkey,
const void *buf, size_t len, time_t timestamp,
const char *serialno, const char *keyref,
const char *dispserialno)
/* Write the S-expression formatted key (BUFFER,LENGTH) 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. 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 *dispserialno,
time_t timestamp)
{
gpg_error_t err;
char *fname;
estream_t fp;
int update, newkey;
nvc_t pk = NULL;
gcry_sexp_t key = NULL;
int remove = 0;
@ -89,54 +93,122 @@ write_extended_private_key (int maybe_update,
char *dispserialno_buffer = NULL;
char **tokenfields = NULL;
if (old_format || newkey)
fname = fname_from_keygrip (grip);
if (!fname)
return out_of_core ();
/* FIXME: Write to a temp file first so that write failures during
key updates won't lead to a key loss. */
if (!force && !gnupg_access (fname, F_OK))
{
/* We must create a new NVC if the key is still in the old
* format and of course if it is a new key. */
pk = nvc_new_private_key ();
if (!pk)
log_error ("secret key file '%s' already exists\n", fname);
xfree (fname);
return gpg_error (GPG_ERR_EEXIST);
}
fp = es_fopen (fname, force? "rb+,mode=-rw" : "wbx,mode=-rw");
if (!fp)
{
gpg_error_t tmperr = gpg_error_from_syserror ();
if (force && gpg_err_code (tmperr) == GPG_ERR_ENOENT)
{
err = gpg_error_from_syserror ();
goto leave;
fp = es_fopen (fname, "wbx,mode=-rw");
if (!fp)
tmperr = gpg_error_from_syserror ();
}
if (!fp)
{
log_error ("can't create '%s': %s\n", fname, gpg_strerror (tmperr));
xfree (fname);
return tmperr;
}
update = 0;
newkey = 1;
}
else if (force)
{
gpg_error_t rc;
char first;
/* See if an existing key is in extended format. */
if (es_fread (&first, 1, 1, fp) != 1)
{
rc = gpg_error_from_syserror ();
log_error ("error reading first byte from '%s': %s\n",
fname, strerror (errno));
xfree (fname);
es_fclose (fp);
return rc;
}
rc = es_fseek (fp, 0, SEEK_SET);
if (rc)
{
log_error ("error seeking in '%s': %s\n", fname, strerror (errno));
xfree (fname);
es_fclose (fp);
return rc;
}
if (first == '(')
{
/* Key is still in the old format - force it into extended
* format. We do not request an update here because an
* existing key is not yet in extended key format and no
* extended infos are yet available. */
update = 0;
newkey = 0;
}
else
{
/* Key is already in the extended format. */
update = 1;
newkey = 0;
}
maybe_update = 0; /* Always write. */
}
else
{ /* Parse the existing NVC. */
{
/* The key file did not exist: we assume this is a new key and
* write the Created: entry. */
update = 0;
newkey = 1;
}
if (update)
{
int lineno = 0;
err = nvc_parse_private_key (&pk, &lineno, fp);
if (err)
if (err && gpg_err_code (err) != GPG_ERR_ENOENT)
{
log_error ("error parsing '%s' line %d: %s\n",
fname, lineno, 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);
/* Turn (BUFFER,LENGTH) into a gcrypt s-expression and set it into
* our name value container. */
err = gcry_sexp_sscan (&key, NULL, buffer, length);
if (err)
goto leave;
err = nvc_set_private_key (pk, key);
if (err)
goto leave;
/* If a timestamp has been supplied and the key is new write a
* creation timestamp. Note that we can't add this item if we are
* still in the old format. We also add an extra 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;
}
/* If requested write a Token line. */
if (serialno && keyref)
{
@ -179,13 +251,12 @@ write_extended_private_key (int maybe_update,
err = nvc_add (pk, "Token:", token);
if (err)
goto leave;
maybe_update = 0; /* Force write. */
}
else
{
/* Token exists: Update the display s/n. It may have
* changed due to changes in a newer software version. */
if (maybe_update && s && (tokenfields = strtokenize (s, " \t\n"))
if (s && (tokenfields = strtokenize (s, " \t\n"))
&& tokenfields[0] && tokenfields[1] && tokenfields[2]
&& tokenfields[3]
&& !strcmp (tokenfields[3], dispserialno))
@ -195,34 +266,44 @@ write_extended_private_key (int maybe_update,
err = nve_set (item, token);
if (err)
goto leave;
maybe_update = 0; /* Force write. */
}
}
}
/* 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;
}
/* Back to start and write. */
err = es_fseek (fp, 0, SEEK_SET);
if (err)
goto leave;
if (!maybe_update)
err = nvc_write (pk, fp);
if (!err)
err = es_fflush (fp);
if (err)
{
err = nvc_write (pk, fp);
if (!err)
err = es_fflush (fp);
if (err)
{
log_error ("error writing '%s': %s\n", fname, gpg_strerror (err));
remove = 1;
goto leave;
}
log_error ("error writing '%s': %s\n", fname, gpg_strerror (err));
remove = 1;
goto leave;
}
if (ftruncate (es_fileno (fp), es_ftello (fp)))
{
err = gpg_error_from_syserror ();
log_error ("error truncating '%s': %s\n", fname, gpg_strerror (err));
remove = 1;
goto leave;
}
if (ftruncate (es_fileno (fp), es_ftello (fp)))
{
err = gpg_error_from_syserror ();
log_error ("error truncating '%s': %s\n", fname, gpg_strerror (err));
remove = 1;
goto leave;
}
if (es_fclose (fp))
@ -235,8 +316,7 @@ write_extended_private_key (int maybe_update,
else
fp = NULL;
if (!maybe_update)
bump_key_eventcounter ();
bump_key_eventcounter ();
leave:
es_fclose (fp);
@ -252,136 +332,6 @@ write_extended_private_key (int maybe_update,
return err;
}
/* 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 TIMESTAMP is not zero and the key does not yet
* exists it will be recorded as creation date. If SERIALNO, KEYREF,
* of DISPSERIALNO are not NULL they will be recorded as well. */
int
agent_write_private_key (const unsigned char *grip,
const void *buffer, size_t length,
int force, time_t timestamp,
const char *serialno, const char *keyref,
const char *dispserialno)
{
char *fname;
estream_t fp;
fname = fname_from_keygrip (grip);
if (!fname)
return gpg_error_from_syserror ();
/* FIXME: Write to a temp file first so that write failures during
key updates won't lead to a key loss. */
if (!force && !gnupg_access (fname, F_OK))
{
log_error ("secret key file '%s' already exists\n", fname);
xfree (fname);
return gpg_error (GPG_ERR_EEXIST);
}
fp = es_fopen (fname, force? "rb+,mode=-rw" : "wbx,mode=-rw");
if (!fp)
{
gpg_error_t tmperr = gpg_error_from_syserror ();
if (force && gpg_err_code (tmperr) == GPG_ERR_ENOENT)
{
fp = es_fopen (fname, "wbx,mode=-rw");
if (!fp)
tmperr = gpg_error_from_syserror ();
}
if (!fp)
{
log_error ("can't create '%s': %s\n", fname, gpg_strerror (tmperr));
xfree (fname);
return tmperr;
}
}
else if (force)
{
gpg_error_t rc;
char first;
/* See if an existing key is in extended format. */
if (es_fread (&first, 1, 1, fp) != 1)
{
rc = gpg_error_from_syserror ();
log_error ("error reading first byte from '%s': %s\n",
fname, strerror (errno));
xfree (fname);
es_fclose (fp);
return rc;
}
rc = es_fseek (fp, 0, SEEK_SET);
if (rc)
{
log_error ("error seeking in '%s': %s\n", fname, strerror (errno));
xfree (fname);
es_fclose (fp);
return rc;
}
if (first != '(')
{
/* Key is already in the extended format. */
return write_extended_private_key (0, fname, fp, 0, 0,
buffer, length,
timestamp, serialno, keyref,
dispserialno);
}
if (first == '(' && opt.enable_extended_key_format)
{
/* Key is in the old format - but we want the extended format. */
return write_extended_private_key (0, fname, fp, 1, 0,
buffer, length,
timestamp, serialno, keyref,
dispserialno);
}
}
if (opt.enable_extended_key_format)
return write_extended_private_key (0, fname, fp, 0, 1,
buffer, length,
timestamp, serialno, keyref,
dispserialno);
if (es_fwrite (buffer, length, 1, fp) != 1)
{
gpg_error_t tmperr = gpg_error_from_syserror ();
log_error ("error writing '%s': %s\n", fname, gpg_strerror (tmperr));
es_fclose (fp);
gnupg_remove (fname);
xfree (fname);
return tmperr;
}
/* When force is given, the file might have to be truncated. */
if (force && ftruncate (es_fileno (fp), es_ftello (fp)))
{
gpg_error_t tmperr = gpg_error_from_syserror ();
log_error ("error truncating '%s': %s\n", fname, gpg_strerror (tmperr));
es_fclose (fp);
gnupg_remove (fname);
xfree (fname);
return tmperr;
}
if (es_fclose (fp))
{
gpg_error_t tmperr = gpg_error_from_syserror ();
log_error ("error closing '%s': %s\n", fname, gpg_strerror (tmperr));
gnupg_remove (fname);
xfree (fname);
return tmperr;
}
bump_key_eventcounter ();
xfree (fname);
return 0;
}
/* Callback function to try the unprotection from the passphrase query
code. */
@ -837,19 +787,14 @@ read_key_file (const unsigned char *grip, gcry_sexp_t *result, nvc_t *r_keymeta)
unsigned char *buf;
size_t buflen, erroff;
gcry_sexp_t s_skey;
char hexgrip[40+4+1];
char first;
*result = NULL;
if (r_keymeta)
*r_keymeta = NULL;
bin2hex (grip, 20, hexgrip);
strcpy (hexgrip+40, ".key");
fname = make_filename (gnupg_homedir (), GNUPG_PRIVATE_KEYS_DIR,
hexgrip, NULL);
fp = es_fopen (fname, "rb");
fname = fname_from_keygrip (grip);
fp = fname? es_fopen (fname, "rb") : NULL;
if (!fp)
{
err = gpg_error_from_syserror ();
@ -1722,15 +1667,13 @@ agent_delete_key (ctrl_t ctrl, const char *desc_text,
/* Write an S-expression formatted shadow key to our key storage.
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
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. If MAYBE_UPDATE is set it is assumed that
the shadow key already exists and we test whether we should update
it (FORCE is ignored in this case). */
* 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
* 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
agent_write_shadow_key (int maybe_update, const unsigned char *grip,
agent_write_shadow_key (const unsigned char *grip,
const char *serialno, const char *keyid,
const unsigned char *pkbuf, int force,
const char *dispserialno)
@ -1739,12 +1682,6 @@ agent_write_shadow_key (int maybe_update, const unsigned char *grip,
unsigned char *shadow_info;
unsigned char *shdkey;
size_t len;
char *fname = NULL;
estream_t fp = NULL;
char first;
if (maybe_update && !opt.enable_extended_key_format)
return 0; /* Silently ignore. */
/* Just in case some caller did not parse the stuff correctly, skip
* leading spaces. */
@ -1766,62 +1703,11 @@ agent_write_shadow_key (int maybe_update, const unsigned char *grip,
}
len = gcry_sexp_canon_len (shdkey, 0, NULL, NULL);
if (maybe_update) /* Update mode. */
{
fname = fname_from_keygrip (grip);
if (!fname)
{
err = gpg_error_from_syserror ();
goto leave;
}
fp = es_fopen (fname, "rb+,mode=-rw");
if (!fp)
{
err = gpg_error_from_syserror ();
log_error ("shadow key file '%s' disappeared\n", fname);
goto leave;
}
/* See if an existing key is in extended format. */
if (es_fread (&first, 1, 1, fp) != 1)
{
err = gpg_error_from_syserror ();
log_error ("error reading first byte from '%s': %s\n",
fname, gpg_strerror (err));
goto leave;
}
if (es_fseek (fp, 0, SEEK_SET))
{
err = gpg_error_from_syserror ();
log_error ("error seeking in '%s': %s\n", fname, gpg_strerror (err));
goto leave;
}
/* "(first == '(')" indicates that the key is in the old format. */
err = write_extended_private_key (maybe_update,
fname, fp, (first == '('), 0,
shdkey, len,
0, serialno, keyid,
dispserialno);
fname = NULL; /* Ownership was transferred. */
fp = NULL; /* Ditto. */
}
else /* Standard mode */
{
err = agent_write_private_key (grip, shdkey, len, force, 0,
serialno, keyid, dispserialno);
}
leave:
xfree (fname);
es_fclose (fp);
err = agent_write_private_key (grip, shdkey, len, force,
serialno, keyid, dispserialno, 0);
xfree (shdkey);
if (err)
log_error ("error %s key: %s\n", maybe_update? "updating":"writing",
gpg_strerror (err));
log_error ("error writing key: %s\n", gpg_strerror (err));
return err;
}

View File

@ -59,7 +59,7 @@ store_key (gcry_sexp_t private, const char *passphrase, int force,
{
unsigned char *p;
rc = agent_protect (buf, passphrase, &p, &len, s2k_count, -1);
rc = agent_protect (buf, passphrase, &p, &len, s2k_count);
if (rc)
{
xfree (buf);
@ -69,8 +69,8 @@ store_key (gcry_sexp_t private, const char *passphrase, int force,
buf = p;
}
rc = agent_write_private_key (grip, buf, len, force, timestamp,
NULL, NULL, NULL);
rc = agent_write_private_key (grip, buf, len, force,
NULL, NULL, NULL, timestamp);
xfree (buf);
return rc;
}

View File

@ -116,8 +116,6 @@ enum cmd_and_opt_values
oCheckSymPassphrasePattern,
oMaxPassphraseDays,
oEnablePassphraseHistory,
oDisableExtendedKeyFormat,
oEnableExtendedKeyFormat,
oStealSocket,
oUseStandardSocket,
oNoUseStandardSocket,
@ -227,8 +225,6 @@ static ARGPARSE_OPTS opts[] = {
/* */ "@"
#endif
),
ARGPARSE_s_n (oDisableExtendedKeyFormat, "disable-extended-key-format", "@"),
ARGPARSE_s_n (oEnableExtendedKeyFormat, "enable-extended-key-format", "@"),
ARGPARSE_s_i (oListenBacklog, "listen-backlog", "@"),
ARGPARSE_op_u (oAutoExpandSecmem, "auto-expand-secmem", "@"),
ARGPARSE_s_s (oFakedSystemTime, "faked-system-time", "@"),
@ -303,7 +299,8 @@ static ARGPARSE_OPTS opts[] = {
ARGPARSE_s_n (oNoUseStandardSocket, "no-use-standard-socket", "@"),
/* Dummy options. */
ARGPARSE_s_n (oNoop, "disable-extended-key-format", "@"),
ARGPARSE_s_n (oNoop, "enable-extended-key-format", "@"),
ARGPARSE_end () /* End of list */
};
@ -874,7 +871,6 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
opt.check_sym_passphrase_pattern = NULL;
opt.max_passphrase_days = MAX_PASSPHRASE_DAYS;
opt.enable_passphrase_history = 0;
opt.enable_extended_key_format = 1;
opt.ignore_cache_for_signing = 0;
opt.allow_mark_trusted = 1;
opt.sys_trustlist_name = NULL;
@ -956,14 +952,6 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
opt.enable_passphrase_history = 1;
break;
case oEnableExtendedKeyFormat:
opt.enable_extended_key_format = 2;
break;
case oDisableExtendedKeyFormat:
if (opt.enable_extended_key_format != 2)
opt.enable_extended_key_format = 0;
break;
case oIgnoreCacheForSigning: opt.ignore_cache_for_signing = 1; break;
case oAllowMarkTrusted: opt.allow_mark_trusted = 1; break;

View File

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

View File

@ -98,7 +98,6 @@ static const char *opt_passphrase;
static char *opt_prompt;
static int opt_status_msg;
static const char *opt_agent_program;
static int opt_debug_use_ocb;
static char *get_passphrase (int promptno);
static void release_passphrase (char *pw);
@ -345,8 +344,7 @@ read_and_protect (const char *fname)
return;
pw = get_passphrase (1);
rc = agent_protect (key, pw, &result, &resultlen, 0,
opt_debug_use_ocb? 1 : -1);
rc = agent_protect (key, pw, &result, &resultlen, 0);
release_passphrase (pw);
xfree (key);
if (rc)
@ -605,7 +603,7 @@ main (int argc, char **argv )
case oHaveCert: opt_have_cert = 1; break;
case oPrompt: opt_prompt = pargs.r.ret_str; break;
case oStatusMsg: opt_status_msg = 1; break;
case oDebugUseOCB: opt_debug_use_ocb = 1; break;
case oDebugUseOCB: /* dummy */; break;
default: pargs.err = ARGPARSE_PRINT_ERROR; break;
}
@ -810,9 +808,8 @@ agent_askpin (ctrl_t ctrl,
int
agent_write_private_key (const unsigned char *grip,
const void *buffer, size_t length, int force,
time_t timestamp,
const char *serialno, const char *keyref,
const char *dispserialno)
const char *dispserialno, time_t timestamp)
{
char hexgrip[40+4+1];
char *p;

View File

@ -366,12 +366,11 @@ do_encryption (const unsigned char *hashbegin, size_t hashlen,
const char *passphrase,
const char *timestamp_exp, size_t timestamp_exp_len,
unsigned char **result, size_t *resultlen,
unsigned long s2k_count, int use_ocb)
unsigned long s2k_count)
{
gcry_cipher_hd_t hd;
const char *modestr;
unsigned char hashvalue[20];
int blklen, enclen, outlen;
int enclen, outlen;
unsigned char *iv = NULL;
unsigned int ivsize; /* Size of the buffer allocated for IV. */
const unsigned char *s2ksalt; /* Points into IV. */
@ -385,44 +384,26 @@ do_encryption (const unsigned char *hashbegin, size_t hashlen,
*resultlen = 0;
*result = NULL;
modestr = (use_ocb? "openpgp-s2k3-ocb-aes"
/* */: "openpgp-s2k3-sha1-" PROT_CIPHER_STRING "-cbc");
modestr = "openpgp-s2k3-ocb-aes";
rc = gcry_cipher_open (&hd, PROT_CIPHER,
use_ocb? GCRY_CIPHER_MODE_OCB :
GCRY_CIPHER_MODE_CBC,
GCRY_CIPHER_MODE_OCB,
GCRY_CIPHER_SECURE);
if (rc)
return rc;
/* We need to work on a copy of the data because this makes it
* easier to add the trailer and the padding and more important we
* have to prefix the text with 2 parenthesis. In CBC mode we
* have to allocate enough space for:
*
* ((<parameter_list>)(4:hash4:sha120:<hashvalue>)) + padding
*
* we always append a full block of random bytes as padding but
* encrypt only what is needed for a full blocksize. In OCB mode we
* have to prefix the text with 2 parenthesis. Due to OCB mode we
* have to allocate enough space for just:
*
* ((<parameter_list>))
*/
blklen = gcry_cipher_get_algo_blklen (PROT_CIPHER);
if (use_ocb)
{
/* (( )) */
outlen = 2 + protlen + 2 ;
enclen = outlen + 16 /* taglen */;
outbuf = gcry_malloc_secure (enclen);
}
else
{
/* (( )( 4:hash 4:sha1 20:<hash> )) <padding> */
outlen = 2 + protlen + 2 + 6 + 6 + 23 + 2 + blklen;
enclen = outlen/blklen * blklen;
outbuf = gcry_malloc_secure (outlen);
}
/* (( )) */
outlen = 2 + protlen + 2 ;
enclen = outlen + 16 /* taglen */;
outbuf = gcry_malloc_secure (enclen);
if (!outbuf)
{
rc = out_of_core ();
@ -432,10 +413,10 @@ do_encryption (const unsigned char *hashbegin, size_t hashlen,
/* Allocate a buffer for the nonce and the salt. */
if (!rc)
{
/* Allocate random bytes to be used as IV, padding and s2k salt
* or in OCB mode for a nonce and the s2k salt. The IV/nonce is
* set later because for OCB we need to set the key first. */
ivsize = (use_ocb? 12 : (blklen*2)) + 8;
/* Allocate random bytes to be used as nonce and s2k salt. The
* nonce is set later because for OCB we need to set the key
* first. */
ivsize = 12 + 8;
iv = xtrymalloc (ivsize);
if (!iv)
rc = gpg_error_from_syserror ();
@ -471,40 +452,17 @@ do_encryption (const unsigned char *hashbegin, size_t hashlen,
goto leave;
/* Set the IV/nonce. */
rc = gcry_cipher_setiv (hd, iv, use_ocb? 12 : blklen);
rc = gcry_cipher_setiv (hd, iv, 12);
if (rc)
goto leave;
if (use_ocb)
{
/* In OCB Mode we use only the public key parameters as AAD. */
rc = gcry_cipher_authenticate (hd, hashbegin, protbegin - hashbegin);
if (!rc)
rc = gcry_cipher_authenticate (hd, timestamp_exp, timestamp_exp_len);
if (!rc)
rc = gcry_cipher_authenticate
(hd, protbegin+protlen, hashlen - (protbegin+protlen - hashbegin));
}
else
{
/* Hash the entire expression for CBC mode. Because
* TIMESTAMP_EXP won't get protected, we can't simply hash a
* continuous buffer but need to call md_write several times. */
gcry_md_hd_t md;
rc = gcry_md_open (&md, GCRY_MD_SHA1, 0 );
if (!rc)
{
gcry_md_write (md, hashbegin, protbegin - hashbegin);
gcry_md_write (md, protbegin, protlen);
gcry_md_write (md, timestamp_exp, timestamp_exp_len);
gcry_md_write (md, protbegin+protlen,
hashlen - (protbegin+protlen - hashbegin));
memcpy (hashvalue, gcry_md_read (md, GCRY_MD_SHA1), 20);
gcry_md_close (md);
}
}
/* In OCB Mode we use only the public key parameters as AAD. */
rc = gcry_cipher_authenticate (hd, hashbegin, protbegin - hashbegin);
if (!rc)
rc = gcry_cipher_authenticate (hd, timestamp_exp, timestamp_exp_len);
if (!rc)
rc = gcry_cipher_authenticate
(hd, protbegin+protlen, hashlen - (protbegin+protlen - hashbegin));
/* Encrypt. */
if (!rc)
@ -514,36 +472,15 @@ do_encryption (const unsigned char *hashbegin, size_t hashlen,
*p++ = '(';
memcpy (p, protbegin, protlen);
p += protlen;
if (use_ocb)
*p++ = ')';
*p++ = ')';
log_assert ( p - outbuf == outlen);
gcry_cipher_final (hd);
rc = gcry_cipher_encrypt (hd, outbuf, outlen, NULL, 0);
if (!rc)
{
*p++ = ')';
*p++ = ')';
}
else
{
memcpy (p, ")(4:hash4:sha120:", 17);
p += 17;
memcpy (p, hashvalue, 20);
p += 20;
*p++ = ')';
*p++ = ')';
memcpy (p, iv+blklen, blklen); /* Add padding. */
p += blklen;
}
assert ( p - outbuf == outlen);
if (use_ocb)
{
gcry_cipher_final (hd);
rc = gcry_cipher_encrypt (hd, outbuf, outlen, NULL, 0);
if (!rc)
{
log_assert (outlen + 16 == enclen);
rc = gcry_cipher_gettag (hd, outbuf + outlen, 16);
}
}
else
{
rc = gcry_cipher_encrypt (hd, outbuf, enclen, NULL, 0);
log_assert (outlen + 16 == enclen);
rc = gcry_cipher_gettag (hd, outbuf + outlen, 16);
}
}
@ -554,24 +491,24 @@ do_encryption (const unsigned char *hashbegin, size_t hashlen,
gcry_cipher_close (hd);
/* Now allocate the buffer we want to return. This is
(protected openpgp-s2k3-sha1-aes-cbc
((sha1 salt no_of_iterations) 16byte_iv)
encrypted_octet_string)
in canoncical format of course. We use asprintf and %n modifier
and dummy values as placeholders. */
*
* (protected openpgp-s2k3-ocb-aes
* ((sha1 salt no_of_iterations) 12byte_nonce)
* encrypted_octet_string)
*
* in canoncical format of course. We use asprintf and %n modifier
* and dummy values as placeholders. */
{
char countbuf[35];
snprintf (countbuf, sizeof countbuf, "%lu",
s2k_count ? s2k_count : get_standard_s2k_count ());
s2k_count ? s2k_count : get_standard_s2k_count ());
p = xtryasprintf
("(9:protected%d:%s((4:sha18:%n_8bytes_%u:%s)%d:%n%*s)%d:%n%*s)",
(int)strlen (modestr), modestr,
&saltpos,
(unsigned int)strlen (countbuf), countbuf,
use_ocb? 12 : blklen, &ivpos, use_ocb? 12 : blklen, "",
12, &ivpos, 12, "",
enclen, &encpos, enclen, "");
if (!p)
{
@ -585,7 +522,7 @@ do_encryption (const unsigned char *hashbegin, size_t hashlen,
*resultlen = strlen (p);
*result = (unsigned char*)p;
memcpy (p+saltpos, s2ksalt, 8);
memcpy (p+ivpos, iv, use_ocb? 12 : blklen);
memcpy (p+ivpos, iv, 12);
memcpy (p+encpos, outbuf, enclen);
xfree (iv);
xfree (outbuf);
@ -601,13 +538,11 @@ do_encryption (const unsigned char *hashbegin, size_t hashlen,
/* Protect the key encoded in canonical format in PLAINKEY. We assume
a valid S-Exp here. With USE_UCB set to -1 the default scheme is
used (ie. either CBC or OCB), set to 0 the old CBC mode is used,
and set to 1 OCB is used. */
* a valid S-Exp here. */
int
agent_protect (const unsigned char *plainkey, const char *passphrase,
unsigned char **result, size_t *resultlen,
unsigned long s2k_count, int use_ocb)
unsigned long s2k_count)
{
int rc;
const char *parmlist;
@ -624,9 +559,6 @@ agent_protect (const unsigned char *plainkey, const char *passphrase,
unsigned char *p;
int have_curve = 0;
if (use_ocb == -1)
use_ocb = !!opt.enable_extended_key_format;
/* Create an S-expression with the protected-at timestamp. */
memcpy (timestamp_exp, "(12:protected-at15:", 19);
gnupg_get_isotime (timestamp_exp+19);
@ -730,7 +662,7 @@ agent_protect (const unsigned char *plainkey, const char *passphrase,
rc = do_encryption (hash_begin, hash_end - hash_begin + 1,
prot_begin, prot_end - prot_begin + 1,
passphrase, timestamp_exp, sizeof (timestamp_exp),
&protected, &protectedlen, s2k_count, use_ocb);
&protected, &protectedlen, s2k_count);
if (rc)
return rc;

View File

@ -196,7 +196,7 @@ test_agent_protect (void)
{
ret = agent_protect ((const unsigned char*)specs[i].key,
specs[i].passphrase,
&specs[i].result, &specs[i].resultlen, 0, -1);
&specs[i].result, &specs[i].resultlen, 0);
if (gpg_err_code (ret) != specs[i].ret_expected)
{
printf ("agent_protect(%d) returned '%i/%s'; expected '%i/%s'\n",

View File

@ -632,16 +632,10 @@ remote machine.
@itemx --disable-extended-key-format
@opindex enable-extended-key-format
@opindex disable-extended-key-format
Since version 2.2.22 keys are created in the extended private key
format by default. Changing the passphrase of a key will also convert
the key to that new format. This key format is supported since GnuPG
version 2.1.12 and thus there should be no need to disable it.
Anyway, the disable option still allows to revert to the old behavior
for new keys; be aware that keys are never migrated back to the old
format. If the enable option has been used the disable option won't
have an effect. The advantage of the extended private key format is
that it is text based and can carry additional meta data. In extended
key format the OCB mode is used for key protection.
These options are obsolete and have no effect. The extended key format
is used for years now and has been supported since 2.1.12. Existing
keys in the old format are migrated to the new format as soon as they
are touched.
@anchor{option --enable-ssh-support}
@item --enable-ssh-support