scd: better handling of extended APDU.
[gnupg.git] / scd / app-p15.c
index 4203a68..8322617 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GnuPG is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation; either version 3 of the License, or
  * (at your option) any later version.
  *
  * GnuPG is distributed in the hope that it will be useful,
@@ -14,8 +14,7 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 /* Information pertaining to the BELPIC developer card samples:
@@ -519,7 +518,7 @@ parse_certid (app_t app, const char *certid,
   objidlen /= 2;
   objid = xtrymalloc (objidlen);
   if (!objid)
-    return gpg_error_from_errno (errno);
+    return gpg_error_from_syserror ();
   for (s=certid, i=0; i < objidlen; i++, s+=2)
     objid[i] = xtoi_2 (s);
   *r_objid = objid;
@@ -691,7 +690,8 @@ read_ef_odf (app_t app, unsigned short odf_fid)
     }
 
   if (buflen)
-    log_info ("warning: %u bytes of garbage detected at end of ODF\n", buflen);
+    log_info ("warning: %u bytes of garbage detected at end of ODF\n",
+              (unsigned int)buflen);
 
   xfree (buffer);
   return 0;
@@ -1129,14 +1129,14 @@ read_ef_prkdf (app_t app, unsigned short fid, prkdf_object_t *result)
                               + objlen/2 * sizeof(unsigned short)));
       if (!prkdf)
         {
-          err = gpg_error_from_errno (errno);
+          err = gpg_error_from_syserror ();
           goto leave;
         }
       prkdf->objidlen = objidlen;
       prkdf->objid = xtrymalloc (objidlen);
       if (!prkdf->objid)
         {
-          err = gpg_error_from_errno (errno);
+          err = gpg_error_from_syserror ();
           xfree (prkdf);
           goto leave;
         }
@@ -1147,7 +1147,7 @@ read_ef_prkdf (app_t app, unsigned short fid, prkdf_object_t *result)
           prkdf->authid = xtrymalloc (authidlen);
           if (!prkdf->authid)
             {
-              err = gpg_error_from_errno (errno);
+              err = gpg_error_from_syserror ();
               xfree (prkdf->objid);
               xfree (prkdf);
               goto leave;
@@ -1415,14 +1415,14 @@ read_ef_cdf (app_t app, unsigned short fid, cdf_object_t *result)
                             + objlen/2 * sizeof(unsigned short)));
       if (!cdf)
         {
-          err = gpg_error_from_errno (errno);
+          err = gpg_error_from_syserror ();
           goto leave;
         }
       cdf->objidlen = objidlen;
       cdf->objid = xtrymalloc (objidlen);
       if (!cdf->objid)
         {
-          err = gpg_error_from_errno (errno);
+          err = gpg_error_from_syserror ();
           xfree (cdf);
           goto leave;
         }
@@ -2134,7 +2134,7 @@ read_ef_aodf (app_t app, unsigned short fid, aodf_object_t *result)
       continue; /* Ready. */
 
     no_core:
-      err = gpg_error_from_errno (errno);
+      err = gpg_error_from_syserror ();
       release_aodf_object (aodf);
       goto leave;
 
@@ -2271,7 +2271,7 @@ read_ef_tokeninfo (app_t app)
   app->app_local->serialno = xtrymalloc (objlen);
   if (!app->app_local->serialno)
     {
-      err = gpg_error_from_errno (errno);
+      err = gpg_error_from_syserror ();
       goto leave;
     }
   memcpy (app->app_local->serialno, p, objlen);
@@ -2363,11 +2363,10 @@ send_certinfo (app_t app, ctrl_t ctrl, const char *certtype,
   for (; certinfo; certinfo = certinfo->next)
     {
       char *buf, *p;
-      int i;
 
       buf = xtrymalloc (9 + certinfo->objidlen*2 + 1);
       if (!buf)
-        return gpg_error_from_errno (errno);
+        return gpg_error_from_syserror ();
       p = stpcpy (buf, "P15");
       if (app->app_local->home_df)
         {
@@ -2375,11 +2374,7 @@ send_certinfo (app_t app, ctrl_t ctrl, const char *certtype,
           p += 5;
         }
       p = stpcpy (p, ".");
-      for (i=0; i < certinfo->objidlen; i++)
-        {
-          sprintf (p, "%02X", certinfo->objid[i]);
-          p += 2;
-        }
+      bin2hex (certinfo->objid, certinfo->objidlen, p);
 
       send_status_info (ctrl, "CERTINFO",
                         certtype, strlen (certtype),
@@ -2458,11 +2453,11 @@ send_keypairinfo (app_t app, ctrl_t ctrl, prkdf_object_t keyinfo)
     {
       char gripstr[40+1];
       char *buf, *p;
-      int i, j;
+      int j;
 
       buf = xtrymalloc (9 + keyinfo->objidlen*2 + 1);
       if (!buf)
-        return gpg_error_from_errno (errno);
+        return gpg_error_from_syserror ();
       p = stpcpy (buf, "P15");
       if (app->app_local->home_df)
         {
@@ -2470,11 +2465,7 @@ send_keypairinfo (app_t app, ctrl_t ctrl, prkdf_object_t keyinfo)
           p += 5;
         }
       p = stpcpy (p, ".");
-      for (i=0; i < keyinfo->objidlen; i++)
-        {
-          sprintf (p, "%02X", keyinfo->objid[i]);
-          p += 2;
-        }
+      bin2hex (keyinfo->objid, keyinfo->objidlen, p);
 
       err = keygripstr_from_prkdf (app, keyinfo, gripstr);
       if (err)
@@ -2501,17 +2492,23 @@ send_keypairinfo (app_t app, ctrl_t ctrl, prkdf_object_t keyinfo)
 
 /* This is the handler for the LEARN command.  */
 static gpg_error_t 
-do_learn_status (app_t app, ctrl_t ctrl)
+do_learn_status (app_t app, ctrl_t ctrl, unsigned int flags)
 {
   gpg_error_t err;
 
-  err = send_certinfo (app, ctrl, "100", app->app_local->certificate_info);
-  if (!err)
-    err = send_certinfo (app, ctrl, "101",
-                         app->app_local->trusted_certificate_info);
-  if (!err)
-    err = send_certinfo (app, ctrl, "102",
-                         app->app_local->useful_certificate_info);
+  if ((flags & 1))
+    err = 0;
+  else
+    {
+      err = send_certinfo (app, ctrl, "100", app->app_local->certificate_info);
+      if (!err)
+        err = send_certinfo (app, ctrl, "101",
+                             app->app_local->trusted_certificate_info);
+      if (!err)
+        err = send_certinfo (app, ctrl, "102",
+                             app->app_local->useful_certificate_info);
+    }
+
   if (!err)
     err = send_keypairinfo (app, ctrl, app->app_local->private_key_info);
 
@@ -2543,7 +2540,7 @@ readcert_by_cdf (app_t app, cdf_object_t cdf,
     {
       *r_cert = xtrymalloc (cdf->imagelen);
       if (!*r_cert)
-        return gpg_error_from_errno (errno);
+        return gpg_error_from_syserror ();
       memcpy (*r_cert, cdf->image, cdf->imagelen);
       *r_certlen = cdf->imagelen;
       return 0;
@@ -2669,7 +2666,6 @@ static gpg_error_t
 do_getattr (app_t app, ctrl_t ctrl, const char *name)
 {
   gpg_error_t err;
-  int i;
 
   if (!strcmp (name, "$AUTHKEYID"))
     {
@@ -2686,7 +2682,7 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
         {
           buf = xtrymalloc (9 + prkdf->objidlen*2 + 1);
           if (!buf)
-            return gpg_error_from_errno (errno);
+            return gpg_error_from_syserror ();
           p = stpcpy (buf, "P15");
           if (app->app_local->home_df)
             {
@@ -2694,11 +2690,7 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
               p += 5;
             }
           p = stpcpy (p, ".");
-          for (i=0; i < prkdf->objidlen; i++)
-            {
-              sprintf (p, "%02X", prkdf->objid[i]);
-              p += 2;
-            }
+          bin2hex (prkdf->objid, prkdf->objidlen, p);
 
           send_status_info (ctrl, name, buf, strlen (buf), NULL, 0);
           xfree (buf);
@@ -2711,7 +2703,7 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
          general rule for it so we need to decide case by case. */
       if (app->app_local->card_type == CARD_TYPE_BELPIC)
         {
-          /* The eID card has a card number printed on the fron matter
+          /* The eID card has a card number printed on the front matter
              which seems to be a good indication. */
           unsigned char *buffer;
           const unsigned char *p;
@@ -2867,8 +2859,9 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
 
   gpg_error_t err;
   int i;
-  unsigned char data[35];   /* Must be large enough for a SHA-1 digest
-                               + the largest OID prefix above. */
+  unsigned char data[36];   /* Must be large enough for a SHA-1 digest
+                               + the largest OID prefix above and also
+                               fit the 36 bytes of md5sha1.  */
   prkdf_object_t prkdf;    /* The private key object. */
   aodf_object_t aodf;      /* The associated authentication object. */
   int no_data_padding = 0; /* True if the card want the data without padding.*/
@@ -2876,7 +2869,7 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
 
   if (!keyidstr || !*keyidstr)
     return gpg_error (GPG_ERR_INV_VALUE);
-  if (indatalen != 20 && indatalen != 16 && indatalen != 35)
+  if (indatalen != 20 && indatalen != 16 && indatalen != 35 && indatalen != 36)
     return gpg_error (GPG_ERR_INV_VALUE);
 
   err = prkdf_object_from_keyidstr (app, keyidstr, &prkdf);
@@ -2916,7 +2909,7 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
   if (aodf->pinflags.integrity_protected
       || aodf->pinflags.confidentiality_protected)
     {
-      log_error ("PIN verification requires unsupported protecion method\n");
+      log_error ("PIN verification requires unsupported protection method\n");
       return gpg_error (GPG_ERR_BAD_PIN_METHOD);
     }
   if (!aodf->stored_length && aodf->pinflags.needs_padding)
@@ -2937,7 +2930,7 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
 
 
   /* Due to the fact that the non-repudiation signature on a BELPIC
-     card requires a ver verify immediately before the DSO we set the
+     card requires a verify immediately before the DSO we set the
      MSE before we do the verification.  Other cards might allow to do
      this also but I don't want to break anything, thus we do it only
      for the BELPIC card here. */
@@ -2947,7 +2940,10 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
       
       mse[0] = 4;    /* Length of the template. */
       mse[1] = 0x80; /* Algorithm reference tag. */
-      mse[2] = 0x02; /* Algorithm: RSASSA-PKCS1-v1.5 using SHA1. */
+      if (hashalgo == MD_USER_TLS_MD5SHA1)
+        mse[2] = 0x01; /* Let card do pkcs#1 0xFF padding. */
+      else
+        mse[2] = 0x02; /* RSASSA-PKCS1-v1.5 using SHA1. */
       mse[3] = 0x84; /* Private key reference tag. */
       mse[4] = prkdf->key_reference_valid? prkdf->key_reference : 0x82;
 
@@ -3058,7 +3054,7 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
           paddedpin = xtrymalloc (aodf->stored_length+1);
           if (!paddedpin)
             {
-              err = gpg_error_from_errno (errno);
+              err = gpg_error_from_syserror ();
               xfree (pinvalue);
               return err;
             }
@@ -3086,7 +3082,7 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
           paddedpin = xtrymalloc (aodf->stored_length+1);
           if (!paddedpin)
             {
-              err = gpg_error_from_errno (errno);
+              err = gpg_error_from_syserror ();
               xfree (pinvalue);
               return err;
             }
@@ -3117,7 +3113,14 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
     }
 
   /* Prepare the DER object from INDATA. */
-  if (indatalen == 35)
+  if (indatalen == 36)
+    {
+      /* No ASN.1 container used. */
+      if (hashalgo != MD_USER_TLS_MD5SHA1)
+        return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
+      memcpy (data, indata, indatalen);
+    }
+  else if (indatalen == 35)
     {
       /* Alright, the caller was so kind to send us an already
          prepared DER object.  Check that it is what we want and that
@@ -3176,17 +3179,19 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
       return err;
     }
 
-  if (no_data_padding)
-    err = iso7816_compute_ds (app->slot, data+15, 20, outdata, outdatalen);
+  if (hashalgo == MD_USER_TLS_MD5SHA1)
+    err = iso7816_compute_ds (app->slot, 0, data, 36, 0, outdata, outdatalen);
+  else if (no_data_padding)
+    err = iso7816_compute_ds (app->slot, 0, data+15, 20, 0,outdata,outdatalen);
   else
-    err = iso7816_compute_ds (app->slot, data, 35, outdata, outdatalen);
+    err = iso7816_compute_ds (app->slot, 0, data, 35, 0, outdata, outdatalen);
   return err;
 }
 
 
 /* Handler for the PKAUTH command. 
 
-   This is basically the same as the PKSIGN command but we firstcheck
+   This is basically the same as the PKSIGN command but we first check
    that the requested key is suitable for authentication; that is, it
    must match the criteria used for the attribute $AUTHKEYID.  See
    do_sign for calling conventions; there is no HASHALGO, though. */
@@ -3199,6 +3204,7 @@ do_auth (app_t app, const char *keyidstr,
 {
   gpg_error_t err;
   prkdf_object_t prkdf;
+  int algo;
 
   if (!keyidstr || !*keyidstr)
     return gpg_error (GPG_ERR_INV_VALUE);
@@ -3211,7 +3217,9 @@ do_auth (app_t app, const char *keyidstr,
       log_error ("key %s may not be used for authentication\n", keyidstr);
       return gpg_error (GPG_ERR_WRONG_KEY_USAGE);
     }
-  return do_sign (app, keyidstr, GCRY_MD_SHA1, pincb, pincb_arg, 
+
+  algo = indatalen == 36? MD_USER_TLS_MD5SHA1 : GCRY_MD_SHA1;
+  return do_sign (app, keyidstr, algo, pincb, pincb_arg, 
                   indata, indatalen, outdata, outdatalen);
 }
 
@@ -3344,7 +3352,7 @@ app_select_p15 (app_t app)
       app->app_local = xtrycalloc (1, sizeof *app->app_local);
       if (!app->app_local)
         {
-          rc = gpg_error_from_errno (errno);
+          rc = gpg_error_from_syserror ();
           goto leave;
         }