Support modifiable key algo attrs and divert on runtime
authorNIIBE Yutaka <gniibe@fsij.org>
Fri, 12 Dec 2014 04:45:58 +0000 (13:45 +0900)
committerNIIBE Yutaka <gniibe@fsij.org>
Fri, 12 Dec 2014 04:53:29 +0000 (13:53 +0900)
ChangeLog
src/gnuk.h
src/openpgp-do.c
src/openpgp.c

index 59256f1..36e48a4 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,22 @@
+2014-11-21  Niibe Yutaka  <gniibe@fsij.org>
+
+       * src/gnuk.h (ALGO_RSA4K, ALGO_NISTP256R1, ALGO_SECP256K1)
+       (ALGO_ED25519, ALGO_RSA2K): New.
+       (struct key_data_internal): Move to ...
+       * src/openpgp-do.c (struct key_data_internal): ... here.
+       (CHECKSUM_ADDR, kdi_len): New.
+       (CKDC_CALC, CKDC_CHECK): New.
+       (compute_key_data_checksum): Add arg PRVKEY_LEN.
+       (gpg_do_load_prvkey, gpg_do_delete_prvkey): Support modifiable key
+       algo attributes.
+       (gpg_do_write_prvkey, gpg_do_public_key, gpg_do_keygen): Likewise.
+       (gpg_do_clear_prvkey): Use MAX_PRVKEY_LEN.
+
+       * src/openpgp.c (gpg_init): Call flash_init_keys after
+       gpg_data_scan.
+       (cmd_pso): Support modifiable key algo attributes.
+       (cmd_internal_authenticate): Likewise.
+
 2014-11-21  Niibe Yutaka  <gniibe@fsij.org>
 
        * src/openpgp-do.c (algorithm_attr_rsa2k): Rename from *_rsa.
index 8bc8921..67c1ab4 100644 (file)
@@ -109,6 +109,12 @@ void gpg_do_keygen (uint8_t kk_byte);
 
 const uint8_t *gpg_get_firmware_update_key (uint8_t keyno);
 
+/* Constants: algo+size */
+#define ALGO_RSA4K      0
+#define ALGO_NISTP256R1 1
+#define ALGO_SECP256K1  2
+#define ALGO_ED25519    3
+#define ALGO_RSA2K      255
 
 enum kind_of_key {
   GPG_KEY_FOR_SIGNING = 0,
@@ -122,6 +128,9 @@ enum size_of_key {
   GPG_KEY_PRIVATE,
 };
 
+int gpg_get_algo_attr (enum kind_of_key kk);
+int gpg_get_algo_attr_key_size (enum kind_of_key kk, enum size_of_key s);
+
 const uint8_t *flash_init (void);
 void flash_init_keys (void);
 void flash_do_release (const uint8_t *);
@@ -160,18 +169,10 @@ extern uint8_t random_bits_start;
 #define MAX_PRVKEY_LEN 512     /* Maximum is the case for RSA 4096-bit.  */
 
 struct key_data {
-  const uint8_t *pubkey;       /* Pointer to public key*/
+  const uint8_t *pubkey;       /* Pointer to public key */
   uint8_t data[MAX_PRVKEY_LEN]; /* decrypted private key data content */
 };
 
-struct key_data_internal {
-  uint32_t data[KEY_CONTENT_LEN/4]; /*
-                                    * Secret key data.
-                                    * RSA: p and q, ECDSA: d, EdDSA: a+seed
-                                    */
-  uint32_t checksum[DATA_ENCRYPTION_KEY_SIZE/4];
-};
-
 struct prvkey_data {
   /*
    * IV: Initial Vector
@@ -260,11 +261,15 @@ uint8_t *rsa_genkey (int);
 
 int ecdsa_sign_p256r1 (const uint8_t *hash, uint8_t *output,
                       const uint8_t *key_data);
-uint8_t *ecdsa_compute_public_p256r1 (const uint8_t *key_data);
+uint8_t *ecc_compute_public_p256r1 (const uint8_t *key_data);
+int ecdh_decrypt_p256r1 (const uint8_t *input, uint8_t *output,
+                        const uint8_t *key_data);
 
 int ecdsa_sign_p256k1 (const uint8_t *hash, uint8_t *output,
                       const uint8_t *key_data);
-uint8_t *ecdsa_compute_public_p256k1 (const uint8_t *key_data);
+uint8_t *ecc_compute_public_p256k1 (const uint8_t *key_data);
+int ecdh_decrypt_p256k1 (const uint8_t *input, uint8_t *output,
+                        const uint8_t *key_data);
 
 int eddsa_sign_25519 (const uint8_t *input, size_t ilen, uint32_t *output,
                      const uint8_t *sk_a, const uint8_t *seed,
index a712c8f..f0b2490 100644 (file)
@@ -861,26 +861,42 @@ get_do_ptr_nr_for_kk (enum kind_of_key kk)
 void
 gpg_do_clear_prvkey (enum kind_of_key kk)
 {
-  memset (kd[kk].data, 0, KEY_CONTENT_LEN);
+  memset (kd[kk].data, 0, MAX_PRVKEY_LEN);
 }
 
 
+#define CHECKSUM_ADDR(kdi,prvkey_len) \
+       (&(kdi).data[prvkey_len / sizeof (uint32_t)])
+#define kdi_len(prvkey_len) (prvkey_len+DATA_ENCRYPTION_KEY_SIZE)
+struct key_data_internal {
+  uint32_t data[(MAX_PRVKEY_LEN+DATA_ENCRYPTION_KEY_SIZE) / sizeof (uint32_t)];
+  /*
+   * Secret key data.
+   * RSA: p and q, ECDSA/ECDH: d, EdDSA: a+seed
+   */
+  /* Checksum */
+};
+
+#define CKDC_CALC  0
+#define CKDC_CHECK 1
 static int
-compute_key_data_checksum (struct key_data_internal *kdi, int check_or_calc)
+compute_key_data_checksum (struct key_data_internal *kdi, int prvkey_len,
+                          int check_or_calc)
 {
   unsigned int i;
   uint32_t d[4] = { 0, 0, 0, 0 };
+  uint32_t *checksum = CHECKSUM_ADDR (*kdi, prvkey_len);
 
-  for (i = 0; i < KEY_CONTENT_LEN / sizeof (uint32_t); i++)
+  for (i = 0; i < prvkey_len / sizeof (uint32_t); i++)
     d[i&3] ^= kdi->data[i];
 
-  if (check_or_calc == 0)      /* store */
+  if (check_or_calc == CKDC_CALC)      /* store */
     {
-      memcpy (kdi->checksum, d, DATA_ENCRYPTION_KEY_SIZE);
+      memcpy (checksum, d, DATA_ENCRYPTION_KEY_SIZE);
       return 0;
     }
   else                         /* check */
-    return memcmp (kdi->checksum, d, DATA_ENCRYPTION_KEY_SIZE) == 0;
+    return memcmp (checksum, d, DATA_ENCRYPTION_KEY_SIZE) == 0;
 }
 
 /*
@@ -892,6 +908,7 @@ int
 gpg_do_load_prvkey (enum kind_of_key kk, int who, const uint8_t *keystring)
 {
   uint8_t nr = get_do_ptr_nr_for_kk (kk);
+  int prvkey_len = gpg_get_algo_attr_key_size (kk, GPG_KEY_PRIVATE);
   const uint8_t *do_data = do_ptr[nr];
   const uint8_t *key_addr;
   uint8_t dek[DATA_ENCRYPTION_KEY_SIZE];
@@ -904,24 +921,25 @@ gpg_do_load_prvkey (enum kind_of_key kk, int who, const uint8_t *keystring)
   if (do_data == NULL)
     return 0;
 
-  key_addr = kd[kk].key_addr;
-  memcpy (kdi.data, key_addr, KEY_CONTENT_LEN);
+  key_addr = kd[kk].pubkey - prvkey_len;
+  memcpy (kdi.data, key_addr, prvkey_len);
   iv = &do_data[1];
-  memcpy (kdi.checksum, iv + INITIAL_VECTOR_SIZE, DATA_ENCRYPTION_KEY_SIZE);
+  memcpy (CHECKSUM_ADDR (kdi, prvkey_len),
+         iv + INITIAL_VECTOR_SIZE, DATA_ENCRYPTION_KEY_SIZE);
 
-  memcpy (dek, iv+16*(who+1), DATA_ENCRYPTION_KEY_SIZE);
+  memcpy (dek, iv + DATA_ENCRYPTION_KEY_SIZE*(who+1), DATA_ENCRYPTION_KEY_SIZE);
   decrypt_dek (keystring, dek);
 
-  decrypt (dek, iv, (uint8_t *)&kdi, sizeof (struct key_data_internal));
+  decrypt (dek, iv, (uint8_t *)&kdi, kdi_len (prvkey_len));
   memset (dek, 0, DATA_ENCRYPTION_KEY_SIZE);
-  if (!compute_key_data_checksum (&kdi, 1))
+  if (!compute_key_data_checksum (&kdi, prvkey_len, CKDC_CHECK))
     {
       DEBUG_INFO ("gpg_do_load_prvkey failed.\r\n");
       return -1;
     }
 
-  memcpy (kd[kk].data, kdi.data, KEY_CONTENT_LEN);
-  DEBUG_BINARY (kd[kk].data, KEY_CONTENT_LEN);
+  memcpy (kd[kk].data, kdi.data, prvkey_len);
+  DEBUG_BINARY (kd[kk].data, prvkey_len);
   return 1;
 }
 
@@ -934,15 +952,17 @@ gpg_do_delete_prvkey (enum kind_of_key kk)
   uint8_t nr = get_do_ptr_nr_for_kk (kk);
   const uint8_t *do_data = do_ptr[nr];
   uint8_t *key_addr;
+  int prvkey_len = gpg_get_algo_attr_key_size (kk, GPG_KEY_PRIVATE);
+  int key_size = gpg_get_algo_attr_key_size (kk, GPG_KEY_STORAGE);
 
   if (do_data == NULL)
     return;
 
   do_ptr[nr] = NULL;
   flash_do_release (do_data);
-  key_addr = kd[kk].key_addr;
-  kd[kk].key_addr = NULL;
-  flash_key_release (key_addr);
+  key_addr = (uint8_t *)kd[kk].pubkey - prvkey_len;
+  kd[kk].pubkey = NULL;
+  flash_key_release (key_addr, key_size);
 
   if (admin_authorized == BY_ADMIN && kk == GPG_KEY_FOR_SIGNING)
     {                  /* Recover admin keystring DO.  */
@@ -973,10 +993,12 @@ gpg_do_delete_prvkey (enum kind_of_key kk)
 }
 
 static int
-gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
-                    const uint8_t *keystring_admin, const uint8_t *pubkey)
+gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data,
+                    int prvkey_len, const uint8_t *keystring_admin,
+                    const uint8_t *pubkey)
 {
   uint8_t nr = get_do_ptr_nr_for_kk (kk);
+  int attr = gpg_get_algo_attr (kk);;
   const uint8_t *p;
   int r;
   struct prvkey_data *pd;
@@ -984,86 +1006,52 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
   const uint8_t *dek, *iv;
   struct key_data_internal kdi;
   uint8_t *pubkey_allocated_here = NULL;
-  int pubkey_len = KEY_CONTENT_LEN;
+  int pubkey_len;
   uint8_t ks[KEYSTRING_MD_SIZE];
   enum kind_of_key kk0;
 
   DEBUG_INFO ("Key import\r\n");
-  DEBUG_SHORT (key_len);
+  DEBUG_SHORT (prvkey_len);
 
   /* Delete it first, if any.  */
   gpg_do_delete_prvkey (kk);
 
-#if defined(RSA_AUTH) && defined(RSA_SIG)
-  if (key_len != KEY_CONTENT_LEN)
-     return -1;
-#elif defined(RSA_AUTH) && !defined(RSA_SIG)
-  /* ECDSA with p256k1 for signature */
-  if (kk != GPG_KEY_FOR_SIGNING && key_len != KEY_CONTENT_LEN)
+  pd = (struct prvkey_data *)malloc (sizeof (struct prvkey_data));
+  if (pd == NULL)
     return -1;
-  if (kk == GPG_KEY_FOR_SIGNING)
+
+  if (attr == ALGO_NISTP256R1 || attr == ALGO_SECP256K1)
     {
-      pubkey_len = key_len * 2;
-      if (key_len != 32)
+      pubkey_len = prvkey_len * 2;
+      if (prvkey_len != 32)
        return -1;
     }
-#elif !defined(RSA_AUTH) && defined(RSA_SIG)
-#if defined(ECDSA_AUTH)
-  /* ECDSA with p256r1 for authentication */
-  if (kk != GPG_KEY_FOR_AUTHENTICATION && key_len != KEY_CONTENT_LEN)
-    return -1;
-  if (kk == GPG_KEY_FOR_AUTHENTICATION)
+  else if (attr == ALGO_ED25519)
     {
-      pubkey_len = key_len * 2;
-      if (key_len != 32)
+      pubkey_len = prvkey_len / 2;
+      if (prvkey_len != 64)
        return -1;
     }
-#else
-  /* EdDSA with Ed25519 for authentication */
-  if (kk != GPG_KEY_FOR_AUTHENTICATION && key_len != KEY_CONTENT_LEN)
-    return -1;
-  if (kk == GPG_KEY_FOR_AUTHENTICATION)
+  else                         /* RSA */
     {
-      pubkey_len = key_len / 2;
-      if (key_len != 64)
+      int key_size = gpg_get_algo_attr_key_size (kk, GPG_KEY_STORAGE);
+
+      pubkey_len = prvkey_len;
+      if (prvkey_len + pubkey_len != key_size)
        return -1;
     }
-#endif
-#else
-#error "not supported."
-#endif
-
-  pd = (struct prvkey_data *)malloc (sizeof (struct prvkey_data));
-  if (pd == NULL)
-    return -1;
 
   if (pubkey == NULL)
     {
-#if defined(RSA_AUTH) && defined(RSA_SIG)
-      pubkey_allocated_here = modulus_calc (key_data, key_len);
-#elif defined(RSA_AUTH) && !defined(RSA_SIG)
-      /* ECDSA with p256k1 for signature */
-      if (kk == GPG_KEY_FOR_SIGNING)
-       pubkey_allocated_here = ecdsa_compute_public_p256k1 (key_data);
-      else
-       pubkey_allocated_here = modulus_calc (key_data, key_len);
-#elif !defined(RSA_AUTH) && defined(RSA_SIG)
-#if defined(ECDSA_AUTH)
-      /* ECDSA with p256r1 for authentication */
-      if (kk == GPG_KEY_FOR_AUTHENTICATION)
-       pubkey_allocated_here = ecdsa_compute_public_p256r1 (key_data);
-      else
-       pubkey_allocated_here = modulus_calc (key_data, key_len);
-#else
-      /* EdDSA with Ed25519 for authentication */
-      if (kk == GPG_KEY_FOR_AUTHENTICATION)
+      if (attr == ALGO_SECP256K1)
+       pubkey_allocated_here = ecc_compute_public_p256k1 (key_data);
+      else if (attr == ALGO_NISTP256R1)
+       pubkey_allocated_here = ecc_compute_public_p256r1 (key_data);
+      else if (attr == ALGO_ED25519)
        pubkey_allocated_here = eddsa_compute_public_25519 (key_data);
-      else
-       pubkey_allocated_here = modulus_calc (key_data, key_len);
-#endif
-#else
-#error "not supported."
-#endif
+      else                             /* RSA */
+       pubkey_allocated_here = modulus_calc (key_data, prvkey_len);
+
       if (pubkey_allocated_here == NULL)
        {
          free (pd);
@@ -1083,38 +1071,17 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
       free (pd);
       return -1;
     }
-  kd[kk].key_addr = key_addr;
+  kd[kk].pubkey = key_addr + prvkey_len;
 
   num_prv_keys++;
 
   DEBUG_INFO ("key_addr: ");
   DEBUG_WORD ((uint32_t)key_addr);
 
-#if defined(RSA_AUTH) && defined(RSA_SIG)
-  memcpy (kdi.data, key_data, KEY_CONTENT_LEN);
-#elif defined(RSA_AUTH) && !defined(RSA_SIG)
-  /* ECDSA with p256k1 for signature */
-  if (kk == GPG_KEY_FOR_SIGNING)
-    {
-      memcpy (kdi.data, key_data, key_len);
-      memset ((uint8_t *)kdi.data + key_len, 0, KEY_CONTENT_LEN - key_len);
-    }
-  else
-    memcpy (kdi.data, key_data, KEY_CONTENT_LEN);
-#elif !defined(RSA_AUTH) && defined(RSA_SIG)
-  /* ECDSA with p256r1 for authentication */
-  /* EdDSA with Ed25519 for authentication */
-  if (kk == GPG_KEY_FOR_AUTHENTICATION)
-    {
-      memcpy (kdi.data, key_data, key_len);
-      memset ((uint8_t *)kdi.data + key_len, 0, KEY_CONTENT_LEN - key_len);
-    }
-  else
-    memcpy (kdi.data, key_data, KEY_CONTENT_LEN);
-#else
-#error "not supported."
-#endif
-  compute_key_data_checksum (&kdi, 0);
+  memcpy (kdi.data, key_data, prvkey_len);
+  memset ((uint8_t *)kdi.data + prvkey_len, 0, MAX_PRVKEY_LEN - prvkey_len);
+
+  compute_key_data_checksum (&kdi, prvkey_len, CKDC_CALC);
 
   dek = random_bytes_get (); /* 32-byte random bytes */
   iv = dek + DATA_ENCRYPTION_KEY_SIZE;
@@ -1136,9 +1103,9 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
        gpg_do_chks_prvkey (kk0, BY_RESETCODE, NULL, 0, NULL);
       }
 
-  encrypt (dek, iv, (uint8_t *)&kdi, sizeof (struct key_data_internal));
+  encrypt (dek, iv, (uint8_t *)&kdi, kdi_len (prvkey_len));
 
-  r = flash_key_write (key_addr, (const uint8_t *)kdi.data,
+  r = flash_key_write (key_addr, (const uint8_t *)kdi.data, prvkey_len,
                       pubkey_allocated_here? pubkey_allocated_here: pubkey,
                       pubkey_len);
   if (pubkey_allocated_here)
@@ -1156,7 +1123,8 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
     }
 
   memcpy (pd->iv, iv, INITIAL_VECTOR_SIZE);
-  memcpy (pd->checksum_encrypted, kdi.checksum, DATA_ENCRYPTION_KEY_SIZE);
+  memcpy (pd->checksum_encrypted, CHECKSUM_ADDR (kdi, prvkey_len),
+         DATA_ENCRYPTION_KEY_SIZE);
 
   encrypt_dek (ks, pd->dek_encrypted_1);
 
@@ -1916,15 +1884,15 @@ gpg_do_put_data (uint16_t tag, const uint8_t *data, int len)
 void
 gpg_do_public_key (uint8_t kk_byte)
 {
-  const uint8_t *key_addr;
-  enum kind_of_key kk;
+  enum kind_of_key kk = kkb_to_kk (kk_byte);
+  int attr = gpg_get_algo_attr (kk);
+  int pubkey_len = gpg_get_algo_attr_key_size (kk, GPG_KEY_PUBLIC);
+  const uint8_t *pubkey = kd[kk].pubkey;
 
   DEBUG_INFO ("Public key\r\n");
   DEBUG_BYTE (kk_byte);
 
-  kk = kkb_to_kk (kk_byte);
-  key_addr = kd[kk].key_addr;
-  if (key_addr == NULL)
+  if (pubkey == NULL)
     {
       DEBUG_INFO ("none.\r\n");
       GPG_NO_RECORD ();
@@ -1936,20 +1904,8 @@ gpg_do_public_key (uint8_t kk_byte)
   /* TAG */
   *res_p++ = 0x7f; *res_p++ = 0x49;
 
-#if defined(RSA_AUTH) && defined(RSA_SIG)
-  if (0)
-#elif defined(RSA_AUTH) && !defined(RSA_SIG)
-  /* ECDSA with p256k1 for signature */
-  if (kk_byte == 0xb6)
-#elif !defined(RSA_AUTH) && defined(RSA_SIG)
-  /* ECDSA with p256r1 for authentication */
-  /* EdDSA with Ed25519 for authentication */
-  if (kk_byte == 0xa4)
-#else
-#error "not supported."
-#endif
-#if defined(ECDSA_AUTH)
-    {                          /* ECDSA */
+  if (attr == ALGO_NISTP256R1 || attr == ALGO_SECP256K1)
+    {                          /* ECDSA or ECDH */
       /* LEN */
       *res_p++ = 2 + 1 + 64;
       {
@@ -1957,11 +1913,11 @@ gpg_do_public_key (uint8_t kk_byte)
        *res_p++ = 0x86; *res_p++ = 0x41;
        *res_p++ = 0x04;        /* No compression of EC point.  */
        /* 64-byte binary (big endian): X || Y */
-       memcpy (res_p, key_addr + KEY_CONTENT_LEN, 64);
+       memcpy (res_p, pubkey, 64);
        res_p += 64;
       }
     }
-#else  /* EDDSA_AUTH */
+  else if (attr == ALGO_ED25519)
     {                          /* EdDSA */
       /* LEN */
       *res_p++ = 2 + 32;
@@ -1969,22 +1925,22 @@ gpg_do_public_key (uint8_t kk_byte)
        /*TAG*/          /* LEN = 32 */
        *res_p++ = 0x86; *res_p++ = 0x20;
        /* 32-byte binary (little endian): Y with parity */
-       memcpy (res_p, key_addr + KEY_CONTENT_LEN, 32);
+       memcpy (res_p, pubkey, 32);
        res_p += 32;
       }
     }
-#endif
   else
     {                          /* RSA */
-      /* LEN = 9+256 */
-      *res_p++ = 0x82; *res_p++ = 0x01; *res_p++ = 0x09;
+      /* LEN = 9+256or512 */
+      *res_p++ = 0x82; *res_p++ = pubkey_len > 256? 0x02: 0x01; *res_p++ = 0x09;
 
       {
-       /*TAG*/          /* LEN = 256 */
-       *res_p++ = 0x81; *res_p++ = 0x82; *res_p++ = 0x01; *res_p++ = 0x00;
-       /* 256-byte binary (big endian) */
-       memcpy (res_p, key_addr + KEY_CONTENT_LEN, KEY_CONTENT_LEN);
-       res_p += 256;
+       /*TAG*/          /* LEN = 256or512 */
+       *res_p++ = 0x81;
+       *res_p++ = 0x82; *res_p++ = pubkey_len > 256? 0x02: 0x01;*res_p++ = 0x00;
+       /* PUBKEY_LEN-byte binary (big endian) */
+       memcpy (res_p, pubkey, pubkey_len);
+       res_p += pubkey_len;
       }
       {
        /*TAG*/          /* LEN= 3 */
@@ -2038,7 +1994,8 @@ gpg_do_write_simple (uint8_t nr, const uint8_t *data, int size)
 void
 gpg_do_keygen (uint8_t kk_byte)
 {
-  enum kind_of_key kk;
+  enum kind_of_key kk = kkb_to_kk (kk_byte);
+  int pubkey_len = gpg_get_algo_attr_key_size (kk, GPG_KEY_PUBLIC);
   const uint8_t *keystring_admin;
   uint8_t *p_q_modulus;
   const uint8_t *p_q;
@@ -2048,13 +2005,12 @@ gpg_do_keygen (uint8_t kk_byte)
   DEBUG_INFO ("Keygen\r\n");
   DEBUG_BYTE (kk_byte);
 
-  kk = kkb_to_kk (kk_byte);
   if (admin_authorized == BY_ADMIN)
     keystring_admin = keystring_md_pw3;
   else
     keystring_admin = NULL;
 
-  p_q_modulus = rsa_genkey ();
+  p_q_modulus = rsa_genkey (pubkey_len);
   if (p_q_modulus == NULL)
     {
       GPG_MEMORY_FAILURE ();
@@ -2062,10 +2018,10 @@ gpg_do_keygen (uint8_t kk_byte)
     }
 
   p_q = p_q_modulus;
-  modulus = p_q_modulus + KEY_CONTENT_LEN;
+  modulus = p_q_modulus + pubkey_len;
 
-  r = gpg_do_write_prvkey (kk, p_q, KEY_CONTENT_LEN, keystring_admin, modulus);
-  memset (p_q_modulus, 0, KEY_CONTENT_LEN*2);
+  r = gpg_do_write_prvkey (kk, p_q, pubkey_len, keystring_admin, modulus);
+  memset (p_q_modulus, 0, pubkey_len * 2);
   free (p_q_modulus);
   if (r < 0)
     {
index c825fa3..e1d1203 100644 (file)
@@ -107,6 +107,7 @@ gpg_init (void)
   file_selection = FILE_NONE;
   flash_data_start = flash_init ();
   gpg_data_scan (flash_data_start);
+  flash_init_keys ();
 }
 
 static void
@@ -815,14 +816,21 @@ static void
 cmd_pso (void)
 {
   int len = apdu.cmd_apdu_data_len;
-  int r;
+  int r = -1;
+  int attr;
+  int pubkey_len;
 
   DEBUG_INFO (" - PSO: ");
   DEBUG_WORD ((uint32_t)&r);
   DEBUG_BINARY (apdu.cmd_apdu_data, apdu.cmd_apdu_data_len);
+  DEBUG_SHORT (len);
 
   if (P1 (apdu) == 0x9e && P2 (apdu) == 0x9a)
     {
+      attr = gpg_get_algo_attr (GPG_KEY_FOR_SIGNING);
+      pubkey_len = gpg_get_algo_attr_key_size (GPG_KEY_FOR_SIGNING,
+                                              GPG_KEY_PUBLIC);
+
       if (!ac_check_status (AC_PSO_CDS_AUTHORIZED))
        {
          DEBUG_INFO ("security error.");
@@ -830,64 +838,81 @@ cmd_pso (void)
          return;
        }
 
-#ifdef RSA_SIG
-      /* Check size of digestInfo */
-      if (len != 34            /* MD5 */
-         && len != 35          /* SHA1 / RIPEMD-160 */
-         && len != 47          /* SHA224 */
-         && len != 51          /* SHA256 */
-         && len != 67          /* SHA384 */
-         && len != 83)         /* SHA512 */
-       {
-         DEBUG_INFO (" wrong length: ");
-         DEBUG_SHORT (len);
-         GPG_ERROR ();
-       }
-      else
+      if (attr == ALGO_RSA2K || attr == ALGO_RSA4K)
        {
-         DEBUG_SHORT (len);
-         DEBUG_BINARY (kd[GPG_KEY_FOR_SIGNING].data, KEY_CONTENT_LEN);
+         /* Check size of digestInfo */
+         if (len != 34         /* MD5 */
+             && len != 35              /* SHA1 / RIPEMD-160 */
+             && len != 47              /* SHA224 */
+             && len != 51              /* SHA256 */
+             && len != 67              /* SHA384 */
+             && len != 83)             /* SHA512 */
+           {
+             DEBUG_INFO (" wrong length");
+             GPG_CONDITION_NOT_SATISFIED ();
+             return;
+           }
+
+         DEBUG_BINARY (kd[GPG_KEY_FOR_SIGNING].data, pubkey_len);
 
          r = rsa_sign (apdu.cmd_apdu_data, res_APDU, len,
-                       &kd[GPG_KEY_FOR_SIGNING]);
+                       &kd[GPG_KEY_FOR_SIGNING], pubkey_len);
          if (r < 0)
-           {
-             ac_reset_pso_cds ();
-             GPG_ERROR ();
-           }
+           ac_reset_pso_cds ();
          else
            /* Success */
            gpg_increment_digital_signature_counter ();
        }
-#else
-      /* ECDSA with p256k1 for signature */
-      if (len != ECDSA_HASH_LEN)
+      else if (attr == ALGO_NISTP256R1 || attr == ALGO_SECP256K1)
        {
-         DEBUG_INFO (" wrong length: ");
-         GPG_CONDITION_NOT_SATISFIED ();
+         /* ECDSA with p256r1/p256k1 for signature */
+         if (len != ECDSA_HASH_LEN)
+           {
+             DEBUG_INFO (" wrong length");
+             GPG_CONDITION_NOT_SATISFIED ();
+             return;
+           }
+
+         if (attr == ALGO_NISTP256R1)
+           r = ecdsa_sign_p256r1 (apdu.cmd_apdu_data, res_APDU,
+                                  kd[GPG_KEY_FOR_SIGNING].data);
+         else                  /* ALGO_SECP256K1 */
+           r = ecdsa_sign_p256k1 (apdu.cmd_apdu_data, res_APDU,
+                                  kd[GPG_KEY_FOR_SIGNING].data);
+         if (r < 0)
+           ac_reset_pso_cds ();
+         else
+           {                   /* Success */
+             gpg_increment_digital_signature_counter ();
+             res_APDU_size = ECDSA_SIGNATURE_LENGTH;
+           }
        }
-      else
+      else if (attr == ALGO_ED25519)
        {
-         DEBUG_SHORT (len);
+         uint32_t output[64/4];        /* Require 4-byte alignment. */
 
-         res_APDU_size = ECDSA_SIGNATURE_LENGTH;
-         r = ecdsa_sign_p256k1 (apdu.cmd_apdu_data, res_APDU,
-                                kd[GPG_KEY_FOR_SIGNING].data);
-         if (r < 0)
+         if (len > EDDSA_HASH_LEN_MAX)
            {
-             ac_reset_pso_cds ();
-             GPG_ERROR ();
+             DEBUG_INFO ("wrong hash length.");
+             GPG_CONDITION_NOT_SATISFIED ();
+             return;
            }
-         else
-           /* Success */
-           gpg_increment_digital_signature_counter ();
+
+         res_APDU_size = EDDSA_SIGNATURE_LENGTH;
+         r = eddsa_sign_25519 (apdu.cmd_apdu_data, len, output,
+                               kd[GPG_KEY_FOR_AUTHENTICATION].data,
+                               kd[GPG_KEY_FOR_AUTHENTICATION].data+32,
+                               kd[GPG_KEY_FOR_AUTHENTICATION].pubkey);
+         memcpy (res_APDU, output, EDDSA_SIGNATURE_LENGTH);
        }
-#endif
     }
   else if (P1 (apdu) == 0x80 && P2 (apdu) == 0x86)
     {
-      DEBUG_SHORT (len);
-      DEBUG_BINARY (kd[GPG_KEY_FOR_DECRYPTION].data, KEY_CONTENT_LEN);
+      attr = gpg_get_algo_attr (GPG_KEY_FOR_DECRYPTION);
+      pubkey_len = gpg_get_algo_attr_key_size (GPG_KEY_FOR_DECRYPTION,
+                                              GPG_KEY_PUBLIC);
+
+      DEBUG_BINARY (kd[GPG_KEY_FOR_DECRYPTION].data, pubkey_len);
 
       if (!ac_check_status (AC_OTHER_AUTHORIZED))
        {
@@ -896,19 +921,40 @@ cmd_pso (void)
          return;
        }
 
-      /* Skip padding 0x00 */
-      len--;
-      if (len != KEY_CONTENT_LEN)
-       GPG_CONDITION_NOT_SATISFIED ();
-      else
+      if (attr == ALGO_RSA2K || attr == ALGO_RSA4K)
        {
+         /* Skip padding 0x00 */
+         len--;
+         if (len != pubkey_len)
+           {
+             GPG_CONDITION_NOT_SATISFIED ();
+             return;
+           }
          r = rsa_decrypt (apdu.cmd_apdu_data+1, res_APDU, len,
                           &kd[GPG_KEY_FOR_DECRYPTION]);
-         if (r < 0)
-           GPG_ERROR ();
+       }
+      else if (attr == ALGO_NISTP256R1 || attr == ALGO_SECP256K1)
+       {
+         /* Format is in big endian MPI: 04 || x || y */
+         if (len != 65 || apdu.cmd_apdu_data[0] != 4)
+           {
+             GPG_CONDITION_NOT_SATISFIED ();
+             return;
+           }
+
+         if (attr == ALGO_NISTP256R1)
+           r = ecdh_decrypt_p256r1 (apdu.cmd_apdu_data, res_APDU,
+                                    kd[GPG_KEY_FOR_DECRYPTION].data);
+         else
+           r = ecdh_decrypt_p256k1 (apdu.cmd_apdu_data, res_APDU,
+                                    kd[GPG_KEY_FOR_DECRYPTION].data);
+
+         if (r == 0)
+           res_APDU_size = 65;
        }
     }
-  else
+
+  if (r < 0)
     {
       DEBUG_INFO (" - ??");
       DEBUG_BYTE (P1 (apdu));
@@ -921,70 +967,50 @@ cmd_pso (void)
 }
 
 
-#if defined(RSA_AUTH)
-#define MAX_DIGEST_INFO_LEN 102 /* 40% */
+#define MAX_RSA_DIGEST_INFO_LEN 102 /* 40% */
 static void
 cmd_internal_authenticate (void)
 {
+  int attr = gpg_get_algo_attr (GPG_KEY_FOR_AUTHENTICATION);
+  int pubkey_len = gpg_get_algo_attr_key_size (GPG_KEY_FOR_AUTHENTICATION,
+                                              GPG_KEY_PUBLIC);
   int len = apdu.cmd_apdu_data_len;
-  int r;
+  int r = -1;
 
   DEBUG_INFO (" - INTERNAL AUTHENTICATE\r\n");
 
-  if (P1 (apdu) == 0x00 && P2 (apdu) == 0x00)
-    {
-      DEBUG_SHORT (len);
-
-      if (!ac_check_status (AC_OTHER_AUTHORIZED))
-       {
-         DEBUG_INFO ("security error.");
-         GPG_SECURITY_FAILURE ();
-         return;
-       }
-
-      if (len > MAX_DIGEST_INFO_LEN)
-       {
-         DEBUG_INFO ("input is too long.");
-         GPG_CONDITION_NOT_SATISFIED ();
-         return;
-       }
-
-      r = rsa_sign (apdu.cmd_apdu_data, res_APDU, len,
-                   &kd[GPG_KEY_FOR_AUTHENTICATION]);
-      if (r < 0)
-       GPG_ERROR ();
-    }
-  else
+  if (P1 (apdu) != 0x00 || P2 (apdu) != 0x00)
     {
       DEBUG_INFO (" - ??");
       DEBUG_BYTE (P1 (apdu));
       DEBUG_INFO (" - ??");
       DEBUG_BYTE (P2 (apdu));
-      GPG_ERROR ();
+      GPG_CONDITION_NOT_SATISFIED ();
+      return;
     }
 
-  DEBUG_INFO ("INTERNAL AUTHENTICATE done.\r\n");
-}
-#elif defined(ECDSA_AUTH)
-static void
-cmd_internal_authenticate (void)
-{
-  int len = apdu.cmd_apdu_data_len;
-  int r;
-
-  DEBUG_INFO (" - INTERNAL AUTHENTICATE\r\n");
-
-  if (P1 (apdu) == 0x00 && P2 (apdu) == 0x00)
+  DEBUG_SHORT (len);
+  if (!ac_check_status (AC_OTHER_AUTHORIZED))
     {
-      DEBUG_SHORT (len);
+      DEBUG_INFO ("security error.");
+      GPG_SECURITY_FAILURE ();
+      return;
+    }
 
-      if (!ac_check_status (AC_OTHER_AUTHORIZED))
+  if (attr == ALGO_RSA2K || attr == ALGO_RSA4K)
+    {
+      if (len > MAX_RSA_DIGEST_INFO_LEN)
        {
-         DEBUG_INFO ("security error.");
-         GPG_SECURITY_FAILURE ();
+         DEBUG_INFO ("input is too long.");
+         GPG_CONDITION_NOT_SATISFIED ();
          return;
        }
 
+      r = rsa_sign (apdu.cmd_apdu_data, res_APDU, len,
+                   &kd[GPG_KEY_FOR_AUTHENTICATION], pubkey_len);
+    }    
+  else if (attr == ALGO_NISTP256R1)
+    {
       if (len != ECDSA_HASH_LEN)
        {
          DEBUG_INFO ("wrong hash length.");
@@ -995,42 +1021,24 @@ cmd_internal_authenticate (void)
       res_APDU_size = ECDSA_SIGNATURE_LENGTH;
       r = ecdsa_sign_p256r1 (apdu.cmd_apdu_data, res_APDU,
                             kd[GPG_KEY_FOR_AUTHENTICATION].data);
-      if (r < 0)
-       GPG_ERROR ();
     }
-  else
+  else if (attr == ALGO_SECP256K1)
     {
-      DEBUG_INFO (" - ??");
-      DEBUG_BYTE (P1 (apdu));
-      DEBUG_INFO (" - ??");
-      DEBUG_BYTE (P2 (apdu));
-      GPG_ERROR ();
-    }
-
-  DEBUG_INFO ("INTERNAL AUTHENTICATE done.\r\n");
-}
-#elif defined(EDDSA_AUTH)
-static void
-cmd_internal_authenticate (void)
-{
-  int len = apdu.cmd_apdu_data_len;
-  int r;
-
-  DEBUG_INFO (" - INTERNAL AUTHENTICATE\r\n");
-
-  if (P1 (apdu) == 0x00 && P2 (apdu) == 0x00)
-    {
-      uint32_t output[64/4];   /* Require 4-byte alignment. */
-
-      DEBUG_SHORT (len);
-
-      if (!ac_check_status (AC_OTHER_AUTHORIZED))
+      if (len != ECDSA_HASH_LEN)
        {
-         DEBUG_INFO ("security error.");
-         GPG_SECURITY_FAILURE ();
+         DEBUG_INFO ("wrong hash length.");
+         GPG_CONDITION_NOT_SATISFIED ();
          return;
        }
 
+      res_APDU_size = ECDSA_SIGNATURE_LENGTH;
+      r = ecdsa_sign_p256k1 (apdu.cmd_apdu_data, res_APDU,
+                            kd[GPG_KEY_FOR_AUTHENTICATION].data);
+    }
+  else if (attr == ALGO_ED25519)
+    {
+      uint32_t output[64/4];   /* Require 4-byte alignment. */
+
       if (len > EDDSA_HASH_LEN_MAX)
        {
          DEBUG_INFO ("wrong hash length.");
@@ -1040,27 +1048,18 @@ cmd_internal_authenticate (void)
 
       res_APDU_size = EDDSA_SIGNATURE_LENGTH;
       r = eddsa_sign_25519 (apdu.cmd_apdu_data, len, output,
-           kd[GPG_KEY_FOR_AUTHENTICATION].data,
-           kd[GPG_KEY_FOR_AUTHENTICATION].data+32,
-           kd[GPG_KEY_FOR_AUTHENTICATION].key_addr + KEY_CONTENT_LEN);
+                           kd[GPG_KEY_FOR_AUTHENTICATION].data,
+                           kd[GPG_KEY_FOR_AUTHENTICATION].data+32,
+                           kd[GPG_KEY_FOR_AUTHENTICATION].pubkey);
       memcpy (res_APDU, output, EDDSA_SIGNATURE_LENGTH);
-      if (r < 0)
-       GPG_ERROR ();
-    }
-  else
-    {
-      DEBUG_INFO (" - ??");
-      DEBUG_BYTE (P1 (apdu));
-      DEBUG_INFO (" - ??");
-      DEBUG_BYTE (P2 (apdu));
-      GPG_ERROR ();
     }
 
+  if (r < 0)
+    GPG_ERROR ();
+
   DEBUG_INFO ("INTERNAL AUTHENTICATE done.\r\n");
 }
-#else
-#error "Authentication not defined."
-#endif
+
 
 #define MBD_OPRATION_WRITE  0
 #define MBD_OPRATION_UPDATE 1