function getServerPublicHostKey()
{
if (!($this->bitmap & self::MASK_CONSTRUCTOR)) {
if (!$this->_connect()) {
return false;
}
}
$signature = $this->signature;
$server_public_host_key = $this->server_public_host_key;
if (strlen($server_public_host_key) < 4) {
return false;
}
extract(unpack('Nlength', Strings::shift($server_public_host_key, 4)));
Strings::shift($server_public_host_key, $length);
if ($this->signature_validated) {
return $this->bitmap ? $this->signature_format . ' ' . Base64::encode($this->server_public_host_key) : false;
}
$this->signature_validated = true;
switch ($this->signature_format) {
case 'ssh-dss':
$zero = new BigInteger();
if (strlen($server_public_host_key) < 4) {
return false;
}
$temp = unpack('Nlength', Strings::shift($server_public_host_key, 4));
$p = new BigInteger(Strings::shift($server_public_host_key, $temp['length']), -256);
if (strlen($server_public_host_key) < 4) {
return false;
}
$temp = unpack('Nlength', Strings::shift($server_public_host_key, 4));
$q = new BigInteger(Strings::shift($server_public_host_key, $temp['length']), -256);
if (strlen($server_public_host_key) < 4) {
return false;
}
$temp = unpack('Nlength', Strings::shift($server_public_host_key, 4));
$g = new BigInteger(Strings::shift($server_public_host_key, $temp['length']), -256);
if (strlen($server_public_host_key) < 4) {
return false;
}
$temp = unpack('Nlength', Strings::shift($server_public_host_key, 4));
$y = new BigInteger(Strings::shift($server_public_host_key, $temp['length']), -256);
/* The value for 'dss_signature_blob' is encoded as a string containing
r, followed by s (which are 160-bit integers, without lengths or
padding, unsigned, and in network byte order). */
$temp = unpack('Nlength', Strings::shift($signature, 4));
if ($temp['length'] != 40) {
$this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
throw new \RuntimeException('Invalid signature');
}
$r = new BigInteger(Strings::shift($signature, 20), 256);
$s = new BigInteger(Strings::shift($signature, 20), 256);
switch (true) {
case $r->equals($zero):
case $r->compare($q) >= 0:
case $s->equals($zero):
case $s->compare($q) >= 0:
$this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
throw new \RuntimeException('Invalid signature');
}
$w = $s->modInverse($q);
$u1 = $w->multiply(new BigInteger(sha1($this->exchange_hash), 16));
list(, $u1) = $u1->divide($q);
$u2 = $w->multiply($r);
list(, $u2) = $u2->divide($q);
$g = $g->modPow($u1, $p);
$y = $y->modPow($u2, $p);
$v = $g->multiply($y);
list(, $v) = $v->divide($p);
list(, $v) = $v->divide($q);
if (!$v->equals($r)) {
//user_error('Bad server signature');
return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
}
break;
case 'ssh-rsa':
if (strlen($server_public_host_key) < 4) {
return false;
}
$temp = unpack('Nlength', Strings::shift($server_public_host_key, 4));
$e = new BigInteger(Strings::shift($server_public_host_key, $temp['length']), -256);
if (strlen($server_public_host_key) < 4) {
return false;
}
$temp = unpack('Nlength', Strings::shift($server_public_host_key, 4));
$rawN = Strings::shift($server_public_host_key, $temp['length']);
$n = new BigInteger($rawN, -256);
$nLength = strlen(ltrim($rawN, ""));
/*
if (strlen($signature) < 4) {
return false;
}
$temp = unpack('Nlength', Strings::shift($signature, 4));
$signature = Strings::shift($signature, $temp['length']);
$rsa = new RSA();
$rsa->load(array('e' => $e, 'n' => $n), 'raw');
$rsa->setHash('sha1');
if (!$rsa->verify($this->exchange_hash, $signature, RSA::PADDING_PKCS1)) {
//user_error('Bad server signature');
return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
}
*/
if (strlen($signature) < 4) {
return false;
}
$temp = unpack('Nlength', Strings::shift($signature, 4));
$s = new BigInteger(Strings::shift($signature, $temp['length']), 256);
// validate an RSA signature per "8.2 RSASSA-PKCS1-v1_5", "5.2.2 RSAVP1", and "9.1 EMSA-PSS" in the
// following URL:
// ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.pdf
// also, see SSHRSA.c (rsa2_verifysig) in PuTTy's source.
if ($s->compare(new BigInteger()) < 0 || $s->compare($n->subtract(new BigInteger(1))) > 0) {
$this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
throw new \RuntimeException('Invalid signature');
}
$s = $s->modPow($e, $n);
$s = $s->toBytes();
$h = pack('N4H*', 0x302130, 0x906052b, 0xe03021a, 0x5000414, sha1($this->exchange_hash));
$h = chr(0x1) . str_repeat(chr(0xff), $nLength - 2 - strlen($h)) . $h;
if ($s != $h) {
//user_error('Bad server signature');
return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
}
break;
default:
$this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
throw new NoSupportedAlgorithmsException('Unsupported signature format');
}
return $this->signature_format . ' ' . Base64::encode($this->server_public_host_key);
}