gpg: In search-keys return "Not found" instead of "No Data".
[gnupg.git] / g10 / parse-packet.c
index eee14f6..21a26c7 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>
 #define MAX_COMMENT_PACKET_LENGTH ( 64 * 1024)
 #define MAX_ATTR_PACKET_LENGTH    ( 16 * 1024*1024)
 
-
 static int mpi_print_mode;
 static int list_mode;
 static estream_t listfp;
 
+/* A linked list of known notation names.  Note that the FLAG is used
+ * to store the length of the name to speed up the check.  */
+static strlist_t known_notations_list;
+
+
 static int parse (parse_packet_ctx_t ctx, PACKET *pkt, int onlykeypkts,
                  off_t * retpos, int *skip, IOBUF out, int do_skip
 #if DEBUG_PARSE_PACKET
@@ -82,6 +86,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,
@@ -186,6 +193,36 @@ mpi_read (iobuf_t inp, unsigned int *ret_nread, int secure)
 }
 
 
+/* Register STRING as a known critical notation name.  */
+void
+register_known_notation (const char *string)
+{
+  strlist_t sl;
+
+  if (!known_notations_list)
+    {
+      sl = add_to_strlist (&known_notations_list,
+                           "preferred-email-encoding@pgp.com");
+      sl->flags = 32;
+      sl = add_to_strlist (&known_notations_list, "pka-address@gnupg.org");
+      sl->flags = 21;
+    }
+  if (!string)
+    return; /* Only initialized the default known notations.  */
+
+  /* In --set-notation we use an exclamation mark to indicate a
+   * critical notation.  As a convenience skip this here.  */
+  if (*string == '!')
+    string++;
+
+  if (!*string || strlist_find (known_notations_list, string))
+    return; /* Empty string or already registered.  */
+
+  sl = add_to_strlist (&known_notations_list, string);
+  sl->flags = strlen (string);
+}
+
+
 int
 set_packet_list_mode (int mode)
 {
@@ -636,6 +673,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 +861,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;
@@ -964,10 +1005,10 @@ skip_packet (IOBUF inp, int pkttype, unsigned long pktlen, int partial)
 }
 
 
-/* Read PKTLEN bytes form INP and return them in a newly allocated
  buffer.  In case of an error (including reading fewer than PKTLEN
  bytes from INP before EOF is returned), NULL is returned and an
  error message is logged.  */
+/* Read PKTLEN bytes from INP and return them in a newly allocated
* buffer.  In case of an error (including reading fewer than PKTLEN
* bytes from INP before EOF is returned), NULL is returned and an
* error message is logged.  */
 static void *
 read_rest (IOBUF inp, size_t pktlen)
 {
@@ -1098,19 +1139,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 +1167,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 +1210,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)
@@ -1171,7 +1220,7 @@ parse_symkeyenc (IOBUF inp, int pkttype, unsigned long pktlen,
     }
   if (s2kmode == 3)
     {
-      k->s2k.count = iobuf_get (inp);
+      k->s2k.count = iobuf_get_noeof (inp);
       pktlen--;
     }
   k->seskeylen = seskeylen;
@@ -1192,10 +1241,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 +1271,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 +1458,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 +1625,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:
@@ -1602,14 +1674,24 @@ parse_one_sig_subpkt (const byte * buffer, size_t n, int type)
 
 /* Return true if we understand the critical notation.  */
 static int
-can_handle_critical_notation (const byte * name, size_t len)
+can_handle_critical_notation (const byte *name, size_t len)
 {
-  if (len == 32 && memcmp (name, "preferred-email-encoding@pgp.com", 32) == 0)
-    return 1;
-  if (len == 21 && memcmp (name, "pka-address@gnupg.org", 21) == 0)
-    return 1;
+  strlist_t sl;
 
-  return 0;
+  register_known_notation (NULL); /* Make sure it is initialized.  */
+
+  for (sl = known_notations_list; sl; sl = sl->next)
+    if (sl->flags == len && !memcmp (sl->d, name, len))
+      return 1; /* Known */
+
+  if (opt.verbose)
+    {
+      log_info(_("Unknown critical signature notation: ") );
+      print_utf8_buffer (log_get_stream(), name, len);
+      log_printf ("\n");
+    }
+
+  return 0; /* Unknown.  */
 }
 
 
@@ -1636,6 +1718,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:
@@ -1702,6 +1785,8 @@ enum_sig_subpkt (const subpktarea_t * pktbuf, sigsubpkttype_t reqtype,
        }
       if (buflen < n)
        goto too_short;
+      if (!buflen)
+        goto no_type_byte;
       type = *buffer;
       if (type & 0x80)
        {
@@ -1776,6 +1861,13 @@ enum_sig_subpkt (const subpktarea_t * pktbuf, sigsubpkttype_t reqtype,
   if (start)
     *start = -1;
   return NULL;
+
+ no_type_byte:
+  if (opt.verbose)
+    log_info ("type octet missing in subpacket\n");
+  if (start)
+    *start = -1;
+  return NULL;
 }
 
 
@@ -1813,21 +1905,23 @@ parse_revkeys (PKT_signature * sig)
   while ((revkey = enum_sig_subpkt (sig->hashed, SIGSUBPKT_REV_KEY,
                                    &len, &seq, NULL)))
     {
-      if (/* The only valid length is 22 bytes.  See RFC 4880
-            5.2.3.15.  */
-         len == 22
-         /* 0x80 bit must be set on the class.  */
+      /* Consider only valid packets.  They must have a length of
+       * either 2+20 or 2+32 octets and bit 7 of the class octet must
+       * be set.  */
+      if ((len == 22 || len == 34)
           && (revkey[0] & 0x80))
        {
          sig->revkey = xrealloc (sig->revkey,
                                  sizeof (struct revocation_key) *
                                  (sig->numrevkeys + 1));
 
-         /* Copy the individual fields.  */
          sig->revkey[sig->numrevkeys].class = revkey[0];
          sig->revkey[sig->numrevkeys].algid = revkey[1];
-         memcpy (sig->revkey[sig->numrevkeys].fpr, &revkey[2], 20);
-
+          len -= 2;
+         sig->revkey[sig->numrevkeys].fprlen = len;
+         memcpy (sig->revkey[sig->numrevkeys].fpr, revkey+2, len);
+         memset (sig->revkey[sig->numrevkeys].fpr+len, 0,
+                  sizeof (sig->revkey[sig->numrevkeys].fpr) - len);
          sig->numrevkeys++;
        }
     }
@@ -1840,7 +1934,7 @@ parse_signature (IOBUF inp, int pkttype, unsigned long pktlen,
 {
   int md5_len = 0;
   unsigned n;
-  int is_v4 = 0;
+  int is_v4or5 = 0;
   int rc = 0;
   int i, ndata;
 
@@ -1853,8 +1947,8 @@ parse_signature (IOBUF inp, int pkttype, unsigned long pktlen,
     }
   sig->version = iobuf_get_noeof (inp);
   pktlen--;
-  if (sig->version == 4)
-    is_v4 = 1;
+  if (sig->version == 4 || sig->version == 5)
+    is_v4or5 = 1;
   else if (sig->version != 2 && sig->version != 3)
     {
       log_error ("packet(%d) with unknown version %d\n",
@@ -1865,7 +1959,7 @@ parse_signature (IOBUF inp, int pkttype, unsigned long pktlen,
       goto leave;
     }
 
-  if (!is_v4)
+  if (!is_v4or5)
     {
       if (pktlen == 0)
        goto underflow;
@@ -1876,7 +1970,7 @@ parse_signature (IOBUF inp, int pkttype, unsigned long pktlen,
     goto underflow;
   sig->sig_class = iobuf_get_noeof (inp);
   pktlen--;
-  if (!is_v4)
+  if (!is_v4or5)
     {
       if (pktlen < 12)
        goto underflow;
@@ -1895,7 +1989,7 @@ parse_signature (IOBUF inp, int pkttype, unsigned long pktlen,
   pktlen--;
   sig->flags.exportable = 1;
   sig->flags.revocable = 1;
-  if (is_v4) /* Read subpackets.  */
+  if (is_v4or5) /* Read subpackets.  */
     {
       if (pktlen < 2)
        goto underflow;
@@ -1966,7 +2060,7 @@ parse_signature (IOBUF inp, int pkttype, unsigned long pktlen,
   sig->digest_start[1] = iobuf_get_noeof (inp);
   pktlen--;
 
-  if (is_v4 && sig->pubkey_algo)  /* Extract required information.  */
+  if (is_v4or5 && sig->pubkey_algo)  /* Extract required information.  */
     {
       const byte *p;
       size_t len;
@@ -2067,7 +2161,7 @@ parse_signature (IOBUF inp, int pkttype, unsigned long pktlen,
                   (ulong) sig->keyid[0], (ulong) sig->keyid[1],
                   sig->version, (ulong) sig->timestamp, md5_len, sig->sig_class,
                   sig->digest_algo, sig->digest_start[0], sig->digest_start[1]);
-      if (is_v4)
+      if (is_v4or5)
        {
          parse_sig_subpkt (sig->hashed, SIGSUBPKT_LIST_HASHED, NULL);
          parse_sig_subpkt (sig->unhashed, SIGSUBPKT_LIST_UNHASHED, NULL);
@@ -2259,7 +2353,7 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
     {
       log_error ("packet(%d) too large\n", pkttype);
       if (list_mode)
-        es_fputs (":key packet: [too larget]\n", listfp);
+        es_fputs (":key packet: [too large]\n", listfp);
       err = gpg_error (GPG_ERR_INV_PACKET);
       goto leave;
     }
@@ -2480,7 +2574,7 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
                      err = gpg_error (GPG_ERR_INV_PACKET);
                      goto leave;
                    }
-                 ski->s2k.count = iobuf_get (inp);
+                 ski->s2k.count = iobuf_get_noeof (inp);
                  pktlen--;
                  if (list_mode)
                    es_fprintf (listfp, "\tprotect count: %lu (%lu)\n",
@@ -3088,7 +3182,7 @@ parse_plaintext (IOBUF inp, int pkttype, unsigned long pktlen,
          pt->name[i] = c;
     }
   /* Fill up NAME so that a check with valgrind won't complain about
-   * reading from uninitalized memory.  This case may be triggred by
+   * reading from uninitialized memory.  This case may be triggred by
    * corrupted packets.  */
   for (; i < namelen; i++)
     pt->name[i] = 0;
@@ -3161,6 +3255,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 +3349,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