diff --git a/include/libssh/session.h b/include/libssh/session.h index 107d4aec..2f1c4269 100644 --- a/include/libssh/session.h +++ b/include/libssh/session.h @@ -90,6 +90,7 @@ enum ssh_pending_call_e { /* server-sig-algs extension */ #define SSH_EXT_SIG_RSA_SHA256 0x01 #define SSH_EXT_SIG_RSA_SHA512 0x02 +#define SSH_EXT_ALL SSH_EXT_SIG_RSA_SHA256 | SSH_EXT_SIG_RSA_SHA512 /* members that are common to ssh_session and ssh_bind */ struct ssh_common_struct { diff --git a/src/kex.c b/src/kex.c index ee36bb31..a2b11d52 100644 --- a/src/kex.c +++ b/src/kex.c @@ -415,7 +415,7 @@ out: } SSH_PACKET_CALLBACK(ssh_packet_kexinit){ - int i; + int i, ok; int server_kex=session->server; ssh_string str = NULL; char *strings[KEX_METHODS_SIZE]; @@ -519,6 +519,22 @@ SSH_PACKET_CALLBACK(ssh_packet_kexinit){ goto error; } + /* + * If client sent a ext-info-c message in the kex list, it supports + * RFC 8308 extension negotiation. + */ + ok = ssh_match_group(session->next_crypto->client_kex.methods[SSH_KEX], + KEX_EXTENSION_CLIENT); + if (ok) { + /* + * Enable all the supported extensions and when the time comes + * (after NEWKEYS) send them to the client. + */ + SSH_LOG(SSH_LOG_DEBUG, "The client supports extension " + "negotiation: enabling all extensions"); + session->extensions = SSH_EXT_ALL; + } + /* * Remember whether 'first_kex_packet_follows' was set and the client * guess was wrong: in this case the next SSH_MSG_KEXDH_INIT message diff --git a/src/server.c b/src/server.c index 8984e6a0..dfabbe83 100644 --- a/src/server.c +++ b/src/server.c @@ -67,7 +67,6 @@ static int dh_handshake_server(ssh_session session); - /** * @addtogroup libssh_server * @@ -194,6 +193,37 @@ static int ssh_server_kexdh_init(ssh_session session, ssh_buffer packet){ return SSH_OK; } +static int ssh_server_send_extensions(ssh_session session) { + int rc; + const char *hostkey_algorithms; + + SSH_LOG(SSH_LOG_PACKET, "Sending SSH_MSG_EXT_INFO"); + /* + * We can list here all the default hostkey methods, since + * they already contain the SHA2 extension algorithms + */ + hostkey_algorithms = ssh_kex_get_default_methods(SSH_HOSTKEYS); + rc = ssh_buffer_pack(session->out_buffer, + "bdss", + SSH2_MSG_EXT_INFO, + 1, /* nr. of extensions */ + "server-sig-algs", + hostkey_algorithms); + if (rc != SSH_OK) { + goto error; + } + + if (ssh_packet_send(session) == SSH_ERROR) { + goto error; + } + + return 0; +error: + ssh_buffer_reinit(session->out_buffer); + + return -1; +} + SSH_PACKET_CALLBACK(ssh_packet_kexdh_init){ int rc = SSH_ERROR; (void)type; @@ -486,6 +516,15 @@ static void ssh_server_connection_callback(ssh_session session){ session->session_state=SSH_SESSION_STATE_AUTHENTICATING; if (session->flags & SSH_SESSION_FLAG_AUTHENTICATED) session->session_state = SSH_SESSION_STATE_AUTHENTICATED; + + /* + * If the client supports extension negotiation, we will send + * our supported extensions now. This is the first message after + * sending NEWKEYS message and after turning on crypto. + */ + if (session->extensions) { + ssh_server_send_extensions(session); + } } break; case SSH_SESSION_STATE_AUTHENTICATING: