gpg: Add option and preference framework for AEAD.
authorWerner Koch <wk@gnupg.org>
Wed, 10 Jan 2018 10:42:38 +0000 (11:42 +0100)
committerWerner Koch <wk@gnupg.org>
Wed, 10 Jan 2018 10:51:03 +0000 (11:51 +0100)
* common/openpgpdefs.h (aead_algo_t): New.
(SIGSUBPKT_PREF_AEAD): New.
* g10/gpg.c (oAEADAlgo, oPersonalAEADPreferences): New.
(opts): New options --aead-algo and --personal-aead-preferences.
(set_compliance_option): Clar aead algo.
(main): Parse and check the new options
* g10/options.h (struct opt): Add fields def_aead_algo and
personal_aead_prefs.
* g10/packet.h (PREFTYPE_AEAD): New enum value.
(PKT_user_id): Add field flags.aead.
(PKT_public_key): Add field flags.aead.
* g10/pkclist.c (select_algo_from_prefs): Support PREFTYPE_AEAD.
* g10/getkey.c (fixup_uidnode): Set AEAD flag.
(merge_selfsigs): Ditto.
* g10/kbnode.c (dump_kbnode): Show aead flag.
* g10/keyedit.c (show_prefs): Ditto.
(show_key_with_all_names_colon): Ditto.
* g10/keygen.c (aead_presf, n_aead_prefs): New vars.
(set_one_pref): Suppport PREFTYPE_AEAD.
(keygen_set_std_prefs): Parse AEAD preferences.
(keygen_get_std_prefs): Ditto.
(add_feature_aead): New.
(keygen_upd_std_prefs): Call that and build AEAD pref  packet.
* g10/main.h (DEFAULT_AEAD_ALGO): New const.
* g10/misc.c (openpgp_aead_test_algo): New.
(openpgp_aead_algo_name): New.
(string_to_aead_algo): New.
(default_aead_algo): New.
--

This is only used in --rfc4880bis mode and not really tested.

Signed-off-by: Werner Koch <wk@gnupg.org>
common/openpgpdefs.h
g10/getkey.c
g10/gpg.c
g10/kbnode.c
g10/keyedit.c
g10/keygen.c
g10/main.h
g10/misc.c
g10/options.h
g10/packet.h
g10/pkclist.c

index 85a4251..aeb3389 100644 (file)
@@ -115,7 +115,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
   }
@@ -144,6 +145,15 @@ cipher_algo_t;
 
 typedef enum
   {
+    AEAD_ALGO_NONE         =  0,
+    AEAD_ALGO_EAX          =  1,
+    AEAD_ALGO_OCB          =  2
+  }
+aead_algo_t;
+
+
+typedef enum
+  {
     PUBKEY_ALGO_RSA         =  1,
     PUBKEY_ALGO_RSA_E       =  2, /* RSA encrypt only (legacy). */
     PUBKEY_ALGO_RSA_S       =  3, /* RSA sign only (legacy).    */
index dabd052..497dace 100644 (file)
@@ -2539,6 +2539,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 +3363,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 +3425,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 +3434,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 +3448,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 61e39b8..fadd2f0 100644 (file)
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -245,6 +245,7 @@ enum cmd_and_opt_values
     oRFC2440Text,
     oNoRFC2440Text,
     oCipherAlgo,
+    oAEADAlgo,
     oDigestAlgo,
     oCertDigestAlgo,
     oCompressAlgo,
@@ -371,6 +372,7 @@ enum cmd_and_opt_values
     oDefaultPreferenceList,
     oDefaultKeyserverURL,
     oPersonalCipherPreferences,
+    oPersonalAEADPreferences,
     oPersonalDigestPreferences,
     oPersonalCompressPreferences,
     oAgentProgram,
@@ -668,6 +670,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", "@"),
@@ -824,6 +827,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", "@"),
@@ -835,6 +839,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", "@"),
 
@@ -2125,6 +2130,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;
@@ -2141,6 +2147,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;
@@ -2157,6 +2164,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;
 
@@ -2286,12 +2294,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;
@@ -2355,6 +2365,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 */
@@ -3113,6 +3124,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;
@@ -3392,6 +3406,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;
@@ -3737,6 +3754,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;
@@ -3796,6 +3820,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"));
@@ -3861,6 +3888,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))
          {
@@ -3890,6 +3923,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"),
@@ -3915,6 +3954,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 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 8d86253..81344eb 100644 (file)
@@ -3118,7 +3118,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 +3128,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)
@@ -3172,6 +3178,8 @@ show_prefs (PKT_user_id * uid, PKT_signature * selfsig, int verbose)
        }
       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 +3325,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 912fa39..d5f7782 100644 (file)
@@ -127,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;
@@ -134,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,
@@ -326,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();
 
@@ -346,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"))
       {
@@ -383,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:
@@ -475,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)
@@ -520,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);
@@ -572,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;
          }
@@ -581,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 *
@@ -594,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++)
     {
@@ -603,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;
@@ -618,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;
 }
@@ -665,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)
 {
@@ -726,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
@@ -744,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);
 
index 4a8f8c3..6abc598 100644 (file)
@@ -41,6 +41,8 @@
 # define DEFAULT_CIPHER_ALGO     CIPHER_ALGO_3DES
 #endif
 
+#define DEFAULT_AEAD_ALGO  AEAD_ALGO_EAX
+
 #define DEFAULT_DIGEST_ALGO     ((GNUPG)? DIGEST_ALGO_SHA256:DIGEST_ALGO_SHA1)
 #define DEFAULT_S2K_DIGEST_ALGO DIGEST_ALGO_SHA1
 #ifdef HAVE_ZIP
@@ -123,6 +125,9 @@ 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);
+
 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);
@@ -151,12 +156,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);
 
index 9016d27..2da0d27 100644 (file)
@@ -582,6 +582,41 @@ 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)
+{
+  switch (algo)
+    {
+    case AEAD_ALGO_NONE:
+      break;
+    case AEAD_ALGO_EAX:
+      return gpg_error (GPG_ERR_NOT_SUPPORTED);
+    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 0 if ALGO is a supported OpenPGP public key algorithm.  */
 int
 openpgp_pk_test_algo (pubkey_algo_t algo)
@@ -1112,6 +1147,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 +1296,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 61f7403..6ad1037 100644 (file)
@@ -92,6 +92,7 @@ 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 def_digest_algo;
@@ -177,6 +178,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;
index 8dca88b..894b389 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 {
@@ -290,6 +291,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 +388,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.  */
@@ -471,7 +474,7 @@ 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;
   /* An iobuf holding the data to be decrypted.  (This is not used for
      encryption!)  */
index 581cae4..a759672 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)