From 1d379b1ebaa9b21f174592f05ab6a8c2c408d7f3 Mon Sep 17 00:00:00 2001 From: Ben Kibbey Date: Sat, 6 Aug 2016 13:05:02 -0400 Subject: [PATCH] ISCACHED: validate the checksum. This command is mostly used to determine if a passphrase is needed to open a data file. If the checksum doesn't match the cached checksum then return GPG_ERR_NO_DATA. Also return GPG_ERR_INV_STATE when --agent or --sign is passed with no opened data file since some data may be forged (see [1]). 1. https://lists.gnupg.org/pipermail/gnupg-devel/2016-August/031459.html --- doc/pwmd.html | 4 +++- src/commands.c | 37 ++++++++++++++++++++++++++----------- 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/doc/pwmd.html b/doc/pwmd.html index f8288c29..3c745063 100644 --- a/doc/pwmd.html +++ b/doc/pwmd.html @@ -1066,7 +1066,9 @@ Next: , Previous: --agent will test the gpg-agent cache for at most one cached key used for opening the data file (see OPEN). To test if -a signing key is cached, pass --sign along with --agent. +a signing key is cached, pass --sign along with --agent. +Both the --agent and --sign options require an opened data +file. *
 An OK response is returned if the specified filename is found in the cache. If not found in the cache but exists on the filesystem then GPG_ERR_NO_DATA is returned. Otherwise a filesystem error is diff --git a/src/commands.c b/src/commands.c index 34dcb231..38594cca 100644 --- a/src/commands.c +++ b/src/commands.c @@ -88,7 +88,7 @@ struct command_table_s static struct command_table_s **command_table; static gpg_error_t do_lock (struct client_s *client, int add); -static gpg_error_t validate_checksum (struct client_s *, +static gpg_error_t validate_checksum (struct client_s *, const char *filename, struct cache_data_s *, unsigned char **, size_t *); static gpg_error_t update_checksum (struct client_s *client); @@ -216,7 +216,7 @@ file_modified (struct client_s *client, struct command_table_s *cmd) rc = lock_flock (client->ctx, client->filename, type, &client->flock_fd); if (!rc) { - rc = validate_checksum (client, NULL, NULL, NULL); + rc = validate_checksum (client, client->filename, NULL, NULL, NULL); if (gpg_err_code (rc) == GPG_ERR_ENOENT && (client->flags & FLAG_NEW)) rc = 0; else if (rc) @@ -358,8 +358,9 @@ update_checksum (struct client_s *client) } static gpg_error_t -validate_checksum (struct client_s *client, struct cache_data_s *cdata, - unsigned char **r_crc, size_t *r_crclen) +validate_checksum (struct client_s *client, const char *filename, + struct cache_data_s *cdata, unsigned char **r_crc, + size_t *r_crclen) { unsigned char *crc; size_t len; @@ -369,7 +370,7 @@ validate_checksum (struct client_s *client, struct cache_data_s *cdata, if (cdata && !cdata->crc) return GPG_ERR_CHECKSUM; - rc = get_checksum (client->filename, &crc, &len); + rc = get_checksum (filename, &crc, &len); if (rc) return rc; @@ -505,7 +506,8 @@ open_command (assuan_context_t ctx, char *line) if (!rc && !(client->flags & FLAG_NEW)) { - rc = validate_checksum (client, cdata, &crc, &crclen); + rc = validate_checksum (client, client->filename, cdata, &crc, + &crclen); if (rc == GPG_ERR_CHECKSUM) { rc = 0; @@ -2224,6 +2226,7 @@ iscached_command (assuan_context_t ctx, char *line) { struct client_s *client = assuan_get_pointer (ctx); gpg_error_t rc; + unsigned char md5file[16]; struct argv_s *args[] = { &(struct argv_s) {"lock", OPTION_TYPE_NOARG, parse_iscached_opt_lock}, &(struct argv_s) {"agent", OPTION_TYPE_NOARG, parse_iscached_opt_agent}, @@ -2240,20 +2243,30 @@ iscached_command (assuan_context_t ctx, char *line) else if (!valid_filename (line)) return send_error (ctx, GPG_ERR_INV_VALUE); - // FIXME: read data file header to fetch keyid to test gpg-agent cache if (!(client->flags & FLAG_OPEN) && ((client->opts & OPT_CACHE_AGENT) || (client->opts & OPT_CACHE_SIGN))) - return send_error (ctx, GPG_ERR_NOT_IMPLEMENTED); + return send_error (ctx, GPG_ERR_INV_STATE); + gcry_md_hash_buffer (GCRY_MD_MD5, md5file, line, strlen (line)); rc = cache_iscached (line, NULL, (client->opts & OPT_CACHE_AGENT), (client->opts & OPT_CACHE_SIGN)); + if (!rc) + { + struct cache_data_s *cdata = cache_get_data (md5file); + + if (cdata) + { + rc = validate_checksum (client, line, cdata, NULL, NULL); + if (rc == GPG_ERR_CHECKSUM) + rc = GPG_ERR_NO_DATA; + } + } + if (client->opts & OPT_LOCK && (!rc || gpg_err_code (rc) == GPG_ERR_NO_DATA)) { - unsigned char md5file[16]; gpg_error_t trc = rc; - gcry_md_hash_buffer (GCRY_MD_MD5, md5file, line, strlen (line)); if (memcmp (md5file, client->md5file, 16)) cleanup_client (client); @@ -4529,7 +4542,9 @@ init_commands () "The default is to test whether the filename is cached in memory. Passing " "option @option{--agent} will test the @command{gpg-agent} cache for at most " "one cached key used for opening the data file (@pxref{OPEN}). To test if " -"a signing key is cached, pass @option{--sign} along with @option{--agent}." +"a signing key is cached, pass @option{--sign} along with @option{--agent}. " +"Both the @option{--agent} and @option{--sign} options require an opened data " +"file." "*@*@" "An @emph{OK} response is returned if the specified @var{filename} is found " "in the cache. If not found in the cache but exists on the filesystem " -- 2.11.4.GIT