From ec13b1c562e34c0fcbc7b848ab6dc187b79cf2c1 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Sat, 26 Jan 2019 23:10:38 +0100 Subject: [PATCH] gpg: Move S2K encoding function to a shared file. * g10/passphrase.c (encode_s2k_iterations): Move function to ... * common/openpgp-s2k.c: new file. Remove default intialization code. * common/openpgpdefs.h (S2K_DECODE_COUNT): New to keep only one copy. * g10/call-agent.c (agent_get_s2k_count): Change to return the count and print an error. * agent/protect.c: Include openpgpdefs.h * g10/card-util.c (gen_kdf_data): Adjust for changes * g10/gpgcompose.c: Include call-agent.h. (sk_esk): Adjust for changes. * g10/passphrase (passphrase_to_dek): Adjust for changes. * g10/main.h (S2K_DECODE_COUNT): Remove macro. Signed-off-by: Werner Koch --- agent/protect.c | 4 +-- common/Makefile.am | 2 +- common/openpgp-s2k.c | 67 ++++++++++++++++++++++++++++++++++++++++++++ common/openpgpdefs.h | 10 +++++++ common/ttyio.c | 2 ++ g10/call-agent.c | 26 ++++++++++++----- g10/call-agent.h | 2 +- g10/card-util.c | 2 +- g10/gpgcompose.c | 10 +++++-- g10/keydb.h | 1 - g10/main.h | 2 -- g10/passphrase.c | 54 ++--------------------------------- 12 files changed, 111 insertions(+), 71 deletions(-) create mode 100644 common/openpgp-s2k.c diff --git a/agent/protect.c b/agent/protect.c index f95527f78..eda247f27 100644 --- a/agent/protect.c +++ b/agent/protect.c @@ -41,6 +41,7 @@ #include "cvt-openpgp.h" #include "../common/sexp-parse.h" +#include "../common/openpgpdefs.h" /* For s2k functions. */ /* The protection mode for encryption. The supported modes for @@ -49,9 +50,6 @@ #define PROT_CIPHER_STRING "aes" #define PROT_CIPHER_KEYLEN (128/8) -/* Decode an rfc4880 encoded S2K count. */ -#define S2K_DECODE_COUNT(_val) ((16ul + ((_val) & 15)) << (((_val) >> 4) + 6)) - /* A table containing the information needed to create a protected private key. */ diff --git a/common/Makefile.am b/common/Makefile.am index d288fa36b..b6a6605f1 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -83,7 +83,7 @@ common_sources = \ localename.c \ session-env.c session-env.h \ userids.c userids.h \ - openpgp-oid.c \ + openpgp-oid.c openpgp-s2k.c \ ssh-utils.c ssh-utils.h \ agent-opt.c \ helpfile.c \ diff --git a/common/openpgp-s2k.c b/common/openpgp-s2k.c new file mode 100644 index 000000000..2b0ba604b --- /dev/null +++ b/common/openpgp-s2k.c @@ -0,0 +1,67 @@ +/* openpgp-s2ks.c - OpenPGP S2K helper functions + * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, + * 2005, 2006 Free Software Foundation, Inc. + * Copyright (C) 2010, 2019 g10 Code GmbH + * + * This file is part of GnuPG. + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of either + * + * - the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 3 of the License, or (at + * your option) any later version. + * + * or + * + * - the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * or both in parallel, as here. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include +#include +#include +#include +#include + +#include "util.h" +#include "openpgpdefs.h" + + +/* Pack an s2k iteration count into the form specified in RFC-48800. + * If we're in between valid values, round up. */ +unsigned char +encode_s2k_iterations (int iterations) +{ + unsigned char c=0; + unsigned char result; + unsigned int count; + + if (iterations <= 1024) + return 0; /* Command line arg compatibility. */ + + if (iterations >= 65011712) + return 255; + + /* Need count to be in the range 16-31 */ + for (count=iterations>>6; count>=32; count>>=1) + c++; + + result = (c<<4)|(count-16); + + if (S2K_DECODE_COUNT(result) < iterations) + result++; + + return result; +} diff --git a/common/openpgpdefs.h b/common/openpgpdefs.h index 8699a178d..aadda434b 100644 --- a/common/openpgpdefs.h +++ b/common/openpgpdefs.h @@ -197,4 +197,14 @@ typedef enum compress_algo_t; + + +/* Decode an rfc4880 encoded S2K count. */ +#define S2K_DECODE_COUNT(_val) ((16ul + ((_val) & 15)) << (((_val) >> 4) + 6)) + + +/*--openpgp-s2k.c --*/ +unsigned char encode_s2k_iterations (int iterations); + + #endif /*GNUPG_COMMON_OPENPGPDEFS_H*/ diff --git a/common/ttyio.c b/common/ttyio.c index c7c9d85ab..374b9f38a 100644 --- a/common/ttyio.c +++ b/common/ttyio.c @@ -564,6 +564,8 @@ do_get( const char *prompt, int hidden ) } + +/* Note: This function never returns NULL. */ char * tty_get( const char *prompt ) { diff --git a/g10/call-agent.c b/g10/call-agent.c index c958b84b7..91af2be39 100644 --- a/g10/call-agent.c +++ b/g10/call-agent.c @@ -1461,19 +1461,19 @@ gpg_agent_get_confirmation (const char *desc) } -/* Return the S2K iteration count as computed by gpg-agent. */ -gpg_error_t -agent_get_s2k_count (unsigned long *r_count) +/* Return the S2K iteration count as computed by gpg-agent. On error + * print a warning and return a default value. */ +unsigned long +agent_get_s2k_count (void) { gpg_error_t err; membuf_t data; char *buf; - - *r_count = 0; + unsigned long count = 0; err = start_agent (NULL, 0); if (err) - return err; + goto leave; init_membuf (&data, 32); err = assuan_transact (agent_ctx, "GETINFO s2k_count", @@ -1489,10 +1489,22 @@ agent_get_s2k_count (unsigned long *r_count) err = gpg_error_from_syserror (); else { - *r_count = strtoul (buf, NULL, 10); + count = strtoul (buf, NULL, 10); xfree (buf); } } + + leave: + if (err || count < 65536) + { + /* Don't print an error if an older agent is used. */ + if (err && gpg_err_code (err) != GPG_ERR_ASS_PARAMETER) + log_error (_("problem with the agent: %s\n"), gpg_strerror (err)); + + /* Default to 65536 which was used up to 2.0.13. */ + return 65536; + } + return err; } diff --git a/g10/call-agent.h b/g10/call-agent.h index 8ea8ffea6..8619a34f8 100644 --- a/g10/call-agent.h +++ b/g10/call-agent.h @@ -146,7 +146,7 @@ gpg_error_t agent_clear_passphrase (const char *cache_id); gpg_error_t gpg_agent_get_confirmation (const char *desc); /* Return the S2K iteration count as computed by gpg-agent. */ -gpg_error_t agent_get_s2k_count (unsigned long *r_count); +unsigned long agent_get_s2k_count (void); /* Check whether a secret key for public key PK is available. Returns 0 if the secret key is available. */ diff --git a/g10/card-util.c b/g10/card-util.c index eca248433..08844bae3 100644 --- a/g10/card-util.c +++ b/g10/card-util.c @@ -2039,7 +2039,7 @@ gen_kdf_data (unsigned char *data, int single_salt) p = data; - s2k_char = encode_s2k_iterations (0); + s2k_char = encode_s2k_iterations (agent_get_s2k_count ()); iterations = S2K_DECODE_COUNT (s2k_char); count_4byte[0] = (iterations >> 24) & 0xff; count_4byte[1] = (iterations >> 16) & 0xff; diff --git a/g10/gpgcompose.c b/g10/gpgcompose.c index 6f573ce46..5c0857590 100644 --- a/g10/gpgcompose.c +++ b/g10/gpgcompose.c @@ -25,6 +25,7 @@ #include "keydb.h" #include "main.h" #include "options.h" +#include "call-agent.h" static int do_debug; #define debug(fmt, ...) \ @@ -2248,9 +2249,12 @@ sk_esk (const char *option, int argc, char *argv[], void *cookie) log_assert (sizeof (si.salt) == sizeof (ske->s2k.salt)); memcpy (ske->s2k.salt, si.salt, sizeof (ske->s2k.salt)); if (! si.s2k_is_session_key) - /* 0 means get the default. */ - ske->s2k.count = encode_s2k_iterations (si.iterations); - + { + if (!si.iterations) + ske->s2k.count = encode_s2k_iterations (agent_get_s2k_count ()); + else + ske->s2k.count = encode_s2k_iterations (si.iterations); + } /* Derive the symmetric key that is either the session key or the key used to encrypt the session key. */ diff --git a/g10/keydb.h b/g10/keydb.h index 1def2bb81..acb424455 100644 --- a/g10/keydb.h +++ b/g10/keydb.h @@ -276,7 +276,6 @@ gpg_error_t build_sk_list (ctrl_t ctrl, strlist_t locusr, SK_LIST *ret_sk_list, unsigned use); /*-- passphrase.h --*/ -unsigned char encode_s2k_iterations (int iterations); int have_static_passphrase(void); const char *get_static_passphrase (void); void set_passphrase_from_string(const char *pass); diff --git a/g10/main.h b/g10/main.h index 86f8589b2..867f6975b 100644 --- a/g10/main.h +++ b/g10/main.h @@ -507,8 +507,6 @@ gpg_error_t card_generate_subkey (ctrl_t ctrl, kbnode_t pub_keyblock); int card_store_subkey (KBNODE node, int use); #endif -#define S2K_DECODE_COUNT(_val) ((16ul + ((_val) & 15)) << (((_val) >> 4) + 6)) - /*-- migrate.c --*/ void migrate_secring (ctrl_t ctrl); diff --git a/g10/passphrase.c b/g10/passphrase.c index 10574ec6a..99a2c0dc2 100644 --- a/g10/passphrase.c +++ b/g10/passphrase.c @@ -48,57 +48,6 @@ static char *next_pw = NULL; static char *last_pw = NULL; - -/* Pack an s2k iteration count into the form specified in 2440. If - we're in between valid values, round up. With value 0 return the - old default. */ -unsigned char -encode_s2k_iterations (int iterations) -{ - gpg_error_t err; - unsigned char c=0; - unsigned char result; - unsigned int count; - - if (!iterations) - { - unsigned long mycnt; - - /* Ask the gpg-agent for a useful iteration count. */ - err = agent_get_s2k_count (&mycnt); - if (err || mycnt < 65536) - { - /* Don't print an error if an older agent is used. */ - if (err && gpg_err_code (err) != GPG_ERR_ASS_PARAMETER) - log_error (_("problem with the agent: %s\n"), gpg_strerror (err)); - /* Default to 65536 which we used up to 2.0.13. */ - return 96; - } - else if (mycnt >= 65011712) - return 255; /* Largest possible value. */ - else - return encode_s2k_iterations ((int)mycnt); - } - - if (iterations <= 1024) - return 0; /* Command line arg compatibility. */ - - if (iterations >= 65011712) - return 255; - - /* Need count to be in the range 16-31 */ - for (count=iterations>>6; count>=32; count>>=1) - c++; - - result = (c<<4)|(count-16); - - if (S2K_DECODE_COUNT(result) < iterations) - result++; - - return result; -} - - int have_static_passphrase() { @@ -106,6 +55,7 @@ have_static_passphrase() && (opt.batch || opt.pinentry_mode == PINENTRY_MODE_LOOPBACK)); } + /* Return a static passphrase. The returned value is only valid as long as no other passphrase related function is called. NULL may be returned if no passphrase has been set; better use @@ -342,7 +292,7 @@ passphrase_to_dek (int cipher_algo, STRING2KEY *s2k, call out to gpg-agent and that should not be done during option processing in main(). */ if (!opt.s2k_count) - opt.s2k_count = encode_s2k_iterations (0); + opt.s2k_count = encode_s2k_iterations (agent_get_s2k_count ()); s2k->count = opt.s2k_count; } }