Net_SSH2::getServerPublicHostKey PHP Method

getServerPublicHostKey() public method

Caching this the first time you connect to a server and checking the result on subsequent connections is recommended. Returns false if the server signature is not signed correctly with the public host key.
public getServerPublicHostKey ( ) : mixed
return mixed
    function getServerPublicHostKey()
    {
        if (!($this->bitmap & NET_SSH2_MASK_CONSTRUCTOR)) {
            if (!$this->_connect()) {
                return false;
            }
        }
        $signature = $this->signature;
        $server_public_host_key = $this->server_public_host_key;
        extract(unpack('Nlength', $this->_string_shift($server_public_host_key, 4)));
        $this->_string_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 Math_BigInteger();
                $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
                $p = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
                $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
                $q = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
                $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
                $g = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
                $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
                $y = new Math_BigInteger($this->_string_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', $this->_string_shift($signature, 4));
                if ($temp['length'] != 40) {
                    user_error('Invalid signature');
                    return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
                }
                $r = new Math_BigInteger($this->_string_shift($signature, 20), 256);
                $s = new Math_BigInteger($this->_string_shift($signature, 20), 256);
                switch (true) {
                    case $r->equals($zero):
                    case $r->compare($q) >= 0:
                    case $s->equals($zero):
                    case $s->compare($q) >= 0:
                        user_error('Invalid signature');
                        return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
                }
                $w = $s->modInverse($q);
                $u1 = $w->multiply(new Math_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':
                $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
                $e = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
                $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
                $rawN = $this->_string_shift($server_public_host_key, $temp['length']);
                $n = new Math_BigInteger($rawN, -256);
                $nLength = strlen(ltrim($rawN, ""));
                /*
                $temp = unpack('Nlength', $this->_string_shift($signature, 4));
                $signature = $this->_string_shift($signature, $temp['length']);
                
                if (!class_exists('Crypt_RSA')) {
                    include_once $_SESSION['settings']['cpassman_dir'].'/includes/libraries/Authentication/phpseclib/Crypt/RSA.php';
                }
                
                $rsa = new Crypt_RSA();
                $rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);
                $rsa->loadKey(array('e' => $e, 'n' => $n), CRYPT_RSA_PUBLIC_FORMAT_RAW);
                if (!$rsa->verify($this->exchange_hash, $signature)) {
                    user_error('Bad server signature');
                    return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
                }
                */
                $temp = unpack('Nlength', $this->_string_shift($signature, 4));
                $s = new Math_BigInteger($this->_string_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 Math_BigInteger()) < 0 || $s->compare($n->subtract(new Math_BigInteger(1))) > 0) {
                    user_error('Invalid signature');
                    return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
                }
                $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:
                user_error('Unsupported signature format');
                return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
        }
        return $this->signature_format . ' ' . base64_encode($this->server_public_host_key);
    }

Usage Example

 public function testGetServerPublicHostKey()
 {
     $ssh = new Net_SSH2($this->getEnv('SSH_HOSTNAME'));
     $this->assertInternalType('string', $ssh->getServerPublicHostKey());
 }