g10,scd: Support single salt for KDF data object.
authorNIIBE Yutaka <gniibe@fsij.org>
Fri, 30 Mar 2018 03:48:04 +0000 (12:48 +0900)
committerNIIBE Yutaka <gniibe@fsij.org>
Fri, 30 Mar 2018 03:48:04 +0000 (12:48 +0900)
* 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>
g10/card-util.c
scd/app-openpgp.c

index 055c9fb..367e315 100644 (file)
@@ -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:
index 7bbec03..ab57d90 100644 (file)
@@ -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;
 }