w32: Also change the directory on daemon startup.
[gnupg.git] / scd / app-openpgp.c
index 90c2661..365f246 100644 (file)
 #include "scdaemon.h"
 #endif /* GNUPG_MAJOR_VERSION != 1 */
 
-#include "util.h"
-#include "i18n.h"
+#include "../common/util.h"
+#include "../common/i18n.h"
 #include "iso7816.h"
 #include "app-common.h"
-#include "tlv.h"
-#include "host2net.h"
-#include "openpgpdefs.h"
+#include "../common/tlv.h"
+#include "../common/host2net.h"
+#include "../common/openpgpdefs.h"
 
 
 /* A table describing the DOs of the card.  */
@@ -76,21 +76,24 @@ static struct {
   int tag;
   int constructed;
   int get_from;  /* Constructed DO with this DO or 0 for direct access. */
-  int binary:1;
-  int dont_cache:1;
-  int flush_on_error:1;
-  int get_immediate_in_v11:1; /* Enable a hack to bypass the cache of
+  unsigned int binary:1;
+  unsigned int dont_cache:1;
+  unsigned int flush_on_error:1;
+  unsigned int get_immediate_in_v11:1; /* Enable a hack to bypass the cache of
                                  this data object if it is used in 1.1
                                  and later versions of the card.  This
                                  does not work with composite DO and
                                  is currently only useful for the CHV
                                  status bytes. */
-  int try_extlen:1;           /* Large object; try to use an extended
-                                 length APDU.  */
+  unsigned int try_extlen:2;           /* Large object; try to use an extended
+                                 length APDU when !=0.  The size is
+                                 determined by extcap.max_certlen_3
+                                 when == 1, and by extcap.max_special_do
+                                 when == 2.  */
   char *desc;
 } data_objects[] = {
-  { 0x005E, 0,    0, 1, 0, 0, 0, 0, "Login Data" },
-  { 0x5F50, 0,    0, 0, 0, 0, 0, 0, "URL" },
+  { 0x005E, 0,    0, 1, 0, 0, 0, 2, "Login Data" },
+  { 0x5F50, 0,    0, 0, 0, 0, 0, 2, "URL" },
   { 0x5F52, 0,    0, 1, 0, 0, 0, 0, "Historical Bytes" },
   { 0x0065, 1,    0, 1, 0, 0, 0, 0, "Cardholder Related Data"},
   { 0x005B, 0, 0x65, 0, 0, 0, 0, 0, "Name" },
@@ -110,10 +113,10 @@ static struct {
   { 0x00CD, 0, 0x6E, 1, 0, 0, 0, 0, "Generation time" },
   { 0x007A, 1,    0, 1, 0, 0, 0, 0, "Security Support Template" },
   { 0x0093, 0, 0x7A, 1, 1, 0, 0, 0, "Digital Signature Counter" },
-  { 0x0101, 0,    0, 0, 0, 0, 0, 0, "Private DO 1"},
-  { 0x0102, 0,    0, 0, 0, 0, 0, 0, "Private DO 2"},
-  { 0x0103, 0,    0, 0, 0, 0, 0, 0, "Private DO 3"},
-  { 0x0104, 0,    0, 0, 0, 0, 0, 0, "Private DO 4"},
+  { 0x0101, 0,    0, 0, 0, 0, 0, 2, "Private DO 1"},
+  { 0x0102, 0,    0, 0, 0, 0, 0, 2, "Private DO 2"},
+  { 0x0103, 0,    0, 0, 0, 0, 0, 2, "Private DO 3"},
+  { 0x0104, 0,    0, 0, 0, 0, 0, 2, "Private DO 4"},
   { 0x7F21, 1,    0, 1, 0, 0, 0, 1, "Cardholder certificate"},
   /* V3.0 */
   { 0x7F74, 0,    0, 1, 0, 0, 0, 0, "General Feature Management"},
@@ -185,18 +188,25 @@ struct app_local_s {
   /* Keep track of extended card capabilities.  */
   struct
   {
-    unsigned int is_v2:1;              /* This is a v2.0 compatible card.  */
-    unsigned int sm_supported:1;       /* Secure Messaging is supported.  */
+    unsigned int is_v2:1;              /* Compatible to v2 or later.        */
+    unsigned int extcap_v3:1;          /* Extcap is in v3 format.           */
+    unsigned int has_button:1;         /* Has confirmation button or not.   */
+
+    unsigned int sm_supported:1;       /* Secure Messaging is supported.    */
     unsigned int get_challenge:1;
     unsigned int key_import:1;
     unsigned int change_force_chv:1;
     unsigned int private_dos:1;
     unsigned int algo_attr_change:1;   /* Algorithm attributes changeable.  */
-    unsigned int has_decrypt:1;        /* Support symmetric decryption.  */
-    unsigned int has_button:1;
-    unsigned int sm_algo:2;            /* Symmetric crypto algo for SM.  */
+    unsigned int has_decrypt:1;        /* Support symmetric decryption.     */
+    unsigned int kdf_do:1;                /* Support KDF DOs.               */
+
+    unsigned int sm_algo:2;            /* Symmetric crypto algo for SM.     */
+    unsigned int pin_blk2:1;           /* PIN block 2 format supported.     */
+    unsigned int mse:1;                /* MSE command supported.            */
     unsigned int max_certlen_3:16;
-    unsigned int max_get_challenge:16; /* Maximum size for get_challenge.  */
+    unsigned int max_get_challenge:16; /* Maximum size for get_challenge.   */
+    unsigned int max_special_do:16;    /* Maximum size for special DOs.     */
   } extcap;
 
   /* Flags used to control the application.  */
@@ -323,7 +333,14 @@ get_cached_data (app_t app, int tag,
     }
 
   if (try_extlen && app->app_local->cardcap.ext_lc_le)
-    exmode = app->app_local->extcap.max_certlen_3;
+    {
+      if (try_extlen == 1)
+        exmode = app->app_local->extcap.max_certlen_3;
+      else if (try_extlen == 2 && app->app_local->extcap.extcap_v3)
+        exmode = app->app_local->extcap.max_special_do;
+      else
+        exmode = 0;
+    }
   else
     exmode = 0;
 
@@ -1280,7 +1297,6 @@ retrieve_key_material (FILE *fp, const char *hexkeyid,
 
       if ( strcmp (fields[0], "pkd") )
         continue; /* Not a key data record.  */
-      i = 0; /* Avoid erroneous compiler warning. */
       if ( nfields < 4 || (i = atoi (fields[1])) < 0 || i > 1
            || (!i && m_new) || (i && e_new))
         {
@@ -1589,7 +1605,7 @@ read_public_key (app_t app, ctrl_t ctrl, u32 created_at, int keyno,
 }
 
 
-/* Get the public key for KEYNO and store it as an S-expresion with
+/* Get the public key for KEYNO and store it as an S-expression with
    the APP handle.  On error that field gets cleared.  If we already
    know about the public key we will just return.  Note that this does
    not mean a key is available; this is solely indicated by the
@@ -1597,7 +1613,7 @@ read_public_key (app_t app, ctrl_t ctrl, u32 created_at, int keyno,
 
    Note that GnuPG 1.x does not need this and it would be too time
    consuming to send it just for the fun of it. However, given that we
-   use the same code in gpg 1.4, we can't use the gcry S-expresion
+   use the same code in gpg 1.4, we can't use the gcry S-expression
    here but need to open encode it. */
 #if GNUPG_MAJOR_VERSION > 1
 static gpg_error_t
@@ -1986,19 +2002,30 @@ get_prompt_info (app_t app, int chvno, unsigned long sigcount, int remaining)
   disp_name = get_disp_name (app);
   if (chvno == 1)
     {
-      result = xtryasprintf (_("Card number:\t%s%%0A"
-                               "Signatures:\t%lu%%0A"
-                               "Cardholder:\t%s"),
+      /* TRANSLATORS: Put a \x1f right before a colon.  This can be
+       * used by pinentry to nicely align the names and values.  Keep
+       * the %s at the start and end of the string.  */
+      result = xtryasprintf (_("%s"
+                               "Number\x1f: %s%%0A"
+                               "Holder\x1f: %s%%0A"
+                               "Counter\x1f: %lu"
+                               "%s"),
+                             "\x1e",
                              serial,
+                             disp_name? disp_name:"",
                              sigcount,
-                             disp_name? disp_name:"");
+                             "");
     }
   else
     {
-      result = xtryasprintf (_("Card number:\t%s%%0A"
-                               "Cardholder:\t%s"),
+      result = xtryasprintf (_("%s"
+                               "Number\x1f: %s%%0A"
+                               "Holder\x1f: %s"
+                               "%s"),
+                             "\x1e",
                              serial,
-                             disp_name? disp_name:"");
+                             disp_name? disp_name:"",
+                             "");
     }
   xfree (disp_name);
   xfree (serial);
@@ -2641,7 +2668,7 @@ do_change_pin (app_t app, ctrl_t ctrl,  const char *chvnostr,
       rc = pincb (pincb_arg, set_resetcode? _("|RN|New Reset Code") :
                   chvno == 3? _("|AN|New Admin PIN") : _("|N|New PIN"),
                   &pinvalue);
-      if (rc)
+      if (rc || pinvalue == NULL)
         {
           log_error (_("error getting new PIN: %s\n"), gpg_strerror (rc));
           goto leave;
@@ -3341,8 +3368,7 @@ rsa_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **),
   maxbits = app->app_local->keyattr[keyno].rsa.n_bits;
   nbits = rsa_n? count_bits (rsa_n, rsa_n_len) : 0;
   if (opt.verbose)
-    log_info ("RSA modulus size is %u bits (%u bytes)\n",
-              nbits, (unsigned int)rsa_n_len);
+    log_info ("RSA modulus size is %u bits\n", nbits);
   if (nbits && nbits != maxbits
       && app->app_local->extcap.algo_attr_change)
     {
@@ -4731,7 +4757,14 @@ do_check_pin (app_t app, const char *keyidstr,
 static void
 show_caps (struct app_local_s *s)
 {
-  log_info ("Version-2 ......: %s\n", s->extcap.is_v2? "yes":"no");
+  log_info ("Version-2+ .....: %s\n", s->extcap.is_v2? "yes":"no");
+  log_info ("Extcap-v3 ......: %s\n", s->extcap.extcap_v3? "yes":"no");
+  log_info ("Button .........: %s\n", s->extcap.has_button? "yes":"no");
+
+  log_info ("SM-Support .....: %s", s->extcap.sm_supported? "yes":"no");
+  if (s->extcap.sm_supported)
+    log_printf (" (%s)", s->extcap.sm_algo==2? "3DES":
+                (s->extcap.sm_algo==2? "AES-128" : "AES-256"));
   log_info ("Get-Challenge ..: %s", s->extcap.get_challenge? "yes":"no");
   if (s->extcap.get_challenge)
     log_printf (" (%u bytes max)", s->extcap.max_get_challenge);
@@ -4739,16 +4772,18 @@ show_caps (struct app_local_s *s)
   log_info ("Change-Force-PW1: %s\n", s->extcap.change_force_chv? "yes":"no");
   log_info ("Private-DOs ....: %s\n", s->extcap.private_dos? "yes":"no");
   log_info ("Algo-Attr-Change: %s\n", s->extcap.algo_attr_change? "yes":"no");
-  log_info ("SM-Support .....: %s", s->extcap.sm_supported? "yes":"no");
-  if (s->extcap.sm_supported)
-    log_printf (" (%s)", s->extcap.sm_algo==2? "3DES":
-                (s->extcap.sm_algo==2? "AES-128" : "AES-256"));
+  log_info ("Symmetric Crypto: %s\n", s->extcap.has_decrypt? "yes":"no");
+  log_info ("KDF-Support ....: %s\n", s->extcap.kdf_do? "yes":"no");
   log_info ("Max-Cert3-Len ..: %u\n", s->extcap.max_certlen_3);
+  if (s->extcap.extcap_v3)
+    {
+      log_info ("PIN-Block-2 ....: %s\n", s->extcap.pin_blk2? "yes":"no");
+      log_info ("MSE-Support ....: %s\n", s->extcap.mse? "yes":"no");
+      log_info ("Max-Special-DOs : %u\n", s->extcap.max_special_do);
+    }
   log_info ("Cmd-Chaining ...: %s\n", s->cardcap.cmd_chaining?"yes":"no");
   log_info ("Ext-Lc-Le ......: %s\n", s->cardcap.ext_lc_le?"yes":"no");
-  log_info ("Status Indicator: %02X\n", s->status_indicator);
-  log_info ("Symmetric crypto: %s\n", s->extcap.has_decrypt? "yes":"no");
-  log_info ("Button..........: %s\n", s->extcap.has_button? "yes":"no");
+  log_info ("Status-Indicator: %02X\n", s->status_indicator);
 
   log_info ("GnuPG-No-Sync ..: %s\n",  s->flags.no_sync? "yes":"no");
   log_info ("GnuPG-Def-PW2 ..: %s\n",  s->flags.def_chv2? "yes":"no");
@@ -4997,6 +5032,8 @@ app_select_openpgp (app_t app)
       if (app->card_version >= 0x0200)
         app->app_local->extcap.is_v2 = 1;
 
+      if (app->card_version >= 0x0300)
+        app->app_local->extcap.extcap_v3 = 1;
 
       /* Read the historical bytes.  */
       relptr = get_one_do (app, 0x5f52, &buffer, &buflen, NULL);
@@ -5039,14 +5076,24 @@ app_select_openpgp (app_t app)
           app->app_local->extcap.private_dos      = !!(*buffer & 0x08);
           app->app_local->extcap.algo_attr_change = !!(*buffer & 0x04);
           app->app_local->extcap.has_decrypt      = !!(*buffer & 0x02);
+          app->app_local->extcap.kdf_do           = !!(*buffer & 0x01);
         }
       if (buflen >= 10)
         {
-          /* Available with v2 cards.  */
+          /* Available with cards of v2 or later.  */
           app->app_local->extcap.sm_algo = buffer[1];
           app->app_local->extcap.max_get_challenge
                                                = (buffer[2] << 8 | buffer[3]);
           app->app_local->extcap.max_certlen_3 = (buffer[4] << 8 | buffer[5]);
+
+          /* Interpretation is different between v2 and v3, unfortunately.  */
+          if (app->app_local->extcap.extcap_v3)
+            {
+              app->app_local->extcap.max_special_do
+                = (buffer[6] << 8 | buffer[7]);
+              app->app_local->extcap.pin_blk2 = !!(buffer[8] & 0x01);
+              app->app_local->extcap.mse= !!(buffer[9] & 0x01);
+            }
         }
       xfree (relptr);