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.

SubKey.php 18KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715
  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  3. /**
  4. * Contains a class representing GPG sub-keys and constants for GPG algorithms
  5. *
  6. * PHP version 5
  7. *
  8. * LICENSE:
  9. *
  10. * This library is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU Lesser General Public License as
  12. * published by the Free Software Foundation; either version 2.1 of the
  13. * License, or (at your option) any later version.
  14. *
  15. * This library is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  18. * Lesser General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU Lesser General Public
  21. * License along with this library; if not, see
  22. * <http://www.gnu.org/licenses/>
  23. *
  24. * @category Encryption
  25. * @package Crypt_GPG
  26. * @author Michael Gauthier <mike@silverorange.com>
  27. * @author Nathan Fredrickson <nathan@silverorange.com>
  28. * @copyright 2005-2010 silverorange
  29. * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
  30. * @link http://pear.php.net/package/Crypt_GPG
  31. */
  32. // {{{ class Crypt_GPG_SubKey
  33. /**
  34. * A class for GPG sub-key information
  35. *
  36. * This class is used to store the results of the {@link Crypt_GPG::getKeys()}
  37. * method. Sub-key objects are members of a {@link Crypt_GPG_Key} object.
  38. *
  39. * @category Encryption
  40. * @package Crypt_GPG
  41. * @author Michael Gauthier <mike@silverorange.com>
  42. * @author Nathan Fredrickson <nathan@silverorange.com>
  43. * @copyright 2005-2010 silverorange
  44. * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
  45. * @link http://pear.php.net/package/Crypt_GPG
  46. * @see Crypt_GPG::getKeys()
  47. * @see Crypt_GPG_Key::getSubKeys()
  48. */
  49. class Crypt_GPG_SubKey
  50. {
  51. // {{{ algorithm class constants
  52. /**
  53. * RSA encryption algorithm.
  54. */
  55. const ALGORITHM_RSA = 1;
  56. /**
  57. * Elgamal encryption algorithm (encryption only).
  58. */
  59. const ALGORITHM_ELGAMAL_ENC = 16;
  60. /**
  61. * DSA encryption algorithm (sometimes called DH, sign only).
  62. */
  63. const ALGORITHM_DSA = 17;
  64. /**
  65. * Elgamal encryption algorithm (signage and encryption - should not be
  66. * used).
  67. */
  68. const ALGORITHM_ELGAMAL_ENC_SGN = 20;
  69. // }}}
  70. // {{{ usage class constants
  71. /**
  72. * Key can be used to encrypt
  73. */
  74. const USAGE_ENCRYPT = 1;
  75. /**
  76. * Key can be used to sign
  77. */
  78. const USAGE_SIGN = 2;
  79. /**
  80. * Key can be used to certify other keys
  81. */
  82. const USAGE_CERTIFY = 4;
  83. /**
  84. * Key can be used for authentication
  85. */
  86. const USAGE_AUTHENTICATION = 8;
  87. // }}}
  88. // {{{ class properties
  89. /**
  90. * The id of this sub-key
  91. *
  92. * @var string
  93. */
  94. private $_id = '';
  95. /**
  96. * The algorithm used to create this sub-key
  97. *
  98. * The value is one of the Crypt_GPG_SubKey::ALGORITHM_* constants.
  99. *
  100. * @var integer
  101. */
  102. private $_algorithm = 0;
  103. /**
  104. * The fingerprint of this sub-key
  105. *
  106. * @var string
  107. */
  108. private $_fingerprint = '';
  109. /**
  110. * Length of this sub-key in bits
  111. *
  112. * @var integer
  113. */
  114. private $_length = 0;
  115. /**
  116. * Date this sub-key was created
  117. *
  118. * This is a Unix timestamp.
  119. *
  120. * @var integer
  121. */
  122. private $_creationDate = 0;
  123. /**
  124. * Date this sub-key expires
  125. *
  126. * This is a Unix timestamp. If this sub-key does not expire, this will be
  127. * zero.
  128. *
  129. * @var integer
  130. */
  131. private $_expirationDate = 0;
  132. /**
  133. * Contains usage flags of this sub-key
  134. *
  135. * @var int
  136. */
  137. private $_usage = 0;
  138. /**
  139. * Whether or not the private key for this sub-key exists in the keyring
  140. *
  141. * @var boolean
  142. */
  143. private $_hasPrivate = false;
  144. /**
  145. * Whether or not this sub-key is revoked
  146. *
  147. * @var boolean
  148. */
  149. private $_isRevoked = false;
  150. // }}}
  151. // {{{ __construct()
  152. /**
  153. * Creates a new sub-key object
  154. *
  155. * Sub-keys can be initialized from an array of named values. Available
  156. * names are:
  157. *
  158. * - <kbd>string id</kbd> - the key id of the sub-key.
  159. * - <kbd>integer algorithm</kbd> - the encryption algorithm of the
  160. * sub-key.
  161. * - <kbd>string fingerprint</kbd> - the fingerprint of the sub-key. The
  162. * fingerprint should not contain
  163. * formatting characters.
  164. * - <kbd>integer length</kbd> - the length of the sub-key in bits.
  165. * - <kbd>integer creation</kbd> - the date the sub-key was created.
  166. * This is a UNIX timestamp.
  167. * - <kbd>integer expiration</kbd> - the date the sub-key expires. This
  168. * is a UNIX timestamp. If the sub-key
  169. * does not expire, use 0.
  170. * - <kbd>boolean canSign</kbd> - whether or not the sub-key can be
  171. * used to sign data.
  172. * - <kbd>boolean canEncrypt</kbd> - whether or not the sub-key can be
  173. * used to encrypt data.
  174. * - <kbd>integer usage</kbd> - the sub-key usage flags
  175. * - <kbd>boolean hasPrivate</kbd> - whether or not the private key for
  176. * the sub-key exists in the keyring.
  177. * - <kbd>boolean isRevoked</kbd> - whether or not this sub-key is
  178. * revoked.
  179. *
  180. * @param Crypt_GPG_SubKey|string|array $key optional. Either an existing
  181. * sub-key object, which is copied; a sub-key string, which is
  182. * parsed; or an array of initial values.
  183. */
  184. public function __construct($key = null)
  185. {
  186. // parse from string
  187. if (is_string($key)) {
  188. $key = self::parse($key);
  189. }
  190. // copy from object
  191. if ($key instanceof Crypt_GPG_SubKey) {
  192. $this->_id = $key->_id;
  193. $this->_algorithm = $key->_algorithm;
  194. $this->_fingerprint = $key->_fingerprint;
  195. $this->_length = $key->_length;
  196. $this->_creationDate = $key->_creationDate;
  197. $this->_expirationDate = $key->_expirationDate;
  198. $this->_usage = $key->_usage;
  199. $this->_hasPrivate = $key->_hasPrivate;
  200. $this->_isRevoked = $key->_isRevoked;
  201. }
  202. // initialize from array
  203. if (is_array($key)) {
  204. if (array_key_exists('id', $key)) {
  205. $this->setId($key['id']);
  206. }
  207. if (array_key_exists('algorithm', $key)) {
  208. $this->setAlgorithm($key['algorithm']);
  209. }
  210. if (array_key_exists('fingerprint', $key)) {
  211. $this->setFingerprint($key['fingerprint']);
  212. }
  213. if (array_key_exists('length', $key)) {
  214. $this->setLength($key['length']);
  215. }
  216. if (array_key_exists('creation', $key)) {
  217. $this->setCreationDate($key['creation']);
  218. }
  219. if (array_key_exists('expiration', $key)) {
  220. $this->setExpirationDate($key['expiration']);
  221. }
  222. if (array_key_exists('usage', $key)) {
  223. $this->setUsage($key['usage']);
  224. }
  225. if (array_key_exists('canSign', $key)) {
  226. $this->setCanSign($key['canSign']);
  227. }
  228. if (array_key_exists('canEncrypt', $key)) {
  229. $this->setCanEncrypt($key['canEncrypt']);
  230. }
  231. if (array_key_exists('hasPrivate', $key)) {
  232. $this->setHasPrivate($key['hasPrivate']);
  233. }
  234. if (array_key_exists('isRevoked', $key)) {
  235. $this->setRevoked($key['isRevoked']);
  236. }
  237. }
  238. }
  239. // }}}
  240. // {{{ getId()
  241. /**
  242. * Gets the id of this sub-key
  243. *
  244. * @return string the id of this sub-key.
  245. */
  246. public function getId()
  247. {
  248. return $this->_id;
  249. }
  250. // }}}
  251. // {{{ getAlgorithm()
  252. /**
  253. * Gets the algorithm used by this sub-key
  254. *
  255. * The algorithm should be one of the Crypt_GPG_SubKey::ALGORITHM_*
  256. * constants.
  257. *
  258. * @return integer the algorithm used by this sub-key.
  259. */
  260. public function getAlgorithm()
  261. {
  262. return $this->_algorithm;
  263. }
  264. // }}}
  265. // {{{ getCreationDate()
  266. /**
  267. * Gets the creation date of this sub-key
  268. *
  269. * This is a Unix timestamp.
  270. *
  271. * @return integer the creation date of this sub-key.
  272. */
  273. public function getCreationDate()
  274. {
  275. return $this->_creationDate;
  276. }
  277. // }}}
  278. // {{{ getExpirationDate()
  279. /**
  280. * Gets the date this sub-key expires
  281. *
  282. * This is a Unix timestamp. If this sub-key does not expire, this will be
  283. * zero.
  284. *
  285. * @return integer the date this sub-key expires.
  286. */
  287. public function getExpirationDate()
  288. {
  289. return $this->_expirationDate;
  290. }
  291. // }}}
  292. // {{{ getFingerprint()
  293. /**
  294. * Gets the fingerprint of this sub-key
  295. *
  296. * @return string the fingerprint of this sub-key.
  297. */
  298. public function getFingerprint()
  299. {
  300. return $this->_fingerprint;
  301. }
  302. // }}}
  303. // {{{ getLength()
  304. /**
  305. * Gets the length of this sub-key in bits
  306. *
  307. * @return integer the length of this sub-key in bits.
  308. */
  309. public function getLength()
  310. {
  311. return $this->_length;
  312. }
  313. // }}}
  314. // {{{ canSign()
  315. /**
  316. * Gets whether or not this sub-key can sign data
  317. *
  318. * @return boolean true if this sub-key can sign data and false if this
  319. * sub-key can not sign data.
  320. */
  321. public function canSign()
  322. {
  323. return ($this->_usage & self::USAGE_SIGN) != 0;
  324. }
  325. // }}}
  326. // {{{ canEncrypt()
  327. /**
  328. * Gets whether or not this sub-key can encrypt data
  329. *
  330. * @return boolean true if this sub-key can encrypt data and false if this
  331. * sub-key can not encrypt data.
  332. */
  333. public function canEncrypt()
  334. {
  335. return ($this->_usage & self::USAGE_ENCRYPT) != 0;
  336. }
  337. // }}}
  338. // {{{ usage()
  339. /**
  340. * Gets usage flags of this sub-key
  341. *
  342. * @return int Sum of usage flags
  343. */
  344. public function usage()
  345. {
  346. return $this->_usage;
  347. }
  348. // }}}
  349. // {{{ hasPrivate()
  350. /**
  351. * Gets whether or not the private key for this sub-key exists in the
  352. * keyring
  353. *
  354. * @return boolean true the private key for this sub-key exists in the
  355. * keyring and false if it does not.
  356. */
  357. public function hasPrivate()
  358. {
  359. return $this->_hasPrivate;
  360. }
  361. // }}}
  362. // {{{ isRevoked()
  363. /**
  364. * Gets whether or not this sub-key is revoked
  365. *
  366. * @return boolean true if this sub-key is revoked and false if it is not.
  367. */
  368. public function isRevoked()
  369. {
  370. return $this->_isRevoked;
  371. }
  372. // }}}
  373. // {{{ setCreationDate()
  374. /**
  375. * Sets the creation date of this sub-key
  376. *
  377. * The creation date is a Unix timestamp.
  378. *
  379. * @param integer $creationDate the creation date of this sub-key.
  380. *
  381. * @return Crypt_GPG_SubKey the current object, for fluent interface.
  382. */
  383. public function setCreationDate($creationDate)
  384. {
  385. $this->_creationDate = intval($creationDate);
  386. return $this;
  387. }
  388. // }}}
  389. // {{{ setExpirationDate()
  390. /**
  391. * Sets the expiration date of this sub-key
  392. *
  393. * The expiration date is a Unix timestamp. Specify zero if this sub-key
  394. * does not expire.
  395. *
  396. * @param integer $expirationDate the expiration date of this sub-key.
  397. *
  398. * @return Crypt_GPG_SubKey the current object, for fluent interface.
  399. */
  400. public function setExpirationDate($expirationDate)
  401. {
  402. $this->_expirationDate = intval($expirationDate);
  403. return $this;
  404. }
  405. // }}}
  406. // {{{ setId()
  407. /**
  408. * Sets the id of this sub-key
  409. *
  410. * @param string $id the id of this sub-key.
  411. *
  412. * @return Crypt_GPG_SubKey the current object, for fluent interface.
  413. */
  414. public function setId($id)
  415. {
  416. $this->_id = strval($id);
  417. return $this;
  418. }
  419. // }}}
  420. // {{{ setAlgorithm()
  421. /**
  422. * Sets the algorithm used by this sub-key
  423. *
  424. * @param integer $algorithm the algorithm used by this sub-key.
  425. *
  426. * @return Crypt_GPG_SubKey the current object, for fluent interface.
  427. */
  428. public function setAlgorithm($algorithm)
  429. {
  430. $this->_algorithm = intval($algorithm);
  431. return $this;
  432. }
  433. // }}}
  434. // {{{ setFingerprint()
  435. /**
  436. * Sets the fingerprint of this sub-key
  437. *
  438. * @param string $fingerprint the fingerprint of this sub-key.
  439. *
  440. * @return Crypt_GPG_SubKey the current object, for fluent interface.
  441. */
  442. public function setFingerprint($fingerprint)
  443. {
  444. $this->_fingerprint = strval($fingerprint);
  445. return $this;
  446. }
  447. // }}}
  448. // {{{ setLength()
  449. /**
  450. * Sets the length of this sub-key in bits
  451. *
  452. * @param integer $length the length of this sub-key in bits.
  453. *
  454. * @return Crypt_GPG_SubKey the current object, for fluent interface.
  455. */
  456. public function setLength($length)
  457. {
  458. $this->_length = intval($length);
  459. return $this;
  460. }
  461. // }}}
  462. // {{{ setCanSign()
  463. /**
  464. * Sets whether or not this sub-key can sign data
  465. *
  466. * @param boolean $canSign true if this sub-key can sign data and false if
  467. * it can not.
  468. *
  469. * @return Crypt_GPG_SubKey the current object, for fluent interface.
  470. */
  471. public function setCanSign($canSign)
  472. {
  473. if ($canSign) {
  474. $this->_usage |= self::USAGE_SIGN;
  475. } else {
  476. $this->_usage &= ~self::USAGE_SIGN;
  477. }
  478. return $this;
  479. }
  480. // }}}
  481. // {{{ setCanEncrypt()
  482. /**
  483. * Sets whether or not this sub-key can encrypt data
  484. *
  485. * @param boolean $canEncrypt true if this sub-key can encrypt data and
  486. * false if it can not.
  487. *
  488. * @return Crypt_GPG_SubKey the current object, for fluent interface.
  489. */
  490. public function setCanEncrypt($canEncrypt)
  491. {
  492. if ($canEncrypt) {
  493. $this->_usage |= self::USAGE_ENCRYPT;
  494. } else {
  495. $this->_usage &= ~self::USAGE_ENCRYPT;
  496. }
  497. return $this;
  498. }
  499. // }}}
  500. // {{{ setUsage()
  501. /**
  502. * Sets usage flags of the sub-key
  503. *
  504. * @param integer $usage Usage flags
  505. *
  506. * @return Crypt_GPG_SubKey the current object, for fluent interface.
  507. */
  508. public function setUsage($usage)
  509. {
  510. $this->_usage = (int) $usage;
  511. return $this;
  512. }
  513. // }}}
  514. // {{{ setHasPrivate()
  515. /**
  516. * Sets whether of not the private key for this sub-key exists in the
  517. * keyring
  518. *
  519. * @param boolean $hasPrivate true if the private key for this sub-key
  520. * exists in the keyring and false if it does
  521. * not.
  522. *
  523. * @return Crypt_GPG_SubKey the current object, for fluent interface.
  524. */
  525. public function setHasPrivate($hasPrivate)
  526. {
  527. $this->_hasPrivate = ($hasPrivate) ? true : false;
  528. return $this;
  529. }
  530. // }}}
  531. // {{{ setRevoked()
  532. /**
  533. * Sets whether or not this sub-key is revoked
  534. *
  535. * @param boolean $isRevoked whether or not this sub-key is revoked.
  536. *
  537. * @return Crypt_GPG_SubKey the current object, for fluent interface.
  538. */
  539. public function setRevoked($isRevoked)
  540. {
  541. $this->_isRevoked = ($isRevoked) ? true : false;
  542. return $this;
  543. }
  544. // }}}
  545. // {{{ parse()
  546. /**
  547. * Parses a sub-key object from a sub-key string
  548. *
  549. * See <b>doc/DETAILS</b> in the
  550. * {@link http://www.gnupg.org/download/ GPG distribution} for information
  551. * on how the sub-key string is parsed.
  552. *
  553. * @param string $string the string containing the sub-key.
  554. *
  555. * @return Crypt_GPG_SubKey the sub-key object parsed from the string.
  556. */
  557. public static function parse($string)
  558. {
  559. $tokens = explode(':', $string);
  560. $subKey = new Crypt_GPG_SubKey();
  561. $subKey->setId($tokens[4]);
  562. $subKey->setLength($tokens[2]);
  563. $subKey->setAlgorithm($tokens[3]);
  564. $subKey->setCreationDate(self::_parseDate($tokens[5]));
  565. $subKey->setExpirationDate(self::_parseDate($tokens[6]));
  566. if ($tokens[1] == 'r') {
  567. $subKey->setRevoked(true);
  568. }
  569. $usage = 0;
  570. $usage_map = array(
  571. 'a' => self::USAGE_AUTHENTICATION,
  572. 'c' => self::USAGE_CERTIFY,
  573. 'e' => self::USAGE_ENCRYPT,
  574. 's' => self::USAGE_SIGN,
  575. );
  576. foreach ($usage_map as $key => $flag) {
  577. if (strpos($tokens[11], $key) !== false) {
  578. $usage |= $flag;
  579. }
  580. }
  581. $subKey->setUsage($usage);
  582. return $subKey;
  583. }
  584. // }}}
  585. // {{{ _parseDate()
  586. /**
  587. * Parses a date string as provided by GPG into a UNIX timestamp
  588. *
  589. * @param string $string the date string.
  590. *
  591. * @return integer the UNIX timestamp corresponding to the provided date
  592. * string.
  593. */
  594. private static function _parseDate($string)
  595. {
  596. if ($string == '') {
  597. $timestamp = 0;
  598. } else {
  599. // all times are in UTC according to GPG documentation
  600. $timeZone = new DateTimeZone('UTC');
  601. if (strpos($string, 'T') === false) {
  602. // interpret as UNIX timestamp
  603. $string = '@' . $string;
  604. }
  605. $date = new DateTime($string, $timeZone);
  606. // convert to UNIX timestamp
  607. $timestamp = intval($date->format('U'));
  608. }
  609. return $timestamp;
  610. }
  611. // }}}
  612. }
  613. // }}}
  614. ?>