Release 0.1.
authorNIIBE Yutaka <gniibe@fsij.org>
Thu, 9 Sep 2010 08:50:34 +0000 (17:50 +0900)
committerNIIBE Yutaka <gniibe@fsij.org>
Thu, 9 Sep 2010 09:30:36 +0000 (18:30 +0900)
AUTHORS
ChangeLog
NEWS
README
src/ac.c
src/config.h
src/gnuk.h
src/openpgp-do.c
src/openpgp.c
src/usb_desc.c
src/usb_prop.c

diff --git a/AUTHORS b/AUTHORS
index 4337719..9f7fdc0 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -6,7 +6,9 @@ Kaz Kojima:
        boards/STM32_PRIMER2/mcuconf.h
        boards/STM32_PRIMER2/hw_config.c
 
-NIIBE Yutaka: wrote
+NIIBE Yutaka:
+    Founder of the project
+    Wrote
        src/ac.c
        src/main.c
        src/usb_lld.h
index c44fae1..135b419 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,30 @@
+2010-09-10  NIIBE Yutaka  <gniibe@fsij.org>
+
+       * src/usb_desc.c (gnukStringSerial): Change the value so that
+       libccid doesn't get confused.
+
+       * src/openpgp.c (gpg_change_keystring): Support key for decryption
+       as well.
+       (cmd_read_binary): Use openpgpcard_aid.
+       (cmd_pso): call ac_reset_pso_other.
+
+       * src/openpgp-do.c (openpgpcard_aid): Renamed from aid, and exported.
+       (do_ds_count_initial_value): New const variable.
+       (num_prv_keys): New variable.
+       (gpg_do_write_prvkey): Remove contents of keystring only if
+       ++num_prv_keys == NUM_ALL_PRV_KEYS.
+       (gpg_do_chks_prvkey): Call flash_do_release.
+       (gpg_do_table_init): Initialize with do_ds_count_initial_value.
+       Initialize num_prv_keys.
+       (gpg_do_write_simple): Support removing DO.
+       (gpg_do_increment_digital_signature_counter): Call flash_do_release.
+
+       * src/gnuk.h (NUM_ALL_PRV_KEYS): New definition.
+       (OPENPGP_CARD_INITIAL_PW1): New definition.
+       (enum kind_of_key): Rename.
+
+       * src/ac.c (ac_reset_pso_cds): New function.
+
 2010-09-09  Kaz Kojima  <kkojima@rr.iij4u.or.jp>
 
        * boards/STM32_PRIMER2/{board.c,board.h,board.mk,hw_config.c,mcuconf.h}:
@@ -48,6 +75,8 @@
        (mpi_write_string, mpi_read_file, mpi_read_file): #if-out to avoid
        stdio of libc.
 
+2010-09-07  NIIBE Yutaka  <gniibe@fsij.org>
+
        * gnuk.svg: New file.
 
 2010-09-06  NIIBE Yutaka  <gniibe@fsij.org>
diff --git a/NEWS b/NEWS
index 0f78dcc..8c60254 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -2,18 +2,22 @@ Gnuk NEWS - User visible changes
 
 * Major changes in Gnuk 0.1
 
-  Released 2010-09-XX, by NIIBE Yutaka
+  Released 2010-09-10, by NIIBE Yutaka
+
+** Enabled force_chv1 (in the pw_status_bytes), so that the decipher works.
+
+** Support both of key for digital signing and key for decryption.
+
+** Decipher is supported.
 
 ** New board support "STM32 Primer2" is added by Kaz Kojima.
 
-** Now, LED behavior is meaningful.  "ON" during execution.
+** LED behavior is meaningful now.  "ON" during execution.
 
 ** Fixed bcdCCID revision number.
 
 ** Logo.
 
-** Decipher is supported.
-
 
 * Major changes in Gnuk 0.0
 
diff --git a/README b/README
index 52f5b57..79fd165 100644 (file)
--- a/README
+++ b/README
@@ -1,22 +1,31 @@
-Gnuk - software for GPG USB Token 
+Gnuk - software for GPG USB Token
 
-                                                           Version 0.0
-                                                            2010-09-06
+                                                           Version 0.1
+                                                            2010-09-10
                                                           Niibe Yutaka
                                      Free Software Initiative of Japan
 
-What's Gnuk
-===========
+What's Gnuk?
+============
 
 Gnuk is software implementation of a USB token for GNU privacy guard.
 Gnuk supports OpenPGP card protocol version 2, and it runs on STM32
 processor.
 
+Please look at the graphics of "gnuk.svg" for the software name.
+
+I wish that Gnuk will be a developer's soother who uses GnuPG.  I have
+been nervous of storing secret key(s) on usual secondary storage.
+While I want to work at different places, but it is not the choice for
+me to bring a card reader all the time.  With Gnuk, this issue will be
+solved by a USB token which is small enough.
+
 
 Release notes
 =============
 
-This is initial release of Gnuk, and it is experimental.
+This is second release of Gnuk.  While it works somehow, it is still
+experimental.
 
 Tested features are:
 
@@ -26,16 +35,18 @@ Tested features are:
 
        * Password handling (PW1, RC, PW3)
 
-       * Key import for signature only.
+       * Key import for both of key for digital signing and key for
+          decryption.
 
        * PSO: Digital Signature
 
+       * PSO: Decipher
 
-It is known not-working:
+It is known not-working well:
 
-       * Multiple key import
+       * Key import multiple times
 
-       * PSO: Decipher
+       * Changing value of password status bytes (0x00C4).
 
 
 Targets
@@ -195,6 +206,16 @@ Inside GDB, we can connect OpenOCD by:
   (gdb) target remote localhost:3333
 
 
+You can see output of PCSCD:
+
+  # /etc/init.d/pcscd stop
+  # LIBCCID_ifdLogLevel=7 /usr/sbin/pcscd --debug --foreground
+
+
+You can observe the traffic of USB using "usbmon".  See the file:
+linux/Documentation/usb/usbmon.txt
+
+
 
 Development history
 ===================
index b6c4224..3222c7d 100644 (file)
--- a/src/ac.c
+++ b/src/ac.c
@@ -22,6 +22,18 @@ ac_check_status (uint8_t ac_flag)
     return (ac_flag & auth_status)? 1 : 0;
 }
 
+void
+ac_reset_pso_cds (void)
+{
+  auth_status &= ~AC_PSO_CDS_AUTHORIZED;
+}
+
+void
+ac_reset_pso_other (void)
+{
+  auth_status &= ~AC_PSO_OTHER_AUTHORIZED;
+}
+
 int
 verify_pso_cds (const uint8_t *pw, int pw_len)
 {
@@ -40,7 +52,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_SIGNATURE, 1, keystring+1)) < 0)
+  if ((r = gpg_do_load_prvkey (GPG_KEY_FOR_SIGNING, 1, keystring+1)) < 0)
     {
       pwsb[PW_STATUS_PW1]--;
       gpg_do_write_simple (NR_DO_PW_STATUS, pwsb, SIZE_PW_STATUS_BYTES);
@@ -56,12 +68,6 @@ verify_pso_cds (const uint8_t *pw, int pw_len)
   return 1;
 }
 
-void
-ac_reset_pso_cds (void)
-{
-  auth_status &= ~AC_PSO_CDS_AUTHORIZED;
-}
-
 int
 verify_pso_other (const uint8_t *pw, int pw_len)
 {
@@ -79,7 +85,7 @@ verify_pso_other (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_DECRYPT, 1, keystring+1)) < 0)
+  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);
index d088159..3dd0958 100644 (file)
@@ -2,9 +2,6 @@
 #define ENABLE_VIRTUAL_COM_PORT 1
 #endif
 
-/* Packet size of USB Bulk transfer for full speed */
-#define GNUK_MAX_PACKET_SIZE 64
-
 #if 0
 /* FSIJ */
 #define MANUFACTURER_IN_AID            0xf5, 0x17
index 0c84a7c..c519152 100644 (file)
@@ -58,7 +58,7 @@ extern int verify_admin (const uint8_t *pw, int pw_len);
 extern int verify_admin_0 (const uint8_t *pw, int buf_len, int pw_len_known);
 
 extern void ac_reset_pso_cds (void);
-
+extern void ac_reset_pso_other (void);
 
 
 extern void write_res_apdu (const uint8_t *p, int len,
@@ -72,8 +72,8 @@ extern void gpg_do_public_key (uint8_t kk_byte);
 
 
 enum kind_of_key {
-  GPG_KEY_FOR_SIGNATURE,
-  GPG_KEY_FOR_DECRYPT,
+  GPG_KEY_FOR_SIGNING,
+  GPG_KEY_FOR_DECRYPTION,
   GPG_KEY_FOR_AUTHENTICATION,
 };
 
@@ -199,3 +199,9 @@ extern uint32_t hardclock (void);
 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 OPENPGP_CARD_INITIAL_PW1 "123456"
+
+const uint8_t openpgpcard_aid[17] __attribute__ ((aligned (1)));
index e0100c1..370f9e0 100644 (file)
@@ -39,7 +39,7 @@
  */
 
 /* AID */
-static const uint8_t aid[] __attribute__ ((aligned (1))) = {
+const uint8_t openpgpcard_aid[17] __attribute__ ((aligned (1))) = {
   16,
   0xd2, 0x76, 0x00, 0x01, 0x24, 0x01,
   0x02, 0x00,                  /* Version 2.0 */
@@ -87,10 +87,14 @@ static const uint8_t algorithm_attr[] __attribute__ ((aligned (1))) = {
   0x00               /* 0: p&q , 3: CRT with N (not yet supported) */
 };
 
-static const uint8_t do_pw_status_bytes_template[] =
-{
+static const uint8_t do_ds_count_initial_value[] __attribute__ ((aligned (1))) = {
+  3,
+  0, 0, 0
+};
+
+static const uint8_t do_pw_status_bytes_template[] __attribute__ ((aligned (1))) = {
   7,
-  1,                           /* PW1 valid for several PSO:CDS commands */
+  0,                           /* PW1 is valid for single PSO:CDS command */
   127, 127, 127,               /* max length of PW1, RC, and PW3 */
   3, 0, 3                      /* Error counter of PW1, RC, and PW3 */
 };
@@ -483,9 +487,9 @@ get_do_ptr_nr_for_kk (enum kind_of_key kk)
 {
   switch (kk)
     {
-    case GPG_KEY_FOR_SIGNATURE:
+    case GPG_KEY_FOR_SIGNING:
       return NR_DO_PRVKEY_SIG;
-    case GPG_KEY_FOR_DECRYPT:
+    case GPG_KEY_FOR_DECRYPTION:
       return NR_DO_PRVKEY_DEC;
     case GPG_KEY_FOR_AUTHENTICATION:
       return NR_DO_PRVKEY_AUT;
@@ -521,7 +525,7 @@ gpg_do_load_prvkey (enum kind_of_key kk, int who, const uint8_t *keystring)
       DEBUG_INFO ("gpg_do_load_prvkey failed.\r\n");
       return -1;
     }
-  /* XXX: more sanity check */
+  /* more sanity check??? */
   return 1;
 }
 
@@ -538,6 +542,8 @@ calc_check32 (const uint8_t *p, int len)
   return check;
 }
 
+static int8_t num_prv_keys;
+
 int
 gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
                     const uint8_t *keystring)
@@ -549,8 +555,9 @@ 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;
-  const uint8_t *ks_pw1 = gpg_do_read_simple (NR_DO_KEYSTRING_PW1);
-  const uint8_t *ks_rc = gpg_do_read_simple (NR_DO_KEYSTRING_RC);
+  const uint8_t *do_data = do_ptr[nr];
+  const uint8_t *ks_pw1;
+  const uint8_t *ks_rc;
 
 #if 0
   assert (key_len == KEY_CONTENT_LEN);
@@ -587,19 +594,42 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
   kd.random = get_random ();
   memcpy (kd.magic, GNUK_MAGIC, KEY_MAGIC_LEN);
 
-  DEBUG_INFO ("enc...");
+  if (do_data)                 /* We have old prvkey */
+    {
+      /* Write new prvkey resetting PW1 and RC */
+      /* Note: if you have other prvkey(s), it becomes bogus */
+      memcpy (pd, do_data+1, sizeof (struct prvkey_data));
+      decrypt (keystring_md_pw3, pd->dek_encrypted_3, DATA_ENCRYPTION_KEY_SIZE);
+      dek = pd->dek_encrypted_3;
+      memcpy (pd->dek_encrypted_1, dek, DATA_ENCRYPTION_KEY_SIZE);
+      memset (pd->dek_encrypted_2, 0, DATA_ENCRYPTION_KEY_SIZE);
+      flash_do_release (do_data);
+      gpg_do_write_simple (NR_DO_KEYSTRING_PW1, NULL, 0);
+      gpg_do_write_simple (NR_DO_KEYSTRING_RC, NULL, 0);
+      flash_key_release (pd->key_addr);
+      flash_do_release (do_data);
+      ks_pw1 = NULL;
+      ks_rc = NULL;
+    }
+  else
+    {
+      dek = random_bytes_get (); /* 16-byte random bytes */
+      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);
+    }
 
-  dek = random_bytes_get (); /* 16-byte random bytes */
   encrypt (dek, (uint8_t *)&kd, sizeof (struct key_data));
 
-  DEBUG_INFO ("done\r\n");
-
   r = flash_key_write (key_addr, kd.data, modulus);
   modulus_free (modulus);
 
   if (r < 0)
     {
-      random_bytes_free (dek);
+      if (do_data == NULL)
+       random_bytes_free (dek);
       free (pd);
       return r;
     }
@@ -609,49 +639,49 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
 
   ac_reset_pso_cds ();
   if (ks_pw1)
-    {
-      uint8_t ks_pw1_len = ks_pw1[0];
-
-      memcpy (pd->dek_encrypted_1, dek, DATA_ENCRYPTION_KEY_SIZE);
-      encrypt (ks_pw1+1, pd->dek_encrypted_1, DATA_ENCRYPTION_KEY_SIZE);
-      /* Only its length */
-      gpg_do_write_simple (NR_DO_KEYSTRING_PW1, &ks_pw1_len, 1);
-    }
+    encrypt (ks_pw1+1, pd->dek_encrypted_1, DATA_ENCRYPTION_KEY_SIZE);
   else
     {
       uint8_t ks123_pw1[KEYSTRING_SIZE_PW1];
 
-      ks123_pw1[0] = 6;
-      sha1 ((uint8_t *)"123456", 6, ks123_pw1+1);
-      memcpy (pd->dek_encrypted_1, dek, DATA_ENCRYPTION_KEY_SIZE);
+      ks123_pw1[0] = strlen (OPENPGP_CARD_INITIAL_PW1);
+      sha1 ((uint8_t *)OPENPGP_CARD_INITIAL_PW1, 6, ks123_pw1+1);
       encrypt (ks123_pw1+1, pd->dek_encrypted_1, DATA_ENCRYPTION_KEY_SIZE);
-      /* Only but its length */
-      gpg_do_write_simple (NR_DO_KEYSTRING_PW1, ks123_pw1, 1);
     }
 
   if (ks_rc)
-    {
-      uint8_t ks_rc_len = ks_rc[0];
-
-      memcpy (pd->dek_encrypted_2, dek, DATA_ENCRYPTION_KEY_SIZE);
-      encrypt (ks_rc+1, pd->dek_encrypted_2, DATA_ENCRYPTION_KEY_SIZE);
-      /* Only its length */
-      gpg_do_write_simple (NR_DO_KEYSTRING_RC, &ks_rc_len, 1);
-    }
+    encrypt (ks_rc+1, pd->dek_encrypted_2, DATA_ENCRYPTION_KEY_SIZE);
   else
     memset (pd->dek_encrypted_2, 0, DATA_ENCRYPTION_KEY_SIZE);
 
-  memcpy (pd->dek_encrypted_3, dek, DATA_ENCRYPTION_KEY_SIZE);
   encrypt (keystring, pd->dek_encrypted_3, DATA_ENCRYPTION_KEY_SIZE);
 
   p = flash_do_write (nr, (const uint8_t *)pd, sizeof (struct prvkey_data));
   do_ptr[nr] = p;
 
-  random_bytes_free (dek);
+  if (do_data == NULL)
+    random_bytes_free (dek);
   free (pd);
   if (p == NULL)
     return -1;
 
+  if (do_data == NULL
+      && ++num_prv_keys == NUM_ALL_PRV_KEYS) /* All keys are registered.  */
+    {
+      /* Remove contents of keystrings from DO, but length */
+      if (ks_pw1)
+       {
+         uint8_t ks_pw1_len = ks_pw1[0];
+         gpg_do_write_simple (NR_DO_KEYSTRING_PW1, &ks_pw1_len, 1);
+       }
+
+      if (ks_rc)
+       {
+         uint8_t ks_rc_len = ks_rc[0];
+         gpg_do_write_simple (NR_DO_KEYSTRING_RC, &ks_rc_len, 1);
+       }
+    }
+
   return 0;
 }
 
@@ -685,6 +715,7 @@ gpg_do_chks_prvkey (enum kind_of_key kk,
   p = flash_do_write (nr, (const uint8_t *)pd, sizeof (struct prvkey_data));
   do_ptr[nr] = p;
 
+  flash_do_release (do_data);
   free (pd);
   if (p == NULL)
     return -1;
@@ -710,9 +741,9 @@ proc_key_import (const uint8_t *data, int len)
   DEBUG_BINARY (data, len);
 
   if (data[4] == 0xb6)
-    kk = GPG_KEY_FOR_SIGNATURE;
+    kk = GPG_KEY_FOR_SIGNING;
   else if (data[4] == 0xb8)
-    kk = GPG_KEY_FOR_DECRYPT;
+    kk = GPG_KEY_FOR_DECRYPTION;
   else                         /* 0xa4 */
     kk = GPG_KEY_FOR_AUTHENTICATION;
 
@@ -721,15 +752,23 @@ proc_key_import (const uint8_t *data, int len)
       uint8_t nr = get_do_ptr_nr_for_kk (kk);
       const uint8_t *do_data = do_ptr[nr];
 
+      /* Delete the key */
       if (do_data)
        {
          uint8_t *key_addr = *(uint8_t **)&do_data[1];
 
-         flash_do_release (do_data);
          flash_key_release (key_addr);
+         flash_do_release (do_data);
        }
-
       do_ptr[nr] = NULL;
+
+      if (--num_prv_keys == 0)
+       {
+         /* 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);
+       }
+
       GPG_SUCCESS ();
       return;
     }
@@ -801,11 +840,11 @@ gpg_do_table[] = {
   { GPG_DO_PW_STATUS, DO_PROC_READWRITE, AC_ALWAYS, AC_ADMIN_AUTHORIZED,
     rw_pw_status },
   /* Fixed data */
-  { GPG_DO_AID, DO_FIXED, AC_ALWAYS, AC_NEVER, aid },
+  { GPG_DO_AID, DO_FIXED, AC_ALWAYS, AC_NEVER, openpgpcard_aid },
   { GPG_DO_EXTCAP, DO_FIXED, AC_ALWAYS, AC_NEVER, extended_capabilities },
   { GPG_DO_ALG_SIG, DO_FIXED, AC_ALWAYS, AC_NEVER, algorithm_attr },
   { GPG_DO_ALG_DEC, DO_FIXED, AC_ALWAYS, AC_NEVER, algorithm_attr },
-  { GPG_DO_ALG_AUT, DO_FIXED, AC_ALWAYS, AC_NEVER, NULL },
+  { GPG_DO_ALG_AUT, DO_FIXED, AC_ALWAYS, AC_NEVER, algorithm_attr },
   /* Compound data: Read access only */
   { GPG_DO_CH_DATA, DO_CN_READ, AC_ALWAYS, AC_NEVER, cn_ch_data },
   { GPG_DO_APP_DATA, DO_CN_READ, AC_ALWAYS, AC_NEVER, cn_app_data },
@@ -829,6 +868,7 @@ gpg_do_table_init (void)
   const uint8_t *p, *p_start;
   int len;
 
+  do_ptr[NR_DO_DS_COUNT] = do_ds_count_initial_value;
   do_ptr[NR_DO_PW_STATUS] = do_pw_status_bytes_template;
   p_start = flash_do_pool ();
 
@@ -863,6 +903,13 @@ gpg_do_table_init (void)
 
   flash_set_do_pool_last (p);
 
+  num_prv_keys = 0;
+  if (do_ptr[NR_DO_PRVKEY_SIG] != NULL)
+    num_prv_keys++;
+  if (do_ptr[NR_DO_PRVKEY_DEC] != NULL)
+    num_prv_keys++;
+  if (do_ptr[NR_DO_PRVKEY_AUT] != NULL)
+    num_prv_keys++;
   return 0;
 }
 
@@ -1171,11 +1218,19 @@ gpg_do_write_simple (uint8_t nr, const uint8_t *data, int size)
   if (*do_data_p)
     flash_do_release (*do_data_p);
 
-  *do_data_p = flash_do_write (nr, data, size);
-  if (*do_data_p)
-    GPG_SUCCESS ();
+  if (data != NULL)
+    {
+      *do_data_p = flash_do_write (nr, data, size);
+      if (*do_data_p)
+       GPG_SUCCESS ();
+      else
+       GPG_MEMORY_FAILURE();
+    }
   else
-    GPG_MEMORY_FAILURE();
+    {
+      *do_data_p = NULL;
+      GPG_SUCCESS ();
+    }
 }
 
 void
@@ -1196,6 +1251,7 @@ gpg_do_increment_digital_signature_counter (void)
   count_data[1] = (count >> 8) & 0xff;
   count_data[2] = count & 0xff;
 
+  flash_do_release (do_data);
   do_ptr[NR_DO_DS_COUNT] = flash_do_write (NR_DO_DS_COUNT, count_data,
                                           SIZE_DIGITAL_SIGNATURE_COUNTER);
 }
index 711327b..1fba13d 100644 (file)
@@ -60,11 +60,6 @@ select_file_TOP_result[] __attribute__ ((aligned (1))) = {
   0x00, 0x00           /* PIN status: OK, PIN blocked?: No */
 };
 
-static const uint8_t
-read_binary_result[] __attribute__ ((aligned (1))) = {
-  0x5a, 0x4, 0x01, 0x02, 0x03, 0x04
-};
-
 void
 write_res_apdu (const uint8_t *p, int len, uint8_t sw1, uint8_t sw2)
 {
@@ -129,17 +124,37 @@ int
 gpg_change_keystring (int who_old, const uint8_t *old_ks,
                      int who_new, const uint8_t *new_ks)
 {
-  int r = gpg_do_load_prvkey (GPG_KEY_FOR_SIGNATURE, who_old, old_ks);
+  int r;
+  int prv_keys_exist = 0;
+
+  r = gpg_do_load_prvkey (GPG_KEY_FOR_SIGNING, who_old, old_ks);
+  if (r < 0)
+    return r;
+
+  if (r > 0)
+    prv_keys_exist++;
+
+  r = gpg_do_chks_prvkey (GPG_KEY_FOR_SIGNING, who_old, old_ks,
+                         who_new, new_ks);
+  if (r < 0)
+    return -2;
 
-  if (r <= 0)
+  r = gpg_do_load_prvkey (GPG_KEY_FOR_DECRYPTION, who_old, old_ks);
+  if (r < 0)
     return r;
 
-  r = gpg_do_chks_prvkey (GPG_KEY_FOR_SIGNATURE, who_old, old_ks,
+  if (r > 0)
+    prv_keys_exist++;
+
+  r = gpg_do_chks_prvkey (GPG_KEY_FOR_DECRYPTION, who_old, old_ks,
                          who_new, new_ks);
   if (r < 0)
     return -2;
 
-  return r;
+  if (prv_keys_exist)
+    return 1;
+  else
+    return 0;
 }
 
 static void
@@ -171,21 +186,16 @@ cmd_change_password (void)
 
       if (pk == NULL)
        {
-         if (len < 6)
+         if (len < (int)strlen (OPENPGP_CARD_INITIAL_PW1))
            {
              DEBUG_INFO ("permission denied.\r\n");
              GPG_SECURITY_FAILURE ();
              return;
            }
 
-         /* pk==NULL implies we have no prvkey */
-         pw_len = 6;
+         pw_len = strlen (OPENPGP_CARD_INITIAL_PW1);
          newpw = pw + pw_len;
          newpw_len = len - pw_len;
-
-         sha1 (newpw, newpw_len, new_ks);
-         new_ks0[0] = newpw_len;
-         goto no_prvkey;
        }
       else
        {
@@ -235,18 +245,17 @@ cmd_change_password (void)
     }
   else if (r == 0 && who == 1) /* no prvkey */
     {
-    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");
+      DEBUG_INFO ("Changed DO_KEYSTRING_PW1.\r\n");
     }
   else if (r > 0 && who == 1)
     {
       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 ("Removed content of DO_KEYSTRING_PW1\r\n");
+      DEBUG_INFO ("Changed length of DO_KEYSTRING_PW1.\r\n");
     }
   else                         /* r >= 0 && who == 3 */
     {
@@ -435,9 +444,15 @@ cmd_read_binary (void)
       if (cmd_APDU[3] >= 6)
        GPG_BAD_P0_P1 ();
       else
-       /* Tag 5a, serial number */
-       write_res_apdu (read_binary_result,
-                       sizeof (read_binary_result), 0x90, 0x00);
+       {
+         int len = openpgpcard_aid[0];
+
+         res_APDU[0] = 0x5a;
+         memcpy (res_APDU+1, openpgpcard_aid, len);
+         res_APDU[len+1] = 0x90;
+         res_APDU[len+2] = 0x00;
+         res_APDU_size = len + 3;
+       }
     }
   else
     GPG_NO_RECORD();
@@ -545,7 +560,10 @@ cmd_pso (void)
 
          r = rsa_sign (&cmd_APDU[data_start], res_APDU, len);
          if (r < 0)
-           GPG_ERROR ();
+           {
+             ac_reset_pso_cds ();
+             GPG_ERROR ();
+           }
          else
            {                   /* Success */
              const uint8_t *pw_status_bytes = gpg_do_read_simple (NR_DO_PW_STATUS);
@@ -572,6 +590,8 @@ cmd_pso (void)
 
       DEBUG_SHORT (len);
 
+      ac_reset_pso_other ();
+
       /* Skip padding 0x00 */
       data_start++;
       len--;
index ca76579..932bc27 100644 (file)
@@ -193,9 +193,10 @@ static const uint8_t gnukStringProduct[] = {
 };
 
 static const uint8_t gnukStringSerial[] = {
-  8,                           /* bLength */
+  8*2+2,                       /* bLength */
   USB_STRING_DESCRIPTOR_TYPE,  /* bDescriptorType */
-  '2', 0, '.', 0, '0', 0
+  '2', 0, '0', 0, '1', 0, '0', 0,
+  '0', 0, '9', 0, '1', 0, '0', 0
 };
 
 const ONE_DESCRIPTOR Device_Descriptor = {
index b1f5fe0..e488fac 100644 (file)
@@ -21,6 +21,9 @@
  *
  */
 
+/* Packet size of USB Bulk transfer for full speed */
+#define GNUK_MAX_PACKET_SIZE 64
+
 #include "config.h"
 #include "usb_lib.h"
 #include "usb_conf.h"