Crypt_GPG
[ class tree: Crypt_GPG ] [ index: Crypt_GPG ] [ all elements ]

Source for file GPGAbstract.php

Documentation is available at GPGAbstract.php

  1. <?php
  2.  
  3. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  4.  
  5. /**
  6.  * Crypt_GPG is a package to use GPG from PHP
  7.  *
  8.  * This package provides an object oriented interface to GNU Privacy
  9.  * Guard (GPG). It requires the GPG executable to be on the system.
  10.  *
  11.  * Though GPG can support symmetric-key cryptography, this package is intended
  12.  * only to facilitate public-key cryptography.
  13.  *
  14.  * This file contains an abstract implementation of a user of the
  15.  * {@link Crypt_GPG_Engine} class.
  16.  *
  17.  * PHP version 5
  18.  *
  19.  * LICENSE:
  20.  *
  21.  * This library is free software; you can redistribute it and/or modify
  22.  * it under the terms of the GNU Lesser General Public License as
  23.  * published by the Free Software Foundation; either version 2.1 of the
  24.  * License, or (at your option) any later version.
  25.  *
  26.  * This library is distributed in the hope that it will be useful,
  27.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  28.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  29.  * Lesser General Public License for more details.
  30.  *
  31.  * You should have received a copy of the GNU Lesser General Public
  32.  * License along with this library; if not, write to the Free Software
  33.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  34.  *
  35.  * @category  Encryption
  36.  * @package   Crypt_GPG
  37.  * @author    Nathan Fredrickson <nathan@silverorange.com>
  38.  * @author    Michael Gauthier <mike@silverorange.com>
  39.  * @copyright 2005-2013 silverorange
  40.  * @license   http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
  41.  * @version   CVS: $Id: GPG.php 305428 2010-11-17 02:47:56Z gauthierm $
  42.  * @link      http://pear.php.net/package/Crypt_GPG
  43.  * @link      http://pear.php.net/manual/en/package.encryption.crypt-gpg.php
  44.  * @link      http://www.gnupg.org/
  45.  */
  46.  
  47. /**
  48.  * GPG key class
  49.  */
  50. require_once 'Crypt/GPG/Key.php';
  51.  
  52. /**
  53.  * GPG sub-key class
  54.  */
  55. require_once 'Crypt/GPG/SubKey.php';
  56.  
  57. /**
  58.  * GPG user id class
  59.  */
  60. require_once 'Crypt/GPG/UserId.php';
  61.  
  62. /**
  63.  * GPG process and I/O engine class
  64.  */
  65. require_once 'Crypt/GPG/Engine.php';
  66.  
  67. /**
  68.  * GPG exception classes
  69.  */
  70. require_once 'Crypt/GPG/Exceptions.php';
  71.  
  72. // {{{ class Crypt_GPGAbstract
  73.  
  74. /**
  75.  * Base class for implementing a user of {@link Crypt_GPG_Engine}
  76.  *
  77.  * @category  Encryption
  78.  * @package   Crypt_GPG
  79.  * @author    Nathan Fredrickson <nathan@silverorange.com>
  80.  * @author    Michael Gauthier <mike@silverorange.com>
  81.  * @copyright 2005-2013 silverorange
  82.  * @license   http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
  83.  * @link      http://pear.php.net/package/Crypt_GPG
  84.  * @link      http://www.gnupg.org/
  85.  */
  86. abstract class Crypt_GPGAbstract
  87. {
  88.     // {{{ class error constants
  89.  
  90.     /**
  91.      * Error code returned when there is no error.
  92.      */
  93.     const ERROR_NONE = 0;
  94.  
  95.     /**
  96.      * Error code returned when an unknown or unhandled error occurs.
  97.      */
  98.     const ERROR_UNKNOWN = 1;
  99.  
  100.     /**
  101.      * Error code returned when a bad passphrase is used.
  102.      */
  103.     const ERROR_BAD_PASSPHRASE = 2;
  104.  
  105.     /**
  106.      * Error code returned when a required passphrase is missing.
  107.      */
  108.     const ERROR_MISSING_PASSPHRASE = 3;
  109.  
  110.     /**
  111.      * Error code returned when a key that is already in the keyring is
  112.      * imported.
  113.      */
  114.     const ERROR_DUPLICATE_KEY = 4;
  115.  
  116.     /**
  117.      * Error code returned the required data is missing for an operation.
  118.      *
  119.      * This could be missing key data, missing encrypted data or missing
  120.      * signature data.
  121.      */
  122.     const ERROR_NO_DATA = 5;
  123.  
  124.     /**
  125.      * Error code returned when an unsigned key is used.
  126.      */
  127.     const ERROR_UNSIGNED_KEY = 6;
  128.  
  129.     /**
  130.      * Error code returned when a key that is not self-signed is used.
  131.      */
  132.     const ERROR_NOT_SELF_SIGNED = 7;
  133.  
  134.     /**
  135.      * Error code returned when a public or private key that is not in the
  136.      * keyring is used.
  137.      */
  138.     const ERROR_KEY_NOT_FOUND = 8;
  139.  
  140.     /**
  141.      * Error code returned when an attempt to delete public key having a
  142.      * private key is made.
  143.      */
  144.     const ERROR_DELETE_PRIVATE_KEY = 9;
  145.  
  146.     /**
  147.      * Error code returned when one or more bad signatures are detected.
  148.      */
  149.     const ERROR_BAD_SIGNATURE = 10;
  150.  
  151.     /**
  152.      * Error code returned when there is a problem reading GnuPG data files.
  153.      */
  154.     const ERROR_FILE_PERMISSIONS = 11;
  155.  
  156.     /**
  157.      * Error code returned when a key could not be created.
  158.      */
  159.     const ERROR_KEY_NOT_CREATED = 12;
  160.  
  161.     /**
  162.      * Error code returned when bad key parameters are used during key
  163.      * generation.
  164.      */
  165.     const ERROR_BAD_KEY_PARAMS = 13;
  166.  
  167.     // }}}
  168.     // {{{ other class constants
  169.  
  170.     /**
  171.      * URI at which package bugs may be reported.
  172.      */
  173.     const BUG_URI = 'http://pear.php.net/bugs/report.php?package=Crypt_GPG';
  174.  
  175.     // }}}
  176.     // {{{ protected class properties
  177.  
  178.     /**
  179.      * Engine used to control the GPG subprocess
  180.      *
  181.      * @var Crypt_GPG_Engine 
  182.      *
  183.      * @see Crypt_GPGAbstract::setEngine()
  184.      */
  185.     protected $engine = null;
  186.  
  187.     // }}}
  188.     // {{{ __construct()
  189.  
  190.     /**
  191.      * Creates a new GPG object
  192.      *
  193.      * Available options are:
  194.      *
  195.      * - <kbd>string  homedir</kbd>        - the directory where the GPG
  196.      *                                       keyring files are stored. If not
  197.      *                                       specified, Crypt_GPG uses the
  198.      *                                       default of <kbd>~/.gnupg</kbd>.
  199.      * - <kbd>string  publicKeyring</kbd>  - the file path of the public
  200.      *                                       keyring. Use this if the public
  201.      *                                       keyring is not in the homedir, or
  202.      *                                       if the keyring is in a directory
  203.      *                                       not writable by the process
  204.      *                                       invoking GPG (like Apache). Then
  205.      *                                       you can specify the path to the
  206.      *                                       keyring with this option
  207.      *                                       (/foo/bar/pubring.gpg), and specify
  208.      *                                       a writable directory (like /tmp)
  209.      *                                       using the <i>homedir</i> option.
  210.      * - <kbd>string  privateKeyring</kbd> - the file path of the private
  211.      *                                       keyring. Use this if the private
  212.      *                                       keyring is not in the homedir, or
  213.      *                                       if the keyring is in a directory
  214.      *                                       not writable by the process
  215.      *                                       invoking GPG (like Apache). Then
  216.      *                                       you can specify the path to the
  217.      *                                       keyring with this option
  218.      *                                       (/foo/bar/secring.gpg), and specify
  219.      *                                       a writable directory (like /tmp)
  220.      *                                       using the <i>homedir</i> option.
  221.      * - <kbd>string  trustDb</kbd>        - the file path of the web-of-trust
  222.      *                                       database. Use this if the trust
  223.      *                                       database is not in the homedir, or
  224.      *                                       if the database is in a directory
  225.      *                                       not writable by the process
  226.      *                                       invoking GPG (like Apache). Then
  227.      *                                       you can specify the path to the
  228.      *                                       trust database with this option
  229.      *                                       (/foo/bar/trustdb.gpg), and specify
  230.      *                                       a writable directory (like /tmp)
  231.      *                                       using the <i>homedir</i> option.
  232.      * - <kbd>string  binary</kbd>         - the location of the GPG binary. If
  233.      *                                       not specified, the driver attempts
  234.      *                                       to auto-detect the GPG binary
  235.      *                                       location using a list of known
  236.      *                                       default locations for the current
  237.      *                                       operating system. The option
  238.      *                                       <kbd>gpgBinary</kbd> is a
  239.      *                                       deprecated alias for this option.
  240.      * - <kbd>string  agent</kbd>          - the location of the GnuPG agent
  241.      *                                       binary. The gpg-agent is only
  242.      *                                       used for GnuPG 2.x. If not
  243.      *                                       specified, the engine attempts
  244.      *                                       to auto-detect the gpg-agent
  245.      *                                       binary location using a list of
  246.      *                                       know default locations for the
  247.      *                                       current operating system.
  248.      * - <kbd>boolean debug</kbd>          - whether or not to use debug mode.
  249.      *                                       When debug mode is on, all
  250.      *                                       communication to and from the GPG
  251.      *                                       subprocess is logged. This can be
  252.      *
  253.      * @param array $options optional. An array of options used to create the
  254.      *                        GPG object. All options are optional and are
  255.      *                        represented as key-value pairs.
  256.      *
  257.      * @throws Crypt_GPG_FileException if the <kbd>homedir</kbd> does not exist
  258.      *          and cannot be created. This can happen if <kbd>homedir</kbd> is
  259.      *          not specified, Crypt_GPG is run as the web user, and the web
  260.      *          user has no home directory. This exception is also thrown if any
  261.      *          of the options <kbd>publicKeyring</kbd>,
  262.      *          <kbd>privateKeyring</kbd> or <kbd>trustDb</kbd> options are
  263.      *          specified but the files do not exist or are are not readable.
  264.      *          This can happen if the user running the Crypt_GPG process (for
  265.      *          example, the Apache user) does not have permission to read the
  266.      *          files.
  267.      *
  268.      * @throws PEAR_Exception if the provided <kbd>binary</kbd> is invalid, or
  269.      *          if no <kbd>binary</kbd> is provided and no suitable binary could
  270.      *          be found.
  271.      *
  272.      * @throws PEAR_Exception if the provided <kbd>agent</kbd> is invalid, or
  273.      *          if no <kbd>agent</kbd> is provided and no suitable gpg-agent
  274.      *          cound be found.
  275.      */
  276.     public function __construct(array $options = array())
  277.     {
  278.         $this->setEngine(new Crypt_GPG_Engine($options));
  279.     }
  280.  
  281.     // }}}
  282.     // {{{ setEngine()
  283.  
  284.     /**
  285.      * Sets the I/O engine to use for GnuPG operations
  286.      *
  287.      * Normally this method does not need to be used. It provides a means for
  288.      * dependency injection.
  289.      *
  290.      * @param Crypt_GPG_Engine $engine the engine to use.
  291.      *
  292.      * @return Crypt_GPGAbstract the current object, for fluent interface.
  293.      */
  294.     public function setEngine(Crypt_GPG_Engine $engine)
  295.     {
  296.         $this->engine = $engine;
  297.         return $this;
  298.     }
  299.  
  300.     // }}}
  301.     // {{{ _getKeys()
  302.  
  303.     /**
  304.      * Gets the available keys in the keyring
  305.      *
  306.      * Calls GPG with the <kbd>--list-keys</kbd> command and grabs keys. See
  307.      * the first section of <b>doc/DETAILS</b> in the
  308.      * {@link http://www.gnupg.org/download/ GPG package} for a detailed
  309.      * description of how the GPG command output is parsed.
  310.      *
  311.      * @param string $keyId optional. Only keys with that match the specified
  312.      *                       pattern are returned. The pattern may be part of
  313.      *                       a user id, a key id or a key fingerprint. If not
  314.      *                       specified, all keys are returned.
  315.      *
  316.      * @return array an array of {@link Crypt_GPG_Key} objects. If no keys
  317.      *                match the specified <kbd>$keyId</kbd> an empty array is
  318.      *                returned.
  319.      *
  320.      * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
  321.      *          Use the <kbd>debug</kbd> option and file a bug report if these
  322.      *          exceptions occur.
  323.      *
  324.      * @see Crypt_GPG_Key
  325.      */
  326.     protected function _getKeys($keyId '')
  327.     {
  328.         // get private key fingerprints
  329.         if ($keyId == ''{
  330.             $operation '--list-secret-keys';
  331.         else {
  332.             $operation '--list-secret-keys ' escapeshellarg($keyId);
  333.         }
  334.  
  335.         // According to The file 'doc/DETAILS' in the GnuPG distribution, using
  336.         // double '--with-fingerprint' also prints the fingerprint for subkeys.
  337.         $arguments = array(
  338.             '--with-colons',
  339.             '--with-fingerprint',
  340.             '--with-fingerprint',
  341.             '--fixed-list-mode'
  342.         );
  343.  
  344.         $output '';
  345.  
  346.         $this->engine->reset();
  347.         $this->engine->setOutput($output);
  348.         $this->engine->setOperation($operation$arguments);
  349.         $this->engine->run();
  350.  
  351.         $code $this->engine->getErrorCode();
  352.  
  353.         switch ($code{
  354.         case self::ERROR_NONE:
  355.         case self::ERROR_KEY_NOT_FOUND:
  356.             // ignore not found key errors
  357.             break;
  358.         case self::ERROR_FILE_PERMISSIONS:
  359.             $filename $this->engine->getErrorFilename();
  360.             if ($filename{
  361.                 throw new Crypt_GPG_FileException(
  362.                     sprintf(
  363.                         'Error reading GnuPG data file \'%s\'. Check to make ' .
  364.                         'sure it is readable by the current user.',
  365.                         $filename
  366.                     ),
  367.                     $code,
  368.                     $filename
  369.                 );
  370.             }
  371.             throw new Crypt_GPG_FileException(
  372.                 'Error reading GnuPG data file. Check to make GnuPG data ' .
  373.                 'files are readable by the current user.',
  374.                 $code
  375.             );
  376.         default:
  377.             throw new Crypt_GPG_Exception(
  378.                 'Unknown error getting keys. Please use the \'debug\' option ' .
  379.                 'when creating the Crypt_GPG object, and file a bug report ' .
  380.                 'at ' . self::BUG_URI,
  381.                 $code
  382.             );
  383.         }
  384.  
  385.         $privateKeyFingerprints = array();
  386.  
  387.         $lines explode(PHP_EOL$output);
  388.         foreach ($lines as $line{
  389.             $lineExp explode(':'$line);
  390.             if ($lineExp[0== 'fpr'{
  391.                 $privateKeyFingerprints[$lineExp[9];
  392.             }
  393.         }
  394.  
  395.         // get public keys
  396.         if ($keyId == ''{
  397.             $operation '--list-public-keys';
  398.         else {
  399.             $operation '--list-public-keys ' escapeshellarg($keyId);
  400.         }
  401.  
  402.         $output '';
  403.  
  404.         $this->engine->reset();
  405.         $this->engine->setOutput($output);
  406.         $this->engine->setOperation($operation$arguments);
  407.         $this->engine->run();
  408.  
  409.         $code $this->engine->getErrorCode();
  410.  
  411.         switch ($code{
  412.         case self::ERROR_NONE:
  413.         case self::ERROR_KEY_NOT_FOUND:
  414.             // ignore not found key errors
  415.             break;
  416.         case self::ERROR_FILE_PERMISSIONS:
  417.             $filename $this->engine->getErrorFilename();
  418.             if ($filename{
  419.                 throw new Crypt_GPG_FileException(
  420.                     sprintf(
  421.                         'Error reading GnuPG data file \'%s\'. Check to make ' .
  422.                         'sure it is readable by the current user.',
  423.                         $filename
  424.                     ),
  425.                     $code,
  426.                     $filename
  427.                 );
  428.             }
  429.             throw new Crypt_GPG_FileException(
  430.                 'Error reading GnuPG data file. Check to make GnuPG data ' .
  431.                 'files are readable by the current user.',
  432.                 $code
  433.             );
  434.         default:
  435.             throw new Crypt_GPG_Exception(
  436.                 'Unknown error getting keys. Please use the \'debug\' option ' .
  437.                 'when creating the Crypt_GPG object, and file a bug report ' .
  438.                 'at ' . self::BUG_URI,
  439.                 $code
  440.             );
  441.         }
  442.  
  443.         $keys = array();
  444.  
  445.         $key    = null; // current key
  446.         $subKey = null; // current sub-key
  447.  
  448.         $lines explode(PHP_EOL$output);
  449.         foreach ($lines as $line{
  450.             $lineExp explode(':'$line);
  451.  
  452.             if ($lineExp[0== 'pub'{
  453.  
  454.                 // new primary key means last key should be added to the array
  455.                 if ($key !== null{
  456.                     $keys[$key;
  457.                 }
  458.  
  459.                 $key = new Crypt_GPG_Key();
  460.  
  461.                 $subKey Crypt_GPG_SubKey::parse($line);
  462.                 $key->addSubKey($subKey);
  463.  
  464.             elseif ($lineExp[0== 'sub'{
  465.  
  466.                 $subKey Crypt_GPG_SubKey::parse($line);
  467.                 $key->addSubKey($subKey);
  468.  
  469.             elseif ($lineExp[0== 'fpr'{
  470.  
  471.                 $fingerprint $lineExp[9];
  472.  
  473.                 // set current sub-key fingerprint
  474.                 $subKey->setFingerprint($fingerprint);
  475.  
  476.                 // if private key exists, set has private to true
  477.                 if (in_array($fingerprint$privateKeyFingerprints)) {
  478.                     $subKey->setHasPrivate(true);
  479.                 }
  480.  
  481.             elseif ($lineExp[0== 'uid'{
  482.  
  483.                 $string stripcslashes($lineExp[9])// as per documentation
  484.                 $userId = new Crypt_GPG_UserId($string);
  485.  
  486.                 if ($lineExp[1== 'r'{
  487.                     $userId->setRevoked(true);
  488.                 }
  489.  
  490.                 $key->addUserId($userId);
  491.  
  492.             }
  493.         }
  494.  
  495.         // add last key
  496.         if ($key !== null{
  497.             $keys[$key;
  498.         }
  499.  
  500.         return $keys;
  501.     }
  502.  
  503.     // }}}
  504. }
  505.  
  506. // }}}
  507.  
  508. ?>

Documentation generated on Wed, 13 Mar 2013 18:30:09 +0000 by phpDocumentor 1.4.3. PEAR Logo Copyright © PHP Group 2004.