From 0c097575a9cd923f648fb5bb695893d46400c3ad Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Fri, 30 Mar 2018 12:48:04 +0900 Subject: [PATCH] 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 --- g10/card-util.c | 48 +++++++++++++++++++++++++++++++---------------- scd/app-openpgp.c | 29 +++++++++++++++++++++------- 2 files changed, 54 insertions(+), 23 deletions(-) diff --git a/g10/card-util.c b/g10/card-util.c index 055c9fbb4..367e31538 100644 --- a/g10/card-util.c +++ b/g10/card-util.c @@ -1978,11 +1978,12 @@ factory_reset (void) #define USER_PIN_DEFAULT "123456" #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. */ 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, 0x82, 0x01, 0x08, @@ -2015,14 +2016,19 @@ gen_kdf_data (unsigned char *data) salt_user = (p += sizeof h1); gcry_randomize (p, 8, GCRY_STRONG_RANDOM); p += 8; - memcpy (p, h2, sizeof h2); - p += sizeof h2; - gcry_randomize (p, 8, GCRY_STRONG_RANDOM); - p += 8; - memcpy (p, h3, sizeof h3); - salt_admin = (p += sizeof h3); - gcry_randomize (p, 8, GCRY_STRONG_RANDOM); - p += 8; + + if (!single_salt) + { + memcpy (p, h2, sizeof h2); + p += sizeof h2; + gcry_randomize (p, 8, GCRY_STRONG_RANDOM); + 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); p += sizeof h4; 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. */ static void -kdf_setup (void) +kdf_setup (const char *args) { struct agent_card_info_s info; 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); @@ -2064,10 +2071,19 @@ kdf_setup (void) goto leave; } - if (!(err = gen_kdf_data (kdf_data)) - && !(err = agent_scd_setattr ("KDF", kdf_data, KDF_DATA_LENGTH, NULL))) - err = agent_scd_getattr ("KDF", &info); + err = gen_kdf_data (kdf_data, single); + if (err) + 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) log_error (_("error for setup KDF: %s\n"), gpg_strerror (err)); @@ -2403,7 +2419,7 @@ card_edit (ctrl_t ctrl, strlist_t commands) break; case cmdKDFSETUP: - kdf_setup (); + kdf_setup (arg_string); break; case cmdKEYATTR: diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 7bbec03ac..ab57d90e6 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -2061,6 +2061,9 @@ get_prompt_info (app_t app, int chvno, unsigned long sigcount, int remaining) 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 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) { gpg_error_t err = 0; - void *relptr; + void *relptr = NULL; unsigned char *buffer; size_t buflen; if (app->app_local->extcap.kdf_do && (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; char dek[32]; + int salt_index; - salt = &buffer[(chvno==3 ? 34 : (chvno==0 ? 24 : 14))]; s2k_count = (((unsigned int)buffer[8] << 24) | (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), GCRY_KDF_ITERSALTED_S2K, 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); wipememory (dek, *r_pinlen); } - - xfree (relptr); - } + } else *r_pinlen = strlen (pinvalue); + leave: + xfree (relptr); return err; }