Bug 1631198 - Allow manual import of autocrypt sender key. r=PatrickBrunschwig
authorKai Engert <kaie@kuix.de>
Sat, 18 Apr 2020 13:46:24 +0200
changeset 38019 804e09a2b5711c710984702bfca2551ac7d4e24d
parent 38018 7e71b9fa21f277a9a50d104010be3c188c69367a
child 38020 1265c97794fd1ceeccc482e571a6cf3d918507cf
push id2595
push userclokep@gmail.com
push dateMon, 04 May 2020 19:02:04 +0000
treeherdercomm-beta@f53913797371 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersPatrickBrunschwig
bugs1631198
Bug 1631198 - Allow manual import of autocrypt sender key. r=PatrickBrunschwig Differential Revision: https://phabricator.services.mozilla.com/D71451
mail/base/content/messageWindow.xhtml
mail/base/content/messenger.xhtml
mail/base/content/msgOpenPGPKey.inc.xhtml
mail/extensions/openpgp/content/modules/autocrypt.jsm
mail/extensions/openpgp/content/modules/decryption.jsm
mail/extensions/openpgp/content/modules/key.jsm
mail/extensions/openpgp/content/modules/keyRing.jsm
mail/extensions/openpgp/content/modules/keyserver.jsm
mail/extensions/openpgp/content/modules/rnp.jsm
mail/extensions/openpgp/content/modules/wkdLookup.jsm
mail/extensions/openpgp/content/strings/bond.dtd
mail/extensions/openpgp/content/ui/enigmailKeyManager.js
mail/extensions/openpgp/content/ui/enigmailMessengerOverlay.js
mail/themes/linux/mail/messageHeader.css
--- a/mail/base/content/messageWindow.xhtml
+++ b/mail/base/content/messageWindow.xhtml
@@ -262,16 +262,21 @@
                messagemanagergroup="browsers"
                onclick="return contentAreaClick(event);"
                oncontextmenu="return mailContextOnContextMenu(event);"
                onresize="return messagePaneOnResize(event);"/>
       <splitter id="attachment-splitter" collapse="after" resizebefore="closest" resizeafter="closest" collapsed="true"/>
       <vbox id="attachmentView" collapsed="true">
 #include msgAttachmentView.inc.xhtml
       </vbox>
+#ifdef MOZ_OPENPGP
+      <vbox>
+#include msgOpenPGPKey.inc.xhtml
+      </vbox>
+#endif
       <findbar id="FindToolbar" browserid="messagepane"/>
     </vbox>
   </hbox>
   <panel id="customizeToolbarSheetPopup" noautohide="true">
     <iframe id="customizeToolbarSheetIFrame"
             style="&dialog.dimensions;"
             hidden="true"/>
   </panel>
--- a/mail/base/content/messenger.xhtml
+++ b/mail/base/content/messenger.xhtml
@@ -816,16 +816,21 @@
                         </stack>
                       </hbox>
                       <splitter id="attachment-splitter" collapse="after"
                                 resizebefore="closest" resizeafter="closest"
                                 collapsed="true"/>
                       <vbox id="attachmentView" collapsed="true">
 #include msgAttachmentView.inc.xhtml
                       </vbox>
+#ifdef MOZ_OPENPGP
+                      <vbox>
+#include msgOpenPGPKey.inc.xhtml
+                      </vbox>
+#endif
                       <findbar id="FindToolbar" browserid="messagepane"/>
                     </vbox>
                   </vbox>
                 </hbox>
                 <hbox id="messenger-notification-footer">
                   <!-- notificationbox will be added here lazily. -->
                 </hbox>
               </box>
new file mode 100644
--- /dev/null
+++ b/mail/base/content/msgOpenPGPKey.inc.xhtml
@@ -0,0 +1,11 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+                        <hbox id="openpgpKeyBox" hidden="true">
+                          <label id="hasKeyOpenPGP" value="&enigmail.hasSenderKey.label;"/>
+                           <toolbarbutton id="openpgpImportButton"
+                                         label="&enigmail.importSenderKey.label;"
+                                         oncommand="Enigmail.msg.importAutocryptKeydata();"/>
+                        </hbox>
+
--- a/mail/extensions/openpgp/content/modules/autocrypt.jsm
+++ b/mail/extensions/openpgp/content/modules/autocrypt.jsm
@@ -43,16 +43,108 @@ const { EnigmailStdlib } = ChromeUtils.i
 );
 const { EnigmailCryptoAPI } = ChromeUtils.import(
   "chrome://openpgp/content/modules/cryptoAPI.jsm"
 );
 
 var gCreatedSetupIds = [];
 
 var EnigmailAutocrypt = {
+  getKeyFromHeader(fromAddr, headerDataArr) {
+    // critical parameters: {param: mandatory}
+    const CRITICAL = {
+      addr: true,
+      keydata: true,
+      type: false, // That's actually oboslete according to the Level 1 spec.
+    };
+
+    try {
+      fromAddr = EnigmailFuncs.stripEmail(fromAddr).toLowerCase();
+    } catch (ex) {
+      throw new Error("getKeyFromHeader error " + ex);
+    }
+    let foundTypes = {};
+    let paramArr = [];
+
+    for (let hdrNum = 0; hdrNum < headerDataArr.length; hdrNum++) {
+      let hdr = headerDataArr[hdrNum].replace(/[\r\n \t]/g, "");
+      let k = hdr.search(/keydata=/);
+      if (k > 0) {
+        let d = hdr.substr(k);
+        if (d.search(/"/) < 0) {
+          hdr = hdr.replace(/keydata=/, 'keydata="') + '"';
+        }
+      }
+
+      paramArr = EnigmailMime.getAllParameters(hdr);
+
+      for (let i in CRITICAL) {
+        if (CRITICAL[i]) {
+          // found mandatory parameter
+          if (!(i in paramArr)) {
+            EnigmailLog.DEBUG(
+              "autocrypt.jsm: getKeyFromHeader: cannot find param '" + i + "'\n"
+            );
+            return null; // do nothing if not all mandatory parts are present
+          }
+        }
+      }
+
+      paramArr.addr = paramArr.addr.toLowerCase();
+
+      if (fromAddr !== paramArr.addr) {
+        EnigmailLog.DEBUG(
+          "autocrypt.jsm: getKeyFromHeader: from Addr " +
+            fromAddr +
+            " != " +
+            paramArr.addr.toLowerCase() +
+            "\n"
+        );
+
+        return null;
+      }
+
+      if (!("type" in paramArr)) {
+        paramArr.type = "1";
+      } else {
+        paramArr.type = paramArr.type.toLowerCase();
+        if (paramArr.type !== "1") {
+          EnigmailLog.DEBUG(
+            "autocrypt.jsm: getKeyFromHeader: unknown type " +
+              paramArr.type +
+              "\n"
+          );
+          return null; // we currently only support 1 (=OpenPGP)
+        }
+      }
+
+      try {
+        atob(paramArr.keydata); // don't need result
+      } catch (ex) {
+        EnigmailLog.DEBUG(
+          "autocrypt.jsm: getKeyFromHeader: key is not base64-encoded\n"
+        );
+        return null;
+      }
+
+      if (paramArr.type in foundTypes) {
+        EnigmailLog.DEBUG(
+          "autocrypt.jsm: getKeyFromHeader: duplicate header for type=" +
+            paramArr.type +
+            "\n"
+        );
+        return null; // do not process anything if more than one Autocrypt header for the same type is found
+      }
+
+      foundTypes[paramArr.type] = 1;
+    }
+
+    return paramArr.keydata;
+  },
+
   /**
    * Process the "Autocrypt:" header and if successful store the update in the database
    *
    * @param {String} fromAddr:               Address of sender (From: header)
    * @param {Array of String} headerDataArr: all instances of the Autocrypt: header found in the message
    * @param {String or Number} dateSent:     "Date:" field of the message as readable string or in seconds after 1970-01-01
    * @param {Boolean} autoCryptEnabled:      if true, autocrypt is enabled for the context of the message
    *
@@ -317,17 +409,17 @@ var EnigmailAutocrypt = {
     let keysObj = {};
     let importedKeys = [];
 
     // TODO: need a MPL version of bytesToArmor
     let pubkey = EnigmailOpenPGP.enigmailFuncs.bytesToArmor(
       EnigmailOpenPGP.armor.public_key,
       keyData
     );
-    await EnigmailKeyRing.importKeyAsync(null, false, pubkey, "", {}, keysObj);
+    await EnigmailKeyRing.importKeyAsync(null, false, pubkey, false, "", {}, keysObj);
 
     if (keysObj.value) {
       importedKeys = importedKeys.concat(keysObj.value);
 
       if (keysObj.value.length > 0) {
         let key = EnigmailKeyRing.getKeyById(keysObj.value[0]);
 
         // enable encryption if state (prefer-encrypt) is "mutual";
@@ -1161,17 +1253,17 @@ function importSetupKey(keyData) {
     {}
   );
   if (msgType === "PRIVATE KEY BLOCK") {
     let headers = EnigmailArmor.getArmorHeaders(keyData);
     if ("autocrypt-prefer-encrypt" in headers) {
       preferEncrypt = headers["autocrypt-prefer-encrypt"];
     }
 
-    let r = EnigmailKeyRing.importKey(null, false, keyData, "", {}, keyObj);
+    let r = EnigmailKeyRing.importKey(null, false, keyData, false, "", {}, keyObj);
 
     if (r === 0 && keyObj.value && keyObj.value.length > 0) {
       return {
         fpr: keyObj.value[0],
         preferEncrypt,
       };
     }
   }
--- a/mail/extensions/openpgp/content/modules/decryption.jsm
+++ b/mail/extensions/openpgp/content/modules/decryption.jsm
@@ -259,16 +259,17 @@ var EnigmailDecryption = {
         return "";
       }
 
       // Import public key
       exitCodeObj.value = EnigmailKeyRing.importKey(
         parent,
         true,
         pgpBlock,
+        false,
         "",
         errorMsgObj
       );
       if (exitCodeObj.value === 0) {
         statusFlagsObj.value |= EnigmailConstants.IMPORTED_KEY;
       }
       return "";
     }
@@ -444,16 +445,17 @@ var EnigmailDecryption = {
       var importedKey = false;
 
       if (innerKeyBlock) {
         var importErrorMsgObj = {};
         var exitStatus = EnigmailKeyRing.importKey(
           parent,
           true,
           innerKeyBlock,
+          false,
           pubKeyId,
           importErrorMsgObj
         );
 
         importedKey = exitStatus === 0;
 
         if (exitStatus > 0) {
           EnigmailDialog.alert(
@@ -587,16 +589,17 @@ var EnigmailDecryption = {
               );
             }
 
             if (exitStatus) {
               exitCodeObj.value = EnigmailKeyRing.importKey(
                 parent,
                 false,
                 byteData,
+                false,
                 "",
                 errorMsgObj
               );
               statusFlagsObj.value = EnigmailConstants.IMPORTED_KEY;
             } else {
               exitCodeObj.value = 0;
               statusFlagsObj.value = EnigmailConstants.DISPLAY_MESSAGE;
             }
--- a/mail/extensions/openpgp/content/modules/key.jsm
+++ b/mail/extensions/openpgp/content/modules/key.jsm
@@ -89,18 +89,24 @@ var EnigmailKey = {
             EnigmailLocale.getString("keyMan.button.revokeKey")
           )
         ) {
           return;
         }
 
         let errorMsgObj = {};
         if (
-          getKeyRing().importKey(null, false, keyBlockStr, keyId, errorMsgObj) >
-          0
+          getKeyRing().importKey(
+            null,
+            false,
+            keyBlockStr,
+            false,
+            keyId,
+            errorMsgObj
+          ) > 0
         ) {
           getDialog().alert(null, errorMsgObj.value);
         }
       }
     } else {
       // Suitable key for revocation certificate is not present in keyring
       getDialog().alert(
         null,
--- a/mail/extensions/openpgp/content/modules/keyRing.jsm
+++ b/mail/extensions/openpgp/content/modules/keyRing.jsm
@@ -513,28 +513,30 @@ var EnigmailKeyRing = {
    *      ExitCode == 0  => success
    *      ExitCode > 0   => error
    *      ExitCode == -1 => Cancelled by user
    */
   importKey(
     parent,
     isInteractive,
     keyBlock,
+    isBinary,
     keyId,
     errorMsgObj,
     importedKeysObj,
     minimizeKey = false,
     limitedUids = []
   ) {
     const cApi = EnigmailCryptoAPI();
     return cApi.sync(
       this.importKeyAsync(
         parent,
         isInteractive,
         keyBlock,
+        isBinary,
         keyId,
         errorMsgObj,
         importedKeysObj,
         minimizeKey,
         limitedUids
       )
     );
   },
@@ -555,51 +557,55 @@ var EnigmailKeyRing = {
    *      ExitCode == 0  => success
    *      ExitCode > 0   => error
    *      ExitCode == -1 => Cancelled by user
    */
   async importKeyAsync(
     parent,
     isInteractive,
     keyBlock,
+    isBinary,
     keyId,
     errorMsgObj,
     importedKeysObj,
     minimizeKey = false,
     limitedUids = []
   ) {
     EnigmailLog.DEBUG(
       `keyRing.jsm: EnigmailKeyRing.importKeyAsync('${keyId}', ${isInteractive}, ${minimizeKey})\n`
     );
 
-    const beginIndexObj = {};
-    const endIndexObj = {};
-    const blockType = EnigmailArmor.locateArmoredBlock(
-      keyBlock,
-      0,
-      "",
-      beginIndexObj,
-      endIndexObj,
-      {}
-    );
-    if (!blockType) {
-      errorMsgObj.value = EnigmailLocale.getString("noPGPblock");
-      return 1;
+    var pgpBlock;
+    if (!isBinary) {
+      const beginIndexObj = {};
+      const endIndexObj = {};
+      const blockType = EnigmailArmor.locateArmoredBlock(
+        keyBlock,
+        0,
+        "",
+        beginIndexObj,
+        endIndexObj,
+        {}
+      );
+      if (!blockType) {
+        errorMsgObj.value = EnigmailLocale.getString("noPGPblock");
+        return 1;
+      }
+
+      if (blockType.search(/^(PUBLIC|PRIVATE) KEY BLOCK$/) !== 0) {
+        errorMsgObj.value = EnigmailLocale.getString("notFirstBlock");
+        return 1;
+      }
+
+      pgpBlock = keyBlock.substr(
+        beginIndexObj.value,
+        endIndexObj.value - beginIndexObj.value + 1
+      );
     }
 
-    if (blockType.search(/^(PUBLIC|PRIVATE) KEY BLOCK$/) !== 0) {
-      errorMsgObj.value = EnigmailLocale.getString("notFirstBlock");
-      return 1;
-    }
-
-    const pgpBlock = keyBlock.substr(
-      beginIndexObj.value,
-      endIndexObj.value - beginIndexObj.value + 1
-    );
-
     if (isInteractive) {
       if (
         !getDialog().confirmDlg(
           parent,
           EnigmailLocale.getString("importKeyConfirm"),
           EnigmailLocale.getString("keyMan.button.import")
         )
       ) {
@@ -612,17 +618,21 @@ var EnigmailKeyRing = {
       throw new Error("importKeyAsync with limitedUids: not implemented");
     }
 
     if (minimizeKey) {
       throw new Error("importKeyAsync with minimizeKey: not implemented");
     }
 
     const cApi = EnigmailCryptoAPI();
-    cApi.sync(cApi.importKeyBlock(pgpBlock, true, false)); // public only
+    if (isBinary) {
+      cApi.sync(cApi.importKeyBlock(keyBlock, true, false)); // public only
+    } else {
+      cApi.sync(cApi.importKeyBlock(pgpBlock, true, false)); // public only
+    }
 
     if (!importedKeysObj) {
       importedKeysObj = {};
     }
     importedKeysObj.value = [];
 
     let exitCode = 0;
 
--- a/mail/extensions/openpgp/content/modules/keyserver.jsm
+++ b/mail/extensions/openpgp/content/modules/keyserver.jsm
@@ -318,16 +318,17 @@ const accessHkpInternal = {
                 importedKeysObj = {};
               let importMinimal =
                 xmlReq.responseText.length > 1024000 &&
                 !EnigmailGpg.getGpgFeature("handles-huge-keys");
               let r = EnigmailKeyRing.importKey(
                 null,
                 false,
                 xmlReq.responseText,
+                false,
                 "",
                 errorMsgObj,
                 importedKeysObj,
                 importMinimal
               );
               if (r === 0) {
                 resolve(importedKeysObj.value);
               } else {
@@ -734,16 +735,17 @@ const accessKeyBase = {
 
                     if (resp.them[hit] !== null) {
                       let errorMsgObj = {},
                         importedKeysObj = {};
                       let r = EnigmailKeyRing.importKey(
                         null,
                         false,
                         resp.them[hit].public_keys.primary.bundle,
+                        false,
                         "",
                         errorMsgObj,
                         importedKeysObj
                       );
                       if (r === 0) {
                         imported.push(importedKeysObj.value);
                       }
                     }
@@ -1415,16 +1417,17 @@ const accessVksServer = {
               reject(createError(EnigmailConstants.KEYSERVER_ERR_SERVER_ERROR));
             } else {
               let errorMsgObj = {},
                 importedKeysObj = {};
               let r = EnigmailKeyRing.importKey(
                 null,
                 false,
                 xmlReq.responseText,
+                false,
                 "",
                 errorMsgObj,
                 importedKeysObj
               );
               if (r === 0) {
                 resolve(importedKeysObj.value);
               } else {
                 reject(
--- a/mail/extensions/openpgp/content/modules/rnp.jsm
+++ b/mail/extensions/openpgp/content/modules/rnp.jsm
@@ -1014,21 +1014,25 @@ var RNP = {
 
   saveKeyRings() {
     RNPLib.saveKeys();
   },
 
   importToFFI(ffi, keyBlockStr, usePublic, useSecret) {
     let input_from_memory = new RNPLib.rnp_input_t();
 
-    var tmp_array = ctypes.char.array()(keyBlockStr);
-    var key_array = ctypes.cast(
-      tmp_array,
-      ctypes.uint8_t.array(keyBlockStr.length)
-    );
+    if (!keyBlockStr) {
+      throw new Error("no keyBlockStr parameter in importToFFI");
+    }
+
+    let arr = [];
+    for (let i = 0; i < keyBlockStr.length; i++) {
+      arr[i] = keyBlockStr.charCodeAt(i);
+    }
+    var key_array = ctypes.uint8_t.array()(arr);
 
     if (
       RNPLib.rnp_input_from_memory(
         input_from_memory.address(),
         key_array,
         keyBlockStr.length,
         false
       )
@@ -1052,21 +1056,23 @@ var RNP = {
       flags,
       jsonInfo.address()
     );
 
     // TODO: parse jsonInfo and return a list of keys,
     // as seen in keyRing.importKeyAsync.
     // (should prevent the incorrect popup "no keys imported".)
 
-    console.debug(
-      "result key listing, rv= %s, result= %s",
-      rv,
-      jsonInfo.readString()
-    );
+    if (!rv) {
+      console.debug(
+        "result key listing, rv= %s, result= %s",
+        rv,
+        jsonInfo.readString()
+      );
+    }
 
     RNPLib.rnp_buffer_destroy(jsonInfo);
     RNPLib.rnp_input_destroy(input_from_memory);
 
     return rv;
   },
 
   isSimpleASCII(str) {
@@ -1087,19 +1093,19 @@ var RNP = {
       }
     }
     return true;
   },
 
   async getKeyListFromKeyBlock(keyBlockStr, pubkey = true, seckey = false) {
     // Create a separate, temporary RNP storage area (FFI),
     // import the key block into it, then get the listing.
-    if (!this.isSimpleASCII(keyBlockStr)) {
-      return null;
-    }
+    //if (!this.isSimpleASCII(keyBlockStr)) {
+    //  return null;
+    //}
 
     let tempFFI = new RNPLib.rnp_ffi_t();
     if (RNPLib.rnp_ffi_create(tempFFI.address(), "GPG", "GPG")) {
       throw new Error("Couldn't initialize librnp.");
     }
 
     // check result
     this.importToFFI(tempFFI, keyBlockStr, pubkey, seckey);
--- a/mail/extensions/openpgp/content/modules/wkdLookup.jsm
+++ b/mail/extensions/openpgp/content/modules/wkdLookup.jsm
@@ -562,17 +562,17 @@ function importDownloadedKeys(keysArr) {
   }
 
   let keyList = EnigmailKey.getKeyListFromKeyBlock(keyData, {}, false);
 
   for (let k in keyList) {
     EnigmailLog.DEBUG("wkdLookup.jsm: importDownloadedKeys: fpr=" + keyList[k].fpr + "\n");
   }
 
-  EnigmailKeyRing.importKey(null, false, keyData, "", {}, {}, false, domainArr);
+  EnigmailKeyRing.importKey(null, false, keyData, false, "", {}, {}, false, domainArr);
   */
 }
 
 /**
  * Get special URLs for specific sites that don't use WKD, but still provide
  * public keys of their users in
  *
  * @param {String}: emailAddr: email address in lowercase
--- a/mail/extensions/openpgp/content/strings/bond.dtd
+++ b/mail/extensions/openpgp/content/strings/bond.dtd
@@ -4,8 +4,11 @@
 <!ENTITY enigmail.ctxDecryptOpen.label              "Decrypt and Open">
 <!ENTITY enigmail.ctxDecryptSave.label              "Decrypt and Save As...">
 <!ENTITY enigmail.ctxImportKey.label                "Import OpenPGP Key">
 <!ENTITY enigmail.ctxVerifyAtt.label                "Verify signature">
 <!ENTITY enigmail.ctxDecryptOpen.accesskey          "D">
 <!ENTITY enigmail.ctxDecryptSave.accesskey          "C">
 <!ENTITY enigmail.ctxImportKey.accesskey            "I">
 <!ENTITY enigmail.ctxVerifyAtt.accesskey            "V">
+
+<!ENTITY enigmail.hasSenderKey.label                "This message claims to contain the sender's OpenPGP public key.">
+<!ENTITY enigmail.importSenderKey.label             "Import…">
--- a/mail/extensions/openpgp/content/ui/enigmailKeyManager.js
+++ b/mail/extensions/openpgp/content/ui/enigmailKeyManager.js
@@ -740,17 +740,24 @@ function enigmailImportFromClipbrd() {
             })
             .join("\n"),
         ])
       );
     }
 
     if (exitStatus) {
       // import
-      EnigmailKeyRing.importKey(window, false, cBoardContent, "", errorMsgObj);
+      EnigmailKeyRing.importKey(
+        window,
+        false,
+        cBoardContent,
+        false,
+        "",
+        errorMsgObj
+      );
       var keyList = preview.map(function(a) {
         return a.id;
       });
       EnigmailDialog.keyImportDlg(window, keyList);
       refreshKeys();
     }
   }
 }
@@ -1050,17 +1057,24 @@ function enigmailImportKeysFromUrl() {
                     return "\t" + a.name + " (" + a.id + ")";
                   })
                   .join("\n"),
               ])
             );
           }
 
           if (exitStatus) {
-            EnigmailKeyRing.importKey(window, false, data, "", errorMsgObj);
+            EnigmailKeyRing.importKey(
+              window,
+              false,
+              data,
+              false,
+              "",
+              errorMsgObj
+            );
             errorMsgObj.preview = preview;
             resolve(errorMsgObj);
           }
         }
       };
 
       try {
         var bufferListener = EnigmailStreams.newStringStreamListener(cbFunc);
--- a/mail/extensions/openpgp/content/ui/enigmailMessengerOverlay.js
+++ b/mail/extensions/openpgp/content/ui/enigmailMessengerOverlay.js
@@ -96,21 +96,19 @@ var EnigmailConstants = ChromeUtils.impo
   "chrome://openpgp/content/modules/constants.jsm"
 ).EnigmailConstants;
 var EnigmailURIs = ChromeUtils.import(
   "chrome://openpgp/content/modules/uris.jsm"
 ).EnigmailURIs;
 var EnigmailProtocolHandler = ChromeUtils.import(
   "chrome://openpgp/content/modules/protocolHandler.jsm"
 ).EnigmailProtocolHandler;
-/*
 var EnigmailAutocrypt = ChromeUtils.import(
   "chrome://openpgp/content/modules/autocrypt.jsm"
 ).EnigmailAutocrypt;
-*/
 var EnigmailMime = ChromeUtils.import(
   "chrome://openpgp/content/modules/mime.jsm"
 ).EnigmailMime;
 var EnigmailArmor = ChromeUtils.import(
   "chrome://openpgp/content/modules/armor.jsm"
 ).EnigmailArmor;
 /*
 var EnigmailWks = ChromeUtils.import(
@@ -299,16 +297,19 @@ Enigmail.msg = {
     EnigmailMsgRead.ensureExtraAddonHeaders();
     gMessageListeners.push(Enigmail.msg.messageListener);
     Enigmail.msg.messageListener.onEndHeaders();
   },
 
   messageListener: {
     onStartHeaders() {
       Enigmail.msg.mimeParts = null;
+      let b = document.getElementById("openpgpKeyBox");
+      b.setAttribute("hidden", true);
+      b.removeAttribute("keydata");
       /*
       if ("autocrypt" in gExpandedHeaderView) {
         delete gExpandedHeaderView.autocrypt;
       }
       */
       if ("openpgp" in gExpandedHeaderView) {
         delete gExpandedHeaderView.openpgp;
       }
@@ -767,28 +768,26 @@ Enigmail.msg = {
           body: "",
           parent: null,
           subParts: [],
         };
       }
 
       // Copy selected headers
       Enigmail.msg.savedHeaders = {
-        //autocrypt: [],
+        autocrypt: [],
       };
 
-      /*
       for (let h in currentHeaderData) {
         if (h.search(/^autocrypt\d*$/) === 0) {
           Enigmail.msg.savedHeaders.autocrypt.push(
             currentHeaderData[h].headerValue
           );
         }
       }
-      */
 
       if (!mimeMsg.fullContentType) {
         mimeMsg.fullContentType = "text/plain";
       }
 
       Enigmail.msg.savedHeaders["content-type"] = mimeMsg.fullContentType;
       this.mimeParts = mimeMsg;
 
@@ -809,37 +808,48 @@ Enigmail.msg = {
           "enigmailMessengerOverlay.js: header " +
             headerName +
             ": '" +
             headerValue +
             "'\n"
         );
       }
 
-      /*
+      let senderAutocryptKey = null;
       if (
         "autocrypt" in Enigmail.msg.savedHeaders &&
         Enigmail.msg.savedHeaders.autocrypt.length > 0 &&
         "from" in currentHeaderData
       ) {
+        /*
         let dateValue = "";
         if ("date" in currentHeaderData) {
           dateValue = currentHeaderData.date.headerValue;
         }
 
         EnigmailAutocrypt.processAutocryptHeader(
           currentHeaderData.from.headerValue,
           Enigmail.msg.savedHeaders.autocrypt,
           dateValue,
           Enigmail.msg.isAutocryptEnabled()
         );
+        */
+
+        senderAutocryptKey = EnigmailAutocrypt.getKeyFromHeader(
+          currentHeaderData.from.headerValue,
+          Enigmail.msg.savedHeaders.autocrypt
+        );
+        if (senderAutocryptKey) {
+          let b = document.getElementById("openpgpKeyBox");
+          b.setAttribute("hidden", false);
+          b.setAttribute("keydata", senderAutocryptKey);
+        }
       } else {
-        Enigmail.msg.createArtificialAutocryptHeader();
+        //Enigmail.msg.createArtificialAutocryptHeader();
       }
-      */
 
       var msgSigned =
         mimeMsg.fullContentType.search(/^multipart\/signed/i) === 0 &&
         EnigmailMime.getProtocol(mimeMsg.fullContentType).search(
           /^application\/pgp-signature/i
         ) === 0;
       var msgEncrypted =
         mimeMsg.fullContentType.search(/^multipart\/encrypted/i) === 0 &&
@@ -1759,16 +1769,36 @@ Enigmail.msg = {
       }
     }
 
     EnigmailLog.ERROR(
       "enigmailMessengerOverlay.js: no node found to replace message display\n"
     );
   },
 
+  importAutocryptKeydata() {
+    let keyDataB64 = document
+      .getElementById("openpgpKeyBox")
+      .getAttribute("keydata");
+    if (!keyDataB64) {
+      return;
+    }
+    let keyData = EnigmailData.decodeBase64(keyDataB64);
+    let errorMsgObj = {};
+    let preview = EnigmailKey.getKeyListFromKeyBlock(keyData, errorMsgObj);
+    if (errorMsgObj.value === "") {
+      this.importKeyDataWithConfirmation(preview, keyData, true);
+    } else {
+      EnigmailDialog.alert(
+        window,
+        EnigmailLocale.getString("previewFailed") + "\n" + errorMsgObj.value
+      );
+    }
+  },
+
   importKeyFromMsgBody(msgData) {
     let beginIndexObj = {};
     let endIndexObj = {};
     let indentStrObj = {};
     let blockType = EnigmailArmor.locateArmoredBlock(
       msgData,
       0,
       "",
@@ -1780,26 +1810,26 @@ Enigmail.msg = {
       return;
     }
 
     let keyData = msgData.substring(beginIndexObj.value, endIndexObj.value);
 
     let errorMsgObj = {};
     let preview = EnigmailKey.getKeyListFromKeyBlock(keyData, errorMsgObj);
     if (errorMsgObj.value === "") {
-      this.importKeyDataWithConfirmation(preview, keyData);
+      this.importKeyDataWithConfirmation(preview, keyData, false);
     } else {
       EnigmailDialog.alert(
         window,
         EnigmailLocale.getString("previewFailed") + "\n" + errorMsgObj.value
       );
     }
   },
 
-  importKeyDataWithConfirmation(preview, keyData) {
+  importKeyDataWithConfirmation(preview, keyData, isBinary) {
     let exitStatus = -1,
       errorMsgObj = {};
     if (preview.length > 0) {
       if (preview.length == 1) {
         exitStatus = EnigmailDialog.confirmDlg(
           window,
           EnigmailLocale.getString("doImportOne", [
             preview[0].name,
@@ -1820,16 +1850,17 @@ Enigmail.msg = {
       }
 
       if (exitStatus) {
         try {
           exitStatus = EnigmailKeyRing.importKey(
             window,
             false,
             keyData,
+            isBinary,
             "",
             errorMsgObj
           );
         } catch (ex) {}
 
         if (exitStatus === 0) {
           var keyList = preview.map(function(a) {
             return a.id;
@@ -2822,17 +2853,17 @@ Enigmail.msg = {
           preview = EnigmailKey.getKeyListFromKeyBlock(
             callbackArg.data,
             errorMsgObj
           );
         }
       }
 
       if (errorMsgObj.value === "") {
-        this.importKeyDataWithConfirmation(preview, callbackArg.data);
+        this.importKeyDataWithConfirmation(preview, callbackArg.data, false);
       } else {
         EnigmailDialog.alert(
           window,
           EnigmailLocale.getString("previewFailed") + "\n" + errorMsgObj.value
         );
       }
       outFile.remove(true);
       return;
--- a/mail/themes/linux/mail/messageHeader.css
+++ b/mail/themes/linux/mail/messageHeader.css
@@ -166,16 +166,20 @@
   list-style-image: url("chrome://messenger/skin/icons/delete.svg");
 }
 
 #attachmentSaveAllSingle,
 #attachmentSaveAllMultiple {
   list-style-image: url("chrome://messenger/skin/icons/save.svg");
 }
 
+#openpgpImportButton {
+  list-style-image: url("chrome://messenger/skin/icons/encryption-key.svg");
+}
+
 .headerName {
   color: #888a85; /* lower contrast */
   text-align: right;
   background-color: transparent;
   padding: 0px;
   margin-inline-end: 3px;
 }