Imported Upstream version 2.2.21 upstream/2.2.21
authorDongHun Kwak <dh0128.kwak@samsung.com>
Tue, 9 Feb 2021 07:00:52 +0000 (16:00 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Tue, 9 Feb 2021 07:00:52 +0000 (16:00 +0900)
110 files changed:
NEWS
agent/agent.h
agent/call-pinentry.c
agent/command.c
agent/cvt-openpgp.c
agent/divert-scd.c
agent/genkey.c
agent/gpg-agent.c
agent/pkdecrypt.c
agent/protect-tool.c
common/audit.c
common/compliance.c
common/compliance.h
common/logging.c
common/logging.h
common/openpgpdefs.h
common/percent.c
common/sexputil.c
common/util.h
configure.ac
dirmngr/crlcache.c
dirmngr/crlfetch.c
dirmngr/dirmngr.c
dirmngr/dns.c
dirmngr/dns.h
dirmngr/ldap-parse-uri.c
dirmngr/misc.c
dirmngr/ocsp.c
dirmngr/validate.c
doc/DETAILS
doc/Makefile.am
doc/gpgsm.texi
g10/call-agent.c
g10/call-agent.h
g10/card-util.c
g10/decrypt-data.c
g10/dek.h
g10/ecdh.c
g10/encrypt.c
g10/export.c
g10/getkey.c
g10/gpg.c
g10/keyedit.c
g10/keyid.c
g10/keylist.c
g10/main.h
g10/mainproc.c
g10/misc.c
g10/packet.h
g10/parse-packet.c
g10/passphrase.c
g10/pubkey-enc.c
g10/sig-check.c
g10/sign.c
g13/call-syshelp.c
g13/g13tuple.c
po/POTFILES.in
po/ca.po
po/cs.po
po/da.po
po/de.po
po/el.po
po/eo.po
po/es.po
po/et.po
po/fi.po
po/fr.po
po/gl.po
po/hu.po
po/id.po
po/it.po
po/ja.po
po/nb.po
po/pl.po
po/pt.po
po/ro.po
po/ru.po
po/sk.po
po/sv.po
po/tr.po
po/uk.po
po/zh_CN.po
po/zh_TW.po
scd/apdu.c
scd/app-common.h
scd/app-dinsig.c
scd/app-help.c
scd/app-nks.c
scd/app-openpgp.c
scd/app-p15.c
scd/app-sc-hsm.c
scd/iso7816.c
scd/iso7816.h
sm/call-agent.c
sm/call-dirmngr.c
sm/certchain.c
sm/certcheck.c
sm/certdump.c
sm/certreqgen.c
sm/decrypt.c
sm/encrypt.c
sm/fingerprint.c
sm/gpgsm.c
sm/gpgsm.h
sm/import.c
sm/keylist.c
sm/misc.c
sm/sign.c
sm/verify.c
tools/send-mail.c

diff --git a/NEWS b/NEWS
index 7ab0bb6..50aeb64 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,49 @@
+Noteworthy changes in version 2.2.21 (2020-07-09)
+-------------------------------------------------
+
+  * gpg: Improve symmetric decryption speed by about 25%.
+    See commit 144b95cc9d.
+
+  * gpg: Support decryption of AEAD encrypted data packets.
+
+  * gpg: Add option --no-include-key-block. [#4856]
+
+  * gpg: Allow for extra padding in ECDH.  [#4908]
+
+  * gpg: Only a single pinentry is shown for symmetric encryption if
+    the pinentry supports this.  [#4971]
+
+  * gpg: Print a note if no keys are given to --delete-key.  [#4959]
+
+  * gpg,gpgsm: The ridiculous passphrase quality bar is not anymore
+    shown.  [#2103]
+
+  * gpgsm: Certificates without a CRL distribution point are now
+    considered valid without looking up a CRL.  The new option
+    --enable-issuer-based-crl-check can be used to revert to the
+    former behaviour.
+
+  * gpgsm: Support rsaPSS signature verification.  [#4538]
+
+  * gpgsm: Unless CRL checking is disabled lookup a missing issuer
+    certificate using the certificate's authorityInfoAccess.  [#4898]
+
+  * gpgsm: Print the certificate's serial number also in decimal
+    notation.
+
+  * gpgsm: Fix possible NULL-deref in messages of --gen-key.  [#4895]
+
+  * scd: Support the CardOS 5 based D-Trust Card 3.1.
+
+  * dirmngr: Allow http URLs with "LOOKUP --url".
+
+  * wkd: Take name of sendmail from configure.  Fixes an OpenBSD
+    specific bug.  [#4886]
+
+  Release-info: https://dev.gnupg.org/T4897
+  See-also: gnupg-announce/2020q3/000446.html
+
+
 Noteworthy changes in version 2.2.20 (2020-03-20)
 -------------------------------------------------
 
index e10e02b..8b5ae60 100644 (file)
@@ -447,7 +447,8 @@ gpg_error_t agent_askpin (ctrl_t ctrl,
 int agent_get_passphrase (ctrl_t ctrl, char **retpass,
                           const char *desc, const char *prompt,
                           const char *errtext, int with_qualitybar,
-                         const char *keyinfo, cache_mode_t cache_mode);
+                         const char *keyinfo, cache_mode_t cache_mode,
+                          struct pin_entry_info_s *pininfo);
 int agent_get_confirmation (ctrl_t ctrl, const char *desc, const char *ok,
                            const char *notokay, int with_cancel);
 int agent_show_message (ctrl_t ctrl, const char *desc, const char *ok_btn);
@@ -484,7 +485,7 @@ int agent_pkdecrypt (ctrl_t ctrl, const char *desc_text,
                      membuf_t *outbuf, int *r_padding);
 
 /*-- genkey.c --*/
-int check_passphrase_constraints (ctrl_t ctrl, const char *pw,
+int check_passphrase_constraints (ctrl_t ctrl, const char *pw, int no_empty,
                                  char **failed_constraint);
 gpg_error_t agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt,
                                       char **r_passphrase);
index b0b5bcb..2af94c9 100644 (file)
@@ -85,6 +85,7 @@ struct entry_parm_s
   int lines;
   size_t size;
   unsigned char *buffer;
+  int status;
 };
 
 
@@ -836,7 +837,7 @@ inq_quality (void *opaque, const char *line)
       else
         {
           percent = estimate_passphrase_quality (pin);
-          if (check_passphrase_constraints (NULL, pin, NULL))
+          if (check_passphrase_constraints (NULL, pin, 0, NULL))
             percent = -percent;
           snprintf (numbuf, sizeof numbuf, "%d", percent);
           rc = assuan_send_data (ctx, numbuf, strlen (numbuf));
@@ -953,6 +954,36 @@ build_cmd_setdesc (char *line, size_t linelen, const char *desc)
 }
 
 
+/* Ask pinentry to get a pin by "GETPIN" command, spawning a thread
+ * detecting the socket's EOF.   */
+static gpg_error_t
+do_getpin (ctrl_t ctrl, struct entry_parm_s *parm)
+{
+  gpg_error_t rc;
+  int saveflag = assuan_get_flag (entry_ctx, ASSUAN_CONFIDENTIAL);
+
+  (void)ctrl;
+
+  assuan_begin_confidential (entry_ctx);
+  rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, parm,
+                        inq_quality, entry_ctx,
+                        pinentry_status_cb, &parm->status);
+  assuan_set_flag (entry_ctx, ASSUAN_CONFIDENTIAL, saveflag);
+  /* Most pinentries out in the wild return the old Assuan error code
+     for canceled which gets translated to an assuan Cancel error and
+     not to the code for a user cancel.  Fix this here. */
+  if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
+    rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
+  /* Change error code in case the window close button was clicked
+     to cancel the operation.  */
+  if ((parm->status & PINENTRY_STATUS_CLOSE_BUTTON)
+      && gpg_err_code (rc) == GPG_ERR_CANCELED)
+    rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_FULLY_CANCELED);
+
+  return rc;
+}
+
+
 \f
 /* Call the Entry and ask for the PIN.  We do check for a valid PIN
    number here and repeat it as long as we have invalid formed
@@ -970,7 +1001,6 @@ agent_askpin (ctrl_t ctrl,
   struct entry_parm_s parm;
   const char *errtext = NULL;
   int is_pin = 0;
-  int saveflag;
 
   if (opt.batch)
     return 0; /* fixme: we should return BAD PIN */
@@ -1114,25 +1144,8 @@ agent_askpin (ctrl_t ctrl,
             return unlock_pinentry (ctrl, rc);
         }
 
-      saveflag = assuan_get_flag (entry_ctx, ASSUAN_CONFIDENTIAL);
-      assuan_begin_confidential (entry_ctx);
-      rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm,
-                            inq_quality, entry_ctx,
-                            pinentry_status_cb, &pininfo->status);
-      assuan_set_flag (entry_ctx, ASSUAN_CONFIDENTIAL, saveflag);
-      /* Most pinentries out in the wild return the old Assuan error code
-         for canceled which gets translated to an assuan Cancel error and
-         not to the code for a user cancel.  Fix this here. */
-      if (rc && gpg_err_source (rc)
-          && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
-        rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
-
-
-      /* Change error code in case the window close button was clicked
-         to cancel the operation.  */
-      if ((pininfo->status & PINENTRY_STATUS_CLOSE_BUTTON)
-         && gpg_err_code (rc) == GPG_ERR_CANCELED)
-        rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_FULLY_CANCELED);
+      rc = do_getpin (ctrl, &parm);
+      pininfo->status = parm.status;
 
       if (gpg_err_code (rc) == GPG_ERR_ASS_TOO_MUCH_DATA)
         errtext = is_pin? L_("PIN too long")
@@ -1183,9 +1196,11 @@ agent_askpin (ctrl_t ctrl,
         }
 
       if ((pininfo->status & PINENTRY_STATUS_PASSWORD_FROM_CACHE))
-       /* The password was read from the cache.  Don't count this
-          against the retry count.  */
-       pininfo->failed_tries --;
+        {
+          /* The password was read from the cache.  Don't count this
+             against the retry count.  */
+          pininfo->failed_tries --;
+        }
     }
 
   return unlock_pinentry (ctrl, gpg_error (pininfo->min_digits? GPG_ERR_BAD_PIN
@@ -1195,19 +1210,22 @@ agent_askpin (ctrl_t ctrl,
 
 \f
 /* Ask for the passphrase using the supplied arguments.  The returned
-   passphrase needs to be freed by the caller. */
+   passphrase needs to be freed by the caller.  PININFO is optional
+   and can be used to have constraints checinkg while the pinentry
+   dialog is open (like what we do in agent_askpin).  This is very
+   similar to agent_akpin and we should eventually merge the two
+   functions. */
 int
 agent_get_passphrase (ctrl_t ctrl,
                       char **retpass, const char *desc, const char *prompt,
                       const char *errtext, int with_qualitybar,
-                     const char *keyinfo, cache_mode_t cache_mode)
+                     const char *keyinfo, cache_mode_t cache_mode,
+                      struct pin_entry_info_s *pininfo)
 {
-
   int rc;
+  int is_pin;
   char line[ASSUAN_LINELENGTH];
   struct entry_parm_s parm;
-  int saveflag;
-  unsigned int pinentry_status;
 
   *retpass = NULL;
   if (opt.batch)
@@ -1215,17 +1233,42 @@ agent_get_passphrase (ctrl_t ctrl,
 
   if (ctrl->pinentry_mode != PINENTRY_MODE_ASK)
     {
+      unsigned char *passphrase;
+      size_t size;
+
       if (ctrl->pinentry_mode == PINENTRY_MODE_CANCEL)
         return gpg_error (GPG_ERR_CANCELED);
 
-      if (ctrl->pinentry_mode == PINENTRY_MODE_LOOPBACK)
+      if (ctrl->pinentry_mode == PINENTRY_MODE_LOOPBACK && pininfo)
         {
-         size_t size;
+         *pininfo->pin = 0; /* Reset the PIN. */
+         rc = pinentry_loopback (ctrl, "PASSPHRASE",
+                                  &passphrase, &size,
+                                  pininfo->max_length - 1);
+          if (rc)
+            return rc;
 
+         memcpy (&pininfo->pin, passphrase, size);
+          wipememory (passphrase, size);
+         xfree (passphrase);
+         pininfo->pin[size] = 0;
+         if (pininfo->check_cb)
+           {
+             /* More checks by utilizing the optional callback. */
+             pininfo->cb_errtext = NULL;
+             rc = pininfo->check_cb (pininfo);
+           }
+         return rc;
+
+        }
+      else if (ctrl->pinentry_mode == PINENTRY_MODE_LOOPBACK)
+        {
+          /* Legacy variant w/o PININFO.  */
          return pinentry_loopback (ctrl, "PASSPHRASE",
                                    (unsigned char **)retpass, &size,
                                     MAX_PASSPHRASE_LEN);
         }
+
       return gpg_error (GPG_ERR_NO_PIN_ENTRY);
     }
 
@@ -1233,9 +1276,14 @@ agent_get_passphrase (ctrl_t ctrl,
   if (rc)
     return rc;
 
-  if (!prompt)
-    prompt = desc && strstr (desc, "PIN")? L_("PIN:"): L_("Passphrase:");
-
+  /* Set IS_PIN and if needed a default prompt.  */
+  if (prompt)
+    is_pin = !!strstr (prompt, "PIN");
+  else
+    {
+      is_pin = desc && strstr (desc, "PIN");
+      prompt = is_pin? L_("PIN:"): L_("Passphrase:");
+    }
 
   /* If we have a KEYINFO string and are normal, user, or ssh cache
      mode, we tell that the Pinentry so it may use it for own caching
@@ -1256,7 +1304,6 @@ agent_get_passphrase (ctrl_t ctrl,
   if (rc && gpg_err_code (rc) != GPG_ERR_ASS_UNKNOWN_CMD)
     return unlock_pinentry (ctrl, rc);
 
-
   if (desc)
     build_cmd_setdesc (line, DIM(line), desc);
   else
@@ -1270,7 +1317,8 @@ agent_get_passphrase (ctrl_t ctrl,
   if (rc)
     return unlock_pinentry (ctrl, rc);
 
-  if (with_qualitybar && opt.min_passphrase_len)
+  if ((with_qualitybar || (pininfo && pininfo->with_qualitybar))
+       && opt.min_passphrase_len)
     {
       rc = setup_qualitybar (ctrl);
       if (rc)
@@ -1280,40 +1328,132 @@ agent_get_passphrase (ctrl_t ctrl,
   if (errtext)
     {
       snprintf (line, DIM(line), "SETERROR %s", errtext);
-      rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
+      rc = assuan_transact (entry_ctx, line,
+                            NULL, NULL, NULL, NULL, NULL, NULL);
       if (rc)
         return unlock_pinentry (ctrl, rc);
     }
 
-  memset (&parm, 0, sizeof parm);
-  parm.size = ASSUAN_LINELENGTH/2 - 5;
-  parm.buffer = gcry_malloc_secure (parm.size+10);
-  if (!parm.buffer)
-    return unlock_pinentry (ctrl, out_of_core ());
+  if (!pininfo)
+    {
+      /* Legacy method without PININFO.  */
+      memset (&parm, 0, sizeof parm);
+      parm.size = ASSUAN_LINELENGTH/2 - 5;
+      parm.buffer = gcry_malloc_secure (parm.size+10);
+      if (!parm.buffer)
+        return unlock_pinentry (ctrl, out_of_core ());
 
-  saveflag = assuan_get_flag (entry_ctx, ASSUAN_CONFIDENTIAL);
-  assuan_begin_confidential (entry_ctx);
-  pinentry_status = 0;
-  rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm,
-                        inq_quality, entry_ctx,
-                        pinentry_status_cb, &pinentry_status);
-  assuan_set_flag (entry_ctx, ASSUAN_CONFIDENTIAL, saveflag);
-  /* Most pinentries out in the wild return the old Assuan error code
-     for canceled which gets translated to an assuan Cancel error and
-     not to the code for a user cancel.  Fix this here. */
-  if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
-    rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
-  /* Change error code in case the window close button was clicked
-     to cancel the operation.  */
-  if ((pinentry_status & PINENTRY_STATUS_CLOSE_BUTTON)
-      && gpg_err_code (rc) == GPG_ERR_CANCELED)
-    rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_FULLY_CANCELED);
+      rc = do_getpin (ctrl, &parm);
+      if (rc)
+        xfree (parm.buffer);
+      else
+        *retpass = parm.buffer;
+      return unlock_pinentry (ctrl, rc);
+    }
 
-  if (rc)
-    xfree (parm.buffer);
-  else
-    *retpass = parm.buffer;
-  return unlock_pinentry (ctrl, rc);
+  /* We got PININFO.  */
+
+  if (pininfo->with_repeat)
+    {
+      snprintf (line, DIM(line), "SETREPEATERROR %s",
+                L_("does not match - try again"));
+      rc = assuan_transact (entry_ctx, line,
+                            NULL, NULL, NULL, NULL, NULL, NULL);
+      if (rc)
+        pininfo->with_repeat = 0; /* Pinentry does not support it.  */
+    }
+  pininfo->repeat_okay = 0;
+  pininfo->status = 0;
+
+  for (;pininfo->failed_tries < pininfo->max_tries; pininfo->failed_tries++)
+    {
+      memset (&parm, 0, sizeof parm);
+      parm.size = pininfo->max_length;
+      parm.buffer = (unsigned char*)pininfo->pin;
+      *pininfo->pin = 0; /* Reset the PIN. */
+
+      if (errtext)
+        {
+          /* TRANSLATORS: The string is appended to an error message in
+             the pinentry.  The %s is the actual error message, the
+             two %d give the current and maximum number of tries. */
+          snprintf (line, DIM(line), L_("SETERROR %s (try %d of %d)"),
+                    errtext, pininfo->failed_tries+1, pininfo->max_tries);
+          rc = assuan_transact (entry_ctx, line,
+                                NULL, NULL, NULL, NULL, NULL, NULL);
+          if (rc)
+            return unlock_pinentry (ctrl, rc);
+          errtext = NULL;
+        }
+
+      if (pininfo->with_repeat)
+        {
+          snprintf (line, DIM(line), "SETREPEAT %s", L_("Repeat:"));
+          rc = assuan_transact (entry_ctx, line,
+                                NULL, NULL, NULL, NULL, NULL, NULL);
+          if (rc)
+            return unlock_pinentry (ctrl, rc);
+        }
+
+      rc = do_getpin (ctrl, &parm);
+      pininfo->status = parm.status;
+      if (gpg_err_code (rc) == GPG_ERR_ASS_TOO_MUCH_DATA)
+        errtext = is_pin? L_("PIN too long")
+                        : L_("Passphrase too long");
+      else if (rc)
+        return unlock_pinentry (ctrl, rc);
+
+      if (!errtext && pininfo->min_digits)
+        {
+          /* do some basic checks on the entered PIN. */
+          if (!all_digitsp (pininfo->pin))
+            errtext = L_("Invalid characters in PIN");
+          else if (pininfo->max_digits
+                   && strlen (pininfo->pin) > pininfo->max_digits)
+            errtext = L_("PIN too long");
+          else if (strlen (pininfo->pin) < pininfo->min_digits)
+            errtext = L_("PIN too short");
+        }
+
+      if (!errtext && pininfo->check_cb)
+        {
+          /* More checks by utilizing the optional callback. */
+          pininfo->cb_errtext = NULL;
+          rc = pininfo->check_cb (pininfo);
+          /* When pinentry cache causes an error, return now.  */
+          if (rc && (pininfo->status & PINENTRY_STATUS_PASSWORD_FROM_CACHE))
+            return unlock_pinentry (ctrl, rc);
+
+          if (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE)
+            {
+              if (pininfo->cb_errtext)
+                errtext = pininfo->cb_errtext;
+              else if (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE
+                       || gpg_err_code (rc) == GPG_ERR_BAD_PIN)
+                errtext = (is_pin? L_("Bad PIN") : L_("Bad Passphrase"));
+            }
+          else if (rc)
+            return unlock_pinentry (ctrl, rc);
+        }
+
+      if (!errtext)
+        {
+          if (pininfo->with_repeat
+              && (pininfo->status & PINENTRY_STATUS_PIN_REPEATED))
+            pininfo->repeat_okay = 1;
+          return unlock_pinentry (ctrl, 0); /* okay, got a PIN or passphrase */
+        }
+
+      if ((pininfo->status & PINENTRY_STATUS_PASSWORD_FROM_CACHE))
+        {
+          /* The password was read from the Pinentry's own cache.
+             Don't count this against the retry count.  */
+          pininfo->failed_tries--;
+        }
+    }
+
+  return unlock_pinentry (ctrl, gpg_error (pininfo->min_digits? GPG_ERR_BAD_PIN
+                          : GPG_ERR_BAD_PASSPHRASE));
 }
 
 
index c24fc80..ebbb42c 100644 (file)
@@ -1400,9 +1400,22 @@ send_back_passphrase (assuan_context_t ctx, int via_data, const char *pw)
 }
 
 
+/* Callback function to compare the first entered PIN with the one
+   currently being entered. */
+static gpg_error_t
+reenter_passphrase_cmp_cb (struct pin_entry_info_s *pi)
+{
+  const char *pin1 = pi->check_cb_arg;
+
+  if (!strcmp (pin1, pi->pin))
+    return 0; /* okay */
+  return gpg_error (GPG_ERR_BAD_PASSPHRASE);
+}
+
+
 static const char hlp_get_passphrase[] =
   "GET_PASSPHRASE [--data] [--check] [--no-ask] [--repeat[=N]]\n"
-  "               [--qualitybar] <cache_id>\n"
+  "               [--qualitybar] [--newsymkey] <cache_id>\n"
   "               [<error_message> <prompt> <description>]\n"
   "\n"
   "This function is usually used to ask for a passphrase to be used\n"
@@ -1424,6 +1437,9 @@ static const char hlp_get_passphrase[] =
   "cache the user will not be asked to enter a passphrase but the error\n"
   "code GPG_ERR_NO_DATA is returned.  \n"
   "\n"
+  "If the option\"--newsymkey\" is used the agent asks for a new passphrase\n"
+  "to be used in symmetric-only encryption.  This must not be empty.\n"
+  "\n"
   "If the option \"--qualitybar\" is used a visual indication of the\n"
   "entered passphrase quality is shown.  (Unless no minimum passphrase\n"
   "length has been configured.)";
@@ -1433,13 +1449,19 @@ cmd_get_passphrase (assuan_context_t ctx, char *line)
   ctrl_t ctrl = assuan_get_pointer (ctx);
   int rc;
   char *pw;
-  char *response;
-  char *cacheid = NULL, *desc = NULL, *prompt = NULL, *errtext = NULL;
+  char *response = NULL;
+  char *response2 = NULL;
+  char *cacheid = NULL;  /* May point into LINE.  */
+  char *desc = NULL;     /* Ditto  */
+  char *prompt = NULL;   /* Ditto  */
+  char *errtext = NULL;  /* Ditto  */
   const char *desc2 = _("Please re-enter this passphrase");
   char *p;
-  int opt_data, opt_check, opt_no_ask, opt_qualbar;
+  int opt_data, opt_check, opt_no_ask, opt_qualbar, opt_newsymkey;
   int opt_repeat = 0;
   char *entry_errtext = NULL;
+  struct pin_entry_info_s *pi = NULL;
+  struct pin_entry_info_s *pi2 = NULL;
 
   if (ctrl->restricted)
     return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
@@ -1456,6 +1478,7 @@ cmd_get_passphrase (assuan_context_t ctx, char *line)
        opt_repeat = 1;
     }
   opt_qualbar = has_option (line, "--qualitybar");
+  opt_newsymkey = has_option (line, "--newsymkey");
   line = skip_options (line);
 
   cacheid = line;
@@ -1505,26 +1528,116 @@ cmd_get_passphrase (assuan_context_t ctx, char *line)
     {
       rc = send_back_passphrase (ctx, opt_data, pw);
       xfree (pw);
+      goto leave;
     }
   else if (opt_no_ask)
-    rc = gpg_error (GPG_ERR_NO_DATA);
-  else
     {
-      /* Note, that we only need to replace the + characters and
-         should leave the other escaping in place because the escaped
-         string is send verbatim to the pinentry which does the
-         unescaping (but not the + replacing) */
-      if (errtext)
-        plus_to_blank (errtext);
-      if (prompt)
-        plus_to_blank (prompt);
-      if (desc)
-        plus_to_blank (desc);
+      rc = gpg_error (GPG_ERR_NO_DATA);
+      goto leave;
+    }
+
+  /* Note, that we only need to replace the + characters and should
+   * leave the other escaping in place because the escaped string is
+   * send verbatim to the pinentry which does the unescaping (but not
+   * the + replacing) */
+  if (errtext)
+    plus_to_blank (errtext);
+  if (prompt)
+    plus_to_blank (prompt);
+  if (desc)
+    plus_to_blank (desc);
 
+  if (opt_newsymkey)
+    {
+      /* We do not want to break any existing usage of this command
+       * and thus we introduced the option --newsymkey to make this
+       * command more useful to query the passphrase for symmetric
+       * encryption.  */
+      pi = gcry_calloc_secure (1, sizeof (*pi) + MAX_PASSPHRASE_LEN + 1);
+      if (!pi)
+        {
+          rc = gpg_error_from_syserror ();
+          goto leave;
+        }
+      pi2 = gcry_calloc_secure (1, sizeof (*pi2) + MAX_PASSPHRASE_LEN + 1);
+      if (!pi2)
+        {
+          rc = gpg_error_from_syserror ();
+          goto leave;
+        }
+      pi->max_length = MAX_PASSPHRASE_LEN + 1;
+      pi->max_tries = 3;
+      pi->with_qualitybar = opt_qualbar;
+      pi->with_repeat = opt_repeat;
+      pi2->max_length = MAX_PASSPHRASE_LEN + 1;
+      pi2->max_tries = 3;
+      pi2->check_cb = reenter_passphrase_cmp_cb;
+      pi2->check_cb_arg = pi->pin;
+
+      for (;;) /* (degenerated for-loop) */
+        {
+          xfree (response);
+          response = NULL;
+          rc = agent_get_passphrase (ctrl, &response,
+                                     desc,
+                                     prompt,
+                                     entry_errtext? entry_errtext:errtext,
+                                     opt_qualbar, cacheid, CACHE_MODE_USER,
+                                     pi);
+          if (rc)
+            goto leave;
+          xfree (entry_errtext);
+          entry_errtext = NULL;
+          /* We don't allow an empty passpharse in this mode.  */
+          if (check_passphrase_constraints (ctrl, pi->pin, 1, &entry_errtext))
+            {
+              pi->failed_tries = 0;
+              pi2->failed_tries = 0;
+              continue;
+            }
+          if (*pi->pin && !pi->repeat_okay)
+            {
+              /* The passphrase is empty and the pinentry did not
+               * already run the repetition check, do it here.  This
+               * is only called when using an old and  simple pinentry. */
+              xfree (response);
+              response = NULL;
+              rc = agent_get_passphrase (ctrl, &response,
+                                         L_("Please re-enter this passphrase"),
+                                         prompt,
+                                         entry_errtext? entry_errtext:errtext,
+                                         opt_qualbar, cacheid, CACHE_MODE_USER,
+                                         pi2);
+              if (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE)
+                { /* The re-entered passphrase one did not match and
+                   * the user did not hit cancel. */
+                  entry_errtext = xtrystrdup (L_("does not match - try again"));
+                  if (!entry_errtext)
+                    {
+                      rc = gpg_error_from_syserror ();
+                      goto leave;
+                    }
+                  continue;
+                }
+            }
+          break;
+        }
+      if (!rc && *pi->pin)
+        {
+          /* Return the passphrase. */
+          if (cacheid)
+            agent_put_cache (ctrl, cacheid, CACHE_MODE_USER, pi->pin, 0);
+          rc = send_back_passphrase (ctx, opt_data, pi->pin);
+        }
+    }
+  else
+    {
     next_try:
+      xfree (response);
+      response = NULL;
       rc = agent_get_passphrase (ctrl, &response, desc, prompt,
                                  entry_errtext? entry_errtext:errtext,
-                                 opt_qualbar, cacheid, CACHE_MODE_USER);
+                                 opt_qualbar, cacheid, CACHE_MODE_USER, NULL);
       xfree (entry_errtext);
       entry_errtext = NULL;
       if (!rc)
@@ -1532,27 +1645,24 @@ cmd_get_passphrase (assuan_context_t ctx, char *line)
           int i;
 
           if (opt_check
-             && check_passphrase_constraints (ctrl, response, &entry_errtext))
+             && check_passphrase_constraints (ctrl, response,0,&entry_errtext))
             {
-              xfree (response);
               goto next_try;
             }
           for (i = 0; i < opt_repeat; i++)
             {
-              char *response2;
-
               if (ctrl->pinentry_mode == PINENTRY_MODE_LOOPBACK)
                 break;
 
+              xfree (response2);
+              response2 = NULL;
               rc = agent_get_passphrase (ctrl, &response2, desc2, prompt,
                                          errtext, 0,
-                                        cacheid, CACHE_MODE_USER);
+                                        cacheid, CACHE_MODE_USER, NULL);
               if (rc)
                 break;
               if (strcmp (response2, response))
                 {
-                  xfree (response2);
-                  xfree (response);
                   entry_errtext = try_percent_escape
                     (_("does not match - try again"), NULL);
                   if (!entry_errtext)
@@ -1562,7 +1672,6 @@ cmd_get_passphrase (assuan_context_t ctx, char *line)
                     }
                   goto next_try;
                 }
-              xfree (response2);
             }
           if (!rc)
             {
@@ -1570,10 +1679,15 @@ cmd_get_passphrase (assuan_context_t ctx, char *line)
                 agent_put_cache (ctrl, cacheid, CACHE_MODE_USER, response, 0);
               rc = send_back_passphrase (ctx, opt_data, response);
             }
-          xfree (response);
         }
     }
 
+ leave:
+  xfree (response);
+  xfree (response2);
+  xfree (entry_errtext);
+  xfree (pi2);
+  xfree (pi);
   return leave_cmd (ctx, rc);
 }
 
@@ -3233,7 +3347,9 @@ command_has_option (const char *cmd, const char *cmdopt)
   if (!strcmp (cmd, "GET_PASSPHRASE"))
     {
       if (!strcmp (cmdopt, "repeat"))
-          return 1;
+        return 1;
+      if (!strcmp (cmdopt, "newsymkey"))
+        return 1;
     }
 
   return 0;
index bf05174..06cd1c8 100644 (file)
@@ -878,11 +878,11 @@ convert_from_openpgp_main (ctrl_t ctrl, gcry_sexp_t s_pgp, int dontcare_exist,
   log_debug ("XXX pubkey_algo=%d\n", pubkey_algo);
   log_debug ("XXX is_protected=%d\n", is_protected);
   log_debug ("XXX protect_algo=%d\n", protect_algo);
-  log_printhex ("XXX iv", iv, ivlen);
+  log_printhex (iv, ivlen, "XXX iv");
   log_debug ("XXX ivlen=%d\n", ivlen);
   log_debug ("XXX s2k_mode=%d\n", s2k_mode);
   log_debug ("XXX s2k_algo=%d\n", s2k_algo);
-  log_printhex ("XXX s2k_salt", s2k_salt, sizeof s2k_salt);
+  log_printhex (s2k_salt, sizeof s2k_salt, "XXX s2k_salt");
   log_debug ("XXX s2k_count=%lu\n", (unsigned long)s2k_count);
   log_debug ("XXX curve='%s'\n", curve);
   for (idx=0; skey[idx]; idx++)
index 191ed7f..b79f7a8 100644 (file)
@@ -169,7 +169,7 @@ encode_md_for_card (const unsigned char *digest, size_t digestlen, int algo,
   memcpy (frame, asn, asnlen);
   memcpy (frame+asnlen, digest, digestlen);
   if (DBG_CRYPTO)
-    log_printhex ("encoded hash:", frame, asnlen+digestlen);
+    log_printhex (frame, asnlen+digestlen, "encoded hash:");
 
   *r_val = frame;
   *r_len = asnlen+digestlen;
index d5c80d0..cddd67d 100644 (file)
@@ -179,7 +179,7 @@ take_this_one_anyway (ctrl_t ctrl, const char *desc)
    message describing the problem is returned in
    *FAILED_CONSTRAINT.  */
 int
-check_passphrase_constraints (ctrl_t ctrl, const char *pw,
+check_passphrase_constraints (ctrl_t ctrl, const char *pw, int no_empty,
                              char **failed_constraint)
 {
   gpg_error_t err = 0;
@@ -198,7 +198,7 @@ check_passphrase_constraints (ctrl_t ctrl, const char *pw,
   /* The first check is to warn about an empty passphrase. */
   if (!*pw)
     {
-      const char *desc = (opt.enforce_passphrase_constraints?
+      const char *desc = (opt.enforce_passphrase_constraints || no_empty?
                           L_("You have not entered a passphrase!%0A"
                              "An empty passphrase is not allowed.") :
                           L_("You have not entered a passphrase - "
@@ -209,7 +209,7 @@ check_passphrase_constraints (ctrl_t ctrl, const char *pw,
       err = 1;
       if (failed_constraint)
        {
-         if (opt.enforce_passphrase_constraints)
+         if (opt.enforce_passphrase_constraints || no_empty)
            *failed_constraint = xstrdup (desc);
          else
            err = take_this_one_anyway2 (ctrl, desc,
@@ -386,7 +386,7 @@ agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt,
     }
   pi->max_length = MAX_PASSPHRASE_LEN + 1;
   pi->max_tries = 3;
-  pi->with_qualitybar = 1;
+  pi->with_qualitybar = 0;
   pi->with_repeat = 1;
   pi2->max_length = MAX_PASSPHRASE_LEN + 1;
   pi2->max_tries = 3;
@@ -399,7 +399,7 @@ agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt,
   initial_errtext = NULL;
   if (!err)
     {
-      if (check_passphrase_constraints (ctrl, pi->pin, &initial_errtext))
+      if (check_passphrase_constraints (ctrl, pi->pin, 0, &initial_errtext))
         {
           pi->failed_tries = 0;
           pi2->failed_tries = 0;
index 27cb70c..3dcbbf8 100644 (file)
@@ -2618,7 +2618,7 @@ putty_message_proc (HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
   if (!data)
     goto leave;
 
-  /* log_printhex ("request:", data, 20); */
+  /* log_printhex (data, 20, "request:"); */
 
   ctrl = xtrycalloc (1, sizeof *ctrl);
   if (!ctrl)
@@ -2639,7 +2639,7 @@ putty_message_proc (HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
   if (!serve_mmapped_ssh_request (ctrl, data, PUTTY_IPC_MAXLEN))
     ret = 1; /* Valid ssh message has been constructed.  */
   agent_deinit_default_ctrl (ctrl);
-  /* log_printhex ("  reply:", data, 20); */
+  /* log_printhex (data, 20, "  reply:"); */
 
  leave:
   xfree (ctrl);
index 46697ba..06a8e0b 100644 (file)
@@ -64,8 +64,8 @@ agent_pkdecrypt (ctrl_t ctrl, const char *desc_text,
 
   if (DBG_CRYPTO)
     {
-      log_printhex ("keygrip:", ctrl->keygrip, 20);
-      log_printhex ("cipher: ", ciphertext, ciphertextlen);
+      log_printhex (ctrl->keygrip, 20, "keygrip:");
+      log_printhex (ciphertext, ciphertextlen, "cipher: ");
     }
   rc = agent_key_from_file (ctrl, NULL, desc_text,
                             ctrl->keygrip, &shadow_info,
index 3bba5c6..00c0748 100644 (file)
@@ -316,6 +316,11 @@ read_key (const char *fname)
   buf = read_file (fname, &buflen);
   if (!buf)
     return NULL;
+  if (buflen >= 4 && !memcmp (buf, "Key:", 4))
+    {
+      log_error ("Extended key format is not supported by this tool\n");
+      return NULL;
+    }
   key = make_canonical (fname, buf, buflen);
   xfree (buf);
   return key;
index 179bf72..718f729 100644 (file)
@@ -1105,6 +1105,7 @@ proc_type_verify (audit_ctx_t ctx)
           switch (gpg_err_code (item->err))
             {
             case 0:                    ok = "good"; break;
+            case GPG_ERR_TRUE:         ok = "n/a";  break;
             case GPG_ERR_CERT_REVOKED: ok = "bad"; break;
             case GPG_ERR_NOT_ENABLED:  ok = "disabled"; break;
             case GPG_ERR_NO_CRL_KNOWN:
index 49aada1..7dbbbd3 100644 (file)
@@ -96,6 +96,7 @@ gnupg_initialize_compliance (int gnupg_module_name)
  * both are compatible from the point of view of this function.  */
 int
 gnupg_pk_is_compliant (enum gnupg_compliance_mode compliance, int algo,
+                       unsigned int algo_flags,
                       gcry_mpi_t key[], unsigned int keylength,
                        const char *curvename)
 {
@@ -148,6 +149,10 @@ gnupg_pk_is_compliant (enum gnupg_compliance_mode compliance, int algo,
           result = (keylength == 2048
                     || keylength == 3072
                     || keylength == 4096);
+          /* rsaPSS was not part of the evaluation and thus we don't
+           * claim compliance.  */
+          if ((algo_flags & PK_ALGO_FLAG_RSAPSS))
+            result = 0;
           break;
 
        case is_dsa:
@@ -197,7 +202,8 @@ gnupg_pk_is_compliant (enum gnupg_compliance_mode compliance, int algo,
  * they produce, and liberal in what they accept.  */
 int
 gnupg_pk_is_allowed (enum gnupg_compliance_mode compliance,
-                    enum pk_use_case use, int algo, gcry_mpi_t key[],
+                    enum pk_use_case use, int algo,
+                     unsigned int algo_flags, gcry_mpi_t key[],
                     unsigned int keylength, const char *curvename)
 {
   int result = 0;
@@ -228,6 +234,10 @@ gnupg_pk_is_allowed (enum gnupg_compliance_mode compliance,
            default:
              log_assert (!"reached");
            }
+          /* rsaPSS was not part of the evaluation and thus we don't
+           * claim compliance.  */
+          if ((algo_flags & PK_ALGO_FLAG_RSAPSS))
+            result = 0;
          break;
 
        case PUBKEY_ALGO_DSA:
index 2076e79..21bd230 100644 (file)
@@ -48,11 +48,17 @@ enum pk_use_case
     PK_USE_SIGNING, PK_USE_VERIFICATION,
   };
 
+/* Flags to distinguish public key algorithm variants.  */
+#define PK_ALGO_FLAG_RSAPSS 1    /* Use rsaPSS padding. */
+
+
 int gnupg_pk_is_compliant (enum gnupg_compliance_mode compliance, int algo,
+                           unsigned int algo_flags,
                            gcry_mpi_t key[], unsigned int keylength,
                            const char *curvename);
 int gnupg_pk_is_allowed (enum gnupg_compliance_mode compliance,
-                         enum pk_use_case use, int algo, gcry_mpi_t key[],
+                         enum pk_use_case use, int algo,
+                         unsigned int algo_flags, gcry_mpi_t key[],
                          unsigned int keylength, const char *curvename);
 int gnupg_cipher_is_compliant (enum gnupg_compliance_mode compliance,
                                cipher_algo_t cipher,
index df55e68..7fe8b74 100644 (file)
@@ -1011,10 +1011,17 @@ log_flush (void)
    dump, with TEXT just an empty string, print a trailing linefeed,
    otherwise print an entire debug line. */
 void
-log_printhex (const char *text, const void *buffer, size_t length)
+log_printhex (const void *buffer, size_t length, const char *fmt, ...)
 {
-  if (text && *text)
-    log_debug ("%s ", text);
+  if (fmt && *fmt)
+    {
+      va_list arg_ptr ;
+
+      va_start (arg_ptr, fmt);
+      do_logv (GPGRT_LOG_DEBUG, 0, NULL, NULL, fmt, arg_ptr);
+      va_end (arg_ptr);
+      log_printf (" ");
+    }
   if (length)
     {
       const unsigned char *p = buffer;
@@ -1022,7 +1029,7 @@ log_printhex (const char *text, const void *buffer, size_t length)
       for (length--, p++; length--; p++)
         log_printf (" %02X", *p);
     }
-  if (text)
+  if (fmt)
     log_printf ("\n");
 }
 
index 2225100..cb1ec11 100644 (file)
@@ -103,11 +103,12 @@ void log_debug_with_string (const char *string, const char *fmt,
 void log_printf (const char *fmt, ...) GPGRT_ATTR_PRINTF(1,2);
 void log_flush (void);
 
-/* Print a hexdump of BUFFER.  With TEXT passes as NULL print just the
-   raw dump, with TEXT being an empty string, print a trailing
-   linefeed, otherwise print an entire debug line with TEXT followed
-   by the hexdump and a final LF.  */
-void log_printhex (const char *text, const void *buffer, size_t length);
+/* Print a hexdump of BUFFER.  With FMT passed as NULL print just the
+ * raw dump, with FMT being an empty string, print a trailing
+ * linefeed, otherwise print an entire debug line with expanded FMT
+ * followed by the hexdump and a final LF.  */
+void log_printhex (const void *buffer, size_t length,
+                   const char *fmt, ...) GPGRT_ATTR_PRINTF(3,4);
 
 void log_clock (const char *string);
 
index 4dcfc25..5cc437a 100644 (file)
@@ -51,6 +51,7 @@ typedef enum
     PKT_ATTRIBUTE     = 17, /* PGP's attribute packet. */
     PKT_ENCRYPTED_MDC = 18, /* Integrity protected encrypted data. */
     PKT_MDC          = 19, /* Manipulation detection code packet. */
+    PKT_ENCRYPTED_AEAD= 20, /* AEAD encrypted data packet. */
     PKT_COMMENT              = 61, /* new comment packet (GnuPG specific). */
     PKT_GPG_CONTROL   = 63  /* internal control packet (GnuPG specific). */
   }
@@ -125,6 +126,16 @@ typedef enum
 sigsubpkttype_t;
 
 
+/* Note that we encode the AEAD algo in a 3 bit field at some places.  */
+typedef enum
+  {
+    AEAD_ALGO_NONE         =  0,
+    AEAD_ALGO_EAX          =  1,
+    AEAD_ALGO_OCB          =  2
+  }
+aead_algo_t;
+
+
 typedef enum
   {
     CIPHER_ALGO_NONE       =  0,
index 569c5fd..224de78 100644 (file)
@@ -87,6 +87,89 @@ percent_plus_escape (const char *string)
 }
 
 
+/* Create a newly malloced string from (DATA,DATALEN) with embedded
+ * nuls quoted as %00.  The standard percent unescaping can be used to
+ * reverse this encoding.  With PLUS_ESCAPE set plus-escaping (spaces
+ * are replaced by a '+') and escaping of characters with values less
+ * than 0x20 is used.  If PREFIX is not NULL it will be prepended to
+ * the output in standard escape format; that is PLUS_ESCAPING is
+ * ignored for PREFIX. */
+char *
+percent_data_escape (int plus_escape, const char *prefix,
+                     const void *data, size_t datalen)
+{
+  char *buffer, *p;
+  const unsigned char *s;
+  size_t n;
+  size_t length = 1;
+
+  if (prefix)
+    {
+      for (s = prefix; *s; s++)
+        {
+          if (*s == '%' || *s < 0x20)
+            length += 3;
+          else
+            length++;
+        }
+    }
+
+  for (s=data, n=datalen; n; s++, n--)
+    {
+      if (!*s || *s == '%' || (plus_escape && (*s < ' ' || *s == '+')))
+        length += 3;
+      else
+        length++;
+    }
+
+  buffer = p = xtrymalloc (length);
+  if (!buffer)
+    return NULL;
+
+  if (prefix)
+    {
+      for (s = prefix; *s; s++)
+        {
+          if (*s == '%' || *s < 0x20)
+            {
+              snprintf (p, 4, "%%%02X", *s);
+              p += 3;
+            }
+          else
+            *p++ = *s;
+        }
+    }
+
+  for (s=data, n=datalen; n; s++, n--)
+    {
+      if (!*s)
+        {
+          memcpy (p, "%00", 3);
+          p += 3;
+        }
+      else if (*s == '%')
+        {
+          memcpy (p, "%25", 3);
+          p += 3;
+        }
+      else if (plus_escape && *s == ' ')
+        {
+          *p++ = '+';
+        }
+      else if (plus_escape && (*s < ' ' || *s == '+'))
+        {
+          snprintf (p, 4, "%%%02X", *s);
+          p += 3;
+        }
+      else
+        *p++ = *s;
+    }
+  *p = 0;
+
+  return buffer;
+}
+
+
 /* Do the percent and plus/space unescaping from STRING to BUFFER and
    return the length of the valid buffer.  Plus unescaping is only
    done if WITHPLUS is true.  An escaped Nul character will be
index e8c8a34..9a79c05 100644 (file)
@@ -640,3 +640,61 @@ pubkey_algo_string (gcry_sexp_t s_pkey, enum gcry_pk_algos *r_algoid)
   xfree (algoname);
   return result;
 }
+
+
+/* Map a pubkey algo id from gcrypt to a string.  This is the same as
+ * gcry_pk_algo_name but makes sure that the ECC algo identifiers are
+ * not all mapped to "ECC".  */
+const char *
+pubkey_algo_to_string (int algo)
+{
+  if (algo == GCRY_PK_ECDSA)
+    return "ECDSA";
+  else if (algo == GCRY_PK_ECDH)
+    return "ECDH";
+  else if (algo == GCRY_PK_EDDSA)
+    return "EdDSA";
+  else
+    return gcry_pk_algo_name (algo);
+}
+
+
+/* Map a hash algo id from gcrypt to a string.  This is the same as
+ * gcry_md_algo_name but the returned string is lower case, as
+ * expected by libksba and it avoids some overhead.  */
+const char *
+hash_algo_to_string (int algo)
+{
+  static const struct
+  {
+    const char *name;
+    int algo;
+  } hashnames[] =
+      {
+       { "sha256",    GCRY_MD_SHA256 },
+       { "sha512",    GCRY_MD_SHA512 },
+       { "sha1",      GCRY_MD_SHA1 },
+       { "sha384",    GCRY_MD_SHA384 },
+       { "sha224",    GCRY_MD_SHA224 },
+       { "sha3-224",  GCRY_MD_SHA3_224 },
+       { "sha3-256",  GCRY_MD_SHA3_256 },
+       { "sha3-384",  GCRY_MD_SHA3_384 },
+       { "sha3-512",  GCRY_MD_SHA3_512 },
+       { "ripemd160", GCRY_MD_RMD160 },
+       { "rmd160",    GCRY_MD_RMD160 },
+       { "md2",       GCRY_MD_MD2 },
+       { "md4",       GCRY_MD_MD4 },
+       { "tiger",     GCRY_MD_TIGER },
+       { "haval",     GCRY_MD_HAVAL },
+#if GCRYPT_VERSION_NUMBER >= 0x010900
+       { "sm3",       GCRY_MD_SM3 },
+#endif
+       { "md5",       GCRY_MD_MD5 }
+      };
+  int i;
+
+  for (i=0; i < DIM (hashnames); i++)
+    if (algo == hashnames[i].algo)
+      return hashnames[i].name;
+  return "?";
+}
index 4d763f0..fd8a7dc 100644 (file)
 #include <errno.h>  /* We need errno.  */
 #include <gpg-error.h> /* We need gpg_error_t and estream. */
 
-/* These error codes are used but not defined in the required
+/* These error codes might be used but not defined in the required
  * libgpg-error version.  Define them here.
  * Example: (#if GPG_ERROR_VERSION_NUMBER < 0x011500 // 1.21)
  */
+#if GPG_ERROR_VERSION_NUMBER < 0x012400 /* 1.36 */
+# define GPG_ERR_NO_AUTH          314
+# define GPG_ERR_BAD_AUTH         315
+#endif
+
+#if GPG_ERROR_VERSION_NUMBER < 0x011b00 /* 1.27 */
+# define GPG_ERR_WRONG_NAME       313
+#endif
+
 #if GPG_ERROR_VERSION_NUMBER < 0x011a00 /* 1.26 */
 # define GPG_ERR_UNKNOWN_FLAG     309
 # define GPG_ERR_INV_ORDER       310
 /* Hash function used with libksba. */
 #define HASH_FNC ((void (*)(void *, const void*,size_t))gcry_md_write)
 
+/* The length of the keygrip.  This is a SHA-1 hash of the key
+ * parameters as generated by gcry_pk_get_keygrip.  */
+#define KEYGRIP_LEN 20
+
+
 /* Get all the stuff from jnlib. */
 #include "../common/logging.h"
 #include "../common/argparse.h"
@@ -207,6 +221,8 @@ int get_pk_algo_from_key (gcry_sexp_t key);
 int get_pk_algo_from_canon_sexp (const unsigned char *keydata,
                                  size_t keydatalen);
 char *pubkey_algo_string (gcry_sexp_t s_pkey, enum gcry_pk_algos *r_algoid);
+const char *pubkey_algo_to_string (int algo);
+const char *hash_algo_to_string (int algo);
 
 /*-- convert.c --*/
 int hex2bin (const char *string, void *buffer, size_t length);
@@ -219,6 +235,8 @@ char *hex2str_alloc (const char *hexstring, size_t *r_count);
 
 /*-- percent.c --*/
 char *percent_plus_escape (const char *string);
+char *percent_data_escape (int plus_escape, const char *prefix,
+                           const void *data, size_t datalen);
 char *percent_plus_unescape (const char *string, int nulrepl);
 char *percent_unescape (const char *string, int nulrepl);
 
index f3c9863..1d05d39 100644 (file)
@@ -29,7 +29,7 @@ min_automake_version="1.14"
 m4_define([mym4_package],[gnupg])
 m4_define([mym4_major], [2])
 m4_define([mym4_minor], [2])
-m4_define([mym4_micro], [20])
+m4_define([mym4_micro], [21])
 
 # To start a new development series, i.e a new major or minor number
 # you need to mark an arbitrary commit before the first beta release
@@ -54,7 +54,7 @@ AC_INIT([mym4_package],[mym4_version], [https://bugs.gnupg.org])
 # build-aux/speedo.mk and Makefile.am
 AC_DEFINE_UNQUOTED(GNUPG_SWDB_TAG, "gnupg22", [swdb tag for this branch])
 
-NEED_GPG_ERROR_VERSION=1.24
+NEED_GPG_ERROR_VERSION=1.25
 
 NEED_LIBGCRYPT_API=1
 NEED_LIBGCRYPT_VERSION=1.7.0
@@ -1220,6 +1220,8 @@ elif test x"$with_mailprog" != xno ; then
     AC_SUBST(SENDMAIL,$with_mailprog)
     AC_MSG_RESULT($with_mailprog)
 fi
+AC_DEFINE_UNQUOTED(NAME_OF_SENDMAIL,"$SENDMAIL",
+                   [Tool with sendmail -t interface])
 
 
 #
@@ -1638,7 +1640,7 @@ if test "$GCC" = yes; then
           AC_MSG_RESULT($_gcc_wopt)
         fi
         if test x"$_gcc_wopt" = xyes ; then
-          mycflags="$mycflags -W -Wno-sign-compare"
+          mycflags="$mycflags -W -Wno-sign-compare -Wno-format-zero-length"
           mycflags="$mycflags -Wno-missing-field-initializers"
         fi
 
index 52f49c0..cd35335 100644 (file)
@@ -1351,7 +1351,7 @@ cache_isvalid (ctrl_t ctrl, const char *issuer_hash,
         {
           log_error (_("WARNING: invalid cache record length for S/N "));
           log_printf ("0x");
-          log_printhex ("", sn, snlen);
+          log_printhex (sn, snlen, "");
         }
       else if (opt.verbose)
         {
@@ -1531,17 +1531,104 @@ crl_cache_cert_isvalid (ctrl_t ctrl, ksba_cert_t cert,
 }
 
 
+/* Return the hash algorithm's algo id from its name given in the
+ * non-null termnated string in (buffer,buflen).  Returns 0 on failure
+ * or if the algo is not known.  */
+static int
+hash_algo_from_buffer (const void *buffer, size_t buflen)
+{
+  char *string;
+  int algo;
+
+  string = xtrymalloc (buflen + 1);
+  if (!string)
+    {
+      log_error (_("out of core\n"));
+      return 0;
+    }
+  memcpy (string, buffer, buflen);
+  string[buflen] = 0;
+  algo = gcry_md_map_name (string);
+  if (!algo)
+    log_error ("unknown digest algorithm '%s' used in certificate\n", string);
+  xfree (string);
+  return algo;
+}
+
+
+/* Return an unsigned integer from the non-null termnated string
+ * (buffer,buflen).  Returns 0 on failure.  */
+static unsigned int
+uint_from_buffer (const void *buffer, size_t buflen)
+{
+  char *string;
+  unsigned int val;
+
+  string = xtrymalloc (buflen + 1);
+  if (!string)
+    {
+      log_error (_("out of core\n"));
+      return 0;
+    }
+  memcpy (string, buffer, buflen);
+  string[buflen] = 0;
+  val = strtoul (string, NULL, 10);
+  xfree (string);
+  return val;
+}
+
+
 /* Prepare a hash context for the signature verification.  Input is
    the CRL and the output is the hash context MD as well as the uses
    algorithm identifier ALGO. */
 static gpg_error_t
-start_sig_check (ksba_crl_t crl, gcry_md_hd_t *md, int *algo)
+start_sig_check (ksba_crl_t crl, gcry_md_hd_t *md, int *algo, int *use_pss)
 {
   gpg_error_t err;
   const char *algoid;
 
+  *use_pss = 0;
   algoid = ksba_crl_get_digest_algo (crl);
-  *algo = gcry_md_map_name (algoid);
+  if (algoid && !strcmp (algoid, "1.2.840.113549.1.1.10"))
+    {
+      /* Parse rsaPSS parameter.  */
+      gcry_buffer_t ioarray[1] = { {0} };
+      ksba_sexp_t pssparam;
+      size_t n;
+      gcry_sexp_t psssexp;
+
+      pssparam = ksba_crl_get_sig_val (crl);
+      n = gcry_sexp_canon_len (pssparam, 0, NULL, NULL);
+      if (!n)
+        {
+          ksba_free (pssparam);
+          log_error (_("got an invalid S-expression from libksba\n"));
+          return gpg_error (GPG_ERR_INV_SEXP);
+        }
+      err = gcry_sexp_sscan (&psssexp, NULL, pssparam, n);
+      ksba_free (pssparam);
+      if (err)
+        {
+          log_error (_("converting S-expression failed: %s\n"),
+                     gcry_strerror (err));
+          return err;
+        }
+
+      err = gcry_sexp_extract_param (psssexp, "sig-val",
+                                    "&'hash-algo'", ioarray, NULL);
+      gcry_sexp_release (psssexp);
+      if (err)
+        {
+          log_error ("extracting params from PSS failed: %s\n",
+                     gpg_strerror (err));
+          return err;
+        }
+      *algo = hash_algo_from_buffer (ioarray[0].data, ioarray[0].len);
+      xfree (ioarray[0].data);
+      *use_pss = 1;
+    }
+  else
+    *algo = gcry_md_map_name (algoid);
   if (!*algo)
     {
       log_error (_("unknown hash algorithm '%s'\n"), algoid? algoid:"?");
@@ -1570,15 +1657,13 @@ start_sig_check (ksba_crl_t crl, gcry_md_hd_t *md, int *algo)
    certificate of the CRL issuer.  This function takes ownership of MD.  */
 static gpg_error_t
 finish_sig_check (ksba_crl_t crl, gcry_md_hd_t md, int algo,
-                  ksba_cert_t issuer_cert)
+                  ksba_cert_t issuer_cert, int use_pss)
 {
   gpg_error_t err;
   ksba_sexp_t sigval = NULL, pubkey = NULL;
-  const char *s;
-  char algoname[50];
   size_t n;
   gcry_sexp_t s_sig = NULL, s_hash = NULL, s_pkey = NULL;
-  unsigned int i;
+  unsigned int saltlen = 0;  /* (used only with use_pss)  */
 
   /* This also stops debugging on the MD.  */
   gcry_md_final (md);
@@ -1600,6 +1685,78 @@ finish_sig_check (ksba_crl_t crl, gcry_md_hd_t md, int algo,
       goto leave;
     }
 
+  if (use_pss)
+    {
+      /* Parse rsaPSS parameter which we should find in S_SIG.  */
+      gcry_buffer_t ioarray[2] = { {0}, {0} };
+      ksba_sexp_t pssparam;
+      gcry_sexp_t psssexp;
+      int hashalgo;
+
+      pssparam = ksba_crl_get_sig_val (crl);
+      n = gcry_sexp_canon_len (pssparam, 0, NULL, NULL);
+      if (!n)
+        {
+          ksba_free (pssparam);
+          log_error (_("got an invalid S-expression from libksba\n"));
+          err = gpg_error (GPG_ERR_INV_SEXP);
+          goto leave;
+        }
+      err = gcry_sexp_sscan (&psssexp, NULL, pssparam, n);
+      ksba_free (pssparam);
+      if (err)
+        {
+          log_error (_("converting S-expression failed: %s\n"),
+                     gcry_strerror (err));
+          goto leave;
+        }
+
+      err = gcry_sexp_extract_param (psssexp, "sig-val",
+                                    "&'hash-algo''salt-length'",
+                                     ioarray+0, ioarray+1, NULL);
+      gcry_sexp_release (psssexp);
+      if (err)
+        {
+          log_error ("extracting params from PSS failed: %s\n",
+                     gpg_strerror (err));
+          goto leave;
+        }
+      hashalgo = hash_algo_from_buffer (ioarray[0].data, ioarray[0].len);
+      saltlen = uint_from_buffer (ioarray[1].data, ioarray[1].len);
+      xfree (ioarray[0].data);
+      xfree (ioarray[1].data);
+      if (hashalgo != algo)
+        {
+          log_error ("hash algo mismatch: %d announced but %d used\n",
+                     algo, hashalgo);
+          return gpg_error (GPG_ERR_INV_CRL);
+        }
+      /* Add some restrictions; see ../sm/certcheck.c for details.  */
+      switch (algo)
+        {
+        case GCRY_MD_SHA1:
+        case GCRY_MD_SHA256:
+        case GCRY_MD_SHA384:
+        case GCRY_MD_SHA512:
+        case GCRY_MD_SHA3_256:
+        case GCRY_MD_SHA3_384:
+        case GCRY_MD_SHA3_512:
+          break;
+        default:
+          log_error ("PSS hash algorithm '%s' rejected\n",
+                     gcry_md_algo_name (algo));
+          return gpg_error (GPG_ERR_DIGEST_ALGO);
+        }
+
+      if (gcry_md_get_algo_dlen (algo) != saltlen)
+        {
+          log_error ("PSS hash algorithm '%s' rejected due to salt length %u\n",
+                     gcry_md_algo_name (algo), saltlen);
+          return gpg_error (GPG_ERR_DIGEST_ALGO);
+        }
+    }
+
+
   /* Get and convert the public key for the issuer certificate. */
   if (DBG_X509)
     dump_cert ("crl_issuer_cert", issuer_cert);
@@ -1620,13 +1777,25 @@ finish_sig_check (ksba_crl_t crl, gcry_md_hd_t md, int algo,
     }
 
   /* Create an S-expression with the actual hash value. */
-  s = gcry_md_algo_name (algo);
-  for (i = 0; *s && i < sizeof(algoname) - 1; s++, i++)
-    algoname[i] = ascii_tolower (*s);
-  algoname[i] = 0;
-  err = gcry_sexp_build (&s_hash, NULL, "(data(flags pkcs1)(hash %s %b))",
-                         algoname,
-                         gcry_md_get_algo_dlen (algo), gcry_md_read (md, algo));
+  if (use_pss)
+    {
+      err = gcry_sexp_build (&s_hash, NULL,
+                             "(data (flags pss)"
+                             "(hash %s %b)"
+                             "(salt-length %u))",
+                             hash_algo_to_string (algo),
+                             (int)gcry_md_get_algo_dlen (algo),
+                             gcry_md_read (md, algo),
+                             saltlen);
+    }
+  else
+    {
+      err = gcry_sexp_build (&s_hash, NULL,
+                             "(data(flags pkcs1)(hash %s %b))",
+                             hash_algo_to_string (algo),
+                             (int)gcry_md_get_algo_dlen (algo),
+                             gcry_md_read (md, algo));
+    }
   if (err)
     {
       log_error (_("creating S-expression failed: %s\n"), gcry_strerror (err));
@@ -1688,6 +1857,7 @@ crl_parse_insert (ctrl_t ctrl, ksba_crl_t crl,
   ksba_cert_t crlissuer_cert = NULL;
   gcry_md_hd_t md = NULL;
   int algo = 0;
+  int use_pss = 0;
   size_t n;
 
   (void)fname;
@@ -1710,7 +1880,7 @@ crl_parse_insert (ctrl_t ctrl, ksba_crl_t crl,
         {
         case KSBA_SR_BEGIN_ITEMS:
           {
-            err = start_sig_check (crl, &md, &algo);
+            err = start_sig_check (crl, &md, &algo, &use_pss);
             if (err)
               goto failure;
 
@@ -1847,7 +2017,7 @@ crl_parse_insert (ctrl_t ctrl, ksba_crl_t crl,
                 goto failure;
               }
 
-            err = finish_sig_check (crl, md, algo, crlissuer_cert);
+            err = finish_sig_check (crl, md, algo, crlissuer_cert, use_pss);
             md = NULL; /* Closed.  */
             if (err)
               {
index 57ac51b..7da3d8b 100644 (file)
@@ -408,40 +408,124 @@ end_cert_fetch (cert_fetch_context_t context)
 }
 
 
+/* Read a certificate from an HTTP URL and return it as an estream
+ * memory buffer at R_FP.  */
+static gpg_error_t
+read_cert_via_http (ctrl_t ctrl, const char *url, estream_t *r_fp)
+{
+  gpg_error_t err;
+  estream_t fp = NULL;
+  estream_t httpfp = NULL;
+  size_t nread, nwritten;
+  char buffer[1024];
+
+  if ((err = ks_http_fetch (ctrl, url, KS_HTTP_FETCH_TRUST_CFG, &httpfp)))
+    goto leave;
+
+  /* We now read the data from the web server into a memory buffer.
+   * To DOS we limit the certificate length to 32k.  */
+  fp = es_fopenmem (32*1024, "rw");
+  if (!fp)
+    {
+      err = gpg_error_from_syserror ();
+      log_error ("error allocating memory buffer: %s\n", gpg_strerror (err));
+      goto leave;
+    }
+
+  for (;;)
+    {
+      if (es_read (httpfp, buffer, sizeof buffer, &nread))
+        {
+          err = gpg_error_from_syserror ();
+          log_error ("error reading '%s': %s\n",
+                     es_fname_get (httpfp), gpg_strerror (err));
+          goto leave;
+        }
+
+      if (!nread)
+        break; /* Ready.  */
+      if (es_write (fp, buffer, nread, &nwritten))
+        {
+          err = gpg_error_from_syserror ();
+          log_error ("error writing '%s': %s\n",
+                     es_fname_get (fp), gpg_strerror (err));
+          goto leave;
+        }
+      else if (nread != nwritten)
+        {
+          err = gpg_error (GPG_ERR_EIO);
+          log_error ("error writing '%s': %s\n",
+                     es_fname_get (fp), "short write");
+          goto leave;
+        }
+    }
+
+  es_rewind (fp);
+  *r_fp = fp;
+  fp = NULL;
+
+ leave:
+  es_fclose (httpfp);
+  es_fclose (fp);
+  return err;
+}
+
+
 /* Lookup a cert by it's URL.  */
 gpg_error_t
 fetch_cert_by_url (ctrl_t ctrl, const char *url,
                   unsigned char **value, size_t *valuelen)
 {
-  const unsigned char *cert_image;
+  const unsigned char *cert_image = NULL;
   size_t cert_image_n;
-  ksba_reader_t reader;
-  ksba_cert_t cert;
+  ksba_reader_t reader = NULL;
+  ksba_cert_t cert = NULL;
   gpg_error_t err;
 
   *value = NULL;
   *valuelen = 0;
-  cert_image = NULL;
-  reader = NULL;
-  cert = NULL;
-
-#if USE_LDAP
-  err = url_fetch_ldap (ctrl, url, NULL, 0, &reader);
-#else
-  (void)ctrl;
-  (void)url;
-  err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
-#endif /*USE_LDAP*/
-  if (err)
-    goto leave;
 
   err = ksba_cert_new (&cert);
   if (err)
     goto leave;
 
-  err = ksba_cert_read_der (cert, reader);
-  if (err)
-    goto leave;
+  if (url && (!strncmp (url, "http:", 5) || !strncmp (url, "https:", 6)))
+    {
+      estream_t stream;
+      void *der;
+      size_t derlen;
+
+      err = read_cert_via_http (ctrl, url, &stream);
+      if (err)
+        goto leave;
+
+      if (es_fclose_snatch (stream, &der, &derlen))
+        {
+          err = gpg_error_from_syserror ();
+          goto leave;
+        }
+
+      err = ksba_cert_init_from_mem (cert, der, derlen);
+      xfree (der);
+      if (err)
+        goto leave;
+    }
+  else /* Assume LDAP.  */
+    {
+#if USE_LDAP
+      err = url_fetch_ldap (ctrl, url, NULL, 0, &reader);
+#else
+      (void)ctrl;
+      (void)url;
+      err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+#endif /*USE_LDAP*/
+      if (err)
+        goto leave;
+
+      err = ksba_cert_read_der (cert, reader);
+      if (err)
+        goto leave;
+    }
 
   cert_image = ksba_cert_get_image (cert, &cert_image_n);
   if (!cert_image || !cert_image_n)
@@ -461,7 +545,6 @@ fetch_cert_by_url (ctrl_t ctrl, const char *url,
   *valuelen = cert_image_n;
 
  leave:
-
   ksba_cert_release (cert);
 #if USE_LDAP
   ldap_wrapper_release_context (reader);
index 3ec6139..3beaab8 100644 (file)
@@ -373,7 +373,7 @@ static npth_key_t my_tlskey_current_fd;
 /* Prototypes. */
 static void cleanup (void);
 #if USE_LDAP
-static ldap_server_t parse_ldapserver_file (const char* filename);
+static ldap_server_t parse_ldapserver_file (const char* filename, int ienoent);
 #endif /*USE_LDAP*/
 static fingerprint_list_t parse_ocsp_signer (const char *string);
 static void netactivity_action (void);
@@ -1100,11 +1100,11 @@ main (int argc, char **argv)
       ldapfile = make_filename (gnupg_homedir (),
                                 "dirmngr_ldapservers.conf",
                                 NULL);
-      opt.ldapservers = parse_ldapserver_file (ldapfile);
+      opt.ldapservers = parse_ldapserver_file (ldapfile, 1);
       xfree (ldapfile);
     }
   else
-      opt.ldapservers = parse_ldapserver_file (ldapfile);
+    opt.ldapservers = parse_ldapserver_file (ldapfile, 0);
 #endif /*USE_LDAP*/
 
 #ifndef HAVE_W32_SYSTEM
@@ -1618,7 +1618,7 @@ dirmngr_deinit_default_ctrl (ctrl_t ctrl)
 */
 #if USE_LDAP
 static ldap_server_t
-parse_ldapserver_file (const char* filename)
+parse_ldapserver_file (const char* filename, int ignore_enoent)
 {
   char buffer[1024];
   char *p;
@@ -1631,7 +1631,10 @@ parse_ldapserver_file (const char* filename)
   if (!fp)
     {
       if (errno == ENOENT)
-        log_info ("No ldapserver file at: '%s'\n", filename);
+        {
+          if (!ignore_enoent)
+            log_info ("No ldapserver file at: '%s'\n", filename);
+        }
       else
         log_error (_("error opening '%s': %s\n"), filename,
                    strerror (errno));
index 4c3b559..43845eb 100644 (file)
@@ -2150,6 +2150,7 @@ static size_t dns_p_lines_fmt(void *dst, size_t lim, dns_error_t *_error, const
 static size_t dns_p_lines(void *dst, size_t lim, dns_error_t *_error, struct dns_packet *P, struct dns_rr_i *I, struct dns_p_lines_i *state) {
        int error, pc;
        size_t len;
+       char __dst[DNS_STRMAXLEN + 1] = { 0 };
 
        *_error = 0;
 
@@ -2168,7 +2169,7 @@ static size_t dns_p_lines(void *dst, size_t lim, dns_error_t *_error, struct dns
        while (dns_rr_grep(&state->rr, 1, I, P, &error)) {
                if (state->section != state->rr.section) {
                        DNS_P_LINE("\n");
-                       DNS_P_LINE(";; [%s:%d]\n", dns_strsection(state->rr.section), dns_p_count(P, state->rr.section));
+                       DNS_P_LINE(";; [%s:%d]\n", dns_strsection(state->rr.section, __dst), dns_p_count(P, state->rr.section));
                }
 
                if (!(len = dns_rr_print(dst, lim, &state->rr, P, &error)))
@@ -3274,6 +3275,7 @@ size_t dns_rr_print(void *_dst, size_t lim, struct dns_rr *rr, struct dns_packet
        union dns_any any;
        size_t n;
        int error;
+       char __dst[DNS_STRMAXLEN + 1] = { 0 };
 
        if (rr->section == DNS_S_QD)
                dns_b_putc(&dst, ';');
@@ -3288,9 +3290,9 @@ size_t dns_rr_print(void *_dst, size_t lim, struct dns_rr *rr, struct dns_packet
        }
 
        dns_b_putc(&dst, ' ');
-       dns_b_puts(&dst, dns_strclass(rr->class));
+       dns_b_puts(&dst, dns_strclass(rr->class, __dst));
        dns_b_putc(&dst, ' ');
-       dns_b_puts(&dst, dns_strtype(rr->type));
+       dns_b_puts(&dst, dns_strtype(rr->type, __dst));
 
        if (rr->section == DNS_S_QD)
                goto epilog;
@@ -4864,6 +4866,7 @@ dns_error_t dns_trace_dump(struct dns_trace *trace, FILE *fp) {
                dns_microseconds_t begin, elapsed;
        } state = { 0 };
        int error;
+       char __dst[DNS_STRMAXLEN + 1] = { 0 };
 
        if (!trace || !trace->fp)
                return EINVAL;
@@ -4886,8 +4889,8 @@ dns_error_t dns_trace_dump(struct dns_trace *trace, FILE *fp) {
                        fprintf(fp, "dns_res_submit:\n");
                        dns_trace_dump_meta(trace, "  ", te, state.elapsed, fp);
                        fprintf(fp, "  qname: %s\n", te->res_submit.qname);
-                       fprintf(fp, "  qtype: %s\n", dns_strtype(te->res_submit.qtype));
-                       fprintf(fp, "  qclass: %s\n", dns_strclass(te->res_submit.qclass));
+                       fprintf(fp, "  qtype: %s\n", dns_strtype(te->res_submit.qtype, __dst));
+                       fprintf(fp, "  qclass: %s\n", dns_strclass(te->res_submit.qclass, __dst));
                        dns_trace_dump_error(trace, "  error: ", te->res_submit.error, fp);
                        break;
                case DNS_TE_RES_FETCH:
@@ -10010,16 +10013,17 @@ int dns_ai_poll(struct dns_addrinfo *ai, int timeout) {
 size_t dns_ai_print(void *_dst, size_t lim, struct addrinfo *ent, struct dns_addrinfo *ai) {
        struct dns_buf dst = DNS_B_INTO(_dst, lim);
        char addr[DNS_PP_MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN) + 1];
+       char __dst[DNS_STRMAXLEN + 1] = { 0 };
 
        dns_b_puts(&dst, "[ ");
        dns_b_puts(&dst, ai->qname);
        dns_b_puts(&dst, " IN ");
        if (ai->qtype) {
-               dns_b_puts(&dst, dns_strtype(ai->qtype));
+               dns_b_puts(&dst, dns_strtype(ai->qtype, __dst));
        } else if (ent->ai_family == AF_INET) {
-               dns_b_puts(&dst, dns_strtype(DNS_T_A));
+               dns_b_puts(&dst, dns_strtype(DNS_T_A, __dst));
        } else if (ent->ai_family == AF_INET6) {
-               dns_b_puts(&dst, dns_strtype(DNS_T_AAAA));
+               dns_b_puts(&dst, dns_strtype(DNS_T_AAAA, __dst));
        } else {
                dns_b_puts(&dst, "0");
        }
@@ -10106,9 +10110,8 @@ static const struct {
        { "AR",         DNS_S_ADDITIONAL },
 };
 
-const char *(dns_strsection)(enum dns_section section) {
-       char _dst[DNS_STRMAXLEN + 1] = { 0 };
-       struct dns_buf dst = DNS_B_INTO(_dst, sizeof _dst);
+const char *(dns_strsection)(enum dns_section section, char *_dst) {
+       struct dns_buf dst = DNS_B_INTO(_dst, DNS_STRMAXLEN + 1);
        unsigned i;
 
        for (i = 0; i < lengthof(dns_sections); i++) {
@@ -10156,9 +10159,8 @@ static const struct {
        { "IN", DNS_C_IN },
 };
 
-const char *(dns_strclass)(enum dns_class type) {
-       char _dst[DNS_STRMAXLEN + 1] = { 0 };
-       struct dns_buf dst = DNS_B_INTO(_dst, sizeof _dst);
+const char *(dns_strclass)(enum dns_class type, char *_dst) {
+       struct dns_buf dst = DNS_B_INTO(_dst, DNS_STRMAXLEN + 1);
        unsigned i;
 
        for (i = 0; i < lengthof(dns_classes); i++) {
@@ -10193,9 +10195,8 @@ enum dns_class dns_iclass(const char *name) {
 } /* dns_iclass() */
 
 
-const char *(dns_strtype)(enum dns_type type) {
-       char _dst[DNS_STRMAXLEN + 1] = { 0 };
-       struct dns_buf dst = DNS_B_INTO(_dst, sizeof _dst);
+const char *(dns_strtype)(enum dns_type type, char *_dst) {
+       struct dns_buf dst = DNS_B_INTO(_dst, DNS_STRMAXLEN + 1);
        unsigned i;
 
        for (i = 0; i < lengthof(dns_rrtypes); i++) {
@@ -10618,6 +10619,7 @@ static int parse_packet(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
        union dns_any any;
        char pretty[sizeof any * 2];
        size_t len;
+       char __dst[DNS_STRMAXLEN + 1] = { 0 };
 
        P->end  = fread(P->data, 1, P->size, stdin);
 
@@ -10634,7 +10636,7 @@ static int parse_packet(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
 
        dns_rr_foreach(&rr, P, .sort = MAIN.sort) {
                if (section != rr.section)
-                       fprintf(stdout, "\n;; [%s:%d]\n", dns_strsection(rr.section), dns_p_count(P, rr.section));
+                       fprintf(stdout, "\n;; [%s:%d]\n", dns_strsection(rr.section, __dst), dns_p_count(P, rr.section));
 
                if ((len = dns_rr_print(pretty, sizeof pretty, &rr, P, &error)))
                        fprintf(stdout, "%s\n", pretty);
@@ -10665,7 +10667,7 @@ static int parse_packet(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
                rr      = rrset[i];
 #endif
                if (section != rr.section)
-                       fprintf(stdout, "\n;; [%s:%d]\n", dns_strsection(rr.section), dns_p_count(Q, rr.section));
+                       fprintf(stdout, "\n;; [%s:%d]\n", dns_strsection(rr.section, __dst), dns_p_count(Q, rr.section));
 
                if ((len = dns_rr_print(pretty, sizeof pretty, &rr, Q, &error)))
                        fprintf(stdout, "%s\n", pretty);
@@ -10944,6 +10946,7 @@ static int send_query(int argc, char *argv[]) {
        struct dns_socket *so;
        int error, type;
        struct dns_options opts = { 0 };
+       char __dst[DNS_STRMAXLEN + 1] = { 0 };
 
        memset(&ss, 0, sizeof ss);
        if (argc > 1) {
@@ -10976,7 +10979,7 @@ static int send_query(int argc, char *argv[]) {
        else
                type    = dns_res_tcp2type(resconf()->options.tcp);
 
-       fprintf(stderr, "querying %s for %s IN %s\n", host, MAIN.qname, dns_strtype(MAIN.qtype));
+       fprintf(stderr, "querying %s for %s IN %s\n", host, MAIN.qname, dns_strtype(MAIN.qtype, __dst));
 
        if (!(so = dns_so_open((struct sockaddr *)&resconf()->iface, type, &opts, &error)))
                panic("dns_so_open: %s", dns_strerror(error));
@@ -11227,11 +11230,12 @@ static int echo_port(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
 
 
 static int isection(int argc, char *argv[]) {
+       char __dst[DNS_STRMAXLEN + 1] = { 0 };
        const char *name = (argc > 1)? argv[1] : "";
        int type;
 
        type = dns_isection(name);
-       name = dns_strsection(type);
+       name = dns_strsection(type, __dst);
 
        printf("%s (%d)\n", name, type);
 
@@ -11240,11 +11244,12 @@ static int isection(int argc, char *argv[]) {
 
 
 static int iclass(int argc, char *argv[]) {
+       char __dst[DNS_STRMAXLEN + 1] = { 0 };
        const char *name = (argc > 1)? argv[1] : "";
        int type;
 
        type = dns_iclass(name);
-       name = dns_strclass(type);
+       name = dns_strclass(type, __dst);
 
        printf("%s (%d)\n", name, type);
 
@@ -11253,11 +11258,12 @@ static int iclass(int argc, char *argv[]) {
 
 
 static int itype(int argc, char *argv[]) {
+       char __dst[DNS_STRMAXLEN + 1] = { 0 };
        const char *name = (argc > 1)? argv[1] : "";
        int type;
 
        type = dns_itype(name);
-       name = dns_strtype(type);
+       name = dns_strtype(type, __dst);
 
        printf("%s (%d)\n", name, type);
 
index 024d6dc..1f647e1 100644 (file)
@@ -272,15 +272,15 @@ enum dns_rcode {
  */
 #define DNS_STRMAXLEN 47 /* "QUESTION|ANSWER|AUTHORITY|ADDITIONAL" */
 
-DNS_PUBLIC const char *dns_strsection(enum dns_section);
+DNS_PUBLIC const char *dns_strsection(enum dns_section, char *);
 
 DNS_PUBLIC enum dns_section dns_isection(const char *);
 
-DNS_PUBLIC const char *dns_strclass(enum dns_class);
+DNS_PUBLIC const char *dns_strclass(enum dns_class, char *);
 
 DNS_PUBLIC enum dns_class dns_iclass(const char *);
 
-DNS_PUBLIC const char *dns_strtype(enum dns_type);
+DNS_PUBLIC const char *dns_strtype(enum dns_type, char *);
 
 DNS_PUBLIC enum dns_type dns_itype(const char *);
 
index 94d4efd..cae0351 100644 (file)
@@ -54,7 +54,7 @@ ldap_uri_p (const char *url)
              && (url[3] == 'p' || url[3] == 'P')
              && (url[4] == ':'
                  || ((url[4] == 's' || url[4] == 'S'
-                      || url[4] == 'i' || url[4] == 'i')
+                      || url[4] == 'i' || url[4] == 'I')
                      && url[5] == ':'))))
        return 1;
       return 0;
index eef04ed..ba47c99 100644 (file)
@@ -284,7 +284,7 @@ dump_string (const char *string)
       else
         {
           log_printf ( "[ ");
-          log_printhex (NULL, string, strlen (string));
+          log_printhex (string, strlen (string), NULL);
           log_printf ( " ]");
         }
     }
index 13e6120..eaa6ca2 100644 (file)
@@ -305,7 +305,7 @@ do_ocsp_request (ctrl_t ctrl, ksba_ocsp_t ocsp,
       if (opt.verbose)
         log_info (_("OCSP responder at '%s' status: %s\n"), url, t);
 
-      /* Get the signature value now because we can all this fucntion
+      /* Get the signature value now because we can call this function
        * only once.  */
       *r_sigval = ksba_ocsp_get_sig_val (ocsp, r_produced_at);
 
index 371852b..901c165 100644 (file)
@@ -888,6 +888,53 @@ pk_algo_from_sexp (gcry_sexp_t pkey)
 }
 
 
+/* Return the hash algorithm's algo id from its name given in the
+ * non-null termnated string in (buffer,buflen).  Returns 0 on failure
+ * or if the algo is not known.  */
+static int
+hash_algo_from_buffer (const void *buffer, size_t buflen)
+{
+  char *string;
+  int algo;
+
+  string = xtrymalloc (buflen + 1);
+  if (!string)
+    {
+      log_error (_("out of core\n"));
+      return 0;
+    }
+  memcpy (string, buffer, buflen);
+  string[buflen] = 0;
+  algo = gcry_md_map_name (string);
+  if (!algo)
+    log_error ("unknown digest algorithm '%s' used in certificate\n", string);
+  xfree (string);
+  return algo;
+}
+
+
+/* Return an unsigned integer from the non-null termnated string
+ * (buffer,buflen).  Returns 0 on failure.  */
+static unsigned int
+uint_from_buffer (const void *buffer, size_t buflen)
+{
+  char *string;
+  unsigned int val;
+
+  string = xtrymalloc (buflen + 1);
+  if (!string)
+    {
+      log_error (_("out of core\n"));
+      return 0;
+    }
+  memcpy (string, buffer, buflen);
+  string[buflen] = 0;
+  val = strtoul (string, NULL, 10);
+  xfree (string);
+  return val;
+}
+
+
 /* Check the signature on CERT using the ISSUER_CERT.  This function
  * does only test the cryptographic signature and nothing else.  It is
  * assumed that the ISSUER_CERT is valid.  */
@@ -897,45 +944,26 @@ check_cert_sig (ksba_cert_t issuer_cert, ksba_cert_t cert)
   gpg_error_t err;
   const char *algoid;
   gcry_md_hd_t md;
-  int i, algo;
+  int algo;
   ksba_sexp_t p;
   size_t n;
   gcry_sexp_t s_sig, s_hash, s_pkey;
-  const char *s;
-  char algo_name[16+1]; /* hash algorithm name converted to lower case. */
+  const char *algo_name; /* hash algorithm name converted to lower case. */
   int digestlen;
   unsigned char *digest;
+  int use_pss = 0;
+  unsigned int saltlen;
 
   /* Hash the target certificate using the algorithm from that certificate.  */
   algoid = ksba_cert_get_digest_algo (cert);
   algo = gcry_md_map_name (algoid);
-  if (!algo)
+  if (!algo && algoid && !strcmp (algoid, "1.2.840.113549.1.1.10"))
+    use_pss = 1;
+  else if (!algo)
     {
       log_error (_("unknown hash algorithm '%s'\n"), algoid? algoid:"?");
       return gpg_error (GPG_ERR_GENERAL);
     }
-  s = gcry_md_algo_name (algo);
-  for (i=0; *s && i < sizeof algo_name - 1; s++, i++)
-    algo_name[i] = tolower (*s);
-  algo_name[i] = 0;
-
-  err = gcry_md_open (&md, algo, 0);
-  if (err)
-    {
-      log_error ("md_open failed: %s\n", gpg_strerror (err));
-      return err;
-    }
-  if (DBG_HASHING)
-    gcry_md_debug (md, "hash.cert");
-
-  err = ksba_cert_hash (cert, 1, HASH_FNC, md);
-  if (err)
-    {
-      log_error ("ksba_cert_hash failed: %s\n", gpg_strerror (err));
-      gcry_md_close (md);
-      return err;
-    }
-  gcry_md_final (md);
 
   /* Get the signature value out of the target certificate.  */
   p = ksba_cert_get_sig_val (cert);
@@ -943,27 +971,96 @@ check_cert_sig (ksba_cert_t issuer_cert, ksba_cert_t cert)
   if (!n)
     {
       log_error ("libksba did not return a proper S-Exp\n");
-      gcry_md_close (md);
       ksba_free (p);
       return gpg_error (GPG_ERR_BUG);
     }
+  err = gcry_sexp_sscan ( &s_sig, NULL, p, n);
+  ksba_free (p);
+  if (err)
+    {
+      log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (err));
+      return err;
+    }
   if (DBG_CRYPTO)
+    gcry_log_debugsxp ("sigval", s_sig);
+
+  if (use_pss)
     {
-      int j;
-      log_debug ("signature value:");
-      for (j=0; j < n; j++)
-        log_printf (" %02X", p[j]);
-      log_printf ("\n");
+      /* Extract the hash algorithm and the salt length from the sigval.  */
+      gcry_buffer_t ioarray[2] = { {0}, {0} };
+
+      err = gcry_sexp_extract_param (s_sig, "sig-val",
+                                    "&'hash-algo''salt-length'",
+                                    ioarray+0, ioarray+1, NULL);
+      if (err)
+        {
+          gcry_sexp_release (s_sig);
+          log_error ("extracting params from PSS failed: %s\n",
+                     gpg_strerror (err));
+          return err;
+        }
+      algo = hash_algo_from_buffer (ioarray[0].data, ioarray[0].len);
+      saltlen = uint_from_buffer (ioarray[1].data, ioarray[1].len);
+      xfree (ioarray[0].data);
+      xfree (ioarray[1].data);
+      if (saltlen < 20)
+        {
+          log_error ("length of PSS salt too short\n");
+          gcry_sexp_release (s_sig);
+          return gpg_error (GPG_ERR_DIGEST_ALGO);
+        }
+      if (!algo)
+        {
+          gcry_sexp_release (s_sig);
+          return gpg_error (GPG_ERR_DIGEST_ALGO);
+        }
+      /* Add some restrictions; see ../sm/certcheck.c for details.  */
+      switch (algo)
+        {
+        case GCRY_MD_SHA1:
+        case GCRY_MD_SHA256:
+        case GCRY_MD_SHA384:
+        case GCRY_MD_SHA512:
+        case GCRY_MD_SHA3_256:
+        case GCRY_MD_SHA3_384:
+        case GCRY_MD_SHA3_512:
+          break;
+        default:
+          log_error ("PSS hash algorithm '%s' rejected\n",
+                     gcry_md_algo_name (algo));
+          gcry_sexp_release (s_sig);
+          return gpg_error (GPG_ERR_DIGEST_ALGO);
+        }
+
+      if (gcry_md_get_algo_dlen (algo) != saltlen)
+        {
+          log_error ("PSS hash algorithm '%s' rejected due to salt length %u\n",
+                     gcry_md_algo_name (algo), saltlen);
+          gcry_sexp_release (s_sig);
+          return gpg_error (GPG_ERR_DIGEST_ALGO);
+        }
     }
 
-  err = gcry_sexp_sscan ( &s_sig, NULL, p, n);
-  ksba_free (p);
+  algo_name = hash_algo_to_string (algo);
+  err = gcry_md_open (&md, algo, 0);
   if (err)
     {
-      log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (err));
+      log_error ("md_open failed: %s\n", gpg_strerror (err));
+      gcry_sexp_release (s_sig);
+      return err;
+    }
+  if (DBG_HASHING)
+    gcry_md_debug (md, "hash.cert");
+
+  err = ksba_cert_hash (cert, 1, HASH_FNC, md);
+  if (err)
+    {
+      log_error ("ksba_cert_hash failed: %s\n", gpg_strerror (err));
       gcry_md_close (md);
+      gcry_sexp_release (s_sig);
       return err;
     }
+  gcry_md_final (md);
 
   /* Get the public key from the issuer certificate.  */
   p = ksba_cert_get_public_key (issuer_cert);
@@ -994,10 +1091,22 @@ check_cert_sig (ksba_cert_t issuer_cert, ksba_cert_t cert)
    * S_SIG     - Signature value as given in the certificate.
    * MD        - Finalized hash context with hash of the certificate.
    * ALGO_NAME - Lowercase hash algorithm name
+   * SALTLEN   - Salt length for rsaPSS.
    */
   digestlen = gcry_md_get_algo_dlen (algo);
   digest = gcry_md_read (md, algo);
-  if (pk_algo_from_sexp (s_pkey) == GCRY_PK_DSA)
+  if (use_pss)
+    {
+      err = gcry_sexp_build (&s_hash, NULL,
+                             "(data (flags pss)"
+                             "(hash %s %b)"
+                             "(salt-length %u))",
+                             algo_name,
+                             (int)digestlen,
+                             digest,
+                             saltlen);
+    }
+  else if (pk_algo_from_sexp (s_pkey) == GCRY_PK_DSA)
     {
       /* NB.: We support only SHA-1 here because we had problems back
        * then to get test data for DSA-2.  Meanwhile DSA has been
@@ -1010,19 +1119,17 @@ check_cert_sig (ksba_cert_t issuer_cert, ksba_cert_t cert)
           gcry_sexp_release (s_pkey);
           return gpg_error (GPG_ERR_INTERNAL);
         }
-      if ( gcry_sexp_build (&s_hash, NULL, "(data(flags raw)(value %b))",
-                            (int)digestlen, digest) )
-        BUG ();
+      err = gcry_sexp_build (&s_hash, NULL, "(data(flags raw)(value %b))",
+                             (int)digestlen, digest);
     }
   else /* Not DSA - we assume RSA  */
     {
-      if ( gcry_sexp_build (&s_hash, NULL, "(data(flags pkcs1)(hash %s %b))",
-                            algo_name, (int)digestlen, digest) )
-        BUG ();
-
+      err = gcry_sexp_build (&s_hash, NULL, "(data(flags pkcs1)(hash %s %b))",
+                             algo_name, (int)digestlen, digest);
     }
 
-  err = gcry_pk_verify (s_sig, s_hash, s_pkey);
+  if (!err)
+    err = gcry_pk_verify (s_sig, s_hash, s_pkey);
   if (DBG_X509)
     log_debug ("gcry_pk_verify: %s\n", gpg_strerror (err));
   gcry_md_close (md);
index 883fe03..acca242 100644 (file)
@@ -545,9 +545,10 @@ pkd:0:1024:B665B1435F4C2 .... FF26ABB:
     actual key used for descryption.  <fpr2> is the fingerprint of the
     primary key.  <otrust> is the letter with the ownertrust; this is
     in general a 'u' which stands for ultimately trusted.
-*** DECRYPTION_INFO <mdc_method> <sym_algo>
+*** DECRYPTION_INFO <mdc_method> <sym_algo> [<aead_algo>]
     Print information about the symmetric encryption algorithm and the
     MDC method.  This will be emitted even if the decryption fails.
+    For an AEAD algorithm AEAD_ALGO is not 0.
 
 *** DECRYPTION_FAILED
     The symmetric decryption failed - one reason could be a wrong
@@ -1138,6 +1139,38 @@ pkd:0:1024:B665B1435F4C2 .... FF26ABB:
 *** BEGIN_STREAM, END_STREAM
     Used to issued by the experimental pipemode.
 
+** Inter-component codes
+   Status codes are also used between the components of the GnuPG
+   system via the Assuan S lines.  Some of them are documented here:
+
+*** PUBKEY_INFO <n> <ubid>
+    The type of the public key in the following D-lines or
+    communicated via a pipe.  <n> is the value of =enum pubkey_types=
+    and <ubid> the Unique Blob ID (UBID) which is the fingerprint of
+    the primary key truncated to 20 octets and formatted in hex.  Note
+    that the keyboxd SEARCH command can be used to lookup the public
+    key using the <ubid> prefixed with a caret (^).
+
+*** KEYPAIRINFO <grip> <keyref> [<usage>] [<keytime>]
+
+    This status is emitted by scdaemon and gpg-agent to convey brief
+    information about keypairs stored on tokens.  <grip> is the
+    hexified keygrip of the key or, if no key is stored, an "X".
+    <keyref> is the ID of a card's key; for example "OPENPGP.2" for
+    the second key slot of an OpenPGP card.  <usage> is optional and
+    returns technically possible key usages, this is a string of
+    single letters describing the usage ('c' for certify, 'e' for
+    encryption, 's' for signing, 'a' for authentication). A '-' can be
+    used to tell that usage flags are not conveyed.  <keytime> is used
+    by OpenPGP cards for the stored key creation time.  A '-' means no
+    info available.  The format is the usual ISO string are a number
+    with the seconds since Epoch.
+*** MANUFACTURER <n> [<string>]
+
+    This status returns the Manufactorer ID as the unsigned number N.
+    For OpenPGP this is weel defined; for other cards this is 0.  The
+    name of the manufacturer is also given as <string>; spaces are not
+    escaped.  For PKCS#15 cards <string> is TokenInfo.manufactorerID.
 
 * Format of the --attribute-fd output
 
index d47d83e..ca13bcf 100644 (file)
@@ -182,6 +182,8 @@ defsincdate: $(gnupg_TEXINFOS)
        if test -e $(top_srcdir)/.git; then \
          (cd $(srcdir) && git log -1 --format='%ct' \
                -- $(gnupg_TEXINFOS) 2>/dev/null) >>defsincdate; \
+        elif test x"$SOURCE_DATE_EPOCH" != x; then   \
+          echo "$SOURCE_DATE_EPOCH" >>defsincdate ; \
        fi
 
 defs.inc : defsincdate Makefile mkdefsinc
index eb30368..1c329a7 100644 (file)
@@ -409,9 +409,14 @@ change it.
 @itemx --disable-crl-checks
 @opindex enable-crl-checks
 @opindex disable-crl-checks
-By default the @acronym{CRL} checks are enabled and the DirMngr is used
-to check for revoked certificates.  The disable option is most useful
-with an off-line network connection to suppress this check.
+By default the @acronym{CRL} checks are enabled and the DirMngr is
+used to check for revoked certificates.  The disable option is most
+useful with an off-line network connection to suppress this check and
+also to avoid that new certificates introduce a web bug by including a
+certificate specific CRL DP.  The disable option also disables an
+issuer certificate lookup via the authorityInfoAccess property of the
+certificate; the @option{--enable-issuer-key-retrieve} can be used
+to make use of that property anyway.
 
 @item  --enable-trusted-cert-crl-check
 @itemx --disable-trusted-cert-crl-check
@@ -438,6 +443,14 @@ hold in the keybox.  The suggested way of doing this is by using it
 along with the option @option{--with-validation} for a key listing
 command.  This option should not be used in a configuration file.
 
+@item --enable-issuer-based-crl-check
+@opindex enable-issuer-based-crl-check
+Run a CRL check even for certificates which do not have any CRL
+distribution point.  This requires that a suitable LDAP server has
+been configured in Dirmngr and that the CRL can be found using the
+issuer.  This option reverts to what GnuPG did up to version 2.2.20.
+This option is in general not useful.
+
 @item  --enable-ocsp
 @itemx --disable-ocsp
 @opindex enable-ocsp
index 574f6ca..7c08c9b 100644 (file)
@@ -484,6 +484,7 @@ agent_release_card_info (struct agent_card_info_s *info)
     return;
 
   xfree (info->reader); info->reader = NULL;
+  xfree (info->manufacturer_name); info->manufacturer_name = NULL;
   xfree (info->serialno); info->serialno = NULL;
   xfree (info->apptype); info->apptype = NULL;
   xfree (info->disp_name); info->disp_name = NULL;
@@ -507,6 +508,7 @@ learn_status_cb (void *opaque, const char *line)
   const char *keyword = line;
   int keywordlen;
   int i;
+  char *endp;
 
   for (keywordlen=0; *line && !spacep (line); line++, keywordlen++)
     ;
@@ -706,6 +708,16 @@ learn_status_cb (void *opaque, const char *line)
       xfree (parm->private_do[no]);
       parm->private_do[no] = unescape_status_string (line);
     }
+  else if (keywordlen == 12 && !memcmp (keyword, "MANUFACTURER", 12))
+    {
+      xfree (parm->manufacturer_name);
+      parm->manufacturer_name = NULL;
+      parm->manufacturer_id = strtoul (line, &endp, 0);
+      while (endp && spacep (endp))
+        endp++;
+      if (endp && *endp)
+        parm->manufacturer_name = xstrdup (endp);
+    }
   else if (keywordlen == 3 && !memcmp (keyword, "KDF", 3))
     {
       unsigned char *data = unescape_status_string (line);
@@ -1518,13 +1530,15 @@ agent_scd_checkpin  (const char *serialno)
 \f
 /* Note: All strings shall be UTF-8. On success the caller needs to
    free the string stored at R_PASSPHRASE. On error NULL will be
-   stored at R_PASSPHRASE and an appropriate fpf error code
-   returned. */
+   stored at R_PASSPHRASE and an appropriate error code returned.
+   Only called from passphrase.c:passphrase_get - see there for more
+   comments on this ugly API. */
 gpg_error_t
 agent_get_passphrase (const char *cache_id,
                       const char *err_msg,
                       const char *prompt,
                       const char *desc_msg,
+                      int newsymkey,
                       int repeat,
                       int check,
                       char **r_passphrase)
@@ -1537,6 +1551,7 @@ agent_get_passphrase (const char *cache_id,
   char *arg4 = NULL;
   membuf_t data;
   struct default_inq_parm_s dfltparm;
+  int have_newsymkey;
 
   memset (&dfltparm, 0, sizeof dfltparm);
 
@@ -1552,6 +1567,10 @@ agent_get_passphrase (const char *cache_id,
                        "GETINFO cmd_has_option GET_PASSPHRASE repeat",
                        NULL, NULL, NULL, NULL, NULL, NULL))
     return gpg_error (GPG_ERR_NOT_SUPPORTED);
+  have_newsymkey = !(assuan_transact
+                     (agent_ctx,
+                      "GETINFO cmd_has_option GET_PASSPHRASE newsymkey",
+                      NULL, NULL, NULL, NULL, NULL, NULL));
 
   if (cache_id && *cache_id)
     if (!(arg1 = percent_plus_escape (cache_id)))
@@ -1566,10 +1585,14 @@ agent_get_passphrase (const char *cache_id,
     if (!(arg4 = percent_plus_escape (desc_msg)))
       goto no_mem;
 
+  /* CHECK && REPEAT or NEWSYMKEY is here an indication that a new
+   * passphrase for symmetric encryption is requested; if the agent
+   * supports this we enable the modern API by also passing --newsymkey.  */
   snprintf (line, DIM(line),
-            "GET_PASSPHRASE --data --repeat=%d%s -- %s %s %s %s",
+            "GET_PASSPHRASE --data --repeat=%d%s%s -- %s %s %s %s",
             repeat,
-            check? " --check --qualitybar":"",
+            ((repeat && check) || newsymkey)? " --check":"",
+            (have_newsymkey && newsymkey)? " --newsymkey":"",
             arg1? arg1:"X",
             arg2? arg2:"X",
             arg3? arg3:"X",
index 94ca154..784ed5c 100644 (file)
@@ -32,6 +32,8 @@ struct agent_card_info_s
   int error;         /* private. */
   char *reader;      /* Reader information.  */
   char *apptype;     /* Malloced application type string.  */
+  unsigned int manufacturer_id;
+  char *manufacturer_name; /* malloced.  */
   char *serialno;    /* malloced hex string. */
   char *disp_name;   /* malloced. */
   char *disp_lang;   /* malloced. */
@@ -133,6 +135,7 @@ gpg_error_t agent_get_passphrase (const char *cache_id,
                                   const char *err_msg,
                                   const char *prompt,
                                   const char *desc_msg,
+                                  int newsymkey,
                                   int repeat,
                                   int check,
                                   char **r_passphrase);
index 3aaea84..00b64b3 100644 (file)
@@ -192,46 +192,6 @@ change_pin (int unblock_v2, int allow_admin)
   agent_release_card_info (&info);
 }
 
-static const char *
-get_manufacturer (unsigned int no)
-{
-  /* Note:  Make sure that there is no colon or linefeed in the string. */
-  switch (no)
-    {
-    case 0x0001: return "PPC Card Systems";
-    case 0x0002: return "Prism";
-    case 0x0003: return "OpenFortress";
-    case 0x0004: return "Wewid";
-    case 0x0005: return "ZeitControl";
-    case 0x0006: return "Yubico";
-    case 0x0007: return "OpenKMS";
-    case 0x0008: return "LogoEmail";
-    case 0x0009: return "Fidesmo";
-    case 0x000A: return "Dangerous Things";
-    case 0x000B: return "Feitian Technologies";
-
-    case 0x002A: return "Magrathea";
-    case 0x0042: return "GnuPG e.V.";
-
-    case 0x1337: return "Warsaw Hackerspace";
-    case 0x2342: return "warpzone"; /* hackerspace Muenster.  */
-    case 0x4354: return "Confidential Technologies";   /* cotech.de */
-    case 0x5443: return "TIF-IT e.V.";
-    case 0x63AF: return "Trustica";
-    case 0xBA53: return "c-base e.V.";
-    case 0xBD0E: return "Paranoidlabs";
-    case 0xF517: return "FSIJ";
-    case 0xF5EC: return "F-Secure";
-
-      /* 0x0000 and 0xFFFF are defined as test cards per spec,
-         0xFF00 to 0xFFFE are assigned for use with randomly created
-         serial numbers.  */
-    case 0x0000:
-    case 0xffff: return "test card";
-    default: return (no & 0xff00) == 0xff00? "unmanaged S/N range":"unknown";
-    }
-}
-
 
 static void
 print_sha1_fpr (estream_t fp, const unsigned char *fpr)
@@ -393,6 +353,7 @@ current_card_status (ctrl_t ctrl, estream_t fp,
   unsigned int uval;
   const unsigned char *thefpr;
   int i;
+  char *pesc;
 
   if (serialno && serialnobuflen)
     *serialno = 0;
@@ -479,7 +440,10 @@ current_card_status (ctrl_t ctrl, estream_t fp,
     {
       es_fprintf (fp, "version:%.4s:\n", info.serialno+12);
       uval = xtoi_2(info.serialno+16)*256 + xtoi_2 (info.serialno+18);
-      es_fprintf (fp, "vendor:%04x:%s:\n", uval, get_manufacturer (uval));
+      pesc = (info.manufacturer_name
+              ? percent_escape (info.manufacturer_name, NULL) : NULL);
+      es_fprintf (fp, "vendor:%04x:%s:\n", uval, pesc? pesc:"");
+      xfree (pesc);
       es_fprintf (fp, "serial:%.8s:\n", info.serialno+20);
 
       print_isoname (fp, "Name of cardholder: ", "name", info.disp_name);
@@ -572,8 +536,7 @@ current_card_status (ctrl_t ctrl, estream_t fp,
                    info.serialno[14] == '0'?"":info.serialno+14,
                    info.serialno[15]);
       tty_fprintf (fp, "Manufacturer .....: %s\n",
-                   get_manufacturer (xtoi_2(info.serialno+16)*256
-                                     + xtoi_2 (info.serialno+18)));
+                   info.manufacturer_name? info.manufacturer_name : "?");
       tty_fprintf (fp, "Serial number ....: %.8s\n", info.serialno+20);
 
       print_isoname (fp, "Name of cardholder: ", "name", info.disp_name);
index 736534d..2793885 100644 (file)
@@ -1,6 +1,7 @@
 /* decrypt-data.c - Decrypt an encrypted data packet
- * Copyright (C) 1998, 1999, 2000, 2001, 2005,
- *               2006, 2009 Free Software Foundation, Inc.
+ * Copyright (C) 1998-2001, 2005-2006, 2009 Free Software Foundation, Inc.
+ * Copyright (C) 1998-2001, 2005-2006, 2009, 2018 Werner Koch
+ * Copyright (C) 2020 g10 Code GmbH
  *
  * This file is part of GnuPG.
  *
@@ -16,6 +17,7 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: GPL-3.0-or-later
  */
 
 #include <config.h>
 #include "../common/compliance.h"
 
 
+static int aead_decode_filter (void *opaque, int control, iobuf_t a,
+                               byte *buf, size_t *ret_len);
 static int mdc_decode_filter ( void *opaque, int control, IOBUF a,
                                byte *buf, size_t *ret_len);
 static int decode_filter ( void *opaque, int control, IOBUF a,
                                        byte *buf, size_t *ret_len);
 
-typedef struct decode_filter_context_s
+/* Our context object.  */
+struct decode_filter_context_s
 {
+  /* Recounter (max value is 2).  We need it because we do not know
+   * whether the iobuf or the outer control code frees this object
+   * first.  */
+  int  refcount;
+
+  /* The cipher handle.  */
   gcry_cipher_hd_t cipher_hd;
+
+  /* The hash handle for use in MDC mode.  */
   gcry_md_hd_t mdc_hash;
-  char defer[22];
-  int  defer_filled;
-  int  eof_seen;
-  int  refcount;
-  int  partial;   /* Working on a partial length packet.  */
-  size_t length;  /* If !partial: Remaining bytes in the packet.  */
-} *decode_filter_ctx_t;
+
+  /* The start IV for AEAD encryption.   */
+  byte startiv[16];
+
+  /* The holdback buffer and its used length.  For AEAD we need 32+1
+   * bytes but we use 48 byte.  For MDC we need 22 bytes; here
+   * holdbacklen will either 0 or 22.  */
+  char holdback[48];
+  unsigned int holdbacklen;
+
+  /* Working on a partial length packet.  */
+  unsigned int partial : 1;
+
+  /* EOF indicator with these true values:
+   *   1 = normal EOF
+   *   2 = premature EOF (tag or hash incomplete)
+   *   3 = premature EOF (general)       */
+  unsigned int eof_seen : 2;
+
+  /* The actually used cipher algo for AEAD.  */
+  byte cipher_algo;
+
+  /* The AEAD algo.  */
+  byte aead_algo;
+
+  /* The encoded chunk byte for AEAD.  */
+  byte chunkbyte;
+
+  /* The decoded CHUNKBYTE.  */
+  uint64_t chunksize;
+
+  /* The chunk index for AEAD.  */
+  uint64_t chunkindex;
+
+  /* The number of bytes in the current chunk.  */
+  uint64_t chunklen;
+
+  /* The total count of decrypted plaintext octets.  */
+  uint64_t total;
+
+  /* Remaining bytes in the packet according to the packet header.
+   * Not used if PARTIAL is true.  */
+  size_t length;
+};
+typedef struct decode_filter_context_s *decode_filter_ctx_t;
 
 
 /* Helper to release the decode context.  */
@@ -69,6 +120,99 @@ release_dfx_context (decode_filter_ctx_t dfx)
 }
 
 
+/* Set the nonce and the additional data for the current chunk.  This
+ * also reset the decryption machinery so that the handle can be
+ * used for a new chunk.  If FINAL is set the final AEAD chunk is
+ * processed.  */
+static gpg_error_t
+aead_set_nonce_and_ad (decode_filter_ctx_t dfx, int final)
+{
+  gpg_error_t err;
+  unsigned char ad[21];
+  unsigned char nonce[16];
+  int i;
+
+  switch (dfx->aead_algo)
+    {
+    case AEAD_ALGO_OCB:
+      memcpy (nonce, dfx->startiv, 15);
+      i = 7;
+      break;
+
+    case AEAD_ALGO_EAX:
+      memcpy (nonce, dfx->startiv, 16);
+      i = 8;
+      break;
+
+    default:
+      BUG ();
+    }
+  nonce[i++] ^= dfx->chunkindex >> 56;
+  nonce[i++] ^= dfx->chunkindex >> 48;
+  nonce[i++] ^= dfx->chunkindex >> 40;
+  nonce[i++] ^= dfx->chunkindex >> 32;
+  nonce[i++] ^= dfx->chunkindex >> 24;
+  nonce[i++] ^= dfx->chunkindex >> 16;
+  nonce[i++] ^= dfx->chunkindex >>  8;
+  nonce[i++] ^= dfx->chunkindex;
+
+  if (DBG_CRYPTO)
+    log_printhex (nonce, i, "nonce:");
+  err = gcry_cipher_setiv (dfx->cipher_hd, nonce, i);
+  if (err)
+    return err;
+
+  ad[0] = (0xc0 | PKT_ENCRYPTED_AEAD);
+  ad[1] = 1;
+  ad[2] = dfx->cipher_algo;
+  ad[3] = dfx->aead_algo;
+  ad[4] = dfx->chunkbyte;
+  ad[5] = dfx->chunkindex >> 56;
+  ad[6] = dfx->chunkindex >> 48;
+  ad[7] = dfx->chunkindex >> 40;
+  ad[8] = dfx->chunkindex >> 32;
+  ad[9] = dfx->chunkindex >> 24;
+  ad[10]= dfx->chunkindex >> 16;
+  ad[11]= dfx->chunkindex >>  8;
+  ad[12]= dfx->chunkindex;
+  if (final)
+    {
+      ad[13] = dfx->total >> 56;
+      ad[14] = dfx->total >> 48;
+      ad[15] = dfx->total >> 40;
+      ad[16] = dfx->total >> 32;
+      ad[17] = dfx->total >> 24;
+      ad[18] = dfx->total >> 16;
+      ad[19] = dfx->total >>  8;
+      ad[20] = dfx->total;
+    }
+  if (DBG_CRYPTO)
+    log_printhex (ad, final? 21 : 13, "authdata:");
+  return gcry_cipher_authenticate (dfx->cipher_hd, ad, final? 21 : 13);
+}
+
+
+/* Helper to check the 16 byte tag in TAGBUF.  The FINAL flag is only
+ * for debug messages.  */
+static gpg_error_t
+aead_checktag (decode_filter_ctx_t dfx, int final, const void *tagbuf)
+{
+  gpg_error_t err;
+
+  if (DBG_FILTER)
+    log_printhex (tagbuf, 16, "tag:");
+  err = gcry_cipher_checktag (dfx->cipher_hd, tagbuf, 16);
+  if (err)
+    {
+      log_error ("gcry_cipher_checktag%s failed: %s\n",
+                 final? " (final)":"", gpg_strerror (err));
+      return err;
+    }
+  if (DBG_FILTER)
+    log_debug ("%stag is valid\n", final?"final ":"");
+  return 0;
+}
+
 
 /****************
  * Decrypt the data, specified by ED with the key DEK.
@@ -77,6 +221,8 @@ int
 decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek)
 {
   decode_filter_ctx_t dfx;
+  enum gcry_cipher_modes ciphermode;
+  unsigned int startivlen;
   byte *p;
   int rc=0, c, i;
   byte temp[32];
@@ -98,9 +244,18 @@ decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek)
       dek->algo_info_printed = 1;
     }
 
+  if (ed->aead_algo)
+    {
+      rc = openpgp_aead_algo_info (ed->aead_algo, &ciphermode, &startivlen);
+      if (rc)
+        goto leave;
+      log_assert (startivlen <= sizeof dfx->startiv);
+    }
+  else
+    ciphermode = GCRY_CIPHER_MODE_CFB;
+
   /* Check compliance.  */
-  if (! gnupg_cipher_is_allowed (opt.compliance, 0, dek->algo,
-                                 GCRY_CIPHER_MODE_CFB))
+  if (!gnupg_cipher_is_allowed (opt.compliance, 0, dek->algo, ciphermode))
     {
       log_error (_("cipher algorithm '%s' may not be used in %s mode\n"),
                 openpgp_cipher_algo_name (dek->algo),
@@ -109,12 +264,8 @@ decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek)
       goto leave;
     }
 
-  {
-    char buf[20];
-
-    snprintf (buf, sizeof buf, "%d %d", ed->mdc_method, dek->algo);
-    write_status_text (STATUS_DECRYPTION_INFO, buf);
-  }
+  write_status_printf (STATUS_DECRYPTION_INFO, "%d %d %d",
+                       ed->mdc_method, dek->algo, 0);
 
   if (opt.show_session_key)
     {
@@ -139,95 +290,181 @@ decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek)
   blocksize = openpgp_cipher_get_algo_blklen (dek->algo);
   if ( !blocksize || blocksize > 16 )
     log_fatal ("unsupported blocksize %u\n", blocksize );
-  nprefix = blocksize;
-  if ( ed->len && ed->len < (nprefix+2) )
-    {
-       /* An invalid message.  We can't check that during parsing
-          because we may not know the used cipher then.  */
-      rc = gpg_error (GPG_ERR_INV_PACKET);
-      goto leave;
-    }
 
-  if ( ed->mdc_method )
+  if (ed->aead_algo)
     {
-      if (gcry_md_open (&dfx->mdc_hash, ed->mdc_method, 0 ))
-        BUG ();
-      if ( DBG_HASHING )
-        gcry_md_debug (dfx->mdc_hash, "checkmdc");
-    }
+      if (blocksize != 16)
+        {
+          rc = gpg_error (GPG_ERR_CIPHER_ALGO);
+          goto leave;
+        }
 
-  rc = openpgp_cipher_open (&dfx->cipher_hd, dek->algo,
-                           GCRY_CIPHER_MODE_CFB,
-                           (GCRY_CIPHER_SECURE
-                            | ((ed->mdc_method || dek->algo >= 100)?
-                               0 : GCRY_CIPHER_ENABLE_SYNC)));
-  if (rc)
-    {
-      /* We should never get an error here cause we already checked
-       * that the algorithm is available.  */
-      BUG();
-    }
+      if (ed->chunkbyte > 56)
+        {
+          log_error ("invalid AEAD chunkbyte %u\n", ed->chunkbyte);
+          rc = gpg_error (GPG_ERR_INV_PACKET);
+          goto leave;
+        }
 
+      /* Read the Start-IV. */
+      if (ed->len)
+        {
+          for (i=0; i < startivlen && ed->len; i++, ed->len--)
+            {
+              if ((c=iobuf_get (ed->buf)) == -1)
+                break;
+              dfx->startiv[i] = c;
+            }
+        }
+      else
+        {
+          for (i=0; i < startivlen; i++ )
+            if ( (c=iobuf_get (ed->buf)) == -1 )
+              break;
+            else
+              dfx->startiv[i] = c;
+        }
+      if (i != startivlen)
+        {
+          log_error ("Start-IV in AEAD packet too short (%d/%u)\n",
+                     i, startivlen);
+          rc = gpg_error (GPG_ERR_TOO_SHORT);
+          goto leave;
+        }
+
+      dfx->cipher_algo = ed->cipher_algo;
+      dfx->aead_algo = ed->aead_algo;
+      dfx->chunkbyte = ed->chunkbyte;
+      dfx->chunksize = (uint64_t)1 << (dfx->chunkbyte + 6);
+
+      if (dek->algo != dfx->cipher_algo)
+        log_info ("Note: different cipher algorithms used (%s/%s)\n",
+                  openpgp_cipher_algo_name (dek->algo),
+                  openpgp_cipher_algo_name (dfx->cipher_algo));
+
+      rc = openpgp_cipher_open (&dfx->cipher_hd,
+                                dfx->cipher_algo,
+                                ciphermode,
+                                GCRY_CIPHER_SECURE);
+      if (rc)
+        goto leave; /* Should never happen.  */
+
+      if (DBG_CRYPTO)
+        log_printhex (dek->key, dek->keylen, "thekey:");
+      rc = gcry_cipher_setkey (dfx->cipher_hd, dek->key, dek->keylen);
+      if (gpg_err_code (rc) == GPG_ERR_WEAK_KEY)
+        {
+          log_info (_("WARNING: message was encrypted with"
+                      " a weak key in the symmetric cipher.\n"));
+          rc = 0;
+        }
+      else if (rc)
+        {
+          log_error("key setup failed: %s\n", gpg_strerror (rc));
+          goto leave;
+        }
+
+      if (!ed->buf)
+        {
+          log_error(_("problem handling encrypted packet\n"));
+          goto leave;
+        }
 
-  /* log_hexdump( "thekey", dek->key, dek->keylen );*/
-  rc = gcry_cipher_setkey (dfx->cipher_hd, dek->key, dek->keylen);
-  if ( gpg_err_code (rc) == GPG_ERR_WEAK_KEY )
-    {
-      log_info(_("WARNING: message was encrypted with"
-                 " a weak key in the symmetric cipher.\n"));
-      rc=0;
     }
-  else if( rc )
+  else /* CFB encryption.  */
     {
-      log_error("key setup failed: %s\n", gpg_strerror (rc) );
-      goto leave;
-    }
+      nprefix = blocksize;
+      if ( ed->len && ed->len < (nprefix+2) )
+        {
+          /* An invalid message.  We can't check that during parsing
+           * because we may not know the used cipher then.  */
+          rc = gpg_error (GPG_ERR_INV_PACKET);
+          goto leave;
+        }
 
-  if (!ed->buf)
-    {
-      log_error(_("problem handling encrypted packet\n"));
-      goto leave;
-    }
+      if ( ed->mdc_method )
+        {
+          if (gcry_md_open (&dfx->mdc_hash, ed->mdc_method, 0 ))
+            BUG ();
+          if ( DBG_HASHING )
+            gcry_md_debug (dfx->mdc_hash, "checkmdc");
+        }
+
+      rc = openpgp_cipher_open (&dfx->cipher_hd, dek->algo,
+                                GCRY_CIPHER_MODE_CFB,
+                                (GCRY_CIPHER_SECURE
+                                 | ((ed->mdc_method || dek->algo >= 100)?
+                                    0 : GCRY_CIPHER_ENABLE_SYNC)));
+      if (rc)
+        {
+          /* We should never get an error here cause we already checked
+           * that the algorithm is available.  */
+          BUG();
+        }
 
-  gcry_cipher_setiv (dfx->cipher_hd, NULL, 0);
 
-  if ( ed->len )
-    {
-      for (i=0; i < (nprefix+2) && ed->len; i++, ed->len-- )
+      /* log_hexdump( "thekey", dek->key, dek->keylen );*/
+      rc = gcry_cipher_setkey (dfx->cipher_hd, dek->key, dek->keylen);
+      if ( gpg_err_code (rc) == GPG_ERR_WEAK_KEY )
         {
-          if ( (c=iobuf_get(ed->buf)) == -1 )
-            break;
-          else
-            temp[i] = c;
+          log_info (_("WARNING: message was encrypted with"
+                      " a weak key in the symmetric cipher.\n"));
+          rc = 0;
+        }
+      else if (rc)
+        {
+          log_error("key setup failed: %s\n", gpg_strerror (rc) );
+          goto leave;
         }
-    }
-  else
-    {
-      for (i=0; i < (nprefix+2); i++ )
-        if ( (c=iobuf_get(ed->buf)) == -1 )
-          break;
-        else
-          temp[i] = c;
-    }
 
-  gcry_cipher_decrypt (dfx->cipher_hd, temp, nprefix+2, NULL, 0);
-  gcry_cipher_sync (dfx->cipher_hd);
-  p = temp;
-  /* log_hexdump( "prefix", temp, nprefix+2 ); */
-  if (dek->symmetric
-      && (p[nprefix-2] != p[nprefix] || p[nprefix-1] != p[nprefix+1]) )
-    {
-      rc = gpg_error (GPG_ERR_BAD_KEY);
-      goto leave;
-    }
+      if (!ed->buf)
+        {
+          log_error (_("problem handling encrypted packet\n"));
+          goto leave;
+        }
 
-  if ( dfx->mdc_hash )
-    gcry_md_write (dfx->mdc_hash, temp, nprefix+2);
+      gcry_cipher_setiv (dfx->cipher_hd, NULL, 0);
+
+      if ( ed->len )
+        {
+          for (i=0; i < (nprefix+2) && ed->len; i++, ed->len-- )
+            {
+              if ( (c=iobuf_get(ed->buf)) == -1 )
+                break;
+              else
+                temp[i] = c;
+            }
+        }
+      else
+        {
+          for (i=0; i < (nprefix+2); i++ )
+            if ( (c=iobuf_get(ed->buf)) == -1 )
+              break;
+            else
+              temp[i] = c;
+        }
+
+      gcry_cipher_decrypt (dfx->cipher_hd, temp, nprefix+2, NULL, 0);
+      gcry_cipher_sync (dfx->cipher_hd);
+      p = temp;
+      /* log_hexdump( "prefix", temp, nprefix+2 ); */
+      if (dek->symmetric
+          && (p[nprefix-2] != p[nprefix] || p[nprefix-1] != p[nprefix+1]) )
+        {
+          rc = gpg_error (GPG_ERR_BAD_KEY);
+          goto leave;
+        }
+
+      if ( dfx->mdc_hash )
+        gcry_md_write (dfx->mdc_hash, temp, nprefix+2);
+    }
 
   dfx->refcount++;
-  dfx->partial = ed->is_partial;
+  dfx->partial = !!ed->is_partial;
   dfx->length = ed->len;
-  if ( ed->mdc_method )
+  if (ed->aead_algo)
+    iobuf_push_filter ( ed->buf, aead_decode_filter, dfx );
+  else if (ed->mdc_method)
     iobuf_push_filter ( ed->buf, mdc_decode_filter, dfx );
   else
     iobuf_push_filter ( ed->buf, decode_filter, dfx );
@@ -287,26 +524,359 @@ decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek)
 
       log_assert (dfx->cipher_hd);
       log_assert (dfx->mdc_hash);
-      gcry_cipher_decrypt (dfx->cipher_hd, dfx->defer, 22, NULL, 0);
-      gcry_md_write (dfx->mdc_hash, dfx->defer, 2);
+      gcry_cipher_decrypt (dfx->cipher_hd, dfx->holdback, 22, NULL, 0);
+      gcry_md_write (dfx->mdc_hash, dfx->holdback, 2);
       gcry_md_final (dfx->mdc_hash);
 
-      if (   dfx->defer[0] != '\xd3'
-          || dfx->defer[1] != '\x14'
+      if (   dfx->holdback[0] != '\xd3'
+          || dfx->holdback[1] != '\x14'
           || datalen != 20
-          || memcmp (gcry_md_read (dfx->mdc_hash, 0), dfx->defer+2, datalen))
+          || memcmp (gcry_md_read (dfx->mdc_hash, 0), dfx->holdback+2, datalen))
         rc = gpg_error (GPG_ERR_BAD_SIGNATURE);
-      /* log_printhex("MDC message:", dfx->defer, 22); */
-      /* log_printhex("MDC calc:", gcry_md_read (dfx->mdc_hash,0), datalen); */
+      /* log_printhex(dfx->holdback, 22, "MDC message:"); */
+      /* log_printhex(gcry_md_read (dfx->mdc_hash,0), datalen, "MDC calc:"); */
     }
 
-
  leave:
   release_dfx_context (dfx);
   return rc;
 }
 
 
+/* Fill BUFFER with up to NBYTES-OFFSET from STREAM utilizing
+ * information from the context DFX.  Returns the new offset which is
+ * the number of bytes read plus the original offset.  On EOF the
+ * respective flag in DFX is set. */
+static size_t
+fill_buffer (decode_filter_ctx_t dfx, iobuf_t stream,
+             byte *buffer, size_t nbytes, size_t offset)
+{
+  size_t nread = offset;
+  size_t curr;
+  int ret;
+
+  if (dfx->partial)
+    {
+      while (nread < nbytes)
+        {
+          curr = nbytes - nread;
+
+          ret = iobuf_read (stream, &buffer[nread], curr);
+          if (ret == -1)
+            {
+              dfx->eof_seen = 1; /* Normal EOF. */
+              break;
+            }
+
+          nread += ret;
+        }
+    }
+  else
+    {
+      while (nread < nbytes && dfx->length)
+        {
+          curr = nbytes - nread;
+          if (curr > dfx->length)
+            curr = dfx->length;
+
+          ret = iobuf_read (stream, &buffer[nread], curr);
+          if (ret == -1)
+            {
+              dfx->eof_seen = 3; /* Premature EOF. */
+              break;
+            }
+
+          nread += ret;
+          dfx->length -= ret;
+        }
+      if (!dfx->length)
+        dfx->eof_seen = 1; /* Normal EOF.  */
+    }
+
+  return nread;
+}
+
+
+/* The core of the AEAD decryption.  This is the underflow function of
+ * the aead_decode_filter.  */
+static gpg_error_t
+aead_underflow (decode_filter_ctx_t dfx, iobuf_t a, byte *buf, size_t *ret_len)
+{
+  const size_t size = *ret_len; /* The allocated size of BUF.  */
+  gpg_error_t err;
+  size_t totallen = 0; /* The number of bytes to return on success or EOF.  */
+  size_t off = 0;      /* The offset into the buffer.  */
+  size_t len;          /* The current number of bytes in BUF+OFF.  */
+
+  log_assert (size > 48); /* Our code requires at least this size.  */
+
+  /* Copy the rest from the last call of this function into BUF.  */
+  len = dfx->holdbacklen;
+  dfx->holdbacklen = 0;
+  memcpy (buf, dfx->holdback, len);
+
+  if (DBG_FILTER)
+    log_debug ("aead_underflow: size=%zu len=%zu%s%s\n", size, len,
+               dfx->partial? " partial":"", dfx->eof_seen? " eof":"");
+
+  /* Read and fill up BUF.  We need to watch out for an EOF so that we
+   * can detect the last chunk which is commonly shorter than the
+   * chunksize.  After the last data byte from the last chunk 32 more
+   * bytes are expected for the last chunk's tag and the following
+   * final chunk's tag.  To detect the EOF we need to try reading at least
+   * one further byte; however we try to read 16 extra bytes to avoid
+   * single byte reads in some lower layers.  The outcome is that we
+   * have up to 48 extra extra octets which we will later put into the
+   * holdback buffer for the next invocation (which handles the EOF
+   * case).  */
+  len = fill_buffer (dfx, a, buf, size, len);
+  if (len < 32)
+    {
+      /* Not enough data for the last two tags.  */
+      err = gpg_error (GPG_ERR_TRUNCATED);
+      goto leave;
+    }
+  if (dfx->eof_seen)
+    {
+      /* If have seen an EOF we copy only the last two auth tags into
+       * the holdback buffer.  */
+      dfx->holdbacklen = 32;
+      memcpy (dfx->holdback, buf+len-32, 32);
+      len -= 32;
+    }
+  else
+    {
+      /* If have not seen an EOF we copy the entire extra 48 bytes
+       * into the holdback buffer for processing at the next call of
+       * this function.  */
+      dfx->holdbacklen = len > 48? 48 : len;
+      memcpy (dfx->holdback, buf+len-dfx->holdbacklen, dfx->holdbacklen);
+      len -= dfx->holdbacklen;
+    }
+  /* log_printhex (dfx->holdback, dfx->holdbacklen, "holdback:"); */
+
+  /* Decrypt the buffer.  This first requires a loop to handle the
+   * case when a chunk ends within the buffer.  */
+  if (DBG_FILTER)
+    log_debug ("decrypt: chunklen=%ju total=%ju size=%zu len=%zu%s\n",
+               dfx->chunklen, dfx->total, size, len,
+               dfx->eof_seen? " eof":"");
+
+  while (len && dfx->chunklen + len >= dfx->chunksize)
+    {
+      size_t n = dfx->chunksize - dfx->chunklen;
+      byte tagbuf[16];
+
+      if (DBG_FILTER)
+        log_debug ("chunksize will be reached: n=%zu\n", n);
+
+      if (!dfx->chunklen)
+        {
+          /* First data for this chunk - prepare.  */
+          err = aead_set_nonce_and_ad (dfx, 0);
+          if (err)
+            goto leave;
+        }
+
+      /* log_printhex (buf, n, "ciph:"); */
+      gcry_cipher_final (dfx->cipher_hd);
+      err = gcry_cipher_decrypt (dfx->cipher_hd, buf+off, n, NULL, 0);
+      if (err)
+        {
+          log_error ("gcry_cipher_decrypt failed (1): %s\n",
+                     gpg_strerror (err));
+          goto leave;
+        }
+      /* log_printhex (buf, n, "plai:"); */
+      totallen += n;
+      dfx->chunklen += n;
+      dfx->total += n;
+      off += n;
+      len -= n;
+
+      if (DBG_FILTER)
+        log_debug ("ndecrypted: %zu (nchunk=%ju) bytes left: %zu at off=%zu\n",
+                   totallen, dfx->chunklen, len, off);
+
+      /* Check the tag.  */
+      if (len < 16)
+        {
+          /* The tag is not entirely in the buffer.  Read the rest of
+           * the tag from the holdback buffer.  Then shift the holdback
+           * buffer and fill it up again.  */
+          memcpy (tagbuf, buf+off, len);
+          memcpy (tagbuf + len, dfx->holdback, 16 - len);
+          dfx->holdbacklen -= 16-len;
+          memmove (dfx->holdback, dfx->holdback + (16-len), dfx->holdbacklen);
+
+          if (dfx->eof_seen)
+            {
+              /* We should have the last chunk's tag in TAGBUF and the
+               * final tag in HOLDBACKBUF.  */
+              if (len || dfx->holdbacklen != 16)
+                {
+                  /* Not enough data for the last two tags.  */
+                  err = gpg_error (GPG_ERR_TRUNCATED);
+                  goto leave;
+                }
+            }
+          else
+            {
+              len = 0;
+              dfx->holdbacklen = fill_buffer (dfx, a, dfx->holdback, 48,
+                                              dfx->holdbacklen);
+              if (dfx->holdbacklen < 32)
+                {
+                  /* Not enough data for the last two tags.  */
+                  err = gpg_error (GPG_ERR_TRUNCATED);
+                  goto leave;
+                }
+            }
+        }
+      else /* We already have the full tag.  */
+        {
+          memcpy (tagbuf, buf+off, 16);
+          /* Remove that tag from the output.  */
+          memmove (buf + off, buf + off + 16, len - 16);
+          len -= 16;
+        }
+      err = aead_checktag (dfx, 0, tagbuf);
+      if (err)
+        goto leave;
+      dfx->chunklen = 0;
+      dfx->chunkindex++;
+
+      continue;
+    }
+
+  /* The bulk decryption of our buffer.  */
+  if (len)
+    {
+      if (!dfx->chunklen)
+        {
+          /* First data for this chunk - prepare.  */
+          err = aead_set_nonce_and_ad (dfx, 0);
+          if (err)
+            goto leave;
+        }
+
+      if (dfx->eof_seen)
+        {
+          /* This is the last block of the last chunk.  Its length may
+           * not be a multiple of the block length.  */
+          gcry_cipher_final (dfx->cipher_hd);
+        }
+      err = gcry_cipher_decrypt (dfx->cipher_hd, buf + off, len, NULL, 0);
+      if (err)
+        {
+          log_error ("gcry_cipher_decrypt failed (2): %s\n",
+                     gpg_strerror (err));
+          goto leave;
+        }
+      totallen += len;
+      dfx->chunklen += len;
+      dfx->total += len;
+      if (DBG_FILTER)
+        log_debug ("ndecrypted: %zu (nchunk=%ju)\n", totallen, dfx->chunklen);
+    }
+
+  if (dfx->eof_seen)
+    {
+
+      if (dfx->chunklen)
+        {
+          if (DBG_FILTER)
+            log_debug ("eof seen: holdback has the last and final tag\n");
+          log_assert (dfx->holdbacklen >= 32);
+          err = aead_checktag (dfx, 0, dfx->holdback);
+          if (err)
+            goto leave;
+          dfx->chunklen = 0;
+          dfx->chunkindex++;
+          off = 16;
+        }
+      else
+        {
+          if (DBG_FILTER)
+            log_debug ("eof seen: holdback has the final tag\n");
+          log_assert (dfx->holdbacklen >= 16);
+          off = 0;
+        }
+
+      /* Check the final chunk.  */
+      err = aead_set_nonce_and_ad (dfx, 1);
+      if (err)
+        goto leave;
+      gcry_cipher_final (dfx->cipher_hd);
+      /* Decrypt an empty string (using HOLDBACK as a dummy).  */
+      err = gcry_cipher_decrypt (dfx->cipher_hd, dfx->holdback, 0, NULL, 0);
+      if (err)
+        {
+          log_error ("gcry_cipher_decrypt failed (final): %s\n",
+                     gpg_strerror (err));
+          goto leave;
+        }
+      err = aead_checktag (dfx, 1, dfx->holdback+off);
+      if (err)
+        goto leave;
+      err = gpg_error (GPG_ERR_EOF);
+    }
+
+ leave:
+  if (DBG_FILTER)
+    log_debug ("aead_underflow: returning %zu (%s)\n",
+               totallen, gpg_strerror (err));
+
+  /* In case of an auth error we map the error code to the same as
+   * used by the MDC decryption.  */
+  if (gpg_err_code (err) == GPG_ERR_CHECKSUM)
+    err = gpg_error (GPG_ERR_BAD_SIGNATURE);
+
+  /* In case of an error we better wipe out the buffer than to convey
+   * partly decrypted data.  */
+  if (err && gpg_err_code (err) != GPG_ERR_EOF)
+    memset (buf, 0, size);
+
+  *ret_len = totallen;
+
+  return err;
+}
+
+
+/* The IOBUF filter used to decrypt AEAD encrypted data.  */
+static int
+aead_decode_filter (void *opaque, int control, IOBUF a,
+                    byte *buf, size_t *ret_len)
+{
+  decode_filter_ctx_t dfx = opaque;
+  int rc = 0;
+
+  if ( control == IOBUFCTRL_UNDERFLOW && dfx->eof_seen )
+    {
+      *ret_len = 0;
+      rc = -1;
+    }
+  else if ( control == IOBUFCTRL_UNDERFLOW )
+    {
+      log_assert (a);
+
+      rc = aead_underflow (dfx, a, buf, ret_len);
+      if (gpg_err_code (rc) == GPG_ERR_EOF)
+        rc = -1; /* We need to use the old convention in the filter.  */
+
+    }
+  else if ( control == IOBUFCTRL_FREE )
+    {
+      release_dfx_context (dfx);
+    }
+  else if ( control == IOBUFCTRL_DESC )
+    {
+      mem2str (buf, "aead_decode_filter", *ret_len);
+    }
+
+  return rc;
+}
+
 
 static int
 mdc_decode_filter (void *opaque, int control, IOBUF a,
@@ -315,7 +885,6 @@ mdc_decode_filter (void *opaque, int control, IOBUF a,
   decode_filter_ctx_t dfx = opaque;
   size_t n, size = *ret_len;
   int rc = 0;
-  int c;
 
   /* Note: We need to distinguish between a partial and a fixed length
      packet.  The first is the usual case as created by GPG.  However
@@ -336,73 +905,29 @@ mdc_decode_filter (void *opaque, int control, IOBUF a,
       log_assert (size > 44); /* Our code requires at least this size.  */
 
       /* Get at least 22 bytes and put it ahead in the buffer.  */
-      if (dfx->partial)
-        {
-          for (n=22; n < 44; n++)
-            {
-              if ( (c = iobuf_get(a)) == -1 )
-                break;
-              buf[n] = c;
-            }
-        }
-      else
-        {
-          for (n=22; n < 44 && dfx->length; n++, dfx->length--)
-            {
-              c = iobuf_get (a);
-              if (c == -1)
-                break; /* Premature EOF.  */
-              buf[n] = c;
-            }
-        }
+      n = fill_buffer (dfx, a, buf, 44, 22);
       if (n == 44)
         {
           /* We have enough stuff - flush the deferred stuff.  */
-          if ( !dfx->defer_filled )  /* First time. */
+          if ( !dfx->holdbacklen )  /* First time. */
             {
               memcpy (buf, buf+22, 22);
               n = 22;
            }
           else
             {
-              memcpy (buf, dfx->defer, 22);
+              memcpy (buf, dfx->holdback, 22);
            }
           /* Fill up the buffer. */
-          if (dfx->partial)
-            {
-              for (; n < size; n++ )
-                {
-                  if ( (c = iobuf_get(a)) == -1 )
-                    {
-                      dfx->eof_seen = 1; /* Normal EOF. */
-                      break;
-                    }
-                  buf[n] = c;
-                }
-            }
-          else
-            {
-              for (; n < size && dfx->length; n++, dfx->length--)
-                {
-                  c = iobuf_get(a);
-                  if (c == -1)
-                    {
-                      dfx->eof_seen = 3; /* Premature EOF. */
-                      break;
-                    }
-                  buf[n] = c;
-                }
-              if (!dfx->length)
-                dfx->eof_seen = 1; /* Normal EOF.  */
-            }
+          n = fill_buffer (dfx, a, buf, size, n);
 
-          /* Move the trailing 22 bytes back to the defer buffer.  We
+          /* Move the trailing 22 bytes back to the holdback buffer.  We
              have at least 44 bytes thus a memmove is not needed.  */
           n -= 22;
-          memcpy (dfx->defer, buf+n, 22 );
-          dfx->defer_filled = 1;
+          memcpy (dfx->holdback, buf+n, 22 );
+          dfx->holdbacklen = 22;
        }
-      else if ( !dfx->defer_filled )  /* EOF seen but empty defer buffer. */
+      else if ( !dfx->holdbacklen )  /* EOF seen but empty holdback buffer. */
         {
           /* This is bad because it means an incomplete hash. */
           n -= 22;
@@ -411,9 +936,9 @@ mdc_decode_filter (void *opaque, int control, IOBUF a,
        }
       else  /* EOF seen (i.e. read less than 22 bytes). */
         {
-          memcpy (buf, dfx->defer, 22 );
+          memcpy (buf, dfx->holdback, 22 );
           n -= 22;
-          memcpy (dfx->defer, buf+n, 22 );
+          memcpy (dfx->holdback, buf+n, 22 );
           dfx->eof_seen = 1; /* Normal EOF. */
        }
 
@@ -449,7 +974,7 @@ decode_filter( void *opaque, int control, IOBUF a, byte *buf, size_t *ret_len)
   decode_filter_ctx_t fc = opaque;
   size_t size = *ret_len;
   size_t n;
-  int c, rc = 0;
+  int rc = 0;
 
 
   if ( control == IOBUFCTRL_UNDERFLOW && fc->eof_seen )
@@ -461,34 +986,7 @@ decode_filter( void *opaque, int control, IOBUF a, byte *buf, size_t *ret_len)
     {
       log_assert (a);
 
-      if (fc->partial)
-        {
-          for (n=0; n < size; n++ )
-            {
-              c = iobuf_get(a);
-              if (c == -1)
-                {
-                  fc->eof_seen = 1; /* Normal EOF. */
-                  break;
-                }
-              buf[n] = c;
-            }
-        }
-      else
-        {
-          for (n=0; n < size && fc->length; n++, fc->length--)
-            {
-              c = iobuf_get(a);
-              if (c == -1)
-                {
-                  fc->eof_seen = 3; /* Premature EOF. */
-                  break;
-                }
-              buf[n] = c;
-            }
-          if (!fc->length)
-            fc->eof_seen = 1; /* Normal EOF.  */
-        }
+      n = fill_buffer (fc, a, buf, size, 0);
       if (n)
         {
           if (fc->cipher_hd)
index 666810c..3654491 100644 (file)
--- a/g10/dek.h
+++ b/g10/dek.h
 #ifndef G10_DEK_H
 #define G10_DEK_H
 
-
 typedef struct
 {
   /* The algorithm (e.g., CIPHER_ALGO_AES).  */
   int algo;
   /* The length of the key (in bytes).  */
   int keylen;
+
   /* Whether we've already printed information about this key.  This
-     is currently only used in decrypt_data() and only if we are in
-     verbose mode.  */
-  int algo_info_printed;
-  int use_mdc;
+   * is currently only used in decrypt_data() and only if we are in
+   * verbose mode.  */
+  unsigned int algo_info_printed : 1;
+
+  /* AEAD shall be used.  The value is the AEAD algo. */
+  int use_aead : 4;
+
+  /* MDC shall be used.  */
+  unsigned int use_mdc : 1;
+
   /* This key was read from a SK-ESK packet (see proc_symkey_enc).  */
-  int symmetric;
-  byte key[32]; /* This is the largest used keylen (256 bit). */
+  unsigned int symmetric : 1;
+
+  /* This is the largest used keylen (256 bit). */
+  byte key[32];
+
+  /* The cacheid for the S2K. */
   char s2k_cacheid[1+16+1];
 } DEK;
 
index dcb3cde..5bbea96 100644 (file)
@@ -76,7 +76,7 @@ pk_ecdh_default_params (unsigned int qbits)
     }
   log_assert (i < DIM (kek_params_table));
   if (DBG_CRYPTO)
-    log_printhex ("ECDH KEK params are", kek_params, sizeof(kek_params) );
+    log_printhex (kek_params, sizeof(kek_params), "ECDH KEK params are");
 
   return gcry_mpi_set_opaque (NULL, kek_params, 4 * 8);
 }
@@ -159,7 +159,7 @@ pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi,
       memset (secret_x+secret_x_size, 0, nbytes-secret_x_size);
 
     if (DBG_CRYPTO)
-      log_printhex ("ECDH shared secret X is:", secret_x, secret_x_size );
+      log_printhex (secret_x, secret_x_size, "ECDH shared secret X is:");
   }
 
   /*** We have now the shared secret bytes in secret_x. ***/
@@ -179,7 +179,7 @@ pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi,
   kek_params_size = (nbits+7)/8;
 
   if (DBG_CRYPTO)
-    log_printhex ("ecdh KDF params:", kek_params, kek_params_size);
+    log_printhex (kek_params, kek_params_size, "ecdh KDF params:");
 
   /* Expect 4 bytes  03 01 hash_alg symm_alg.  */
   if (kek_params_size != 4 || kek_params[0] != 3 || kek_params[1] != 1)
@@ -236,7 +236,7 @@ pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi,
       }
 
     if(DBG_CRYPTO)
-      log_printhex ("ecdh KDF message params are:", message, message_size);
+      log_printhex (message, message_size, "ecdh KDF message params are:");
   }
 
   /* Derive a KEK (key wrapping key) using MESSAGE and SECRET_X. */
@@ -272,7 +272,7 @@ pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi,
     /* We could have allocated more, so clean the tail before returning.  */
     memset (secret_x+secret_x_size, 0, old_size - secret_x_size);
     if (DBG_CRYPTO)
-      log_printhex ("ecdh KEK is:", secret_x, secret_x_size );
+      log_printhex (secret_x, secret_x_size, "ecdh KEK is:");
   }
 
   /* And, finally, aeswrap with key secret_x.  */
@@ -338,7 +338,7 @@ pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi,
           }
 
         if (DBG_CRYPTO)
-          log_printhex ("ecdh encrypting  :", in, data_buf_size );
+          log_printhex (in, data_buf_size, "ecdh encrypting  :");
 
         err = gcry_cipher_encrypt (hd, data_buf+1, data_buf_size+8,
                                    in, data_buf_size);
@@ -354,7 +354,7 @@ pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi,
         data_buf[0] = data_buf_size+8;
 
         if (DBG_CRYPTO)
-          log_printhex ("ecdh encrypted to:", data_buf+1, data_buf[0] );
+          log_printhex (data_buf+1, data_buf[0], "ecdh encrypted to:");
 
         result = gcry_mpi_set_opaque (NULL, data_buf, 8 * (1+data_buf[0]));
         if (!result)
@@ -391,7 +391,7 @@ pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi,
         data_buf_size = data_buf[0];
 
         if (DBG_CRYPTO)
-          log_printhex ("ecdh decrypting :", data_buf+1, data_buf_size);
+          log_printhex (data_buf+1, data_buf_size, "ecdh decrypting :");
 
         err = gcry_cipher_decrypt (hd, in, data_buf_size, data_buf+1,
                                    data_buf_size);
@@ -407,7 +407,7 @@ pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi,
         data_buf_size -= 8;
 
         if (DBG_CRYPTO)
-          log_printhex ("ecdh decrypted to :", in, data_buf_size);
+          log_printhex (in, data_buf_size, "ecdh decrypted to :");
 
         /* Padding is removed later.  */
         /* if (in[data_buf_size-1] > 8 ) */
index 543f1a7..42cad2b 100644 (file)
@@ -110,7 +110,7 @@ encrypt_seskey (DEK *dek, DEK **seskey, byte *enckey)
 
 
 /* Shall we use the MDC?  Yes - unless rfc-2440 compatibility is
- * requested. */
+ * requested.  Must return 1 or 0. */
 int
 use_mdc (pk_list_t pk_list,int algo)
 {
@@ -191,18 +191,9 @@ encrypt_simple (const char *filename, int mode, int use_seskey)
   cfx.dek = NULL;
   if ( mode )
     {
-      int canceled;
-
-      s2k = xmalloc_clear( sizeof *s2k );
-      s2k->mode = opt.s2k_mode;
-      s2k->hash_algo = S2K_DIGEST_ALGO;
-      cfx.dek = passphrase_to_dek (default_cipher_algo (), s2k, 1, 0,
-                                   NULL, &canceled);
-      if ( !cfx.dek || !cfx.dek->keylen )
+      rc = setup_symkey (&s2k, &cfx.dek);
+      if (rc)
         {
-          rc = gpg_error (canceled? GPG_ERR_CANCELED:GPG_ERR_INV_PASSPHRASE);
-          xfree (cfx.dek);
-          xfree (s2k);
           iobuf_close (inp);
           log_error (_("error creating passphrase: %s\n"), gpg_strerror (rc));
           release_progress_context (pfx);
@@ -378,22 +369,22 @@ encrypt_simple (const char *filename, int mode, int use_seskey)
 }
 
 
-int
-setup_symkey (STRING2KEY **symkey_s2k,DEK **symkey_dek)
+gpg_error_t
+setup_symkey (STRING2KEY **symkey_s2k, DEK **symkey_dek)
 {
   int canceled;
 
-  *symkey_s2k=xmalloc_clear(sizeof(STRING2KEY));
+  *symkey_s2k = xmalloc_clear (sizeof **symkey_s2k);
   (*symkey_s2k)->mode = opt.s2k_mode;
   (*symkey_s2k)->hash_algo = S2K_DIGEST_ALGO;
 
-  *symkey_dek = passphrase_to_dek (opt.s2k_cipher_algo,
+  *symkey_dek = passphrase_to_dek (default_cipher_algo (),
                                    *symkey_s2k, 1, 0, NULL, &canceled);
-  if(!*symkey_dek || !(*symkey_dek)->keylen)
+  if (!*symkey_dek || !(*symkey_dek)->keylen)
     {
       xfree(*symkey_dek);
       xfree(*symkey_s2k);
-      return gpg_error (canceled?GPG_ERR_CANCELED:GPG_ERR_BAD_PASSPHRASE);
+      return gpg_error (canceled?GPG_ERR_CANCELED:GPG_ERR_INV_PASSPHRASE);
     }
 
   return 0;
@@ -619,15 +610,15 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
         PKT_public_key *pk = pkr->pk;
         unsigned int nbits = nbits_from_pk (pk);
 
-        if (!gnupg_pk_is_compliant (opt.compliance,
-                                    pk->pubkey_algo, pk->pkey, nbits, NULL))
+        if (!gnupg_pk_is_compliant (opt.compliance, pk->pubkey_algo, 0,
+                                    pk->pkey, nbits, NULL))
           log_info (_("WARNING: key %s is not suitable for encryption"
                       " in %s mode\n"),
                     keystr_from_pk (pk),
                     gnupg_compliance_option_string (opt.compliance));
 
         if (compliant
-            && !gnupg_pk_is_compliant (CO_DE_VS, pk->pubkey_algo, pk->pkey,
+            && !gnupg_pk_is_compliant (CO_DE_VS, pk->pubkey_algo, 0, pk->pkey,
                                        nbits, NULL))
           compliant = 0;
       }
@@ -660,7 +651,7 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
 
   make_session_key (cfx.dek);
   if (DBG_CRYPTO)
-    log_printhex ("DEK is: ", cfx.dek->key, cfx.dek->keylen );
+    log_printhex (cfx.dek->key, cfx.dek->keylen, "DEK is: ");
 
   rc = write_pubkey_enc_from_list (ctrl, pk_list, cfx.dek, out);
   if (rc)
@@ -854,7 +845,7 @@ encrypt_filter (void *opaque, int control,
 
           make_session_key ( efx->cfx.dek );
           if (DBG_CRYPTO)
-            log_printhex ("DEK is: ", efx->cfx.dek->key, efx->cfx.dek->keylen);
+            log_printhex (efx->cfx.dek->key, efx->cfx.dek->keylen, "DEK is: ");
 
           rc = write_pubkey_enc_from_list (efx->ctrl,
                                            efx->pk_list, efx->cfx.dek, a);
index 3f4b565..5149277 100644 (file)
@@ -1028,11 +1028,11 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk)
   /* log_debug ("XXX pubkey_algo=%d\n", pubkey_algo); */
   /* log_debug ("XXX is_protected=%d\n", is_protected); */
   /* log_debug ("XXX protect_algo=%d\n", protect_algo); */
-  /* log_printhex ("XXX iv", iv, ivlen); */
+  /* log_printhex (iv, ivlen, "XXX iv"); */
   /* log_debug ("XXX ivlen=%d\n", ivlen); */
   /* log_debug ("XXX s2k_mode=%d\n", s2k_mode); */
   /* log_debug ("XXX s2k_algo=%d\n", s2k_algo); */
-  /* log_printhex ("XXX s2k_salt", s2k_salt, sizeof s2k_salt); */
+  /* log_printhex (s2k_salt, sizeof s2k_salt, "XXX s2k_salt"); */
   /* log_debug ("XXX s2k_count=%lu\n", (unsigned long)s2k_count); */
   /* for (idx=0; skey[idx]; idx++) */
   /*   { */
@@ -1043,7 +1043,7 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk)
   /*         void *p; */
   /*         unsigned int nbits; */
   /*         p = gcry_mpi_get_opaque (skey[idx], &nbits); */
-  /*         log_printhex (NULL, p, (nbits+7)/8); */
+  /*         log_printhex ( p, (nbits+7)/8, NULL); */
   /*       } */
   /*     else */
   /*       gcry_mpi_dump (skey[idx]); */
@@ -1110,7 +1110,7 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk)
       /*         void *p; */
       /*         unsigned int nbits; */
       /*         p = gcry_mpi_get_opaque (skey[idx], &nbits); */
-      /*         log_printhex (NULL, p, (nbits+7)/8); */
+      /*         log_printhex (p, (nbits+7)/8, NULL); */
       /*       } */
       /*     else */
       /*       gcry_mpi_dump (skey[idx]); */
index cafed3a..3d0dd0b 100644 (file)
@@ -2414,8 +2414,8 @@ fixup_uidnode (KBNODE uidnode, KBNODE signode, u32 keycreated)
 {
   PKT_user_id *uid = uidnode->pkt->pkt.user_id;
   PKT_signature *sig = signode->pkt->pkt.signature;
-  const byte *p, *sym, *hash, *zip;
-  size_t n, nsym, nhash, nzip;
+  const byte *p, *sym, *aead, *hash, *zip;
+  size_t n, nsym, naead, nhash, nzip;
 
   sig->flags.chosen_selfsig = 1;/* We chose this one. */
   uid->created = 0;            /* Not created == invalid. */
@@ -2470,6 +2470,9 @@ fixup_uidnode (KBNODE uidnode, KBNODE signode, u32 keycreated)
   p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_SYM, &n);
   sym = p;
   nsym = p ? n : 0;
+  p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_AEAD, &n);
+  aead = p;
+  naead = p ? n : 0;
   p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_HASH, &n);
   hash = p;
   nhash = p ? n : 0;
@@ -2490,6 +2493,11 @@ fixup_uidnode (KBNODE uidnode, KBNODE signode, u32 keycreated)
          uid->prefs[n].type = PREFTYPE_SYM;
          uid->prefs[n].value = *sym++;
        }
+      for (; naead; naead--, n++)
+       {
+         uid->prefs[n].type = PREFTYPE_AEAD;
+         uid->prefs[n].value = *aead++;
+       }
       for (; nhash; nhash--, n++)
        {
          uid->prefs[n].type = PREFTYPE_HASH;
@@ -2510,6 +2518,12 @@ fixup_uidnode (KBNODE uidnode, KBNODE signode, u32 keycreated)
   if (p && n && (p[0] & 0x01))
     uid->flags.mdc = 1;
 
+  /* See whether we have the AEAD feature.  */
+  uid->flags.aead = 0;
+  p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_FEATURES, &n);
+  if (p && n && (p[0] & 0x02))
+    uid->flags.aead = 1;
+
   /* And the keyserver modify flag.  */
   uid->flags.ks_modify = 1;
   p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KS_FLAGS, &n);
@@ -3332,6 +3346,7 @@ merge_selfsigs (ctrl_t ctrl, kbnode_t keyblock)
   PKT_public_key *main_pk;
   prefitem_t *prefs;
   unsigned int mdc_feature;
+  unsigned int aead_feature;
 
   if (keyblock->pkt->pkttype != PKT_PUBLIC_KEY)
     {
@@ -3393,7 +3408,7 @@ merge_selfsigs (ctrl_t ctrl, kbnode_t keyblock)
    * all preferences.
    * Do a similar thing for the MDC feature flag.  */
   prefs = NULL;
-  mdc_feature = 0;
+  mdc_feature = aead_feature = 0;
   for (k = keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY; k = k->next)
     {
       if (k->pkt->pkttype == PKT_USER_ID
@@ -3402,6 +3417,7 @@ merge_selfsigs (ctrl_t ctrl, kbnode_t keyblock)
        {
          prefs = k->pkt->pkt.user_id->prefs;
          mdc_feature = k->pkt->pkt.user_id->flags.mdc;
+         aead_feature = k->pkt->pkt.user_id->flags.aead;
          break;
        }
     }
@@ -3415,6 +3431,7 @@ merge_selfsigs (ctrl_t ctrl, kbnode_t keyblock)
            xfree (pk->prefs);
          pk->prefs = copy_prefs (prefs);
          pk->flags.mdc = mdc_feature;
+         pk->flags.aead = aead_feature;
        }
     }
 }
index 68cc220..1dc97a8 100644 (file)
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -893,6 +893,7 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_n (oNoAutostart, "no-autostart", "@"),
   ARGPARSE_s_n (oNoSymkeyCache, "no-symkey-cache", "@"),
   ARGPARSE_s_n (oIncludeKeyBlock, "include-key-block", "@"),
+  ARGPARSE_s_n (oNoIncludeKeyBlock, "no-include-key-block", "@"),
   ARGPARSE_s_n (oAutoKeyImport,   "auto-key-import", "@"),
   ARGPARSE_s_n (oNoAutoKeyImport, "no-auto-key-import", "@"),
 
@@ -4436,7 +4437,10 @@ main (int argc, char **argv)
       case aDeleteSecretKeys:
       case aDeleteSecretAndPublicKeys:
        sl = NULL;
-       /* I'm adding these in reverse order as add_to_strlist2
+        /* Print a note if the user did not specify any key.  */
+        if (!argc && !opt.quiet)
+          log_info (_("Note: %s\n"), gpg_strerror (GPG_ERR_NO_KEY));
+        /* I'm adding these in reverse order as add_to_strlist2
            reverses them again, and it's easier to understand in the
            proper order :) */
        for( ; argc; argc-- )
index 7ed997a..a7932ce 100644 (file)
@@ -3069,6 +3069,23 @@ show_prefs (PKT_user_id * uid, PKT_signature * selfsig, int verbose)
          tty_printf ("%s", openpgp_cipher_algo_name (CIPHER_ALGO_3DES));
        }
       tty_printf ("\n     ");
+      tty_printf (_("AEAD: "));
+      for (i = any = 0; prefs[i].type; i++)
+       {
+         if (prefs[i].type == PREFTYPE_AEAD)
+           {
+             if (any)
+               tty_printf (", ");
+             any = 1;
+             /* We don't want to display strings for experimental algos */
+             if (!openpgp_aead_test_algo (prefs[i].value)
+                 && prefs[i].value < 100)
+               tty_printf ("%s", openpgp_aead_algo_name (prefs[i].value));
+             else
+               tty_printf ("[%d]", prefs[i].value);
+           }
+       }
+      tty_printf ("\n     ");
       tty_printf (_("Digest: "));
       for (i = any = 0; prefs[i].type; i++)
        {
@@ -3123,7 +3140,7 @@ show_prefs (PKT_user_id * uid, PKT_signature * selfsig, int verbose)
            }
          tty_printf ("%s", compress_algo_to_string (COMPRESS_ALGO_NONE));
        }
-      if (uid->flags.mdc || !uid->flags.ks_modify)
+      if (uid->flags.mdc || uid->flags.aead || !uid->flags.ks_modify)
        {
          tty_printf ("\n     ");
          tty_printf (_("Features: "));
@@ -3133,6 +3150,12 @@ show_prefs (PKT_user_id * uid, PKT_signature * selfsig, int verbose)
              tty_printf ("MDC");
              any = 1;
            }
+         if (!uid->flags.aead)
+           {
+             if (any)
+               tty_printf (", ");
+             tty_printf ("AEAD");
+           }
          if (!uid->flags.ks_modify)
            {
              if (any)
@@ -3171,12 +3194,15 @@ show_prefs (PKT_user_id * uid, PKT_signature * selfsig, int verbose)
       for (i = 0; prefs[i].type; i++)
        {
          tty_printf (" %c%d", prefs[i].type == PREFTYPE_SYM ? 'S' :
+                     prefs[i].type == PREFTYPE_AEAD ? 'A' :
                      prefs[i].type == PREFTYPE_HASH ? 'H' :
                      prefs[i].type == PREFTYPE_ZIP ? 'Z' : '?',
                      prefs[i].value);
        }
       if (uid->flags.mdc)
        tty_printf (" [mdc]");
+      if (uid->flags.aead)
+       tty_printf (" [aead]");
       if (!uid->flags.ks_modify)
        tty_printf (" [no-ks-modify]");
       tty_printf ("\n");
index 5b868cd..69d85da 100644 (file)
@@ -953,7 +953,7 @@ keygrip_from_pk (PKT_public_key *pk, unsigned char *array)
   else
     {
       if (DBG_PACKET)
-        log_printhex ("keygrip=", array, 20);
+        log_printhex (array, 20, "keygrip=");
       /* FIXME: Save the keygrip in PK.  */
     }
   gcry_sexp_release (s_pkey);
index 8ff4085..5b0f7ba 100644 (file)
@@ -1340,7 +1340,7 @@ print_compliance_flags (PKT_public_key *pk,
       es_fputs (gnupg_status_compliance_flag (CO_GNUPG), es_stdout);
       any++;
     }
-  if (gnupg_pk_is_compliant (CO_DE_VS, pk->pubkey_algo, pk->pkey,
+  if (gnupg_pk_is_compliant (CO_DE_VS, pk->pubkey_algo, 0, pk->pkey,
                             keylength, curvename))
     {
       es_fprintf (es_stdout, any ? " %s" : "%s",
index 250467a..bb046ba 100644 (file)
@@ -122,6 +122,12 @@ int openpgp_cipher_blocklen (cipher_algo_t algo);
 int openpgp_cipher_test_algo(cipher_algo_t algo);
 const char *openpgp_cipher_algo_name (cipher_algo_t algo);
 
+gpg_error_t openpgp_aead_test_algo (aead_algo_t algo);
+const char *openpgp_aead_algo_name (aead_algo_t algo);
+gpg_error_t openpgp_aead_algo_info (aead_algo_t algo,
+                                    enum gcry_cipher_modes *r_mode,
+                                    unsigned int *r_noncelen);
+
 pubkey_algo_t map_pk_gcry_to_openpgp (enum gcry_pk_algos algo);
 int openpgp_pk_test_algo (pubkey_algo_t algo);
 int openpgp_pk_test_algo2 (pubkey_algo_t algo, unsigned int use);
@@ -223,7 +229,7 @@ int  cpr_get_answer_okay_cancel (const char *keyword,
 void display_online_help( const char *keyword );
 
 /*-- encode.c --*/
-int setup_symkey (STRING2KEY **symkey_s2k,DEK **symkey_dek);
+gpg_error_t setup_symkey (STRING2KEY **symkey_s2k,DEK **symkey_dek);
 void encrypt_seskey (DEK *dek, DEK **seskey, byte *enckey);
 int use_mdc (pk_list_t pk_list,int algo);
 int encrypt_symmetric (const char *filename );
index d278c2d..79ff211 100644 (file)
@@ -97,6 +97,7 @@ struct mainproc_context
   int trustletter;  /* Temporary usage in list_node. */
   ulong symkeys;    /* Number of symmetrically encrypted session keys.  */
   struct kidlist_item *pkenc_list; /* List of encryption packets. */
+  int seen_pkt_encrypted_aead; /* PKT_ENCRYPTED_AEAD packet seen. */
   struct {
     unsigned int sig_seen:1;      /* Set to true if a signature packet
                                      has been seen. */
@@ -145,6 +146,7 @@ release_list( CTX c )
   c->any.data = 0;
   c->any.uncompress_failed = 0;
   c->last_was_session_key = 0;
+  c->seen_pkt_encrypted_aead = 0;
   xfree (c->dek);
   c->dek = NULL;
 }
@@ -252,47 +254,111 @@ add_signature (CTX c, PACKET *pkt)
   return 1;
 }
 
-static int
+
+static gpg_error_t
 symkey_decrypt_seskey (DEK *dek, byte *seskey, size_t slen)
 {
+  gpg_error_t err;
   gcry_cipher_hd_t hd;
+  enum gcry_cipher_modes ciphermode;
+  unsigned int noncelen, keylen;
 
-  if(slen < 17 || slen > 33)
+  if (dek->use_aead)
+    {
+      err = openpgp_aead_algo_info (dek->use_aead, &ciphermode, &noncelen);
+      if (err)
+        return err;
+    }
+  else
+    {
+      ciphermode = GCRY_CIPHER_MODE_CFB;
+      noncelen = 0;
+    }
+
+  /* Check that the session key has a size of 16 to 32 bytes.  */
+  if ((dek->use_aead && (slen < (noncelen + 16 + 16)
+                         || slen > (noncelen + 32 + 16)))
+      || (!dek->use_aead && (slen < 17 || slen > 33)))
     {
       log_error ( _("weird size for an encrypted session key (%d)\n"),
                  (int)slen);
-      return GPG_ERR_BAD_KEY;
+      return gpg_error (GPG_ERR_BAD_KEY);
     }
 
-  if (openpgp_cipher_open (&hd, dek->algo, GCRY_CIPHER_MODE_CFB, 1))
-      BUG ();
-  if (gcry_cipher_setkey ( hd, dek->key, dek->keylen ))
-    BUG ();
-  gcry_cipher_setiv ( hd, NULL, 0 );
-  gcry_cipher_decrypt ( hd, seskey, slen, NULL, 0 );
-  gcry_cipher_close ( hd );
-
-  /* Here we can only test whether the algo given in decrypted
-   * session key is a valid OpenPGP algo.  With 11 defined
-   * symmetric algorithms we will miss 4.3% of wrong passphrases
-   * here.  The actual checking is done later during bulk
-   * decryption; we can't bring this check forward easily.  */
-  if (openpgp_cipher_test_algo (seskey[0]))
-    return gpg_error (GPG_ERR_BAD_KEY);
-
-  /* Now we replace the dek components with the real session key to
-     decrypt the contents of the sequencing packet. */
+  err = openpgp_cipher_open (&hd, dek->algo, ciphermode, 1);
+  if (!err)
+    err = gcry_cipher_setkey (hd, dek->key, dek->keylen);
+  if (!err)
+    err = gcry_cipher_setiv (hd, noncelen? seskey : NULL, noncelen);
+  if (err)
+    goto leave;
 
-  dek->keylen=slen-1;
-  dek->algo=seskey[0];
-
-  if(dek->keylen > DIM(dek->key))
-    BUG ();
+  if (dek->use_aead)
+    {
+      byte ad[4];
+
+      ad[0] = (0xc0 | PKT_SYMKEY_ENC);
+      ad[1] = 5;
+      ad[2] = dek->algo;
+      ad[3] = dek->use_aead;
+      err = gcry_cipher_authenticate (hd, ad, 4);
+      if (err)
+        goto leave;
+      gcry_cipher_final (hd);
+      keylen = slen - noncelen - 16;
+      err = gcry_cipher_decrypt (hd, seskey+noncelen, keylen, NULL, 0);
+      if (err)
+        goto leave;
+      err = gcry_cipher_checktag (hd, seskey+noncelen+keylen, 16);
+      if (err)
+        goto leave;
+      /* Now we replace the dek components with the real session key to
+       * decrypt the contents of the sequencing packet. */
+      if (keylen > DIM(dek->key))
+        {
+          err = gpg_error (GPG_ERR_TOO_LARGE);
+          goto leave;
+        }
+      dek->keylen = keylen;
+      memcpy (dek->key, seskey + noncelen, dek->keylen);
+    }
+  else
+    {
+      gcry_cipher_decrypt (hd, seskey, slen, NULL, 0);
+
+      /* Here we can only test whether the algo given in decrypted
+       * session key is a valid OpenPGP algo.  With 11 defined
+       * symmetric algorithms we will miss 4.3% of wrong passphrases
+       * here.  The actual checking is done later during bulk
+       * decryption; we can't bring this check forward easily.  We
+       * need to use the GPG_ERR_CHECKSUM so that we won't run into
+       * the gnupg < 2.2 bug compatible case which would terminate the
+       * process on GPG_ERR_CIPHER_ALGO.  Note that with AEAD (above)
+       * we will have a reliable test here.  */
+      if (openpgp_cipher_test_algo (seskey[0])
+          || openpgp_cipher_get_algo_keylen (seskey[0]) != slen - 1)
+        {
+          err = gpg_error (GPG_ERR_CHECKSUM);
+          goto leave;
+        }
 
-  memcpy(dek->key, seskey + 1, dek->keylen);
+      /* Now we replace the dek components with the real session key to
+       * decrypt the contents of the sequencing packet. */
+      keylen = slen-1;
+      if (keylen > DIM(dek->key))
+        {
+          err = gpg_error (GPG_ERR_TOO_LARGE);
+          goto leave;
+        }
+      dek->algo = seskey[0];
+      dek->keylen = slen-1;
+      memcpy (dek->key, seskey + 1, dek->keylen);
+    }
 
   /*log_hexdump( "thekey", dek->key, dek->keylen );*/
 
+ leave:
+  gcry_cipher_close (hd);
   return 0;
 }
 
@@ -300,6 +366,7 @@ symkey_decrypt_seskey (DEK *dek, byte *seskey, size_t slen)
 static void
 proc_symkey_enc (CTX c, PACKET *pkt)
 {
+  gpg_error_t err;
   PKT_symkey_enc *enc;
 
   enc = pkt->pkt.symkey_enc;
@@ -309,15 +376,20 @@ proc_symkey_enc (CTX c, PACKET *pkt)
     {
       int algo = enc->cipher_algo;
       const char *s = openpgp_cipher_algo_name (algo);
+      const char *a = (enc->aead_algo ? openpgp_aead_algo_name (enc->aead_algo)
+                       /**/           : "CFB");
 
       if (!openpgp_cipher_test_algo (algo))
         {
           if (!opt.quiet)
             {
+              /* Note: TMPSTR is only used to avoid i18n changes.  */
+              char *tmpstr = xstrconcat (s, ".", a, NULL);
               if (enc->seskeylen)
-                log_info (_("%s encrypted session key\n"), );
+                log_info (_("%s encrypted session key\n"), tmpstr);
               else
-                log_info (_("%s encrypted data\n"), s );
+                log_info (_("%s encrypted data\n"), tmpstr);
+              xfree (tmpstr);
             }
         }
       else
@@ -349,6 +421,7 @@ proc_symkey_enc (CTX c, PACKET *pkt)
           if (c->dek)
             {
               c->dek->symmetric = 1;
+              c->dek->use_aead = enc->aead_algo;
 
               /* FIXME: This doesn't work perfectly if a symmetric key
                  comes before a public key in the message - if the
@@ -359,9 +432,16 @@ proc_symkey_enc (CTX c, PACKET *pkt)
                  come later. */
               if (enc->seskeylen)
                 {
-                  if (symkey_decrypt_seskey (c->dek,
-                                             enc->seskey, enc->seskeylen))
+                  err = symkey_decrypt_seskey (c->dek,
+                                               enc->seskey, enc->seskeylen);
+                  if (err)
                     {
+                      log_info ("decryption of the symmetrically encrypted"
+                                 " session key failed: %s\n",
+                                 gpg_strerror (err));
+                      if (gpg_err_code (err) != GPG_ERR_BAD_KEY
+                          && gpg_err_code (err) != GPG_ERR_CHECKSUM)
+                        log_fatal ("process terminated to be bug compatible\n");
                       if (c->dek->s2k_cacheid[0])
                         {
                           if (opt.debug)
@@ -550,6 +630,9 @@ proc_encrypted (CTX c, PACKET *pkt)
   int result = 0;
   int early_plaintext = literals_seen;
 
+  if (pkt->pkttype == PKT_ENCRYPTED_AEAD)
+    c->seen_pkt_encrypted_aead = 1;
+
   if (early_plaintext)
     {
       log_info (_("WARNING: multiple plaintexts seen\n"));
@@ -656,8 +739,8 @@ proc_encrypted (CTX c, PACKET *pkt)
           memset (pk, 0, sizeof *pk);
           pk->pubkey_algo = i->pubkey_algo;
           if (get_pubkey (c->ctrl, pk, i->kid) != 0
-              || ! gnupg_pk_is_compliant (CO_DE_VS, pk->pubkey_algo, pk->pkey,
-                                          nbits_from_pk (pk), NULL))
+              || ! gnupg_pk_is_compliant (CO_DE_VS, pk->pubkey_algo, 0,
+                                          pk->pkey, nbits_from_pk (pk), NULL))
             compliant = 0;
           release_public_key_parts (pk);
         }
@@ -683,7 +766,8 @@ proc_encrypted (CTX c, PACKET *pkt)
     ;
   else if (!result
            && !opt.ignore_mdc_error
-           && !pkt->pkt.encrypted->mdc_method)
+           && !pkt->pkt.encrypted->mdc_method
+           && !pkt->pkt.encrypted->aead_algo)
     {
       /* The message has been decrypted but does not carry an MDC.
        * The option --ignore-mdc-error has also not been used.  To
@@ -712,17 +796,25 @@ proc_encrypted (CTX c, PACKET *pkt)
       write_status (STATUS_DECRYPTION_FAILED);
     }
   else if (!result || (gpg_err_code (result) == GPG_ERR_BAD_SIGNATURE
+                       && !pkt->pkt.encrypted->aead_algo
                        && opt.ignore_mdc_error))
     {
+      /* All is fine or for an MDC message the MDC failed but the
+       * --ignore-mdc-error option is active.  For compatibility
+       * reasons we issue GOODMDC also for AEAD messages.  */
       write_status (STATUS_DECRYPTION_OKAY);
       if (opt.verbose > 1)
         log_info(_("decryption okay\n"));
-      if (pkt->pkt.encrypted->mdc_method && !result)
+
+      if (pkt->pkt.encrypted->aead_algo)
+        write_status (STATUS_GOODMDC);
+      else if (pkt->pkt.encrypted->mdc_method && !result)
         write_status (STATUS_GOODMDC);
       else
         log_info (_("WARNING: message was not integrity protected\n"));
     }
-  else if (gpg_err_code (result) == GPG_ERR_BAD_SIGNATURE)
+  else if (gpg_err_code (result) == GPG_ERR_BAD_SIGNATURE
+           || gpg_err_code (result) == GPG_ERR_TRUNCATED)
     {
       glo_ctrl.lasterr = result;
       log_error (_("WARNING: encrypted message has been manipulated!\n"));
@@ -732,6 +824,7 @@ proc_encrypted (CTX c, PACKET *pkt)
   else
     {
       if ((gpg_err_code (result) == GPG_ERR_BAD_KEY
+          || gpg_err_code (result) == GPG_ERR_CHECKSUM
           || gpg_err_code (result) == GPG_ERR_CIPHER_ALGO)
           && *c->dek->s2k_cacheid != '\0')
         {
@@ -761,6 +854,21 @@ proc_encrypted (CTX c, PACKET *pkt)
 }
 
 
+static int
+have_seen_pkt_encrypted_aead( CTX c )
+{
+  CTX cc;
+
+  for (cc = c; cc; cc = cc->anchor)
+    {
+      if (cc->seen_pkt_encrypted_aead)
+       return 1;
+    }
+
+  return 0;
+}
+
+
 static void
 proc_plaintext( CTX c, PACKET *pkt )
 {
@@ -836,7 +944,7 @@ proc_plaintext( CTX c, PACKET *pkt )
         }
     }
 
-  if (!any && !opt.skip_verify)
+  if (!any && !opt.skip_verify && !have_seen_pkt_encrypted_aead(c))
     {
       /* This is for the old GPG LITERAL+SIG case.  It's not legal
          according to 2440, so hopefully it won't come up that often.
@@ -1467,7 +1575,8 @@ do_proc_packets (ctrl_t ctrl, CTX c, iobuf_t a)
             case PKT_PUBKEY_ENC:    proc_pubkey_enc (ctrl, c, pkt); break;
             case PKT_SYMKEY_ENC:    proc_symkey_enc (c, pkt); break;
             case PKT_ENCRYPTED:
-            case PKT_ENCRYPTED_MDC: proc_encrypted (c, pkt); break;
+            case PKT_ENCRYPTED_MDC:
+            case PKT_ENCRYPTED_AEAD:proc_encrypted (c, pkt); break;
             case PKT_COMPRESSED:    rc = proc_compressed (c, pkt); break;
             default: newpkt = 0; break;
            }
@@ -1483,6 +1592,7 @@ do_proc_packets (ctrl_t ctrl, CTX c, iobuf_t a)
             case PKT_PUBKEY_ENC:
             case PKT_ENCRYPTED:
             case PKT_ENCRYPTED_MDC:
+            case PKT_ENCRYPTED_AEAD:
               write_status_text( STATUS_UNEXPECTED, "0" );
               rc = GPG_ERR_UNEXPECTED;
               goto leave;
@@ -1510,7 +1620,8 @@ do_proc_packets (ctrl_t ctrl, CTX c, iobuf_t a)
             case PKT_SYMKEY_ENC:  proc_symkey_enc (c, pkt); break;
             case PKT_PUBKEY_ENC:  proc_pubkey_enc (ctrl, c, pkt); break;
             case PKT_ENCRYPTED:
-            case PKT_ENCRYPTED_MDC: proc_encrypted (c, pkt); break;
+            case PKT_ENCRYPTED_MDC:
+            case PKT_ENCRYPTED_AEAD: proc_encrypted (c, pkt); break;
             case PKT_PLAINTEXT:   proc_plaintext (c, pkt); break;
             case PKT_COMPRESSED:  rc = proc_compressed (c, pkt); break;
             case PKT_ONEPASS_SIG: newpkt = add_onepass_sig (c, pkt); break;
@@ -1537,7 +1648,8 @@ do_proc_packets (ctrl_t ctrl, CTX c, iobuf_t a)
             case PKT_PUBKEY_ENC:  proc_pubkey_enc (ctrl, c, pkt); break;
             case PKT_SYMKEY_ENC:  proc_symkey_enc (c, pkt); break;
             case PKT_ENCRYPTED:
-            case PKT_ENCRYPTED_MDC: proc_encrypted (c, pkt); break;
+            case PKT_ENCRYPTED_MDC:
+            case PKT_ENCRYPTED_AEAD: proc_encrypted (c, pkt); break;
             case PKT_PLAINTEXT:   proc_plaintext (c, pkt); break;
             case PKT_COMPRESSED:  rc = proc_compressed (c, pkt); break;
             case PKT_ONEPASS_SIG: newpkt = add_onepass_sig (c, pkt); break;
@@ -2317,7 +2429,7 @@ check_sig_and_print (CTX c, kbnode_t node)
 
       /* Print compliance warning for Good signatures.  */
       if (!rc && pk && !opt.quiet
-          && !gnupg_pk_is_compliant (opt.compliance, pk->pubkey_algo,
+          && !gnupg_pk_is_compliant (opt.compliance, pk->pubkey_algo, 0,
                                      pk->pkey, nbits_from_pk (pk), NULL))
         {
           log_info (_("WARNING: This key is not suitable for signing"
@@ -2401,7 +2513,7 @@ check_sig_and_print (CTX c, kbnode_t node)
 
       /* Compute compliance with CO_DE_VS.  */
       if (pk && is_status_enabled ()
-          && gnupg_pk_is_compliant (CO_DE_VS, pk->pubkey_algo, pk->pkey,
+          && gnupg_pk_is_compliant (CO_DE_VS, pk->pubkey_algo, 0, pk->pkey,
                                     nbits_from_pk (pk), NULL)
           && gnupg_digest_is_compliant (CO_DE_VS, sig->digest_algo))
         write_status_strings (STATUS_VERIFICATION_COMPLIANCE_MODE,
index 291d36f..22ed47e 100644 (file)
 #include "../common/i18n.h"
 #include "../common/zb32.h"
 
+/* FIXME: Libgcrypt 1.9 will support EAX.  Until we name this a
+ * requirement we hardwire the enum used for EAX.  */
+#define MY_GCRY_CIPHER_MODE_EAX 14
+
 
 #ifdef ENABLE_SELINUX_HACKS
 /* A object and a global variable to keep track of files marked as
@@ -602,6 +606,80 @@ openpgp_cipher_algo_name (cipher_algo_t algo)
 }
 
 
+/* Return 0 if ALGO is supported.  Return an error if not. */
+gpg_error_t
+openpgp_aead_test_algo (aead_algo_t algo)
+{
+  /* FIXME: We currently have no easy way to test whether libgcrypt
+   * implements a mode.  The only way we can do this is to open a
+   * cipher context with that mode and close it immediately.  That is
+   * a bit costly.  So we look at the libgcrypt version and assume
+   * nothing has been patched out.  */
+  switch (algo)
+    {
+    case AEAD_ALGO_NONE:
+      break;
+
+    case AEAD_ALGO_EAX:
+#if GCRYPT_VERSION_NUMBER < 0x010900
+      break;
+#else
+      return 0;
+#endif
+
+    case AEAD_ALGO_OCB:
+      return 0;
+    }
+
+  return gpg_error (GPG_ERR_INV_CIPHER_MODE);
+}
+
+
+/* Map the OpenPGP AEAD algorithm with ID ALGO to a string
+ * representation of the algorithm name.  For unknown algorithm IDs
+ * this function returns "?".  */
+const char *
+openpgp_aead_algo_name (aead_algo_t algo)
+{
+  switch (algo)
+    {
+    case AEAD_ALGO_NONE:  break;
+    case AEAD_ALGO_EAX:   return "EAX";
+    case AEAD_ALGO_OCB:   return "OCB";
+    }
+
+  return "?";
+}
+
+
+/* Return information for the AEAD algorithm ALGO.  The corresponding
+ * Libgcrypt ciphermode is stored at R_MODE and the required number of
+ * octets for the nonce at R_NONCELEN.  On error and error code is
+ * returned.  Note that the taglen is always 128 bits.  */
+gpg_error_t
+openpgp_aead_algo_info (aead_algo_t algo, enum gcry_cipher_modes *r_mode,
+                        unsigned int *r_noncelen)
+{
+  switch (algo)
+    {
+    case AEAD_ALGO_OCB:
+      *r_mode = GCRY_CIPHER_MODE_OCB;
+      *r_noncelen = 15;
+      break;
+
+    case AEAD_ALGO_EAX:
+      *r_mode = MY_GCRY_CIPHER_MODE_EAX;
+      *r_noncelen = 16;
+      break;
+
+    default:
+      log_error ("unsupported AEAD algo %d\n", algo);
+      return gpg_error (GPG_ERR_INV_CIPHER_MODE);
+    }
+  return 0;
+}
+
+
 /* Return 0 if ALGO is a supported OpenPGP public key algorithm.  */
 int
 openpgp_pk_test_algo (pubkey_algo_t algo)
index 4c0655c..187fffc 100644 (file)
@@ -77,7 +77,8 @@ typedef enum {
     PREFTYPE_NONE = 0,
     PREFTYPE_SYM = 1,
     PREFTYPE_HASH = 2,
-    PREFTYPE_ZIP = 3
+    PREFTYPE_ZIP = 3,
+    PREFTYPE_AEAD = 4
 } preftype_t;
 
 typedef struct {
@@ -104,6 +105,8 @@ typedef struct {
      be different from the algorithm that is used to encrypt the SED
      packet.)  */
   byte cipher_algo;
+  /* The AEAD algorithm or 0 for CFB encryption.  */
+  byte aead_algo;
   /* The string-to-key specifier.  */
   STRING2KEY s2k;
   /* The length of SESKEY in bytes or 0 if this packet does not
@@ -111,7 +114,8 @@ typedef struct {
      S2K function on the password is the session key. See RFC 4880,
      Section 5.3.)  */
   byte seskeylen;
-  /* The session key as encrypted by the S2K specifier.  */
+  /* The session key as encrypted by the S2K specifier.  For AEAD this
+   * includes the nonce and the authentication tag.  */
   byte seskey[1];
 } PKT_symkey_enc;
 
@@ -297,6 +301,7 @@ typedef struct
   struct
   {
     unsigned int mdc:1;
+    unsigned int aead:1;
     unsigned int ks_modify:1;
     unsigned int compacted:1;
     unsigned int primary:2; /* 2 if set via the primary flag, 1 if calculated */
@@ -393,6 +398,7 @@ typedef struct
   struct
   {
     unsigned int mdc:1;           /* MDC feature set.  */
+    unsigned int aead:1;          /* AEAD feature set.  */
     unsigned int disabled_valid:1;/* The next flag is valid.  */
     unsigned int disabled:1;      /* The key has been disabled.  */
     unsigned int primary:1;       /* This is a primary key.  */
@@ -463,12 +469,13 @@ typedef struct {
 typedef struct {
   /* Remaining length of encrypted data. */
   u32  len;
-  /* When encrypting, the first block size bytes of data are random
-     data and the following 2 bytes are copies of the last two bytes
-     of the random data (RFC 4880, Section 5.7).  This provides a
-     simple check that the key is correct.  extralen is the size of
-     this extra data.  This is used by build_packet when writing out
-     the packet's header. */
+  /* When encrypting in CFB mode, the first block size bytes of data
+   * are random data and the following 2 bytes are copies of the last
+   * two bytes of the random data (RFC 4880, Section 5.7).  This
+   * provides a simple check that the key is correct.  EXTRALEN is the
+   * size of this extra data or, in AEAD mode, the length of the
+   * headers and the tags.  This is used by build_packet when writing
+   * out the packet's header. */
   int  extralen;
   /* Whether the serialized version of the packet used / should use
      the new format.  */
@@ -480,6 +487,15 @@ typedef struct {
   /* If 0, MDC is disabled.  Otherwise, the MDC method that was used
      (currently, only DIGEST_ALGO_SHA1 is supported).  */
   byte mdc_method;
+  /* If 0, AEAD is not used.  Otherwise, the used AEAD algorithm.
+   * MDC_METHOD (above) shall be zero if AEAD is used.  */
+  byte aead_algo;
+  /* The cipher algo for/from the AEAD packet.  0 for other encryption
+   * packets. */
+  byte cipher_algo;
+  /* The chunk byte from the AEAD packet.  */
+  byte chunkbyte;
+
   /* An iobuf holding the data to be decrypted.  (This is not used for
      encryption!)  */
   iobuf_t buf;
index 6646bec..9cb254e 100644 (file)
@@ -81,6 +81,9 @@ static int parse_compressed (IOBUF inp, int pkttype, unsigned long pktlen,
                             PACKET * packet, int new_ctb);
 static int parse_encrypted (IOBUF inp, int pkttype, unsigned long pktlen,
                            PACKET * packet, int new_ctb, int partial);
+static gpg_error_t parse_encrypted_aead (IOBUF inp, int pkttype,
+                                         unsigned long pktlen, PACKET *packet,
+                                         int partial);
 static int parse_mdc (IOBUF inp, int pkttype, unsigned long pktlen,
                      PACKET * packet, int new_ctb);
 static int parse_gpg_control (IOBUF inp, int pkttype, unsigned long pktlen,
@@ -665,6 +668,7 @@ parse (parse_packet_ctx_t ctx, PACKET *pkt, int onlykeypkts, off_t * retpos,
             case PKT_PLAINTEXT:
             case PKT_ENCRYPTED:
             case PKT_ENCRYPTED_MDC:
+            case PKT_ENCRYPTED_AEAD:
             case PKT_COMPRESSED:
               iobuf_set_partial_body_length_mode (inp, c & 0xff);
               pktlen = 0;      /* To indicate partial length.  */
@@ -852,6 +856,9 @@ parse (parse_packet_ctx_t ctx, PACKET *pkt, int onlykeypkts, off_t * retpos,
     case PKT_MDC:
       rc = parse_mdc (inp, pkttype, pktlen, pkt, new_ctb);
       break;
+    case PKT_ENCRYPTED_AEAD:
+      rc = parse_encrypted_aead (inp, pkttype, pktlen, pkt, partial);
+      break;
     case PKT_GPG_CONTROL:
       rc = parse_gpg_control (inp, pkttype, pktlen, pkt, partial);
       break;
@@ -1127,19 +1134,17 @@ parse_symkeyenc (IOBUF inp, int pkttype, unsigned long pktlen,
 {
   PKT_symkey_enc *k;
   int rc = 0;
-  int i, version, s2kmode, cipher_algo, hash_algo, seskeylen, minlen;
+  int i, version, s2kmode, cipher_algo, aead_algo, hash_algo, seskeylen, minlen;
 
   if (pktlen < 4)
-    {
-      log_error ("packet(%d) too short\n", pkttype);
-      if (list_mode)
-        es_fprintf (listfp, ":symkey enc packet: [too short]\n");
-      rc = gpg_error (GPG_ERR_INV_PACKET);
-      goto leave;
-    }
+    goto too_short;
   version = iobuf_get_noeof (inp);
   pktlen--;
-  if (version != 4)
+  if (version == 4)
+    ;
+  else if (version == 5)
+    ;
+  else
     {
       log_error ("packet(%d) with unknown version %d\n", pkttype, version);
       if (list_mode)
@@ -1157,6 +1162,15 @@ parse_symkeyenc (IOBUF inp, int pkttype, unsigned long pktlen,
     }
   cipher_algo = iobuf_get_noeof (inp);
   pktlen--;
+  if (version == 5)
+    {
+      aead_algo = iobuf_get_noeof (inp);
+      pktlen--;
+    }
+  else
+    aead_algo = 0;
+  if (pktlen < 2)
+    goto too_short;
   s2kmode = iobuf_get_noeof (inp);
   pktlen--;
   hash_algo = iobuf_get_noeof (inp);
@@ -1191,6 +1205,7 @@ parse_symkeyenc (IOBUF inp, int pkttype, unsigned long pktlen,
                                              + seskeylen - 1);
   k->version = version;
   k->cipher_algo = cipher_algo;
+  k->aead_algo = aead_algo;
   k->s2k.mode = s2kmode;
   k->s2k.hash_algo = hash_algo;
   if (s2kmode == 1 || s2kmode == 3)
@@ -1221,10 +1236,20 @@ parse_symkeyenc (IOBUF inp, int pkttype, unsigned long pktlen,
   if (list_mode)
     {
       es_fprintf (listfp,
-                  ":symkey enc packet: version %d, cipher %d, s2k %d, hash %d",
-                  version, cipher_algo, s2kmode, hash_algo);
+                  ":symkey enc packet: version %d, cipher %d, aead %d,"
+                  "s2k %d, hash %d",
+                  version, cipher_algo, aead_algo, s2kmode, hash_algo);
       if (seskeylen)
-       es_fprintf (listfp, ", seskey %d bits", (seskeylen - 1) * 8);
+        {
+          /* To compute the size of the session key we need to know
+           * the size of the AEAD nonce which we may not know.  Thus
+           * we show only the size of the entire encrypted session
+           * key.  */
+          if (aead_algo)
+            es_fprintf (listfp, ", encrypted seskey %d bytes", seskeylen);
+          else
+            es_fprintf (listfp, ", seskey %d bits", (seskeylen - 1) * 8);
+        }
       es_fprintf (listfp, "\n");
       if (s2kmode == 1 || s2kmode == 3)
        {
@@ -1241,6 +1266,13 @@ parse_symkeyenc (IOBUF inp, int pkttype, unsigned long pktlen,
  leave:
   iobuf_skip_rest (inp, pktlen, 0);
   return rc;
+
+ too_short:
+  log_error ("packet(%d) too short\n", pkttype);
+  if (list_mode)
+    es_fprintf (listfp, ":symkey enc packet: [too short]\n");
+  rc = gpg_error (GPG_ERR_INV_PACKET);
+  goto leave;
 }
 
 
@@ -1421,6 +1453,11 @@ dump_sig_subpkt (int hashed, int type, int critical,
       for (i = 0; i < length; i++)
        es_fprintf (listfp, " %d", buffer[i]);
       break;
+    case SIGSUBPKT_PREF_AEAD:
+      es_fputs ("pref-aead-algos:", listfp);
+      for (i = 0; i < length; i++)
+        es_fprintf (listfp, " %d", buffer[i]);
+      break;
     case SIGSUBPKT_REV_KEY:
       es_fputs ("revocation key: ", listfp);
       if (length < 22)
@@ -1601,6 +1638,7 @@ parse_one_sig_subpkt (const byte * buffer, size_t n, int type)
     case SIGSUBPKT_KEY_FLAGS:
     case SIGSUBPKT_KS_FLAGS:
     case SIGSUBPKT_PREF_SYM:
+    case SIGSUBPKT_PREF_AEAD:
     case SIGSUBPKT_PREF_HASH:
     case SIGSUBPKT_PREF_COMPR:
     case SIGSUBPKT_POLICY:
@@ -3253,6 +3291,9 @@ parse_encrypted (IOBUF inp, int pkttype, unsigned long pktlen,
   ed->buf = NULL;
   ed->new_ctb = new_ctb;
   ed->is_partial = partial;
+  ed->aead_algo = 0;
+  ed->cipher_algo = 0; /* Only used with AEAD.  */
+  ed->chunkbyte = 0;   /* Only used with AEAD.  */
   if (pkttype == PKT_ENCRYPTED_MDC)
     {
       /* Fixme: add some pktlen sanity checks.  */
@@ -3344,6 +3385,81 @@ parse_mdc (IOBUF inp, int pkttype, unsigned long pktlen,
 }
 
 
+static gpg_error_t
+parse_encrypted_aead (iobuf_t inp, int pkttype, unsigned long pktlen,
+                      PACKET *pkt, int partial)
+{
+  int rc = 0;
+  PKT_encrypted *ed;
+  unsigned long orig_pktlen = pktlen;
+  int version;
+
+  ed = pkt->pkt.encrypted = xtrymalloc (sizeof *pkt->pkt.encrypted);
+  if (!ed)
+    return gpg_error_from_syserror ();
+  ed->len = 0;
+  ed->extralen = 0;  /* (only used in build_packet.)  */
+  ed->buf = NULL;
+  ed->new_ctb = 1;   /* (packet number requires a new CTB anyway.)  */
+  ed->is_partial = partial;
+  ed->mdc_method = 0;
+  /* A basic sanity check.  We need one version byte, one algo byte,
+   * one aead algo byte, one chunkbyte, at least 15 byte IV.  */
+  if (orig_pktlen && pktlen < 19)
+    {
+      log_error ("packet(%d) too short\n", pkttype);
+      if (list_mode)
+        es_fputs (":aead encrypted packet: [too short]\n", listfp);
+      rc = gpg_error (GPG_ERR_INV_PACKET);
+      iobuf_skip_rest (inp, pktlen, partial);
+      goto leave;
+    }
+
+  version = iobuf_get_noeof (inp);
+  if (orig_pktlen)
+    pktlen--;
+  if (version != 1)
+    {
+      log_error ("aead encrypted packet with unknown version %d\n",
+                 version);
+      if (list_mode)
+        es_fputs (":aead encrypted packet: [unknown version]\n", listfp);
+      /*skip_rest(inp, pktlen); should we really do this? */
+      rc = gpg_error (GPG_ERR_INV_PACKET);
+      goto leave;
+    }
+
+  ed->cipher_algo = iobuf_get_noeof (inp);
+  if (orig_pktlen)
+    pktlen--;
+  ed->aead_algo = iobuf_get_noeof (inp);
+  if (orig_pktlen)
+    pktlen--;
+  ed->chunkbyte = iobuf_get_noeof (inp);
+  if (orig_pktlen)
+    pktlen--;
+
+  /* Store the remaining length of the encrypted data.  We read the
+   * rest during decryption.  */
+  ed->len = pktlen;
+
+  if (list_mode)
+    {
+      es_fprintf (listfp, ":aead encrypted packet: cipher=%u aead=%u cb=%u\n",
+                  ed->cipher_algo, ed->aead_algo, ed->chunkbyte);
+      if (orig_pktlen)
+       es_fprintf (listfp, "\tlength: %lu\n", orig_pktlen);
+      else
+       es_fprintf (listfp, "\tlength: unknown\n");
+    }
+
+  ed->buf = inp;
+
+ leave:
+  return rc;
+}
+
+
 /*
  * This packet is internally generated by us (in armor.c) to transfer
  * some information to the lower layer.  To make sure that this packet
index 10574ec..df80af8 100644 (file)
@@ -212,6 +212,10 @@ read_passphrase_from_fd( int fd )
  * Ask the GPG Agent for the passphrase.
  * If NOCACHE is set the symmetric passpharse caching will not be used.
  *
+ * If REPEAT is positive, a new passphrase is requested and the agent
+ * shall require REPEAT times repetitions of the entered passphrase.
+ * This is used for symmetric encryption.
+ *
  * Note that TRYAGAIN_TEXT must not be translated.  If CANCELED is not
  * NULL, the function does set it to 1 if the user canceled the
  * operation.  If CACHEID is not NULL, it will be used as the cacheID
@@ -219,7 +223,7 @@ read_passphrase_from_fd( int fd )
  * computed, this will be used as the cacheid.
  */
 static char *
-passphrase_get (int nocache, const char *cacheid, int repeat,
+passphrase_get (int newsymkey, int nocache, const char *cacheid, int repeat,
                 const char *tryagain_text, int *canceled)
 {
   int rc;
@@ -240,9 +244,19 @@ passphrase_get (int nocache, const char *cacheid, int repeat,
   if (tryagain_text)
     tryagain_text = _(tryagain_text);
 
+  /* Here we have:
+   * REPEAT is set in create mode and if opt.passphrase_repeat is set.
+   * (Thus it is not a clean indication that we want a new passphrase).
+   * NOCACHE is set in create mode or if --no-symkey-cache is used.
+   * CACHEID is only set if caching shall be used.
+   * NEWSYMKEY has been added latter to make it clear that a new key
+   * is requested.  The whole chain of API is a bit too complex since
+   * we we stripped things out over time; however, there is no time
+   * for a full state analysis and thus this new parameter.
+   */
   rc = agent_get_passphrase (my_cacheid, tryagain_text, NULL,
                              _("Enter passphrase\n"),
-                             repeat, nocache, &pw);
+                             newsymkey, repeat, nocache, &pw);
 
   i18n_switchback (orig_codeset);
 
@@ -318,7 +332,7 @@ passphrase_to_dek (int cipher_algo, STRING2KEY *s2k,
   *canceled = 0;
 
   if (opt.no_symkey_cache)
-    nocache = 1;  /* Force no symmtric key caching.  */
+    nocache = 1;  /* Force no symmetric key caching.  */
 
   if ( !s2k )
     {
@@ -389,7 +403,7 @@ passphrase_to_dek (int cipher_algo, STRING2KEY *s2k,
         }
 
       /* Divert to the gpg-agent. */
-      pw = passphrase_get (create && nocache, s2k_cacheid,
+      pw = passphrase_get (create, create && nocache, s2k_cacheid,
                            create? opt.passphrase_repeat : 0,
                            tryagain_text, canceled);
       if (*canceled)
index 4e6f893..30a4bc0 100644 (file)
@@ -92,7 +92,7 @@ get_session_key (ctrl_t ctrl, PKT_pubkey_enc * k, DEK * dek)
         {
           /* Check compliance.  */
           if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_DECRYPTION,
-                                     sk->pubkey_algo,
+                                     sk->pubkey_algo, 0,
                                      sk->pkey, nbits_from_pk (sk), NULL))
             {
               log_info (_("key %s is not suitable for decryption"
@@ -133,7 +133,7 @@ get_session_key (ctrl_t ctrl, PKT_pubkey_enc * k, DEK * dek)
 
           /* Check compliance.  */
           if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_DECRYPTION,
-                                     sk->pubkey_algo,
+                                     sk->pubkey_algo, 0,
                                      sk->pkey, nbits_from_pk (sk), NULL))
             {
               log_info (_("key %s is not suitable for decryption"
@@ -259,7 +259,7 @@ get_it (ctrl_t ctrl,
    * CSUM
    */
   if (DBG_CRYPTO)
-    log_printhex ("DEK frame:", frame, nframe);
+    log_printhex (frame, nframe, "DEK frame:");
   n = 0;
 
   if (sk->pubkey_algo == PUBKEY_ALGO_ECDH)
@@ -288,10 +288,7 @@ get_it (ctrl_t ctrl,
         goto leave;
 
       /* Now the frame are the bytes decrypted but padded session key.  */
-
-      /* Allow double padding for the benefit of DEK size concealment.
-         Higher than this is wasteful. */
-      if (!nframe || frame[nframe-1] > 8*2 || nframe <= 8
+      if (!nframe || nframe <= 8
           || frame[nframe-1] > nframe)
         {
           err = gpg_error (GPG_ERR_WRONG_SECKEY);
@@ -375,7 +372,7 @@ get_it (ctrl_t ctrl,
   if (DBG_CLOCK)
     log_clock ("decryption ready");
   if (DBG_CRYPTO)
-    log_printhex ("DEK is:", dek->key, dek->keylen);
+    log_printhex (dek->key, dek->keylen, "DEK is:");
 
   /* Check that the algo is in the preferences and whether it has
    * expired.  Also print a status line with the key's fingerprint.  */
index 44e7871..e71e662 100644 (file)
@@ -164,7 +164,7 @@ check_signature2 (ctrl_t ctrl,
   else if (get_pubkey_for_sig (ctrl, pk, sig, forced_pk))
     rc = gpg_error (GPG_ERR_NO_PUBKEY);
   else if (!gnupg_pk_is_allowed (opt.compliance, PK_USE_VERIFICATION,
-                                 pk->pubkey_algo, pk->pkey,
+                                 pk->pubkey_algo, 0, pk->pkey,
                                  nbits_from_pk (pk),
                                  NULL))
     {
index 6e9f68e..a71ceda 100644 (file)
@@ -395,7 +395,8 @@ do_sign (ctrl_t ctrl, PKT_public_key *pksk, PKT_signature *sig,
       goto leave;
     }
 
-  if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_SIGNING, pksk->pubkey_algo,
+  if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_SIGNING,
+                             pksk->pubkey_algo, 0,
                              pksk->pkey, nbits_from_pk (pksk), NULL))
     {
       log_error (_("key %s may not be used for signing in %s mode\n"),
index 8a50c3f..b160ba3 100644 (file)
@@ -366,7 +366,7 @@ create_inq_cb (void *opaque, const char *line)
           void *ciphertext;
           size_t ciphertextlen;
 
-          log_printhex ("plain", plaintext, plaintextlen);
+          log_printhex (plaintext, plaintextlen, "plain");
           err = g13_encrypt_keyblob (parm->ctrl,
                                      plaintext, plaintextlen,
                                      &ciphertext, &ciphertextlen);
index b10ebbc..6693826 100644 (file)
@@ -318,7 +318,7 @@ dump_tupledesc (tupledesc_t tuples)
               if (n < 100 && all_printable (value, n))
                 log_printf ("%.*s\n", (int)n, (const char*)value);
               else
-                log_printhex ("", value, n);
+                log_printhex (value, n, "");
               break;
 
             case KEYBLOB_TAG_CONT_NSEC:
@@ -327,11 +327,11 @@ dump_tupledesc (tupledesc_t tuples)
               if (!convert_uint (value, n, &uint))
                 log_printf ("%llu\n", uint);
               else
-                log_printhex ("", value, n);
+                log_printhex (value, n, "");
               break;
 
             default:
-              log_printhex ("", value, n);
+              log_printhex (value, n, "");
               break;
             }
         }
index 15f7485..bd90a6c 100644 (file)
@@ -79,6 +79,7 @@ g10/verify.c
 
 kbx/kbxutil.c
 
+scd/app-p15.c
 scd/app-nks.c
 scd/app-openpgp.c
 scd/app-dinsig.c
index a52d77a..1927a17 100644 (file)
--- a/po/ca.po
+++ b/po/ca.po
@@ -115,6 +115,9 @@ msgstr ""
 #. the pinentry.  The %s is the actual error message, the
 #. two %d give the current and maximum number of tries.
 #. Do not translate the "SETERROR" keyword.
+#. TRANSLATORS: The string is appended to an error message in
+#. the pinentry.  The %s is the actual error message, the
+#. two %d give the current and maximum number of tries.
 #, c-format
 msgid "SETERROR %s (try %d of %d)"
 msgstr ""
@@ -3811,6 +3814,9 @@ msgstr "error: l'empremta digital és invàlida\n"
 msgid "subkey \"%s\" not found\n"
 msgstr "no s'ha trobat la clau «%s»: %s\n"
 
+msgid "AEAD: "
+msgstr ""
+
 msgid "Digest: "
 msgstr "Resum: "
 
@@ -6607,6 +6613,26 @@ msgid ""
 "List, export, import Keybox data\n"
 msgstr "Forma d'ús: gpg [opcions] [fitxers] (-h per a veure l'ajuda)"
 
+#. TRANSLATORS: Put a \x1f right before a colon.  This can be
+#. * used by pinentry to nicely align the names and values.  Keep
+#. * the %s at the start and end of the string.
+#, c-format
+msgid "%sNumber\1f: %s%%0AHolder\1f: %s%s"
+msgstr ""
+
+#. TRANSLATORS: This is the number of remaining attempts to
+#. * enter a PIN.  Use %%0A (double-percent,0A) for a linefeed.
+#, c-format
+msgid "Remaining attempts: %d"
+msgstr ""
+
+msgid "||Please enter the PIN for the key to create qualified signatures."
+msgstr ""
+
+#, fuzzy
+msgid "||Please enter the PIN for the standard keys."
+msgstr "canvia la contrasenya"
+
 #, c-format
 msgid "RSA modulus missing or not of size %d bits\n"
 msgstr ""
@@ -6628,10 +6654,6 @@ msgid "|N|Please enter a new PIN for the standard keys."
 msgstr "canvia la contrasenya"
 
 #, fuzzy
-msgid "||Please enter the PIN for the standard keys."
-msgstr "canvia la contrasenya"
-
-#, fuzzy
 msgid "|NP|Please enter a new PIN Unblocking Code (PUK) for the standard keys."
 msgstr "Seleccioneu la raó de la revocació:\n"
 
@@ -6642,9 +6664,6 @@ msgstr "Seleccioneu la raó de la revocació:\n"
 msgid "|N|Please enter a new PIN for the key to create qualified signatures."
 msgstr ""
 
-msgid "||Please enter the PIN for the key to create qualified signatures."
-msgstr ""
-
 msgid ""
 "|NP|Please enter a new PIN Unblocking Code (PUK) for the key to create "
 "qualified signatures."
@@ -6700,16 +6719,6 @@ msgid "%sNumber\1f: %s%%0AHolder\1f: %s%%0ACounter\1f: %lu%s"
 msgstr ""
 
 #, c-format
-msgid "%sNumber\1f: %s%%0AHolder\1f: %s%s"
-msgstr ""
-
-#. TRANSLATORS: This is the number of remaining attempts to
-#. * enter a PIN.  Use %%0A (double-percent,0A) for a linefeed.
-#, c-format
-msgid "Remaining attempts: %d"
-msgstr ""
-
-#, c-format
 msgid "using default PIN as %s\n"
 msgstr ""
 
@@ -6967,6 +6976,10 @@ msgstr "s'està escrivint la clau secreta a «%s»\n"
 msgid "certificate policy not allowed"
 msgstr "s'està escrivint la clau secreta a «%s»\n"
 
+#, fuzzy, c-format
+msgid "failed to get the fingerprint\n"
+msgstr "no s'ha pogut emmagatzemar l'empremta digital: %s\n"
+
 #, c-format
 msgid "looking up issuer at external location\n"
 msgstr ""
@@ -6975,6 +6988,11 @@ msgstr ""
 msgid "number of issuers matching: %d\n"
 msgstr ""
 
+#, fuzzy, c-format
+#| msgid "%s: can't access: %s\n"
+msgid "can't get authorityInfoAccess: %s\n"
+msgstr "%s: no s'ha pogut accedir: %s\n"
+
 #, c-format
 msgid "looking up issuer from the Dirmngr cache\n"
 msgstr ""
@@ -7603,10 +7621,6 @@ msgstr "error en la creació de la contrasenya: %s\n"
 msgid "error reading input: %s\n"
 msgstr "error en la lectura de «%s»: %s\n"
 
-#, fuzzy, c-format
-msgid "failed to get the fingerprint\n"
-msgstr "no s'ha pogut emmagatzemar l'empremta digital: %s\n"
-
 #, c-format
 msgid "problem looking for existing certificate: %s\n"
 msgstr ""
@@ -7686,8 +7700,8 @@ msgid "[date not given]"
 msgstr ""
 
 #, fuzzy, c-format
-msgid " using certificate ID 0x%08lX\n"
-msgstr "error en la creació de la contrasenya: %s\n"
+msgid "algorithm:"
+msgstr "armadura: %s\n"
 
 #, c-format
 msgid ""
@@ -8019,15 +8033,6 @@ msgid "error getting data from cache file: %s\n"
 msgstr "error en crear «%s»: %s\n"
 
 #, fuzzy, c-format
-#| msgid "invalid hash algorithm `%s'\n"
-msgid "unknown hash algorithm '%s'\n"
-msgstr "l'algoritme de dispersió és invàlid «%s»\n"
-
-#, c-format
-msgid "gcry_md_open for algorithm %d failed: %s\n"
-msgstr ""
-
-#, fuzzy, c-format
 #| msgid "invalid response from agent\n"
 msgid "got an invalid S-expression from libksba\n"
 msgstr "la resposta de l'agent és invàlida\n"
@@ -8038,6 +8043,15 @@ msgid "converting S-expression failed: %s\n"
 msgstr "no s'han pogut canviar els permissos de «%s»: %s\n"
 
 #, fuzzy, c-format
+#| msgid "invalid hash algorithm `%s'\n"
+msgid "unknown hash algorithm '%s'\n"
+msgstr "l'algoritme de dispersió és invàlid «%s»\n"
+
+#, c-format
+msgid "gcry_md_open for algorithm %d failed: %s\n"
+msgstr ""
+
+#, fuzzy, c-format
 #| msgid "changing permission of  `%s' failed: %s\n"
 msgid "creating S-expression failed: %s\n"
 msgstr "no s'han pogut canviar els permissos de «%s»: %s\n"
@@ -8834,11 +8848,6 @@ msgstr "Certificat correcte"
 msgid "failed to allocate OCSP context: %s\n"
 msgstr "no s'ha pogut inicialitzar la base de dades de confiança: %s\n"
 
-#, fuzzy, c-format
-#| msgid "%s: can't access: %s\n"
-msgid "can't get authorityInfoAccess: %s\n"
-msgstr "%s: no s'ha pogut accedir: %s\n"
-
 #, c-format
 msgid "no default OCSP responder defined\n"
 msgstr ""
@@ -9433,6 +9442,10 @@ msgid ""
 msgstr ""
 
 #, fuzzy
+#~ msgid " using certificate ID 0x%08lX\n"
+#~ msgstr "error en la creació de la contrasenya: %s\n"
+
+#, fuzzy
 #~| msgid "you may not use %s while in %s mode\n"
 #~ msgid ""
 #~ "keyserver option \"honor-keyserver-url\" may not be used in Tor mode\n"
index 3a2f82b..2dd0cd4 100644 (file)
--- a/po/cs.po
+++ b/po/cs.po
@@ -125,6 +125,9 @@ msgstr "neshodují se – zkuste to znovu"
 #. the pinentry.  The %s is the actual error message, the
 #. two %d give the current and maximum number of tries.
 #. Do not translate the "SETERROR" keyword.
+#. TRANSLATORS: The string is appended to an error message in
+#. the pinentry.  The %s is the actual error message, the
+#. two %d give the current and maximum number of tries.
 #, c-format
 msgid "SETERROR %s (try %d of %d)"
 msgstr "SETERROR %s (pokus %d z %d)"
@@ -3510,6 +3513,9 @@ msgstr "„%s“ není řádný otisk\n"
 msgid "subkey \"%s\" not found\n"
 msgstr "podklíč „%s“ nenalezen\n"
 
+msgid "AEAD: "
+msgstr ""
+
 msgid "Digest: "
 msgstr "Hash: "
 
@@ -6214,6 +6220,26 @@ msgstr ""
 "Syntaxe: kbxutil [volby] [soubory]\n"
 "Vypisuje, exportuje, importuje schránku na klíče (keybox).\n"
 
+#. TRANSLATORS: Put a \x1f right before a colon.  This can be
+#. * used by pinentry to nicely align the names and values.  Keep
+#. * the %s at the start and end of the string.
+#, c-format
+msgid "%sNumber\1f: %s%%0AHolder\1f: %s%s"
+msgstr "%sČíslo\1f: %s%%0ADržitel\1f: %s%s"
+
+#. TRANSLATORS: This is the number of remaining attempts to
+#. * enter a PIN.  Use %%0A (double-percent,0A) for a linefeed.
+#, c-format
+msgid "Remaining attempts: %d"
+msgstr "Zbývá pokusů: %d"
+
+msgid "||Please enter the PIN for the key to create qualified signatures."
+msgstr ""
+"||Prosím, zadejte PIN klíče určeného na tvorbu kvalifikovaných podpisů."
+
+msgid "||Please enter the PIN for the standard keys."
+msgstr "||Prosím, zadejte PIN pro standardní klíče."
+
 #, c-format
 msgid "RSA modulus missing or not of size %d bits\n"
 msgstr "schází RSA modulus nebo nemá velikost %d bitů\n"
@@ -6235,9 +6261,6 @@ msgstr "NullPIN ještě nebyl změněn\n"
 msgid "|N|Please enter a new PIN for the standard keys."
 msgstr "|N|Prosím, zadejte nový PIN pro standardní klíče."
 
-msgid "||Please enter the PIN for the standard keys."
-msgstr "||Prosím, zadejte PIN pro standardní klíče."
-
 msgid "|NP|Please enter a new PIN Unblocking Code (PUK) for the standard keys."
 msgstr "|NP|Prosím, zadejte nový kód pro odblokování (PUK) standardních klíčů."
 
@@ -6248,10 +6271,6 @@ msgid "|N|Please enter a new PIN for the key to create qualified signatures."
 msgstr ""
 "|N|Prosím, zadejte nový PIN klíče určeného na tvorbu kvalifikovaných podpisů."
 
-msgid "||Please enter the PIN for the key to create qualified signatures."
-msgstr ""
-"||Prosím, zadejte PIN klíče určeného na tvorbu kvalifikovaných podpisů."
-
 msgid ""
 "|NP|Please enter a new PIN Unblocking Code (PUK) for the key to create "
 "qualified signatures."
@@ -6310,16 +6329,6 @@ msgid "%sNumber\1f: %s%%0AHolder\1f: %s%%0ACounter\1f: %lu%s"
 msgstr "%sČíslo\1f: %s%%0ADržitel\1f: %s%%0APočítadlo\1f: %lu%s"
 
 #, c-format
-msgid "%sNumber\1f: %s%%0AHolder\1f: %s%s"
-msgstr "%sČíslo\1f: %s%%0ADržitel\1f: %s%s"
-
-#. TRANSLATORS: This is the number of remaining attempts to
-#. * enter a PIN.  Use %%0A (double-percent,0A) for a linefeed.
-#, c-format
-msgid "Remaining attempts: %d"
-msgstr "Zbývá pokusů: %d"
-
-#, c-format
 msgid "using default PIN as %s\n"
 msgstr "použije se výchozí PIN jako %s\n"
 
@@ -6570,6 +6579,10 @@ msgid "certificate policy not allowed"
 msgstr "certifikační politika není dovolena"
 
 #, c-format
+msgid "failed to get the fingerprint\n"
+msgstr "otisk se nepodařilo získat\n"
+
+#, c-format
 msgid "looking up issuer at external location\n"
 msgstr "hledám vydavatele na jiném místě\n"
 
@@ -6578,6 +6591,10 @@ msgid "number of issuers matching: %d\n"
 msgstr "počet odpovídajících vydavatelů: %d\n"
 
 #, c-format
+msgid "can't get authorityInfoAccess: %s\n"
+msgstr "authorityInfoAccess nelze získat: %s\n"
+
+#, c-format
 msgid "looking up issuer from the Dirmngr cache\n"
 msgstr "hledám vydavatele ve vyrovnávací paměti Dirmngr\n"
 
@@ -7162,10 +7179,6 @@ msgid "error reading input: %s\n"
 msgstr "chyba při čtení vstupu: %s\n"
 
 #, c-format
-msgid "failed to get the fingerprint\n"
-msgstr "otisk se nepodařilo získat\n"
-
-#, c-format
 msgid "problem looking for existing certificate: %s\n"
 msgstr "problém při hledání existujícího certifikátu: %s\n"
 
@@ -7255,9 +7268,10 @@ msgstr "Podpis vytvořen "
 msgid "[date not given]"
 msgstr "[datum neudáno]"
 
-#, c-format
-msgid " using certificate ID 0x%08lX\n"
-msgstr " pomocí certifikátu s ID 0x%08lX\n"
+#, fuzzy, c-format
+#| msgid "algorithm: %s"
+msgid "algorithm:"
+msgstr "algoritmus: %s"
 
 #, c-format
 msgid ""
@@ -7594,14 +7608,6 @@ msgid "error getting data from cache file: %s\n"
 msgstr "chyba při získávání dat ze souboru keše: %s\n"
 
 #, c-format
-msgid "unknown hash algorithm '%s'\n"
-msgstr "neznámý hašovací algoritmus „%s“\n"
-
-#, c-format
-msgid "gcry_md_open for algorithm %d failed: %s\n"
-msgstr "gcry_md_open selhalo na algoritmu %d: %s\n"
-
-#, c-format
 msgid "got an invalid S-expression from libksba\n"
 msgstr "z libksba obdržen neplatný S-výraz\n"
 
@@ -7610,6 +7616,14 @@ msgid "converting S-expression failed: %s\n"
 msgstr "převod S-výrazu se nezdařil: %s\n"
 
 #, c-format
+msgid "unknown hash algorithm '%s'\n"
+msgstr "neznámý hašovací algoritmus „%s“\n"
+
+#, c-format
+msgid "gcry_md_open for algorithm %d failed: %s\n"
+msgstr "gcry_md_open selhalo na algoritmu %d: %s\n"
+
+#, c-format
 msgid "creating S-expression failed: %s\n"
 msgstr "výroba S-výrazu selhala: %s\n"
 
@@ -8363,10 +8377,6 @@ msgid "failed to allocate OCSP context: %s\n"
 msgstr "alokace OCSP kontextu selhala: %s\n"
 
 #, c-format
-msgid "can't get authorityInfoAccess: %s\n"
-msgstr "authorityInfoAccess nelze získat: %s\n"
-
-#, c-format
 msgid "no default OCSP responder defined\n"
 msgstr "žádný výchozí OCSP odpovídač nedefinován\n"
 
@@ -8939,6 +8949,9 @@ msgstr ""
 "Syntaxe: gpg-check-pattern [volby] soubor_se_vzorem\n"
 "Prověří heslo zadané na vstupu proti souboru se vzory\n"
 
+#~ msgid " using certificate ID 0x%08lX\n"
+#~ msgstr " pomocí certifikátu s ID 0x%08lX\n"
+
 #, fuzzy
 #~| msgid "option '%s' may not be used in %s mode\n"
 #~ msgid ""
index ec9c191..4c1dd54 100644 (file)
--- a/po/da.po
+++ b/po/da.po
@@ -116,6 +116,9 @@ msgstr "matcher ikke - prøv igen"
 #. the pinentry.  The %s is the actual error message, the
 #. two %d give the current and maximum number of tries.
 #. Do not translate the "SETERROR" keyword.
+#. TRANSLATORS: The string is appended to an error message in
+#. the pinentry.  The %s is the actual error message, the
+#. two %d give the current and maximum number of tries.
 #, c-format
 msgid "SETERROR %s (try %d of %d)"
 msgstr "SETERROR %s (forsøg %d af %d)"
@@ -3767,6 +3770,9 @@ msgstr "ugyldig fingeraftryk"
 msgid "subkey \"%s\" not found\n"
 msgstr "nøglen »%s« blev ikke fundet: %s\n"
 
+msgid "AEAD: "
+msgstr ""
+
 msgid "Digest: "
 msgstr "Sammendrag: "
 
@@ -6555,6 +6561,27 @@ msgstr ""
 "Syntaks: kbxutil [tilvalg] [filer]\n"
 "Vis, eksporter, importer Keybox-data\n"
 
+#. TRANSLATORS: Put a \x1f right before a colon.  This can be
+#. * used by pinentry to nicely align the names and values.  Keep
+#. * the %s at the start and end of the string.
+#, c-format
+msgid "%sNumber\1f: %s%%0AHolder\1f: %s%s"
+msgstr ""
+
+#. TRANSLATORS: This is the number of remaining attempts to
+#. * enter a PIN.  Use %%0A (double-percent,0A) for a linefeed.
+#, c-format
+msgid "Remaining attempts: %d"
+msgstr ""
+
+msgid "||Please enter the PIN for the key to create qualified signatures."
+msgstr ""
+"||Indtast venligst PIN'en for nøglen til at oprette kvalificerede "
+"underskrifter."
+
+msgid "||Please enter the PIN for the standard keys."
+msgstr "||Indtast venligst PIn'en for standardnøglerne."
+
 #, c-format
 msgid "RSA modulus missing or not of size %d bits\n"
 msgstr "RSA-modulus mangler eller har ikke størrelsen %d bit\n"
@@ -6574,9 +6601,6 @@ msgstr "NullPIN'en er endnu ikke ændret\n"
 msgid "|N|Please enter a new PIN for the standard keys."
 msgstr "|N|Indtast venligst en ny PIN for standardnøglerne."
 
-msgid "||Please enter the PIN for the standard keys."
-msgstr "||Indtast venligst PIn'en for standardnøglerne."
-
 msgid "|NP|Please enter a new PIN Unblocking Code (PUK) for the standard keys."
 msgstr ""
 "|NP|Indtast venligst en ny PIN Unblocking Code (PUK) for standardnøglerne."
@@ -6589,11 +6613,6 @@ msgstr ""
 "|N|Indtast venligst en ny PIN for nøglen til at oprette kvalificerede "
 "underskrifter."
 
-msgid "||Please enter the PIN for the key to create qualified signatures."
-msgstr ""
-"||Indtast venligst PIN'en for nøglen til at oprette kvalificerede "
-"underskrifter."
-
 msgid ""
 "|NP|Please enter a new PIN Unblocking Code (PUK) for the key to create "
 "qualified signatures."
@@ -6653,16 +6672,6 @@ msgid "%sNumber\1f: %s%%0AHolder\1f: %s%%0ACounter\1f: %lu%s"
 msgstr ""
 
 #, c-format
-msgid "%sNumber\1f: %s%%0AHolder\1f: %s%s"
-msgstr ""
-
-#. TRANSLATORS: This is the number of remaining attempts to
-#. * enter a PIN.  Use %%0A (double-percent,0A) for a linefeed.
-#, c-format
-msgid "Remaining attempts: %d"
-msgstr ""
-
-#, c-format
 msgid "using default PIN as %s\n"
 msgstr "bruger standard-PIN som %s\n"
 
@@ -6926,6 +6935,10 @@ msgid "certificate policy not allowed"
 msgstr "certifikatpolitik er ikke tilladt"
 
 #, c-format
+msgid "failed to get the fingerprint\n"
+msgstr "kunne ikke indhente fingeraftrykket\n"
+
+#, c-format
 msgid "looking up issuer at external location\n"
 msgstr "slår udsteder op på ekstern placering\n"
 
@@ -6933,6 +6946,11 @@ msgstr "slår udsteder op på ekstern placering\n"
 msgid "number of issuers matching: %d\n"
 msgstr "antallet af udstedere der matcher: %d\n"
 
+#, fuzzy, c-format
+#| msgid "can't access `%s': %s\n"
+msgid "can't get authorityInfoAccess: %s\n"
+msgstr "kan ikke tilgå »%s«: %s\n"
+
 #, c-format
 msgid "looking up issuer from the Dirmngr cache\n"
 msgstr "slår udsteder op fra Dirmngr-mellemlageret\n"
@@ -7551,10 +7569,6 @@ msgid "error reading input: %s\n"
 msgstr "fejl ved læsning af inddata: %s\n"
 
 #, c-format
-msgid "failed to get the fingerprint\n"
-msgstr "kunne ikke indhente fingeraftrykket\n"
-
-#, c-format
 msgid "problem looking for existing certificate: %s\n"
 msgstr "problem under udkig efter eksisterende certifikat: %s\n"
 
@@ -7646,9 +7660,10 @@ msgstr "Underskrift lavet "
 msgid "[date not given]"
 msgstr "[dato ikke angivet]"
 
-#, c-format
-msgid " using certificate ID 0x%08lX\n"
-msgstr " bruger certifikat-id 0x%08lX\n"
+#, fuzzy, c-format
+#| msgid "algorithm: %s"
+msgid "algorithm:"
+msgstr "algoritme: %s"
 
 #, c-format
 msgid ""
@@ -8021,15 +8036,6 @@ msgstr ""
 msgid "error getting data from cache file: %s\n"
 msgstr "fejl ved indhentelse af gemte flag: %s\n"
 
-#, fuzzy, c-format
-#| msgid "invalid hash algorithm `%s'\n"
-msgid "unknown hash algorithm '%s'\n"
-msgstr "ugyldig hash-algoritme »%s«\n"
-
-#, c-format
-msgid "gcry_md_open for algorithm %d failed: %s\n"
-msgstr ""
-
 #, c-format
 msgid "got an invalid S-expression from libksba\n"
 msgstr ""
@@ -8040,6 +8046,15 @@ msgid "converting S-expression failed: %s\n"
 msgstr "iconv_open mislykkedes: %s:\n"
 
 #, fuzzy, c-format
+#| msgid "invalid hash algorithm `%s'\n"
+msgid "unknown hash algorithm '%s'\n"
+msgstr "ugyldig hash-algoritme »%s«\n"
+
+#, c-format
+msgid "gcry_md_open for algorithm %d failed: %s\n"
+msgstr ""
+
+#, fuzzy, c-format
 #| msgid "receiving line failed: %s\n"
 msgid "creating S-expression failed: %s\n"
 msgstr "modtagelse af linje mislykkedes: %s\n"
@@ -8917,11 +8932,6 @@ msgstr "fejl ved lagring af certifikat\n"
 msgid "failed to allocate OCSP context: %s\n"
 msgstr "kunne ikke allokere keyDB-håndtag\n"
 
-#, fuzzy, c-format
-#| msgid "can't access `%s': %s\n"
-msgid "can't get authorityInfoAccess: %s\n"
-msgstr "kan ikke tilgå »%s«: %s\n"
-
 #, c-format
 msgid "no default OCSP responder defined\n"
 msgstr ""
@@ -9560,6 +9570,9 @@ msgstr ""
 "Syntaks: gpg-check-pattern [tilvalg] mønsterfil\n"
 "Kontroller en adgangsfrase angivet på stdin mod mønsterfilen\n"
 
+#~ msgid " using certificate ID 0x%08lX\n"
+#~ msgstr " bruger certifikat-id 0x%08lX\n"
+
 #, fuzzy
 #~| msgid "you may not use %s while in %s mode\n"
 #~ msgid ""
index 1ad7f35..00b6993 100644 (file)
--- a/po/de.po
+++ b/po/de.po
@@ -9,7 +9,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: gnupg-2.1.0\n"
 "Report-Msgid-Bugs-To: translations@gnupg.org\n"
-"PO-Revision-Date: 2020-03-19 14:27+0100\n"
+"PO-Revision-Date: 2020-07-09 11:31+0200\n"
 "Last-Translator: Werner Koch <wk@gnupg.org>\n"
 "Language-Team: German <de@li.org>\n"
 "Language: de\n"
@@ -101,6 +101,9 @@ msgstr "Keine Übereinstimmung - bitte nochmal versuchen."
 #. the pinentry.  The %s is the actual error message, the
 #. two %d give the current and maximum number of tries.
 #. Do not translate the "SETERROR" keyword.
+#. TRANSLATORS: The string is appended to an error message in
+#. the pinentry.  The %s is the actual error message, the
+#. two %d give the current and maximum number of tries.
 #, c-format
 msgid "SETERROR %s (try %d of %d)"
 msgstr "SETERROR %s (Versuch %d von %d)"
@@ -3544,6 +3547,9 @@ msgstr "\"%s\" ist kein gültiger Fingerabdruck\n"
 msgid "subkey \"%s\" not found\n"
 msgstr "Unterschlüssel \"%s\" nicht gefunden\n"
 
+msgid "AEAD: "
+msgstr "AEAD: "
+
 msgid "Digest: "
 msgstr "Digest: "
 
@@ -6300,6 +6306,27 @@ msgstr ""
 "Syntax: kbxutil [Optionen] [Dateien]\n"
 "Anlisten exportieren und Importieren von KeyBox Dateien\n"
 
+#. TRANSLATORS: Put a \x1f right before a colon.  This can be
+#. * used by pinentry to nicely align the names and values.  Keep
+#. * the %s at the start and end of the string.
+#, c-format
+msgid "%sNumber\1f: %s%%0AHolder\1f: %s%s"
+msgstr "%sNummer\1f: %s%%0ABesitzer\1f: %s%s"
+
+#. TRANSLATORS: This is the number of remaining attempts to
+#. * enter a PIN.  Use %%0A (double-percent,0A) for a linefeed.
+#, c-format
+msgid "Remaining attempts: %d"
+msgstr "Verbliebene Versuche: %d"
+
+msgid "||Please enter the PIN for the key to create qualified signatures."
+msgstr ""
+"||Bitte geben Sie die PIN für den Schlüssel zur Erstellung qualifizierter "
+"Signaturen ein."
+
+msgid "||Please enter the PIN for the standard keys."
+msgstr "||Bitte die PIN für den Standard-Schlüssel eingeben."
+
 #, c-format
 msgid "RSA modulus missing or not of size %d bits\n"
 msgstr "Der RSA Modulus fehlt oder ist nicht %d Bits lang\n"
@@ -6319,9 +6346,6 @@ msgstr "Die Nullpin wurde noch nicht geändert\n"
 msgid "|N|Please enter a new PIN for the standard keys."
 msgstr "|N|Bitte eine neue PIN für den Standard-Schlüssel eingeben."
 
-msgid "||Please enter the PIN for the standard keys."
-msgstr "||Bitte die PIN für den Standard-Schlüssel eingeben."
-
 msgid "|NP|Please enter a new PIN Unblocking Code (PUK) for the standard keys."
 msgstr ""
 "|NP|Bitte geben Sie einen neuen PIN Entsperrcode (PUK) für den Standard-"
@@ -6336,11 +6360,6 @@ msgstr ""
 "|N|Bitte geben Sie eine neue PIN für den Schlüssel zur Erstellung "
 "qualifizierter Signaturen ein."
 
-msgid "||Please enter the PIN for the key to create qualified signatures."
-msgstr ""
-"||Bitte geben Sie die PIN für den Schlüssel zur Erstellung qualifizierter "
-"Signaturen ein."
-
 msgid ""
 "|NP|Please enter a new PIN Unblocking Code (PUK) for the key to create "
 "qualified signatures."
@@ -6399,16 +6418,6 @@ msgid "%sNumber\1f: %s%%0AHolder\1f: %s%%0ACounter\1f: %lu%s"
 msgstr "%sNummer\1f: %s%%0ABesitzer\1f: %s%%0AAnzahl\1f: %lu%s"
 
 #, c-format
-msgid "%sNumber\1f: %s%%0AHolder\1f: %s%s"
-msgstr "%sNummer\1f: %s%%0ABesitzer\1f: %s%s"
-
-#. TRANSLATORS: This is the number of remaining attempts to
-#. * enter a PIN.  Use %%0A (double-percent,0A) for a linefeed.
-#, c-format
-msgid "Remaining attempts: %d"
-msgstr "Verbliebene Versuche: %d"
-
-#, c-format
 msgid "using default PIN as %s\n"
 msgstr "Die Standard PIN wird für %s benutzt\n"
 
@@ -6658,6 +6667,10 @@ msgid "certificate policy not allowed"
 msgstr "Die Zertifikatsrichtlinie ist nicht erlaubt"
 
 #, c-format
+msgid "failed to get the fingerprint\n"
+msgstr "Kann den Fingerprint nicht ermitteln\n"
+
+#, c-format
 msgid "looking up issuer at external location\n"
 msgstr "Der Herausgeber wird von einer externen Stelle gesucht\n"
 
@@ -6666,6 +6679,10 @@ msgid "number of issuers matching: %d\n"
 msgstr "Anzahl der übereinstimmenden Herausgeber: %d\n"
 
 #, c-format
+msgid "can't get authorityInfoAccess: %s\n"
+msgstr "authorityInfoAccess kann nicht geholt werden: %s\n"
+
+#, c-format
 msgid "looking up issuer from the Dirmngr cache\n"
 msgstr "Der Herausgeber wird im Cache des Dirmngr gesucht\n"
 
@@ -7261,10 +7278,6 @@ msgid "error reading input: %s\n"
 msgstr "Fehler beim Lesen der Eingabe: %s\n"
 
 #, c-format
-msgid "failed to get the fingerprint\n"
-msgstr "Kann den Fingerprint nicht ermitteln\n"
-
-#, c-format
 msgid "problem looking for existing certificate: %s\n"
 msgstr "Problem bei der Suche nach vorhandenem Zertifikat: %s\n"
 
@@ -7359,8 +7372,8 @@ msgid "[date not given]"
 msgstr "[Datum nicht vorhanden]"
 
 #, c-format
-msgid " using certificate ID 0x%08lX\n"
-msgstr " mittels Zertifikat ID 0x%08lX\n"
+msgid "algorithm:"
+msgstr "Verfahren:"
 
 #, c-format
 msgid ""
@@ -7708,14 +7721,6 @@ msgid "error getting data from cache file: %s\n"
 msgstr "Fehler beim Holen der Daten aus der Zwischenspeicherdatei: %s\n"
 
 #, c-format
-msgid "unknown hash algorithm '%s'\n"
-msgstr "Ungültige Hashmethode `%s'\n"
-
-#, c-format
-msgid "gcry_md_open for algorithm %d failed: %s\n"
-msgstr "gcry_md_open für Methode %d fehlgeschlagen: %s\n"
-
-#, c-format
 msgid "got an invalid S-expression from libksba\n"
 msgstr "Ungültige S-Expression von Libksba erhalten\n"
 
@@ -7724,6 +7729,14 @@ msgid "converting S-expression failed: %s\n"
 msgstr "Konvertierung der S-Expression fehlgeschlagen: %s\n"
 
 #, c-format
+msgid "unknown hash algorithm '%s'\n"
+msgstr "Ungültige Hashmethode `%s'\n"
+
+#, c-format
+msgid "gcry_md_open for algorithm %d failed: %s\n"
+msgstr "gcry_md_open für Methode %d fehlgeschlagen: %s\n"
+
+#, c-format
 msgid "creating S-expression failed: %s\n"
 msgstr "Erzeugen der S-Expression fehlgeschlagen: %s\n"
 
@@ -8488,10 +8501,6 @@ msgid "failed to allocate OCSP context: %s\n"
 msgstr "Fehler beim Bereitstellen eines OCSP Kontext: %s\n"
 
 #, c-format
-msgid "can't get authorityInfoAccess: %s\n"
-msgstr "authorityInfoAccess kann nicht geholt werden: %s\n"
-
-#, c-format
 msgid "no default OCSP responder defined\n"
 msgstr "Kein  voreingestellter OCSP Responder definiert\n"
 
@@ -9064,6 +9073,9 @@ msgstr ""
 "Syntax: gpg-check-pattern [optionen] Musterdatei\n"
 "Die von stdin gelesene Passphrase gegen die Musterdatei prüfen\n"
 
+#~ msgid " using certificate ID 0x%08lX\n"
+#~ msgstr " mittels Zertifikat ID 0x%08lX\n"
+
 #, fuzzy
 #~ msgid ""
 #~ "keyserver option \"honor-keyserver-url\" may not be used in Tor mode\n"
index 7dcc708..f4f620d 100644 (file)
--- a/po/el.po
+++ b/po/el.po
@@ -96,6 +96,9 @@ msgstr ""
 #. the pinentry.  The %s is the actual error message, the
 #. two %d give the current and maximum number of tries.
 #. Do not translate the "SETERROR" keyword.
+#. TRANSLATORS: The string is appended to an error message in
+#. the pinentry.  The %s is the actual error message, the
+#. two %d give the current and maximum number of tries.
 #, c-format
 msgid "SETERROR %s (try %d of %d)"
 msgstr ""
@@ -3715,6 +3718,9 @@ msgstr "σφάλμα: μη έγκυρο αποτύπωμα\n"
 msgid "subkey \"%s\" not found\n"
 msgstr "το κλειδί '%s' δε βρέθηκε: %s\n"
 
+msgid "AEAD: "
+msgstr ""
+
 msgid "Digest: "
 msgstr "Περίληψη: "
 
@@ -6474,6 +6480,26 @@ msgid ""
 "List, export, import Keybox data\n"
 msgstr "Χρήση: gpg [επιλογές] [αρχεία] (-h για βοήθεια)"
 
+#. TRANSLATORS: Put a \x1f right before a colon.  This can be
+#. * used by pinentry to nicely align the names and values.  Keep
+#. * the %s at the start and end of the string.
+#, c-format
+msgid "%sNumber\1f: %s%%0AHolder\1f: %s%s"
+msgstr ""
+
+#. TRANSLATORS: This is the number of remaining attempts to
+#. * enter a PIN.  Use %%0A (double-percent,0A) for a linefeed.
+#, c-format
+msgid "Remaining attempts: %d"
+msgstr ""
+
+msgid "||Please enter the PIN for the key to create qualified signatures."
+msgstr ""
+
+#, fuzzy
+msgid "||Please enter the PIN for the standard keys."
+msgstr "αλλαγή της φράσης κλειδί"
+
 #, c-format
 msgid "RSA modulus missing or not of size %d bits\n"
 msgstr ""
@@ -6495,10 +6521,6 @@ msgid "|N|Please enter a new PIN for the standard keys."
 msgstr "αλλαγή της φράσης κλειδί"
 
 #, fuzzy
-msgid "||Please enter the PIN for the standard keys."
-msgstr "αλλαγή της φράσης κλειδί"
-
-#, fuzzy
 msgid "|NP|Please enter a new PIN Unblocking Code (PUK) for the standard keys."
 msgstr "Παρακαλώ επιλέξτε την αιτία για την ανάκληση:\n"
 
@@ -6509,9 +6531,6 @@ msgstr "Παρακαλώ επιλέξτε την αιτία για την ανά
 msgid "|N|Please enter a new PIN for the key to create qualified signatures."
 msgstr ""
 
-msgid "||Please enter the PIN for the key to create qualified signatures."
-msgstr ""
-
 msgid ""
 "|NP|Please enter a new PIN Unblocking Code (PUK) for the key to create "
 "qualified signatures."
@@ -6567,16 +6586,6 @@ msgid "%sNumber\1f: %s%%0AHolder\1f: %s%%0ACounter\1f: %lu%s"
 msgstr ""
 
 #, c-format
-msgid "%sNumber\1f: %s%%0AHolder\1f: %s%s"
-msgstr ""
-
-#. TRANSLATORS: This is the number of remaining attempts to
-#. * enter a PIN.  Use %%0A (double-percent,0A) for a linefeed.
-#, c-format
-msgid "Remaining attempts: %d"
-msgstr ""
-
-#, c-format
 msgid "using default PIN as %s\n"
 msgstr ""
 
@@ -6832,6 +6841,10 @@ msgstr "εγγραφή του μυστικού κλειδιού στο `%s'\n"
 msgid "certificate policy not allowed"
 msgstr "εγγραφή του μυστικού κλειδιού στο `%s'\n"
 
+#, fuzzy, c-format
+msgid "failed to get the fingerprint\n"
+msgstr "αποτυχία αρχικοποίησης της TrustDB: %s\n"
+
 #, c-format
 msgid "looking up issuer at external location\n"
 msgstr ""
@@ -6840,6 +6853,11 @@ msgstr ""
 msgid "number of issuers matching: %d\n"
 msgstr ""
 
+#, fuzzy, c-format
+#| msgid "%s: can't access: %s\n"
+msgid "can't get authorityInfoAccess: %s\n"
+msgstr "%s: αδυναμία πρόσβασης: %s\n"
+
 #, c-format
 msgid "looking up issuer from the Dirmngr cache\n"
 msgstr ""
@@ -7447,10 +7465,6 @@ msgstr "σφάλμα στη δημιουργία της φράσης κλειδ
 msgid "error reading input: %s\n"
 msgstr "σφάλμα κατά την ανάγνωση του `%s': %s\n"
 
-#, fuzzy, c-format
-msgid "failed to get the fingerprint\n"
-msgstr "αποτυχία αρχικοποίησης της TrustDB: %s\n"
-
 #, c-format
 msgid "problem looking for existing certificate: %s\n"
 msgstr ""
@@ -7530,8 +7544,8 @@ msgid "[date not given]"
 msgstr ""
 
 #, fuzzy, c-format
-msgid " using certificate ID 0x%08lX\n"
-msgstr "σφάλμα στη δημιουργία της φράσης κλειδί: %s\n"
+msgid "algorithm:"
+msgstr "θωράκιση: %s\n"
 
 #, c-format
 msgid ""
@@ -7863,15 +7877,6 @@ msgid "error getting data from cache file: %s\n"
 msgstr "σφάλμα στη δημιουργία της φράσης κλειδί: %s\n"
 
 #, fuzzy, c-format
-#| msgid "invalid hash algorithm `%s'\n"
-msgid "unknown hash algorithm '%s'\n"
-msgstr "μη έγκυρος αλγόριθμος  hash `%s'\n"
-
-#, c-format
-msgid "gcry_md_open for algorithm %d failed: %s\n"
-msgstr ""
-
-#, fuzzy, c-format
 #| msgid "invalid response from agent\n"
 msgid "got an invalid S-expression from libksba\n"
 msgstr "μη έγκυρη απάντηση από τον agent\n"
@@ -7881,6 +7886,15 @@ msgid "converting S-expression failed: %s\n"
 msgstr "αδυναμία πρόσβασης του αρχείου: %s\n"
 
 #, fuzzy, c-format
+#| msgid "invalid hash algorithm `%s'\n"
+msgid "unknown hash algorithm '%s'\n"
+msgstr "μη έγκυρος αλγόριθμος  hash `%s'\n"
+
+#, c-format
+msgid "gcry_md_open for algorithm %d failed: %s\n"
+msgstr ""
+
+#, fuzzy, c-format
 msgid "creating S-expression failed: %s\n"
 msgstr "διαγραφή block κλειδιών απέτυχε: %s\n"
 
@@ -8663,11 +8677,6 @@ msgstr "δημιουργία ενός πιστοποιητικού ανάκλη
 msgid "failed to allocate OCSP context: %s\n"
 msgstr "αποτυχία αρχικοποίησης της TrustDB: %s\n"
 
-#, fuzzy, c-format
-#| msgid "%s: can't access: %s\n"
-msgid "can't get authorityInfoAccess: %s\n"
-msgstr "%s: αδυναμία πρόσβασης: %s\n"
-
 #, c-format
 msgid "no default OCSP responder defined\n"
 msgstr ""
@@ -9262,6 +9271,10 @@ msgid ""
 msgstr ""
 
 #, fuzzy
+#~ msgid " using certificate ID 0x%08lX\n"
+#~ msgstr "σφάλμα στη δημιουργία της φράσης κλειδί: %s\n"
+
+#, fuzzy
 #~| msgid "you may not use %s while in %s mode\n"
 #~ msgid ""
 #~ "keyserver option \"honor-keyserver-url\" may not be used in Tor mode\n"
index ae5ed19..323e9e3 100644 (file)
--- a/po/eo.po
+++ b/po/eo.po
@@ -96,6 +96,9 @@ msgstr ""
 #. the pinentry.  The %s is the actual error message, the
 #. two %d give the current and maximum number of tries.
 #. Do not translate the "SETERROR" keyword.
+#. TRANSLATORS: The string is appended to an error message in
+#. the pinentry.  The %s is the actual error message, the
+#. two %d give the current and maximum number of tries.
 #, c-format
 msgid "SETERROR %s (try %d of %d)"
 msgstr ""
@@ -3687,6 +3690,9 @@ msgstr "%s: nevalida dosiero-versio %d\n"
 msgid "subkey \"%s\" not found\n"
 msgstr "ŝlosilo '%s' ne trovita: %s\n"
 
+msgid "AEAD: "
+msgstr ""
+
 msgid "Digest: "
 msgstr ""
 
@@ -6389,6 +6395,26 @@ msgid ""
 "List, export, import Keybox data\n"
 msgstr "Uzado: gpg [opcioj] [dosieroj] (-h por helpo)"
 
+#. TRANSLATORS: Put a \x1f right before a colon.  This can be
+#. * used by pinentry to nicely align the names and values.  Keep
+#. * the %s at the start and end of the string.
+#, c-format
+msgid "%sNumber\1f: %s%%0AHolder\1f: %s%s"
+msgstr ""
+
+#. TRANSLATORS: This is the number of remaining attempts to
+#. * enter a PIN.  Use %%0A (double-percent,0A) for a linefeed.
+#, c-format
+msgid "Remaining attempts: %d"
+msgstr ""
+
+msgid "||Please enter the PIN for the key to create qualified signatures."
+msgstr ""
+
+#, fuzzy
+msgid "||Please enter the PIN for the standard keys."
+msgstr "ŝanĝi la pasfrazon"
+
 #, c-format
 msgid "RSA modulus missing or not of size %d bits\n"
 msgstr ""
@@ -6410,10 +6436,6 @@ msgid "|N|Please enter a new PIN for the standard keys."
 msgstr "ŝanĝi la pasfrazon"
 
 #, fuzzy
-msgid "||Please enter the PIN for the standard keys."
-msgstr "ŝanĝi la pasfrazon"
-
-#, fuzzy
 msgid "|NP|Please enter a new PIN Unblocking Code (PUK) for the standard keys."
 msgstr "Kialo por revoko: "
 
@@ -6424,9 +6446,6 @@ msgstr "Kialo por revoko: "
 msgid "|N|Please enter a new PIN for the key to create qualified signatures."
 msgstr ""
 
-msgid "||Please enter the PIN for the key to create qualified signatures."
-msgstr ""
-
 msgid ""
 "|NP|Please enter a new PIN Unblocking Code (PUK) for the key to create "
 "qualified signatures."
@@ -6482,16 +6501,6 @@ msgid "%sNumber\1f: %s%%0AHolder\1f: %s%%0ACounter\1f: %lu%s"
 msgstr ""
 
 #, c-format
-msgid "%sNumber\1f: %s%%0AHolder\1f: %s%s"
-msgstr ""
-
-#. TRANSLATORS: This is the number of remaining attempts to
-#. * enter a PIN.  Use %%0A (double-percent,0A) for a linefeed.
-#, c-format
-msgid "Remaining attempts: %d"
-msgstr ""
-
-#, c-format
 msgid "using default PIN as %s\n"
 msgstr ""
 
@@ -6748,6 +6757,10 @@ msgstr "skribas sekretan ŝlosilon al '%s'\n"
 msgid "certificate policy not allowed"
 msgstr "skribas sekretan ŝlosilon al '%s'\n"
 
+#, fuzzy, c-format
+msgid "failed to get the fingerprint\n"
+msgstr "malsukcesis doni komencajn valorojn al fido-datenaro: %s\n"
+
 #, c-format
 msgid "looking up issuer at external location\n"
 msgstr ""
@@ -6756,6 +6769,11 @@ msgstr ""
 msgid "number of issuers matching: %d\n"
 msgstr ""
 
+#, fuzzy, c-format
+#| msgid "%s: can't access: %s\n"
+msgid "can't get authorityInfoAccess: %s\n"
+msgstr "%s: ne povas aliri: %s\n"
+
 #, c-format
 msgid "looking up issuer from the Dirmngr cache\n"
 msgstr ""
@@ -7370,10 +7388,6 @@ msgstr "eraro dum kreado de pasfrazo: %s\n"
 msgid "error reading input: %s\n"
 msgstr "eraro dum legado de '%s': %s\n"
 
-#, fuzzy, c-format
-msgid "failed to get the fingerprint\n"
-msgstr "malsukcesis doni komencajn valorojn al fido-datenaro: %s\n"
-
 #, c-format
 msgid "problem looking for existing certificate: %s\n"
 msgstr ""
@@ -7453,8 +7467,8 @@ msgid "[date not given]"
 msgstr ""
 
 #, fuzzy, c-format
-msgid " using certificate ID 0x%08lX\n"
-msgstr "eraro dum kreado de pasfrazo: %s\n"
+msgid "algorithm:"
+msgstr "kiraso: %s\n"
 
 #, c-format
 msgid ""
@@ -7779,15 +7793,6 @@ msgstr ""
 msgid "error getting data from cache file: %s\n"
 msgstr "eraro dum kreado de pasfrazo: %s\n"
 
-#, fuzzy, c-format
-#| msgid "invalid hash algorithm `%s'\n"
-msgid "unknown hash algorithm '%s'\n"
-msgstr "nevalida kompendi-metodo '%s'\n"
-
-#, c-format
-msgid "gcry_md_open for algorithm %d failed: %s\n"
-msgstr ""
-
 #, c-format
 msgid "got an invalid S-expression from libksba\n"
 msgstr ""
@@ -7798,6 +7803,15 @@ msgid "converting S-expression failed: %s\n"
 msgstr "ŝanĝo de permesoj de '%s' malsukcesis: %s\n"
 
 #, fuzzy, c-format
+#| msgid "invalid hash algorithm `%s'\n"
+msgid "unknown hash algorithm '%s'\n"
+msgstr "nevalida kompendi-metodo '%s'\n"
+
+#, c-format
+msgid "gcry_md_open for algorithm %d failed: %s\n"
+msgstr ""
+
+#, fuzzy, c-format
 #| msgid "changing permission of  `%s' failed: %s\n"
 msgid "creating S-expression failed: %s\n"
 msgstr "ŝanĝo de permesoj de '%s' malsukcesis: %s\n"
@@ -8578,11 +8592,6 @@ msgstr "Bona atestilo"
 msgid "failed to allocate OCSP context: %s\n"
 msgstr "malsukcesis doni komencajn valorojn al fido-datenaro: %s\n"
 
-#, fuzzy, c-format
-#| msgid "%s: can't access: %s\n"
-msgid "can't get authorityInfoAccess: %s\n"
-msgstr "%s: ne povas aliri: %s\n"
-
 #, c-format
 msgid "no default OCSP responder defined\n"
 msgstr ""
@@ -9176,6 +9185,10 @@ msgid ""
 msgstr ""
 
 #, fuzzy
+#~ msgid " using certificate ID 0x%08lX\n"
+#~ msgstr "eraro dum kreado de pasfrazo: %s\n"
+
+#, fuzzy
 #~ msgid ""
 #~ "keyserver option \"honor-keyserver-url\" may not be used in Tor mode\n"
 #~ msgstr "Tiu komando ne eblas en la reĝimo %s.\n"
index e04efba..23a9483 100644 (file)
--- a/po/es.po
+++ b/po/es.po
@@ -106,6 +106,9 @@ msgstr "no coincide - reinténtelo"
 #. the pinentry.  The %s is the actual error message, the
 #. two %d give the current and maximum number of tries.
 #. Do not translate the "SETERROR" keyword.
+#. TRANSLATORS: The string is appended to an error message in
+#. the pinentry.  The %s is the actual error message, the
+#. two %d give the current and maximum number of tries.
 #, c-format
 msgid "SETERROR %s (try %d of %d)"
 msgstr "SETERROR %s (intento %d de %d)"
@@ -3509,6 +3512,9 @@ msgstr "\"%s\" no es una huella digital válida\n"
 msgid "subkey \"%s\" not found\n"
 msgstr "subclave \"%s\" no encontrada\n"
 
+msgid "AEAD: "
+msgstr ""
+
 msgid "Digest: "
 msgstr "Resumen: "
 
@@ -6202,6 +6208,25 @@ msgstr ""
 "Sintaxis: kbxutil [opciones] [ficheros]\n"
 "Listar, exportar, importar datos Keybox\n"
 
+#. TRANSLATORS: Put a \x1f right before a colon.  This can be
+#. * used by pinentry to nicely align the names and values.  Keep
+#. * the %s at the start and end of the string.
+#, c-format
+msgid "%sNumber\1f: %s%%0AHolder\1f: %s%s"
+msgstr "%sNúmero\1f: %s%%0ATitular\1f: %s%s"
+
+#. TRANSLATORS: This is the number of remaining attempts to
+#. * enter a PIN.  Use %%0A (double-percent,0A) for a linefeed.
+#, c-format
+msgid "Remaining attempts: %d"
+msgstr "Intentos disponibles: %d"
+
+msgid "||Please enter the PIN for the key to create qualified signatures."
+msgstr "||Introduzca un PIN para la clave que crea firmas cualificadas."
+
+msgid "||Please enter the PIN for the standard keys."
+msgstr "||Por favor, introduzca PIN para claves estándar."
+
 #, c-format
 msgid "RSA modulus missing or not of size %d bits\n"
 msgstr "falta el módulo RSA o no es de %d bits\n"
@@ -6221,9 +6246,6 @@ msgstr "el PIN-Nulo no ha sido cambiado\n"
 msgid "|N|Please enter a new PIN for the standard keys."
 msgstr "|N|Por favor introduzca un nuevo PIN para las claves estándar."
 
-msgid "||Please enter the PIN for the standard keys."
-msgstr "||Por favor, introduzca PIN para claves estándar."
-
 msgid "|NP|Please enter a new PIN Unblocking Code (PUK) for the standard keys."
 msgstr "|NP|Introduzca nuevo PIN Unblocking Code (PUK) para claves estándar."
 
@@ -6234,9 +6256,6 @@ msgstr ""
 msgid "|N|Please enter a new PIN for the key to create qualified signatures."
 msgstr "|N|Entre un nuevo PIN para la clave que crea firmas cualificadas."
 
-msgid "||Please enter the PIN for the key to create qualified signatures."
-msgstr "||Introduzca un PIN para la clave que crea firmas cualificadas."
-
 msgid ""
 "|NP|Please enter a new PIN Unblocking Code (PUK) for the key to create "
 "qualified signatures."
@@ -6295,16 +6314,6 @@ msgid "%sNumber\1f: %s%%0AHolder\1f: %s%%0ACounter\1f: %lu%s"
 msgstr "%sNumber\1f: %s%%0AHolder\1f: %s%%0ACounter\1f: %lu%s"
 
 #, c-format
-msgid "%sNumber\1f: %s%%0AHolder\1f: %s%s"
-msgstr "%sNúmero\1f: %s%%0ATitular\1f: %s%s"
-
-#. TRANSLATORS: This is the number of remaining attempts to
-#. * enter a PIN.  Use %%0A (double-percent,0A) for a linefeed.
-#, c-format
-msgid "Remaining attempts: %d"
-msgstr "Intentos disponibles: %d"
-
-#, c-format
 msgid "using default PIN as %s\n"
 msgstr "usando PIN por defecto %s\n"
 
@@ -6553,6 +6562,10 @@ msgid "certificate policy not allowed"
 msgstr "no se permite política de certificado"
 
 #, c-format
+msgid "failed to get the fingerprint\n"
+msgstr "fallo obteniendo huella digital\n"
+
+#, c-format
 msgid "looking up issuer at external location\n"
 msgstr "buscando al emisor en una localización externa\n"
 
@@ -6561,6 +6574,10 @@ msgid "number of issuers matching: %d\n"
 msgstr "numero de emisores coincidentes: %d\n"
 
 #, c-format
+msgid "can't get authorityInfoAccess: %s\n"
+msgstr "no se ha podido obtener authorityInfoAccess: %s\n"
+
+#, c-format
 msgid "looking up issuer from the Dirmngr cache\n"
 msgstr "buscando emisor en el caché de Dirmngr\n"
 
@@ -7149,10 +7166,6 @@ msgid "error reading input: %s\n"
 msgstr "error al leer la entrada: %s\n"
 
 #, c-format
-msgid "failed to get the fingerprint\n"
-msgstr "fallo obteniendo huella digital\n"
-
-#, c-format
 msgid "problem looking for existing certificate: %s\n"
 msgstr "problema buscando el certificado existente: %s\n"
 
@@ -7240,9 +7253,10 @@ msgstr "Firmado el "
 msgid "[date not given]"
 msgstr "[no hay fecha]"
 
-#, c-format
-msgid " using certificate ID 0x%08lX\n"
-msgstr " usando el certificado ID 0x%08lX\n"
+#, fuzzy, c-format
+#| msgid "algorithm: %s"
+msgid "algorithm:"
+msgstr "algoritmo: %s"
 
 #, c-format
 msgid ""
@@ -7573,14 +7587,6 @@ msgid "error getting data from cache file: %s\n"
 msgstr "error al obtener datos del archivo de cache: %s\n"
 
 #, c-format
-msgid "unknown hash algorithm '%s'\n"
-msgstr "algoritmo hash inválido '%s'\n"
-
-#, c-format
-msgid "gcry_md_open for algorithm %d failed: %s\n"
-msgstr "gcry_md_open para algoritmo %d ha fallado: %s\n"
-
-#, c-format
 msgid "got an invalid S-expression from libksba\n"
 msgstr "respuesta S-expression de libksba no válida\n"
 
@@ -7589,6 +7595,14 @@ msgid "converting S-expression failed: %s\n"
 msgstr "he fallado al convertir la expresión S-expression: %s\n"
 
 #, c-format
+msgid "unknown hash algorithm '%s'\n"
+msgstr "algoritmo hash inválido '%s'\n"
+
+#, c-format
+msgid "gcry_md_open for algorithm %d failed: %s\n"
+msgstr "gcry_md_open para algoritmo %d ha fallado: %s\n"
+
+#, c-format
 msgid "creating S-expression failed: %s\n"
 msgstr "fallo al crear S-expression: %s\n"
 
@@ -8356,10 +8370,6 @@ msgid "failed to allocate OCSP context: %s\n"
 msgstr "fallo al asignar el contexto OCSP: %s\n"
 
 #, c-format
-msgid "can't get authorityInfoAccess: %s\n"
-msgstr "no se ha podido obtener authorityInfoAccess: %s\n"
-
-#, c-format
 msgid "no default OCSP responder defined\n"
 msgstr "no hay un OCSP responder predeterminado\n"
 
@@ -8948,6 +8958,9 @@ msgstr ""
 "Compara frase contraseña dada en entrada estándar con un fichero de "
 "patrones\n"
 
+#~ msgid " using certificate ID 0x%08lX\n"
+#~ msgstr " usando el certificado ID 0x%08lX\n"
+
 #, fuzzy
 #~| msgid "option '%s' may not be used in %s mode\n"
 #~ msgid ""
index cf5e858..fbc3510 100644 (file)
--- a/po/et.po
+++ b/po/et.po
@@ -93,6 +93,9 @@ msgstr ""
 #. the pinentry.  The %s is the actual error message, the
 #. two %d give the current and maximum number of tries.
 #. Do not translate the "SETERROR" keyword.
+#. TRANSLATORS: The string is appended to an error message in
+#. the pinentry.  The %s is the actual error message, the
+#. two %d give the current and maximum number of tries.
 #, c-format
 msgid "SETERROR %s (try %d of %d)"
 msgstr ""
@@ -3687,6 +3690,9 @@ msgstr "viga: vigane sõrmejälg\n"
 msgid "subkey \"%s\" not found\n"
 msgstr "võtit '%s' ei leitud: %s\n"
 
+msgid "AEAD: "
+msgstr ""
+
 msgid "Digest: "
 msgstr "Teatelühend: "
 
@@ -6395,6 +6401,26 @@ msgid ""
 "List, export, import Keybox data\n"
 msgstr "Kasuta: gpg [võtmed] [failid] (-h näitab abiinfot)"
 
+#. TRANSLATORS: Put a \x1f right before a colon.  This can be
+#. * used by pinentry to nicely align the names and values.  Keep
+#. * the %s at the start and end of the string.
+#, c-format
+msgid "%sNumber\1f: %s%%0AHolder\1f: %s%s"
+msgstr ""
+
+#. TRANSLATORS: This is the number of remaining attempts to
+#. * enter a PIN.  Use %%0A (double-percent,0A) for a linefeed.
+#, c-format
+msgid "Remaining attempts: %d"
+msgstr ""
+
+msgid "||Please enter the PIN for the key to create qualified signatures."
+msgstr ""
+
+#, fuzzy
+msgid "||Please enter the PIN for the standard keys."
+msgstr "muuda parooli"
+
 #, c-format
 msgid "RSA modulus missing or not of size %d bits\n"
 msgstr ""
@@ -6416,10 +6442,6 @@ msgid "|N|Please enter a new PIN for the standard keys."
 msgstr "muuda parooli"
 
 #, fuzzy
-msgid "||Please enter the PIN for the standard keys."
-msgstr "muuda parooli"
-
-#, fuzzy
 msgid "|NP|Please enter a new PIN Unblocking Code (PUK) for the standard keys."
 msgstr "Palun valige tühistamise põhjus:\n"
 
@@ -6430,9 +6452,6 @@ msgstr "Palun valige tühistamise põhjus:\n"
 msgid "|N|Please enter a new PIN for the key to create qualified signatures."
 msgstr ""
 
-msgid "||Please enter the PIN for the key to create qualified signatures."
-msgstr ""
-
 msgid ""
 "|NP|Please enter a new PIN Unblocking Code (PUK) for the key to create "
 "qualified signatures."
@@ -6488,16 +6507,6 @@ msgid "%sNumber\1f: %s%%0AHolder\1f: %s%%0ACounter\1f: %lu%s"
 msgstr ""
 
 #, c-format
-msgid "%sNumber\1f: %s%%0AHolder\1f: %s%s"
-msgstr ""
-
-#. TRANSLATORS: This is the number of remaining attempts to
-#. * enter a PIN.  Use %%0A (double-percent,0A) for a linefeed.
-#, c-format
-msgid "Remaining attempts: %d"
-msgstr ""
-
-#, c-format
 msgid "using default PIN as %s\n"
 msgstr ""
 
@@ -6753,6 +6762,10 @@ msgstr "kirjutan salajase võtme faili `%s'\n"
 msgid "certificate policy not allowed"
 msgstr "kirjutan salajase võtme faili `%s'\n"
 
+#, fuzzy, c-format
+msgid "failed to get the fingerprint\n"
+msgstr "TrustDB initsialiseerimine ebaõnnestus: %s\n"
+
 #, c-format
 msgid "looking up issuer at external location\n"
 msgstr ""
@@ -6761,6 +6774,11 @@ msgstr ""
 msgid "number of issuers matching: %d\n"
 msgstr ""
 
+#, fuzzy, c-format
+#| msgid "%s: can't access: %s\n"
+msgid "can't get authorityInfoAccess: %s\n"
+msgstr "%s: ei õnnestu kasutada: %s\n"
+
 #, c-format
 msgid "looking up issuer from the Dirmngr cache\n"
 msgstr ""
@@ -7367,10 +7385,6 @@ msgstr "viga parooli loomisel: %s\n"
 msgid "error reading input: %s\n"
 msgstr "viga `%s' lugemisel: %s\n"
 
-#, fuzzy, c-format
-msgid "failed to get the fingerprint\n"
-msgstr "TrustDB initsialiseerimine ebaõnnestus: %s\n"
-
 #, c-format
 msgid "problem looking for existing certificate: %s\n"
 msgstr ""
@@ -7450,8 +7464,8 @@ msgid "[date not given]"
 msgstr ""
 
 #, fuzzy, c-format
-msgid " using certificate ID 0x%08lX\n"
-msgstr "viga parooli loomisel: %s\n"
+msgid "algorithm:"
+msgstr "pakend: %s\n"
 
 #, c-format
 msgid ""
@@ -7781,15 +7795,6 @@ msgid "error getting data from cache file: %s\n"
 msgstr "viga parooli loomisel: %s\n"
 
 #, fuzzy, c-format
-#| msgid "invalid hash algorithm `%s'\n"
-msgid "unknown hash algorithm '%s'\n"
-msgstr "vigane räsialgoritm `%s'\n"
-
-#, c-format
-msgid "gcry_md_open for algorithm %d failed: %s\n"
-msgstr ""
-
-#, fuzzy, c-format
 #| msgid "invalid response from agent\n"
 msgid "got an invalid S-expression from libksba\n"
 msgstr "vigane vastus agendilt\n"
@@ -7799,6 +7804,15 @@ msgid "converting S-expression failed: %s\n"
 msgstr "faili ei õnnestu avada: %s\n"
 
 #, fuzzy, c-format
+#| msgid "invalid hash algorithm `%s'\n"
+msgid "unknown hash algorithm '%s'\n"
+msgstr "vigane räsialgoritm `%s'\n"
+
+#, c-format
+msgid "gcry_md_open for algorithm %d failed: %s\n"
+msgstr ""
+
+#, fuzzy, c-format
 msgid "creating S-expression failed: %s\n"
 msgstr "võtmebloki kustutamine ebaõnnestus: %s\n"
 
@@ -8579,11 +8593,6 @@ msgstr "genereeri tühistamise sertifikaat"
 msgid "failed to allocate OCSP context: %s\n"
 msgstr "TrustDB initsialiseerimine ebaõnnestus: %s\n"
 
-#, fuzzy, c-format
-#| msgid "%s: can't access: %s\n"
-msgid "can't get authorityInfoAccess: %s\n"
-msgstr "%s: ei õnnestu kasutada: %s\n"
-
 #, c-format
 msgid "no default OCSP responder defined\n"
 msgstr ""
@@ -9178,6 +9187,10 @@ msgid ""
 msgstr ""
 
 #, fuzzy
+#~ msgid " using certificate ID 0x%08lX\n"
+#~ msgstr "viga parooli loomisel: %s\n"
+
+#, fuzzy
 #~| msgid "you may not use %s while in %s mode\n"
 #~ msgid ""
 #~ "keyserver option \"honor-keyserver-url\" may not be used in Tor mode\n"
index 05e7d4d..ffca851 100644 (file)
--- a/po/fi.po
+++ b/po/fi.po
@@ -109,6 +109,9 @@ msgstr ""
 #. the pinentry.  The %s is the actual error message, the
 #. two %d give the current and maximum number of tries.
 #. Do not translate the "SETERROR" keyword.
+#. TRANSLATORS: The string is appended to an error message in
+#. the pinentry.  The %s is the actual error message, the
+#. two %d give the current and maximum number of tries.
 #, c-format
 msgid "SETERROR %s (try %d of %d)"
 msgstr ""
@@ -3707,6 +3710,9 @@ msgstr "virhe: sormenjälki on väärä\n"
 msgid "subkey \"%s\" not found\n"
 msgstr "avainta \"%s\" ei löydy: %s\n"
 
+msgid "AEAD: "
+msgstr ""
+
 msgid "Digest: "
 msgstr "Tiiviste: "
 
@@ -6454,6 +6460,26 @@ msgid ""
 "List, export, import Keybox data\n"
 msgstr "Käyttö: gpg [valitsimet] [tiedostot] (-h näyttää ohjeen)"
 
+#. TRANSLATORS: Put a \x1f right before a colon.  This can be
+#. * used by pinentry to nicely align the names and values.  Keep
+#. * the %s at the start and end of the string.
+#, c-format
+msgid "%sNumber\1f: %s%%0AHolder\1f: %s%s"
+msgstr ""
+
+#. TRANSLATORS: This is the number of remaining attempts to
+#. * enter a PIN.  Use %%0A (double-percent,0A) for a linefeed.
+#, c-format
+msgid "Remaining attempts: %d"
+msgstr ""
+
+msgid "||Please enter the PIN for the key to create qualified signatures."
+msgstr ""
+
+#, fuzzy
+msgid "||Please enter the PIN for the standard keys."
+msgstr "muuta salasanaa"
+
 #, c-format
 msgid "RSA modulus missing or not of size %d bits\n"
 msgstr ""
@@ -6475,10 +6501,6 @@ msgid "|N|Please enter a new PIN for the standard keys."
 msgstr "muuta salasanaa"
 
 #, fuzzy
-msgid "||Please enter the PIN for the standard keys."
-msgstr "muuta salasanaa"
-
-#, fuzzy
 msgid "|NP|Please enter a new PIN Unblocking Code (PUK) for the standard keys."
 msgstr "Valitse mitätöinnin syy:\n"
 
@@ -6489,9 +6511,6 @@ msgstr "Valitse mitätöinnin syy:\n"
 msgid "|N|Please enter a new PIN for the key to create qualified signatures."
 msgstr ""
 
-msgid "||Please enter the PIN for the key to create qualified signatures."
-msgstr ""
-
 msgid ""
 "|NP|Please enter a new PIN Unblocking Code (PUK) for the key to create "
 "qualified signatures."
@@ -6547,16 +6566,6 @@ msgid "%sNumber\1f: %s%%0AHolder\1f: %s%%0ACounter\1f: %lu%s"
 msgstr ""
 
 #, c-format
-msgid "%sNumber\1f: %s%%0AHolder\1f: %s%s"
-msgstr ""
-
-#. TRANSLATORS: This is the number of remaining attempts to
-#. * enter a PIN.  Use %%0A (double-percent,0A) for a linefeed.
-#, c-format
-msgid "Remaining attempts: %d"
-msgstr ""
-
-#, c-format
 msgid "using default PIN as %s\n"
 msgstr ""
 
@@ -6813,6 +6822,10 @@ msgstr "kirjoitan salaisen avaimen kohteeseen \"%s\"\n"
 msgid "certificate policy not allowed"
 msgstr "kirjoitan salaisen avaimen kohteeseen \"%s\"\n"
 
+#, fuzzy, c-format
+msgid "failed to get the fingerprint\n"
+msgstr "TrustDB:n alustaminen ei onnistu: %s\n"
+
 #, c-format
 msgid "looking up issuer at external location\n"
 msgstr ""
@@ -6821,6 +6834,11 @@ msgstr ""
 msgid "number of issuers matching: %d\n"
 msgstr ""
 
+#, fuzzy, c-format
+#| msgid "%s: can't access: %s\n"
+msgid "can't get authorityInfoAccess: %s\n"
+msgstr "%s: kohteeseen ei päästä: %s\n"
+
 #, c-format
 msgid "looking up issuer from the Dirmngr cache\n"
 msgstr ""
@@ -7427,10 +7445,6 @@ msgstr "virhe luotaessa salasanaa: %s\n"
 msgid "error reading input: %s\n"
 msgstr "virhe luettaessa tiedostoa \"%s\": %s\n"
 
-#, fuzzy, c-format
-msgid "failed to get the fingerprint\n"
-msgstr "TrustDB:n alustaminen ei onnistu: %s\n"
-
 #, c-format
 msgid "problem looking for existing certificate: %s\n"
 msgstr ""
@@ -7510,8 +7524,8 @@ msgid "[date not given]"
 msgstr ""
 
 #, fuzzy, c-format
-msgid " using certificate ID 0x%08lX\n"
-msgstr "virhe luotaessa salasanaa: %s\n"
+msgid "algorithm:"
+msgstr "ascii-koodaus: %s\n"
 
 #, c-format
 msgid ""
@@ -7842,15 +7856,6 @@ msgid "error getting data from cache file: %s\n"
 msgstr "virhe luotaessa salasanaa: %s\n"
 
 #, fuzzy, c-format
-#| msgid "invalid hash algorithm `%s'\n"
-msgid "unknown hash algorithm '%s'\n"
-msgstr "virheellinen tiivistealgoritmi \"%s\"\n"
-
-#, c-format
-msgid "gcry_md_open for algorithm %d failed: %s\n"
-msgstr ""
-
-#, fuzzy, c-format
 #| msgid "invalid response from agent\n"
 msgid "got an invalid S-expression from libksba\n"
 msgstr "agentin lähettämä vastaus ei kelpaa\n"
@@ -7860,6 +7865,15 @@ msgid "converting S-expression failed: %s\n"
 msgstr "ei voi avata tiedostoa: %s\n"
 
 #, fuzzy, c-format
+#| msgid "invalid hash algorithm `%s'\n"
+msgid "unknown hash algorithm '%s'\n"
+msgstr "virheellinen tiivistealgoritmi \"%s\"\n"
+
+#, c-format
+msgid "gcry_md_open for algorithm %d failed: %s\n"
+msgstr ""
+
+#, fuzzy, c-format
 msgid "creating S-expression failed: %s\n"
 msgstr "avainlohkojen poisto epäonnistui: %s\n"
 
@@ -8642,11 +8656,6 @@ msgstr "luo mitätöintivarmenne"
 msgid "failed to allocate OCSP context: %s\n"
 msgstr "TrustDB:n alustaminen ei onnistu: %s\n"
 
-#, fuzzy, c-format
-#| msgid "%s: can't access: %s\n"
-msgid "can't get authorityInfoAccess: %s\n"
-msgstr "%s: kohteeseen ei päästä: %s\n"
-
 #, c-format
 msgid "no default OCSP responder defined\n"
 msgstr ""
@@ -9241,6 +9250,10 @@ msgid ""
 msgstr ""
 
 #, fuzzy
+#~ msgid " using certificate ID 0x%08lX\n"
+#~ msgstr "virhe luotaessa salasanaa: %s\n"
+
+#, fuzzy
 #~| msgid "you may not use %s while in %s mode\n"
 #~ msgid ""
 #~ "keyserver option \"honor-keyserver-url\" may not be used in Tor mode\n"
index 84cceb9..1d753b1 100644 (file)
--- a/po/fr.po
+++ b/po/fr.po
@@ -108,6 +108,9 @@ msgstr "ne correspond pas — veuillez réessayer"
 #. the pinentry.  The %s is the actual error message, the
 #. two %d give the current and maximum number of tries.
 #. Do not translate the "SETERROR" keyword.
+#. TRANSLATORS: The string is appended to an error message in
+#. the pinentry.  The %s is the actual error message, the
+#. two %d give the current and maximum number of tries.
 #, c-format
 msgid "SETERROR %s (try %d of %d)"
 msgstr "SETERROR %s (essai %d sur %d)"
@@ -3650,6 +3653,9 @@ msgstr "« %s » n’est pas une empreinte\n"
 msgid "subkey \"%s\" not found\n"
 msgstr "clef « %s » introuvable : %s\n"
 
+msgid "AEAD: "
+msgstr ""
+
 msgid "Digest: "
 msgstr "Hachage : "
 
@@ -6469,6 +6475,27 @@ msgstr ""
 "Syntaxe : kbxutil [options] [fichiers]\n"
 "Afficher, exporter, importer les données de trousseau local\n"
 
+#. TRANSLATORS: Put a \x1f right before a colon.  This can be
+#. * used by pinentry to nicely align the names and values.  Keep
+#. * the %s at the start and end of the string.
+#, c-format
+msgid "%sNumber\1f: %s%%0AHolder\1f: %s%s"
+msgstr ""
+
+#. TRANSLATORS: This is the number of remaining attempts to
+#. * enter a PIN.  Use %%0A (double-percent,0A) for a linefeed.
+#, c-format
+msgid "Remaining attempts: %d"
+msgstr ""
+
+msgid "||Please enter the PIN for the key to create qualified signatures."
+msgstr ""
+"||Veuillez entrer le code personnel pour permettre à la clef de créer des "
+"signatures qualifiées."
+
+msgid "||Please enter the PIN for the standard keys."
+msgstr "||Veuillez entrer le code personnel pour les clefs standards."
+
 #, c-format
 msgid "RSA modulus missing or not of size %d bits\n"
 msgstr "le module RSA est manquant ou sa taille n'est pas de %d bits\n"
@@ -6488,9 +6515,6 @@ msgstr "le code personnel nul n'a pas encore été modifié\n"
 msgid "|N|Please enter a new PIN for the standard keys."
 msgstr "|N|Veuillez entrer un nouveau code personnel pour les clefs standards."
 
-msgid "||Please enter the PIN for the standard keys."
-msgstr "||Veuillez entrer le code personnel pour les clefs standards."
-
 msgid "|NP|Please enter a new PIN Unblocking Code (PUK) for the standard keys."
 msgstr ""
 "|NP|Veuillez entrer un nouveau code de déblocage personnel (CDP) pour les "
@@ -6506,11 +6530,6 @@ msgstr ""
 "|N|Veuillez entrer un nouveau code personnel pour permettre à la clef de "
 "créer des signatures qualifiées."
 
-msgid "||Please enter the PIN for the key to create qualified signatures."
-msgstr ""
-"||Veuillez entrer le code personnel pour permettre à la clef de créer des "
-"signatures qualifiées."
-
 msgid ""
 "|NP|Please enter a new PIN Unblocking Code (PUK) for the key to create "
 "qualified signatures."
@@ -6570,16 +6589,6 @@ msgid "%sNumber\1f: %s%%0AHolder\1f: %s%%0ACounter\1f: %lu%s"
 msgstr ""
 
 #, c-format
-msgid "%sNumber\1f: %s%%0AHolder\1f: %s%s"
-msgstr ""
-
-#. TRANSLATORS: This is the number of remaining attempts to
-#. * enter a PIN.  Use %%0A (double-percent,0A) for a linefeed.
-#, c-format
-msgid "Remaining attempts: %d"
-msgstr ""
-
-#, c-format
 msgid "using default PIN as %s\n"
 msgstr "utilisation du code personnel par défaut en tant que %s\n"
 
@@ -6849,6 +6858,10 @@ msgid "certificate policy not allowed"
 msgstr "politique de certificat non autorisée"
 
 #, c-format
+msgid "failed to get the fingerprint\n"
+msgstr "impossible d'obtenir l'empreinte\n"
+
+#, c-format
 msgid "looking up issuer at external location\n"
 msgstr "recherche d'émetteur à l'extérieur\n"
 
@@ -6857,6 +6870,10 @@ msgid "number of issuers matching: %d\n"
 msgstr "nombre d'émetteurs correspondants : %d\n"
 
 #, c-format
+msgid "can't get authorityInfoAccess: %s\n"
+msgstr "impossible d'obtenir authorityInfoAccess : %s\n"
+
+#, c-format
 msgid "looking up issuer from the Dirmngr cache\n"
 msgstr "recherche d'émetteur dans le cache du Dirmngr\n"
 
@@ -7452,10 +7469,6 @@ msgid "error reading input: %s\n"
 msgstr "erreur de lecture de l'entrée : %s\n"
 
 #, c-format
-msgid "failed to get the fingerprint\n"
-msgstr "impossible d'obtenir l'empreinte\n"
-
-#, c-format
 msgid "problem looking for existing certificate: %s\n"
 msgstr "problème de recherche de certificat existant : %s\n"
 
@@ -7550,9 +7563,10 @@ msgstr "Signature faite le "
 msgid "[date not given]"
 msgstr "[date non donnée]"
 
-#, c-format
-msgid " using certificate ID 0x%08lX\n"
-msgstr " en utilisant le certificat d'identifiant 0x%08lX\n"
+#, fuzzy, c-format
+#| msgid "algorithm: %s"
+msgid "algorithm:"
+msgstr "algorithme : %s"
 
 #, c-format
 msgid ""
@@ -7898,14 +7912,6 @@ msgid "error getting data from cache file: %s\n"
 msgstr "erreur de lecture des données du fichier de cache : %s\n"
 
 #, c-format
-msgid "unknown hash algorithm '%s'\n"
-msgstr "algorithme de hachage « %s » inconnu\n"
-
-#, c-format
-msgid "gcry_md_open for algorithm %d failed: %s\n"
-msgstr "échec de gcry_md_open pour l'algorithme %d : %s\n"
-
-#, c-format
 msgid "got an invalid S-expression from libksba\n"
 msgstr "expression symbolique incorrecte obtenue de libksba\n"
 
@@ -7914,6 +7920,14 @@ msgid "converting S-expression failed: %s\n"
 msgstr "échec de conversion d'expression symbolique : %s\n"
 
 #, c-format
+msgid "unknown hash algorithm '%s'\n"
+msgstr "algorithme de hachage « %s » inconnu\n"
+
+#, c-format
+msgid "gcry_md_open for algorithm %d failed: %s\n"
+msgstr "échec de gcry_md_open pour l'algorithme %d : %s\n"
+
+#, c-format
 msgid "creating S-expression failed: %s\n"
 msgstr "échec de création d'expression symbolique : %s\n"
 
@@ -8712,10 +8726,6 @@ msgid "failed to allocate OCSP context: %s\n"
 msgstr "échec d'allocation du contexte OCSP : %s\n"
 
 #, c-format
-msgid "can't get authorityInfoAccess: %s\n"
-msgstr "impossible d'obtenir authorityInfoAccess : %s\n"
-
-#, c-format
 msgid "no default OCSP responder defined\n"
 msgstr "aucun répondeur OCSP par défaut défini\n"
 
@@ -9321,6 +9331,9 @@ msgstr ""
 "Vérifier une phrase secrète donnée sur l'entrée standard par rapport à "
 "ficmotif\n"
 
+#~ msgid " using certificate ID 0x%08lX\n"
+#~ msgstr " en utilisant le certificat d'identifiant 0x%08lX\n"
+
 #, fuzzy
 #~| msgid "you may not use %s while in %s mode\n"
 #~ msgid ""
index 0362895..396e8b7 100644 (file)
--- a/po/gl.po
+++ b/po/gl.po
@@ -94,6 +94,9 @@ msgstr ""
 #. the pinentry.  The %s is the actual error message, the
 #. two %d give the current and maximum number of tries.
 #. Do not translate the "SETERROR" keyword.
+#. TRANSLATORS: The string is appended to an error message in
+#. the pinentry.  The %s is the actual error message, the
+#. two %d give the current and maximum number of tries.
 #, c-format
 msgid "SETERROR %s (try %d of %d)"
 msgstr ""
@@ -3711,6 +3714,9 @@ msgstr "erro: pegada dactilar non válida\n"
 msgid "subkey \"%s\" not found\n"
 msgstr "non se atopou a chave `%s': %s\n"
 
+msgid "AEAD: "
+msgstr ""
+
 msgid "Digest: "
 msgstr "Resumo: "
 
@@ -6458,6 +6464,26 @@ msgid ""
 "List, export, import Keybox data\n"
 msgstr "Uso: gpg [opcións] [ficheiros] (-h para ve-la axuda)"
 
+#. TRANSLATORS: Put a \x1f right before a colon.  This can be
+#. * used by pinentry to nicely align the names and values.  Keep
+#. * the %s at the start and end of the string.
+#, c-format
+msgid "%sNumber\1f: %s%%0AHolder\1f: %s%s"
+msgstr ""
+
+#. TRANSLATORS: This is the number of remaining attempts to
+#. * enter a PIN.  Use %%0A (double-percent,0A) for a linefeed.
+#, c-format
+msgid "Remaining attempts: %d"
+msgstr ""
+
+msgid "||Please enter the PIN for the key to create qualified signatures."
+msgstr ""
+
+#, fuzzy
+msgid "||Please enter the PIN for the standard keys."
+msgstr "cambia-lo contrasinal"
+
 #, c-format
 msgid "RSA modulus missing or not of size %d bits\n"
 msgstr ""
@@ -6479,10 +6505,6 @@ msgid "|N|Please enter a new PIN for the standard keys."
 msgstr "cambia-lo contrasinal"
 
 #, fuzzy
-msgid "||Please enter the PIN for the standard keys."
-msgstr "cambia-lo contrasinal"
-
-#, fuzzy
 msgid "|NP|Please enter a new PIN Unblocking Code (PUK) for the standard keys."
 msgstr "Por favor, escolla o motivo da revocación:\n"
 
@@ -6493,9 +6515,6 @@ msgstr "Por favor, escolla o motivo da revocación:\n"
 msgid "|N|Please enter a new PIN for the key to create qualified signatures."
 msgstr ""
 
-msgid "||Please enter the PIN for the key to create qualified signatures."
-msgstr ""
-
 msgid ""
 "|NP|Please enter a new PIN Unblocking Code (PUK) for the key to create "
 "qualified signatures."
@@ -6551,16 +6570,6 @@ msgid "%sNumber\1f: %s%%0AHolder\1f: %s%%0ACounter\1f: %lu%s"
 msgstr ""
 
 #, c-format
-msgid "%sNumber\1f: %s%%0AHolder\1f: %s%s"
-msgstr ""
-
-#. TRANSLATORS: This is the number of remaining attempts to
-#. * enter a PIN.  Use %%0A (double-percent,0A) for a linefeed.
-#, c-format
-msgid "Remaining attempts: %d"
-msgstr ""
-
-#, c-format
 msgid "using default PIN as %s\n"
 msgstr ""
 
@@ -6817,6 +6826,10 @@ msgstr "gravando a chave secreta en `%s'\n"
 msgid "certificate policy not allowed"
 msgstr "gravando a chave secreta en `%s'\n"
 
+#, fuzzy, c-format
+msgid "failed to get the fingerprint\n"
+msgstr "non se puido inicializa-la base de datos de confianzas: %s\n"
+
 #, c-format
 msgid "looking up issuer at external location\n"
 msgstr ""
@@ -6825,6 +6838,11 @@ msgstr ""
 msgid "number of issuers matching: %d\n"
 msgstr ""
 
+#, fuzzy, c-format
+#| msgid "%s: can't access: %s\n"
+msgid "can't get authorityInfoAccess: %s\n"
+msgstr "%s: non é posible acceder: %s\n"
+
 #, c-format
 msgid "looking up issuer from the Dirmngr cache\n"
 msgstr ""
@@ -7439,10 +7457,6 @@ msgstr "erro ao crea-lo contrasinal: %s\n"
 msgid "error reading input: %s\n"
 msgstr "erro lendo `%s': %s\n"
 
-#, fuzzy, c-format
-msgid "failed to get the fingerprint\n"
-msgstr "non se puido inicializa-la base de datos de confianzas: %s\n"
-
 #, c-format
 msgid "problem looking for existing certificate: %s\n"
 msgstr ""
@@ -7522,8 +7536,8 @@ msgid "[date not given]"
 msgstr ""
 
 #, fuzzy, c-format
-msgid " using certificate ID 0x%08lX\n"
-msgstr "erro ao crea-lo contrasinal: %s\n"
+msgid "algorithm:"
+msgstr "armadura: %s\n"
 
 #, c-format
 msgid ""
@@ -7854,15 +7868,6 @@ msgid "error getting data from cache file: %s\n"
 msgstr "erro ao crea-lo contrasinal: %s\n"
 
 #, fuzzy, c-format
-#| msgid "invalid hash algorithm `%s'\n"
-msgid "unknown hash algorithm '%s'\n"
-msgstr "algoritmo de hash non válido `%s'\n"
-
-#, c-format
-msgid "gcry_md_open for algorithm %d failed: %s\n"
-msgstr ""
-
-#, fuzzy, c-format
 #| msgid "invalid response from agent\n"
 msgid "got an invalid S-expression from libksba\n"
 msgstr "resposta do axente non válida\n"
@@ -7873,6 +7878,15 @@ msgid "converting S-expression failed: %s\n"
 msgstr "o cambio de permisos de `%s' fallou: %s\n"
 
 #, fuzzy, c-format
+#| msgid "invalid hash algorithm `%s'\n"
+msgid "unknown hash algorithm '%s'\n"
+msgstr "algoritmo de hash non válido `%s'\n"
+
+#, c-format
+msgid "gcry_md_open for algorithm %d failed: %s\n"
+msgstr ""
+
+#, fuzzy, c-format
 #| msgid "changing permission of  `%s' failed: %s\n"
 msgid "creating S-expression failed: %s\n"
 msgstr "o cambio de permisos de `%s' fallou: %s\n"
@@ -8658,11 +8672,6 @@ msgstr "Certificado correcto"
 msgid "failed to allocate OCSP context: %s\n"
 msgstr "non se puido inicializa-la base de datos de confianzas: %s\n"
 
-#, fuzzy, c-format
-#| msgid "%s: can't access: %s\n"
-msgid "can't get authorityInfoAccess: %s\n"
-msgstr "%s: non é posible acceder: %s\n"
-
 #, c-format
 msgid "no default OCSP responder defined\n"
 msgstr ""
@@ -9259,6 +9268,10 @@ msgid ""
 msgstr ""
 
 #, fuzzy
+#~ msgid " using certificate ID 0x%08lX\n"
+#~ msgstr "erro ao crea-lo contrasinal: %s\n"
+
+#, fuzzy
 #~| msgid "you may not use %s while in %s mode\n"
 #~ msgid ""
 #~ "keyserver option \"honor-keyserver-url\" may not be used in Tor mode\n"
index edde068..36c342a 100644 (file)
--- a/po/hu.po
+++ b/po/hu.po
@@ -1,12 +1,12 @@
 # GnuPG Hungarian translation.
-# Copyright (C) 2003, 2004 Free Software Foundation, Inc.
-# Nagy Ferenc László <nfl@nfllab.com>, 2003, 2004.
+# Copyright (C) 2003, 2004, 2020 Free Software Foundation, Inc.
+# Nagy Ferenc László <nfl@nfllab.com>, 2003, 2004, 2020.
 #
 msgid ""
 msgstr ""
-"Project-Id-Version: gnupg 1.2.5\n"
+"Project-Id-Version: gnupg 2.2.20\n"
 "Report-Msgid-Bugs-To: translations@gnupg.org\n"
-"PO-Revision-Date: 2004-06-19 21:53+0200\n"
+"PO-Revision-Date: 2020-06-09 23:10+0200\n"
 "Last-Translator: Nagy Ferenc László <nfl@nfllab.com>\n"
 "Language-Team: Hungarian <translation-team-hu@lists.sourceforge.net>\n"
 "Language: hu\n"
@@ -93,6 +93,9 @@ msgstr ""
 #. the pinentry.  The %s is the actual error message, the
 #. two %d give the current and maximum number of tries.
 #. Do not translate the "SETERROR" keyword.
+#. TRANSLATORS: The string is appended to an error message in
+#. the pinentry.  The %s is the actual error message, the
+#. two %d give the current and maximum number of tries.
 #, c-format
 msgid "SETERROR %s (try %d of %d)"
 msgstr ""
@@ -3686,6 +3689,9 @@ msgstr "Hiba: Érvénytelen ujjlenyomat.\n"
 msgid "subkey \"%s\" not found\n"
 msgstr "\"%s\" kulcs nem található: %s\n"
 
+msgid "AEAD: "
+msgstr ""
+
 msgid "Digest: "
 msgstr "Kivonat: "
 
@@ -4397,16 +4403,11 @@ msgid "Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? "
 msgstr ""
 "(N)év, (M)egjegyzés, (E)-mail megváltoztatása vagy (R)endben/(K)ilépés? "
 
-#, fuzzy
-#| msgid "Change (N)ame, (C)omment, (E)mail or (Q)uit? "
 msgid "Change (N)ame, (E)mail, or (Q)uit? "
-msgstr "(N)év, (M)egjegyzés, (E)-mail megváltoztatása vagy (K)ilépés? "
+msgstr "(N)év, (E)-mail megváltoztatása vagy (K)ilépés? "
 
-#, fuzzy
-#| msgid "Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? "
 msgid "Change (N)ame, (E)mail, or (O)kay/(Q)uit? "
-msgstr ""
-"(N)év, (M)egjegyzés, (E)-mail megváltoztatása vagy (R)endben/(K)ilépés? "
+msgstr "(N)év, (E)-mail megváltoztatása vagy (R)endben/(K)ilépés? "
 
 msgid "Please correct the error first\n"
 msgstr "Kérem, előbb javítsa ki a hibát!\n"
@@ -6424,6 +6425,26 @@ msgid ""
 "List, export, import Keybox data\n"
 msgstr "Használat: gpg [opciók] [fájlok] (-h a súgóhoz)"
 
+#. TRANSLATORS: Put a \x1f right before a colon.  This can be
+#. * used by pinentry to nicely align the names and values.  Keep
+#. * the %s at the start and end of the string.
+#, c-format
+msgid "%sNumber\1f: %s%%0AHolder\1f: %s%s"
+msgstr ""
+
+#. TRANSLATORS: This is the number of remaining attempts to
+#. * enter a PIN.  Use %%0A (double-percent,0A) for a linefeed.
+#, c-format
+msgid "Remaining attempts: %d"
+msgstr ""
+
+msgid "||Please enter the PIN for the key to create qualified signatures."
+msgstr ""
+
+#, fuzzy
+msgid "||Please enter the PIN for the standard keys."
+msgstr "jelszóváltoztatás"
+
 #, c-format
 msgid "RSA modulus missing or not of size %d bits\n"
 msgstr ""
@@ -6445,10 +6466,6 @@ msgid "|N|Please enter a new PIN for the standard keys."
 msgstr "jelszóváltoztatás"
 
 #, fuzzy
-msgid "||Please enter the PIN for the standard keys."
-msgstr "jelszóváltoztatás"
-
-#, fuzzy
 msgid "|NP|Please enter a new PIN Unblocking Code (PUK) for the standard keys."
 msgstr "Kérem, válassza ki a visszavonás okát:\n"
 
@@ -6459,9 +6476,6 @@ msgstr "Kérem, válassza ki a visszavonás okát:\n"
 msgid "|N|Please enter a new PIN for the key to create qualified signatures."
 msgstr ""
 
-msgid "||Please enter the PIN for the key to create qualified signatures."
-msgstr ""
-
 msgid ""
 "|NP|Please enter a new PIN Unblocking Code (PUK) for the key to create "
 "qualified signatures."
@@ -6517,16 +6531,6 @@ msgid "%sNumber\1f: %s%%0AHolder\1f: %s%%0ACounter\1f: %lu%s"
 msgstr ""
 
 #, c-format
-msgid "%sNumber\1f: %s%%0AHolder\1f: %s%s"
-msgstr ""
-
-#. TRANSLATORS: This is the number of remaining attempts to
-#. * enter a PIN.  Use %%0A (double-percent,0A) for a linefeed.
-#, c-format
-msgid "Remaining attempts: %d"
-msgstr ""
-
-#, c-format
 msgid "using default PIN as %s\n"
 msgstr ""
 
@@ -6782,6 +6786,10 @@ msgstr "Írom a titkos kulcsot a %s állományba.\n"
 msgid "certificate policy not allowed"
 msgstr "Írom a titkos kulcsot a %s állományba.\n"
 
+#, fuzzy, c-format
+msgid "failed to get the fingerprint\n"
+msgstr "Bizalmi adatbázis (%s) inicializálása sikertelen!\n"
+
 #, c-format
 msgid "looking up issuer at external location\n"
 msgstr ""
@@ -6790,6 +6798,11 @@ msgstr ""
 msgid "number of issuers matching: %d\n"
 msgstr ""
 
+#, fuzzy, c-format
+#| msgid "%s: can't access: %s\n"
+msgid "can't get authorityInfoAccess: %s\n"
+msgstr "%s: Nem tudom elérni: %s.\n"
+
 #, c-format
 msgid "looking up issuer from the Dirmngr cache\n"
 msgstr ""
@@ -7397,10 +7410,6 @@ msgstr "Hiba a jelszó létrehozásakor: %s.\n"
 msgid "error reading input: %s\n"
 msgstr "Hiba \"%s\" olvasásakor: %s\n"
 
-#, fuzzy, c-format
-msgid "failed to get the fingerprint\n"
-msgstr "Bizalmi adatbázis (%s) inicializálása sikertelen!\n"
-
 #, c-format
 msgid "problem looking for existing certificate: %s\n"
 msgstr ""
@@ -7480,8 +7489,8 @@ msgid "[date not given]"
 msgstr ""
 
 #, fuzzy, c-format
-msgid " using certificate ID 0x%08lX\n"
-msgstr "Hiba a jelszó létrehozásakor: %s.\n"
+msgid "algorithm:"
+msgstr "Páncél: %s\n"
 
 #, c-format
 msgid ""
@@ -7811,15 +7820,6 @@ msgid "error getting data from cache file: %s\n"
 msgstr "Hiba a jelszó létrehozásakor: %s.\n"
 
 #, fuzzy, c-format
-#| msgid "invalid hash algorithm `%s'\n"
-msgid "unknown hash algorithm '%s'\n"
-msgstr "Érvénytelen kivonatoló algoritmus: %s\n"
-
-#, c-format
-msgid "gcry_md_open for algorithm %d failed: %s\n"
-msgstr ""
-
-#, fuzzy, c-format
 #| msgid "invalid response from agent\n"
 msgid "got an invalid S-expression from libksba\n"
 msgstr "Érvénytelen válasz az ügynöktől!\n"
@@ -7829,6 +7829,15 @@ msgid "converting S-expression failed: %s\n"
 msgstr "Nem tudom megnyitni az állományt: %s.\n"
 
 #, fuzzy, c-format
+#| msgid "invalid hash algorithm `%s'\n"
+msgid "unknown hash algorithm '%s'\n"
+msgstr "Érvénytelen kivonatoló algoritmus: %s\n"
+
+#, c-format
+msgid "gcry_md_open for algorithm %d failed: %s\n"
+msgstr ""
+
+#, fuzzy, c-format
 msgid "creating S-expression failed: %s\n"
 msgstr "A kulcsblokk törlése sikertelen: %s.\n"
 
@@ -8609,11 +8618,6 @@ msgstr "visszavonási igazolás készítése"
 msgid "failed to allocate OCSP context: %s\n"
 msgstr "Bizalmi adatbázis (%s) inicializálása sikertelen!\n"
 
-#, fuzzy, c-format
-#| msgid "%s: can't access: %s\n"
-msgid "can't get authorityInfoAccess: %s\n"
-msgstr "%s: Nem tudom elérni: %s.\n"
-
 #, c-format
 msgid "no default OCSP responder defined\n"
 msgstr ""
@@ -9208,6 +9212,10 @@ msgid ""
 msgstr ""
 
 #, fuzzy
+#~ msgid " using certificate ID 0x%08lX\n"
+#~ msgstr "Hiba a jelszó létrehozásakor: %s.\n"
+
+#, fuzzy
 #~| msgid "you may not use %s while in %s mode\n"
 #~ msgid ""
 #~ "keyserver option \"honor-keyserver-url\" may not be used in Tor mode\n"
index 3f60baf..9fd5575 100644 (file)
--- a/po/id.po
+++ b/po/id.po
@@ -98,6 +98,9 @@ msgstr ""
 #. the pinentry.  The %s is the actual error message, the
 #. two %d give the current and maximum number of tries.
 #. Do not translate the "SETERROR" keyword.
+#. TRANSLATORS: The string is appended to an error message in
+#. the pinentry.  The %s is the actual error message, the
+#. two %d give the current and maximum number of tries.
 #, c-format
 msgid "SETERROR %s (try %d of %d)"
 msgstr ""
@@ -3691,6 +3694,9 @@ msgstr "kesalahan: fingerprint tidak valid\n"
 msgid "subkey \"%s\" not found\n"
 msgstr "kunci '%s' tidak ditemukan: %s\n"
 
+msgid "AEAD: "
+msgstr ""
+
 msgid "Digest: "
 msgstr "Digest: "
 
@@ -6417,6 +6423,26 @@ msgid ""
 "List, export, import Keybox data\n"
 msgstr "Pemakaian: gpg [pilihan] [file] (-h untuk bantuan)"
 
+#. TRANSLATORS: Put a \x1f right before a colon.  This can be
+#. * used by pinentry to nicely align the names and values.  Keep
+#. * the %s at the start and end of the string.
+#, c-format
+msgid "%sNumber\1f: %s%%0AHolder\1f: %s%s"
+msgstr ""
+
+#. TRANSLATORS: This is the number of remaining attempts to
+#. * enter a PIN.  Use %%0A (double-percent,0A) for a linefeed.
+#, c-format
+msgid "Remaining attempts: %d"
+msgstr ""
+
+msgid "||Please enter the PIN for the key to create qualified signatures."
+msgstr ""
+
+#, fuzzy
+msgid "||Please enter the PIN for the standard keys."
+msgstr "ubah passphrase"
+
 #, c-format
 msgid "RSA modulus missing or not of size %d bits\n"
 msgstr ""
@@ -6438,10 +6464,6 @@ msgid "|N|Please enter a new PIN for the standard keys."
 msgstr "ubah passphrase"
 
 #, fuzzy
-msgid "||Please enter the PIN for the standard keys."
-msgstr "ubah passphrase"
-
-#, fuzzy
 msgid "|NP|Please enter a new PIN Unblocking Code (PUK) for the standard keys."
 msgstr "Silakan pilih alasan untuk pembatalan:\n"
 
@@ -6452,9 +6474,6 @@ msgstr "Silakan pilih alasan untuk pembatalan:\n"
 msgid "|N|Please enter a new PIN for the key to create qualified signatures."
 msgstr ""
 
-msgid "||Please enter the PIN for the key to create qualified signatures."
-msgstr ""
-
 msgid ""
 "|NP|Please enter a new PIN Unblocking Code (PUK) for the key to create "
 "qualified signatures."
@@ -6510,16 +6529,6 @@ msgid "%sNumber\1f: %s%%0AHolder\1f: %s%%0ACounter\1f: %lu%s"
 msgstr ""
 
 #, c-format
-msgid "%sNumber\1f: %s%%0AHolder\1f: %s%s"
-msgstr ""
-
-#. TRANSLATORS: This is the number of remaining attempts to
-#. * enter a PIN.  Use %%0A (double-percent,0A) for a linefeed.
-#, c-format
-msgid "Remaining attempts: %d"
-msgstr ""
-
-#, c-format
 msgid "using default PIN as %s\n"
 msgstr ""
 
@@ -6775,6 +6784,10 @@ msgstr "menulis kunci rahasia ke `%s'\n"
 msgid "certificate policy not allowed"
 msgstr "menulis kunci rahasia ke `%s'\n"
 
+#, fuzzy, c-format
+msgid "failed to get the fingerprint\n"
+msgstr "gagal inisialisasi TrustDB: %s\n"
+
 #, c-format
 msgid "looking up issuer at external location\n"
 msgstr ""
@@ -6783,6 +6796,11 @@ msgstr ""
 msgid "number of issuers matching: %d\n"
 msgstr ""
 
+#, fuzzy, c-format
+#| msgid "%s: can't access: %s\n"
+msgid "can't get authorityInfoAccess: %s\n"
+msgstr "%s: tidak dapat mengakses: %s\n"
+
 #, c-format
 msgid "looking up issuer from the Dirmngr cache\n"
 msgstr ""
@@ -7390,10 +7408,6 @@ msgstr "kesalahan penciptaan passphrase: %s\n"
 msgid "error reading input: %s\n"
 msgstr "kesalahan membaca `%s': %s\n"
 
-#, fuzzy, c-format
-msgid "failed to get the fingerprint\n"
-msgstr "gagal inisialisasi TrustDB: %s\n"
-
 #, c-format
 msgid "problem looking for existing certificate: %s\n"
 msgstr ""
@@ -7473,8 +7487,8 @@ msgid "[date not given]"
 msgstr ""
 
 #, fuzzy, c-format
-msgid " using certificate ID 0x%08lX\n"
-msgstr "kesalahan penciptaan passphrase: %s\n"
+msgid "algorithm:"
+msgstr "armor: %s\n"
 
 #, c-format
 msgid ""
@@ -7804,15 +7818,6 @@ msgid "error getting data from cache file: %s\n"
 msgstr "kesalahan penciptaan passphrase: %s\n"
 
 #, fuzzy, c-format
-#| msgid "invalid hash algorithm `%s'\n"
-msgid "unknown hash algorithm '%s'\n"
-msgstr "algoritma hash tidak valid `%s'\n"
-
-#, c-format
-msgid "gcry_md_open for algorithm %d failed: %s\n"
-msgstr ""
-
-#, fuzzy, c-format
 #| msgid "invalid response from agent\n"
 msgid "got an invalid S-expression from libksba\n"
 msgstr "respon tidak valid dari agen\n"
@@ -7822,6 +7827,15 @@ msgid "converting S-expression failed: %s\n"
 msgstr "tidak dapat membuka file: %s\n"
 
 #, fuzzy, c-format
+#| msgid "invalid hash algorithm `%s'\n"
+msgid "unknown hash algorithm '%s'\n"
+msgstr "algoritma hash tidak valid `%s'\n"
+
+#, c-format
+msgid "gcry_md_open for algorithm %d failed: %s\n"
+msgstr ""
+
+#, fuzzy, c-format
 msgid "creating S-expression failed: %s\n"
 msgstr "gagal menghapus keyblok: %s\n"
 
@@ -8602,11 +8616,6 @@ msgstr "buat sertifikat revokasi"
 msgid "failed to allocate OCSP context: %s\n"
 msgstr "gagal inisialisasi TrustDB: %s\n"
 
-#, fuzzy, c-format
-#| msgid "%s: can't access: %s\n"
-msgid "can't get authorityInfoAccess: %s\n"
-msgstr "%s: tidak dapat mengakses: %s\n"
-
 #, c-format
 msgid "no default OCSP responder defined\n"
 msgstr ""
@@ -9201,6 +9210,10 @@ msgid ""
 msgstr ""
 
 #, fuzzy
+#~ msgid " using certificate ID 0x%08lX\n"
+#~ msgstr "kesalahan penciptaan passphrase: %s\n"
+
+#, fuzzy
 #~| msgid "you may not use %s while in %s mode\n"
 #~ msgid ""
 #~ "keyserver option \"honor-keyserver-url\" may not be used in Tor mode\n"
index d61e748..08d32bf 100644 (file)
--- a/po/it.po
+++ b/po/it.po
@@ -93,6 +93,9 @@ msgstr ""
 #. the pinentry.  The %s is the actual error message, the
 #. two %d give the current and maximum number of tries.
 #. Do not translate the "SETERROR" keyword.
+#. TRANSLATORS: The string is appended to an error message in
+#. the pinentry.  The %s is the actual error message, the
+#. two %d give the current and maximum number of tries.
 #, c-format
 msgid "SETERROR %s (try %d of %d)"
 msgstr ""
@@ -3698,6 +3701,9 @@ msgstr "errore: impronta digitale non valida\n"
 msgid "subkey \"%s\" not found\n"
 msgstr "chiave `%s' non trovata: %s\n"
 
+msgid "AEAD: "
+msgstr ""
+
 msgid "Digest: "
 msgstr "Digest: "
 
@@ -6456,6 +6462,26 @@ msgid ""
 "List, export, import Keybox data\n"
 msgstr "Uso: gpg [opzioni] [files] (-h per l'aiuto)"
 
+#. TRANSLATORS: Put a \x1f right before a colon.  This can be
+#. * used by pinentry to nicely align the names and values.  Keep
+#. * the %s at the start and end of the string.
+#, c-format
+msgid "%sNumber\1f: %s%%0AHolder\1f: %s%s"
+msgstr ""
+
+#. TRANSLATORS: This is the number of remaining attempts to
+#. * enter a PIN.  Use %%0A (double-percent,0A) for a linefeed.
+#, c-format
+msgid "Remaining attempts: %d"
+msgstr ""
+
+msgid "||Please enter the PIN for the key to create qualified signatures."
+msgstr ""
+
+#, fuzzy
+msgid "||Please enter the PIN for the standard keys."
+msgstr "cambia la passphrase"
+
 #, c-format
 msgid "RSA modulus missing or not of size %d bits\n"
 msgstr ""
@@ -6477,10 +6503,6 @@ msgid "|N|Please enter a new PIN for the standard keys."
 msgstr "cambia la passphrase"
 
 #, fuzzy
-msgid "||Please enter the PIN for the standard keys."
-msgstr "cambia la passphrase"
-
-#, fuzzy
 msgid "|NP|Please enter a new PIN Unblocking Code (PUK) for the standard keys."
 msgstr "Per favore scegli il motivo della revoca:\n"
 
@@ -6491,9 +6513,6 @@ msgstr "Per favore scegli il motivo della revoca:\n"
 msgid "|N|Please enter a new PIN for the key to create qualified signatures."
 msgstr ""
 
-msgid "||Please enter the PIN for the key to create qualified signatures."
-msgstr ""
-
 msgid ""
 "|NP|Please enter a new PIN Unblocking Code (PUK) for the key to create "
 "qualified signatures."
@@ -6549,16 +6568,6 @@ msgid "%sNumber\1f: %s%%0AHolder\1f: %s%%0ACounter\1f: %lu%s"
 msgstr ""
 
 #, c-format
-msgid "%sNumber\1f: %s%%0AHolder\1f: %s%s"
-msgstr ""
-
-#. TRANSLATORS: This is the number of remaining attempts to
-#. * enter a PIN.  Use %%0A (double-percent,0A) for a linefeed.
-#, c-format
-msgid "Remaining attempts: %d"
-msgstr ""
-
-#, c-format
 msgid "using default PIN as %s\n"
 msgstr ""
 
@@ -6814,6 +6823,10 @@ msgstr "scrittura della chiave segreta in `%s'\n"
 msgid "certificate policy not allowed"
 msgstr "scrittura della chiave segreta in `%s'\n"
 
+#, fuzzy, c-format
+msgid "failed to get the fingerprint\n"
+msgstr "inizializzazione del trustdb fallita: %s\n"
+
 #, c-format
 msgid "looking up issuer at external location\n"
 msgstr ""
@@ -6822,6 +6835,11 @@ msgstr ""
 msgid "number of issuers matching: %d\n"
 msgstr ""
 
+#, fuzzy, c-format
+#| msgid "%s: can't access: %s\n"
+msgid "can't get authorityInfoAccess: %s\n"
+msgstr "%s: impossibile acedere a: %s\n"
+
 #, c-format
 msgid "looking up issuer from the Dirmngr cache\n"
 msgstr ""
@@ -7428,10 +7446,6 @@ msgstr "errore nella creazione della passhprase: %s\n"
 msgid "error reading input: %s\n"
 msgstr "errore leggendo `%s': %s\n"
 
-#, fuzzy, c-format
-msgid "failed to get the fingerprint\n"
-msgstr "inizializzazione del trustdb fallita: %s\n"
-
 #, c-format
 msgid "problem looking for existing certificate: %s\n"
 msgstr ""
@@ -7511,8 +7525,8 @@ msgid "[date not given]"
 msgstr ""
 
 #, fuzzy, c-format
-msgid " using certificate ID 0x%08lX\n"
-msgstr "errore nella creazione della passhprase: %s\n"
+msgid "algorithm:"
+msgstr "armatura: %s\n"
 
 #, c-format
 msgid ""
@@ -7843,15 +7857,6 @@ msgid "error getting data from cache file: %s\n"
 msgstr "errore nella creazione della passhprase: %s\n"
 
 #, fuzzy, c-format
-#| msgid "invalid hash algorithm `%s'\n"
-msgid "unknown hash algorithm '%s'\n"
-msgstr "algoritmo di hash non valido `%s'\n"
-
-#, c-format
-msgid "gcry_md_open for algorithm %d failed: %s\n"
-msgstr ""
-
-#, fuzzy, c-format
 #| msgid "invalid response from agent\n"
 msgid "got an invalid S-expression from libksba\n"
 msgstr "risposta non valida dall'agent\n"
@@ -7861,6 +7866,15 @@ msgid "converting S-expression failed: %s\n"
 msgstr "impossibile aprire il file: %s\n"
 
 #, fuzzy, c-format
+#| msgid "invalid hash algorithm `%s'\n"
+msgid "unknown hash algorithm '%s'\n"
+msgstr "algoritmo di hash non valido `%s'\n"
+
+#, c-format
+msgid "gcry_md_open for algorithm %d failed: %s\n"
+msgstr ""
+
+#, fuzzy, c-format
 msgid "creating S-expression failed: %s\n"
 msgstr "cancellazione del keyblock fallita: %s\n"
 
@@ -8643,11 +8657,6 @@ msgstr "genera un certificato di revoca"
 msgid "failed to allocate OCSP context: %s\n"
 msgstr "inizializzazione del trustdb fallita: %s\n"
 
-#, fuzzy, c-format
-#| msgid "%s: can't access: %s\n"
-msgid "can't get authorityInfoAccess: %s\n"
-msgstr "%s: impossibile acedere a: %s\n"
-
 #, c-format
 msgid "no default OCSP responder defined\n"
 msgstr ""
@@ -9242,6 +9251,10 @@ msgid ""
 msgstr ""
 
 #, fuzzy
+#~ msgid " using certificate ID 0x%08lX\n"
+#~ msgstr "errore nella creazione della passhprase: %s\n"
+
+#, fuzzy
 #~| msgid "you may not use %s while in %s mode\n"
 #~ msgid ""
 #~ "keyserver option \"honor-keyserver-url\" may not be used in Tor mode\n"
index 27680f7..59a9845 100644 (file)
--- a/po/ja.po
+++ b/po/ja.po
@@ -10,7 +10,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: gnupg 2.2.20\n"
 "Report-Msgid-Bugs-To: translations@gnupg.org\n"
-"PO-Revision-Date: 2020-03-19 09:27+0900\n"
+"PO-Revision-Date: 2020-07-07 09:37+0900\n"
 "Last-Translator: NIIBE Yutaka <gniibe@fsij.org>\n"
 "Language-Team: none\n"
 "Language: ja\n"
@@ -97,6 +97,9 @@ msgstr "一致しません - もう一度"
 #. the pinentry.  The %s is the actual error message, the
 #. two %d give the current and maximum number of tries.
 #. Do not translate the "SETERROR" keyword.
+#. TRANSLATORS: The string is appended to an error message in
+#. the pinentry.  The %s is the actual error message, the
+#. two %d give the current and maximum number of tries.
 #, c-format
 msgid "SETERROR %s (try %d of %d)"
 msgstr "SETERROR %s (現在 %d / 最大 %d)"
@@ -3423,6 +3426,9 @@ msgstr "\"%s\"は正しいフィンガープリントではありません\n"
 msgid "subkey \"%s\" not found\n"
 msgstr "副鍵\"%s\"が見つかりません\n"
 
+msgid "AEAD: "
+msgstr "AEAD: "
+
 msgid "Digest: "
 msgstr "ダイジェスト: "
 
@@ -5998,6 +6004,25 @@ msgstr ""
 "形式:  kbxutil [オプション] [ファイル]\n"
 "Keyboxデータを一覧、エクスポート、インポート\n"
 
+#. TRANSLATORS: Put a \x1f right before a colon.  This can be
+#. * used by pinentry to nicely align the names and values.  Keep
+#. * the %s at the start and end of the string.
+#, c-format
+msgid "%sNumber\1f: %s%%0AHolder\1f: %s%s"
+msgstr "%s番号\1f: %s%%0A保持者\1f: %s%s"
+
+#. TRANSLATORS: This is the number of remaining attempts to
+#. * enter a PIN.  Use %%0A (double-percent,0A) for a linefeed.
+#, c-format
+msgid "Remaining attempts: %d"
+msgstr "残された試行回数: %d"
+
+msgid "||Please enter the PIN for the key to create qualified signatures."
+msgstr "||新しいPINを認定署名を生成する鍵のために入力してください。"
+
+msgid "||Please enter the PIN for the standard keys."
+msgstr "||PINを標準の鍵のために入力してください。"
+
 #, c-format
 msgid "RSA modulus missing or not of size %d bits\n"
 msgstr "RSAのモジュラスがないか、%dビットのものではありません\n"
@@ -6017,9 +6042,6 @@ msgstr "NullPINが変更されていません\n"
 msgid "|N|Please enter a new PIN for the standard keys."
 msgstr "|N|新しいPINを標準の鍵のために入力してください。"
 
-msgid "||Please enter the PIN for the standard keys."
-msgstr "||PINを標準の鍵のために入力してください。"
-
 msgid "|NP|Please enter a new PIN Unblocking Code (PUK) for the standard keys."
 msgstr "|NP|標準の鍵の新しいPIN Unblocking Code (PUK)を入力してください。"
 
@@ -6029,9 +6051,6 @@ msgstr "|P|標準の鍵のPIN Unblocking Code (PUK)を入力してください
 msgid "|N|Please enter a new PIN for the key to create qualified signatures."
 msgstr "|N|新しいPINを認定署名を生成する鍵のために入力してください。"
 
-msgid "||Please enter the PIN for the key to create qualified signatures."
-msgstr "||新しいPINを認定署名を生成する鍵のために入力してください。"
-
 msgid ""
 "|NP|Please enter a new PIN Unblocking Code (PUK) for the key to create "
 "qualified signatures."
@@ -6088,16 +6107,6 @@ msgid "%sNumber\1f: %s%%0AHolder\1f: %s%%0ACounter\1f: %lu%s"
 msgstr "%s番号\1f: %s%%0A保持者\1f: %s%%0Aカウンタ\1f: %lu%s"
 
 #, c-format
-msgid "%sNumber\1f: %s%%0AHolder\1f: %s%s"
-msgstr "%s番号\1f: %s%%0A保持者\1f: %s%s"
-
-#. TRANSLATORS: This is the number of remaining attempts to
-#. * enter a PIN.  Use %%0A (double-percent,0A) for a linefeed.
-#, c-format
-msgid "Remaining attempts: %d"
-msgstr "残された試行回数: %d"
-
-#, c-format
 msgid "using default PIN as %s\n"
 msgstr "デフォルトPINを%sとして使います\n"
 
@@ -6343,6 +6352,10 @@ msgid "certificate policy not allowed"
 msgstr "証明書ポリシーは認められません"
 
 #, c-format
+msgid "failed to get the fingerprint\n"
+msgstr "フィンガープリントの取得に失敗しました\n"
+
+#, c-format
 msgid "looking up issuer at external location\n"
 msgstr "発行者の外部ロケーションを調べています\n"
 
@@ -6351,6 +6364,10 @@ msgid "number of issuers matching: %d\n"
 msgstr "マッチする発行者の数: %d\n"
 
 #, c-format
+msgid "can't get authorityInfoAccess: %s\n"
+msgstr "authorityInfoAccessを取得できません: %s\n"
+
+#, c-format
 msgid "looking up issuer from the Dirmngr cache\n"
 msgstr "Dirmngrキャッシュから発行者を調べています\n"
 
@@ -6933,10 +6950,6 @@ msgid "error reading input: %s\n"
 msgstr "入力読み込みエラー: %s\n"
 
 #, c-format
-msgid "failed to get the fingerprint\n"
-msgstr "フィンガープリントの取得に失敗しました\n"
-
-#, c-format
 msgid "problem looking for existing certificate: %s\n"
 msgstr "既存の証明書の検索の問題: %s\n"
 
@@ -7028,8 +7041,8 @@ msgid "[date not given]"
 msgstr "[日時指定なし]"
 
 #, c-format
-msgid " using certificate ID 0x%08lX\n"
-msgstr " 証明書 ID 0x%08lXを用います\n"
+msgid "algorithm:"
+msgstr "アルゴリズム:"
 
 #, c-format
 msgid ""
@@ -7353,14 +7366,6 @@ msgid "error getting data from cache file: %s\n"
 msgstr "キャッシュ・ファイルからデータの取得エラー: %s\n"
 
 #, c-format
-msgid "unknown hash algorithm '%s'\n"
-msgstr "不明なハッシュ・アルゴリズム'%s'\n"
-
-#, c-format
-msgid "gcry_md_open for algorithm %d failed: %s\n"
-msgstr "アルゴリズム%dのgcry_md_openが失敗: %s\n"
-
-#, c-format
 msgid "got an invalid S-expression from libksba\n"
 msgstr "libksbaから無効なS-式を取得しました\n"
 
@@ -7369,6 +7374,14 @@ msgid "converting S-expression failed: %s\n"
 msgstr "S式の変換に失敗しました: %s\n"
 
 #, c-format
+msgid "unknown hash algorithm '%s'\n"
+msgstr "不明なハッシュ・アルゴリズム'%s'\n"
+
+#, c-format
+msgid "gcry_md_open for algorithm %d failed: %s\n"
+msgstr "アルゴリズム%dのgcry_md_openが失敗: %s\n"
+
+#, c-format
 msgid "creating S-expression failed: %s\n"
 msgstr "S式の作成に失敗しました: %s\n"
 
@@ -8119,10 +8132,6 @@ msgid "failed to allocate OCSP context: %s\n"
 msgstr "OCSPコンテクストの確保に失敗しました: %s\n"
 
 #, c-format
-msgid "can't get authorityInfoAccess: %s\n"
-msgstr "authorityInfoAccessを取得できません: %s\n"
-
-#, c-format
 msgid "no default OCSP responder defined\n"
 msgstr "デフォルトOCSPレスポンダが定義されていません\n"
 
@@ -8691,6 +8700,9 @@ msgstr ""
 "形式: gpg-check-pattern [オプション] パターンファイル\n"
 "パターンファイルに対して標準入力のパスフレーズを確認する\n"
 
+#~ msgid " using certificate ID 0x%08lX\n"
+#~ msgstr " 証明書 ID 0x%08lXを用います\n"
+
 #~ msgid "male"
 #~ msgstr "男"
 
index 3ff40cf..3d3c745 100644 (file)
--- a/po/nb.po
+++ b/po/nb.po
@@ -101,6 +101,9 @@ msgstr "feil. Prøv igjen"
 #. the pinentry.  The %s is the actual error message, the
 #. two %d give the current and maximum number of tries.
 #. Do not translate the "SETERROR" keyword.
+#. TRANSLATORS: The string is appended to an error message in
+#. the pinentry.  The %s is the actual error message, the
+#. two %d give the current and maximum number of tries.
 #, c-format
 msgid "SETERROR %s (try %d of %d)"
 msgstr "SETERROR %s (forsøk %d av %d)"
@@ -3482,6 +3485,9 @@ msgstr "«%s» er et ugyldig fingeravtrykk\n"
 msgid "subkey \"%s\" not found\n"
 msgstr "fant ikke undernøkkel «%s»\n"
 
+msgid "AEAD: "
+msgstr ""
+
 msgid "Digest: "
 msgstr "Kontrollsum: "
 
@@ -6148,6 +6154,25 @@ msgstr ""
 "Syntaks: kbxutil [valg] [filer]\n"
 "Vis, eksporter eller importer Keybox-data\n"
 
+#. TRANSLATORS: Put a \x1f right before a colon.  This can be
+#. * used by pinentry to nicely align the names and values.  Keep
+#. * the %s at the start and end of the string.
+#, c-format
+msgid "%sNumber\1f: %s%%0AHolder\1f: %s%s"
+msgstr "%sNummer\\x1f: %s%%0AHolder\\x1f: %s%s"
+
+#. TRANSLATORS: This is the number of remaining attempts to
+#. * enter a PIN.  Use %%0A (double-percent,0A) for a linefeed.
+#, c-format
+msgid "Remaining attempts: %d"
+msgstr "Gjenstående forsøk: %d"
+
+msgid "||Please enter the PIN for the key to create qualified signatures."
+msgstr "||Skriv inn PIN for å la nøkkelen lage kvalifiserte signaturer."
+
+msgid "||Please enter the PIN for the standard keys."
+msgstr "||Skriv inn PIN-kode for standardnøkler."
+
 #, c-format
 msgid "RSA modulus missing or not of size %d bits\n"
 msgstr "RSA-modulus mangler eller er av annen størrelse enn %d bit\n"
@@ -6167,9 +6192,6 @@ msgstr "NullPIN er ikke blitt endret enda\n"
 msgid "|N|Please enter a new PIN for the standard keys."
 msgstr "|N|Skriv inn ny PIN-kode for standardnøkler."
 
-msgid "||Please enter the PIN for the standard keys."
-msgstr "||Skriv inn PIN-kode for standardnøkler."
-
 msgid "|NP|Please enter a new PIN Unblocking Code (PUK) for the standard keys."
 msgstr "|NP|Skriv inn ny PIN-opplåsingskode (PUK) for standardnøkler."
 
@@ -6179,9 +6201,6 @@ msgstr "|P|Skriv inn PIN-opplåsingskode (PUK) for standardnøkler."
 msgid "|N|Please enter a new PIN for the key to create qualified signatures."
 msgstr "|N|Skriv inn ny PIN for å la nøkkelen lage kvalifiserte signaturer."
 
-msgid "||Please enter the PIN for the key to create qualified signatures."
-msgstr "||Skriv inn PIN for å la nøkkelen lage kvalifiserte signaturer."
-
 msgid ""
 "|NP|Please enter a new PIN Unblocking Code (PUK) for the key to create "
 "qualified signatures."
@@ -6237,16 +6256,6 @@ msgid "%sNumber\1f: %s%%0AHolder\1f: %s%%0ACounter\1f: %lu%s"
 msgstr "%sNummer\\x1f: %s%%0AHolder\\x1f: %s%%0ATeller\\x1f: %lu%s"
 
 #, c-format
-msgid "%sNumber\1f: %s%%0AHolder\1f: %s%s"
-msgstr "%sNummer\\x1f: %s%%0AHolder\\x1f: %s%s"
-
-#. TRANSLATORS: This is the number of remaining attempts to
-#. * enter a PIN.  Use %%0A (double-percent,0A) for a linefeed.
-#, c-format
-msgid "Remaining attempts: %d"
-msgstr "Gjenstående forsøk: %d"
-
-#, c-format
 msgid "using default PIN as %s\n"
 msgstr "bruker forvalgt PIN som %s\n"
 
@@ -6492,6 +6501,10 @@ msgid "certificate policy not allowed"
 msgstr "sertifikatregelverk tillates ikke"
 
 #, c-format
+msgid "failed to get the fingerprint\n"
+msgstr "klarte ikke å hente fingeravtrykk\n"
+
+#, c-format
 msgid "looking up issuer at external location\n"
 msgstr "slår opp utsteder på ekstern plassering\n"
 
@@ -6500,6 +6513,10 @@ msgid "number of issuers matching: %d\n"
 msgstr "antall ustedere funnet: %d\n"
 
 #, c-format
+msgid "can't get authorityInfoAccess: %s\n"
+msgstr "klarte ikke å hente «authorityInfoAccess»: %s\n"
+
+#, c-format
 msgid "looking up issuer from the Dirmngr cache\n"
 msgstr "slår opp utsteder fra Dirmngr-hurtiglager\n"
 
@@ -7083,10 +7100,6 @@ msgid "error reading input: %s\n"
 msgstr "feil under lesing av inndata: %s\n"
 
 #, c-format
-msgid "failed to get the fingerprint\n"
-msgstr "klarte ikke å hente fingeravtrykk\n"
-
-#, c-format
 msgid "problem looking for existing certificate: %s\n"
 msgstr "klarte ikke å søke etter sertifikat: %s\n"
 
@@ -7176,9 +7189,10 @@ msgstr "Signatur fullført"
 msgid "[date not given]"
 msgstr "[dato ikke oppgitt]"
 
-#, c-format
-msgid " using certificate ID 0x%08lX\n"
-msgstr " ved bruk av sertifikat-ID 0x%08lX\n"
+#, fuzzy, c-format
+#| msgid "algorithm: %s"
+msgid "algorithm:"
+msgstr "algoritme: %s"
 
 #, c-format
 msgid ""
@@ -7504,14 +7518,6 @@ msgid "error getting data from cache file: %s\n"
 msgstr "feil under henting av data fra hurtiglager-fil: %s\n"
 
 #, c-format
-msgid "unknown hash algorithm '%s'\n"
-msgstr "«%s» er en ugyldig summeringsalgoritme\n"
-
-#, c-format
-msgid "gcry_md_open for algorithm %d failed: %s\n"
-msgstr "«gcry_md_open» for algoritme %d mislyktes: %s\n"
-
-#, c-format
 msgid "got an invalid S-expression from libksba\n"
 msgstr "fikk ugyldig S-uttrykk fra libksba\n"
 
@@ -7520,6 +7526,14 @@ msgid "converting S-expression failed: %s\n"
 msgstr "konvertering av S-uttrykk mislyktes: %s\n"
 
 #, c-format
+msgid "unknown hash algorithm '%s'\n"
+msgstr "«%s» er en ugyldig summeringsalgoritme\n"
+
+#, c-format
+msgid "gcry_md_open for algorithm %d failed: %s\n"
+msgstr "«gcry_md_open» for algoritme %d mislyktes: %s\n"
+
+#, c-format
 msgid "creating S-expression failed: %s\n"
 msgstr "oppretting av S-uttrykk mislyktes: %s\n"
 
@@ -8272,10 +8286,6 @@ msgid "failed to allocate OCSP context: %s\n"
 msgstr "klarte ikke å tildele OCSP-kontekst: %s\n"
 
 #, c-format
-msgid "can't get authorityInfoAccess: %s\n"
-msgstr "klarte ikke å hente «authorityInfoAccess»: %s\n"
-
-#, c-format
 msgid "no default OCSP responder defined\n"
 msgstr "ingen forvalgt OCSP-svartjeneste\n"
 
@@ -8850,6 +8860,9 @@ msgstr ""
 "Syntaks: gpg-check-pattern [valg] mønsterfil\n"
 "Kontroller passordfrase oppgitt på standard innkanal mot valgt mønsterfil\n"
 
+#~ msgid " using certificate ID 0x%08lX\n"
+#~ msgstr " ved bruk av sertifikat-ID 0x%08lX\n"
+
 #, fuzzy
 #~| msgid "option '%s' may not be used in %s mode\n"
 #~ msgid ""
index f116b0c..1aa6a9c 100644 (file)
--- a/po/pl.po
+++ b/po/pl.po
@@ -95,6 +95,9 @@ msgstr "nie pasują - proszę spróbować jeszcze raz"
 #. the pinentry.  The %s is the actual error message, the
 #. two %d give the current and maximum number of tries.
 #. Do not translate the "SETERROR" keyword.
+#. TRANSLATORS: The string is appended to an error message in
+#. the pinentry.  The %s is the actual error message, the
+#. two %d give the current and maximum number of tries.
 #, c-format
 msgid "SETERROR %s (try %d of %d)"
 msgstr "SETERROR %s (próba %d z %d)"
@@ -3500,6 +3503,9 @@ msgstr ",,%s'' nie jest właściwym odciskiem\n"
 msgid "subkey \"%s\" not found\n"
 msgstr "podklucz ,,%s'' nie został odnaleziony\n"
 
+msgid "AEAD: "
+msgstr ""
+
 msgid "Digest: "
 msgstr "Skrót: "
 
@@ -6249,6 +6255,26 @@ msgstr ""
 "Składnia: kbxutil [opcje] [pliki]\n"
 "Wypisywanie, eksport, import danych Keybox\n"
 
+#. TRANSLATORS: Put a \x1f right before a colon.  This can be
+#. * used by pinentry to nicely align the names and values.  Keep
+#. * the %s at the start and end of the string.
+#, c-format
+msgid "%sNumber\1f: %s%%0AHolder\1f: %s%s"
+msgstr "%sNumer\1f: %s%%0AWłaściciel\1f: %s%s"
+
+#. TRANSLATORS: This is the number of remaining attempts to
+#. * enter a PIN.  Use %%0A (double-percent,0A) for a linefeed.
+#, c-format
+msgid "Remaining attempts: %d"
+msgstr "Pozostało prób: %d"
+
+msgid "||Please enter the PIN for the key to create qualified signatures."
+msgstr ""
+"||Proszę wprowadzić PIN PIN dla klucza do tworzenia podpisów kwalifikowanych."
+
+msgid "||Please enter the PIN for the standard keys."
+msgstr "||Proszę wprowadzić PIN dla zwykłych kluczy."
+
 #, c-format
 msgid "RSA modulus missing or not of size %d bits\n"
 msgstr "reszta RSA brakująca lub o rozmiarze innym niż %d bity\n"
@@ -6268,9 +6294,6 @@ msgstr "NullPIN nie został jeszcze zmieniony\n"
 msgid "|N|Please enter a new PIN for the standard keys."
 msgstr "|N|Proszę wprowadzić nowy PIN dla zwykłych kluczy."
 
-msgid "||Please enter the PIN for the standard keys."
-msgstr "||Proszę wprowadzić PIN dla zwykłych kluczy."
-
 msgid "|NP|Please enter a new PIN Unblocking Code (PUK) for the standard keys."
 msgstr ""
 "|NP|Proszę wprowadzić nowy kod oblokowujący PIN (PUK) dla zwykłych kluczy."
@@ -6283,10 +6306,6 @@ msgstr ""
 "|N|Proszę wprowadzić nowy PIN dla klucza do tworzenia podpisów "
 "kwalifikowanych."
 
-msgid "||Please enter the PIN for the key to create qualified signatures."
-msgstr ""
-"||Proszę wprowadzić PIN PIN dla klucza do tworzenia podpisów kwalifikowanych."
-
 msgid ""
 "|NP|Please enter a new PIN Unblocking Code (PUK) for the key to create "
 "qualified signatures."
@@ -6345,16 +6364,6 @@ msgid "%sNumber\1f: %s%%0AHolder\1f: %s%%0ACounter\1f: %lu%s"
 msgstr "%sNumer\1f: %s%%0AWłaściciel\1f: %s%%0ALicznik\1f: %lu%s"
 
 #, c-format
-msgid "%sNumber\1f: %s%%0AHolder\1f: %s%s"
-msgstr "%sNumer\1f: %s%%0AWłaściciel\1f: %s%s"
-
-#. TRANSLATORS: This is the number of remaining attempts to
-#. * enter a PIN.  Use %%0A (double-percent,0A) for a linefeed.
-#, c-format
-msgid "Remaining attempts: %d"
-msgstr "Pozostało prób: %d"
-
-#, c-format
 msgid "using default PIN as %s\n"
 msgstr "użycie domyślnego PIN-u jako %s\n"
 
@@ -6607,6 +6616,10 @@ msgid "certificate policy not allowed"
 msgstr "polityka certyfikatu niedozwolona"
 
 #, c-format
+msgid "failed to get the fingerprint\n"
+msgstr "nie udało się pobrać odcisku\n"
+
+#, c-format
 msgid "looking up issuer at external location\n"
 msgstr "poszukiwanie wystawcy na zewnątrz\n"
 
@@ -6615,6 +6628,10 @@ msgid "number of issuers matching: %d\n"
 msgstr "liczba pasujących wystawców: %d\n"
 
 #, c-format
+msgid "can't get authorityInfoAccess: %s\n"
+msgstr "nie można uzyskać authorityInfoAccess: %s\n"
+
+#, c-format
 msgid "looking up issuer from the Dirmngr cache\n"
 msgstr "poszukiwanie wystawcy w pamięci podręcznej Dirmngr\n"
 
@@ -7198,10 +7215,6 @@ msgid "error reading input: %s\n"
 msgstr "błąd odczytu wejścia: %s\n"
 
 #, c-format
-msgid "failed to get the fingerprint\n"
-msgstr "nie udało się pobrać odcisku\n"
-
-#, c-format
 msgid "problem looking for existing certificate: %s\n"
 msgstr "problem odszukaniem istniejącego certyfikatu: %s\n"
 
@@ -7292,9 +7305,10 @@ msgstr "Podpisano w "
 msgid "[date not given]"
 msgstr "[nie podano daty]"
 
-#, c-format
-msgid " using certificate ID 0x%08lX\n"
-msgstr " przy użyciu certyfikatu o ID 0x%08lX\n"
+#, fuzzy, c-format
+#| msgid "algorithm: %s"
+msgid "algorithm:"
+msgstr "algorytm: %s"
 
 #, c-format
 msgid ""
@@ -7628,14 +7642,6 @@ msgid "error getting data from cache file: %s\n"
 msgstr "błąd pobierania danych z pliku pamięci podręcznej: %s\n"
 
 #, c-format
-msgid "unknown hash algorithm '%s'\n"
-msgstr "niewłaściwy algorytm skrótu ,,%s''\n"
-
-#, c-format
-msgid "gcry_md_open for algorithm %d failed: %s\n"
-msgstr "gcry_md_open dla algorytmu %d nie powiodło się: %s\n"
-
-#, c-format
 msgid "got an invalid S-expression from libksba\n"
 msgstr "odebrano błędne S-wyrażenie z libksba\n"
 
@@ -7644,6 +7650,14 @@ msgid "converting S-expression failed: %s\n"
 msgstr "konwersja S-wyrażenia nie powiodła się: %s\n"
 
 #, c-format
+msgid "unknown hash algorithm '%s'\n"
+msgstr "niewłaściwy algorytm skrótu ,,%s''\n"
+
+#, c-format
+msgid "gcry_md_open for algorithm %d failed: %s\n"
+msgstr "gcry_md_open dla algorytmu %d nie powiodło się: %s\n"
+
+#, c-format
 msgid "creating S-expression failed: %s\n"
 msgstr "tworzenie S-wyrażenia nie powiodło się: %s\n"
 
@@ -8404,10 +8418,6 @@ msgid "failed to allocate OCSP context: %s\n"
 msgstr "nie udało się przydzielić kontekstu OCSP: %s\n"
 
 #, c-format
-msgid "can't get authorityInfoAccess: %s\n"
-msgstr "nie można uzyskać authorityInfoAccess: %s\n"
-
-#, c-format
 msgid "no default OCSP responder defined\n"
 msgstr "nie zdefiniowano domyślnego respondera OCSP\n"
 
@@ -8983,6 +8993,9 @@ msgstr ""
 "Składnia: gpg-check-pattern [opcje] plik-wzorców\n"
 "Sprawdzanie hasła ze standardowego wejścia względem pliku wzorców\n"
 
+#~ msgid " using certificate ID 0x%08lX\n"
+#~ msgstr " przy użyciu certyfikatu o ID 0x%08lX\n"
+
 #, fuzzy
 #~| msgid "option '%s' may not be used in %s mode\n"
 #~ msgid ""
index d3d9d7f..b7f7d6f 100644 (file)
--- a/po/pt.po
+++ b/po/pt.po
@@ -96,6 +96,9 @@ msgstr ""
 #. the pinentry.  The %s is the actual error message, the
 #. two %d give the current and maximum number of tries.
 #. Do not translate the "SETERROR" keyword.
+#. TRANSLATORS: The string is appended to an error message in
+#. the pinentry.  The %s is the actual error message, the
+#. two %d give the current and maximum number of tries.
 #, c-format
 msgid "SETERROR %s (try %d of %d)"
 msgstr ""
@@ -3695,6 +3698,9 @@ msgstr "%s: versão de ficheiro inválida %d\n"
 msgid "subkey \"%s\" not found\n"
 msgstr "chave `%s' não encontrada: %s\n"
 
+msgid "AEAD: "
+msgstr ""
+
 msgid "Digest: "
 msgstr "'Digest': "
 
@@ -6413,6 +6419,26 @@ msgid ""
 "List, export, import Keybox data\n"
 msgstr "Uso: gpg [opções] [ficheiros] (-h para ajuda)"
 
+#. TRANSLATORS: Put a \x1f right before a colon.  This can be
+#. * used by pinentry to nicely align the names and values.  Keep
+#. * the %s at the start and end of the string.
+#, c-format
+msgid "%sNumber\1f: %s%%0AHolder\1f: %s%s"
+msgstr ""
+
+#. TRANSLATORS: This is the number of remaining attempts to
+#. * enter a PIN.  Use %%0A (double-percent,0A) for a linefeed.
+#, c-format
+msgid "Remaining attempts: %d"
+msgstr ""
+
+msgid "||Please enter the PIN for the key to create qualified signatures."
+msgstr ""
+
+#, fuzzy
+msgid "||Please enter the PIN for the standard keys."
+msgstr "muda a frase secreta"
+
 #, c-format
 msgid "RSA modulus missing or not of size %d bits\n"
 msgstr ""
@@ -6434,10 +6460,6 @@ msgid "|N|Please enter a new PIN for the standard keys."
 msgstr "muda a frase secreta"
 
 #, fuzzy
-msgid "||Please enter the PIN for the standard keys."
-msgstr "muda a frase secreta"
-
-#, fuzzy
 msgid "|NP|Please enter a new PIN Unblocking Code (PUK) for the standard keys."
 msgstr "motivo da revocação: "
 
@@ -6448,9 +6470,6 @@ msgstr "motivo da revocação: "
 msgid "|N|Please enter a new PIN for the key to create qualified signatures."
 msgstr ""
 
-msgid "||Please enter the PIN for the key to create qualified signatures."
-msgstr ""
-
 msgid ""
 "|NP|Please enter a new PIN Unblocking Code (PUK) for the key to create "
 "qualified signatures."
@@ -6506,16 +6525,6 @@ msgid "%sNumber\1f: %s%%0AHolder\1f: %s%%0ACounter\1f: %lu%s"
 msgstr ""
 
 #, c-format
-msgid "%sNumber\1f: %s%%0AHolder\1f: %s%s"
-msgstr ""
-
-#. TRANSLATORS: This is the number of remaining attempts to
-#. * enter a PIN.  Use %%0A (double-percent,0A) for a linefeed.
-#, c-format
-msgid "Remaining attempts: %d"
-msgstr ""
-
-#, c-format
 msgid "using default PIN as %s\n"
 msgstr ""
 
@@ -6771,6 +6780,10 @@ msgstr "a escrever chave privada para `%s'\n"
 msgid "certificate policy not allowed"
 msgstr "a escrever chave privada para `%s'\n"
 
+#, fuzzy, c-format
+msgid "failed to get the fingerprint\n"
+msgstr "falha ao inicializar a base de dados de confiança: %s\n"
+
 #, c-format
 msgid "looking up issuer at external location\n"
 msgstr ""
@@ -6779,6 +6792,11 @@ msgstr ""
 msgid "number of issuers matching: %d\n"
 msgstr ""
 
+#, fuzzy, c-format
+#| msgid "%s: can't access: %s\n"
+msgid "can't get authorityInfoAccess: %s\n"
+msgstr "%s: impossível aceder: %s\n"
+
 #, c-format
 msgid "looking up issuer from the Dirmngr cache\n"
 msgstr ""
@@ -7389,10 +7407,6 @@ msgstr "erro na criação da frase secreta: %s\n"
 msgid "error reading input: %s\n"
 msgstr "erro na leitura de `%s': %s\n"
 
-#, fuzzy, c-format
-msgid "failed to get the fingerprint\n"
-msgstr "falha ao inicializar a base de dados de confiança: %s\n"
-
 #, c-format
 msgid "problem looking for existing certificate: %s\n"
 msgstr ""
@@ -7472,8 +7486,8 @@ msgid "[date not given]"
 msgstr ""
 
 #, fuzzy, c-format
-msgid " using certificate ID 0x%08lX\n"
-msgstr "erro na criação da frase secreta: %s\n"
+msgid "algorithm:"
+msgstr "armadura: %s\n"
 
 #, c-format
 msgid ""
@@ -7802,6 +7816,14 @@ msgstr ""
 msgid "error getting data from cache file: %s\n"
 msgstr "erro na criação da frase secreta: %s\n"
 
+#, c-format
+msgid "got an invalid S-expression from libksba\n"
+msgstr ""
+
+#, fuzzy, c-format
+msgid "converting S-expression failed: %s\n"
+msgstr "impossível abrir %s: %s\n"
+
 #, fuzzy, c-format
 #| msgid "invalid hash algorithm `%s'\n"
 msgid "unknown hash algorithm '%s'\n"
@@ -7811,14 +7833,6 @@ msgstr "algoritmo de dispersão inválido `%s'\n"
 msgid "gcry_md_open for algorithm %d failed: %s\n"
 msgstr ""
 
-#, c-format
-msgid "got an invalid S-expression from libksba\n"
-msgstr ""
-
-#, fuzzy, c-format
-msgid "converting S-expression failed: %s\n"
-msgstr "impossível abrir %s: %s\n"
-
 #, fuzzy, c-format
 msgid "creating S-expression failed: %s\n"
 msgstr "remoção do bloco de chave falhou: %s\n"
@@ -8602,11 +8616,6 @@ msgstr "gerar um certificado de revogação"
 msgid "failed to allocate OCSP context: %s\n"
 msgstr "falha ao inicializar a base de dados de confiança: %s\n"
 
-#, fuzzy, c-format
-#| msgid "%s: can't access: %s\n"
-msgid "can't get authorityInfoAccess: %s\n"
-msgstr "%s: impossível aceder: %s\n"
-
 #, c-format
 msgid "no default OCSP responder defined\n"
 msgstr ""
@@ -9202,6 +9211,10 @@ msgid ""
 msgstr ""
 
 #, fuzzy
+#~ msgid " using certificate ID 0x%08lX\n"
+#~ msgstr "erro na criação da frase secreta: %s\n"
+
+#, fuzzy
 #~| msgid "you may not use %s while in %s mode\n"
 #~ msgid ""
 #~ "keyserver option \"honor-keyserver-url\" may not be used in Tor mode\n"
index 575cde3..54ed771 100644 (file)
--- a/po/ro.po
+++ b/po/ro.po
@@ -100,6 +100,9 @@ msgstr ""
 #. the pinentry.  The %s is the actual error message, the
 #. two %d give the current and maximum number of tries.
 #. Do not translate the "SETERROR" keyword.
+#. TRANSLATORS: The string is appended to an error message in
+#. the pinentry.  The %s is the actual error message, the
+#. two %d give the current and maximum number of tries.
 #, c-format
 msgid "SETERROR %s (try %d of %d)"
 msgstr ""
@@ -3736,6 +3739,9 @@ msgstr "amprentă invalidă"
 msgid "subkey \"%s\" not found\n"
 msgstr "cheia \"%s\" nu a fost găsită: %s\n"
 
+msgid "AEAD: "
+msgstr ""
+
 msgid "Digest: "
 msgstr "Rezumat: "
 
@@ -6502,6 +6508,26 @@ msgid ""
 "List, export, import Keybox data\n"
 msgstr "Folosire: gpg [opţiuni] [fişiere] (-h pentru ajutor)"
 
+#. TRANSLATORS: Put a \x1f right before a colon.  This can be
+#. * used by pinentry to nicely align the names and values.  Keep
+#. * the %s at the start and end of the string.
+#, c-format
+msgid "%sNumber\1f: %s%%0AHolder\1f: %s%s"
+msgstr ""
+
+#. TRANSLATORS: This is the number of remaining attempts to
+#. * enter a PIN.  Use %%0A (double-percent,0A) for a linefeed.
+#, c-format
+msgid "Remaining attempts: %d"
+msgstr ""
+
+msgid "||Please enter the PIN for the key to create qualified signatures."
+msgstr ""
+
+#, fuzzy
+msgid "||Please enter the PIN for the standard keys."
+msgstr "||Vă rugăm introduceţi PIN%%0A[semnături făcute: %lu]"
+
 #, c-format
 msgid "RSA modulus missing or not of size %d bits\n"
 msgstr "modulus-ul RSA lipseşte sau nu are %d biţi\n"
@@ -6523,10 +6549,6 @@ msgid "|N|Please enter a new PIN for the standard keys."
 msgstr "||Vă rugăm introduceţi PIN%%0A[semnături făcute: %lu]"
 
 #, fuzzy
-msgid "||Please enter the PIN for the standard keys."
-msgstr "||Vă rugăm introduceţi PIN%%0A[semnături făcute: %lu]"
-
-#, fuzzy
 msgid "|NP|Please enter a new PIN Unblocking Code (PUK) for the standard keys."
 msgstr "||Vă rugăm introduceţi PIN%%0A[semnături făcute: %lu]"
 
@@ -6537,9 +6559,6 @@ msgstr "||Vă rugăm introduceţi PIN%%0A[semnături făcute: %lu]"
 msgid "|N|Please enter a new PIN for the key to create qualified signatures."
 msgstr ""
 
-msgid "||Please enter the PIN for the key to create qualified signatures."
-msgstr ""
-
 msgid ""
 "|NP|Please enter a new PIN Unblocking Code (PUK) for the key to create "
 "qualified signatures."
@@ -6595,16 +6614,6 @@ msgid "%sNumber\1f: %s%%0AHolder\1f: %s%%0ACounter\1f: %lu%s"
 msgstr ""
 
 #, c-format
-msgid "%sNumber\1f: %s%%0AHolder\1f: %s%s"
-msgstr ""
-
-#. TRANSLATORS: This is the number of remaining attempts to
-#. * enter a PIN.  Use %%0A (double-percent,0A) for a linefeed.
-#, c-format
-msgid "Remaining attempts: %d"
-msgstr ""
-
-#, c-format
 msgid "using default PIN as %s\n"
 msgstr ""
 
@@ -6866,6 +6875,10 @@ msgstr "exportul cheilor secrete nu este permis\n"
 msgid "certificate policy not allowed"
 msgstr "exportul cheilor secrete nu este permis\n"
 
+#, fuzzy, c-format
+msgid "failed to get the fingerprint\n"
+msgstr "am eşuat să stochez amprenta: %s\n"
+
 #, c-format
 msgid "looking up issuer at external location\n"
 msgstr ""
@@ -6874,6 +6887,11 @@ msgstr ""
 msgid "number of issuers matching: %d\n"
 msgstr ""
 
+#, fuzzy, c-format
+#| msgid "%s: can't access: %s\n"
+msgid "can't get authorityInfoAccess: %s\n"
+msgstr "%s: nu pot accesa: %s\n"
+
 #, c-format
 msgid "looking up issuer from the Dirmngr cache\n"
 msgstr ""
@@ -7486,10 +7504,6 @@ msgstr "eroare la obţinerea numărului serial: %s\n"
 msgid "error reading input: %s\n"
 msgstr "eroare la citire `%s': %s\n"
 
-#, fuzzy, c-format
-msgid "failed to get the fingerprint\n"
-msgstr "am eşuat să stochez amprenta: %s\n"
-
 #, c-format
 msgid "problem looking for existing certificate: %s\n"
 msgstr ""
@@ -7569,8 +7583,8 @@ msgid "[date not given]"
 msgstr ""
 
 #, fuzzy, c-format
-msgid " using certificate ID 0x%08lX\n"
-msgstr "eroare la obţinerea numărului serial: %s\n"
+msgid "algorithm:"
+msgstr "validitate: %s"
 
 #, c-format
 msgid ""
@@ -7904,15 +7918,6 @@ msgid "error getting data from cache file: %s\n"
 msgstr "eroare la obţinere noului PIN: %s\n"
 
 #, fuzzy, c-format
-#| msgid "invalid hash algorithm `%s'\n"
-msgid "unknown hash algorithm '%s'\n"
-msgstr "algoritm hash invalid `%s'\n"
-
-#, c-format
-msgid "gcry_md_open for algorithm %d failed: %s\n"
-msgstr ""
-
-#, fuzzy, c-format
 #| msgid "invalid response from agent\n"
 msgid "got an invalid S-expression from libksba\n"
 msgstr "răspuns invalid de la agent\n"
@@ -7922,6 +7927,15 @@ msgid "converting S-expression failed: %s\n"
 msgstr "nu pot deschide fişierul: %s\n"
 
 #, fuzzy, c-format
+#| msgid "invalid hash algorithm `%s'\n"
+msgid "unknown hash algorithm '%s'\n"
+msgstr "algoritm hash invalid `%s'\n"
+
+#, c-format
+msgid "gcry_md_open for algorithm %d failed: %s\n"
+msgstr ""
+
+#, fuzzy, c-format
 msgid "creating S-expression failed: %s\n"
 msgstr "citirea cheii publice a eşuat: %s\n"
 
@@ -8724,11 +8738,6 @@ msgstr "generează un certificat de revocare"
 msgid "failed to allocate OCSP context: %s\n"
 msgstr "am eşuat să stochez cheia: %s\n"
 
-#, fuzzy, c-format
-#| msgid "%s: can't access: %s\n"
-msgid "can't get authorityInfoAccess: %s\n"
-msgstr "%s: nu pot accesa: %s\n"
-
 #, c-format
 msgid "no default OCSP responder defined\n"
 msgstr ""
@@ -9327,6 +9336,10 @@ msgid ""
 msgstr ""
 
 #, fuzzy
+#~ msgid " using certificate ID 0x%08lX\n"
+#~ msgstr "eroare la obţinerea numărului serial: %s\n"
+
+#, fuzzy
 #~| msgid "you may not use %s while in %s mode\n"
 #~ msgid ""
 #~ "keyserver option \"honor-keyserver-url\" may not be used in Tor mode\n"
index c56c60c..d48299f 100644 (file)
--- a/po/ru.po
+++ b/po/ru.po
@@ -98,6 +98,9 @@ msgstr "не подходит - попробуйте еще раз"
 #. the pinentry.  The %s is the actual error message, the
 #. two %d give the current and maximum number of tries.
 #. Do not translate the "SETERROR" keyword.
+#. TRANSLATORS: The string is appended to an error message in
+#. the pinentry.  The %s is the actual error message, the
+#. two %d give the current and maximum number of tries.
 #, c-format
 msgid "SETERROR %s (try %d of %d)"
 msgstr "SETERROR %s (попытка %d из %d)"
@@ -3495,6 +3498,9 @@ msgstr "\"%s\" - не правильный отпечаток\n"
 msgid "subkey \"%s\" not found\n"
 msgstr "подключ \"%s\" не найден\n"
 
+msgid "AEAD: "
+msgstr ""
+
 msgid "Digest: "
 msgstr "Хеш: "
 
@@ -6213,6 +6219,25 @@ msgstr ""
 "Синтаксис: kbxutil [параметры] [файлы]\n"
 "Просмотр, экспорт, импорт данных щита с ключами\n"
 
+#. TRANSLATORS: Put a \x1f right before a colon.  This can be
+#. * used by pinentry to nicely align the names and values.  Keep
+#. * the %s at the start and end of the string.
+#, c-format
+msgid "%sNumber\1f: %s%%0AHolder\1f: %s%s"
+msgstr "%sНомер\1f: %s%%0AДержатель\1f: %s%s"
+
+#. TRANSLATORS: This is the number of remaining attempts to
+#. * enter a PIN.  Use %%0A (double-percent,0A) for a linefeed.
+#, c-format
+msgid "Remaining attempts: %d"
+msgstr "Осталось попыток: %d"
+
+msgid "||Please enter the PIN for the key to create qualified signatures."
+msgstr "||Введите PIN ключа для создания квалифицированных подписей."
+
+msgid "||Please enter the PIN for the standard keys."
+msgstr "|A|Введите PIN для стандартных ключей."
+
 #, c-format
 msgid "RSA modulus missing or not of size %d bits\n"
 msgstr "Модули RSA пропущены, или их размер не равен %d бит\n"
@@ -6232,9 +6257,6 @@ msgstr "пустой PIN до сих пор не изменен\n"
 msgid "|N|Please enter a new PIN for the standard keys."
 msgstr "|A|Введите новый PIN для стандартных ключей."
 
-msgid "||Please enter the PIN for the standard keys."
-msgstr "|A|Введите PIN для стандартных ключей."
-
 msgid "|NP|Please enter a new PIN Unblocking Code (PUK) for the standard keys."
 msgstr "|NP|Введите новый код разблокировки PIN (PUK) для стандартных ключей."
 
@@ -6244,9 +6266,6 @@ msgstr "|P|Введите код разблокировки PIN (PUK) для с
 msgid "|N|Please enter a new PIN for the key to create qualified signatures."
 msgstr "|N|Введите новый PIN ключа для создания квалифицированных подписей."
 
-msgid "||Please enter the PIN for the key to create qualified signatures."
-msgstr "||Введите PIN ключа для создания квалифицированных подписей."
-
 msgid ""
 "|NP|Please enter a new PIN Unblocking Code (PUK) for the key to create "
 "qualified signatures."
@@ -6305,16 +6324,6 @@ msgid "%sNumber\1f: %s%%0AHolder\1f: %s%%0ACounter\1f: %lu%s"
 msgstr "%sНомер\1f: %s%%0AДержатель\1f: %s%%0AСчетчик\1f: %lu%s"
 
 #, c-format
-msgid "%sNumber\1f: %s%%0AHolder\1f: %s%s"
-msgstr "%sНомер\1f: %s%%0AДержатель\1f: %s%s"
-
-#. TRANSLATORS: This is the number of remaining attempts to
-#. * enter a PIN.  Use %%0A (double-percent,0A) for a linefeed.
-#, c-format
-msgid "Remaining attempts: %d"
-msgstr "Осталось попыток: %d"
-
-#, c-format
 msgid "using default PIN as %s\n"
 msgstr "основной PIN применяется как %s\n"
 
@@ -6567,6 +6576,10 @@ msgid "certificate policy not allowed"
 msgstr "правила сертификата недопустимы"
 
 #, c-format
+msgid "failed to get the fingerprint\n"
+msgstr "сбой получения отпечатка\n"
+
+#, c-format
 msgid "looking up issuer at external location\n"
 msgstr "внешний поиск издателя\n"
 
@@ -6575,6 +6588,10 @@ msgid "number of issuers matching: %d\n"
 msgstr "число соответствующих издателей: %d\n"
 
 #, c-format
+msgid "can't get authorityInfoAccess: %s\n"
+msgstr "не могу получить authorityInfoAccess: %s\n"
+
+#, c-format
 msgid "looking up issuer from the Dirmngr cache\n"
 msgstr "поиск издателя в буфере Dirmngr\n"
 
@@ -7158,10 +7175,6 @@ msgid "error reading input: %s\n"
 msgstr "ошибка чтения ввода: %s\n"
 
 #, c-format
-msgid "failed to get the fingerprint\n"
-msgstr "сбой получения отпечатка\n"
-
-#, c-format
 msgid "problem looking for existing certificate: %s\n"
 msgstr "проблема поиска существующего сертификата: %s\n"
 
@@ -7253,9 +7266,10 @@ msgstr "Подпись сделана "
 msgid "[date not given]"
 msgstr "[дата не указана]"
 
-#, c-format
-msgid " using certificate ID 0x%08lX\n"
-msgstr " с помощью сертификата с идентификатором 0x%08lX\n"
+#, fuzzy, c-format
+#| msgid "algorithm: %s"
+msgid "algorithm:"
+msgstr "алгоритм: %s"
 
 #, c-format
 msgid ""
@@ -7591,14 +7605,6 @@ msgid "error getting data from cache file: %s\n"
 msgstr "ошибка получения данных из файла буфера: %s\n"
 
 #, c-format
-msgid "unknown hash algorithm '%s'\n"
-msgstr "недопустимая хеш-функция '%s'\n"
-
-#, c-format
-msgid "gcry_md_open for algorithm %d failed: %s\n"
-msgstr "сбой gcry_md_open для алгоритма %d: %s\n"
-
-#, c-format
 msgid "got an invalid S-expression from libksba\n"
 msgstr "из libksba получено недопустимое S-выражение\n"
 
@@ -7607,6 +7613,14 @@ msgid "converting S-expression failed: %s\n"
 msgstr "сбой преобразования S-выражения: %s\n"
 
 #, c-format
+msgid "unknown hash algorithm '%s'\n"
+msgstr "недопустимая хеш-функция '%s'\n"
+
+#, c-format
+msgid "gcry_md_open for algorithm %d failed: %s\n"
+msgstr "сбой gcry_md_open для алгоритма %d: %s\n"
+
+#, c-format
 msgid "creating S-expression failed: %s\n"
 msgstr "сбой создания S-выражения: %s\n"
 
@@ -8382,10 +8396,6 @@ msgid "failed to allocate OCSP context: %s\n"
 msgstr "сбой при выделении памяти под контекст OCSP: %s\n"
 
 #, c-format
-msgid "can't get authorityInfoAccess: %s\n"
-msgstr "не могу получить authorityInfoAccess: %s\n"
-
-#, c-format
 msgid "no default OCSP responder defined\n"
 msgstr "не определен основной ответчик OCSP\n"
 
@@ -8962,6 +8972,9 @@ msgstr ""
 "Синтаксис: gpg-check-pattern [параметры] файл_образцов\n"
 "Проверить фразу-пароль, поступающую из stdin, по файлу образцов\n"
 
+#~ msgid " using certificate ID 0x%08lX\n"
+#~ msgstr " с помощью сертификата с идентификатором 0x%08lX\n"
+
 #, fuzzy
 #~| msgid "option '%s' may not be used in %s mode\n"
 #~ msgid ""
index 045c745..768f796 100644 (file)
--- a/po/sk.po
+++ b/po/sk.po
@@ -96,6 +96,9 @@ msgstr ""
 #. the pinentry.  The %s is the actual error message, the
 #. two %d give the current and maximum number of tries.
 #. Do not translate the "SETERROR" keyword.
+#. TRANSLATORS: The string is appended to an error message in
+#. the pinentry.  The %s is the actual error message, the
+#. two %d give the current and maximum number of tries.
 #, c-format
 msgid "SETERROR %s (try %d of %d)"
 msgstr ""
@@ -3712,6 +3715,9 @@ msgstr "chyba: neplatný odtlačok\n"
 msgid "subkey \"%s\" not found\n"
 msgstr "kľúč `%s' nebol nájdený: %s\n"
 
+msgid "AEAD: "
+msgstr ""
+
 msgid "Digest: "
 msgstr "Digest: "
 
@@ -6446,6 +6452,26 @@ msgid ""
 "List, export, import Keybox data\n"
 msgstr "Použitie: gpg [možnosti] [súbory] (-h pre pomoc)"
 
+#. TRANSLATORS: Put a \x1f right before a colon.  This can be
+#. * used by pinentry to nicely align the names and values.  Keep
+#. * the %s at the start and end of the string.
+#, c-format
+msgid "%sNumber\1f: %s%%0AHolder\1f: %s%s"
+msgstr ""
+
+#. TRANSLATORS: This is the number of remaining attempts to
+#. * enter a PIN.  Use %%0A (double-percent,0A) for a linefeed.
+#, c-format
+msgid "Remaining attempts: %d"
+msgstr ""
+
+msgid "||Please enter the PIN for the key to create qualified signatures."
+msgstr ""
+
+#, fuzzy
+msgid "||Please enter the PIN for the standard keys."
+msgstr "zmeniť heslo"
+
 #, c-format
 msgid "RSA modulus missing or not of size %d bits\n"
 msgstr ""
@@ -6467,10 +6493,6 @@ msgid "|N|Please enter a new PIN for the standard keys."
 msgstr "zmeniť heslo"
 
 #, fuzzy
-msgid "||Please enter the PIN for the standard keys."
-msgstr "zmeniť heslo"
-
-#, fuzzy
 msgid "|NP|Please enter a new PIN Unblocking Code (PUK) for the standard keys."
 msgstr "Prosím výberte dôvod na revokáciu:\n"
 
@@ -6481,9 +6503,6 @@ msgstr "Prosím výberte dôvod na revokáciu:\n"
 msgid "|N|Please enter a new PIN for the key to create qualified signatures."
 msgstr ""
 
-msgid "||Please enter the PIN for the key to create qualified signatures."
-msgstr ""
-
 msgid ""
 "|NP|Please enter a new PIN Unblocking Code (PUK) for the key to create "
 "qualified signatures."
@@ -6539,16 +6558,6 @@ msgid "%sNumber\1f: %s%%0AHolder\1f: %s%%0ACounter\1f: %lu%s"
 msgstr ""
 
 #, c-format
-msgid "%sNumber\1f: %s%%0AHolder\1f: %s%s"
-msgstr ""
-
-#. TRANSLATORS: This is the number of remaining attempts to
-#. * enter a PIN.  Use %%0A (double-percent,0A) for a linefeed.
-#, c-format
-msgid "Remaining attempts: %d"
-msgstr ""
-
-#, c-format
 msgid "using default PIN as %s\n"
 msgstr ""
 
@@ -6804,6 +6813,10 @@ msgstr "zapisujem tajný kľúč do `%s'\n"
 msgid "certificate policy not allowed"
 msgstr "zapisujem tajný kľúč do `%s'\n"
 
+#, fuzzy, c-format
+msgid "failed to get the fingerprint\n"
+msgstr "nemôžem inicializovať databázu dôvery: %s\n"
+
 #, c-format
 msgid "looking up issuer at external location\n"
 msgstr ""
@@ -6812,6 +6825,11 @@ msgstr ""
 msgid "number of issuers matching: %d\n"
 msgstr ""
 
+#, fuzzy, c-format
+#| msgid "%s: can't access: %s\n"
+msgid "can't get authorityInfoAccess: %s\n"
+msgstr "%s: nemôžem pristupovať k: %s\n"
+
 #, c-format
 msgid "looking up issuer from the Dirmngr cache\n"
 msgstr ""
@@ -7422,10 +7440,6 @@ msgstr "chyba pri vytváraní hesla: %s\n"
 msgid "error reading input: %s\n"
 msgstr "chyba pri čítaní `%s': %s\n"
 
-#, fuzzy, c-format
-msgid "failed to get the fingerprint\n"
-msgstr "nemôžem inicializovať databázu dôvery: %s\n"
-
 #, c-format
 msgid "problem looking for existing certificate: %s\n"
 msgstr ""
@@ -7505,8 +7519,8 @@ msgid "[date not given]"
 msgstr ""
 
 #, fuzzy, c-format
-msgid " using certificate ID 0x%08lX\n"
-msgstr "chyba pri vytváraní hesla: %s\n"
+msgid "algorithm:"
+msgstr "ASCII kódovanie: %s\n"
 
 #, c-format
 msgid ""
@@ -7836,15 +7850,6 @@ msgid "error getting data from cache file: %s\n"
 msgstr "chyba pri vytváraní hesla: %s\n"
 
 #, fuzzy, c-format
-#| msgid "invalid hash algorithm `%s'\n"
-msgid "unknown hash algorithm '%s'\n"
-msgstr "neplatný hashovací algoritmus `%s'\n"
-
-#, c-format
-msgid "gcry_md_open for algorithm %d failed: %s\n"
-msgstr ""
-
-#, fuzzy, c-format
 #| msgid "invalid response from agent\n"
 msgid "got an invalid S-expression from libksba\n"
 msgstr "neplatná reakcia od agenta\n"
@@ -7854,6 +7859,15 @@ msgid "converting S-expression failed: %s\n"
 msgstr "nemožno otvoriť súbor: %s\n"
 
 #, fuzzy, c-format
+#| msgid "invalid hash algorithm `%s'\n"
+msgid "unknown hash algorithm '%s'\n"
+msgstr "neplatný hashovací algoritmus `%s'\n"
+
+#, c-format
+msgid "gcry_md_open for algorithm %d failed: %s\n"
+msgstr ""
+
+#, fuzzy, c-format
 msgid "creating S-expression failed: %s\n"
 msgstr "zmazanie bloku kľúča sa nepodarilo:  %s\n"
 
@@ -8635,11 +8649,6 @@ msgstr "vytvoriť revokačný certifikát"
 msgid "failed to allocate OCSP context: %s\n"
 msgstr "nemôžem inicializovať databázu dôvery: %s\n"
 
-#, fuzzy, c-format
-#| msgid "%s: can't access: %s\n"
-msgid "can't get authorityInfoAccess: %s\n"
-msgstr "%s: nemôžem pristupovať k: %s\n"
-
 #, c-format
 msgid "no default OCSP responder defined\n"
 msgstr ""
@@ -9234,6 +9243,10 @@ msgid ""
 msgstr ""
 
 #, fuzzy
+#~ msgid " using certificate ID 0x%08lX\n"
+#~ msgstr "chyba pri vytváraní hesla: %s\n"
+
+#, fuzzy
 #~| msgid "you may not use %s while in %s mode\n"
 #~ msgid ""
 #~ "keyserver option \"honor-keyserver-url\" may not be used in Tor mode\n"
index 8632420..053b871 100644 (file)
--- a/po/sv.po
+++ b/po/sv.po
@@ -125,6 +125,9 @@ msgstr "stämmer inte överens - försök igen"
 #. the pinentry.  The %s is the actual error message, the
 #. two %d give the current and maximum number of tries.
 #. Do not translate the "SETERROR" keyword.
+#. TRANSLATORS: The string is appended to an error message in
+#. the pinentry.  The %s is the actual error message, the
+#. two %d give the current and maximum number of tries.
 #, c-format
 msgid "SETERROR %s (try %d of %d)"
 msgstr "SETERROR %s (försök %d av %d)"
@@ -3833,6 +3836,9 @@ msgstr "ogiltigt fingeravtryck"
 msgid "subkey \"%s\" not found\n"
 msgstr "nyckeln \"%s\" hittades inte: %s\n"
 
+msgid "AEAD: "
+msgstr ""
+
 msgid "Digest: "
 msgstr "Sammandrag: "
 
@@ -6678,6 +6684,25 @@ msgstr ""
 "Syntax: kbxutil [flaggor] [filer]\n"
 "lista, exportera, importera nyckelskåpsdata\n"
 
+#. TRANSLATORS: Put a \x1f right before a colon.  This can be
+#. * used by pinentry to nicely align the names and values.  Keep
+#. * the %s at the start and end of the string.
+#, c-format
+msgid "%sNumber\1f: %s%%0AHolder\1f: %s%s"
+msgstr ""
+
+#. TRANSLATORS: This is the number of remaining attempts to
+#. * enter a PIN.  Use %%0A (double-percent,0A) for a linefeed.
+#, c-format
+msgid "Remaining attempts: %d"
+msgstr ""
+
+msgid "||Please enter the PIN for the key to create qualified signatures."
+msgstr "||Ange PIN-koden för nyckeln att skapa kvalificerade signaturer med."
+
+msgid "||Please enter the PIN for the standard keys."
+msgstr "||Ange PIN-koden för standardnycklarna."
+
 #, c-format
 msgid "RSA modulus missing or not of size %d bits\n"
 msgstr "RSA modulus saknas eller är inte %d bitar stor\n"
@@ -6697,9 +6722,6 @@ msgstr "NullPIN har ännu inte ändrats\n"
 msgid "|N|Please enter a new PIN for the standard keys."
 msgstr "|N|Ange en ny PIN-kod för standardnycklarna."
 
-msgid "||Please enter the PIN for the standard keys."
-msgstr "||Ange PIN-koden för standardnycklarna."
-
 msgid "|NP|Please enter a new PIN Unblocking Code (PUK) for the standard keys."
 msgstr "|NP|Ange en ny upplåsningskod (PUK-kod) för standardnycklarna."
 
@@ -6710,9 +6732,6 @@ msgid "|N|Please enter a new PIN for the key to create qualified signatures."
 msgstr ""
 "|N|Ange en ny PIN-kod för nyckeln att skapa kvalificerade signaturer med."
 
-msgid "||Please enter the PIN for the key to create qualified signatures."
-msgstr "||Ange PIN-koden för nyckeln att skapa kvalificerade signaturer med."
-
 msgid ""
 "|NP|Please enter a new PIN Unblocking Code (PUK) for the key to create "
 "qualified signatures."
@@ -6772,16 +6791,6 @@ msgid "%sNumber\1f: %s%%0AHolder\1f: %s%%0ACounter\1f: %lu%s"
 msgstr ""
 
 #, c-format
-msgid "%sNumber\1f: %s%%0AHolder\1f: %s%s"
-msgstr ""
-
-#. TRANSLATORS: This is the number of remaining attempts to
-#. * enter a PIN.  Use %%0A (double-percent,0A) for a linefeed.
-#, c-format
-msgid "Remaining attempts: %d"
-msgstr ""
-
-#, c-format
 msgid "using default PIN as %s\n"
 msgstr "använder standard-PIN som %s\n"
 
@@ -7054,6 +7063,10 @@ msgid "certificate policy not allowed"
 msgstr "certifikatpolicy tillåts inte"
 
 #, c-format
+msgid "failed to get the fingerprint\n"
+msgstr "misslyckades med att få fingeravtrycket\n"
+
+#, c-format
 msgid "looking up issuer at external location\n"
 msgstr "slår upp utfärdare på extern plats\n"
 
@@ -7061,6 +7074,11 @@ msgstr "slår upp utfärdare på extern plats\n"
 msgid "number of issuers matching: %d\n"
 msgstr "antal utfärdare som matchar: %d\n"
 
+#, fuzzy, c-format
+#| msgid "can't access `%s': %s\n"
+msgid "can't get authorityInfoAccess: %s\n"
+msgstr "kan inte komma åt \"%s\": %s\n"
+
 #, c-format
 msgid "looking up issuer from the Dirmngr cache\n"
 msgstr "slår upp utfärdare från Dirmngr-cachen\n"
@@ -7687,10 +7705,6 @@ msgid "error reading input: %s\n"
 msgstr "fel vid läsning av indata: %s\n"
 
 #, c-format
-msgid "failed to get the fingerprint\n"
-msgstr "misslyckades med att få fingeravtrycket\n"
-
-#, c-format
 msgid "problem looking for existing certificate: %s\n"
 msgstr "problem vid sökandet efter befintligt certifikat: %s\n"
 
@@ -7783,9 +7797,10 @@ msgstr "Signatur gjord "
 msgid "[date not given]"
 msgstr "[datum inte angivet]"
 
-#, c-format
-msgid " using certificate ID 0x%08lX\n"
-msgstr " använder certifikat-id 0x%08lX\n"
+#, fuzzy, c-format
+#| msgid "algorithm: %s"
+msgid "algorithm:"
+msgstr "algoritm: %s"
 
 #, c-format
 msgid ""
@@ -8157,15 +8172,6 @@ msgstr ""
 msgid "error getting data from cache file: %s\n"
 msgstr "fel vid hämtning av lagrade flaggor: %s\n"
 
-#, fuzzy, c-format
-#| msgid "invalid hash algorithm `%s'\n"
-msgid "unknown hash algorithm '%s'\n"
-msgstr "ogiltig kontrollsummealgoritm \"%s\"\n"
-
-#, c-format
-msgid "gcry_md_open for algorithm %d failed: %s\n"
-msgstr ""
-
 #, c-format
 msgid "got an invalid S-expression from libksba\n"
 msgstr ""
@@ -8176,6 +8182,15 @@ msgid "converting S-expression failed: %s\n"
 msgstr "iconv_open misslyckades: %s\n"
 
 #, fuzzy, c-format
+#| msgid "invalid hash algorithm `%s'\n"
+msgid "unknown hash algorithm '%s'\n"
+msgstr "ogiltig kontrollsummealgoritm \"%s\"\n"
+
+#, c-format
+msgid "gcry_md_open for algorithm %d failed: %s\n"
+msgstr ""
+
+#, fuzzy, c-format
 #| msgid "receiving line failed: %s\n"
 msgid "creating S-expression failed: %s\n"
 msgstr "mottagande rad misslyckades: %s\n"
@@ -9058,11 +9073,6 @@ msgstr "fel vid lagring av certifikat\n"
 msgid "failed to allocate OCSP context: %s\n"
 msgstr "misslyckades med att allokera keyDB-hanterare\n"
 
-#, fuzzy, c-format
-#| msgid "can't access `%s': %s\n"
-msgid "can't get authorityInfoAccess: %s\n"
-msgstr "kan inte komma åt \"%s\": %s\n"
-
 #, c-format
 msgid "no default OCSP responder defined\n"
 msgstr ""
@@ -9704,6 +9714,9 @@ msgstr ""
 "Syntax: gpg-check-pattern [flaggor] mönsterfil\n"
 "Kontrollera en lösenfras angiven på standard in mot mönsterfilen\n"
 
+#~ msgid " using certificate ID 0x%08lX\n"
+#~ msgstr " använder certifikat-id 0x%08lX\n"
+
 #, fuzzy
 #~| msgid "you may not use %s while in %s mode\n"
 #~ msgid ""
index 50e9feb..03b225a 100644 (file)
--- a/po/tr.po
+++ b/po/tr.po
@@ -99,6 +99,9 @@ msgstr "aynı değiller - tekrar deneyin"
 #. the pinentry.  The %s is the actual error message, the
 #. two %d give the current and maximum number of tries.
 #. Do not translate the "SETERROR" keyword.
+#. TRANSLATORS: The string is appended to an error message in
+#. the pinentry.  The %s is the actual error message, the
+#. two %d give the current and maximum number of tries.
 #, c-format
 msgid "SETERROR %s (try %d of %d)"
 msgstr "SETERROR %s (%d/%d dene)"
@@ -3776,6 +3779,9 @@ msgstr "parmakizi geçersiz"
 msgid "subkey \"%s\" not found\n"
 msgstr "anahtar \"%s\" yok: %s\n"
 
+msgid "AEAD: "
+msgstr ""
+
 msgid "Digest: "
 msgstr "Özet: "
 
@@ -6588,6 +6594,26 @@ msgstr ""
 "Sözdizimi: kbxutil [seçenekler] [dosyalar]\n"
 "Anahtar kutusu verisini listeler, ithal ve ihraç eder\n"
 
+#. TRANSLATORS: Put a \x1f right before a colon.  This can be
+#. * used by pinentry to nicely align the names and values.  Keep
+#. * the %s at the start and end of the string.
+#, c-format
+msgid "%sNumber\1f: %s%%0AHolder\1f: %s%s"
+msgstr ""
+
+#. TRANSLATORS: This is the number of remaining attempts to
+#. * enter a PIN.  Use %%0A (double-percent,0A) for a linefeed.
+#, c-format
+msgid "Remaining attempts: %d"
+msgstr ""
+
+msgid "||Please enter the PIN for the key to create qualified signatures."
+msgstr ""
+
+#, fuzzy
+msgid "||Please enter the PIN for the standard keys."
+msgstr "|A|Lütfen Yönetici PIN'ini okuyucu tuştakımından giriniz"
+
 #, c-format
 msgid "RSA modulus missing or not of size %d bits\n"
 msgstr "RSA modülü ya eksik ya da %d bitlik değil\n"
@@ -6609,10 +6635,6 @@ msgid "|N|Please enter a new PIN for the standard keys."
 msgstr "||Lütfen PIN'inizi okuyucunun tuştakımından giriniz"
 
 #, fuzzy
-msgid "||Please enter the PIN for the standard keys."
-msgstr "|A|Lütfen Yönetici PIN'ini okuyucu tuştakımından giriniz"
-
-#, fuzzy
 msgid "|NP|Please enter a new PIN Unblocking Code (PUK) for the standard keys."
 msgstr "||Lütfen kart için Sıfırlama Kodunu giriniz"
 
@@ -6623,9 +6645,6 @@ msgstr "||Lütfen kart için Sıfırlama Kodunu giriniz"
 msgid "|N|Please enter a new PIN for the key to create qualified signatures."
 msgstr ""
 
-msgid "||Please enter the PIN for the key to create qualified signatures."
-msgstr ""
-
 msgid ""
 "|NP|Please enter a new PIN Unblocking Code (PUK) for the key to create "
 "qualified signatures."
@@ -6681,16 +6700,6 @@ msgid "%sNumber\1f: %s%%0AHolder\1f: %s%%0ACounter\1f: %lu%s"
 msgstr ""
 
 #, c-format
-msgid "%sNumber\1f: %s%%0AHolder\1f: %s%s"
-msgstr ""
-
-#. TRANSLATORS: This is the number of remaining attempts to
-#. * enter a PIN.  Use %%0A (double-percent,0A) for a linefeed.
-#, c-format
-msgid "Remaining attempts: %d"
-msgstr ""
-
-#, c-format
 msgid "using default PIN as %s\n"
 msgstr "%s olarak öntanımlı PIN kullanılıyor\n"
 
@@ -6964,6 +6973,10 @@ msgid "certificate policy not allowed"
 msgstr "sertifika poliçesine izin verilmiyor"
 
 #, c-format
+msgid "failed to get the fingerprint\n"
+msgstr "parmakizinin alınması başarısız oldu\n"
+
+#, c-format
 msgid "looking up issuer at external location\n"
 msgstr "harici bir sertifikacı arar\n"
 
@@ -6971,6 +6984,11 @@ msgstr "harici bir sertifikacı arar\n"
 msgid "number of issuers matching: %d\n"
 msgstr "eşleşen sertifikacı sayısı: %d\n"
 
+#, fuzzy, c-format
+#| msgid "can't access `%s': %s\n"
+msgid "can't get authorityInfoAccess: %s\n"
+msgstr "'%s' erişilemiyor: %s\n"
+
 #, c-format
 msgid "looking up issuer from the Dirmngr cache\n"
 msgstr "Dirmngr önbelleğinde sertifikacıyı arar\n"
@@ -7595,10 +7613,6 @@ msgid "error reading input: %s\n"
 msgstr "girdi okunurken hata: %s\n"
 
 #, c-format
-msgid "failed to get the fingerprint\n"
-msgstr "parmakizinin alınması başarısız oldu\n"
-
-#, c-format
 msgid "problem looking for existing certificate: %s\n"
 msgstr "mevcut sertifika aranırken sorun çıktı: %s\n"
 
@@ -7689,9 +7703,10 @@ msgstr "İmza "
 msgid "[date not given]"
 msgstr "[belirtilmeyen tarihte]"
 
-#, c-format
-msgid " using certificate ID 0x%08lX\n"
-msgstr " sertifika kimliği 0x%08lX kullanılarak yapıldı\n"
+#, fuzzy, c-format
+#| msgid "algorithm: %s"
+msgid "algorithm:"
+msgstr "algoritma: %s"
 
 #, c-format
 msgid ""
@@ -8062,15 +8077,6 @@ msgstr ""
 msgid "error getting data from cache file: %s\n"
 msgstr "saklanmış bayraklar alınırken hata: %s\n"
 
-#, fuzzy, c-format
-#| msgid "invalid hash algorithm `%s'\n"
-msgid "unknown hash algorithm '%s'\n"
-msgstr "`%s' çittirim algoritması geçersiz\n"
-
-#, c-format
-msgid "gcry_md_open for algorithm %d failed: %s\n"
-msgstr ""
-
 #, c-format
 msgid "got an invalid S-expression from libksba\n"
 msgstr ""
@@ -8081,6 +8087,15 @@ msgid "converting S-expression failed: %s\n"
 msgstr "iconv_open başarısız: %s\n"
 
 #, fuzzy, c-format
+#| msgid "invalid hash algorithm `%s'\n"
+msgid "unknown hash algorithm '%s'\n"
+msgstr "`%s' çittirim algoritması geçersiz\n"
+
+#, c-format
+msgid "gcry_md_open for algorithm %d failed: %s\n"
+msgstr ""
+
+#, fuzzy, c-format
 #| msgid "receiving line failed: %s\n"
 msgid "creating S-expression failed: %s\n"
 msgstr "satır alımı başarısız: %s\n"
@@ -8958,11 +8973,6 @@ msgstr "sertifika saklanırken hata\n"
 msgid "failed to allocate OCSP context: %s\n"
 msgstr "anahtar veritabanı eylemcisine yer ayrılması başarısız oldu\n"
 
-#, fuzzy, c-format
-#| msgid "can't access `%s': %s\n"
-msgid "can't get authorityInfoAccess: %s\n"
-msgstr "'%s' erişilemiyor: %s\n"
-
 #, c-format
 msgid "no default OCSP responder defined\n"
 msgstr ""
@@ -9606,6 +9616,9 @@ msgstr ""
 "Standart girdiden verilen anahtar parolasını örüntü dosyasıyla "
 "karşılaştırır\n"
 
+#~ msgid " using certificate ID 0x%08lX\n"
+#~ msgstr " sertifika kimliği 0x%08lX kullanılarak yapıldı\n"
+
 #, fuzzy
 #~| msgid "you may not use %s while in %s mode\n"
 #~ msgid ""
index 7586c9b..232fe6c 100644 (file)
--- a/po/uk.po
+++ b/po/uk.po
@@ -98,6 +98,9 @@ msgstr "паролі не збігаються, повторіть спробу"
 #. the pinentry.  The %s is the actual error message, the
 #. two %d give the current and maximum number of tries.
 #. Do not translate the "SETERROR" keyword.
+#. TRANSLATORS: The string is appended to an error message in
+#. the pinentry.  The %s is the actual error message, the
+#. two %d give the current and maximum number of tries.
 #, c-format
 msgid "SETERROR %s (try %d of %d)"
 msgstr "SETERROR %s (спроба %d з %d)"
@@ -3563,6 +3566,9 @@ msgstr "«%s» не є відбитком\n"
 msgid "subkey \"%s\" not found\n"
 msgstr "ключ «%s» не знайдено\n"
 
+msgid "AEAD: "
+msgstr ""
+
 msgid "Digest: "
 msgstr "Контрольна сума: "
 
@@ -6333,6 +6339,27 @@ msgstr ""
 "Синтаксис: kbxutil [параметри] [файли]\n"
 "Перегляд, експортування, імпортування даних Keybox\n"
 
+#. TRANSLATORS: Put a \x1f right before a colon.  This can be
+#. * used by pinentry to nicely align the names and values.  Keep
+#. * the %s at the start and end of the string.
+#, c-format
+msgid "%sNumber\1f: %s%%0AHolder\1f: %s%s"
+msgstr ""
+
+#. TRANSLATORS: This is the number of remaining attempts to
+#. * enter a PIN.  Use %%0A (double-percent,0A) for a linefeed.
+#, c-format
+msgid "Remaining attempts: %d"
+msgstr ""
+
+msgid "||Please enter the PIN for the key to create qualified signatures."
+msgstr ""
+"||Будь ласка, вкажіть пінкод для ключа, призначеного для створення якісних "
+"підписів."
+
+msgid "||Please enter the PIN for the standard keys."
+msgstr "||Вкажіть пінкод для стандартних ключів."
+
 #, c-format
 msgid "RSA modulus missing or not of size %d bits\n"
 msgstr ""
@@ -6356,9 +6383,6 @@ msgstr "NullPIN ще не було змінено\n"
 msgid "|N|Please enter a new PIN for the standard keys."
 msgstr "|N|Вкажіть новий пінкод для стандартних ключів."
 
-msgid "||Please enter the PIN for the standard keys."
-msgstr "||Вкажіть пінкод для стандартних ключів."
-
 msgid "|NP|Please enter a new PIN Unblocking Code (PUK) for the standard keys."
 msgstr ""
 "|NP|Будь ласка, вкажіть новий код розблокування пінкоду (PUK) для "
@@ -6374,11 +6398,6 @@ msgstr ""
 "|N|Будь ласка, вкажіть новий пінкод для ключа, призначеного для створення "
 "якісних підписів."
 
-msgid "||Please enter the PIN for the key to create qualified signatures."
-msgstr ""
-"||Будь ласка, вкажіть пінкод для ключа, призначеного для створення якісних "
-"підписів."
-
 msgid ""
 "|NP|Please enter a new PIN Unblocking Code (PUK) for the key to create "
 "qualified signatures."
@@ -6437,16 +6456,6 @@ msgid "%sNumber\1f: %s%%0AHolder\1f: %s%%0ACounter\1f: %lu%s"
 msgstr ""
 
 #, c-format
-msgid "%sNumber\1f: %s%%0AHolder\1f: %s%s"
-msgstr ""
-
-#. TRANSLATORS: This is the number of remaining attempts to
-#. * enter a PIN.  Use %%0A (double-percent,0A) for a linefeed.
-#, c-format
-msgid "Remaining attempts: %d"
-msgstr ""
-
-#, c-format
 msgid "using default PIN as %s\n"
 msgstr "використовуємо типовий пінкод як %s\n"
 
@@ -6705,6 +6714,10 @@ msgid "certificate policy not allowed"
 msgstr "заборонено правила сертифікації"
 
 #, c-format
+msgid "failed to get the fingerprint\n"
+msgstr "не вдалося отримати відбиток\n"
+
+#, c-format
 msgid "looking up issuer at external location\n"
 msgstr "пошук видавця за зовнішньою адресою\n"
 
@@ -6713,6 +6726,10 @@ msgid "number of issuers matching: %d\n"
 msgstr "кількість відповідних видавців: %d\n"
 
 #, c-format
+msgid "can't get authorityInfoAccess: %s\n"
+msgstr "не вдалося отримати authorityInfoAccess: %s\n"
+
+#, c-format
 msgid "looking up issuer from the Dirmngr cache\n"
 msgstr "пошук видавця у кеші dirmngr\n"
 
@@ -7304,10 +7321,6 @@ msgid "error reading input: %s\n"
 msgstr "помилка під час спроби читання вхідних даних: %s\n"
 
 #, c-format
-msgid "failed to get the fingerprint\n"
-msgstr "не вдалося отримати відбиток\n"
-
-#, c-format
 msgid "problem looking for existing certificate: %s\n"
 msgstr "проблем з пошуком вже створеного сертифіката: %s\n"
 
@@ -7398,9 +7411,10 @@ msgstr "Підпис створено "
 msgid "[date not given]"
 msgstr "[дату не вказано]"
 
-#, c-format
-msgid " using certificate ID 0x%08lX\n"
-msgstr " використовуємо ідентифікатор сертифіката 0x%08lX\n"
+#, fuzzy, c-format
+#| msgid "algorithm: %s"
+msgid "algorithm:"
+msgstr "алгоритм: %s"
 
 #, c-format
 msgid ""
@@ -7731,14 +7745,6 @@ msgid "error getting data from cache file: %s\n"
 msgstr "помилка під час спроби отримання даних з файла кешу: %s\n"
 
 #, c-format
-msgid "unknown hash algorithm '%s'\n"
-msgstr "невідомий алгоритм хешування «%s»\n"
-
-#, c-format
-msgid "gcry_md_open for algorithm %d failed: %s\n"
-msgstr "помилка використання gcry_md_open для алгоритму %d: %s\n"
-
-#, c-format
 msgid "got an invalid S-expression from libksba\n"
 msgstr "отримано некоректний вираз S з libksba\n"
 
@@ -7747,6 +7753,14 @@ msgid "converting S-expression failed: %s\n"
 msgstr "спроба перетворення виразу S зазнала невдачі: %s\n"
 
 #, c-format
+msgid "unknown hash algorithm '%s'\n"
+msgstr "невідомий алгоритм хешування «%s»\n"
+
+#, c-format
+msgid "gcry_md_open for algorithm %d failed: %s\n"
+msgstr "помилка використання gcry_md_open для алгоритму %d: %s\n"
+
+#, c-format
 msgid "creating S-expression failed: %s\n"
 msgstr "спроба створення виразу S зазнала невдачі: %s\n"
 
@@ -8509,10 +8523,6 @@ msgid "failed to allocate OCSP context: %s\n"
 msgstr "не вдалося розмістити контекст OCSP: %s\n"
 
 #, c-format
-msgid "can't get authorityInfoAccess: %s\n"
-msgstr "не вдалося отримати authorityInfoAccess: %s\n"
-
-#, c-format
 msgid "no default OCSP responder defined\n"
 msgstr "не визначено типового відповідача за OCSP\n"
 
@@ -9091,6 +9101,9 @@ msgstr ""
 "Синтаксис: gpg-check-pattern [параметри] файл_шаблонів\n"
 "Перевірити пароль, вказаний у stdin, за допомогою файла_шаблонів\n"
 
+#~ msgid " using certificate ID 0x%08lX\n"
+#~ msgstr " використовуємо ідентифікатор сертифіката 0x%08lX\n"
+
 #, fuzzy
 #~| msgid "you may not use %s while in %s mode\n"
 #~ msgid ""
index a46ad1b..48f2ea7 100644 (file)
@@ -93,6 +93,9 @@ msgstr "不匹配 - 请重试"
 #. the pinentry.  The %s is the actual error message, the
 #. two %d give the current and maximum number of tries.
 #. Do not translate the "SETERROR" keyword.
+#. TRANSLATORS: The string is appended to an error message in
+#. the pinentry.  The %s is the actual error message, the
+#. two %d give the current and maximum number of tries.
 #, c-format
 msgid "SETERROR %s (try %d of %d)"
 msgstr ""
@@ -3418,6 +3421,9 @@ msgstr "“%s” 不是一个正确的指纹\n"
 msgid "subkey \"%s\" not found\n"
 msgstr "子密钥 “%s” 未找到\n"
 
+msgid "AEAD: "
+msgstr "AEAD: "
+
 msgid "Digest: "
 msgstr "摘要: "
 
@@ -5969,6 +5975,25 @@ msgstr ""
 "语法:kbxutil [选项] [文件]\n"
 "列出、导出或导入钥匙箱数据\n"
 
+#. TRANSLATORS: Put a \x1f right before a colon.  This can be
+#. * used by pinentry to nicely align the names and values.  Keep
+#. * the %s at the start and end of the string.
+#, c-format
+msgid "%sNumber\1f: %s%%0AHolder\1f: %s%s"
+msgstr "%s数字\1f: %s%%0A持有者\1f: %s%s"
+
+#. TRANSLATORS: This is the number of remaining attempts to
+#. * enter a PIN.  Use %%0A (double-percent,0A) for a linefeed.
+#, c-format
+msgid "Remaining attempts: %d"
+msgstr "剩余尝试:%d"
+
+msgid "||Please enter the PIN for the key to create qualified signatures."
+msgstr "||请为这个密钥输入 PIN 以创建合格的签名。"
+
+msgid "||Please enter the PIN for the standard keys."
+msgstr "||请输入标准密钥的 PIN。"
+
 #, c-format
 msgid "RSA modulus missing or not of size %d bits\n"
 msgstr "RSA 余数缺失或者不是 %d 位长\n"
@@ -5988,9 +6013,6 @@ msgstr "尚未变更 NullPIN\n"
 msgid "|N|Please enter a new PIN for the standard keys."
 msgstr "|N|请为标准密钥输入一个新的 PIN。"
 
-msgid "||Please enter the PIN for the standard keys."
-msgstr "||请输入标准密钥的 PIN。"
-
 msgid "|NP|Please enter a new PIN Unblocking Code (PUK) for the standard keys."
 msgstr "|NP|请为标准密钥输入一个新的 PIN 解锁码(PUK)。"
 
@@ -6000,9 +6022,6 @@ msgstr "|NP|请输入标准密钥的 PIN 解锁码(PUK)。"
 msgid "|N|Please enter a new PIN for the key to create qualified signatures."
 msgstr "|N|请为这个密钥输入一个新的 PIN 以创建合格的签名。"
 
-msgid "||Please enter the PIN for the key to create qualified signatures."
-msgstr "||请为这个密钥输入 PIN 以创建合格的签名。"
-
 msgid ""
 "|NP|Please enter a new PIN Unblocking Code (PUK) for the key to create "
 "qualified signatures."
@@ -6057,16 +6076,6 @@ msgid "%sNumber\1f: %s%%0AHolder\1f: %s%%0ACounter\1f: %lu%s"
 msgstr "%s数字\1f: %s%%0A持有者\1f: %s%%0A计数\1f: %lu%s"
 
 #, c-format
-msgid "%sNumber\1f: %s%%0AHolder\1f: %s%s"
-msgstr "%s数字\1f: %s%%0A持有者\1f: %s%s"
-
-#. TRANSLATORS: This is the number of remaining attempts to
-#. * enter a PIN.  Use %%0A (double-percent,0A) for a linefeed.
-#, c-format
-msgid "Remaining attempts: %d"
-msgstr "剩余尝试:%d"
-
-#, c-format
 msgid "using default PIN as %s\n"
 msgstr "使用默认 PIN 作为 %s\n"
 
@@ -6308,6 +6317,10 @@ msgid "certificate policy not allowed"
 msgstr "证书策略不被允许"
 
 #, c-format
+msgid "failed to get the fingerprint\n"
+msgstr "获取指纹失败\n"
+
+#, c-format
 msgid "looking up issuer at external location\n"
 msgstr "在外部位置查找签发者\n"
 
@@ -6316,6 +6329,10 @@ msgid "number of issuers matching: %d\n"
 msgstr "匹配的签发者数目:%d\n"
 
 #, c-format
+msgid "can't get authorityInfoAccess: %s\n"
+msgstr "无法获取 authorityInfoAccess:%s\n"
+
+#, c-format
 msgid "looking up issuer from the Dirmngr cache\n"
 msgstr "在 Dirmngr 缓存中查找签发者\n"
 
@@ -6892,10 +6909,6 @@ msgid "error reading input: %s\n"
 msgstr "读取输入时出现错误:%s\n"
 
 #, c-format
-msgid "failed to get the fingerprint\n"
-msgstr "获取指纹失败\n"
-
-#, c-format
 msgid "problem looking for existing certificate: %s\n"
 msgstr "查找现存证书时出现问题:%s\n"
 
@@ -6981,9 +6994,10 @@ msgstr "已签名 "
 msgid "[date not given]"
 msgstr "[日期未指定]"
 
-#, c-format
-msgid " using certificate ID 0x%08lX\n"
-msgstr " 正在使用的证书标识 0x%08lX\n"
+#, fuzzy, c-format
+#| msgid "algorithm: %s"
+msgid "algorithm:"
+msgstr "算法: %s"
 
 #, c-format
 msgid ""
@@ -7312,14 +7326,6 @@ msgid "error getting data from cache file: %s\n"
 msgstr "从缓存文件中获取数据时出现错误:%s\n"
 
 #, c-format
-msgid "unknown hash algorithm '%s'\n"
-msgstr "未知的散列算法‘%s’\n"
-
-#, c-format
-msgid "gcry_md_open for algorithm %d failed: %s\n"
-msgstr "算法 %d 的 gcry_md_open 方法失败:%s\n"
-
-#, c-format
 msgid "got an invalid S-expression from libksba\n"
 msgstr "从  libksba 获得了无效的 S 表达式\n"
 
@@ -7328,6 +7334,14 @@ msgid "converting S-expression failed: %s\n"
 msgstr "转换 S 表达式时失败:%s\n"
 
 #, c-format
+msgid "unknown hash algorithm '%s'\n"
+msgstr "未知的散列算法‘%s’\n"
+
+#, c-format
+msgid "gcry_md_open for algorithm %d failed: %s\n"
+msgstr "算法 %d 的 gcry_md_open 方法失败:%s\n"
+
+#, c-format
 msgid "creating S-expression failed: %s\n"
 msgstr "创建 S 表达式时失败:%s\n"
 
@@ -8074,10 +8088,6 @@ msgid "failed to allocate OCSP context: %s\n"
 msgstr "分配 OCSP 上下文时失败:%s\n"
 
 #, c-format
-msgid "can't get authorityInfoAccess: %s\n"
-msgstr "无法获取 authorityInfoAccess:%s\n"
-
-#, c-format
 msgid "no default OCSP responder defined\n"
 msgstr "未定义默认的 OCSP 响应者\n"
 
@@ -8652,6 +8662,9 @@ msgstr ""
 "语法:gpg-check-pattern [选项] patternfile\n"
 "按照 patternfile 检查一个由标准输入(stdin)给定的密码\n"
 
+#~ msgid " using certificate ID 0x%08lX\n"
+#~ msgstr " 正在使用的证书标识 0x%08lX\n"
+
 #, fuzzy
 #~| msgid "option '%s' may not be used in %s mode\n"
 #~ msgid ""
@@ -8733,9 +8746,6 @@ msgstr ""
 #~ msgid "         \"%s\": preference for AEAD algorithm %s\n"
 #~ msgstr "         \"%s\":关于 AEAD 算法 %s 的偏好设置\n"
 
-#~ msgid "AEAD: "
-#~ msgstr "AEAD: "
-
 #~ msgid "too many AEAD preferences\n"
 #~ msgstr "过多的 AEAD 偏好设置\n"
 
index beb8bc1..50d7ca6 100644 (file)
@@ -106,6 +106,9 @@ msgstr "前後不一致 - 請再試一次"
 #. the pinentry.  The %s is the actual error message, the
 #. two %d give the current and maximum number of tries.
 #. Do not translate the "SETERROR" keyword.
+#. TRANSLATORS: The string is appended to an error message in
+#. the pinentry.  The %s is the actual error message, the
+#. two %d give the current and maximum number of tries.
 #, c-format
 msgid "SETERROR %s (try %d of %d)"
 msgstr "SETERROR %s (第 %d 次嘗試, 最多 %d 次)"
@@ -3516,6 +3519,9 @@ msgstr "\"%s\" 不是指紋\n"
 msgid "subkey \"%s\" not found\n"
 msgstr "找不到金鑰 \"%s\": %s\n"
 
+msgid "AEAD: "
+msgstr ""
+
 msgid "Digest: "
 msgstr "摘要: "
 
@@ -6165,6 +6171,25 @@ msgstr ""
 "語法: kbxutil [選項] [檔案]\n"
 "列出, 匯出, 匯入金鑰鑰匙盒資料\n"
 
+#. TRANSLATORS: Put a \x1f right before a colon.  This can be
+#. * used by pinentry to nicely align the names and values.  Keep
+#. * the %s at the start and end of the string.
+#, c-format
+msgid "%sNumber\1f: %s%%0AHolder\1f: %s%s"
+msgstr ""
+
+#. TRANSLATORS: This is the number of remaining attempts to
+#. * enter a PIN.  Use %%0A (double-percent,0A) for a linefeed.
+#, c-format
+msgid "Remaining attempts: %d"
+msgstr ""
+
+msgid "||Please enter the PIN for the key to create qualified signatures."
+msgstr "||請輸入金鑰的個人識別碼 (PIN) 以建立完善的簽章."
+
+msgid "||Please enter the PIN for the standard keys."
+msgstr "||請輸入標準金鑰的個人識別碼 (PIN)."
+
 #, c-format
 msgid "RSA modulus missing or not of size %d bits\n"
 msgstr "RSA 模組缺漏或者並非 %d 位元大\n"
@@ -6184,9 +6209,6 @@ msgstr "NullPIN 還沒有變更過\n"
 msgid "|N|Please enter a new PIN for the standard keys."
 msgstr "|N|請輸入標準金鑰將採用的新個人識別碼 (PIN)."
 
-msgid "||Please enter the PIN for the standard keys."
-msgstr "||請輸入標準金鑰的個人識別碼 (PIN)."
-
 msgid "|NP|Please enter a new PIN Unblocking Code (PUK) for the standard keys."
 msgstr "|NP|請輸入標準金鑰將採用的 PIN 重設碼 (PUK)."
 
@@ -6196,9 +6218,6 @@ msgstr "|P|請輸入標準金鑰的 PIN 重設碼 (PUK)."
 msgid "|N|Please enter a new PIN for the key to create qualified signatures."
 msgstr "|N|請輸入金鑰的新個人識別碼 (PIN) 以建立完善的簽章."
 
-msgid "||Please enter the PIN for the key to create qualified signatures."
-msgstr "||請輸入金鑰的個人識別碼 (PIN) 以建立完善的簽章."
-
 msgid ""
 "|NP|Please enter a new PIN Unblocking Code (PUK) for the key to create "
 "qualified signatures."
@@ -6254,16 +6273,6 @@ msgid "%sNumber\1f: %s%%0AHolder\1f: %s%%0ACounter\1f: %lu%s"
 msgstr ""
 
 #, c-format
-msgid "%sNumber\1f: %s%%0AHolder\1f: %s%s"
-msgstr ""
-
-#. TRANSLATORS: This is the number of remaining attempts to
-#. * enter a PIN.  Use %%0A (double-percent,0A) for a linefeed.
-#, c-format
-msgid "Remaining attempts: %d"
-msgstr ""
-
-#, c-format
 msgid "using default PIN as %s\n"
 msgstr "以 %s 做為預設 PIN\n"
 
@@ -6510,6 +6519,10 @@ msgid "certificate policy not allowed"
 msgstr "未允許憑證原則"
 
 #, c-format
+msgid "failed to get the fingerprint\n"
+msgstr "取得指紋失敗\n"
+
+#, c-format
 msgid "looking up issuer at external location\n"
 msgstr "從外部位置尋找發行者\n"
 
@@ -6518,6 +6531,10 @@ msgid "number of issuers matching: %d\n"
 msgstr "吻合的發行者數量: %d\n"
 
 #, c-format
+msgid "can't get authorityInfoAccess: %s\n"
+msgstr "無法取得 authorityInfoAccess: %s\n"
+
+#, c-format
 msgid "looking up issuer from the Dirmngr cache\n"
 msgstr "從 Dirmngr 快取尋找發行者\n"
 
@@ -7094,10 +7111,6 @@ msgid "error reading input: %s\n"
 msgstr "讀取輸入時出錯: %s\n"
 
 #, c-format
-msgid "failed to get the fingerprint\n"
-msgstr "取得指紋失敗\n"
-
-#, c-format
 msgid "problem looking for existing certificate: %s\n"
 msgstr "查找既有憑證的問題: %s\n"
 
@@ -7183,9 +7196,10 @@ msgstr "簽章建立於 "
 msgid "[date not given]"
 msgstr "[   未給定日期  ]"
 
-#, c-format
-msgid " using certificate ID 0x%08lX\n"
-msgstr " 以憑證 ID 0x%08lX\n"
+#, fuzzy, c-format
+#| msgid "algorithm: %s"
+msgid "algorithm:"
+msgstr "演算法: %s"
 
 #, c-format
 msgid ""
@@ -7506,14 +7520,6 @@ msgid "error getting data from cache file: %s\n"
 msgstr "從快取檔案取得資料時出錯: %s\n"
 
 #, c-format
-msgid "unknown hash algorithm '%s'\n"
-msgstr "未知的雜湊演算法 '%s'\n"
-
-#, c-format
-msgid "gcry_md_open for algorithm %d failed: %s\n"
-msgstr "演算法 %d 的 gcry_md_open 失敗: %s\n"
-
-#, c-format
 msgid "got an invalid S-expression from libksba\n"
 msgstr "從 libksba 得到無效的 S-表示式\n"
 
@@ -7522,6 +7528,14 @@ msgid "converting S-expression failed: %s\n"
 msgstr "轉換 S-表示式時失敗: %s\n"
 
 #, c-format
+msgid "unknown hash algorithm '%s'\n"
+msgstr "未知的雜湊演算法 '%s'\n"
+
+#, c-format
+msgid "gcry_md_open for algorithm %d failed: %s\n"
+msgstr "演算法 %d 的 gcry_md_open 失敗: %s\n"
+
+#, c-format
 msgid "creating S-expression failed: %s\n"
 msgstr "建立 S-表示式時失敗: %s\n"
 
@@ -8270,10 +8284,6 @@ msgid "failed to allocate OCSP context: %s\n"
 msgstr "配置 OCSP 脈絡失敗: %s\n"
 
 #, c-format
-msgid "can't get authorityInfoAccess: %s\n"
-msgstr "無法取得 authorityInfoAccess: %s\n"
-
-#, c-format
 msgid "no default OCSP responder defined\n"
 msgstr "無定義預設 OCSP 回應程式\n"
 
@@ -8865,6 +8875,9 @@ msgstr ""
 "語法: gpg-check-pattern [選項] 樣式檔案\n"
 "用樣式檔案來檢查由標準輸入給定的密語\n"
 
+#~ msgid " using certificate ID 0x%08lX\n"
+#~ msgstr " 以憑證 ID 0x%08lX\n"
+
 #, fuzzy
 #~| msgid "you may not use %s while in %s mode\n"
 #~ msgid ""
index 274f2db..dfd9451 100644 (file)
@@ -475,7 +475,7 @@ dump_reader_status (int slot)
   if (reader_table[slot].atrlen)
     {
       log_info ("slot %d: ATR=", slot);
-      log_printhex ("", reader_table[slot].atr, reader_table[slot].atrlen);
+      log_printhex (reader_table[slot].atr, reader_table[slot].atrlen, "");
     }
 }
 
@@ -739,7 +739,7 @@ pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
     return err;
 
   if (DBG_CARD_IO)
-    log_printhex ("  PCSC_data:", apdu, apdulen);
+    log_printhex (apdu, apdulen, "  PCSC_data:");
 
   if ((reader_table[slot].pcsc.protocol & PCSC_PROTOCOL_T1))
       send_pci.protocol = PCSC_PROTOCOL_T1;
@@ -1453,7 +1453,7 @@ send_apdu_ccid (int slot, unsigned char *apdu, size_t apdulen,
     return err;
 
   if (DBG_CARD_IO)
-    log_printhex (" raw apdu:", apdu, apdulen);
+    log_printhex (apdu, apdulen, " raw apdu:");
 
   maxbuflen = *buflen;
   if (pininfo)
@@ -1723,7 +1723,7 @@ my_rapdu_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
 
   *buflen = 0;
   if (DBG_CARD_IO)
-    log_printhex ("  APDU_data:", apdu, apdulen);
+    log_printhex (apdu, apdulen, "  APDU_data:");
 
   if (apdulen < 4)
     {
@@ -2879,7 +2879,7 @@ send_le (int slot, int class, int ins, int p0, int p1,
       log_debug (" response: sw=%04X  datalen=%d\n",
                  sw, (unsigned int)resultlen);
       if ( !retbuf && (sw == SW_SUCCESS || (sw & 0xff00) == SW_MORE_DATA))
-        log_printhex ("    dump: ", result, resultlen);
+        log_printhex (result, resultlen, "    dump: ");
     }
 
   if (sw == SW_SUCCESS || sw == SW_EOF_REACHED)
@@ -2952,7 +2952,7 @@ send_le (int slot, int class, int ins, int p0, int p1,
               log_debug ("     more: sw=%04X  datalen=%d\n",
                          sw, (unsigned int)resultlen);
               if (!retbuf && (sw==SW_SUCCESS || (sw&0xff00)==SW_MORE_DATA))
-                log_printhex ("     dump: ", result, resultlen);
+                log_printhex (result, resultlen, "     dump: ");
             }
 
           if ((sw & 0xff00) == SW_MORE_DATA
@@ -2998,7 +2998,7 @@ send_le (int slot, int class, int ins, int p0, int p1,
   xfree (result_buffer);
 
   if (DBG_CARD_IO && retbuf && sw == SW_SUCCESS)
-    log_printhex ("      dump: ", *retbuf, *retbuflen);
+    log_printhex (*retbuf, *retbuflen, "      dump: ");
 
   return sw;
 }
@@ -3164,7 +3164,7 @@ apdu_send_direct (int slot, size_t extended_length,
       log_debug (" response: sw=%04X  datalen=%d\n",
                  sw, (unsigned int)resultlen);
       if ( !retbuf && (sw == SW_SUCCESS || (sw & 0xff00) == SW_MORE_DATA))
-        log_printhex ("     dump: ", result, resultlen);
+        log_printhex (result, resultlen, "     dump: ");
     }
 
   if (handle_more && (sw & 0xff00) == SW_MORE_DATA)
@@ -3220,7 +3220,7 @@ apdu_send_direct (int slot, size_t extended_length,
               log_debug ("     more: sw=%04X  datalen=%d\n",
                          sw, (unsigned int)resultlen);
               if (!retbuf && (sw==SW_SUCCESS || (sw&0xff00)==SW_MORE_DATA))
-                log_printhex ("     dump: ", result, resultlen);
+                log_printhex (result, resultlen, "     dump: ");
             }
 
           if ((sw & 0xff00) == SW_MORE_DATA
@@ -3292,7 +3292,7 @@ apdu_send_direct (int slot, size_t extended_length,
     *r_sw = sw;
 
   if (DBG_CARD_IO && retbuf)
-    log_printhex ("      dump: ", *retbuf, *retbuflen);
+    log_printhex (*retbuf, *retbuflen, "      dump: ");
 
 
   return 0;
index 2619823..89467dc 100644 (file)
@@ -119,9 +119,26 @@ struct app_ctx_s {
   } fnc;
 };
 
+
+/* Helper to get the slot from an APP object. */
+static inline int
+app_get_slot (app_t app)
+{
+  /* Note that this is a similar function of the one in 2.3 which we
+   * use to make back porting easier.  */
+  if (app)
+    return app->slot;
+  return -1;
+}
+
+
 /*-- app-help.c --*/
 unsigned int app_help_count_bits (const unsigned char *a, size_t len);
-gpg_error_t app_help_get_keygrip_string (ksba_cert_t cert, char *hexkeygrip);
+gpg_error_t app_help_get_keygrip_string_pk (const void *pk, size_t pklen,
+                                            char *hexkeygrip,
+                                            gcry_sexp_t *r_pkey);
+gpg_error_t app_help_get_keygrip_string (ksba_cert_t cert, char *hexkeygrip,
+                                         gcry_sexp_t *r_pkey);
 size_t app_help_read_length_of_cert (int slot, int fid, size_t *r_certoff);
 
 
index bea2856..b0c47af 100644 (file)
@@ -137,7 +137,7 @@ do_learn_status (app_t app, ctrl_t ctrl, unsigned int flags)
       ksba_cert_release (cert);
       return err;
     }
-  err = app_help_get_keygrip_string (cert, hexkeygrip);
+  err = app_help_get_keygrip_string (cert, hexkeygrip, NULL);
   if (err)
     {
       log_error ("failed to calculate the keygrip for FID 0x%04X\n", fid);
index 842a73d..4b8a024 100644 (file)
@@ -52,26 +52,24 @@ app_help_count_bits (const unsigned char *a, size_t len)
 }
 
 
-/* Return the KEYGRIP for the certificate CERT as an hex encoded
-   string in the user provided buffer HEXKEYGRIP which must be of at
-   least 41 bytes. */
+/* Return the KEYGRIP for the canonical encoded public key (PK,PKLEN)
+ * as an hex encoded string in the user provided buffer HEXKEYGRIP
+ * which must be of at least 41 bytes.  If R_PKEY is not NULL and the
+ * function succeeded, the S-expression representing the key is
+ * stored there.  The caller needs to call gcry_sexp_release on
+ * that.  */
 gpg_error_t
-app_help_get_keygrip_string (ksba_cert_t cert, char *hexkeygrip)
+app_help_get_keygrip_string_pk (const void *pk, size_t pklen, char *hexkeygrip,
+                                gcry_sexp_t *r_pkey)
 {
   gpg_error_t err;
   gcry_sexp_t s_pkey;
-  ksba_sexp_t p;
-  size_t n;
-  unsigned char array[20];
+  unsigned char array[KEYGRIP_LEN];
 
-  p = ksba_cert_get_public_key (cert);
-  if (!p)
-    return gpg_error (GPG_ERR_BUG);
-  n = gcry_sexp_canon_len (p, 0, NULL, NULL);
-  if (!n)
-    return gpg_error (GPG_ERR_INV_SEXP);
-  err = gcry_sexp_sscan (&s_pkey, NULL, (char*)p, n);
-  xfree (p);
+  if (r_pkey)
+    *r_pkey = NULL;
+
+  err = gcry_sexp_sscan (&s_pkey, NULL, pk, pklen);
   if (err)
     return err; /* Can't parse that S-expression. */
   if (!gcry_pk_get_keygrip (s_pkey, array))
@@ -79,14 +77,45 @@ app_help_get_keygrip_string (ksba_cert_t cert, char *hexkeygrip)
       gcry_sexp_release (s_pkey);
       return gpg_error (GPG_ERR_GENERAL); /* Failed to calculate the keygrip.*/
     }
-  gcry_sexp_release (s_pkey);
 
-  bin2hex (array, 20, hexkeygrip);
+  if (r_pkey)
+    *r_pkey = s_pkey;
+  else
+    gcry_sexp_release (s_pkey);
+
+  bin2hex (array, KEYGRIP_LEN, hexkeygrip);
 
   return 0;
 }
 
 
+/* Return the KEYGRIP for the certificate CERT as an hex encoded
+ * string in the user provided buffer HEXKEYGRIP which must be of at
+ * least 41 bytes.  If R_PKEY is not NULL and the function succeeded,
+ * the S-expression representing the key is stored there.  The caller
+ * needs to call gcry_sexp_release on that. */
+gpg_error_t
+app_help_get_keygrip_string (ksba_cert_t cert, char *hexkeygrip,
+                             gcry_sexp_t *r_pkey)
+{
+  gpg_error_t err;
+  ksba_sexp_t p;
+  size_t n;
+
+  if (r_pkey)
+    *r_pkey = NULL;
+
+  p = ksba_cert_get_public_key (cert);
+  if (!p)
+    return gpg_error (GPG_ERR_BUG);
+  n = gcry_sexp_canon_len (p, 0, NULL, NULL);
+  if (!n)
+    return gpg_error (GPG_ERR_INV_SEXP);
+  err = app_help_get_keygrip_string_pk ((void*)p, n, hexkeygrip, r_pkey);
+  ksba_free (p);
+  return err;
+}
+
 
 /* Given the SLOT and the File ID FID, return the length of the
    certificate contained in that file. Returns 0 if the file does not
index 9371932..58a5349 100644 (file)
@@ -248,53 +248,17 @@ keygripstr_from_pk_file (app_t app, int fid, char *r_gripstr)
 
 
 /* TCOS responds to a verify with empty data (i.e. without the Lc
-   byte) with the status of the PIN.  PWID is the PIN ID, If SIGG is
-   true, the application is switched into SigG mode.
-   Returns:
-            -1 = Error retrieving the data,
-            -2 = No such PIN,
-            -3 = PIN blocked,
-            -4 = NullPIN activ,
-        n >= 0 = Number of verification attempts left.  */
+ * byte) with the status of the PIN.  PWID is the PIN ID, If SIGG is
+ * true, the application is switched into SigG mode.  Returns:
+ * ISO7816_VERIFY_* codes or non-negative number of verification
+ * attempts left.  */
 static int
 get_chv_status (app_t app, int sigg, int pwid)
 {
-  unsigned char *result = NULL;
-  size_t resultlen;
-  char command[4];
-  int rc;
-
   if (switch_application (app, sigg))
     return sigg? -2 : -1; /* No such PIN / General error.  */
 
-  command[0] = 0x00;
-  command[1] = 0x20;
-  command[2] = 0x00;
-  command[3] = pwid;
-
-  if (apdu_send_direct (app->slot, 0, (unsigned char *)command,
-                        4, 0, NULL, &result, &resultlen))
-    rc = -1; /* Error. */
-  else if (resultlen < 2)
-    rc = -1; /* Error. */
-  else
-    {
-      unsigned int sw = buf16_to_uint (result+resultlen-2);
-
-      if (sw == 0x6a88)
-        rc = -2; /* No such PIN.  */
-      else if (sw == 0x6983)
-        rc = -3; /* PIN is blocked.  */
-      else if (sw == 0x6985)
-        rc = -4; /* NullPIN is activ.  */
-      else if ((sw & 0xfff0) == 0x63C0)
-        rc = (sw & 0x000f); /* PIN has N tries left.  */
-      else
-        rc = -1; /* Other error.  */
-    }
-  xfree (result);
-
-  return rc;
+  return iso7816_verify_status (app_get_slot (app), pwid);
 }
 
 
index fe13f28..7fc903b 100644 (file)
@@ -268,6 +268,47 @@ static gpg_error_t change_keyattr_from_string
                             void *pincb_arg,
                             const void *value, size_t valuelen);
 
+\f
+/* Return the OpenPGP card manufacturer name. */
+static const char *
+get_manufacturer (unsigned int no)
+{
+  /* Note:  Make sure that there is no colon or linefeed in the string. */
+  switch (no)
+    {
+    case 0x0001: return "PPC Card Systems";
+    case 0x0002: return "Prism";
+    case 0x0003: return "OpenFortress";
+    case 0x0004: return "Wewid";
+    case 0x0005: return "ZeitControl";
+    case 0x0006: return "Yubico";
+    case 0x0007: return "OpenKMS";
+    case 0x0008: return "LogoEmail";
+    case 0x0009: return "Fidesmo";
+    case 0x000A: return "Dangerous Things";
+    case 0x000B: return "Feitian Technologies";
+
+    case 0x002A: return "Magrathea";
+    case 0x0042: return "GnuPG e.V.";
+
+    case 0x1337: return "Warsaw Hackerspace";
+    case 0x2342: return "warpzone"; /* hackerspace Muenster.  */
+    case 0x4354: return "Confidential Technologies";   /* cotech.de */
+    case 0x5443: return "TIF-IT e.V.";
+    case 0x63AF: return "Trustica";
+    case 0xBA53: return "c-base e.V.";
+    case 0xBD0E: return "Paranoidlabs";
+    case 0xF517: return "FSIJ";
+    case 0xF5EC: return "F-Secure";
+
+      /* 0x0000 and 0xFFFF are defined as test cards per spec,
+       * 0xFF00 to 0xFFFE are assigned for use with randomly created
+       * serial numbers.  */
+    case 0x0000:
+    case 0xffff: return "test card";
+    default: return (no & 0xff00) == 0xff00? "unmanaged S/N range":"unknown";
+    }
+}
 
 
 
@@ -567,7 +608,7 @@ dump_all_do (int slot)
           if (data_objects[i].binary)
             {
               log_info ("DO '%s': ", data_objects[i].desc);
-              log_printhex ("", buffer, buflen);
+              log_printhex (buffer, buflen, "");
             }
           else
             log_info ("DO '%s': '%.*s'\n",
@@ -597,7 +638,7 @@ dump_all_do (int slot)
                           if (valuelen > 200)
                             log_info ("[%u]\n", (unsigned int)valuelen);
                           else
-                            log_printhex ("", value, valuelen);
+                            log_printhex (value, valuelen, "");
                         }
                       else
                         log_info ("DO '%s': '%.*s'\n",
@@ -992,6 +1033,7 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
     { "$SIGNKEYID",   0x0000, -7 },
     { "$DISPSERIALNO",0x0000, -4 },
     { "KDF",          0x00F9, 5 },
+    { "MANUFACTURER", 0x0000, -8 },
     { NULL, 0 }
   };
   int idx, i, rc;
@@ -1083,6 +1125,13 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
       send_status_info (ctrl, table[idx].name, tmp, strlen (tmp), NULL, 0);
       return 0;
     }
+  if (table[idx].special == -8)
+    {
+      return send_status_printf
+        (ctrl, table[idx].name, "%u %s",
+         app->app_local->manufacturer,
+         get_manufacturer (app->app_local->manufacturer));
+    }
 
   relptr = get_one_do (app, table[idx].tag, &value, &valuelen, &rc);
   if (relptr)
@@ -1860,6 +1909,7 @@ do_learn_status (app_t app, ctrl_t ctrl, unsigned int flags)
   (void)flags;
 
   do_getattr (app, ctrl, "EXTCAP");
+  do_getattr (app, ctrl, "MANUFACTURER");
   do_getattr (app, ctrl, "DISP-NAME");
   do_getattr (app, ctrl, "DISP-LANG");
   do_getattr (app, ctrl, "DISP-SEX");
@@ -4239,7 +4289,7 @@ compare_fingerprint (app_t app, int keyno, unsigned char *sha1fpr)
       return gpg_error (GPG_ERR_GENERAL);
     }
   fpr = find_tlv (buffer, buflen, 0x00C5, &n);
-  if (!fpr || n != 60)
+  if (!fpr || n < 60)
     {
       xfree (buffer);
       log_error (_("error reading fingerprint DO\n"));
@@ -5156,7 +5206,7 @@ parse_algorithm_attribute (app_t app, int keyno)
       curve = ecc_curve (buffer + 1, oidlen);
 
       if (!curve)
-        log_printhex ("Curve with OID not supported: ", buffer+1, buflen-1);
+        log_printhex (buffer+1, buflen-1, "Curve with OID not supported: ");
       else
         {
           app->app_local->keyattr[keyno].key_type = KEY_TYPE_ECC;
@@ -5174,7 +5224,7 @@ parse_algorithm_attribute (app_t app, int keyno)
         }
     }
   else if (opt.verbose)
-    log_printhex ("", buffer, buflen);
+    log_printhex (buffer, buflen, "");
 
   xfree (relptr);
 }
@@ -5216,7 +5266,7 @@ app_select_openpgp (app_t app)
       if (opt.verbose)
         {
           log_info ("AID: ");
-          log_printhex ("", buffer, buflen);
+          log_printhex (buffer, buflen, "");
         }
 
       app->card_version = buffer[6] << 8;
@@ -5249,7 +5299,7 @@ app_select_openpgp (app_t app)
           if (opt.verbose)
             {
               log_info ("Historical Bytes: ");
-              log_printhex ("", buffer, buflen);
+              log_printhex (buffer, buflen, "");
             }
           parse_historical (app->app_local, buffer, buflen);
           xfree (relptr);
index 0bb5f9e..9ad0d16 100644 (file)
@@ -1,5 +1,6 @@
 /* app-p15.c - The pkcs#15 card application.
  *     Copyright (C) 2005 Free Software Foundation, Inc.
+ *     Copyright (C) 2020 g10 Code GmbH
  *
  * This file is part of GnuPG.
  *
@@ -15,6 +16,7 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: GPL-3.0-or-later
  */
 
 /* Information pertaining to the BELPIC developer card samples:
@@ -39,6 +41,7 @@
 
 #include "iso7816.h"
 #include "app-common.h"
+#include "../common/i18n.h"
 #include "../common/tlv.h"
 #include "apdu.h" /* fixme: we should move the card detection to a
                      separate file */
@@ -49,10 +52,22 @@ typedef enum
     CARD_TYPE_UNKNOWN,
     CARD_TYPE_TCOS,
     CARD_TYPE_MICARDO,
+    CARD_TYPE_CARDOS_50,
     CARD_TYPE_BELPIC   /* Belgian eID card specs. */
   }
 card_type_t;
 
+/* The OS of card as specified by card_type_t is not always
+ * sufficient.  Thus we also distinguish the actual product build upon
+ * the given OS.  */
+typedef enum
+  {
+    CARD_PRODUCT_UNKNOWN,
+    CARD_PRODUCT_DTRUST    /* D-Trust GmbH (bundesdruckerei.de) */
+  }
+card_product_t;
+
+
 /* A list card types with ATRs noticed with these cards. */
 #define X(a) ((unsigned char const *)(a))
 static struct
@@ -79,7 +94,8 @@ static struct
   { 26, X("\x3B\xFE\x94\x00\xFF\x80\xB1\xFA\x45\x1F\x03\x45\x73\x74\x45\x49"
           "\x44\x20\x76\x65\x72\x20\x31\x2E\x30\x43"),
     CARD_TYPE_MICARDO }, /* EstEID (Estonian Big Brother card) */
-
+  { 11, X("\x3b\xd2\x18\x00\x81\x31\xfe\x58\xc9\x01\x14"),
+    CARD_TYPE_CARDOS_50 }, /* CardOS 5.0 */
   { 0 }
 };
 #undef X
@@ -135,7 +151,12 @@ struct cdf_object_s
   /* Link to next item when used in a linked list. */
   struct cdf_object_s *next;
 
-  /* Length and allocated buffer with the Id of this object. */
+  /* Flags to indicate whether fields are valid.  */
+  unsigned int have_off:1;
+
+  /* Length and allocated buffer with the Id of this object.
+   * This field is used for X.509 in PKCS#11 to make it easier to
+   * match a private key with a certificate.  */
   size_t objidlen;
   unsigned char *objid;
 
@@ -144,8 +165,6 @@ struct cdf_object_s
   size_t imagelen;
   unsigned char *image;
 
-  /* Set to true if a length and offset is available. */
-  int have_off;
   /* The offset and length of the object.  They are only valid if
      HAVE_OFF is true and set to 0 if HAVE_OFF is false. */
   unsigned long off, len;
@@ -169,6 +188,37 @@ struct prkdf_object_s
   /* Link to next item when used in a linked list. */
   struct prkdf_object_s *next;
 
+  /* Flags to indicate whether fields are valid.  */
+  unsigned int keygrip_valid:1;
+  unsigned int key_reference_valid:1;
+  unsigned int have_off:1;
+
+  /* Flag indicating that the corresponding PIN has already been
+   * verified. */
+  unsigned int pin_verified:1;
+
+  /* The key's usage flags. */
+  keyusage_flags_t usageflags;
+
+  /* The keygrip of the key.  This is used as a cache.  */
+  char keygrip[2*KEYGRIP_LEN+1];
+
+  /* The Gcrypt algo identifier for the key.  It is valid if the
+   * keygrip is also valid.  */
+  int keyalgo;
+
+  /* The length of the key in bits (e.g. for RSA the length of the
+   * modulus).  It is valid if the keygrip is also valid.  */
+  unsigned int keynbits;
+
+  /* Malloced CN from the Subject-DN of the corresponding certificate
+   * or NULL if not known.  */
+  char *common_name;
+
+  /* Malloced SerialNumber from the Subject-DN of the corresponding
+   * certificate or NULL if not known.  */
+  char *serial_number;
+
   /* Length and allocated buffer with the Id of this object. */
   size_t objidlen;
   unsigned char *objid;
@@ -178,17 +228,11 @@ struct prkdf_object_s
   size_t authidlen;
   unsigned char *authid;
 
-  /* The key's usage flags. */
-  keyusage_flags_t usageflags;
-
   /* The keyReference and a flag telling whether it is valid. */
   unsigned long key_reference;
-  int key_reference_valid;
 
-  /* Set to true if a length and offset is available. */
-  int have_off;
   /* The offset and length of the object.  They are only valid if
-     HAVE_OFF is true and set to 0 if HAVE_OFF is false. */
+   * HAVE_OFF is true otherwise they are set to 0. */
   unsigned long off, len;
 
   /* The length of the path as given in the PrKDF and the path itself.
@@ -209,6 +253,9 @@ struct aodf_object_s
   /* Link to next item when used in a linked list. */
   struct aodf_object_s *next;
 
+  /* Flags to indicate whether fields are valid.  */
+  unsigned int have_off:1;
+
   /* Length and allocated buffer with the Id of this object. */
   size_t objidlen;
   unsigned char *objid;
@@ -218,6 +265,9 @@ struct aodf_object_s
   size_t authidlen;
   unsigned char *authid;
 
+  /* The file ID of this AODF.  */
+  unsigned short fid;
+
   /* The PIN Flags. */
   struct
   {
@@ -256,9 +306,6 @@ struct aodf_object_s
   char pad_char;
   int pad_char_valid;
 
-
-  /* Set to true if a length and offset is available. */
-  int have_off;
   /* The offset and length of the object.  They are only valid if
      HAVE_OFF is true and set to 0 if HAVE_OFF is false. */
   unsigned long off, len;
@@ -279,9 +326,12 @@ struct app_local_s
      hierarchy.  Thus we assume this is directly below the MF.  */
   unsigned short home_df;
 
-  /* The type of the card. */
+  /* The type of the card's OS. */
   card_type_t card_type;
 
+  /* The vendor's product.  */
+  card_product_t card_product;
+
   /* Flag indicating whether we may use direct path selection. */
   int direct_path_selection;
 
@@ -304,6 +354,9 @@ struct app_local_s
   unsigned char *serialno;
   size_t serialnolen;
 
+  /* The manufacturerID from the TokenInfo EF.  Malloced. */
+  char *manufacturer_id;
+
   /* Information on all certificates. */
   cdf_object_t certificate_info;
   /* Information on all trusted certificates. */
@@ -321,8 +374,11 @@ struct app_local_s
 
 
 /*** Local prototypes.  ***/
+static gpg_error_t keygrip_from_prkdf (app_t app, prkdf_object_t prkdf);
 static gpg_error_t readcert_by_cdf (app_t app, cdf_object_t cdf,
                                     unsigned char **r_cert, size_t *r_certlen);
+static char *get_dispserialno (app_t app, prkdf_object_t prkdf);
+static gpg_error_t do_getattr (app_t app, ctrl_t ctrl, const char *name);
 
 
 
@@ -347,6 +403,8 @@ release_prkdflist (prkdf_object_t a)
   while (a)
     {
       prkdf_object_t tmp = a->next;
+      xfree (a->common_name);
+      xfree (a->serial_number);
       xfree (a->objid);
       xfree (a->authid);
       xfree (a);
@@ -391,6 +449,7 @@ do_deinit (app_t app)
       release_cdflist (app->app_local->useful_certificate_info);
       release_prkdflist (app->app_local->private_key_info);
       release_aodflist (app->app_local->auth_object_info);
+      xfree (app->app_local->manufacturer_id);
       xfree (app->app_local->serialno);
       xfree (app->app_local);
       app->app_local = NULL;
@@ -412,14 +471,14 @@ select_and_read_binary (int slot, unsigned short efid, const char *efid_desc,
   err = iso7816_select_file (slot, efid, 0);
   if (err)
     {
-      log_error ("error selecting %s (0x%04X): %s\n",
+      log_error ("p15: error selecting %s (0x%04X): %s\n",
                  efid_desc, efid, gpg_strerror (err));
       return err;
     }
   err = iso7816_read_binary (slot, 0, 0, buffer, buflen);
   if (err)
     {
-      log_error ("error reading %s (0x%04X): %s\n",
+      log_error ("p15: error reading %s (0x%04X): %s\n",
                  efid_desc, efid, gpg_strerror (err));
       return err;
     }
@@ -439,14 +498,14 @@ select_ef_by_path (app_t app, const unsigned short *path, size_t pathlen)
     return gpg_error (GPG_ERR_INV_VALUE);
 
   if (pathlen && *path != 0x3f00 )
-    log_debug ("WARNING: relative path selection not yet implemented\n");
+    log_error ("p15: warning: relative path selection not yet implemented\n");
 
   if (app->app_local->direct_path_selection)
     {
       err = iso7816_select_path (app->slot, path+1, pathlen-1);
       if (err)
         {
-          log_error ("error selecting path ");
+          log_error ("p15: error selecting path ");
           for (j=0; j < pathlen; j++)
             log_printf ("%04hX", path[j]);
           log_printf (": %s\n", gpg_strerror (err));
@@ -464,7 +523,7 @@ select_ef_by_path (app_t app, const unsigned short *path, size_t pathlen)
           err = iso7816_select_file (app->slot, path[i], !(i+1 == pathlen));
           if (err)
             {
-              log_error ("error selecting part %d from path ", i);
+              log_error ("p15: error selecting part %d from path ", i);
               for (j=0; j < pathlen; j++)
                 log_printf ("%04hX", path[j]);
               log_printf (": %s\n", gpg_strerror (err));
@@ -492,35 +551,55 @@ parse_certid (app_t app, const char *certid,
   *r_objid = NULL;
   *r_objidlen = 0;
 
-  if (app->app_local->home_df)
-    snprintf (tmpbuf, sizeof tmpbuf,
-              "P15-%04X.", (unsigned int)(app->app_local->home_df & 0xffff));
-  else
-    strcpy (tmpbuf, "P15.");
-  if (strncmp (certid, tmpbuf, strlen (tmpbuf)) )
-    {
-      if (!strncmp (certid, "P15.", 4)
-          || (!strncmp (certid, "P15-", 4)
-              && hexdigitp (certid+4)
-              && hexdigitp (certid+5)
-              && hexdigitp (certid+6)
-              && hexdigitp (certid+7)
-              && certid[8] == '.'))
+  if (certid[0] != 'P' && strlen (certid) == 40)  /* This is a keygrip.  */
+    {
+      prkdf_object_t prkdf;
+
+      for (prkdf = app->app_local->private_key_info;
+           prkdf; prkdf = prkdf->next)
+        if (!keygrip_from_prkdf (app, prkdf)
+            && !strcmp (certid, prkdf->keygrip))
+          break;
+      if (!prkdf || !prkdf->objidlen || !prkdf->objid)
         return gpg_error (GPG_ERR_NOT_FOUND);
-      return gpg_error (GPG_ERR_INV_ID);
-    }
-  certid += strlen (tmpbuf);
-
-  for (s=certid, objidlen=0; hexdigitp (s); s++, objidlen++)
-    ;
-  if (*s || !objidlen || (objidlen%2))
-    return gpg_error (GPG_ERR_INV_ID);
-  objidlen /= 2;
-  objid = xtrymalloc (objidlen);
-  if (!objid)
-    return gpg_error_from_syserror ();
-  for (s=certid, i=0; i < objidlen; i++, s+=2)
-    objid[i] = xtoi_2 (s);
+      objidlen = prkdf->objidlen;
+      objid = xtrymalloc (objidlen);
+      if (!objid)
+        return gpg_error_from_syserror ();
+      memcpy (objid, prkdf->objid, prkdf->objidlen);
+    }
+  else /* This is a usual keyref.  */
+    {
+      if (app->app_local->home_df)
+        snprintf (tmpbuf, sizeof tmpbuf, "P15-%04X.",
+                  (unsigned int)(app->app_local->home_df & 0xffff));
+      else
+        strcpy (tmpbuf, "P15.");
+      if (strncmp (certid, tmpbuf, strlen (tmpbuf)) )
+        {
+          if (!strncmp (certid, "P15.", 4)
+              || (!strncmp (certid, "P15-", 4)
+                  && hexdigitp (certid+4)
+                  && hexdigitp (certid+5)
+                  && hexdigitp (certid+6)
+                  && hexdigitp (certid+7)
+                  && certid[8] == '.'))
+            return gpg_error (GPG_ERR_NOT_FOUND);
+          return gpg_error (GPG_ERR_INV_ID);
+        }
+      certid += strlen (tmpbuf);
+      for (s=certid, objidlen=0; hexdigitp (s); s++, objidlen++)
+        ;
+      if (*s || !objidlen || (objidlen%2))
+        return gpg_error (GPG_ERR_INV_ID);
+      objidlen /= 2;
+      objid = xtrymalloc (objidlen);
+      if (!objid)
+        return gpg_error_from_syserror ();
+      for (s=certid, i=0; i < objidlen; i++, s+=2)
+        objid[i] = xtoi_2 (s);
+    }
+
   *r_objid = objid;
   *r_objidlen = objidlen;
   return 0;
@@ -595,9 +674,9 @@ prkdf_object_from_keyidstr (app_t app, const char *keyidstr,
 
    A0 06 30 04 04 02 60 34  = Private Keys
    A4 06 30 04 04 02 60 35  = Certificates
-   A5 06 30 04 04 02 60 36  = TrustedCertificates
-   A7 06 30 04 04 02 60 37  = DataObjects
-   A8 06 30 04 04 02 60 38  = AuthObjects
+   A5 06 30 04 04 02 60 36  = Trusted Certificates
+   A7 06 30 04 04 02 60 37  = Data Objects
+   A8 06 30 04 04 02 60 38  = Auth Objects
 
    These are all PathOrObjects using the path CHOICE element.  The
    paths are octet strings of length 2.  Using this Path CHOICE
@@ -608,9 +687,10 @@ read_ef_odf (app_t app, unsigned short odf_fid)
 {
   gpg_error_t err;
   unsigned char *buffer, *p;
-  size_t buflen;
+  size_t buflen, n;
   unsigned short value;
   size_t offset;
+  unsigned short home_df = 0;
 
   err = select_and_read_binary (app->slot, odf_fid, "ODF", &buffer, &buflen);
   if (err)
@@ -618,10 +698,12 @@ read_ef_odf (app_t app, unsigned short odf_fid)
 
   if (buflen < 8)
     {
-      log_error ("error: ODF too short\n");
+      log_error ("p15: error: ODF too short\n");
       xfree (buffer);
       return gpg_error (GPG_ERR_INV_OBJ);
     }
+
+  home_df = app->app_local->home_df;
   p = buffer;
   while (buflen && *p && *p != 0xff)
     {
@@ -634,17 +716,35 @@ read_ef_odf (app_t app, unsigned short odf_fid)
       else if ( buflen >= 12
                 && (p[0] & 0xf0) == 0xA0
                 && !memcmp (p+1, "\x0a\x30\x08\x04\x06\x3F\x00", 7)
-                && app->app_local->home_df == ((p[8]<<8)|p[9]) )
+                && (!home_df || home_df == ((p[8]<<8)|p[9])) )
         {
+          /* If we do not know the home DF, we take it from the first
+           * ODF object.  Here are sample values:
+           * a0 0a 30 08 0406 3f00 5015 4401
+           * a1 0a 30 08 0406 3f00 5015 4411
+           * a4 0a 30 08 0406 3f00 5015 4441
+           * a5 0a 30 08 0406 3f00 5015 4451
+           * a8 0a 30 08 0406 3f00 5015 4481
+           * 00000000 */
+          if (!home_df)
+            {
+              home_df = ((p[8]<<8)|p[9]);
+              app->app_local->home_df = home_df;
+              log_info ("p15: application directory detected as 0x%04hX\n",
+                        home_df);
+              /* We assume that direct path selection is possible.  */
+              app->app_local->direct_path_selection = 1;
+            }
+
           /* We only allow a full path if all files are at the same
-             level and below the home directory.  The extend this we
+             level and below the home directory.  To extend this we
              would need to make use of new data type capable of
              keeping a full path. */
           offset = 10;
         }
       else
         {
-          log_error ("ODF format is not supported by us\n");
+          log_printhex (p, buflen, "p15: ODF format not supported:");
           xfree (buffer);
           return gpg_error (GPG_ERR_INV_OBJ);
         }
@@ -663,7 +763,8 @@ read_ef_odf (app_t app, unsigned short odf_fid)
         }
       if (value)
         {
-          log_error ("duplicate object type %d in ODF ignored\n",(p[0]&0x0f));
+          log_error ("p15: duplicate object type %d in ODF ignored\n",
+                     (p[0]&0x0f));
           continue;
         }
       value = ((p[offset] << 8) | p[offset+1]);
@@ -679,7 +780,8 @@ read_ef_odf (app_t app, unsigned short odf_fid)
         case 7: app->app_local->odf.data_objects = value; break;
         case 8: app->app_local->odf.auth_objects = value; break;
         default:
-          log_error ("unknown object type %d in ODF ignored\n", (p[0]&0x0f));
+          log_error ("p15: unknown object type %d in ODF ignored\n",
+                     (p[0]&0x0f));
         }
       offset += 2;
 
@@ -690,8 +792,16 @@ 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",
-              (unsigned int)buflen);
+    {
+      /* Print a warning if non-null garbage is left over.  */
+      for (n=0; n < buflen && !p[n]; n++)
+        ;
+      if (n < buflen)
+        {
+          log_info ("p15: warning: garbage detected at end of ODF: ");
+          log_printhex (p, buflen, "");
+        }
+    }
 
   xfree (buffer);
   return 0;
@@ -861,7 +971,8 @@ read_ef_prkdf (app_t app, unsigned short fid, prkdf_object_t *result)
         err = gpg_error (GPG_ERR_INV_OBJ);
       if (err)
         {
-          log_error ("error parsing PrKDF record: %s\n", gpg_strerror (err));
+          log_error ("p15: error parsing PrKDF record: %s\n",
+                     gpg_strerror (err));
           goto leave;
         }
       pp = p;
@@ -1202,38 +1313,41 @@ read_ef_prkdf (app_t app, unsigned short fid, prkdf_object_t *result)
         }
 
 
-      log_debug ("PrKDF %04hX: id=", fid);
-      for (i=0; i < prkdf->objidlen; i++)
-        log_printf ("%02X", prkdf->objid[i]);
-      log_printf (" path=");
-      for (i=0; i < prkdf->pathlen; i++)
-        log_printf ("%04hX", prkdf->path[i]);
-      if (prkdf->have_off)
-        log_printf ("[%lu/%lu]", prkdf->off, prkdf->len);
-      if (prkdf->authid)
-        {
-          log_printf (" authid=");
-          for (i=0; i < prkdf->authidlen; i++)
-            log_printf ("%02X", prkdf->authid[i]);
-        }
-      if (prkdf->key_reference_valid)
-        log_printf (" keyref=0x%02lX", prkdf->key_reference);
-      log_printf (" usage=");
-      s = "";
-      if (prkdf->usageflags.encrypt) log_printf ("%sencrypt", s), s = ",";
-      if (prkdf->usageflags.decrypt) log_printf ("%sdecrypt", s), s = ",";
-      if (prkdf->usageflags.sign   ) log_printf ("%ssign", s), s = ",";
-      if (prkdf->usageflags.sign_recover)
-        log_printf ("%ssign_recover", s), s = ",";
-      if (prkdf->usageflags.wrap   ) log_printf ("%swrap", s), s = ",";
-      if (prkdf->usageflags.unwrap ) log_printf ("%sunwrap", s), s = ",";
-      if (prkdf->usageflags.verify ) log_printf ("%sverify", s), s = ",";
-      if (prkdf->usageflags.verify_recover)
-        log_printf ("%sverify_recover", s), s = ",";
-      if (prkdf->usageflags.derive ) log_printf ("%sderive", s), s = ",";
-      if (prkdf->usageflags.non_repudiation)
-        log_printf ("%snon_repudiation", s), s = ",";
-      log_printf ("\n");
+      if (opt.verbose)
+        {
+          log_info ("p15: PrKDF %04hX: id=", fid);
+          for (i=0; i < prkdf->objidlen; i++)
+            log_printf ("%02X", prkdf->objid[i]);
+          log_printf (" path=");
+          for (i=0; i < prkdf->pathlen; i++)
+            log_printf ("%s%04hX", i?"/":"",prkdf->path[i]);
+          if (prkdf->have_off)
+            log_printf ("[%lu/%lu]", prkdf->off, prkdf->len);
+          if (prkdf->authid)
+            {
+              log_printf (" authid=");
+              for (i=0; i < prkdf->authidlen; i++)
+                log_printf ("%02X", prkdf->authid[i]);
+            }
+          if (prkdf->key_reference_valid)
+            log_printf (" keyref=0x%02lX", prkdf->key_reference);
+          log_info ("p15:             usage=");
+          s = "";
+          if (prkdf->usageflags.encrypt) log_printf ("%sencrypt", s), s = ",";
+          if (prkdf->usageflags.decrypt) log_printf ("%sdecrypt", s), s = ",";
+          if (prkdf->usageflags.sign   ) log_printf ("%ssign", s), s = ",";
+          if (prkdf->usageflags.sign_recover)
+            log_printf ("%ssign_recover", s), s = ",";
+          if (prkdf->usageflags.wrap   ) log_printf ("%swrap", s), s = ",";
+          if (prkdf->usageflags.unwrap ) log_printf ("%sunwrap", s), s = ",";
+          if (prkdf->usageflags.verify ) log_printf ("%sverify", s), s = ",";
+          if (prkdf->usageflags.verify_recover)
+            log_printf ("%sverify_recover", s), s = ",";
+          if (prkdf->usageflags.derive ) log_printf ("%sderive", s), s = ",";
+          if (prkdf->usageflags.non_repudiation)
+            log_printf ("%snon_repudiation", s), s = ",";
+          log_printf ("\n");
+        }
 
       /* Put it into the list. */
       prkdf->next = prkdflist;
@@ -1242,7 +1356,7 @@ read_ef_prkdf (app_t app, unsigned short fid, prkdf_object_t *result)
       continue; /* Ready. */
 
     parse_error:
-      log_error ("error parsing PrKDF record (%d): %s - skipped\n",
+      log_error ("p15: error parsing PrKDF record (%d): %s - skipped\n",
                  where, errstr? errstr : gpg_strerror (err));
       if (prkdf)
         {
@@ -1309,7 +1423,7 @@ read_ef_cdf (app_t app, unsigned short fid, cdf_object_t *result)
         err = gpg_error (GPG_ERR_INV_OBJ);
       if (err)
         {
-          log_error ("error parsing CDF record: %s\n", gpg_strerror (err));
+          log_error ("p15: error parsing CDF record: %s\n", gpg_strerror (err));
           goto leave;
         }
       pp = p;
@@ -1470,15 +1584,18 @@ read_ef_cdf (app_t app, unsigned short fid, cdf_object_t *result)
           cdf->len = ul;
         }
 
-      log_debug ("CDF %04hX: id=", fid);
-      for (i=0; i < cdf->objidlen; i++)
-        log_printf ("%02X", cdf->objid[i]);
-      log_printf (" path=");
-      for (i=0; i < cdf->pathlen; i++)
-        log_printf ("%04hX", cdf->path[i]);
-      if (cdf->have_off)
-        log_printf ("[%lu/%lu]", cdf->off, cdf->len);
-      log_printf ("\n");
+      if (opt.verbose)
+        {
+          log_info ("p15: CDF %04hX: id=", fid);
+          for (i=0; i < cdf->objidlen; i++)
+            log_printf ("%02X", cdf->objid[i]);
+          log_printf (" path=");
+          for (i=0; i < cdf->pathlen; i++)
+            log_printf ("%s%04hX", i?"/":"", cdf->path[i]);
+          if (cdf->have_off)
+            log_printf ("[%lu/%lu]", cdf->off, cdf->len);
+          log_printf ("\n");
+        }
 
       /* Put it into the list. */
       cdf->next = cdflist;
@@ -1487,7 +1604,7 @@ read_ef_cdf (app_t app, unsigned short fid, cdf_object_t *result)
       continue; /* Ready. */
 
     parse_error:
-      log_error ("error parsing CDF record (%d): %s - skipped\n",
+      log_error ("p15: error parsing CDF record (%d): %s - skipped\n",
                  where, errstr? errstr : gpg_strerror (err));
       xfree (cdf);
       err = 0;
@@ -1583,7 +1700,8 @@ read_ef_aodf (app_t app, unsigned short fid, aodf_object_t *result)
         err = gpg_error (GPG_ERR_INV_OBJ);
       if (err)
         {
-          log_error ("error parsing AODF record: %s\n", gpg_strerror (err));
+          log_error ("p15: error parsing AODF record: %s\n",
+                     gpg_strerror (err));
           goto leave;
         }
       pp = p;
@@ -1595,6 +1713,7 @@ read_ef_aodf (app_t app, unsigned short fid, aodf_object_t *result)
       aodf = xtrycalloc (1, sizeof *aodf);
       if (!aodf)
         goto no_core;
+      aodf->fid = fid;
 
       /* Parse the commonObjectAttributes.  */
       where = __LINE__;
@@ -2057,73 +2176,77 @@ read_ef_aodf (app_t app, unsigned short fid, aodf_object_t *result)
          extensions of pkcs#15. */
 
     ready:
-      log_debug ("AODF %04hX: id=", fid);
-      for (i=0; i < aodf->objidlen; i++)
-        log_printf ("%02X", aodf->objid[i]);
-      if (aodf->authid)
-        {
-          log_printf (" authid=");
-          for (i=0; i < aodf->authidlen; i++)
-            log_printf ("%02X", aodf->authid[i]);
-        }
-      log_printf (" flags=");
-      s = "";
-      if (aodf->pinflags.case_sensitive)
-        log_printf ("%scase_sensitive", s), s = ",";
-      if (aodf->pinflags.local)
-        log_printf ("%slocal", s), s = ",";
-      if (aodf->pinflags.change_disabled)
-        log_printf ("%schange_disabled", s), s = ",";
-      if (aodf->pinflags.unblock_disabled)
-        log_printf ("%sunblock_disabled", s), s = ",";
-      if (aodf->pinflags.initialized)
-        log_printf ("%sinitialized", s), s = ",";
-      if (aodf->pinflags.needs_padding)
-        log_printf ("%sneeds_padding", s), s = ",";
-      if (aodf->pinflags.unblocking_pin)
-        log_printf ("%sunblocking_pin", s), s = ",";
-      if (aodf->pinflags.so_pin)
-        log_printf ("%sso_pin", s), s = ",";
-      if (aodf->pinflags.disable_allowed)
-        log_printf ("%sdisable_allowed", s), s = ",";
-      if (aodf->pinflags.integrity_protected)
-        log_printf ("%sintegrity_protected", s), s = ",";
-      if (aodf->pinflags.confidentiality_protected)
-        log_printf ("%sconfidentiality_protected", s), s = ",";
-      if (aodf->pinflags.exchange_ref_data)
-        log_printf ("%sexchange_ref_data", s), s = ",";
-      {
-        char numbuf[50];
-        switch (aodf->pintype)
+      if (opt.verbose)
+        {
+          log_info ("p15: AODF %04hX: id=", fid);
+          for (i=0; i < aodf->objidlen; i++)
+            log_printf ("%02X", aodf->objid[i]);
+          if (aodf->authid)
+            {
+              log_printf (" authid=");
+              for (i=0; i < aodf->authidlen; i++)
+                log_printf ("%02X", aodf->authid[i]);
+            }
+          if (aodf->pin_reference_valid)
+            log_printf (" pinref=0x%02lX", aodf->pin_reference);
+          if (aodf->pathlen)
+            {
+              log_printf (" path=");
+              for (i=0; i < aodf->pathlen; i++)
+                log_printf ("%s%04hX", i?"/":"",aodf->path[i]);
+              if (aodf->have_off)
+                log_printf ("[%lu/%lu]", aodf->off, aodf->len);
+            }
+          log_printf (" min=%lu", aodf->min_length);
+          log_printf (" stored=%lu", aodf->stored_length);
+          if (aodf->max_length_valid)
+            log_printf (" max=%lu", aodf->max_length);
+          if (aodf->pad_char_valid)
+            log_printf (" pad=0x%02x", aodf->pad_char);
+
+          log_info ("p15:            flags=");
+          s = "";
+          if (aodf->pinflags.case_sensitive)
+            log_printf ("%scase_sensitive", s), s = ",";
+          if (aodf->pinflags.local)
+            log_printf ("%slocal", s), s = ",";
+          if (aodf->pinflags.change_disabled)
+            log_printf ("%schange_disabled", s), s = ",";
+          if (aodf->pinflags.unblock_disabled)
+            log_printf ("%sunblock_disabled", s), s = ",";
+          if (aodf->pinflags.initialized)
+            log_printf ("%sinitialized", s), s = ",";
+          if (aodf->pinflags.needs_padding)
+            log_printf ("%sneeds_padding", s), s = ",";
+          if (aodf->pinflags.unblocking_pin)
+            log_printf ("%sunblocking_pin", s), s = ",";
+          if (aodf->pinflags.so_pin)
+            log_printf ("%sso_pin", s), s = ",";
+          if (aodf->pinflags.disable_allowed)
+            log_printf ("%sdisable_allowed", s), s = ",";
+          if (aodf->pinflags.integrity_protected)
+            log_printf ("%sintegrity_protected", s), s = ",";
+          if (aodf->pinflags.confidentiality_protected)
+            log_printf ("%sconfidentiality_protected", s), s = ",";
+          if (aodf->pinflags.exchange_ref_data)
+            log_printf ("%sexchange_ref_data", s), s = ",";
           {
-          case PIN_TYPE_BCD: s = "bcd"; break;
-          case PIN_TYPE_ASCII_NUMERIC: s = "ascii-numeric"; break;
-          case PIN_TYPE_UTF8: s = "utf8"; break;
-          case PIN_TYPE_HALF_NIBBLE_BCD: s = "half-nibble-bcd"; break;
-          case PIN_TYPE_ISO9564_1: s = "iso9564-1"; break;
-          default:
-            sprintf (numbuf, "%lu", (unsigned long)aodf->pintype);
-            s = numbuf;
+            char numbuf[50];
+            switch (aodf->pintype)
+              {
+              case PIN_TYPE_BCD: s = "bcd"; break;
+              case PIN_TYPE_ASCII_NUMERIC: s = "ascii-numeric"; break;
+              case PIN_TYPE_UTF8: s = "utf8"; break;
+              case PIN_TYPE_HALF_NIBBLE_BCD: s = "half-nibble-bcd"; break;
+              case PIN_TYPE_ISO9564_1: s = "iso9564-1"; break;
+              default:
+                sprintf (numbuf, "%lu", (unsigned long)aodf->pintype);
+                s = numbuf;
+              }
+            log_printf (" type=%s", s);
           }
-        log_printf (" type=%s", s);
-      }
-      log_printf (" min=%lu", aodf->min_length);
-      log_printf (" stored=%lu", aodf->stored_length);
-      if (aodf->max_length_valid)
-        log_printf (" max=%lu", aodf->max_length);
-      if (aodf->pad_char_valid)
-        log_printf (" pad=0x%02x", aodf->pad_char);
-      if (aodf->pin_reference_valid)
-        log_printf (" pinref=0x%02lX", aodf->pin_reference);
-      if (aodf->pathlen)
-        {
-          log_printf (" path=");
-          for (i=0; i < aodf->pathlen; i++)
-            log_printf ("%04hX", aodf->path[i]);
-          if (aodf->have_off)
-            log_printf ("[%lu/%lu]", aodf->off, aodf->len);
+          log_printf ("\n");
         }
-      log_printf ("\n");
 
       /* Put it into the list. */
       aodf->next = aodflist;
@@ -2137,7 +2260,7 @@ read_ef_aodf (app_t app, unsigned short fid, aodf_object_t *result)
       goto leave;
 
     parse_error:
-      log_error ("error parsing AODF record (%d): %s - skipped\n",
+      log_error ("p15: error parsing AODF record (%d): %s - skipped\n",
                  where, errstr? errstr : gpg_strerror (err));
       err = 0;
       release_aodf_object (aodf);
@@ -2153,6 +2276,62 @@ read_ef_aodf (app_t app, unsigned short fid, aodf_object_t *result)
 }
 
 
+/* Print the BIT STRING with the tokenflags from the TokenInfo.  */
+static void
+print_tokeninfo_tokenflags (const unsigned char *der, size_t derlen)
+{
+  unsigned int bits, mask;
+  int i, unused, full;
+  int other = 0;
+
+  if (!derlen)
+    {
+      log_printf (" [invalid object]");
+      return;
+    }
+
+  unused = *der++; derlen--;
+  if ((!derlen && unused) || unused/8 > derlen)
+    {
+      log_printf (" [wrong encoding]");
+      return;
+    }
+  full = derlen - (unused+7)/8;
+  unused %= 8;
+  mask = 0;
+  for (i=1; unused; i <<= 1, unused--)
+    mask |= i;
+
+  /* First octet */
+  if (derlen)
+    {
+      bits = *der++; derlen--;
+      if (full)
+        full--;
+      else
+        {
+          bits &= ~mask;
+          mask = 0;
+        }
+    }
+  else
+    bits = 0;
+  if ((bits & 0x80)) log_printf (" readonly");
+  if ((bits & 0x40)) log_printf (" loginRequired");
+  if ((bits & 0x20)) log_printf (" prnGeneration");
+  if ((bits & 0x10)) log_printf (" eidCompliant");
+  if ((bits & 0x08)) other = 1;
+  if ((bits & 0x04)) other = 1;
+  if ((bits & 0x02)) other = 1;
+  if ((bits & 0x01)) other = 1;
+
+  /* Next octet.  */
+  if (derlen)
+    other = 1;
+
+  if (other)
+    log_printf (" [unknown]");
+}
 
 
 
@@ -2216,6 +2395,10 @@ read_ef_tokeninfo (app_t app)
   int class, tag, constructed, ndef;
   unsigned long ul;
 
+  xfree (app->app_local->manufacturer_id);
+  app->app_local->manufacturer_id = NULL;
+  app->app_local->card_product = CARD_PRODUCT_UNKNOWN;
+
   err = select_and_read_binary (app->slot, 0x5032, "TokenInfo",
                                 &buffer, &buflen);
   if (err)
@@ -2230,7 +2413,7 @@ read_ef_tokeninfo (app_t app)
     err = gpg_error (GPG_ERR_INV_OBJ);
   if (err)
     {
-      log_error ("error parsing TokenInfo: %s\n", gpg_strerror (err));
+      log_error ("p15: error parsing TokenInfo: %s\n", gpg_strerror (err));
       goto leave;
     }
 
@@ -2252,11 +2435,13 @@ read_ef_tokeninfo (app_t app)
     }
   if (ul)
     {
-      log_error ("invalid version %lu in TokenInfo\n", ul);
+      log_error ("p15: invalid version %lu in TokenInfo\n", ul);
       err = gpg_error (GPG_ERR_INV_OBJ);
       goto leave;
     }
 
+  if (opt.verbose)
+    log_info ("p15: TokenInfo:\n");
   /* serialNumber.  */
   err = parse_ber_header (&p, &n, &class, &tag, &constructed,
                           &ndef, &objlen, &hdrlen);
@@ -2274,7 +2459,68 @@ read_ef_tokeninfo (app_t app)
     }
   memcpy (app->app_local->serialno, p, objlen);
   app->app_local->serialnolen = objlen;
-  log_printhex ("Serialnumber from EF(TokenInfo) is:", p, objlen);
+  if (opt.verbose)
+    {
+      /* (We use a separate log_info to avoid the "DBG:" prefix.)  */
+      log_info ("p15:  serialNumber .: ");
+      log_printhex (p, objlen, "");
+    }
+  p += objlen;
+  n -= objlen;
+
+  /* Is there an optional manufacturerID?  */
+  err = parse_ber_header (&p, &n, &class, &tag, &constructed,
+                          &ndef, &objlen, &hdrlen);
+  if (!err && (objlen > n || !objlen))
+    err = gpg_error (GPG_ERR_INV_OBJ);
+  if (err)
+    goto leave;
+  if (class == CLASS_UNIVERSAL && tag == TAG_UTF8_STRING)
+    {
+      if (opt.verbose)
+        log_info ("p15:  manufacturerID: %.*s\n", (int)objlen, p);
+      app->app_local->manufacturer_id = percent_data_escape (0, NULL,
+                                                             p, objlen);
+      p += objlen;
+      n -= objlen;
+      /* Get next TLV.  */
+      err = parse_ber_header (&p, &n, &class, &tag, &constructed,
+                              &ndef, &objlen, &hdrlen);
+      if (!err && (objlen > n || !objlen))
+        err = gpg_error (GPG_ERR_INV_OBJ);
+      if (err)
+        goto leave;
+    }
+  if (class == CLASS_CONTEXT && tag == 0)
+    {
+      if (opt.verbose)
+        log_info ("p15:  label ........: %.*s\n", (int)objlen, p);
+      if (objlen > 15 && !memcmp (p, "D-TRUST Card V3", 15)
+          && app->app_local->card_type == CARD_TYPE_CARDOS_50)
+        app->app_local->card_product = CARD_PRODUCT_DTRUST;
+
+      p += objlen;
+      n -= objlen;
+      /* Get next TLV.  */
+      err = parse_ber_header (&p, &n, &class, &tag, &constructed,
+                              &ndef, &objlen, &hdrlen);
+      if (!err && (objlen > n || !objlen))
+        err = gpg_error (GPG_ERR_INV_OBJ);
+      if (err)
+        goto leave;
+    }
+  /* The next is the mandatory tokenflags object.  */
+  if (class == CLASS_UNIVERSAL && tag == TAG_BIT_STRING)
+    {
+      if (opt.verbose)
+        {
+          log_info ("p15:  tokenflags ...:");
+          print_tokeninfo_tokenflags (p, objlen);
+          log_printf ("\n");
+        }
+      p += objlen;
+      n -= objlen;
+    }
 
  leave:
   xfree (buffer);
@@ -2386,21 +2632,31 @@ send_certinfo (app_t app, ctrl_t ctrl, const char *certtype,
 
 
 /* Get the keygrip of the private key object PRKDF.  On success the
-   keygrip gets returned in the caller provided 41 byte buffer
  R_GRIPSTR. */
+ * keygrip, the algo and the length are stored in the KEYGRIP,
* KEYALGO, and KEYNBITS fields of the PRKDF object.  */
 static gpg_error_t
-keygripstr_from_prkdf (app_t app, prkdf_object_t prkdf, char *r_gripstr)
+keygrip_from_prkdf (app_t app, prkdf_object_t prkdf)
 {
   gpg_error_t err;
   cdf_object_t cdf;
   unsigned char *der;
   size_t derlen;
   ksba_cert_t cert;
+  gcry_sexp_t s_pkey = NULL;
+
+  /* Easy if we got a cached version.  */
+  if (prkdf->keygrip_valid)
+    return 0;
+
+  xfree (prkdf->common_name);
+  prkdf->common_name = NULL;
+  xfree (prkdf->serial_number);
+  prkdf->serial_number = NULL;
 
   /* FIXME: We should check whether a public key directory file and a
      matching public key for PRKDF is available.  This should make
      extraction of the key much easier.  My current test card doesn't
-     have one, so we can only use the fallback solution bu looking for
+     have one, so we can only use the fallback solution by looking for
      a matching certificate and extract the key from there. */
 
   /* Look for a matching certificate. A certificate matches if the Id
@@ -2420,67 +2676,172 @@ keygripstr_from_prkdf (app_t app, prkdf_object_t prkdf, char *r_gripstr)
           && !memcmp (cdf->objid, prkdf->objid, prkdf->objidlen))
         break;
   if (!cdf)
-    return gpg_error (GPG_ERR_NOT_FOUND);
+    {
+      err = gpg_error (GPG_ERR_NOT_FOUND);
+      goto leave;
+    }
 
   err = readcert_by_cdf (app, cdf, &der, &derlen);
   if (err)
-    return err;
+    goto leave;
 
   err = ksba_cert_new (&cert);
   if (!err)
     err = ksba_cert_init_from_mem (cert, der, derlen);
   xfree (der);
   if (!err)
-    err = app_help_get_keygrip_string (cert, r_gripstr);
+    err = app_help_get_keygrip_string (cert, prkdf->keygrip, &s_pkey);
+  if (!err)
+    {
+      /* Try to get the CN and the SerialNumber from the certificate;
+       * we use a very simple approach here which should work in many
+       * cases.  Eventually we should add a rfc-2253 parser into
+       * libksba to make it easier to parse such a string.
+       *
+       * First example string:
+       *   "CN=Otto Schily,O=Miniluv,C=DE"
+       * Second example string:
+       *   "2.5.4.5=#445452323030303236333531,2.5.4.4=#4B6F6368,"
+       *   "2.5.4.42=#5765726E6572,CN=Werner Koch,OU=For testing"
+       *   " purposes only!,O=Testorganisation,C=DE"
+       */
+      char *dn = ksba_cert_get_subject (cert, 0);
+      if (dn)
+        {
+          char *p, *pend, *buf;
+
+          p = strstr (dn, "CN=");
+          if (p && (p==dn || p[-1] == ','))
+            {
+              p += 3;
+              if (!(pend = strchr (p, ',')))
+                pend = p + strlen (p);
+              if (pend && pend > p
+                  && (prkdf->common_name = xtrymalloc ((pend - p) + 1)))
+                {
+                  memcpy (prkdf->common_name, p, pend-p);
+                  prkdf->common_name[pend-p] = 0;
+                }
+            }
+          p = strstr (dn, "2.5.4.5=#"); /* OID of the SerialNumber */
+          if (p && (p==dn || p[-1] == ','))
+            {
+              p += 9;
+              if (!(pend = strchr (p, ',')))
+                pend = p + strlen (p);
+              if (pend && pend > p
+                  && (buf = xtrymalloc ((pend - p) + 1)))
+                {
+                  memcpy (buf, p, pend-p);
+                  buf[pend-p] = 0;
+                  if (!hex2str (buf, buf, strlen (buf)+1, NULL))
+                    xfree (buf);  /* Invalid hex encoding.  */
+                  else
+                    prkdf->serial_number = buf;
+                }
+            }
+          ksba_free (dn);
+        }
+    }
+
   ksba_cert_release (cert);
+  if (err)
+    goto leave;
+
+  prkdf->keyalgo = get_pk_algo_from_key (s_pkey);
+  if (!prkdf->keyalgo)
+    {
+      err = gpg_error (GPG_ERR_PUBKEY_ALGO);
+      goto leave;
+    }
+
+  prkdf->keynbits = gcry_pk_get_nbits (s_pkey);
+  if (!prkdf->keynbits)
+    {
+      err = gpg_error (GPG_ERR_PUBKEY_ALGO);
+      goto leave;
+    }
+
+  prkdf->keygrip_valid = 1;  /* Yeah, got everything.  */
 
+ leave:
+  gcry_sexp_release (s_pkey);
   return err;
 }
 
 
+/* Return a malloced keyref string for PRKDF.  Returns NULL on
+ * malloc failure.  */
+static char *
+keyref_from_prkdf (app_t app, prkdf_object_t prkdf)
+{
+  char *buf, *p;
+
+  buf = xtrymalloc (4 + 5 + prkdf->objidlen*2 + 1);
+  if (!buf)
+    return NULL;
+  p = stpcpy (buf, "P15");
+  if (app->app_local->home_df)
+    {
+      snprintf (p, 6, "-%04X",
+                (unsigned int)(app->app_local->home_df & 0xffff));
+      p += 5;
+    }
+  p = stpcpy (p, ".");
+  bin2hex (prkdf->objid, prkdf->objidlen, p);
+  return buf;
+}
 
 
 /* Helper to do_learn_status: Send information about all known
    keypairs back.  FIXME: much code duplication from
    send_certinfo(). */
 static gpg_error_t
-send_keypairinfo (app_t app, ctrl_t ctrl, prkdf_object_t keyinfo)
+send_keypairinfo (app_t app, ctrl_t ctrl, prkdf_object_t prkdf)
 {
   gpg_error_t err;
 
-  for (; keyinfo; keyinfo = keyinfo->next)
+  for (; prkdf; prkdf = prkdf->next)
     {
-      char gripstr[40+1];
-      char *buf, *p;
+      char *buf;
       int j;
 
-      buf = xtrymalloc (9 + keyinfo->objidlen*2 + 1);
+      buf = keyref_from_prkdf (app, prkdf);
       if (!buf)
         return gpg_error_from_syserror ();
-      p = stpcpy (buf, "P15");
-      if (app->app_local->home_df)
-        {
-          snprintf (p, 6, "-%04X",
-                    (unsigned int)(app->app_local->home_df & 0xffff));
-          p += 5;
-        }
-      p = stpcpy (p, ".");
-      bin2hex (keyinfo->objid, keyinfo->objidlen, p);
 
-      err = keygripstr_from_prkdf (app, keyinfo, gripstr);
+      err = keygrip_from_prkdf (app, prkdf);
       if (err)
         {
-          log_error ("can't get keygrip from ");
-          for (j=0; j < keyinfo->pathlen; j++)
-            log_printf ("%04hX", keyinfo->path[j]);
+          log_error ("p15: error getting keygrip from ");
+          for (j=0; j < prkdf->pathlen; j++)
+            log_printf ("%s%04hX", j?"/":"", prkdf->path[j]);
           log_printf (": %s\n", gpg_strerror (err));
         }
       else
         {
-          assert (strlen (gripstr) == 40);
+          char usage[5];
+          size_t usagelen = 0;
+
+          if (prkdf->usageflags.sign
+              || prkdf->usageflags.sign_recover
+              || prkdf->usageflags.non_repudiation)
+            usage[usagelen++] = 's';
+          if (prkdf->usageflags.sign
+              || prkdf->usageflags.sign_recover)
+            usage[usagelen++] = 'c';
+          if (prkdf->usageflags.decrypt
+              || prkdf->usageflags.unwrap)
+            usage[usagelen++] = 'e';
+          if (prkdf->usageflags.sign
+              || prkdf->usageflags.sign_recover)
+            usage[usagelen++] = 'a';
+
+          log_assert (strlen (prkdf->keygrip) == 40);
           send_status_info (ctrl, "KEYPAIRINFO",
-                            gripstr, 40,
+                            prkdf->keygrip, 2*KEYGRIP_LEN,
                             buf, strlen (buf),
+                            usage, usagelen,
                             NULL, (size_t)0);
         }
       xfree (buf);
@@ -2500,7 +2861,10 @@ do_learn_status (app_t app, ctrl_t ctrl, unsigned int flags)
     err = 0;
   else
     {
-      err = send_certinfo (app, ctrl, "100", app->app_local->certificate_info);
+      err = do_getattr (app, ctrl, "MANUFACTURER");
+      if (!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);
@@ -2553,14 +2917,18 @@ readcert_by_cdf (app_t app, cdf_object_t cdf,
   if (err)
     goto leave;
 
-  err = iso7816_read_binary (app->slot, cdf->off, cdf->len, &buffer, &buflen);
+  err = iso7816_read_binary_ext (app_get_slot (app), 1, cdf->off, cdf->len,
+                                 &buffer, &buflen);
   if (!err && (!buflen || *buffer == 0xff))
     err = gpg_error (GPG_ERR_NOT_FOUND);
   if (err)
     {
-      log_error ("error reading certificate with Id ");
+      log_error ("p15: error reading certificate id=");
       for (i=0; i < cdf->objidlen; i++)
         log_printf ("%02X", cdf->objid[i]);
+      log_printf (" at ");
+      for (i=0; i < cdf->pathlen; i++)
+        log_printf ("%s%04hX", i? "/":"", cdf->path[i]);
       log_printf (": %s\n", gpg_strerror (err));
       goto leave;
     }
@@ -2666,37 +3034,42 @@ static gpg_error_t
 do_getattr (app_t app, ctrl_t ctrl, const char *name)
 {
   gpg_error_t err;
+  prkdf_object_t prkdf;
 
-  if (!strcmp (name, "$AUTHKEYID"))
+  if (!strcmp (name, "$AUTHKEYID")
+      || !strcmp (name, "$ENCRKEYID")
+      || !strcmp (name, "$SIGNKEYID"))
     {
-      char *buf, *p;
-      prkdf_object_t prkdf;
+      char *buf;
 
-      /* We return the ID of the first private keycapable of
-         signing. */
+      /* We return the ID of the first private key capable of the
+       * requested action.  Note that we do not yet return
+       * non_repudiation keys for $SIGNKEYID because our D-Trust
+       * testcard uses rsaPSS, which is not supported by gpgsm and not
+       * covered by the VS-NfD approval.  */
       for (prkdf = app->app_local->private_key_info; prkdf;
            prkdf = prkdf->next)
-        if (prkdf->usageflags.sign)
-          break;
+        {
+          if (name[1] == 'A' && (prkdf->usageflags.sign
+                                 || prkdf->usageflags.sign_recover))
+            break;
+          else if (name[1] == 'E' && (prkdf->usageflags.decrypt
+                                      || prkdf->usageflags.unwrap))
+            break;
+          else if (name[1] == 'S' && (prkdf->usageflags.sign
+                                      || prkdf->usageflags.sign_recover))
+            break;
+        }
       if (prkdf)
         {
-          buf = xtrymalloc (9 + prkdf->objidlen*2 + 1);
+          buf = keyref_from_prkdf (app, prkdf);
           if (!buf)
             return gpg_error_from_syserror ();
-          p = stpcpy (buf, "P15");
-          if (app->app_local->home_df)
-            {
-              snprintf (p, 6, "-%04X",
-                        (unsigned int)(app->app_local->home_df & 0xffff));
-              p += 5;
-            }
-          p = stpcpy (p, ".");
-          bin2hex (prkdf->objid, prkdf->objidlen, p);
 
           send_status_info (ctrl, name, buf, strlen (buf), NULL, 0);
           xfree (buf);
-          return 0;
         }
+      return 0;
     }
   else if (!strcmp (name, "$DISPSERIALNO"))
     {
@@ -2716,7 +3089,8 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
             err = iso7816_read_binary (app->slot, 0, 0, &buffer, &buflen);
           if (err)
             {
-              log_error ("error accessing EF(ID): %s\n", gpg_strerror (err));
+              log_error ("p15: error accessing EF(ID): %s\n",
+                         gpg_strerror (err));
               return err;
             }
 
@@ -2736,7 +3110,41 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
             }
           xfree (buffer);
         }
-
+      else
+        {
+          /* We use the first private key object which has a serial
+           * number set.  If none was found, we parse the first
+           * object and see whether this has then a serial number.  */
+          for (prkdf = app->app_local->private_key_info; prkdf;
+               prkdf = prkdf->next)
+            if (prkdf->serial_number)
+              break;
+          if (!prkdf && app->app_local->private_key_info)
+            {
+              prkdf = app->app_local->private_key_info;
+              keygrip_from_prkdf (app, prkdf);
+              if (!prkdf->serial_number)
+                prkdf = NULL;
+            }
+          if (prkdf)
+            {
+              char *sn = get_dispserialno (app, prkdf);
+              /* Unless there is a bogus S/N in the cert we should
+               * have a suitable one from the cert here now.  */
+              err = send_status_printf (ctrl, name, "%s", sn);
+              xfree (sn);
+              return err;
+            }
+        }
+      /* No abbreviated serial number. */
+    }
+  else if (!strcmp (name, "MANUFACTURER"))
+    {
+      if (app->app_local->manufacturer_id)
+        return send_status_printf (ctrl, "MANUFACTURER", "0 %s",
+                                   app->app_local->manufacturer_id);
+      else
+        return 0;
     }
   return gpg_error (GPG_ERR_INV_NAME);
 }
@@ -2761,7 +3169,7 @@ micardo_mse (app_t app, unsigned short fid)
   err = iso7816_select_file (app->slot, 0x0013, 0);
   if (err)
     {
-      log_error ("error reading EF_keyD: %s\n", gpg_strerror (err));
+      log_error ("p15: error reading EF_keyD: %s\n", gpg_strerror (err));
       return err;
     }
 
@@ -2777,11 +3185,15 @@ micardo_mse (app_t app, unsigned short fid)
         break; /* ready */
       if (err)
         {
-          log_error ("error reading EF_keyD record: %s\n",
+          log_error ("p15: error reading EF_keyD record: %s\n",
                      gpg_strerror (err));
           return err;
         }
-      log_printhex ("keyD record:", buffer, buflen);
+      if (opt.verbose)
+        {
+          log_info (buffer, buflen, "p15: keyD record: ");
+          log_printhex (buffer, buflen, "");
+        }
       p = find_tlv (buffer, buflen, 0x83, &n);
       if (p && n == 4 && ((p[2]<<8)|p[3]) == fid)
         {
@@ -2803,7 +3215,7 @@ micardo_mse (app_t app, unsigned short fid)
     }
   if (se_num == -1)
     {
-      log_error ("CRT for keyfile %04hX not found\n", fid);
+      log_error ("p15: CRT for keyfile %04hX not found\n", fid);
       return gpg_error (GPG_ERR_NOT_FOUND);
     }
 
@@ -2814,7 +3226,7 @@ micardo_mse (app_t app, unsigned short fid)
       err = iso7816_manage_security_env (app->slot, 0xf3, se_num, NULL, 0);
       if (err)
         {
-          log_error ("restoring SE to %d failed: %s\n",
+          log_error ("p15: restoring SE to %d failed: %s\n",
                      se_num, gpg_strerror (err));
           return err;
         }
@@ -2829,7 +3241,7 @@ micardo_mse (app_t app, unsigned short fid)
   err = iso7816_manage_security_env (app->slot, 0x41, 0xb6, msebuf, 5);
   if (err)
     {
-      log_error ("setting SE to reference file %04hX failed: %s\n",
+      log_error ("p15: setting SE to reference file %04hX failed: %s\n",
                  refdata, gpg_strerror (err));
       return err;
     }
@@ -2838,40 +3250,415 @@ micardo_mse (app_t app, unsigned short fid)
 
 
 
-/* Handler for the PKSIGN command.
-
-   Create the signature and return the allocated result in OUTDATA.
-   If a PIN is required, the PINCB will be used to ask for the PIN;
-   that callback should return the PIN in an allocated buffer and
-   store that as the 3rd argument.  */
+/* Prepare the verification of the PIN for the key PRKDF by checking
+ * the AODF and selecting the key file.  KEYREF is used for error
+ * messages.  */
 static gpg_error_t
-do_sign (app_t app, const char *keyidstr, int hashalgo,
-         gpg_error_t (*pincb)(void*, const char *, char **),
-         void *pincb_arg,
-         const void *indata, size_t indatalen,
-         unsigned char **outdata, size_t *outdatalen )
+prepare_verify_pin (app_t app, const char *keyref,
+                    prkdf_object_t prkdf, aodf_object_t aodf)
 {
-  static unsigned char sha1_prefix[15] = /* Object ID is 1.3.14.3.2.26 */
-    { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03,
-      0x02, 0x1a, 0x05, 0x00, 0x04, 0x14 };
-  static unsigned char rmd160_prefix[15] = /* Object ID is 1.3.36.3.2.1 */
-    { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x24, 0x03,
-      0x02, 0x01, 0x05, 0x00, 0x04, 0x14 };
-
   gpg_error_t err;
   int i;
-  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.*/
-  int mse_done = 0;        /* Set to true if the MSE has been done. */
 
-  if (!keyidstr || !*keyidstr)
-    return gpg_error (GPG_ERR_INV_VALUE);
-  if (indatalen != 20 && indatalen != 16 && indatalen != 35 && indatalen != 36)
-    return gpg_error (GPG_ERR_INV_VALUE);
+  if (opt.verbose)
+    {
+      log_info ("p15: using AODF %04hX id=", aodf->fid);
+      for (i=0; i < aodf->objidlen; i++)
+        log_printf ("%02X", aodf->objid[i]);
+      log_printf ("\n");
+    }
+
+  if (aodf->authid && opt.verbose)
+    log_info ("p15: PIN is controlled by another authentication token\n");
+
+  if (aodf->pinflags.integrity_protected
+      || aodf->pinflags.confidentiality_protected)
+    {
+      log_error ("p15: "
+                 "PIN verification requires unsupported protection method\n");
+      return gpg_error (GPG_ERR_BAD_PIN_METHOD);
+    }
+  if (!aodf->stored_length && aodf->pinflags.needs_padding)
+    {
+      log_error ("p15: "
+                 "PIN verification requires padding but no length known\n");
+      return gpg_error (GPG_ERR_INV_CARD);
+    }
+
+
+  if (app->app_local->card_product == CARD_PRODUCT_DTRUST)
+    {
+      /* According to our protocol analysis we need to select a
+       * special AID here.  Before that the master file needs to be
+       * selected.  (RID A000000167 is assigned to IBM) */
+      static char const dtrust_aid[] =
+        { 0xA0, 0x00, 0x00, 0x01, 0x67, 0x45, 0x53, 0x49, 0x47, 0x4E };
+
+      err = iso7816_select_mf (app_get_slot (app));
+      if (!err)
+        err = iso7816_select_application (app_get_slot (app),
+                                          dtrust_aid, sizeof dtrust_aid, 0);
+      if (err)
+        log_error ("p15: error selecting D-TRUST's AID for key %s: %s\n",
+                   keyref, gpg_strerror (err));
+    }
+  else
+    {
+      /* Standard case: Select the key file.  Note that this may
+       * change the security environment thus we need to do it before
+       * PIN verification. */
+      err = select_ef_by_path (app, prkdf->path, prkdf->pathlen);
+      if (err)
+        log_error ("p15: error selecting file for key %s: %s\n",
+                   keyref, gpg_strerror (err));
+    }
+
+  return err;
+}
+
+
+static int
+any_control_or_space (const char *string)
+{
+  const unsigned char *s;
+
+  for (s = string; *string; string++)
+    if (*s <= 0x20 || *s >= 0x7f)
+      return 1;
+  return 0;
+}
+
+
+/* Return a malloced serial number to be shown to the user.  PRKDF is
+ * used to get it from a certificate; PRKDF may be NULL.  */
+static char *
+get_dispserialno (app_t app, prkdf_object_t prkdf)
+{
+  char *serial;
+
+  /* We prefer the SerialNumber RDN from the Subject-DN but we don't
+   * use it if it features a percent sign (special character in pin
+   * prompts) or has any control character.  */
+  if (prkdf && prkdf->serial_number && *prkdf->serial_number
+      && !strchr (prkdf->serial_number, '%')
+      && !any_control_or_space (prkdf->serial_number))
+    {
+      serial = xtrystrdup (prkdf->serial_number);
+    }
+  else
+    {
+      serial = app_get_serialno (app);
+    }
+  return serial;
+}
+
+
+/* Return an allocated string to be used as prompt.  Returns NULL on
+ * malloc error.  */
+static char *
+make_pin_prompt (app_t app, int remaining, const char *firstline,
+                 prkdf_object_t prkdf)
+{
+  char *serial, *tmpbuf, *result;
+
+  serial = get_dispserialno (app, prkdf);
+
+  /* TRANSLATORS: Put a \x1f right before a colon.  This can be
+   * used by pinentry to nicely align the names and values.  Keep
+   * the %s at the start and end of the string.  */
+  result = xtryasprintf (_("%s"
+                           "Number\x1f: %s%%0A"
+                           "Holder\x1f: %s"
+                           "%s"),
+                         "\x1e",
+                         serial,
+                         prkdf->common_name? prkdf->common_name: "",
+                         "");
+  xfree (serial);
+  if (!result)
+    return NULL; /* Out of core.  */
+
+  /* Append a "remaining attempts" info if needed.  */
+  if (remaining != -1 && remaining < 3)
+    {
+      char *rembuf;
+
+      /* TRANSLATORS: This is the number of remaining attempts to
+       * enter a PIN.  Use %%0A (double-percent,0A) for a linefeed. */
+      rembuf = xtryasprintf (_("Remaining attempts: %d"), remaining);
+      if (rembuf)
+        {
+          tmpbuf = strconcat (firstline, "%0A%0A", result,
+                              "%0A%0A", rembuf, NULL);
+          xfree (rembuf);
+        }
+      else
+        tmpbuf = NULL;
+      xfree (result);
+      result = tmpbuf;
+    }
+  else
+    {
+      tmpbuf = strconcat (firstline, "%0A%0A", result, NULL);
+      xfree (result);
+      result = tmpbuf;
+    }
+
+  return result;
+}
+
+
+/* Given the private key object PRKDF and its authentication object
+ * AODF ask for the PIN and verify that PIN.  */
+static gpg_error_t
+verify_pin (app_t app,
+            gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg,
+            prkdf_object_t prkdf, aodf_object_t aodf)
+{
+  gpg_error_t err;
+  char *pinvalue;
+  size_t pinvaluelen;
+  const char *label;
+  const char *errstr;
+  const char *s;
+  int remaining;
+  int pin_reference;
+  int i;
+
+  if (!aodf)
+    return 0;
+
+  pin_reference = aodf->pin_reference_valid? aodf->pin_reference : 0;
+
+  if (app->app_local->card_type == CARD_TYPE_CARDOS_50)
+    {
+      /* We know that this card supports a verify status check.  Note
+       * that in contrast to PIV cards ISO7816_VERIFY_NOT_NEEDED is
+       * not supported.  */
+      remaining = iso7816_verify_status (app_get_slot (app), pin_reference);
+      if (remaining < 0)
+        remaining = -1; /* We don't care about the concrete error.  */
+      if (remaining < 3)
+        {
+          if (remaining >= 0)
+            log_info ("p15: PIN has %d attempts left\n", remaining);
+          /* On error or if less than 3 better ask. */
+          prkdf->pin_verified = 0;
+        }
+    }
+  else
+    remaining = -1;  /* Unknown.  */
+
+  /* Check whether we already verified it.  */
+  if (prkdf->pin_verified)
+    return 0;  /* Already done.  */
+
+  if (prkdf->usageflags.non_repudiation
+      && (app->app_local->card_type == CARD_TYPE_BELPIC
+          || app->app_local->card_product == CARD_PRODUCT_DTRUST))
+    label = _("||Please enter the PIN for the key to create "
+              "qualified signatures.");
+  else
+    label = _("||Please enter the PIN for the standard keys.");
+
+  {
+    char *prompt = make_pin_prompt (app, remaining, label, prkdf);
+    if (!prompt)
+      err = gpg_error_from_syserror ();
+    else
+      err = pincb (pincb_arg, prompt, &pinvalue);
+    xfree (prompt);
+  }
+  if (err)
+    {
+      log_info ("p15: PIN callback returned error: %s\n", gpg_strerror (err));
+      return err;
+    }
+
+  /* We might need to cope with UTF8 things here.  Not sure how
+     min_length etc. are exactly defined, for now we take them as
+     a plain octet count. */
+  if (strlen (pinvalue) < aodf->min_length)
+    {
+      log_error ("p15: PIN is too short; minimum length is %lu\n",
+                 aodf->min_length);
+      err = gpg_error (GPG_ERR_BAD_PIN);
+    }
+  else if (aodf->stored_length && strlen (pinvalue) > aodf->stored_length)
+    {
+      /* This would otherwise truncate the PIN silently. */
+      log_error ("p15: PIN is too large; maximum length is %lu\n",
+                 aodf->stored_length);
+      err = gpg_error (GPG_ERR_BAD_PIN);
+    }
+  else if (aodf->max_length_valid && strlen (pinvalue) > aodf->max_length)
+    {
+      log_error ("p15: PIN is too large; maximum length is %lu\n",
+                 aodf->max_length);
+      err = gpg_error (GPG_ERR_BAD_PIN);
+    }
+
+  if (err)
+    {
+      xfree (pinvalue);
+      return err;
+    }
+
+  errstr = NULL;
+  err = 0;
+  switch (aodf->pintype)
+    {
+    case PIN_TYPE_BCD:
+    case PIN_TYPE_ASCII_NUMERIC:
+      for (s=pinvalue; digitp (s); s++)
+        ;
+      if (*s)
+        {
+          errstr = "Non-numeric digits found in PIN";
+          err = gpg_error (GPG_ERR_BAD_PIN);
+        }
+      break;
+    case PIN_TYPE_UTF8:
+      break;
+    case PIN_TYPE_HALF_NIBBLE_BCD:
+      errstr = "PIN type Half-Nibble-BCD is not supported";
+      break;
+    case PIN_TYPE_ISO9564_1:
+      errstr = "PIN type ISO9564-1 is not supported";
+      break;
+    default:
+      errstr = "Unknown PIN type";
+      break;
+    }
+  if (errstr)
+    {
+      log_error ("p15: can't verify PIN: %s\n", errstr);
+      xfree (pinvalue);
+      return err? err : gpg_error (GPG_ERR_BAD_PIN_METHOD);
+    }
+
+
+  if (aodf->pintype == PIN_TYPE_BCD )
+    {
+      char *paddedpin;
+      int ndigits;
+
+      for (ndigits=0, s=pinvalue; *s; ndigits++, s++)
+        ;
+      paddedpin = xtrymalloc (aodf->stored_length+1);
+      if (!paddedpin)
+        {
+          err = gpg_error_from_syserror ();
+          xfree (pinvalue);
+          return err;
+        }
+
+      i = 0;
+      paddedpin[i++] = 0x20 | (ndigits & 0x0f);
+      for (s=pinvalue; i < aodf->stored_length && *s && s[1]; s = s+2 )
+        paddedpin[i++] = (((*s - '0') << 4) | ((s[1] - '0') & 0x0f));
+      if (i < aodf->stored_length && *s)
+        paddedpin[i++] = (((*s - '0') << 4)
+                          |((aodf->pad_char_valid?aodf->pad_char:0)&0x0f));
+
+      if (aodf->pinflags.needs_padding)
+        {
+          while (i < aodf->stored_length)
+            paddedpin[i++] = aodf->pad_char_valid? aodf->pad_char : 0;
+        }
+
+      xfree (pinvalue);
+      pinvalue = paddedpin;
+      pinvaluelen = i;
+    }
+  else if (aodf->pinflags.needs_padding)
+    {
+      char *paddedpin;
+
+      paddedpin = xtrymalloc (aodf->stored_length+1);
+      if (!paddedpin)
+        {
+          err = gpg_error_from_syserror ();
+          xfree (pinvalue);
+          return err;
+        }
+      for (i=0, s=pinvalue; i < aodf->stored_length && *s; i++, s++)
+        paddedpin[i] = *s;
+      /* Not sure what padding char to use if none has been set.
+         For now we use 0x00; maybe a space would be better. */
+      for (; i < aodf->stored_length; i++)
+        paddedpin[i] = aodf->pad_char_valid? aodf->pad_char : 0;
+      paddedpin[i] = 0;
+      pinvaluelen = i;
+      xfree (pinvalue);
+      pinvalue = paddedpin;
+    }
+  else
+    pinvaluelen = strlen (pinvalue);
+
+  /* log_printhex (pinvalue, pinvaluelen, */
+  /*               "about to verify with ref %lu pin:", pin_reference); */
+  err = iso7816_verify (app_get_slot (app), pin_reference,
+                        pinvalue, pinvaluelen);
+  xfree (pinvalue);
+  if (err)
+    {
+      log_error ("p15: PIN verification failed: %s\n", gpg_strerror (err));
+      return err;
+    }
+  if (opt.verbose)
+    log_info ("p15: PIN verification succeeded\n");
+  prkdf->pin_verified = 1;
+
+  return 0;
+}
+
+
+
+
+/* Handler for the PKSIGN command.
+
+   Create the signature and return the allocated result in OUTDATA.
+   If a PIN is required, the PINCB will be used to ask for the PIN;
+   that callback should return the PIN in an allocated buffer and
+   store that as the 3rd argument.  */
+static gpg_error_t
+do_sign (app_t app, const char *keyidstr, int hashalgo,
+         gpg_error_t (*pincb)(void*, const char *, char **),
+         void *pincb_arg,
+         const void *indata, size_t indatalen,
+         unsigned char **outdata, size_t *outdatalen )
+{
+  static unsigned char sha256_prefix[19] = /* OID: 2.16.840.1.101.3.4.2.1 */
+    { 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48,
+      0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20 };
+  static unsigned char sha1_prefix[15] = /* Object ID is 1.3.14.3.2.26 */
+    { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03,
+      0x02, 0x1a, 0x05, 0x00, 0x04, 0x14 };
+  static unsigned char rmd160_prefix[15] = /* Object ID is 1.3.36.3.2.1 */
+    { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x24, 0x03,
+      0x02, 0x01, 0x05, 0x00, 0x04, 0x14 };
+
+  gpg_error_t err;
+  unsigned char data[32+19]; /* Must be large enough for a SHA-256 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.*/
+  int mse_done = 0;        /* Set to true if the MSE has been done. */
+  unsigned int hashlen;    /* Length of the hash.  */
+  unsigned int datalen;    /* Length of the data to sign (prefix+hash).  */
+  unsigned char *dataptr;
+  int exmode, le_value;
+
+
+  if (!keyidstr || !*keyidstr)
+    return gpg_error (GPG_ERR_INV_VALUE);
+  if (indatalen != 20 && indatalen != 16
+      && indatalen != 35 && indatalen != 36
+      && indatalen != (32+19))
+    return gpg_error (GPG_ERR_INV_VALUE);
 
   err = prkdf_object_from_keyidstr (app, keyidstr, &prkdf);
   if (err)
@@ -2879,13 +3666,13 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
   if (!(prkdf->usageflags.sign || prkdf->usageflags.sign_recover
         ||prkdf->usageflags.non_repudiation))
     {
-      log_error ("key %s may not be used for signing\n", keyidstr);
+      log_error ("p15: key %s may not be used for signing\n", keyidstr);
       return gpg_error (GPG_ERR_WRONG_KEY_USAGE);
     }
 
   if (!prkdf->authid)
     {
-      log_error ("no authentication object defined for %s\n", keyidstr);
+      log_error ("p15: no authentication object defined for %s\n", keyidstr);
       /* fixme: we might want to go ahead and do without PIN
          verification. */
       return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
@@ -2898,37 +3685,25 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
       break;
   if (!aodf)
     {
-      log_error ("authentication object for %s missing\n", keyidstr);
-      return gpg_error (GPG_ERR_INV_CARD);
-    }
-  if (aodf->authid)
-    {
-      log_error ("PIN verification is protected by an "
-                 "additional authentication token\n");
-      return gpg_error (GPG_ERR_BAD_PIN_METHOD);
-    }
-  if (aodf->pinflags.integrity_protected
-      || aodf->pinflags.confidentiality_protected)
-    {
-      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)
-    {
-      log_error ("PIN verification requires padding but no length known\n");
+      log_error ("p15: authentication object for %s missing\n", keyidstr);
       return gpg_error (GPG_ERR_INV_CARD);
     }
 
-  /* Select the key file.  Note that this may change the security
-     environment thus we do it before PIN verification. */
-  err = select_ef_by_path (app, prkdf->path, prkdf->pathlen);
+  /* We need some more info about the key - get the keygrip to
+   * populate these fields.  */
+  err = keygrip_from_prkdf (app, prkdf);
   if (err)
     {
-      log_error ("error selecting file for key %s: %s\n",
-                 keyidstr, gpg_strerror (errno));
+      log_error ("p15: keygrip_from_prkdf failed: %s\n", gpg_strerror (err));
       return err;
     }
 
+  /* Prepare PIN verification.  This is split so that we can do
+   * MSE operation for some task after having selected the key file but
+   * before sending the verify APDU.  */
+  err = prepare_verify_pin (app, keyidstr, prkdf, aodf);
+  if (err)
+    return err;
 
   /* Due to the fact that the non-repudiation signature on a BELPIC
      card requires a verify immediately before the DSO we set the
@@ -2956,162 +3731,16 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
     }
   if (err)
     {
-      log_error ("MSE failed: %s\n", gpg_strerror (err));
+      log_error ("p15: MSE failed: %s\n", gpg_strerror (err));
       return err;
     }
 
+  /* Now that we have all the information available run the actual PIN
+   * verification.*/
+  err = verify_pin (app, pincb, pincb_arg, prkdf, aodf);
+  if (err)
+    return err;
 
-  /* Now that we have all the information available, prepare and run
-     the PIN verification.*/
-  if (1)
-    {
-      char *pinvalue;
-      size_t pinvaluelen;
-      const char *errstr;
-      const char *s;
-
-      if (prkdf->usageflags.non_repudiation
-          && app->app_local->card_type == CARD_TYPE_BELPIC)
-        err = pincb (pincb_arg, "PIN (qualified signature!)", &pinvalue);
-      else
-        err = pincb (pincb_arg, "PIN", &pinvalue);
-      if (err)
-        {
-          log_info ("PIN callback returned error: %s\n", gpg_strerror (err));
-          return err;
-        }
-
-      /* We might need to cope with UTF8 things here.  Not sure how
-         min_length etc. are exactly defined, for now we take them as
-         a plain octet count. */
-
-      if (strlen (pinvalue) < aodf->min_length)
-        {
-          log_error ("PIN is too short; minimum length is %lu\n",
-                     aodf->min_length);
-          err = gpg_error (GPG_ERR_BAD_PIN);
-        }
-      else if (aodf->stored_length && strlen (pinvalue) > aodf->stored_length)
-        {
-          /* This would otherwise truncate the PIN silently. */
-          log_error ("PIN is too large; maximum length is %lu\n",
-                     aodf->stored_length);
-          err = gpg_error (GPG_ERR_BAD_PIN);
-        }
-      else if (aodf->max_length_valid && strlen (pinvalue) > aodf->max_length)
-        {
-          log_error ("PIN is too large; maximum length is %lu\n",
-                     aodf->max_length);
-          err = gpg_error (GPG_ERR_BAD_PIN);
-        }
-
-      if (err)
-        {
-          xfree (pinvalue);
-          return err;
-        }
-
-      errstr = NULL;
-      err = 0;
-      switch (aodf->pintype)
-        {
-        case PIN_TYPE_BCD:
-        case PIN_TYPE_ASCII_NUMERIC:
-          for (s=pinvalue; digitp (s); s++)
-            ;
-          if (*s)
-            {
-              errstr = "Non-numeric digits found in PIN";
-              err = gpg_error (GPG_ERR_BAD_PIN);
-            }
-          break;
-        case PIN_TYPE_UTF8:
-          break;
-        case PIN_TYPE_HALF_NIBBLE_BCD:
-          errstr = "PIN type Half-Nibble-BCD is not supported";
-          break;
-        case PIN_TYPE_ISO9564_1:
-          errstr = "PIN type ISO9564-1 is not supported";
-          break;
-        default:
-          errstr = "Unknown PIN type";
-          break;
-        }
-      if (errstr)
-        {
-          log_error ("can't verify PIN: %s\n", errstr);
-          xfree (pinvalue);
-          return err? err : gpg_error (GPG_ERR_BAD_PIN_METHOD);
-        }
-
-
-      if (aodf->pintype == PIN_TYPE_BCD )
-        {
-          char *paddedpin;
-          int ndigits;
-
-          for (ndigits=0, s=pinvalue; *s; ndigits++, s++)
-            ;
-          paddedpin = xtrymalloc (aodf->stored_length+1);
-          if (!paddedpin)
-            {
-              err = gpg_error_from_syserror ();
-              xfree (pinvalue);
-              return err;
-            }
-
-          i = 0;
-          paddedpin[i++] = 0x20 | (ndigits & 0x0f);
-          for (s=pinvalue; i < aodf->stored_length && *s && s[1]; s = s+2 )
-            paddedpin[i++] = (((*s - '0') << 4) | ((s[1] - '0') & 0x0f));
-          if (i < aodf->stored_length && *s)
-            paddedpin[i++] = (((*s - '0') << 4)
-                              |((aodf->pad_char_valid?aodf->pad_char:0)&0x0f));
-
-          if (aodf->pinflags.needs_padding)
-            while (i < aodf->stored_length)
-              paddedpin[i++] = aodf->pad_char_valid? aodf->pad_char : 0;
-
-          xfree (pinvalue);
-          pinvalue = paddedpin;
-          pinvaluelen = i;
-        }
-      else if (aodf->pinflags.needs_padding)
-        {
-          char *paddedpin;
-
-          paddedpin = xtrymalloc (aodf->stored_length+1);
-          if (!paddedpin)
-            {
-              err = gpg_error_from_syserror ();
-              xfree (pinvalue);
-              return err;
-            }
-          for (i=0, s=pinvalue; i < aodf->stored_length && *s; i++, s++)
-            paddedpin[i] = *s;
-          /* Not sure what padding char to use if none has been set.
-             For now we use 0x00; maybe a space would be better. */
-          for (; i < aodf->stored_length; i++)
-            paddedpin[i] = aodf->pad_char_valid? aodf->pad_char : 0;
-          paddedpin[i] = 0;
-          pinvaluelen = i;
-          xfree (pinvalue);
-          pinvalue = paddedpin;
-        }
-      else
-        pinvaluelen = strlen (pinvalue);
-
-      err = iso7816_verify (app->slot,
-                            aodf->pin_reference_valid? aodf->pin_reference : 0,
-                            pinvalue, pinvaluelen);
-      xfree (pinvalue);
-      if (err)
-        {
-          log_error ("PIN verification failed: %s\n", gpg_strerror (err));
-          return err;
-        }
-      log_debug ("PIN verification succeeded\n");
-    }
 
   /* Prepare the DER object from INDATA. */
   if (indatalen == 36)
@@ -3120,6 +3749,7 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
       if (hashalgo != MD_USER_TLS_MD5SHA1)
         return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
       memcpy (data, indata, indatalen);
+      datalen = hashlen = 36;
     }
   else if (indatalen == 35)
     {
@@ -3134,20 +3764,50 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
       else
         return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
       memcpy (data, indata, indatalen);
+      datalen = 35;
+      hashlen = 20;
+    }
+  else if (indatalen == 32 + 19)
+    {
+      /* Seems to be a prepared SHA256 DER object.  */
+      if (hashalgo == GCRY_MD_SHA256 && !memcmp (indata, sha256_prefix, 19))
+        ;
+      else
+        return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
+      memcpy (data, indata, indatalen);
+      datalen = 51;
+      hashlen = 32;
     }
   else
     {
       /* Need to prepend the prefix. */
-      if (hashalgo == GCRY_MD_SHA1)
-        memcpy (data, sha1_prefix, 15);
+      if (hashalgo == GCRY_MD_SHA256)
+        {
+          memcpy (data, sha256_prefix, 19);
+          memcpy (data+19, indata, indatalen);
+          datalen = 51;
+          hashlen = 32;
+        }
+      else if (hashalgo == GCRY_MD_SHA1)
+        {
+          memcpy (data, sha1_prefix, 15);
+          memcpy (data+15, indata, indatalen);
+          datalen = 35;
+          hashlen = 20;
+        }
       else if (hashalgo == GCRY_MD_RMD160)
-        memcpy (data, rmd160_prefix, 15);
+        {
+          memcpy (data, rmd160_prefix, 15);
+          memcpy (data+15, indata, indatalen);
+          datalen = 35;
+          hashlen = 20;
+        }
       else
         return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
-      memcpy (data+15, indata, indatalen);
     }
 
-  /* Manage security environment needs to be weaked for certain cards. */
+
+  /* Manage security environment needs to be tweaked for certain cards. */
   if (mse_done)
     err = 0;
   else if (app->app_local->card_type == CARD_TYPE_TCOS)
@@ -3176,16 +3836,32 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
     }
   if (err)
     {
-      log_error ("MSE failed: %s\n", gpg_strerror (err));
+      log_error ("p15: MSE failed: %s\n", gpg_strerror (err));
       return err;
     }
 
-  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);
+  dataptr = data;
+  if (no_data_padding)
+    {
+      dataptr += datalen - hashlen;
+      datalen = hashlen;
+    }
+
+  if (prkdf->keyalgo == GCRY_PK_RSA && prkdf->keynbits > 2048)
+    {
+      exmode = 1;
+      le_value = prkdf->keynbits / 8;
+    }
   else
-    err = iso7816_compute_ds (app->slot, 0, data, 35, 0, outdata, outdatalen);
+    {
+      exmode = 0;
+      le_value = 0;
+    }
+
+  err = iso7816_compute_ds (app_get_slot (app),
+                            exmode, dataptr, datalen,
+                            le_value, outdata, outdatalen);
+
   return err;
 }
 
@@ -3215,7 +3891,7 @@ do_auth (app_t app, const char *keyidstr,
     return err;
   if (!prkdf->usageflags.sign)
     {
-      log_error ("key %s may not be used for authentication\n", keyidstr);
+      log_error ("p15: key %s may not be used for authentication\n", keyidstr);
       return gpg_error (GPG_ERR_WRONG_KEY_USAGE);
     }
 
@@ -3225,6 +3901,134 @@ do_auth (app_t app, const char *keyidstr,
 }
 
 
+/* Handler for the PKDECRYPT command.  Decrypt the data in INDATA and
+ * return the allocated result in OUTDATA.  If a PIN is required the
+ * PINCB will be used to ask for the PIN; it should return the PIN in
+ * an allocated buffer and put it into PIN.  */
+static gpg_error_t
+do_decipher (app_t app, const char *keyidstr,
+             gpg_error_t (*pincb)(void*, const char *, char **),
+             void *pincb_arg,
+             const void *indata, size_t indatalen,
+             unsigned char **outdata, size_t *outdatalen,
+             unsigned int *r_info)
+{
+  gpg_error_t err;
+  prkdf_object_t prkdf;    /* The private key object. */
+  aodf_object_t aodf;      /* The associated authentication object. */
+  int exmode, le_value, padind;
+
+  (void)r_info;
+
+  if (!keyidstr || !*keyidstr)
+    return gpg_error (GPG_ERR_INV_VALUE);
+  if (!indatalen || !indata || !outdatalen || !outdata)
+    return gpg_error (GPG_ERR_INV_ARG);
+
+  err = prkdf_object_from_keyidstr (app, keyidstr, &prkdf);
+  if (err)
+    return err;
+  if (!(prkdf->usageflags.decrypt || prkdf->usageflags.unwrap))
+    {
+      log_error ("p15: key %s may not be used for decruption\n", keyidstr);
+      return gpg_error (GPG_ERR_WRONG_KEY_USAGE);
+    }
+
+  /* Find the authentication object to this private key object. */
+  if (!prkdf->authid)
+    {
+      log_error ("p15: no authentication object defined for %s\n", keyidstr);
+      /* fixme: we might want to go ahead and do without PIN
+         verification. */
+      return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
+    }
+  for (aodf = app->app_local->auth_object_info; aodf; aodf = aodf->next)
+    if (aodf->objidlen == prkdf->authidlen
+        && !memcmp (aodf->objid, prkdf->authid, prkdf->authidlen))
+      break;
+  if (!aodf)
+    {
+      log_error ("p15: authentication object for %s missing\n", keyidstr);
+      return gpg_error (GPG_ERR_INV_CARD);
+    }
+
+  /* We need some more info about the key - get the keygrip to
+   * populate these fields.  */
+  err = keygrip_from_prkdf (app, prkdf);
+  if (err)
+    {
+      log_error ("p15: keygrip_from_prkdf failed: %s\n", gpg_strerror (err));
+      return err;
+    }
+
+  /* Verify the PIN.  */
+  err = prepare_verify_pin (app, keyidstr, prkdf, aodf);
+  if (!err)
+    err = verify_pin (app, pincb, pincb_arg, prkdf, aodf);
+  if (err)
+    return err;
+
+
+  /* The next is guess work for CardOS.  */
+  if (app->app_local->card_product == CARD_PRODUCT_DTRUST)
+    {
+      /* From analyzing an USB trace of a Windows signing application
+       * we see that the SE is simply reset to 0x14.  It seems to be
+       * sufficient to do this for decryption; signing still works
+       * with the standard code despite that our trace showed that
+       * there the SE is restored to 0x09.  Note that the special
+       * D-Trust AID is in any case select by prepare_verify_pin.
+       *
+       * Hey, D-Trust please hand over the specs so that you can
+       * actually sell your cards and we can properly implement it;
+       * other vendors understand this and do not demand ridiculous
+       * paper work or complicated procedures to get samples.  */
+      err = iso7816_manage_security_env (app_get_slot (app),
+                                         0xF3, 0x14, NULL, 0);
+
+    }
+  else if (prkdf->key_reference_valid)
+    {
+      unsigned char mse[6];
+
+      /* Note: This works with CardOS but the D-Trust card has the
+       * problem that the next created signature would be broken.  */
+
+      mse[0] = 0x80; /* Algorithm reference.  */
+      mse[1] = 1;
+      mse[2] = 0x0a; /* RSA, no padding.  */
+      mse[3] = 0x84;
+      mse[4] = 1;
+      mse[5] = prkdf->key_reference;
+      err = iso7816_manage_security_env (app_get_slot (app), 0x41, 0xB8,
+                                         mse, sizeof mse);
+    }
+  /* Check for MSE error.  */
+  if (err)
+    {
+      log_error ("p15: MSE failed: %s\n", gpg_strerror (err));
+      return err;
+    }
+
+  exmode = le_value = 0;
+  padind = 0;
+  if (prkdf->keyalgo == GCRY_PK_RSA && prkdf->keynbits > 2048)
+    {
+      exmode = 1;   /* Extended length w/o a limit.  */
+      le_value = prkdf->keynbits / 8;
+    }
+
+  if (app->app_local->card_product == CARD_PRODUCT_DTRUST)
+    padind = 0x81;
+
+  err = iso7816_decipher (app_get_slot (app), exmode,
+                          indata, indatalen,
+                          le_value, padind,
+                          outdata, outdatalen);
+  return err;
+}
+
+
 \f
 /* Assume that EF(DIR) has been selected.  Read its content and figure
    out the home EF of pkcs#15.  Return that home DF or 0 if not found
@@ -3244,7 +4048,7 @@ read_home_df (int slot, int *r_belpic)
   err = iso7816_read_binary (slot, 0, 0, &buffer, &buflen);
   if (err)
     {
-      log_error ("error reading EF{DIR}: %s\n", gpg_strerror (err));
+      log_error ("p15: error reading EF(DIR): %s\n", gpg_strerror (err));
       return 0;
     }
 
@@ -3258,14 +4062,15 @@ read_home_df (int slot, int *r_belpic)
                                   && !memcmp (pp, pkcs15be_aid, nn)))))
         {
           pp = find_tlv (p, n, 0x50, &nn);
-          if (pp) /* fixme: Filter log value? */
-            log_info ("pkcs#15 application label from EF(DIR) is '%.*s'\n",
+          if (pp && opt.verbose)
+            log_info ("p15: application label from EF(DIR) is '%.*s'\n",
                       (int)nn, pp);
           pp = find_tlv (p, n, 0x51, &nn);
           if (pp && nn == 4 && *pp == 0x3f && !pp[1])
             {
               result = ((pp[2] << 8) | pp[3]);
-              log_info ("pkcs#15 application directory is 0x%04hX\n", result);
+              if (opt.verbose)
+                log_info ("p15: application directory is 0x%04hX\n", result);
             }
         }
     }
@@ -3294,11 +4099,11 @@ app_select_p15 (app_t app)
          does only allow for that.  Many other cards supports this
          selection method too.  Note, that we don't use
          select_application above for the Belgian card - the call
-         works but it seems that it did not switch to the correct DF.
+         works but it seems that it does not switch to the correct DF.
          Using the 2f02 just works. */
       unsigned short path[1] = { 0x2f00 };
 
-      rc = iso7816_select_path (app->slot, path, 1);
+      rc = iso7816_select_path (slot, path, 1);
       if (!rc)
         {
           direct = 1;
@@ -3306,7 +4111,7 @@ app_select_p15 (app_t app)
           if (def_home_df)
             {
               path[0] = def_home_df;
-              rc = iso7816_select_path (app->slot, path, 1);
+              rc = iso7816_select_path (slot, path, 1);
             }
         }
     }
@@ -3368,6 +4173,8 @@ app_select_p15 (app_t app)
          the common APP structure. */
       app->app_local->card_type = card_type;
 
+      app->app_local->card_product = CARD_PRODUCT_UNKNOWN;
+
       /* Store whether we may and should use direct path selection. */
       app->app_local->direct_path_selection = direct;
 
@@ -3411,7 +4218,7 @@ app_select_p15 (app_t app)
       app->fnc.genkey = NULL;
       app->fnc.sign = do_sign;
       app->fnc.auth = do_auth;
-      app->fnc.decipher = NULL;
+      app->fnc.decipher = do_decipher;
       app->fnc.change_pin = NULL;
       app->fnc.check_pin = NULL;
 
index 8094b24..352b16c 100644 (file)
@@ -1354,7 +1354,7 @@ keygripstr_from_prkdf (app_t app, prkdf_object_t prkdf, char *r_gripstr)
     err = ksba_cert_init_from_mem (cert, der, derlen);
   xfree (der);
   if (!err)
-    err = app_help_get_keygrip_string (cert, r_gripstr);
+    err = app_help_get_keygrip_string (cert, r_gripstr, NULL);
   ksba_cert_release (cert);
 
   return err;
index 627481f..092a119 100644 (file)
@@ -103,6 +103,8 @@ map_sw (int sw)
         ec = GPG_ERR_GENERAL; /* Should not happen. */
       else if ((sw & 0xff00) == SW_MORE_DATA)
         ec = 0; /* This should actually never been seen here. */
+      else if ((sw & 0xfff0) == 0x63C0)
+        ec = GPG_ERR_BAD_PIN;
       else
         ec = GPG_ERR_CARD;
     }
@@ -139,6 +141,32 @@ iso7816_select_application (int slot, const char *aid, size_t aidlen,
 }
 
 
+/* This is the same as iso7816_select_application but may return data
+ * at RESULT,RESULTLEN).  */
+gpg_error_t
+iso7816_select_application_ext (int slot, const char *aid, size_t aidlen,
+                                unsigned int flags,
+                                unsigned char **result, size_t *resultlen)
+{
+  int sw;
+  sw = apdu_send (slot, 0, 0x00, CMD_SELECT_FILE, 4,
+                  (flags&1)? 0:0x0c, aidlen, aid,
+                  result, resultlen);
+  return map_sw (sw);
+}
+
+
+/* Simple MF selection as supported by some cards.  */
+gpg_error_t
+iso7816_select_mf (int slot)
+{
+  int sw;
+
+  sw = apdu_send_simple (slot, 0, 0x00, CMD_SELECT_FILE, 0x000, 0x0c, -1, NULL);
+  return map_sw (sw);
+}
+
+
 gpg_error_t
 iso7816_select_file (int slot, int tag, int is_dir)
 {
@@ -289,6 +317,39 @@ iso7816_verify (int slot, int chvno, const char *chv, size_t chvlen)
   return map_sw (sw);
 }
 
+
+/* Some cards support a VERIFY command variant to check the status of
+ * the the CHV without a need to try a CHV.  In contrast to the other
+ * functions this function returns the special codes ISO7816_VERIFY_*
+ * or a non-negative number with the left attempts.  */
+int
+iso7816_verify_status (int slot, int chvno)
+{
+  unsigned char apdu[4];
+  unsigned int sw;
+  int result;
+
+  apdu[0] = 0x00;
+  apdu[1] = ISO7816_VERIFY;
+  apdu[2] = 0x00;
+  apdu[3] = chvno;
+  if (!iso7816_apdu_direct (slot, apdu, 4, 0, &sw, NULL, NULL))
+    result = ISO7816_VERIFY_NOT_NEEDED;  /* Not returned by all cards.  */
+  else if (sw == 0x6a88 || sw == 0x6a80)
+    result = ISO7816_VERIFY_NO_PIN;
+  else if (sw == 0x6983)
+    result = ISO7816_VERIFY_BLOCKED;
+  else if (sw == 0x6985)
+    result = ISO7816_VERIFY_NULLPIN;     /* TCOS card  */
+  else if ((sw & 0xfff0) == 0x63C0)
+    result = (sw & 0x000f);
+  else
+    result = ISO7816_VERIFY_ERROR;
+
+  return result;
+}
+
+
 /* Perform a CHANGE_REFERENCE_DATA command on SLOT for the card holder
    verification vector CHVNO.  With PININFO non-NULL the pinpad of the
    reader will be used.  If IS_EXCHANGE is 0, a "change reference
@@ -722,8 +783,9 @@ iso7816_get_challenge (int slot, int length, unsigned char *buffer)
    stored in a newly allocated buffer at the address passed by RESULT.
    Returns the length of this data at the address of RESULTLEN. */
 gpg_error_t
-iso7816_read_binary (int slot, size_t offset, size_t nmax,
-                     unsigned char **result, size_t *resultlen)
+iso7816_read_binary_ext (int slot, int extended_mode,
+                         size_t offset, size_t nmax,
+                         unsigned char **result, size_t *resultlen)
 {
   int sw;
   unsigned char *buffer;
@@ -746,13 +808,13 @@ iso7816_read_binary (int slot, size_t offset, size_t nmax,
       buffer = NULL;
       bufferlen = 0;
       n = read_all? 0 : nmax;
-      sw = apdu_send_le (slot, 0, 0x00, CMD_READ_BINARY,
+      sw = apdu_send_le (slot, extended_mode, 0x00, CMD_READ_BINARY,
                          ((offset>>8) & 0xff), (offset & 0xff) , -1, NULL,
                          n, &buffer, &bufferlen);
       if ( SW_EXACT_LENGTH_P(sw) )
         {
           n = (sw & 0x00ff);
-          sw = apdu_send_le (slot, 0, 0x00, CMD_READ_BINARY,
+          sw = apdu_send_le (slot, extended_mode, 0x00, CMD_READ_BINARY,
                              ((offset>>8) & 0xff), (offset & 0xff) , -1, NULL,
                              n, &buffer, &bufferlen);
         }
@@ -811,6 +873,15 @@ iso7816_read_binary (int slot, size_t offset, size_t nmax,
   return 0;
 }
 
+
+gpg_error_t
+iso7816_read_binary (int slot, size_t offset, size_t nmax,
+                     unsigned char **result, size_t *resultlen)
+{
+  return iso7816_read_binary_ext (slot, 0, offset, nmax, result, resultlen);
+}
+
+
 /* Perform a READ RECORD command. RECNO gives the record number to
    read with 0 indicating the current record.  RECCOUNT must be 1 (not
    all cards support reading of more than one record).  SHORT_EF
index 8da5a94..bad558d 100644 (file)
 #define ISO7816_CHANGE_REFERENCE_DATA 0x24
 #define ISO7816_RESET_RETRY_COUNTER   0x2C
 
+/* Error codes returned by iso7816_verify_status.  A non-negative
+ * number gives the number of left tries.
+ * NB: The values are also used by the CHV-STATUS lines and thus are
+ * part of the public interface.  Do not change them.  */
+#define ISO7816_VERIFY_ERROR        (-1)
+#define ISO7816_VERIFY_NO_PIN       (-2)
+#define ISO7816_VERIFY_BLOCKED      (-3)
+#define ISO7816_VERIFY_NULLPIN      (-4)
+#define ISO7816_VERIFY_NOT_NEEDED   (-5)
 
 /* Information to be passed to pinpad equipped readers.  See
    ccid-driver.c for details. */
@@ -51,6 +60,12 @@ gpg_error_t iso7816_map_sw (int sw);
 gpg_error_t iso7816_select_application (int slot,
                                         const char *aid, size_t aidlen,
                                         unsigned int flags);
+gpg_error_t iso7816_select_application_ext (int slot,
+                                            const char *aid, size_t aidlen,
+                                            unsigned int flags,
+                                            unsigned char **result,
+                                            size_t *resultlen);
+gpg_error_t iso7816_select_mf (int slot);
 gpg_error_t iso7816_select_file (int slot, int tag, int is_dir);
 gpg_error_t iso7816_select_path (int slot,
                                  const unsigned short *path, size_t pathlen);
@@ -65,6 +80,7 @@ gpg_error_t iso7816_check_pinpad (int slot, int command,
 gpg_error_t iso7816_verify (int slot,
                             int chvno, const char *chv, size_t chvlen);
 gpg_error_t iso7816_verify_kp (int slot, int chvno, pininfo_t *pininfo);
+int iso7816_verify_status (int slot, int chvno);
 gpg_error_t iso7816_change_reference_data (int slot, int chvno,
                                const char *oldchv, size_t oldchvlen,
                                const char *newchv, size_t newchvlen);
@@ -117,6 +133,9 @@ gpg_error_t iso7816_read_public_key (int slot, int extended_mode,
 gpg_error_t iso7816_get_challenge (int slot,
                                    int length, unsigned char *buffer);
 
+gpg_error_t iso7816_read_binary_ext (int slot, int extended_mode,
+                                     size_t offset, size_t nmax,
+                                     unsigned char **result, size_t *resultlen);
 gpg_error_t iso7816_read_binary (int slot, size_t offset, size_t nmax,
                                  unsigned char **result, size_t *resultlen);
 gpg_error_t iso7816_read_record (int slot, int recno, int reccount,
index 281e479..d9c419e 100644 (file)
@@ -1248,7 +1248,7 @@ gpgsm_agent_ask_passphrase (ctrl_t ctrl, const char *desc_msg, int repeat,
     return gpg_error_from_syserror ();
 
   snprintf (line, DIM(line), "GET_PASSPHRASE --data%s -- X X X %s",
-            repeat? " --repeat=1 --check --qualitybar":"",
+            repeat? " --repeat=1 --check":"",
             arg4);
   xfree (arg4);
 
index fb05413..36afd22 100644 (file)
@@ -756,20 +756,24 @@ lookup_status_cb (void *opaque, const char *line)
 
 
 /* Run the Directory Manager's lookup command using the pattern
-   compiled from the strings given in NAMES.  The caller must provide
-   the callback CB which will be passed cert by cert.  Note that CTRL
-   is optional.  With CACHE_ONLY the dirmngr will search only its own
-   key cache. */
+   compiled from the strings given in NAMES or from URI.  The caller
+   must provide the callback CB which will be passed cert by cert.
+   Note that CTRL is optional.  With CACHE_ONLY the dirmngr will
+   search only its own key cache. */
 int
-gpgsm_dirmngr_lookup (ctrl_t ctrl, strlist_t names, int cache_only,
+gpgsm_dirmngr_lookup (ctrl_t ctrl, strlist_t names, const char *uri,
+                      int cache_only,
                       void (*cb)(void*, ksba_cert_t), void *cb_value)
 {
   int rc;
-  char *pattern;
   char line[ASSUAN_LINELENGTH];
   struct lookup_parm_s parm;
   size_t len;
   assuan_context_t ctx;
+  const char *s;
+
+  if ((names && uri) || (!names && !uri))
+    return gpg_error (GPG_ERR_INV_ARG);
 
   /* The lookup function can be invoked from the callback of a lookup
      function, for example to walk the chain.  */
@@ -792,19 +796,35 @@ gpgsm_dirmngr_lookup (ctrl_t ctrl, strlist_t names, int cache_only,
       log_fatal ("both dirmngr contexts are in use\n");
     }
 
-  pattern = pattern_from_strlist (names);
-  if (!pattern)
+  if (names)
     {
-      if (ctx == dirmngr_ctx)
-       release_dirmngr (ctrl);
-      else
-       release_dirmngr2 (ctrl);
+      char *pattern = pattern_from_strlist (names);
+      if (!pattern)
+        {
+          if (ctx == dirmngr_ctx)
+            release_dirmngr (ctrl);
+          else
+            release_dirmngr2 (ctrl);
 
-      return out_of_core ();
+          return out_of_core ();
+        }
+      snprintf (line, DIM(line), "LOOKUP%s %s",
+                cache_only? " --cache-only":"", pattern);
+      xfree (pattern);
+    }
+  else
+    {
+      for (s=uri; *s; s++)
+        if (*s <= ' ')
+          {
+            if (ctx == dirmngr_ctx)
+              release_dirmngr (ctrl);
+            else
+              release_dirmngr2 (ctrl);
+            return gpg_error (GPG_ERR_INV_URI);
+          }
+      snprintf (line, DIM(line), "LOOKUP --url %s", uri);
     }
-  snprintf (line, DIM(line), "LOOKUP%s %s",
-            cache_only? " --cache-only":"", pattern);
-  xfree (pattern);
 
   parm.ctrl = ctrl;
   parm.ctx = ctx;
index f59dc75..5f83202 100644 (file)
 #include "../common/tlv.h"
 
 
+/* The OID for the authorityInfoAccess's caIssuers.  */
+static const char oidstr_caIssuers[] = "1.3.6.1.5.5.7.48.2";
+
+
 /* Object to keep track of certain root certificates. */
 struct marktrusted_info_s
 {
@@ -573,6 +577,9 @@ struct find_up_store_certs_s
 {
   ctrl_t ctrl;
   int count;
+  unsigned int want_fpr:1;
+  unsigned int got_fpr:1;
+  unsigned char fpr[20];
 };
 
 static void
@@ -582,6 +589,13 @@ find_up_store_certs_cb (void *cb_value, ksba_cert_t cert)
 
   if (keydb_store_cert (parm->ctrl, cert, 1, NULL))
     log_error ("error storing issuer certificate as ephemeral\n");
+  else if (parm->want_fpr && !parm->got_fpr)
+    {
+      if (!gpgsm_get_fingerprint (cert, 0, parm->fpr, NULL))
+        log_error (_("failed to get the fingerprint\n"));
+      else
+        parm->got_fpr = 1;
+    }
   parm->count++;
 }
 
@@ -602,6 +616,8 @@ find_up_external (ctrl_t ctrl, KEYDB_HANDLE kh,
   const char *s;
 
   find_up_store_certs_parm.ctrl = ctrl;
+  find_up_store_certs_parm.want_fpr = 0;
+  find_up_store_certs_parm.got_fpr = 0;
   find_up_store_certs_parm.count = 0;
 
   if (opt.verbose)
@@ -620,7 +636,7 @@ find_up_external (ctrl_t ctrl, KEYDB_HANDLE kh,
   add_to_strlist (&names, pattern);
   xfree (pattern);
 
-  rc = gpgsm_dirmngr_lookup (ctrl, names, 0, find_up_store_certs_cb,
+  rc = gpgsm_dirmngr_lookup (ctrl, names, NULL, 0, find_up_store_certs_cb,
                              &find_up_store_certs_parm);
   free_strlist (names);
 
@@ -653,6 +669,105 @@ find_up_external (ctrl_t ctrl, KEYDB_HANDLE kh,
 }
 
 
+/* Helper for find_up().  Locate the certificate for CERT using the
+ * caIssuer from the authorityInfoAccess.  KH is the keydb context we
+ * are currently using.  On success 0 is returned and the certificate
+ * may be retrieved from the keydb using keydb_get_cert().  If no
+ * suitable authorityInfoAccess is encoded in the certificate
+ * GPG_ERR_NOT_FOUND is returned. */
+static gpg_error_t
+find_up_via_auth_info_access (ctrl_t ctrl, KEYDB_HANDLE kh, ksba_cert_t cert)
+{
+  gpg_error_t err;
+  struct find_up_store_certs_s find_up_store_certs_parm;
+  char *url, *ldapurl;
+  int idx, i;
+  char *oid;
+  ksba_name_t name;
+
+  find_up_store_certs_parm.ctrl = ctrl;
+  find_up_store_certs_parm.want_fpr = 1;
+  find_up_store_certs_parm.got_fpr = 0;
+  find_up_store_certs_parm.count = 0;
+
+  /* Find suitable URLs; if there is a http scheme we prefer that.  */
+  url = ldapurl = NULL;
+  for (idx=0;
+       !url && !(err = ksba_cert_get_authority_info_access (cert, idx,
+                                                            &oid, &name));
+       idx++)
+    {
+      if (!strcmp (oid, oidstr_caIssuers))
+        {
+          for (i=0; !url && ksba_name_enum (name, i); i++)
+            {
+              char *p = ksba_name_get_uri (name, i);
+              if (p)
+                {
+                  if (!strncmp (p, "http:", 5) || !strncmp (p, "https:", 6))
+                    url = p;
+                  else if (ldapurl)
+                    xfree (p); /* We already got one.  */
+                  else if (!strncmp (p, "ldap:",5) || !strncmp (p, "ldaps:",6))
+                    ldapurl = p;
+                }
+              else
+                xfree (p);
+            }
+        }
+      ksba_name_release (name);
+      ksba_free (oid);
+    }
+  if (err && gpg_err_code (err) != GPG_ERR_EOF)
+    {
+      log_error (_("can't get authorityInfoAccess: %s\n"), gpg_strerror (err));
+      return err;
+    }
+  if (!url && ldapurl)
+    {
+      /* No HTTP scheme; fallback to LDAP if available.  */
+      url = ldapurl;
+      ldapurl = NULL;
+    }
+  xfree (ldapurl);
+  if (!url)
+    return gpg_error (GPG_ERR_NOT_FOUND);
+
+  if (opt.verbose)
+    log_info ("looking up issuer via authorityInfoAccess.caIssuers\n");
+
+  err = gpgsm_dirmngr_lookup (ctrl, NULL, url, 0, find_up_store_certs_cb,
+                              &find_up_store_certs_parm);
+
+  /* Although we might receive several certificates we use only the
+   * first one.  Or more exacty the first one for which we retrieved
+   * the fingerprint.  */
+  if (opt.verbose)
+    log_info ("number of caIssuers found: %d\n",
+              find_up_store_certs_parm.count);
+  if (err)
+    {
+      log_error ("external URL lookup failed: %s\n", gpg_strerror (err));
+      err = gpg_error (GPG_ERR_NOT_FOUND);
+    }
+  else if (!find_up_store_certs_parm.got_fpr)
+    err = gpg_error (GPG_ERR_NOT_FOUND);
+  else
+    {
+      int old;
+      /* The retrieved certificates are currently stored in the
+       * ephemeral key DB, so we temporary switch to ephemeral
+       * mode. */
+      old = keydb_set_ephemeral (kh, 1);
+      keydb_search_reset (kh);
+      err = keydb_search_fpr (ctrl, kh, find_up_store_certs_parm.fpr);
+      keydb_set_ephemeral (kh, old);
+    }
+
+  return err;
+}
+
+
 /* Helper for find_up().  Ask the dirmngr for the certificate for
    ISSUER with optional SERIALNO.  KH is the keydb context we are
    currently using.  With SUBJECT_MODE set, ISSUER is searched as the
@@ -693,7 +808,7 @@ find_up_dirmngr (ctrl_t ctrl, KEYDB_HANDLE kh,
   add_to_strlist (&names, pattern);
   xfree (pattern);
 
-  rc = gpgsm_dirmngr_lookup (ctrl, names, 1, find_up_store_certs_cb,
+  rc = gpgsm_dirmngr_lookup (ctrl, names, NULL, 1, find_up_store_certs_cb,
                              &find_up_store_certs_parm);
   free_strlist (names);
 
@@ -813,11 +928,24 @@ find_up (ctrl_t ctrl, KEYDB_HANDLE kh,
         }
 
       /* If we still didn't found it, try an external lookup.  */
-      if (rc == -1 && opt.auto_issuer_key_retrieve && !find_next)
+      if (rc == -1 && !find_next && !ctrl->offline)
         {
-          rc = find_up_external (ctrl, kh, issuer, keyid);
-          if (!rc && DBG_X509)
-            log_debug ("  found via authid and external lookup\n");
+          /* We allow AIA also if CRLs are enabled; both can be used
+           * as a web bug so it does not make sense to not use AIA if
+           * CRL checks are enabled.  */
+          if ((opt.auto_issuer_key_retrieve || !opt.no_crl_check)
+              && !find_up_via_auth_info_access (ctrl, kh, cert))
+            {
+              if (DBG_X509)
+                log_debug ("  found via authorityInfoAccess.caIssuers\n");
+              rc = 0;
+            }
+          else if (opt.auto_issuer_key_retrieve)
+            {
+              rc = find_up_external (ctrl, kh, issuer, keyid);
+              if (!rc && DBG_X509)
+                log_debug ("  found via authid and external lookup\n");
+            }
         }
 
 
@@ -876,11 +1004,21 @@ find_up (ctrl_t ctrl, KEYDB_HANDLE kh,
     }
 
   /* Still not found.  If enabled, try an external lookup.  */
-  if (rc == -1 && opt.auto_issuer_key_retrieve && !find_next)
+  if (rc == -1 && !find_next && !ctrl->offline)
     {
-      rc = find_up_external (ctrl, kh, issuer, NULL);
-      if (!rc && DBG_X509)
-        log_debug ("  found via issuer and external lookup\n");
+      if ((opt.auto_issuer_key_retrieve || !opt.no_crl_check)
+          && !find_up_via_auth_info_access (ctrl, kh, cert))
+        {
+          if (DBG_X509)
+            log_debug ("  found via authorityInfoAccess.caIssuers\n");
+          rc = 0;
+        }
+      else if (opt.auto_issuer_key_retrieve)
+        {
+          rc = find_up_external (ctrl, kh, issuer, NULL);
+          if (!rc && DBG_X509)
+            log_debug ("  found via issuer and external lookup\n");
+        }
     }
 
   return rc;
@@ -1054,6 +1192,24 @@ is_cert_still_valid (ctrl_t ctrl, int force_ocsp, int lm, estream_t fp,
       return 0;
     }
 
+
+  if (!(force_ocsp || ctrl->use_ocsp)
+      && !opt.enable_issuer_based_crl_check)
+    {
+      err = ksba_cert_get_crl_dist_point (subject_cert, 0, NULL, NULL, NULL);
+      if (gpg_err_code (err) == GPG_ERR_EOF)
+        {
+          /* No DP specified in the certificate.  Thus the CA does not
+           * consider a CRL useful and the user of the certificate
+           * also does not consider this to be a critical thing.  In
+           * this case we can conclude that the certificate shall not
+           * be revocable.  Note that we reach this point here only if
+           * no OCSP responder shall be used.  */
+          audit_log_ok (ctrl->audit, AUDIT_CRL_CHECK, gpg_error (GPG_ERR_TRUE));
+          return 0;
+        }
+    }
+
   err = gpgsm_dirmngr_isvalid (ctrl,
                                subject_cert, issuer_cert,
                                force_ocsp? 2 : !!ctrl->use_ocsp);
index 1102bcc..12b3ec9 100644 (file)
@@ -1,5 +1,7 @@
 /* certcheck.c - check one certificate
- *     Copyright (C) 2001, 2003, 2004 Free Software Foundation, Inc.
+ * Copyright (C) 2001, 2003, 2004 Free Software Foundation, Inc.
+ * Copyright (C) 2001-2019 Werner Koch
+ * Copyright (C) 2015-2020 g10 Code GmbH
  *
  * This file is part of GnuPG.
  *
@@ -15,6 +17,7 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: GPL-3.0-or-later
  */
 
 #include <config.h>
@@ -220,6 +223,126 @@ pk_algo_from_sexp (gcry_sexp_t pkey)
 }
 
 
+/* Return the hash algorithm's algo id from its name given in the
+ * non-null termnated string in (buffer,buflen).  Returns 0 on failure
+ * or if the algo is not known.  */
+static int
+hash_algo_from_buffer (const void *buffer, size_t buflen)
+{
+  char *string;
+  int algo;
+
+  string = xtrymalloc (buflen + 1);
+  if (!string)
+    {
+      log_error (_("out of core\n"));
+      return 0;
+    }
+  memcpy (string, buffer, buflen);
+  string[buflen] = 0;
+  algo = gcry_md_map_name (string);
+  if (!algo)
+    log_error ("unknown digest algorithm '%s' used in certificate\n", string);
+  xfree (string);
+  return algo;
+}
+
+
+/* Return an unsigned integer from the non-null termnated string
+ * (buffer,buflen).  Returns 0 on failure.  */
+static unsigned int
+uint_from_buffer (const void *buffer, size_t buflen)
+{
+  char *string;
+  unsigned int val;
+
+  string = xtrymalloc (buflen + 1);
+  if (!string)
+    {
+      log_error (_("out of core\n"));
+      return 0;
+    }
+  memcpy (string, buffer, buflen);
+  string[buflen] = 0;
+  val = strtoul (string, NULL, 10);
+  xfree (string);
+  return val;
+}
+
+
+/* Extract the hash algorithm and the salt length from the sigval.  */
+static gpg_error_t
+extract_pss_params (gcry_sexp_t s_sig, int *r_algo, unsigned int *r_saltlen)
+{
+  gpg_error_t err;
+  gcry_buffer_t ioarray[2] = { {0}, {0} };
+
+  err = gcry_sexp_extract_param (s_sig, "sig-val",
+                                 "&'hash-algo''salt-length'",
+                                 ioarray+0, ioarray+1, NULL);
+  if (err)
+    {
+      log_error ("extracting params from PSS failed: %s\n", gpg_strerror (err));
+      return err;
+    }
+
+  *r_algo = hash_algo_from_buffer (ioarray[0].data, ioarray[0].len);
+  *r_saltlen = uint_from_buffer (ioarray[1].data, ioarray[1].len);
+  xfree (ioarray[0].data);
+  xfree (ioarray[1].data);
+  if (*r_saltlen < 20)
+    {
+      log_error ("length of PSS salt too short\n");
+      gcry_sexp_release (s_sig);
+      return gpg_error (GPG_ERR_DIGEST_ALGO);
+    }
+  if (!*r_algo)
+    {
+      return gpg_error (GPG_ERR_DIGEST_ALGO);
+    }
+
+  /* PSS has no hash function firewall like PKCS#1 and thus offers
+   * a path for hash algorithm replacement.  To avoid this it makes
+   * sense to restrict the allowed hash algorithms and also allow only
+   * matching salt lengths.  According to Peter Gutmann:
+   *  "Beware of bugs in the above signature scheme;
+   *   I have only proved it secure, not implemented it"
+   *   - Apologies to Donald Knuth.
+   * https://www.metzdowd.com/pipermail/cryptography/2019-November/035449.html
+   *
+   * Given the set of supported algorithms currently available in
+   * Libgcrypt and the extra hash checks we have in some compliance
+   * modes, it would be hard to trick gpgsm to verify a forged
+   * signature.  However, if eventually someone adds the xor256 hash
+   * algorithm (1.3.6.1.4.1.3029.3.2) to Libgcrypt we would be doomed.
+   */
+  switch (*r_algo)
+    {
+    case GCRY_MD_SHA1:
+    case GCRY_MD_SHA256:
+    case GCRY_MD_SHA384:
+    case GCRY_MD_SHA512:
+    case GCRY_MD_SHA3_256:
+    case GCRY_MD_SHA3_384:
+    case GCRY_MD_SHA3_512:
+      break;
+    default:
+      log_error ("PSS hash algorithm '%s' rejected\n",
+                 gcry_md_algo_name (*r_algo));
+      return gpg_error (GPG_ERR_DIGEST_ALGO);
+    }
+
+  if (gcry_md_get_algo_dlen (*r_algo) != *r_saltlen)
+    {
+      log_error ("PSS hash algorithm '%s' rejected due to salt length %u\n",
+                 gcry_md_algo_name (*r_algo), *r_saltlen);
+      return gpg_error (GPG_ERR_DIGEST_ALGO);
+    }
+
+  return 0;
+}
+
+
 /* Check the signature on CERT using the ISSUER-CERT.  This function
    does only test the cryptographic signature and nothing else.  It is
    assumed that the ISSUER_CERT is valid. */
@@ -229,66 +352,76 @@ gpgsm_check_cert_sig (ksba_cert_t issuer_cert, ksba_cert_t cert)
   const char *algoid;
   gcry_md_hd_t md;
   int rc, algo;
-  gcry_mpi_t frame;
   ksba_sexp_t p;
   size_t n;
-  gcry_sexp_t s_sig, s_hash, s_pkey;
+  gcry_sexp_t s_sig, s_data, s_pkey;
+  int use_pss = 0;
+  unsigned int saltlen;
 
   algo = gcry_md_map_name ( (algoid=ksba_cert_get_digest_algo (cert)));
-  if (!algo)
+  if (!algo && algoid && !strcmp (algoid, "1.2.840.113549.1.1.10"))
+    use_pss = 1;
+  else if (!algo)
     {
-      log_error ("unknown hash algorithm '%s'\n", algoid? algoid:"?");
+      log_error ("unknown digest algorithm '%s' used certificate\n",
+                 algoid? algoid:"?");
       if (algoid
           && (  !strcmp (algoid, "1.2.840.113549.1.1.2")
                 ||!strcmp (algoid, "1.2.840.113549.2.2")))
         log_info (_("(this is the MD2 algorithm)\n"));
       return gpg_error (GPG_ERR_GENERAL);
     }
-  rc = gcry_md_open (&md, algo, 0);
-  if (rc)
-    {
-      log_error ("md_open failed: %s\n", gpg_strerror (rc));
-      return rc;
-    }
-  if (DBG_HASHING)
-    gcry_md_debug (md, "hash.cert");
-
-  rc = ksba_cert_hash (cert, 1, HASH_FNC, md);
-  if (rc)
-    {
-      log_error ("ksba_cert_hash failed: %s\n", gpg_strerror (rc));
-      gcry_md_close (md);
-      return rc;
-    }
-  gcry_md_final (md);
 
+  /* The the signature from the certificate.  */
   p = ksba_cert_get_sig_val (cert);
   n = gcry_sexp_canon_len (p, 0, NULL, NULL);
   if (!n)
     {
       log_error ("libksba did not return a proper S-Exp\n");
-      gcry_md_close (md);
       ksba_free (p);
       return gpg_error (GPG_ERR_BUG);
     }
+  rc = gcry_sexp_sscan ( &s_sig, NULL, (char*)p, n);
+  ksba_free (p);
+  if (rc)
+    {
+      log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (rc));
+      return rc;
+    }
   if (DBG_CRYPTO)
+    gcry_log_debugsxp ("sigval", s_sig);
+
+  if (use_pss)
     {
-      int j;
-      log_debug ("signature value:");
-      for (j=0; j < n; j++)
-        log_printf (" %02X", p[j]);
-      log_printf ("\n");
+      rc = extract_pss_params (s_sig, &algo, &saltlen);
+      if (rc)
+        {
+          gcry_sexp_release (s_sig);
+          return rc;
+        }
     }
 
-  rc = gcry_sexp_sscan ( &s_sig, NULL, (char*)p, n);
-  ksba_free (p);
+
+  /* Hash the to-be-signed parts of the certificate.  */
+  rc = gcry_md_open (&md, algo, 0);
   if (rc)
     {
-      log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (rc));
+      log_error ("md_open failed: %s\n", gpg_strerror (rc));
+      return rc;
+    }
+  if (DBG_HASHING)
+    gcry_md_debug (md, "hash.cert");
+
+  rc = ksba_cert_hash (cert, 1, HASH_FNC, md);
+  if (rc)
+    {
+      log_error ("ksba_cert_hash failed: %s\n", gpg_strerror (rc));
       gcry_md_close (md);
       return rc;
     }
+  gcry_md_final (md);
 
+  /* Get the public key from the certificate.  */
   p = ksba_cert_get_public_key (issuer_cert);
   n = gcry_sexp_canon_len (p, 0, NULL, NULL);
   if (!n)
@@ -308,29 +441,50 @@ gpgsm_check_cert_sig (ksba_cert_t issuer_cert, ksba_cert_t cert)
       gcry_sexp_release (s_sig);
       return rc;
     }
+  if (DBG_CRYPTO)
+    gcry_log_debugsxp ("pubkey:", s_pkey);
 
-  rc = do_encode_md (md, algo, pk_algo_from_sexp (s_pkey),
-                     gcry_pk_get_nbits (s_pkey), s_pkey, &frame);
-  if (rc)
+  if (use_pss)
     {
-      gcry_md_close (md);
-      gcry_sexp_release (s_sig);
-      gcry_sexp_release (s_pkey);
-      return rc;
+      rc = gcry_sexp_build (&s_data, NULL,
+                            "(data (flags pss)"
+                            "(hash %s %b)"
+                            "(salt-length %u))",
+                            hash_algo_to_string (algo),
+                            (int)gcry_md_get_algo_dlen (algo),
+                            gcry_md_read (md, algo),
+                            saltlen);
+      if (rc)
+        BUG ();
     }
+  else
+    {
+      /* RSA or DSA: Prepare the hash for verification.  */
+      gcry_mpi_t frame;
 
-  /* put hash into the S-Exp s_hash */
-  if ( gcry_sexp_build (&s_hash, NULL, "%m", frame) )
-    BUG ();
-  gcry_mpi_release (frame);
-
+      rc = do_encode_md (md, algo, pk_algo_from_sexp (s_pkey),
+                         gcry_pk_get_nbits (s_pkey), s_pkey, &frame);
+      if (rc)
+        {
+          gcry_md_close (md);
+          gcry_sexp_release (s_sig);
+          gcry_sexp_release (s_pkey);
+          return rc;
+        }
+      if ( gcry_sexp_build (&s_data, NULL, "%m", frame) )
+        BUG ();
+      gcry_mpi_release (frame);
+    }
+  if (DBG_CRYPTO)
+    gcry_log_debugsxp ("data:", s_data);
 
-  rc = gcry_pk_verify (s_sig, s_hash, s_pkey);
+  /* Verify.  */
+  rc = gcry_pk_verify (s_sig, s_data, s_pkey);
   if (DBG_X509)
       log_debug ("gcry_pk_verify: %s\n", gpg_strerror (rc));
   gcry_md_close (md);
   gcry_sexp_release (s_sig);
-  gcry_sexp_release (s_hash);
+  gcry_sexp_release (s_data);
   gcry_sexp_release (s_pkey);
   return rc;
 }
@@ -338,30 +492,41 @@ gpgsm_check_cert_sig (ksba_cert_t issuer_cert, ksba_cert_t cert)
 
 
 int
-gpgsm_check_cms_signature (ksba_cert_t cert, ksba_const_sexp_t sigval,
-                           gcry_md_hd_t md, int mdalgo, int *r_pkalgo)
+gpgsm_check_cms_signature (ksba_cert_t cert, gcry_sexp_t s_sig,
+                           gcry_md_hd_t md, int mdalgo,
+                           unsigned int pkalgoflags, int *r_pkalgo)
 {
   int rc;
   ksba_sexp_t p;
-  gcry_mpi_t frame;
-  gcry_sexp_t s_sig, s_hash, s_pkey;
+  gcry_sexp_t s_hash, s_pkey;
   size_t n;
   int pkalgo;
+  int use_pss;
+  unsigned int saltlen = 0;
 
   if (r_pkalgo)
     *r_pkalgo = 0;
 
-  n = gcry_sexp_canon_len (sigval, 0, NULL, NULL);
-  if (!n)
-    {
-      log_error ("libksba did not return a proper S-Exp\n");
-      return gpg_error (GPG_ERR_BUG);
-    }
-  rc = gcry_sexp_sscan (&s_sig, NULL, (char*)sigval, n);
-  if (rc)
+  /* Check whether rsaPSS is needed.  This information is indicated in
+   * the SIG-VAL and already provided to us by the caller so that we
+   * do not need to parse this out. */
+  use_pss = !!(pkalgoflags & PK_ALGO_FLAG_RSAPSS);
+  if (use_pss)
     {
-      log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (rc));
-      return rc;
+      int algo;
+
+      rc = extract_pss_params (s_sig, &algo, &saltlen);
+      if (rc)
+        {
+          gcry_sexp_release (s_sig);
+          return rc;
+        }
+      if (algo != mdalgo)
+        {
+          log_error ("PSS hash algo mismatch (%d/%d)\n", mdalgo, algo);
+          gcry_sexp_release (s_sig);
+          return gpg_error (GPG_ERR_DIGEST_ALGO);
+        }
     }
 
   p = ksba_cert_get_public_key (cert);
@@ -370,41 +535,57 @@ gpgsm_check_cms_signature (ksba_cert_t cert, ksba_const_sexp_t sigval,
     {
       log_error ("libksba did not return a proper S-Exp\n");
       ksba_free (p);
-      gcry_sexp_release (s_sig);
       return gpg_error (GPG_ERR_BUG);
     }
   if (DBG_CRYPTO)
-    log_printhex ("public key: ", p, n);
+    log_printhex (p, n, "public key: ");
 
   rc = gcry_sexp_sscan ( &s_pkey, NULL, (char*)p, n);
   ksba_free (p);
   if (rc)
     {
       log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (rc));
-      gcry_sexp_release (s_sig);
       return rc;
     }
 
   pkalgo = pk_algo_from_sexp (s_pkey);
   if (r_pkalgo)
     *r_pkalgo = pkalgo;
-  rc = do_encode_md (md, mdalgo, pkalgo,
-                     gcry_pk_get_nbits (s_pkey), s_pkey, &frame);
-  if (rc)
+
+  if (use_pss)
     {
-      gcry_sexp_release (s_sig);
-      gcry_sexp_release (s_pkey);
-      return rc;
+      rc = gcry_sexp_build (&s_hash, NULL,
+                            "(data (flags pss)"
+                            "(hash %s %b)"
+                            "(salt-length %u))",
+                            hash_algo_to_string (mdalgo),
+                            (int)gcry_md_get_algo_dlen (mdalgo),
+                            gcry_md_read (md, mdalgo),
+                            saltlen);
+      if (rc)
+        BUG ();
+    }
+  else
+    {
+      /* RSA or DSA: Prepare the hash for verification.  */
+      gcry_mpi_t frame;
+
+      rc = do_encode_md (md, mdalgo, pkalgo,
+                         gcry_pk_get_nbits (s_pkey), s_pkey, &frame);
+      if (rc)
+        {
+          gcry_sexp_release (s_pkey);
+          return rc;
+        }
+      /* put hash into the S-Exp s_hash */
+      if ( gcry_sexp_build (&s_hash, NULL, "%m", frame) )
+        BUG ();
+      gcry_mpi_release (frame);
     }
-  /* put hash into the S-Exp s_hash */
-  if ( gcry_sexp_build (&s_hash, NULL, "%m", frame) )
-    BUG ();
-  gcry_mpi_release (frame);
 
   rc = gcry_pk_verify (s_sig, s_hash, s_pkey);
   if (DBG_X509)
-      log_debug ("gcry_pk_verify: %s\n", gpg_strerror (rc));
-  gcry_sexp_release (s_sig);
+    log_debug ("gcry_pk_verify: %s\n", gpg_strerror (rc));
   gcry_sexp_release (s_hash);
   gcry_sexp_release (s_pkey);
   return rc;
index ede1210..c177cab 100644 (file)
@@ -38,7 +38,7 @@
 
 #include "keydb.h"
 #include "../common/i18n.h"
-
+#include "../common/membuf.h"
 
 struct dn_array_s {
   char *key;
@@ -73,6 +73,85 @@ gpgsm_print_serial (estream_t fp, ksba_const_sexp_t sn)
 }
 
 
+/* Print the first element of an S-Expression in decimal notation
+ * assuming it is a non-negative integer. */
+void
+gpgsm_print_serial_decimal (estream_t fp, ksba_const_sexp_t sn)
+{
+  const char *p = (const char *)sn;
+  unsigned long n, i;
+  char *endp;
+  gcry_mpi_t a, r, ten;
+#if GCRYPT_VERSION_NUMBER >= 0x010900 /* >= 1.9.0 */
+  unsigned int dd;
+#else
+  unsigned char numbuf[10];
+#endif
+
+  if (!p)
+    es_fputs (_("none"), fp);
+  else if (*p != '(')
+    es_fputs ("[Internal error - not an S-expression]", fp);
+  else
+    {
+      p++;
+      n = strtoul (p, &endp, 10);
+      p = endp;
+      if (*p++ != ':')
+        es_fputs ("[Internal Error - invalid S-expression]", fp);
+      else if (gcry_mpi_scan (&a, GCRYMPI_FMT_USG, p, n, NULL))
+        es_fputs ("[Internal Error - can't convert to decimal]", fp);
+      else
+        {
+          membuf_t mb = MEMBUF_ZERO;
+          char *buf;
+          int c;
+
+          ten = gcry_mpi_set_ui (NULL, 10);
+          r = gcry_mpi_new (0);
+
+          do
+            {
+              gcry_mpi_div (a, r, a, ten, 0);
+#if GCRYPT_VERSION_NUMBER >= 0x010900 /* >= 1.9.0 */
+              gcry_mpi_get_ui (&dd, r);
+              put_membuf_printf (&mb, "%u", dd);
+#else
+              *numbuf = 0;  /* Need to clear because USB format prints
+                             * an empty string for a value of 0.  */
+              gcry_mpi_print (GCRYMPI_FMT_USG, numbuf, 10, NULL, r);
+              put_membuf_printf (&mb, "%u", (unsigned int)*numbuf);
+#endif
+            }
+          while (gcry_mpi_cmp_ui (a, 0));
+
+          /* Make sure we have at least an empty string, get it,
+           * reverse it, and print it. */
+          put_membuf (&mb, "", 1);
+          buf = get_membuf (&mb, NULL);
+          if (!buf)
+            es_fputs ("[Internal Error - out of core]", fp);
+          else
+            {
+              n = strlen (buf);
+              for (i=0; i < n/2; i++)
+                {
+                  c = buf[i];
+                  buf[i] = buf[n-1-i];
+                  buf[n-1-i] = c;
+                }
+              es_fputs (buf, fp);
+              xfree (buf);
+            }
+
+          gcry_mpi_release (r);
+          gcry_mpi_release (ten);
+          gcry_mpi_release (a);
+        }
+    }
+}
+
+
 /* Dump the serial number or any other simple S-expression. */
 void
 gpgsm_dump_serial (ksba_const_sexp_t sn)
@@ -167,7 +246,7 @@ gpgsm_dump_string (const char *string)
       else
         {
           log_printf ( "[ ");
-          log_printhex (NULL, string, strlen (string));
+          log_printhex (string, strlen (string), NULL);
           log_printf ( " ]");
         }
     }
index 3dec4fa..92d6ffe 100644 (file)
@@ -198,7 +198,7 @@ parse_parameter_usage (struct para_data_s *para, enum para_name key)
         use |= GCRY_PK_USAGE_CERT;
       else
         {
-          log_error ("line %d: invalid usage list\n", r->lnr);
+          log_error ("line %d: invalid usage list\n", r?r->lnr:0);
           return -1; /* error */
         }
     }
@@ -461,7 +461,10 @@ proc_parameters (ctrl_t ctrl, struct para_data_s *para,
   if ( (i < 1 || i != GCRY_PK_RSA) && !cardkeyid )
     {
       r = get_parameter (para, pKEYTYPE, 0);
-      log_error (_("line %d: invalid algorithm\n"), r->lnr);
+      if (r)
+        log_error (_("line %d: invalid algorithm\n"), r?r->lnr:0);
+      else
+        log_error ("No Key-Type specified\n");
       return gpg_error (GPG_ERR_INV_PARAMETER);
     }
 
@@ -476,7 +479,7 @@ proc_parameters (ctrl_t ctrl, struct para_data_s *para,
       /* The BSI specs dated 2002-11-25 don't allow lengths below 1024. */
       r = get_parameter (para, pKEYLENGTH, 0);
       log_error (_("line %d: invalid key length %u (valid are %d to %d)\n"),
-                 r->lnr, nbits, 1024, 4096);
+                 r?r->lnr:0, nbits, 1024, 4096);
       xfree (cardkeyid);
       return gpg_error (GPG_ERR_INV_PARAMETER);
     }
@@ -493,7 +496,7 @@ proc_parameters (ctrl_t ctrl, struct para_data_s *para,
   if (!(s=get_parameter_value (para, pNAMEDN, 0)))
     {
       r = get_parameter (para, pNAMEDN, 0);
-      log_error (_("line %d: no subject name given\n"), r->lnr);
+      log_error (_("line %d: no subject name given\n"), r?r->lnr:0);
       xfree (cardkeyid);
       return gpg_error (GPG_ERR_INV_PARAMETER);
     }
@@ -503,10 +506,10 @@ proc_parameters (ctrl_t ctrl, struct para_data_s *para,
       r = get_parameter (para, pNAMEDN, 0);
       if (gpg_err_code (err) == GPG_ERR_UNKNOWN_NAME)
         log_error (_("line %d: invalid subject name label '%.*s'\n"),
-                   r->lnr, (int)errlen, s+erroff);
+                   r?r->lnr:0, (int)errlen, s+erroff);
       else
         log_error (_("line %d: invalid subject name '%s' at pos %d\n"),
-                   r->lnr, s, (int)erroff);
+                   r?r->lnr:0, s, (int)erroff);
 
       xfree (cardkeyid);
       return gpg_error (GPG_ERR_INV_PARAMETER);
@@ -522,7 +525,7 @@ proc_parameters (ctrl_t ctrl, struct para_data_s *para,
           || strstr(s, ".."))
         {
           r = get_parameter (para, pNAMEEMAIL, seq);
-          log_error (_("line %d: not a valid email address\n"), r->lnr);
+          log_error (_("line %d: not a valid email address\n"), r?r->lnr:0);
           xfree (cardkeyid);
           return gpg_error (GPG_ERR_INV_PARAMETER);
         }
@@ -541,7 +544,7 @@ proc_parameters (ctrl_t ctrl, struct para_data_s *para,
           if (*s)
             {
               r = get_parameter (para, pSERIAL, 0);
-              log_error (_("line %d: invalid serial number\n"), r->lnr);
+              log_error (_("line %d: invalid serial number\n"), r?r->lnr:0);
               xfree (cardkeyid);
               return gpg_error (GPG_ERR_INV_PARAMETER);
             }
@@ -558,10 +561,10 @@ proc_parameters (ctrl_t ctrl, struct para_data_s *para,
           r = get_parameter (para, pISSUERDN, 0);
           if (gpg_err_code (err) == GPG_ERR_UNKNOWN_NAME)
             log_error (_("line %d: invalid issuer name label '%.*s'\n"),
-                       r->lnr, (int)errlen, string+erroff);
+                       r?r->lnr:0, (int)errlen, string+erroff);
           else
             log_error (_("line %d: invalid issuer name '%s' at pos %d\n"),
-                       r->lnr, string, (int)erroff);
+                       r?r->lnr:0, string, (int)erroff);
           xfree (cardkeyid);
           return gpg_error (GPG_ERR_INV_PARAMETER);
         }
@@ -572,7 +575,7 @@ proc_parameters (ctrl_t ctrl, struct para_data_s *para,
   if (string && !string2isotime (NULL, string))
     {
       r = get_parameter (para, pNOTBEFORE, 0);
-      log_error (_("line %d: invalid date given\n"), r->lnr);
+      log_error (_("line %d: invalid date given\n"), r?r->lnr:0);
       xfree (cardkeyid);
       return gpg_error (GPG_ERR_INV_PARAMETER);
     }
@@ -583,7 +586,7 @@ proc_parameters (ctrl_t ctrl, struct para_data_s *para,
   if (string && !string2isotime (NULL, string))
     {
       r = get_parameter (para, pNOTAFTER, 0);
-      log_error (_("line %d: invalid date given\n"), r->lnr);
+      log_error (_("line %d: invalid date given\n"), r?r->lnr:0);
       xfree (cardkeyid);
       return gpg_error (GPG_ERR_INV_PARAMETER);
     }
@@ -597,7 +600,7 @@ proc_parameters (ctrl_t ctrl, struct para_data_s *para,
         {
           r = get_parameter (para, pKEYTYPE, 0);
           log_error (_("line %d: error getting signing key by keygrip '%s'"
-                       ": %s\n"), r->lnr, s, gpg_strerror (rc));
+                       ": %s\n"), r?r->lnr:0, s, gpg_strerror (rc));
           xfree (cardkeyid);
           return rc;
         }
@@ -615,7 +618,7 @@ proc_parameters (ctrl_t ctrl, struct para_data_s *para,
                         || mdalgo == GCRY_MD_SHA512)))
       {
         r = get_parameter (para, pHASHALGO, 0);
-        log_error (_("line %d: invalid hash algorithm given\n"), r->lnr);
+        log_error (_("line %d: invalid hash algorithm given\n"), r?r->lnr:0);
         xfree (cardkeyid);
         return gpg_error (GPG_ERR_INV_PARAMETER);
       }
@@ -630,7 +633,7 @@ proc_parameters (ctrl_t ctrl, struct para_data_s *para,
       if (*s || (i&1))
         {
           r = get_parameter (para, pAUTHKEYID, 0);
-          log_error (_("line %d: invalid authority-key-id\n"), r->lnr);
+          log_error (_("line %d: invalid authority-key-id\n"), r?r->lnr:0);
           xfree (cardkeyid);
           return gpg_error (GPG_ERR_INV_PARAMETER);
         }
@@ -645,7 +648,7 @@ proc_parameters (ctrl_t ctrl, struct para_data_s *para,
       if (*s || (i&1))
         {
           r = get_parameter (para, pSUBJKEYID, 0);
-          log_error (_("line %d: invalid subject-key-id\n"), r->lnr);
+          log_error (_("line %d: invalid subject-key-id\n"), r?r->lnr:0);
           xfree (cardkeyid);
           return gpg_error (GPG_ERR_INV_PARAMETER);
         }
@@ -683,7 +686,7 @@ proc_parameters (ctrl_t ctrl, struct para_data_s *para,
       if (!okay)
         {
           r = get_parameter (para, pEXTENSION, seq);
-          log_error (_("line %d: invalid extension syntax\n"), r->lnr);
+          log_error (_("line %d: invalid extension syntax\n"), r? r->lnr:0);
           xfree (cardkeyid);
           return gpg_error (GPG_ERR_INV_PARAMETER);
         }
@@ -697,7 +700,7 @@ proc_parameters (ctrl_t ctrl, struct para_data_s *para,
         {
           r = get_parameter (para, pKEYTYPE, 0);
           log_error (_("line %d: error reading key '%s' from card: %s\n"),
-                     r->lnr, cardkeyid, gpg_strerror (rc));
+                     r?r->lnr:0, cardkeyid, gpg_strerror (rc));
           xfree (sigkey);
           xfree (cardkeyid);
           return rc;
@@ -727,7 +730,7 @@ proc_parameters (ctrl_t ctrl, struct para_data_s *para,
         {
           r = get_parameter (para, pKEYTYPE, 0);
           log_error (_("line %d: key generation failed: %s <%s>\n"),
-                     r->lnr, gpg_strerror (rc), gpg_strsource (rc));
+                     r?r->lnr:0, gpg_strerror (rc), gpg_strsource (rc));
           xfree (sigkey);
           xfree (cardkeyid);
           return rc;
index db0768e..90eba88 100644 (file)
@@ -72,7 +72,7 @@ prepare_decryption (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
     }
 
   if (DBG_CRYPTO)
-    log_printhex ("pkcs1 encoded session key:", seskey, seskeylen);
+    log_printhex (seskey, seskeylen, "pkcs1 encoded session key:");
 
   n=0;
   if (seskeylen == 32 || seskeylen == 24 || seskeylen == 16)
@@ -115,7 +115,7 @@ prepare_decryption (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
     }
 
   if (DBG_CRYPTO)
-    log_printhex ("session key:", seskey+n, seskeylen-n);
+    log_printhex (seskey+n, seskeylen-n, "session key:");
 
   rc = gcry_cipher_open (&parm->hd, parm->algo, parm->mode, 0);
   if (rc)
@@ -483,7 +483,7 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, estream_t out_fp)
                     /* Check compliance.  */
                     if (!gnupg_pk_is_allowed (opt.compliance,
                                               PK_USE_DECRYPTION,
-                                              pk_algo, NULL, nbits, NULL))
+                                              pk_algo, 0, NULL, nbits, NULL))
                       {
                         char  kidstr[10+1];
 
@@ -501,7 +501,7 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, estream_t out_fp)
                     /* Check that all certs are compliant with CO_DE_VS.  */
                     is_de_vs =
                       (is_de_vs
-                       && gnupg_pk_is_compliant (CO_DE_VS, pk_algo, NULL,
+                       && gnupg_pk_is_compliant (CO_DE_VS, pk_algo, 0, NULL,
                                                  nbits, NULL));
                   }
 
index 6213a66..f03097c 100644 (file)
@@ -480,7 +480,8 @@ gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, int data_fd, estream_t out_fp)
 
       /* Check compliance.  */
       pk_algo = gpgsm_get_key_algo_info (cl->cert, &nbits);
-      if (!gnupg_pk_is_compliant (opt.compliance, pk_algo, NULL, nbits, NULL))
+      if (!gnupg_pk_is_compliant (opt.compliance, pk_algo, 0,
+                                  NULL, nbits, NULL))
         {
           char  kidstr[10+1];
 
@@ -495,7 +496,7 @@ gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, int data_fd, estream_t out_fp)
       /* Fixme: When adding ECC we need to provide the curvename and
        * the key to gnupg_pk_is_compliant.  */
       if (compliant
-          && !gnupg_pk_is_compliant (CO_DE_VS, pk_algo, NULL, nbits, NULL))
+          && !gnupg_pk_is_compliant (CO_DE_VS, pk_algo, 0, NULL, nbits, NULL))
         compliant = 0;
 
       rc = encrypt_dek (dek, cl->cert, &encval);
index fbcec58..2e01cf1 100644 (file)
@@ -196,7 +196,7 @@ gpgsm_get_keygrip (ksba_cert_t cert, unsigned char *array)
       return NULL;
     }
   if (DBG_X509)
-    log_printhex ("keygrip=", array, 20);
+    log_printhex (array, 20, "keygrip=");
 
   return array;
 }
@@ -277,6 +277,41 @@ gpgsm_get_key_algo_info (ksba_cert_t cert, unsigned int *nbits)
 }
 
 
+/* This is a wrapper around pubkey_algo_string which takes a KSBA
+ * certificate instead of a Gcrypt public key.  Note that this
+ * function may return NULL on error.  */
+char *
+gpgsm_pubkey_algo_string (ksba_cert_t cert, int *r_algoid)
+{
+  gpg_error_t err;
+  gcry_sexp_t s_pkey;
+  ksba_sexp_t p;
+  size_t n;
+  enum gcry_pk_algos algoid;
+  char *algostr;
+
+  p = ksba_cert_get_public_key (cert);
+  if (!p)
+    return NULL;
+  n = gcry_sexp_canon_len (p, 0, NULL, NULL);
+  if (!n)
+    {
+      xfree (p);
+      return NULL;
+    }
+  err = gcry_sexp_sscan (&s_pkey, NULL, (char *)p, n);
+  xfree (p);
+  if (err)
+    return NULL;
+
+  algostr = pubkey_algo_string (s_pkey, r_algoid? &algoid : NULL);
+  if (algostr && r_algoid)
+    *r_algoid = algoid;
+
+  gcry_sexp_release (s_pkey);
+  return algostr;
+}
+
 
 \f
 /* For certain purposes we need a certificate id which has an upper
index 387e4d2..bb27672 100644 (file)
@@ -144,6 +144,7 @@ enum cmd_and_opt_values {
   oDisableTrustedCertCRLCheck,
   oEnableTrustedCertCRLCheck,
   oForceCRLRefresh,
+  oEnableIssuerBasedCRLCheck,
 
   oDisableOCSP,
   oEnableOCSP,
@@ -402,6 +403,8 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_n (oNoCommonCertsImport, "no-common-certs-import", "@"),
   ARGPARSE_s_s (oIgnoreCertExtension, "ignore-cert-extension", "@"),
   ARGPARSE_s_n (oNoAutostart, "no-autostart", "@"),
+  ARGPARSE_s_n (oEnableIssuerBasedCRLCheck, "enable-issuer-based-crl-check",
+                "@"),
 
   /* Command aliases.  */
   ARGPARSE_c (aListKeys, "list-key", "@"),
@@ -1202,6 +1205,9 @@ main ( int argc, char **argv)
         case oForceCRLRefresh:
           opt.force_crl_refresh = 1;
           break;
+        case oEnableIssuerBasedCRLCheck:
+          opt.enable_issuer_based_crl_check = 1;
+          break;
 
         case oDisableOCSP:
           ctrl.use_ocsp = opt.enable_ocsp = 0;
index a9fb4c8..d128344 100644 (file)
@@ -124,6 +124,7 @@ struct
   int no_crl_check;         /* Don't do a CRL check */
   int no_trusted_cert_crl_check; /* Don't run a CRL check for trusted certs. */
   int force_crl_refresh;    /* Force refreshing the CRL. */
+  int enable_issuer_based_crl_check; /* Backward compatibility hack.  */
   int enable_ocsp;          /* Default to use OCSP checks. */
 
   char *policy_file;        /* full pathname of policy file */
@@ -263,11 +264,13 @@ unsigned long gpgsm_get_short_fingerprint (ksba_cert_t cert,
 unsigned char *gpgsm_get_keygrip (ksba_cert_t cert, unsigned char *array);
 char *gpgsm_get_keygrip_hexstring (ksba_cert_t cert);
 int  gpgsm_get_key_algo_info (ksba_cert_t cert, unsigned int *nbits);
+char *gpgsm_pubkey_algo_string (ksba_cert_t cert, int *r_algoid);
 char *gpgsm_get_certid (ksba_cert_t cert);
 
 
 /*-- certdump.c --*/
 void gpgsm_print_serial (estream_t fp, ksba_const_sexp_t p);
+void gpgsm_print_serial_decimal (estream_t fp, ksba_const_sexp_t sn);
 void gpgsm_print_time (estream_t fp, ksba_isotime_t t);
 void gpgsm_print_name2 (FILE *fp, const char *string, int translate);
 void gpgsm_print_name (FILE *fp, const char *string);
@@ -293,8 +296,10 @@ char *gpgsm_format_keydesc (ksba_cert_t cert);
 
 /*-- certcheck.c --*/
 int gpgsm_check_cert_sig (ksba_cert_t issuer_cert, ksba_cert_t cert);
-int gpgsm_check_cms_signature (ksba_cert_t cert, ksba_const_sexp_t sigval,
-                               gcry_md_hd_t md, int hash_algo, int *r_pkalgo);
+int gpgsm_check_cms_signature (ksba_cert_t cert, gcry_sexp_t sigval,
+                               gcry_md_hd_t md,
+                               int hash_algo, unsigned int pkalgoflags,
+                               int *r_pkalgo);
 /* fixme: move create functions to another file */
 int gpgsm_create_cms_signature (ctrl_t ctrl,
                                 ksba_cert_t cert, gcry_md_hd_t md, int mdalgo,
@@ -423,7 +428,8 @@ gpg_error_t gpgsm_agent_export_key (ctrl_t ctrl, const char *keygrip,
 int gpgsm_dirmngr_isvalid (ctrl_t ctrl,
                            ksba_cert_t cert, ksba_cert_t issuer_cert,
                            int use_ocsp);
-int gpgsm_dirmngr_lookup (ctrl_t ctrl, strlist_t names, int cache_only,
+int gpgsm_dirmngr_lookup (ctrl_t ctrl, strlist_t names, const char *uri,
+                          int cache_only,
                           void (*cb)(void*, ksba_cert_t), void *cb_value);
 int gpgsm_dirmngr_run_command (ctrl_t ctrl, const char *command,
                                int argc, char **argv);
@@ -435,6 +441,9 @@ gpg_error_t transform_sigval (const unsigned char *sigval, size_t sigvallen,
                               int mdalgo,
                               unsigned char **r_newsigval,
                               size_t *r_newsigvallen);
+gcry_sexp_t gpgsm_ksba_cms_get_sig_val (ksba_cms_t cms, int idx);
+int gpgsm_get_hash_algo_from_sigval (gcry_sexp_t sigval,
+                                     unsigned int *r_pkalgo_flags);
 
 
 
index 8796cd2..ca69382 100644 (file)
@@ -836,7 +836,7 @@ parse_p12 (ctrl_t ctrl, ksba_reader_t reader, struct stats_s *stats)
       log_error ("can't calculate keygrip\n");
       goto leave;
     }
-  log_printhex ("keygrip=", grip, 20);
+  log_printhex (grip, 20, "keygrip=");
 
   /* Convert to canonical encoding using a function which pads it to a
      multiple of 64 bits.  We need this padding for AESWRAP.  */
index 6efc6bd..8c7fafc 100644 (file)
@@ -361,7 +361,10 @@ print_compliance_flags (ksba_cert_t cert, int algo, unsigned int nbits,
 {
   int hashalgo;
 
-  if (gnupg_pk_is_compliant (CO_DE_VS, algo, NULL, nbits, NULL))
+  /* Note that we do not need to test for PK_ALGO_FLAG_RSAPSS because
+   * that is not a property of the key but one of the created
+   * signature.  */
+  if (gnupg_pk_is_compliant (CO_DE_VS, algo, 0, NULL, nbits, NULL))
     {
       hashalgo = gcry_md_map_name (ksba_cert_get_digest_algo (cert));
       if (gnupg_digest_is_compliant (CO_DE_VS, hashalgo))
@@ -738,8 +741,11 @@ list_cert_raw (ctrl_t ctrl, KEYDB_HANDLE hd,
   sexp = ksba_cert_get_serial (cert);
   es_fputs ("          S/N: ", fp);
   gpgsm_print_serial (fp, sexp);
-  ksba_free (sexp);
   es_putc ('\n', fp);
+  es_fputs ("        (dec): ", fp);
+  gpgsm_print_serial_decimal (fp, sexp);
+  es_putc ('\n', fp);
+  ksba_free (sexp);
 
   dn = ksba_cert_get_issuer (cert, 0);
   es_fputs ("       Issuer: ", fp);
@@ -1118,8 +1124,11 @@ list_cert_std (ctrl_t ctrl, ksba_cert_t cert, estream_t fp, int have_secret,
   sexp = ksba_cert_get_serial (cert);
   es_fputs ("          S/N: ", fp);
   gpgsm_print_serial (fp, sexp);
-  ksba_free (sexp);
   es_putc ('\n', fp);
+  es_fputs ("        (dec): ", fp);
+  gpgsm_print_serial_decimal (fp, sexp);
+  es_putc ('\n', fp);
+  ksba_free (sexp);
 
   dn = ksba_cert_get_issuer (cert, 0);
   es_fputs ("       Issuer: ", fp);
@@ -1607,7 +1616,7 @@ list_external_keys (ctrl_t ctrl, strlist_t names, estream_t fp, int raw_mode)
   parm.with_chain = ctrl->with_chain;
   parm.raw_mode  = raw_mode;
 
-  rc = gpgsm_dirmngr_lookup (ctrl, names, 0, list_external_cb, &parm);
+  rc = gpgsm_dirmngr_lookup (ctrl, names, NULL, 0, list_external_cb, &parm);
   if (gpg_err_code (rc) == GPG_ERR_EOF || rc == -1
       || gpg_err_code (rc) == GPG_ERR_NOT_FOUND)
     rc = 0; /* "Not found" is not an error here. */
index 6d04776..66d928c 100644 (file)
--- a/sm/misc.c
+++ b/sm/misc.c
@@ -216,3 +216,93 @@ transform_sigval (const unsigned char *sigval, size_t sigvallen, int mdalgo,
 
   return err;
 }
+
+
+/* Wrapper around ksba_cms_get_sig_val to return a gcrypt object
+ * instaed of ksba's canonical s-expression.  On errror NULL is return
+ * and in some cases an error message is printed.  */
+gcry_sexp_t
+gpgsm_ksba_cms_get_sig_val (ksba_cms_t cms, int idx)
+{
+  gpg_error_t err;
+  ksba_sexp_t sigval;
+  gcry_sexp_t s_sigval;
+  size_t n;
+
+  sigval = ksba_cms_get_sig_val (cms, idx);
+  if (!sigval)
+    return NULL;
+  n = gcry_sexp_canon_len (sigval, 0, NULL, NULL);
+  if (!n)
+    {
+      log_error ("%s: libksba did not return a proper S-Exp\n", __func__);
+      ksba_free (sigval);
+      return NULL;
+    }
+  err = gcry_sexp_sscan (&s_sigval, NULL, (char*)sigval, n);
+  ksba_free (sigval);
+  if (err)
+    {
+      log_error ("%s: gcry_sexp_scan failed: %s\n",
+                 __func__, gpg_strerror (err));
+      s_sigval = NULL;
+    }
+
+  return s_sigval;
+}
+
+
+/* Return the hash algorithm from the S-expression SIGVAL.  Returns 0
+ * if the hash algorithm is not encoded in SIGVAL or it is not
+ * supported by libgcrypt.  It further stores flag values for the
+ * public key algorithm at R_PKALGO_FLAGS; the only flag we currently
+ * support is PK_ALGO_FLAG_RSAPSS.  */
+int
+gpgsm_get_hash_algo_from_sigval (gcry_sexp_t sigval_arg,
+                                 unsigned int *r_pkalgo_flags)
+{
+  gcry_sexp_t sigval, l1;
+  size_t n;
+  const char *s;
+  char *string;
+  int hashalgo;
+  int i;
+
+  *r_pkalgo_flags = 0;
+
+  sigval = gcry_sexp_find_token (sigval_arg, "sig-val", 0);
+  if (!sigval)
+    return 0;   /* Not a sig-val.  */
+
+  /* First check whether this is a rsaPSS signature and return that as
+   * additional info.  */
+  l1 = gcry_sexp_find_token (sigval, "flags", 0);
+  if (l1)
+    {
+      /* Note that the flag parser assumes that the list of flags
+       * contains only strings and in particular not a sub-list.  This
+       * is always the case for the current libksba. */
+      for (i=1; (s = gcry_sexp_nth_data (l1, i, &n)); i++)
+        if (n == 3 && !memcmp (s, "pss", 3))
+          {
+            *r_pkalgo_flags |= PK_ALGO_FLAG_RSAPSS;
+            break;
+          }
+      gcry_sexp_release (l1);
+    }
+
+  l1 = gcry_sexp_find_token (sigval, "hash", 0);
+  if (!l1)
+    {
+      gcry_sexp_release (sigval);
+      return 0; /* hash algorithm not given in sigval. */
+    }
+  string = gcry_sexp_nth_string (l1, 1);
+  gcry_sexp_release (sigval);
+  if (!string)
+    return 0; /* hash algorithm has no value. */
+  hashalgo = gcry_md_map_name (string);
+  gcry_free (string);
+
+  return hashalgo;
+}
index fd6ebe0..dd7612f 100644 (file)
--- a/sm/sign.c
+++ b/sm/sign.c
@@ -486,7 +486,7 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
         unsigned int nbits;
         int pk_algo = gpgsm_get_key_algo_info (cl->cert, &nbits);
 
-        if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_SIGNING, pk_algo,
+        if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_SIGNING, pk_algo, 0,
                                    NULL, nbits, NULL))
           {
             char  kidstr[10+1];
index 10b3f43..0fa365f 100644 (file)
@@ -1,6 +1,8 @@
 /* verify.c - Verify a messages signature
  * Copyright (C) 2001, 2002, 2003, 2007,
  *               2010 Free Software Foundation, Inc.
+ * Copyright (C) 2001-2019 Werner Koch
+ * Copyright (C) 2015-2020 g10 Code GmbH
  *
  * This file is part of GnuPG.
  *
@@ -16,6 +18,7 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: GPL-3.0-or-later
  */
 
 #include <config.h>
@@ -286,7 +289,7 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, estream_t out_fp)
   for (signer=0; ; signer++)
     {
       char *issuer = NULL;
-      ksba_sexp_t sigval = NULL;
+      gcry_sexp_t sigval = NULL;
       ksba_isotime_t sigtime, keyexptime;
       ksba_sexp_t serial;
       char *msgdigest = NULL;
@@ -294,7 +297,11 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, estream_t out_fp)
       char *ctattr;
       int sigval_hash_algo;
       int info_pkalgo;
-      unsigned int verifyflags;
+      unsigned int nbits;
+      int pkalgo;
+      char *pkalgostr = NULL;
+      char *pkfpr = NULL;
+      unsigned int pkalgoflags, verifyflags;
 
       rc = ksba_cms_get_issuer_serial (cms, signer, &issuer, &serial);
       if (!signer && gpg_err_code (rc) == GPG_ERR_NO_DATA
@@ -400,20 +407,19 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, estream_t out_fp)
       rc = 0;
 
 
-      sigval = ksba_cms_get_sig_val (cms, signer);
+      sigval = gpgsm_ksba_cms_get_sig_val (cms, signer);
       if (!sigval)
         {
           log_error ("no signature value available\n");
           audit_log_s (ctrl->audit, AUDIT_SIG_STATUS, "bad");
           goto next_signer;
         }
-      sigval_hash_algo = hash_algo_from_sigval (sigval);
+
+      sigval_hash_algo = gpgsm_get_hash_algo_from_sigval (sigval, &pkalgoflags);
       if (DBG_X509)
         {
-          log_debug ("signer %d - signature available (sigval hash=%d)",
-                     signer, sigval_hash_algo);
-/*           log_printhex ("sigval    ", sigval, */
-/*                         gcry_sexp_canon_len (sigval, 0, NULL, NULL)); */
+          log_debug ("signer %d - signature available (sigval hash=%d pkaf=%u)",
+                     signer, sigval_hash_algo, pkalgoflags);
         }
       if (!sigval_hash_algo)
         sigval_hash_algo = algo; /* Fallback used e.g. with old libksba. */
@@ -450,49 +456,68 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, estream_t out_fp)
           goto next_signer;
         }
 
-      /* Check compliance.  */
-      {
-        unsigned int nbits;
-        int pk_algo = gpgsm_get_key_algo_info (cert, &nbits);
-
-        if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_VERIFICATION,
-                                   pk_algo, NULL, nbits, NULL))
-          {
-            char  kidstr[10+1];
-
-            snprintf (kidstr, sizeof kidstr, "0x%08lX",
-                      gpgsm_get_short_fingerprint (cert, NULL));
-            log_error (_("key %s may not be used for signing in %s mode\n"),
-                       kidstr,
-                       gnupg_compliance_option_string (opt.compliance));
-            goto next_signer;
-          }
-
-        if (! gnupg_digest_is_allowed (opt.compliance, 0, sigval_hash_algo))
-          {
-            log_error (_("digest algorithm '%s' may not be used in %s mode\n"),
-                       gcry_md_algo_name (sigval_hash_algo),
-                       gnupg_compliance_option_string (opt.compliance));
-            goto next_signer;
-          }
-
-        /* Check compliance with CO_DE_VS.  */
-        if (gnupg_pk_is_compliant (CO_DE_VS, pk_algo, NULL, nbits, NULL)
-            && gnupg_digest_is_compliant (CO_DE_VS, sigval_hash_algo))
-          gpgsm_status (ctrl, STATUS_VERIFICATION_COMPLIANCE_MODE,
-                        gnupg_status_compliance_flag (CO_DE_VS));
-      }
+      pkfpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
+      pkalgostr = gpgsm_pubkey_algo_string (cert, NULL);
+      pkalgo = gpgsm_get_key_algo_info (cert, &nbits);
 
       log_info (_("Signature made "));
       if (*sigtime)
-        dump_isotime (sigtime);
+        {
+          /* We take the freedom as noted in RFC3339 to use a space
+           * instead of the "T" delimiter between date and time.  We
+           * also append a separate UTC instead of a "Z" or "+00:00"
+           * suffix because that makes it clear to everyone what kind
+           * of time this is.  */
+          dump_isotime (sigtime);
+          log_printf (" UTC");
+        }
       else
         log_printf (_("[date not given]"));
-      log_printf (_(" using certificate ID 0x%08lX\n"),
-                  gpgsm_get_short_fingerprint (cert, NULL));
+      log_info (_("               using %s key %s\n"), pkalgostr, pkfpr);
+      if (opt.verbose)
+        {
+          log_info (_("algorithm:"));
+          log_printf (" %s + %s",
+                      pubkey_algo_to_string (pkalgo),
+                      gcry_md_algo_name (sigval_hash_algo));
+          if (algo != sigval_hash_algo)
+            log_printf (" (%s)", gcry_md_algo_name (algo));
+          log_printf ("\n");
+        }
 
       audit_log_i (ctrl->audit, AUDIT_DATA_HASH_ALGO, algo);
 
+      /* Check compliance.  */
+      if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_VERIFICATION,
+                                 pkalgo, pkalgoflags, NULL, nbits, NULL))
+        {
+          char  kidstr[10+1];
+
+          snprintf (kidstr, sizeof kidstr, "0x%08lX",
+                    gpgsm_get_short_fingerprint (cert, NULL));
+          log_error (_("key %s may not be used for signing in %s mode\n"),
+                     kidstr,
+                     gnupg_compliance_option_string (opt.compliance));
+          goto next_signer;
+        }
+
+      if (!gnupg_digest_is_allowed (opt.compliance, 0, sigval_hash_algo))
+        {
+          log_error (_("digest algorithm '%s' may not be used in %s mode\n"),
+                     gcry_md_algo_name (sigval_hash_algo),
+                     gnupg_compliance_option_string (opt.compliance));
+          goto next_signer;
+        }
+
+      /* Check compliance with CO_DE_VS.  */
+      if (gnupg_pk_is_compliant (CO_DE_VS, pkalgo, pkalgoflags,
+                                 NULL, nbits, NULL)
+          && gnupg_digest_is_compliant (CO_DE_VS, sigval_hash_algo))
+        gpgsm_status (ctrl, STATUS_VERIFICATION_COMPLIANCE_MODE,
+                      gnupg_status_compliance_flag (CO_DE_VS));
+
+
+      /* Now we can check the signature.  */
       if (msgdigest)
         { /* Signed attributes are available. */
           gcry_md_hd_t md;
@@ -512,10 +537,10 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, estream_t out_fp)
               if (DBG_X509)
                 {
                   if (msgdigest)
-                    log_printhex ("message:  ", msgdigest, msgdigestlen);
+                    log_printhex (msgdigest, msgdigestlen, "message:  ");
                   if (s)
-                    log_printhex ("computed: ",
-                                  s, gcry_md_get_algo_dlen (algo));
+                    log_printhex (s, gcry_md_get_algo_dlen (algo),
+                                  "computed: ");
                 }
               fpr = gpgsm_fpr_and_name_for_status (cert);
               gpgsm_status (ctrl, STATUS_BADSIG, fpr);
@@ -545,14 +570,14 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, estream_t out_fp)
               audit_log_s (ctrl->audit, AUDIT_SIG_STATUS, "error");
               goto next_signer;
             }
-          rc = gpgsm_check_cms_signature (cert, sigval, md,
-                                          sigval_hash_algo, &info_pkalgo);
+          rc = gpgsm_check_cms_signature (cert, sigval, md, sigval_hash_algo,
+                                          pkalgoflags, &info_pkalgo);
           gcry_md_close (md);
         }
       else
         {
           rc = gpgsm_check_cms_signature (cert, sigval, data_md,
-                                          algo, &info_pkalgo);
+                                          algo, pkalgoflags, &info_pkalgo);
         }
 
       if (rc)
@@ -669,8 +694,10 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, estream_t out_fp)
       rc = 0;
       xfree (issuer);
       xfree (serial);
-      xfree (sigval);
+      gcry_sexp_release (sigval);
       xfree (msgdigest);
+      xfree (pkalgostr);
+      xfree (pkfpr);
       ksba_cert_release (cert);
       cert = NULL;
     }
index 9f07c7a..6492c43 100644 (file)
@@ -33,7 +33,7 @@ static gpg_error_t
 run_sendmail (estream_t data)
 {
   gpg_error_t err;
-  const char pgmname[] = "/usr/lib/sendmail";
+  const char pgmname[] = NAME_OF_SENDMAIL;
   const char *argv[3];
 
   argv[0] = "-oi";