new management of pass phrase
authorNIIBE Yutaka <gniibe@fsij.org>
Tue, 15 Oct 2013 03:52:55 +0000 (12:52 +0900)
committerNIIBE Yutaka <gniibe@fsij.org>
Tue, 15 Oct 2013 03:52:55 +0000 (12:52 +0900)
ChangeLog
src/openpgp-do.c
src/openpgp.c

index 8481149..00fab3b 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2013-10-15  Niibe Yutaka  <gniibe@fsij.org>
+
+       * src/openpgp.c (cmd_change_password, cmd_reset_user_password): It
+       is now error to change User's pass phrase with no keys.
+
+       * src/openpgp-do.c (proc_resetting_code): Likewise for resetting
+       code.
+       (gpg_do_delete_prvkey): New.
+       (gpg_do_write_prvkey): Make sure to delete the key before writing.
+       User's pass phrase is always the one of factory setting.
+       (gpg_do_chks_prvkey): Support removing the key.
+       (proc_key_import): Use gpg_do_delete_prvkey.
+       (gpg_do_keygen): Use factory setting pass phrase.
+
 2013-10-11  Niibe Yutaka  <gniibe@fsij.org>
 
        * src/ac.c (verify_user_0, verify_admin_00): Fix conditions.
index 167b09d..29e7f25 100644 (file)
@@ -578,9 +578,8 @@ proc_resetting_code (const uint8_t *data, int len)
     }
   else if (r == 0)
     {
-      DEBUG_INFO ("done (no prvkey).\r\n");
-      new_ks0[0] |= PW_LEN_KEYSTRING_BIT;
-      gpg_do_write_simple (NR_DO_KEYSTRING_RC, new_ks0, KEYSTRING_SIZE);
+      DEBUG_INFO ("error (no prvkey).\r\n");
+      return 0;
     }
   else
     {
@@ -730,6 +729,48 @@ gpg_do_load_prvkey (enum kind_of_key kk, int who, const uint8_t *keystring)
 
 static int8_t num_prv_keys;
 
+static void
+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 - NR_DO__FIRST__];
+
+  if (do_data == NULL)
+    return;
+
+  do_ptr[nr - NR_DO__FIRST__] = NULL;
+  flash_do_release (do_data);
+
+  if (admin_authorized == BY_ADMIN && kk == GPG_KEY_FOR_SIGNING)
+    {                  /* Recover admin keystring DO.  */
+      const uint8_t *ks_pw3 = gpg_do_read_simple (NR_DO_KEYSTRING_PW3);
+
+      if (ks_pw3 != NULL)
+       {
+         uint8_t ks0[KEYSTRING_SIZE];
+
+         ks0[0] = ks_pw3[0] | PW_LEN_KEYSTRING_BIT;
+         memcpy (KS_GET_SALT (ks0), KS_GET_SALT (ks_pw3), SALT_SIZE);
+         memcpy (KS_GET_KEYSTRING (ks0), keystring_md_pw3, KEYSTRING_MD_SIZE);
+         gpg_do_write_simple (NR_DO_KEYSTRING_PW3, ks0, KEYSTRING_SIZE);
+       }
+    }
+
+  if (--num_prv_keys == 0)
+    {
+      flash_keystore_release ();
+
+      /* Delete PW1 and RC if any.  */
+      gpg_do_write_simple (NR_DO_KEYSTRING_PW1, NULL, 0);
+      gpg_do_write_simple (NR_DO_KEYSTRING_RC, NULL, 0);
+
+      ac_reset_pso_cds ();
+      ac_reset_other ();
+      if (admin_authorized == BY_USER)
+       ac_reset_admin ();
+    }
+}
+
 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)
@@ -740,23 +781,17 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
   struct prvkey_data *pd;
   uint8_t *key_addr;
   const uint8_t *dek, *iv;
-  const uint8_t *do_data = do_ptr[nr - NR_DO__FIRST__];
-  const uint8_t *ks_pw1;
-  const uint8_t *ks_rc;
   struct key_data_internal kdi;
   uint8_t *pubkey_allocated_here = NULL;
-  uint8_t ks_pw1_len = 0;
-  uint8_t ks_rc_len = 0;
   int pubkey_len = KEY_CONTENT_LEN;
-  uint8_t ks_info0[KS_META_SIZE];
-  uint8_t ks_info1[KS_META_SIZE];
+  uint8_t ks[KEYSTRING_MD_SIZE];
+  enum kind_of_key kk0;
 
   DEBUG_INFO ("Key import\r\n");
   DEBUG_SHORT (key_len);
 
-  if (do_data)
-    /* No replace support, you need to remove it first.  */
-    return -1;
+  /* Delete it first, if any.  */
+  gpg_do_delete_prvkey (kk);
 
 #ifdef RSA_AUTH
   if (key_len != KEY_CONTENT_LEN)
@@ -827,8 +862,20 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
   memcpy (pd->dek_encrypted_1, dek, DATA_ENCRYPTION_KEY_SIZE);
   memcpy (pd->dek_encrypted_2, dek, DATA_ENCRYPTION_KEY_SIZE);
   memcpy (pd->dek_encrypted_3, dek, DATA_ENCRYPTION_KEY_SIZE);
-  ks_pw1 = gpg_do_read_simple (NR_DO_KEYSTRING_PW1);
-  ks_rc = gpg_do_read_simple (NR_DO_KEYSTRING_RC);
+
+  s2k (NULL, 0, (const uint8_t *)OPENPGP_CARD_INITIAL_PW1,
+       strlen (OPENPGP_CARD_INITIAL_PW1), ks);
+
+  /* Handle existing keys and keystring DOs.  */
+  gpg_do_write_simple (NR_DO_KEYSTRING_PW1, NULL, 0);
+  gpg_do_write_simple (NR_DO_KEYSTRING_RC, NULL, 0);
+  for (kk0 = 0; kk0 <= GPG_KEY_FOR_AUTHENTICATION; kk++)
+    if (kk0 != kk)
+      {
+       gpg_do_chks_prvkey (kk0, admin_authorized, keystring_md_pw3,
+                           BY_USER, ks);
+       gpg_do_chks_prvkey (kk0, BY_RESETCODE, NULL, 0, NULL);
+      }
 
   encrypt (dek, iv, (uint8_t *)&kdi, sizeof (struct key_data_internal));
 
@@ -853,29 +900,9 @@ 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);
 
-  if (ks_pw1 && ((ks_pw1_len = ks_pw1[0]) & PW_LEN_KEYSTRING_BIT))
-    {
-      ks_info0[0] = ks_pw1_len & PW_LEN_MASK;
-      memcpy (KS_GET_SALT (ks_info0), KS_GET_SALT (ks_pw1), SALT_SIZE);
-      encrypt_dek (KS_GET_KEYSTRING (ks_pw1), pd->dek_encrypted_1);
-    }
-  else
-    {
-      uint8_t ks[KEYSTRING_MD_SIZE];
+  encrypt_dek (ks, pd->dek_encrypted_1);
 
-      s2k (NULL, 0, (const uint8_t *)OPENPGP_CARD_INITIAL_PW1,
-          strlen (OPENPGP_CARD_INITIAL_PW1), ks);
-      encrypt_dek (ks, pd->dek_encrypted_1);
-    }
-
-  if (ks_rc && ((ks_rc_len = ks_rc[0]) & PW_LEN_KEYSTRING_BIT))
-    {
-      ks_info1[0] = ks_rc_len & PW_LEN_MASK;
-      memcpy (KS_GET_SALT (ks_info1), KS_GET_SALT (ks_rc), SALT_SIZE);
-      encrypt_dek (KS_GET_KEYSTRING (ks_rc), pd->dek_encrypted_2);
-    }
-  else
-    memset (pd->dek_encrypted_2, 0, DATA_ENCRYPTION_KEY_SIZE);
+  memset (pd->dek_encrypted_2, 0, DATA_ENCRYPTION_KEY_SIZE);
 
   if (keystring_admin)
     encrypt_dek (keystring_admin, pd->dek_encrypted_3);
@@ -894,12 +921,13 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
   if (keystring_admin && kk == GPG_KEY_FOR_SIGNING)
     {
       const uint8_t *ks_admin = gpg_do_read_simple (NR_DO_KEYSTRING_PW3);
+      uint8_t ks_info[KS_META_SIZE];
 
       if (ks_admin != NULL && (ks_admin[0] & PW_LEN_KEYSTRING_BIT))
        {
-         ks_info0[0] = ks_admin[0] & PW_LEN_MASK;
-         memcpy (KS_GET_SALT (ks_info0), KS_GET_SALT (ks_admin), SALT_SIZE);
-         gpg_do_write_simple (NR_DO_KEYSTRING_PW3, ks_info0, KS_META_SIZE);
+         ks_info[0] = ks_admin[0] & PW_LEN_MASK;
+         memcpy (KS_GET_SALT (ks_info), KS_GET_SALT (ks_admin), SALT_SIZE);
+         gpg_do_write_simple (NR_DO_KEYSTRING_PW3, ks_info, KS_META_SIZE);
        }
       else
        {
@@ -907,20 +935,6 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
        }
     }
 
-  if (++num_prv_keys == NUM_ALL_PRV_KEYS) /* All keys are registered.  */
-    { /* Remove contents of keystrings from DO, but length and salt.  */
-      /*
-       * Note that flash_do_write (above) or gpg_do_write_simple
-       * (below) may result garbage collection for flash ROM.  Thus,
-       * the access to ks_pw1/ks_rc must not be done here but before.
-       */
-      if ((ks_pw1_len & PW_LEN_KEYSTRING_BIT))
-       gpg_do_write_simple (NR_DO_KEYSTRING_PW1, ks_info0, KS_META_SIZE);
-
-      if ((ks_rc_len & PW_LEN_KEYSTRING_BIT))
-       gpg_do_write_simple (NR_DO_KEYSTRING_RC, ks_info1, KS_META_SIZE);
-    }
-
   return 0;
 }
 
@@ -935,6 +949,7 @@ gpg_do_chks_prvkey (enum kind_of_key kk,
   struct prvkey_data *pd;
   const uint8_t *p;
   uint8_t *dek_p;
+  int update_needed = 0;
 
   if (do_data == NULL)
     return 0;                  /* No private key */
@@ -944,23 +959,44 @@ gpg_do_chks_prvkey (enum kind_of_key kk,
     return -1;
 
   memcpy (pd, &do_data[1], sizeof (struct prvkey_data));
-  flash_do_release (do_data);
 
   dek_p = ((uint8_t *)pd) + 4 + INITIAL_VECTOR_SIZE
     + DATA_ENCRYPTION_KEY_SIZE * who_old;
   memcpy (dek, dek_p, DATA_ENCRYPTION_KEY_SIZE);
-  decrypt_dek (old_ks, dek);
-  encrypt_dek (new_ks, dek);
-  dek_p += DATA_ENCRYPTION_KEY_SIZE * (who_new - who_old);
-  memcpy (dek_p, dek, DATA_ENCRYPTION_KEY_SIZE);
+  if (who_new == 0)            /* Remove */
+    {
+      int i;
 
-  do_ptr[nr - NR_DO__FIRST__] = NULL;
-  p = flash_do_write (nr, (const uint8_t *)pd, sizeof (struct prvkey_data));
-  do_ptr[nr - NR_DO__FIRST__] = p;
+      for (i = 0; i < DATA_ENCRYPTION_KEY_SIZE; i++)
+       if (dek_p[i] != 0)
+         {
+           update_needed = 1;
+           dek_p[i] = 0;
+         }
+    }
+  else
+    {
+      decrypt_dek (old_ks, dek);
+      encrypt_dek (new_ks, dek);
+      dek_p += DATA_ENCRYPTION_KEY_SIZE * (who_new - who_old);
+      if (memcmp (dek_p, dek, DATA_ENCRYPTION_KEY_SIZE) != 0)
+       {
+         memcpy (dek_p, dek, DATA_ENCRYPTION_KEY_SIZE);
+         update_needed = 1;
+       }
+    }
+
+  if (update_needed)
+    {
+      flash_do_release (do_data);
+      do_ptr[nr - NR_DO__FIRST__] = NULL;
+      p = flash_do_write (nr, (const uint8_t *)pd, sizeof (struct prvkey_data));
+      do_ptr[nr - NR_DO__FIRST__] = p;
+    }
 
   memset (pd, 0, sizeof (struct prvkey_data));
   free (pd);
-  if (p == NULL)
+  if (update_needed && p == NULL)
     return -1;
 
   return 1;
@@ -1033,45 +1069,7 @@ proc_key_import (const uint8_t *data, int len)
       || (kk == GPG_KEY_FOR_AUTHENTICATION && len <= 12))
 #endif
     {                                      /* Deletion of the key */
-      uint8_t nr = get_do_ptr_nr_for_kk (kk);
-      const uint8_t *do_data = do_ptr[nr - NR_DO__FIRST__];
-
-      if (do_data == NULL)
-       return 1;
-
-      do_ptr[nr - NR_DO__FIRST__] = NULL;
-      flash_do_release (do_data);
-
-      if (admin_authorized == BY_ADMIN && kk == GPG_KEY_FOR_SIGNING)
-       {                       /* Recover admin keystring DO.  */
-         const uint8_t *ks_pw3 = gpg_do_read_simple (NR_DO_KEYSTRING_PW3);
-
-         if (ks_pw3 != NULL)
-           {
-             uint8_t ks0[KEYSTRING_SIZE];
-
-             ks0[0] = ks_pw3[0] | PW_LEN_KEYSTRING_BIT;
-             memcpy (KS_GET_SALT (ks0), KS_GET_SALT (ks_pw3), SALT_SIZE);
-             memcpy (KS_GET_KEYSTRING (ks0),
-                     keystring_md_pw3, KEYSTRING_MD_SIZE);
-             gpg_do_write_simple (NR_DO_KEYSTRING_PW3, ks0, KEYSTRING_SIZE);
-           }
-       }
-
-      if (--num_prv_keys == 0)
-       {
-         flash_keystore_release ();
-
-         /* Delete PW1 and RC if any.  */
-         gpg_do_write_simple (NR_DO_KEYSTRING_PW1, NULL, 0);
-         gpg_do_write_simple (NR_DO_KEYSTRING_RC, NULL, 0);
-
-         ac_reset_pso_cds ();
-         ac_reset_other ();
-         if (admin_authorized == BY_USER)
-           ac_reset_admin ();
-       }
-
+      gpg_do_delete_prvkey (kk);
       return 1;
     }
 
@@ -1727,30 +1725,14 @@ gpg_do_keygen (uint8_t kk_byte)
 
   if (kk == GPG_KEY_FOR_SIGNING)
     {
-      const uint8_t *ks_pw1 = gpg_do_read_simple (NR_DO_KEYSTRING_PW1);
+      const uint8_t *pw = (const uint8_t *)OPENPGP_CARD_INITIAL_PW1;
       uint8_t keystring[KEYSTRING_MD_SIZE];
-      const uint8_t *ks;
 
       /* GnuPG expects it's ready for signing. */
       /* Don't call ac_reset_pso_cds here, but load the private key */
 
-      if (ks_pw1 == NULL)
-       {
-         const uint8_t * pw = (const uint8_t *)OPENPGP_CARD_INITIAL_PW1;
-
-         s2k (NULL, 0, pw, strlen (OPENPGP_CARD_INITIAL_PW1), keystring);
-         ks = keystring;
-       }
-      else
-       if ((ks_pw1[0] & PW_LEN_KEYSTRING_BIT) != 0)
-         ks = KS_GET_KEYSTRING (ks_pw1);
-       else
-         {
-           GPG_ERROR ();
-           return;
-         }
-
-      gpg_do_load_prvkey (GPG_KEY_FOR_SIGNING, BY_USER, ks);
+      s2k (NULL, 0, pw, strlen (OPENPGP_CARD_INITIAL_PW1), keystring);
+      gpg_do_load_prvkey (GPG_KEY_FOR_SIGNING, BY_USER, keystring);
     }
   else
     ac_reset_other ();
index 191f66c..cb141c0 100644 (file)
@@ -382,14 +382,8 @@ cmd_change_password (void)
     }
   else if (r == 0 && who == BY_USER)   /* no prvkey */
     {
-      new_ks0[0] |= PW_LEN_KEYSTRING_BIT;
-      gpg_do_write_simple (NR_DO_KEYSTRING_PW1, new_ks0, KEYSTRING_SIZE);
-      ac_reset_pso_cds ();
-      ac_reset_other ();
-      if (admin_authorized == BY_USER)
-       ac_reset_admin ();
-      DEBUG_INFO ("Changed DO_KEYSTRING_PW1.\r\n");
-      GPG_SUCCESS ();
+      DEBUG_INFO ("user pass change not supported with no keys.\r\n");
+      GPG_CONDITION_NOT_SATISFIED ();
     }
   else if (r > 0 && who == BY_USER)
     {
@@ -519,27 +513,14 @@ cmd_reset_user_password (void)
        }
       else if (r < 0)
        {
-       sec_fail:
          DEBUG_INFO ("failed.\r\n");
          gpg_pw_increment_err_counter (PW_ERR_RC);
          GPG_SECURITY_FAILURE ();
        }
       else if (r == 0)
        {
-         if ((ks_rc[0] & PW_LEN_KEYSTRING_BIT) == 0
-             || memcmp (KS_GET_KEYSTRING (ks_rc),
-                        old_ks, KEYSTRING_MD_SIZE) != 0)
-           goto sec_fail;
-         DEBUG_INFO ("done (no prvkey).\r\n");
-         new_ks0[0] |= PW_LEN_KEYSTRING_BIT;
-         gpg_do_write_simple (NR_DO_KEYSTRING_PW1, new_ks0, KEYSTRING_SIZE);
-         ac_reset_pso_cds ();
-         ac_reset_other ();
-         if (admin_authorized == BY_USER)
-           ac_reset_admin ();
-         gpg_pw_reset_err_counter (PW_ERR_RC);
-         gpg_pw_reset_err_counter (PW_ERR_PW1);
-         GPG_SUCCESS ();
+         DEBUG_INFO ("user pass change not supported with no keys.\r\n");
+         GPG_CONDITION_NOT_SATISFIED ();
        }
       else
        {
@@ -583,15 +564,8 @@ cmd_reset_user_password (void)
        }
       else if (r == 0)
        {
-         DEBUG_INFO ("done (no privkey).\r\n");
-         new_ks0[0] |= PW_LEN_KEYSTRING_BIT;
-         gpg_do_write_simple (NR_DO_KEYSTRING_PW1, new_ks0, KEYSTRING_SIZE);
-         ac_reset_pso_cds ();
-         ac_reset_other ();
-         if (admin_authorized == BY_USER)
-           ac_reset_admin ();
-         gpg_pw_reset_err_counter (PW_ERR_PW1);
-         GPG_SUCCESS ();
+         DEBUG_INFO ("user pass change not supported with no keys.\r\n");
+         GPG_CONDITION_NOT_SATISFIED ();
        }
       else
        {