Implement "INTERNAL AUTHENTICATE" command.
authorNIIBE Yutaka <gniibe@fsij.org>
Sat, 16 Oct 2010 00:22:18 +0000 (09:22 +0900)
committerNIIBE Yutaka <gniibe@fsij.org>
Sat, 16 Oct 2010 00:22:18 +0000 (09:22 +0900)
AUTHORS
ChangeLog
src/ac.c
src/call-rsa.c
src/gnuk.h
src/openpgp.c

diff --git a/AUTHORS b/AUTHORS
index 7ab8c40..dcea8e7 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -10,6 +10,7 @@ NIIBE Yutaka:
     Founder of the project.
     Wrote:
        gnuk.svg
+       src/configure
        src/ac.c
        src/main.c
        src/usb_lld.h
index de1813f..b547735 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,26 @@
+2010-10-16  NIIBE Yutaka  <gniibe@fsij.org>
+
+       Implement "INTERNAL AUTHENTICATE" command.
+
+       * src/gnuk.h (BY_USER, BY_RESETCODE, BY_ADMIN): New defines.
+       (NUM_ALL_PRV_KEYS): Now it's 3 (was: 2).
+
+       * src/openpgp.c (INS_INTERNAL_AUTHENTICATE): New define.
+       (cmd_internal_authenticate): New function.
+       (cmds): Added INS_INTERNAL_AUTHENTICATE.
+       (cmd_change_password): Use BY_USER.
+       (cmd_reset_user_password): Use BY_USER, BY_RESETCODE, BY_ADMIN.
+       (cmd_pso): Load GPG_KEY_FOR_DECRYPTION here.
+       (cmd_pso): Removed adding status word into res_APDU...
+       * src/call-rsa.c (rsa_sign): and moved adding status word into
+       res_APDU here.
+
+       * src/ac.c (pw1_keystring): New variable.
+       (ac_reset_pso_other): Clear pw1_keystring.
+       (verify_pso_cds): Use BY_USER.
+       (verify_pso_other): Just check the length of password here, and
+       defer real check to cmd_pso or cmd_internal_authenticate.
+
 2010-10-14  NIIBE Yutaka  <gniibe@fsij.org>
 
        Adding 'configure' support.
index 3222c7d..8f39747 100644 (file)
--- a/src/ac.c
+++ b/src/ac.c
@@ -28,9 +28,12 @@ ac_reset_pso_cds (void)
   auth_status &= ~AC_PSO_CDS_AUTHORIZED;
 }
 
+uint8_t pw1_keystring[KEYSTRING_SIZE_PW1];
+
 void
 ac_reset_pso_other (void)
 {
+  memset (pw1_keystring, 0, KEYSTRING_SIZE_PW1);
   auth_status &= ~AC_PSO_OTHER_AUTHORIZED;
 }
 
@@ -52,7 +55,7 @@ verify_pso_cds (const uint8_t *pw, int pw_len)
   keystring[0] = pw_len;
   sha1 (pw, pw_len, keystring+1);
   memcpy (pwsb, pw_status_bytes, SIZE_PW_STATUS_BYTES);
-  if ((r = gpg_do_load_prvkey (GPG_KEY_FOR_SIGNING, 1, keystring+1)) < 0)
+  if ((r = gpg_do_load_prvkey (GPG_KEY_FOR_SIGNING, BY_USER, keystring+1)) < 0)
     {
       pwsb[PW_STATUS_PW1]--;
       gpg_do_write_simple (NR_DO_PW_STATUS, pwsb, SIZE_PW_STATUS_BYTES);
@@ -71,34 +74,41 @@ verify_pso_cds (const uint8_t *pw, int pw_len)
 int
 verify_pso_other (const uint8_t *pw, int pw_len)
 {
-  int r;
   const uint8_t *pw_status_bytes = gpg_do_read_simple (NR_DO_PW_STATUS);
-  uint8_t keystring[KEYSTRING_SIZE_PW1];
   uint8_t pwsb[SIZE_PW_STATUS_BYTES];
+  const uint8_t *ks_pw1;
+
+  DEBUG_INFO ("verify_pso_other\r\n");
 
   if (pw_status_bytes == NULL
       || pw_status_bytes[PW_STATUS_PW1] == 0) /* locked */
     return 0;
 
-  DEBUG_INFO ("verify_pso_other\r\n");
-
-  keystring[0] = pw_len;
-  sha1 (pw, pw_len, keystring+1);
   memcpy (pwsb, pw_status_bytes, SIZE_PW_STATUS_BYTES);
-  if ((r = gpg_do_load_prvkey (GPG_KEY_FOR_DECRYPTION, 1, keystring+1)) < 0)
-    {
-      pwsb[PW_STATUS_PW1]--;
-      gpg_do_write_simple (NR_DO_PW_STATUS, pwsb, SIZE_PW_STATUS_BYTES);
-      return r;
+
+  /*
+   * We check only the length of password string now.
+   * Real check is defered to decrypt/authenticate routines.
+   */
+  ks_pw1 = gpg_do_read_simple (NR_DO_KEYSTRING_PW1);
+  if ((ks_pw1 == NULL && pw_len == strlen (OPENPGP_CARD_INITIAL_PW1))
+      || (ks_pw1 != NULL && pw_len == ks_pw1[0]))
+    {                          /* No problem */
+      /*
+       * We don't reset pwsb[PW_STATUS_PW1] here.
+       * Because password may be wrong.
+       */
+      pw1_keystring[0] = pw_len;
+      sha1 (pw, pw_len, pw1_keystring+1);
+      auth_status |= AC_PSO_OTHER_AUTHORIZED;
+      return 1;
     }
-  else if (pwsb[PW_STATUS_PW1] != 3)
+  else
     {
-      pwsb[PW_STATUS_PW1] = 3;
+      pwsb[PW_STATUS_PW1]--;
       gpg_do_write_simple (NR_DO_PW_STATUS, pwsb, SIZE_PW_STATUS_BYTES);
+      return 0;
     }
-
-  auth_status |= AC_PSO_OTHER_AUTHORIZED;
-  return 1;
 }
 
 /*
index 12a3bcd..6fc90c7 100644 (file)
@@ -28,6 +28,8 @@
 #include "polarssl/config.h"
 #include "polarssl/rsa.h"
 
+#define RSA_SIGNATURE_LENGTH 256 /* 256 byte == 2048-bit */
+
 static rsa_context rsa_ctx;
 
 int
@@ -76,6 +78,9 @@ rsa_sign (const uint8_t *raw_message, uint8_t *output, int msg_len)
     }
   else
     {
+      res_APDU[RSA_SIGNATURE_LENGTH] =  0x90;
+      res_APDU[RSA_SIGNATURE_LENGTH+1] =  0x00;
+      res_APDU_size = RSA_SIGNATURE_LENGTH + 2;
       DEBUG_INFO ("done.\r\n");
       return 0;
     }
@@ -165,7 +170,6 @@ rsa_decrypt (const uint8_t *input, uint8_t *output, int msg_len)
       res_APDU[output_len] = 0x90;
       res_APDU[output_len+1] = 0x00;
       res_APDU_size = output_len + 2;
-
       DEBUG_INFO ("done.\r\n");
       return 0;
     }
index bebae09..7cdc30d 100644 (file)
@@ -104,12 +104,23 @@ struct key_data {
 #define DATA_ENCRYPTION_KEY_SIZE 16
 struct prvkey_data {
   const uint8_t *key_addr;
+  /*
+   * CRM: [C]heck, [R]andom, and [M]agic in struct key_data
+   *
+   */
   uint8_t crm_encrypted[ADDITIONAL_DATA_SIZE];
-  uint8_t dek_encrypted_1[DATA_ENCRYPTION_KEY_SIZE];
-  uint8_t dek_encrypted_2[DATA_ENCRYPTION_KEY_SIZE];
-  uint8_t dek_encrypted_3[DATA_ENCRYPTION_KEY_SIZE];
+  /*
+   * DEK: Data Encryption Key
+   */
+  uint8_t dek_encrypted_1[DATA_ENCRYPTION_KEY_SIZE]; /* For user */
+  uint8_t dek_encrypted_2[DATA_ENCRYPTION_KEY_SIZE]; /* For resetcode */
+  uint8_t dek_encrypted_3[DATA_ENCRYPTION_KEY_SIZE]; /* For admin */
 };
 
+#define BY_USER                1
+#define BY_RESETCODE   2
+#define BY_ADMIN       3
+
 extern int flash_key_write (uint8_t *key_addr, const uint8_t *key_data, const uint8_t *modulus);
 
 #define KEYSTRING_PASSLEN_SIZE  1
@@ -204,7 +215,9 @@ extern void gpg_do_reset_pw_counter (uint8_t which);
 
 extern void set_led (int);
 
-#define NUM_ALL_PRV_KEYS 2     /* SIG and DEC *//* we don't support AUT yet */
+#define NUM_ALL_PRV_KEYS 3     /* SIG, DEC and AUT */
+
+extern uint8_t pw1_keystring[KEYSTRING_SIZE_PW1];
 
 #define OPENPGP_CARD_INITIAL_PW1 "123456"
 
index 2b6634d..dcc368b 100644 (file)
 #include "polarssl/config.h"
 #include "polarssl/sha1.h"
 
-#define RSA_SIGNATURE_LENGTH 256 /* 256 byte == 2048-bit */
-
 #define INS_VERIFY                             0x20
 #define INS_CHANGE_REFERENCE_DATA              0x24
 #define INS_PSO                                        0x2a
 #define INS_RESET_RETRY_COUNTER                        0x2c
 #define INS_PGP_GENERATE_ASYMMETRIC_KEY_PAIR   0x47
+#define INS_INTERNAL_AUTHENTICATE              0x88
 #define INS_SELECT_FILE                                0xa4
 #define INS_READ_BINARY                                0xb0
 #define INS_GET_DATA                           0xca
@@ -180,7 +179,7 @@ cmd_change_password (void)
       pw += 2;
     }
 
-  if (who == 1)                        /* PW1 */
+  if (who == BY_USER)                  /* PW1 */
     {
       const uint8_t *pk = gpg_do_read_simple (NR_DO_KEYSTRING_PW1);
 
@@ -243,21 +242,21 @@ cmd_change_password (void)
       DEBUG_INFO ("security error.\r\n");
       GPG_SECURITY_FAILURE ();
     }
-  else if (r == 0 && who == 1) /* no prvkey */
+  else if (r == 0 && who == BY_USER)   /* no prvkey */
     {
       gpg_do_write_simple (NR_DO_KEYSTRING_PW1, new_ks0, KEYSTRING_SIZE_PW1);
       ac_reset_pso_cds ();
       gpg_do_reset_pw_counter (PW_STATUS_PW1);
       DEBUG_INFO ("Changed DO_KEYSTRING_PW1.\r\n");
     }
-  else if (r > 0 && who == 1)
+  else if (r > 0 && who == BY_USER)
     {
       gpg_do_write_simple (NR_DO_KEYSTRING_PW1, new_ks0, 1);
       ac_reset_pso_cds ();
       gpg_do_reset_pw_counter (PW_STATUS_PW1);
       DEBUG_INFO ("Changed length of DO_KEYSTRING_PW1.\r\n");
     }
-  else                         /* r >= 0 && who == 3 */
+  else                         /* r >= 0 && who == BY_ADMIN */
     {
       DEBUG_INFO ("done.\r\n");
       gpg_do_reset_pw_counter (PW_STATUS_PW3);
@@ -313,7 +312,7 @@ cmd_reset_user_password (void)
       sha1 (pw, pw_len, old_ks);
       sha1 (newpw, newpw_len, new_ks);
       new_ks0[0] = newpw_len;
-      r = gpg_change_keystring (2, old_ks, 1, new_ks);
+      r = gpg_change_keystring (BY_RESETCODE, old_ks, BY_USER, new_ks);
       if (r < -2)
        {
          DEBUG_INFO ("memory error.\r\n");
@@ -362,7 +361,7 @@ cmd_reset_user_password (void)
       newpw = pw;
       sha1 (newpw, newpw_len, new_ks);
       new_ks0[0] = newpw_len;
-      r = gpg_change_keystring (3, old_ks, 1, new_ks);
+      r = gpg_change_keystring (BY_ADMIN, old_ks, BY_USER, new_ks);
       if (r < -2)
        {
          DEBUG_INFO ("memory error.\r\n");
@@ -570,10 +569,6 @@ cmd_pso (void)
            {                   /* Success */
              const uint8_t *pw_status_bytes = gpg_do_read_simple (NR_DO_PW_STATUS);
 
-             res_APDU[RSA_SIGNATURE_LENGTH] =  0x90;
-             res_APDU[RSA_SIGNATURE_LENGTH+1] =  0x00;
-             res_APDU_size = RSA_SIGNATURE_LENGTH + 2;
-
              if (pw_status_bytes[0] == 0)
                ac_reset_pso_cds ();
 
@@ -583,14 +578,34 @@ cmd_pso (void)
     }
   else if (cmd_APDU[2] == 0x80 && cmd_APDU[3] == 0x86)
     {
-      if (!ac_check_status (AC_PSO_OTHER_AUTHORIZED))
+      const uint8_t *pw_status_bytes = gpg_do_read_simple (NR_DO_PW_STATUS);
+      uint8_t pwsb[SIZE_PW_STATUS_BYTES];
+
+      DEBUG_SHORT (len);
+
+      if (pw_status_bytes == NULL
+         || pw_status_bytes[PW_STATUS_PW1] == 0 /* locked */
+         || !ac_check_status (AC_PSO_OTHER_AUTHORIZED))
        {
          DEBUG_INFO ("security error.");
          GPG_SECURITY_FAILURE ();
          return;
        }
 
-      DEBUG_SHORT (len);
+      memcpy (pwsb, pw_status_bytes, SIZE_PW_STATUS_BYTES);
+      if ((r = gpg_do_load_prvkey (GPG_KEY_FOR_DECRYPTION, BY_USER,
+                                  pw1_keystring + 1)) < 0)
+       {
+         pwsb[PW_STATUS_PW1]--;
+         gpg_do_write_simple (NR_DO_PW_STATUS, pwsb, SIZE_PW_STATUS_BYTES);
+         GPG_SECURITY_FAILURE ();
+         return;
+       }
+      else if (pwsb[PW_STATUS_PW1] != 3) /* Failure in the past? */
+       {                      /* Reset counter as it's success now */
+         pwsb[PW_STATUS_PW1] = 3;
+         gpg_do_write_simple (NR_DO_PW_STATUS, pwsb, SIZE_PW_STATUS_BYTES);
+       }
 
       ac_reset_pso_other ();
 
@@ -613,6 +628,69 @@ cmd_pso (void)
   DEBUG_INFO ("PSO done.\r\n");
 }
 
+static void
+cmd_internal_authenticate (void)
+{
+  int len = cmd_APDU[4];
+  int data_start = 5;
+  int r;
+  const uint8_t *pw_status_bytes = gpg_do_read_simple (NR_DO_PW_STATUS);
+  uint8_t pwsb[SIZE_PW_STATUS_BYTES];
+
+  if (len == 0)
+    {
+      len = (cmd_APDU[5]<<8) | cmd_APDU[6];
+      data_start = 7;
+    }
+
+  DEBUG_INFO (" - INTERNAL AUTHENTICATE\r\n");
+
+  if (cmd_APDU[2] == 0x00 && cmd_APDU[3] == 0x00)
+    {
+      DEBUG_SHORT (len);
+
+        if (pw_status_bytes == NULL
+         || pw_status_bytes[PW_STATUS_PW1] == 0 /* locked */
+         || !ac_check_status (AC_PSO_OTHER_AUTHORIZED))
+       {
+         DEBUG_INFO ("security error.");
+         GPG_SECURITY_FAILURE ();
+         return;
+       }
+
+      memcpy (pwsb, pw_status_bytes, SIZE_PW_STATUS_BYTES);
+      if ((r = gpg_do_load_prvkey (GPG_KEY_FOR_AUTHENTICATION, BY_USER,
+                                  pw1_keystring + 1)) < 0)
+       {
+         pwsb[PW_STATUS_PW1]--;
+         gpg_do_write_simple (NR_DO_PW_STATUS, pwsb, SIZE_PW_STATUS_BYTES);
+         GPG_SECURITY_FAILURE ();
+         return;
+       }
+      else if (pwsb[PW_STATUS_PW1] != 3) /* Failure in the past? */
+       {                      /* Reset counter as it's success now */
+         pwsb[PW_STATUS_PW1] = 3;
+         gpg_do_write_simple (NR_DO_PW_STATUS, pwsb, SIZE_PW_STATUS_BYTES);
+       }
+
+      ac_reset_pso_other ();
+
+      r = rsa_sign (&cmd_APDU[data_start], res_APDU, len);
+      if (r < 0)
+       GPG_ERROR ();
+    }
+  else
+    {
+      DEBUG_INFO (" - ??");
+      DEBUG_BYTE (cmd_APDU[2]);
+      DEBUG_INFO (" - ??");
+      DEBUG_BYTE (cmd_APDU[3]);
+      GPG_ERROR ();
+    }
+
+  DEBUG_INFO ("INTERNAL AUTHENTICATE done.\r\n");
+}
+
 struct command
 {
   uint8_t command;
@@ -625,6 +703,7 @@ const struct command cmds[] = {
   { INS_PSO, cmd_pso },
   { INS_RESET_RETRY_COUNTER, cmd_reset_user_password },
   { INS_PGP_GENERATE_ASYMMETRIC_KEY_PAIR, cmd_pgp_gakp },
+  { INS_INTERNAL_AUTHENTICATE, cmd_internal_authenticate },
   { INS_SELECT_FILE, cmd_select_file },
   { INS_READ_BINARY, cmd_read_binary },
   { INS_GET_DATA, cmd_get_data },