Identity.php 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. <?php
  2. /**
  3. * Pure-PHP ssh-agent client.
  4. *
  5. * PHP version 5
  6. *
  7. * @category System
  8. * @package SSH\Agent
  9. * @author Jim Wigginton <terrafrost@php.net>
  10. * @copyright 2009 Jim Wigginton
  11. * @license http://www.opensource.org/licenses/mit-license.html MIT License
  12. * @link http://phpseclib.sourceforge.net
  13. * @internal See http://api.libssh.org/rfc/PROTOCOL.agent
  14. */
  15. namespace phpseclib\System\SSH\Agent;
  16. use phpseclib\Crypt\RSA;
  17. use phpseclib\Exception\UnsupportedAlgorithmException;
  18. use phpseclib\System\SSH\Agent;
  19. /**
  20. * Pure-PHP ssh-agent client identity object
  21. *
  22. * Instantiation should only be performed by \phpseclib\System\SSH\Agent class.
  23. * This could be thought of as implementing an interface that phpseclib\Crypt\RSA
  24. * implements. ie. maybe a Net_SSH_Auth_PublicKey interface or something.
  25. * The methods in this interface would be getPublicKey and sign since those are the
  26. * methods phpseclib looks for to perform public key authentication.
  27. *
  28. * @package SSH\Agent
  29. * @author Jim Wigginton <terrafrost@php.net>
  30. * @access internal
  31. */
  32. class Identity
  33. {
  34. /**
  35. * Key Object
  36. *
  37. * @var \phpseclib\Crypt\RSA
  38. * @access private
  39. * @see self::getPublicKey()
  40. */
  41. var $key;
  42. /**
  43. * Key Blob
  44. *
  45. * @var string
  46. * @access private
  47. * @see self::sign()
  48. */
  49. var $key_blob;
  50. /**
  51. * Socket Resource
  52. *
  53. * @var resource
  54. * @access private
  55. * @see self::sign()
  56. */
  57. var $fsock;
  58. /**
  59. * Default Constructor.
  60. *
  61. * @param resource $fsock
  62. * @return \phpseclib\System\SSH\Agent\Identity
  63. * @access private
  64. */
  65. function __construct($fsock)
  66. {
  67. $this->fsock = $fsock;
  68. }
  69. /**
  70. * Set Public Key
  71. *
  72. * Called by \phpseclib\System\SSH\Agent::requestIdentities()
  73. *
  74. * @param \phpseclib\Crypt\RSA $key
  75. * @access private
  76. */
  77. function setPublicKey($key)
  78. {
  79. $this->key = $key;
  80. $this->key->setPublicKey();
  81. }
  82. /**
  83. * Set Public Key
  84. *
  85. * Called by \phpseclib\System\SSH\Agent::requestIdentities(). The key blob could be extracted from $this->key
  86. * but this saves a small amount of computation.
  87. *
  88. * @param string $key_blob
  89. * @access private
  90. */
  91. function setPublicKeyBlob($key_blob)
  92. {
  93. $this->key_blob = $key_blob;
  94. }
  95. /**
  96. * Get Public Key
  97. *
  98. * Wrapper for $this->key->getPublicKey()
  99. *
  100. * @param int $type optional
  101. * @return mixed
  102. * @access public
  103. */
  104. function getPublicKey($type = 'PKCS8')
  105. {
  106. return $this->key->getPublicKey($type);
  107. }
  108. /**
  109. * Sets the hash
  110. *
  111. * ssh-agent only supports signatures with sha1 hashes but to maintain BC with RSA.php this function exists
  112. *
  113. * @param string $hash optional
  114. * @throws \phpseclib\Exception\UnsupportedAlgorithmException if the algorithm is unsupported
  115. * @access public
  116. */
  117. function setHash($hash = 'sha1')
  118. {
  119. if ($hash != 'sha1') {
  120. throw new UnsupportedAlgorithmException('ssh-agent can only be used with the sha1 hash');
  121. }
  122. }
  123. /**
  124. * Create a signature
  125. *
  126. * See "2.6.2 Protocol 2 private key signature request"
  127. *
  128. * @param string $message
  129. * @param int $padding optional
  130. * @return string
  131. * @throws \RuntimeException on connection errors
  132. * @throws \phpseclib\Exception\UnsupportedAlgorithmException if the algorithm is unsupported
  133. * @access public
  134. */
  135. function sign($message, $padding = RSA::PADDING_PKCS1)
  136. {
  137. if ($padding != RSA::PADDING_PKCS1 && $padding != RSA::PADDING_RELAXED_PKCS1) {
  138. throw new UnsupportedAlgorithmException('ssh-agent can only create PKCS1 signatures');
  139. }
  140. // the last parameter (currently 0) is for flags and ssh-agent only defines one flag (for ssh-dss): SSH_AGENT_OLD_SIGNATURE
  141. $packet = pack('CNa*Na*N', Agent::SSH_AGENTC_SIGN_REQUEST, strlen($this->key_blob), $this->key_blob, strlen($message), $message, 0);
  142. $packet = pack('Na*', strlen($packet), $packet);
  143. if (strlen($packet) != fputs($this->fsock, $packet)) {
  144. throw new \RuntimeException('Connection closed during signing');
  145. }
  146. $length = current(unpack('N', fread($this->fsock, 4)));
  147. $type = ord(fread($this->fsock, 1));
  148. if ($type != Agent::SSH_AGENT_SIGN_RESPONSE) {
  149. throw new \RuntimeException('Unable to retreive signature');
  150. }
  151. $signature_blob = fread($this->fsock, $length - 1);
  152. // the only other signature format defined - ssh-dss - is the same length as ssh-rsa
  153. // the + 12 is for the other various SSH added length fields
  154. return substr($signature_blob, strlen('ssh-rsa') + 12);
  155. }
  156. }