You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

GPGAbstract.php 17KB

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