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