prompt change.
[gnupg.git] / scd / app-openpgp.c
index 94dff60..cfc51ce 100644 (file)
@@ -85,6 +85,7 @@ static struct {
   { 0x0102, 0,    0, 0, 0, 0, 0, "Private DO 2"},
   { 0x0103, 0,    0, 0, 0, 0, 0, "Private DO 3"},
   { 0x0104, 0,    0, 0, 0, 0, 0, "Private DO 4"},
+  { 0x7F21, 1,    0, 1, 0, 0, 0, "Cardholder certificate"},
   { 0 }
 };
 
@@ -120,10 +121,12 @@ struct app_local_s {
   /* Keep track of card capabilities.  */
   struct 
   {
+    unsigned int is_v2:1;  /* This is a v2.0 compatible card.  */
     unsigned int get_challenge:1;
     unsigned int key_import:1;
     unsigned int change_force_chv:1;
     unsigned int private_dos:1;
+    unsigned int max_certlen_3:16;
   } extcap;
 
   /* Flags used to control the application.  */
@@ -481,7 +484,7 @@ count_bits (const unsigned char *a, size_t len)
   return n;
 }
 
-/* GnuPG makes special use of the login-data DO, this fucntion parses
+/* GnuPG makes special use of the login-data DO, this function parses
    the login data to store the flags for later use.  It may be called
    at any time and should be called after changing the login-data DO.
 
@@ -740,11 +743,12 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
     {
       char tmp[50];
 
-      sprintf (tmp, "gc=%d ki=%d fc=%d pd=%d", 
+      sprintf (tmp, "gc=%d ki=%d fc=%d pd=%d mcl3=%u", 
                app->app_local->extcap.get_challenge,
                app->app_local->extcap.key_import,
                app->app_local->extcap.change_force_chv,
-               app->app_local->extcap.private_dos);
+               app->app_local->extcap.private_dos,
+               app->app_local->extcap.max_certlen_3);
       send_status_info (ctrl, table[idx].name, tmp, strlen (tmp), NULL, 0);
       return 0;
     }
@@ -1274,6 +1278,47 @@ do_readkey (app_t app, const char *keyid, unsigned char **pk, size_t *pklen)
 #endif
 }
 
+/* Read the statdard certificate of an OpenPGP v2 card.  It is
+   returned in a freshly allocated buffer with that address stored at
+   CERT and the length of the certificate stored at CERTLEN.  CERTID
+   needs to be set to "OpenPGP.3".  */
+static gpg_error_t
+do_readcert (app_t app, const char *certid,
+             unsigned char **cert, size_t *certlen)
+{
+#if GNUPG_MAJOR_VERSION > 1
+  gpg_error_t err;
+  unsigned char *buffer;
+  size_t buflen;
+  void *relptr;
+
+  *cert = NULL;
+  *certlen = 0;
+  if (strcmp (certid, "OPENPGP.3"))
+    return gpg_error (GPG_ERR_INV_ID);
+  if (app->app_local->extcap.is_v2)
+    return gpg_error (GPG_ERR_NOT_FOUND);
+
+  relptr = get_one_do (app, 0x00C4, &buffer, &buflen, NULL);
+  if (!relptr)
+    return gpg_error (GPG_ERR_NOT_FOUND);
+
+  *cert = xtrymalloc (buflen);
+  if (!*cert)
+    err = gpg_error_from_syserror ();
+  else
+    {
+      memcpy (*cert, buffer, buflen);
+      *certlen = buflen;
+      err  = 0;
+    }
+  xfree (relptr);
+  return err;
+#else
+  return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+#endif
+}
+
 
 /* Verify a CHV either using using the pinentry or if possibile by
    using a keypad.  PINCB and PINCB_ARG describe the usual callback
@@ -1300,6 +1345,25 @@ verify_a_chv (app_t app,
 
   *pinvalue = NULL;
 
+  if (chvno == 2 && app->app_local->flags.def_chv2)
+    {
+      /* Special case for def_chv2 mechanism. */
+      if (opt.verbose)
+        log_info (_("using default PIN as %s\n"), "CHV2");
+      rc = iso7816_verify (app->slot, 0x82, "123456", 6);
+      if (rc)
+        {
+          /* Verification of CHV2 with the default PIN failed,
+             although the card pretends to have the default PIN set as
+             CHV2.  We better disable the def_chv2 flag now. */
+          log_info (_("failed to use default PIN as %s: %s"
+                      " - disabling further default use\n"),
+                    "CHV2", gpg_strerror (rc));
+          app->app_local->flags.def_chv2 = 0;
+        }
+      return rc;
+    }
+
   memset (&pininfo, 0, sizeof pininfo);
   pininfo.mode = 1;
   pininfo.minlen = minlen;
@@ -1348,7 +1412,7 @@ verify_a_chv (app_t app,
 #define PROMPTSTRING  _("||Please enter the PIN%%0A[sigs done: %lu]")
           size_t promptsize = strlen (PROMPTSTRING) + 50;
 
-          prompt = xmalloc (promptsize);
+          prompt = xtrymalloc (promptsize);
           if (!prompt)
             return gpg_error_from_syserror ();
           snprintf (prompt, promptsize-1, PROMPTSTRING, sigcount);
@@ -1357,7 +1421,7 @@ verify_a_chv (app_t app,
 #undef PROMPTSTRING
         }
       else
-        rc = pincb (pincb_arg, "PIN", pinvalue); 
+        rc = pincb (pincb_arg, _("||Please enter the PIN"), pinvalue); 
 
       if (rc)
         {
@@ -1569,6 +1633,7 @@ do_setattr (app_t app, const char *name,
     int tag;
     int need_chv;
     int special;
+    unsigned int need_v2:1;
   } table[] = {
     { "DISP-NAME",    0x005B, 3 },
     { "LOGIN-DATA",   0x005E, 3, 2 },
@@ -1583,6 +1648,7 @@ do_setattr (app_t app, const char *name,
     { "PRIVATE-DO-2", 0x0102, 3 },
     { "PRIVATE-DO-3", 0x0103, 2 },
     { "PRIVATE-DO-4", 0x0104, 3 },
+    { "CERT-3",       0x7F21, 3, 0, 1 },
     { NULL, 0 }
   };
 
@@ -1591,6 +1657,8 @@ do_setattr (app_t app, const char *name,
     ;
   if (!table[idx].name)
     return gpg_error (GPG_ERR_INV_NAME); 
+  if (!table[idx].need_v2)
+    return gpg_error (GPG_ERR_NOT_SUPPORTED); 
 
   switch (table[idx].need_chv)
     {
@@ -1625,13 +1693,15 @@ do_setattr (app_t app, const char *name,
 
 /* Handle the PASSWD command. */
 static gpg_error_t 
-do_change_pin (app_t app, ctrl_t ctrl,  const char *chvnostr, int reset_mode,
+do_change_pin (app_t app, ctrl_t ctrl,  const char *chvnostr, 
+               unsigned int flags,
                gpg_error_t (*pincb)(void*, const char *, char **),
                void *pincb_arg)
 {
   int rc = 0;
   int chvno = atoi (chvnostr);
   char *pinvalue;
+  int reset_mode = !!(flags & APP_CHANGE_FLAG_RESET);
 
   if (reset_mode && chvno == 3)
     {
@@ -2698,6 +2768,9 @@ app_select_openpgp (app_t app)
           goto leave;
         }
 
+      if (app->card_version >= 0x0200)
+        app->app_local->extcap.is_v2 = 1;
+
       relptr = get_one_do (app, 0x00C4, &buffer, &buflen, NULL);
       if (!relptr)
         {
@@ -2722,6 +2795,11 @@ app_select_openpgp (app_t app)
           app->app_local->extcap.change_force_chv = !!(*buffer & 0x10);
           app->app_local->extcap.private_dos      = !!(*buffer & 0x08);
         }
+      if (buflen >= 10)
+        {
+          /* Available with v2 cards.  */
+          app->app_local->extcap.max_certlen_3 = (buffer[4] << 8 | buffer[5]);
+        }
       xfree (relptr);
       
       /* Some of the first cards accidently don't set the
@@ -2736,6 +2814,7 @@ app_select_openpgp (app_t app)
 
       app->fnc.deinit = do_deinit;
       app->fnc.learn_status = do_learn_status;
+      app->fnc.readcert = do_readcert;
       app->fnc.readkey = do_readkey;
       app->fnc.getattr = do_getattr;
       app->fnc.setattr = do_setattr;