Merge branch 'STABLE-BRANCH-2-2'
authorWerner Koch <wk@gnupg.org>
Thu, 22 Feb 2018 15:19:56 +0000 (16:19 +0100)
committerWerner Koch <wk@gnupg.org>
Thu, 22 Feb 2018 15:19:56 +0000 (16:19 +0100)
105 files changed:
AUTHORS
NEWS
README
agent/agent.h
agent/call-pinentry.c
agent/call-scd.c
agent/command-ssh.c
agent/command.c
agent/cvt-openpgp.c
agent/divert-scd.c
agent/pkdecrypt.c
agent/protect.c
autogen.rc
autogen.sh
common/Makefile.am
common/asshelp.c
common/exechelp-posix.c
common/exechelp-w32.c
common/exechelp-w32ce.c
common/exechelp.h
common/iobuf.c
common/iobuf.h
common/logging.c
common/logging.h
common/miscellaneous.c
common/openpgpdefs.h
common/pkscreening.c [new file with mode: 0644]
common/pkscreening.h [new file with mode: 0644]
common/sysutils.c
common/util.h
configure.ac
dirmngr/crlcache.c
dirmngr/dirmngr.c
dirmngr/http.c
dirmngr/misc.c
doc/DETAILS
doc/HACKING
doc/Makefile.am
doc/examples/README
doc/examples/qualified.txt [moved from doc/qualified.txt with 98% similarity]
doc/gpg.texi
doc/gpgsm.texi
doc/howto-create-a-server-cert.texi
doc/wks.texi
g10/Makefile.am
g10/build-packet.c
g10/call-agent.c
g10/card-util.c
g10/cipher-aead.c [new file with mode: 0644]
g10/cipher.c
g10/decrypt-data.c
g10/dek.h
g10/ecdh.c
g10/encrypt.c
g10/filter.h
g10/getkey.c
g10/gpg.c
g10/gpg.h
g10/gpgcompose.c
g10/import.c
g10/kbnode.c
g10/keydb.h
g10/keyedit.c
g10/keygen.c
g10/keyid.c
g10/keylist.c
g10/main.h
g10/mainproc.c
g10/misc.c
g10/openfile.c
g10/options.h
g10/packet.h
g10/parse-packet.c
g10/pkclist.c
g10/pubkey-enc.c
g10/sig-check.c
g10/sign.c
g10/tdbdump.c
g10/tofu.c
g13/call-syshelp.c
g13/g13tuple.c
kbx/kbxutil.c
scd/apdu.c
scd/apdu.h
scd/app-openpgp.c
scd/app-p15.c
scd/iso7816.c
sm/certchain.c
sm/certcheck.c
sm/certdump.c
sm/certreqgen-ui.c
sm/certreqgen.c
sm/decrypt.c
sm/fingerprint.c
sm/gpgsm.c
sm/gpgsm.h
sm/import.c
sm/keylist.c
sm/qualified.c
sm/verify.c
tests/openpgp/Makefile.am
tests/openpgp/all-tests.scm
tests/openpgp/armor.scm
tests/openpgp/defs.scm
tools/gpgconf-comp.c

diff --git a/AUTHORS b/AUTHORS
index 473b94c..0dabbc1 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -38,15 +38,188 @@ List of Copyright holders
 Authors with a FSF copyright assignment
 =======================================
 
-The list of authors who signed a FSF copyright assignment is kept in
-the GIT master branch's copy of this file.
+Ales Nyakhaychyk <nyakhaychyk@i1fn.linux.by> Translations [be]
+
+Andrey Jivsov <openpgp@brainhub.org>  Assigns past and future changes for ECC.
+    (g10/ecdh.c.  other changes to support ECC)
+
+Ben Kibbey  <bjk@luxsci.net>  Assigns past and future changes.
+
+Birger Langkjer <birger.langkjer@image.dk> Translations [da]
+
+Maxim Britov <maxim.britov@gmail.com> Translations [ru]
+
+Daniel Resare  <daniel@resare.com> Translations [sv]
+Per Tunedal    <per@clipanish.com> Translations [sv]
+Daniel Nylander <po@danielnylander.se> Translations [sv]
+
+Daiki Ueno <ueno@unixuser.org>  Assigns Past and Future Changes.
+    (changed:passphrase.c and related code)
+
+David Shaw <dshaw@jabberwocky.com> Assigns past and future changes.
+    (all in keyserver/,
+     a lot of changes in g10/ see the ChangeLog,
+     bug fixes here and there)
+
+Dokianakis Theofanis <madf@hellug.gr> Translations [el]
+
+Edmund GRIMLEY EVANS <edmundo@rano.org> Translations [eo]
+
+Florian Weimer <fw@deneb.enyo.de>  Assigns past and future changes
+    (changed:g10/parse-packet.c, include/iobuf.h, util/iobuf.c)
+
+g10 Code GmbH   <info@g10code.com>  Assigns past and future changes
+    (all work since 2001 as indicated by mail addresses in ChangeLogs)
+
+Gaël Quéri  <gael@lautre.net>  Translations [fr]
+    (fixed a lot of typos)
+
+Gregory Steuck <steuck@iname.com> Translations [ru]
+
+Nagy Ferenc László <nfl@nfllab.com> Translations [hu]
+
+Ivo Timmermans <itimmermans@bigfoot.com> Translations [nl]
+
+Jacobo Tarri'o Barreiro <jtarrio@iname.com> Translations [gl]
+
+Janusz Aleksander Urbanowicz <alex@bofh.torun.pl> Translations [pl]
+Jakub Bogusz <qboosh@pld-linux.org> Translations [pl]
+
+Jedi Lin <Jedi@idej.org> Translations [zh-tw]
+
+Jouni Hiltunen <jouni.hiltunen@kolumbus.fi> Translations [fi]
+Tommi Vainikainen <Tommi.Vainikainen@iki.fi> Translations [fi]
+
+Laurentiu Buzdugan <lbgnupg@rolix.org> Translations [ro]
+
+Magda Procha'zkova'  <magda@math.muni.cz> Translations [cs]
+
+Michael Roth  <mroth@nessie.de>  Assigns changes.
+    (wrote cipher/des.c., changes and bug fixes all over the place)
+
+Michal Majer <mmajer@econ.umb.sk> Translations [sk]
+
+Marco d'Itri <md@linux.it> Translations [it]
+
+Marcus Brinkmann  <marcus@g10code.de>
+    (gpgconf and fixes all over the place)
+
+Matthew Skala <mskala@ansuz.sooke.bc.ca>  Disclaimer
+    (wrote cipher/twofish.c)
+
+Moritz Schulte  <moritz@g10code.com>
+   (ssh support gpg-agent)
+
+Niklas Hernaeus <nh@df.lth.se> Disclaimer
+    (weak key patches)
+
+Nilgun Belma Buguner <nilgun@technologist.com> Translations [tr]
+
+Nils Ellmenreich  <nils 'at' infosun.fmi.uni-passau.de>
+                                      Assigns past and future changes
+    (configure.in, cipher/rndlinux.c, FAQ)
+
+Paul Eggert <eggert@twinsun.com>
+    (configuration macros for LFS)
+
+Pavel I. Shajdo <pshajdo@gmail.com> Translations [ru]
+    (man pages)
+
+Pedro Morais <morais@poli.org> Translations [pt_PT]
+
+Rémi Guyomarch        <rguyom@mail.dotcom.fr> Assigns past and future changes.
+    (g10/compress.c, g10/encr-data.c,
+     g10/free-packet.c, g10/mdfilter.c, g10/plaintext.c, util/iobuf.c)
+
+Stefan Bellon   <sbellon@sbellon.de> Assigns past and future changes.
+   (All patches to support RISC OS)
+
+Timo Schulz     <twoaday@freakmail.de> Assigns past and future changes.
+   (util/w32reg.c, g10/passphrase.c, g10/hkp.c)
+
+Tedi Heriyanto <tedi_h@gmx.net> Translations [id]
+
+Thiago Jung Bauermann <jungmann@cwb.matrix.com.br> Translations [pt_BR]
+Rafael Caetano dos Santos <rcaetano@linux.ime.usp.br> Translations [pt_BR]
+
+Toomas Soome <tsoome@ut.ee> Translations [et]
+
+Urko Lusa <ulusa@euskalnet.net> Translations [es_ES]
+
+Walter Koch <koch@u32.de>  Translations [de]
+
+Werner Koch  <wk@gnupg.org>  Assigns GNU Privacy Guard and future changes.
+    (started the whole thing, wrote the S/MIME extensions, the
+     smartcard daemon and the gpg-agent)
+
+Yosiaki IIDA <iida@ring.gr.jp> Translations [ja]
+
+Yuri Chornoivan, yurchor at ukr dot net: Translations [uk]
+
+Yutaka Niibe   Assigns Past and Future Changes
+     (scd/)
 
 
 Authors with a DCO
 ==================
 
-The list of authors who signed the Developer's Certificate of Origin
-is kept in the GIT master branch's copy of this file.
+Andre Heinecke <aheinecke@intevation.de>
+2014-09-19:4525694.FcpLvWDUFT@esus:
+
+Andreas Schwier <andreas.schwier@cardcontact.de>
+2014-07-22:53CED1D8.1010306@cardcontact.de:
+
+Arnaud Fontaine <arnaud.fontaine at ssi.gouv.fr>
+2016-10-17:580484F4.8040806@ssi.gouv.fr:
+
+Christian Aistleitner <christian@quelltextlich.at>
+2013-05-26:20130626112332.GA2228@quelltextlich.at:
+
+Damien Goutte-Gattat <dgouttegattat@incenp.org>
+2015-01-17:54BA49AA.2040708@incenp.org:
+
+Daniel Kahn Gillmor <dkg@fifthhorseman.net>
+2014-09-24:87oau6w9q7.fsf@alice.fifthhorseman.net:
+
+Hans of Guardian <hans@guardianproject.info>
+2013-06-26:D84473D7-F3F7-43D5-A9CE-16580B88D574@guardianproject.info:
+
+Ineiev <ineiev@gnu.org>
+2017-05-09:20170509121611.GH25850@gnu.org:
+
+Jonas Borgström <jonas@borgstrom.se>
+2013-08-29:521F1E7A.5080602@borgstrom.se:
+
+Joshua Rogers <git@internot.info>
+2014-12-22:5497FE75.7010503@internot.info:
+
+Jussi Kivilinna <jussi.kivilinna@iki.fi>
+2018-02-11:2d8b7014-ff67-1e73-1152-9ff9fb8c10d7@iki.fi:
+
+Kyle Butt <kylebutt@gmail.com>
+2013-05-29:CAAODAYLbCtqOG6msLLL0UTdASKWT6u2ptxsgUQ1JpusBESBoNQ@mail.gmail.com:
+
+Phil Pennock <phil.pennock@spodhuis.org>
+Phil Pennock <phil@pennock-tech.com>
+2017-01-19:20170119061225.GA26207@breadbox.private.spodhuis.org:
+
+Rainer Perske <rainer.perske@uni-muenster.de>
+2017-10-24:permail-2017102014511105be2aed00002fc6-perske@message-id.uni-muenster.de:
+
+Stefan Tomanek <tomanek@internet-sicherheit.de>
+2014-01-30:20140129234449.GY30808@zirkel.wertarbyte.de:
+
+Tobias Mueller <muelli@cryptobitch.de>
+2016-11-23:1479937342.11180.3.camel@cryptobitch.de:
+
+Werner Koch <wk@gnupg.org>
+2013-03-29:87620ahchj.fsf@vigenere.g10code.de:
+
+William L. Thomson Jr. <wlt@o-sinc.com>
+2017-05-23:assp.0316398ca8.20170523093623.00a17d03@o-sinc.com:
+
+Yann E. MORIN <yann.morin.1998@free.fr>
+2016-07-10:20160710093202.GA3688@free.fr:
 
 
 Other authors
diff --git a/NEWS b/NEWS
index 4a4f87e..4fa20b2 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,54 +1,7 @@
-Noteworthy changes in version 2.2.6 (unreleased)
+Noteworthy changes in version 2.3.0 (unreleased)
 ------------------------------------------------
 
-
-Noteworthy changes in version 2.2.5 (2018-02-22)
-------------------------------------------------
-
-  * gpg: Allow the use of the "cv25519" and "ed25519" short names in
-    addition to the canonical curve names in --batch --gen-key.
-
-  * gpg: Make sure to print all secret keys with option --list-only
-    and --decrypt.  [#3718]
-
-  * gpg: Fix the use of future-default with --quick-add-key for
-    signing keys.  [#3747]
-
-  * gpg: Select a secret key by checking availability under gpg-agent.
-    [#1967]
-
-  * gpg: Fix reversed prompt texts for --only-sign-text-ids.  [#3787]
-
-  * gpg,gpgsm: Fix detection of bogus keybox blobs on 32 bit systems.
-    [#3770]
-
-  * gpgsm: Fix regression since 2.1 in --export-secret-key-raw which
-    got $d mod (q-1)$ wrong.  Note that most tools automatically fixup
-    that parameter anyway.
-
-  * ssh: Fix a regression in getting the client'd PID on *BSD and
-    macOS.
-
-  * scd: Support the KDF Data Object of the OpenPGP card 3.3.  [#3152]
-
-  * scd: Fix a regression in the internal CCID driver for certain card
-    readers.  [#3508]
-
-  * scd: Fix a problem on NetBSD killing scdaemon on gpg-agent
-    shutdown.  [#3778]
-
-  * dirmngr: Improve returned error description on failure of DNS
-    resolving.  [#3756]
-
-  * wks: Implement command --install-key for gpg-wks-server.
-
-  * Add option STATIC=1 to the Speedo build system to allow a build
-    with statically linked versions of the core GnuPG libraries.  Also
-    use --enable-wks-tools by default by Speedo builds for Unix.
-
-
-Noteworthy changes in version 2.2.4 (2017-12-20)
-------------------------------------------------
+  Changes also found in 2.2.4:
 
   * gpg: Change default preferences to prefer SHA512.
 
@@ -77,11 +30,7 @@ Noteworthy changes in version 2.2.4 (2017-12-20)
   * New configure option --enable-run-gnupg-user-socket to first try a
     socket directory which is not removed by systemd at session end.
 
-  See-also: gnupg-announce/2017q4/000419.html
-
-
-Noteworthy changes in version 2.2.3 (2017-11-20)
-------------------------------------------------
+  Changes also found in 2.2.3:
 
   * gpgsm: Fix initial keybox creation on Windows. [#3507]
 
@@ -101,8 +50,7 @@ Noteworthy changes in version 2.2.3 (2017-11-20)
   See-also: gnupg-announce/2017q4/000417.html
 
 
-Noteworthy changes in version 2.2.2 (2017-11-07)
-------------------------------------------------
+  Changes also found in 2.2.2:
 
   * gpg: Avoid duplicate key imports by concurrently running gpg
     processes. [#3446]
@@ -145,9 +93,7 @@ Noteworthy changes in version 2.2.2 (2017-11-07)
 
   See-also: gnupg-announce/2017q4/000416.html
 
-
-Noteworthy changes in version 2.2.1 (2017-09-19)
-------------------------------------------------
+  Changes also found in 2.2.1:
 
   * gpg: Fix formatting of the user id in batch mode key generation
     if only "name-email" is given.
@@ -167,7 +113,12 @@ Noteworthy changes in version 2.2.1 (2017-09-19)
     certificates are configured.  If build with GNUTLS, this was
     already the case.
 
-  See-also: gnupg-announce/2017q3/000415.html
+  Release dates of 2.2.x versions:
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  Version 2.2.1 (2017-09-19)
+  Version 2.2.2 (2017-11-07)
+  Version 2.2.3 (2017-11-20)
+  Version 2.2.4 (2017-12-20)
 
 
 Noteworthy changes in version 2.2.0 (2017-08-28)
diff --git a/README b/README
index d46efd9..39ccc4d 100644 (file)
--- a/README
+++ b/README
@@ -26,7 +26,8 @@
 
   Note that the 2.0 series of GnuPG will reach end-of-life on
   2017-12-31.  It is not possible to install a 2.2.x version along
-  with any 2.0.x version.
+  with any 2.0.x version.  However, it is possible to install GnuPG
+  1.4 along with any 2.x version.
 
 
 * BUILD INSTRUCTIONS
index c2d8579..687635d 100644 (file)
@@ -230,6 +230,7 @@ struct server_control_s
   char *lc_ctype;
   char *lc_messages;
   unsigned long client_pid;
+  int client_uid;
 
   /* The current pinentry mode.  */
   pinentry_mode_t pinentry_mode;
index a088681..af4eb06 100644 (file)
@@ -598,8 +598,9 @@ start_pinentry (ctrl_t ctrl)
         nodename = utsbuf.nodename;
 #endif /*!HAVE_W32_SYSTEM*/
 
-      if ((optstr = xtryasprintf ("OPTION owner=%lu %s",
-                                  ctrl->client_pid, nodename)))
+      if ((optstr = xtryasprintf ("OPTION owner=%lu/%d %s",
+                                  ctrl->client_pid, ctrl->client_uid,
+                                  nodename)))
         {
           assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
                            NULL);
index cf61a35..6ce0cdd 100644 (file)
@@ -89,7 +89,6 @@ struct inq_needpin_parm_s
   const char *getpin_cb_desc;
   assuan_context_t passthru;  /* If not NULL, pass unknown inquiries
                                  up to the caller.  */
-  int any_inq_seen;
 
   /* The next fields are used by inq_writekey_parm.  */
   const unsigned char *keydata;
@@ -727,7 +726,6 @@ inq_needpin (void *opaque, const char *line)
   size_t pinlen;
   int rc;
 
-  parm->any_inq_seen = 1;
   if ((s = has_leading_keyword (line, "NEEDPIN")))
     {
       line = s;
@@ -811,30 +809,6 @@ hash_algo_option (int algo)
 }
 
 
-static gpg_error_t
-cancel_inquire (ctrl_t ctrl, gpg_error_t rc)
-{
-  gpg_error_t oldrc = rc;
-
-  /* The inquire callback was called and transact returned a
-     cancel error.  We assume that the inquired process sent a
-     CANCEL.  The passthrough code is not able to pass on the
-     CANCEL and thus scdaemon would stuck on this.  As a
-     workaround we send a CANCEL now.  */
-  rc = assuan_write_line (ctrl->scd_local->ctx, "CAN");
-  if (!rc) {
-    char *line;
-    size_t len;
-
-    rc = assuan_read_line (ctrl->scd_local->ctx, &line, &len);
-    if (!rc)
-      rc = oldrc;
-  }
-
-  return rc;
-}
-
-
 /* Create a signature using the current card.  MDALGO is either 0 or
  * gives the digest algorithm.  DESC_TEXT is an additional parameter
  * passed to GETPIN_CB. */
@@ -875,7 +849,6 @@ agent_card_pksign (ctrl_t ctrl,
   inqparm.getpin_cb_arg = getpin_cb_arg;
   inqparm.getpin_cb_desc = desc_text;
   inqparm.passthru = 0;
-  inqparm.any_inq_seen = 0;
   inqparm.keydata = NULL;
   inqparm.keydatalen = 0;
 
@@ -888,9 +861,6 @@ agent_card_pksign (ctrl_t ctrl,
                         put_membuf_cb, &data,
                         inq_needpin, &inqparm,
                         NULL, NULL);
-  if (inqparm.any_inq_seen && (gpg_err_code(rc) == GPG_ERR_CANCELED ||
-       gpg_err_code(rc) == GPG_ERR_ASS_CANCELED))
-    rc = cancel_inquire (ctrl, rc);
 
   if (rc)
     {
@@ -974,7 +944,6 @@ agent_card_pkdecrypt (ctrl_t ctrl,
   inqparm.getpin_cb_arg = getpin_cb_arg;
   inqparm.getpin_cb_desc = desc_text;
   inqparm.passthru = 0;
-  inqparm.any_inq_seen = 0;
   inqparm.keydata = NULL;
   inqparm.keydatalen = 0;
   snprintf (line, DIM(line), "PKDECRYPT %s", keyid);
@@ -982,9 +951,6 @@ agent_card_pkdecrypt (ctrl_t ctrl,
                         put_membuf_cb, &data,
                         inq_needpin, &inqparm,
                         padding_info_cb, r_padding);
-  if (inqparm.any_inq_seen && (gpg_err_code(rc) == GPG_ERR_CANCELED ||
-       gpg_err_code(rc) == GPG_ERR_ASS_CANCELED))
-    rc = cancel_inquire (ctrl, rc);
 
   if (rc)
     {
@@ -1111,15 +1077,11 @@ agent_card_writekey (ctrl_t ctrl,  int force, const char *serialno,
   parms.getpin_cb_arg = getpin_cb_arg;
   parms.getpin_cb_desc= NULL;
   parms.passthru = 0;
-  parms.any_inq_seen = 0;
   parms.keydata = keydata;
   parms.keydatalen = keydatalen;
 
   rc = assuan_transact (ctrl->scd_local->ctx, line, NULL, NULL,
                         inq_writekey_parms, &parms, NULL, NULL);
-  if (parms.any_inq_seen && (gpg_err_code(rc) == GPG_ERR_CANCELED ||
-                             gpg_err_code(rc) == GPG_ERR_ASS_CANCELED))
-    rc = cancel_inquire (ctrl, rc);
   return unlock_scd (ctrl, rc);
 }
 
@@ -1344,7 +1306,6 @@ agent_card_scd (ctrl_t ctrl, const char *cmdline,
   inqparm.getpin_cb_arg = getpin_cb_arg;
   inqparm.getpin_cb_desc = NULL;
   inqparm.passthru = assuan_context;
-  inqparm.any_inq_seen = 0;
   inqparm.keydata = NULL;
   inqparm.keydatalen = 0;
 
@@ -1354,8 +1315,6 @@ agent_card_scd (ctrl_t ctrl, const char *cmdline,
                         pass_data_thru, assuan_context,
                         inq_needpin, &inqparm,
                         pass_status_thru, assuan_context);
-  if (inqparm.any_inq_seen && gpg_err_code(rc) == GPG_ERR_ASS_CANCELED)
-    rc = cancel_inquire (ctrl, rc);
 
   assuan_set_flag (ctrl->scd_local->ctx, ASSUAN_CONVEY_COMMENTS, saveflag);
   if (rc)
index e0b7238..7155446 100644 (file)
@@ -258,6 +258,11 @@ static gpg_error_t ssh_signature_encoder_eddsa (ssh_key_type_spec_t *spec,
 static gpg_error_t ssh_key_extract_comment (gcry_sexp_t key, char **comment);
 
 
+struct peer_info_s
+{
+  unsigned long pid;
+  int uid;
+};
 
 /* Global variables.  */
 
@@ -3584,10 +3589,11 @@ ssh_request_process (ctrl_t ctrl, estream_t stream_sock)
 
 
 /* Return the peer's pid.  */
-static unsigned long
-get_client_pid (int fd)
+static void
+get_client_info (int fd, struct peer_info_s *out)
 {
-  pid_t client_pid = (pid_t)0;
+  pid_t client_pid = (pid_t)(-1);
+  uid_t client_uid = (uid_t)-1;
 
 #ifdef SO_PEERCRED
   {
@@ -3602,8 +3608,10 @@ get_client_pid (int fd)
       {
 #if defined (HAVE_STRUCT_SOCKPEERCRED_PID) || defined (HAVE_STRUCT_UCRED_PID)
         client_pid = cr.pid;
+        client_uid = cr.uid;
 #elif defined (HAVE_STRUCT_UCRED_CR_PID)
         client_pid = cr.cr_pid;
+        client_pid = cr.cr_uid;
 #else
 #error "Unknown SO_PEERCRED struct"
 #endif
@@ -3614,6 +3622,15 @@ get_client_pid (int fd)
     socklen_t len = sizeof (pid_t);
 
     getsockopt (fd, SOL_LOCAL, LOCAL_PEERPID, &client_pid, &len);
+#if defined (LOCAL_PEERCRED)
+    {
+      struct xucred cr;
+      len = sizeof (struct xucred);
+
+      if (!getsockopt (fd, SOL_LOCAL, LOCAL_PEERCRED, &cr, &len))
+       client_uid = cr.cr_uid;
+    }
+#endif
   }
 #elif defined (LOCAL_PEEREID)
   {
@@ -3622,6 +3639,7 @@ get_client_pid (int fd)
 
     if (getsockopt (fd, 0, LOCAL_PEEREID, &unp, &unpl) != -1)
       client_pid = unp.unp_pid;
+      client_uid = unp.unp_euid;
   }
 #elif defined (HAVE_GETPEERUCRED)
   {
@@ -3629,7 +3647,8 @@ get_client_pid (int fd)
 
     if (getpeerucred (fd, &ucred) != -1)
       {
-        client_pid= ucred_getpid (ucred);
+        client_pid = ucred_getpid (ucred);
+       client_uid = ucred_geteuid (ucred);
         ucred_free (ucred);
       }
   }
@@ -3637,7 +3656,8 @@ get_client_pid (int fd)
   (void)fd;
 #endif
 
-  return (unsigned long)client_pid;
+  out->pid = (client_pid == (pid_t)(-1)? 0 : (unsigned long)client_pid);
+  out->uid = (int)client_uid;
 }
 
 
@@ -3648,12 +3668,15 @@ start_command_handler_ssh (ctrl_t ctrl, gnupg_fd_t sock_client)
   estream_t stream_sock = NULL;
   gpg_error_t err;
   int ret;
+  struct peer_info_s peer_info;
 
   err = agent_copy_startup_env (ctrl);
   if (err)
     goto out;
 
-  ctrl->client_pid = get_client_pid (FD2INT(sock_client));
+  get_client_info (FD2INT(sock_client), &peer_info);
+  ctrl->client_pid = peer_info.pid;
+  ctrl->client_uid = peer_info.uid;
 
   /* Create stream from socket.  */
   stream_sock = es_fdopen (FD2INT(sock_client), "r+");
index f9bc6ca..e2486a5 100644 (file)
@@ -843,7 +843,7 @@ static const char hlp_genkey[] =
   "\n"
   "  C: GENKEY\n"
   "  S: INQUIRE KEYPARAM\n"
-  "  C: D (genkey (rsa (nbits  2048)))\n"
+  "  C: D (genkey (rsa (nbits 3072)))\n"
   "  C: END\n"
   "  S: D (public-key\n"
   "  S: D   (rsa (n 326487324683264) (e 10001)))\n"
@@ -3317,7 +3317,7 @@ start_command_handler (ctrl_t ctrl, gnupg_fd_t listen_fd, gnupg_fd_t fd)
 
   for (;;)
     {
-      pid_t client_pid;
+      assuan_peercred_t client_creds;
 
       rc = assuan_accept (ctx);
       if (gpg_err_code (rc) == GPG_ERR_EOF || rc == -1)
@@ -3330,12 +3330,20 @@ start_command_handler (ctrl_t ctrl, gnupg_fd_t listen_fd, gnupg_fd_t fd)
           break;
         }
 
-      client_pid = assuan_get_pid (ctx);
-      ctrl->server_local->connect_from_self = (client_pid == getpid ());
-      if (client_pid != ASSUAN_INVALID_PID)
-        ctrl->client_pid = (unsigned long)client_pid;
+      rc = assuan_get_peercred (ctx, &client_creds);
+      if (rc)
+        {
+          log_info ("Assuan get_peercred failed: %s\n", gpg_strerror (rc));
+          client_creds->pid = assuan_get_pid (ctx);
+          ctrl->client_uid = -1;
+        }
+      ctrl->server_local->connect_from_self =
+        (client_creds->pid == getpid ());
+      if (client_creds->pid != ASSUAN_INVALID_PID)
+        ctrl->client_pid = (unsigned long)client_creds->pid;
       else
         ctrl->client_pid = 0;
+      ctrl->client_uid = client_creds->uid;
 
       rc = assuan_process (ctx);
       if (rc)
index ee12221..c4d0334 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 88b35cd..b85b490 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 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 7b5abf2..16ae715 100644 (file)
@@ -163,7 +163,7 @@ calibrate_s2k_count_one (unsigned long count)
 
 
 /* Measure the time we need to do the hash operations and deduce an
-   S2K count which requires about 100ms of time.  */
+   S2K count which requires roughly some targeted amount of time.  */
 static unsigned long
 calibrate_s2k_count (void)
 {
@@ -175,11 +175,11 @@ calibrate_s2k_count (void)
       ms = calibrate_s2k_count_one (count);
       if (opt.verbose > 1)
         log_info ("S2K calibration: %lu -> %lums\n", count, ms);
-      if (ms > 100)
+      if (ms > AGENT_S2K_CALIBRATION)
         break;
     }
 
-  count = (unsigned long)(((double)count / ms) * 100);
+  count = (unsigned long)(((double)count / ms) * AGENT_S2K_CALIBRATION);
   count /= 1024;
   count *= 1024;
   if (count < 65536)
index 3ea03e0..aa56591 100644 (file)
@@ -1,7 +1,7 @@
 # autogen.sh configuration for GnuPG                           -*- sh -*-
 
 display_name=GnuPG
-
+patches_to=gnupg-devel@gnupg.org
 #version_parts=3
 
 case "$myhost:$myhostsub" in
index b238550..4b511bf 100755 (executable)
@@ -469,6 +469,7 @@ EOF
       chmod +x  .git/hooks/commit-msg
       if [ x"${display_name}" != x ]; then
          git config format.subjectPrefix "PATCH ${display_name}"
+         git config sendemail.to "${patches_to}"
       fi
   fi
 fi
index fcbe7ea..94318da 100644 (file)
@@ -94,7 +94,8 @@ common_sources = \
        name-value.c name-value.h \
        recsel.c recsel.h \
        ksba-io-support.c ksba-io-support.h \
-       compliance.c compliance.h
+       compliance.c compliance.h \
+       pkscreening.c pkscreening.h
 
 
 if HAVE_W32_SYSTEM
index f3a92f9..5209ea6 100644 (file)
@@ -93,7 +93,7 @@ my_libassuan_log_handler (assuan_context_t ctx, void *hook,
     return 0; /* Temporary disabled.  */
 
   if (msg)
-    log_string (GPGRT_LOG_DEBUG, msg);
+    log_string (GPGRT_LOGLVL_DEBUG, msg);
 
   return 1;
 }
@@ -307,6 +307,71 @@ unlock_spawning (lock_spawn_t *lock, const char *name)
     }
 }
 
+
+/* Helper for start_new_gpg_agent and start_new_dirmngr.
+ * Values for WHICH are:
+ *   0 - Start gpg-agent
+ *   1 - Start dirmngr
+ * SECS give the number of seconds to wait.  SOCKNAME is the name of
+ * the socket to connect.  VERBOSE is the usual verbose flag. CTX is
+ * the assuan context.  DID_SUCCESS_MSG will be set to 1 if a success
+ * messages has been printed.
+ */
+static gpg_error_t
+wait_for_sock (int secs, int which, const char *sockname,
+               int verbose, assuan_context_t ctx, int *did_success_msg)
+{
+  gpg_error_t err = 0;
+  int target_us = secs * 1000000;
+  int elapsed_us = 0;
+  /*
+   * 977us * 1024 = just a little more than 1s.
+   * so we will double this timeout 10 times in the first
+   * second, and then switch over to 1s checkins.
+   */
+  int next_sleep_us = 977;
+  int lastalert = secs+1;
+  int secsleft;
+
+  while (elapsed_us < target_us)
+    {
+      if (verbose)
+        {
+          secsleft = (target_us - elapsed_us + 999999)/1000000;
+          /* log_clock ("left=%d last=%d targ=%d elap=%d next=%d\n", */
+          /*            secsleft, lastalert, target_us, elapsed_us, */
+          /*            next_sleep_us); */
+          if (secsleft < lastalert)
+            {
+              log_info (which == 1?
+                        _("waiting for the dirmngr to come up ... (%ds)\n"):
+                        _("waiting for the agent to come up ... (%ds)\n"),
+                        secsleft);
+              lastalert = secsleft;
+            }
+        }
+      gnupg_usleep (next_sleep_us);
+      elapsed_us += next_sleep_us;
+      err = assuan_socket_connect (ctx, sockname, 0, 0);
+      if (!err)
+        {
+          if (verbose)
+            {
+              log_info (which == 1?
+                        _("connection to the dirmngr established\n"):
+                        _("connection to the agent established\n"));
+              *did_success_msg = 1;
+            }
+          break;
+        }
+      next_sleep_us *= 2;
+      if (next_sleep_us > 1000000)
+        next_sleep_us = 1000000;
+    }
+  return err;
+}
+
+
 /* Try to connect to the agent via socket or start it if it is not
    running and AUTOSTART is set.  Handle the server's initial
    greeting.  Returns a new assuan context at R_CTX or an error
@@ -433,25 +498,8 @@ start_new_gpg_agent (assuan_context_t *r_ctx,
             log_error ("failed to start agent '%s': %s\n",
                        agent_program, gpg_strerror (err));
           else
-            {
-              for (i=0; i < SECS_TO_WAIT_FOR_AGENT; i++)
-                {
-                  if (verbose)
-                    log_info (_("waiting for the agent to come up ... (%ds)\n"),
-                              SECS_TO_WAIT_FOR_AGENT - i);
-                  gnupg_sleep (1);
-                  err = assuan_socket_connect (ctx, sockname, 0, 0);
-                  if (!err)
-                    {
-                      if (verbose)
-                        {
-                          log_info (_("connection to agent established\n"));
-                          did_success_msg = 1;
-                        }
-                      break;
-                    }
-                }
-            }
+            err = wait_for_sock (SECS_TO_WAIT_FOR_AGENT, 0,
+                                 sockname, verbose, ctx, &did_success_msg);
         }
 
       unlock_spawning (&lock, "agent");
@@ -468,7 +516,7 @@ start_new_gpg_agent (assuan_context_t *r_ctx,
     }
 
   if (debug && !did_success_msg)
-    log_debug ("connection to agent established\n");
+    log_debug ("connection to the agent established\n");
 
   err = assuan_transact (ctx, "RESET",
                          NULL, NULL, NULL, NULL, NULL, NULL);
@@ -485,7 +533,7 @@ start_new_gpg_agent (assuan_context_t *r_ctx,
                                 NULL, NULL, NULL, NULL, NULL, NULL))
             {
               if (verbose)
-                log_info (_("connection to agent is in restricted mode\n"));
+                log_info (_("connection to the agent is in restricted mode\n"));
               err = 0;
             }
         }
@@ -542,7 +590,7 @@ start_new_dirmngr (assuan_context_t *r_ctx,
         dirmngr_program = gnupg_module_name (GNUPG_MODULE_NAME_DIRMNGR);
 
       if (verbose)
-        log_info (_("no running Dirmngr - starting '%s'\n"),
+        log_info (_("no running dirmngr - starting '%s'\n"),
                   dirmngr_program);
 
       if (status_cb)
@@ -584,29 +632,8 @@ start_new_dirmngr (assuan_context_t *r_ctx,
             log_error ("failed to start the dirmngr '%s': %s\n",
                        dirmngr_program, gpg_strerror (err));
           else
-            {
-              int i;
-
-              for (i=0; i < SECS_TO_WAIT_FOR_DIRMNGR; i++)
-                {
-                  if (verbose)
-                    log_info (_("waiting for the dirmngr "
-                                "to come up ... (%ds)\n"),
-                              SECS_TO_WAIT_FOR_DIRMNGR - i);
-                  gnupg_sleep (1);
-                  err = assuan_socket_connect (ctx, sockname, 0, 0);
-                  if (!err)
-                    {
-                      if (verbose)
-                        {
-                          log_info (_("connection to the dirmngr"
-                                      " established\n"));
-                          did_success_msg = 1;
-                        }
-                      break;
-                    }
-                }
-            }
+            err = wait_for_sock (SECS_TO_WAIT_FOR_DIRMNGR, 1,
+                                 sockname, verbose, ctx, &did_success_msg);
         }
 
       unlock_spawning (&lock, "dirmngr");
index 7237993..425f2b4 100644 (file)
@@ -1,6 +1,6 @@
 /* exechelp.c - Fork and exec helpers for POSIX
- * Copyright (C) 2004, 2007, 2008, 2009,
- *               2010 Free Software Foundation, Inc.
+ * Copyright (C) 2004, 2007-2009, 2010 Free Software Foundation, Inc.
+ * Copyright (C) 2004, 2006-2012, 2014-2017 g10 Code GmbH
  *
  * This file is part of GnuPG.
  *
@@ -26,6 +26,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: (LGPL-3.0+ OR GPL-2.0+)
  */
 
 #include <config.h>
@@ -784,30 +785,32 @@ gnupg_wait_processes (const char **pgmnames, pid_t *pids, size_t count,
         }
     }
 
-  if (ec == 0)
-    for (i = 0; i < count; i++)
-      {
-        if (WIFEXITED (r_exitcodes[i]) && WEXITSTATUS (r_exitcodes[i]) == 127)
-          {
-            log_error (_("error running '%s': probably not installed\n"),
-                       pgmnames[i]);
-            ec = GPG_ERR_CONFIGURATION;
-          }
-        else if (WIFEXITED (r_exitcodes[i]) && WEXITSTATUS (r_exitcodes[i]))
-          {
-            if (dummy)
-              log_error (_("error running '%s': exit status %d\n"),
-                         pgmnames[i], WEXITSTATUS (r_exitcodes[i]));
-            else
-              r_exitcodes[i] = WEXITSTATUS (r_exitcodes[i]);
-            ec = GPG_ERR_GENERAL;
-          }
-        else if (!WIFEXITED (r_exitcodes[i]))
-          {
-            log_error (_("error running '%s': terminated\n"), pgmnames[i]);
-            ec = GPG_ERR_GENERAL;
-          }
-      }
+  for (i = 0; i < count; i++)
+    {
+      if (r_exitcodes[i] == -1)
+        continue;
+
+      if (WIFEXITED (r_exitcodes[i]) && WEXITSTATUS (r_exitcodes[i]) == 127)
+        {
+          log_error (_("error running '%s': probably not installed\n"),
+                     pgmnames[i]);
+          ec = GPG_ERR_CONFIGURATION;
+        }
+      else if (WIFEXITED (r_exitcodes[i]) && WEXITSTATUS (r_exitcodes[i]))
+        {
+          if (dummy)
+            log_error (_("error running '%s': exit status %d\n"),
+                       pgmnames[i], WEXITSTATUS (r_exitcodes[i]));
+          else
+            r_exitcodes[i] = WEXITSTATUS (r_exitcodes[i]);
+          ec = GPG_ERR_GENERAL;
+        }
+      else if (!WIFEXITED (r_exitcodes[i]))
+        {
+          log_error (_("error running '%s': terminated\n"), pgmnames[i]);
+          ec = GPG_ERR_GENERAL;
+        }
+    }
 
   xfree (dummy);
   return gpg_err_make (GPG_ERR_SOURCE_DEFAULT, ec);
index 2c44e2c..fddcbb6 100644 (file)
@@ -1,6 +1,6 @@
 /* exechelp-w32.c - Fork and exec helpers for W32.
- * Copyright (C) 2004, 2007, 2008, 2009,
- *               2010 Free Software Foundation, Inc.
+ * Copyright (C) 2004, 2007-2009, 2010 Free Software Foundation, Inc.
+ * Copyright (C) 2004, 2006-2012, 2014-2017 g10 Code GmbH
  *
  * This file is part of GnuPG.
  *
@@ -26,6 +26,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: (LGPL-3.0+ OR GPL-2.0+)
  */
 
 #include <config.h>
index ec9f014..3d68a01 100644 (file)
@@ -1,6 +1,6 @@
 /* exechelp-w32.c - Fork and exec helpers for W32CE.
- * Copyright (C) 2004, 2007, 2008, 2009,
- *               2010 Free Software Foundation, Inc.
+ * Copyright (C) 2004, 2007-2009, 2010 Free Software Foundation, Inc.
+ * Copyright (C) 2010-2012, 2014-2016 g10 Code GmbH
  *
  * This file is part of GnuPG.
  *
@@ -26,6 +26,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: (LGPL-3.0+ OR GPL-2.0+)
  */
 
 #include <config.h>
index 2b40ba0..9e1f56f 100644 (file)
@@ -1,5 +1,6 @@
 /* exechelp.h - Definitions for the fork and exec helpers
  * Copyright (C) 2004, 2009, 2010 Free Software Foundation, Inc.
+ * Copyright (C) 2004, 2006-2012, 2014-2017 g10 Code GmbH
  *
  * This file is part of GnuPG.
  *
@@ -25,6 +26,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: (LGPL-3.0+ OR GPL-2.0+)
  */
 
 #ifndef GNUPG_COMMON_EXECHELP_H
index 5a9fd7c..02c9b49 100644 (file)
 
 /*-- Begin configurable part.  --*/
 
-/* The size of the internal buffers.
-   NOTE: If you change this value you MUST also adjust the regression
-   test "armored_key_8192" in armor.test! */
-#define IOBUF_BUFFER_SIZE  8192
+/* The standard size of the internal buffers.  */
+#define DEFAULT_IOBUF_BUFFER_SIZE  (64*1024)
 
 /* To avoid a potential DoS with compression packets we better limit
    the number of filters in a chain.  */
 
 /*-- End configurable part.  --*/
 
+/* The size of the iobuffers.  This can be chnages using the
+ * iobuf_set_buffer_size fucntion.  */
+static unsigned int iobuf_buffer_size = DEFAULT_IOBUF_BUFFER_SIZE;
+
 
 #ifdef HAVE_W32_SYSTEM
 # ifdef HAVE_W32CE_SYSTEM
@@ -92,6 +94,7 @@ typedef struct
   int keep_open;
   int no_cache;
   int eof_seen;
+  int delayed_rc;
   int print_only_name; /* Flags indicating that fname is not a real file.  */
   char fname[1];       /* Name of the file.  */
 } file_filter_ctx_t;
@@ -167,7 +170,7 @@ static int translate_file_handle (int fd, int for_write);
    to be sent to A's filter function.
 
    If A is a IOBUF_OUTPUT_TEMP filter, then this also enlarges the
-   buffer by IOBUF_BUFFER_SIZE.
+   buffer by iobuf_buffer_size.
 
    May only be called on an IOBUF_OUTPUT or IOBUF_OUTPUT_TEMP filters.  */
 static int filter_flush (iobuf_t a);
@@ -451,12 +454,20 @@ file_filter (void *opaque, int control, iobuf_t chain, byte * buf,
 
   if (control == IOBUFCTRL_UNDERFLOW)
     {
-      assert (size); /* We need a buffer.  */
+      log_assert (size); /* We need a buffer.  */
       if (a->eof_seen)
        {
          rc = -1;
          *ret_len = 0;
        }
+      else if (a->delayed_rc)
+        {
+          rc = a->delayed_rc;
+          a->delayed_rc = 0;
+          if (rc == -1)
+            a->eof_seen = -1;
+         *ret_len = 0;
+        }
       else
        {
 #ifdef HAVE_W32_SYSTEM
@@ -487,29 +498,39 @@ file_filter (void *opaque, int control, iobuf_t chain, byte * buf,
          int n;
 
          nbytes = 0;
-         do
-           {
-             n = read (f, buf, size);
-           }
-         while (n == -1 && errno == EINTR);
-         if (n == -1)
-           {                   /* error */
-             if (errno != EPIPE)
-               {
-                 rc = gpg_error_from_syserror ();
-                 log_error ("%s: read error: %s\n",
-                            a->fname, strerror (errno));
-               }
-           }
-         else if (!n)
-           {                   /* eof */
-             a->eof_seen = 1;
-             rc = -1;
-           }
-         else
-           {
-             nbytes = n;
-           }
+        read_more:
+          do
+            {
+              n = read (f, buf + nbytes, size - nbytes);
+            }
+          while (n == -1 && errno == EINTR);
+          if (n > 0)
+            {
+              nbytes += n;
+              if (nbytes < size)
+                goto read_more;
+            }
+          else if (!n) /* eof */
+            {
+              if (nbytes)
+                a->delayed_rc = -1;
+              else
+                {
+                  a->eof_seen = 1;
+                  rc = -1;
+                }
+            }
+          else /* error */
+            {
+              rc = gpg_error_from_syserror ();
+              if (gpg_err_code (rc) != GPG_ERR_EPIPE)
+                log_error ("%s: read error: %s\n", a->fname, gpg_strerror (rc));
+              if (nbytes)
+                {
+                  a->delayed_rc = rc;
+                  rc = 0;
+                }
+            }
 #endif
          *ret_len = nbytes;
        }
@@ -569,6 +590,7 @@ file_filter (void *opaque, int control, iobuf_t chain, byte * buf,
   else if (control == IOBUFCTRL_INIT)
     {
       a->eof_seen = 0;
+      a->delayed_rc = 0;
       a->keep_open = 0;
       a->no_cache = 0;
     }
@@ -1053,6 +1075,30 @@ block_filter (void *opaque, int control, iobuf_t chain, byte * buffer,
   return rc;
 }
 
+
+/* Change the default size for all IOBUFs to KILOBYTE.  This needs to
+ * be called before any iobufs are used and can only be used once.
+ * Returns the current value.  Using 0 has no effect except for
+ * returning the current value.  */
+unsigned int
+iobuf_set_buffer_size (unsigned int kilobyte)
+{
+  static int used;
+
+  if (!used && kilobyte)
+    {
+      if (kilobyte < 4)
+        kilobyte = 4;
+      else if (kilobyte > 16*1024)
+        kilobyte = 16*1024;
+
+      iobuf_buffer_size = kilobyte * 1024;
+      used = 1;
+    }
+  return iobuf_buffer_size / 1024;
+}
+
+
 #define MAX_IOBUF_DESC 32
 /*
  * Fill the buffer by the description of iobuf A.
@@ -1105,7 +1151,7 @@ iobuf_alloc (int use, size_t bufsize)
   if (bufsize == 0)
     {
       log_bug ("iobuf_alloc() passed a bufsize of 0!\n");
-      bufsize = IOBUF_BUFFER_SIZE;
+      bufsize = iobuf_buffer_size;
     }
 
   a = xcalloc (1, sizeof *a);
@@ -1213,7 +1259,7 @@ iobuf_cancel (iobuf_t a)
 iobuf_t
 iobuf_temp (void)
 {
-  return iobuf_alloc (IOBUF_OUTPUT_TEMP, IOBUF_BUFFER_SIZE);
+  return iobuf_alloc (IOBUF_OUTPUT_TEMP, iobuf_buffer_size);
 }
 
 iobuf_t
@@ -1288,7 +1334,7 @@ do_open (const char *fname, int special_filenames,
        return NULL;
     }
 
-  a = iobuf_alloc (use, IOBUF_BUFFER_SIZE);
+  a = iobuf_alloc (use, iobuf_buffer_size);
   fcx = xmalloc (sizeof *fcx + strlen (fname));
   fcx->fp = fp;
   fcx->print_only_name = print_only;
@@ -1335,7 +1381,7 @@ do_iobuf_fdopen (int fd, const char *mode, int keep_open)
   fp = INT2FD (fd);
 
   a = iobuf_alloc (strchr (mode, 'w') ? IOBUF_OUTPUT : IOBUF_INPUT,
-                  IOBUF_BUFFER_SIZE);
+                  iobuf_buffer_size);
   fcx = xmalloc (sizeof *fcx + 20);
   fcx->fp = fp;
   fcx->print_only_name = 1;
@@ -1373,7 +1419,7 @@ iobuf_esopen (estream_t estream, const char *mode, int keep_open)
   size_t len = 0;
 
   a = iobuf_alloc (strchr (mode, 'w') ? IOBUF_OUTPUT : IOBUF_INPUT,
-                  IOBUF_BUFFER_SIZE);
+                  iobuf_buffer_size);
   fcx = xtrymalloc (sizeof *fcx + 30);
   fcx->fp = estream;
   fcx->print_only_name = 1;
@@ -1398,7 +1444,7 @@ iobuf_sockopen (int fd, const char *mode)
   size_t len;
 
   a = iobuf_alloc (strchr (mode, 'w') ? IOBUF_OUTPUT : IOBUF_INPUT,
-                  IOBUF_BUFFER_SIZE);
+                  iobuf_buffer_size);
   scx = xmalloc (sizeof *scx + 25);
   scx->sock = fd;
   scx->print_only_name = 1;
@@ -1599,13 +1645,13 @@ iobuf_push_filter2 (iobuf_t a,
         increased accordingly.  We don't need to allocate a 10 MB
         buffer for a non-terminal filter.  Just use the default
         size.  */
-      a->d.size = IOBUF_BUFFER_SIZE;
+      a->d.size = iobuf_buffer_size;
     }
   else if (a->use == IOBUF_INPUT_TEMP)
     /* Same idea as above.  */
     {
       a->use = IOBUF_INPUT;
-      a->d.size = IOBUF_BUFFER_SIZE;
+      a->d.size = iobuf_buffer_size;
     }
 
   /* The new filter (A) gets a new buffer.
@@ -1922,7 +1968,7 @@ filter_flush (iobuf_t a)
 
   if (a->use == IOBUF_OUTPUT_TEMP)
     {                          /* increase the temp buffer */
-      size_t newsize = a->d.size + IOBUF_BUFFER_SIZE;
+      size_t newsize = a->d.size + iobuf_buffer_size;
 
       if (DBG_IOBUF)
        log_debug ("increasing temp iobuf from %lu to %lu\n",
index 22e02da..1615638 100644 (file)
@@ -259,6 +259,12 @@ struct iobuf_struct
 EXTERN_UNLESS_MAIN_MODULE int iobuf_debug_mode;
 
 
+/* Change the default size for all IOBUFs to KILOBYTE.  This needs to
+ * be called before any iobufs are used and can only be used once.
+ * Returns the current value.  Using 0 has no effect except for
+ * returning the current value.  */
+unsigned int iobuf_set_buffer_size (unsigned int kilobyte);
+
 /* Returns whether the specified filename corresponds to a pipe.  In
    particular, this function checks if FNAME is "-" and, if special
    filenames are enabled (see check_special_filename), whether
index c4eaca4..88860e7 100644 (file)
 #include "logging.h"
 #include "sysutils.h"
 
+#if defined(GPGRT_ENABLE_LOG_MACROS) && defined(log_debug_string)
+      /* Nothing to do; the libgpgrt functions are used.  */
+#else /* Use our own logging functions.  */
+
 #ifdef HAVE_W32_SYSTEM
 # ifndef S_IRWXG
 #  define S_IRGRP S_IRUSR
@@ -885,7 +889,7 @@ log_logv (int level, const char *fmt, va_list arg_ptr)
  * Note that PREFIX is an additional string and independent of the
  * prefix set by log_set_prefix.  */
 void
-log_logv_with_prefix (int level, const char *prefix,
+log_logv_prefix (int level, const char *prefix,
                       const char *fmt, va_list arg_ptr)
 {
   do_logv (level, 0, NULL, prefix, fmt, arg_ptr);
@@ -977,7 +981,7 @@ log_debug (const char *fmt, ...)
  * printed with LFs expanded to include the prefix and a final --end--
  * marker.  */
 void
-log_debug_with_string (const char *string, const char *fmt, ...)
+log_debug_string (const char *string, const char *fmt, ...)
 {
   va_list arg_ptr ;
 
@@ -1011,7 +1015,7 @@ 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 *text)
 {
   if (text && *text)
     log_debug ("%s ", text);
@@ -1039,14 +1043,16 @@ log_printsexp () {}
 is found in sexputils.c
 */
 
-
+/* Print a microsecond timestamp followed by a FORMAT.  */
 void
-log_clock (const char *string)
+log_clock (const char *fmt, ...)
 {
-#if 0
+#if ENABLE_LOG_CLOCK
   static unsigned long long initial;
   struct timespec tv;
   unsigned long long now;
+  char clockbuf[50];
+  va_list arg_ptr;
 
   if (clock_gettime (CLOCK_REALTIME, &tv))
     {
@@ -1059,11 +1065,21 @@ log_clock (const char *string)
   if (!initial)
     initial = now;
 
-  log_debug ("[%6llu] %s", (now - initial)/1000, string);
-#else
-  /* You need to link with -ltr to enable the above code.  */
-  log_debug ("[not enabled in the source] %s", string);
-#endif
+  snprintf (clockbuf, sizeof clockbuf, "[%6llu] ", (now - initial)/1000);
+  va_start (arg_ptr, fmt);
+  do_logv (GPGRT_LOG_DEBUG, 0, NULL, clockbuf, fmt, arg_ptr);
+  va_end (arg_ptr);
+
+#else /*!ENABLE_LOG_CLOCK*/
+
+  /* You may need to link with -ltr to use the above code.  */
+  va_list arg_ptr;
+
+  va_start (arg_ptr, fmt);
+  do_logv (GPGRT_LOG_DEBUG, 0, NULL, "[no clock] ", fmt, arg_ptr);
+  va_end (arg_ptr);
+
+#endif  /*!ENABLE_LOG_CLOCK*/
 }
 
 
@@ -1101,3 +1117,5 @@ _log_assert (const char *expr, const char *file, int line)
   abort (); /* Never called; just to make the compiler happy.  */
 }
 #endif /*!GPGRT_HAVE_MACRO_FUNCTION*/
+
+#endif /* Use our own logging functions.  */
index 2225100..a20b8f8 100644 (file)
 #include "mischelp.h"
 #include "w32help.h"
 
+#if defined(GPGRT_ENABLE_LOG_MACROS) && defined(log_debug_string)
+  /* We use the libgpg-error provided log functions.  but we need one
+   * more function:  */
+# ifdef GPGRT_HAVE_MACRO_FUNCTION
+#  define BUG() bug_at ( __FILE__, __LINE__, __FUNCTION__)
+static inline void bug_at (const char *file, int line, const char *func)
+                           GPGRT_ATTR_NORETURN;
+static inline void
+bug_at (const char *file, int line, const char *func)
+{
+  gpgrt_log (GPGRT_LOGLVL_BUG, "there is a bug at %s:%d:%s\n",
+             file, line, func);
+  abort ();
+}
+# else
+#  define BUG() bug_at ( __FILE__, __LINE__)
+static inline void bug_at (const char *file, int line)
+                           GPGRT_ATTR_NORETURN;
+static inline void
+bug_at (const char *file, int line)
+{
+  gpgrt_log (GPGRT_LOGLVL_BUG, "there is a bug at %s:%d\n", file, line);
+  abort ();
+}
+# endif /*!GPGRT_HAVE_MACRO_FUNCTION*/
+
+
+#else /* Use gnupg internal logging functions.  */
+
 int  log_get_errorcount (int clear);
 void log_inc_errorcount (void);
 void log_set_file( const char *name );
@@ -88,18 +117,27 @@ enum jnlib_log_levels {
     GPGRT_LOG_BUG,
     GPGRT_LOG_DEBUG
 };
+#define GPGRT_LOGLVL_BEGIN  GPGRT_LOG_BEGIN
+#define GPGRT_LOGLVL_CONT   GPGRT_LOG_CONT
+#define GPGRT_LOGLVL_INFO   GPGRT_LOG_INFO
+#define GPGRT_LOGLVL_WARN   GPGRT_LOG_WARN
+#define GPGRT_LOGLVL_ERROR  GPGRT_LOG_ERROR
+#define GPGRT_LOGLVL_FATAL  GPGRT_LOG_FATAL
+#define GPGRT_LOGLVL_BUG    GPGRT_LOG_BUG
+#define GPGRT_LOGLVL_DEBUG  GPGRT_LOG_DEBUG
+
 void log_log (int level, const char *fmt, ...) GPGRT_ATTR_PRINTF(2,3);
 void log_logv (int level, const char *fmt, va_list arg_ptr);
-void log_logv_with_prefix (int level, const char *prefix,
-                           const char *fmt, va_list arg_ptr);
+void log_logv_prefix (int level, const char *prefix,
+                      const char *fmt, va_list arg_ptr);
 void log_string (int level, const char *string);
 void log_bug (const char *fmt, ...)    GPGRT_ATTR_NR_PRINTF(1,2);
 void log_fatal (const char *fmt, ...)  GPGRT_ATTR_NR_PRINTF(1,2);
 void log_error (const char *fmt, ...)  GPGRT_ATTR_PRINTF(1,2);
 void log_info (const char *fmt, ...)   GPGRT_ATTR_PRINTF(1,2);
 void log_debug (const char *fmt, ...)  GPGRT_ATTR_PRINTF(1,2);
-void log_debug_with_string (const char *string, const char *fmt,
-                            ...) GPGRT_ATTR_PRINTF(2,3);
+void log_debug_string (const char *string, const char *fmt,
+                       ...) GPGRT_ATTR_PRINTF(2,3);
 void log_printf (const char *fmt, ...) GPGRT_ATTR_PRINTF(1,2);
 void log_flush (void);
 
@@ -107,10 +145,11 @@ void log_flush (void);
    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);
+void log_printhex (const void *buffer, size_t length, const char *text);
 
-void log_clock (const char *string);
+void log_clock (const char *fmt, ...) GPGRT_ATTR_PRINTF(1,2);
 
+#endif /* Use gnupg internal logging functions.  */
 
 /* Some handy assertion macros which don't abort.  */
 
index caeb66f..7997a1a 100644 (file)
@@ -45,14 +45,14 @@ my_gcry_logger (void *dummy, int level, const char *fmt, va_list arg_ptr)
   /* Map the log levels.  */
   switch (level)
     {
-    case GCRY_LOG_CONT: level = GPGRT_LOG_CONT; break;
-    case GCRY_LOG_INFO: level = GPGRT_LOG_INFO; break;
-    case GCRY_LOG_WARN: level = GPGRT_LOG_WARN; break;
-    case GCRY_LOG_ERROR:level = GPGRT_LOG_ERROR; break;
-    case GCRY_LOG_FATAL:level = GPGRT_LOG_FATAL; break;
-    case GCRY_LOG_BUG:  level = GPGRT_LOG_BUG; break;
-    case GCRY_LOG_DEBUG:level = GPGRT_LOG_DEBUG; break;
-    default:            level = GPGRT_LOG_ERROR; break;
+    case GCRY_LOG_CONT: level = GPGRT_LOGLVL_CONT; break;
+    case GCRY_LOG_INFO: level = GPGRT_LOGLVL_INFO; break;
+    case GCRY_LOG_WARN: level = GPGRT_LOGLVL_WARN; break;
+    case GCRY_LOG_ERROR:level = GPGRT_LOGLVL_ERROR; break;
+    case GCRY_LOG_FATAL:level = GPGRT_LOGLVL_FATAL; break;
+    case GCRY_LOG_BUG:  level = GPGRT_LOGLVL_BUG; break;
+    case GCRY_LOG_DEBUG:level = GPGRT_LOGLVL_DEBUG; break;
+    default:            level = GPGRT_LOGLVL_ERROR; break;
     }
   log_logv (level, fmt, arg_ptr);
 }
index 85a4251..8699a17 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). */
   }
@@ -115,7 +116,8 @@ typedef enum
     SIGSUBPKT_FEATURES      = 30, /* Feature flags. */
 
     SIGSUBPKT_SIGNATURE     = 32, /* Embedded signature. */
-    SIGSUBPKT_ISSUER_FPR    = 33, /* EXPERIMENTAL: Issuer fingerprint. */
+    SIGSUBPKT_ISSUER_FPR    = 33, /* Issuer fingerprint. */
+    SIGSUBPKT_PREF_AEAD     = 34, /* Preferred AEAD algorithms. */
 
     SIGSUBPKT_FLAG_CRITICAL = 128
   }
@@ -142,6 +144,16 @@ typedef enum
 cipher_algo_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
   {
     PUBKEY_ALGO_RSA         =  1,
diff --git a/common/pkscreening.c b/common/pkscreening.c
new file mode 100644 (file)
index 0000000..a3bfb47
--- /dev/null
@@ -0,0 +1,159 @@
+/* pkscreening.c - Screen public keys for vulnerabilities
+ * Copyright (C) 2017 Werner Koch
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+
+#include "util.h"
+#include "pkscreening.h"
+
+
+/* Helper */
+static inline gpg_error_t
+my_error (gpg_err_code_t ec)
+{
+  return gpg_err_make (default_errsource, ec);
+}
+
+
+/* Emulation of the new gcry_mpi_get_ui function.  */
+static gpg_error_t
+my_mpi_get_ui (unsigned int *v, gcry_mpi_t a)
+{
+  gpg_error_t err;
+  unsigned char buf[8];
+  size_t n;
+  int i, mul;
+
+  if (gcry_mpi_cmp_ui (a, 16384) > 0)
+    return my_error (GPG_ERR_ERANGE); /* Clearly too large for our purpose.  */
+
+  err = gcry_mpi_print (GCRYMPI_FMT_USG, buf, sizeof buf, &n, a);
+  if (err)
+    return err;
+
+  *v = 0;
+  for (i = n - 1, mul = 1; i >= 0; i--, mul *= 256)
+    *v += mul * buf[i];
+
+  return 0;
+}
+
+
+/* Detect whether the MODULUS of a public RSA key is affected by the
+ * ROCA vulnerability as found in the Infinion RSA library
+ * (CVE-2017-15361).  Returns 0 if not affected, GPG_ERR_TRUE if
+ * affected, GPG_ERR_BAD_MPI if an opaque RSA was passed, or other
+ * error codes if something weird happened  */
+gpg_error_t
+screen_key_for_roca (gcry_mpi_t modulus)
+{
+  static struct {
+    unsigned int prime_ui;
+    const char *print_hex;
+    gcry_mpi_t prime;
+    gcry_mpi_t print;
+  } table[] = {
+   { 3,   "0x6" },
+   { 5,   "0x1E" },
+   { 7,   "0x7E" },
+   { 11,  "0x402" },
+   { 13,  "0x161A" },
+   { 17,  "0x1A316" },
+   { 19,  "0x30AF2" },
+   { 23,  "0x7FFFFE" },
+   { 29,  "0x1FFFFFFE" },
+   { 31,  "0x7FFFFFFE" },
+   { 37,  "0x4000402"  },
+   { 41,  "0x1FFFFFFFFFE" },
+   { 43,  "0x7FFFFFFFFFE" },
+   { 47,  "0x7FFFFFFFFFFE" },
+   { 53,  "0x12DD703303AED2" },
+   { 59,  "0x7FFFFFFFFFFFFFE" },
+   { 61,  "0x1434026619900B0A" },
+   { 67,  "0x7FFFFFFFFFFFFFFFE" },
+   { 71,  "0x1164729716B1D977E" },
+   { 73,  "0x147811A48004962078A" },
+   { 79,  "0xB4010404000640502"   },
+   { 83,  "0x7FFFFFFFFFFFFFFFFFFFE" },
+   { 89,  "0x1FFFFFFFFFFFFFFFFFFFFFE" },
+   { 97,  "0x1000000006000001800000002" },
+   { 101, "0x1FFFFFFFFFFFFFFFFFFFFFFFFE" },
+   { 103, "0x16380E9115BD964257768FE396" },
+   { 107, "0x27816EA9821633397BE6A897E1A" },
+   { 109, "0x1752639F4E85B003685CBE7192BA" },
+   { 113, "0x1FFFFFFFFFFFFFFFFFFFFFFFFFFFE" },
+   { 127, "0x6CA09850C2813205A04C81430A190536" },
+   { 131, "0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE" },
+   { 137, "0x1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE" },
+   { 139, "0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE" },
+   { 149, "0x1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE" },
+   { 151, "0x50C018BC00482458DAC35B1A2412003D18030A" },
+   { 157, "0x161FB414D76AF63826461899071BD5BACA0B7E1A" },
+   { 163, "0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE" },
+   { 167, "0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE" }
+  };
+  gpg_error_t err;
+  int i;
+  gcry_mpi_t rem;
+  unsigned int bitno;
+
+  /* Initialize on the first call. */
+  if (!table[0].prime)
+    {
+      /* We pass primes[i] to the call so that in case of a concurrent
+       * second thread the already allocated space is reused.  */
+      for (i = 0; i < DIM (table); i++)
+        {
+          table[i].prime = gcry_mpi_set_ui (table[i].prime, table[i].prime_ui);
+          if (gcry_mpi_scan (&table[i].print, GCRYMPI_FMT_HEX,
+                             table[i].print_hex, 0, NULL))
+            BUG ();
+        }
+    }
+
+  /* Check that it is not NULL or an opaque MPI.  */
+  if (!modulus || gcry_mpi_get_flag (modulus, GCRYMPI_FLAG_OPAQUE))
+    return my_error (GPG_ERR_BAD_MPI);
+
+  /* We divide the modulus of an RSA public key by a set of small
+   * PRIMEs and examine all the remainders.  If all the bits at the
+   * index given by the remainder are set in the corresponding PRINT
+   * masks the key is very likely vulnerable.  If any of the tested
+   * bits is zero, the key is not vulnerable.  */
+  rem = gcry_mpi_new (0);
+  for (i = 0; i < DIM (table); i++)
+    {
+      gcry_mpi_mod (rem, modulus, table[i].prime);
+      err = my_mpi_get_ui (&bitno, rem);
+      if (gpg_err_code (err) == GPG_ERR_ERANGE)
+        continue;
+      if (err)
+        goto leave;
+      if (!gcry_mpi_test_bit (table[i].print, bitno))
+        goto leave;  /* Not vulnerable.  */
+    }
+
+  /* Very likely vulnerable */
+  err = my_error (GPG_ERR_TRUE);
+
+ leave:
+  gcry_mpi_release (rem);
+  return err;
+}
diff --git a/common/pkscreening.h b/common/pkscreening.h
new file mode 100644 (file)
index 0000000..a647589
--- /dev/null
@@ -0,0 +1,26 @@
+/* pkscreening.c - Screen public keys for vulnerabilities
+ * Copyright (C) 2017 Werner Koch
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef GNUPG_COMMON_PKSCREENING_H
+#define GNUPG_COMMON_PKSCREENING_H
+
+gpg_error_t screen_key_for_roca (gcry_mpi_t modulus);
+
+
+#endif /*GNUPG_COMMON_PKSCREENING_H*/
index e90010c..55a7ee9 100644 (file)
@@ -340,11 +340,10 @@ gnupg_usleep (unsigned int usecs)
       struct timespec req;
       struct timespec rem;
 
-      req.tv_sec = 0;
-      req.tv_nsec = usecs * 1000;
-
+      req.tv_sec  = usecs / 1000000;
+      req.tv_nsec = (usecs % 1000000) * 1000;
       while (nanosleep (&req, &rem) < 0 && errno == EINTR)
-        req = rem;
+          req = rem;
     }
 
 #else /*Standard Unix*/
index c6d19c6..f372281 100644 (file)
 /* 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"
index 8252db9..f680658 100644 (file)
@@ -27,8 +27,8 @@ min_automake_version="1.14"
 # another commit and push so that the git magic is able to work.
 m4_define([mym4_package],[gnupg])
 m4_define([mym4_major], [2])
-m4_define([mym4_minor], [2])
-m4_define([mym4_micro], [6])
+m4_define([mym4_minor], [3])
+m4_define([mym4_micro], [0])
 
 # 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
@@ -116,8 +116,8 @@ use_tls_library=no
 large_secmem=no
 show_tor_support=no
 
-
-GNUPG_BUILD_PROGRAM(gpg, yes)
+# gpg is a required part and can't be disabled anymore.
+build_gpg=yes
 GNUPG_BUILD_PROGRAM(gpgsm, yes)
 # The agent is a required part and can't be disabled anymore.
 build_agent=yes
@@ -244,6 +244,15 @@ fi
 AC_DEFINE_UNQUOTED(SECMEM_BUFFER_SIZE,$SECMEM_BUFFER_SIZE,
                    [Size of secure memory buffer])
 
+AC_MSG_CHECKING([calibrated passphrase-stretching (s2k) duration])
+AC_ARG_WITH(agent-s2k-calibration,
+              AC_HELP_STRING([--with-agent-s2k-calibration=MSEC],
+                             [calibrate passphrase stretching (s2k) to MSEC milliseconds]),
+              agent_s2k_calibration=$withval, agent_s2k_calibration=100)
+AC_MSG_RESULT($agent_s2k_calibration milliseconds)
+AC_DEFINE_UNQUOTED(AGENT_S2K_CALIBRATION, $agent_s2k_calibration,
+                   [Agent s2k calibration time (ms)])
+
 AC_MSG_CHECKING([whether to enable trust models])
 AC_ARG_ENABLE(trust-models,
               AC_HELP_STRING([--disable-trust-models],
@@ -548,9 +557,12 @@ AH_BOTTOM([
 # endif
 #endif
 
-/* Provide the es_ macro for estream.  */
+/* Enable the es_ macros from gpgrt.  */
 #define GPGRT_ENABLE_ES_MACROS 1
 
+/* Enable the log_ macros from gpgrt.  */
+#define GPGRT_ENABLE_LOG_MACROS 1
+
 /* Tell libgcrypt not to use its own libgpg-error implementation. */
 #define USE_LIBGPG_ERROR 1
 
@@ -602,9 +614,8 @@ AC_PROG_RANLIB
 AC_CHECK_TOOL(AR, ar, :)
 AC_PATH_PROG(PERL,"perl")
 AC_CHECK_TOOL(WINDRES, windres, :)
-AC_PATH_PROG(YAT2M, "yat2m")
+AC_PATH_PROG(YAT2M, "yat2m", "./yat2m" )
 AC_ARG_VAR(YAT2M, [tool to convert texi to man pages])
-AM_CONDITIONAL(HAVE_YAT2M, test -n "$ac_cv_path_YAT2M")
 AC_ISC_POSIX
 AC_SYS_LARGEFILE
 GNUPG_CHECK_USTAR
@@ -1612,7 +1623,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
 
@@ -1687,6 +1698,19 @@ AC_ARG_ENABLE(optimization,
                    fi])
 
 #
+# log_debug has certain requirements which might hamper portability.
+# Thus we use an option to enable it.
+#
+AC_MSG_CHECKING([whether to enable log_clock])
+AC_ARG_ENABLE(log_clock,
+              AC_HELP_STRING([--enable-log-clock],
+                             [enable log_clock timestamps]),
+              enable_log_clock=$enableval, enable_log_clock=no)
+AC_MSG_RESULT($enable_log_clock)
+if test "$enable_log_clock" = yes ; then
+  AC_DEFINE(ENABLE_LOG_CLOCK,1,[Defined to use log_clock timestamps])
+fi
+
 # Add -Werror to CFLAGS.  This hack can be used to avoid problems with
 # misbehaving autoconf tests in case the user supplied -Werror.
 #
index 6eeeb8d..8687c7b 100644 (file)
@@ -1346,7 +1346,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)
         {
index 17adae2..00caf06 100644 (file)
@@ -787,12 +787,12 @@ my_ntbtls_log_handler (void *opaque, int level, const char *fmt, va_list argv)
   (void)opaque;
 
   if (level == -1)
-    log_logv_with_prefix (GPGRT_LOG_INFO, "ntbtls: ", fmt, argv);
+    log_logv_prefix (GPGRT_LOGLVL_INFO, "ntbtls: ", fmt, argv);
   else
     {
       char prefix[10+20];
       snprintf (prefix, sizeof prefix, "ntbtls(%d): ", level);
-      log_logv_with_prefix (GPGRT_LOG_DEBUG, prefix, fmt, argv);
+      log_logv_prefix (GPGRT_LOGLVL_DEBUG, prefix, fmt, argv);
     }
 }
 #endif
@@ -1203,6 +1203,14 @@ main (int argc, char **argv)
           current_logfile = xstrdup (logfile);
         }
 
+      if (debug_wait)
+        {
+          log_debug ("waiting for debugger - my pid is %u .....\n",
+                     (unsigned int)getpid());
+          gnupg_sleep (debug_wait);
+          log_debug ("... okay\n");
+        }
+
 #ifndef HAVE_W32_SYSTEM
       if (strchr (socket_name, ':'))
         {
index 8e778df..cc7f5a5 100644 (file)
@@ -1053,7 +1053,7 @@ http_start_data (http_t hd)
   if (!hd->in_data)
     {
       if (opt_debug || (hd->flags & HTTP_FLAG_LOG_RESP))
-        log_debug_with_string ("\r\n", "http.c:request-header:");
+        log_debug_string ("\r\n", "http.c:request-header:");
       es_fputs ("\r\n", hd->fp_write);
       es_fflush (hd->fp_write);
       hd->in_data = 1;
@@ -1844,7 +1844,7 @@ send_request (http_t hd, const char *httphost, const char *auth,
         return gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
 
       if (opt_debug || (hd->flags & HTTP_FLAG_LOG_RESP))
-        log_debug_with_string (request, "http.c:request:");
+        log_debug_string (request, "http.c:request:");
 
       cookie = xtrycalloc (1, sizeof *cookie);
       if (! cookie)
@@ -2159,7 +2159,7 @@ send_request (http_t hd, const char *httphost, const char *auth,
     }
 
   if (opt_debug || (hd->flags & HTTP_FLAG_LOG_RESP))
-    log_debug_with_string (request, "http.c:request:");
+    log_debug_string (request, "http.c:request:");
 
   /* First setup estream so that we can write even the first line
      using estream.  This is also required for the sake of gnutls. */
@@ -2195,7 +2195,7 @@ send_request (http_t hd, const char *httphost, const char *auth,
       for (;headers; headers=headers->next)
         {
           if (opt_debug || (hd->flags & HTTP_FLAG_LOG_RESP))
-            log_debug_with_string (headers->d, "http.c:request-header:");
+            log_debug_string (headers->d, "http.c:request-header:");
           if ((es_fputs (headers->d, hd->fp_write) || es_fflush (hd->fp_write))
               || (es_fputs("\r\n",hd->fp_write) || es_fflush(hd->fp_write)))
             {
@@ -2446,7 +2446,7 @@ parse_response (http_t hd)
        return GPG_ERR_EOF;
 
       if (opt_debug || (hd->flags & HTTP_FLAG_LOG_RESP))
-        log_debug_with_string (line, "http.c:response:\n");
+        log_debug_string (line, "http.c:response:\n");
     }
   while (!*line);
 
index 6291a9a..1270b83 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 e54e8a0..a4063b4 100644 (file)
@@ -222,12 +222,14 @@ described here.
 
 *** Field 18 - Compliance flags
 
-    Space separated list of asserted compliance modes for this key.
+    Space separated list of asserted compliance modes and
+    screening result for this key.
 
     Valid values are:
 
     - 8  :: The key is compliant with RFC4880bis
     - 23 :: The key is compliant with compliance mode "de-vs".
+    - 6001 :: Screening hit on the ROCA vulnerability.
 
 *** Field 19 - Last update
 
@@ -516,9 +518,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
@@ -538,8 +541,10 @@ pkd:0:1024:B665B1435F4C2 .... FF26ABB:
     --override-session-key.  It is not an indication that the
     decryption will or has succeeded.
 
-*** BEGIN_ENCRYPTION  <mdc_method> <sym_algo>
+*** BEGIN_ENCRYPTION  <mdc_method> <sym_algo> [<aead_algo>]
     Mark the start of the actual encryption process.
+    MDC_METHOD shall be 0 if an AEAD_ALGO is not 0.  Users should
+    however ignore MDC_METHOD if AEAD_ALGO is not 0.
 
 *** END_ENCRYPTION
     Mark the end of the actual encryption process.
index bd16856..17c5826 100644 (file)
@@ -33,9 +33,9 @@ not be copied to the ChangeLog, separate it by a line consisting of
 two dashes at the begin of a line.
 
 The one-line summary usually starts with a keyword to identify the
-mainly affected subsystem.  If more than one keyword is required the
-are delimited by a comma (e.g. =scd,w32:=). Commonly found keywords
-are
+mainly affected subsystem (that is not the directory).  If more than
+one keyword is required they are delimited by a comma
+(e.g. =scd,w32:=). Commonly found keywords are
 
  - agent   :: The gpg-agent component
  - build   :: Changes to the build system
@@ -207,10 +207,6 @@ Note that such a comment will be removed if the git commit option
   - The predefined macro =__func__=:
     : log_debug ("%s: Problem with foo\n", __func__);
 
-  - Variable declaration inside a for():
-    : for (int i = 0; i < 5; ++)
-    :   bar (i);
-
   Although we usually make use of the =u16=, =u32=, and =u64= types,
   it is also possible to include =<stdint.h>= and use =int16_t=,
   =int32_t=, =int64_t=, =uint16_t=, =uint32_t=, and =uint64_t=.  But do
index aba84ba..21e3e45 100644 (file)
@@ -22,7 +22,7 @@ AM_CPPFLAGS =
 include $(top_srcdir)/am/cmacros.am
 
 examples = examples/README examples/scd-event examples/trustlist.txt   \
-          examples/vsnfd.prf examples/debug.prf                        \
+          examples/vsnfd.prf examples/debug.prf examples/qualified.txt \
           examples/systemd-user/README                                 \
           examples/systemd-user/dirmngr.service                        \
           examples/systemd-user/dirmngr.socket                         \
@@ -43,7 +43,7 @@ helpfiles = help.txt help.be.txt help.ca.txt help.cs.txt              \
 
 profiles =
 
-EXTRA_DIST = samplekeys.asc mksamplekeys com-certs.pem qualified.txt \
+EXTRA_DIST = samplekeys.asc mksamplekeys com-certs.pem \
             gnupg-logo.eps gnupg-logo.pdf gnupg-logo.png gnupg-logo-tr.png \
             gnupg-module-overview.png gnupg-module-overview.pdf \
              gnupg-card-architecture.png gnupg-card-architecture.pdf \
@@ -112,16 +112,8 @@ DISTCLEANFILES = gnupg.tmp gnupg.ops yat2m-stamp.tmp yat2m-stamp \
                  gnupg-module-overview.eps \
                 $(myman_pages) gnupg.7
 
-if HAVE_YAT2M
-YAT2M_CMD = $(YAT2M)
-YAT2M_DEP = $(YAT2M)
-else
-YAT2M_CMD = ./yat2m
-YAT2M_DEP = yat2m
-
 yat2m: yat2m.c
        $(CC_FOR_BUILD) -o $@ $(srcdir)/yat2m.c
-endif
 
 mkdefsinc: mkdefsinc.c Makefile ../config.h
        $(CC_FOR_BUILD) -I. -I.. -I$(srcdir) $(AM_CPPFLAGS) \
@@ -154,12 +146,12 @@ yat2m-stamp: $(myman_sources) defs.inc
        @touch yat2m-stamp.tmp
        incd="`test -f defsincdate || echo '$(srcdir)/'`defsincdate"; \
        for file in $(myman_sources) ; do \
-              $(YAT2M_CMD) $(YAT2M_OPTIONS) --store \
+              $(YAT2M) $(YAT2M_OPTIONS) --store \
                   --date "`cat $$incd 2>/dev/null`" \
                  `test -f '$$file' || echo '$(srcdir)/'`$$file ; done
        @mv -f yat2m-stamp.tmp $@
 
-yat2m-stamp: $(YAT2M_DEP)
+yat2m-stamp: $(YAT2M)
 
 $(myman_pages) gnupg.7 : yat2m-stamp defs.inc
        @if test -f $@; then :; else \
index 77ee807..4d6a5be 100644 (file)
@@ -9,3 +9,5 @@ trustlist.txt   A list of trustworthy root certificates
 gpgconf.conf    A sample configuration file for gpgconf.
 
 systemd-user    Sample files for a Linux-only init system.
+
+qualified.txt   Sample file for qualified.txt.
similarity index 98%
rename from doc/qualified.txt
rename to doc/examples/qualified.txt
index c0e4da5..eba11f2 100644 (file)
@@ -29,7 +29,7 @@
 #
 #                 Germany
 #
-# The information for Germany is available 
+# The information for Germany is available
 # at http://www.bundesnetzagentur.de
 #*******************************************
 
@@ -74,7 +74,7 @@ DB:45:3D:1B:B0:1A:F3:23:10:6B:DE:D0:09:61:57:AA:F4:25:E0:5B  de
 #Serial number: 02
 #       Issuer: /CN=9R-CA 1:PN/O=Regulierungsbehörde für
 #               Telekommunikation und Post/C=DE
-#      Subject: /CN=9R-CA 1:PN/O=Regulierungsbehörde für 
+#      Subject: /CN=9R-CA 1:PN/O=Regulierungsbehörde für
 #               Telekommunikation und Post/C=DE
 #     validity: 2004-11-25 14:59:11 through 2007-12-31 14:56:59
 #     key type: 1024 bit RSA
@@ -118,7 +118,7 @@ A0:8B:DF:3B:AA:EE:3F:9D:64:6C:47:81:23:21:D4:A6:18:81:67:1D  de
 #    key usage: certSign
 #     policies: 1.3.36.8.1.1:N:
 # chain length: unlimited
-# [checked: 2008-06-25] 
+# [checked: 2008-06-25]
 44:7E:D4:E3:9A:D7:92:E2:07:FA:53:1A:2E:F5:B8:02:5B:47:57:B0  de
 
 #           ID: 0x46A2CC8A
@@ -130,7 +130,7 @@ A0:8B:DF:3B:AA:EE:3F:9D:64:6C:47:81:23:21:D4:A6:18:81:67:1D  de
 #    key usage: certSign
 #     policies: 1.3.36.8.1.1:N:
 # chain length: unlimited
-# [checked: 2008-06-25] 
+# [checked: 2008-06-25]
 AC:A7:BE:45:1F:A6:BF:09:F2:D1:3F:08:7B:BC:EB:7F:46:A2:CC:8A  de
 
 
@@ -215,7 +215,7 @@ E0:BF:1B:91:91:6B:88:E4:F1:15:92:22:CE:37:23:96:B1:4A:2E:5C  de
 #     key type: 2048 bit RSA
 #    key usage: certSign crlSign
 # chain length: 1
-#[checked: 2007-12-13 via received ZIP file with qualified signature from 
+#[checked: 2007-12-13 via received ZIP file with qualified signature from
 #         /CN=Dr. Matthias Stehle/O=Deutscher Sparkassenverlag
 #         /C=DE/SerialNumber=DSV0000000008/SN=Stehle/GN=Matthias Georg]
 C9:2F:E6:50:DB:32:59:E0:CE:65:55:F3:8C:76:E0:B8:A8:FE:A3:CA  de
@@ -230,7 +230,7 @@ C9:2F:E6:50:DB:32:59:E0:CE:65:55:F3:8C:76:E0:B8:A8:FE:A3:CA  de
 #     key type: 2048 bit RSA
 #    key usage: certSign crlSign
 # chain length: 1
-#[checked: 2007-12-13 via received ZIP file with qualified signature from 
+#[checked: 2007-12-13 via received ZIP file with qualified signature from
 #         /CN=Dr. Matthias Stehle/O=Deutscher Sparkassenverlag
 #         /C=DE/SerialNumber=DSV0000000008/SN=Stehle/GN=Matthias Georg"]
 D5:C7:50:F2:FE:4E:EE:D7:C7:B1:E4:13:7B:FB:54:84:3A:7D:97:9B  de
index ddebc69..8fea489 100644 (file)
@@ -2257,6 +2257,16 @@ works properly with such messages, there is often a desire to set a
 maximum file size that will be generated before processing is forced to
 stop by the OS limits. Defaults to 0, which means "no limit".
 
+@item --chunk-size @var{n}
+@opindex chunk-size
+The AEAD encryption mode encrypts the data in chunks so that a
+receiving side can check for transmission errors or tampering at the
+end of each chunk and does not need to delay this until all data has
+been received.  The used chunk size is 2^@var{n} byte.  The lowest
+allowed value for @var{n} is 6 (64 byte) and the largest is 62 (4
+EiB). The default value for @var{n} is 30 which creates chunks not
+larger than 1 GiB.
+
 @item --input-size-hint @var{n}
 @opindex input-size-hint
 This option can be used to tell GPG the size of the input data in
@@ -2594,6 +2604,16 @@ is the default.
 @itemx --no-force-v4-certs
 These options are obsolete and have no effect since GnuPG 2.1.
 
+@item --force-aead
+@opindex force-aead
+Force the use of AEAD encryption over MDC encryption.  AEAD is a
+modern and faster way to do authenticated encrytion than the old MDC
+method.  See also options @option{--aead-algo} and
+@option{--chunk-size}.
+
+This option requires the use of option @option{--rfc4880bis} to
+declare that a not yet standardized feature is used.
+
 @item --force-mdc
 @opindex force-mdc
 Force the use of encryption with a modification detection code. This
@@ -2625,6 +2645,16 @@ preferences, as GPG will only select an algorithm that is usable by
 all recipients.  The most highly ranked cipher in this list is also
 used for the @option{--symmetric} encryption command.
 
+@item --personal-aead-preferences @var{string}
+@opindex personal-aead-preferences
+Set the list of personal AEAD preferences to @var{string}.  Use
+@command{@gpgname --version} to get a list of available algorithms,
+and use @code{none} to set no preference at all.  This allows the user
+to safely override the algorithm chosen by the recipient key
+preferences, as GPG will only select an algorithm that is usable by
+all recipients.  The most highly ranked cipher in this list is also
+used for the @option{--symmetric} encryption command.
+
 @item --personal-digest-preferences @var{string}
 @opindex personal-digest-preferences
 Set the list of personal digest preferences to @var{string}.  Use
@@ -2831,6 +2861,12 @@ Set all useful debugging flags.
 Set stdout into line buffered mode.  This option is only honored when
 given on the command line.
 
+@item --debug-set-iobuf-size @var{n}
+@opindex debug-iolbf
+Change the buffer size of the IOBUFs to @var{n} kilobyte.  Using 0
+prints the current size.  Note well: This is a maintainer only option
+and may thus be changed or removed at any time without notice.
+
 @item --faked-system-time @var{epoch}
 @opindex faked-system-time
 This option is only useful for testing; it sets the system time back or
@@ -2983,17 +3019,28 @@ Use @var{name} as cipher algorithm. Running the program with the
 command @option{--version} yields a list of supported algorithms. If
 this is not used the cipher algorithm is selected from the preferences
 stored with the key. In general, you do not want to use this option as
-it allows you to violate the OpenPGP standard.
+it allows you to violate the OpenPGP standard.  The option
 @option{--personal-cipher-preferences} is the safe way to accomplish the
 same thing.
 
+@item --aead-algo @var{name}
+@opindex aead-algo
+Specify that the AEAD algorithm @var{name} is to be used.  This is
+useful for symmetric encryption where no key preference are available
+to select the AEAD algorithm.  Runing @command{@gpgname} with option
+@option{--version} shows the available AEAD algorithms.  In general,
+you do not want to use this option as it allows you to violate the
+OpenPGP standard.  The option @option{--personal-aead-preferences} is
+the safe way to accomplish the same thing.
+
 @item --digest-algo @var{name}
 @opindex digest-algo
 Use @var{name} as the message digest algorithm. Running the program
-with the command @option{--version} yields a list of supported algorithms. In
-general, you do not want to use this option as it allows you to
-violate the OpenPGP standard. @option{--personal-digest-preferences} is the
-safe way to accomplish the same thing.
+with the command @option{--version} yields a list of supported
+algorithms. In general, you do not want to use this option as it
+allows you to violate the OpenPGP standard.  The option
+@option{--personal-digest-preferences} is the safe way to accomplish
+the same thing.
 
 @item --compress-algo @var{name}
 @opindex compress-algo
@@ -3015,8 +3062,9 @@ significant in low memory situations. Note, however, that PGP (all
 versions) only supports ZIP compression. Using any algorithm other
 than ZIP or "none" will make the message unreadable with PGP. In
 general, you do not want to use this option as it allows you to
-violate the OpenPGP standard. @option{--personal-compress-preferences} is the
-safe way to accomplish the same thing.
+violate the OpenPGP standard.  The option
+@option{--personal-compress-preferences} is the safe way to accomplish
+the same thing.
 
 @item --cert-digest-algo @var{name}
 @opindex cert-digest-algo
index cd2a741..37a5353 100644 (file)
@@ -843,15 +843,9 @@ purposes.
 
 Note that even if a certificate is listed in this file, this does not
 mean that the certificate is trusted; in general the certificates listed
-in this file need to be listed also in @file{trustlist.txt}.
-
-This is a global file an installed in the data directory
-(e.g. @file{@value{DATADIR}/qualified.txt}).  GnuPG installs a suitable
-file with root certificates as used in Germany.  As new Root-CA
-certificates may be issued over time, these entries may need to be
-updated; new distributions of this software should come with an updated
-list but it is still the responsibility of the Administrator to check
-that this list is correct.
+in this file need to be listed also in @file{trustlist.txt}. This is a global
+file an installed in the sysconf directory (e.g.
+@file{@value{SYSCONFDIR}/qualified.txt}).
 
 Every time @command{gpgsm} uses a certificate for signing or verification
 this file will be consulted to check whether the certificate under
@@ -1073,7 +1067,7 @@ key. The algorithm must be capable of signing.  This is a required
 parameter.  The only supported value for @var{algo} is @samp{rsa}.
 
 @item Key-Length: @var{nbits}
-The requested length of a generated key in bits.  Defaults to 2048.
+The requested length of a generated key in bits.  Defaults to 3072.
 
 @item Key-Grip: @var{hexstring}
 This is optional and used to generate a CSR or certificate for an
index 55f1a91..30e28bd 100644 (file)
@@ -31,14 +31,14 @@ Let's continue:
 
 @cartouche
 @example
-  What keysize do you want? (2048)
-  Requested keysize is 2048 bits
+  What keysize do you want? (3072)
+  Requested keysize is 3072 bits
 @end example
 @end cartouche
 
-Hitting enter chooses the default RSA key size of 2048 bits.  Smaller
-keys are too weak on the modern Internet.  If you choose a larger
-(stronger) key, your server will need to do more work.
+Hitting enter chooses the default RSA key size of 3072 bits.  Keys
+smaller than 2048 bits are too weak on the modern Internet.  If you
+choose a larger (stronger) key, your server will need to do more work.
 
 @cartouche
 @example
@@ -124,7 +124,7 @@ request:
 @example
   These parameters are used:
       Key-Type: RSA
-      Key-Length: 2048
+      Key-Length: 3072
       Key-Usage: sign, encrypt
       Name-DN: CN=example.com
       Name-DNS: example.com
@@ -224,7 +224,7 @@ To see the content of your certificate, you may now enter:
             aka: (dns-name example.com)
             aka: (dns-name www.example.com)
        validity: 2015-07-01 16:20:51 through 2016-07-01 16:20:51
-       key type: 2048 bit RSA
+       key type: 3072 bit RSA
       key usage: digitalSignature keyEncipherment
   ext key usage: clientAuth (suggested), serverAuth (suggested), [...]
     fingerprint: 0F:9C:27:B2:DA:05:5F:CB:33:D8:19:E9:65:B9:4F:BD:B1:98:CC:57
index 6d62282..4508ae2 100644 (file)
@@ -338,10 +338,11 @@ the submission address:
 The output of the last command looks similar to this:
 
 @example
-  sec   rsa2048 2016-08-30 [SC]
+  sec   rsa3072 2016-08-30 [SC]
         C0FCF8642D830C53246211400346653590B3795B
   uid           [ultimate] key-submission@@example.net
-  ssb   rsa2048 2016-08-30 [E]
+                bxzcxpxk8h87z1k7bzk86xn5aj47intu@@example.net
+  ssb   rsa3072 2016-08-30 [E]
 @end example
 
 Take the fingerprint from that output and manually publish the key:
index cc4ef5c..cba65b2 100644 (file)
@@ -132,6 +132,7 @@ gpg_sources = server.c          \
              decrypt.c         \
              decrypt-data.c    \
              cipher.c          \
+             cipher-aead.c     \
              encrypt.c         \
              sign.c            \
              verify.c          \
index d4a1d6a..b4e03d0 100644 (file)
@@ -42,6 +42,7 @@ static u32 calc_plaintext( PKT_plaintext *pt );
 static int do_plaintext( IOBUF out, int ctb, PKT_plaintext *pt );
 static int do_encrypted( IOBUF out, int ctb, PKT_encrypted *ed );
 static int do_encrypted_mdc( IOBUF out, int ctb, PKT_encrypted *ed );
+static int do_encrypted_aead (iobuf_t out, int ctb, PKT_encrypted *ed);
 static int do_compressed( IOBUF out, int ctb, PKT_compressed *cd );
 static int do_signature( IOBUF out, int ctb, PKT_signature *sig );
 static int do_onepass_sig( IOBUF out, int ctb, PKT_onepass_sig *ops );
@@ -106,6 +107,7 @@ build_packet (IOBUF out, PACKET *pkt)
       break;
     case PKT_ENCRYPTED:
     case PKT_ENCRYPTED_MDC:
+    case PKT_ENCRYPTED_AEAD:
       new_ctb = pkt->pkt.encrypted->new_ctb;
       break;
     case PKT_COMPRESSED:
@@ -158,6 +160,9 @@ build_packet (IOBUF out, PACKET *pkt)
     case PKT_ENCRYPTED_MDC:
       rc = do_encrypted_mdc (out, ctb, pkt->pkt.encrypted);
       break;
+    case PKT_ENCRYPTED_AEAD:
+      rc = do_encrypted_aead (out, ctb, pkt->pkt.encrypted);
+      break;
     case PKT_COMPRESSED:
       rc = do_compressed (out, ctb, pkt->pkt.compressed);
       break;
@@ -612,11 +617,8 @@ do_symkey_enc( IOBUF out, int ctb, PKT_symkey_enc *enc )
   IOBUF a = iobuf_temp();
 
   log_assert (ctb_pkttype (ctb) == PKT_SYMKEY_ENC);
+  log_assert (enc->version == 4 || enc->version == 5);
 
-  /* The only acceptable version.  */
-  log_assert( enc->version == 4 );
-
-  /* RFC 4880, Section 3.7.  */
   switch (enc->s2k.mode)
     {
     case 0: /* Simple S2K.  */
@@ -627,23 +629,26 @@ do_symkey_enc( IOBUF out, int ctb, PKT_symkey_enc *enc )
     default:
       log_bug ("do_symkey_enc: s2k=%d\n", enc->s2k.mode);
     }
-    iobuf_put( a, enc->version );
-    iobuf_put( a, enc->cipher_algo );
-    iobuf_put( a, enc->s2k.mode );
-    iobuf_put( a, enc->s2k.hash_algo );
-    if( enc->s2k.mode == 1 || enc->s2k.mode == 3 ) {
-       iobuf_write(a, enc->s2k.salt, 8 );
-       if( enc->s2k.mode == 3 )
-           iobuf_put(a, enc->s2k.count);
+  iobuf_put (a, enc->version);
+  iobuf_put (a, enc->cipher_algo);
+  if (enc->version == 5)
+    iobuf_put (a, enc->aead_algo);
+  iobuf_put (a, enc->s2k.mode);
+  iobuf_put (a, enc->s2k.hash_algo);
+  if (enc->s2k.mode == 1 || enc->s2k.mode == 3)
+    {
+      iobuf_write (a, enc->s2k.salt, 8);
+      if (enc->s2k.mode == 3)
+        iobuf_put (a, enc->s2k.count);
     }
-    if( enc->seskeylen )
-       iobuf_write(a, enc->seskey, enc->seskeylen );
+  if (enc->seskeylen)
+    iobuf_write (a, enc->seskey, enc->seskeylen);
 
-    write_header(out, ctb, iobuf_get_temp_length(a) );
-    rc = iobuf_write_temp( out, a );
+  write_header (out, ctb, iobuf_get_temp_length(a));
+  rc = iobuf_write_temp (out, a);
 
-    iobuf_close(a);
-    return rc;
+  iobuf_close (a);
+  return rc;
 }
 
 
@@ -812,6 +817,32 @@ do_encrypted_mdc( IOBUF out, int ctb, PKT_encrypted *ed )
 }
 
 
+/* Serialize the symmetrically AEAD encrypted data packet
+ * (rfc4880bis-03, Section 5.16) described by ED and write it to OUT.
+ *
+ * Note: this only writes only packet's header.  The caller must then
+ * follow up and write the actual encrypted data.  This should be done
+ * by pushing the the cipher_filter_aead.  */
+static int
+do_encrypted_aead (iobuf_t out, int ctb, PKT_encrypted *ed)
+{
+  u32 n;
+
+  log_assert (ctb_pkttype (ctb) == PKT_ENCRYPTED_AEAD);
+
+  n = ed->len ? (ed->len + ed->extralen + 4) : 0;
+  write_header (out, ctb, n );
+  iobuf_writebyte (out, 1); /* Version.  */
+  iobuf_writebyte (out, ed->cipher_algo);
+  iobuf_writebyte (out, ed->aead_algo);
+  iobuf_writebyte (out, ed->chunkbyte);
+
+  /* This is all. The caller has to write the encrypted data */
+
+  return 0;
+}
+
+
 /* Serialize the compressed packet (RFC 4880, Section 5.6) described
    by CD and write it to OUT.
 
index 545b244..61d06c6 100644 (file)
@@ -195,7 +195,7 @@ warn_version_mismatch (assuan_context_t ctx, const char *servername, int mode)
   err = get_assuan_server_version (ctx, mode, &serverversion);
   if (err)
     log_log (gpg_err_code (err) == GPG_ERR_NOT_SUPPORTED?
-             GPGRT_LOG_INFO : GPGRT_LOG_ERROR,
+             GPGRT_LOGLVL_INFO : GPGRT_LOGLVL_ERROR,
              _("error getting version from '%s': %s\n"),
              servername, gpg_strerror (err));
   else if (compare_version_strings (serverversion, myversion) < 0)
@@ -1474,7 +1474,7 @@ agent_probe_any_secret_key (ctrl_t ctrl, kbnode_t keyblock)
   char *p;
   kbnode_t kbctx, node;
   int nkeys;
-  unsigned char grip[20];
+  unsigned char grip[KEYGRIP_LEN];
 
   err = start_agent (ctrl, 0);
   if (err)
@@ -1854,10 +1854,16 @@ agent_pksign (ctrl_t ctrl, const char *cache_nonce,
   snprintf (line, sizeof line, "PKSIGN%s%s",
             cache_nonce? " -- ":"",
             cache_nonce? cache_nonce:"");
+
+  if (DBG_CLOCK)
+    log_clock ("enter signing");
   err = assuan_transact (agent_ctx, line,
                          put_membuf_cb, &data,
                          default_inq_cb, &dfltparm,
                          NULL, NULL);
+  if (DBG_CLOCK)
+    log_clock ("leave signing");
+
   if (err)
     xfree (get_membuf (&data, NULL));
   else
index 759dde8..4c1ab03 100644 (file)
@@ -532,9 +532,9 @@ current_card_status (ctrl_t ctrl, estream_t fp,
 
       print_isoname (fp, "Name of cardholder: ", "name", info.disp_name);
       print_name (fp, "Language prefs ...: ", info.disp_lang);
-      tty_fprintf (fp,    "Sex ..............: %s\n",
-                   info.disp_sex == 1? _("male"):
-                   info.disp_sex == 2? _("female") : _("unspecified"));
+      tty_fprintf (fp, "Salutation .......: %s\n",
+                   info.disp_sex == 1? _("Mr."):
+                   info.disp_sex == 2? _("Mrs.") : "");
       print_name (fp, "URL of public key : ", info.pubkey_url);
       print_name (fp, "Login data .......: ", info.login_data);
       if (info.private_do[0])
@@ -1089,7 +1089,7 @@ change_sex (void)
   int rc;
 
   data = cpr_get ("cardedit.change_sex",
-                  _("Sex ((M)ale, (F)emale or space): "));
+                  _("Salutation (M = Mr., F = Mrs., or space): "));
   if (!data)
     return -1;
   trim_spaces (data);
@@ -1110,7 +1110,7 @@ change_sex (void)
 
   rc = agent_scd_setattr ("DISP-SEX", str, 1, NULL );
   if (rc)
-    log_error ("error setting sex: %s\n", gpg_strerror (rc));
+    log_error ("error setting salutation: %s\n", gpg_strerror (rc));
   xfree (data);
   write_sc_op_status (rc);
   return rc;
@@ -1123,7 +1123,8 @@ change_cafpr (int fprno)
   char *data;
   const char *s;
   int i, c, rc;
-  unsigned char fpr[20];
+  unsigned char fpr[MAX_FINGERPRINT_LEN];
+  int fprlen;
 
   data = cpr_get ("cardedit.change_cafpr", _("CA fingerprint: "));
   if (!data)
@@ -1131,7 +1132,7 @@ change_cafpr (int fprno)
   trim_spaces (data);
   cpr_kill_prompt ();
 
-  for (i=0, s=data; i < 20 && *s; )
+  for (i=0, s=data; i < MAX_FINGERPRINT_LEN && *s; )
     {
       while (spacep(s))
         s++;
@@ -1145,8 +1146,9 @@ change_cafpr (int fprno)
       fpr[i++] = c;
       s += 2;
     }
+  fprlen = i;
   xfree (data);
-  if (i != 20 || *s)
+  if ((fprlen != 20 && fprlen != 32) || *s)
     {
       tty_printf (_("Error: invalid formatted fingerprint.\n"));
       return -1;
@@ -1154,7 +1156,7 @@ change_cafpr (int fprno)
 
   rc = agent_scd_setattr (fprno==1?"CA-FPR-1":
                           fprno==2?"CA-FPR-2":
-                          fprno==3?"CA-FPR-3":"x", fpr, 20, NULL );
+                          fprno==3?"CA-FPR-3":"x", fpr, fprlen, NULL );
   if (rc)
     log_error ("error setting cafpr: %s\n", gpg_strerror (rc));
   write_sc_op_status (rc);
@@ -1316,12 +1318,11 @@ show_keysize_warning (void)
     return;
   shown = 1;
   tty_printf
-    (_("Note: There is no guarantee that the card "
-       "supports the requested size.\n"
-       "      If the key generation does not succeed, "
-       "please check the\n"
-       "      documentation of your card to see what "
-       "sizes are allowed.\n"));
+    (_("Note: There is no guarantee that the card supports the requested\n"
+       "      key type or size.  If the key generation does not succeed,\n"
+       "      please check the documentation of your card to see which\n"
+       "      key types and sizes are supported.\n")
+     );
 }
 
 
@@ -1381,8 +1382,12 @@ ask_card_keyattr (int keyno, unsigned int nbits)
             }
           else
             {
+              char name[30];
+
+              snprintf (name, sizeof name, "rsa%u", req_nbits);
               tty_printf (_("The card will now be re-configured"
-                            " to generate a key of %u bits\n"), req_nbits);
+                            " to generate a key of type: %s\n"),
+                          name);
               show_keysize_warning ();
               return req_nbits;
             }
@@ -1887,7 +1892,8 @@ static struct
     { "fetch"   , cmdFETCH , 0, N_("fetch the key specified in the card URL")},
     { "login"   , cmdLOGIN , 1, N_("change the login name")},
     { "lang"    , cmdLANG  , 1, N_("change the language preferences")},
-    { "sex"     , cmdSEX   , 1, N_("change card holder's sex")},
+    { "salutation",cmdSEX  , 1, N_("change card holder's salutation")},
+    { "sex"       ,cmdSEX  , 1, NULL },  /* Backward compatibility.  */
     { "cafpr"   , cmdCAFPR , 1, N_("change a CA fingerprint")},
     { "forcesig", cmdFORCESIG, 1, N_("toggle the signature force PIN flag")},
     { "generate", cmdGENERATE, 1, N_("generate new keys")},
diff --git a/g10/cipher-aead.c b/g10/cipher-aead.c
new file mode 100644 (file)
index 0000000..573bb43
--- /dev/null
@@ -0,0 +1,457 @@
+/* cipher-aead.c - Enciphering filter for AEAD modes
+ * Copyright (C) 2018 Werner koch
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: GPL-3.0+
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "gpg.h"
+#include "../common/status.h"
+#include "../common/iobuf.h"
+#include "../common/util.h"
+#include "filter.h"
+#include "packet.h"
+#include "options.h"
+#include "main.h"
+
+
+/* The size of the buffer we allocate to encrypt the data.  This must
+ * be a multiple of the OCB blocksize (16 byte).  */
+#define AEAD_ENC_BUFFER_SIZE (64*1024)
+
+
+/* Wrapper around iobuf_write to make sure that a proper error code is
+ * always returned.  */
+static gpg_error_t
+my_iobuf_write (iobuf_t a, const void *buffer, size_t buflen)
+{
+  if (iobuf_write (a, buffer, buflen))
+    {
+      gpg_error_t err = iobuf_error (a);
+      if (!err || !gpg_err_code (err)) /* (The latter should never happen) */
+        err = gpg_error (GPG_ERR_EIO);
+      return err;
+    }
+  return 0;
+}
+
+
+/* Set the additional data for the current chunk.  If FINAL is set the
+ * final AEAD chunk is processed.  */
+static gpg_error_t
+set_additional_data (cipher_filter_context_t *cfx, int final)
+{
+  unsigned char ad[21];
+
+  ad[0] = (0xc0 | PKT_ENCRYPTED_AEAD);
+  ad[1] = 1;
+  ad[2] = cfx->dek->algo;
+  ad[3] = cfx->dek->use_aead;
+  ad[4] = cfx->chunkbyte;
+  ad[5] = cfx->chunkindex >> 56;
+  ad[6] = cfx->chunkindex >> 48;
+  ad[7] = cfx->chunkindex >> 40;
+  ad[8] = cfx->chunkindex >> 32;
+  ad[9] = cfx->chunkindex >> 24;
+  ad[10]= cfx->chunkindex >> 16;
+  ad[11]= cfx->chunkindex >>  8;
+  ad[12]= cfx->chunkindex;
+  if (final)
+    {
+      ad[13] = cfx->total >> 56;
+      ad[14] = cfx->total >> 48;
+      ad[15] = cfx->total >> 40;
+      ad[16] = cfx->total >> 32;
+      ad[17] = cfx->total >> 24;
+      ad[18] = cfx->total >> 16;
+      ad[19] = cfx->total >>  8;
+      ad[20] = cfx->total;
+    }
+  if (DBG_CRYPTO)
+    log_printhex (ad, final? 21 : 13, "authdata:");
+  return gcry_cipher_authenticate (cfx->cipher_hd, ad, final? 21 : 13);
+}
+
+
+/* Set the nonce.  This also reset the encryption machinery so that
+ * the handle can be used for a new chunk.  */
+static gpg_error_t
+set_nonce (cipher_filter_context_t *cfx)
+{
+  unsigned char nonce[16];
+  int i;
+
+  switch (cfx->dek->use_aead)
+    {
+    case AEAD_ALGO_OCB:
+      memcpy (nonce, cfx->startiv, 15);
+      i = 7;
+      break;
+
+    case AEAD_ALGO_EAX:
+      memcpy (nonce, cfx->startiv, 16);
+      i = 8;
+      break;
+
+    default:
+      BUG ();
+    }
+
+  nonce[i++] ^= cfx->chunkindex >> 56;
+  nonce[i++] ^= cfx->chunkindex >> 48;
+  nonce[i++] ^= cfx->chunkindex >> 40;
+  nonce[i++] ^= cfx->chunkindex >> 32;
+  nonce[i++] ^= cfx->chunkindex >> 24;
+  nonce[i++] ^= cfx->chunkindex >> 16;
+  nonce[i++] ^= cfx->chunkindex >>  8;
+  nonce[i++] ^= cfx->chunkindex;
+
+  if (DBG_CRYPTO)
+    log_printhex (nonce, 15, "nonce:");
+  return gcry_cipher_setiv (cfx->cipher_hd, nonce, i);
+}
+
+
+static gpg_error_t
+write_header (cipher_filter_context_t *cfx, iobuf_t a)
+{
+  gpg_error_t err;
+  PACKET pkt;
+  PKT_encrypted ed;
+  unsigned int blocksize;
+  unsigned int startivlen;
+  enum gcry_cipher_modes ciphermode;
+
+  log_assert (cfx->dek->use_aead);
+
+  blocksize = openpgp_cipher_get_algo_blklen (cfx->dek->algo);
+  if (blocksize != 16 )
+    log_fatal ("unsupported blocksize %u for AEAD\n", blocksize);
+
+  err = openpgp_aead_algo_info (cfx->dek->use_aead, &ciphermode, &startivlen);
+  if (err)
+    goto leave;
+
+  log_assert (opt.chunk_size >= 6 && opt.chunk_size <= 62);
+  cfx->chunkbyte = opt.chunk_size - 6;
+  cfx->chunksize = (uint64_t)1 << (cfx->chunkbyte + 6);
+  cfx->chunklen = 0;
+  cfx->bufsize = AEAD_ENC_BUFFER_SIZE;
+  cfx->buflen = 0;
+  cfx->buffer = xtrymalloc (cfx->bufsize);
+  if (!cfx->buffer)
+    return gpg_error_from_syserror ();
+
+  memset (&ed, 0, sizeof ed);
+  ed.new_ctb = 1;  /* (Is anyway required for the packet type).  */
+  ed.len = 0; /* fixme: cfx->datalen */
+  ed.extralen    = startivlen + 16; /* (16 is the taglen) */
+  ed.cipher_algo = cfx->dek->algo;
+  ed.aead_algo   = cfx->dek->use_aead;
+  ed.chunkbyte   = cfx->chunkbyte;
+
+  init_packet (&pkt);
+  pkt.pkttype = PKT_ENCRYPTED_AEAD;
+  pkt.pkt.encrypted = &ed;
+
+  if (DBG_FILTER)
+    log_debug ("aead packet: len=%lu extralen=%d\n",
+               (unsigned long)ed.len, ed.extralen);
+
+  write_status_printf (STATUS_BEGIN_ENCRYPTION, "0 %d %d",
+                       cfx->dek->algo, ed.aead_algo);
+  print_cipher_algo_note (cfx->dek->algo);
+
+  if (build_packet( a, &pkt))
+    log_bug ("build_packet(ENCRYPTED_AEAD) failed\n");
+
+  log_assert (sizeof cfx->startiv >= startivlen);
+  gcry_randomize (cfx->startiv, startivlen, GCRY_STRONG_RANDOM);
+  err = my_iobuf_write (a, cfx->startiv, startivlen);
+  if (err)
+    goto leave;
+
+  err = openpgp_cipher_open (&cfx->cipher_hd,
+                             cfx->dek->algo,
+                             ciphermode,
+                             GCRY_CIPHER_SECURE);
+  if (err)
+    goto leave;
+
+  if (DBG_CRYPTO)
+    log_printhex (cfx->dek->key, cfx->dek->keylen, "thekey:");
+  err = gcry_cipher_setkey (cfx->cipher_hd, cfx->dek->key, cfx->dek->keylen);
+  if (err)
+    return err;
+
+  err = set_nonce (cfx);
+  if (err)
+    return err;
+
+  err = set_additional_data (cfx, 0);
+  if (err)
+    return err;
+
+  cfx->wrote_header = 1;
+
+ leave:
+  return err;
+}
+
+
+/* Get and write the auth tag to stream A.  */
+static gpg_error_t
+write_auth_tag (cipher_filter_context_t *cfx, iobuf_t a)
+{
+  gpg_error_t err;
+  char tag[16];
+
+  err = gcry_cipher_gettag (cfx->cipher_hd, tag, 16);
+  if (err)
+    goto leave;
+  err = my_iobuf_write (a, tag, 16);
+  if (err)
+    goto leave;
+
+ leave:
+  return err;
+}
+
+
+/* Write the final chunk to stream A.  */
+static gpg_error_t
+write_final_chunk (cipher_filter_context_t *cfx, iobuf_t a)
+{
+  gpg_error_t err;
+  char dummy[1];
+
+  cfx->chunkindex++;
+
+  err = set_nonce (cfx);
+  if (err)
+    goto leave;
+  err = set_additional_data (cfx, 1);
+  if (err)
+    goto leave;
+
+  gcry_cipher_final (cfx->cipher_hd);
+
+  /* Encrypt an empty string.  */
+  err = gcry_cipher_encrypt (cfx->cipher_hd, dummy, 0, NULL, 0);
+  if (err)
+    goto leave;
+
+  err = write_auth_tag (cfx, a);
+
+ leave:
+  return err;
+}
+
+
+/* The core of the flush sub-function of cipher_filter_aead.   */
+static gpg_error_t
+do_flush (cipher_filter_context_t *cfx, iobuf_t a, byte *buf, size_t size)
+{
+  gpg_error_t err = 0;
+  int newchunk = 0;
+  size_t n;
+
+  /* Put the data into a buffer, flush and encrypt as needed.  */
+  if (DBG_FILTER)
+    log_debug ("flushing %zu bytes (cur buflen=%zu)\n", size, cfx->buflen);
+  do
+    {
+      if (cfx->buflen + size < cfx->bufsize)
+        n = size;
+      else
+        n = cfx->bufsize - cfx->buflen;
+
+      if (cfx->chunklen + cfx->buflen + n >= cfx->chunksize)
+        {
+          size_t n1 = cfx->chunksize - (cfx->chunklen + cfx->buflen);
+          newchunk = 1;
+          if (DBG_FILTER)
+            log_debug ("chunksize %ju reached;"
+                       " cur buflen=%zu using %zu of %zu\n",
+                       (uintmax_t)cfx->chunksize, (uintmax_t)cfx->buflen,
+                       n1, n);
+          n = n1;
+        }
+
+      memcpy (cfx->buffer + cfx->buflen, buf, n);
+      cfx->buflen += n;
+      buf  += n;
+      size -= n;
+
+      if (cfx->buflen == cfx->bufsize || newchunk)
+        {
+          if (DBG_FILTER)
+            log_debug ("encrypting: buflen=%zu %s n=%zu\n",
+                       cfx->buflen, newchunk?"(newchunk)":"", n);
+          if (newchunk)
+            gcry_cipher_final (cfx->cipher_hd);
+          if (!DBG_FILTER)
+            ;
+          else if (newchunk)
+            log_printhex (cfx->buffer, cfx->buflen, "plain(1):");
+          else if (cfx->buflen > 32)
+            log_printhex (cfx->buffer + cfx->buflen - 32, 32,
+                          "plain(last 32):");
+
+          /* Take care: even with a buflen of zero an encrypt needs to
+           * be called after gcry_cipher_final and before
+           * gcry_cipher_gettag - at least with libgcrypt 1.8 and OCB
+           * mode.  */
+          gcry_cipher_encrypt (cfx->cipher_hd, cfx->buffer, cfx->buflen,
+                               NULL, 0);
+          if (newchunk && DBG_FILTER)
+            log_printhex (cfx->buffer, cfx->buflen, "ciphr(1):");
+          err = my_iobuf_write (a, cfx->buffer, cfx->buflen);
+          if (err)
+            goto leave;
+          cfx->chunklen += cfx->buflen;
+          cfx->total += cfx->buflen;
+          cfx->buflen = 0;
+
+          if (newchunk)
+            {
+              if (DBG_FILTER)
+                log_debug ("chunklen=%ju  total=%ju\n",
+                           (uintmax_t)cfx->chunklen, (uintmax_t)cfx->total);
+              err = write_auth_tag (cfx, a);
+              if (err)
+                {
+                  log_error ("gcry_cipher_gettag failed: %s\n",
+                             gpg_strerror (err));
+                  goto leave;
+                }
+
+              if (DBG_FILTER)
+                log_debug ("starting a new chunk (cur size=%zu)\n", size);
+              cfx->chunkindex++;
+              cfx->chunklen = 0;
+              err = set_nonce (cfx);
+              if (err)
+                goto leave;
+              err = set_additional_data (cfx, 0);
+              if (err)
+                goto leave;
+              newchunk = 0;
+            }
+        }
+    }
+  while (size);
+
+ leave:
+  return err;
+}
+
+
+/* The core of the free sub-function of cipher_filter_aead.   */
+static gpg_error_t
+do_free (cipher_filter_context_t *cfx, iobuf_t a)
+{
+  gpg_error_t err = 0;
+
+  if (DBG_FILTER)
+    log_debug ("do_free: buflen=%zu\n", cfx->buflen);
+
+  /* FIXME: Check what happens if we just wrote the last chunk and no
+   * more bytes were to encrypt.  We should then not call finalize and
+   * write the auth tag again, right?  May this at all happen?  */
+
+  /* Call finalize which will also allow us to flush out and encrypt
+   * the last arbitrary length buffer.  */
+  gcry_cipher_final (cfx->cipher_hd);
+
+  /* Encrypt any remaining bytes.  */
+  if (cfx->buflen)
+    {
+      if (DBG_FILTER)
+        log_debug ("processing last %zu bytes of the last chunk\n",
+                   cfx->buflen);
+      gcry_cipher_encrypt (cfx->cipher_hd, cfx->buffer, cfx->buflen, NULL, 0);
+      err = my_iobuf_write (a, cfx->buffer, cfx->buflen);
+      if (err)
+        goto leave;
+      /* log_printhex (cfx->buffer, cfx->buflen, "wrote:"); */
+      cfx->chunklen += cfx->buflen;
+      cfx->total += cfx->buflen;
+    }
+  else /* Dummy encryption.  */
+    gcry_cipher_encrypt (cfx->cipher_hd, cfx->buffer, 0, NULL, 0);
+
+  /* Get and write the authentication tag.  */
+  if (DBG_FILTER)
+    log_debug ("chunklen=%ju  total=%ju\n",
+               (uintmax_t)cfx->chunklen, (uintmax_t)cfx->total);
+  err = write_auth_tag (cfx, a);
+  if (err)
+    goto leave;
+
+  /* Write the final chunk.  */
+  if (DBG_FILTER)
+    log_debug ("creating final chunk\n");
+  err = write_final_chunk (cfx, a);
+
+ leave:
+  xfree (cfx->buffer);
+  cfx->buffer = NULL;
+  gcry_cipher_close (cfx->cipher_hd);
+  cfx->cipher_hd = NULL;
+  return err;
+}
+
+
+/*
+ * This filter is used to encrypt data with an AEAD algorithm
+ */
+int
+cipher_filter_aead (void *opaque, int control,
+                    iobuf_t a, byte *buf, size_t *ret_len)
+{
+  cipher_filter_context_t *cfx = opaque;
+  size_t size = *ret_len;
+  int rc = 0;
+
+  if (control == IOBUFCTRL_UNDERFLOW) /* decrypt */
+    {
+      rc = -1; /* not used */
+    }
+  else if (control == IOBUFCTRL_FLUSH) /* encrypt */
+    {
+      if (!cfx->wrote_header && (rc=write_header (cfx, a)))
+        ;
+      else
+        rc = do_flush (cfx, a, buf, size);
+    }
+  else if (control == IOBUFCTRL_FREE)
+    {
+      rc = do_free (cfx, a);
+    }
+  else if (control == IOBUFCTRL_DESC)
+    {
+      mem2str (buf, "cipher_filter_aead", *ret_len);
+    }
+
+  return rc;
+}
index b950d0c..ad7399d 100644 (file)
@@ -1,4 +1,4 @@
-/* cipher.c - En-/De-ciphering filter
+/* cipher.c - Enciphering filter for the old CFB mode.
  * Copyright (C) 1998-2003, 2006, 2009 Free Software Foundation, Inc.
  * Copyright (C) 1998-2003, 2006, 2009, 2017 Werner koch
  *
@@ -117,7 +117,8 @@ write_header (cipher_filter_context_t *cfx, iobuf_t a)
  * This filter is used to en/de-cipher data with a symmetric algorithm
  */
 int
-cipher_filter (void *opaque, int control, iobuf_t a, byte *buf, size_t *ret_len)
+cipher_filter_cfb (void *opaque, int control,
+                   iobuf_t a, byte *buf, size_t *ret_len)
 {
   cipher_filter_context_t *cfx = opaque;
   size_t size = *ret_len;
@@ -177,7 +178,7 @@ cipher_filter (void *opaque, int control, iobuf_t a, byte *buf, size_t *ret_len)
     }
   else if (control == IOBUFCTRL_DESC)
     {
-      mem2str (buf, "cipher_filter", *ret_len);
+      mem2str (buf, "cipher_filter_cfb", *ret_len);
     }
 
   return rc;
index 736534d..afdedcb 100644 (file)
@@ -1,6 +1,6 @@
 /* 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
  *
  * This file is part of GnuPG.
  *
 #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 becuase 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.  */
+  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 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 +117,80 @@ release_dfx_context (decode_filter_ctx_t dfx)
 }
 
 
+/* Set the nonce for AEAD.  This also reset the decryption machinery
+ * so that the handle can be used for a new chunk.  */
+static gpg_error_t
+aead_set_nonce (decode_filter_ctx_t dfx)
+{
+  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:");
+  return gcry_cipher_setiv (dfx->cipher_hd, nonce, i);
+}
+
+
+/* Set the additional data for the current chunk.  If FINAL is set the
+ * final AEAD chunk is processed.  */
+static gpg_error_t
+aead_set_ad (decode_filter_ctx_t dfx, int final)
+{
+  unsigned char ad[21];
+
+  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);
+}
+
 
 /****************
  * Decrypt the data, specified by ED with the key DEK.
@@ -80,8 +202,8 @@ decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek)
   byte *p;
   int rc=0, c, i;
   byte temp[32];
-  unsigned blocksize;
-  unsigned nprefix;
+  unsigned int blocksize;
+  unsigned int nprefix;
 
   dfx = xtrycalloc (1, sizeof *dfx);
   if (!dfx)
@@ -91,8 +213,10 @@ decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek)
   if ( opt.verbose && !dek->algo_info_printed )
     {
       if (!openpgp_cipher_test_algo (dek->algo))
-        log_info (_("%s encrypted data\n"),
-                  openpgp_cipher_algo_name (dek->algo));
+        log_info (_("%s.%s encrypted data\n"),
+                  openpgp_cipher_algo_name (dek->algo),
+                  ed->aead_algo? openpgp_aead_algo_name (ed->aead_algo)
+                  /**/         : "CFB");
       else
         log_info (_("encrypted with unknown algorithm %d\n"), dek->algo );
       dek->algo_info_printed = 1;
@@ -109,19 +233,18 @@ 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, ed->aead_algo);
 
   if (opt.show_session_key)
     {
-      char numbuf[25];
+      char numbuf[30];
       char *hexbuf;
 
-      snprintf (numbuf, sizeof numbuf, "%d:", dek->algo);
+      if (ed->aead_algo)
+        snprintf (numbuf, sizeof numbuf, "%d.%u:", dek->algo, ed->aead_algo);
+      else
+        snprintf (numbuf, sizeof numbuf, "%d:", dek->algo);
       hexbuf = bin2hex (dek->key, dek->keylen, NULL);
       if (!hexbuf)
         {
@@ -139,95 +262,196 @@ 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) )
+  if (ed->aead_algo)
     {
-       /* 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;
-    }
+      enum gcry_cipher_modes ciphermode;
+      unsigned int startivlen;
 
-  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");
-    }
+      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();
-    }
+      rc = openpgp_aead_algo_info (ed->aead_algo, &ciphermode, &startivlen);
+      if (rc)
+        goto leave;
+      log_assert (startivlen <= sizeof dfx->startiv);
 
+      if (ed->chunkbyte > 56)
+        {
+          log_error ("invalid AEAD chunkbyte %u\n", ed->chunkbyte);
+          rc = gpg_error (GPG_ERR_INV_PACKET);
+          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 )
-    {
-      log_error("key setup failed: %s\n", gpg_strerror (rc) );
-      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;
+        }
 
-  if (!ed->buf)
-    {
-      log_error(_("problem handling encrypted packet\n"));
-      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);
 
-  gcry_cipher_setiv (dfx->cipher_hd, NULL, 0);
+      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));
 
-  if ( ed->len )
-    {
-      for (i=0; i < (nprefix+2) && ed->len; i++, ed->len-- )
+      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)
         {
-          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;
+        }
+
+      if (!ed->buf)
+        {
+          log_error(_("problem handling encrypted packet\n"));
+          goto leave;
+        }
+
+      rc = aead_set_nonce (dfx);
+      if (rc)
+        goto leave;
+
+      rc = aead_set_ad (dfx, 0);
+      if (rc)
+        goto leave;
+
     }
-  else
+  else /* CFB encryption.  */
     {
-      for (i=0; i < (nprefix+2); i++ )
-        if ( (c=iobuf_get(ed->buf)) == -1 )
-          break;
-        else
-          temp[i] = c;
-    }
+      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;
+        }
 
-  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->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();
+        }
 
-  if ( dfx->mdc_hash )
-    gcry_md_write (dfx->mdc_hash, temp, nprefix+2);
+
+      /* 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 )
+        {
+          log_error("key setup failed: %s\n", gpg_strerror (rc) );
+          goto leave;
+        }
+
+      if (!ed->buf)
+        {
+          log_error(_("problem handling encrypted packet\n"));
+          goto leave;
+        }
+
+      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,16 +511,16 @@ 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 message:", dfx->holdback, 22); */
       /* log_printhex("MDC calc:", gcry_md_read (dfx->mdc_hash,0), datalen); */
     }
 
@@ -307,6 +531,321 @@ decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek)
 }
 
 
+/* 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.  */
+  int c;
+
+  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\n",
+               size, len, dfx->eof_seen? " eof":"");
+
+  /* Read and fill up BUF.  We need to watchout 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 read at least
+   * one further byte; however we try to ready 16 extra bytes to avoid
+   * singel 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).  */
+  if (dfx->partial)
+    {
+      for (; len < size; len++ )
+        {
+          if ((c = iobuf_get (a)) == -1)
+            {
+              dfx->eof_seen = 1; /* Normal EOF. */
+              break;
+            }
+          buf[len] = c;
+        }
+    }
+  else
+    {
+      for (; len < size && dfx->length; len++, dfx->length--)
+        {
+          c = iobuf_get (a);
+          if (c == -1)
+            {
+              dfx->eof_seen = 3; /* Premature EOF. */
+              break;
+            }
+          buf[len] = c;
+        }
+      if (!dfx->length)
+        dfx->eof_seen = 1; /* Normal EOF.  */
+    }
+
+  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 requires a loop because a chunk may end
+   * within the buffer.  */
+  if (DBG_FILTER)
+    log_debug ("decrypt loop: chunklen=%ju total=%ju size=%zu len=%zu%s\n",
+               (uintmax_t)dfx->chunklen, (uintmax_t)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);
+      /* 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 ("bytes left: %zu at off=%zu\n", 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.  The 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);
+
+          len = dfx->holdbacklen;
+          if (dfx->partial)
+            {
+              for (; len < 48; len++ )
+                {
+                  if ((c = iobuf_get (a)) == -1)
+                    {
+                      dfx->eof_seen = 1; /* Normal EOF. */
+                      break;
+                    }
+                  dfx->holdback[len] = c;
+                }
+            }
+          else
+            {
+              for (; len < 48 && dfx->length; len++, dfx->length--)
+                {
+                  c = iobuf_get (a);
+                  if (c == -1)
+                    {
+                      dfx->eof_seen = 3; /* Premature EOF. */
+                      break;
+                    }
+                  dfx->holdback[len] = c;
+                }
+              if (!dfx->length)
+                dfx->eof_seen = 1; /* Normal EOF.  */
+            }
+          if (len < 32)
+            {
+              /* Not enough data for the last two tags.  */
+              err = gpg_error (GPG_ERR_TRUNCATED);
+              goto leave;
+            }
+          dfx->holdbacklen = len;
+          /* log_printhex (dfx->holdback, dfx->holdbacklen, "holdback:"); */
+          len = 0;
+        }
+      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;
+        }
+      if (DBG_CRYPTO)
+        log_printhex (tagbuf, 16, "tag:");
+      err = gcry_cipher_checktag (dfx->cipher_hd, tagbuf, 16);
+      if (err)
+        {
+          if (DBG_FILTER)
+            log_debug ("gcry_cipher_checktag failed (1): %s\n",
+                       gpg_strerror (err));
+          goto leave;
+        }
+
+      /* Prepare a new chunk.  */
+      dfx->chunklen = 0;
+      dfx->chunkindex++;
+      err = aead_set_nonce (dfx);
+      if (err)
+        goto leave;
+      err = aead_set_ad (dfx, 0);
+      if (err)
+        goto leave;
+
+      continue;
+    }
+
+  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 (dfx->eof_seen)
+    {
+      if (DBG_FILTER)
+        log_debug ("eof seen: holdback buffer has the tags.\n");
+
+      log_assert (dfx->holdbacklen >= 32);
+
+      if (DBG_FILTER)
+        log_printhex (dfx->holdback, 16, "tag:");
+      err = gcry_cipher_checktag (dfx->cipher_hd, dfx->holdback, 16);
+      if (err)
+        {
+          log_error ("gcry_cipher_checktag failed (2): %s\n",
+                     gpg_strerror (err));
+          goto leave;
+        }
+
+      /* Check the final chunk.  */
+      dfx->chunkindex++;
+      err = aead_set_nonce (dfx);
+      if (err)
+        goto leave;
+      err = aead_set_ad (dfx, 1);
+      if (err)
+        goto leave;
+      gcry_cipher_final (dfx->cipher_hd);
+      /* decrypt an empty string.  */
+      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;
+        }
+      /* log_printhex (dfx->holdback+16, 16, "tag:"); */
+      err = gcry_cipher_checktag (dfx->cipher_hd, dfx->holdback+16, 16);
+      if (err)
+        {
+          if (DBG_FILTER)
+            log_debug ("gcry_cipher_checktag failed (final): %s\n",
+                       gpg_strerror (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,
@@ -357,15 +896,16 @@ mdc_decode_filter (void *opaque, int control, IOBUF a,
         }
       if (n == 44)
         {
-          /* We have enough stuff - flush the deferred stuff.  */
-          if ( !dfx->defer_filled )  /* First time. */
+          /* We have enough stuff - flush the holdback buffer.  */
+          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)
@@ -396,13 +936,13 @@ mdc_decode_filter (void *opaque, int control, IOBUF a,
                 dfx->eof_seen = 1; /* Normal EOF.  */
             }
 
-          /* 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. */
         {
           /* This is bad because it means an incomplete hash. */
           n -= 22;
@@ -411,9 +951,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. */
        }
 
index 666810c..1e861f5 100644 (file)
--- a/g10/dek.h
+++ b/g10/dek.h
@@ -1,5 +1,5 @@
 /* dek.h - The data encryption key structure.
- * Copyright (C) 2014 Werner Koch
+ * Copyright (C) 2014, 2017 Werner Koch
  *
  * This file is part of GnuPG.
  *
@@ -26,14 +26,25 @@ typedef struct
   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.  */
+  int algo_info_printed : 1;
+
+  /* AEAD shall be used.  The value is the AEAD algo. */
+  int use_aead : 4;
+
+  /* MDC shall be used.  */
+  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). */
+  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 6c2a56b..6587cc4 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 c68d6d5..c6c9e3a 100644 (file)
@@ -47,12 +47,12 @@ static int write_pubkey_enc_from_list (ctrl_t ctrl,
 
 /****************
  * Encrypt FILENAME with only the symmetric cipher.  Take input from
- * stdin if FILENAME is NULL.
+ * stdin if FILENAME is NULL.  If --force-aead is used we use an SKESK.
  */
 int
 encrypt_symmetric (const char *filename)
 {
-  return encrypt_simple( filename, 1, );
+  return encrypt_simple( filename, 1, opt.force_aead);
 }
 
 
@@ -67,45 +67,173 @@ encrypt_store (const char *filename)
 }
 
 
-/* *SESKEY contains the unencrypted session key ((*SESKEY)->KEY) and
-   the algorithm that will be used to encrypt the contents of the SED
-   packet ((*SESKEY)->ALGO).  If *SESKEY is NULL, then a random
-   session key that is appropriate for DEK->ALGO is generated and
-   stored there.
-
-   Encrypt that session key using DEK and store the result in ENCKEY,
-   which must be large enough to hold (*SESKEY)->KEYLEN + 1 bytes.  */
-void
-encrypt_seskey (DEK *dek, DEK **seskey, byte *enckey)
+/* Encrypt a session key using DEK and store a pointer to the result
+ * at R_ENCKEY and its length at R_ENCKEYLEN.
+ *
+ * R_SESKEY points to the unencrypted session key (.KEY, .KEYLEN) and
+ * the algorithm that will be used to encrypt the contents of the
+ * SKESK packet (.ALGO).  If R_SESKEY points to NULL, then a random
+ * session key that is appropriate for DEK->ALGO is generated and
+ * stored at R_SESKEY.  If AEAD_ALGO is not 0 the given AEAD algorithm
+ * is used for encryption.
+ */
+gpg_error_t
+encrypt_seskey (DEK *dek, aead_algo_t aead_algo,
+                DEK **r_seskey, void **r_enckey, size_t *r_enckeylen)
 {
-  gcry_cipher_hd_t hd;
-  byte buf[33];
+  gpg_error_t err;
+  gcry_cipher_hd_t hd = NULL;
+  byte *buf = NULL;
+  DEK *seskey;
+
+  *r_enckey = NULL;
+  *r_enckeylen = 0;
 
-  log_assert ( dek->keylen <= 32 );
-  if (!*seskey)
+  if (*r_seskey)
+    seskey = *r_seskey;
+  else
     {
-      *seskey=xmalloc_clear(sizeof(DEK));
-      (*seskey)->algo=dek->algo;
-      make_session_key(*seskey);
+      seskey = xtrycalloc (1, sizeof(DEK));
+      if (!seskey)
+        {
+          err = gpg_error_from_syserror ();
+          goto leave;
+        }
+      seskey->algo = dek->algo;
+      make_session_key (seskey);
       /*log_hexdump( "thekey", c->key, c->keylen );*/
     }
 
-  /* The encrypted session key is prefixed with a one-octet algorithm id.  */
-  buf[0] = (*seskey)->algo;
-  memcpy( buf + 1, (*seskey)->key, (*seskey)->keylen );
-
-  /* We only pass already checked values to the following function,
-     thus we consider any failure as fatal.  */
-  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_encrypt (hd, buf, (*seskey)->keylen + 1, NULL, 0);
+
+  if (aead_algo)
+    {
+      unsigned int noncelen;
+      enum gcry_cipher_modes ciphermode;
+      byte ad[4];
+
+      err = openpgp_aead_algo_info (aead_algo, &ciphermode, &noncelen);
+      if (err)
+        goto leave;
+
+      /* Allocate space for the nonce, the key, and the authentication
+       * tag (16).  */
+      buf = xtrymalloc_secure (noncelen + seskey->keylen + 16);
+      if (!buf)
+        {
+          err = gpg_error_from_syserror ();
+          goto leave;
+        }
+
+      gcry_randomize (buf, noncelen, GCRY_STRONG_RANDOM);
+
+      err = openpgp_cipher_open (&hd, dek->algo,
+                                 ciphermode, GCRY_CIPHER_SECURE);
+      if (!err)
+        err = gcry_cipher_setkey (hd, dek->key, dek->keylen);
+      if (!err)
+        err = gcry_cipher_setiv (hd, buf, noncelen);
+      if (err)
+        goto leave;
+
+      ad[0] = (0xc0 | PKT_SYMKEY_ENC);
+      ad[1] = 5;
+      ad[2] = dek->algo;
+      ad[3] = aead_algo;
+      err = gcry_cipher_authenticate (hd, ad, 4);
+      if (err)
+        goto leave;
+
+      memcpy (buf + noncelen, seskey->key, seskey->keylen);
+      gcry_cipher_final (hd);
+      err = gcry_cipher_encrypt (hd, buf + noncelen, seskey->keylen, NULL,0);
+      if (err)
+        goto leave;
+      err = gcry_cipher_gettag (hd, buf + noncelen + seskey->keylen, 16);
+      if (err)
+        goto leave;
+      *r_enckeylen = noncelen + seskey->keylen + 16;
+      *r_enckey = buf;
+      buf = NULL;
+    }
+  else
+    {
+      /* In the old version 4 SKESK the encrypted session key is
+       * prefixed with a one-octet algorithm id.  */
+      buf = xtrymalloc_secure (1 + seskey->keylen);
+      if (!buf)
+        {
+          err = gpg_error_from_syserror ();
+          goto leave;
+        }
+      buf[0] = seskey->algo;
+      memcpy (buf + 1, seskey->key, seskey->keylen);
+
+      err = openpgp_cipher_open (&hd, dek->algo, GCRY_CIPHER_MODE_CFB, 1);
+      if (!err)
+        err = gcry_cipher_setkey (hd, dek->key, dek->keylen);
+      if (!err)
+        err = gcry_cipher_setiv (hd, NULL, 0);
+      if (!err)
+        err = gcry_cipher_encrypt (hd, buf, seskey->keylen + 1, NULL, 0);
+      if (err)
+        goto leave;
+      *r_enckeylen = seskey->keylen + 1;
+      *r_enckey = buf;
+      buf = NULL;
+    }
+
+  /* Return the session key in case we allocated it.  */
+  *r_seskey = seskey;
+  seskey = NULL;
+
+ leave:
   gcry_cipher_close (hd);
+  if (seskey != *r_seskey)
+    xfree (seskey);
+  xfree (buf);
+  return err;
+}
+
+
+/* Return the AEAD algo if we shall use AEAD mode.  Returns 0 if AEAD
+ * shall not be used.  */
+aead_algo_t
+use_aead (pk_list_t pk_list, int algo)
+{
+  int can_use;
+
+  if (!opt.flags.rfc4880bis)
+    {
+      if (opt.force_aead)
+        log_info ("Warning: Option %s currently requires option '%s'\n",
+                  "--force-aead", "--rfc4880bis");
+      return 0;
+    }
+
+  can_use = openpgp_cipher_get_algo_blklen (algo) == 16;
+
+  /* With --force-mdc we clearly do not want AEAD.  */
+  if (opt.force_mdc)
+    return 0;
+
+  /* However with --force-aead we want AEAD.  */
+  if (opt.force_aead)
+    {
+      if (!can_use)
+        {
+          log_info ("Warning: request to use AEAD ignored for cipher '%s'\n",
+                    openpgp_cipher_algo_name (algo));
+          return 0;
+        }
+      return default_aead_algo ();
+    }
 
-  memcpy( enckey, buf, (*seskey)->keylen + 1 );
-  wipememory( buf, sizeof buf ); /* burn key */
+  /* AEAD does only work with 128 bit cipher blocklength.  */
+  if (!can_use)
+    return 0;
+
+  /* If all keys support AEAD we can use it.  */
+  return select_aead_from_pklist (pk_list);
 }
 
 
@@ -174,9 +302,9 @@ encrypt_simple (const char *filename, int mode, int use_seskey)
   PACKET pkt;
   PKT_plaintext *pt = NULL;
   STRING2KEY *s2k = NULL;
-  byte enckey[33];
+  void *enckey = NULL;
+  size_t enckeylen = 0;
   int rc = 0;
-  int seskeylen = 0;
   u32 filesize;
   cipher_filter_context_t cfx;
   armor_filter_context_t  *afx = NULL;
@@ -229,6 +357,7 @@ encrypt_simple (const char *filename, int mode, int use_seskey)
   if ( mode )
     {
       int canceled;
+      aead_algo_t aead_algo;
 
       s2k = xmalloc_clear( sizeof *s2k );
       s2k->mode = opt.s2k_mode;
@@ -252,23 +381,42 @@ encrypt_simple (const char *filename, int mode, int use_seskey)
                       "due to the S2K mode\n"));
         }
 
+      /* See whether we want to use AEAD.  */
+      aead_algo = use_aead (NULL, cfx.dek->algo);
+
       if ( use_seskey )
         {
           DEK *dek = NULL;
 
-          seskeylen = openpgp_cipher_get_algo_keylen (default_cipher_algo ());
-          encrypt_seskey( cfx.dek, &dek, enckey );
-          xfree( cfx.dek ); cfx.dek = dek;
+          rc = encrypt_seskey (cfx.dek, aead_algo, &dek, &enckey, &enckeylen);
+          if (rc)
+            {
+              xfree (cfx.dek);
+              xfree (s2k);
+              iobuf_close (inp);
+              release_progress_context (pfx);
+              return rc;
+            }
+          /* Replace key in DEK.  */
+          xfree (cfx.dek);
+          cfx.dek = dek;
         }
 
-      if (opt.verbose)
-        log_info(_("using cipher %s\n"),
-                 openpgp_cipher_algo_name (cfx.dek->algo));
+      if (aead_algo)
+        cfx.dek->use_aead = aead_algo;
+      else
+        cfx.dek->use_mdc = !!use_mdc (NULL, cfx.dek->algo);
 
-      cfx.dek->use_mdc=use_mdc(NULL,cfx.dek->algo);
+      if (opt.verbose)
+        log_info(_("using cipher %s.%s\n"),
+                 openpgp_cipher_algo_name (cfx.dek->algo),
+                 cfx.dek->use_aead? openpgp_aead_algo_name (cfx.dek->use_aead)
+                 /**/             : "CFB");
     }
 
-  if (do_compress && cfx.dek && cfx.dek->use_mdc
+  if (do_compress
+      && cfx.dek
+      && (cfx.dek->use_mdc || cfx.dek->use_aead)
       && is_file_compressed(filename, &rc))
     {
       if (opt.verbose)
@@ -293,20 +441,24 @@ encrypt_simple (const char *filename, int mode, int use_seskey)
 
   if ( s2k )
     {
-      PKT_symkey_enc *enc = xmalloc_clear( sizeof *enc + seskeylen + 1 );
-      enc->version = 4;
+      /* Fixme: This is quite similar to write_symkey_enc.  */
+      PKT_symkey_enc *enc = xmalloc_clear (sizeof *enc + enckeylen);
+      enc->version = cfx.dek->use_aead ? 5 : 4;
       enc->cipher_algo = cfx.dek->algo;
+      enc->aead_algo = cfx.dek->use_aead;
       enc->s2k = *s2k;
-      if ( use_seskey && seskeylen )
+      if (enckeylen)
         {
-          enc->seskeylen = seskeylen + 1; /* algo id */
-          memcpy (enc->seskey, enckey, seskeylen + 1 );
+          enc->seskeylen = enckeylen;
+          memcpy (enc->seskey, enckey, enckeylen);
         }
       pkt.pkttype = PKT_SYMKEY_ENC;
       pkt.pkt.symkey_enc = enc;
       if ((rc = build_packet( out, &pkt )))
         log_error("build symkey packet failed: %s\n", gpg_strerror (rc) );
       xfree (enc);
+      xfree (enckey);
+      enckey = NULL;
     }
 
   if (!opt.no_literal)
@@ -363,12 +515,15 @@ encrypt_simple (const char *filename, int mode, int use_seskey)
 
   /* Register the cipher filter. */
   if (mode)
-    iobuf_push_filter ( out, cipher_filter, &cfx );
+    iobuf_push_filter (out,
+                       cfx.dek->use_aead? cipher_filter_aead
+                       /**/             : cipher_filter_cfb,
+                       &cfx );
 
   /* Register the compress filter. */
   if ( do_compress )
     {
-      if (cfx.dek && cfx.dek->use_mdc)
+      if (cfx.dek && (cfx.dek->use_mdc || cfx.dek->use_aead))
         zfx.new_ctb = 1;
       push_compress_filter (out, &zfx, default_compress_algo());
     }
@@ -407,6 +562,7 @@ encrypt_simple (const char *filename, int mode, int use_seskey)
   if (pt)
     pt->buf = NULL;
   free_packet (&pkt, NULL);
+  xfree (enckey);
   xfree (cfx.dek);
   xfree (s2k);
   release_armor_context (afx);
@@ -438,23 +594,33 @@ setup_symkey (STRING2KEY **symkey_s2k,DEK **symkey_dek)
 
 
 static int
-write_symkey_enc (STRING2KEY *symkey_s2k, DEK *symkey_dek, DEK *dek,
-                  iobuf_t out)
+write_symkey_enc (STRING2KEY *symkey_s2k, aead_algo_t aead_algo,
+                  DEK *symkey_dek, DEK *dek, iobuf_t out)
 {
-  int rc, seskeylen = openpgp_cipher_get_algo_keylen (dek->algo);
-
+  int rc;
+  void *enckey;
+  size_t enckeylen;
   PKT_symkey_enc *enc;
-  byte enckey[33];
   PACKET pkt;
 
-  enc=xmalloc_clear(sizeof(PKT_symkey_enc)+seskeylen+1);
-  encrypt_seskey(symkey_dek,&dek,enckey);
+  rc = encrypt_seskey (symkey_dek, aead_algo, &dek, &enckey, &enckeylen);
+  if (rc)
+    return rc;
+  enc = xtrycalloc (1, sizeof (PKT_symkey_enc) + enckeylen);
+  if (!enc)
+    {
+      rc = gpg_error_from_syserror ();
+      xfree (enckey);
+      return rc;
+    }
 
-  enc->version = 4;
+  enc->version = aead_algo? 5 : 4;
   enc->cipher_algo = opt.s2k_cipher_algo;
+  enc->aead_algo = aead_algo;
   enc->s2k = *symkey_s2k;
-  enc->seskeylen = seskeylen + 1; /* algo id */
-  memcpy( enc->seskey, enckey, seskeylen + 1 );
+  enc->seskeylen = enckeylen;
+  memcpy (enc->seskey, enckey, enckeylen);
+  xfree (enckey);
 
   pkt.pkttype = PKT_SYMKEY_ENC;
   pkt.pkt.symkey_enc = enc;
@@ -462,7 +628,7 @@ write_symkey_enc (STRING2KEY *symkey_s2k, DEK *symkey_dek, DEK *dek,
   if ((rc=build_packet(out,&pkt)))
     log_error("build symkey_enc packet failed: %s\n",gpg_strerror (rc));
 
-  xfree(enc);
+  xfree (enc);
   return rc;
 }
 
@@ -676,14 +842,17 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
                           gnupg_status_compliance_flag (CO_DE_VS),
                           NULL);
 
-  cfx.dek->use_mdc = use_mdc (pk_list,cfx.dek->algo);
+  cfx.dek->use_aead = use_aead (pk_list, cfx.dek->algo);
+  if (!cfx.dek->use_aead)
+    cfx.dek->use_mdc = !!use_mdc (pk_list, cfx.dek->algo);
 
   /* Only do the is-file-already-compressed check if we are using a
-     MDC.  This forces compressed files to be re-compressed if we do
-     not have a MDC to give some protection against chosen ciphertext
-     attacks. */
-
-  if (do_compress && cfx.dek->use_mdc && is_file_compressed(filename, &rc2))
+   * MDC or AEAD.  This forces compressed files to be re-compressed if
+   * we do not have a MDC to give some protection against chosen
+   * ciphertext attacks. */
+  if (do_compress
+      && (cfx.dek->use_mdc || cfx.dek->use_aead)
+      && is_file_compressed (filename, &rc2))
     {
       if (opt.verbose)
         log_info(_("'%s' already compressed\n"), filename);
@@ -697,17 +866,18 @@ 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)
     goto leave;
 
   /* We put the passphrase (if any) after any public keys as this
-     seems to be the most useful on the recipient side - there is no
-     point in prompting a user for a passphrase if they have the
-     secret key needed to decrypt.  */
-  if(use_symkey && (rc = write_symkey_enc(symkey_s2k,symkey_dek,cfx.dek,out)))
+   * seems to be the most useful on the recipient side - there is no
+   * point in prompting a user for a passphrase if they have the
+   * secret key needed to decrypt.  */
+  if (use_symkey && (rc = write_symkey_enc (symkey_s2k, cfx.dek->use_aead,
+                                            symkey_dek, cfx.dek, out)))
     goto leave;
 
   if (!opt.no_literal)
@@ -750,7 +920,10 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
     cfx.datalen = filesize && !do_compress ? filesize : 0;
 
   /* Register the cipher filter. */
-  iobuf_push_filter (out, cipher_filter, &cfx);
+  iobuf_push_filter (out,
+                     cfx.dek->use_aead? cipher_filter_aead
+                     /**/             : cipher_filter_cfb,
+                     &cfx);
 
   /* Register the compress filter. */
   if (do_compress)
@@ -777,7 +950,7 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
       /* Algo 0 means no compression. */
       if (compr_algo)
         {
-          if (cfx.dek && cfx.dek->use_mdc)
+          if (cfx.dek && (cfx.dek->use_mdc || cfx.dek->use_aead))
             zfx.new_ctb = 1;
           push_compress_filter (out,&zfx,compr_algo);
         }
@@ -887,11 +1060,13 @@ encrypt_filter (void *opaque, int control,
              efx->cfx.dek->algo = opt.def_cipher_algo;
            }
 
-          efx->cfx.dek->use_mdc = use_mdc (efx->pk_list,efx->cfx.dek->algo);
+          efx->cfx.dek->use_aead = use_aead (efx->pk_list, efx->cfx.dek->algo);
+          if (!efx->cfx.dek->use_aead)
+            efx->cfx.dek->use_mdc = !!use_mdc (efx->pk_list,efx->cfx.dek->algo);
 
           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);
@@ -900,13 +1075,16 @@ encrypt_filter (void *opaque, int control,
 
           if(efx->symkey_s2k && efx->symkey_dek)
             {
-              rc=write_symkey_enc(efx->symkey_s2k,efx->symkey_dek,
-                                  efx->cfx.dek,a);
-              if(rc)
+              rc = write_symkey_enc (efx->symkey_s2k, efx->cfx.dek->use_aead,
+                                     efx->symkey_dek, efx->cfx.dek, a);
+              if (rc)
                 return rc;
             }
 
-          iobuf_push_filter (a, cipher_filter, &efx->cfx);
+          iobuf_push_filter (a,
+                             efx->cfx.dek->use_aead? cipher_filter_aead
+                             /**/                  : cipher_filter_cfb,
+                             &efx->cfx);
 
           efx->header_okay = 1;
         }
@@ -967,9 +1145,11 @@ write_pubkey_enc (ctrl_t ctrl,
       if ( opt.verbose )
         {
           char *ustr = get_user_id_string_native (ctrl, enc->keyid);
-          log_info (_("%s/%s encrypted for: \"%s\"\n"),
+          log_info (_("%s/%s.%s encrypted for: \"%s\"\n"),
                     openpgp_pk_algo_name (enc->pubkey_algo),
                     openpgp_cipher_algo_name (dek->algo),
+                    dek->use_aead? openpgp_aead_algo_name (dek->use_aead)
+                    /**/         : "CFB",
                     ustr );
           xfree (ustr);
         }
index 9e4b1e5..cd177f4 100644 (file)
@@ -88,15 +88,52 @@ struct compress_filter_context_s {
 typedef struct compress_filter_context_s compress_filter_context_t;
 
 
-typedef struct {
-    DEK *dek;
-    u32 datalen;
-    gcry_cipher_hd_t cipher_hd;
-    unsigned int wrote_header : 1;
-    unsigned int short_blklen_warn : 1;
-    unsigned long short_blklen_count;
-    gcry_md_hd_t mdc_hash;
-    byte enchash[20];
+typedef struct
+{
+  /* Object with the key and algo */
+  DEK *dek;
+
+  /* Length of the data to encrypt if known - 32 bit because OpenPGP
+   * requires partial encoding for a larger data size.  */
+  u32 datalen;
+
+  /* The current cipher handle.  */
+  gcry_cipher_hd_t cipher_hd;
+
+  /* Various processing flags.  */
+  unsigned int wrote_header : 1;
+  unsigned int short_blklen_warn : 1;
+  unsigned long short_blklen_count;
+
+  /* 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 encrypted plaintext octets.  Note that we
+   * don't care about encrypting more than 16 Exabyte. */
+  uint64_t total;
+
+  /* The hash context and a buffer used for MDC.  */
+  gcry_md_hd_t mdc_hash;
+  byte enchash[20];
+
+  /* The start IV for AEAD encryption.   */
+  byte startiv[16];
+
+  /* Using a large buffer for encryption makes processing easier and
+   * also makes sure the data is well aligned.  */
+  char *buffer;
+  size_t bufsize;  /* Allocated length.  */
+  size_t buflen;   /* Used length.       */
+
 } cipher_filter_context_t;
 
 
@@ -145,8 +182,12 @@ void push_compress_filter2(iobuf_t out,compress_filter_context_t *zfx,
                           int algo,int rel);
 
 /*-- cipher.c --*/
-int cipher_filter( void *opaque, int control,
-                  iobuf_t chain, byte *buf, size_t *ret_len);
+int cipher_filter_cfb (void *opaque, int control,
+                       iobuf_t chain, byte *buf, size_t *ret_len);
+
+/*-- cipher-aead.c --*/
+int cipher_filter_aead (void *opaque, int control,
+                        iobuf_t chain, byte *buf, size_t *ret_len);
 
 /*-- textfilter.c --*/
 int text_filter( void *opaque, int control,
index dabd052..a838c3c 100644 (file)
@@ -2443,8 +2443,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. */
@@ -2499,6 +2499,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;
@@ -2507,7 +2510,7 @@ fixup_uidnode (KBNODE uidnode, KBNODE signode, u32 keycreated)
   nzip = p ? n : 0;
   if (uid->prefs)
     xfree (uid->prefs);
-  n = nsym + nhash + nzip;
+  n = nsym + naead + nhash + nzip;
   if (!n)
     uid->prefs = NULL;
   else
@@ -2519,6 +2522,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;
@@ -2539,6 +2547,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] & 0x01))
+    uid->flags.aead = 1;
+
   /* And the keyserver modify flag.  */
   uid->flags.ks_modify = 1;
   p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KS_FLAGS, &n);
@@ -3357,6 +3371,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)
     {
@@ -3418,7 +3433,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
@@ -3427,6 +3442,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;
        }
     }
@@ -3440,6 +3456,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 62d6131..cbac967 100644 (file)
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -105,6 +105,7 @@ enum cmd_and_opt_values
     oBatch       = 500,
     oMaxOutput,
     oInputSizeHint,
+    oChunkSize,
     oSigNotation,
     oCertNotation,
     oShowNotation,
@@ -197,6 +198,7 @@ enum cmd_and_opt_values
     oWithSubkeyFingerprint,
     oWithICAOSpelling,
     oWithKeygrip,
+    oWithKeyScreening,
     oWithSecret,
     oWithWKDHash,
     oWithColons,
@@ -221,6 +223,7 @@ enum cmd_and_opt_values
     oDebugLevel,
     oDebugAll,
     oDebugIOLBF,
+    oDebugSetIobufSize,
     oStatusFD,
     oStatusFile,
     oAttributeFD,
@@ -244,6 +247,7 @@ enum cmd_and_opt_values
     oRFC2440Text,
     oNoRFC2440Text,
     oCipherAlgo,
+    oAEADAlgo,
     oDigestAlgo,
     oCertDigestAlgo,
     oCompressAlgo,
@@ -302,6 +306,7 @@ enum cmd_and_opt_values
     oNoForceMDC,
     oDisableMDC,
     oNoDisableMDC,
+    oForceAEAD,
     oS2KMode,
     oS2KDigest,
     oS2KCipher,
@@ -370,6 +375,7 @@ enum cmd_and_opt_values
     oDefaultPreferenceList,
     oDefaultKeyserverURL,
     oPersonalCipherPreferences,
+    oPersonalAEADPreferences,
     oPersonalDigestPreferences,
     oPersonalCompressPreferences,
     oAgentProgram,
@@ -592,6 +598,7 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_s (oOutput, "output", N_("|FILE|write output to FILE")),
   ARGPARSE_p_u (oMaxOutput, "max-output", "@"),
   ARGPARSE_s_s (oInputSizeHint, "input-size-hint", "@"),
+  ARGPARSE_s_i (oChunkSize, "chunk-size", "@"),
 
   ARGPARSE_s_n (oVerbose, "verbose", N_("verbose")),
   ARGPARSE_s_n (oQuiet,          "quiet",   "@"),
@@ -602,6 +609,8 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_n (oDisableMDC, "disable-mdc", "@"),
   ARGPARSE_s_n (oNoDisableMDC, "no-disable-mdc", "@"),
 
+  ARGPARSE_s_n (oForceAEAD, "force-aead", "@"),
+
   ARGPARSE_s_n (oDisableSignerUID, "disable-signer-uid", "@"),
 
   ARGPARSE_s_n (oDryRun, "dry-run", N_("do not make any changes")),
@@ -634,6 +643,7 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_s (oDebugLevel, "debug-level", "@"),
   ARGPARSE_s_n (oDebugAll, "debug-all", "@"),
   ARGPARSE_s_n (oDebugIOLBF, "debug-iolbf", "@"),
+  ARGPARSE_s_u (oDebugSetIobufSize, "debug-set-iobuf-size", "@"),
   ARGPARSE_s_i (oStatusFD, "status-fd", "@"),
   ARGPARSE_s_s (oStatusFile, "status-file", "@"),
   ARGPARSE_s_i (oAttributeFD, "attribute-fd", "@"),
@@ -667,6 +677,7 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_s (oS2KCipher, "s2k-cipher-algo", "@"),
   ARGPARSE_s_i (oS2KCount, "s2k-count", "@"),
   ARGPARSE_s_s (oCipherAlgo, "cipher-algo", "@"),
+  ARGPARSE_s_s (oAEADAlgo,   "aead-algo", "@"),
   ARGPARSE_s_s (oDigestAlgo, "digest-algo", "@"),
   ARGPARSE_s_s (oCertDigestAlgo, "cert-digest-algo", "@"),
   ARGPARSE_s_s (oCompressAlgo,"compress-algo", "@"),
@@ -785,6 +796,7 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_n (oWithSubkeyFingerprint, "with-subkey-fingerprints", "@"),
   ARGPARSE_s_n (oWithICAOSpelling, "with-icao-spelling", "@"),
   ARGPARSE_s_n (oWithKeygrip,     "with-keygrip", "@"),
+  ARGPARSE_s_n (oWithKeyScreening,"with-key-screening", "@"),
   ARGPARSE_s_n (oWithSecret,      "with-secret", "@"),
   ARGPARSE_s_n (oWithWKDHash,     "with-wkd-hash", "@"),
   ARGPARSE_s_n (oWithKeyOrigin,   "with-key-origin", "@"),
@@ -822,6 +834,7 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_s (oDefaultPreferenceList,  "default-preference-list", "@"),
   ARGPARSE_s_s (oDefaultKeyserverURL,  "default-keyserver-url", "@"),
   ARGPARSE_s_s (oPersonalCipherPreferences, "personal-cipher-preferences","@"),
+  ARGPARSE_s_s (oPersonalAEADPreferences, "personal-aead-preferences","@"),
   ARGPARSE_s_s (oPersonalDigestPreferences, "personal-digest-preferences","@"),
   ARGPARSE_s_s (oPersonalCompressPreferences,
                                          "personal-compress-preferences", "@"),
@@ -833,6 +846,7 @@ static ARGPARSE_OPTS opts[] = {
   /* Aliases.  I constantly mistype these, and assume other people do
      as well. */
   ARGPARSE_s_s (oPersonalCipherPreferences, "personal-cipher-prefs", "@"),
+  ARGPARSE_s_s (oPersonalAEADPreferences,   "personal-aead-prefs", "@"),
   ARGPARSE_s_s (oPersonalDigestPreferences, "personal-digest-prefs", "@"),
   ARGPARSE_s_s (oPersonalCompressPreferences, "personal-compress-prefs", "@"),
 
@@ -944,6 +958,8 @@ int g10_errors_seen = 0;
 
 static int utf8_strings = 0;
 static int maybe_setuid = 1;
+static unsigned int opt_set_iobuf_size;
+static unsigned int opt_set_iobuf_size_used;
 
 static char *build_list( const char *text, char letter,
                         const char *(*mapf)(int), int (*chkf)(int) );
@@ -1006,6 +1022,18 @@ build_list_cipher_algo_name (int algo)
 }
 
 static int
+build_list_aead_test_algo (int algo)
+{
+  return openpgp_aead_test_algo (algo);
+}
+
+static const char *
+build_list_aead_algo_name (int algo)
+{
+  return openpgp_aead_algo_name (algo);
+}
+
+static int
 build_list_md_test_algo (int algo)
 {
   /* By default we do not accept MD5 based signatures.  To avoid
@@ -1026,7 +1054,7 @@ build_list_md_algo_name (int algo)
 static const char *
 my_strusage( int level )
 {
-  static char *digests, *pubkeys, *ciphers, *zips, *ver_gcry;
+  static char *digests, *pubkeys, *ciphers, *zips, *aeads, *ver_gcry;
   const char *p;
 
     switch( level ) {
@@ -1086,13 +1114,20 @@ my_strusage( int level )
        p = ciphers;
        break;
       case 36:
+       if (!aeads)
+          aeads = build_list ("AEAD: ", 'A',
+                              build_list_aead_algo_name,
+                              build_list_aead_test_algo);
+       p = aeads;
+       break;
+      case 37:
        if( !digests )
            digests = build_list(_("Hash: "), 'H',
                                  build_list_md_algo_name,
                                  build_list_md_test_algo );
        p = digests;
        break;
-      case 37:
+      case 38:
        if( !zips )
            zips = build_list(_("Compression: "),'Z',
                               compress_algo_to_string,
@@ -1113,6 +1148,7 @@ build_list (const char *text, char letter,
   membuf_t mb;
   int indent;
   int i, j, len;
+  int limit;
   const char *s;
   char *string;
 
@@ -1123,7 +1159,8 @@ build_list (const char *text, char letter,
   len = 0;
   init_membuf (&mb, 512);
 
-  for (i=0; i <= 110; i++ )
+  limit = (letter == 'A')? 4 : 110;
+  for (i=0; i <= limit; i++ )
     {
       if (!chkf (i) && (s = mapf (i)))
         {
@@ -1243,6 +1280,10 @@ set_debug (const char *level)
 
   if (opt.debug)
     parse_debug_flag (NULL, &opt.debug, debug_flags);
+
+  if (opt_set_iobuf_size || opt_set_iobuf_size_used)
+    log_debug ("iobuf buffer size is %uk\n",
+               iobuf_set_buffer_size (opt_set_iobuf_size));
 }
 
 
@@ -2123,6 +2164,7 @@ set_compliance_option (enum cmd_and_opt_values option)
       opt.escape_from = 1;
       opt.not_dash_escaped = 0;
       opt.def_cipher_algo = 0;
+      opt.def_aead_algo = 0;
       opt.def_digest_algo = 0;
       opt.cert_digest_algo = 0;
       opt.compress_algo = -1;
@@ -2139,6 +2181,7 @@ set_compliance_option (enum cmd_and_opt_values option)
       opt.escape_from = 0;
       opt.not_dash_escaped = 0;
       opt.def_cipher_algo = 0;
+      opt.def_aead_algo = 0;
       opt.def_digest_algo = 0;
       opt.cert_digest_algo = 0;
       opt.compress_algo = -1;
@@ -2155,6 +2198,7 @@ set_compliance_option (enum cmd_and_opt_values option)
       set_compliance_option (oOpenPGP);
       opt.compliance = CO_DE_VS;
       opt.force_mdc = 1;
+      opt.def_aead_algo = 0;
       /* Fixme: Change other options.  */
       break;
 
@@ -2284,12 +2328,14 @@ main (int argc, char **argv)
     const char *trustdb_name = NULL;
 #endif /*!NO_TRUST_MODELS*/
     char *def_cipher_string = NULL;
+    char *def_aead_string = NULL;
     char *def_digest_string = NULL;
     char *compress_algo_string = NULL;
     char *cert_digest_string = NULL;
     char *s2k_cipher_string = NULL;
     char *s2k_digest_string = NULL;
     char *pers_cipher_list = NULL;
+    char *pers_aead_list = NULL;
     char *pers_digest_list = NULL;
     char *pers_compress_list = NULL;
     int eyes_only=0;
@@ -2353,6 +2399,7 @@ main (int argc, char **argv)
     opt.bz2_compress_level = -1; /* defaults to standard compress level */
     /* note: if you change these lines, look at oOpenPGP */
     opt.def_cipher_algo = 0;
+    opt.def_aead_algo = 0;
     opt.def_digest_algo = 0;
     opt.cert_digest_algo = 0;
     opt.compress_algo = -1; /* defaults to DEFAULT_COMPRESS_ALGO */
@@ -2632,6 +2679,10 @@ main (int argc, char **argv)
             opt.input_size_hint = string_to_u64 (pargs.r.ret_str);
             break;
 
+          case oChunkSize:
+            opt.chunk_size = pargs.r.ret_int;
+            break;
+
          case oQuiet: opt.quiet = 1; break;
          case oNoTTY: tty_no_terminal(1); break;
          case oDryRun: opt.dry_run = 1; break;
@@ -2699,6 +2750,11 @@ main (int argc, char **argv)
 
           case oDebugIOLBF: break; /* Already set in pre-parse step.  */
 
+          case oDebugSetIobufSize:
+            opt_set_iobuf_size = pargs.r.ret_ulong;
+            opt_set_iobuf_size_used = 1;
+            break;
+
          case oStatusFD:
             set_status_fd ( translate_sys2libc_fd_int (pargs.r.ret_int, 1) );
             break;
@@ -2737,6 +2793,10 @@ main (int argc, char **argv)
             opt.with_keygrip = 1;
             break;
 
+         case oWithKeyScreening:
+            opt.with_key_screening = 1;
+            break;
+
          case oWithSecret:
             opt.with_secret = 1;
             break;
@@ -2960,6 +3020,8 @@ main (int argc, char **argv)
          case oDisableMDC: opt.disable_mdc = 1; break;
          case oNoDisableMDC: opt.disable_mdc = 0; break;
 
+         case oForceAEAD: opt.force_aead = 1; break;
+
           case oDisableSignerUID: opt.flags.disable_signer_uid = 1; break;
 
          case oS2KMode:   opt.s2k_mode = pargs.r.ret_int; break;
@@ -3107,6 +3169,9 @@ main (int argc, char **argv)
          case oCipherAlgo:
             def_cipher_string = xstrdup(pargs.r.ret_str);
             break;
+         case oAEADAlgo:
+            def_aead_string = xstrdup (pargs.r.ret_str);
+            break;
          case oDigestAlgo:
             def_digest_string = xstrdup(pargs.r.ret_str);
             break;
@@ -3386,6 +3451,9 @@ main (int argc, char **argv)
           case oPersonalCipherPreferences:
            pers_cipher_list=pargs.r.ret_str;
            break;
+          case oPersonalAEADPreferences:
+           pers_aead_list = pargs.r.ret_str;
+           break;
           case oPersonalDigestPreferences:
            pers_digest_list=pargs.r.ret_str;
            break;
@@ -3731,6 +3799,13 @@ main (int argc, char **argv)
        if ( openpgp_cipher_test_algo (opt.def_cipher_algo) )
            log_error(_("selected cipher algorithm is invalid\n"));
     }
+    if (def_aead_string)
+      {
+       opt.def_aead_algo = string_to_aead_algo (def_aead_string);
+       xfree (def_aead_string); def_aead_string = NULL;
+       if (openpgp_aead_test_algo (opt.def_aead_algo))
+          log_error(_("selected AEAD algorithm is invalid\n"));
+      }
     if( def_digest_string ) {
        opt.def_digest_algo = string_to_digest_algo (def_digest_string);
        xfree(def_digest_string); def_digest_string = NULL;
@@ -3790,6 +3865,9 @@ main (int argc, char **argv)
        keygen_set_std_prefs(pers_cipher_list,PREFTYPE_SYM))
       log_error(_("invalid personal cipher preferences\n"));
 
+    if (pers_aead_list && keygen_set_std_prefs (pers_aead_list, PREFTYPE_AEAD))
+      log_error(_("invalid personal AEAD preferences\n"));
+
     if(pers_digest_list &&
        keygen_set_std_prefs(pers_digest_list,PREFTYPE_HASH))
       log_error(_("invalid personal digest preferences\n"));
@@ -3798,6 +3876,21 @@ main (int argc, char **argv)
        keygen_set_std_prefs(pers_compress_list,PREFTYPE_ZIP))
       log_error(_("invalid personal compress preferences\n"));
 
+    /* Check chunk size.  Please fix also the man page if you chnage
+     * the default.  The limits are given by the specs.  */
+    if (!opt.chunk_size)
+      opt.chunk_size = 30; /* Default to 1 GiB chunks.  */
+    else if (opt.chunk_size < 6)
+      {
+        opt.chunk_size = 6;
+        log_info (_("chunk size invalid - using %d\n"), opt.chunk_size);
+      }
+    else if (opt.chunk_size > 62)
+      {
+        opt.chunk_size = 62;
+        log_info (_("chunk size invalid - using %d\n"), opt.chunk_size);
+      }
+
     /* We don't support all possible commands with multifile yet */
     if(multifile)
       {
@@ -3844,7 +3937,7 @@ main (int argc, char **argv)
     /* Check our chosen algorithms against the list of legal
        algorithms. */
 
-    if(!GNUPG)
+    if(!GNUPG && !opt.flags.rfc4880bis)
       {
        const char *badalg=NULL;
        preftype_t badtype=PREFTYPE_NONE;
@@ -3855,6 +3948,12 @@ main (int argc, char **argv)
            badalg = openpgp_cipher_algo_name (opt.def_cipher_algo);
            badtype = PREFTYPE_SYM;
          }
+       else if(opt.def_aead_algo
+          && !algo_available(PREFTYPE_AEAD, opt.def_aead_algo, NULL))
+         {
+           badalg = openpgp_aead_algo_name (opt.def_aead_algo);
+           badtype = PREFTYPE_AEAD;
+         }
        else if(opt.def_digest_algo
                && !algo_available(PREFTYPE_HASH,opt.def_digest_algo,NULL))
          {
@@ -3884,6 +3983,12 @@ main (int argc, char **argv)
                         badalg,
                           gnupg_compliance_option_string (opt.compliance));
                break;
+             case PREFTYPE_AEAD:
+               log_info (_("AEAD algorithm '%s'"
+                            " may not be used in %s mode\n"),
+                          badalg,
+                          gnupg_compliance_option_string (opt.compliance));
+               break;
              case PREFTYPE_HASH:
                log_info (_("digest algorithm '%s'"
                             " may not be used in %s mode\n"),
@@ -3909,6 +4014,7 @@ main (int argc, char **argv)
      * is not.  This is us being nice to the user informing her early
      * that the chosen algorithms are not available.  We also check
      * and enforce this right before the actual operation.  */
+    /* FIXME: We also need to check the AEAD algo. */
     if (opt.def_cipher_algo
        && ! gnupg_cipher_is_allowed (opt.compliance,
                                      cmd == aEncr
index 9b8b77c..03fe384 100644 (file)
--- a/g10/gpg.h
+++ b/g10/gpg.h
 #define MAX_EXTERN_MPI_BITS 16384
 
 /* The maximum length of a binary fingerprints.  This is used to
-   provide a static buffer and will be increased if we need to support
-   longer fingerprints.
-   Warning: At some places we still use 20 instead of this macro. */
-#define MAX_FINGERPRINT_LEN 20
+ * provide a static buffer and will be increased if we need to support
+ * longer fingerprints.  Warning: At some places we have some
+ * assumption on a 20 byte fingerprint.
+ * Watch out for FIXME(fingerprint) */
+#define MAX_FINGERPRINT_LEN 32
 
 /* The maximum length of a formatted fingerprint as returned by
  format_hexfingerprint().  */
-#define MAX_FORMATTED_FINGERPRINT_LEN 50
* format_hexfingerprint().  */
+#define MAX_FORMATTED_FINGERPRINT_LEN 59
 
 
 /*
index 2b42bfb..094bc76 100644 (file)
@@ -2283,9 +2283,11 @@ sk_esk (const char *option, int argc, char *argv[], void *cookie)
       DEK *sesdekp = &sesdek;
 
       /* Now encrypt the session key (or rather, the algorithm used to
-         encrypt the SED plus the session key) using ENCKEY.  */
-      ske->seskeylen = 1 + sesdek.keylen;
-      encrypt_seskey (&s2kdek, &sesdekp, ske->seskey);
+         encrypt the SKESK plus the session key) using ENCKEY.  */
+      err = encrypt_seskey (&s2kdek, 0, &sesdekp,
+                            (void**)&ske->seskey, (size_t *)&ske->seskeylen);
+      if (err)
+        log_fatal ("encrypt_seskey failed: %s\n", gpg_strerror (err));
 
       /* Save the session key for later.  */
       session_key = sesdek;
@@ -2573,7 +2575,7 @@ encrypted (const char *option, int argc, char *argv[], void *cookie)
 
   cfx->datalen = 0;
 
-  filter_push (out, cipher_filter, cfx, PKT_ENCRYPTED, cfx->datalen == 0);
+  filter_push (out, cipher_filter_cfb, cfx, PKT_ENCRYPTED, cfx->datalen == 0);
 
   debug ("Wrote encrypted packet:\n");
 
@@ -2746,7 +2748,7 @@ literal_name (const char *option, int argc, char *argv[], void *cookie)
 {
   struct litinfo *li = cookie;
 
-  if (argc <= 1)
+  if (argc <= 0)
     log_fatal ("Usage: %s NAME\n", option);
 
   if (strlen (argv[0]) > 255)
index 71e3955..ed679d5 100644 (file)
@@ -1113,6 +1113,24 @@ check_prefs (ctrl_t ctrl, kbnode_t keyblock)
                      problem=1;
                    }
                }
+             else if(prefs->type==PREFTYPE_AEAD)
+               {
+                 if (openpgp_aead_test_algo (prefs->value))
+                   {
+                      /* FIXME: The test below is wrong.  We should
+                       * check if ...algo_name yields a "?" and
+                       * only in that case use NUM.  */
+                     const char *algo =
+                        (openpgp_aead_test_algo (prefs->value)
+                         ? num
+                         : openpgp_aead_algo_name (prefs->value));
+                     if(!problem)
+                       check_prefs_warning(pk);
+                     log_info(_("         \"%s\": preference for AEAD"
+                                " algorithm %s\n"), user, algo);
+                     problem=1;
+                   }
+               }
              else if(prefs->type==PREFTYPE_HASH)
                {
                  if(openpgp_md_test_algo(prefs->value))
@@ -2255,6 +2273,7 @@ transfer_secret_keys (ctrl_t ctrl, struct import_stats_s *stats,
         {
           char countbuf[35];
 
+          /* FIXME: Support AEAD */
           /* Note that the IVLEN may be zero if we are working on a
              dummy key.  We can't express that in an S-expression and
              thus we send dummy data for the IV.  */
index c2aaacd..64def05 100644 (file)
@@ -415,13 +415,14 @@ dump_kbnode (KBNODE node)
         {
           PKT_public_key *pk = node->pkt->pkt.public_key;
 
-          log_printf ("  keyid=%08lX a=%d u=%d %c%c%c%c\n",
+          log_printf ("  keyid=%08lX a=%d u=%d %c%c%c%c%c\n",
                       (ulong)keyid_from_pk( pk, NULL ),
                       pk->pubkey_algo, pk->pubkey_usage,
                       pk->has_expired? 'e':'.',
                       pk->flags.revoked? 'r':'.',
                       pk->flags.valid?    'v':'.',
-                      pk->flags.mdc?   'm':'.');
+                      pk->flags.mdc?   'm':'.',
+                      pk->flags.aead?  'a':'.');
         }
       else
         log_printf ("\n");
index 7393768..f2ea8a7 100644 (file)
@@ -232,6 +232,7 @@ int  algo_available( preftype_t preftype, int algo,
 int  select_algo_from_prefs( PK_LIST pk_list, int preftype,
                             int request, const union pref_hint *hint);
 int  select_mdc_from_pklist (PK_LIST pk_list);
+aead_algo_t select_aead_from_pklist (pk_list_t pk_list);
 void warn_missing_mdc_from_pklist (PK_LIST pk_list);
 void warn_missing_aes_from_pklist (PK_LIST pk_list);
 
index 17cf7d6..2c33a29 100644 (file)
@@ -1142,7 +1142,7 @@ change_passphrase (ctrl_t ctrl, kbnode_t keyblock)
           if (err)
             log_log ((gpg_err_code (err) == GPG_ERR_CANCELED
                       || gpg_err_code (err) == GPG_ERR_FULLY_CANCELED)
-                     ? GPGRT_LOG_INFO : GPGRT_LOG_ERROR,
+                     ? GPGRT_LOGLVL_INFO : GPGRT_LOGLVL_ERROR,
                      _("key %s: error changing passphrase: %s\n"),
                        keystr_with_sub (keyid, subid),
                        gpg_strerror (err));
@@ -3064,6 +3064,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++)
        {
@@ -3118,7 +3135,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: "));
@@ -3128,6 +3145,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)
@@ -3166,12 +3189,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");
@@ -3317,6 +3343,8 @@ show_key_with_all_names_colon (ctrl_t ctrl, estream_t fp, kbnode_t keyblock)
                }
              if (uid->flags.mdc)
                es_fputs (",mdc", fp);
+             if (uid->flags.aead)
+               es_fputs (",aead", fp);
              if (!uid->flags.ks_modify)
                es_fputs (",no-ks-modify", fp);
            }
index 8de6538..cded87c 100644 (file)
 #include "../common/mbox-util.h"
 
 
-/* The default algorithms.  If you change them remember to change them
-   also in gpg.c:gpgconf_list.  You should also check that the value
+/* The default algorithms.  If you change them, you should ensure the value
    is inside the bounds enforced by ask_keysize and gen_xxx.  See also
    get_keysize_range which encodes the allowed ranges.  */
-#define DEFAULT_STD_KEY_PARAM  "rsa2048/cert,sign+rsa2048/encr"
+#define DEFAULT_STD_KEY_PARAM  "rsa3072/cert,sign+rsa3072/encr"
 #define FUTURE_STD_KEY_PARAM   "ed25519/cert,sign+cv25519/encr"
 
 /* When generating keys using the streamlined key generation dialog,
@@ -91,7 +90,7 @@ enum para_name {
   pHANDLE,
   pKEYSERVER,
   pKEYGRIP,
-  pSUBKEYGRIP,
+  pSUBKEYGRIP
 };
 
 struct para_data_s {
@@ -128,6 +127,9 @@ struct opaque_data_usage_and_pk {
 };
 
 
+/* FIXME: These globals vars are ugly.  And using MAX_PREFS even for
+ * aeads is useless, given that we don't expects more than a very few
+ * algorithms.  */
 static int prefs_initialized = 0;
 static byte sym_prefs[MAX_PREFS];
 static int nsym_prefs;
@@ -135,7 +137,11 @@ static byte hash_prefs[MAX_PREFS];
 static int nhash_prefs;
 static byte zip_prefs[MAX_PREFS];
 static int nzip_prefs;
-static int mdc_available,ks_modify;
+static byte aead_prefs[MAX_PREFS];
+static int naead_prefs;
+static int mdc_available;
+static int ks_modify;
+static int aead_available;
 
 static gpg_error_t parse_algo_usage_expire (ctrl_t ctrl, int for_subkey,
                                      const char *algostr, const char *usagestr,
@@ -327,6 +333,8 @@ set_one_pref (int val, int type, const char *item, byte *buf, int *nbuf)
          log_info(_("too many digest preferences\n"));
        else if(type==3)
          log_info(_("too many compression preferences\n"));
+       else if(type==4)
+         log_info(_("too many AEAD preferences\n"));
        else
          BUG();
 
@@ -347,10 +355,10 @@ set_one_pref (int val, int type, const char *item, byte *buf, int *nbuf)
 int
 keygen_set_std_prefs (const char *string,int personal)
 {
-    byte sym[MAX_PREFS], hash[MAX_PREFS], zip[MAX_PREFS];
-    int nsym=0, nhash=0, nzip=0, val, rc=0;
+    byte sym[MAX_PREFS], hash[MAX_PREFS], zip[MAX_PREFS], aead[MAX_PREFS];
+    int nsym=0, nhash=0, nzip=0, naead=0, val, rc=0;
     int mdc=1, modify=0; /* mdc defaults on, modify defaults off. */
-    char dummy_string[20*4+1]; /* Enough for 20 items. */
+    char dummy_string[25*4+1]; /* Enough for 25 items. */
 
     if (!string || !ascii_strcasecmp (string, "default"))
       {
@@ -384,6 +392,11 @@ keygen_set_std_prefs (const char *string,int personal)
              strcat(dummy_string,"S7 ");
            strcat(dummy_string,"S2 "); /* 3DES */
 
+            if (opt.flags.rfc4880bis && !openpgp_aead_test_algo (AEAD_ALGO_OCB))
+             strcat(dummy_string,"A2 ");
+            if (opt.flags.rfc4880bis && !openpgp_aead_test_algo (AEAD_ALGO_EAX))
+             strcat(dummy_string,"A1 ");
+
             if (personal)
               {
                 /* The default internal hash algo order is:
@@ -476,6 +489,11 @@ keygen_set_std_prefs (const char *string,int personal)
                if(set_one_pref(val,3,tok,zip,&nzip))
                  rc=-1;
              }
+           else if ((val=string_to_aead_algo (tok)))
+             {
+               if (set_one_pref (val, 4, tok, aead, &naead))
+                 rc = -1;
+             }
            else if (ascii_strcasecmp(tok,"mdc")==0)
              mdc=1;
            else if (ascii_strcasecmp(tok,"no-mdc")==0)
@@ -521,6 +539,29 @@ keygen_set_std_prefs (const char *string,int personal)
                    opt.personal_cipher_prefs[i].value = 0;
                  }
              }
+           else if (personal == PREFTYPE_AEAD)
+             {
+               xfree(opt.personal_aead_prefs);
+
+               if (!naead)
+                 opt.personal_aead_prefs = NULL;
+               else
+                 {
+                   int i;
+
+                   opt.personal_aead_prefs=
+                     xmalloc(sizeof(prefitem_t *)*(naead+1));
+
+                   for (i=0; i<naead; i++)
+                     {
+                       opt.personal_aead_prefs[i].type = PREFTYPE_AEAD;
+                       opt.personal_aead_prefs[i].value = sym[i];
+                     }
+
+                   opt.personal_aead_prefs[i].type = PREFTYPE_NONE;
+                   opt.personal_aead_prefs[i].value = 0;
+                 }
+             }
            else if(personal==PREFTYPE_HASH)
              {
                xfree(opt.personal_digest_prefs);
@@ -573,7 +614,9 @@ keygen_set_std_prefs (const char *string,int personal)
            memcpy (sym_prefs,  sym,  (nsym_prefs=nsym));
            memcpy (hash_prefs, hash, (nhash_prefs=nhash));
            memcpy (zip_prefs,  zip,  (nzip_prefs=nzip));
+           memcpy (aead_prefs, aead,  (naead_prefs=naead));
            mdc_available = mdc;
+            aead_available = !!naead;
            ks_modify = modify;
            prefs_initialized = 1;
          }
@@ -582,6 +625,7 @@ keygen_set_std_prefs (const char *string,int personal)
     return rc;
 }
 
+
 /* Return a fake user ID containing the preferences.  Caller must
    free. */
 PKT_user_id *
@@ -595,8 +639,8 @@ keygen_get_std_prefs(void)
 
   uid->ref=1;
 
-  uid->prefs=xmalloc((sizeof(prefitem_t *)*
-                     (nsym_prefs+nhash_prefs+nzip_prefs+1)));
+  uid->prefs = xmalloc ((sizeof(prefitem_t *)*
+                         (nsym_prefs+naead_prefs+nhash_prefs+nzip_prefs+1)));
 
   for(i=0;i<nsym_prefs;i++,j++)
     {
@@ -604,6 +648,12 @@ keygen_get_std_prefs(void)
       uid->prefs[j].value=sym_prefs[i];
     }
 
+  for (i=0; i < naead_prefs; i++, j++)
+    {
+      uid->prefs[j].type = PREFTYPE_AEAD;
+      uid->prefs[j].value = aead_prefs[i];
+    }
+
   for(i=0;i<nhash_prefs;i++,j++)
     {
       uid->prefs[j].type=PREFTYPE_HASH;
@@ -619,8 +669,9 @@ keygen_get_std_prefs(void)
   uid->prefs[j].type=PREFTYPE_NONE;
   uid->prefs[j].value=0;
 
-  uid->flags.mdc=mdc_available;
-  uid->flags.ks_modify=ks_modify;
+  uid->flags.mdc = mdc_available;
+  uid->flags.aead = aead_available;
+  uid->flags.ks_modify = ks_modify;
 
   return uid;
 }
@@ -666,6 +717,49 @@ add_feature_mdc (PKT_signature *sig,int enabled)
     xfree (buf);
 }
 
+
+static void
+add_feature_aead (PKT_signature *sig, int enabled)
+{
+  const byte *s;
+  size_t n;
+  int i;
+  char *buf;
+
+  s = parse_sig_subpkt (sig->hashed, SIGSUBPKT_FEATURES, &n );
+  if (s && n && ((enabled && (s[0] & 0x02)) || (!enabled && !(s[0] & 0x02))))
+    return; /* Already set or cleared */
+
+  if (!s || !n)
+    { /* Create a new one */
+      n = 1;
+      buf = xmalloc_clear (n);
+    }
+  else
+    {
+      buf = xmalloc (n);
+      memcpy (buf, s, n);
+    }
+
+  if (enabled)
+    buf[0] |= 0x02; /* AEAD supported */
+  else
+    buf[0] &= ~0x02;
+
+  /* Are there any bits set? */
+  for (i=0; i < n; i++)
+    if (buf[i])
+      break;
+
+  if (i == n)
+    delete_sig_subpkt (sig->hashed, SIGSUBPKT_FEATURES);
+  else
+    build_sig_subpkt (sig, SIGSUBPKT_FEATURES, buf, n);
+
+  xfree (buf);
+}
+
+
 static void
 add_keyserver_modify (PKT_signature *sig,int enabled)
 {
@@ -727,6 +821,14 @@ keygen_upd_std_prefs (PKT_signature *sig, void *opaque)
       delete_sig_subpkt (sig->unhashed, SIGSUBPKT_PREF_SYM);
     }
 
+  if (naead_prefs)
+    build_sig_subpkt (sig, SIGSUBPKT_PREF_AEAD, aead_prefs, naead_prefs);
+  else
+    {
+      delete_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_AEAD);
+      delete_sig_subpkt (sig->unhashed, SIGSUBPKT_PREF_AEAD);
+    }
+
   if (nhash_prefs)
     build_sig_subpkt (sig, SIGSUBPKT_PREF_HASH, hash_prefs, nhash_prefs);
   else
@@ -745,6 +847,7 @@ keygen_upd_std_prefs (PKT_signature *sig, void *opaque)
 
   /* Make sure that the MDC feature flag is set if needed.  */
   add_feature_mdc (sig,mdc_available);
+  add_feature_aead (sig, aead_available);
   add_keyserver_modify (sig,ks_modify);
   keygen_add_keyserver_url(sig,NULL);
 
@@ -1648,7 +1751,7 @@ gen_rsa (int algo, unsigned int nbits, KBNODE pub_root,
 
   if (nbits < 1024)
     {
-      nbits = 2048;
+      nbits = 3072;
       log_info (_("keysize invalid; using %u bits\n"), nbits );
     }
   else if (nbits > maxsize)
@@ -2117,7 +2220,7 @@ get_keysize_range (int algo, unsigned int *min, unsigned int *max)
     default:
       *min = opt.compliance == CO_DE_VS ? 2048: 1024;
       *max = 4096;
-      def = 2048;
+      def = 3072;
       break;
     }
 
index ba35ec2..a9034ee 100644 (file)
@@ -73,7 +73,7 @@ pubkey_letter( int algo )
    is copied to the supplied buffer up a length of BUFSIZE-1.
    Examples for the output are:
 
-   "rsa2048"  - RSA with 2048 bit
+   "rsa3072"  - RSA with 3072 bit
    "elg1024"  - Elgamal with 1024 bit
    "ed25519"  - ECC using the curve Ed25519.
    "E_1.2.3.4"  - ECC using the unsupported curve with OID "1.2.3.4".
@@ -83,7 +83,7 @@ pubkey_letter( int algo )
    If the option --legacy-list-mode is active, the output use the
    legacy format:
 
-   "2048R" - RSA with 2048 bit
+   "3072R" - RSA with 3072 bit
    "1024g" - Elgamal with 1024 bit
    "256E"  - ECDSA using a curve with 256 bit
 
@@ -839,8 +839,22 @@ format_hexfingerprint (const char *fingerprint, char *buffer, size_t buflen)
               /* Half way through we add a second space.  */
               + 1);
     }
+  else if (hexlen == 64 || hexlen == 50)  /* v5 fingerprint */
+    {
+      /* The v5 fingerprint is commonly printed truncated to 25
+       * octets.  We accept the truncated as well as the full hex
+       * version here and format it like this:
+       * B2CCB6 838332 5D61BA C50F9F 5E CD21A8 0AC8C5 2565C8 C52565
+       */
+      hexlen = 50;
+      space = 8 * 6 + 2 + 8 + 1;
+    }
   else  /* Other fingerprint versions - print as is.  */
     {
+      /* We truncated here so that we do not need to provide a buffer
+       * of a length which is in reality never used.  */
+      if (hexlen > MAX_FORMATTED_FINGERPRINT_LEN - 1)
+        hexlen = MAX_FORMATTED_FINGERPRINT_LEN - 1;
       space = hexlen + 1;
     }
 
@@ -853,7 +867,7 @@ format_hexfingerprint (const char *fingerprint, char *buffer, size_t buflen)
     {
       for (i = 0, j = 0; i < 40; i ++)
         {
-          if (i && i % 4 == 0)
+          if (i && !(i % 4))
             buffer[j ++] = ' ';
           if (i == 40 / 2)
             buffer[j ++] = ' ';
@@ -863,9 +877,29 @@ format_hexfingerprint (const char *fingerprint, char *buffer, size_t buflen)
       buffer[j ++] = 0;
       log_assert (j == space);
     }
+  else if (hexlen == 50)  /* v5 fingerprint */
+    {
+      for (i=j=0; i < 24; i++)
+        {
+          if (i && !(i % 6))
+            buffer[j++] = ' ';
+          buffer[j++] = fingerprint[i];
+        }
+      buffer[j++] = ' ';
+      buffer[j++] = fingerprint[i++];
+      buffer[j++] = fingerprint[i++];
+      for (; i < 50; i++)
+        {
+          if (!((i-26) % 6))
+            buffer[j++] = ' ';
+          buffer[j++] = fingerprint[i];
+        }
+      buffer[j++] = 0;
+      log_assert (j == space);
+    }
   else
     {
-      strcpy (buffer, fingerprint);
+      mem2str (buffer, fingerprint, space);
     }
 
   return buffer;
@@ -948,7 +982,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);
@@ -963,18 +997,18 @@ gpg_error_t
 hexkeygrip_from_pk (PKT_public_key *pk, char **r_grip)
 {
   gpg_error_t err;
-  unsigned char grip[20];
+  unsigned char grip[KEYGRIP_LEN];
 
   *r_grip = NULL;
   err = keygrip_from_pk (pk, grip);
   if (!err)
     {
-      char * buf = xtrymalloc (20*2+1);
+      char * buf = xtrymalloc (KEYGRIP_LEN * 2 + 1);
       if (!buf)
         err = gpg_error_from_syserror ();
       else
         {
-          bin2hex (grip, 20, buf);
+          bin2hex (grip, KEYGRIP_LEN, buf);
           *r_grip = buf;
         }
     }
index 86d1c56..bcbad45 100644 (file)
@@ -45,6 +45,7 @@
 #include "../common/zb32.h"
 #include "tofu.h"
 #include "../common/compliance.h"
+#include "../common/pkscreening.h"
 
 
 static void list_all (ctrl_t, int, int);
@@ -696,6 +697,37 @@ print_key_data (PKT_public_key * pk)
     }
 }
 
+
+/* Various public key screenings.  (Right now just ROCA).  With
+ * COLON_MODE set the output is formatted for use in the compliance
+ * field of a colon listing.
+ */
+static void
+print_pk_screening (PKT_public_key *pk, int colon_mode)
+{
+  gpg_error_t err;
+
+  if (is_RSA (pk->pubkey_algo) && pubkey_get_npkey (pk->pubkey_algo))
+    {
+      err = screen_key_for_roca (pk->pkey[0]);
+      if (!err)
+        ;
+      else if (gpg_err_code (err) == GPG_ERR_TRUE)
+        {
+          if (colon_mode)
+            es_fprintf (es_stdout, colon_mode > 1? " %d":"%d", 6001);
+          else
+            es_fprintf (es_stdout,
+                        "      Screening: ROCA vulnerability detected\n");
+        }
+      else if (!colon_mode)
+        es_fprintf (es_stdout, "      Screening: [ROCA check failed: %s]\n",
+                    gpg_strerror (err));
+    }
+
+}
+
+
 static void
 print_capabilities (ctrl_t ctrl, PKT_public_key *pk, KBNODE keyblock)
 {
@@ -922,6 +954,9 @@ list_keyblock_print (ctrl_t ctrl, kbnode_t keyblock, int secret, int fpr,
   if (opt.with_key_data)
     print_key_data (pk);
 
+  if (opt.with_key_screening)
+    print_pk_screening (pk, 0);
+
   if (opt.with_key_origin
       && (pk->keyorg || pk->keyupdate || pk->updateurl))
     {
@@ -1063,6 +1098,8 @@ list_keyblock_print (ctrl_t ctrl, kbnode_t keyblock, int secret, int fpr,
             es_fprintf (es_stdout, "      Keygrip = %s\n", hexgrip);
          if (opt.with_key_data)
            print_key_data (pk2);
+          if (opt.with_key_screening)
+            print_pk_screening (pk2, 0);
        }
       else if (opt.list_sigs
               && node->pkt->pkttype == PKT_SIGNATURE && !skip_sigs)
@@ -1227,6 +1264,9 @@ print_compliance_flags (PKT_public_key *pk,
                  gnupg_status_compliance_flag (CO_DE_VS));
       any++;
     }
+
+  if (opt.with_key_screening)
+    print_pk_screening (pk, 1+any);
 }
 
 
@@ -1906,6 +1946,9 @@ print_card_serialno (const char *serialno)
  * pub   dsa2048 2007-12-31 [SC] [expires: 2018-12-31]
  *       80615870F5BAD690333686D0F2AD85AC1E42B367
  *
+ * pub   rsa2048 2017-12-31 [SC] [expires: 2028-12-31]
+ *       80615870F5BAD690333686D0F2AD85AC1E42B3671122334455
+ *
  * Some global options may result in a different output format.  If
  * SECRET is set, "sec" or "ssb" is used instead of "pub" or "sub" and
  * depending on the value a flag character is shown:
index 6c15a2a..de8639e 100644 (file)
@@ -31,7 +31,9 @@
    (i.e. uncompressed) rather than 1 (zip).  However, the real world
    issues of speed and size come into play here. */
 
-#if GPG_USE_AES128
+#if GPG_USE_AES256
+# define DEFAULT_CIPHER_ALGO     CIPHER_ALGO_AES256
+#elif GPG_USE_AES128
 # define DEFAULT_CIPHER_ALGO     CIPHER_ALGO_AES
 #elif GPG_USE_CAST5
 # define DEFAULT_CIPHER_ALGO     CIPHER_ALGO_CAST5
 # define DEFAULT_CIPHER_ALGO     CIPHER_ALGO_3DES
 #endif
 
+#if GCRYPT_VERSION_NUMBER < 0x019000
+# define DEFAULT_AEAD_ALGO  AEAD_ALGO_OCB
+#else
+# define DEFAULT_AEAD_ALGO  AEAD_ALGO_EAX
+#endif
+
 #define DEFAULT_DIGEST_ALGO     ((GNUPG)? DIGEST_ALGO_SHA256:DIGEST_ALGO_SHA1)
 #define DEFAULT_S2K_DIGEST_ALGO DIGEST_ALGO_SHA1
 #ifdef HAVE_ZIP
@@ -121,6 +129,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);
@@ -149,12 +163,14 @@ void obsolete_scdaemon_option (const char *configname,
                                unsigned int configlineno, const char *name);
 
 int string_to_cipher_algo (const char *string);
+aead_algo_t string_to_aead_algo (const char *string);
 int string_to_digest_algo (const char *string);
 
 const char *compress_algo_to_string(int algo);
 int string_to_compress_algo(const char *string);
 int check_compress_algo(int algo);
 int default_cipher_algo(void);
+aead_algo_t default_aead_algo(void);
 int default_compress_algo(void);
 void compliance_failure(void);
 
@@ -223,7 +239,9 @@ void display_online_help( const char *keyword );
 
 /*-- encode.c --*/
 int setup_symkey (STRING2KEY **symkey_s2k,DEK **symkey_dek);
-void encrypt_seskey (DEK *dek, DEK **seskey, byte *enckey);
+gpg_error_t encrypt_seskey (DEK *dek, aead_algo_t aead_algo, DEK **r_seskey,
+                            void **r_enckey, size_t *r_enckeylen);
+aead_algo_t use_aead (pk_list_t pk_list, int algo);
 int use_mdc (pk_list_t pk_list,int algo);
 int encrypt_symmetric (const char *filename );
 int encrypt_store (const char *filename );
@@ -323,7 +341,7 @@ gpg_error_t generate_card_subkeypair (ctrl_t ctrl, kbnode_t pub_keyblock,
 int overwrite_filep( const char *fname );
 char *make_outfile_name( const char *iname );
 char *ask_outfile_name( const char *name, size_t namelen );
-int open_outfile (int inp_fd, const char *iname, int mode,
+int open_outfile (int out_fd, const char *iname, int mode,
                   int restrictedperm, iobuf_t *a);
 char *get_matching_datafile (const char *sigfilename);
 iobuf_t open_sigfile (const char *sigfilename, progress_filter_context_t *pfx);
index 512d33c..f2a28df 100644 (file)
@@ -245,46 +245,101 @@ 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;
+  unsigned int noncelen, keylen;
+  enum gcry_cipher_modes ciphermode;
+
+  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;
+    }
 
-  if(slen < 17 || slen > 33)
+  /* 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 );
+  err = openpgp_cipher_open (&hd, dek->algo, ciphermode, GCRY_CIPHER_SECURE);
+  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;
 
-  /* Now we replace the dek components with the real session key to
-     decrypt the contents of the sequencing packet. */
-
-  dek->keylen=slen-1;
-  dek->algo=seskey[0];
-
-  if(dek->keylen > DIM(dek->key))
-    BUG ();
-
-  memcpy(dek->key, seskey + 1, dek->keylen);
+  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 );
+      /* 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 = keylen;
+      memcpy (dek->key, seskey + 1, dek->keylen);
+    }
 
   /*log_hexdump( "thekey", dek->key, dek->keylen );*/
 
-  return 0;
+ leave:
+  gcry_cipher_close (hd);
+  return err;
 }
 
 
 static void
 proc_symkey_enc (CTX c, PACKET *pkt)
 {
+  gpg_error_t err;
   PKT_symkey_enc *enc;
 
   enc = pkt->pkt.symkey_enc;
@@ -294,19 +349,21 @@ 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)
             {
               if (enc->seskeylen)
-                log_info (_("%s encrypted session key\n"), s );
+                log_info (_("%s.%s encrypted session key\n"), s, a );
               else
-                log_info (_("%s encrypted data\n"), s );
+                log_info (_("%s.%s encrypted data\n"), s, a );
             }
         }
       else
-        log_error (_("encrypted with unknown algorithm %d\n"), algo);
+        log_error (_("encrypted with unknown algorithm %d.%s\n"), algo, a);
 
       if (openpgp_md_test_algo (enc->s2k.hash_algo))
         {
@@ -334,6 +391,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
@@ -344,9 +402,24 @@ 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"
+                                   " with GnuPG <= 2.2\n");
+                      if (c->dek->s2k_cacheid[0])
+                        {
+                          if (opt.debug)
+                            log_debug ("cleared passphrase cached with ID:"
+                                       " %s\n", c->dek->s2k_cacheid);
+                          passphrase_clear_cache (c->dek->s2k_cacheid);
+                        }
                       xfree (c->dek);
                       c->dek = NULL;
                     }
@@ -650,6 +723,7 @@ proc_encrypted (CTX c, PACKET *pkt)
   else if (!result
            && !opt.ignore_mdc_error
            && !pkt->pkt.encrypted->mdc_method
+           && !pkt->pkt.encrypted->aead_algo
            && openpgp_cipher_get_algo_blklen (c->dek->algo) != 8
            && c->dek->algo != CIPHER_ALGO_TWOFISH)
     {
@@ -664,17 +738,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 if (!opt.no_mdc_warn)
         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"));
@@ -684,6 +766,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')
         {
@@ -1393,7 +1476,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;
            }
@@ -1409,6 +1493,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;
@@ -1436,7 +1521,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;
@@ -1463,7 +1549,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;
index 77c8f26..8c54793 100644 (file)
 #include "../common/zb32.h"
 
 
+/* FIXME: Libgcrypt 1.9 will support EAX.  Until we kame 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
    secured. */
@@ -396,7 +401,7 @@ print_further_info (const char *format, ...)
 
   log_info (_("(further info: "));
   va_start (arg_ptr, format);
-  log_logv (GPGRT_LOG_CONT, format, arg_ptr);
+  log_logv (GPGRT_LOGLVL_CONT, format, arg_ptr);
   va_end (arg_ptr);
   log_printf (")\n");
 }
@@ -582,6 +587,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)
@@ -1112,6 +1191,39 @@ string_to_cipher_algo (const char *string)
   return val;
 }
 
+
+/*
+ * Map an AEAD mode string to a an AEAD algorithm number as defined by
+ * rrc4880bis.  Also support the "An" syntax as used by the preference
+ * strings.
+ */
+aead_algo_t
+string_to_aead_algo (const char *string)
+{
+  int result;
+
+  if (!string)
+    result = 0;
+  if (!ascii_strcasecmp (string, "EAX"))
+    result = 1;
+  else if (!ascii_strcasecmp (string, "OCB"))
+    result = 2;
+  else if ((string[0]=='A' || string[0]=='a'))
+    {
+      char *endptr;
+
+      string++;
+      result = strtol (string, &endptr, 10);
+      if (!*string || *endptr || result < 1 || result > 2)
+        result = 0;
+    }
+  else
+    result = 0;
+
+  return result;
+}
+
+
 /*
  * Wrapper around gcry_md_map_name to provide a fallback using the
  * "Hn" syntax as used by the preference strings.
@@ -1228,6 +1340,18 @@ default_cipher_algo(void)
     return opt.s2k_cipher_algo;
 }
 
+
+aead_algo_t
+default_aead_algo(void)
+{
+  if(opt.def_aead_algo)
+    return opt.def_aead_algo;
+  else if(opt.personal_aead_prefs)
+    return opt.personal_aead_prefs[0].value;
+  else
+    return DEFAULT_AEAD_ALGO;
+}
+
 /* There is no default_digest_algo function, but see
    sign.c:hash_for() */
 
index 78f4dbb..f4730da 100644 (file)
@@ -171,32 +171,34 @@ ask_outfile_name( const char *name, size_t namelen )
  *     2 = use ".sig"
  *      3 = use ".rev"
  *
- * If INP_FD is not -1 the function simply creates an IOBUF for that
- * file descriptor and ignore INAME and MODE.  Note that INP_FD won't
- * be closed if the returned IOBUF is closed.  With RESTRICTEDPERM a
- * file will be created with mode 700 if possible.
- */
+ * With RESTRICTEDPERM a file will be created with mode 700 if
+ * possible.
+ *
+ * If OUT_FD is not -1 the function simply creates an IOBUF for that
+ * file descriptor and ignores INAME and MODE.  Note that OUT_FD won't
+ * be closed if the returned IOBUF is closed.  This is used for gpg's
+ * --server mode.  */
 int
-open_outfile (int inp_fd, const char *iname, int mode, int restrictedperm,
+open_outfile (int out_fd, const char *iname, int mode, int restrictedperm,
               iobuf_t *a)
 {
   int rc = 0;
 
   *a = NULL;
-  if (inp_fd != -1)
+  if (out_fd != -1)
     {
       char xname[64];
 
-      *a = iobuf_fdopen_nc (inp_fd, "wb");
+      *a = iobuf_fdopen_nc (out_fd, "wb");
       if (!*a)
         {
           rc = gpg_error_from_syserror ();
-          snprintf (xname, sizeof xname, "[fd %d]", inp_fd);
+          snprintf (xname, sizeof xname, "[fd %d]", out_fd);
           log_error (_("can't open '%s': %s\n"), xname, gpg_strerror (rc));
         }
       else if (opt.verbose)
         {
-          snprintf (xname, sizeof xname, "[fd %d]", inp_fd);
+          snprintf (xname, sizeof xname, "[fd %d]", out_fd);
           log_info (_("writing to '%s'\n"), xname);
         }
     }
index 130bec8..471aee7 100644 (file)
@@ -62,6 +62,9 @@ struct
    * progress info and to decide on how to allocate buffers.  */
   uint64_t input_size_hint;
 
+  /* The AEAD chunk size expressed as a power of 2.  */
+  int chunk_size;
+
   int dry_run;
   int autostart;
   int list_only;
@@ -82,6 +85,7 @@ struct
   int with_fingerprint; /* Option --with-fingerprint active.  */
   int with_subkey_fingerprint; /* Option --with-subkey-fingerprint active.  */
   int with_keygrip;     /* Option --with-keygrip active.  */
+  int with_key_screening;/* Option --with-key-screening active.  */
   int with_tofu_info;   /* Option --with-tofu_info active.  */
   int with_secret;      /* Option --with-secret active.  */
   int with_wkd_hash;    /* Option --with-wkd-hash.  */
@@ -91,8 +95,10 @@ struct
   int no_armor;
   int list_packets; /* Option --list-packets active.  */
   int def_cipher_algo;
+  int def_aead_algo;
   int force_mdc;
   int disable_mdc;
+  int force_aead;
   int def_digest_algo;
   int cert_digest_algo;
   int compress_algo;
@@ -176,6 +182,7 @@ struct
   const char *def_preference_list;
   const char *def_keyserver_url;
   prefitem_t *personal_cipher_prefs;
+  prefitem_t *personal_aead_prefs;
   prefitem_t *personal_digest_prefs;
   prefitem_t *personal_compress_prefs;
   struct weakhash *weak_digests;
@@ -315,7 +322,6 @@ struct {
 #define DBG_TRUST  (opt.debug & DBG_TRUST_VALUE)
 #define DBG_HASHING (opt.debug & DBG_HASHING_VALUE)
 #define DBG_IPC     (opt.debug & DBG_IPC_VALUE)
-#define DBG_IPC     (opt.debug & DBG_IPC_VALUE)
 #define DBG_CLOCK   (opt.debug & DBG_CLOCK_VALUE)
 #define DBG_LOOKUP  (opt.debug & DBG_LOOKUP_VALUE)
 #define DBG_EXTPROG (opt.debug & DBG_EXTPROG_VALUE)
index 8dca88b..4f4569f 100644 (file)
@@ -72,7 +72,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 {
@@ -93,12 +94,14 @@ typedef struct
 /* A symmetric-key encrypted session key packet as defined in RFC
    4880, Section 5.3.  All fields are serialized.  */
 typedef struct {
-  /* RFC 4880: this must be 4.  */
+  /* We support version 4 (rfc4880) and 5 (rfc4880bis).  */
   byte version;
-  /* The cipher algorithm used to encrypt the session key.  (This may
-     be different from the algorithm that is used to encrypt the SED
-     packet.)  */
+  /* The cipher algorithm used to encrypt the session key.  Note that
+   * this may be different from the algorithm that is used to encrypt
+   * bulk data.  */
   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
@@ -106,7 +109,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;
 
@@ -290,6 +294,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 */
@@ -386,6 +391,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.  */
@@ -456,12 +462,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.  */
@@ -471,8 +478,17 @@ typedef struct {
      Note: this is ignored when encrypting.  */
   byte is_partial;
   /* If 0, MDC is disabled.  Otherwise, the MDC method that was used
-     (currently, only DIGEST_ALGO_SHA1 is supported).  */
+     (only DIGEST_ALGO_SHA1 has ever been defined).  */
   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 eee14f6..e3ff432 100644 (file)
@@ -1,7 +1,6 @@
 /* parse-packet.c  - read packets
- * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
- *               2007, 2009, 2010 Free Software Foundation, Inc.
- * Copyright (C) 2014 Werner Koch
+ * Copyright (C) 1998-2007, 2009-2010 Free Software Foundation, Inc.
+ * Copyright (C) 2014, 2018 Werner Koch
  * Copyright (C) 2015 g10 Code GmbH
  *
  * This file is part of GnuPG.
@@ -18,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+
  */
 
 #include <config.h>
@@ -82,6 +82,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,
@@ -636,6 +639,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.  */
@@ -823,6 +827,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;
@@ -1098,19 +1105,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)
@@ -1128,6 +1133,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);
@@ -1162,6 +1176,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)
@@ -1192,10 +1207,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 seize 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)
        {
@@ -1212,6 +1237,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;
 }
 
 
@@ -1392,6 +1424,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)
@@ -1554,6 +1591,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:
@@ -1636,6 +1674,7 @@ can_handle_critical (const byte * buffer, size_t n, int type)
     case SIGSUBPKT_ISSUER:     /* issuer key ID */
     case SIGSUBPKT_ISSUER_FPR: /* issuer fingerprint */
     case SIGSUBPKT_PREF_SYM:
+    case SIGSUBPKT_PREF_AEAD:
     case SIGSUBPKT_PREF_HASH:
     case SIGSUBPKT_PREF_COMPR:
     case SIGSUBPKT_KEY_FLAGS:
@@ -3161,6 +3200,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.  */
@@ -3252,6 +3294,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 581cae4..6ec5537 100644 (file)
@@ -1468,9 +1468,12 @@ select_algo_from_prefs(PK_LIST pk_list, int preftype,
             support.  All this doesn't mean IDEA is actually
             available, of course. */
           implicit=CIPHER_ALGO_3DES;
-
          break;
 
+       case PREFTYPE_AEAD:
+          /* No implicit algo.  */
+          break;
+
        case PREFTYPE_HASH:
          /* While I am including this code for completeness, note
             that currently --pgp2 mode locks the hash at MD5, so this
@@ -1553,6 +1556,8 @@ select_algo_from_prefs(PK_LIST pk_list, int preftype,
       prefs=NULL;
       if(preftype==PREFTYPE_SYM && opt.personal_cipher_prefs)
        prefs=opt.personal_cipher_prefs;
+      else if(preftype==PREFTYPE_AEAD && opt.personal_aead_prefs)
+       prefs=opt.personal_aead_prefs;
       else if(preftype==PREFTYPE_HASH && opt.personal_digest_prefs)
        prefs=opt.personal_digest_prefs;
       else if(preftype==PREFTYPE_ZIP && opt.personal_compress_prefs)
@@ -1646,6 +1651,32 @@ select_mdc_from_pklist (PK_LIST pk_list)
 }
 
 
+/* Select the AEAD flag from the pk_list.  We can only use AEAD if all
+ * recipients support this feature.  Returns the AEAD to be used or 0
+ * if AEAD shall not be used.  */
+aead_algo_t
+select_aead_from_pklist (PK_LIST pk_list)
+{
+  pk_list_t pkr;
+  int aead;
+
+  if (!pk_list)
+    return 0;
+
+  for (pkr = pk_list; pkr; pkr = pkr->next)
+    {
+      if (pkr->pk->user_id) /* selected by user ID */
+        aead = pkr->pk->user_id->flags.aead;
+      else
+        aead = pkr->pk->flags.aead;
+      if (!aead)
+        return 0;  /* At least one recipient does not support it. */
+    }
+
+  return default_aead_algo (); /* Yes, AEAD can be used. */
+}
+
+
 /* Print a warning for all keys in PK_LIST missing the MDC feature. */
 void
 warn_missing_mdc_from_pklist (PK_LIST pk_list)
index d7ba953..0185097 100644 (file)
@@ -255,7 +255,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)
@@ -361,7 +361,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 23af12b..f8e366b 100644 (file)
@@ -233,7 +233,7 @@ check_signature2 (ctrl_t ctrl,
        unsigned char *p, *buffer;
         size_t n, nbytes;
         int i;
-        char hashbuf[20];
+        char hashbuf[20];  /* We use SHA-1 here.  */
 
         nbytes = 6;
        for (i=0; i < nsig; i++ )
@@ -510,7 +510,11 @@ check_signature_end_simple (PKT_public_key *pk, PKT_signature *sig,
         return GPG_ERR_GENERAL;
 
     /* Verify the signature.  */
+    if (DBG_CLOCK && sig->sig_class <= 0x01)
+      log_clock ("enter pk_verify");
     rc = pk_verify( pk->pubkey_algo, result, sig->data, pk->pkey );
+    if (DBG_CLOCK && sig->sig_class <= 0x01)
+      log_clock ("leave pk_verify");
     gcry_mpi_release (result);
 
     if( !rc && sig->flags.unknown_critical )
index 4cf0cd3..df71ccc 100644 (file)
@@ -1326,9 +1326,6 @@ sign_symencrypt_file (ctrl_t ctrl, const char *fname, strlist_t locusr)
     s2k->hash_algo = S2K_DIGEST_ALGO;
 
     algo = default_cipher_algo();
-    if (!opt.quiet || !opt.batch)
-        log_info (_("%s encryption will be used\n"),
-                  openpgp_cipher_algo_name (algo) );
     cfx.dek = passphrase_to_dek (algo, s2k, 1, 1, NULL, &canceled);
 
     if (!cfx.dek || !cfx.dek->keylen) {
@@ -1337,7 +1334,15 @@ sign_symencrypt_file (ctrl_t ctrl, const char *fname, strlist_t locusr)
         goto leave;
     }
 
-    cfx.dek->use_mdc = use_mdc (NULL, cfx.dek->algo);
+    cfx.dek->use_aead = use_aead (NULL, cfx.dek->algo);
+    if (!cfx.dek->use_aead)
+      cfx.dek->use_mdc = !!use_mdc (NULL, cfx.dek->algo);
+
+    if (!opt.quiet || !opt.batch)
+        log_info (_("%s.%s encryption will be used\n"),
+                  openpgp_cipher_algo_name (algo),
+                  cfx.dek->use_aead? openpgp_aead_algo_name (cfx.dek->use_aead)
+                  /**/             : "CFB");
 
     /* now create the outfile */
     rc = open_outfile (-1, fname, opt.armor? 1:0, 0, &out);
@@ -1376,12 +1381,15 @@ sign_symencrypt_file (ctrl_t ctrl, const char *fname, strlist_t locusr)
     }
 
     /* Push the encryption filter */
-    iobuf_push_filter( out, cipher_filter, &cfx );
+    iobuf_push_filter (out,
+                       cfx.dek->use_aead? cipher_filter_aead
+                       /**/             : cipher_filter_cfb,
+                       &cfx);
 
     /* Push the compress filter */
     if (default_compress_algo())
       {
-        if (cfx.dek && cfx.dek->use_mdc)
+        if (cfx.dek && (cfx.dek->use_mdc || cfx.dek->use_aead))
           zfx.new_ctb = 1;
         push_compress_filter (out, &zfx,default_compress_algo() );
       }
index 5ea903f..37bf78b 100644 (file)
@@ -129,7 +129,7 @@ import_ownertrust (ctrl_t ctrl, const char *fname )
     char *p;
     size_t n, fprlen;
     unsigned int otrust;
-    byte fpr[20];
+    byte fpr[MAX_FINGERPRINT_LEN];
     int any = 0;
     int rc;
 
@@ -171,7 +171,7 @@ import_ownertrust (ctrl_t ctrl, const char *fname )
            continue;
        }
        fprlen&nb