Bug 1629195 - When importing OpenPGP secret key, also handle subkey password. r=PatrickBrunschwig DONTBUILD
authorKai Engert <kaie@kuix.de>
Sat, 11 Apr 2020 01:45:02 +0200
changeset 29251 960a0f2e22ef0fc8e240e82fb0b464c84c57753d
parent 29250 0cac707a2014c4c8c14b14a410630bdc9c14c847
child 29252 202c8ea2eccc7d6a2fc9d8d8d0a9b4d295d60faf
push id17274
push userkaie@kuix.de
push dateSat, 11 Apr 2020 21:13:45 +0000
treeherdercomm-central@960a0f2e22ef [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersPatrickBrunschwig
bugs1629195
Bug 1629195 - When importing OpenPGP secret key, also handle subkey password. r=PatrickBrunschwig DONTBUILD Differential Revision: https://phabricator.services.mozilla.com/D70581
mail/extensions/openpgp/content/modules/rnp.jsm
mail/extensions/openpgp/content/modules/rnpLib.jsm
--- a/mail/extensions/openpgp/content/modules/rnp.jsm
+++ b/mail/extensions/openpgp/content/modules/rnp.jsm
@@ -1134,17 +1134,19 @@ var RNP = {
     result.errorMsg = "";
 
     let tempFFI = new RNPLib.rnp_ffi_t();
     if (RNPLib.rnp_ffi_create(tempFFI.address(), "GPG", "GPG")) {
       throw new Error("Couldn't initialize librnp.");
     }
 
     // TODO: check result
-    this.importToFFI(tempFFI, keyBlockStr, pubkey, seckey);
+    if (this.importToFFI(tempFFI, keyBlockStr, pubkey, seckey)) {
+      throw new Error("RNP.importToFFI failed");
+    }
 
     let keys = await this.getKeysFromFFI(tempFFI, true);
 
     let recentPass = "";
 
     // Prior to importing, ensure we can unprotect all keys
     for (let ki = 0; ki < keys.length; ki++) {
       let k = keys[ki];
@@ -1153,16 +1155,32 @@ var RNP = {
         throw new Error("cannot get key handle for imported key: " + k.fpr);
       }
 
       if (k.secretAvailable) {
         while (!userFlags.canceled) {
           let rv = RNPLib.rnp_key_unprotect(impKey, recentPass);
 
           if (rv == 0) {
+            let sub_count = new ctypes.size_t();
+            if (RNPLib.rnp_key_get_subkey_count(impKey, sub_count.address())) {
+              throw new Error("rnp_key_get_subkey_count failed");
+            }
+            for (let i = 0; i < sub_count.value; i++) {
+              let sub_handle = new RNPLib.rnp_key_handle_t();
+              if (
+                RNPLib.rnp_key_get_subkey_at(impKey, i, sub_handle.address())
+              ) {
+                throw new Error("rnp_key_get_subkey_at failed");
+              }
+              if (RNPLib.rnp_key_unprotect(sub_handle, recentPass)) {
+                throw new Error("rnp_key_unprotect failed");
+              }
+              RNPLib.rnp_key_handle_destroy(sub_handle);
+            }
             break;
           }
 
           if (rv != RNPLib.RNP_ERROR_BAD_PASSWORD || !passCB) {
             throw new Error("rnp_key_unprotect failed");
           }
 
           recentPass = passCB(win, k.fpr, userFlags);
@@ -1175,30 +1193,16 @@ var RNP = {
       }
     }
 
     if (!userFlags.canceled) {
       for (let ki = 0; ki < keys.length; ki++) {
         let k = keys[ki];
         let impKey = await this.getKeyHandleByIdentifier(tempFFI, "0x" + k.fpr);
 
-        if (
-          k.secretAvailable &&
-          RNPLib.rnp_key_protect(
-            impKey,
-            OpenPGPMasterpass.retrieveOpenPGPPassword(),
-            null,
-            null,
-            null,
-            0
-          )
-        ) {
-          throw new Error("rnp_key_protect failed");
-        }
-
         let exportFlags =
           RNPLib.RNP_KEY_EXPORT_ARMORED | RNPLib.RNP_KEY_EXPORT_SUBKEYS;
 
         if (pubkey) {
           exportFlags |= RNPLib.RNP_KEY_EXPORT_PUBLIC;
         }
         if (seckey) {
           exportFlags |= RNPLib.RNP_KEY_EXPORT_SECRET;
@@ -1253,16 +1257,47 @@ var RNP = {
             input_from_memory,
             importFlags,
             null
           )
         ) {
           throw new Error("rnp_import_keys failed");
         }
 
+        let impKey2 = await this.getKeyHandleByIdentifier(
+          RNPLib.ffi,
+          "0x" + k.fpr
+        );
+
+        if (k.secretAvailable) {
+          let newPass = OpenPGPMasterpass.retrieveOpenPGPPassword();
+          if (RNPLib.rnp_key_protect(impKey2, newPass, null, null, null, 0)) {
+            throw new Error("rnp_key_protect failed");
+          }
+
+          let sub_count = new ctypes.size_t();
+          if (RNPLib.rnp_key_get_subkey_count(impKey2, sub_count.address())) {
+            throw new Error("rnp_key_get_subkey_count failed");
+          }
+          for (let i = 0; i < sub_count.value; i++) {
+            let sub_handle = new RNPLib.rnp_key_handle_t();
+            if (
+              RNPLib.rnp_key_get_subkey_at(impKey2, i, sub_handle.address())
+            ) {
+              throw new Error("rnp_key_get_subkey_at failed");
+            }
+            if (
+              RNPLib.rnp_key_protect(sub_handle, newPass, null, null, null, 0)
+            ) {
+              throw new Error("rnp_key_protect failed");
+            }
+            RNPLib.rnp_key_handle_destroy(sub_handle);
+          }
+        }
+
         result.importedKeys.push("0x" + k.id);
 
         RNPLib.rnp_input_destroy(input_from_memory);
         RNPLib.rnp_output_destroy(output_to_memory);
         RNPLib.rnp_key_handle_destroy(impKey);
       }
 
       result.exitCode = 0;
--- a/mail/extensions/openpgp/content/modules/rnpLib.jsm
+++ b/mail/extensions/openpgp/content/modules/rnpLib.jsm
@@ -658,16 +658,32 @@ function enableRNPLibJS() {
       rnp_key_handle_t,
       ctypes.char.ptr,
       ctypes.char.ptr,
       ctypes.char.ptr,
       ctypes.char.ptr,
       ctypes.size_t
     ),
 
+    rnp_key_is_protected: librnp.declare(
+      "rnp_key_is_protected",
+      abi,
+      rnp_result_t,
+      rnp_key_handle_t,
+      ctypes.bool.ptr
+    ),
+
+    rnp_key_is_locked: librnp.declare(
+      "rnp_key_is_locked",
+      abi,
+      rnp_result_t,
+      rnp_key_handle_t,
+      ctypes.bool.ptr
+    ),
+
     rnp_op_generate_create: librnp.declare(
       "rnp_op_generate_create",
       abi,
       rnp_result_t,
       rnp_op_generate_t.ptr,
       rnp_ffi_t,
       ctypes.char.ptr
     ),