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_Crypt_Pgp:: class contains all functions related to handling
  4:  * PGP messages within IMP.
  5:  *
  6:  * Copyright 2002-2012 Horde LLC (http://www.horde.org/)
  7:  *
  8:  * See the enclosed file COPYING for license information (GPL). If you
  9:  * did not receive this file, see http://www.horde.org/licenses/gpl.
 10:  *
 11:  * @author   Michael Slusarz <slusarz@horde.org>
 12:  * @category Horde
 13:  * @license  http://www.horde.org/licenses/gpl GPL
 14:  * @package  IMP
 15:  */
 16: class IMP_Crypt_Pgp extends Horde_Crypt_Pgp
 17: {
 18:     /* Name of PGP public key field in addressbook. */
 19:     const PUBKEY_FIELD = 'pgpPublicKey';
 20: 
 21:     /* Encryption type constants. */
 22:     const ENCRYPT = 'pgp_encrypt';
 23:     const SIGN = 'pgp_sign';
 24:     const SIGNENC = 'pgp_signenc';
 25:     const SYM_ENCRYPT = 'pgp_sym_enc';
 26:     const SYM_SIGNENC = 'pgp_syn_sign';
 27: 
 28:     /**
 29:      * Return the list of available encryption options for composing.
 30:      *
 31:      * @return array  Keys are encryption type constants, values are gettext
 32:      *                strings describing the encryption type.
 33:      */
 34:     public function encryptList()
 35:     {
 36:         $ret = array(
 37:             self::ENCRYPT => _("PGP Encrypt Message")
 38:         );
 39: 
 40:         if ($this->getPersonalPrivateKey()) {
 41:             $ret += array(
 42:                 self::SIGN => _("PGP Sign Message"),
 43:                 self::SIGNENC => _("PGP Sign/Encrypt Message")
 44:             );
 45:         }
 46: 
 47:         return $ret + array(
 48:             self::SYM_ENCRYPT => _("PGP Encrypt Message with passphrase"),
 49:             self::SYM_SIGNENC => _("PGP Sign/Encrypt Message with passphrase")
 50:         );
 51:     }
 52: 
 53:     /**
 54:      * Generate the personal Public/Private keypair and store in prefs.
 55:      *
 56:      * @param string $realname    See Horde_Crypt_Pgp::
 57:      * @param string $email       See Horde_Crypt_Pgp::
 58:      * @param string $passphrase  See Horde_Crypt_Pgp::
 59:      * @param string $comment     See Horde_Crypt_Pgp::
 60:      * @param string $keylength   See Horde_Crypt_Pgp::
 61:      *
 62:      * @throws Horde_Crypt_Exception
 63:      */
 64:     public function generatePersonalKeys($name, $email, $passphrase,
 65:                                          $comment = '', $keylength = 1024)
 66:     {
 67:         $keys = $this->generateKey($name, $email, $passphrase, $comment, $keylength);
 68: 
 69:         /* Store the keys in the user's preferences. */
 70:         $this->addPersonalPublicKey($keys['public']);
 71:         $this->addPersonalPrivateKey($keys['private']);
 72:     }
 73: 
 74:     /**
 75:      * Add the personal public key to the prefs.
 76:      *
 77:      * @param mixed $public_key  The public key to add (either string or
 78:      *                           array).
 79:      */
 80:     public function addPersonalPublicKey($public_key)
 81:     {
 82:         $GLOBALS['prefs']->setValue('pgp_public_key', (is_array($public_key)) ? implode('', $public_key) : $public_key);
 83:     }
 84: 
 85:     /**
 86:      * Add the personal private key to the prefs.
 87:      *
 88:      * @param mixed $private_key  The private key to add (either string or
 89:      *                            array).
 90:      */
 91:     public function addPersonalPrivateKey($private_key)
 92:     {
 93:         $GLOBALS['prefs']->setValue('pgp_private_key', (is_array($private_key)) ? implode('', $private_key) : $private_key);
 94:     }
 95: 
 96:     /**
 97:      * Get the personal public key from the prefs.
 98:      *
 99:      * @return string  The personal PGP public key.
100:      */
101:     public function getPersonalPublicKey()
102:     {
103:         return $GLOBALS['prefs']->getValue('pgp_public_key');
104:     }
105: 
106:     /**
107:      * Get the personal private key from the prefs.
108:      *
109:      * @return string  The personal PGP private key.
110:      */
111:     public function getPersonalPrivateKey()
112:     {
113:         return $GLOBALS['prefs']->getValue('pgp_private_key');
114:     }
115: 
116:     /**
117:      * Deletes the specified personal keys from the prefs.
118:      */
119:     public function deletePersonalKeys()
120:     {
121:         $GLOBALS['prefs']->setValue('pgp_public_key', '');
122:         $GLOBALS['prefs']->setValue('pgp_private_key', '');
123: 
124:         $this->unsetPassphrase('personal');
125:     }
126: 
127:     /**
128:      * Add a public key to an address book.
129:      *
130:      * @param string $public_key  An PGP public key.
131:      *
132:      * @return array  See Horde_Crypt_Pgp::pgpPacketInformation()
133:      * @throws Horde_Crypt_Exception
134:      * @throws Horde_Exception
135:      */
136:     public function addPublicKey($public_key)
137:     {
138:         /* Make sure the key is valid. */
139:         $key_info = $this->pgpPacketInformation($public_key);
140:         if (!isset($key_info['signature'])) {
141:             throw new Horde_Crypt_Exception(_("Not a valid public key."));
142:         }
143: 
144:         /* Remove the '_SIGNATURE' entry. */
145:         unset($key_info['signature']['_SIGNATURE']);
146: 
147:         /* Store all signatures that appear in the key. */
148:         foreach ($key_info['signature'] as $id => $sig) {
149:             /* Check to make sure the key does not already exist in ANY
150:              * address book and remove the id from the key_info for a correct
151:              * output. */
152:             try {
153:                 $result = $this->getPublicKey($sig['email'], array('nocache' => true, 'noserver' => true));
154:                 if (!empty($result)) {
155:                     unset($key_info['signature'][$id]);
156:                     continue;
157:                 }
158:             } catch (Horde_Crypt_Exception $e) {}
159: 
160:             /* Add key to the user's address book. */
161:             $GLOBALS['registry']->call('contacts/addField', array($sig['email'], $sig['name'], self::PUBKEY_FIELD, $public_key, $GLOBALS['prefs']->getValue('add_source')));
162:         }
163: 
164:         return $key_info;
165:     }
166: 
167:     /**
168:      * Retrieves a public key by e-mail.
169:      *
170:      * First, the key will be attempted to be retrieved from a user's address
171:      * book(s).
172:      * Second, if unsuccessful, the key is attempted to be retrieved via a
173:      * public PGP keyserver.
174:      *
175:      * @param string $address  The e-mail address to search by.
176:      * @param array $options   Additional options:
177:      * <pre>
178:      * 'keyid' - (string) The key ID of the user's key.
179:      *           DEFAULT: key ID not used
180:      * 'nocache' - (boolean) Don't retrieve from cache?
181:      *             DEFAULT: false
182:      * 'noserver' - (boolean) Whether to check the public key servers for the
183:      *              key.
184:      *              DEFAULT: false
185:      * </pre>
186:      *
187:      * @return string  The PGP public key requested.
188:      * @throws Horde_Crypt_Exception
189:      */
190:     public function getPublicKey($address, $options = array())
191:     {
192:         $keyid = empty($options['keyid'])
193:             ? ''
194:             : $options['keyid'];
195: 
196:         /* If there is a cache driver configured, try to get the public key
197:          * from the cache. */
198:         if (empty($options['nocache']) && ($cache = $GLOBALS['injector']->getInstance('Horde_Cache'))) {
199:             $result = $cache->get("PGPpublicKey_" . $address . $keyid, 3600);
200:             if ($result) {
201:                 Horde::logMessage('PGPpublicKey: ' . serialize($result), 'DEBUG');
202:                 return $result;
203:             }
204:         }
205: 
206:         try {
207:             $key = Horde::callHook('pgp_key', array($address, $keyid), 'imp');
208:             if ($key) {
209:                 return $key;
210:             }
211:         } catch (Horde_Exception_HookNotSet $e) {}
212: 
213:         /* Try retrieving by e-mail only first. */
214:         $params = IMP::getAddressbookSearchParams();
215:         $result = null;
216:         try {
217:             $result = $GLOBALS['registry']->call('contacts/getField', array($address, self::PUBKEY_FIELD, $params['sources'], true, true));
218:         } catch (Horde_Exception $e) {}
219: 
220:         if (is_null($result)) {
221:             /* TODO: Retrieve by ID. */
222: 
223:             /* See if the address points to the user's public key. */
224:             $identity = $GLOBALS['injector']->getInstance('IMP_Identity');
225:             $personal_pubkey = $this->getPersonalPublicKey();
226:             if (!empty($personal_pubkey) && $identity->hasAddress($address)) {
227:                 $result = $personal_pubkey;
228:             } elseif (empty($options['noserver'])) {
229:                 try {
230:                     $result = $this->getFromPublicKeyserver($keyid, $address);
231: 
232:                     /* If there is a cache driver configured and a cache
233:                      * object exists, store the retrieved public key in the
234:                      * cache. */
235:                     if (is_object($cache)) {
236:                         $cache->set("PGPpublicKey_" . $address . $keyid, $result, 3600);
237:                     }
238:                 } catch (Horde_Crypt_Exception $e) {
239:                     /* Return now, if no public key found at all. */
240:                     Horde::logMessage('PGPpublicKey: ' . $e->getMessage(), 'DEBUG');
241:                     throw new Horde_Crypt_Exception(sprintf(_("Could not retrieve public key for %s."), $address));
242:                 }
243:             } else {
244:                 $result = '';
245:             }
246:         }
247: 
248:         /* If more than one public key is returned, just return the first in
249:          * the array. There is no way of knowing which is the "preferred" key,
250:          * if the keys are different. */
251:         if (is_array($result)) {
252:             reset($result);
253:         }
254: 
255:         return $result;
256:     }
257: 
258:     /**
259:      * Retrieves all public keys from a user's address book(s).
260:      *
261:      * @return array  All PGP public keys available.
262:      * @throws Horde_Crypt_Exception
263:      */
264:     public function listPublicKeys()
265:     {
266:         $params = IMP::getAddressbookSearchParams();
267:         if (empty($params['sources'])) {
268:             return array();
269:         }
270: 
271:         return $GLOBALS['registry']->call('contacts/getAllAttributeValues', array(self::PUBKEY_FIELD, $params['sources']));
272:     }
273: 
274:     /**
275:      * Deletes a public key from a user's address book(s) by e-mail.
276:      *
277:      * @param string $email  The e-mail address to delete.
278:      *
279:      * @throws Horde_Crypt_Exception
280:      */
281:     public function deletePublicKey($email)
282:     {
283:         $params = IMP::getAddressbookSearchParams();
284:         return $GLOBALS['registry']->call('contacts/deleteField', array($email, self::PUBKEY_FIELD, $params['sources']));
285:     }
286: 
287:     /**
288:      * Get a public key via a public PGP keyserver.
289:      *
290:      * @param string $keyid    The key ID of the requested key.
291:      * @param string $address  The email address of the requested key.
292:      *
293:      * @return string  See Horde_Crypt_Pgp::getPublicKeyserver()
294:      * @throws Horde_Crypt_Exception
295:      */
296:     public function getFromPublicKeyserver($keyid, $address = null)
297:     {
298:         return $this->_keyserverConnect($keyid, 'get', $address);
299:     }
300: 
301:     /**
302:      * Send a public key to a public PGP keyserver.
303:      *
304:      * @param string $pubkey  The PGP public key.
305:      *
306:      * @return string  See Horde_Crypt_Pgp::putPublicKeyserver()
307:      * @throws Horde_Crypt_Exception
308:      */
309:     public function sendToPublicKeyserver($pubkey)
310:     {
311:         return $this->_keyserverConnect($pubkey, 'put');
312:     }
313: 
314:     /**
315:      * Connect to the keyservers
316:      *
317:      * @param string $data        The data to send to the keyserver.
318:      * @param string $method      The method to use - either 'get' or 'put'.
319:      * @param string $additional  Any additional data.
320:      *
321:      * @return string  See Horde_Crypt_Pgp::getPublicKeyserver() -or-
322:      *                     Horde_Crypt_Pgp::putPublicKeyserver().
323:      * @throws Horde_Crypt_Exception
324:      */
325:     protected function _keyserverConnect($data, $method, $additional = null)
326:     {
327:         global $conf;
328: 
329:         if (empty($conf['gnupg']['keyserver'])) {
330:             throw new Horde_Crypt_Exception(_("Public PGP keyserver support has been disabled."));
331:         }
332: 
333:         $timeout = empty($conf['gnupg']['timeout'])
334:             ? Horde_Crypt_Pgp::KEYSERVER_TIMEOUT
335:             : $conf['gnupg']['timeout'];
336: 
337:         if ($method == 'put') {
338:             return $this->putPublicKeyserver($data, $conf['gnupg']['keyserver'][0], $timeout);
339:         }
340: 
341:         foreach ($conf['gnupg']['keyserver'] as $server) {
342:             try {
343:                 return $this->getPublicKeyserver($data, $server, $timeout, $additional);
344:             } catch (Horde_Crypt_Exception $e) {}
345:         }
346:         throw new Horde_Crypt_Exception(_("Could not connect to public PGP keyserver"));
347:     }
348: 
349:     /**
350:      * Verifies a signed message with a given public key.
351:      *
352:      * @param string $text       The text to verify.
353:      * @param string $address    E-mail address of public key.
354:      * @param string $signature  A PGP signature block.
355:      * @param string $charset    Charset to use.
356:      *
357:      * @return stdClass  See Horde_Crypt_Pgp::decrypt().
358:      * @throws Horde_Crypt_Exception
359:      */
360:     public function verifySignature($text, $address, $signature = '',
361:                                     $charset = null)
362:     {
363:         if (!empty($signature)) {
364:             $packet_info = $this->pgpPacketInformation($signature);
365:             if (isset($packet_info['keyid'])) {
366:                 $keyid = $packet_info['keyid'];
367:             }
368:         }
369: 
370:         if (!isset($keyid)) {
371:             $keyid = $this->getSignersKeyID($text);
372:         }
373: 
374:         /* Get key ID of key. */
375:         $public_key = $this->getPublicKey($address, array('keyid' => $keyid));
376: 
377:         if (empty($signature)) {
378:             $options = array('type' => 'signature');
379:         } else {
380:             $options = array('type' => 'detached-signature', 'signature' => $signature);
381:         }
382:         $options['pubkey'] = $public_key;
383: 
384:         if (!empty($charset)) {
385:             $options['charset'] = $charset;
386:         }
387: 
388:         return $this->decrypt($text, $options);
389:     }
390: 
391:     /**
392:      * Decrypt a message with user's public/private keypair or a passphrase.
393:      *
394:      * @param string $text         The text to decrypt.
395:      * @param string $type         Either 'literal', 'personal', or
396:      *                             'symmetric'.
397:      * @param boolean $passphrase  If $type is 'personal' or 'symmetrical',
398:      *                             the passphrase to use.
399:      *
400:      * @return stdClass  See Horde_Crypt_Pgp::decrypt().
401:      * @throws Horde_Crypt_Exception
402:      */
403:     public function decryptMessage($text, $type, $passphrase = null)
404:     {
405:         switch ($type) {
406:         case 'literal':
407:             return $this->decrypt($text, array('type' => 'message', 'no_passphrase' => true));
408:             break;
409: 
410:         case 'symmetric':
411:             return $this->decrypt($text, array('type' => 'message', 'passphrase' => $passphrase));
412:             break;
413: 
414:         case 'personal':
415:             return $this->decrypt($text, array('type' => 'message', 'pubkey' => $this->getPersonalPublicKey(), 'privkey' => $this->getPersonalPrivateKey(), 'passphrase' => $passphrase));
416:         }
417:     }
418: 
419:     /**
420:      * Gets a passphrase from the session cache.
421:      *
422:      * @param integer $type  The type of passphrase. Either 'personal' or
423:      *                       'symmetric'.
424:      * @param string $id     If $type is 'symmetric', the ID of the stored
425:      *                       passphrase.
426:      *
427:      * @return mixed  The passphrase, if set, or null.
428:      */
429:     public function getPassphrase($type, $id = null)
430:     {
431:         if ($type == 'personal') {
432:             $id = 'personal';
433:         }
434: 
435:         if (!($cache = $GLOBALS['session']->get('imp', 'pgp')) ||
436:             !isset($cache[$type][$id])) {
437:             return null;
438:         }
439: 
440:         $secret = $GLOBALS['injector']->getInstance('Horde_Secret');
441:         return $secret->read($secret->getKey('imp'), $cache[$type][$id]);
442:     }
443: 
444:     /**
445:      * Store's the user's passphrase in the session cache.
446:      *
447:      * @param integer $type       The type of passphrase. Either 'personal' or
448:      *                            'symmetric'.
449:      * @param string $passphrase  The user's passphrase.
450:      * @param string $id          If $type is 'symmetric', the ID of the
451:      *                            stored passphrase.
452:      *
453:      * @return boolean  Returns true if correct passphrase, false if incorrect.
454:      */
455:     public function storePassphrase($type, $passphrase, $id = null)
456:     {
457:         if ($type == 'personal') {
458:             if ($this->verifyPassphrase($this->getPersonalPublicKey(), $this->getPersonalPrivateKey(), $passphrase) === false) {
459:                 return false;
460:             }
461:             $id = 'personal';
462:         }
463: 
464:         $secret = $GLOBALS['injector']->getInstance('Horde_Secret');
465: 
466:         $cache = $GLOBALS['session']->get('imp', 'pgp', Horde_Session::TYPE_ARRAY);
467:         $cache[$type][$id] = $secret->write($secret->getKey('imp'), $passphrase);
468:         $GLOBALS['session']->set('imp', 'pgp', $cache);
469: 
470:         return true;
471:     }
472: 
473:     /**
474:      * Clear the passphrase from the session cache.
475:      *
476:      * @param integer $type       The type of passphrase. Either 'personal' or
477:      *                            'symmetric'.
478:      * @param string $id          If $type is 'symmetric', the ID of the
479:      *                            stored passphrase. Else, all passphrases
480:      *                            are deleted.
481:      */
482:     public function unsetPassphrase($type, $id = null)
483:     {
484:         if ($cache = $GLOBALS['session']->get('imp', 'pgp')) {
485:             if (($type == 'symmetric') && !is_null($id)) {
486:                 unset($cache['symmetric'][$id]);
487:             } else {
488:                 unset($cache[$type]);
489:             }
490:             $GLOBALS['session']->set('imp', 'pgp', $cache);
491:         }
492:     }
493: 
494:     /**
495:      * Generates a cache ID for symmetric message data.
496:      *
497:      * @param string $mailbox  The mailbox of the message.
498:      * @param integer $uid     The UID of the message.
499:      * @param string $id       The MIME ID of the message.
500:      *
501:      * @return string  A unique symmetric cache ID.
502:      */
503:     public function getSymmetricId($mailbox, $uid, $id)
504:     {
505:         return implode('|', array($mailbox, $uid, $id));
506:     }
507: 
508:     /**
509:      * Generates the javascript code for saving public keys.
510:      *
511:      * @param string $mailbox  The mailbox of the message.
512:      * @param integer $uid     The UID of the message.
513:      * @param string $id       The MIME ID of the message.
514:      *
515:      * @return string  The URL for saving public keys.
516:      */
517:     public function savePublicKeyUrl($mailbox, $uid, $id)
518:     {
519:         $params = array(
520:             'actionID' => 'save_attachment_public_key',
521:             'mailbox' => $mailbox,
522:             'uid' => $uid,
523:             'mime_id' => $id
524:         );
525:         return Horde::popupJs(Horde::url('pgp.php'), array('params' => $params, 'height' => 200, 'width' => 450));
526:     }
527: 
528:     /**
529:      * Provide the list of parameters needed for signing a message.
530:      *
531:      * @return array  The list of parameters needed by encrypt().
532:      */
533:     protected function _signParameters()
534:     {
535:         return array(
536:             'pubkey' => $this->getPersonalPublicKey(),
537:             'privkey' => $this->getPersonalPrivateKey(),
538:             'passphrase' => $this->getPassphrase('personal')
539:         );
540:     }
541: 
542:     /**
543:      * Provide the list of parameters needed for encrypting a message.
544:      *
545:      * @param array $addresses   The e-mail address of the keys to use for
546:      *                           encryption.
547:      * @param string $symmetric  If true, the symmetric password to use for
548:      *                           encrypting. If null, uses the personal key.
549:      *
550:      * @return array  The list of parameters needed by encrypt().
551:      * @throws Horde_Crypt_Exception
552:      */
553:     protected function _encryptParameters($addresses, $symmetric)
554:     {
555:         if (!is_null($symmetric)) {
556:             return array(
557:                 'symmetric' => true,
558:                 'passphrase' => $symmetric
559:             );
560:         }
561: 
562:         $addr_list = array();
563: 
564:         foreach ($addresses as $val) {
565:             $addrOb = Horde_Mime_Address::bareAddress($val, $GLOBALS['session']->get('imp', 'maildomain'), true);
566:             $key_addr = array_pop($addrOb);
567: 
568:             /* Get the public key for the address. */
569:             $addr_list[$key_addr] = $this->getPublicKey($key_addr);
570:         }
571: 
572:         return array('recips' => $addr_list);
573:     }
574: 
575:     /**
576:      * Sign a Horde_Mime_Part using PGP using IMP default parameters.
577:      *
578:      * @param Horde_Mime_Part $mime_part  The object to sign.
579:      *
580:      * @return Horde_Mime_Part  See Horde_Crypt_Pgp::signMIMEPart().
581:      * @throws Horde_Crypt_Exception
582:      */
583:     public function impSignMimePart($mime_part)
584:     {
585:         return $this->signMimePart($mime_part, $this->_signParameters());
586:     }
587: 
588:     /**
589:      * Encrypt a Horde_Mime_Part using PGP using IMP default parameters.
590:      *
591:      * @param Horde_Mime_Part $mime_part  The object to encrypt.
592:      * @param array $addresses            The e-mail address of the keys to
593:      *                                    use for encryption.
594:      * @param string $symmetric           If true, the symmetric password to
595:      *                                    use for encrypting. If null, uses
596:      *                                    the personal key.
597:      *
598:      * @return Horde_Mime_Part  See Horde_Crypt_Pgp::encryptMimePart().
599:      * @throws Horde_Crypt_Exception
600:      */
601:     public function impEncryptMimePart($mime_part, $addresses,
602:                                        $symmetric = null)
603:     {
604:         return $this->encryptMimePart($mime_part, $this->_encryptParameters($addresses, $symmetric));
605:     }
606: 
607:     /**
608:      * Sign and Encrypt a Horde_Mime_Part using PGP using IMP default
609:      * parameters.
610:      *
611:      * @param Horde_Mime_Part $mime_part  The object to sign and encrypt.
612:      * @param array $addresses            The e-mail address of the keys to
613:      *                                    use for encryption.
614:      * @param string $symmetric           If true, the symmetric password to
615:      *                                    use for encrypting. If null, uses
616:      *                                    the personal key.
617:      *
618:      * @return Horde_Mime_Part  See Horde_Crypt_Pgp::signAndencryptMimePart().
619:      * @throws Horde_Crypt_Exception
620:      */
621:     public function impSignAndEncryptMimePart($mime_part, $addresses,
622:                                               $symmetric = null)
623:     {
624:         return $this->signAndEncryptMimePart($mime_part, $this->_signParameters(), $this->_encryptParameters($addresses, $symmetric));
625:     }
626: 
627:     /**
628:      * Generate a Horde_Mime_Part object, in accordance with RFC 2015/3156,
629:      * that contains the user's public key.
630:      *
631:      * @return Horde_Mime_Part  See Horde_Crypt_Pgp::publicKeyMimePart().
632:      */
633:     public function publicKeyMimePart()
634:     {
635:         return parent::publicKeyMimePart($this->getPersonalPublicKey());
636:     }
637: 
638:     /* UI related functions. */
639: 
640:     /**
641:      * Print PGP Key information.
642:      *
643:      * @param string $key  The PGP key.
644:      */
645:     public function printKeyInfo($key = '')
646:     {
647:         try {
648:             $key_info = $this->pgpPrettyKey($key);
649:         } catch (Horde_Crypt_Exception $e) {
650:             Horde::logMessage($e, 'INFO');
651:             $key_info = $e->getMessage();
652:         }
653: 
654:         $this->textWindowOutput('PGP Key Information', $key_info);
655:     }
656: 
657:     /**
658:      * Output text in a window.
659:      *
660:      * @param string $name  The window name.
661:      * @param string $msg   The text contents.
662:      */
663:     public function textWindowOutput($name, $msg)
664:     {
665:         $GLOBALS['browser']->downloadHeaders($name, 'text/plain; charset=' . 'UTF-8', true, strlen($msg));
666:         echo $msg;
667:     }
668: 
669:     /**
670:      * Generate import key dialog.
671:      *
672:      * @param string $target  Action ID for the UI screen.
673:      * @param string $reload  The reload cache value.
674:      */
675:     public function importKeyDialog($target, $reload)
676:     {
677:         $title = _("Import PGP Key");
678:         require IMP_TEMPLATES . '/common-header.inc';
679: 
680:         /* Need to use regular status notification - AJAX notifications won't
681:          * show in popup windows. */
682:         if (IMP::getViewMode() == 'dimp') {
683:             $GLOBALS['notification']->detach('status');
684:             $GLOBALS['notification']->attach('status');
685:         }
686:         IMP::status();
687: 
688:         $t = $GLOBALS['injector']->createInstance('Horde_Template');
689:         $t->setOption('gettext', true);
690:         $t->set('selfurl', Horde::url('pgp.php'));
691:         $t->set('broken_mp_form', $GLOBALS['browser']->hasQuirk('broken_multipart_form'));
692:         $t->set('reload', htmlspecialchars($reload));
693:         $t->set('target', $target);
694:         $t->set('forminput', Horde_Util::formInput());
695:         $t->set('import_public_key', $target == 'process_import_public_key');
696:         $t->set('import_personal_public_key', $target == 'process_import_personal_public_key');
697:         $t->set('import_personal_private_key', $target == 'process_import_personal_private_key');
698:         echo $t->fetch(IMP_TEMPLATES . '/pgp/import_key.html');
699:     }
700: 
701:     /**
702:      * Attempt to import a key from form/uploaded data.
703:      *
704:      * @param string $key  Key string.
705:      *
706:      * @return string  The key contents.
707:      * @throws Horde_Browser_Exception
708:      */
709:     public function getImportKey($key)
710:     {
711:         if (!empty($key)) {
712:             return $key;
713:         }
714: 
715:         $GLOBALS['browser']->wasFileUploaded('upload_key', _("key"));
716:         return file_get_contents($_FILES['upload_key']['tmp_name']);
717:     }
718: 
719:     /**
720:      * Reload the window.
721:      *
722:      * @param string $reload  The reload cache value.
723:      */
724:     public function reloadWindow($reload)
725:     {
726:         global $session;
727: 
728:         $href = $session->retrieve($reload);
729:         $session->purge($reload);
730: 
731:         echo Horde::wrapInlineScript(array(
732:             'opener.focus();'.
733:             'opener.location.href="' . $href . '";',
734:             'window.close();'
735:         ));
736:     }
737: 
738: }
739: 
API documentation generated by ApiGen