1
0
mirror of git://git.gnupg.org/gnupg.git synced 2025-03-28 22:49:59 +01:00

g10,scd: Support single salt for KDF data object.

* g10/card-util.c (gen_kdf_data): Support single salt.
(kdf_setup): Can have argument for single salt.
* scd/app-openpgp.c (pin2hash_if_kdf): Support single salt.

--

Gnuk has "admin-less" mode.  To support "admin-less" mode with KDF
feature, salt should be same for user and admin.  Thus, I introduce a
valid use of single salt.

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
This commit is contained in:
NIIBE Yutaka 2018-03-30 12:48:04 +09:00
parent 820380335a
commit 0c097575a9
2 changed files with 54 additions and 23 deletions

View File

@ -1978,11 +1978,12 @@ factory_reset (void)
#define USER_PIN_DEFAULT "123456" #define USER_PIN_DEFAULT "123456"
#define ADMIN_PIN_DEFAULT "12345678" #define ADMIN_PIN_DEFAULT "12345678"
#define KDF_DATA_LENGTH 110 #define KDF_DATA_LENGTH_MIN 90
#define KDF_DATA_LENGTH_MAX 110
/* Generate KDF data. */ /* Generate KDF data. */
static gpg_error_t static gpg_error_t
gen_kdf_data (unsigned char *data) gen_kdf_data (unsigned char *data, int single_salt)
{ {
const unsigned char h0[] = { 0x81, 0x01, 0x03, const unsigned char h0[] = { 0x81, 0x01, 0x03,
0x82, 0x01, 0x08, 0x82, 0x01, 0x08,
@ -2015,14 +2016,19 @@ gen_kdf_data (unsigned char *data)
salt_user = (p += sizeof h1); salt_user = (p += sizeof h1);
gcry_randomize (p, 8, GCRY_STRONG_RANDOM); gcry_randomize (p, 8, GCRY_STRONG_RANDOM);
p += 8; p += 8;
memcpy (p, h2, sizeof h2);
p += sizeof h2; if (!single_salt)
gcry_randomize (p, 8, GCRY_STRONG_RANDOM); {
p += 8; memcpy (p, h2, sizeof h2);
memcpy (p, h3, sizeof h3); p += sizeof h2;
salt_admin = (p += sizeof h3); gcry_randomize (p, 8, GCRY_STRONG_RANDOM);
gcry_randomize (p, 8, GCRY_STRONG_RANDOM); p += 8;
p += 8; memcpy (p, h3, sizeof h3);
salt_admin = (p += sizeof h3);
gcry_randomize (p, 8, GCRY_STRONG_RANDOM);
p += 8;
}
memcpy (p, h4, sizeof h4); memcpy (p, h4, sizeof h4);
p += sizeof h4; p += sizeof h4;
err = gcry_kdf_derive (USER_PIN_DEFAULT, strlen (USER_PIN_DEFAULT), err = gcry_kdf_derive (USER_PIN_DEFAULT, strlen (USER_PIN_DEFAULT),
@ -2043,11 +2049,12 @@ gen_kdf_data (unsigned char *data)
/* Setup KDF data object which is used for PIN authentication. */ /* Setup KDF data object which is used for PIN authentication. */
static void static void
kdf_setup (void) kdf_setup (const char *args)
{ {
struct agent_card_info_s info; struct agent_card_info_s info;
gpg_error_t err; gpg_error_t err;
unsigned char kdf_data[KDF_DATA_LENGTH]; unsigned char kdf_data[KDF_DATA_LENGTH_MAX];
int single = (*args != 0);
memset (&info, 0, sizeof info); memset (&info, 0, sizeof info);
@ -2064,10 +2071,19 @@ kdf_setup (void)
goto leave; goto leave;
} }
if (!(err = gen_kdf_data (kdf_data)) err = gen_kdf_data (kdf_data, single);
&& !(err = agent_scd_setattr ("KDF", kdf_data, KDF_DATA_LENGTH, NULL))) if (err)
err = agent_scd_getattr ("KDF", &info); goto leave_error;
err = agent_scd_setattr ("KDF", kdf_data,
single ? KDF_DATA_LENGTH_MIN : KDF_DATA_LENGTH_MAX,
NULL);
if (err)
goto leave_error;
err = agent_scd_getattr ("KDF", &info);
leave_error:
if (err) if (err)
log_error (_("error for setup KDF: %s\n"), gpg_strerror (err)); log_error (_("error for setup KDF: %s\n"), gpg_strerror (err));
@ -2403,7 +2419,7 @@ card_edit (ctrl_t ctrl, strlist_t commands)
break; break;
case cmdKDFSETUP: case cmdKDFSETUP:
kdf_setup (); kdf_setup (arg_string);
break; break;
case cmdKEYATTR: case cmdKEYATTR:

View File

@ -2061,6 +2061,9 @@ get_prompt_info (app_t app, int chvno, unsigned long sigcount, int remaining)
return result; return result;
} }
#define KDF_DATA_LENGTH_MIN 90
#define KDF_DATA_LENGTH_MAX 110
/* Compute hash if KDF-DO is available. CHVNO must be 0 for reset /* Compute hash if KDF-DO is available. CHVNO must be 0 for reset
code, 1 or 2 for user pin and 3 for admin pin. code, 1 or 2 for user pin and 3 for admin pin.
*/ */
@ -2068,21 +2071,33 @@ static gpg_error_t
pin2hash_if_kdf (app_t app, int chvno, char *pinvalue, int *r_pinlen) pin2hash_if_kdf (app_t app, int chvno, char *pinvalue, int *r_pinlen)
{ {
gpg_error_t err = 0; gpg_error_t err = 0;
void *relptr; void *relptr = NULL;
unsigned char *buffer; unsigned char *buffer;
size_t buflen; size_t buflen;
if (app->app_local->extcap.kdf_do if (app->app_local->extcap.kdf_do
&& (relptr = get_one_do (app, 0x00F9, &buffer, &buflen, NULL)) && (relptr = get_one_do (app, 0x00F9, &buffer, &buflen, NULL))
&& buflen == 110 && (buffer[2] == 0x03)) && buflen >= KDF_DATA_LENGTH_MIN && (buffer[2] == 0x03))
{ {
char *salt; const char *salt;
unsigned long s2k_count; unsigned long s2k_count;
char dek[32]; char dek[32];
int salt_index;
salt = &buffer[(chvno==3 ? 34 : (chvno==0 ? 24 : 14))];
s2k_count = (((unsigned int)buffer[8] << 24) s2k_count = (((unsigned int)buffer[8] << 24)
| (buffer[9] << 16) | (buffer[10] << 8) | buffer[11]); | (buffer[9] << 16) | (buffer[10] << 8) | buffer[11]);
if (buflen == KDF_DATA_LENGTH_MIN)
salt_index =14;
else if (buflen == KDF_DATA_LENGTH_MAX)
salt_index = (chvno==3 ? 34 : (chvno==0 ? 24 : 14));
else
{
err = gpg_error (GPG_ERR_INV_DATA);
goto leave;
}
salt = &buffer[salt_index];
err = gcry_kdf_derive (pinvalue, strlen (pinvalue), err = gcry_kdf_derive (pinvalue, strlen (pinvalue),
GCRY_KDF_ITERSALTED_S2K, GCRY_KDF_ITERSALTED_S2K,
DIGEST_ALGO_SHA256, salt, 8, DIGEST_ALGO_SHA256, salt, 8,
@ -2094,12 +2109,12 @@ pin2hash_if_kdf (app_t app, int chvno, char *pinvalue, int *r_pinlen)
memcpy (pinvalue, dek, *r_pinlen); memcpy (pinvalue, dek, *r_pinlen);
wipememory (dek, *r_pinlen); wipememory (dek, *r_pinlen);
} }
}
xfree (relptr);
}
else else
*r_pinlen = strlen (pinvalue); *r_pinlen = strlen (pinvalue);
leave:
xfree (relptr);
return err; return err;
} }