WIP of SMIME support: First attempt to decrypt a smime encrypted message

This commit is contained in:
Hadi Nategh 2017-01-26 17:45:07 +01:00
parent dc4a825c54
commit 2d8b8fc5dc
2 changed files with 118 additions and 27 deletions

View File

@ -35,25 +35,35 @@ class Smime extends Horde_Crypt_Smime
'application/pkcs7-signature',
);
/**
* SMIME signature only types
* @var type
*/
static $SMIME_SIGNATURE_ONLY_TYPES = array (
'application/x-pkcs7-signature',
'application/pkcs7-signature',
'multipart/signed'
);
/*
* SMIME public key regular expresion
*/
static public $pubkey_regexp = '/-----BEGIN PUBLIC KEY-----.*-----END PUBLIC KEY-----\r?\n/s/';
static public $pubkey_regexp = '/-----BEGIN PUBLIC KEY-----.*-----END PUBLIC KEY-----\r?\n/s';
/*
* SMIME encrypted private key regular expresion
*/
static public $privkey_encrypted_regexp = '/-----BEGIN ENCRYPTED PRIVATE KEY-----.*-----END ENCRYPTED PRIVATE KEY-----\r?\n/s/';
static public $privkey_encrypted_regexp = '/-----BEGIN ENCRYPTED PRIVATE KEY-----.*-----END ENCRYPTED PRIVATE KEY-----\r?\n/s';
/*
* SMIME private key regular expresion
*/
static public $privkey_regexp = '/-----BEGIN PRIVATE KEY-----.*-----END PRIVATE KEY-----\r?\n/s/';
static public $privkey_regexp = '/-----BEGIN PRIVATE KEY-----.*-----END PRIVATE KEY-----\r?\n/s';
/*
* SMIME certificate regular expresion
*/
static public $certificate_regexp = '/-----BEGIN CERTIFICATE-----.*-----END CERTIFICATE-----\r?\n/s/';
static public $certificate_regexp = '/-----BEGIN CERTIFICATE-----.*-----END CERTIFICATE-----\r?\n/s';
/**
* Constructor.
@ -77,6 +87,18 @@ class Smime extends Horde_Crypt_Smime
return in_array($_mime, self::$SMIME_TYPES);
}
/**
* Check if a given mime type is smime type of signature only
*
* @param string $_mime mimetype
*
* @return type
*/
public static function isSmimeSignatureOnly ($_mime)
{
return in_array($_mime, self::$SMIME_SIGNATURE_ONLY_TYPES);
}
/**
* Check if the openssl is supported
*
@ -96,7 +118,8 @@ class Smime extends Horde_Crypt_Smime
/**
* Extract public key from certificate
*
* @param type $cert
* @param string $cert content of certificate in PEM format
*
* @return string returns public key
*/
public function get_publickey ($cert)
@ -109,11 +132,12 @@ class Smime extends Horde_Crypt_Smime
/**
* Extract certificates info from a p12 file
*
* @param string $pkcs12
* @param string $passphrase
* @param string $pkcs12 content of p12 file in string
* @param string $passphrase = '', passphrase to unlock the p12 file
*
* @return boolean|array returns array of certs info or false if not successful
*/
public function extractCertPKCS12 ($pkcs12, $passphrase)
public function extractCertPKCS12 ($pkcs12, $passphrase = '')
{
$certs = array ();
if (openssl_pkcs12_read($pkcs12, $certs, $passphrase))

View File

@ -2011,15 +2011,23 @@ $filter['before']= date("d-M-Y", $cutoffdate2);
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);
if ($smimeData['signed'])
{
$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);
}
if ($smimeData['required_password'])
{
$response = Api\Json\Response::get();
$response->call('app.mail.smimeRequestPassphrase');
}
}
//error_log(__METHOD__.__LINE__.array2string($attachments));
@ -2091,6 +2099,35 @@ $filter['before']= date("d-M-Y", $cutoffdate2);
$etpl->exec('mail.mail_ui.displayMessage',$content,$sel_options,$readonlys,$preserv,2);
}
/**
* decrypt given smime encrypted message
*
* @param string $_message
* @param string $_passphrase
* @return array|string return
*/
function decryptSmimeBody ($_message, $_passphrase = '')
{
$AB_bo = new addressbook_bo();
$credents = Mail\Credentials::read($this->mail_bo->profileID, Mail\Credentials::SMIME, $GLOBALS['egw_info']['user']['account_id']);
$certkey = $AB_bo->get_smime_keys($GLOBALS['egw_info']['user']['account_email']);
if (!$this->smime->verifyPassphrase($credents['acc_smime_password'], $_passphrase))
{
return array (
'password_required' => true,
'msg' => 'Authentication failure!'
);
}
$params = array (
'type' => 'message',
'pubkey' => $certkey[$GLOBALS['egw_info']['user']['account_email']],
'privkey' => $credents['acc_smime_password'],
'passphrase'=> $_passphrase
);
return $this->smime->decrypt($_message, $params);
}
/**
* Resolve certificate from smime attachment
*
@ -2102,21 +2139,40 @@ $filter['before']= date("d-M-Y", $cutoffdate2);
*/
function resolveSmimeAttachment (&$attachments, $_uid, $_partID, $_mailbox)
{
$smime = new Mail\Smime;
$this->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']
);
$message = $this->mail_bo->getMessageRawBody($_uid, $_partID, $_mailbox);
if (!Mail\Smime::isSmimeSignatureOnly($attachment['mimeType']))
{
try {
$message = $this->decryptSmimeBody($message);
} catch (Exception $ex) {
return array('msg', $ex->getMessage());
}
}
try {
$cert = $this->smime->verify($message);
$data = array (
'verify' => $cert->verify,
'cert' => $cert->cert,
'msg' => $cert->msg,
'certHtml' => $this->smime->certToHTML($cert->cert),
'partID' => $attachment['partID'],
'signed' => true,
'message' => $message
);
} catch (Exception $ex) {
$data = array (
'signed' => false,
'message' => $message
);
}
unset ($attachments[$key]);
}
}
@ -2930,7 +2986,18 @@ $filter['before']= date("d-M-Y", $cutoffdate2);
$structure = $this->mail_bo->getStructure($uid, $partID, $mailbox, false);
$calendar_part = null;
$bodyParts = $this->mail_bo->getMessageBody($uid, ($htmlOptions?$htmlOptions:''), $partID, $structure, false, $mailbox, $calendar_part);
$mimeType = $structure->getType();
if (Mail\Smime::isSmime( $mimeType) && !Mail\Smime::isSmimeSignatureOnly($mimeType))
{
$smimeAttachments = array ( array('mimeType' => $mimeType));
$smime = $this->resolveSmimeAttachment($smimeAttachments, $uid, 0, $mailbox);
if ($smime['message'])
{
$bodyParts[0]['body'] = $smime['message'];
}
}
// for meeting requests (multipart alternative with text/calendar part) let calendar render it
if ($calendar_part && isset($GLOBALS['egw_info']['user']['apps']['calendar']))
{