Implement writable key algorithm attributes
authorNIIBE Yutaka <gniibe@fsij.org>
Fri, 12 Dec 2014 04:11:04 +0000 (13:11 +0900)
committerNIIBE Yutaka <gniibe@fsij.org>
Fri, 12 Dec 2014 04:12:06 +0000 (13:12 +0900)
ChangeLog
src/openpgp-do.c

index 68a363a..59256f1 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2014-11-21  Niibe Yutaka  <gniibe@fsij.org>
+
+       * src/openpgp-do.c (algorithm_attr_rsa2k): Rename from *_rsa.
+       (algorithm_attr_rsa4k): New.
+       (get_algo_attr_pointer, kk_to_nr, gpg_get_algo_attr)
+       (get_algo_attr_data_object, gpg_get_algo_attr_key_size): New.
+       (rw_algorithm_attr): New.
+       (gpg_do_table): Register rw_algorithm_attr for GPG_DO_ALG_*.
+       (gpg_data_scan, gpg_data_copy): Handle algo attributes.
+
+       (rw_pw_status): Fix checking against redundant write.
+
 2014-11-20  Niibe Yutaka  <gniibe@fsij.org>
 
        * src/openpgp-do.c (extended_capabilities): Key attributes can be
index 64162eb..a712c8f 100644 (file)
@@ -85,8 +85,7 @@ uint16_t data_objects_number_of_bytes;
 
 /*
  * Compile time vars:
- *   Historical Bytes (template), Extended Capabilities,
- *   and Algorithm Attributes
+ *   Historical Bytes (template), Extended Capabilities.
  */
 
 /* Historical Bytes (template) */
@@ -126,29 +125,42 @@ static const uint8_t extended_capabilities[] __attribute__ ((aligned (1))) = {
 };
 
 /* Algorithm Attributes */
-static const uint8_t algorithm_attr_rsa[] __attribute__ ((aligned (1))) = {
+#define OPENPGP_ALGO_RSA   0x01
+#define OPENPGP_ALGO_ECDH  0x12
+#define OPENPGP_ALGO_ECDSA 0x13
+#define OPENPGP_ALGO_EDDSA 0x16 /* It catches 22, finally.  */
+
+static const uint8_t algorithm_attr_rsa2k[] __attribute__ ((aligned (1))) = {
   6,
-  0x01, /* RSA */
+  OPENPGP_ALGO_RSA,
   0x08, 0x00,        /* Length modulus (in bit): 2048 */
   0x00, 0x20,        /* Length exponent (in bit): 32  */
-  0x00               /* 0: p&q , 3: CRT with N (not yet supported) */
+  0x00               /* 0: Acceptable format is: P and Q */
+};
+
+static const uint8_t algorithm_attr_rsa4k[] __attribute__ ((aligned (1))) = {
+  6,
+  OPENPGP_ALGO_RSA,
+  0x10, 0x00,        /* Length modulus (in bit): 4096 */
+  0x00, 0x20,        /* Length exponent (in bit): 32  */
+  0x00               /* 0: Acceptable format is: P and Q */
 };
 
 static const uint8_t algorithm_attr_p256r1[] __attribute__ ((aligned (1))) = {
   9,
-  0x13, /* ECDSA */
+  OPENPGP_ALGO_ECDSA,
   0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07 /* OID of NIST curve P-256 */
 };
 
 static const uint8_t algorithm_attr_p256k1[] __attribute__ ((aligned (1))) = {
   6,
-  0x13, /* ECDSA */
+  OPENPGP_ALGO_ECDSA,
   0x2b, 0x81, 0x04, 0x00, 0x0a /* OID of curve secp256k1 */
 };
 
 static const uint8_t algorithm_attr_ed25519[] __attribute__ ((aligned (1))) = {
   10,
-  0x69, /* EdDSA (experimental) */
+  OPENPGP_ALGO_EDDSA,
   /* OID of the curve Ed25519 */
   0x2b, 0x06, 0x01, 0x04, 0x01, 0xda, 0x47, 0x0f, 0x01
 };
@@ -174,6 +186,105 @@ gpg_get_pw1_lifetime (void)
 }
 
 
+/*
+ * Representation of algorithm attributes:
+ *    0: ALGO_ATTR_<>_P == NULL : RSA-2048
+ *    N: ALGO_ATTR_<>_P != NULL : 
+ *
+ */
+static const uint8_t *algo_attr_sig_p;
+static const uint8_t *algo_attr_dec_p;
+static const uint8_t *algo_attr_aut_p;
+
+static const uint8_t **
+get_algo_attr_pointer (enum kind_of_key kk)
+{
+  if (kk == GPG_KEY_FOR_SIGNING)
+    return &algo_attr_sig_p;
+  else if (kk == GPG_KEY_FOR_DECRYPTION)
+    return &algo_attr_dec_p;
+  else
+    return &algo_attr_aut_p;
+}
+
+static int
+kk_to_nr (enum kind_of_key kk)
+{
+  int nr;
+
+  if (kk == GPG_KEY_FOR_SIGNING)
+    nr = NR_KEY_ALGO_ATTR_SIG;
+  else if (kk == GPG_KEY_FOR_DECRYPTION)
+    nr = NR_KEY_ALGO_ATTR_DEC;
+  else
+    nr = NR_KEY_ALGO_ATTR_AUT;
+
+  return nr;
+}
+
+int
+gpg_get_algo_attr (enum kind_of_key kk)
+{
+  const uint8_t *algo_attr_p = *get_algo_attr_pointer (kk);
+
+  if (algo_attr_p == NULL)
+    return ALGO_RSA2K;
+
+  return algo_attr_p[1];
+}
+
+static const uint8_t *
+get_algo_attr_data_object (enum kind_of_key kk)
+{
+  const uint8_t *algo_attr_p = *get_algo_attr_pointer (kk);
+
+  if (algo_attr_p == NULL)
+    return algorithm_attr_rsa2k;
+
+  if (algo_attr_p[1] == ALGO_RSA4K)
+    return algorithm_attr_rsa4k;
+  else if (algo_attr_p[1] == ALGO_NISTP256R1)
+    return algorithm_attr_p256r1;
+  else if (algo_attr_p[1] == ALGO_SECP256K1)
+    return algorithm_attr_p256k1;
+  else if (algo_attr_p[1] == ALGO_ED25519)
+    return algorithm_attr_ed25519;
+
+  return algorithm_attr_rsa2k;
+}
+
+int
+gpg_get_algo_attr_key_size (enum kind_of_key kk, enum size_of_key s)
+{
+  const uint8_t *algo_attr_p = *get_algo_attr_pointer (kk);
+
+  if (algo_attr_p == NULL)
+    if (s == GPG_KEY_STORAGE)
+      return 512;
+    else
+      return 256;
+  else if (algo_attr_p[1] == ALGO_RSA4K)
+    if (s == GPG_KEY_STORAGE)
+      return 1024;
+    else
+      return 512;
+  else if (algo_attr_p[1] == ALGO_NISTP256R1 || algo_attr_p[1] == ALGO_SECP256K1)
+    if (s == GPG_KEY_STORAGE)
+      return 128;
+    else if (s == GPG_KEY_PUBLIC)
+      return 64;
+    else
+      return 32;
+  else                         /* ED25519 */
+    if (s == GPG_KEY_STORAGE)
+      return 128;
+    else if (s == GPG_KEY_PUBLIC)
+      return 32;
+    else
+      return 64;
+}
+
+
 static uint32_t digital_signature_counter;
 
 static const uint8_t *
@@ -525,25 +636,24 @@ rw_pw_status (uint16_t tag, int with_tag,
 {
   if (is_write)
     {
-      (void)len;               /* Should be SIZE_PW_STATUS_BYTES */
+      if (len != 1)
+       return 0;               /* Failure */
 
-      /* Only the first byte of DATA is checked */
-      if (data[0] == 0)
+      /* The first byte of DATA specifies the lifetime.  */
+      if (data[0] == 0 && pw1_lifetime_p != NULL)
        {
          flash_bool_clear (&pw1_lifetime_p);
-         if (pw1_lifetime_p == NULL)
-           return 1;
-         else
+         if (pw1_lifetime_p != NULL) /* No change after update */
            return 0;
        }
-      else
+      else if (pw1_lifetime_p == NULL)
        {
          pw1_lifetime_p = flash_bool_write (NR_BOOL_PW1_LIFETIME);
-         if (pw1_lifetime_p != NULL)
-           return 1;
-         else
+         if (pw1_lifetime_p == NULL) /* No change after update */
            return 0;
        }
+
+      return 1;                        /* Success */
     }
   else
     {
@@ -564,6 +674,78 @@ rw_pw_status (uint16_t tag, int with_tag,
     }
 }
 
+static int
+rw_algorithm_attr (uint16_t tag, int with_tag,
+                  const uint8_t *data, int len, int is_write)
+{
+  enum kind_of_key kk;
+
+  if (tag == GPG_DO_ALG_SIG)
+    kk = GPG_KEY_FOR_SIGNING;
+  else if (tag == GPG_DO_ALG_DEC)
+    kk = GPG_KEY_FOR_DECRYPTION;
+  else
+    kk = GPG_KEY_FOR_AUTHENTICATION;
+
+  if (is_write)
+    {
+      int algo = -1;
+      const uint8_t **algo_attr_pp = get_algo_attr_pointer (kk);
+
+      if (len == 6)
+       {
+         if (memcmp (data, algorithm_attr_rsa2k+1, 6) == 0)
+           algo = ALGO_RSA2K;
+         else if (memcmp (data, algorithm_attr_rsa4k+1, 6) == 0)
+           algo = ALGO_RSA4K;
+         else if ((tag != GPG_DO_ALG_DEC
+                   && memcmp (data, algorithm_attr_p256k1+1, 6) == 0)
+                  || (tag == GPG_DO_ALG_DEC && data[0]==OPENPGP_ALGO_ECDH
+                      && memcmp (data+1, algorithm_attr_p256k1+2, 5) == 0))
+           algo = ALGO_SECP256K1;
+       }
+      else if (len == 9
+              && ((tag != GPG_DO_ALG_DEC
+                   && memcmp (data, algorithm_attr_p256r1+1, 9) == 0)
+                  || (tag == GPG_DO_ALG_DEC && data[0]==OPENPGP_ALGO_ECDH
+                      && memcmp (data+1, algorithm_attr_p256r1+2, 8) == 0)))
+       algo = ALGO_NISTP256R1;
+      else if (len == 10 && memcmp (data, algorithm_attr_ed25519+1, 10) == 0)
+       algo = ALGO_ED25519;
+
+      if (algo < 0)
+       return 0;               /* Error */
+      else if (algo == ALGO_RSA2K && *algo_attr_pp != NULL)
+       {
+         // xxx: make sure there is no key registered
+         flash_enum_clear (algo_attr_pp);
+         if (*algo_attr_pp != NULL)
+           return 0;
+       }
+      else if (*algo_attr_pp == NULL || (*algo_attr_pp)[1] != algo)
+       {
+         int nr = kk_to_nr (kk);
+
+         // xxx: make sure there is no key registered
+         *algo_attr_pp = flash_enum_write (nr, algo);
+         if (*algo_attr_pp == NULL)
+           return 0;
+       }
+
+      return 1;
+    }
+  else
+    {
+      const uint8_t *algo_attr_do = get_algo_attr_data_object (kk);
+
+      copy_do_1 (tag, algo_attr_do, with_tag);
+      /* Override the byte when GPG_DO_ALG_DEC.  */
+      if (tag == GPG_DO_ALG_DEC && algo_attr_do[1] == OPENPGP_ALGO_ECDSA)
+       *(res_p - algo_attr_do[0]) = OPENPGP_ALGO_ECDH;
+      return 1;
+    }
+}
+
 static int
 proc_resetting_code (const uint8_t *data, int len)
 {
@@ -1273,23 +1455,14 @@ gpg_do_table[] = {
   /* Pseudo DO READ/WRITE: calculated */
   { GPG_DO_PW_STATUS, DO_PROC_READWRITE, AC_ALWAYS, AC_ADMIN_AUTHORIZED,
     rw_pw_status },
+  { GPG_DO_ALG_SIG, DO_PROC_READWRITE, AC_ALWAYS, AC_ADMIN_AUTHORIZED,
+    rw_algorithm_attr },
+  { GPG_DO_ALG_DEC, DO_PROC_READWRITE, AC_ALWAYS, AC_ADMIN_AUTHORIZED,
+    rw_algorithm_attr },
+  { GPG_DO_ALG_AUT, DO_PROC_READWRITE, AC_ALWAYS, AC_ADMIN_AUTHORIZED,
+    rw_algorithm_attr },
   /* Fixed data */
   { GPG_DO_EXTCAP, DO_FIXED, AC_ALWAYS, AC_NEVER, extended_capabilities },
-#ifdef RSA_SIG
-  { GPG_DO_ALG_SIG, DO_FIXED, AC_ALWAYS, AC_NEVER, algorithm_attr_rsa },
-#else
-  { GPG_DO_ALG_SIG, DO_FIXED, AC_ALWAYS, AC_NEVER, algorithm_attr_p256k1 },
-#endif
-  { GPG_DO_ALG_DEC, DO_FIXED, AC_ALWAYS, AC_NEVER, algorithm_attr_rsa },
-#if defined(RSA_AUTH)
-  { GPG_DO_ALG_AUT, DO_FIXED, AC_ALWAYS, AC_NEVER, algorithm_attr_rsa },
-#elif defined(ECDSA_AUTH)
-  { GPG_DO_ALG_AUT, DO_FIXED, AC_ALWAYS, AC_NEVER, algorithm_attr_p256r1 },
-#elif defined(EDDSA_AUTH)
-  { GPG_DO_ALG_AUT, DO_FIXED, AC_ALWAYS, AC_NEVER, algorithm_attr_ed25519 },
-#else
-#error "Not supported (AUTH)."
-#endif
   /* Compound data: Read access only */
   { GPG_DO_CH_DATA, DO_CMP_READ, AC_ALWAYS, AC_NEVER, cmp_ch_data },
   { GPG_DO_APP_DATA, DO_CMP_READ, AC_ALWAYS, AC_NEVER, cmp_app_data },
@@ -1326,6 +1499,7 @@ gpg_data_scan (const uint8_t *p_start)
   pw_err_counter_p[PW_ERR_PW1] = NULL;
   pw_err_counter_p[PW_ERR_RC] = NULL;
   pw_err_counter_p[PW_ERR_PW3] = NULL;
+  algo_attr_sig_p = algo_attr_dec_p = algo_attr_aut_p = NULL;
 
   /* Traverse DO, counters, etc. in DATA pool */
   p = p_start;
@@ -1365,13 +1539,29 @@ gpg_data_scan (const uint8_t *p_start)
              case NR_BOOL_PW1_LIFETIME:
                pw1_lifetime_p = p - 1;
                p++;
-               continue;
+               break;
+             case NR_KEY_ALGO_ATTR_SIG:
+               algo_attr_sig_p = p - 1;
+               p++;
+               break;
+             case NR_KEY_ALGO_ATTR_DEC:
+               algo_attr_dec_p = p - 1;
+               p++;
+               break;
+             case NR_KEY_ALGO_ATTR_AUT:
+               algo_attr_aut_p = p - 1;
+               p++;
+               break;
              case NR_COUNTER_123:
                p++;
                if (second_byte <= PW_ERR_PW3)
                  pw_err_counter_p[second_byte] = p;
                p += 2;
                break;
+             default:
+               /* Something going wrong.  ignore this word. */
+               p++;
+               break;
              }
        }
     }
@@ -1432,6 +1622,27 @@ gpg_data_copy (const uint8_t *p_start)
       p += 2;
     }
 
+  if (algo_attr_sig_p != NULL)
+    {
+      flash_enum_write_internal (p, NR_KEY_ALGO_ATTR_SIG, algo_attr_sig_p[1]);
+      algo_attr_sig_p = p;
+      p += 2;
+    }
+
+  if (algo_attr_dec_p != NULL)
+    {
+      flash_enum_write_internal (p, NR_KEY_ALGO_ATTR_DEC, algo_attr_dec_p[1]);
+      algo_attr_dec_p = p;
+      p += 2;
+    }
+
+  if (algo_attr_aut_p != NULL)
+    {
+      flash_enum_write_internal (p, NR_KEY_ALGO_ATTR_AUT, algo_attr_aut_p[1]);
+      algo_attr_aut_p = p;
+      p += 2;
+    }
+
   for (i = 0; i < 3; i++)
     if ((v = flash_cnt123_get_value (pw_err_counter_p[i])) != 0)
       {