pssht  latest
SSH server library written in PHP
RFC5656.php
1 <?php
2 
3 /*
4 * This file is part of pssht.
5 *
6 * (c) François Poirotte <clicky@erebot.net>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11 
13 
18 {
20  protected $H;
21 
23  protected $curve;
24 
26  protected $Q_S;
27 
29  protected $K;
30 
32  protected $K_S;
33 
35  protected $kexDHInit;
36 
38  protected $kexAlgo;
39 
41  protected $serverKEX;
42 
44  protected $clientKEX;
45 
47  protected $serverIdent;
48 
50  protected $clientIdent;
51 
52 
83  public function __construct(
84  \fpoirotte\Pssht\ECC\Curve $curve,
85  \fpoirotte\Pssht\Messages\KEX\ECDH\INIT\RFC5656 $kexDHInit,
86  \fpoirotte\Pssht\Key\KeyInterface $key,
87  \fpoirotte\Pssht\Encryption\EncryptionInterface $encryptionAlgo,
88  \fpoirotte\Pssht\KEX\KEXInterface $kexAlgo,
89  \fpoirotte\Pssht\Messages\KEXINIT $serverKEX,
90  \fpoirotte\Pssht\Messages\KEXINIT $clientKEX,
93  ) {
94  if (!is_string($serverIdent)) {
95  throw new \InvalidArgumentException();
96  }
97 
98  if (!is_string($clientIdent)) {
99  throw new \InvalidArgumentException();
100  }
101 
102  $len = strlen(gmp_strval($curve->getOrder(), 2));
103  $len = ceil($len / 8);
104  $randBytes = openssl_random_pseudo_bytes($len);
105  $d_S = gmp_mod(gmp_init(bin2hex($randBytes), 16), $curve->getModulus());
106  $this->Q_S = $curve->getGenerator()->multiply($curve, $d_S);
107  $Q_C = $kexDHInit->getQ();
108 
110  $algorithms = \fpoirotte\Pssht\Algorithms::factory();
111  $cls = $algorithms->getClass('Key', 'ecdsa-sha2-' . $curve->getName());
112  $clientPK = new $cls($Q_C);
113  if (!$clientPK->isValid()) {
114  throw new \InvalidArgumentException();
115  }
116 
117  // EC Co-factor DH (sec1-v2, section 3.3.2).
118  $P = $Q_C->multiply($curve, gmp_mul($curve->getCofactor(), $d_S));
119  if ($P->isIdentity($curve)) {
120  throw new \InvalidArgumentException();
121  }
122  $this->K = $P->x;
123 
124  $this->curve = $curve;
125  $this->K_S = $key;
126  $this->kexDHInit = $kexDHInit;
127  $this->kexAlgo = $kexAlgo;
128  $this->serverKEX = $serverKEX;
129  $this->clientKEX = $clientKEX;
130  $this->serverIdent = $serverIdent;
131  $this->clientIdent = $clientIdent;
132 
133  $msgId = chr(\fpoirotte\Pssht\Messages\KEXINIT::getMessageId());
134  // $sub is used to create the structure for the hashing function.
135  $sub = new \fpoirotte\Pssht\Wire\Encoder(new \fpoirotte\Pssht\Buffer());
136  $this->K_S->serialize($sub);
137  $K_S = $sub->getBuffer()->get(0);
138  $sub->encodeString($this->clientIdent);
139  $sub->encodeString($this->serverIdent);
140  // $sub2 is used to compute the value
141  // of various fields inside the structure.
142  $sub2 = new \fpoirotte\Pssht\Wire\Encoder(new \fpoirotte\Pssht\Buffer());
143  $sub2->encodeBytes($msgId); // Add message identifier.
144  $this->clientKEX->serialize($sub2);
145  $sub->encodeString($sub2->getBuffer()->get(0));
146  $sub2->encodeBytes($msgId); // Add message identifier.
147  $this->serverKEX->serialize($sub2);
148  $sub->encodeString($sub2->getBuffer()->get(0));
149  $sub->encodeString($K_S);
150  $sub->encodeString($Q_C->serialize($curve));
151  $sub->encodeString($this->Q_S->serialize($curve));
152  $sub->encodeMpint($this->K);
153 
154  $logging = \Plop\Plop::getInstance();
155  $origData = $sub->getBuffer()->get(0);
156  $data = wordwrap(bin2hex($origData), 4, ' ', true);
157  $data = wordwrap($data, 32 + 7, PHP_EOL, true);
158  $logging->debug("Signature payload:\r\n%s", array($data));
159 
160  $this->H = $this->kexAlgo->hash($origData);
161  }
162 
163  public static function getMessageId()
164  {
165  return 31;
166  }
167 
168  public function serialize(\fpoirotte\Pssht\Wire\Encoder $encoder)
169  {
170  $sub = new \fpoirotte\Pssht\Wire\Encoder(new \fpoirotte\Pssht\Buffer());
171  $this->K_S->serialize($sub);
172 
173  $encoder->encodeString($sub->getBuffer()->get(0));
174  $encoder->encodeString($this->Q_S->serialize($this->curve));
175 
176  $sub->encodeString($this->K_S->getName());
177  $sub->encodeString($this->K_S->sign($this->H));
178  $encoder->encodeString($sub->getBuffer()->get(0));
179  return $this;
180  }
181 
182  public static function unserialize(\fpoirotte\Pssht\Wire\Decoder $decoder)
183  {
185  throw new \RuntimeException();
186  }
187 
195  public function getSharedSecret()
196  {
197  return $this->K;
198  }
199 
206  public function getExchangeHash()
207  {
208  return $this->H;
209  }
210 }
$serverIdent
Server&#39;s identification string.
Definition: RFC5656.php:47
$Q_S
Server&#39;s ephemeral public key.
Definition: RFC5656.php:26
__construct(\fpoirotte\Pssht\ECC\Curve $curve,\fpoirotte\Pssht\Messages\KEX\ECDH\INIT\RFC5656 $kexDHInit,\fpoirotte\Pssht\Key\KeyInterface $key,\fpoirotte\Pssht\Encryption\EncryptionInterface $encryptionAlgo,\fpoirotte\Pssht\KEX\KEXInterface $kexAlgo,\fpoirotte\Pssht\Messages\KEXINIT $serverKEX,\fpoirotte\Pssht\Messages\KEXINIT $clientKEX, $serverIdent, $clientIdent)
Definition: RFC5656.php:83
$K_S
Server&#39;s public host key.
Definition: RFC5656.php:32
static unserialize(\fpoirotte\Pssht\Wire\Decoder $decoder)
Definition: RFC5656.php:182
serialize(\fpoirotte\Pssht\Wire\Encoder $encoder)
Definition: RFC5656.php:168
$kexAlgo
Key exchange algorithm to use.
Definition: RFC5656.php:38
$serverKEX
Algorithms supported by the server.
Definition: RFC5656.php:41
$clientKEX
Algorithms supported by the client.
Definition: RFC5656.php:44
$kexDHInit
Client&#39;s contribution to the Diffie-Hellman Key Exchange.
Definition: RFC5656.php:35
$clientIdent
Client&#39;s identification string.
Definition: RFC5656.php:50