[ Index ] |
|
Code source de IMP H3 (4.1.5) |
1 <?php 2 3 require_once 'Horde/Crypt/pgp.php'; 4 5 /** 6 * Name of PGP public key field in addressbook. 7 */ 8 define('IMP_PGP_PUBKEY_FIELD', 'pgpPublicKey'); 9 10 /** 11 * The IMP_PGP:: class contains all functions related to handling 12 * PGP messages within IMP. 13 * 14 * $Horde: imp/lib/Crypt/PGP.php,v 1.90.2.19 2007/03/09 11:42:18 jan Exp $ 15 * 16 * Copyright 2002-2007 Michael Slusarz <slusarz@bigworm.colorado.edu> 17 * 18 * See the enclosed file COPYING for license information (GPL). If you 19 * did not receive this file, see http://www.fsf.org/copyleft/gpl.html. 20 * 21 * @author Michael Slusarz <slusarz@bigworm.colorado.edu> 22 * @since IMP 4.0 23 * @package IMP 24 */ 25 class IMP_PGP extends Horde_Crypt_pgp { 26 27 /** 28 * The list of available sources to search for keys. 29 * 30 * @var array 31 */ 32 var $_sources = array(); 33 34 /** 35 * Constructor 36 */ 37 function IMP_PGP() 38 { 39 /* Get the listing of all sources we search for public keys. */ 40 if (($sources = $GLOBALS['prefs']->getValue('search_sources'))) { 41 $this->_sources = explode("\t", $sources); 42 if ((count($this->_sources) == 1) && empty($this->_sources[0])) { 43 $this->_sources = array(); 44 } 45 } 46 47 parent::Horde_Crypt_pgp(array('program' => $GLOBALS['conf']['utils']['gnupg'], 48 'temp' => Horde::getTempDir())); 49 } 50 51 /** 52 * Generate the personal Public/Private keypair and store in prefs. 53 * 54 * @param string $realname See Horde_Crypt_pgp:: 55 * @param string $email See Horde_Crypt_pgp:: 56 * @param string $passphrase See Horde_Crypt_pgp:: 57 * @param string $comment See Horde_Crypt_pgp:: 58 * @param string $keylength See Horde_Crypt_pgp:: 59 * 60 * @return PEAR_Error Returns a PEAR_Error object on error. 61 */ 62 function generatePersonalKeys($name, $email, $passphrase, $comment = '', 63 $keylength = 1024) 64 { 65 $keys = $this->generateKey($name, $email, $passphrase, $comment, $keylength); 66 if (is_a($keys, 'PEAR_Error')) return $keys; 67 68 /* Store the keys in the user's preferences. */ 69 $this->addPersonalPublicKey($keys['public']); 70 $this->addPersonalPrivateKey($keys['private']); 71 } 72 73 /** 74 * Add the personal public key to the prefs. 75 * 76 * @param mixed $public_key The public key to add (either string or 77 * array). 78 */ 79 function addPersonalPublicKey($public_key) 80 { 81 $GLOBALS['prefs']->setValue('pgp_public_key', (is_array($public_key)) ? implode('', $public_key) : $public_key); 82 } 83 84 /** 85 * Add the personal private key to the prefs. 86 * 87 * @param mixed $private_key The private key to add (either string or 88 * array). 89 */ 90 function addPersonalPrivateKey($private_key) 91 { 92 $GLOBALS['prefs']->setValue('pgp_private_key', (is_array($private_key)) ? implode('', $private_key) : $private_key); 93 } 94 95 /** 96 * Get the personal public key from the prefs. 97 * 98 * @return string The personal PGP public key. 99 */ 100 function getPersonalPublicKey() 101 { 102 return $GLOBALS['prefs']->getValue('pgp_public_key'); 103 } 104 105 /** 106 * Get the personal private key from the prefs. 107 * 108 * @return string The personal PGP private key. 109 */ 110 function getPersonalPrivateKey() 111 { 112 return $GLOBALS['prefs']->getValue('pgp_private_key'); 113 } 114 115 /** 116 * Deletes the specified personal keys from the prefs. 117 */ 118 function deletePersonalKeys() 119 { 120 $GLOBALS['prefs']->setValue('pgp_public_key', ''); 121 $GLOBALS['prefs']->setValue('pgp_private_key', ''); 122 123 $this->unsetPassphrase(); 124 } 125 126 /** 127 * Add a public key to an address book. 128 * 129 * @param string $public_key An PGP public key. 130 * 131 * @return array See Horde_Crypt_pgp::pgpPacketInformation() 132 * Returns PEAR_Error or error. 133 */ 134 function addPublicKey($public_key) 135 { 136 /* Make sure the key is valid. */ 137 $key_info = $this->pgpPacketInformation($public_key); 138 if (!isset($key_info['signature'])) { 139 return PEAR::raiseError(_("Not a valid public key."), 'horde.error'); 140 } 141 142 /* Remove the '_SIGNATURE' entry. */ 143 unset($key_info['signature']['_SIGNATURE']); 144 145 /* Store all signatures that appear in the key. */ 146 foreach ($key_info['signature'] as $id => $sig) { 147 /* Check to make sure the key does not already exist in ANY 148 address book and removes the id from the key_info for a 149 correct output. */ 150 $result = $this->getPublicKey($sig['email'], null, true); 151 if (!is_a($result, 'PEAR_Error') && !empty($result)) { 152 unset($key_info['signature'][$id]); 153 continue; 154 } 155 156 /* Add key to the user's address book. */ 157 $result = $GLOBALS['registry']->call('contacts/addField', array($sig['email'], $sig['name'], IMP_PGP_PUBKEY_FIELD, $public_key, $GLOBALS['prefs']->getValue('add_source'))); 158 if (is_a($result, 'PEAR_Error')) { 159 return $result; 160 } 161 } 162 163 return $key_info; 164 } 165 166 /** 167 * Retrieves a public key by e-mail. 168 * First, the key will be attempted to be retrieved from a user's 169 * address book(s). 170 * Second, if unsuccessful, the key is attempted to be retrieved via 171 * a public PGP keyserver. 172 * 173 * @param string $address The e-mail address to search by. 174 * @param string $fingerprint The fingerprint of the user's key. 175 * 176 * @return string The PGP public key requested. Returns PEAR_Error object 177 * on error. 178 */ 179 function getPublicKey($address, $fingerprint = null) 180 { 181 /* Try retrieving by e-mail only first. */ 182 $result = $GLOBALS['registry']->call('contacts/getField', array($address, IMP_PGP_PUBKEY_FIELD, $this->_sources, false, true)); 183 184 /* TODO: Retrieve by ID. */ 185 186 /* Try retrieving via a PGP public keyserver. */ 187 if (is_a($result, 'PEAR_Error') && !empty($fingerprint)) { 188 $result = $this->getFromPublicKeyserver($fingerprint); 189 } 190 191 /* See if the address points to the user's public key. */ 192 if (is_a($result, 'PEAR_Error')) { 193 require_once 'Horde/Identity.php'; 194 $identity = &Identity::singleton(array('imp', 'imp')); 195 $personal_pubkey = $this->getPersonalPublicKey(); 196 if (!empty($personal_pubkey) && $identity->hasAddress($address)) { 197 return $personal_pubkey; 198 } 199 } 200 201 /* If more than one public key is returned, just return the first in 202 * the array. There is no way of knowing which is the "preferred" key, 203 * if the keys are different. */ 204 if (is_array($result)) { 205 return reset($result); 206 } 207 208 return $result; 209 } 210 211 /** 212 * Retrieves all public keys from a user's address book(s). 213 * 214 * @return array All PGP public keys available. Returns PEAR_Error object 215 * on error. 216 * 217 */ 218 function listPublicKeys() 219 { 220 if (empty($this->_sources)) { 221 return array(); 222 } else { 223 return $GLOBALS['registry']->call('contacts/getAllAttributeValues', array(IMP_PGP_PUBKEY_FIELD, $this->_sources)); 224 } 225 } 226 227 /** 228 * Deletes a public key from a user's address book(s) by e-mail. 229 * 230 * @param string $email The e-mail address to delete. 231 * 232 * @return PEAR_Error Returns PEAR_Error object on error. 233 */ 234 function deletePublicKey($email) 235 { 236 return $GLOBALS['registry']->call('contacts/deleteField', array($email, IMP_PGP_PUBKEY_FIELD, $this->_sources)); 237 } 238 239 /** 240 * Parse a message into its PGP components. 241 * 242 * @param string $text See Horde_Crypt_pgp::parsePGPData() 243 * 244 * @return array Returns an array of MIME_Part objects. 245 * If there was no PGP data, returns false. 246 */ 247 function &parseMessage($text) 248 { 249 $result = $this->parsePGPData($text); 250 if (empty($result) || 251 ((count($result) == 1) && ($result[0]['type'] == PGP_ARMOR_TEXT))) { 252 $result = false; 253 return $result; 254 } 255 256 include_once 'Horde/MIME/Part.php'; 257 258 $return_array = array(); 259 260 reset($result); 261 do { 262 $block = current($result); 263 $temp_part = &new MIME_Part(); 264 $temp_part->setContents(implode("\n", $block['data'])); 265 266 /* Since private keys should NEVER be sent across email (in fact, 267 there is no MIME type to handle them) we will render them, if 268 someone is foolish enough to send one, in simple text. */ 269 if (($block['type'] == PGP_ARMOR_TEXT) || 270 ($block['type'] == PGP_ARMOR_PRIVATE_KEY)) { 271 $temp_part->setType('text/plain'); 272 } elseif ($block['type'] == PGP_ARMOR_PUBLIC_KEY) { 273 $temp_part->setType('application/pgp-keys'); 274 } elseif ($block['type'] == PGP_ARMOR_MESSAGE) { 275 $temp_part->setType('application/pgp-encrypted'); 276 } elseif ($block['type'] == PGP_ARMOR_SIGNED_MESSAGE) { 277 $temp_part->setType('application/pgp-signature'); 278 if (($block = next($result))) { 279 if (!empty($block) && ($block['type'] == PGP_ARMOR_SIGNATURE)) { 280 $temp_part->appendContents("\n" . implode("\n", $block['data'])); 281 } 282 } 283 } elseif ($block['type'] == PGP_ARMOR_SIGNATURE) { 284 continue; 285 } 286 287 $return_array[] = $temp_part; 288 } while (next($result)); 289 290 return $return_array; 291 } 292 293 /** 294 * Renders a text message with PGP components. 295 * 296 * @param MIME_Part &$part The MIME_Part containing the data to 297 * render. 298 * @param MIME_Contents &$contents The MIME_Contents:: module to use to 299 * output the text. 300 * 301 * @return string Returns the rendered text. 302 * If there was no PGP data, returns false. 303 */ 304 function parseMessageOutput(&$part, &$contents) 305 { 306 if (!($parts = &$this->parseMessage($part->getContents()))) { 307 return false; 308 } 309 310 $text = ''; 311 312 require_once 'Horde/MIME/Message.php'; 313 314 $base_ob = &$contents->getBaseObjectPtr(); 315 $addr = $base_ob->getFromAddress(); 316 317 $message = &new MIME_Message(); 318 foreach ($parts as $val) { 319 $message->addPart($val); 320 } 321 322 $mc = &new MIME_Contents($message, array('download' => 'download_attach', 'view' => 'view_attach'), array(&$contents)); 323 $message->buildMessage(); 324 325 foreach ($message->getParts() as $val) { 326 /* If the part appears to be nothing but empty space, don't 327 display it. */ 328 if (($val->getBytes() < 5) && 329 !(rtrim($val->getContents()))) { 330 continue; 331 } 332 $v = &$mc->getMIMEViewer($val); 333 if (!is_a($v, 'IMP_MIME_Viewer_pgp')) { 334 $text .= $mc->formatStatusMsg(_("The message below has not been digitally signed or encrypted with PGP."), Horde::img('alerts/warning.png', _("Warning"), '', $GLOBALS['registry']->getImageDir('horde'))); 335 } 336 $text .= $mc->renderMIMEPart($val); 337 } 338 339 return $text; 340 } 341 342 /** 343 * Returns the signed data only for a plaintext signed MIME_Part. 344 * 345 * @param MIME_Part $mime_part The MIME_Part object with a plaintext PGP 346 * signed message in the contents. 347 * 348 * @return string The contents of the signed message. 349 */ 350 function getSignedMessage(&$mime_part) 351 { 352 $msg = ''; 353 354 /* Just output signed data - remove all PGP headers. */ 355 $result = $this->parsePGPData($mime_part->getContents()); 356 foreach ($result as $block) { 357 if ($block['type'] == PGP_ARMOR_SIGNED_MESSAGE) { 358 $headerSeen = false; 359 $headerDone = false; 360 foreach ($block['data'] as $line) { 361 if ($headerDone) { 362 $msg .= $line . "\n"; 363 } elseif (strpos($line, "-----") === 0) { 364 $headerSeen = true; 365 continue; 366 } elseif ($headerSeen) { 367 /* There are some versions of GnuPG (like Version: 368 GnuPG v1.2.1 (MingW32)) which separate headers from 369 content with a line containing a blank, but this 370 isn't RFC conforming, so this isn't handled. 371 It results in a good signature with an empty 372 message. 373 The wrong code would be: 374 elseif (empty($line) || (strcmp($line, ' ') == 0)) 375 */ 376 $line = trim($line); 377 if (empty($line)) { 378 $headerDone = true; 379 } 380 } 381 } 382 } 383 } 384 385 return rtrim($msg); 386 } 387 388 /** 389 * Get a public key via a public PGP keyserver. 390 * 391 * @param string $fingerprint The fingerprint of the requested key. 392 * 393 * @return string See Horde_Crypt_pgp::getPublicKeyserver() 394 */ 395 function getFromPublicKeyserver($fingerprint) 396 { 397 return $this->_keyserverConnect($fingerprint, 'get'); 398 } 399 400 /** 401 * Send a public key to a public PGP keyserver. 402 * 403 * @param string $pubkey The PGP public key. 404 * 405 * @return string See Horde_Crypt_pgp::putPublicKeyserver() 406 */ 407 function sendToPublicKeyserver($pubkey) 408 { 409 return $this->_keyserverConnect($pubkey, 'put'); 410 } 411 412 /** 413 * Connect to the keyservers 414 * 415 * @access private 416 * 417 * @param string $data The data to send to the keyserver. 418 * @param string $method The method to use - either 'get' or 'put'. 419 * 420 * @return string See Horde_Crypt_pgp::getPublicKeyserver() -or- 421 * Horde_Crypt_pgp::putPublicKeyserver(). 422 */ 423 function _keyserverConnect($data, $method) 424 { 425 global $conf; 426 427 if (!empty($conf['utils']['gnupg_keyserver'])) { 428 $timeout = (empty($conf['utils']['gnupg_timeout'])) ? PGP_KEYSERVER_TIMEOUT : $conf['utils']['gnupg_timeout']; 429 if ($method == 'get') { 430 foreach ($conf['utils']['gnupg_keyserver'] as $server) { 431 $result = $this->getPublicKeyserver($data, $server, $timeout); 432 if (!is_a($result, 'PEAR_Error')) { 433 return $result; 434 } 435 } 436 return $result; 437 } else { 438 return $this->putPublicKeyserver($data, $conf['utils']['gnupg_keyserver'][0], $timeout); 439 } 440 } else { 441 return PEAR::raiseError(_("Public PGP keyserver support has been disabled."), 'horde.warning'); 442 } 443 } 444 445 /** 446 * Verifies a signed message with a given public key. 447 * 448 * @param string $text The text to verify. 449 * @param string $address E-mail address of public key. 450 * @param string $signature A PGP signature block. 451 * 452 * @return string See Horde_Crypt_pgp::decryptSignature() 453 * -OR- 454 * Horde_Crypt_pgp::decryptDetachedSignature() 455 */ 456 function verifySignature($text, $address, $signature = '') 457 { 458 $fingerprint = null; 459 460 /* Get fingerprint of key. */ 461 if (!empty($signature)) { 462 $packet_info = $this->pgpPacketInformation($signature); 463 if (isset($packet_info['fingerprint'])) { 464 $fingerprint = $packet_info['fingerprint']; 465 } 466 } else { 467 $fingerprint = $this->getSignersFingerprint($text); 468 } 469 470 $public_key = $this->getPublicKey($address, $fingerprint); 471 if (is_a($public_key, 'PEAR_Error')) { 472 return $public_key; 473 } 474 475 if (!empty($signature)) { 476 $options = array('type' => 'detached-signature', 'signature' => $signature); 477 } else { 478 $options = array('type' => 'signature'); 479 } 480 $options['pubkey'] = $public_key; 481 482 /* decrypt() returns a PEAR_Error object on error. */ 483 return $this->decrypt($text, $options); 484 } 485 486 487 /** 488 * Decrypt a message with user's public/private keypair. 489 * 490 * @param string $text The text to decrypt. 491 * @param boolean $passphrase Whether a passphrase has to be used. 492 * 493 * @return string The decrypted message. Returns PEAR_Error object on 494 * error. 495 */ 496 function decryptMessage($text, $passphrase = true) 497 { 498 /* decrypt() returns a PEAR_Error object on error. */ 499 if (!$passphrase) { 500 return $this->decrypt($text, array('type' => 'message', 'no_passphrase' => true)); 501 } else { 502 return $this->decrypt($text, array('type' => 'message', 'pubkey' => $this->getPersonalPublicKey(), 'privkey' => $this->getPersonalPrivateKey(), 'passphrase' => $this->getPassphrase())); 503 } 504 } 505 506 /** 507 * Gets the user's passphrase from the session cache. 508 * 509 * @return string The passphrase, if set. 510 */ 511 function getPassphrase() 512 { 513 global $imp; 514 515 if (isset($imp['pgp_passphrase'])) { 516 return Secret::read(Secret::getKey('imp'), $imp['pgp_passphrase']); 517 } 518 } 519 520 /** 521 * Store's the user's passphrase in the session cache. 522 * 523 * @param string $passphrase The user's passphrase. 524 * 525 * @return boolean Returns true if correct passphrase, false if incorrect. 526 */ 527 function storePassphrase($passphrase) 528 { 529 if ($this->verifyPassphrase($this->getPersonalPublicKey(), $this->getPersonalPrivateKey(), $passphrase) === false) { 530 return false; 531 } 532 533 $GLOBALS['imp']['pgp_passphrase'] = Secret::write(Secret::getKey('imp'), $passphrase); 534 535 return true; 536 } 537 538 /** 539 * Clear the passphrase from the session cache. 540 */ 541 function unsetPassphrase() 542 { 543 unset($GLOBALS['imp']['pgp_passphrase']); 544 } 545 546 /** 547 * Generates the javascript code for saving public keys. 548 * 549 * @param MIME_Part &$mime_part The MIME_Part containing the public key. 550 * @param string $cache The MIME_Part identifier. 551 * 552 * @return string The URL for saving public keys. 553 */ 554 function savePublicKeyURL(&$mime_part, $cache = null) 555 { 556 if (empty($cache)) { 557 require_once 'Horde/SessionObjects.php'; 558 $cacheSess = &Horde_SessionObjects::singleton(); 559 $oid = $cacheSess->storeOid($mime_part); 560 } 561 562 return $this->getJSOpenWinCode('save_attachment_public_key', false, array('mimecache' => $oid)); 563 } 564 565 /** 566 * Print out the link for the javascript PGP popup. 567 * 568 * @param string $actionid The ActionID to perform. 569 * @param mixed $reload If true, reload base window on close. If text, 570 * run this JS on close. If false, don't do 571 * anything on close. 572 * @param array $params Additional parameters needed for the reload 573 * page. 574 * 575 * @return string The javascript link. 576 */ 577 function getJSOpenWinCode($actionid, $reload = true, $params = null) 578 { 579 $popup_url = Horde::applicationUrl('pgp.php'); 580 $popup_url = Util::addParameter($popup_url, 'actionID', $actionid, false); 581 if (!empty($reload)) { 582 if (is_bool($reload)) { 583 $popup_url = Util::addParameter($popup_url, 'reload', Util::removeParameter(Horde::selfUrl(true), array('actionID')), false); 584 } else { 585 require_once 'Horde/SessionObjects.php'; 586 $cacheSess = &Horde_SessionObjects::singleton(); 587 $popup_url = Util::addParameter($popup_url, 'passphrase_action', $cacheSess->storeOid($reload, false), false); 588 } 589 } 590 591 if (is_array($params)) { 592 foreach ($params as $key => $val) { 593 $popup_url = Util::addParameter($popup_url, $key, $val, false); 594 } 595 } 596 597 return "popup_imp('" . $popup_url . "',450,200);"; 598 } 599 600 /** 601 * Provide the list of parameters needed for signing a message. 602 * 603 * @access private 604 * 605 * @return array The list of parameters needed by encrypt(). 606 */ 607 function _signParameters() 608 { 609 return array('pubkey' => $this->getPersonalPublicKey(), 'privkey' => $this->getPersonalPrivateKey(), 'passphrase' => $this->getPassphrase()); 610 } 611 612 /** 613 * Provide the list of parameters needed for encrypting a message. 614 * 615 * @access private 616 * 617 * @param array $addresses The e-mail address of the keys to use for 618 * encryption. 619 * 620 * @return array The list of parameters needed by encrypt(). 621 * Returns PEAR_Error on error. 622 */ 623 function _encryptParameters($addresses) 624 { 625 $addr_list = array(); 626 627 foreach ($addresses as $val) { 628 /* We can only encrypt if we are sending to a single person. */ 629 $addrOb = IMP::bareAddress($val, true); 630 $key_addr = array_pop($addrOb); 631 632 /* Get the public key for the address. */ 633 $public_key = $this->getPublicKey($key_addr); 634 if (is_a($public_key, 'PEAR_Error')) { 635 return $public_key; 636 } 637 $addr_list[$key_addr] = $public_key; 638 } 639 640 if (!empty($this->multipleRecipientEncryption)) { 641 return array('recips' => $addr_list); 642 } else { 643 return array('pubkey' => $public_key, 'email' => $key_addr); 644 } 645 } 646 647 /** 648 * Sign a MIME_Part using PGP using IMP default parameters. 649 * 650 * @param MIME_Part $mime_part The MIME_Part object to sign. 651 * 652 * @return MIME_Part See Horde_Crypt_pgp::signMIMEPart(). Returns 653 * PEAR_Error object on error. 654 */ 655 function IMPsignMIMEPart($mime_part) 656 { 657 return $this->signMIMEPart($mime_part, $this->_signParameters()); 658 } 659 660 /** 661 * Encrypt a MIME_Part using PGP using IMP default parameters. 662 * 663 * @param MIME_Part $mime_part The MIME_Part object to encrypt. 664 * @param array $addresses The e-mail address of the keys to use for 665 * encryption. 666 * 667 * @return MIME_Part See Horde_Crypt_pgp::encryptMIMEPart(). Returns 668 * PEAR_Error object on error. 669 */ 670 function IMPencryptMIMEPart($mime_part, $addresses) 671 { 672 $params = $this->_encryptParameters($addresses); 673 if (is_a($params, 'PEAR_Error')) { 674 return $params; 675 } 676 return $this->encryptMIMEPart($mime_part, $params); 677 } 678 679 /** 680 * Sign and Encrypt a MIME_Part using PGP using IMP default parameters. 681 * 682 * @param MIME_Part $mime_part The MIME_Part object to sign and encrypt. 683 * @param array $addresses The e-mail address of the keys to use for 684 * encryption. 685 * 686 * @return MIME_Part See Horde_Crypt_pgp::signAndencryptMIMEPart(). 687 * Returns PEAR_Error object on error. 688 */ 689 function IMPsignAndEncryptMIMEPart($mime_part, $addresses) 690 { 691 $encrypt_params = $this->_encryptParameters($addresses); 692 if (is_a($encrypt_params, 'PEAR_Error')) { 693 return $encrypt_params; 694 } 695 return $this->signAndEncryptMIMEPart($mime_part, $this->_signParameters(), $encrypt_params); 696 } 697 698 /** 699 * Generate a MIME_Part object, in accordance with RFC 2015/3156, that 700 * contains the user's public key. 701 * 702 * @return MIME_Part See Horde_Crypt_pgp::publicKeyMIMEPart(). 703 */ 704 function publicKeyMIMEPart() 705 { 706 return parent::publicKeyMIMEPart($this->getPersonalPublicKey()); 707 } 708 709 }
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Thu Nov 29 12:30:07 2007 | par Balluche grâce à PHPXref 0.7 |
![]() |