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 <wk@gnupg.org>
This commit is contained in:
Werner Koch 2019-01-26 23:10:38 +01:00
parent 0415b80227
commit ec13b1c562
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
12 changed files with 111 additions and 71 deletions

View File

@ -41,6 +41,7 @@
#include "cvt-openpgp.h" #include "cvt-openpgp.h"
#include "../common/sexp-parse.h" #include "../common/sexp-parse.h"
#include "../common/openpgpdefs.h" /* For s2k functions. */
/* The protection mode for encryption. The supported modes for /* The protection mode for encryption. The supported modes for
@ -49,9 +50,6 @@
#define PROT_CIPHER_STRING "aes" #define PROT_CIPHER_STRING "aes"
#define PROT_CIPHER_KEYLEN (128/8) #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 /* A table containing the information needed to create a protected
private key. */ private key. */

View File

@ -83,7 +83,7 @@ common_sources = \
localename.c \ localename.c \
session-env.c session-env.h \ session-env.c session-env.h \
userids.c userids.h \ userids.c userids.h \
openpgp-oid.c \ openpgp-oid.c openpgp-s2k.c \
ssh-utils.c ssh-utils.h \ ssh-utils.c ssh-utils.h \
agent-opt.c \ agent-opt.c \
helpfile.c \ helpfile.c \

67
common/openpgp-s2k.c Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <stdlib.h>
#include <errno.h>
#include <ctype.h>
#include <assert.h>
#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;
}

View File

@ -197,4 +197,14 @@ typedef enum
compress_algo_t; 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*/ #endif /*GNUPG_COMMON_OPENPGPDEFS_H*/

View File

@ -564,6 +564,8 @@ do_get( const char *prompt, int hidden )
} }
/* Note: This function never returns NULL. */
char * char *
tty_get( const char *prompt ) tty_get( const char *prompt )
{ {

View File

@ -1461,19 +1461,19 @@ gpg_agent_get_confirmation (const char *desc)
} }
/* Return the S2K iteration count as computed by gpg-agent. */ /* Return the S2K iteration count as computed by gpg-agent. On error
gpg_error_t * print a warning and return a default value. */
agent_get_s2k_count (unsigned long *r_count) unsigned long
agent_get_s2k_count (void)
{ {
gpg_error_t err; gpg_error_t err;
membuf_t data; membuf_t data;
char *buf; char *buf;
unsigned long count = 0;
*r_count = 0;
err = start_agent (NULL, 0); err = start_agent (NULL, 0);
if (err) if (err)
return err; goto leave;
init_membuf (&data, 32); init_membuf (&data, 32);
err = assuan_transact (agent_ctx, "GETINFO s2k_count", 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 (); err = gpg_error_from_syserror ();
else else
{ {
*r_count = strtoul (buf, NULL, 10); count = strtoul (buf, NULL, 10);
xfree (buf); 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; return err;
} }

View File

@ -146,7 +146,7 @@ gpg_error_t agent_clear_passphrase (const char *cache_id);
gpg_error_t gpg_agent_get_confirmation (const char *desc); gpg_error_t gpg_agent_get_confirmation (const char *desc);
/* Return the S2K iteration count as computed by gpg-agent. */ /* 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 /* Check whether a secret key for public key PK is available. Returns
0 if the secret key is available. */ 0 if the secret key is available. */

View File

@ -2039,7 +2039,7 @@ gen_kdf_data (unsigned char *data, int single_salt)
p = data; p = data;
s2k_char = encode_s2k_iterations (0); s2k_char = encode_s2k_iterations (agent_get_s2k_count ());
iterations = S2K_DECODE_COUNT (s2k_char); iterations = S2K_DECODE_COUNT (s2k_char);
count_4byte[0] = (iterations >> 24) & 0xff; count_4byte[0] = (iterations >> 24) & 0xff;
count_4byte[1] = (iterations >> 16) & 0xff; count_4byte[1] = (iterations >> 16) & 0xff;

View File

@ -25,6 +25,7 @@
#include "keydb.h" #include "keydb.h"
#include "main.h" #include "main.h"
#include "options.h" #include "options.h"
#include "call-agent.h"
static int do_debug; static int do_debug;
#define debug(fmt, ...) \ #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)); log_assert (sizeof (si.salt) == sizeof (ske->s2k.salt));
memcpy (ske->s2k.salt, si.salt, sizeof (ske->s2k.salt)); memcpy (ske->s2k.salt, si.salt, sizeof (ske->s2k.salt));
if (! si.s2k_is_session_key) 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 /* Derive the symmetric key that is either the session key or the
key used to encrypt the session key. */ key used to encrypt the session key. */

View File

@ -276,7 +276,6 @@ gpg_error_t build_sk_list (ctrl_t ctrl, strlist_t locusr,
SK_LIST *ret_sk_list, unsigned use); SK_LIST *ret_sk_list, unsigned use);
/*-- passphrase.h --*/ /*-- passphrase.h --*/
unsigned char encode_s2k_iterations (int iterations);
int have_static_passphrase(void); int have_static_passphrase(void);
const char *get_static_passphrase (void); const char *get_static_passphrase (void);
void set_passphrase_from_string(const char *pass); void set_passphrase_from_string(const char *pass);

View File

@ -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); int card_store_subkey (KBNODE node, int use);
#endif #endif
#define S2K_DECODE_COUNT(_val) ((16ul + ((_val) & 15)) << (((_val) >> 4) + 6))
/*-- migrate.c --*/ /*-- migrate.c --*/
void migrate_secring (ctrl_t ctrl); void migrate_secring (ctrl_t ctrl);

View File

@ -48,57 +48,6 @@ static char *next_pw = NULL;
static char *last_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 int
have_static_passphrase() have_static_passphrase()
{ {
@ -106,6 +55,7 @@ have_static_passphrase()
&& (opt.batch || opt.pinentry_mode == PINENTRY_MODE_LOOPBACK)); && (opt.batch || opt.pinentry_mode == PINENTRY_MODE_LOOPBACK));
} }
/* Return a static passphrase. The returned value is only valid as /* Return a static passphrase. The returned value is only valid as
long as no other passphrase related function is called. NULL may long as no other passphrase related function is called. NULL may
be returned if no passphrase has been set; better use 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 call out to gpg-agent and that should not be done during
option processing in main(). */ option processing in main(). */
if (!opt.s2k_count) 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; s2k->count = opt.s2k_count;
} }
} }