Support single-salt KDF for admin-less mode.
authorNIIBE Yutaka <gniibe@fsij.org>
Fri, 30 Mar 2018 01:36:11 +0000 (10:36 +0900)
committerNIIBE Yutaka <gniibe@fsij.org>
Fri, 30 Mar 2018 06:57:34 +0000 (15:57 +0900)
ChangeLog
src/openpgp-do.c

index 623380f..e5b93a8 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2018-03-30  NIIBE Yutaka  <gniibe@fsij.org>
+
+       * src/openpgp-do.c (rw_kdf): Support single-salt KDF.
+       (gpg_do_get_initial_pw_setting): Likewise.
+       (gpg_do_kdf_check): Likewise.
+
 2018-03-22  NIIBE Yutaka  <gniibe@fsij.org>
 
        * src/openpgp-do.c (rw_kdf): Do format validation earlier.
index 4e80c26..09f1336 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * openpgp-do.c -- OpenPGP card Data Objects (DO) handling
  *
- * Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017
+ * Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018
  *               Free Software Initiative of Japan
  * Author: NIIBE Yutaka <gniibe@fsij.org>
  *
@@ -807,7 +807,8 @@ rw_algorithm_attr (uint16_t tag, int with_tag,
     }
 }
 
-#define SIZE_OF_KDF_DO             110
+#define SIZE_OF_KDF_DO_MIN              90
+#define SIZE_OF_KDF_DO_MAX             110
 #define OPENPGP_KDF_ITERSALTED_S2K 3
 #define OPENPGP_SHA256             8
 
@@ -827,19 +828,33 @@ rw_kdf (uint16_t tag, int with_tag, const uint8_t *data, int len, int is_write)
        return 0;
 
       /* The valid data format is:
-        81 01 03 = KDF_ITERSALTED_S2K
-        82 01 08 = SHA256
-        83 04 4-byte... = count
-        84 08 8-byte... = salt user
-        85 08 8-byte... = salt reset-code
-        86 08 8-byte... = salt admin
-        87 20 32-byte user hash
-        88 20 32-byte admin hash
+        Deleting:
+           nothing
+        Minimum (for admin-less):
+          81 01 03 = KDF_ITERSALTED_S2K
+          82 01 08 = SHA256
+          83 04 4-byte... = count
+          84 08 8-byte... = salt
+          87 20 32-byte user hash
+          88 20 32-byte admin hash
+        Full:
+          81 01 03 = KDF_ITERSALTED_S2K
+          82 01 08 = SHA256
+          83 04 4-byte... = count
+          84 08 8-byte... = salt user
+          85 08 8-byte... = salt reset-code
+          86 08 8-byte... = salt admin
+          87 20 32-byte user hash
+          88 20 32-byte admin hash
       */
-      if (len != SIZE_OF_KDF_DO ||
-         !(data[0] == 0x81 && data[3] == 0x82 && data[6] == 0x83
-           && data[12] == 0x84 && data[22] == 0x85 && data[32] == 0x86
-           && data[42] == 0x87 && data[76] == 0x88))
+      if (!(len == 0
+           || (len == SIZE_OF_KDF_DO_MIN &&
+               (data[0] == 0x81 && data[3] == 0x82 && data[6] == 0x83
+                && data[12] == 0x84 && data[22] == 0x87 && data[56] == 0x88))
+           || (len == SIZE_OF_KDF_DO_MAX &&
+               (data[0] == 0x81 && data[3] == 0x82 && data[6] == 0x83
+                && data[12] == 0x84 && data[22] == 0x85 && data[32] == 0x86
+                && data[42] == 0x87 && data[76] == 0x88))))
        return 0;
 
       if (*do_data_p)
@@ -852,7 +867,7 @@ rw_kdf (uint16_t tag, int with_tag, const uint8_t *data, int len, int is_write)
        }
       else
        {
-         *do_data_p = flash_do_write (NR_DO_KDF, data, SIZE_OF_KDF_DO);
+         *do_data_p = flash_do_write (NR_DO_KDF, data, len);
          if (*do_data_p)
            return 1;
          else
@@ -873,10 +888,22 @@ rw_kdf (uint16_t tag, int with_tag, const uint8_t *data, int len, int is_write)
 int
 gpg_do_kdf_check (int len, int how_many)
 {
-  const uint8_t *kdf_spec = gpg_do_read_simple (NR_DO_KDF);
+  const uint8_t *kdf_do = do_ptr[NR_DO_KDF];
 
-  if (kdf_spec && (kdf_spec[43] * how_many) != len)
-    return 0;
+  if (kdf_do)
+    {
+      const uint8_t *kdf_spec = kdf_do+1;
+      int kdf_do_len = kdf_do[0];
+      int hash_len;
+
+      if (kdf_do_len == SIZE_OF_KDF_DO_MAX)      
+       hash_len = kdf_spec[43];
+      else
+       hash_len = kdf_spec[23];
+
+      if ((hash_len * how_many) == len)
+       return 0;
+    }
 
   return 1;
 }
@@ -884,15 +911,29 @@ gpg_do_kdf_check (int len, int how_many)
 void
 gpg_do_get_initial_pw_setting (int is_pw3, int *r_len, const uint8_t **r_p)
 {
-  const uint8_t *kdf_spec = gpg_do_read_simple (NR_DO_KDF);
+  const uint8_t *kdf_do = do_ptr[NR_DO_KDF];
 
-  if (kdf_spec)
+  if (kdf_do)
     {
+      int len = kdf_do[0];
+      const uint8_t *kdf_spec = kdf_do+1;
+
       *r_len = 32;
-      if (is_pw3)
-       *r_p = kdf_spec + 78;
+
+      if (len == SIZE_OF_KDF_DO_MIN)
+       {
+         if (is_pw3)
+           *r_p = kdf_spec + 58;
+         else
+           *r_p = kdf_spec + 24;
+       }
       else
-       *r_p = kdf_spec + 44;
+       {
+         if (is_pw3)
+           *r_p = kdf_spec + 78;
+         else
+           *r_p = kdf_spec + 44;
+       }
     }
   else
     {