summaryrefslogtreecommitdiffstats
path: root/agent
diff options
context:
space:
mode:
Diffstat (limited to 'agent')
-rw-r--r--agent/Makefile.am11
-rw-r--r--agent/Makefile.in32
-rw-r--r--agent/agent.h25
-rw-r--r--agent/call-pinentry.c22
-rw-r--r--agent/call-scd.c2
-rw-r--r--agent/command-ssh.c6
-rw-r--r--agent/command.c211
-rw-r--r--agent/cvt-openpgp.c6
-rw-r--r--agent/findkey.c595
-rw-r--r--agent/genkey.c6
-rw-r--r--agent/gpg-agent.c16
-rw-r--r--agent/gpg-agent.w32-manifest.in9
-rw-r--r--agent/learncard.c11
-rw-r--r--agent/pkdecrypt.c2
-rw-r--r--agent/pksign.c2
-rw-r--r--agent/protect-tool.c13
-rw-r--r--agent/protect.c154
-rw-r--r--agent/t-protect.c2
-rw-r--r--agent/trustlist.c27
19 files changed, 523 insertions, 629 deletions
diff --git a/agent/Makefile.am b/agent/Makefile.am
index f0ba964..ad7e967 100644
--- a/agent/Makefile.am
+++ b/agent/Makefile.am
@@ -1,3 +1,4 @@
+# Makefile.am - agent
# Copyright (C) 2001, 2003, 2004, 2005 Free Software Foundation, Inc.
#
# This file is part of GnuPG.
@@ -35,10 +36,10 @@ AM_CPPFLAGS =
include $(top_srcdir)/am/cmacros.am
if HAVE_W32_SYSTEM
-gpg_agent_robjs = $(resource_objs) gpg-agent-w32info.o
-gpg-agent-w32info.o : gpg-agent.w32-manifest
+gpg_agent_rc_objs = $(resource_objs) gpg-agent-w32info.o
+gpg-agent-w32info.o : gpg-agent.w32-manifest ../common/w32info-rc.h
else
-gpg_agent_robjs =
+gpg_agent_rc_objs =
endif
AM_CFLAGS = $(LIBGCRYPT_CFLAGS) $(GPG_ERROR_CFLAGS)
@@ -74,9 +75,9 @@ gpg_agent_CFLAGS = $(AM_CFLAGS) $(LIBASSUAN_CFLAGS) $(NPTH_CFLAGS) \
gpg_agent_LDADD = $(commonpth_libs) \
$(LIBGCRYPT_LIBS) $(LIBASSUAN_LIBS) $(NPTH_LIBS) \
$(GPG_ERROR_LIBS) $(LIBINTL) $(NETLIBS) $(LIBICONV) \
- $(gpg_agent_robjs)
+ $(gpg_agent_rc_objs)
gpg_agent_LDFLAGS = $(extra_bin_ldflags)
-gpg_agent_DEPENDENCIES = $(gpg_agent_robjs)
+gpg_agent_DEPENDENCIES = $(gpg_agent_rc_objs)
gpg_protect_tool_SOURCES = \
protect-tool.c \
diff --git a/agent/Makefile.in b/agent/Makefile.in
index ab8735f..9ec037c 100644
--- a/agent/Makefile.in
+++ b/agent/Makefile.in
@@ -14,6 +14,7 @@
@SET_MAKE@
+# Makefile.am - agent
# Copyright (C) 2001, 2003, 2004, 2005 Free Software Foundation, Inc.
#
# This file is part of GnuPG.
@@ -151,17 +152,16 @@ ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/autobuild.m4 \
$(top_srcdir)/m4/codeset.m4 $(top_srcdir)/m4/gettext.m4 \
$(top_srcdir)/m4/gpg-error.m4 $(top_srcdir)/m4/iconv.m4 \
- $(top_srcdir)/m4/isc-posix.m4 $(top_srcdir)/m4/ksba.m4 \
- $(top_srcdir)/m4/lcmessage.m4 $(top_srcdir)/m4/ldap.m4 \
- $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \
- $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libassuan.m4 \
- $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/nls.m4 \
- $(top_srcdir)/m4/npth.m4 $(top_srcdir)/m4/ntbtls.m4 \
- $(top_srcdir)/m4/pkg.m4 $(top_srcdir)/m4/po.m4 \
- $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/readline.m4 \
- $(top_srcdir)/m4/socklen.m4 $(top_srcdir)/m4/sys_socket_h.m4 \
- $(top_srcdir)/m4/tar-ustar.m4 $(top_srcdir)/acinclude.m4 \
- $(top_srcdir)/configure.ac
+ $(top_srcdir)/m4/ksba.m4 $(top_srcdir)/m4/lcmessage.m4 \
+ $(top_srcdir)/m4/ldap.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/libassuan.m4 $(top_srcdir)/m4/libgcrypt.m4 \
+ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/npth.m4 \
+ $(top_srcdir)/m4/ntbtls.m4 $(top_srcdir)/m4/pkg.m4 \
+ $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+ $(top_srcdir)/m4/readline.m4 $(top_srcdir)/m4/socklen.m4 \
+ $(top_srcdir)/m4/sys_socket_h.m4 $(top_srcdir)/m4/tar-ustar.m4 \
+ $(top_srcdir)/acinclude.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
@@ -533,8 +533,8 @@ libcommon = ../common/libcommon.a
libcommonpth = ../common/libcommonpth.a
libcommontls = ../common/libcommontls.a
libcommontlsnpth = ../common/libcommontlsnpth.a
-@HAVE_W32_SYSTEM_FALSE@gpg_agent_robjs =
-@HAVE_W32_SYSTEM_TRUE@gpg_agent_robjs = $(resource_objs) gpg-agent-w32info.o
+@HAVE_W32_SYSTEM_FALSE@gpg_agent_rc_objs =
+@HAVE_W32_SYSTEM_TRUE@gpg_agent_rc_objs = $(resource_objs) gpg-agent-w32info.o
AM_CFLAGS = $(LIBGCRYPT_CFLAGS) $(GPG_ERROR_CFLAGS)
gpg_agent_SOURCES = \
gpg-agent.c agent.h \
@@ -563,10 +563,10 @@ gpg_agent_CFLAGS = $(AM_CFLAGS) $(LIBASSUAN_CFLAGS) $(NPTH_CFLAGS) \
gpg_agent_LDADD = $(commonpth_libs) \
$(LIBGCRYPT_LIBS) $(LIBASSUAN_LIBS) $(NPTH_LIBS) \
$(GPG_ERROR_LIBS) $(LIBINTL) $(NETLIBS) $(LIBICONV) \
- $(gpg_agent_robjs)
+ $(gpg_agent_rc_objs)
gpg_agent_LDFLAGS = $(extra_bin_ldflags)
-gpg_agent_DEPENDENCIES = $(gpg_agent_robjs)
+gpg_agent_DEPENDENCIES = $(gpg_agent_rc_objs)
gpg_protect_tool_SOURCES = \
protect-tool.c \
protect.c cvt-openpgp.c
@@ -1397,7 +1397,7 @@ uninstall-am: uninstall-binPROGRAMS uninstall-libexecPROGRAMS
@HAVE_W32_SYSTEM_TRUE@.rc.o:
@HAVE_W32_SYSTEM_TRUE@ $(WINDRES) $(DEFAULT_INCLUDES) $(INCLUDES) "$<" "$@"
-@HAVE_W32_SYSTEM_TRUE@gpg-agent-w32info.o : gpg-agent.w32-manifest
+@HAVE_W32_SYSTEM_TRUE@gpg-agent-w32info.o : gpg-agent.w32-manifest ../common/w32info-rc.h
# Make sure that all libs are build before we use them. This is
# important for things like make -j2.
diff --git a/agent/agent.h b/agent/agent.h
index 56e13ec..d32b892 100644
--- a/agent/agent.h
+++ b/agent/agent.h
@@ -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
@@ -429,10 +422,10 @@ void start_command_handler_ssh (ctrl_t, gnupg_fd_t);
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 void *buffer, size_t length,
+ int force, int reallyforce,
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,
@@ -441,7 +434,8 @@ gpg_error_t agent_key_from_file (ctrl_t ctrl,
cache_mode_t cache_mode,
lookup_ttl_t lookup_ttl,
gcry_sexp_t *result,
- char **r_passphrase);
+ char **r_passphrase,
+ uint64_t *r_timestamp);
gpg_error_t agent_raw_key_from_file (ctrl_t ctrl, const unsigned char *grip,
gcry_sexp_t *result);
gpg_error_t agent_keymeta_from_file (ctrl_t ctrl, const unsigned char *grip,
@@ -533,7 +527,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,10 +546,10 @@ 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,
+ int reallyforce,
const char *dispserialno);
@@ -636,7 +630,8 @@ void agent_card_killscd (void);
/*-- learncard.c --*/
-int agent_handle_learn (ctrl_t ctrl, int send, void *assuan_context, int force);
+int agent_handle_learn (ctrl_t ctrl, int send, void *assuan_context,
+ int force, int reallyforce);
/*-- cvt-openpgp.c --*/
diff --git a/agent/call-pinentry.c b/agent/call-pinentry.c
index 5fcf98b..cbb6bae 100644
--- a/agent/call-pinentry.c
+++ b/agent/call-pinentry.c
@@ -57,7 +57,9 @@
* passphrase will be rendered as zbase32 which results for 150 bits
* in a string of 30 characters. That fits nicely into the 5
* character blocking which pinentry can do. 128 bits would actually
- * be sufficient but can't be formatted nicely. */
+ * be sufficient but can't be formatted nicely. Please do not change
+ * this value because pattern check files may let such passwords
+ * always pass. */
#define DEFAULT_GENPIN_BITS 150
/* The assuan context of the current pinentry. */
@@ -551,6 +553,7 @@ start_pinentry (ctrl_t ctrl)
"passphrase visible on the screen?") },
{ "tt-visi",N_("|pinentry-tt|Make passphrase visible") },
{ "tt-hide",N_("|pinentry-tt|Hide passphrase") },
+ { "capshint", N_("Caps Lock is on") },
{ NULL, NULL}
};
char *optstr;
@@ -834,21 +837,20 @@ estimate_passphrase_quality (const char *pw)
/* Generate a random passphrase in zBase32 encoding (RFC-6189) to be
- * used by Pinentry to suggest a passphrase. */
+ * used by Pinentry to suggest a passphrase. Note that we have the
+ * same algorithm in gpg.c for --gen-random at level 30. It is
+ * important that we always output exactly 30 characters to match the
+ * special exception we have in the pattern file for symmetric
+ * encryption. */
static char *
generate_pin (void)
{
- unsigned int nbits = opt.min_passphrase_len * 8;
- size_t nbytes;
+ unsigned int nbits = DEFAULT_GENPIN_BITS;
+ size_t nbytes = nbytes = (nbits + 7) / 8;
void *rand;
char *generated;
- if (nbits < 128)
- nbits = DEFAULT_GENPIN_BITS;
-
- nbytes = (nbits + 7) / 8;
-
- rand = gcry_random_bytes_secure (nbytes, GCRY_STRONG_RANDOM);
+ rand = gcry_random_bytes_secure (nbytes, GCRY_STRONG_RANDOM);
if (!rand)
{
log_error ("failed to generate random pin\n");
diff --git a/agent/call-scd.c b/agent/call-scd.c
index c5b95f4..cd66070 100644
--- a/agent/call-scd.c
+++ b/agent/call-scd.c
@@ -501,7 +501,9 @@ agent_scd_check_aliveness (void)
none of these context are actually in use. */
struct scd_local_s *sl;
+#ifndef HAVE_W32_SYSTEM
assuan_set_flag (primary_scd_ctx, ASSUAN_NO_WAITPID, 1);
+#endif
assuan_release (primary_scd_ctx);
for (sl=scd_local_list; sl; sl = sl->next_local)
diff --git a/agent/command-ssh.c b/agent/command-ssh.c
index 21dd53c..bd1a418 100644
--- a/agent/command-ssh.c
+++ b/agent/command-ssh.c
@@ -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, 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
@@ -3160,7 +3160,7 @@ 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);
+ NULL, NULL, NULL, 0);
if (err)
goto out;
diff --git a/agent/command.c b/agent/command.c
index b682c55..940e017 100644
--- a/agent/command.c
+++ b/agent/command.c
@@ -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, 0,
+ dispserialno);
if (rc)
goto leave;
@@ -1292,9 +1282,6 @@ cmd_keyinfo (assuan_context_t ctx, char *line)
char hexgrip[41];
int disabled, ttl, confirm, is_ssh;
- if (ctrl->restricted)
- return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
-
if (has_option (line, "--ssh-list"))
list_mode = 2;
else
@@ -1343,6 +1330,9 @@ cmd_keyinfo (assuan_context_t ctx, char *line)
char *dirname;
gnupg_dirent_t dir_entry;
+ if (ctrl->restricted)
+ return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
+
dirname = make_filename_try (gnupg_homedir (),
GNUPG_PRIVATE_KEYS_DIR, NULL);
if (!dirname)
@@ -1865,16 +1855,18 @@ cmd_learn (assuan_context_t ctx, char *line)
{
ctrl_t ctrl = assuan_get_pointer (ctx);
gpg_error_t err;
- int send, sendinfo, force;
+ int send, sendinfo, force, reallyforce;
send = has_option (line, "--send");
sendinfo = send? 1 : has_option (line, "--sendinfo");
force = has_option (line, "--force");
+ reallyforce = has_option (line, "--reallyforce");
if (ctrl->restricted)
return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
- err = agent_handle_learn (ctrl, send, sendinfo? ctx : NULL, force);
+ err = agent_handle_learn (ctrl, send, sendinfo? ctx : NULL,
+ force, reallyforce);
return leave_cmd (ctx, err);
}
@@ -1951,7 +1943,7 @@ cmd_passwd (assuan_context_t ctx, char *line)
opt_verify? NULL : cache_nonce,
ctrl->server_local->keydesc,
grip, &shadow_info, CACHE_MODE_IGNORE, NULL,
- &s_skey, &passphrase);
+ &s_skey, &passphrase, NULL);
if (err)
;
else if (shadow_info)
@@ -2435,14 +2427,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);
+ err = agent_write_private_key (grip, finalkey, finalkeylen, force, 0,
+ NULL, NULL, NULL, opt_timestamp);
}
else
- err = agent_write_private_key (grip, key, realkeylen, force,
- opt_timestamp, NULL, NULL, NULL);
+ err = agent_write_private_key (grip, key, realkeylen, force, 0,
+ NULL, NULL, NULL, opt_timestamp);
leave:
gcry_sexp_release (openpgp_sexp);
@@ -2532,7 +2524,7 @@ cmd_export_key (assuan_context_t ctx, char *line)
err = agent_key_from_file (ctrl, cache_nonce,
ctrl->server_local->keydesc, grip,
&shadow_info, CACHE_MODE_IGNORE, NULL, &s_skey,
- openpgp ? &passphrase : NULL);
+ openpgp ? &passphrase : NULL, NULL);
if (err)
goto leave;
if (shadow_info)
@@ -2677,28 +2669,30 @@ cmd_delete_key (assuan_context_t ctx, char *line)
-#if SIZEOF_TIME_T > SIZEOF_UNSIGNED_LONG
-#define KEYTOCARD_TIMESTAMP_FORMAT "(10:created-at10:%010llu))"
-#else
-#define KEYTOCARD_TIMESTAMP_FORMAT "(10:created-at10:%010lu))"
-#endif
-
static const char hlp_keytocard[] =
- "KEYTOCARD [--force] <hexstring_with_keygrip> <serialno> <id> <timestamp>\n"
- "\n";
+ "KEYTOCARD [--force] <hexgrip> <serialno> <keyref> [<timestamp> [<ecdh>]]\n"
+ "\n"
+ "TIMESTAMP is required for OpenPGP and defaults to the Epoch.\n"
+ "ECDH are the hexified ECDH parameters for OpenPGP.\n"
+ "SERIALNO is used for checking; use \"-\" to disable the check.";
static gpg_error_t
cmd_keytocard (assuan_context_t ctx, char *line)
{
ctrl_t ctrl = assuan_get_pointer (ctx);
int force;
gpg_error_t err = 0;
+ char *argv[5];
+ int argc;
unsigned char grip[20];
+ const char *serialno, *keyref;
gcry_sexp_t s_skey = NULL;
unsigned char *keydata;
size_t keydatalen;
- const char *serialno, *timestamp_str, *id;
unsigned char *shadow_info = NULL;
- time_t timestamp;
+ uint64_t timestamp;
+ char *ecdh_params = NULL;
+ unsigned int ecdh_params_len;
+ unsigned int extralen1, extralen2;
if (ctrl->restricted)
return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
@@ -2706,7 +2700,14 @@ cmd_keytocard (assuan_context_t ctx, char *line)
force = has_option (line, "--force");
line = skip_options (line);
- err = parse_keygrip (ctx, line, grip);
+ argc = split_fields (line, argv, DIM (argv));
+ if (argc < 3)
+ {
+ err = gpg_error (GPG_ERR_MISSING_VALUE);
+ goto leave;
+ }
+
+ err = parse_keygrip (ctx, argv[0], grip);
if (err)
goto leave;
@@ -2716,82 +2717,112 @@ cmd_keytocard (assuan_context_t ctx, char *line)
goto leave;
}
- /* Fixme: Replace the parsing code by split_fields(). */
- line += 40;
- while (*line && (*line == ' ' || *line == '\t'))
- line++;
- serialno = line;
- while (*line && (*line != ' ' && *line != '\t'))
- line++;
- if (!*line)
- {
- err = gpg_error (GPG_ERR_MISSING_VALUE);
- goto leave;
- }
- *line = '\0';
- line++;
- while (*line && (*line == ' ' || *line == '\t'))
- line++;
- id = line;
- while (*line && (*line != ' ' && *line != '\t'))
- line++;
- if (!*line)
- {
- err = gpg_error (GPG_ERR_MISSING_VALUE);
- goto leave;
- }
- *line = '\0';
- line++;
- while (*line && (*line == ' ' || *line == '\t'))
- line++;
- timestamp_str = line;
- while (*line && (*line != ' ' && *line != '\t'))
- line++;
- if (*line)
- *line = '\0';
+ /* Note that checking of the s/n is currently not implemented but we
+ * want to provide a clean interface if we ever implement it. */
+ serialno = argv[1];
+ if (!strcmp (serialno, "-"))
+ serialno = NULL;
- if ((timestamp = isotime2epoch (timestamp_str)) == (time_t)(-1))
- {
- err = gpg_error (GPG_ERR_INV_TIME);
- goto leave;
- }
+ keyref = argv[2];
err = agent_key_from_file (ctrl, NULL, ctrl->server_local->keydesc, grip,
&shadow_info, CACHE_MODE_IGNORE, NULL,
- &s_skey, NULL);
+ &s_skey, NULL, &timestamp);
if (err)
+ goto leave;
+
+ if (shadow_info)
{
- xfree (shadow_info);
+ /* Key is already on a smartcard - wer can't extract it. */
+ err = gpg_error (GPG_ERR_UNUSABLE_SECKEY);
goto leave;
}
- if (shadow_info)
+
+ /* Default to the creation time as stored in the private key. The
+ * parameter is here so that gpg can make sure that the timestamp is
+ * used. It is also important for OpenPGP cards to allow computing
+ * of the fingerprint. Same goes for the ECDH params. */
+ if (argc > 3)
{
- /* Key is on a smartcard already. */
- xfree (shadow_info);
- gcry_sexp_release (s_skey);
- err = gpg_error (GPG_ERR_UNUSABLE_SECKEY);
+ timestamp = isotime2epoch_u64 (argv[3]);
+ if (argc > 4)
+ {
+ size_t n;
+
+ err = parse_hexstring (ctx, argv[4], &n);
+ if (err)
+ goto leave; /* Badly formatted ecdh params. */
+ n /= 2;
+ if (n < 4)
+ {
+ err = set_error (GPG_ERR_ASS_PARAMETER, "ecdh param too short");
+ goto leave;
+ }
+ ecdh_params_len = n;
+ ecdh_params = xtrymalloc (ecdh_params_len);
+ if (!ecdh_params)
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+ if (hex2bin (argv[4], ecdh_params, ecdh_params_len) < 0)
+ {
+ err = set_error (GPG_ERR_BUG, "hex2bin");
+ goto leave;
+ }
+ }
+ }
+ else if (timestamp == (uint64_t)(-1))
+ timestamp = isotime2epoch_u64 ("19700101T000000");
+
+ if (timestamp == (uint64_t)(-1))
+ {
+ err = gpg_error (GPG_ERR_INV_TIME);
goto leave;
}
- keydatalen = gcry_sexp_sprint (s_skey, GCRYSEXP_FMT_CANON, NULL, 0);
- keydata = xtrymalloc_secure (keydatalen + 30);
+ /* Note: We can't use make_canon_sexp because we need to allocate a
+ * few extra bytes for our hack below. The 20 for extralen2
+ * accounts for the sexp length of ecdh_params. */
+ keydatalen = gcry_sexp_sprint (s_skey, GCRYSEXP_FMT_CANON, NULL, 0);
+ extralen1 = 30;
+ extralen2 = ecdh_params? (20+20+ecdh_params_len) : 0;
+ keydata = xtrymalloc_secure (keydatalen + extralen1 + extralen2);
if (keydata == NULL)
{
err = gpg_error_from_syserror ();
- gcry_sexp_release (s_skey);
goto leave;
}
-
gcry_sexp_sprint (s_skey, GCRYSEXP_FMT_CANON, keydata, keydatalen);
gcry_sexp_release (s_skey);
+ s_skey = NULL;
+
keydatalen--; /* Decrement for last '\0'. */
- /* Add timestamp "created-at" in the private key */
- snprintf (keydata+keydatalen-1, 30, KEYTOCARD_TIMESTAMP_FORMAT, timestamp);
+
+ /* Hack to insert the timestamp "created-at" into the private key. */
+ snprintf (keydata+keydatalen-1, extralen1, "(10:created-at10:%010llu))",
+ (unsigned long long)timestamp);
keydatalen += 10 + 19 - 1;
- err = divert_writekey (ctrl, force, serialno, id, keydata, keydatalen);
+
+ /* Hack to insert the timestamp "ecdh-params" into the private key. */
+ if (ecdh_params)
+ {
+ snprintf (keydata+keydatalen-1, extralen2, "(11:ecdh-params%u:",
+ ecdh_params_len);
+ keydatalen += strlen (keydata+keydatalen-1) -1;
+ memcpy (keydata+keydatalen, ecdh_params, ecdh_params_len);
+ keydatalen += ecdh_params_len;
+ memcpy (keydata+keydatalen, "))", 3);
+ keydatalen += 2;
+ }
+
+ err = divert_writekey (ctrl, force, serialno, keyref, keydata, keydatalen);
xfree (keydata);
leave:
+ xfree (ecdh_params);
+ gcry_sexp_release (s_skey);
+ xfree (shadow_info);
return leave_cmd (ctx, err);
}
diff --git a/agent/cvt-openpgp.c b/agent/cvt-openpgp.c
index 78f2989..fe51506 100644
--- a/agent/cvt-openpgp.c
+++ b/agent/cvt-openpgp.c
@@ -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*/, 0, 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*/, 0, NULL, NULL, NULL, 0);
}
}
diff --git a/agent/findkey.c b/agent/findkey.c
index dadcc3c..a5055bc 100644
--- a/agent/findkey.c
+++ b/agent/findkey.c
@@ -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.
*
@@ -26,10 +27,8 @@
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
-#include <assert.h>
#include <unistd.h>
#include <sys/stat.h>
-#include <assert.h>
#include <npth.h> /* (we use pth_sleep) */
#include "agent.h"
@@ -41,6 +40,13 @@
#define O_BINARY 0
#endif
+
+static gpg_error_t read_key_file (const unsigned char *grip,
+ gcry_sexp_t *result, nvc_t *r_keymeta,
+ char **r_orig_key_value);
+static gpg_error_t is_shadowed_key (gcry_sexp_t s_skey);
+
+
/* Helper to pass data to the check callback of the unprotect function. */
struct try_unprotect_arg_s
{
@@ -52,96 +58,134 @@ struct try_unprotect_arg_s
};
-/* Return the file name for the 20 byte keygrip GRIP. Return NULL on
- * error. */
+/* Return the file name for the 20 byte keygrip GRIP. With FOR_NEW
+ * create a file name for later renaming to the actual name. Return
+ * NULL on error. */
static char *
-fname_from_keygrip (const unsigned char *grip)
+fname_from_keygrip (const unsigned char *grip, int for_new)
{
- char hexgrip[40+4+1];
+ char hexgrip[40+4+4+1];
bin2hex (grip, 20, hexgrip);
- strcpy (hexgrip+40, ".key");
+ strcpy (hexgrip+40, for_new? ".key.tmp" : ".key");
return make_filename_try (gnupg_homedir (), GNUPG_PRIVATE_KEYS_DIR,
hexgrip, NULL);
}
-/* 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 be 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, int reallyforce,
+ const char *serialno, const char *keyref,
+ const char *dispserialno,
+ time_t timestamp)
{
gpg_error_t err;
+ char *oldfname = NULL;
+ char *fname = NULL;
+ estream_t fp;
+ int newkey = 0;
nvc_t pk = NULL;
gcry_sexp_t key = NULL;
+ int is_regular;
int remove = 0;
char *token0 = NULL;
char *token = NULL;
char *dispserialno_buffer = NULL;
char **tokenfields = NULL;
+ int blocksigs = 0;
+ char *orig_key_value = NULL;
+ const char *s;
+ int force_modify = 0;
+
+ oldfname = fname_from_keygrip (grip, 0);
+ if (!oldfname)
+ return out_of_core ();
- if (old_format || newkey)
+ err = read_key_file (grip, &key, &pk, &orig_key_value);
+ if (err)
{
- /* 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)
+ if (gpg_err_code (err) == GPG_ERR_ENOENT)
+ newkey = 1;
+ else
{
- err = gpg_error_from_syserror ();
+ log_error ("can't open '%s': %s\n", oldfname, gpg_strerror (err));
goto leave;
}
- maybe_update = 0; /* Always write. */
}
- else
- { /* Parse the existing NVC. */
- int lineno = 0;
- err = nvc_parse_private_key (&pk, &lineno, fp);
- if (err)
+ nvc_modified (pk, 1); /* Clear that flag after a read. */
+
+ if (!pk)
+ {
+ /* Key is still in the old format or does not exist - create a
+ * new container. */
+ pk = nvc_new_private_key ();
+ if (!pk)
{
- log_error ("error parsing '%s' line %d: %s\n",
- fname, lineno, gpg_strerror (err));
+ err = gpg_error_from_syserror ();
goto leave;
}
+ force_modify = 1;
}
- es_clearerr (fp);
- err = gcry_sexp_sscan (&key, NULL, buf, len);
+ /* Check whether we already have a regular key. */
+ is_regular = (key && gpg_err_code (is_shadowed_key (key)) != GPG_ERR_TRUE);
+
+ /* Turn (BUFFER,LENGTH) into a gcrypt s-expression and set it into
+ * our name value container. */
+ gcry_sexp_release (key);
+ 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:"))
+ /* Detect whether the key value actually changed and if not clear
+ * the modified flag. This extra check is required because
+ * read_key_file removes the Key entry from the container and we
+ * then create a new Key entry which might be the same, though. */
+ if (!force_modify
+ && orig_key_value && (s = nvc_get_string (pk, "Key:"))
+ && !strcmp (orig_key_value, s))
{
- gnupg_isotime_t timebuf;
+ nvc_modified (pk, 1); /* Clear that flag. */
+ }
+ xfree (orig_key_value);
+ orig_key_value = NULL;
- epoch2isotime (timebuf, timestamp);
- err = nvc_add (pk, "Created:", timebuf);
- if (err)
- goto leave;
+ /* Check that we do not update a regular key with a shadow key. */
+ if (is_regular && gpg_err_code (is_shadowed_key (key)) == GPG_ERR_TRUE)
+ {
+ if (!reallyforce)
+ {
+ log_info ("updating regular key file '%s'"
+ " by a shadow key inhibited\n", oldfname);
+ err = 0; /* Simply ignore the error. */
+ goto leave;
+ }
+ }
+ /* Check that we update a regular key only in force mode. */
+ if (is_regular && !force)
+ {
+ log_error ("secret key file '%s' already exists\n", oldfname);
+ err = gpg_error (GPG_ERR_EEXIST);
+ goto leave;
}
/* If requested write a Token line. */
if (serialno && keyref)
{
nve_t item;
- const char *s;
size_t token0len;
if (dispserialno)
@@ -179,50 +223,63 @@ 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))
; /* No need to update Token entry. */
else
{
- err = nve_set (item, token);
+ err = nve_set (pk, item, token);
if (err)
goto leave;
- maybe_update = 0; /* Force write. */
}
}
}
- err = es_fseek (fp, 0, SEEK_SET);
- if (err)
- goto leave;
-
- if (!maybe_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:"))
{
- err = nvc_write (pk, fp);
- if (!err)
- err = es_fflush (fp);
+ gnupg_isotime_t timebuf;
+
+ epoch2isotime (timebuf, timestamp);
+ err = nvc_add (pk, "Created:", timebuf);
if (err)
- {
- log_error ("error writing '%s': %s\n", fname, gpg_strerror (err));
- remove = 1;
- goto leave;
- }
+ 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;
- }
+ /* Check whether we need to write the file at all. */
+ if (!nvc_modified (pk, 0))
+ {
+ err = 0;
+ goto leave;
+ }
+
+ /* Create a temporary file for writing. */
+ fname = fname_from_keygrip (grip, 1);
+ fp = fname ? es_fopen (fname, "wbx,mode=-rw") : NULL;
+ if (!fp)
+ {
+ err = gpg_error_from_syserror ();
+ log_error ("can't create '%s': %s\n", fname, gpg_strerror (err));
+ goto leave;
+ }
+
+ err = nvc_write (pk, fp);
+ if (!err && es_fflush (fp))
+ err = gpg_error_from_syserror ();
+ if (err)
+ {
+ log_error ("error writing '%s': %s\n", fname, gpg_strerror (err));
+ remove = 1;
+ goto leave;
}
if (es_fclose (fp))
@@ -232,17 +289,28 @@ write_extended_private_key (int maybe_update,
remove = 1;
goto leave;
}
- else
- fp = NULL;
+ fp = NULL;
- if (!maybe_update)
- bump_key_eventcounter ();
+ err = gnupg_rename_file (fname, oldfname, &blocksigs);
+ if (err)
+ {
+ err = gpg_error_from_syserror ();
+ log_error ("error renaming '%s': %s\n", fname, gpg_strerror (err));
+ remove = 1;
+ goto leave;
+ }
+
+ bump_key_eventcounter ();
leave:
+ if (blocksigs)
+ gnupg_unblock_all_signals ();
es_fclose (fp);
- if (remove)
+ if (remove && fname)
gnupg_remove (fname);
+ xfree (orig_key_value);
xfree (fname);
+ xfree (oldfname);
xfree (token);
xfree (token0);
xfree (dispserialno_buffer);
@@ -252,136 +320,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. */
@@ -395,7 +333,7 @@ try_unprotect_cb (struct pin_entry_info_s *pi)
gnupg_isotime_t now, protected_at, tmptime;
char *desc = NULL;
- assert (!arg->unprotected_key);
+ log_assert (!arg->unprotected_key);
arg->change_required = 0;
err = agent_unprotect (ctrl, arg->protected_key, pi->pin, protected_at,
@@ -772,7 +710,7 @@ unprotect (ctrl_t ctrl, const char *cache_nonce, const char *desc_text,
}
else
{
- assert (arg.unprotected_key);
+ log_assert (arg.unprotected_key);
if (arg.change_required)
{
/* The callback told as that the user should change their
@@ -780,7 +718,7 @@ unprotect (ctrl_t ctrl, const char *cache_nonce, const char *desc_text,
size_t canlen, erroff;
gcry_sexp_t s_skey;
- assert (arg.unprotected_key);
+ log_assert (arg.unprotected_key);
canlen = gcry_sexp_canon_len (arg.unprotected_key, 0, NULL, NULL);
rc = gcry_sexp_sscan (&s_skey, &erroff,
(char*)arg.unprotected_key, canlen);
@@ -824,39 +762,43 @@ unprotect (ctrl_t ctrl, const char *cache_nonce, const char *desc_text,
/* Read the key identified by GRIP from the private key directory and
* return it as an gcrypt S-expression object in RESULT. If R_KEYMETA
- * is not NULl and the extended key format is used, the meta data
- * items are stored there. However the "Key:" item is removed from
- * it. On failure returns an error code and stores NULL at RESULT. */
+ * is not NULL, the meta data items are stored there. However the
+ * "Key:" item is removed. If R_ORIG_KEY_VALUE is non-NULL and the
+ * Key items was removed, its value is stored at that R_ORIG_KEY_VALUE
+ * and the caller must free it. Returns an error code and stores NULL
+ * at RESULT. */
static gpg_error_t
-read_key_file (const unsigned char *grip, gcry_sexp_t *result, nvc_t *r_keymeta)
+read_key_file (const unsigned char *grip, gcry_sexp_t *result, nvc_t *r_keymeta,
+ char **r_orig_key_value)
{
gpg_error_t err;
char *fname;
- estream_t fp;
+ estream_t fp = NULL;
struct stat st;
- unsigned char *buf;
+ unsigned char *buf = NULL;
size_t buflen, erroff;
gcry_sexp_t s_skey;
- char hexgrip[40+4+1];
char first;
*result = NULL;
if (r_keymeta)
*r_keymeta = NULL;
+ if (r_orig_key_value)
+ *r_orig_key_value = NULL;
- bin2hex (grip, 20, hexgrip);
- strcpy (hexgrip+40, ".key");
-
- fname = make_filename (gnupg_homedir (), GNUPG_PRIVATE_KEYS_DIR,
- hexgrip, NULL);
+ fname = fname_from_keygrip (grip, 0);
+ if (!fname)
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
fp = es_fopen (fname, "rb");
if (!fp)
{
err = gpg_error_from_syserror ();
if (gpg_err_code (err) != GPG_ERR_ENOENT)
log_error ("can't open '%s': %s\n", fname, gpg_strerror (err));
- xfree (fname);
- return err;
+ goto leave;
}
if (es_fread (&first, 1, 1, fp) != 1)
@@ -864,18 +806,14 @@ read_key_file (const unsigned char *grip, gcry_sexp_t *result, nvc_t *r_keymeta)
err = gpg_error_from_syserror ();
log_error ("error reading first byte from '%s': %s\n",
fname, gpg_strerror (err));
- xfree (fname);
- es_fclose (fp);
- return 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));
- xfree (fname);
- es_fclose (fp);
- return err;
+ goto leave;
}
if (first != '(')
@@ -885,8 +823,6 @@ read_key_file (const unsigned char *grip, gcry_sexp_t *result, nvc_t *r_keymeta)
int line;
err = nvc_parse_private_key (&pk, &line, fp);
- es_fclose (fp);
-
if (err)
log_error ("error parsing '%s' line %d: %s\n",
fname, line, gpg_strerror (err));
@@ -897,24 +833,37 @@ read_key_file (const unsigned char *grip, gcry_sexp_t *result, nvc_t *r_keymeta)
log_error ("error getting private key from '%s': %s\n",
fname, gpg_strerror (err));
else
- nvc_delete_named (pk, "Key:");
+ {
+ if (r_orig_key_value)
+ {
+ const char *s = nvc_get_string (pk, "Key:");
+ if (s)
+ {
+ *r_orig_key_value = xtrystrdup (s);
+ if (!*r_orig_key_value)
+ {
+ err = gpg_error_from_syserror ();
+ nvc_release (pk);
+ goto leave;
+ }
+ }
+ }
+ nvc_delete_named (pk, "Key:");
+ }
}
if (!err && r_keymeta)
*r_keymeta = pk;
else
nvc_release (pk);
- xfree (fname);
- return err;
+ goto leave;
}
if (fstat (es_fileno (fp), &st))
{
err = gpg_error_from_syserror ();
log_error ("can't stat '%s': %s\n", fname, gpg_strerror (err));
- xfree (fname);
- es_fclose (fp);
- return err;
+ goto leave;
}
buflen = st.st_size;
@@ -924,11 +873,7 @@ read_key_file (const unsigned char *grip, gcry_sexp_t *result, nvc_t *r_keymeta)
err = gpg_error_from_syserror ();
log_error ("error allocating %zu bytes for '%s': %s\n",
buflen, fname, gpg_strerror (err));
- xfree (fname);
- es_fclose (fp);
- xfree (buf);
- return err;
-
+ goto leave;
}
if (es_fread (buf, buflen, 1, fp) != 1)
@@ -936,25 +881,24 @@ read_key_file (const unsigned char *grip, gcry_sexp_t *result, nvc_t *r_keymeta)
err = gpg_error_from_syserror ();
log_error ("error reading %zu bytes from '%s': %s\n",
buflen, fname, gpg_strerror (err));
- xfree (fname);
- es_fclose (fp);
- xfree (buf);
- return err;
+ goto leave;
}
/* Convert the file into a gcrypt S-expression object. */
err = gcry_sexp_sscan (&s_skey, &erroff, (char*)buf, buflen);
- xfree (fname);
- es_fclose (fp);
- xfree (buf);
if (err)
{
log_error ("failed to build S-Exp (off=%u): %s\n",
(unsigned int)erroff, gpg_strerror (err));
- return err;
+ goto leave;
}
*result = s_skey;
- return 0;
+
+ leave:
+ es_fclose (fp);
+ xfree (fname);
+ xfree (buf);
+ return err;
}
@@ -997,20 +941,24 @@ agent_key_from_file (ctrl_t ctrl, const char *cache_nonce,
const char *desc_text,
const unsigned char *grip, unsigned char **shadow_info,
cache_mode_t cache_mode, lookup_ttl_t lookup_ttl,
- gcry_sexp_t *result, char **r_passphrase)
+ gcry_sexp_t *result, char **r_passphrase,
+ uint64_t *r_timestamp)
{
gpg_error_t err;
unsigned char *buf;
size_t len, buflen, erroff;
gcry_sexp_t s_skey;
+ nvc_t keymeta = NULL;
*result = NULL;
if (shadow_info)
*shadow_info = NULL;
if (r_passphrase)
*r_passphrase = NULL;
+ if (r_timestamp)
+ *r_timestamp = (uint64_t)(-1);
- err = read_key_file (grip, &s_skey, NULL);
+ err = read_key_file (grip, &s_skey, &keymeta, NULL);
if (err)
{
if (gpg_err_code (err) == GPG_ERR_ENOENT)
@@ -1023,7 +971,19 @@ agent_key_from_file (ctrl_t ctrl, const char *cache_nonce,
now. */
err = make_canon_sexp (s_skey, &buf, &len);
if (err)
- return err;
+ {
+ nvc_release (keymeta);
+ return err;
+ }
+
+ if (r_timestamp && keymeta)
+ {
+ const char *created = nvc_get_string (keymeta, "Created:");
+
+ if (created)
+ *r_timestamp = isotime2epoch_u64 (created);
+ }
+ nvc_release (keymeta);
switch (agent_private_key_type (buf))
{
@@ -1325,6 +1285,29 @@ agent_is_eddsa_key (gcry_sexp_t s_key)
}
+/* This function returns GPG_ERR_TRUE if S_SKEY represents a shadowed
+ * key. 0 is return for other key types. Any other error may occur
+ * if S_SKEY is not valid. */
+static gpg_error_t
+is_shadowed_key (gcry_sexp_t s_skey)
+{
+ gpg_error_t err;
+ unsigned char *buf;
+ size_t buflen;
+
+ err = make_canon_sexp (s_skey, &buf, &buflen);
+ if (err)
+ return err;
+
+ if (agent_private_key_type (buf) == PRIVATE_KEY_SHADOWED)
+ err = gpg_error (GPG_ERR_TRUE);
+
+ wipememory (buf, buflen);
+ xfree (buf);
+ return err;
+}
+
+
/* Return the key for the keygrip GRIP. The result is stored at
RESULT. This function extracts the key from the private key
database and returns it as an S-expression object as it is. On
@@ -1340,7 +1323,7 @@ agent_raw_key_from_file (ctrl_t ctrl, const unsigned char *grip,
*result = NULL;
- err = read_key_file (grip, &s_skey, NULL);
+ err = read_key_file (grip, &s_skey, NULL, NULL);
if (!err)
*result = s_skey;
return err;
@@ -1356,7 +1339,7 @@ agent_keymeta_from_file (ctrl_t ctrl, const unsigned char *grip,
(void)ctrl;
- err = read_key_file (grip, &s_skey, r_keymeta);
+ err = read_key_file (grip, &s_skey, r_keymeta, NULL);
gcry_sexp_release (s_skey);
return err;
}
@@ -1394,7 +1377,7 @@ agent_public_key_from_file (ctrl_t ctrl,
*result = NULL;
- err = read_key_file (grip, &s_skey, NULL);
+ err = read_key_file (grip, &s_skey, NULL, NULL);
if (err)
return err;
@@ -1431,7 +1414,7 @@ agent_public_key_from_file (ctrl_t ctrl,
such a task. After all that is what we do in protect.c. Need
to find common patterns and write a straightformward API to use
them. */
- assert (sizeof (size_t) <= sizeof (void*));
+ log_assert (sizeof (size_t) <= sizeof (void*));
format = xtrymalloc (15+4+7*npkey+10+15+1+1);
if (!format)
@@ -1456,14 +1439,14 @@ agent_public_key_from_file (ctrl_t ctrl,
*p++ = '(';
*p++ = *s++;
p = stpcpy (p, " %m)");
- assert (argidx < DIM (args));
+ log_assert (argidx < DIM (args));
args[argidx++] = &array[idx];
}
*p++ = ')';
if (uri)
{
p = stpcpy (p, "(uri %b)");
- assert (argidx+1 < DIM (args));
+ log_assert (argidx+1 < DIM (args));
uri_intlen = (int)uri_length;
args[argidx++] = (void *)&uri_intlen;
args[argidx++] = (void *)&uri;
@@ -1471,14 +1454,14 @@ agent_public_key_from_file (ctrl_t ctrl,
if (comment)
{
p = stpcpy (p, "(comment %b)");
- assert (argidx+1 < DIM (args));
+ log_assert (argidx+1 < DIM (args));
comment_intlen = (int)comment_length;
args[argidx++] = (void *)&comment_intlen;
args[argidx++] = (void*)&comment;
}
*p++ = ')';
*p = 0;
- assert (argidx < DIM (args));
+ log_assert (argidx < DIM (args));
args[argidx] = NULL;
err = gcry_sexp_build_array (&list, NULL, format, args);
@@ -1541,7 +1524,7 @@ agent_key_info_from_file (ctrl_t ctrl, const unsigned char *grip,
{
gcry_sexp_t sexp;
- err = read_key_file (grip, &sexp, NULL);
+ err = read_key_file (grip, &sexp, NULL, NULL);
if (err)
{
if (gpg_err_code (err) == GPG_ERR_ENOENT)
@@ -1575,7 +1558,7 @@ agent_key_info_from_file (ctrl_t ctrl, const unsigned char *grip,
if (!err)
{
n = gcry_sexp_canon_len (s, 0, NULL, NULL);
- assert (n);
+ log_assert (n);
*r_shadow_info = xtrymalloc (n);
if (!*r_shadow_info)
err = gpg_error_from_syserror ();
@@ -1625,7 +1608,7 @@ agent_delete_key (ctrl_t ctrl, const char *desc_text,
char *default_desc = NULL;
int key_type;
- err = read_key_file (grip, &s_skey, NULL);
+ err = read_key_file (grip, &s_skey, NULL, NULL);
if (gpg_err_code (err) == GPG_ERR_ENOENT)
err = gpg_error (GPG_ERR_NO_SECKEY);
if (err)
@@ -1722,29 +1705,22 @@ 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
+ * REALLYFORCE is also true, even a private key will be overwritten by
+ * a shadown key. 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 unsigned char *pkbuf, int force, int reallyforce,
const char *dispserialno)
{
gpg_error_t err;
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 +1742,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, reallyforce,
+ 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;
}
diff --git a/agent/genkey.c b/agent/genkey.c
index a944ac7..d080bac 100644
--- a/agent/genkey.c
+++ b/agent/genkey.c
@@ -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, 0,
+ NULL, NULL, NULL, timestamp);
xfree (buf);
return rc;
}
diff --git a/agent/gpg-agent.c b/agent/gpg-agent.c
index 53b86dd..c3b71b0 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,
@@ -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;
diff --git a/agent/gpg-agent.w32-manifest.in b/agent/gpg-agent.w32-manifest.in
index d865aef..1ec3268 100644
--- a/agent/gpg-agent.w32-manifest.in
+++ b/agent/gpg-agent.w32-manifest.in
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
-<description>GNU Privacy Guard (Private key daemon)</description>
+<description>GNU Privacy Guard (Private Key Daemon)</description>
<assemblyIdentity
type="win32"
name="GnuPG.gpg-agent"
@@ -15,4 +15,11 @@
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/><!-- Vista -->
</application>
</compatibility>
+<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
+ <security>
+ <requestedPrivileges>
+ <requestedExecutionLevel level="asInvoker"/>
+ </requestedPrivileges>
+ </security>
+</trustInfo>
</assembly>
diff --git a/agent/learncard.c b/agent/learncard.c
index 2e491e1..f007b6d 100644
--- a/agent/learncard.c
+++ b/agent/learncard.c
@@ -297,9 +297,12 @@ send_cert_back (ctrl_t ctrl, const char *id, void *assuan_context)
}
/* Perform the learn operation. If ASSUAN_CONTEXT is not NULL and
- SEND is true all new certificates are send back via Assuan. */
+ SEND is true all new certificates are send back via Assuan. If
+ REALLYFORCE is true a private key will be overwritten by a stub
+ key. */
int
-agent_handle_learn (ctrl_t ctrl, int send, void *assuan_context, int force)
+agent_handle_learn (ctrl_t ctrl, int send, void *assuan_context,
+ int force, int reallyforce)
{
int rc;
struct kpinfo_cb_parm_s parm;
@@ -413,8 +416,8 @@ 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,
- force, dispserialno);
+ rc = agent_write_shadow_key (grip, serialno, item->id, pubkey,
+ force, reallyforce, dispserialno);
xfree (dispserialno);
}
xfree (pubkey);
diff --git a/agent/pkdecrypt.c b/agent/pkdecrypt.c
index 6aed96b..ccd395d 100644
--- a/agent/pkdecrypt.c
+++ b/agent/pkdecrypt.c
@@ -69,7 +69,7 @@ agent_pkdecrypt (ctrl_t ctrl, const char *desc_text,
}
rc = agent_key_from_file (ctrl, NULL, desc_text,
ctrl->keygrip, &shadow_info,
- CACHE_MODE_NORMAL, NULL, &s_skey, NULL);
+ CACHE_MODE_NORMAL, NULL, &s_skey, NULL, NULL);
if (rc)
{
if (gpg_err_code (rc) != GPG_ERR_NO_SECKEY)
diff --git a/agent/pksign.c b/agent/pksign.c
index 09d61b8..571541d 100644
--- a/agent/pksign.c
+++ b/agent/pksign.c
@@ -311,7 +311,7 @@ agent_pksign_do (ctrl_t ctrl, const char *cache_nonce,
err = agent_key_from_file (ctrl, cache_nonce, desc_text, ctrl->keygrip,
&shadow_info, cache_mode, lookup_ttl,
- &s_skey, NULL);
+ &s_skey, NULL, NULL);
if (err)
{
if (gpg_err_code (err) != GPG_ERR_NO_SECKEY)
diff --git a/agent/protect-tool.c b/agent/protect-tool.c
index fb2c71d..35ed993 100644
--- a/agent/protect-tool.c
+++ b/agent/protect-tool.c
@@ -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;
}
@@ -809,14 +807,15 @@ agent_askpin (ctrl_t ctrl,
* to stdout. */
int
agent_write_private_key (const unsigned char *grip,
- const void *buffer, size_t length, int force,
- time_t timestamp,
+ const void *buffer, size_t length,
+ int force, int reallyforce,
const char *serialno, const char *keyref,
- const char *dispserialno)
+ const char *dispserialno, time_t timestamp)
{
char hexgrip[40+4+1];
char *p;
+ (void)reallyforce;
(void)force;
(void)timestamp;
(void)serialno;
diff --git a/agent/protect.c b/agent/protect.c
index 87df685..6bf1400 100644
--- a/agent/protect.c
+++ b/agent/protect.c
@@ -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++ = ')';
- }
- 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
+ *p++ = ')';
+ *p++ = ')';
+ log_assert ( p - outbuf == outlen);
+ 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);
}
}
@@ -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;
diff --git a/agent/t-protect.c b/agent/t-protect.c
index 88b5525..e6edbff 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 086d8ae..5617370 100644
--- a/agent/trustlist.c
+++ b/agent/trustlist.c
@@ -45,6 +45,8 @@ struct trustitem_s
int relax:1; /* Relax checking of root certificate
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. */
};
@@ -322,6 +324,10 @@ read_one_trustfile (const char *fname, int systrust,
ti->flags.relax = 1;
else if (n == 2 && !memcmp (p, "cm", 2))
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);
@@ -474,17 +480,20 @@ istrusted_internal (ctrl_t ctrl, const char *fpr, int *r_disabled,
in a locked state. */
if (already_locked)
;
- else if (ti->flags.relax)
+ else if (ti->flags.relax || ti->flags.cm || ti->flags.qual
+ || ti->flags.de_vs)
{
unlock_trusttable ();
locked = 0;
- err = agent_write_status (ctrl, "TRUSTLISTFLAG", "relax", NULL);
- }
- else if (ti->flags.cm)
- {
- unlock_trusttable ();
- locked = 0;
- err = agent_write_status (ctrl, "TRUSTLISTFLAG", "cm", NULL);
+ err = 0;
+ if (ti->flags.relax)
+ err = agent_write_status (ctrl,"TRUSTLISTFLAG", "relax",NULL);
+ if (!err && ti->flags.cm)
+ 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)
@@ -646,7 +655,7 @@ agent_marktrusted (ctrl_t ctrl, const char *name, const char *fpr, int flag)
if (!fname)
return gpg_error_from_syserror ();
- if ((ec = access (fname, W_OK)) && ec != GPG_ERR_ENOENT)
+ if ((ec = gnupg_access (fname, W_OK)) && ec != GPG_ERR_ENOENT)
{
xfree (fname);
return gpg_error (GPG_ERR_EPERM);