From 88ed121f2406fcec2f383d1cdc79359c2c878998 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Mon, 20 Jun 2016 19:29:49 +0200 Subject: [PATCH] Enigma: Add possibility to export private keys (#5321) --- CHANGELOG | 1 + plugins/enigma/enigma.js | 43 ++++++++++++++++++++- plugins/enigma/lib/enigma_driver.php | 3 +- plugins/enigma/lib/enigma_driver_gnupg.php | 12 +++++- plugins/enigma/lib/enigma_driver_phpssl.php | 4 ++ plugins/enigma/lib/enigma_engine.php | 5 ++- plugins/enigma/lib/enigma_key.php | 14 +++++++ plugins/enigma/lib/enigma_ui.php | 14 +++++-- plugins/enigma/localization/en_US.inc | 4 ++ 9 files changed, 89 insertions(+), 11 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 25d734fb728..888c9bed555 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -28,6 +28,7 @@ CHANGELOG Roundcube Webmail - Enigma: Fix keys import from inside of an encrypted message (#5285) - Enigma: Fix malformed signed messages with force_7bit=true (#5292) - Enigma: Add possibility to configure gpg binary location (enigma_pgp_binary) +- Enigma: Add possibility to export private keys (#5321) - Fix searching by email address in contacts with multiple addresses (#5291) - Fix handling of --delete argument in moduserprefs.sh script (#5296) - Workaround PHP issue by calling closelog() on script shutdown when using log_driver=syslog (#5289) diff --git a/plugins/enigma/enigma.js b/plugins/enigma/enigma.js index 1318a4352f0..4119f0aa32e 100644 --- a/plugins/enigma/enigma.js +++ b/plugins/enigma/enigma.js @@ -150,12 +150,50 @@ rcube_webmail.prototype.enigma_delete = function() // Export key(s) rcube_webmail.prototype.enigma_export = function(selected) { - var keys = selected ? this.keys_list.get_selection().join(',') : '*'; + var priv = false, + list = this.keys_list, + keys = selected ? list.get_selection().join(',') : '*', + args = {_a: 'export', _keys: keys}; if (!keys.length) return; - this.goto_url('plugin.enigmakeys', {_a: 'export', _keys: keys}, false, true); + // find out wether selected keys are private + if (keys == '*') + priv = true; + else + $.each(list.get_selection(), function() { + flags = $(list.rows[this].obj).data('flags'); + if (flags && flags.indexOf('p') >= 0) { + priv = true; + return false; + } + }); + + // ask the user about including private key in the export + if (priv) + return this.show_popup_dialog( + this.get_label('enigma.keyexportprompt'), + this.get_label('enigma.exportkeys'), + [{ + text: this.get_label('enigma.onlypubkeys'), + click: function(e) { + rcmail.goto_url('plugin.enigmakeys', args, false, true); + $(this).remove(); + } + }, + { + text: this.get_label('enigma.withprivkeys'), + click: function(e) { + args._priv = 1; + rcmail.goto_url('plugin.enigmakeys', args, false, true); + $(this).remove(); + } + }], + {width: 400} + ); + + this.goto_url('plugin.enigmakeys', args, false, true); }; // Submit key(s) import form @@ -318,6 +356,7 @@ rcube_webmail.prototype.enigma_add_list_row = function(r) row.id = 'rcmrow' + r.id; row.className = css_class; + if (r.flags) $(row).data('flags', r.flags); col.innerHTML = r.name; row.appendChild(col); diff --git a/plugins/enigma/lib/enigma_driver.php b/plugins/enigma/lib/enigma_driver.php index d0d3918d5d7..1ed5fbc3d9c 100644 --- a/plugins/enigma/lib/enigma_driver.php +++ b/plugins/enigma/lib/enigma_driver.php @@ -88,10 +88,11 @@ abstract function import($content, $isfile = false); * Key/Cert export. * * @param string Key ID + * @param bool Include private key * * @return mixed Key content or enigma_error */ - abstract function export($key); + abstract function export($key, $with_private = false); /** * Keys listing. diff --git a/plugins/enigma/lib/enigma_driver_gnupg.php b/plugins/enigma/lib/enigma_driver_gnupg.php index 0b2f51a1c65..9d7998c61df 100644 --- a/plugins/enigma/lib/enigma_driver_gnupg.php +++ b/plugins/enigma/lib/enigma_driver_gnupg.php @@ -215,13 +215,21 @@ public function import($content, $isfile=false) * Key export. * * @param string Key ID + * @param bool Include private key * * @return mixed Key content or enigma_error */ - public function export($keyid) + public function export($keyid, $with_private = false) { try { - return $this->gpg->exportPublicKey($keyid, true); + $key = $this->gpg->exportPublicKey($keyid, true); + + if ($with_private) { + $priv = $this->gpg->exportPrivateKey($keyid, true); + $key .= $priv; + } + + return $key; } catch (Exception $e) { return $this->get_error_from_exception($e); diff --git a/plugins/enigma/lib/enigma_driver_phpssl.php b/plugins/enigma/lib/enigma_driver_phpssl.php index 638cd3d7cae..967811da0f8 100644 --- a/plugins/enigma/lib/enigma_driver_phpssl.php +++ b/plugins/enigma/lib/enigma_driver_phpssl.php @@ -126,6 +126,10 @@ public function import($content, $isfile=false) { } + public function export($key, $with_private = false) + { + } + public function list_keys($pattern='') { } diff --git a/plugins/enigma/lib/enigma_engine.php b/plugins/enigma/lib/enigma_engine.php index a4ee0819ec1..00f584f8400 100644 --- a/plugins/enigma/lib/enigma_engine.php +++ b/plugins/enigma/lib/enigma_engine.php @@ -1126,13 +1126,14 @@ function import_key($content, $isfile=false) * * @param string Key ID * @param resource Optional output stream + * @param bool Include private key * * @return mixed Key content or enigma_error */ - function export_key($key, $fp = null) + function export_key($key, $fp = null, $include_private = false) { $this->load_pgp_driver(); - $result = $this->pgp_driver->export($key, $fp); + $result = $this->pgp_driver->export($key, $include_private); if ($result instanceof enigma_error) { rcube::raise_error(array( diff --git a/plugins/enigma/lib/enigma_key.php b/plugins/enigma/lib/enigma_key.php index 3498f4f2c4a..f44c463683a 100644 --- a/plugins/enigma/lib/enigma_key.php +++ b/plugins/enigma/lib/enigma_key.php @@ -93,6 +93,20 @@ function is_expired() return false; } + /** + * Returns true if any of subkeys is a private key + */ + function is_private() + { + $now = time(); + + foreach ($this->subkeys as $subkey) + if ($subkey->has_private) + return true; + + return false; + } + /** * Get key ID by user email */ diff --git a/plugins/enigma/lib/enigma_ui.php b/plugins/enigma/lib/enigma_ui.php index b8193eb33ec..6ccf23f0819 100644 --- a/plugins/enigma/lib/enigma_ui.php +++ b/plugins/enigma/lib/enigma_ui.php @@ -223,7 +223,9 @@ function tpl_keys_list($attrib) $this->rc->output->include_script('list.js'); // add some labels to client - $this->rc->output->add_label('enigma.keyremoveconfirm', 'enigma.keyremoving'); + $this->rc->output->add_label('enigma.keyremoveconfirm', 'enigma.keyremoving', + 'enigma.keyexportprompt', 'enigma.withprivkeys', 'enigma.onlypubkeys', 'enigma.exportkeys' + ); return $out; } @@ -259,8 +261,11 @@ private function key_list() // Add rows foreach ($list as $key) { - $this->rc->output->command('enigma_add_list_row', - array('name' => rcube::Q($key->name), 'id' => $key->id)); + $this->rc->output->command('enigma_add_list_row', array( + 'name' => rcube::Q($key->name), + 'id' => $key->id, + 'flags' => $key->is_private() ? 'p' : '' + )); } } @@ -462,6 +467,7 @@ private function key_export() $this->rc->request_security_check(rcube_utils::INPUT_GET); $keys = rcube_utils::get_input_value('_keys', rcube_utils::INPUT_GPC); + $priv = rcube_utils::get_input_value('_priv', rcube_utils::INPUT_GPC); $engine = $this->enigma->load_engine(); $list = $keys == '*' ? $engine->list_keys() : explode(',', $keys); @@ -477,7 +483,7 @@ private function key_export() if ($fp = fopen('php://output', 'w')) { foreach ($list as $key) { - $engine->export_key(is_object($key) ? $key->id : $key, $fp); + $engine->export_key(is_object($key) ? $key->id : $key, $fp, (bool) $priv); } } } diff --git a/plugins/enigma/localization/en_US.inc b/plugins/enigma/localization/en_US.inc index 1ef6045720b..cbe8a361b2d 100644 --- a/plugins/enigma/localization/en_US.inc +++ b/plugins/enigma/localization/en_US.inc @@ -85,6 +85,10 @@ $labels['enterkeypass'] = 'A passphrase is needed to unlock the secret key ($key $labels['arialabelkeyexportoptions'] = 'Keys export options'; $labels['attachpubkeymsg'] = 'Attach my public key'; +$labels['keyexportprompt'] = 'Do you want to include secret keys in the saved OpenPGP keys file?'; +$labels['onlypubkeys'] = 'Export Public Keys Only'; +$labels['withprivkeys'] = 'Export Secret Keys'; + $messages = array(); $messages['sigvalid'] = 'Verified signature from $sender.'; $messages['sigvalidpartial'] = 'Verified signature from $sender, but part of the body was not signed.';