W.I.P of SMIME support for mail application:

- Resolve smime p7b attachment and translate it to PEM format
- Assign a button to show the message is signed plus handler for showing the certificate
- Fix Smime class to only use php openssl extension
This commit is contained in:
Hadi Nategh 2017-01-19 18:52:28 +01:00
parent 845a1ec3e7
commit a3562129b0
5 changed files with 99 additions and 50 deletions

View File

@ -13,8 +13,6 @@
namespace EGroupware\Api\Mail;
use EGroupware\Api;
use Horde_Crypt_Exception;
use Horde_Crypt_Translation;
use Horde_Crypt_Smime;
/**
@ -23,13 +21,6 @@ use Horde_Crypt_Smime;
class Smime extends Horde_Crypt_Smime
{
/**
* openssl binary path
*
* @var string
*/
protected $sslpath;
static $SMIME_TYPES = array (
'application/pkcs8',
'application/pkcs7',
@ -37,7 +28,9 @@ class Smime extends Horde_Crypt_Smime
'application/pkcs8',
'multipart/signed',
'application/x-pkcs7-signature',
'application/x-pkcs7-mime'
'application/x-pkcs7-mime',
'application/pkcs7-mime',
'application/pkcs7-signature',
);
/**
* Constructor.
@ -47,8 +40,6 @@ class Smime extends Horde_Crypt_Smime
public function __construct($params = array())
{
parent::__construct($params);
$mailconfig = Api\Config::read('mail');
$this->sslpath = $mailconfig['opensslpath']? $mailconfig['opensslpath']: '';
}
/**
@ -78,41 +69,4 @@ class Smime extends Horde_Crypt_Smime
}
return true;
}
/**
* Extract Certificates from given PKCS7 data
*
* @param string $pkcs7
* @return string returns
* @throws Horde_Crypt_Exception
*/
public function extractCerticatesFromPKCS7 ($pkcs7)
{
$this->checkForOpenSSL();
// Create temp file for input
$input = $this->_createTempFile('smime-pkcs7');
$output = $this->_createTempFile('smime-pkcs7-out');
/* Write text to file. */
file_put_contents($input, $pkcs7);
exec($this->sslpath . ' pkcs7 -print_certs -inform der -in ' . $input . ' -outform PEM -out ' . $output);
$ret = file_get_contents($output);
if ($ret) return $ret;
throw new Horde_Crypt_Exception(Horde_Crypt_Translation::t("OpenSSL error: Could not extract certificates from pkcs7 part."));
}
/**
* Extract the contents from signed S/MIME data.
*
* @param string $data The signed S/MIME data.
*
* @return string The contents embedded in the signed data.
* @throws Horde_Crypt_Exception
*/
public function extractSignedContents ($data) {
return parent::extractSignedContents($data, $this->sslpath);
}
}

View File

@ -1546,7 +1546,7 @@ $filter['before']= date("d-M-Y", $cutoffdate2);
if (empty($rowsFetched['messages'])) $rowsFetched['messages'] = $rowsFetched['rowsFetched'];
//error_log(__METHOD__.__LINE__.' Rows fetched:'.$rowsFetched.' Data:'.array2string($sortResult));
$cols = array('row_id','uid','status','attachments','subject','address','toaddress','fromaddress','ccaddress','additionaltoaddress','date','size','modified','bodypreview');
$cols = array('row_id','uid','status','attachments','subject','address','toaddress','fromaddress','ccaddress','additionaltoaddress','date','size','modified','bodypreview', 'security');
if ($GLOBALS['egw_info']['user']['preferences']['common']['select_mode']=='EGW_SELECTMODE_TOGGLE') unset($cols[0]);
$rows = $mail_ui->header2gridelements($sortResult['header'],$cols, $_folderName, $folderType=$toSchema);
//error_log(__METHOD__.__LINE__.array2string($rows));
@ -1878,6 +1878,16 @@ $filter['before']= date("d-M-Y", $cutoffdate2);
{
$data["bodypreview"] = $header['bodypreview'];
}
if (is_array($data['attachmentsBlock']))
{
foreach ($data['attachmentsBlock'] as &$attch)
{
if (Mail\Smime::isSmime($attch['mimetype']))
{
$data['smimeSigUrl'] = $attch['mime_url'];
}
}
}
$rv[] = $data;
//error_log(__METHOD__.__LINE__.array2string($data));
}
@ -1996,6 +2006,22 @@ $filter['before']= date("d-M-Y", $cutoffdate2);
// we do NOT want to see those, that are embedded in the list of attachments
if ($htmlOptions !='always_display') $fetchEmbeddedImages = true;
$attachments = $this->mail_bo->getMessageAttachments($uid, $partID, null, $fetchEmbeddedImages,true,true,$mailbox);
$smimeData = $this->resolveSmimeAttachment ($attachments, $uid, $partID, $mailbox, $rowID);
if (is_array($smimeData))
{
$error_msg[] = $smimeData['msg'];
$linkData = array
(
'menuaction' => 'mail.mail_ui.getAttachment',
'id' => $rowID,
'part' => $smimeData['partID'],
'is_winmail' => false,
'mailbox' => base64_encode($mailbox)
);
$content['smimeSigUrl'] = Egw::link('/index.php',$linkData);
}
//error_log(__METHOD__.__LINE__.array2string($attachments));
$attachmentHTMLBlock = self::createAttachmentBlock($attachments, $rowID, $uid, $mailbox);
@ -2065,6 +2091,47 @@ $filter['before']= date("d-M-Y", $cutoffdate2);
$etpl->exec('mail.mail_ui.displayMessage',$content,$sel_options,$readonlys,$preserv,2);
}
/**
* Resolve certificate from smime attachment
*
* @param array &$attachments
* @param int $_uid
* @param int $_partID
* @param string $_mailbox
* @return array
*/
function resolveSmimeAttachment (&$attachments, $_uid, $_partID, $_mailbox)
{
$smime = new Mail\Smime;
foreach ($attachments as $key => $attachment)
{
if (Mail\Smime::isSmime($attachment['mimeType']))
{
$message = $this->mail_bo->getMessageRawBody($_uid,$_partID,$_mailbox);
$cert = $smime->verify($message);
$data = array (
'verify' => $cert->verify,
'cert' => $cert->cert,
'msg' => $cert->msg,
'certHtml' => $smime->certToHTML($cert->cert),
'partID' => $attachment['partID']
);
unset ($attachments[$key]);
}
}
return $data;
}
function getSmimeCert ()
{
if (isset($_GET['id'])) $id = $_GET['id'];
if (isset($_GET['partID'])) $partID = $_GET['partid'];
$cert = $this->resolveSmimeAttachment($attachments, $id, $partID, $mailbox);
echo ($cert);
}
/**
* Build actions for display toolbar
*/
@ -2500,6 +2567,15 @@ $filter['before']= date("d-M-Y", $cutoffdate2);
}
//Import failed, download content anyway
}
// Display smime certificate
if (Mail\Smime::isSmime($attachment['type']))
{
$smimeAttachments = array ( array('mimeType' => $attachment['type'] ));
$smime = $this->resolveSmimeAttachment($smimeAttachments, $uid, 0, $mailbox);
Api\Header\Content::safe($smime['certHtml'], '', $attachment['type'], $size=0, false, true);
echo $smime['certHtml'];
exit();
}
}
//error_log(__METHOD__.__LINE__.'->'.array2string($attachment));
$filename = ($attachment['name']?$attachment['name']:($attachment['filename']?$attachment['filename']:$mailbox.'_uid'.$uid.'_part'.$part));

View File

@ -5504,5 +5504,18 @@ app.classes.mail = AppJS.extend(
});
});
},
/**
* Open smime certificate
*
* @param {type} egw
* @param {type} widget
* @returns {undefined}
*/
smimeSigBtn: function (egw, widget)
{
var url = this.et2.getArrayMgr("content").getEntry('smimeSigUrl');
window.egw.openPopup(url,'700','400');
}
});

View File

@ -17,6 +17,7 @@
<hbox class="mailDisplayHeaders" align="right" width="30%">
<description value="Date"/>
<date-time id="mail_displaydate" readonly="true"/>
<buttononly id="smimeSigBtn" image="smimeSignature" onclick="app.mail.smimeSigBtn"/>
</hbox>
</hbox>

View File

@ -84,6 +84,7 @@
<column width="30%"/>
<column width="30%"/>
<column width="80"/>
<column width="80"/>
</columns>
<rows>
<row class="th">
@ -96,6 +97,7 @@
<nextmatch-sortheader label="to" id="toaddress"/>
<nextmatch-sortheader label="from" id="fromaddress"/>
<nextmatch-sortheader align="center" label="size" id="size"/>
<nextmatch-header statustext="security" label="Security" id="security"/>
</row>
<row class="$row_cont[class]">
<description span="1" class="status_img"/>
@ -110,6 +112,9 @@
<url-email id="${row}[toaddress]" contact_plus = "true" readonly="true"/>
<url-email id="${row}[fromaddress]" contact_plus = "true" readonly="true"/>
<vfs-size align="right" id="${row}[size]" no_lang="1" readonly="true"/>
<vbox>
<buttononly id="smimeSigBtn" image="smimeSignature" disabled="!@$row_cont[smimeSigUrl]"/>
</vbox>
</row>
</rows>
</grid>