[PATCH] scdaemon change for OpenPGPcard V3: Please test

NIIBE Yutaka gniibe at fsij.org
Tue Nov 22 09:40:15 CET 2016


Hello,

I found that OpenPGPcard V3 specification changed the semantics
of some data in Extended Capabilities.  I think that it is good
if scdaemon can support OpenPGPcard V2 and V3.

Here is my change.  Users who have OpenPGP card implementations,
I'd like to ask you testing with this code.

For Gnuk, it doesn't use extended Lc and extended Le at all, so it
doesn't matter.  (Although I tested already.)


diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c
index d1c9efe..0586fe4 100644
--- a/scd/app-openpgp.c
+++ b/scd/app-openpgp.c
@@ -195,10 +195,8 @@ struct app_local_s {
     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 max_certlen_3:16;
+    unsigned int max_certlen:16;
     unsigned int max_get_challenge:16; /* Maximum size for
get_challenge.  */
-    unsigned int max_cmd_data:16;      /* Maximum data size for a
command.  */
-    unsigned int max_rsp_data:16;      /* Maximum size of a response.  */
   } extcap;

   /* Flags used to control the application.  */
@@ -325,7 +323,7 @@ get_cached_data (app_t app, int tag,
     }

   if (try_extlen && app->app_local->cardcap.ext_lc_le)
-    exmode = app->app_local->extcap.max_rsp_data;
+    exmode = app->app_local->extcap.max_certlen + 2;
   else
     exmode = 0;

@@ -455,10 +453,7 @@ get_one_do (app_t app, int tag, unsigned char
**result, size_t *nbytes,

   if (app->card_version > 0x0100 && data_objects[i].get_immediate_in_v11)
     {
-      if (data_objects[i].try_extlen && app->app_local->cardcap.ext_lc_le)
-        exmode = app->app_local->extcap.max_rsp_data;
-      else
-        exmode = 0;
+      exmode = 0;
       rc = iso7816_get_data (app->slot, exmode, tag, &buffer, &buflen);
       if (rc)
         {
@@ -922,6 +917,40 @@ send_key_attr (ctrl_t ctrl, app_t app, const char
*keyword, int keyno)
 }


+
+enum {
+  OP_GET_PUBKEY,
+  OP_SIGN,
+  OP_DECIPHER,
+  OP_AUTH,
+};
+
+static int
+determine_response_size (app_t app, int keyno, int op)
+{
+  int size = 256;               /* Default */
+
+  if (app->app_local->keyattr[keyno].key_type == KEY_TYPE_RSA)
+    {
+      if (op == OP_GET_PUBKEY)
+        {
+          size = 2 + 3 /* header */
+            + 4 /* tag+len */ + app->app_local->keyattr[keyno].rsa.n_bits/8
+            + 2 /* tag+len */ +
app->app_local->keyattr[keyno].rsa.e_bits/8;
+
+          if (app->app_local->keyattr[keyno].rsa.n_bits <= 1024)
+            size = size - 2;
+        }
+      else
+        size = app->app_local->keyattr[keyno].rsa.n_bits / 8;
+
+      size += 2;        /* Add two for status bytes.  */
+    }
+
+  return size;
+}
+
+
 /* Implement the GETATTR command.  This is similar to the LEARN
    command but returns just one value via the status interface. */
 static gpg_error_t
@@ -991,13 +1020,13 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
       char tmp[110];

       snprintf (tmp, sizeof tmp,
-                "gc=%d ki=%d fc=%d pd=%d mcl3=%u aac=%d "
+                "gc=%d ki=%d fc=%d pd=%d mcl=%u aac=%d "
                 "sm=%d si=%u dec=%d bt=%d",
                 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.max_certlen_3,
+                app->app_local->extcap.max_certlen,
                 app->app_local->extcap.algo_attr_change,
                 (app->app_local->extcap.sm_supported
                  ? (app->app_local->extcap.sm_algo == 0? CIPHER_ALGO_3DES :
@@ -1534,7 +1563,7 @@ get_public_key (app_t app, int keyno)
       if (app->app_local->cardcap.ext_lc_le)
         {
           exmode = 1;    /* Use extended length.  */
-          le_value = app->app_local->extcap.max_rsp_data;
+          le_value = determine_response_size (app, keyno, OP_GET_PUBKEY);
         }
       else
         {
@@ -2285,7 +2314,7 @@ do_writecert (app_t app, ctrl_t ctrl,
     return gpg_error (GPG_ERR_INV_ARG);
   if (!app->app_local->extcap.is_v2)
     return gpg_error (GPG_ERR_NOT_SUPPORTED);
-  if (certdatalen > app->app_local->extcap.max_certlen_3)
+  if (certdatalen > app->app_local->extcap.max_certlen)
     return gpg_error (GPG_ERR_TOO_LARGE);
   return do_setattr (app, "CERT-3", pincb, pincb_arg, certdata,
certdatalen);
 #else
@@ -3774,7 +3803,7 @@ do_genkey (app_t app, ctrl_t ctrl,  const char
*keynostr, unsigned int flags,
       if (app->app_local->cardcap.ext_lc_le && keybits > 1900)
         {
           exmode = 1;    /* Use extended length w/o a limit.  */
-          le_value = app->app_local->extcap.max_rsp_data;
+          le_value = determine_response_size (app, keyno, OP_GET_PUBKEY);
           /* No need to check le_value because it comes from a 16 bit
              value and thus can't create an overflow on a 32 bit
              system.  */
@@ -4125,7 +4154,7 @@ do_sign (app_t app, const char *keyidstr, int
hashalgo,
   if (app->app_local->cardcap.ext_lc_le)
     {
       exmode = 1;    /* Use extended length.  */
-      le_value = app->app_local->extcap.max_rsp_data;
+      le_value = determine_response_size (app, 0, OP_SIGN);
     }
   else
     {
@@ -4228,7 +4257,7 @@ do_auth (app_t app, const char *keyidstr,
       if (app->app_local->cardcap.ext_lc_le)
         {
           exmode = 1;    /* Use extended length.  */
-          le_value = app->app_local->extcap.max_rsp_data;
+          le_value = determine_response_size (app, 2, OP_AUTH);
         }
       else
         {
@@ -4420,7 +4449,7 @@ do_decipher (app_t app, const char *keyidstr,
   if (app->app_local->cardcap.ext_lc_le && indatalen > 254 )
     {
       exmode = 1;    /* Extended length w/o a limit.  */
-      le_value = app->app_local->extcap.max_rsp_data;
+      le_value = determine_response_size (app, 1, OP_DECIPHER);
     }
   else if (app->app_local->cardcap.cmd_chaining && indatalen > 254)
     {
@@ -4577,9 +4606,7 @@ show_caps (struct app_local_s *s)
   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 ("Max-Cert3-Len ..: %u\n", s->extcap.max_certlen_3);
-  log_info ("Max-Cmd-Data ...: %u\n", s->extcap.max_cmd_data);
-  log_info ("Max-Rsp-Data ...: %u\n", s->extcap.max_rsp_data);
+  log_info ("Max-Cert-Len ..: %u\n", s->extcap.max_certlen);
   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);
@@ -4882,9 +4909,7 @@ app_select_openpgp (app_t app)
           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]);
-          app->app_local->extcap.max_cmd_data  = (buffer[6] << 8 |
buffer[7]);
-          app->app_local->extcap.max_rsp_data  = (buffer[8] << 8 |
buffer[9]);
+          app->app_local->extcap.max_certlen = (buffer[4] << 8 |
buffer[5]);
         }
       xfree (relptr);

-- 



More information about the Gnupg-devel mailing list