From a0dfcb14a8d51d5cb9e60ec90af2ef5b7a446ca1 Mon Sep 17 00:00:00 2001
From: Aleksander Machniak <alec@alec.pl>
Date: Tue, 18 Aug 2015 07:41:44 -0400
Subject: [PATCH] Enigma: Optional server-side key generation
---
plugins/enigma/lib/enigma_driver_gnupg.php | 33 ++++++++++-
plugins/enigma/lib/enigma_ui.php | 48 +++++++++++++++
plugins/enigma/localization/en_US.inc | 1
plugins/enigma/README | 4
plugins/enigma/lib/enigma_driver.php | 6 +-
plugins/enigma/enigma.js | 9 ++
plugins/enigma/lib/enigma_engine.php | 23 +++++++
plugins/enigma/config.inc.php.dist | 11 +++
8 files changed, 124 insertions(+), 11 deletions(-)
diff --git a/plugins/enigma/README b/plugins/enigma/README
index 1d8f7dd..1cd0e2d 100644
--- a/plugins/enigma/README
+++ b/plugins/enigma/README
@@ -17,7 +17,8 @@
+ PGP: signatures verification
+ PGP: messages decryption
+ PGP: Sending of encrypted/signed messages
-+ PGP: keys management UI (keys import and delete)
++ PGP: keys management UI (key import, delete)
++ PGP: key generation (client- or server-side)
+ Handling of PGP keys attached to incoming messages
+ User preferences to disable plugin features
@@ -28,7 +29,6 @@
TODO (later):
-------------
- Handling of big messages with temp files
-- Server-side keys generation (warning: no-entropy issue, max_execution_time issue)
- Key info in contact details page (optional)
- Extended key management:
- disable,
diff --git a/plugins/enigma/config.inc.php.dist b/plugins/enigma/config.inc.php.dist
index 832f355..17e72de 100644
--- a/plugins/enigma/config.inc.php.dist
+++ b/plugins/enigma/config.inc.php.dist
@@ -28,3 +28,14 @@
// Default for how long to store private key passwords (in minutes).
// When set to 0 passwords will be stored for the whole session.
$config['enigma_password_time'] = 5;
+
+// Enables server-side keys generation which would be used
+// if user browser does not support web-crypto features.
+//
+// WARNING: Key generation requires true random numbers, and as such can be
+// slow. If the operating system runs out of entropy, key generation will
+// block until more entropy is available.
+//
+// To solve that a hardware entropy generator or
+// an entropy gathering daemon may be installed (e.g. randomsound).
+$config['enigma_keygen_server'] = false;
diff --git a/plugins/enigma/enigma.js b/plugins/enigma/enigma.js
index a9b56eb..8479c79 100644
--- a/plugins/enigma/enigma.js
+++ b/plugins/enigma/enigma.js
@@ -97,7 +97,7 @@
openpgp.generateKeyPair(options).then(function(keypair) {
// success
- post = {_a: 'import', _keys: keypair.privateKeyArmored};
+ var post = {_a: 'import', _keys: keypair.privateKeyArmored};
// send request to server
rcmail.http_post('plugin.enigmakeys', post, lock);
@@ -108,8 +108,13 @@
});
}
// generate keys on the server
+ else if (rcmail.env.enigma_keygen_server) {
+ lock = this.set_busy(true, 'enigma.keygenerating');
+ options = {_a: 'generate', _user: user, _password: password, _size: size};
+ rcmail.http_post('plugin.enigmakeys', options, lock);
+ }
else {
- // @TODO
+ rcmail.display_message(rcmail.gettext('enigma.keygennosupport'), 'error');
}
};
diff --git a/plugins/enigma/lib/enigma_driver.php b/plugins/enigma/lib/enigma_driver.php
index 4c8340e..6326ef7 100644
--- a/plugins/enigma/lib/enigma_driver.php
+++ b/plugins/enigma/lib/enigma_driver.php
@@ -67,7 +67,7 @@
*
* @return mixed Import status array or enigma_error
*/
- abstract function import($content, $isfile=false);
+ abstract function import($content, $isfile = false);
/**
* Keys listing.
@@ -76,7 +76,7 @@
*
* @return mixed Array of enigma_key objects or enigma_error
*/
- abstract function list_keys($pattern='');
+ abstract function list_keys($pattern = '');
/**
* Single key information.
@@ -90,7 +90,7 @@
/**
* Key pair generation.
*
- * @param array Key/User data
+ * @param array Key/User data (name, email, password, size)
*
* @return mixed Key (enigma_key) object or enigma_error
*/
diff --git a/plugins/enigma/lib/enigma_driver_gnupg.php b/plugins/enigma/lib/enigma_driver_gnupg.php
index b9376e1..c7fc2dc 100644
--- a/plugins/enigma/lib/enigma_driver_gnupg.php
+++ b/plugins/enigma/lib/enigma_driver_gnupg.php
@@ -188,8 +188,32 @@
return $list;
}
+ /**
+ * Key pair generation.
+ *
+ * @param array Key/User data (user, email, password, size)
+ *
+ * @return mixed Key (enigma_key) object or enigma_error
+ */
public function gen_key($data)
{
+ try {
+ $keygen = new Crypt_GPG_KeyGenerator(array(
+ 'homedir' => $this->homedir,
+ // 'binary' => '/usr/bin/gpg2',
+ // 'debug' => true,
+ ));
+
+ $key = $keygen
+ ->setExpirationDate(0)
+ ->setPassphrase($data['password'])
+ ->generateKey($data['user'], $data['email']);
+
+ return $this->parse_key($key);
+ }
+ catch (Exception $e) {
+ return $this->get_error_from_exception($e);
+ }
}
public function delete_key($keyid)
@@ -263,12 +287,15 @@
$data['bad'] = $e->getBadPassphrases();
$data['missing'] = $e->getMissingPassphrases();
}
- else if ($e instanceof Crypt_GPG_NoDataException)
+ else if ($e instanceof Crypt_GPG_NoDataException) {
$error = enigma_error::E_NODATA;
- else if ($e instanceof Crypt_GPG_DeletePrivateKeyException)
+ }
+ else if ($e instanceof Crypt_GPG_DeletePrivateKeyException) {
$error = enigma_error::E_DELKEY;
- else
+ }
+ else {
$error = enigma_error::E_INTERNAL;
+ }
$msg = $e->getMessage();
diff --git a/plugins/enigma/lib/enigma_engine.php b/plugins/enigma/lib/enigma_engine.php
index 85c2882..58982ca 100644
--- a/plugins/enigma/lib/enigma_engine.php
+++ b/plugins/enigma/lib/enigma_engine.php
@@ -927,6 +927,29 @@
}
/**
+ * PGP keys pair generation.
+ *
+ * @param array Key pair parameters
+ *
+ * @return mixed enigma_key or enigma_error
+ */
+ function generate_key($data)
+ {
+ $this->load_pgp_driver();
+ $result = $this->pgp_driver->gen_key($data);
+
+ if ($result instanceof enigma_error) {
+ rcube::raise_error(array(
+ 'code' => 600, 'type' => 'php',
+ 'file' => __FILE__, 'line' => __LINE__,
+ 'message' => "Enigma plugin: " . $result->getMessage()
+ ), true, false);
+ }
+
+ return $result;
+ }
+
+ /**
* PGP keys/certs importing.
*
* @param mixed Import file name or content
diff --git a/plugins/enigma/lib/enigma_ui.php b/plugins/enigma/lib/enigma_ui.php
index d0c5e29..8bb29d6 100644
--- a/plugins/enigma/lib/enigma_ui.php
+++ b/plugins/enigma/lib/enigma_ui.php
@@ -59,6 +59,10 @@
$this->key_import();
break;
+ case 'generate':
+ $this->key_generate();
+ break;
+
case 'create':
$this->key_create();
break;
@@ -484,6 +488,45 @@
}
/**
+ * Server-side key pair generation handler
+ */
+ private function key_generate()
+ {
+ $user = rcube_utils::get_input_value('_user', rcube_utils::INPUT_POST, true);
+ $pass = rcube_utils::get_input_value('_password', rcube_utils::INPUT_POST, true);
+ $size = (int) rcube_utils::get_input_value('_size', rcube_utils::INPUT_POST);
+
+ if ($size > 4096) {
+ $size = 4096;
+ }
+
+ $ident = rcube_mime::decode_address_list($user, 1, false);
+
+ if (empty($ident)) {
+ $this->rc->output->show_message('enigma.keygenerateerror', 'error');
+ $this->rc->output->send();
+ }
+
+ $this->enigma->load_engine();
+ $result = $this->enigma->engine->generate_key(array(
+ 'user' => $ident[1]['name'],
+ 'email' => $ident[1]['mailto'],
+ 'password' => $pass,
+ 'size' => $size,
+ ));
+
+ if ($result instanceof enigma_key) {
+ $this->rc->output->command('enigma_key_create_success');
+ $this->rc->output->show_message('enigma.keygeneratesuccess', 'confirmation');
+ }
+ else {
+ $this->rc->output->show_message('enigma.keygenerateerror', 'error');
+ }
+
+ $this->rc->output->send();
+ }
+
+ /**
* Key generation page handler
*/
private function key_create()
@@ -493,6 +536,8 @@
$this->rc->output->add_handlers(array(
'keyform' => array($this, 'tpl_key_create_form'),
));
+
+ $this->rc->output->set_env('enigma_keygen_server', $this->rc->config->get('enigma_keygen_server'));
$this->rc->output->set_pagetitle($this->enigma->gettext('keygenerate'));
$this->rc->output->send('enigma.keycreate');
@@ -538,7 +583,8 @@
$this->rc->output->add_gui_object('keyform', $attrib['id']);
$this->rc->output->add_label('enigma.keygenerating', 'enigma.formerror',
- 'enigma.passwordsdiffer', 'enigma.keygenerateerror', 'enigma.nonameident');
+ 'enigma.passwordsdiffer', 'enigma.keygenerateerror', 'enigma.nonameident',
+ 'enigma.keygennosupport');
return $this->rc->output->form_tag(array(), $table->show($attrib));
}
diff --git a/plugins/enigma/localization/en_US.inc b/plugins/enigma/localization/en_US.inc
index 2cda183..f4f6d54 100644
--- a/plugins/enigma/localization/en_US.inc
+++ b/plugins/enigma/localization/en_US.inc
@@ -98,5 +98,6 @@
$messages['nonameident'] = 'Idenity must have a user name defined!';
$messages['keygenerateerror'] = 'Failed to generate a key pair';
$messages['keygeneratesuccess'] = 'A key pair generated and imported successfully.';
+$messages['keygennosupport'] = 'Your web browser does not support cryptography. Unable to generate a key pair!';
?>
--
Gitblit v1.9.1