From 84cbc20b0bb2da5532ae8f5514d826ade13e447f Mon Sep 17 00:00:00 2001 From: Michael M Slusarz Date: Wed, 25 Feb 2009 22:30:40 -0700 Subject: [PATCH] Horde 4-ify Horde_Crypt. Rework driver naming scheme Use file_put_contents() in Pgp driver. Convert to full Exception handling. --- framework/Crypt/lib/Horde/Crypt.php | 56 ++-- .../Crypt/lib/Horde/Crypt/{pgp.php => Pgp.php} | 312 ++++++++++----------- .../Crypt/lib/Horde/Crypt/{smime.php => Smime.php} | 127 ++++----- framework/Crypt/package.xml | 8 +- framework/Crypt/test/Horde/Crypt/pgp.inc | 2 +- framework/Crypt/test/Horde/Crypt/smime.inc | 2 +- 6 files changed, 226 insertions(+), 281 deletions(-) rename framework/Crypt/lib/Horde/Crypt/{pgp.php => Pgp.php} (87%) rename framework/Crypt/lib/Horde/Crypt/{smime.php => Smime.php} (91%) diff --git a/framework/Crypt/lib/Horde/Crypt.php b/framework/Crypt/lib/Horde/Crypt.php index 5d35bcc64..0dfa3ef28 100644 --- a/framework/Crypt/lib/Horde/Crypt.php +++ b/framework/Crypt/lib/Horde/Crypt.php @@ -14,6 +14,13 @@ class Horde_Crypt { /** + * Singleton instances. + * + * @var array + */ + static protected $_instances = array(); + + /** * The temporary directory to use. * * @var string @@ -30,8 +37,8 @@ class Horde_Crypt * @param array $params A hash containing any additional configuration or * parameters a subclass might need. * - * @return Horde_Crypt The newly created concrete Horde_Crypt instance, or - * false on an error. + * @return Horde_Crypt The newly created concrete Horde_Crypt instance. + * @throws Horde_Exception */ static public function factory($driver, $params = array()) { @@ -43,26 +50,17 @@ class Horde_Crypt } /* Return a base Horde_Crypt object if no driver is specified. */ - if (empty($driver) || (strcmp($driver, 'none') == 0)) { + if (empty($driver) || (strcasecmp($driver, 'none') == 0)) { return new Horde_Crypt(); } - $class = 'Horde_Crypt_' . $driver; - if (!empty($app)) { - $class = $app . '_' . $class; - } + $class = (empty($app) ? 'Horde' : $app) . '_Crypt_' . ucfirst($driver); - if (!class_exists($class)) { - if (empty($app)) { - include_once dirname(__FILE__) . '/Crypt/' . $driver . '.php'; - } else { - include_once $GLOBALS['registry']->get('fileroot', $app) . '/lib/Crypt/' . $driver . '.php'; - } + if (class_exists($class)) { + return new $class($params); } - return class_exists($class) - ? new $class($params) - : PEAR::raiseError('Class definition of ' . $class . ' not found.'); + throw new Horde_Exception('Class definition of ' . $class . ' not found.'); } /** @@ -73,7 +71,7 @@ class Horde_Crypt * This should be used if multiple crypto backends (and, thus, * multiple Horde_Crypt instances) are required. * - * This method must be invoked as: $var = &Horde_Crypt::singleton() + * This method must be invoked as: $var = Horde_Crypt::singleton() * * @param mixed $driver The type of concrete Horde_Crypt subclass to * return. If $driver is an array, then we will look @@ -82,26 +80,25 @@ class Horde_Crypt * @param array $params A hash containing any additional configuration or * connection parameters a subclass might need. * - * @return Horde_Crypt The concrete Horde_Crypt reference, or false on an - * error. + * @return Horde_Crypt The concrete Horde_Crypt reference. + * @throws Horde_Exception */ static public function &singleton($driver, $params = array()) { - static $instances = array(); + ksort($params); + $signature = hash('md5', serialize(array($driver, $params))); - $signature = serialize(array($driver, $params)); - if (!isset($instances[$signature])) { - $instances[$signature] = Horde_Crypt::factory($driver, $params); + if (!isset(self::$_instances[$signature])) { + self::$_instances[$signature] = Horde_Crypt::factory($driver, $params); } - return $instances[$signature]; + return self::$_instances[$signature]; } /** - * Outputs error message if we are not using a secure connection. + * Throws exception if not using a secure connection. * - * @return PEAR_Error Returns a PEAR_Error object if there is no secure - * connection. + * @throws Horde_Exception */ public function requireSecureConnection() { @@ -131,7 +128,7 @@ class Horde_Crypt } } - return PEAR::raiseError(_("The encryption features require a secure web connection.")); + throw new Horde_Exception (_("The encryption features require a secure web connection.")); } /** @@ -156,6 +153,7 @@ class Horde_Crypt * @param array $params An array of arguments needed to decrypt the data. * * @return array The decrypted data. + * @throws Horde_Exception */ public function decrypt($data, $params = array()) { @@ -166,8 +164,6 @@ class Horde_Crypt * Create a temporary file that will be deleted at the end of this * process. * - * @access private - * * @param string $descrip Description string to use in filename. * @param boolean $delete Delete the file automatically? * diff --git a/framework/Crypt/lib/Horde/Crypt/pgp.php b/framework/Crypt/lib/Horde/Crypt/Pgp.php similarity index 87% rename from framework/Crypt/lib/Horde/Crypt/pgp.php rename to framework/Crypt/lib/Horde/Crypt/Pgp.php index db144b141..a8b07e87e 100644 --- a/framework/Crypt/lib/Horde/Crypt/pgp.php +++ b/framework/Crypt/lib/Horde/Crypt/Pgp.php @@ -1,6 +1,6 @@ * @package Horde_Crypt */ -class Horde_Crypt_pgp extends Horde_Crypt +class Horde_Crypt_Pgp extends Horde_Crypt { /** * Armor Header Lines - From RFC 2440: @@ -122,13 +122,15 @@ class Horde_Crypt_pgp extends Horde_Crypt * @param array $params Parameter array containing the path to the GnuPG * binary (key = 'program') and to a temporary * directory. + * + * @throws Horde_Exception */ - public function __construct($params = array()) + protected function __construct($params = array()) { $this->_tempdir = Util::createTempDir(true, $params['temp']); if (empty($params['program'])) { - Horde::fatal(PEAR::raiseError('The location of the GnuPG binary must be given to the Horde_Crypt_pgp:: class.'), __FILE__, __LINE__); + Horde::fatal(new Horde_Exception('The location of the GnuPG binary must be given to the Horde_Crypt_Pgp:: class.'), __FILE__, __LINE__); } /* Store the location of GnuPG and set common options. */ @@ -156,15 +158,14 @@ class Horde_Crypt_pgp extends Horde_Crypt * @param string $comment The comment to use for the key. * @param integer $keylength The keylength to use for the key. * - * @return array An array consisting of the public key and the private - * key, or PEAR_Error on error. + * @return array An array consisting of: *
-     * Return array:
      * Key            Value
      * --------------------------
      * 'public'   =>  Public Key
      * 'private'  =>  Private Key
      * 
+ * @throws Horde_Exception */ public function generateKey($realname, $email, $passphrase, $comment = '', $keylength = 1024) @@ -175,20 +176,21 @@ class Horde_Crypt_pgp extends Horde_Crypt /* Create the config file necessary for GnuPG to run in batch mode. */ /* TODO: Sanitize input, More user customizable? */ - $input = array(); - $input[] = '%pubring ' . $pub_file; - $input[] = '%secring ' . $secret_file; - $input[] = 'Key-Type: DSA'; - $input[] = 'Key-Length: 1024'; - $input[] = 'Subkey-Type: ELG-E'; - $input[] = 'Subkey-Length: ' . $keylength; - $input[] = 'Name-Real: ' . $realname; + $input = array( + '%pubring ' . $pub_file, + '%secring ' . $secret_file, + 'Key-Type: DSA', + 'Key-Length: 1024', + 'Subkey-Type: ELG-E', + 'Subkey-Length: ' . $keylength, + 'Name-Real: ' . $realname, + 'Name-Email: ' . $email, + 'Expire-Date: 0', + 'Passphrase: ' . $passphrase + ); if (!empty($comment)) { $input[] = 'Name-Comment: ' . $comment; } - $input[] = 'Name-Email: ' . $email; - $input[] = 'Expire-Date: 0'; - $input[] = 'Passphrase: ' . $passphrase; $input[] = '%commit'; /* Run through gpg binary. */ @@ -209,7 +211,7 @@ class Horde_Crypt_pgp extends Horde_Crypt if (!empty($result->stderr)) { $msg .= ' ' . _("Returned error message:") . ' ' . $result->stderr; } - return PEAR::raiseError($msg, 'horde.error'); + throw new Horde_Exception($msg, 'horde.error'); } return array('public' => $public_key, 'private' => $secret_key); @@ -270,9 +272,7 @@ class Horde_Crypt_pgp extends Horde_Crypt $sig_id = $uid_idx = 0; /* Store message in temporary file. */ - $fp = fopen($input, 'w+'); - fputs($fp, $pgpdata); - fclose($fp); + file_put_contents($input, $pgpdata); $cmdline = array( '--list-packets', @@ -379,6 +379,9 @@ class Horde_Crypt_pgp extends Horde_Crypt return $data_array; } + /** + * TODO + */ protected function _pgpPacketInformationHelper($a) { return chr(hexdec($a[1])); @@ -438,11 +441,17 @@ class Horde_Crypt_pgp extends Horde_Crypt return $msg; } + /** + * TODO + */ protected function _pgpPrettyKeyFormatter(&$s, $k, $m) { $s .= ':' . str_repeat(' ', $m - String::length($s)); } + /** + * TODO + */ protected function _getKeyIDString($keyid) { /* Get the 8 character key ID string. */ @@ -596,10 +605,7 @@ class Horde_Crypt_pgp extends Horde_Crypt $keyid = null; $input = $this->_createTempFile('horde-pgp'); - - $fp = fopen($input, 'w+'); - fputs($fp, $text); - fclose($fp); + file_put_contents($input, $text); $cmdline = array( '--verify', @@ -621,19 +627,21 @@ class Horde_Crypt_pgp extends Horde_Crypt * @param string $passphrase The user's passphrase. * * @return boolean Returns true on valid passphrase, false on invalid - * passphrase, and PEAR_Error on error. + * passphrase. */ public function verifyPassphrase($public_key, $private_key, $passphrase) { /* Encrypt a test message. */ - $result = $this->encrypt('Test', array('type' => 'message', 'pubkey' => $public_key)); - if (is_a($result, 'PEAR_Error')) { + try { + $this->encrypt('Test', array('type' => 'message', 'pubkey' => $public_key)); + } catch (Horde_Exception $e) { return false; } /* Try to decrypt the message. */ - $result = $this->decrypt($result, array('type' => 'message', 'pubkey' => $public_key, 'privkey' => $private_key, 'passphrase' => $passphrase)); - if (is_a($result, 'PEAR_Error')) { + try { + $this->decrypt($result, array('type' => 'message', 'pubkey' => $public_key, 'privkey' => $private_key, 'passphrase' => $passphrase)); + } catch (Horde_Exception $e) { return false; } @@ -699,7 +707,7 @@ class Horde_Crypt_pgp extends Horde_Crypt * @param float $timeout The keyserver timeout. * @param string $address The email address of the PGP key. * - * @return string The PGP public key, or PEAR_Error on error. + * @return string The PGP public key. */ public function getPublicKeyserver($keyid, $server = self::KEYSERVER_PUBLIC, @@ -708,25 +716,19 @@ class Horde_Crypt_pgp extends Horde_Crypt { if (empty($keyid) && !empty($address)) { $keyid = $this->getKeyID($address, $server, $timeout); - if (is_a($keyid, 'PEAR_Error')) { - return $keyid; - } } /* Connect to the public keyserver. */ $uri = '/pks/lookup?op=get&search=' . $this->_getKeyIDString($keyid); $output = $this->_connectKeyserver('GET', $server, $uri, '', $timeout); - if (is_a($output, 'PEAR_Error')) { - return $output; - } /* Strip HTML Tags from output. */ if (($start = strstr($output, '-----BEGIN'))) { $length = strpos($start, '-----END') + 34; return substr($start, 0, $length); - } else { - return PEAR::raiseError(_("Could not obtain public key from the keyserver."), 'horde.error'); } + + throw new Horde_Exception(_("Could not obtain public key from the keyserver."), 'horde.error'); } /** @@ -736,7 +738,7 @@ class Horde_Crypt_pgp extends Horde_Crypt * @param string $server The keyserver to use. * @param float $timeout The keyserver timeout. * - * @return PEAR_Error PEAR_Error on error/failure. + * @throws Horde_Exception */ public function putPublicKeyserver($pubkey, $server = self::KEYSERVER_PUBLIC, @@ -746,13 +748,13 @@ class Horde_Crypt_pgp extends Horde_Crypt $info = $this->pgpPacketInformation($pubkey); /* See if the public key already exists on the keyserver. */ - if (!is_a($this->getPublicKeyserver($info['keyid'], $server, $timeout), 'PEAR_Error')) { - return PEAR::raiseError(_("Key already exists on the public keyserver."), 'horde.warning'); + try { + $this->getPublicKeyserver($info['keyid'], $server, $timeout); + } catch (Horde_Exception $e) { + throw new Horde_Exception(_("Key already exists on the public keyserver."), 'horde.warning'); } - /* Connect to the public keyserver. _connectKeyserver() - * returns a PEAR_Error object on error and the output text on - * success. */ + /* Connect to the public keyserver. _connectKeyserver() */ $pubkey = 'keytext=' . urlencode(rtrim($pubkey)); $cmd = array( 'Host: ' . $server . ':11371', @@ -764,10 +766,7 @@ class Horde_Crypt_pgp extends Horde_Crypt $pubkey ); - $result = $this->_connectKeyserver('POST', $server, '/pks/add', implode("\r\n", $cmd), $timeout); - if (is_a($result, 'PEAR_Error')) { - return $result; - } + return $this->_connectKeyserver('POST', $server, '/pks/add', implode("\r\n", $cmd), $timeout); } /** @@ -778,17 +777,15 @@ class Horde_Crypt_pgp extends Horde_Crypt * @param string $server The keyserver to use. * @param float $timeout The keyserver timeout. * - * @return string The PGP key ID, or PEAR_Error on error. + * @return string The PGP key ID. + * @throws Horde_Exception */ public function getKeyID($address, $server = self::KEYSERVER_PUBLIC, - $timeout = self::KEYSERVER_TIMEOUT) + $timeout = self::KEYSERVER_TIMEOUT) { /* Connect to the public keyserver. */ $uri = '/pks/lookup?op=index&options=mr&search=' . urlencode($address); $output = $this->_connectKeyserver('GET', $server, $uri, '', $timeout); - if (is_a($output, 'PEAR_Error')) { - return $output; - } if (($start = strstr($output, '-----BEGIN PGP PUBLIC KEY BLOCK'))) { /* The server returned the matching key immediately. */ @@ -820,7 +817,7 @@ class Horde_Crypt_pgp extends Horde_Crypt } } - return PEAR::raiseError(_("Could not obtain public key from the keyserver.")); + throw new Horde_Exception(_("Could not obtain public key from the keyserver.")); } /** @@ -872,8 +869,8 @@ class Horde_Crypt_pgp extends Horde_Crypt * @param string $command The PGP command to run. * @param float $timeout The timeout value. * - * @return string The text from standard output on success, or PEAR_Error - * on error/failure. + * @return string The text from standard output on success. + * @throws Horde_Exception */ protected function _connectKeyserver($method, $server, $resource, $command, $timeout) @@ -897,34 +894,25 @@ class Horde_Crypt_pgp extends Horde_Crypt /* Attempt to get the key from the keyserver. */ do { - $connError = false; $errno = $errstr = null; /* The HKP server is located on port 11371. */ $fp = @fsockopen($server, $port, $errno, $errstr, $timeout); - if (!$fp) { - $connError = true; - } else { + if ($fp) { fputs($fp, $command . "\n\n"); while (!feof($fp)) { $output .= fgets($fp, 1024); } fclose($fp); + return $output; } + } while (++$connRefuse < self::KEYSERVER_REFUSE); - if ($connError) { - if (++$connRefuse === self::KEYSERVER_REFUSE) { - if ($errno == 0) { - $output = PEAR::raiseError(_("Connection refused to the public keyserver."), 'horde.error'); - } else { - $output = PEAR::raiseError(sprintf(_("Connection refused to the public keyserver. Reason: %s (%s)"), String::convertCharset($errstr, NLS::getExternalCharset()), $errno), 'horde.error'); - } - break; - } - } - } while ($connError); - - return $output; + if ($errno == 0) { + throw new Horde_Exception(_("Connection refused to the public keyserver."), 'horde.error'); + } else { + throw new Horde_Exception(sprintf(_("Connection refused to the public keyserver. Reason: %s (%s)"), String::convertCharset($errstr, NLS::getExternalCharset()), $errno), 'horde.error'); + } } /** @@ -935,7 +923,8 @@ class Horde_Crypt_pgp extends Horde_Crypt * See the individual _encrypt*() functions for the * parameter requirements. * - * @return string The encrypted message, or PEAR_Error on error. + * @return string The encrypted message. + * @throws Horde_Exception */ public function encrypt($text, $params = array()) { @@ -956,7 +945,12 @@ class Horde_Crypt_pgp extends Horde_Crypt * See the individual _decrypt*() functions for the * parameter requirements. * - * @return string The decrypted message, or PEAR_Error on error. + * @return stdClass An object with the following properties: + *
+     * 'message' - (string) The signature result text.
+     * 'result' - (boolean) The result of the signature test.
+     * 
+ * @throws Horde_Exception */ public function decrypt($text, $params = array()) { @@ -1062,15 +1056,14 @@ class Horde_Crypt_pgp extends Horde_Crypt * 'symmetric' is true) * * - * @return string The encrypted message, or PEAR_Error on error. + * @return string The encrypted message. + * @throws Horde_Exception */ protected function _encryptMessage($text, $params) { /* Create temp files for input. */ $input = $this->_createTempFile('horde-pgp'); - $fp = fopen($input, 'w+'); - fputs($fp, $text); - fclose($fp); + file_put_contents($input, $text); /* Build command line. */ $cmdline = array( @@ -1097,7 +1090,7 @@ class Horde_Crypt_pgp extends Horde_Crypt $result = $this->_callGpg($cmdline, 'w', empty($params['symmetric']) ? null : $params['passphrase'], true, true); if (empty($result->output)) { $error = preg_replace('/\n.*/', '', $result->stderr); - return PEAR::raiseError(_("Could not PGP encrypt message: ") . $error, 'horde.error'); + throw new Horde_Exception(_("Could not PGP encrypt message: ") . $error, 'horde.error'); } return $result->output; @@ -1120,7 +1113,8 @@ class Horde_Crypt_pgp extends Horde_Crypt * 'detach' -- Make a detached signature (DEFAULT) * * - * @return string The signed message, or PEAR_Error on error. + * @return string The signed message. + * @throws Horde_Exception */ protected function _encryptSignature($text, $params) { @@ -1128,7 +1122,7 @@ class Horde_Crypt_pgp extends Horde_Crypt if (!isset($params['pubkey']) || !isset($params['privkey']) || !isset($params['passphrase'])) { - return PEAR::raiseError(_("A public PGP key, private PGP key, and passphrase are required to sign a message."), 'horde.error'); + throw new Horde_Exception(_("A public PGP key, private PGP key, and passphrase are required to sign a message."), 'horde.error'); } /* Create temp files for input. */ @@ -1139,9 +1133,7 @@ class Horde_Crypt_pgp extends Horde_Crypt $sec_keyring = $this->_putInKeyring(array($params['privkey']), 'private'); /* Store message in temporary file. */ - $fp = fopen($input, 'w+'); - fputs($fp, $text); - fclose($fp); + file_put_contents($input, $text); /* Determine the signature type to use. */ $cmdline = array(); @@ -1167,10 +1159,10 @@ class Horde_Crypt_pgp extends Horde_Crypt $result = $this->_callGpg($cmdline, 'w', $params['passphrase'], true, true); if (empty($result->output)) { $error = preg_replace('/\n.*/', '', $result->stderr); - return PEAR::raiseError(_("Could not PGP sign message: ") . $error, 'horde.error'); - } else { - return $result->output; + throw new Horde_Exception(_("Could not PGP sign message: ") . $error, 'horde.error'); } + + return $result->output; } /** @@ -1188,12 +1180,17 @@ class Horde_Crypt_pgp extends Horde_Crypt * 'passphrase' => Passphrase for PGP Key. (REQUIRED) * * - * @return stdClass An object with the following properties, or PEAR_Error - * on error: + * @return stdClass An object with the following properties: *
      * 'message'     -  The decrypted message.
      * 'sig_result'  -  The result of the signature test.
      * 
+ * @return stdClass An object with the following properties: + *
+     * 'message' - (string) The signature result text.
+     * 'result' - (boolean) The result of the signature test.
+     * 
+ * @throws Horde_Exception */ protected function _decryptMessage($text, $params) { @@ -1201,16 +1198,14 @@ class Horde_Crypt_pgp extends Horde_Crypt /* Check for required parameters. */ if (!isset($params['passphrase']) && empty($params['no_passphrase'])) { - return PEAR::raiseError(_("A passphrase is required to decrypt a message."), 'horde.error'); + throw new Horde_Exception(_("A passphrase is required to decrypt a message."), 'horde.error'); } /* Create temp files. */ $input = $this->_createTempFile('horde-pgp'); /* Store message in file. */ - $fp = fopen($input, 'w+'); - fputs($fp, $text); - fclose($fp); + file_put_contents($input, $text); /* Build command line. */ $cmdline = array( @@ -1239,22 +1234,11 @@ class Horde_Crypt_pgp extends Horde_Crypt } if (empty($result->output)) { $error = preg_replace('/\n.*/', '', $result->stderr); - return PEAR::raiseError(_("Could not decrypt PGP data: ") . $error, 'horde.error'); + throw new Horde_Exception(_("Could not decrypt PGP data: ") . $error, 'horde.error'); } /* Create the return object. */ - $ob = new stdClass; - $ob->message = $result->output; - - /* Check the PGP signature. */ - $sig_check = $this->_checkSignatureResult($result->stderr); - if (is_a($sig_check, 'PEAR_Error')) { - $ob->sig_result = $sig_check; - } else { - $ob->sig_result = ($sig_check) ? $result->stderr : ''; - } - - return $ob; + return $this->_checkSignatureResult($result->stderr, $result->output); } /** @@ -1270,18 +1254,22 @@ class Horde_Crypt_pgp extends Horde_Crypt * 'signature' => PGP signature block. (REQUIRED for detached signature) * * - * @return string The verification message from gpg. If no signature, - * returns empty string, and PEAR_Error on error. + * @return stdClass An object with the following properties: + *
+     * 'message' - (string) The signature result text.
+     * 'result' - (boolean) The result of the signature test.
+     * 
+ * @throws Horde_Exception */ protected function _decryptSignature($text, $params) { /* Check for required parameters. */ if (!isset($params['pubkey'])) { - return PEAR::raiseError(_("A public PGP key is required to verify a signed message."), 'horde.error'); + throw new Horde_Exception(_("A public PGP key is required to verify a signed message."), 'horde.error'); } if (($params['type'] === 'detached-signature') && !isset($params['signature'])) { - return PEAR::raiseError(_("The detached PGP signature block is required to verify the signed message."), 'horde.error'); + throw new Horde_Exception(_("The detached PGP signature block is required to verify the signed message."), 'horde.error'); } $good_sig_flag = 0; @@ -1293,9 +1281,7 @@ class Horde_Crypt_pgp extends Horde_Crypt $keyring = $this->_putInKeyring($params['pubkey']); /* Store the message in a temporary file. */ - $fp = fopen($input, 'w+'); - fputs($fp, $text); - fclose($fp); + file_put_contents($input, $text); /* Options for the GPG binary. */ $cmdline = array( @@ -1311,45 +1297,45 @@ class Horde_Crypt_pgp extends Horde_Crypt if ($params['type'] === 'detached-signature') { $sigfile = $this->_createTempFile('horde-pgp'); $cmdline[] = $sigfile . ' ' . $input; - - $fp = fopen($sigfile, 'w+'); - fputs($fp, $params['signature']); - fclose($fp); + file_put_contents($sigfile, $params['signature']); } else { $cmdline[] = $input; } /* Verify the signature. We need to catch standard error output, * since this is where the signature information is sent. */ - $result = $this->_callGpg($cmdline, 'r', null, true, true); - $sig_result = $this->_checkSignatureResult($result->stderr); - if (is_a($sig_result, 'PEAR_Error')) { - return $sig_result; - } else { - return ($sig_result) ? $result->stderr : ''; - } + $result = $this->_callGpg($cmdline, 'r', null, true, true, true); + return $this->_checkSignatureResult($result->stderr, $result->stderr); } /** * Checks signature result from the GnuPG binary. * - * @param string $result The signature result. + * @param string $result The signature result. + * @param string $message The decrypted message data. * - * @return boolean True if signature is good. + * @return stdClass An object with the following properties: + *
+     * 'message' - (string) The signature result text.
+     * 'result' - (boolean) The result of the signature test.
+     * 
+ * @throws Horde_Exception */ - protected function _checkSignatureResult($result) + protected function _checkSignatureResult($result, $message = null) { /* Good signature: * gpg: Good signature from "blah blah blah (Comment)" * Bad signature: * gpg: BAD signature from "blah blah blah (Comment)" */ if (strpos($result, 'gpg: BAD signature') !== false) { - return PEAR::raiseError($result, 'horde.error'); - } elseif (strpos($result, 'gpg: Good signature') !== false) { - return true; - } else { - return false; + throw new Horde_Exception($result, 'horde.error'); } + + $ob = new stdClass; + $ob->message = $message; + $ob->result = (strpos($result, 'gpg: Good signature') !== false); + + return $ob; } /** @@ -1360,7 +1346,8 @@ class Horde_Crypt_pgp extends Horde_Crypt * @see _encryptSignature(). * * @return mixed A Horde_Mime_Part object that is signed according to RFC - * 3156, or PEAR_Error on error. + * 3156. + * @throws Horde_Exception */ public function signMIMEPart($mime_part, $params = array()) { @@ -1373,9 +1360,6 @@ class Horde_Crypt_pgp extends Horde_Crypt $mime_part->strict7bit(true); $msg_sign = $this->encrypt($mime_part->toCanonicalString(), $params); - if (is_a($msg_sign, 'PEAR_Error')) { - return $msg_sign; - } /* Add the PGP signature. */ $charset = NLS::getEmailCharset(); @@ -1388,7 +1372,7 @@ class Horde_Crypt_pgp extends Horde_Crypt /* Get the algorithim information from the signature. Since we are * analyzing a signature packet, we need to use the special keyword - * '_SIGNATURE' - see Horde_Crypt_pgp. */ + * '_SIGNATURE' - see Horde_Crypt_Pgp. */ $sig_info = $this->pgpPacketSignature($msg_sign, '_SIGNATURE'); /* Setup the multipart MIME Part. */ @@ -1412,7 +1396,8 @@ class Horde_Crypt_pgp extends Horde_Crypt * @see _encryptMessage(). * * @return mixed A Horde_Mime_Part object that is encrypted according to - * RFC 3156, or PEAR_Error on error. + * RFC 3156. + * @throws Horde_Exception */ public function encryptMIMEPart($mime_part, $params = array()) { @@ -1420,9 +1405,6 @@ class Horde_Crypt_pgp extends Horde_Crypt $signenc_body = $mime_part->toCanonicalString(); $message_encrypt = $this->encrypt($signenc_body, $params); - if (is_a($message_encrypt, 'PEAR_Error')) { - return $message_encrypt; - } /* Set up MIME Structure according to RFC 3156. */ $charset = NLS::getEmailCharset(); @@ -1459,22 +1441,17 @@ class Horde_Crypt_pgp extends Horde_Crypt * encryption. @see _encryptMessage(). * * @return mixed A Horde_Mime_Part object that is signed and encrypted - * according to RFC 3156, or PEAR_Error on error. + * according to RFC 3156. + * @throws Horde_Exception */ public function signAndEncryptMIMEPart($mime_part, $sign_params = array(), $encrypt_params = array()) { /* RFC 3156 requires that the entire signed message be encrypted. We - * need to explicitly call using Horde_Crypt_pgp:: because we don't + * need to explicitly call using Horde_Crypt_Pgp:: because we don't * know whether a subclass has extended these methods. */ $part = $this->signMIMEPart($mime_part, $sign_params); - if (is_a($part, 'PEAR_Error')) { - return $part; - } $part = $this->encryptMIMEPart($part, $encrypt_params); - if (is_a($part, 'PEAR_Error')) { - return $part; - } $part->setContents('This message is in MIME format and has been PGP signed and encrypted.' . "\n"); $charset = NLS::getEmailCharset(); @@ -1494,8 +1471,6 @@ class Horde_Crypt_pgp extends Horde_Crypt */ public function publicKeyMIMEPart($key) { - include_once 'Horde/Mime/Part.php'; - $charset = NLS::getEmailCharset(); $part = new Horde_Mime_Part(); $part->setType('application/pgp-keys'); @@ -1509,12 +1484,13 @@ class Horde_Crypt_pgp extends Horde_Crypt /** * Function that handles interfacing with the GnuPG binary. * - * @param array $options Options and commands to pass to GnuPG. - * @param string $mode 'r' to read from stdout, 'w' to write to stdin. - * @param array $input Input to write to stdin. - * @param boolean $output If true, collect and store output in object returned. - * @param boolean $stderr If true, collect and store stderr in object returned. - * @param boolean $verbose If true, run GnuPG with quiet flag. + * @param array $options Options and commands to pass to GnuPG. + * @param string $mode 'r' to read from stdout, 'w' to write to + * stdin. + * @param array $input Input to write to stdin. + * @param boolean $output Collect and store output in object returned? + * @param boolean $stderr Collect and store stderr in object returned? + * @param boolean $verbose Run GnuPG with verbose flag? * * @return stdClass Class with members output, stderr, and stdout. */ @@ -1596,18 +1572,20 @@ class Horde_Crypt_pgp extends Horde_Crypt * @param string $email The email to use for the key. * @param string $passphrase The passphrase to use for the key. * - * @return string The revocation certificate, or PEAR_Error on error. + * @return string The revocation certificate. + * @throws Horde_Exception */ public function generateRevocation($key, $email, $passphrase) { $keyring = $this->_putInKeyring($key, 'private'); /* Prepare the canned answers. */ - $input = array(); - $input[] = 'y'; // Really generate a revocation certificate - $input[] = '0'; // Refuse to specify a reason - $input[] = ''; // Empty comment - $input[] = 'y'; // Confirm empty comment + $input = array( + 'y', // Really generate a revocation certificate + '0', // Refuse to specify a reason + '', // Empty comment + 'y', // Confirm empty comment + ); if (!empty($passphrase)) { $input[] = $passphrase; } @@ -1622,7 +1600,7 @@ class Horde_Crypt_pgp extends Horde_Crypt /* If the key is empty, something went wrong. */ if (empty($results->output)) { - return PEAR::raiseError(_("Revocation key not generated successfully."), 'horde.error'); + throw new Horde_Exception(_("Revocation key not generated successfully."), 'horde.error'); } return $results->output; diff --git a/framework/Crypt/lib/Horde/Crypt/smime.php b/framework/Crypt/lib/Horde/Crypt/Smime.php similarity index 91% rename from framework/Crypt/lib/Horde/Crypt/smime.php rename to framework/Crypt/lib/Horde/Crypt/Smime.php index 44d4eca20..ec1cd7468 100644 --- a/framework/Crypt/lib/Horde/Crypt/smime.php +++ b/framework/Crypt/lib/Horde/Crypt/Smime.php @@ -1,6 +1,6 @@ * @package Horde_Crypt */ -class Horde_Crypt_smime extends Horde_Crypt +class Horde_Crypt_Smime extends Horde_Crypt { /** * Object Identifers to name array. @@ -67,7 +67,7 @@ class Horde_Crypt_smime extends Horde_Crypt * @param array $params Parameter array. * 'temp' => Location of temporary directory. */ - function __construct($params) + protected function __construct($params) { $this->_tempdir = $params['temp']; } @@ -80,15 +80,12 @@ class Horde_Crypt_smime extends Horde_Crypt * * @return boolean Returns true on valid passphrase, false on invalid * passphrase. - * Returns PEAR_Error on error. */ public function verifyPassphrase($private_key, $passphrase) { - if (is_null($passphrase)) { - $res = openssl_pkey_get_private($private_key); - } else { - $res = openssl_pkey_get_private($private_key, $passphrase); - } + $res = is_null($passphrase) + ? openssl_pkey_get_private($private_key) + : openssl_pkey_get_private($private_key, $passphrase); return is_resource($res); } @@ -102,15 +99,12 @@ class Horde_Crypt_smime extends Horde_Crypt * the parameter requirements. * * @return string The encrypted message. - * Returns PEAR_Error object on error. + * @throws Horde_Exception */ public function encrypt($text, $params = array()) { /* Check for availability of OpenSSL PHP extension. */ - $openssl = $this->checkForOpenSSL(); - if (is_a($openssl, 'PEAR_Error')) { - return $openssl; - } + $this->checkForOpenSSL(); if (isset($params['type'])) { if ($params['type'] === 'message') { @@ -130,15 +124,12 @@ class Horde_Crypt_smime extends Horde_Crypt * the parameter requirements. * * @return string The decrypted message. - * Returns PEAR_Error object on error. + * @throws Horde_Exception */ public function decrypt($text, $params = array()) { /* Check for availability of OpenSSL PHP extension. */ - $openssl = $this->checkForOpenSSL(); - if (is_a($openssl, 'PEAR_Error')) { - return $openssl; - } + $this->checkForOpenSSL(); if (isset($params['type'])) { if ($params['type'] === 'message') { @@ -157,19 +148,16 @@ class Horde_Crypt_smime extends Horde_Crypt * @param mixed $certs Either a single or array of root certificates. * * @return stdClass Object with the following elements: - * 'result' -> Returns true on success; - * PEAR_Error object on error. + * 'result' -> Returns true on success. * 'cert' -> The certificate of the signer stored * in the message (in PEM format). * 'email' -> The email of the signing person. + * @throws Horde_Exception */ public function verify($text, $certs) { /* Check for availability of OpenSSL PHP extension. */ $openssl = $this->checkForOpenSSL(); - if (is_a($openssl, 'PEAR_Error')) { - return $openssl; - } /* Create temp files for input/output. */ $input = $this->_createTempFile('horde-smime'); @@ -206,11 +194,11 @@ class Horde_Crypt_smime extends Horde_Crypt $result = openssl_pkcs7_verify($input, PKCS7_NOVERIFY, $output); if ($result === true) { - $ob->result = PEAR::raiseError(_("Message Verified Successfully but the signer's certificate could not be verified."), 'horde.warning'); + throw new Horde_Exception(_("Message Verified Successfully but the signer's certificate could not be verified."), 'horde.warning'); } elseif ($result == -1) { - $ob->result = PEAR::raiseError(_("Verification failed - an unknown error has occurred."), 'horde.error'); + throw new Horde_Exception(_("Verification failed - an unknown error has occurred."), 'horde.error'); } else { - $ob->result = PEAR::raiseError(_("Verification failed - this message may have been tampered with."), 'horde.error'); + throw new Horde_Exception(_("Verification failed - this message may have been tampered with."), 'horde.error'); } $ob->cert = file_get_contents($output); @@ -226,15 +214,12 @@ class Horde_Crypt_smime extends Horde_Crypt * @param string $sslpath The path to the OpenSSL binary. * * @return string The contents embedded in the signed data. - * Returns PEAR_Error on error. + * @throws Horde_Exception */ public function extractSignedContents($data, $sslpath) { /* Check for availability of OpenSSL PHP extension. */ - $openssl = $this->checkForOpenSSL(); - if (is_a($openssl, 'PEAR_Error')) { - return $openssl; - } + $this->checkForOpenSSL(); /* Create temp files for input/output. */ $input = $this->_createTempFile('horde-smime'); @@ -247,9 +232,11 @@ class Horde_Crypt_smime extends Horde_Crypt exec($sslpath . ' smime -verify -noverify -nochain -in ' . $input . ' -out ' . $output); $ret = file_get_contents($output); - return $ret - ? $ret - : PEAR::raiseError(_("OpenSSL error: Could not extract data from signed S/MIME part."), 'horde.error'); + if ($ret) { + return $ret; + } + + throw new Horde_Exception(_("OpenSSL error: Could not extract data from signed S/MIME part."), 'horde.error'); } /** @@ -258,16 +245,13 @@ class Horde_Crypt_smime extends Horde_Crypt * @param Horde_Mime_Part $mime_part The object to sign. * @param array $params The parameters required for signing. * - * @return mixed A Horde_Mime_Part object that is signed, or a - * PEAR_Error object on error. + * @return mixed A Horde_Mime_Part object that is signed. + * @throws Horde_Exception */ public function signMIMEPart($mime_part, $params) { /* Sign the part as a message */ $message = $this->encrypt($mime_part->toCanonicalString(), $params); - if (is_a($message, 'PEAR_Error')) { - return $message; - } /* Break the result into its components */ $mime_message = Horde_Mime_Part::parseMessage($message); @@ -295,16 +279,13 @@ class Horde_Crypt_smime extends Horde_Crypt * @param array $params The parameters required for * encryption. * - * @return mixed A Horde_Mime_Part object that is encrypted or a - * PEAR_Error on error. + * @return mixed A Horde_Mime_Part object that is encrypted. + * @throws Horde_Exception */ public function encryptMIMEPart($mime_part, $params = array()) { /* Sign the part as a message */ $message = $this->encrypt($mime_part->toCanonicalString(), $params); - if (is_a($message, 'PEAR_Error')) { - return $message; - } /* Get charset for mime part description. */ $charset = NLS::getEmailCharset(); @@ -333,13 +314,13 @@ class Horde_Crypt_smime extends Horde_Crypt * * * @return string The encrypted message. - * Return PEAR_Error object on error. + * @throws Horde_Exception */ protected function _encryptMessage($text, $params) { /* Check for required parameters. */ if (!isset($params['pubkey'])) { - return PEAR::raiseError(_("A public S/MIME key is required to encrypt a message."), 'horde.error'); + throw new Horde_Exception(_("A public S/MIME key is required to encrypt a message."), 'horde.error'); } /* Create temp files for input/output. */ @@ -358,7 +339,7 @@ class Horde_Crypt_smime extends Horde_Crypt } } - return PEAR::raiseError(_("Could not S/MIME encrypt message."), 'horde.error'); + throw new Horde_Exception(_("Could not S/MIME encrypt message."), 'horde.error'); } /** @@ -380,7 +361,7 @@ class Horde_Crypt_smime extends Horde_Crypt * * * @return string The signed message. - * Return PEAR_Error object on error. + * @throws Horde_Exception */ protected function _encryptSignature($text, $params) { @@ -388,7 +369,7 @@ class Horde_Crypt_smime extends Horde_Crypt if (!isset($params['pubkey']) || !isset($params['privkey']) || !array_key_exists('passphrase', $params)) { - return PEAR::raiseError(_("A public S/MIME key, private S/MIME key, and passphrase are required to sign a message."), 'horde.error'); + throw new Horde_Exception(_("A public S/MIME key, private S/MIME key, and passphrase are required to sign a message."), 'horde.error'); } /* Create temp files for input/output/certificates. */ @@ -406,11 +387,9 @@ class Horde_Crypt_smime extends Horde_Crypt } /* Determine the signature type to use. */ - if (isset($params['sigtype']) && ($params['sigtype'] == 'cleartext')) { - $flags = PKCS7_TEXT; - } else { - $flags = PKCS7_DETACHED; - } + $flags = (isset($params['sigtype']) && ($params['sigtype'] == 'cleartext')) + ? PKCS7_TEXT + : PKCS7_DETACHED; $privkey = (is_null($params['passphrase'])) ? $params['privkey'] : array($params['privkey'], $params['passphrase']); @@ -421,7 +400,7 @@ class Horde_Crypt_smime extends Horde_Crypt } if (!$res) { - return PEAR::raiseError(_("Could not S/MIME sign message."), 'horde.error'); + throw new Horde_Exception(_("Could not S/MIME sign message."), 'horde.error'); } $data = file_get_contents($output); @@ -444,7 +423,7 @@ class Horde_Crypt_smime extends Horde_Crypt * * * @return string The decrypted message. - * Returns PEAR_Error object on error. + * @throws Horde_Exception */ protected function _decryptMessage($text, $params) { @@ -452,7 +431,7 @@ class Horde_Crypt_smime extends Horde_Crypt if (!isset($params['pubkey']) || !isset($params['privkey']) || !array_key_exists('passphrase', $params)) { - return PEAR::raiseError(_("A public S/MIME key, private S/MIME key, and passphrase are required to decrypt a message."), 'horde.error'); + throw new Horde_Exception(_("A public S/MIME key, private S/MIME key, and passphrase are required to decrypt a message."), 'horde.error'); } /* Create temp files for input/output. */ @@ -468,7 +447,7 @@ class Horde_Crypt_smime extends Horde_Crypt return file_get_contents($output); } - return PEAR::raiseError(_("Could not decrypt S/MIME data."), 'horde.error'); + throw new Horde_Exception(_("Could not decrypt S/MIME data."), 'horde.error'); } /** @@ -482,16 +461,12 @@ class Horde_Crypt_smime extends Horde_Crypt * @see _encryptMessage(). * * @return mixed A Horde_Mime_Part object that is signed and encrypted. - * Returns PEAR_Error on error. + * @throws Horde_Exception */ public function signAndEncryptMIMEPart($mime_part, $sign_params = array(), $encrypt_params = array()) { $part = $this->signMIMEPart($mime_part, $sign_params); - if (is_a($part, 'PEAR_Error')) { - return $part; - } - return $this->encryptMIMEPart($part, $encrypt_params); } @@ -1152,23 +1127,22 @@ class Horde_Crypt_smime extends Horde_Crypt * @param array $params The parameters needed for verification. * * @return string The verification message. - * Returns PEAR_Error object on error. + * @throws Horde_Exception */ protected function _decryptSignature($text, $params) { - return PEAR::raiseError('_decryptSignature() ' . _("not yet implemented")); + throw new Horde_Exception('_decryptSignature() ' . _("not yet implemented")); } /** * Check for the presence of the OpenSSL extension to PHP. * - * @return boolean Returns true if the openssl extension is available. - * Returns a PEAR_Error if not. + * @throws Horde_Exception */ public function checkForOpenSSL() { if (!Util::extensionExists('openssl')) { - return PEAR::raiseError(_("The openssl module is required for the Horde_Crypt_smime:: class.")); + throw new Horde_Exception(_("The openssl module is required for the Horde_Crypt_Smime:: class.")); } } @@ -1177,8 +1151,8 @@ class Horde_Crypt_smime extends Horde_Crypt * * @param string $key The public key. * - * @return mixed Returns the first email address found, or null if - * there are none. + * @return mixed Returns the first email address found, or null if + * there are none. */ public function getEmailFromKey($key) { @@ -1231,18 +1205,15 @@ class Horde_Crypt_smime extends Horde_Crypt * 'private' - The private key in PEM format. * 'public' - The public key in PEM format. * 'certs' - An array of additional certs. - * Returns PEAR_Error on error. + * @throws Horde_Exception */ public function parsePKCS12Data($pkcs12, $params) { /* Check for availability of OpenSSL PHP extension. */ - $openssl = $this->checkForOpenSSL(); - if (is_a($openssl, 'PEAR_Error')) { - return $openssl; - } + $this->checkForOpenSSL(); if (!isset($params['sslpath'])) { - return PEAR::raiseError(_("No path to the OpenSSL binary provided. The OpenSSL binary is necessary to work with PKCS 12 data."), 'horde.error'); + throw new Horde_Exception(_("No path to the OpenSSL binary provided. The OpenSSL binary is necessary to work with PKCS 12 data."), 'horde.error'); } $sslpath = escapeshellcmd($params['sslpath']); @@ -1277,7 +1248,7 @@ class Horde_Crypt_smime extends Horde_Crypt } $ob->private = trim(file_get_contents($output)); if (empty($ob->private)) { - return PEAR::raiseError(_("Password incorrect"), 'horde.error'); + throw new Horde_Exception(_("Password incorrect"), 'horde.error'); } /* Extract the client public key next. */ diff --git a/framework/Crypt/package.xml b/framework/Crypt/package.xml index 8b911b9de..b7e42bcba 100644 --- a/framework/Crypt/package.xml +++ b/framework/Crypt/package.xml @@ -30,8 +30,8 @@ http://pear.php.net/dtd/package-2.0.xsd"> - - + + @@ -99,8 +99,8 @@ http://pear.php.net/dtd/package-2.0.xsd"> - - + + diff --git a/framework/Crypt/test/Horde/Crypt/pgp.inc b/framework/Crypt/test/Horde/Crypt/pgp.inc index ea02f312d..f294dcdb8 100644 --- a/framework/Crypt/test/Horde/Crypt/pgp.inc +++ b/framework/Crypt/test/Horde/Crypt/pgp.inc @@ -13,7 +13,7 @@ require $filedir . '/../../../lib/Horde/Crypt.php'; $_SERVER['HTTPS'] = 'on'; $browser = &Browser::singleton(); -$pgp = Horde_Crypt::factory('pgp', array( +$pgp = Horde_Crypt::factory('Pgp', array( 'program' => '/usr/bin/gpg', 'temp' => Util::getTempDir() )); diff --git a/framework/Crypt/test/Horde/Crypt/smime.inc b/framework/Crypt/test/Horde/Crypt/smime.inc index fab7acda2..77de29817 100644 --- a/framework/Crypt/test/Horde/Crypt/smime.inc +++ b/framework/Crypt/test/Horde/Crypt/smime.inc @@ -8,4 +8,4 @@ require 'Horde/String.php'; require 'Horde/Util.php'; require dirname(__FILE__) . '/../../../lib/Horde/Crypt.php'; -$smime = Horde_Crypt::factory('smime', array('temp' => Util::getTempDir())); +$smime = Horde_Crypt::factory('Smime', array('temp' => Util::getTempDir())); -- 2.11.0