Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 20 additions & 5 deletions config.m4
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,27 @@ if test "$PHP_SSH2" != "no"; then

PHP_ADD_INCLUDE($SSH2_DIR/include)

saved_CPPFLAGS=$CPPFLAGS
CPPFLAGS="-I$SSH2_DIR/include $CPPFLAGS"
AC_MSG_CHECKING([for libssh2 version >= 1.9.0])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <libssh2.h>
#if LIBSSH2_VERSION_NUM < 0x010900
#error libssh2 1.9.0 or newer is required
#endif
]], [[]])], [
AC_MSG_RESULT([yes])
], [
AC_MSG_ERROR([libssh2 version >= 1.9.0 not found])
])
CPPFLAGS=$saved_CPPFLAGS

PHP_CHECK_LIBRARY(ssh2,libssh2_session_hostkey,
[
PHP_ADD_LIBRARY_WITH_PATH(ssh2, $SSH2_DIR/lib, SSH2_SHARED_LIBADD)
AC_DEFINE(HAVE_SSH2LIB,1,[Have libssh2])
],[
AC_MSG_ERROR([libssh2 version >= 1.2 not found])
AC_MSG_ERROR([libssh2 library not found or too old; version 1.9.0 or newer is required])
],[
-L$SSH2_DIR/lib -lm
])
Expand All @@ -39,7 +54,7 @@ if test "$PHP_SSH2" != "no"; then
[
AC_DEFINE(PHP_SSH2_AGENT_AUTH, 1, [Have libssh2 with ssh-agent support])
],[
AC_MSG_WARN([libssh2 <= 1.2.3, ssh-agent subsystem support not enabled])
AC_MSG_ERROR([libssh2_agent_init not found; ensure the linked libssh2 matches the 1.9.0 or newer headers])
],[
-L$SSH2_DIR/lib -lm
])
Expand All @@ -48,7 +63,7 @@ if test "$PHP_SSH2" != "no"; then
[
AC_DEFINE(PHP_SSH2_SESSION_TIMEOUT, 1, [Have libssh2 with session timeout support])
],[
AC_MSG_WARN([libssh2 < 1.2.9, session timeout support not enabled])
AC_MSG_ERROR([libssh2_session_set_timeout not found; ensure the linked libssh2 matches the 1.9.0 or newer headers])
],[
-L$SSH2_DIR/lib -lm
])
Expand All @@ -57,7 +72,7 @@ if test "$PHP_SSH2" != "no"; then
[
AC_DEFINE(PHP_SSH2_KEEPALIVE, 1, [Have libssh2 with keepalive support])
],[
AC_MSG_WARN([libssh2 keepalive support not available])
AC_MSG_ERROR([libssh2_keepalive_config not found; ensure the linked libssh2 matches the 1.9.0 or newer headers])
],[
-L$SSH2_DIR/lib -lm
])
Expand All @@ -66,7 +81,7 @@ if test "$PHP_SSH2" != "no"; then
[
AC_DEFINE(PHP_SSH2_CHANNEL_SIGNAL, 1, [Have libssh2 with channel signal support])
],[
AC_MSG_WARN([libssh2 < 1.9.0, channel signal support not available])
AC_MSG_ERROR([libssh2_channel_signal_ex not found; ensure the linked libssh2 matches the 1.9.0 or newer headers])
],[
-L$SSH2_DIR/lib -lm
])
Expand Down
1 change: 1 addition & 0 deletions package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
<file role="test" name="ssh2_auth_pubkey_file.phpt"/>
<file role="test" name="ssh2_connect.phpt"/>
<file role="test" name="ssh2_exec.phpt"/>
<file role="test" name="ssh2_hostkey.phpt"/>
<file role="test" name="ssh2_keepalive.phpt"/>
<file role="test" name="ssh2_poll.phpt"/>
<file role="test" name="ssh2_send_eof.phpt"/>
Expand Down
5 changes: 5 additions & 0 deletions php_ssh2.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@
#include "ext/standard/url.h"
#include "main/php_network.h"

#if LIBSSH2_VERSION_NUM < 0x010900
#error "The ssh2 extension requires libssh2 1.9.0 or newer"
#endif

#define PHP_SSH2_VERSION "1.5.0"
#define PHP_SSH2_DEFAULT_PORT 22

Expand All @@ -32,6 +36,7 @@
#define PHP_SSH2_FINGERPRINT_SHA1 0x0001
#define PHP_SSH2_FINGERPRINT_HEX 0x0000
#define PHP_SSH2_FINGERPRINT_RAW 0x0002
#define PHP_SSH2_FINGERPRINT_SHA256 0x0004

#define PHP_SSH2_TERM_UNIT_CHARS 0x0000
#define PHP_SSH2_TERM_UNIT_PIXELS 0x0001
Expand Down
64 changes: 61 additions & 3 deletions ssh2.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@
#define MD5_DIGEST_LENGTH 16
#endif

#ifndef SHA256_DIGEST_LENGTH
#define SHA256_DIGEST_LENGTH 32
#endif

/* True global resources - no need for thread safety here */
int le_ssh2_session;
int le_ssh2_listener;
Expand Down Expand Up @@ -591,18 +595,28 @@ PHP_FUNCTION(ssh2_fingerprint)
zval *zsession;
const char *fingerprint;
zend_long flags = 0;
int i, fingerprint_len;
size_t i, fingerprint_len;
int hash_type;

if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|l", &zsession, &flags) == FAILURE) {
return;
}
fingerprint_len = (flags & PHP_SSH2_FINGERPRINT_SHA1) ? SHA_DIGEST_LENGTH : MD5_DIGEST_LENGTH;
if (flags & PHP_SSH2_FINGERPRINT_SHA256) {
fingerprint_len = SHA256_DIGEST_LENGTH;
hash_type = LIBSSH2_HOSTKEY_HASH_SHA256;
} else if (flags & PHP_SSH2_FINGERPRINT_SHA1) {
fingerprint_len = SHA_DIGEST_LENGTH;
hash_type = LIBSSH2_HOSTKEY_HASH_SHA1;
} else {
fingerprint_len = MD5_DIGEST_LENGTH;
hash_type = LIBSSH2_HOSTKEY_HASH_MD5;
}

if ((session = (LIBSSH2_SESSION *)zend_fetch_resource(Z_RES_P(zsession), PHP_SSH2_SESSION_RES_NAME, le_ssh2_session)) == NULL) {
RETURN_FALSE;
}

fingerprint = (char*)libssh2_hostkey_hash(session, (flags & PHP_SSH2_FINGERPRINT_SHA1) ? LIBSSH2_HOSTKEY_HASH_SHA1 : LIBSSH2_HOSTKEY_HASH_MD5);
fingerprint = (char*)libssh2_hostkey_hash(session, hash_type);
if (!fingerprint) {
php_error_docref(NULL, E_WARNING, "Unable to retrieve fingerprint from specified session");
RETURN_FALSE;
Expand Down Expand Up @@ -631,6 +645,36 @@ PHP_FUNCTION(ssh2_fingerprint)
}
/* }}} */

/* {{{ proto array ssh2_hostkey(resource session)
* Returns the server's raw host key and type
*/
PHP_FUNCTION(ssh2_hostkey)
{
LIBSSH2_SESSION *session;
zval *zsession;
const char *hostkey;
size_t hostkey_len;
int type;

if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &zsession) == FAILURE) {
return;
}

if ((session = (LIBSSH2_SESSION *)zend_fetch_resource(Z_RES_P(zsession), PHP_SSH2_SESSION_RES_NAME, le_ssh2_session)) == NULL) {
RETURN_FALSE;
}

hostkey = libssh2_session_hostkey(session, &hostkey_len, &type);
if (!hostkey) {
RETURN_FALSE;
}

array_init(return_value);
add_assoc_stringl(return_value, "key", (char *)hostkey, hostkey_len);
add_assoc_long(return_value, "type", type);
}
/* }}} */

/* {{{ proto array ssh2_auth_none(resource session, string username)
* Attempt "none" authentication, returns a list of allowed methods on failed authentication,
* false on utter failure, or true on success
Expand Down Expand Up @@ -1417,6 +1461,15 @@ PHP_MINIT_FUNCTION(ssh2)
REGISTER_LONG_CONSTANT("SSH2_FINGERPRINT_SHA1", PHP_SSH2_FINGERPRINT_SHA1, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("SSH2_FINGERPRINT_HEX", PHP_SSH2_FINGERPRINT_HEX, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("SSH2_FINGERPRINT_RAW", PHP_SSH2_FINGERPRINT_RAW, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("SSH2_FINGERPRINT_SHA256", PHP_SSH2_FINGERPRINT_SHA256, CONST_CS | CONST_PERSISTENT);

REGISTER_LONG_CONSTANT("SSH2_HOSTKEY_TYPE_UNKNOWN", LIBSSH2_HOSTKEY_TYPE_UNKNOWN, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("SSH2_HOSTKEY_TYPE_RSA", LIBSSH2_HOSTKEY_TYPE_RSA, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("SSH2_HOSTKEY_TYPE_DSS", LIBSSH2_HOSTKEY_TYPE_DSS, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("SSH2_HOSTKEY_TYPE_ECDSA_256", LIBSSH2_HOSTKEY_TYPE_ECDSA_256, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("SSH2_HOSTKEY_TYPE_ECDSA_384", LIBSSH2_HOSTKEY_TYPE_ECDSA_384, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("SSH2_HOSTKEY_TYPE_ECDSA_521", LIBSSH2_HOSTKEY_TYPE_ECDSA_521, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("SSH2_HOSTKEY_TYPE_ED25519", LIBSSH2_HOSTKEY_TYPE_ED25519, CONST_CS | CONST_PERSISTENT);

REGISTER_LONG_CONSTANT("SSH2_TERM_UNIT_CHARS", PHP_SSH2_TERM_UNIT_CHARS, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("SSH2_TERM_UNIT_PIXELS", PHP_SSH2_TERM_UNIT_PIXELS, CONST_CS | CONST_PERSISTENT);
Expand Down Expand Up @@ -1513,6 +1566,10 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_ssh2_fingerprint, 0, 0, 1)
ZEND_ARG_INFO(0, flags)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO(arginfo_ssh2_hostkey, 1)
ZEND_ARG_INFO(0, session)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO(arginfo_ssh2_auth_none, 2)
ZEND_ARG_INFO(0, session)
ZEND_ARG_INFO(0, username)
Expand Down Expand Up @@ -1727,6 +1784,7 @@ zend_function_entry ssh2_functions[] = {
#endif
PHP_FE(ssh2_methods_negotiated, arginfo_ssh2_methods_negotiated)
PHP_FE(ssh2_fingerprint, arginfo_ssh2_fingerprint)
PHP_FE(ssh2_hostkey, arginfo_ssh2_hostkey)

PHP_FE(ssh2_auth_none, arginfo_ssh2_auth_none)
PHP_FE(ssh2_auth_password, arginfo_ssh2_auth_password)
Expand Down
28 changes: 28 additions & 0 deletions tests/ssh2_hostkey.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
--TEST--
Raw host-key metadata and SHA-256 fingerprints describe the same server key
--SKIPIF--
<?php require('ssh2_skip.inc'); ?>
--FILE--
<?php
require('ssh2_test.inc');

$ssh = ssh2_connect(TEST_SSH2_HOSTNAME, TEST_SSH2_PORT);
$hostkey = ssh2_hostkey($ssh);
$fingerprint = ssh2_fingerprint($ssh, SSH2_FINGERPRINT_SHA256 | SSH2_FINGERPRINT_RAW);

var_dump(is_array($hostkey));
var_dump(is_string($hostkey['key']));
var_dump($hostkey['key'] !== '');
var_dump(is_int($hostkey['type']));
var_dump($hostkey['type'] !== SSH2_HOSTKEY_TYPE_UNKNOWN);
var_dump(strlen($fingerprint));
var_dump($fingerprint === hash('sha256', $hostkey['key'], true));
?>
--EXPECT--
bool(true)
bool(true)
bool(true)
bool(true)
bool(true)
int(32)
bool(true)