common: Provide a function for mapping packet types to strings.
[gnupg.git] / scd / app-openpgp.c
index f7ad274..7dd1566 100644 (file)
@@ -1223,7 +1223,7 @@ retrieve_key_material (FILE *fp, const char *hexkeyid,
 /* Get the public key for KEYNO and store it as an S-expresion 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 soley indicated by the
+   not mean a key is available; this is solely indicated by the
    presence of the app->app_local->pk[KEYNO].key field.
 
    Note that GnuPG 1.x does not need this and it would be too time
@@ -1468,7 +1468,7 @@ get_public_key (app_t app, int keyno)
   xfree (buffer);
   xfree (mbuf);
   xfree (ebuf);
-  return 0;
+  return err;
 }
 #endif /* GNUPG_MAJOR_VERSION > 1 */
 
@@ -1548,7 +1548,7 @@ do_learn_status (app_t app, ctrl_t ctrl, unsigned int flags)
   send_keypair_info (app, ctrl, 2);
   send_keypair_info (app, ctrl, 3);
   /* Note: We do not send the Cardholder Certificate, because that is
-     relativly long and for OpenPGP applications not really needed.  */
+     relatively long and for OpenPGP applications not really needed.  */
   return 0;
 }
 
@@ -1675,7 +1675,7 @@ check_pinpad_request (app_t app, pininfo_t *pininfo, int admin_pin)
 }
 
 
-/* Verify a CHV either using using the pinentry or if possibile by
+/* Verify a CHV either using using the pinentry or if possible by
    using a pinpad.  PINCB and PINCB_ARG describe the usual callback
    for the pinentry.  CHVNO must be either 1 or 2. SIGCOUNT is only
    used with CHV1.  PINVALUE is the address of a pointer which will
@@ -1874,8 +1874,11 @@ build_enter_admin_pin_prompt (app_t app, char **r_prompt)
   remaining = value[6];
   xfree (relptr);
 
-  log_info(_("%d Admin PIN attempts remaining before card"
-             " is permanently locked\n"), remaining);
+  log_info (ngettext("%d Admin PIN attempt remaining before card"
+                     " is permanently locked\n",
+                     "%d Admin PIN attempts remaining before card"
+                     " is permanently locked\n",
+                     remaining), remaining);
 
   if (remaining < 3)
     {
@@ -2729,6 +2732,43 @@ change_keyattr (app_t app, int keyno, const unsigned char *buf, size_t buflen,
 }
 
 
+static gpg_error_t
+change_rsa_keyattr (app_t app, int keyno, unsigned int nbits,
+                    gpg_error_t (*pincb)(void*, const char *, char **),
+                    void *pincb_arg)
+{
+  gpg_error_t err = 0;
+  unsigned char *buf;
+  size_t buflen;
+  void *relptr;
+
+  /* Read the current attributes into a buffer.  */
+  relptr = get_one_do (app, 0xC1+keyno, &buf, &buflen, NULL);
+  if (!relptr)
+    err = gpg_error (GPG_ERR_CARD);
+  else if (buflen < 6 || buf[0] != PUBKEY_ALGO_RSA)
+    {
+      /* Attriutes too short or not an RSA key.  */
+      xfree (relptr);
+      err = gpg_error (GPG_ERR_CARD);
+    }
+  else
+    {
+      /* We only change n_bits and don't touch anything else.  Before we
+         do so, we round up NBITS to a sensible way in the same way as
+         gpg's key generation does it.  This may help to sort out problems
+         with a few bits too short keys.  */
+      nbits = ((nbits + 31) / 32) * 32;
+      buf[1] = (nbits >> 8);
+      buf[2] = nbits;
+      err = change_keyattr (app, keyno, buf, buflen, pincb, pincb_arg);
+      xfree (relptr);
+    }
+
+  return err;
+}
+
+
 /* Helper to process an setattr command for name KEY-ATTR.
    In (VALUE,VALUELEN), it expects following string:
         RSA: "--force <key> <algo> rsa<nbits>"
@@ -2756,8 +2796,8 @@ change_keyattr_from_string (app_t app,
   /* Because this function deletes the key we require the string
      "--force" in the data to make clear that something serious might
      happen.  */
-  sscanf (string, " --force %d %d %n", &key, &algo, &n);
-  if (n < 13)
+  sscanf (string, "--force %d %d %n", &key, &algo, &n);
+  if (n < 12)
     {
       err = gpg_error (GPG_ERR_INV_DATA);
       goto leave;
@@ -2779,36 +2819,7 @@ change_keyattr_from_string (app_t app,
       else if (nbits > 4096)
         err = gpg_error (GPG_ERR_TOO_LARGE);
       else
-        {
-          unsigned char *buf;
-          size_t buflen;
-          void *relptr;
-
-          /* Read the current attributes into a buffer.  */
-          relptr = get_one_do (app, 0xC1+keyno, &buf, &buflen, NULL);
-          if (!relptr)
-            {
-              err = gpg_error (GPG_ERR_CARD);
-              goto leave;
-            }
-          if (buflen < 6 || buf[0] != PUBKEY_ALGO_RSA)
-            {
-              /* Attriutes too short or not an RSA key.  */
-              xfree (relptr);
-              err = gpg_error (GPG_ERR_CARD);
-              goto leave;
-            }
-
-          /* We only change n_bits and don't touch anything else.  Before we
-             do so, we round up NBITS to a sensible way in the same way as
-             gpg's key generation does it.  This may help to sort out problems
-             with a few bits too short keys.  */
-          nbits = ((nbits + 31) / 32) * 32;
-          buf[1] = (nbits >> 8);
-          buf[2] = nbits;
-          err = change_keyattr (app, keyno, buf, buflen, pincb, pincb_arg);
-          xfree (relptr);
-        }
+        err = change_rsa_keyattr (app, keyno, nbits, pincb, pincb_arg);
     }
   else if (algo == PUBKEY_ALGO_ECDH || algo == PUBKEY_ALGO_ECDSA
            || algo == PUBKEY_ALGO_EDDSA)
@@ -2971,6 +2982,14 @@ rsa_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **),
   if (opt.verbose)
     log_info ("RSA modulus size is %u bits (%u bytes)\n",
               nbits, (unsigned int)rsa_n_len);
+  if (nbits && nbits != maxbits
+      && app->app_local->extcap.algo_attr_change)
+    {
+      /* Try to switch the key to a new length.  */
+      err = change_rsa_keyattr (app, keyno, nbits, pincb, pincb_arg);
+      if (!err)
+        maxbits = app->app_local->keyattr[keyno].rsa.n_bits;
+    }
   if (nbits != maxbits)
     {
       log_error (_("RSA modulus missing or not of size %d bits\n"),
@@ -3227,11 +3246,12 @@ ecc_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **),
         {
           const unsigned char **buf2;
           size_t *buf2len;
+          int native = flag_djb_tweak;
 
           switch (*tok)
             {
             case 'q': buf2 = &ecc_q; buf2len = &ecc_q_len; break;
-            case 'd': buf2 = &ecc_d; buf2len = &ecc_d_len; break;
+            case 'd': buf2 = &ecc_d; buf2len = &ecc_d_len; native = 0; break;
             default: buf2 = NULL;  buf2len = NULL; break;
             }
           if (buf2 && *buf2)
@@ -3241,13 +3261,16 @@ ecc_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **),
             }
           if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
             goto leave;
-          if (tok && buf2 && !flag_djb_tweak)
-            /* It's MPI.  Strip off leading zero bytes and save. */
-            for (;toklen && !*tok; toklen--, tok++)
-              ;
+          if (tok && buf2)
+            {
+              if (!native)
+                /* Strip off leading zero bytes and save. */
+                for (;toklen && !*tok; toklen--, tok++)
+                  ;
 
-          *buf2 = tok;
-          *buf2len = toklen;
+              *buf2 = tok;
+              *buf2len = toklen;
+            }
         }
       /* Skip until end of list. */
       last_depth2 = depth;
@@ -3327,9 +3350,22 @@ ecc_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **),
       || app->app_local->keyattr[keyno].ecc.oid != oidstr
       || app->app_local->keyattr[keyno].ecc.flags != flag_djb_tweak)
     {
-      log_error ("key attribute on card doesn't match\n");
-      err = gpg_error (GPG_ERR_INV_VALUE);
-      goto leave;
+      if (app->app_local->extcap.algo_attr_change)
+        {
+          unsigned char keyattr[oid_len];
+
+          keyattr[0] = algo;
+          memcpy (keyattr+1, oidbuf+1, oid_len-1);
+          err = change_keyattr (app, keyno, keyattr, oid_len, pincb, pincb_arg);
+          if (err)
+            goto leave;
+        }
+      else
+        {
+          log_error ("key attribute on card doesn't match\n");
+          err = gpg_error (GPG_ERR_INV_VALUE);
+          goto leave;
+        }
     }
 
   if (opt.verbose)
@@ -3554,8 +3590,13 @@ do_genkey (app_t app, ctrl_t ctrl,  const char *keynostr, unsigned int flags,
       log_error (_("generating key failed\n"));
       goto leave;
     }
-  log_info (_("key generation completed (%d seconds)\n"),
-            (int)(time (NULL) - start_at));
+
+  {
+    int nsecs = (int)(time (NULL) - start_at);
+    log_info (ngettext("key generation completed (%d second)\n",
+                       "key generation completed (%d seconds)\n",
+                       nsecs), nsecs);
+  }
 
   keydata = find_tlv (buffer, buflen, 0x7F49, &keydatalen);
   if (!keydata)
@@ -3590,6 +3631,11 @@ do_genkey (app_t app, ctrl_t ctrl,  const char *keynostr, unsigned int flags,
   send_status_info (ctrl, "KEY-CREATED-AT",
                     numbuf, (size_t)strlen(numbuf), NULL, 0);
 
+  for (; mlen && !*m; mlen--, m++) /* strip leading zeroes */
+    ;
+  for (; elen && !*e; elen--, e++) /* strip leading zeroes */
+    ;
+
   rc = store_fpr (app, keyno, (u32)created_at, fprbuf, PUBKEY_ALGO_RSA,
                   m, mlen, e, elen);
   if (rc)
@@ -4081,9 +4127,12 @@ do_decipher (app_t app, const char *keyidstr,
   if (rc)
     return rc;
 
-  if (indatalen == 16 + 1 || indatalen == 32 + 1)
-    /* PSO:DECIPHER with symmetric key.  */
-    padind = -1;
+  if ((indatalen == 16 + 1 || indatalen == 32 + 1)
+      && ((char *)indata)[0] == 0x02)
+    {
+      /* PSO:DECIPHER with symmetric key.  */
+      padind = -1;
+    }
   else if (app->app_local->keyattr[1].key_type == KEY_TYPE_RSA)
     {
       /* We might encounter a couple of leading zeroes in the
@@ -4139,6 +4188,27 @@ do_decipher (app_t app, const char *keyidstr,
     }
   else if (app->app_local->keyattr[1].key_type == KEY_TYPE_ECC)
     {
+      int old_format_len = 0;
+
+      if (app->app_local->keyattr[1].ecc.flags)
+        {
+          if (indatalen > 32 && (indatalen % 2))
+            { /*
+               * Skip the prefix.  It may be 0x40 (in new format), or MPI
+               * head of 0x00 (in old format).
+               */
+              indata = (const char *)indata + 1;
+              indatalen--;
+            }
+          else if (indatalen < 32)
+            { /*
+               * Old format trancated by MPI handling.
+               */
+              old_format_len = indatalen;
+              indatalen = 32;
+            }
+        }
+
       fixuplen = 7;
       fixbuf = xtrymalloc (fixuplen + indatalen);
       if (!fixbuf)
@@ -4152,7 +4222,16 @@ do_decipher (app_t app, const char *keyidstr,
       fixbuf[4] = (char)(indatalen+2);
       fixbuf[5] = '\x86';
       fixbuf[6] = (char)indatalen;
-      memcpy (fixbuf+fixuplen, indata, indatalen);
+      if (old_format_len)
+        {
+          memset (fixbuf+fixuplen, 0, 32 - old_format_len);
+          memcpy (fixbuf+fixuplen + 32 - old_format_len,
+                  indata, old_format_len);
+        }
+      else
+        {
+          memcpy (fixbuf+fixuplen, indata, indatalen);
+        }
       indata = fixbuf;
       indatalen = fixuplen + indatalen;
 
@@ -4178,6 +4257,21 @@ do_decipher (app_t app, const char *keyidstr,
                          indata, indatalen, le_value, padind,
                          outdata, outdatalen);
   xfree (fixbuf);
+  if (app->app_local->keyattr[1].key_type == KEY_TYPE_ECC
+      && app->app_local->keyattr[1].ecc.flags)
+    { /* Add the prefix 0x40 */
+      fixbuf = xtrymalloc (*outdatalen + 1);
+      if (!fixbuf)
+        {
+          xfree (*outdata);
+          return gpg_error_from_syserror ();
+        }
+      fixbuf[0] = 0x40;
+      memcpy (fixbuf+1, *outdata, *outdatalen);
+      xfree (*outdata);
+      *outdata = fixbuf;
+      *outdatalen = *outdatalen + 1;
+    }
 
   if (gpg_err_code (rc) == GPG_ERR_CARD /* actual SW is 0x640a */
       && app->app_local->manufacturer == 5
@@ -4599,7 +4693,7 @@ app_select_openpgp (app_t app)
         }
       xfree (relptr);
 
-      /* Some of the first cards accidently don't set the
+      /* Some of the first cards accidentally don't set the
          CHANGE_FORCE_CHV bit but allow it anyway. */
       if (app->card_version <= 0x0100 && manufacturer == 1)
         app->app_local->extcap.change_force_chv = 1;