]> granicus.if.org Git - neomutt/commitdiff
Autocrypt outgoing emails
authorKevin McCarthy <kevin@8t8.us>
Sun, 21 Jul 2019 22:15:06 +0000 (15:15 -0700)
committerRichard Russon <rich@flatcap.org>
Mon, 19 Aug 2019 23:14:27 +0000 (00:14 +0100)
Change crypt_get_keys() to query autocrypt.

When oppenc_mode is set, we still query the original keyring
regardless, because the compose menu can still run oppenc even if
autocrypt is on.

Since mutt_autocrypt_ui_recommendation() checks each key as part of
making the recommendation, add a keylist parameter and use that
function.

Add gpgme changes to use the autocrypt context for encryption.

Postpone work:
* Change mutt_protect() to have a postpone parameter.  Remove the
  manual toggling of the SEC_SIGN bit outside the call when postponing.

* Since autocrypt doesn't set the SEC_SIGN bit, this allows us to turn off
  signing inside mutt_protect() for both normal and autocrypt mode.

* Set the autocrypt postpone key in AutocryptDefaultKey.

Write autocrypt and gossip headers in outgoing emails.

Co-authored-by: Richard Russon <rich@flatcap.org>
13 files changed:
autocrypt/autocrypt.c
autocrypt/autocrypt.h
compose.c
globals.h
ncrypt/crypt.c
ncrypt/crypt_gpgme.c
ncrypt/cryptglue.c
ncrypt/cryptglue.h
ncrypt/ncrypt.h
options.h
postpone.c
send.c
sendlib.c

index cf5d7c1934cfc0478c3463b0244ccbc04cb546cd..9aab282bb06a8c3b9b16d84fae6aeb0388580b38 100644 (file)
@@ -450,13 +450,19 @@ cleanup:
   return rv;
 }
 
-enum AutocryptRec mutt_autocrypt_ui_recommendation(struct Email *hdr)
+/* Returns the recommendation.  If the recommendataion is > NO and
+ * keylist is not NULL, keylist will be populated with the autocrypt
+ * keyids
+ */
+enum AutocryptRec mutt_autocrypt_ui_recommendation(struct Email *hdr, char **keylist)
 {
   enum AutocryptRec rv = AUTOCRYPT_REC_OFF;
   struct AutocryptAccount *account = NULL;
   struct AutocryptPeer *peer = NULL;
   struct Address *recip = NULL;
   int all_encrypt = 1, has_discourage = 0;
+  struct Buffer *keylist_buf = NULL;
+  const char *matching_key;
 
   if (!C_Autocrypt || mutt_autocrypt_init(0) || !hdr)
     return AUTOCRYPT_REC_OFF;
@@ -471,6 +477,9 @@ enum AutocryptRec mutt_autocrypt_ui_recommendation(struct Email *hdr)
   if (mutt_autocrypt_db_account_get(from, &account) <= 0)
     goto cleanup;
 
+  keylist_buf = mutt_buffer_pool_get();
+  mutt_buffer_addstr(keylist_buf, account->keyid);
+
   struct AddressList recips = TAILQ_HEAD_INITIALIZER(recips);
 
   mutt_addrlist_copy(&recips, &hdr->env->to, false);
@@ -488,6 +497,8 @@ enum AutocryptRec mutt_autocrypt_ui_recommendation(struct Email *hdr)
 
     if (mutt_autocrypt_gpgme_is_valid_key(peer->keyid))
     {
+      matching_key = peer->keyid;
+
       if (!(peer->last_seen && peer->autocrypt_timestamp) ||
           (peer->last_seen - peer->autocrypt_timestamp > 35 * 24 * 60 * 60))
       {
@@ -500,12 +511,18 @@ enum AutocryptRec mutt_autocrypt_ui_recommendation(struct Email *hdr)
     }
     else if (mutt_autocrypt_gpgme_is_valid_key(peer->gossip_keyid))
     {
+      matching_key = peer->gossip_keyid;
+
       has_discourage = 1;
       all_encrypt = 0;
     }
     else
       goto cleanup;
 
+    if (mutt_buffer_len(keylist_buf))
+      mutt_buffer_addch(keylist_buf, ' ');
+    mutt_buffer_addstr(keylist_buf, matching_key);
+
     mutt_autocrypt_db_peer_free(&peer);
   }
 
@@ -516,9 +533,191 @@ enum AutocryptRec mutt_autocrypt_ui_recommendation(struct Email *hdr)
   else
     rv = AUTOCRYPT_REC_AVAILABLE;
 
+  if (keylist)
+    mutt_str_replace(keylist, mutt_b2s(keylist_buf));
+
+cleanup:
+  mutt_autocrypt_db_account_free(&account);
+  mutt_addrlist_clear(&recips);
+  mutt_autocrypt_db_peer_free(&peer);
+  mutt_buffer_pool_release(&keylist_buf);
+  return rv;
+}
+
+int mutt_autocrypt_set_sign_as_default_key(struct Email *hdr)
+{
+  int rv = -1;
+  struct AutocryptAccount *account = NULL;
+
+  if (!C_Autocrypt || mutt_autocrypt_init(0) || !hdr)
+    return -1;
+
+  struct Address *from = TAILQ_FIRST(&hdr->env->from);
+  if (!from || TAILQ_NEXT(from, entries))
+    return -1;
+
+  if (mutt_autocrypt_db_account_get(from, &account) <= 0)
+    goto cleanup;
+  if (!account->keyid)
+    goto cleanup;
+
+  mutt_str_replace(&AutocryptSignAs, account->keyid);
+  mutt_str_replace(&AutocryptDefaultKey, account->keyid);
+
+  rv = 0;
+
+cleanup:
+  mutt_autocrypt_db_account_free(&account);
+  return rv;
+}
+
+static void write_autocrypt_header_line(FILE *fp, const char *addr,
+                                        int prefer_encrypt, const char *keydata)
+{
+  int count = 0;
+
+  fprintf(fp, "addr=%s; ", addr);
+  if (prefer_encrypt)
+    fputs("prefer-encrypt=mutual; ", fp);
+  fputs("keydata=\n", fp);
+
+  while (*keydata)
+  {
+    count = 0;
+    fputs("\t", fp);
+    while (*keydata && count < 75)
+    {
+      fputc(*keydata, fp);
+      count++;
+      keydata++;
+    }
+    fputs("\n", fp);
+  }
+}
+
+int mutt_autocrypt_write_autocrypt_header(struct Envelope *env, FILE *fp)
+{
+  int rv = -1;
+  struct AutocryptAccount *account = NULL;
+
+  if (!C_Autocrypt || mutt_autocrypt_init(0) || !env)
+    return -1;
+
+  struct Address *from = TAILQ_FIRST(&env->from);
+  if (!from || TAILQ_NEXT(from, entries))
+    return -1;
+
+  if (mutt_autocrypt_db_account_get(from, &account) <= 0)
+    goto cleanup;
+  if (!account->keydata)
+    goto cleanup;
+
+  fputs("Autocrypt: ", fp);
+  write_autocrypt_header_line(fp, account->email_addr, account->prefer_encrypt,
+                              account->keydata);
+
+  rv = 0;
+
 cleanup:
   mutt_autocrypt_db_account_free(&account);
+  return rv;
+}
+
+int mutt_autocrypt_write_gossip_headers(struct Envelope *env, FILE *fp)
+{
+  struct AutocryptHeader *gossip;
+
+  if (!C_Autocrypt || mutt_autocrypt_init(0) || !env)
+    return -1;
+
+  for (gossip = env->autocrypt_gossip; gossip; gossip = gossip->next)
+  {
+    fputs("Autocrypt-Gossip: ", fp);
+    write_autocrypt_header_line(fp, gossip->addr, 0, gossip->keydata);
+  }
+
+  return 0;
+}
+
+int mutt_autocrypt_generate_gossip_list(struct Email *hdr)
+{
+  int rv = -1;
+  struct AutocryptPeer *peer = NULL;
+  struct AutocryptAccount *account = NULL;
+  struct Address *recip = NULL;
+  struct AutocryptHeader *gossip;
+  const char *keydata, *addr;
+  struct Envelope *mime_headers;
+
+  if (!C_Autocrypt || mutt_autocrypt_init(0) || !hdr)
+    return -1;
+
+  mime_headers = hdr->content->mime_headers;
+  if (!mime_headers)
+    mime_headers = hdr->content->mime_headers = mutt_env_new();
+  mutt_free_autocrypthdr(&mime_headers->autocrypt_gossip);
+
+  struct AddressList recips = TAILQ_HEAD_INITIALIZER(recips);
+
+  mutt_addrlist_copy(&recips, &hdr->env->to, false);
+  mutt_addrlist_copy(&recips, &hdr->env->cc, false);
+
+  TAILQ_FOREACH(recip, &recips, entries)
+  {
+    /* At this point, we just accept missing keys and include what
+     * we can. */
+    if (mutt_autocrypt_db_peer_get(recip, &peer) <= 0)
+      continue;
+
+    keydata = NULL;
+    if (mutt_autocrypt_gpgme_is_valid_key(peer->keyid))
+      keydata = peer->keydata;
+    else if (mutt_autocrypt_gpgme_is_valid_key(peer->gossip_keyid))
+      keydata = peer->gossip_keydata;
+
+    if (keydata)
+    {
+      gossip = mutt_new_autocrypthdr();
+      gossip->addr = mutt_str_strdup(peer->email_addr);
+      gossip->keydata = mutt_str_strdup(keydata);
+      gossip->next = mime_headers->autocrypt_gossip;
+      mime_headers->autocrypt_gossip = gossip;
+    }
+
+    mutt_autocrypt_db_peer_free(&peer);
+  }
+
+  TAILQ_FOREACH(recip, &hdr->env->reply_to, entries)
+  {
+    addr = keydata = NULL;
+    if (mutt_autocrypt_db_account_get(recip, &account) > 0)
+    {
+      addr = account->email_addr;
+      keydata = account->keydata;
+    }
+    else if (mutt_autocrypt_db_peer_get(recip, &peer) > 0)
+    {
+      addr = peer->email_addr;
+      if (mutt_autocrypt_gpgme_is_valid_key(peer->keyid))
+        keydata = peer->keydata;
+      else if (mutt_autocrypt_gpgme_is_valid_key(peer->gossip_keyid))
+        keydata = peer->gossip_keydata;
+    }
+
+    if (keydata)
+    {
+      gossip = mutt_new_autocrypthdr();
+      gossip->addr = mutt_str_strdup(addr);
+      gossip->keydata = mutt_str_strdup(keydata);
+      gossip->next = mime_headers->autocrypt_gossip;
+      mime_headers->autocrypt_gossip = gossip;
+    }
+    mutt_autocrypt_db_account_free(&account);
+    mutt_autocrypt_db_peer_free(&peer);
+  }
+
   mutt_addrlist_clear(&recips);
+  mutt_autocrypt_db_account_free(&account);
   mutt_autocrypt_db_peer_free(&peer);
   return rv;
 }
index d3f10fa4f1e71ca07c353cf7f5a760c244005837..95a77305abc89b8b76f8965232a2bb70e0be0967 100644 (file)
@@ -80,6 +80,10 @@ int mutt_autocrypt_init (int);
 void mutt_autocrypt_cleanup (void);
 int mutt_autocrypt_process_autocrypt_header (struct Email *hdr, struct Envelope *env);
 int mutt_autocrypt_process_gossip_header (struct Email *hdr, struct Envelope *env);
-enum AutocryptRec mutt_autocrypt_ui_recommendation (struct Email *hdr);
+enum AutocryptRec mutt_autocrypt_ui_recommendation (struct Email *hdr, char **keylist);
+int mutt_autocrypt_set_sign_as_default_key (struct Email *hdr);
+int mutt_autocrypt_write_autocrypt_header (struct Envelope *env, FILE *fp);
+int mutt_autocrypt_write_gossip_headers (struct Envelope *env, FILE *fp);
+int mutt_autocrypt_generate_gossip_list (struct Email *hdr);
 
 #endif /* MUTT_AUTOCRYPT_AUTOCRYPT_H */
index fc4d5dc4dbbdeebcd97eb627c306d2c6a212cac4..79caa1056d9569a07a7d4e6a130ca78aba9ca45d 100644 (file)
--- a/compose.c
+++ b/compose.c
@@ -337,7 +337,7 @@ static void autocrypt_compose_menu(struct Email *e)
   {
     case 1:
       e->security |= (SEC_AUTOCRYPT | SEC_AUTOCRYPT_OVERRIDE);
-      e->security &= ~(SEC_ENCRYPT | SEC_SIGN | SEC_OPPENCRYPT);
+      e->security &= ~(SEC_ENCRYPT | SEC_SIGN | SEC_OPPENCRYPT | SEC_INLINE);
       break;
     case 2:
       e->security &= ~SEC_AUTOCRYPT;
@@ -444,24 +444,27 @@ static void redraw_crypt_lines(struct ComposeRedrawData *rd)
 #ifdef USE_AUTOCRYPT
   mutt_window_move(MuttIndexWindow, HDR_AUTOCRYPT, 0);
   mutt_window_clrtoeol(MuttIndexWindow);
-  SET_COLOR(MT_COLOR_COMPOSE_HEADER);
-  printw("%*s", HeaderPadding[HDR_AUTOCRYPT], _(Prompts[HDR_AUTOCRYPT]));
-  NORMAL_COLOR;
-  if (C_Autocrypt && (e->security & SEC_AUTOCRYPT))
-  {
-    SET_COLOR(MT_COLOR_COMPOSE_SECURITY_ENCRYPT);
-    addstr(_("Encrypt"));
-  }
-  else
+  if (C_Autocrypt)
   {
-    SET_COLOR(MT_COLOR_COMPOSE_SECURITY_NONE);
-    addstr(_("Off"));
-  }
+    SET_COLOR(MT_COLOR_COMPOSE_HEADER);
+    printw("%*s", HeaderPadding[HDR_AUTOCRYPT], _(Prompts[HDR_AUTOCRYPT]));
+    NORMAL_COLOR;
+    if (e->security & SEC_AUTOCRYPT)
+    {
+      SET_COLOR(MT_COLOR_COMPOSE_SECURITY_ENCRYPT);
+      addstr(_("Encrypt"));
+    }
+    else
+    {
+      SET_COLOR(MT_COLOR_COMPOSE_SECURITY_NONE);
+      addstr(_("Off"));
+    }
 
-  SET_COLOR(MT_COLOR_COMPOSE_HEADER);
-  mutt_window_mvprintw(MuttIndexWindow, HDR_AUTOCRYPT, 40, "%s", _("Recommendation: "));
-  NORMAL_COLOR;
-  printw("%s", _(AutocryptRecUiFlags[rd->autocrypt_rec]));
+    SET_COLOR(MT_COLOR_COMPOSE_HEADER);
+    mutt_window_mvprintw(MuttIndexWindow, HDR_AUTOCRYPT, 40, "%s", _("Recommendation: "));
+    NORMAL_COLOR;
+    printw("%s", _(AutocryptRecUiFlags[rd->autocrypt_rec]));
+  }
 #endif
 }
 
@@ -473,28 +476,29 @@ static void update_crypt_info(struct ComposeRedrawData *rd)
     crypt_opportunistic_encrypt(e);
 
 #ifdef USE_AUTOCRYPT
-  rd->autocrypt_rec = mutt_autocrypt_ui_recommendation(e);
-
-  /* Anything that enables SEC_ENCRYPT or SEC_SIGN, or turns on SMIME
-   * overrides autocrypt, be it oppenc or the user having turned on
-   * those flags manually. */
-  if (e->security & (SEC_ENCRYPT | SEC_SIGN | APPLICATION_SMIME))
-    e->security &= ~(SEC_AUTOCRYPT | SEC_AUTOCRYPT_OVERRIDE);
-  else
+  if (C_Autocrypt)
   {
-    if (!(e->security & SEC_AUTOCRYPT_OVERRIDE))
+    rd->autocrypt_rec = mutt_autocrypt_ui_recommendation(e, NULL);
+
+    /* Anything that enables SEC_ENCRYPT or SEC_SIGN, or turns on SMIME
+    * overrides autocrypt, be it oppenc or the user having turned on
+    * those flags manually. */
+    if (e->security & (SEC_ENCRYPT | SEC_SIGN | APPLICATION_SMIME))
+      e->security &= ~(SEC_AUTOCRYPT | SEC_AUTOCRYPT_OVERRIDE);
+    else
     {
-      if (rd->autocrypt_rec == AUTOCRYPT_REC_YES)
-        e->security |= SEC_AUTOCRYPT;
-      else
-        e->security &= ~SEC_AUTOCRYPT;
+      if (!(e->security & SEC_AUTOCRYPT_OVERRIDE))
+      {
+        if (rd->autocrypt_rec == AUTOCRYPT_REC_YES)
+        {
+          e->security |= SEC_AUTOCRYPT;
+          e->security &= ~SEC_INLINE;
+        }
+        else
+          e->security &= ~SEC_AUTOCRYPT;
+      }
     }
   }
-  /* TODO:
-   * - autocrypt menu for manually enabling/disabling (turns on override)
-   * - deal with pgp and smime menu and their effects on security->SEC_AUTOCRYPT
-   *   when encryption or signing is enabled or if switch to smime mode
-   */
 #endif
 
   redraw_crypt_lines(rd);
@@ -2134,6 +2138,9 @@ int mutt_compose_menu(struct Email *e, char *fcc, size_t fcclen, struct Email *e
 #endif
 #ifdef USE_AUTOCRYPT
       case OP_COMPOSE_AUTOCRYPT_MENU:
+        if (!C_Autocrypt)
+          break;
+
         if ((WithCrypto & APPLICATION_SMIME) && (e->security & APPLICATION_SMIME))
         {
           if (e->security & (SEC_ENCRYPT | SEC_SIGN))
@@ -2157,6 +2164,15 @@ int mutt_compose_menu(struct Email *e, char *fcc, size_t fcclen, struct Email *e
     }
   }
 
+#ifdef USE_AUTOCRYPT
+  /* This is a fail-safe to make sure the bit isn't somehow turned
+   * on.  The user could have disabled the option after setting SEC_AUTOCRYPT,
+   * or perhaps resuming or replying to an autocrypt message.
+   */
+  if (!C_Autocrypt)
+    e->security &= ~SEC_AUTOCRYPT;
+#endif
+
   mutt_menu_pop_current(menu);
   mutt_menu_destroy(&menu);
 
index e31bafa4b1bd471dbc25f0658d87de27e02c1eaf..13d3aa5e7f34bc1b9626d202100d60ceb2e700a4 100644 (file)
--- a/globals.h
+++ b/globals.h
@@ -98,6 +98,8 @@ WHERE char *C_AttributionLocale;             ///< Config: Locale for dates in th
 WHERE char *C_AttachFormat;                  ///< Config: printf-like format string for the attachment menu
 #ifdef USE_AUTOCRYPT
 WHERE char *C_AutocryptDir;
+WHERE char *AutocryptSignAs;  /* This is used in ncrypt/crypt_gpgme.c */
+WHERE char *AutocryptDefaultKey;  /* Used for postponing messages */
 #endif
 WHERE char *C_ConfigCharset;                 ///< Config: Character set that the config files are in
 WHERE char *C_CryptProtectedHeadersSubject;  ///< Config: Use this as the subject for encrypted emails
index 7fc8e175209bad5d6eb80c59ade5f6732c95d62c..9e367fc3d423708b3f70c53b2d3d7e72b8c8c284 100644 (file)
@@ -58,6 +58,9 @@
 #include "send.h"
 #include "sendlib.h"
 #include "state.h"
+#ifdef USE_AUTOCRYPT
+#include "autocrypt/autocrypt.h"
+#endif
 
 struct Mailbox;
 
@@ -164,24 +167,35 @@ bool crypt_valid_passphrase(SecurityFlags flags)
  * @param keylist List of keys to encrypt to (space-separated)
  * @retval  0 Success
  * @retval -1 Error
+ *
+ * In postpone mode, signing is automatically disabled.
  */
-int mutt_protect(struct Email *e, char *keylist)
+int mutt_protect(struct Email *e, char *keylist, int postpone)
 {
   struct Body *pbody = NULL, *tmp_pbody = NULL;
   struct Body *tmp_smime_pbody = NULL;
   struct Body *tmp_pgp_pbody = NULL;
-  int flags = (WithCrypto & APPLICATION_PGP) ? e->security : 0;
+  int security, sign, has_retainable_sig = 0;
 
   if (!WithCrypto)
     return -1;
 
-  if (!(e->security & (SEC_ENCRYPT | SEC_SIGN)))
+  security = e->security;
+  sign = security & (SEC_AUTOCRYPT | SEC_SIGN);
+  if (postpone)
+  {
+    sign = 0;
+    security &= ~SEC_SIGN;
+  }
+
+  if (!(security & (SEC_ENCRYPT | SEC_AUTOCRYPT)) && !sign)
     return 0;
 
-  if ((e->security & SEC_SIGN) && !crypt_valid_passphrase(e->security))
+  if (sign && !(security & SEC_AUTOCRYPT) && !crypt_valid_passphrase(security))
     return -1;
 
-  if (((WithCrypto & APPLICATION_PGP) != 0) && ((e->security & PGP_INLINE) == PGP_INLINE))
+  if ((WithCrypto & APPLICATION_PGP) && !(security & SEC_AUTOCRYPT) &&
+      ((security & PGP_INLINE) == PGP_INLINE))
   {
     if ((e->content->type != TYPE_TEXT) ||
         (mutt_str_strcasecmp(e->content->subtype, "plain") != 0))
@@ -214,7 +228,7 @@ int mutt_protect(struct Email *e, char *keylist)
         mutt_endwin();
         puts(_("Invoking PGP..."));
       }
-      pbody = crypt_pgp_traditional_encryptsign(e->content, flags, keylist);
+      pbody = crypt_pgp_traditional_encryptsign(e->content, security, keylist);
       if (pbody)
       {
         e->content = pbody;
@@ -242,7 +256,7 @@ int mutt_protect(struct Email *e, char *keylist)
   if (WithCrypto & APPLICATION_PGP)
     tmp_pgp_pbody = e->content;
 
-  if (C_CryptUsePka && (e->security & SEC_SIGN))
+  if (C_CryptUsePka && sign)
   {
     /* Set sender (necessary for e.g. PKA).  */
     const char *mailbox = NULL;
@@ -259,9 +273,9 @@ int mutt_protect(struct Email *e, char *keylist)
     if (!mailbox && C_EnvelopeFromAddress)
       mailbox = C_EnvelopeFromAddress->mailbox;
 
-    if (((WithCrypto & APPLICATION_SMIME) != 0) && (e->security & APPLICATION_SMIME))
+    if (((WithCrypto & APPLICATION_SMIME) != 0) && (security & APPLICATION_SMIME))
       crypt_smime_set_sender(mailbox);
-    else if (((WithCrypto & APPLICATION_PGP) != 0) && (e->security & APPLICATION_PGP))
+    else if (((WithCrypto & APPLICATION_PGP) != 0) && (security & APPLICATION_PGP))
       crypt_pgp_set_sender(mailbox);
 
     if (free_from)
@@ -280,9 +294,27 @@ int mutt_protect(struct Email *e, char *keylist)
     e->content->mime_headers = protected_headers;
   }
 
-  if (e->security & SEC_SIGN)
+  /* A note about e->content->mime_headers.  If postpone or send
+   * fails, the mime_headers is cleared out before returning to the
+   * compose menu.  So despite the "robustness" code above and in the
+   * gen_gossip_list function below, mime_headers will not be set when
+   * entering mutt_protect().
+   *
+   * This is important to note because the user could toggle
+   * $crypt_protected_headers_write or $autocrypt off back in the
+   * compose menu.  We don't want mutt_write_rfc822_header() to write
+   * stale data from one option if the other is set.
+   */
+#ifdef USE_AUTOCRYPT
+  if (C_Autocrypt && !postpone && (security & SEC_AUTOCRYPT))
   {
-    if (((WithCrypto & APPLICATION_SMIME) != 0) && (e->security & APPLICATION_SMIME))
+    mutt_autocrypt_generate_gossip_list(e);
+  }
+#endif
+
+  if (sign)
+  {
+    if (((WithCrypto & APPLICATION_SMIME) != 0) && (security & APPLICATION_SMIME))
     {
       tmp_pbody = crypt_smime_sign_message(e->content);
       if (!tmp_pbody)
@@ -291,27 +323,28 @@ int mutt_protect(struct Email *e, char *keylist)
       tmp_smime_pbody = tmp_pbody;
     }
 
-    if (((WithCrypto & APPLICATION_PGP) != 0) && (e->security & APPLICATION_PGP) &&
-        (!(flags & SEC_ENCRYPT) || C_PgpRetainableSigs))
+    if (((WithCrypto & APPLICATION_PGP) != 0) && (security & APPLICATION_PGP) &&
+        (!(security & (SEC_ENCRYPT | SEC_AUTOCRYPT)) || C_PgpRetainableSigs))
     {
       tmp_pbody = crypt_pgp_sign_message(e->content);
       if (!tmp_pbody)
         goto bail;
 
-      flags &= ~SEC_SIGN;
+      has_retainable_sig = 1;
+      sign = 0;
       pbody = tmp_pbody;
       tmp_pgp_pbody = tmp_pbody;
     }
 
-    if ((WithCrypto != 0) && (e->security & APPLICATION_SMIME) && (e->security & APPLICATION_PGP))
+    if ((WithCrypto != 0) && (security & APPLICATION_SMIME) && (security & APPLICATION_PGP))
     {
       /* here comes the draft ;-) */
     }
   }
 
-  if (e->security & SEC_ENCRYPT)
+  if (security & (SEC_ENCRYPT | SEC_AUTOCRYPT))
   {
-    if (((WithCrypto & APPLICATION_SMIME) != 0) && (e->security & APPLICATION_SMIME))
+    if (((WithCrypto & APPLICATION_SMIME) != 0) && (security & APPLICATION_SMIME))
     {
       tmp_pbody = crypt_smime_build_smime_entity(tmp_smime_pbody, keylist);
       if (!tmp_pbody)
@@ -331,13 +364,13 @@ int mutt_protect(struct Email *e, char *keylist)
       pbody = tmp_pbody;
     }
 
-    if (((WithCrypto & APPLICATION_PGP) != 0) && (e->security & APPLICATION_PGP))
+    if (((WithCrypto & APPLICATION_PGP) != 0) && (security & APPLICATION_PGP))
     {
-      pbody = crypt_pgp_encrypt_message(tmp_pgp_pbody, keylist, (flags & SEC_SIGN));
+      pbody = crypt_pgp_encrypt_message(e, tmp_pgp_pbody, keylist, sign);
       if (!pbody)
       {
         /* did we perform a retainable signature? */
-        if (flags != e->security)
+        if (has_retainable_sig)
         {
           /* remove the outer multipart layer */
           tmp_pgp_pbody = mutt_remove_multipart(tmp_pgp_pbody);
@@ -352,7 +385,7 @@ int mutt_protect(struct Email *e, char *keylist)
        * signatures.
 
        */
-      if (flags != e->security)
+      if (has_retainable_sig)
       {
         tmp_pgp_pbody = mutt_remove_multipart(tmp_pgp_pbody);
         mutt_body_free(&tmp_pgp_pbody->next);
@@ -925,6 +958,17 @@ int crypt_get_keys(struct Email *e, char **keylist, bool oppenc_mode)
   /* Do a quick check to make sure that we can find all of the encryption
    * keys if the user has requested this service.  */
 
+  *keylist = NULL;
+
+#ifdef USE_AUTOCRYPT
+  if (!oppenc_mode && (e->security & SEC_AUTOCRYPT))
+  {
+    if (mutt_autocrypt_ui_recommendation(e, keylist) <= AUTOCRYPT_REC_NO)
+      return (-1);
+    return (0);
+  }
+#endif
+
   if (WithCrypto & APPLICATION_PGP)
     OptPgpCheckTrust = true;
 
@@ -934,8 +978,6 @@ int crypt_get_keys(struct Email *e, char **keylist, bool oppenc_mode)
   mutt_addrlist_qualify(&addrlist, fqdn);
   mutt_addrlist_dedupe(&addrlist);
 
-  *keylist = NULL;
-
   if (oppenc_mode || (e->security & SEC_ENCRYPT))
   {
     if (((WithCrypto & APPLICATION_PGP) != 0) && (e->security & APPLICATION_PGP))
index af7e9f163146679a9b653140f0094791700e4e24..aab9ea3f7f8647662fa9e2f0dbb6acc8f3327064 100644 (file)
@@ -719,6 +719,12 @@ static gpgme_ctx_t create_gpgme_context(bool for_smime)
   gpgme_ctx_t ctx;
 
   err = gpgme_new(&ctx);
+
+#ifdef USE_AUTOCRYPT
+  if (!err && OptAutocryptGpgme)
+    err = gpgme_ctx_set_engine_info(ctx, GPGME_PROTOCOL_OpenPGP, NULL, C_AutocryptDir);
+#endif
+
   if (err != 0)
   {
     mutt_error(_("error creating gpgme context: %s"), gpgme_strerror(err));
@@ -1116,13 +1122,22 @@ static gpgme_key_t *create_recipient_set(const char *keylist, bool use_smime)
  */
 static int set_signer(gpgme_ctx_t ctx, bool for_smime)
 {
-  char *signid = for_smime ? C_SmimeDefaultKey : C_PgpSignAs;
+  char *signid = NULL;
   gpgme_error_t err;
   gpgme_ctx_t listctx;
   gpgme_key_t key, key2;
   char *fpr = NULL, *fpr2 = NULL;
 
-  if (!signid || !*signid)
+  if (for_smime)
+    signid = C_SmimeSignAs ? C_SmimeSignAs : C_SmimeDefaultKey;
+#ifdef USE_AUTOCRYPT
+  else if (OptAutocryptGpgme)
+    signid = AutocryptSignAs;
+#endif
+  else
+    signid = C_PgpSignAs ? C_PgpSignAs : C_PgpDefaultKey;
+
+  if (!signid)
     return 0;
 
   listctx = create_gpgme_context(for_smime);
index 09d0da2e6bc570b88ed608b92f927af36afac12c..c7e63eb25b8f0b95d44857026fa0bb4c3cdc8b53 100644 (file)
 #include "crypt_mod.h"
 #include "curs_lib.h"
 #include "ncrypt.h"
+#include "options.h"
+#ifdef USE_AUTOCRYPT
+#include "autocrypt/autocrypt.h"
+#endif
 
 struct Address;
 struct AddressList;
@@ -62,6 +66,7 @@ extern struct CryptModuleSpecs CryptModSmimeClassic;
 #endif
 
 #ifdef CRYPT_BACKEND_GPGME
+#include "ncrypt/crypt_gpgme.h"
 extern struct CryptModuleSpecs CryptModPgpGpgme;
 extern struct CryptModuleSpecs CryptModSmimeGpgme;
 #endif
@@ -291,8 +296,25 @@ struct Body *crypt_pgp_sign_message(struct Body *a)
 /**
  * crypt_pgp_encrypt_message - Wrapper for CryptModuleSpecs::pgp_encrypt_message()
  */
-struct Body *crypt_pgp_encrypt_message(struct Body *a, char *keylist, bool sign)
+struct Body *crypt_pgp_encrypt_message(struct Email *msg, struct Body *a,
+                                       char *keylist, int sign)
 {
+#ifdef USE_AUTOCRYPT
+  struct Body *result;
+
+  if (msg->security & SEC_AUTOCRYPT)
+  {
+    if (mutt_autocrypt_set_sign_as_default_key(msg))
+      return NULL;
+
+    OptAutocryptGpgme = true;
+    result = pgp_gpgme_encrypt_message(a, keylist, sign);
+    OptAutocryptGpgme = false;
+
+    return result;
+  }
+#endif
+
   if (CRYPT_MOD_CALL_CHECK(PGP, pgp_encrypt_message))
     return CRYPT_MOD_CALL(PGP, pgp_encrypt_message)(a, keylist, sign);
 
index 193fea9c960490bac6d2692beeb005ad28c83e20..70257c4178a28f193199f6e4cb5389d881b93bf4 100644 (file)
@@ -30,7 +30,7 @@ struct AddressList;
 struct Body;
 struct State;
 
-struct Body *crypt_pgp_encrypt_message(struct Body *a, char *keylist, bool sign);
+struct Body *crypt_pgp_encrypt_message (struct Email *msg, struct Body *a, char *keylist, int sign);
 char *       crypt_pgp_find_keys(struct AddressList *al, bool oppenc_mode);
 void         crypt_pgp_invoke_import(const char *fname);
 void         crypt_pgp_set_sender(const char *sender);
index a69e2ca6e9c427c967096596db0901b1a71beb40..2f25628d041e475e349682da12d4289ae279b873 100644 (file)
@@ -198,7 +198,7 @@ SecurityFlags mutt_is_malformed_multipart_pgp_encrypted(struct Body *b);
 SecurityFlags mutt_is_multipart_encrypted(struct Body *b);
 SecurityFlags mutt_is_multipart_signed(struct Body *b);
 int          mutt_is_valid_multipart_pgp_encrypted(struct Body *b);
-int          mutt_protect(struct Email *e, char *keylist);
+int          mutt_protect(struct Email *e, char *keylist, int);
 int          mutt_protected_headers_handler(struct Body *m, struct State *s);
 bool         mutt_should_hide_protected_subject(struct Email *e);
 int          mutt_signed_handler(struct Body *a, struct State *s);
index 2d26f12c6ff9c355b74fdd441d9ec42e730fbbc3..a1503323861cca292728092a2307cf65476ece65 100644 (file)
--- a/options.h
+++ b/options.h
@@ -29,6 +29,7 @@
 /* pseudo options */
 
 WHERE bool OptAttachMsg;           /**< (pseudo) used by attach-message */
+WHERE bool OptAutocryptGpgme;      /**< (pseudo) use Autocrypt context inside ncrypt/crypt_gpgme.c */
 WHERE bool OptAuxSort;             /**< (pseudo) using auxiliary sort function */
 WHERE bool OptDontHandlePgpKeys; /**< (pseudo) used to extract PGP keys */
 WHERE bool OptForceRefresh;        /**< (pseudo) refresh even during macros */
index c1fd96b0da552e8694d5199320817deb1c0f8698..0bc70347963632ba5c954269cef4863faf9e3403 100644 (file)
@@ -517,6 +517,20 @@ SecurityFlags mutt_parse_crypt_hdr(const char *p, bool set_empty_signas, Securit
         flags |= SEC_OPPENCRYPT;
         break;
 
+      case 'a':
+      case 'A':
+#ifdef USE_AUTOCRYPT
+        flags |= SEC_AUTOCRYPT;
+#endif
+        break;
+
+      case 'z':
+      case 'Z':
+#ifdef USE_AUTOCRYPT
+        flags |= SEC_AUTOCRYPT_OVERRIDE;
+#endif
+        break;
+
       case 's':
       case 'S':
         flags |= SEC_SIGN;
diff --git a/send.c b/send.c
index d778ed60a95d3c3e0bfdc6e0e569b152b0eea770..4c9efc4758b22350f7fcc0e20fc52fc39ff28ed9 100644 (file)
--- a/send.c
+++ b/send.c
@@ -84,6 +84,9 @@
 #ifdef USE_IMAP
 #include "imap/imap.h"
 #endif
+#ifdef USE_AUTOCRYPT
+#include "autocrypt/autocrypt.h"
+#endif
 
 /* These Config Variables are only used in send.c */
 unsigned char C_AbortNoattach; ///< Config: Abort sending the email if attachments are missing
@@ -1603,17 +1606,17 @@ static int save_fcc(struct Email *e, char *fcc, size_t fcc_len, struct Body *cle
    * Protected Headers. */
   if (!C_FccBeforeSend)
   {
-    if ((WithCrypto != 0) && (e->security & (SEC_ENCRYPT | SEC_SIGN)) && C_FccClear)
+    if (WithCrypto && (e->security & (SEC_ENCRYPT | SEC_SIGN | SEC_AUTOCRYPT)) && C_FccClear)
     {
       e->content = clear_content;
-      e->security &= ~(SEC_ENCRYPT | SEC_SIGN);
+      e->security &= ~(SEC_ENCRYPT | SEC_SIGN | SEC_AUTOCRYPT);
       mutt_env_free(&e->content->mime_headers);
     }
 
     /* check to see if the user wants copies of all attachments */
     if (e->content->type == TYPE_MULTIPART)
     {
-      if ((WithCrypto != 0) && (e->security & (SEC_ENCRYPT | SEC_SIGN)) &&
+      if ((WithCrypto != 0) && (e->security & (SEC_ENCRYPT | SEC_SIGN | SEC_AUTOCRYPT)) &&
           ((mutt_str_strcmp(e->content->subtype, "encrypted") == 0) ||
            (mutt_str_strcmp(e->content->subtype, "signed") == 0)))
       {
@@ -1630,7 +1633,7 @@ static int save_fcc(struct Email *e, char *fcc, size_t fcc_len, struct Body *cle
           /* this means writing only the main part */
           e->content = clear_content->parts;
 
-          if (mutt_protect(e, pgpkeylist) == -1)
+          if (mutt_protect(e, pgpkeylist, 0) == -1)
           {
             /* we can't do much about it at this point, so
            * fallback to saving the whole thing to fcc */
@@ -1750,7 +1753,7 @@ static int postpone_message(struct Email *e_post, struct Email *e_cur, char *fcc
 
   mutt_encode_descriptions(e_post->content, true);
 
-  if ((WithCrypto != 0) && C_PostponeEncrypt && (e_post->security & SEC_ENCRYPT))
+  if (WithCrypto && C_PostponeEncrypt && (e_post->security & (SEC_ENCRYPT | SEC_AUTOCRYPT)))
   {
     if (((WithCrypto & APPLICATION_PGP) != 0) && (e_post->security & APPLICATION_PGP))
       encrypt_as = C_PgpDefaultKey;
@@ -1759,26 +1762,27 @@ static int postpone_message(struct Email *e_post, struct Email *e_cur, char *fcc
     if (!encrypt_as)
       encrypt_as = C_PostponeEncryptAs;
 
-    if (encrypt_as)
+#ifdef USE_AUTOCRYPT
+    if (e_post->security & SEC_AUTOCRYPT)
     {
-      bool is_signed = (e_post->security & SEC_SIGN);
-      if (is_signed)
-        e_post->security &= ~SEC_SIGN;
+      if (mutt_autocrypt_set_sign_as_default_key(e_post))
+        return -1;
+      encrypt_as = AutocryptDefaultKey;
+    }
+#endif
 
+    if (encrypt_as)
+    {
       pgpkeylist = mutt_str_strdup(encrypt_as);
       clear_content = e_post->content;
-      if (mutt_protect(e_post, pgpkeylist) == -1)
+      if (mutt_protect(e_post, pgpkeylist, 1) == -1)
       {
-        if (is_signed)
-          e_post->security |= SEC_SIGN;
         FREE(&pgpkeylist);
         e_post->content = mutt_remove_multipart(e_post->content);
         decode_descriptions(e_post->content);
         return -1;
       }
 
-      if (is_signed)
-        e_post->security |= SEC_SIGN;
       FREE(&pgpkeylist);
 
       mutt_encode_descriptions(e_post->content, false);
@@ -2241,23 +2245,36 @@ int ci_send_message(SendFlags flags, struct Email *e_templ, const char *tempfile
   if ((WithCrypto != 0) && (e_templ->security == 0) &&
       !(flags & (SEND_BATCH | SEND_MAILX | SEND_POSTPONED | SEND_RESEND)))
   {
-    if (C_CryptAutosign)
-      e_templ->security |= SEC_SIGN;
-    if (C_CryptAutoencrypt)
-      e_templ->security |= SEC_ENCRYPT;
-    if (C_CryptReplyencrypt && e_cur && (e_cur->security & SEC_ENCRYPT))
-      e_templ->security |= SEC_ENCRYPT;
-    if (C_CryptReplysign && e_cur && (e_cur->security & SEC_SIGN))
-      e_templ->security |= SEC_SIGN;
-    if (C_CryptReplysignencrypted && e_cur && (e_cur->security & SEC_ENCRYPT))
-      e_templ->security |= SEC_SIGN;
-    if (((WithCrypto & APPLICATION_PGP) != 0) &&
-        ((e_templ->security & (SEC_ENCRYPT | SEC_SIGN)) || C_CryptOpportunisticEncrypt))
-    {
-      if (C_PgpAutoinline)
-        e_templ->security |= SEC_INLINE;
-      if (C_PgpReplyinline && e_cur && (e_cur->security & SEC_INLINE))
-        e_templ->security |= SEC_INLINE;
+    if (
+#ifdef USE_AUTOCRYPT
+        C_Autocrypt
+#else
+        0
+#endif
+        && e_cur && (e_cur->security & SEC_AUTOCRYPT))
+    {
+      e_templ->security |= (SEC_AUTOCRYPT | SEC_AUTOCRYPT_OVERRIDE);
+    }
+    else
+    {
+      if (C_CryptAutosign)
+        e_templ->security |= SEC_SIGN;
+      if (C_CryptAutoencrypt)
+        e_templ->security |= SEC_ENCRYPT;
+      if (C_CryptReplyencrypt && e_cur && (e_cur->security & SEC_ENCRYPT))
+        e_templ->security |= SEC_ENCRYPT;
+      if (C_CryptReplysign && e_cur && (e_cur->security & SEC_SIGN))
+        e_templ->security |= SEC_SIGN;
+      if (C_CryptReplysignencrypted && e_cur && (e_cur->security & SEC_ENCRYPT))
+        e_templ->security |= SEC_SIGN;
+      if ((WithCrypto & APPLICATION_PGP) &&
+          ((e_templ->security & (SEC_ENCRYPT | SEC_SIGN)) || C_CryptOpportunisticEncrypt))
+      {
+        if (C_PgpAutoinline)
+          e_templ->security |= SEC_INLINE;
+        if (C_PgpReplyinline && e_cur && (e_cur->security & SEC_INLINE))
+          e_templ->security |= SEC_INLINE;
+      }
     }
 
     if (e_templ->security || C_CryptOpportunisticEncrypt)
@@ -2308,7 +2325,7 @@ int ci_send_message(SendFlags flags, struct Email *e_templ, const char *tempfile
       /* If something has already enabled encryption, e.g. C_CryptAutoencrypt
        * or C_CryptReplyencrypt, then don't enable opportunistic encrypt for
        * the message.  */
-      if (!(e_templ->security & SEC_ENCRYPT))
+      if (!(e_templ->security & (SEC_ENCRYPT | SEC_AUTOCRYPT)))
       {
         e_templ->security |= SEC_OPPENCRYPT;
         crypt_opportunistic_encrypt(e_templ);
@@ -2464,13 +2481,13 @@ int ci_send_message(SendFlags flags, struct Email *e_templ, const char *tempfile
 
   if (WithCrypto)
   {
-    if (e_templ->security & (SEC_ENCRYPT | SEC_SIGN))
+    if (e_templ->security & (SEC_ENCRYPT | SEC_SIGN | SEC_AUTOCRYPT))
     {
       /* save the decrypted attachments */
       clear_content = e_templ->content;
 
       if ((crypt_get_keys(e_templ, &pgpkeylist, 0) == -1) ||
-          (mutt_protect(e_templ, pgpkeylist) == -1))
+          (mutt_protect(e_templ, pgpkeylist, 0) == -1))
       {
         e_templ->content = mutt_remove_multipart(e_templ->content);
 
@@ -2511,7 +2528,7 @@ int ci_send_message(SendFlags flags, struct Email *e_templ, const char *tempfile
     {
       if (!WithCrypto)
         ;
-      else if ((e_templ->security & SEC_ENCRYPT) ||
+      else if ((e_templ->security & (SEC_ENCRYPT | SEC_AUTOCRYPT)) ||
                ((e_templ->security & SEC_SIGN) && (e_templ->content->type == TYPE_APPLICATION)))
       {
         mutt_body_free(&e_templ->content); /* destroy PGP data */
index 33ef9b974aae699c7ff67d4610da1ca81d35d48f..ac281e7f4b1b31393d6b6672c67bda6800d589bf 100644 (file)
--- a/sendlib.c
+++ b/sendlib.c
@@ -74,6 +74,9 @@
 #else
 #define EX_OK 0
 #endif
+#ifdef USE_AUTOCRYPT
+#include "autocrypt/autocrypt.h"
+#endif
 
 /* These Config Variables are only used in sendlib.c */
 bool C_Allow8bit; ///< Config: Allow 8-bit messages, don't use quoted-printable or base64
@@ -483,8 +486,15 @@ int mutt_write_mime_header(struct Body *a, FILE *fp)
   if (a->encoding != ENC_7BIT)
     fprintf(fp, "Content-Transfer-Encoding: %s\n", ENCODING(a->encoding));
 
-  if (C_CryptProtectedHeadersWrite && a->mime_headers)
+  if ((C_CryptProtectedHeadersWrite
+#ifdef USE_AUTOCRYPT
+       || C_Autocrypt
+#endif
+       ) &&
+      a->mime_headers)
+  {
     mutt_rfc822_write_header(fp, a->mime_headers, NULL, MUTT_WRITE_HEADER_MIME, false, false);
+  }
 
   /* Do NOT add the terminator here!!! */
   return ferror(fp) ? -1 : 0;
@@ -2359,6 +2369,16 @@ int mutt_rfc822_write_header(FILE *fp, struct Envelope *env,
     fputc('\n', fp);
   }
 
+#ifdef USE_AUTOCRYPT
+  if (C_Autocrypt)
+  {
+    if (mode == MUTT_WRITE_HEADER_NORMAL)
+      mutt_autocrypt_write_autocrypt_header(env, fp);
+    if (mode == MUTT_WRITE_HEADER_MIME)
+      mutt_autocrypt_write_gossip_headers(env, fp);
+  }
+#endif
+
   /* Add any user defined headers */
   struct ListNode *tmp = NULL;
   STAILQ_FOREACH(tmp, &env->userhdrs, entries)
@@ -3264,6 +3284,12 @@ int mutt_write_fcc(const char *path, struct Email *e, const char *msgid,
     }
     if (e->security & SEC_INLINE)
       fputc('I', msg->fp);
+#ifdef USE_AUTOCRYPT
+    if (e->security & SEC_AUTOCRYPT)
+      fputc('A', msg->fp);
+    if (e->security & SEC_AUTOCRYPT_OVERRIDE)
+      fputc('Z', msg->fp);
+#endif
     fputc('\n', msg->fp);
   }