scd: Add support of ECC pubkey attribute.
authorNIIBE Yutaka <gniibe@fsij.org>
Fri, 16 Sep 2016 06:20:32 +0000 (15:20 +0900)
committerNIIBE Yutaka <gniibe@fsij.org>
Fri, 16 Sep 2016 06:36:45 +0000 (15:36 +0900)
* scd/app-openpgp.c (ECC_FLAG_PUBKEY): New.
(send_key_attr, get_public_key, ecc_writekey, do_auth, do_decipher)
(parse_algorithm_attribute): Check ECC_FLAG_DJB_TWEAK.
(build_ecc_privkey_template): Add ECC_Q and ECC_Q_LEN.
Support offering public key when ECC_FLAG_PUBKEY sets.
(ecc_writekey): Supply ECC_Q and ECC_Q_LEN.
(parse_algorithm_attribute): Parse pubkey-required byte.

--

OpenPGPcard protocol specification version 3.2 supports algorithm
attributes for ECC key which specifies public key data is required for
"keytocard" command.  This change supports the feature.

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
scd/app-openpgp.c

index 7dd1566..563a045 100644 (file)
@@ -236,6 +236,7 @@ struct app_local_s {
 };
 
 #define ECC_FLAG_DJB_TWEAK (1 << 0)
+#define ECC_FLAG_PUBKEY    (1 << 1)
 
 
 /***** Local prototypes  *****/
@@ -910,7 +911,7 @@ send_key_attr (ctrl_t ctrl, app_t app, const char *keyword, int keyno)
       snprintf (buffer, sizeof buffer, "%d %d %s",
                 keyno+1,
                 keyno==1? PUBKEY_ALGO_ECDH :
-                app->app_local->keyattr[keyno].ecc.flags?
+                (app->app_local->keyattr[keyno].ecc.flags & ECC_FLAG_DJB_TWEAK)?
                 PUBKEY_ALGO_EDDSA : PUBKEY_ALGO_ECDSA,
                 openpgp_oid_to_curve (app->app_local->keyattr[keyno].ecc.oid, 0));
     }
@@ -1387,7 +1388,7 @@ get_public_key (app_t app, int keyno)
 
   if ((app->app_local->keyattr[keyno].key_type == KEY_TYPE_RSA
        || (app->app_local->keyattr[keyno].key_type == KEY_TYPE_ECC
-           && !app->app_local->keyattr[keyno].ecc.flags))
+           && !(app->app_local->keyattr[keyno].ecc.flags & ECC_FLAG_DJB_TWEAK)))
       && mlen && (*m & 0x80))
     {               /* Prepend numbers with a 0 if needed for MPI.  */
       *mbuf = 0;
@@ -1395,7 +1396,7 @@ get_public_key (app_t app, int keyno)
       mlen++;
     }
   else if (app->app_local->keyattr[keyno].key_type == KEY_TYPE_ECC
-           && app->app_local->keyattr[keyno].ecc.flags)
+           && (app->app_local->keyattr[keyno].ecc.flags & ECC_FLAG_DJB_TWEAK))
     {               /* Prepend 0x40 prefix.  */
       *mbuf = 0x40;
       memcpy (mbuf+1, m, mlen);
@@ -1429,7 +1430,7 @@ get_public_key (app_t app, int keyno)
     {
       char *format;
 
-      if (!app->app_local->keyattr[keyno].ecc.flags)
+      if (!(app->app_local->keyattr[keyno].ecc.flags & ECC_FLAG_DJB_TWEAK))
         format = "(public-key(ecc(curve%s)(q%b)))";
       else if (keyno == 1)
         format = "(public-key(ecc(curve%s)(flags djb-tweak)(q%b)))";
@@ -2633,9 +2634,10 @@ build_privkey_template (app_t app, int keyno,
 static gpg_error_t
 build_ecc_privkey_template (app_t app, int keyno,
                             const unsigned char *ecc_d, size_t ecc_d_len,
+                            const unsigned char *ecc_q, size_t ecc_q_len,
                             unsigned char **result, size_t *resultlen)
 {
-  unsigned char privkey[2];
+  unsigned char privkey[2+2];
   size_t privkey_len;
   unsigned char exthdr[2+2+1];
   size_t exthdr_len;
@@ -2645,8 +2647,10 @@ build_ecc_privkey_template (app_t app, int keyno,
   size_t datalen;
   unsigned char *template;
   size_t template_size;
+  int pubkey_required;
 
-  (void)app;
+  pubkey_required = !!(app->app_local->keyattr[keyno].ecc.flags
+                       & ECC_FLAG_PUBKEY);
 
   *result = NULL;
   *resultlen = 0;
@@ -2658,8 +2662,15 @@ build_ecc_privkey_template (app_t app, int keyno,
   tp += add_tlv (tp, 0x92, ecc_d_len);
   datalen += ecc_d_len;
 
+  if (pubkey_required)
+    {
+      tp += add_tlv (tp, 0x99, ecc_q_len);
+      datalen += ecc_q_len;
+    }
+
   privkey_len = tp - privkey;
 
+
   /* Build the extended header list without the private key template.  */
   tp = exthdr;
   *tp++ = keyno ==0 ? 0xb6 : keyno == 1? 0xb8 : 0xa4;
@@ -2693,6 +2704,12 @@ build_ecc_privkey_template (app_t app, int keyno,
   memcpy (tp, ecc_d, ecc_d_len);
   tp += ecc_d_len;
 
+  if (pubkey_required)
+    {
+      memcpy (tp, ecc_q, ecc_q_len);
+      tp += ecc_q_len;
+    }
+
   assert (tp - template == template_size);
 
   *result = template;
@@ -3348,7 +3365,8 @@ ecc_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **),
 
   if (app->app_local->keyattr[keyno].key_type != KEY_TYPE_ECC
       || app->app_local->keyattr[keyno].ecc.oid != oidstr
-      || app->app_local->keyattr[keyno].ecc.flags != flag_djb_tweak)
+      || (flag_djb_tweak !=
+          (app->app_local->keyattr[keyno].ecc.flags & ECC_FLAG_DJB_TWEAK)))
     {
       if (app->app_local->extcap.algo_attr_change)
         {
@@ -3387,6 +3405,7 @@ ecc_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **),
 
       err = build_ecc_privkey_template (app, keyno,
                                         ecc_d, ecc_d_len,
+                                        ecc_q, ecc_q_len,
                                         &template, &template_len);
       if (err)
         goto leave;
@@ -3991,7 +4010,7 @@ do_auth (app_t app, const char *keyidstr,
 
   if (app->app_local->keyattr[2].key_type == KEY_TYPE_ECC)
     {
-      if (!app->app_local->keyattr[2].ecc.flags
+      if (!(app->app_local->keyattr[2].ecc.flags & ECC_FLAG_DJB_TWEAK)
           && (indatalen == 51 || indatalen == 67 || indatalen == 83))
         {
           const char *p = (const char *)indata + 19;
@@ -4190,7 +4209,7 @@ do_decipher (app_t app, const char *keyidstr,
     {
       int old_format_len = 0;
 
-      if (app->app_local->keyattr[1].ecc.flags)
+      if ((app->app_local->keyattr[1].ecc.flags & ECC_FLAG_DJB_TWEAK))
         {
           if (indatalen > 32 && (indatalen % 2))
             { /*
@@ -4258,7 +4277,7 @@ do_decipher (app_t app, const char *keyidstr,
                          outdata, outdatalen);
   xfree (fixbuf);
   if (app->app_local->keyattr[1].key_type == KEY_TYPE_ECC
-      && app->app_local->keyattr[1].ecc.flags)
+      && (app->app_local->keyattr[1].ecc.flags & ECC_FLAG_DJB_TWEAK))
     { /* Add the prefix 0x40 */
       fixbuf = xtrymalloc (*outdatalen + 1);
       if (!fixbuf)
@@ -4550,7 +4569,19 @@ parse_algorithm_attribute (app_t app, int keyno)
   else if (*buffer == PUBKEY_ALGO_ECDH || *buffer == PUBKEY_ALGO_ECDSA
            || *buffer == PUBKEY_ALGO_EDDSA)
     {
-      const char *oid = ecc_oid (buffer + 1, buflen - 1);
+      const char *oid;
+      int oidlen = buflen - 1;
+
+      app->app_local->keyattr[keyno].ecc.flags = 0;
+
+      if (buffer[buflen-1] == 0x00 || buffer[buflen-1] == 0xff)
+        { /* Found "pubkey required"-byte for private key template.  */
+          oidlen--;
+          if (buffer[buflen-1] == 0xff)
+            app->app_local->keyattr[keyno].ecc.flags |= ECC_FLAG_PUBKEY;
+        }
+
+      oid = ecc_oid (buffer + 1, oidlen);
 
       if (!oid)
         log_printhex ("Curve with OID not supported: ", buffer+1, buflen-1);
@@ -4562,14 +4593,12 @@ parse_algorithm_attribute (app_t app, int keyno)
               || (*buffer == PUBKEY_ALGO_ECDH
                   && !strcmp (app->app_local->keyattr[keyno].ecc.oid,
                               "1.3.6.1.4.1.3029.1.5.1")))
-            app->app_local->keyattr[keyno].ecc.flags = ECC_FLAG_DJB_TWEAK;
-          else
-            app->app_local->keyattr[keyno].ecc.flags = 0;
+            app->app_local->keyattr[keyno].ecc.flags |= ECC_FLAG_DJB_TWEAK;
           if (opt.verbose)
             log_printf
               ("ECC, curve=%s%s\n", app->app_local->keyattr[keyno].ecc.oid,
-               !app->app_local->keyattr[keyno].ecc.flags ? "":
-               keyno==1? " (djb-tweak)": " (eddsa)");
+               !(app->app_local->keyattr[keyno].ecc.flags & ECC_FLAG_DJB_TWEAK)?
+               "": keyno==1? " (djb-tweak)": " (eddsa)");
         }
     }
   else if (opt.verbose)