From c9e2ab488e047295eae76bdd0cb2d1807c191ee5 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak <alec@alec.pl> Date: Thu, 21 Jan 2016 05:05:01 -0500 Subject: [PATCH] Enigma: Fix handling of encrypted + signed messages (#1490632) --- CHANGELOG | 2 + plugins/enigma/lib/enigma_ui.php | 16 +++++-- program/lib/Roundcube/rcube_mime_decode.php | 2 + plugins/enigma/lib/enigma_engine.php | 60 ++++++++++++++++++++++++------ 4 files changed, 63 insertions(+), 17 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 91cb3c3..5773cb4 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,8 @@ CHANGELOG Roundcube Webmail =========================== +- Enigma: Fix handling of encrypted + signed messages (#1490632) +- Enigma: Fix invalid boundary use in signed messages structure - Enable use of TLSv1.1 and TLSv1.2 for IMAP (#1490640) - Save copy of original .htaccess file when using installto.sh script (1490623) - Fix regression where some message attachments could be missing on edit/forward (#1490608) diff --git a/plugins/enigma/lib/enigma_engine.php b/plugins/enigma/lib/enigma_engine.php index b95ed1a..17e87b6 100644 --- a/plugins/enigma/lib/enigma_engine.php +++ b/plugins/enigma/lib/enigma_engine.php @@ -367,7 +367,7 @@ } // Get message body from IMAP server - $body = $this->get_part_body($p['object'], $part->mime_id); + $body = $this->get_part_body($p['object'], $part); // @TODO: big message body could be a file resource // PGP signed message @@ -520,8 +520,8 @@ // Get bodies // Note: The first part body need to be full part body with headers // it also cannot be decoded - $msg_body = $this->get_part_body($p['object'], $msg_part->mime_id, true); - $sig_body = $this->get_part_body($p['object'], $sig_part->mime_id); + $msg_body = $this->get_part_body($p['object'], $msg_part, true); + $sig_body = $this->get_part_body($p['object'], $sig_part); // Verify $sig = $this->pgp_verify($msg_body, $sig_body); @@ -673,7 +673,7 @@ $part = $struct->parts[1]; // Get body - $body = $this->get_part_body($p['object'], $part->mime_id); + $body = $this->get_part_body($p['object'], $part); // Decrypt $result = $this->pgp_decrypt($body); @@ -681,6 +681,21 @@ if ($result === true) { // Parse decrypted message $struct = $this->parse_body($body); + + // If there's signed content verify the signature + if ($struct->mimetype == 'multipart/signed') { + // set signed part body + $body = $this->extract_signed_body($body, $struct->ctype_parameters['boundary']); + + $struct->parts[0]->enigma_body = $body; + $struct->parts[1]->enigma_body = $struct->parts[1]->body; + + $this->part_structure(array( + 'object' => $p['object'], + 'structure' => $struct, + 'mimetype' => $struct->mimetype + )); + } // Modify original message structure $this->modify_structure($p, $struct); @@ -1102,20 +1117,27 @@ /** * Get message part body. * - * @param rcube_message Message object - * @param string Message part ID - * @param bool Return raw body with headers + * @param rcube_message Message object + * @param rcube_message_part Message part + * @param bool Return raw body with headers */ - private function get_part_body($msg, $part_id, $full = false) + private function get_part_body($msg, $part, $full = false) { // @TODO: Handle big bodies using file handles - if ($full) { + + // $enigma_body is set if this is a part already extracted + // from encrypted message + if ($part->enigma_body) { + $body = $part->enigma_body; + unset($part->enigma_body); + } + else if ($full) { $storage = $this->rc->get_storage(); - $body = $storage->get_raw_headers($msg->uid, $part_id); - $body .= $storage->get_raw_body($msg->uid, null, $part_id); + $body = $storage->get_raw_headers($msg->uid, $part->mime_id); + $body .= $storage->get_raw_body($msg->uid, null, $part->mime_id); } else { - $body = $msg->get_part_body($part_id, false); + $body = $msg->get_part_body($part->mime_id, false); } return $body; @@ -1192,6 +1214,20 @@ } /** + * Extracts body of the multipart/signed part + */ + private function extract_signed_body($body, $boundary) + { + $boundary = '--' . $boundary; + $boundary_len = strlen($boundary) + 2; + $start = strpos($body, $boundary) + $boundary_len; + $end = strpos($body, $boundary, $start); + $body = substr($body, $start, $end - $start - 2); + + return $body; + } + + /** * Checks if specified message part is a PGP-key or S/MIME cert data * * @param rcube_message_part Part object diff --git a/plugins/enigma/lib/enigma_ui.php b/plugins/enigma/lib/enigma_ui.php index c12ac41..e32dee2 100644 --- a/plugins/enigma/lib/enigma_ui.php +++ b/plugins/enigma/lib/enigma_ui.php @@ -756,15 +756,21 @@ return $p; } - $engine = $this->enigma->engine; - $part_id = $p['part']->mime_id; + $engine = $this->enigma->engine; + $part_id = $p['part']->mime_id; + $parent_id = preg_replace('/\.[0-9]+$/', '', $part_id); // Decryption status - if (isset($engine->decryptions[$part_id])) { + if (($status = $engine->decryptions[$part_id]) + || ($parent_id !== '' && ($status = $engine->decryptions[$parent_id])) + ) { $attach_scripts = true; - // get decryption status - $status = $engine->decryptions[$part_id]; + // show the message only once + unset($engine->decryptions[$part_id]); + if ($parent_id !== '') { + unset($engine->decryptions[$parent_id]); + } // display status info $attrib['id'] = 'enigma-message'; diff --git a/program/lib/Roundcube/rcube_mime_decode.php b/program/lib/Roundcube/rcube_mime_decode.php index 320ac58..f624f8d 100644 --- a/program/lib/Roundcube/rcube_mime_decode.php +++ b/program/lib/Roundcube/rcube_mime_decode.php @@ -176,6 +176,8 @@ case 'multipart/alternative': case 'multipart/related': case 'multipart/mixed': + case 'multipart/signed': + case 'multipart/encrypted': if (!isset($content_type['other']['boundary'])) { return false; } -- Gitblit v1.9.1