aboutsummaryrefslogtreecommitdiffstats
path: root/agent
diff options
context:
space:
mode:
Diffstat (limited to 'agent')
-rw-r--r--agent/agent.h11
-rw-r--r--agent/call-pinentry.c21
-rw-r--r--agent/command-ssh.c229
-rw-r--r--agent/command.c21
-rw-r--r--agent/cvt-openpgp.c2
-rw-r--r--agent/findkey.c269
-rw-r--r--agent/genkey.c2
-rw-r--r--agent/gpg-agent.c19
-rw-r--r--agent/keyformat.txt4
-rw-r--r--agent/pkdecrypt.c15
-rw-r--r--agent/preset-passphrase.c9
-rw-r--r--agent/protect-tool.c6
-rw-r--r--agent/protect.c136
-rw-r--r--agent/t-protect.c2
-rw-r--r--agent/trustlist.c8
15 files changed, 406 insertions, 348 deletions
diff --git a/agent/agent.h b/agent/agent.h
index ee5c67568..4e7452eee 100644
--- a/agent/agent.h
+++ b/agent/agent.h
@@ -141,13 +141,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
@@ -479,7 +472,7 @@ gpg_error_t agent_public_key_from_file (ctrl_t ctrl,
gcry_sexp_t *result);
gpg_error_t agent_ssh_key_from_file (ctrl_t ctrl,
const unsigned char *grip,
- gcry_sexp_t *result);
+ gcry_sexp_t *result, int *r_order);
int agent_pk_get_algo (gcry_sexp_t s_key);
int agent_is_tpm2_key(gcry_sexp_t s_key);
int agent_key_available (const unsigned char *grip);
@@ -566,7 +559,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,
diff --git a/agent/call-pinentry.c b/agent/call-pinentry.c
index c6c52be74..656d5f623 100644
--- a/agent/call-pinentry.c
+++ b/agent/call-pinentry.c
@@ -1543,6 +1543,17 @@ agent_askpin (ctrl_t ctrl,
NULL, NULL, NULL, NULL, NULL, NULL);
if (rc)
pininfo->with_repeat = 0; /* Pinentry does not support it. */
+
+ if (pininfo->with_repeat)
+ {
+ snprintf (line, DIM(line), "SETREPEATOK %s",
+ L_("Passphrases match."));
+ rc = assuan_transact (entry_ctx, line,
+ NULL, NULL, NULL, NULL, NULL, NULL);
+ if (rc)
+ rc = 0; /* Pinentry does not support it. */
+ }
+
}
pininfo->repeat_okay = 0;
pininfo->status = 0;
@@ -1802,6 +1813,16 @@ agent_get_passphrase (ctrl_t ctrl,
if (rc)
pininfo->with_repeat = 0; /* Pinentry does not support it. */
+ if (pininfo->with_repeat)
+ {
+ snprintf (line, DIM(line), "SETREPEATOK %s",
+ L_("Passphrases match."));
+ rc = assuan_transact (entry_ctx, line,
+ NULL, NULL, NULL, NULL, NULL, NULL);
+ if (rc)
+ rc = 0; /* Pinentry does not support it. */
+ }
+
(void)setup_genpin (ctrl);
rc = setup_enforced_constraints (ctrl);
diff --git a/agent/command-ssh.c b/agent/command-ssh.c
index f237f9355..b41177be6 100644
--- a/agent/command-ssh.c
+++ b/agent/command-ssh.c
@@ -231,6 +231,22 @@ struct ssh_control_file_s
};
+/* Two objects definition to hold keys for later sorting. */
+struct key_collection_item_s
+{
+ gcry_sexp_t key; /* Public key. (owned by us) */
+ char *cardsn; /* Serial number of a card or NULL. (owned by us) */
+ int order; /* Computed ordinal */
+};
+
+struct key_collection_s
+{
+ struct key_collection_item_s *items;
+ size_t allocated;
+ size_t nitems;
+};
+
+
/* Prototypes. */
static gpg_error_t ssh_handler_request_identities (ctrl_t ctrl,
estream_t request,
@@ -1030,10 +1046,11 @@ read_control_file_item (ssh_control_file_t cf)
HEXGRIP is found; return success in this case and store true at
DISABLED if the found key has been disabled. If R_TTL is not NULL
a specified TTL for that key is stored there. If R_CONFIRM is not
- NULL it is set to 1 if the key has the confirm flag set. */
+ NULL it is set to 1 if the key has the confirm flag set. The line
+ number where the item was found is stored at R_LNR. */
static gpg_error_t
search_control_file (ssh_control_file_t cf, const char *hexgrip,
- int *r_disabled, int *r_ttl, int *r_confirm)
+ int *r_disabled, int *r_ttl, int *r_confirm, int *r_lnr)
{
gpg_error_t err;
@@ -1045,6 +1062,8 @@ search_control_file (ssh_control_file_t cf, const char *hexgrip,
*r_ttl = 0;
if (r_confirm)
*r_confirm = 0;
+ if (r_lnr)
+ *r_lnr = -1;
rewind_control_file (cf);
while (!(err=read_control_file_item (cf)))
@@ -1062,6 +1081,8 @@ search_control_file (ssh_control_file_t cf, const char *hexgrip,
*r_ttl = cf->item.ttl;
if (r_confirm)
*r_confirm = cf->item.confirm;
+ if (r_lnr)
+ *r_lnr = cf->lnr;
}
return err;
}
@@ -1090,7 +1111,7 @@ add_control_entry (ctrl_t ctrl, ssh_key_type_spec_t *spec,
if (err)
return err;
- err = search_control_file (cf, hexgrip, &disabled, NULL, NULL);
+ err = search_control_file (cf, hexgrip, &disabled, NULL, NULL, NULL);
if (err && gpg_err_code(err) == GPG_ERR_EOF)
{
struct tm *tp;
@@ -1141,7 +1162,7 @@ ttl_from_sshcontrol (const char *hexgrip)
if (open_control_file (&cf, 0))
return 0; /* Error: Use the global default TTL. */
- if (search_control_file (cf, hexgrip, &disabled, &ttl, NULL)
+ if (search_control_file (cf, hexgrip, &disabled, &ttl, NULL, NULL)
|| disabled)
ttl = 0; /* Use the global default if not found or disabled. */
@@ -1164,7 +1185,7 @@ confirm_flag_from_sshcontrol (const char *hexgrip)
if (open_control_file (&cf, 0))
return 1; /* Error: Better ask for confirmation. */
- if (search_control_file (cf, hexgrip, &disabled, NULL, &confirm)
+ if (search_control_file (cf, hexgrip, &disabled, NULL, &confirm, NULL)
|| disabled)
confirm = 0; /* If not found or disabled, there is no reason to
ask for confirmation. */
@@ -1250,7 +1271,8 @@ ssh_search_control_file (ssh_control_file_t cf,
if (i != 40)
err = gpg_error (GPG_ERR_INV_LENGTH);
else
- err = search_control_file (cf, uphexgrip, r_disabled, r_ttl, r_confirm);
+ err = search_control_file (cf, uphexgrip, r_disabled, r_ttl, r_confirm,
+ NULL);
if (gpg_err_code (err) == GPG_ERR_EOF)
err = gpg_error (GPG_ERR_NOT_FOUND);
return err;
@@ -2483,8 +2505,71 @@ get_ssh_keyinfo_on_cards (ctrl_t ctrl)
return keyinfo_on_cards;
}
+
+/* Append (KEY,CARDSN,LNR,ORDER) to ARRAY. The array must initially
+ * be passed as a cleared struct. ARRAY takes ownership of KEY and
+ * CARDSN. */
static gpg_error_t
-ssh_send_available_keys (ctrl_t ctrl, estream_t key_blobs, u32 *key_counter_p)
+add_to_key_array (struct key_collection_s *array, gcry_sexp_t key,
+ char *cardsn, int order)
+{
+ if (array->nitems == array->allocated)
+ {
+ struct key_collection_item_s *newitems;
+ size_t newsize = ((array->allocated + 63)/64 + 1) * 64;
+
+ newitems = xtryreallocarray (array->items, array->allocated, newsize+1,
+ sizeof *newitems);
+ if (!newitems)
+ return gpg_error_from_syserror ();
+ array->allocated = newsize;
+ array->items = newitems;
+ }
+ array->items[array->nitems].key = key;
+ array->items[array->nitems].cardsn = cardsn;
+ array->items[array->nitems].order = order;
+ array->nitems++;
+ return 0;
+}
+
+/* Release the content of ARRAY. */
+static void
+free_key_array (struct key_collection_s *array)
+{
+ if (array && array->items)
+ {
+ unsigned int n;
+
+ for (n = 0; n < array->nitems; n++)
+ {
+ gcry_sexp_release (array->items[n].key);
+ xfree (array->items[n].cardsn);
+ }
+ xfree (array->items);
+ }
+}
+
+
+/* Helper for the qsort in ssh_send_available_keys. */
+static int
+compare_key_collection_items (const void *arg_a, const void *arg_b)
+{
+ const struct key_collection_item_s *a
+ = (const struct key_collection_item_s *)arg_a;
+ const struct key_collection_item_s *b
+ = (const struct key_collection_item_s *)arg_b;
+ int res;
+
+ res = a->order - b->order;
+ /* If we are comparing two cards we sort by serial number. */
+ if (!res && a->order == 1)
+ res = strcmp (a->cardsn?a->cardsn:"", b->cardsn?b->cardsn:"");
+ return res;
+}
+
+
+static gpg_error_t
+ssh_send_available_keys (ctrl_t ctrl, estream_t key_blobs, u32 *r_key_counter)
{
gpg_error_t err;
char *dirname;
@@ -2495,6 +2580,8 @@ ssh_send_available_keys (ctrl_t ctrl, estream_t key_blobs, u32 *key_counter_p)
struct card_key_info_s *keyinfo_on_cards, *l;
char *cardsn;
gcry_sexp_t key_public = NULL;
+ int count;
+ struct key_collection_s keyarray = { NULL };
err = open_control_file (&cf, 0);
if (err)
@@ -2526,7 +2613,7 @@ ssh_send_available_keys (ctrl_t ctrl, estream_t key_blobs, u32 *key_counter_p)
while ( (dir_entry = gnupg_readdir (dir)) )
{
struct card_key_info_s *l_prev = NULL;
- int disabled, is_ssh;
+ int disabled, is_ssh, lnr, order;
unsigned char grip[20];
cardsn = NULL;
@@ -2548,15 +2635,32 @@ ssh_send_available_keys (ctrl_t ctrl, estream_t key_blobs, u32 *key_counter_p)
/* Check if it's listed in "ssh_control" file. */
disabled = is_ssh = 0;
- err = search_control_file (cf, hexgrip, &disabled, NULL, NULL);
+ err = search_control_file (cf, hexgrip, &disabled, NULL, NULL, &lnr);
if (!err)
{
if (!disabled)
- is_ssh = 1;
+ {
+ is_ssh = 1;
+ }
}
else if (gpg_err_code (err) != GPG_ERR_EOF)
break;
+ /* Clamp LNR value and set the ordinal.
+ * Current use of ordinals:
+ * 1..99999 - inserted cards (right now only 1)
+ * 100000..199999 - listed in sshcontrol
+ * 200000..299999 - order taken from Use-for-ssh
+ */
+ if (is_ssh)
+ {
+ if (lnr < 1)
+ lnr = 0;
+ else if (lnr > 99999)
+ lnr = 99999;
+ order = lnr + 100000;
+ }
+
if (l)
{
err = card_key_available (ctrl, l, &key_public, &cardsn);
@@ -2570,81 +2674,92 @@ ssh_send_available_keys (ctrl_t ctrl, estream_t key_blobs, u32 *key_counter_p)
xfree (l->usage);
xfree (l);
l = NULL;
+ /* If we want to allow that the user to change the sorting
+ * order of card keys (which are sorted by their s/n), we
+ * would need to get the use-for-ssh: value from the stub
+ * file and set an appropriate ordinal. */
+ order = 1;
}
else if (is_ssh)
err = agent_public_key_from_file (ctrl, grip, &key_public);
- else
- /* Examine the file if it's suitable for SSH. */
- err = agent_ssh_key_from_file (ctrl, grip, &key_public);
+ else /* Examine the file if it's suitable for SSH. */
+ {
+ err = agent_ssh_key_from_file (ctrl, grip, &key_public, &order);
+ if (order < 0 || err)
+ order = 0;
+ else if (order > 99999)
+ order = 99999;
+ order += 200000;
+ }
if (err)
{
- /* Clear ERR, skiping the key in question. */
+ /* Clear ERR, skipping the key in question. */
err = 0;
continue;
}
- err = ssh_send_key_public (key_blobs, key_public, cardsn);
- xfree (cardsn);
+ err = add_to_key_array (&keyarray, key_public, cardsn, order);
if (err)
{
- if (opt.debug)
- gcry_log_debugsxp ("pubkey", key_public);
- if (gpg_err_code (err) == GPG_ERR_UNKNOWN_CURVE
- || gpg_err_code (err) == GPG_ERR_INV_CURVE)
- {
- /* For example a Brainpool curve or a curve we don't
- * support at all but a smartcard lists that curve.
- * We ignore them. */
- }
- else
- {
- gcry_sexp_release (key_public);
- break; /* the readdir loop. */
- }
+ gcry_sexp_release (key_public);
+ xfree (cardsn);
+ goto leave;
}
- else /* Success */
- (*key_counter_p)++;
-
- gcry_sexp_release (key_public);
}
gnupg_closedir (dir);
ssh_close_control_file (cf);
/* Lastly, handle remaining keys which don't have the stub files. */
- for (l = keyinfo_on_cards; l; l = l->next)
+ for (l = keyinfo_on_cards, count=0; l; l = l->next, count++)
{
cardsn = NULL;
if (card_key_available (ctrl, l, &key_public, &cardsn))
continue;
- err = ssh_send_key_public (key_blobs, key_public, cardsn);
- xfree (cardsn);
+ err = add_to_key_array (&keyarray, key_public, cardsn, 300000+count);
if (err)
{
- if (opt.debug)
- gcry_log_debugsxp ("pubkey", key_public);
- if (gpg_err_code (err) == GPG_ERR_UNKNOWN_CURVE
- || gpg_err_code (err) == GPG_ERR_INV_CURVE)
- {
- /* For example a Brainpool curve or a curve we don't
- * support at all but a smartcard lists that curve.
- * We ignore them. */
- }
- else
- {
- gcry_sexp_release (key_public);
- break;
- }
+ gcry_sexp_release (key_public);
+ xfree (cardsn);
+ goto leave;
}
- else /* Success. */
- (*key_counter_p)++;
-
- gcry_sexp_release (key_public);
}
- agent_card_free_keyinfo (keyinfo_on_cards);
+ /* Sort the array. */
+ qsort (keyarray.items, keyarray.nitems, sizeof *keyarray.items,
+ compare_key_collection_items);
+ if (opt.debug)
+ for (count=0; count < keyarray.nitems; count++)
+ log_debug ("sshkeys[%d]: order=%d, pubkey=%p sn=%s\n",
+ count, keyarray.items[count].order,
+ keyarray.items[count].key, keyarray.items[count].cardsn);
+
+ /* And print the keys. */
+ for (count=0; count < keyarray.nitems; count++)
+ {
+ err = ssh_send_key_public (key_blobs, keyarray.items[count].key,
+ keyarray.items[count].cardsn);
+ if (err)
+ {
+ if (opt.debug)
+ gcry_log_debugsxp ("pubkey", keyarray.items[count].key);
+ if (gpg_err_code (err) == GPG_ERR_UNKNOWN_CURVE
+ || gpg_err_code (err) == GPG_ERR_INV_CURVE)
+ {
+ /* For example a Brainpool curve or a curve we don't
+ * support at all but a smartcard lists that curve.
+ * We ignore them. */
+ }
+ else
+ goto leave;
+ }
+ }
+ *r_key_counter = count;
+ leave:
+ agent_card_free_keyinfo (keyinfo_on_cards);
+ free_key_array (&keyarray);
return err;
}
@@ -3027,7 +3142,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
diff --git a/agent/command.c b/agent/command.c
index c113caba7..9481f47c3 100644
--- a/agent/command.c
+++ b/agent/command.c
@@ -1218,12 +1218,6 @@ cmd_keyattr (assuan_context_t ctx, char *line)
if (ctrl->restricted)
return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
- if (!opt.enable_extended_key_format)
- {
- err = gpg_error (GPG_ERR_NOT_SUPPORTED);
- goto leave;
- }
-
opt_delete = has_option (line, "--delete");
line = skip_options (line);
@@ -2497,14 +2491,17 @@ cmd_passwd (assuan_context_t ctx, char *line)
static const char hlp_preset_passphrase[] =
- "PRESET_PASSPHRASE [--inquire] <string_or_keygrip> <timeout> [<hexstring>]\n"
+ "PRESET_PASSPHRASE [--inquire] [--restricted] \\\n"
+ " <string_or_keygrip> <timeout> [<hexstring>]\n"
"\n"
"Set the cached passphrase/PIN for the key identified by the keygrip\n"
"to passwd for the given time, where -1 means infinite and 0 means\n"
"the default (currently only a timeout of -1 is allowed, which means\n"
"to never expire it). If passwd is not provided, ask for it via the\n"
"pinentry module unless --inquire is passed in which case the passphrase\n"
- "is retrieved from the client via a server inquire.\n";
+ "is retrieved from the client via a server inquire. The option\n"
+ "--restricted can be used to put the passphrase into the cache used\n"
+ "by restricted connections.";
static gpg_error_t
cmd_preset_passphrase (assuan_context_t ctx, char *line)
{
@@ -2515,6 +2512,7 @@ cmd_preset_passphrase (assuan_context_t ctx, char *line)
int ttl;
size_t len;
int opt_inquire;
+ int opt_restricted;
if (ctrl->restricted)
return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
@@ -2523,6 +2521,7 @@ cmd_preset_passphrase (assuan_context_t ctx, char *line)
return set_error (GPG_ERR_NOT_SUPPORTED, "no --allow-preset-passphrase");
opt_inquire = has_option (line, "--inquire");
+ opt_restricted = has_option (line, "--restricted");
line = skip_options (line);
grip_clear = line;
while (*line && (*line != ' ' && *line != '\t'))
@@ -2585,7 +2584,11 @@ cmd_preset_passphrase (assuan_context_t ctx, char *line)
if (!rc)
{
+ int save_restricted = ctrl->restricted;
+ if (opt_restricted)
+ ctrl->restricted = 1;
rc = agent_put_cache (ctrl, grip_clear, CACHE_MODE_ANY, passphrase, ttl);
+ ctrl->restricted = save_restricted;
if (opt_inquire)
{
wipememory (passphrase, len);
@@ -2910,7 +2913,7 @@ 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,
NULL, NULL, opt_timestamp);
diff --git a/agent/cvt-openpgp.c b/agent/cvt-openpgp.c
index d170fdedc..9bb815ff8 100644
--- a/agent/cvt-openpgp.c
+++ b/agent/cvt-openpgp.c
@@ -1146,7 +1146,7 @@ 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,
NULL, NULL, 0);
xfree (protectedkey);
diff --git a/agent/findkey.c b/agent/findkey.c
index 20962bd43..098d5224f 100644
--- a/agent/findkey.c
+++ b/agent/findkey.c
@@ -2,6 +2,7 @@
* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007,
* 2010, 2011 Free Software Foundation, Inc.
* Copyright (C) 2014, 2019 Werner Koch
+ * Copyright (C) 2023 g10 Code GmbH
*
* This file is part of GnuPG.
*
@@ -79,19 +80,114 @@ 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, int newkey,
- const void *buf, size_t len,
- const char *serialno, const char *keyref,
- time_t timestamp)
+/* 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,
+ time_t timestamp)
{
gpg_error_t err;
+ char *fname;
+ estream_t fp;
+ char hexgrip[40+4+1];
+ int update, newkey;
nvc_t pk = NULL;
gcry_sexp_t key = NULL;
int remove = 0;
char *token = NULL;
+ bin2hex (grip, 20, hexgrip);
+ strcpy (hexgrip+40, ".key");
+
+ fname = make_filename (gnupg_homedir (), GNUPG_PRIVATE_KEYS_DIR,
+ hexgrip, NULL);
+
+ /* 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;
+ }
+ 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;
+ }
+ }
+ else
+ {
+ /* 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 line;
@@ -115,10 +211,11 @@ write_extended_private_key (char *fname, estream_t fp, int update, int newkey,
}
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;
@@ -153,7 +250,7 @@ write_extended_private_key (char *fname, estream_t fp, int update, int newkey,
}
}
- /* If a timestamp has been supplied and the key is new write a
+ /* 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:"))
@@ -166,7 +263,7 @@ write_extended_private_key (char *fname, estream_t fp, int update, int newkey,
goto leave;
}
-
+ /* Back to start and write. */
err = es_fseek (fp, 0, SEEK_SET);
if (err)
goto leave;
@@ -212,133 +309,6 @@ write_extended_private_key (char *fname, estream_t fp, int update, int newkey,
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 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,
- time_t timestamp)
-{
- char *fname;
- estream_t fp;
- char hexgrip[40+4+1];
-
- bin2hex (grip, 20, hexgrip);
- strcpy (hexgrip+40, ".key");
-
- fname = make_filename (gnupg_homedir (), GNUPG_PRIVATE_KEYS_DIR,
- hexgrip, NULL);
-
- /* 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 (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, 0, buffer, length,
- serialno, keyref, timestamp);
- }
- }
-
- if (opt.enable_extended_key_format)
- return write_extended_private_key (fname, fp, 0, 1, buffer, length,
- serialno, keyref, timestamp);
-
- 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;
-}
-
gpg_error_t
agent_update_private_key (const unsigned char *grip, nvc_t pk)
@@ -393,6 +363,7 @@ agent_update_private_key (const unsigned char *grip, nvc_t pk)
return err;
}
+
/* Callback function to try the unprotection from the passphrase query
code. */
static gpg_error_t
@@ -1186,6 +1157,15 @@ agent_key_from_file (ctrl_t ctrl, const char *cache_nonce,
return gpg_error (GPG_ERR_NO_SECKEY);
err = read_key_file (grip? grip : ctrl->keygrip, &s_skey, &keymeta);
+ if (err)
+ {
+ if (gpg_err_code (err) == GPG_ERR_ENOENT)
+ err = gpg_error (GPG_ERR_NO_SECKEY);
+ else
+ log_error ("findkey: error reading key file: %s\n",
+ gpg_strerror (err));
+ return err;
+ }
/* For use with the protection functions we also need the key as an
canonical encoded S-expression in a buffer. Create this buffer
@@ -1422,10 +1402,11 @@ agent_raw_key_from_file (ctrl_t ctrl, const unsigned char *grip,
/* Return the public key for the keygrip GRIP. The result is stored
at RESULT. This function extracts the public key from the private
key database. On failure an error code is returned and NULL stored
- at RESULT. */
+ at RESULT. If R_SSHORDER is not NULL the ordinal from the
+ Use-for-ssh attribute is stored at that address. */
static gpg_error_t
public_key_from_file (ctrl_t ctrl, const unsigned char *grip,
- gcry_sexp_t *result, int for_ssh)
+ gcry_sexp_t *result, int for_ssh, int *r_sshorder)
{
gpg_error_t err;
int i, idx;
@@ -1451,6 +1432,8 @@ public_key_from_file (ctrl_t ctrl, const unsigned char *grip,
(void)ctrl;
*result = NULL;
+ if (r_sshorder)
+ *r_sshorder = 0;
err = read_key_file (grip, &s_skey, for_ssh? &keymeta : NULL);
if (err)
@@ -1470,6 +1453,8 @@ public_key_from_file (ctrl_t ctrl, const unsigned char *grip,
if (!is_ssh)
return gpg_error (GPG_ERR_WRONG_KEY_USAGE);
+ if (r_sshorder)
+ *r_sshorder = is_ssh;
}
for (i=0; i < DIM (array); i++)
@@ -1565,15 +1550,15 @@ agent_public_key_from_file (ctrl_t ctrl,
const unsigned char *grip,
gcry_sexp_t *result)
{
- return public_key_from_file (ctrl, grip, result, 0);
+ return public_key_from_file (ctrl, grip, result, 0, NULL);
}
gpg_error_t
agent_ssh_key_from_file (ctrl_t ctrl,
const unsigned char *grip,
- gcry_sexp_t *result)
+ gcry_sexp_t *result, int *r_order)
{
- return public_key_from_file (ctrl, grip, result, 1);
+ return public_key_from_file (ctrl, grip, result, 1, r_order);
}
diff --git a/agent/genkey.c b/agent/genkey.c
index fb0084193..e2c6335bc 100644
--- a/agent/genkey.c
+++ b/agent/genkey.c
@@ -57,7 +57,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);
diff --git a/agent/gpg-agent.c b/agent/gpg-agent.c
index 412eb43e1..1db422737 100644
--- a/agent/gpg-agent.c
+++ b/agent/gpg-agent.c
@@ -116,8 +116,6 @@ enum cmd_and_opt_values
oCheckSymPassphrasePattern,
oMaxPassphraseDays,
oEnablePassphraseHistory,
- oDisableExtendedKeyFormat,
- oEnableExtendedKeyFormat,
oStealSocket,
oUseStandardSocket,
oNoUseStandardSocket,
@@ -147,6 +145,7 @@ enum cmd_and_opt_values
oS2KCalibration,
oAutoExpandSecmem,
oListenBacklog,
+ oInactivityTimeout,
oWriteEnvFile,
@@ -185,7 +184,7 @@ static gpgrt_opt_t opts[] = {
ARGPARSE_s_s (oHomedir, "homedir", "@"),
ARGPARSE_conffile (oOptions, "options", N_("|FILE|read options from FILE")),
ARGPARSE_noconffile (oNoOptions, "no-options", "@"),
-
+ ARGPARSE_s_i (oInactivityTimeout, "inactivity-timeout", "@"),
ARGPARSE_header ("Monitor", N_("Options controlling the diagnostic output")),
@@ -237,8 +236,6 @@ static gpgrt_opt_t 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", "@"),
@@ -314,7 +311,8 @@ static gpgrt_opt_t 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 */
};
@@ -884,7 +882,6 @@ parse_rereadable_options (gpgrt_argparse_t *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;
@@ -973,14 +970,6 @@ parse_rereadable_options (gpgrt_argparse_t *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;
diff --git a/agent/keyformat.txt b/agent/keyformat.txt
index 42e6d215e..bbcaa7e2c 100644
--- a/agent/keyformat.txt
+++ b/agent/keyformat.txt
@@ -122,7 +122,9 @@ similar to the "shadow" parameter:
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.
+should exist. If another non-zero value between 1 and 99999 is used,
+this is taken to establish the order in which the keys are returned to
+ssh; lower numbers are returned first.
*** Use-for-p11
If given and the value is "yes" or "1" the key is allowed for use by
diff --git a/agent/pkdecrypt.c b/agent/pkdecrypt.c
index 82818f863..c26f21d35 100644
--- a/agent/pkdecrypt.c
+++ b/agent/pkdecrypt.c
@@ -74,8 +74,7 @@ agent_pkdecrypt (ctrl_t ctrl, const char *desc_text,
no_shadow_info = 1;
else if (err)
{
- if (gpg_err_code (err) != GPG_ERR_NO_SECKEY)
- log_error ("failed to read the secret key\n");
+ log_error ("failed to read the secret key\n");
goto leave;
}
@@ -88,7 +87,7 @@ agent_pkdecrypt (ctrl_t ctrl, const char *desc_text,
goto leave;
}
- if (agent_is_tpm2_key (s_skey))
+ if (s_skey && agent_is_tpm2_key (s_skey))
err = divert_tpm2_pkdecrypt (ctrl, ciphertext, shadow_info,
&buf, &len, r_padding);
else
@@ -96,7 +95,15 @@ agent_pkdecrypt (ctrl_t ctrl, const char *desc_text,
&buf, &len, r_padding);
if (err)
{
- log_error ("smartcard decryption failed: %s\n", gpg_strerror (err));
+ /* We restore the original error (ie. no seckey) is no card
+ * has been found and we have no shadow key. This avoids a
+ * surprising "card removed" error code. */
+ if ((gpg_err_code (err) == GPG_ERR_CARD_REMOVED
+ || gpg_err_code (err) == GPG_ERR_CARD_NOT_PRESENT)
+ && no_shadow_info)
+ err = gpg_error (GPG_ERR_NO_SECKEY);
+ else
+ log_error ("smartcard decryption failed: %s\n", gpg_strerror (err));
goto leave;
}
diff --git a/agent/preset-passphrase.c b/agent/preset-passphrase.c
index df6da00e3..4cf624462 100644
--- a/agent/preset-passphrase.c
+++ b/agent/preset-passphrase.c
@@ -63,11 +63,13 @@ enum cmd_and_opt_values
oNoVerbose = 500,
oHomedir,
+ oRestricted,
aTest };
static const char *opt_passphrase;
+static int opt_restricted;
static gpgrt_opt_t opts[] = {
@@ -79,6 +81,7 @@ static gpgrt_opt_t opts[] = {
{ oForget, "forget", 256, "forget passphrase"},
{ oHomedir, "homedir", 2, "@" },
+ { oRestricted, "restricted", 0, "put into the restricted cache"},
ARGPARSE_end ()
};
@@ -156,7 +159,9 @@ preset_passphrase (const char *keygrip)
return;
}
- rc = asprintf (&line, "PRESET_PASSPHRASE %s -1 %s\n", keygrip,
+ rc = asprintf (&line, "PRESET_PASSPHRASE %s%s -1 %s\n",
+ opt_restricted? "--restricted ":"",
+ keygrip,
passphrase_esc);
wipememory (passphrase_esc, strlen (passphrase_esc));
xfree (passphrase_esc);
@@ -232,6 +237,8 @@ main (int argc, char **argv)
case oForget: cmd = oForget; break;
case oPassphrase: opt_passphrase = pargs.r.ret_str; break;
+ case oRestricted: opt_restricted = 1; break;
+
default : pargs.err = 2; break;
}
}
diff --git a/agent/protect-tool.c b/agent/protect-tool.c
index bb17033a8..87cf36814 100644
--- a/agent/protect-tool.c
+++ b/agent/protect-tool.c
@@ -97,7 +97,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);
@@ -343,8 +342,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)
@@ -610,7 +608,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;
}
diff --git a/agent/protect.c b/agent/protect.c
index 1084ee208..7197cf7e6 100644
--- a/agent/protect.c
+++ b/agent/protect.c
@@ -379,12 +379,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. */
@@ -398,44 +397,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 ();
@@ -445,10 +426,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 ();
@@ -484,40 +465,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)
@@ -527,36 +485,15 @@ do_encryption (const unsigned char *hashbegin, size_t hashlen,
*p++ = '(';
memcpy (p, protbegin, protlen);
p += protlen;
- if (use_ocb)
- {
- *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;
- }
+ *p++ = ')';
+ *p++ = ')';
log_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
+ gcry_cipher_final (hd);
+ rc = gcry_cipher_encrypt (hd, outbuf, outlen, NULL, 0);
+ if (!rc)
{
- rc = gcry_cipher_encrypt (hd, outbuf, enclen, NULL, 0);
+ log_assert (outlen + 16 == enclen);
+ rc = gcry_cipher_gettag (hd, outbuf + outlen, 16);
}
}
@@ -584,7 +521,7 @@ do_encryption (const unsigned char *hashbegin, size_t hashlen,
(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)
{
@@ -598,7 +535,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);
@@ -614,13 +551,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;
@@ -637,9 +572,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);
@@ -743,7 +675,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;
diff --git a/agent/t-protect.c b/agent/t-protect.c
index 88b552585..e6edbffba 100644
--- a/agent/t-protect.c
+++ b/agent/t-protect.c
@@ -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",
diff --git a/agent/trustlist.c b/agent/trustlist.c
index 4d23eb1b0..330f233b8 100644
--- a/agent/trustlist.c
+++ b/agent/trustlist.c
@@ -45,6 +45,7 @@ struct trustitem_s
constraints. */
int cm:1; /* Use chain model for validation. */
int qual:1; /* Root CA for qualified signatures. */
+ int de_vs:1; /* Root CA for de-vs compliant PKI. */
} flags;
unsigned char fpr[20]; /* The binary fingerprint. */
};
@@ -324,6 +325,8 @@ read_one_trustfile (const char *fname, int systrust,
ti->flags.cm = 1;
else if (n == 4 && !memcmp (p, "qual", 4) && systrust)
ti->flags.qual = 1;
+ else if (n == 4 && !memcmp (p, "de-vs", 4) && systrust)
+ ti->flags.de_vs = 1;
else
log_error ("flag '%.*s' in '%s', line %d ignored\n",
n, p, fname, lnr);
@@ -476,7 +479,8 @@ istrusted_internal (ctrl_t ctrl, const char *fpr, int *r_disabled,
in a locked state. */
if (already_locked)
;
- else if (ti->flags.relax || ti->flags.cm || ti->flags.qual)
+ else if (ti->flags.relax || ti->flags.cm || ti->flags.qual
+ || ti->flags.de_vs)
{
unlock_trusttable ();
locked = 0;
@@ -487,6 +491,8 @@ istrusted_internal (ctrl_t ctrl, const char *fpr, int *r_disabled,
err = agent_write_status (ctrl,"TRUSTLISTFLAG", "cm", NULL);
if (!err && ti->flags.qual)
err = agent_write_status (ctrl,"TRUSTLISTFLAG", "qual",NULL);
+ if (!err && ti->flags.de_vs)
+ err = agent_write_status (ctrl,"TRUSTLISTFLAG", "de-vs",NULL);
}
if (!err)