3 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
6 * Crypt_GPG is a package to use GPG from PHP
8 * This file contains an engine that handles GPG subprocess control and I/O.
9 * PHP's process manipulation functions are used to handle the GPG subprocess.
15 * This library is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU Lesser General Public License as
17 * published by the Free Software Foundation; either version 2.1 of the
18 * License, or (at your option) any later version.
20 * This library is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 * Lesser General Public License for more details.
25 * You should have received a copy of the GNU Lesser General Public
26 * License along with this library; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 * @category Encryption
31 * @author Nathan Fredrickson <nathan@silverorange.com>
32 * @author Michael Gauthier <mike@silverorange.com>
33 * @copyright 2005-2010 silverorange
34 * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
35 * @version CVS: $Id: Engine.php 302822 2010-08-26 17:30:57Z gauthierm $
36 * @link http://pear.php.net/package/Crypt_GPG
37 * @link http://www.gnupg.org/
41 * Crypt_GPG base class.
43 require_once 'Crypt/GPG.php';
46 * GPG exception classes.
48 require_once 'Crypt/GPG/Exceptions.php';
51 * Standard PEAR exception is used if GPG binary is not found.
53 require_once 'PEAR/Exception.php';
55 // {{{ class Crypt_GPG_Engine
58 * Native PHP Crypt_GPG I/O engine
60 * This class is used internally by Crypt_GPG and does not need be used
61 * directly. See the {@link Crypt_GPG} class for end-user API.
63 * This engine uses PHP's native process control functions to directly control
64 * the GPG process. The GPG executable is required to be on the system.
66 * All data is passed to the GPG subprocess using file descriptors. This is the
67 * most secure method of passing data to the GPG subprocess.
69 * @category Encryption
71 * @author Nathan Fredrickson <nathan@silverorange.com>
72 * @author Michael Gauthier <mike@silverorange.com>
73 * @copyright 2005-2010 silverorange
74 * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
75 * @link http://pear.php.net/package/Crypt_GPG
76 * @link http://www.gnupg.org/
78 class Crypt_GPG_Engine
83 * Size of data chunks that are sent to and retrieved from the IPC pipes.
85 * PHP reads 8192 bytes. If this is set to less than 8192, PHP reads 8192
86 * and buffers the rest so we might as well just read 8192.
88 * Using values other than 8192 also triggers PHP bugs.
90 * @see http://bugs.php.net/bug.php?id=35224
92 const CHUNK_SIZE = 8192;
95 * Standard input file descriptor. This is used to pass data to the GPG
101 * Standard output file descriptor. This is used to receive normal output
102 * from the GPG process.
107 * Standard output file descriptor. This is used to receive error output
108 * from the GPG process.
113 * GPG status output file descriptor. The status file descriptor outputs
114 * detailed information for many GPG commands. See the second section of
115 * the file <b>doc/DETAILS</b> in the
116 * {@link http://www.gnupg.org/download/ GPG package} for a detailed
117 * description of GPG's status output.
122 * Command input file descriptor. This is used for methods requiring
125 const FD_COMMAND = 4;
128 * Extra message input file descriptor. This is used for passing signed
129 * data when verifying a detached signature.
131 const FD_MESSAGE = 5;
134 * Minimum version of GnuPG that is supported.
136 const MIN_VERSION = '1.0.2';
139 // {{{ private class properties
142 * Whether or not to use debugging mode
144 * When set to true, every GPG command is echoed before it is run. Sensitive
145 * data is always handled using pipes and is not specified as part of the
146 * command. As a result, sensitive data is never displayed when debug is
147 * enabled. Sensitive data includes private key data and passphrases.
149 * Debugging is off by default.
152 * @see Crypt_GPG_Engine::__construct()
154 private $_debug = false;
157 * Location of GPG binary
160 * @see Crypt_GPG_Engine::__construct()
161 * @see Crypt_GPG_Engine::_getBinary()
163 private $_binary = '';
166 * Directory containing the GPG key files
168 * This property only contains the path when the <i>homedir</i> option
169 * is specified in the constructor.
172 * @see Crypt_GPG_Engine::__construct()
174 private $_homedir = '';
177 * File path of the public keyring
179 * This property only contains the file path when the <i>public_keyring</i>
180 * option is specified in the constructor.
182 * If the specified file path starts with <kbd>~/</kbd>, the path is
183 * relative to the <i>homedir</i> if specified, otherwise to
184 * <kbd>~/.gnupg</kbd>.
187 * @see Crypt_GPG_Engine::__construct()
189 private $_publicKeyring = '';
192 * File path of the private (secret) keyring
194 * This property only contains the file path when the <i>private_keyring</i>
195 * option is specified in the constructor.
197 * If the specified file path starts with <kbd>~/</kbd>, the path is
198 * relative to the <i>homedir</i> if specified, otherwise to
199 * <kbd>~/.gnupg</kbd>.
202 * @see Crypt_GPG_Engine::__construct()
204 private $_privateKeyring = '';
207 * File path of the trust database
209 * This property only contains the file path when the <i>trust_db</i>
210 * option is specified in the constructor.
212 * If the specified file path starts with <kbd>~/</kbd>, the path is
213 * relative to the <i>homedir</i> if specified, otherwise to
214 * <kbd>~/.gnupg</kbd>.
217 * @see Crypt_GPG_Engine::__construct()
219 private $_trustDb = '';
222 * Array of pipes used for communication with the GPG binary
224 * This is an array of file descriptor resources.
228 private $_pipes = array();
231 * Array of currently opened pipes
233 * This array is used to keep track of remaining opened pipes so they can
234 * be closed when the GPG subprocess is finished. This array is a subset of
235 * the {@link Crypt_GPG_Engine::$_pipes} array and contains opened file
236 * descriptor resources.
239 * @see Crypt_GPG_Engine::_closePipe()
241 private $_openPipes = array();
244 * A handle for the GPG process
248 private $_process = null;
251 * Whether or not the operating system is Darwin (OS X)
255 private $_isDarwin = false;
258 * Commands to be sent to GPG's command input stream
261 * @see Crypt_GPG_Engine::sendCommand()
263 private $_commandBuffer = '';
266 * Array of status line handlers
269 * @see Crypt_GPG_Engine::addStatusHandler()
271 private $_statusHandlers = array();
274 * Array of error line handlers
277 * @see Crypt_GPG_Engine::addErrorHandler()
279 private $_errorHandlers = array();
282 * The error code of the current operation
285 * @see Crypt_GPG_Engine::getErrorCode()
287 private $_errorCode = Crypt_GPG::ERROR_NONE;
290 * File related to the error code of the current operation
293 * @see Crypt_GPG_Engine::getErrorFilename()
295 private $_errorFilename = '';
298 * Key id related to the error code of the current operation
301 * @see Crypt_GPG_Engine::getErrorKeyId()
303 private $_errorkeyId = '';
306 * The number of currently needed passphrases
308 * If this is not zero when the GPG command is completed, the error code is
309 * set to {@link Crypt_GPG::ERROR_MISSING_PASSPHRASE}.
313 private $_needPassphrase = 0;
318 * This is data to send to GPG. Either a string or a stream resource.
320 * @var string|resource
321 * @see Crypt_GPG_Engine::setInput()
323 private $_input = null;
326 * The extra message input source
328 * Either a string or a stream resource.
330 * @var string|resource
331 * @see Crypt_GPG_Engine::setMessage()
333 private $_message = null;
336 * The output location
338 * This is where the output from GPG is sent. Either a string or a stream
341 * @var string|resource
342 * @see Crypt_GPG_Engine::setOutput()
344 private $_output = '';
347 * The GPG operation to execute
350 * @see Crypt_GPG_Engine::setOperation()
355 * Arguments for the current operation
358 * @see Crypt_GPG_Engine::setOperation()
360 private $_arguments = array();
363 * The version number of the GPG binary
366 * @see Crypt_GPG_Engine::getVersion()
368 private $_version = '';
371 * Cached value indicating whether or not mbstring function overloading is
374 * This is cached for optimal performance inside the I/O loop.
377 * @see Crypt_GPG_Engine::_byteLength()
378 * @see Crypt_GPG_Engine::_byteSubstring()
380 private static $_mbStringOverload = null;
386 * Creates a new GPG engine
388 * Available options are:
390 * - <kbd>string homedir</kbd> - the directory where the GPG
391 * keyring files are stored. If not
392 * specified, Crypt_GPG uses the
393 * default of <kbd>~/.gnupg</kbd>.
394 * - <kbd>string publicKeyring</kbd> - the file path of the public
395 * keyring. Use this if the public
396 * keyring is not in the homedir, or
397 * if the keyring is in a directory
398 * not writable by the process
399 * invoking GPG (like Apache). Then
400 * you can specify the path to the
401 * keyring with this option
402 * (/foo/bar/pubring.gpg), and specify
403 * a writable directory (like /tmp)
404 * using the <i>homedir</i> option.
405 * - <kbd>string privateKeyring</kbd> - the file path of the private
406 * keyring. Use this if the private
407 * keyring is not in the homedir, or
408 * if the keyring is in a directory
409 * not writable by the process
410 * invoking GPG (like Apache). Then
411 * you can specify the path to the
412 * keyring with this option
413 * (/foo/bar/secring.gpg), and specify
414 * a writable directory (like /tmp)
415 * using the <i>homedir</i> option.
416 * - <kbd>string trustDb</kbd> - the file path of the web-of-trust
417 * database. Use this if the trust
418 * database is not in the homedir, or
419 * if the database is in a directory
420 * not writable by the process
421 * invoking GPG (like Apache). Then
422 * you can specify the path to the
423 * trust database with this option
424 * (/foo/bar/trustdb.gpg), and specify
425 * a writable directory (like /tmp)
426 * using the <i>homedir</i> option.
427 * - <kbd>string binary</kbd> - the location of the GPG binary. If
428 * not specified, the driver attempts
429 * to auto-detect the GPG binary
430 * location using a list of known
431 * default locations for the current
432 * operating system. The option
433 * <kbd>gpgBinary</kbd> is a
434 * deprecated alias for this option.
435 * - <kbd>boolean debug</kbd> - whether or not to use debug mode.
436 * When debug mode is on, all
437 * communication to and from the GPG
438 * subprocess is logged. This can be
439 * useful to diagnose errors when
442 * @param array $options optional. An array of options used to create the
443 * GPG object. All options are optional and are
444 * represented as key-value pairs.
446 * @throws Crypt_GPG_FileException if the <kbd>homedir</kbd> does not exist
447 * and cannot be created. This can happen if <kbd>homedir</kbd> is
448 * not specified, Crypt_GPG is run as the web user, and the web
449 * user has no home directory. This exception is also thrown if any
450 * of the options <kbd>publicKeyring</kbd>,
451 * <kbd>privateKeyring</kbd> or <kbd>trustDb</kbd> options are
452 * specified but the files do not exist or are are not readable.
453 * This can happen if the user running the Crypt_GPG process (for
454 * example, the Apache user) does not have permission to read the
457 * @throws PEAR_Exception if the provided <kbd>binary</kbd> is invalid, or
458 * if no <kbd>binary</kbd> is provided and no suitable binary could
461 public function __construct(array $options = array())
463 $this->_isDarwin = (strncmp(strtoupper(PHP_OS), 'DARWIN', 6) === 0);
465 // populate mbstring overloading cache if not set
466 if (self::$_mbStringOverload === null) {
467 self::$_mbStringOverload = (extension_loaded('mbstring')
468 && (ini_get('mbstring.func_overload') & 0x02) === 0x02);
472 if (array_key_exists('homedir', $options)) {
473 $this->_homedir = (string)$options['homedir'];
475 // note: this requires the package OS dep exclude 'windows'
476 $info = posix_getpwuid(posix_getuid());
477 $this->_homedir = $info['dir'].'/.gnupg';
480 // attempt to create homedir if it does not exist
481 if (!is_dir($this->_homedir)) {
482 if (@mkdir($this->_homedir, 0777, true)) {
483 // Set permissions on homedir. Parent directories are created
484 // with 0777, homedir is set to 0700.
485 chmod($this->_homedir, 0700);
487 throw new Crypt_GPG_FileException('The \'homedir\' "' .
488 $this->_homedir . '" is not readable or does not exist '.
489 'and cannot be created. This can happen if \'homedir\' '.
490 'is not specified in the Crypt_GPG options, Crypt_GPG is '.
491 'run as the web user, and the web user has no home '.
498 if (array_key_exists('binary', $options)) {
499 $this->_binary = (string)$options['binary'];
500 } elseif (array_key_exists('gpgBinary', $options)) {
502 $this->_binary = (string)$options['gpgBinary'];
504 $this->_binary = $this->_getBinary();
507 if ($this->_binary == '' || !is_executable($this->_binary)) {
508 throw new PEAR_Exception('GPG binary not found. If you are sure '.
509 'the GPG binary is installed, please specify the location of '.
510 'the GPG binary using the \'binary\' driver option.');
516 * Normally, GnuPG expects keyrings to be in the homedir and expects
517 * to be able to write temporary files in the homedir. Sometimes,
518 * keyrings are not in the homedir, or location of the keyrings does
519 * not allow writing temporary files. In this case, the <i>homedir</i>
520 * option by itself is not enough to specify the keyrings because GnuPG
521 * can not write required temporary files. Additional options are
522 * provided so you can specify the location of the keyrings separately
526 // get public keyring
527 if (array_key_exists('publicKeyring', $options)) {
528 $this->_publicKeyring = (string)$options['publicKeyring'];
529 if (!is_readable($this->_publicKeyring)) {
530 throw new Crypt_GPG_FileException('The \'publicKeyring\' "' .
531 $this->_publicKeyring . '" does not exist or is ' .
532 'not readable. Check the location and ensure the file ' .
533 'permissions are correct.', 0, $this->_publicKeyring);
537 // get private keyring
538 if (array_key_exists('privateKeyring', $options)) {
539 $this->_privateKeyring = (string)$options['privateKeyring'];
540 if (!is_readable($this->_privateKeyring)) {
541 throw new Crypt_GPG_FileException('The \'privateKeyring\' "' .
542 $this->_privateKeyring . '" does not exist or is ' .
543 'not readable. Check the location and ensure the file ' .
544 'permissions are correct.', 0, $this->_privateKeyring);
548 // get trust database
549 if (array_key_exists('trustDb', $options)) {
550 $this->_trustDb = (string)$options['trustDb'];
551 if (!is_readable($this->_trustDb)) {
552 throw new Crypt_GPG_FileException('The \'trustDb\' "' .
553 $this->_trustDb . '" does not exist or is not readable. ' .
554 'Check the location and ensure the file permissions are ' .
555 'correct.', 0, $this->_trustDb);
559 if (array_key_exists('debug', $options)) {
560 $this->_debug = (boolean)$options['debug'];
568 * Closes open GPG subprocesses when this object is destroyed
570 * Subprocesses should never be left open by this class unless there is
571 * an unknown error and unexpected script termination occurs.
573 public function __destruct()
575 $this->_closeSubprocess();
579 // {{{ addErrorHandler()
582 * Adds an error handler method
584 * The method is run every time a new error line is received from the GPG
585 * subprocess. The handler method must accept the error line to be handled
586 * as its first parameter.
588 * @param callback $callback the callback method to use.
589 * @param array $args optional. Additional arguments to pass as
590 * parameters to the callback method.
594 public function addErrorHandler($callback, array $args = array())
596 $this->_errorHandlers[] = array(
597 'callback' => $callback,
603 // {{{ addStatusHandler()
606 * Adds a status handler method
608 * The method is run every time a new status line is received from the
609 * GPG subprocess. The handler method must accept the status line to be
610 * handled as its first parameter.
612 * @param callback $callback the callback method to use.
613 * @param array $args optional. Additional arguments to pass as
614 * parameters to the callback method.
618 public function addStatusHandler($callback, array $args = array())
620 $this->_statusHandlers[] = array(
621 'callback' => $callback,
630 * Sends a command to the GPG subprocess over the command file-descriptor
633 * @param string $command the command to send.
637 * @sensitive $command
639 public function sendCommand($command)
641 if (array_key_exists(self::FD_COMMAND, $this->_openPipes)) {
642 $this->_commandBuffer .= $command . PHP_EOL;
650 * Resets the GPG engine, preparing it for a new operation
654 * @see Crypt_GPG_Engine::run()
655 * @see Crypt_GPG_Engine::setOperation()
657 public function reset()
659 $this->_operation = '';
660 $this->_arguments = array();
661 $this->_input = null;
662 $this->_message = null;
664 $this->_errorCode = Crypt_GPG::ERROR_NONE;
665 $this->_needPassphrase = 0;
666 $this->_commandBuffer = '';
668 $this->_statusHandlers = array();
669 $this->_errorHandlers = array();
671 $this->addStatusHandler(array($this, '_handleErrorStatus'));
672 $this->addErrorHandler(array($this, '_handleErrorError'));
675 $this->addStatusHandler(array($this, '_handleDebugStatus'));
676 $this->addErrorHandler(array($this, '_handleDebugError'));
684 * Runs the current GPG operation
686 * This creates and manages the GPG subprocess.
688 * The operation must be set with {@link Crypt_GPG_Engine::setOperation()}
689 * before this method is called.
693 * @throws Crypt_GPG_InvalidOperationException if no operation is specified.
695 * @see Crypt_GPG_Engine::reset()
696 * @see Crypt_GPG_Engine::setOperation()
698 public function run()
700 if ($this->_operation === '') {
701 throw new Crypt_GPG_InvalidOperationException('No GPG operation ' .
702 'specified. Use Crypt_GPG_Engine::setOperation() before ' .
703 'calling Crypt_GPG_Engine::run().');
706 $this->_openSubprocess();
708 $this->_closeSubprocess();
712 // {{{ getErrorCode()
715 * Gets the error code of the last executed operation
717 * This value is only meaningful after {@link Crypt_GPG_Engine::run()} has
720 * @return integer the error code of the last executed operation.
722 public function getErrorCode()
724 return $this->_errorCode;
728 // {{{ getErrorFilename()
731 * Gets the file related to the error code of the last executed operation
733 * This value is only meaningful after {@link Crypt_GPG_Engine::run()} has
734 * been executed. If there is no file related to the error, an empty string
737 * @return string the file related to the error code of the last executed
740 public function getErrorFilename()
742 return $this->_errorFilename;
746 // {{{ getErrorKeyId()
749 * Gets the key id related to the error code of the last executed operation
751 * This value is only meaningful after {@link Crypt_GPG_Engine::run()} has
752 * been executed. If there is no key id related to the error, an empty
753 * string is returned.
755 * @return string the key id related to the error code of the last executed
758 public function getErrorKeyId()
760 return $this->_errorKeyId;
767 * Sets the input source for the current GPG operation
769 * @param string|resource &$input either a reference to the string
770 * containing the input data or an open
771 * stream resource containing the input
776 public function setInput(&$input)
778 $this->_input =& $input;
785 * Sets the message source for the current GPG operation
787 * Detached signature data should be specified here.
789 * @param string|resource &$message either a reference to the string
790 * containing the message data or an open
791 * stream resource containing the message
796 public function setMessage(&$message)
798 $this->_message =& $message;
805 * Sets the output destination for the current GPG operation
807 * @param string|resource &$output either a reference to the string in
808 * which to store GPG output or an open
809 * stream resource to which the output data
814 public function setOutput(&$output)
816 $this->_output =& $output;
820 // {{{ setOperation()
823 * Sets the operation to perform
825 * @param string $operation the operation to perform. This should be one
826 * of GPG's operations. For example,
827 * <kbd>--encrypt</kbd>, <kbd>--decrypt</kbd>,
828 * <kbd>--sign</kbd>, etc.
829 * @param array $arguments optional. Additional arguments for the GPG
830 * subprocess. See the GPG manual for specific
835 * @see Crypt_GPG_Engine::reset()
836 * @see Crypt_GPG_Engine::run()
838 public function setOperation($operation, array $arguments = array())
840 $this->_operation = $operation;
841 $this->_arguments = $arguments;
848 * Gets the version of the GnuPG binary
850 * @return string a version number string containing the version of GnuPG
851 * being used. This value is suitable to use with PHP's
852 * version_compare() function.
854 * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
855 * Use the <kbd>debug</kbd> option and file a bug report if these
858 * @throws Crypt_GPG_UnsupportedException if the provided binary is not
859 * GnuPG or if the GnuPG version is less than 1.0.2.
861 public function getVersion()
863 if ($this->_version == '') {
866 'homedir' => $this->_homedir,
867 'binary' => $this->_binary,
868 'debug' => $this->_debug
871 $engine = new self($options);
874 // Set a garbage version so we do not end up looking up the version
876 $engine->_version = '1.0.0';
879 $engine->setOutput($info);
880 $engine->setOperation('--version');
883 $code = $this->getErrorCode();
885 if ($code !== Crypt_GPG::ERROR_NONE) {
886 throw new Crypt_GPG_Exception(
887 'Unknown error getting GnuPG version information. Please ' .
888 'use the \'debug\' option when creating the Crypt_GPG ' .
889 'object, and file a bug report at ' . Crypt_GPG::BUG_URI,
894 $expression = '/gpg \(GnuPG\) (\S+)/';
896 if (preg_match($expression, $info, $matches) === 1) {
897 $this->_version = $matches[1];
899 throw new Crypt_GPG_Exception(
900 'No GnuPG version information provided by the binary "' .
901 $this->_binary . '". Are you sure it is GnuPG?');
904 if (version_compare($this->_version, self::MIN_VERSION, 'lt')) {
905 throw new Crypt_GPG_Exception(
906 'The version of GnuPG being used (' . $this->_version .
907 ') is not supported by Crypt_GPG. The minimum version ' .
908 'required by Crypt_GPG is ' . self::MIN_VERSION);
913 return $this->_version;
917 // {{{ _handleErrorStatus()
920 * Handles error values in the status output from GPG
922 * This method is responsible for setting the
923 * {@link Crypt_GPG_Engine::$_errorCode}. See <b>doc/DETAILS</b> in the
924 * {@link http://www.gnupg.org/download/ GPG distribution} for detailed
925 * information on GPG's status output.
927 * @param string $line the status line to handle.
931 private function _handleErrorStatus($line)
933 $tokens = explode(' ', $line);
934 switch ($tokens[0]) {
935 case 'BAD_PASSPHRASE':
936 $this->_errorCode = Crypt_GPG::ERROR_BAD_PASSPHRASE;
939 case 'MISSING_PASSPHRASE':
940 $this->_errorCode = Crypt_GPG::ERROR_MISSING_PASSPHRASE;
944 $this->_errorCode = Crypt_GPG::ERROR_NO_DATA;
947 case 'DELETE_PROBLEM':
948 if ($tokens[1] == '1') {
949 $this->_errorCode = Crypt_GPG::ERROR_KEY_NOT_FOUND;
951 } elseif ($tokens[1] == '2') {
952 $this->_errorCode = Crypt_GPG::ERROR_DELETE_PRIVATE_KEY;
958 if ($tokens[12] > 0) {
959 $this->_errorCode = Crypt_GPG::ERROR_DUPLICATE_KEY;
965 $this->_errorKeyId = $tokens[1];
966 $this->_errorCode = Crypt_GPG::ERROR_KEY_NOT_FOUND;
969 case 'NEED_PASSPHRASE':
970 $this->_needPassphrase++;
973 case 'GOOD_PASSPHRASE':
974 $this->_needPassphrase--;
981 $this->_errorCode = Crypt_GPG::ERROR_BAD_SIGNATURE;
988 // {{{ _handleErrorError()
991 * Handles error values in the error output from GPG
993 * This method is responsible for setting the
994 * {@link Crypt_GPG_Engine::$_errorCode}.
996 * @param string $line the error line to handle.
1000 private function _handleErrorError($line)
1002 if ($this->_errorCode === Crypt_GPG::ERROR_NONE) {
1003 $pattern = '/no valid OpenPGP data found/';
1004 if (preg_match($pattern, $line) === 1) {
1005 $this->_errorCode = Crypt_GPG::ERROR_NO_DATA;
1009 if ($this->_errorCode === Crypt_GPG::ERROR_NONE) {
1010 $pattern = '/No secret key|secret key not available/';
1011 if (preg_match($pattern, $line) === 1) {
1012 $this->_errorCode = Crypt_GPG::ERROR_KEY_NOT_FOUND;
1016 if ($this->_errorCode === Crypt_GPG::ERROR_NONE) {
1017 $pattern = '/No public key|public key not found/';
1018 if (preg_match($pattern, $line) === 1) {
1019 $this->_errorCode = Crypt_GPG::ERROR_KEY_NOT_FOUND;
1023 if ($this->_errorCode === Crypt_GPG::ERROR_NONE) {
1025 $pattern = '/can\'t (?:access|open) `(.*?)\'/';
1026 if (preg_match($pattern, $line, $matches) === 1) {
1027 $this->_errorFilename = $matches[1];
1028 $this->_errorCode = Crypt_GPG::ERROR_FILE_PERMISSIONS;
1034 // {{{ _handleDebugStatus()
1037 * Displays debug output for status lines
1039 * @param string $line the status line to handle.
1043 private function _handleDebugStatus($line)
1045 $this->_debug('STATUS: ' . $line);
1049 // {{{ _handleDebugError()
1052 * Displays debug output for error lines
1054 * @param string $line the error line to handle.
1058 private function _handleDebugError($line)
1060 $this->_debug('ERROR: ' . $line);
1067 * Performs internal streaming operations for the subprocess using either
1068 * strings or streams as input / output points
1070 * This is the main I/O loop for streaming to and from the GPG subprocess.
1072 * The implementation of this method is verbose mainly for performance
1073 * reasons. Adding streams to a lookup array and looping the array inside
1074 * the main I/O loop would be siginficantly slower for large streams.
1078 * @throws Crypt_GPG_Exception if there is an error selecting streams for
1079 * reading or writing. If this occurs, please file a bug report at
1080 * http://pear.php.net/bugs/report.php?package=Crypt_GPG.
1082 private function _process()
1084 $this->_debug('BEGIN PROCESSING');
1086 $this->_commandBuffer = ''; // buffers input to GPG
1087 $messageBuffer = ''; // buffers input to GPG
1088 $inputBuffer = ''; // buffers input to GPG
1089 $outputBuffer = ''; // buffers output from GPG
1090 $statusBuffer = ''; // buffers output from GPG
1091 $errorBuffer = ''; // buffers output from GPG
1092 $inputComplete = false; // input stream is completely buffered
1093 $messageComplete = false; // message stream is completely buffered
1095 if (is_string($this->_input)) {
1096 $inputBuffer = $this->_input;
1097 $inputComplete = true;
1100 if (is_string($this->_message)) {
1101 $messageBuffer = $this->_message;
1102 $messageComplete = true;
1105 if (is_string($this->_output)) {
1106 $outputBuffer =& $this->_output;
1109 // convenience variables
1110 $fdInput = $this->_pipes[self::FD_INPUT];
1111 $fdOutput = $this->_pipes[self::FD_OUTPUT];
1112 $fdError = $this->_pipes[self::FD_ERROR];
1113 $fdStatus = $this->_pipes[self::FD_STATUS];
1114 $fdCommand = $this->_pipes[self::FD_COMMAND];
1115 $fdMessage = $this->_pipes[self::FD_MESSAGE];
1119 $inputStreams = array();
1120 $outputStreams = array();
1121 $exceptionStreams = array();
1123 // set up input streams
1124 if (is_resource($this->_input) && !$inputComplete) {
1125 if (feof($this->_input)) {
1126 $inputComplete = true;
1128 $inputStreams[] = $this->_input;
1132 // close GPG input pipe if there is no more data
1133 if ($inputBuffer == '' && $inputComplete) {
1134 $this->_debug('=> closing GPG input pipe');
1135 $this->_closePipe(self::FD_INPUT);
1138 if (is_resource($this->_message) && !$messageComplete) {
1139 if (feof($this->_message)) {
1140 $messageComplete = true;
1142 $inputStreams[] = $this->_message;
1146 // close GPG message pipe if there is no more data
1147 if ($messageBuffer == '' && $messageComplete) {
1148 $this->_debug('=> closing GPG message pipe');
1149 $this->_closePipe(self::FD_MESSAGE);
1152 if (!feof($fdOutput)) {
1153 $inputStreams[] = $fdOutput;
1156 if (!feof($fdStatus)) {
1157 $inputStreams[] = $fdStatus;
1160 if (!feof($fdError)) {
1161 $inputStreams[] = $fdError;
1164 // set up output streams
1165 if ($outputBuffer != '' && is_resource($this->_output)) {
1166 $outputStreams[] = $this->_output;
1169 if ($this->_commandBuffer != '') {
1170 $outputStreams[] = $fdCommand;
1173 if ($messageBuffer != '') {
1174 $outputStreams[] = $fdMessage;
1177 if ($inputBuffer != '') {
1178 $outputStreams[] = $fdInput;
1181 // no streams left to read or write, we're all done
1182 if (count($inputStreams) === 0 && count($outputStreams) === 0) {
1186 $this->_debug('selecting streams');
1188 $ready = stream_select(
1195 $this->_debug('=> got ' . $ready);
1197 if ($ready === false) {
1198 throw new Crypt_GPG_Exception(
1199 'Error selecting stream for communication with GPG ' .
1200 'subprocess. Please file a bug report at: ' .
1201 'http://pear.php.net/bugs/report.php?package=Crypt_GPG');
1205 throw new Crypt_GPG_Exception(
1206 'stream_select() returned 0. This can not happen! Please ' .
1207 'file a bug report at: ' .
1208 'http://pear.php.net/bugs/report.php?package=Crypt_GPG');
1211 // write input (to GPG)
1212 if (in_array($fdInput, $outputStreams)) {
1213 $this->_debug('GPG is ready for input');
1215 $chunk = self::_byteSubstring(
1221 $length = self::_byteLength($chunk);
1224 '=> about to write ' . $length . ' bytes to GPG input'
1227 $length = fwrite($fdInput, $chunk, $length);
1229 $this->_debug('=> wrote ' . $length . ' bytes');
1231 $inputBuffer = self::_byteSubstring(
1237 // read input (from PHP stream)
1238 if (in_array($this->_input, $inputStreams)) {
1239 $this->_debug('input stream is ready for reading');
1241 '=> about to read ' . self::CHUNK_SIZE .
1242 ' bytes from input stream'
1245 $chunk = fread($this->_input, self::CHUNK_SIZE);
1246 $length = self::_byteLength($chunk);
1247 $inputBuffer .= $chunk;
1249 $this->_debug('=> read ' . $length . ' bytes');
1252 // write message (to GPG)
1253 if (in_array($fdMessage, $outputStreams)) {
1254 $this->_debug('GPG is ready for message data');
1256 $chunk = self::_byteSubstring(
1262 $length = self::_byteLength($chunk);
1265 '=> about to write ' . $length . ' bytes to GPG message'
1268 $length = fwrite($fdMessage, $chunk, $length);
1269 $this->_debug('=> wrote ' . $length . ' bytes');
1271 $messageBuffer = self::_byteSubstring($messageBuffer, $length);
1274 // read message (from PHP stream)
1275 if (in_array($this->_message, $inputStreams)) {
1276 $this->_debug('message stream is ready for reading');
1278 '=> about to read ' . self::CHUNK_SIZE .
1279 ' bytes from message stream'
1282 $chunk = fread($this->_message, self::CHUNK_SIZE);
1283 $length = self::_byteLength($chunk);
1284 $messageBuffer .= $chunk;
1286 $this->_debug('=> read ' . $length . ' bytes');
1289 // read output (from GPG)
1290 if (in_array($fdOutput, $inputStreams)) {
1291 $this->_debug('GPG output stream ready for reading');
1293 '=> about to read ' . self::CHUNK_SIZE .
1294 ' bytes from GPG output'
1297 $chunk = fread($fdOutput, self::CHUNK_SIZE);
1298 $length = self::_byteLength($chunk);
1299 $outputBuffer .= $chunk;
1301 $this->_debug('=> read ' . $length . ' bytes');
1304 // write output (to PHP stream)
1305 if (in_array($this->_output, $outputStreams)) {
1306 $this->_debug('output stream is ready for data');
1308 $chunk = self::_byteSubstring(
1314 $length = self::_byteLength($chunk);
1317 '=> about to write ' . $length . ' bytes to output stream'
1320 $length = fwrite($this->_output, $chunk, $length);
1322 $this->_debug('=> wrote ' . $length . ' bytes');
1324 $outputBuffer = self::_byteSubstring($outputBuffer, $length);
1327 // read error (from GPG)
1328 if (in_array($fdError, $inputStreams)) {
1329 $this->_debug('GPG error stream ready for reading');
1331 '=> about to read ' . self::CHUNK_SIZE .
1332 ' bytes from GPG error'
1335 $chunk = fread($fdError, self::CHUNK_SIZE);
1336 $length = self::_byteLength($chunk);
1337 $errorBuffer .= $chunk;
1339 $this->_debug('=> read ' . $length . ' bytes');
1341 // pass lines to error handlers
1342 while (($pos = strpos($errorBuffer, PHP_EOL)) !== false) {
1343 $line = self::_byteSubstring($errorBuffer, 0, $pos);
1344 foreach ($this->_errorHandlers as $handler) {
1345 array_unshift($handler['args'], $line);
1346 call_user_func_array(
1347 $handler['callback'],
1351 array_shift($handler['args']);
1353 $errorBuffer = self::_byteSubString(
1355 $pos + self::_byteLength(PHP_EOL)
1360 // read status (from GPG)
1361 if (in_array($fdStatus, $inputStreams)) {
1362 $this->_debug('GPG status stream ready for reading');
1364 '=> about to read ' . self::CHUNK_SIZE .
1365 ' bytes from GPG status'
1368 $chunk = fread($fdStatus, self::CHUNK_SIZE);
1369 $length = self::_byteLength($chunk);
1370 $statusBuffer .= $chunk;
1372 $this->_debug('=> read ' . $length . ' bytes');
1374 // pass lines to status handlers
1375 while (($pos = strpos($statusBuffer, PHP_EOL)) !== false) {
1376 $line = self::_byteSubstring($statusBuffer, 0, $pos);
1377 // only pass lines beginning with magic prefix
1378 if (self::_byteSubstring($line, 0, 9) == '[GNUPG:] ') {
1379 $line = self::_byteSubstring($line, 9);
1380 foreach ($this->_statusHandlers as $handler) {
1381 array_unshift($handler['args'], $line);
1382 call_user_func_array(
1383 $handler['callback'],
1387 array_shift($handler['args']);
1390 $statusBuffer = self::_byteSubString(
1392 $pos + self::_byteLength(PHP_EOL)
1397 // write command (to GPG)
1398 if (in_array($fdCommand, $outputStreams)) {
1399 $this->_debug('GPG is ready for command data');
1402 $chunk = self::_byteSubstring(
1403 $this->_commandBuffer,
1408 $length = self::_byteLength($chunk);
1411 '=> about to write ' . $length . ' bytes to GPG command'
1414 $length = fwrite($fdCommand, $chunk, $length);
1416 $this->_debug('=> wrote ' . $length);
1418 $this->_commandBuffer = self::_byteSubstring(
1419 $this->_commandBuffer,
1424 } // end loop while streams are open
1426 $this->_debug('END PROCESSING');
1430 // {{{ _openSubprocess()
1433 * Opens an internal GPG subprocess for the current operation
1435 * Opens a GPG subprocess, then connects the subprocess to some pipes. Sets
1436 * the private class property {@link Crypt_GPG_Engine::$_process} to
1437 * the new subprocess.
1441 * @throws Crypt_GPG_OpenSubprocessException if the subprocess could not be
1444 * @see Crypt_GPG_Engine::setOperation()
1445 * @see Crypt_GPG_Engine::_closeSubprocess()
1446 * @see Crypt_GPG_Engine::$_process
1448 private function _openSubprocess()
1450 $version = $this->getVersion();
1454 // Newer versions of GnuPG return localized results. Crypt_GPG only
1455 // works with English, so set the locale to 'C' for the subprocess.
1456 $env['LC_ALL'] = 'C';
1458 $commandLine = $this->_binary;
1460 $defaultArguments = array(
1461 '--status-fd ' . escapeshellarg(self::FD_STATUS),
1462 '--command-fd ' . escapeshellarg(self::FD_COMMAND),
1463 '--no-secmem-warning',
1465 '--no-default-keyring', // ignored if keying files are not specified
1466 '--no-options' // prevent creation of ~/.gnupg directory
1469 if (version_compare($version, '1.0.7', 'ge')) {
1470 if (version_compare($version, '2.0.0', 'lt')) {
1471 $defaultArguments[] = '--no-use-agent';
1473 $defaultArguments[] = '--no-permission-warning';
1476 if (version_compare($version, '1.4.2', 'ge')) {
1477 $defaultArguments[] = '--exit-on-status-write-error';
1480 if (version_compare($version, '1.3.2', 'ge')) {
1481 $defaultArguments[] = '--trust-model always';
1483 $defaultArguments[] = '--always-trust';
1486 $arguments = array_merge($defaultArguments, $this->_arguments);
1488 if ($this->_homedir) {
1489 $arguments[] = '--homedir ' . escapeshellarg($this->_homedir);
1491 // the random seed file makes subsequent actions faster so only
1492 // disable it if we have to.
1493 if (!is_writeable($this->_homedir)) {
1494 $arguments[] = '--no-random-seed-file';
1498 if ($this->_publicKeyring) {
1499 $arguments[] = '--keyring ' . escapeshellarg($this->_publicKeyring);
1502 if ($this->_privateKeyring) {
1503 $arguments[] = '--secret-keyring ' .
1504 escapeshellarg($this->_privateKeyring);
1507 if ($this->_trustDb) {
1508 $arguments[] = '--trustdb-name ' . escapeshellarg($this->_trustDb);
1511 $commandLine .= ' ' . implode(' ', $arguments) . ' ' .
1514 // Binary operations will not work on Windows with PHP < 5.2.6. This is
1515 // in case stream_select() ever works on Windows.
1516 $rb = (version_compare(PHP_VERSION, '5.2.6') < 0) ? 'r' : 'rb';
1517 $wb = (version_compare(PHP_VERSION, '5.2.6') < 0) ? 'w' : 'wb';
1519 $descriptorSpec = array(
1520 self::FD_INPUT => array('pipe', $rb), // stdin
1521 self::FD_OUTPUT => array('pipe', $wb), // stdout
1522 self::FD_ERROR => array('pipe', $wb), // stderr
1523 self::FD_STATUS => array('pipe', $wb), // status
1524 self::FD_COMMAND => array('pipe', $rb), // command
1525 self::FD_MESSAGE => array('pipe', $rb) // message
1528 $this->_debug('OPENING SUBPROCESS WITH THE FOLLOWING COMMAND:');
1529 $this->_debug($commandLine);
1531 $this->_process = proc_open(
1537 array('binary_pipes' => true)
1540 if (!is_resource($this->_process)) {
1541 throw new Crypt_GPG_OpenSubprocessException(
1542 'Unable to open GPG subprocess.', 0, $commandLine);
1545 $this->_openPipes = $this->_pipes;
1546 $this->_errorCode = Crypt_GPG::ERROR_NONE;
1550 // {{{ _closeSubprocess()
1553 * Closes a the internal GPG subprocess
1555 * Closes the internal GPG subprocess. Sets the private class property
1556 * {@link Crypt_GPG_Engine::$_process} to null.
1560 * @see Crypt_GPG_Engine::_openSubprocess()
1561 * @see Crypt_GPG_Engine::$_process
1563 private function _closeSubprocess()
1565 if (is_resource($this->_process)) {
1566 $this->_debug('CLOSING SUBPROCESS');
1568 // close remaining open pipes
1569 foreach (array_keys($this->_openPipes) as $pipeNumber) {
1570 $this->_closePipe($pipeNumber);
1573 $exitCode = proc_close($this->_process);
1575 if ($exitCode != 0) {
1577 '=> subprocess returned an unexpected exit code: ' .
1581 if ($this->_errorCode === Crypt_GPG::ERROR_NONE) {
1582 if ($this->_needPassphrase > 0) {
1583 $this->_errorCode = Crypt_GPG::ERROR_MISSING_PASSPHRASE;
1585 $this->_errorCode = Crypt_GPG::ERROR_UNKNOWN;
1590 $this->_process = null;
1591 $this->_pipes = array();
1599 * Closes an opened pipe used to communicate with the GPG subprocess
1601 * If the pipe is already closed, it is ignored. If the pipe is open, it
1602 * is flushed and then closed.
1604 * @param integer $pipeNumber the file descriptor number of the pipe to
1609 private function _closePipe($pipeNumber)
1611 $pipeNumber = intval($pipeNumber);
1612 if (array_key_exists($pipeNumber, $this->_openPipes)) {
1613 fflush($this->_openPipes[$pipeNumber]);
1614 fclose($this->_openPipes[$pipeNumber]);
1615 unset($this->_openPipes[$pipeNumber]);
1623 * Gets the name of the GPG binary for the current operating system
1625 * This method is called if the '<kbd>binary</kbd>' option is <i>not</i>
1626 * specified when creating this driver.
1628 * @return string the name of the GPG binary for the current operating
1629 * system. If no suitable binary could be found, an empty
1630 * string is returned.
1632 private function _getBinary()
1636 if ($this->_isDarwin) {
1637 $binaryFiles = array(
1638 '/opt/local/bin/gpg', // MacPorts
1639 '/usr/local/bin/gpg', // Mac GPG
1640 '/sw/bin/gpg', // Fink
1644 $binaryFiles = array(
1646 '/usr/local/bin/gpg'
1650 foreach ($binaryFiles as $binaryFile) {
1651 if (is_executable($binaryFile)) {
1652 $binary = $binaryFile;
1664 * Displays debug text if debugging is turned on
1666 * Debugging text is prepended with a debug identifier and echoed to stdout.
1668 * @param string $text the debugging text to display.
1672 private function _debug($text)
1674 if ($this->_debug) {
1675 if (array_key_exists('SHELL', $_ENV)) {
1676 foreach (explode(PHP_EOL, $text) as $line) {
1677 echo "Crypt_GPG DEBUG: ", $line, PHP_EOL;
1680 // running on a web server, format debug output nicely
1681 foreach (explode(PHP_EOL, $text) as $line) {
1682 echo "Crypt_GPG DEBUG: <strong>", $line,
1683 '</strong><br />', PHP_EOL;
1690 // {{{ _byteLength()
1693 * Gets the length of a string in bytes even if mbstring function
1694 * overloading is turned on
1696 * This is used for stream-based communication with the GPG subprocess.
1698 * @param string $string the string for which to get the length.
1700 * @return integer the length of the string in bytes.
1702 * @see Crypt_GPG_Engine::$_mbStringOverload
1704 private static function _byteLength($string)
1706 if (self::$_mbStringOverload) {
1707 return mb_strlen($string, '8bit');
1710 return strlen((binary)$string);
1714 // {{{ _byteSubstring()
1717 * Gets the substring of a string in bytes even if mbstring function
1718 * overloading is turned on
1720 * This is used for stream-based communication with the GPG subprocess.
1722 * @param string $string the input string.
1723 * @param integer $start the starting point at which to get the substring.
1724 * @param integer $length optional. The length of the substring.
1726 * @return string the extracted part of the string. Unlike the default PHP
1727 * <kbd>substr()</kbd> function, the returned value is
1728 * always a string and never false.
1730 * @see Crypt_GPG_Engine::$_mbStringOverload
1732 private static function _byteSubstring($string, $start, $length = null)
1734 if (self::$_mbStringOverload) {
1735 if ($length === null) {
1739 self::_byteLength($string) - $start, '8bit'
1743 return mb_substr($string, $start, $length, '8bit');
1746 if ($length === null) {
1747 return (string)substr((binary)$string, $start);
1750 return (string)substr((binary)$string, $start, $length);