Enigma: Optional server-side key generation
| | |
| | | + 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 |
| | | |
| | |
| | | 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, |
| | |
| | | // 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; |
| | |
| | | |
| | | 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); |
| | |
| | | }); |
| | | } |
| | | // 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'); |
| | | } |
| | | }; |
| | | |
| | |
| | | * |
| | | * @return mixed Import status array or enigma_error |
| | | */ |
| | | abstract function import($content, $isfile=false); |
| | | abstract function import($content, $isfile = false); |
| | | |
| | | /** |
| | | * Keys listing. |
| | |
| | | * |
| | | * @return mixed Array of enigma_key objects or enigma_error |
| | | */ |
| | | abstract function list_keys($pattern=''); |
| | | abstract function list_keys($pattern = ''); |
| | | |
| | | /** |
| | | * Single key information. |
| | |
| | | /** |
| | | * 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 |
| | | */ |
| | |
| | | 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) |
| | |
| | | $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(); |
| | | |
| | |
| | | } |
| | | |
| | | /** |
| | | * 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 |
| | |
| | | $this->key_import(); |
| | | break; |
| | | |
| | | case 'generate': |
| | | $this->key_generate(); |
| | | break; |
| | | |
| | | case 'create': |
| | | $this->key_create(); |
| | | break; |
| | |
| | | } |
| | | |
| | | /** |
| | | * 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() |
| | |
| | | $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'); |
| | |
| | | |
| | | $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)); |
| | | } |
| | |
| | | $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!'; |
| | | |
| | | ?> |