Overview

Packages

  • IMP
  • None

Classes

  • IMP
  • IMP_Ajax_Application
  • IMP_Ajax_Imple_ContactAutoCompleter
  • IMP_Ajax_Imple_PassphraseDialog
  • IMP_Ajax_Queue
  • IMP_Api
  • IMP_Auth
  • IMP_Block_Newmail
  • IMP_Block_Summary
  • IMP_Compose
  • IMP_Compose_Exception
  • IMP_Compose_Stationery
  • IMP_Contents
  • IMP_Crypt_Pgp
  • IMP_Crypt_Smime
  • IMP_Dimp
  • IMP_Exception
  • IMP_Factory_AuthImap
  • IMP_Factory_Compose
  • IMP_Factory_Contents
  • IMP_Factory_Flags
  • IMP_Factory_Identity
  • IMP_Factory_Imap
  • IMP_Factory_Imaptree
  • IMP_Factory_Mail
  • IMP_Factory_Mailbox
  • IMP_Factory_MailboxList
  • IMP_Factory_MimeViewer
  • IMP_Factory_Pgp
  • IMP_Factory_Quota
  • IMP_Factory_Search
  • IMP_Factory_Sentmail
  • IMP_Factory_Smime
  • IMP_Filter
  • IMP_Flag_Base
  • IMP_Flag_Imap
  • IMP_Flag_Imap_Answered
  • IMP_Flag_Imap_Deleted
  • IMP_Flag_Imap_Draft
  • IMP_Flag_Imap_Flagged
  • IMP_Flag_Imap_Forwarded
  • IMP_Flag_Imap_Junk
  • IMP_Flag_Imap_NotJunk
  • IMP_Flag_Imap_Seen
  • IMP_Flag_System_Attachment
  • IMP_Flag_System_Encrypted
  • IMP_Flag_System_HighPriority
  • IMP_Flag_System_List
  • IMP_Flag_System_LowPriority
  • IMP_Flag_System_Match_Address
  • IMP_Flag_System_Match_Flag
  • IMP_Flag_System_Match_Header
  • IMP_Flag_System_Personal
  • IMP_Flag_System_Signed
  • IMP_Flag_System_Unseen
  • IMP_Flag_User
  • IMP_Flags
  • IMP_Imap
  • IMP_Imap_Acl
  • IMP_Imap_Exception
  • IMP_Imap_PermanentFlags
  • IMP_Imap_Thread
  • IMP_Imap_Tree
  • IMP_Indices
  • IMP_Indices_Form
  • IMP_LoginTasks_SystemTask_GarbageCollection
  • IMP_LoginTasks_SystemTask_Upgrade
  • IMP_LoginTasks_SystemTask_UpgradeAuth
  • IMP_LoginTasks_Task_Autocreate
  • IMP_LoginTasks_Task_DeleteAttachmentsMonthly
  • IMP_LoginTasks_Task_DeleteSentmailMonthly
  • IMP_LoginTasks_Task_FilterOnLogin
  • IMP_LoginTasks_Task_PurgeSentmail
  • IMP_LoginTasks_Task_PurgeSpam
  • IMP_LoginTasks_Task_PurgeTrash
  • IMP_LoginTasks_Task_RecoverDraft
  • IMP_LoginTasks_Task_RenameSentmailMonthly
  • IMP_Mailbox
  • IMP_Mailbox_List
  • IMP_Mailbox_List_Track
  • IMP_Maillog
  • IMP_Menu_Dimp
  • IMP_Message
  • IMP_Mime_Status
  • IMP_Mime_Viewer_Alternative
  • IMP_Mime_Viewer_Appledouble
  • IMP_Mime_Viewer_Audio
  • IMP_Mime_Viewer_Enriched
  • IMP_Mime_Viewer_Externalbody
  • IMP_Mime_Viewer_Html
  • IMP_Mime_Viewer_Images
  • IMP_Mime_Viewer_Itip
  • IMP_Mime_Viewer_Mdn
  • IMP_Mime_Viewer_Partial
  • IMP_Mime_Viewer_Pdf
  • IMP_Mime_Viewer_Pgp
  • IMP_Mime_Viewer_Plain
  • IMP_Mime_Viewer_Related
  • IMP_Mime_Viewer_Rfc822
  • IMP_Mime_Viewer_Smil
  • IMP_Mime_Viewer_Smime
  • IMP_Mime_Viewer_Status
  • IMP_Mime_Viewer_Vcard
  • IMP_Mime_Viewer_Video
  • IMP_Mime_Viewer_Zip
  • IMP_Notification_Event_Status
  • IMP_Notification_Handler_Decorator_ImapAlerts
  • IMP_Notification_Handler_Decorator_NewmailNotify
  • IMP_Notification_Listener_AjaxStatus
  • Imp_Prefs_Identity
  • IMP_Prefs_Ui
  • IMP_Quota
  • IMP_Quota_Base
  • IMP_Quota_Command
  • IMP_Quota_Hook
  • IMP_Quota_Imap
  • IMP_Quota_Maildir
  • IMP_Quota_Mdaemon
  • IMP_Quota_Mercury32
  • IMP_Quota_Null
  • IMP_Quota_Sql
  • IMP_Search
  • IMP_Search_Element
  • IMP_Search_Element_Attachment
  • IMP_Search_Element_Autogenerated
  • IMP_Search_Element_Bulk
  • IMP_Search_Element_Contacts
  • IMP_Search_Element_Date
  • IMP_Search_Element_Flag
  • IMP_Search_Element_Header
  • IMP_Search_Element_Mailinglist
  • IMP_Search_Element_Or
  • IMP_Search_Element_Personal
  • IMP_Search_Element_Recipient
  • IMP_Search_Element_Size
  • IMP_Search_Element_Text
  • IMP_Search_Element_Within
  • IMP_Search_Filter
  • IMP_Search_Filter_Attachment
  • IMP_Search_Filter_Autogenerated
  • IMP_Search_Filter_Builtin
  • IMP_Search_Filter_Bulk
  • IMP_Search_Filter_Contacts
  • IMP_Search_Filter_Mailinglist
  • IMP_Search_Filter_Personal
  • IMP_Search_Query
  • IMP_Search_Vfolder
  • IMP_Search_Vfolder_Builtin
  • IMP_Search_Vfolder_Vinbox
  • IMP_Search_Vfolder_Vtrash
  • IMP_Sentmail
  • IMP_Sentmail_Base
  • IMP_Sentmail_Null
  • IMP_Sentmail_Sql
  • IMP_Spam
  • IMP_Test
  • IMP_Tree_Flist
  • IMP_Tree_Jquerymobile
  • IMP_Tree_Simplehtml
  • IMP_Ui_Compose
  • IMP_Ui_Editor
  • IMP_Ui_Folder
  • IMP_Ui_Headers
  • IMP_Ui_Imageview
  • IMP_Ui_Mailbox
  • IMP_Ui_Message
  • IMP_Ui_Mimp
  • IMP_Ui_Search
  • IMP_Views_Compose
  • IMP_Views_ListMessages
  • IMP_Views_ShowMessage
  • Overview
  • Package
  • Class
  • Tree
  1: <?php
  2: /**
  3:  * The IMP_Mime_Viewer_Smime class allows viewing/decrypting of S/MIME
  4:  * messages (RFC 2633).
  5:  *
  6:  * This class handles the following MIME types:
  7:  *   application/pkcs7-mime
  8:  *   application/x-pkcs7-mime
  9:  *   application/pkcs7-signature (in multipart/signed part)
 10:  *   application/x-pkcs7-signature (in multipart/signed part)
 11:  *
 12:  * This class may add the following parameters to the URL:
 13:  *   'smime_verify_msg' - (boolean) Do verification of S/MIME message.
 14:  *   'view_smime_key' - (boolean) Display the S/MIME Key.
 15:  *
 16:  * Copyright 2002-2012 Horde LLC (http://www.horde.org/)
 17:  *
 18:  * See the enclosed file COPYING for license information (GPL). If you
 19:  * did not receive this file, see http://www.horde.org/licenses/gpl.
 20:  *
 21:  * @author   Mike Cochrane <mike@graftonhall.co.nz>
 22:  * @author   Michael Slusarz <slusarz@horde.org>
 23:  * @category Horde
 24:  * @license  http://www.horde.org/licenses/gpl GPL
 25:  * @package  IMP
 26:  */
 27: class IMP_Mime_Viewer_Smime extends Horde_Mime_Viewer_Base
 28: {
 29:     /**
 30:      * This driver's display capabilities.
 31:      *
 32:      * @var array
 33:      */
 34:     protected $_capability = array(
 35:         'full' => false,
 36:         'info' => false,
 37:         'inline' => true,
 38:         'raw' => false
 39:     );
 40: 
 41:     /**
 42:      * Metadata for the current viewer/data.
 43:      *
 44:      * @var array
 45:      */
 46:     protected $_metadata = array(
 47:         'compressed' => false,
 48:         'embedded' => true,
 49:         'forceinline' => true
 50:     );
 51: 
 52:     /**
 53:      * IMP_Crypt_Smime object.
 54:      *
 55:      * @var IMP_Crypt_Smime
 56:      */
 57:     protected $_impsmime = null;
 58: 
 59:     /**
 60:      * Cached data.
 61:      *
 62:      * @var array
 63:      */
 64:     static protected $_cache = array();
 65: 
 66:     /**
 67:      * Init the S/MIME Horde_Crypt object.
 68:      */
 69:     protected function _initSmime()
 70:     {
 71:         if (is_null($this->_impsmime) &&
 72:             $GLOBALS['prefs']->getValue('use_smime')) {
 73:             try {
 74:                 $this->_impsmime = $GLOBALS['injector']->getInstance('IMP_Crypt_Smime');
 75:                 $this->_impsmime->checkForOpenSSL();
 76:             } catch (Horde_Exception $e) {
 77:                 $this->_impsmime = null;
 78:             }
 79:         }
 80:     }
 81: 
 82:     /**
 83:      * Return the rendered inline version of the Horde_Mime_Part object.
 84:      *
 85:      * @return array  See parent::render().
 86:      */
 87:     protected function _renderInline()
 88:     {
 89:         /* Check to see if S/MIME support is available. */
 90:         $this->_initSmime();
 91: 
 92:         if (Horde_Util::getFormData('view_smime_key')) {
 93:             return $this->_outputSmimeKey();
 94:         }
 95: 
 96:         if (is_null($this->_impsmime)) {
 97:             $this->_impsmime = false;
 98:         } else {
 99:             /* We need to insert JavaScript code now if S/MIME support is
100:              * active. */
101:             Horde::addScriptFile('imp.js', 'imp');
102:         }
103: 
104:         $id = $this->_mimepart->getMimeId();
105: 
106:         switch ($this->_mimepart->getType()) {
107:         case 'multipart/signed';
108:             if (!in_array($this->_mimepart->getContentTypeParameter('protocol'), array('application/pkcs7-signature', 'application/x-pkcs7-signature'))) {
109:                 return array();
110:             }
111:             $this->_parseSignedData(true);
112:             // Fall-through
113: 
114:         case 'application/pkcs7-mime':
115:         case 'application/x-pkcs7-mime':
116:             if (isset(self::$_cache[$id])) {
117:                 $ret = array(
118:                     $id => array(
119:                         'data' => null,
120:                         'status' => self::$_cache[$id]['status'],
121:                         'type' => 'text/plain; charset=' . $this->getConfigParam('charset'),
122:                         'wrap' => self::$_cache[$id]['wrap']
123:                     )
124:                 );
125:                 if (isset(self::$_cache[$id]['sig'])) {
126:                     $ret[self::$_cache[$id]['sig']] = null;
127:                 }
128:                 return $ret;
129:             }
130:             // Fall-through
131: 
132:         default:
133:             return array();
134:         }
135:     }
136: 
137:     /**
138:      * If this MIME part can contain embedded MIME parts, and those embedded
139:      * MIME parts exist, return an altered version of the Horde_Mime_Part that
140:      * contains the embedded MIME part information.
141:      *
142:      * @return mixed  A Horde_Mime_Part with the embedded MIME part information
143:      *                or null if no embedded MIME parts exist.
144:      */
145:     protected function _getEmbeddedMimeParts()
146:     {
147:         if (!in_array($this->_mimepart->getType(), array('application/pkcs7-mime', 'application/x-pkcs7-mime'))) {
148:             return null;
149:         }
150: 
151:         // 'smime-type' must be 'enveloped-data' or 'signed-data'
152:         switch ($this->_mimepart->getContentTypeParameter('smime-type')) {
153:         case 'signed-data':
154:             return $this->_parseSignedData();
155: 
156:         case 'enveloped-data':
157:         default:
158:             /* Thunderbird bug: it doesn't include the smime-type parameter
159:              * for 'enveloped-data'. So do explicit check for enveloped
160:              * data. */
161:             return $this->_parseEnvelopedData();
162:         }
163:     }
164: 
165:     /**
166:      * Parse enveloped (encrypted) data.
167:      *
168:      * @return mixed  See self::_getEmbeddedMimeParts().
169:      */
170:     protected function _parseEnvelopedData()
171:     {
172:         $base_id = $this->_mimepart->getMimeId();
173: 
174:         /* Initialize inline data. */
175:         $status = new IMP_Mime_Status(_("The data in this part has been encrypted via S/MIME."));
176:         $status->icon('mime/encryption.png', 'S/MIME');
177:         self::$_cache[$base_id] = array(
178:             'status' => $status,
179:             'wrap' => ''
180:         );
181: 
182:         /* Is PGP active? */
183:         $this->_initSmime();
184:         if (empty($this->_impsmime)) {
185:             $status->addText(_("S/MIME support is not currently enabled so the data is unable to be decrypted."));
186:             return null;
187:         }
188: 
189:         if (!$this->_impsmime->getPersonalPrivateKey()) {
190:             $status->addText(_("No personal private key exists so the data is unable to be decrypted."));
191:             return null;
192:         }
193: 
194:         /* Make sure we have a passphrase. */
195:         $passphrase = $this->_impsmime->getPassphrase();
196:         if ($passphrase === false) {
197:             $imple = $GLOBALS['injector']->getInstance('Horde_Core_Factory_Imple')->create(array('imp', 'PassphraseDialog'), array(
198:                 'type' => 'smimePersonal'
199:             ));
200:             $status->addText(Horde::link('#', '', '', '', '', '', '', array('id' => $imple->getPassphraseId())) . _("You must enter the passphrase for your S/MIME private key to view this data.") . '</a>');
201:             return null;
202:         }
203: 
204:         $raw_text = $this->_getPartStream($this->_mimepart->getMimeId());
205: 
206:         try {
207:             $decrypted_data = $this->_impsmime->decryptMessage($this->_mimepart->replaceEOL($raw_text, Horde_Mime_Part::RFC_EOL));
208:         } catch (Horde_Exception $e) {
209:             $status->addText($e->getMessage());
210:             return null;
211:         }
212: 
213:         self::$_cache[$base_id]['wrap'] = 'mimePartWrapValid';
214: 
215:         $new_part = Horde_Mime_Part::parseMessage($decrypted_data, array(
216:             'forcemime' => true
217:         ));
218: 
219:         $hdrs = $this->getConfigParam('imp_contents')->getHeader();
220:         $new_part->setMetadata('imp-smime-from', $hdrs->getValue('from'));
221: 
222:         return $new_part;
223:     }
224: 
225:     /**
226:      * Parse signed data.
227:      *
228:      * @param boolean $sig_only  Only do signature checking?
229:      *
230:      * @return mixed  See self::_getEmbeddedMimeParts().
231:      */
232:     protected function _parseSignedData($sig_only = false)
233:     {
234:         $partlist = array_keys($this->_mimepart->contentTypeMap());
235:         $base_id = reset($partlist);
236:         $sig_id = Horde_Mime::mimeIdArithmetic(next($partlist), 'next');
237: 
238:         /* Initialize inline data. */
239:         $status = new IMP_Mime_Status(_("The data in this part has been digitally signed via S/MIME."));
240:         $status->icon('mime/encryption.png', 'S/MIME');
241: 
242:         self::$_cache[$base_id] = array(
243:             'sig' => $sig_id,
244:             'status' => $status,
245:             'wrap' => 'mimePartWrap'
246:         );
247: 
248:         if (!$GLOBALS['prefs']->getValue('use_smime')) {
249:             $status->addText(_("S/MIME support is not enabled so the digital signature is unable to be verified."));
250:             return null;
251:         }
252: 
253:         if ($this->getConfigParam('imp_contents')->isEmbedded($base_id)) {
254:             $hdrs = new Horde_Mime_Headers();
255:             $hdrs->addHeader('From', $this->_mimepart->getMetadata('imp-smime-from'));
256: 
257:             $stream = $this->_mimepart->toString(array(
258:                 'headers' => $hdrs,
259:                 'stream' => true
260:             ));
261:         } else {
262:             $stream = $this->_getPartStream($base_id);
263:         }
264: 
265:         $raw_text = $this->_mimepart->replaceEOL($stream, Horde_Mime_Part::RFC_EOL);
266: 
267:         $this->_initSmime();
268:         $sig_result = null;
269: 
270:         if ($GLOBALS['prefs']->getValue('smime_verify') ||
271:             Horde_Util::getFormData('smime_verify_msg')) {
272:             try {
273:                 $sig_result = $this->_impsmime->verifySignature($raw_text);
274:                 if ($sig_result->verify) {
275:                     $status->action(IMP_Mime_Status::SUCCESS);
276:                 } else {
277:                     $status->action(IMP_Mime_Status::WARNING);
278:                 }
279:                 self::$_cache[$base_id]['wrap'] = 'mimePartWrapValid';
280: 
281:                 $email = is_array($sig_result->email)
282:                     ? implode(', ', $sig_result->email)
283:                     : $sig_result->email;
284: 
285:                 $status->addText($sig_result->msg);
286: 
287:                 if (!empty($sig_result->cert)) {
288:                     $cert = $this->_impsmime->parseCert($sig_result->cert);
289:                     if (isset($cert['certificate']['subject']['CommonName'])) {
290:                         $email = $cert['certificate']['subject']['CommonName'] . ' (' . trim($email) . ')';
291:                     }
292:                 }
293: 
294:                 if (strlen($email)) {
295:                     $status->addText(sprintf(_("Sender: %s"), htmlspecialchars($email)));
296:                 }
297: 
298:                 if (!empty($sig_result->cert) &&
299:                     isset($sig_result->email) &&
300:                     $GLOBALS['registry']->hasMethod('contacts/addField') &&
301:                     $GLOBALS['prefs']->getValue('add_source')) {
302:                     $status_out = '[' . $this->getConfigParam('imp_contents')->linkViewJS($this->_mimepart, 'view_attach', _("View Certificate"), array('params' => array('mode' => IMP_Contents::RENDER_INLINE, 'view_smime_key' => 1))) . ']';
303:                     try {
304:                         $this->_impsmime->getPublicKey($sig_result->email);
305:                     } catch (Horde_Exception $e) {
306:                         $status_out .= ' [' . Horde::link('#', '', null, null, $this->_impsmime->savePublicKeyURL($this->getConfigParam('imp_contents')->getMailbox(), $this->getConfigParam('imp_contents')->getUid(), $base_id) . ' return false;') . _("Save Certificate in your Address Book") . '</a>]';
307:                     }
308:                     $status->addText($status_out);
309:                 }
310:             } catch (Horde_Exception $e) {
311:                 $status->action(IMP_Mime_Status::ERROR);
312:                 self::$_cache[$base_id]['wrap'] = 'mimePartWrapInvalid';
313:                 $status->addText($e->getMessage());
314:             }
315:         } else {
316:             switch (IMP::getViewMode()) {
317:             case 'imp':
318:                 $status->addText(Horde::link(IMP::selfUrl()->add('smime_verify_msg', 1)) . _("Click HERE to verify the data.") . '</a>');
319:                 break;
320: 
321:             case 'dimp':
322:                 $status->addText(Horde::link('#', '', 'smimeVerifyMsg') . _("Click HERE to verify the data.") . '</a>');
323:                 break;
324:             }
325:         }
326: 
327:         if ($sig_only) {
328:             return;
329:         }
330: 
331:         $subpart = $this->getConfigParam('imp_contents')->getMIMEPart($sig_id);
332:         if (empty($subpart)) {
333:             try {
334:                 $msg_data = $this->_impsmime->extractSignedContents($raw_text);
335:                 $subpart = Horde_Mime_Part::parseMessage($msg_data, array('forcemime' => true));
336:             } catch (Horde_Exception $e) {
337:                 $status->addText($e->getMessage());
338:                 return null;
339:             }
340:         }
341: 
342:         return $subpart;
343:     }
344: 
345:     /**
346:      * Generates HTML output for the S/MIME key.
347:      *
348:      * @return string  The HTML output.
349:      */
350:     protected function _outputSmimeKey()
351:     {
352:         if (empty($this->_impsmime)) {
353:             return array();
354:         }
355: 
356:         $raw_text = $this->_getPartStream($this->_mimepart->getMimeId());
357: 
358:         try {
359:             $sig_result = $this->_impsmime->verifySignature($this->_mimepart->replaceEOL($raw_text, Horde_Mime_Part::RFC_EOL));
360:         } catch (Horde_Exception $e) {
361:             return array();
362:         }
363: 
364:         return array(
365:             $this->_mimepart->getMimeId() => array(
366:                 'data' => $this->_impsmime->certToHTML($sig_result->cert),
367:                 'type' => 'text/html; charset=' . $this->getConfigParam('charset')
368:             )
369:         );
370:     }
371: 
372:     /**
373:      */
374:     protected function _getPartStream($id)
375:     {
376:         return $id
377:             ? $this->getConfigParam('imp_contents')->getBodyPart($id, array('mimeheaders' => true, 'stream' => true))
378:             : $this->getConfigParam('imp_contents')->fullMessageText();
379:     }
380: 
381: }
382: 
API documentation generated by ApiGen