diff --git a/include/libssh/packet.h b/include/libssh/packet.h index 1a9283d8..a3bcb9a8 100644 --- a/include/libssh/packet.h +++ b/include/libssh/packet.h @@ -51,6 +51,7 @@ SSH_PACKET_CALLBACK(ssh_packet_ignore_callback); SSH_PACKET_CALLBACK(ssh_packet_dh_reply); SSH_PACKET_CALLBACK(ssh_packet_newkeys); SSH_PACKET_CALLBACK(ssh_packet_service_accept); +SSH_PACKET_CALLBACK(ssh_packet_ext_info); #ifdef WITH_SERVER SSH_PACKET_CALLBACK(ssh_packet_kexdh_init); diff --git a/include/libssh/session.h b/include/libssh/session.h index 6cb79628..00717652 100644 --- a/include/libssh/session.h +++ b/include/libssh/session.h @@ -86,6 +86,11 @@ enum ssh_pending_call_e { #define SSH_OPT_FLAG_KBDINT_AUTH 0x4 #define SSH_OPT_FLAG_GSSAPI_AUTH 0x8 +/* extensions flags */ +/* server-sig-algs extension */ +#define SSH_EXT_SIG_RSA_SHA256 0x01 +#define SSH_EXT_SIG_RSA_SHA512 0x02 + /* members that are common to ssh_session and ssh_bind */ struct ssh_common_struct { struct error_struct error; @@ -114,6 +119,9 @@ struct ssh_session_struct { /* session flags (SSH_SESSION_FLAG_*) */ int flags; + /* Extensions negotiated using RFC 8308 */ + uint32_t extensions; + ssh_string banner; /* that's the issue banner from the server */ char *discon_msg; /* disconnect message from diff --git a/include/libssh/ssh2.h b/include/libssh/ssh2.h index 8b39b9a6..35214330 100644 --- a/include/libssh/ssh2.h +++ b/include/libssh/ssh2.h @@ -7,6 +7,7 @@ #define SSH2_MSG_DEBUG 4 #define SSH2_MSG_SERVICE_REQUEST 5 #define SSH2_MSG_SERVICE_ACCEPT 6 +#define SSH2_MSG_EXT_INFO 7 #define SSH2_MSG_KEXINIT 20 #define SSH2_MSG_NEWKEYS 21 diff --git a/src/packet.c b/src/packet.c index 16f96149..5b9252f5 100644 --- a/src/packet.c +++ b/src/packet.c @@ -59,8 +59,9 @@ static ssh_packet_callback default_packet_handlers[]= { NULL, #endif ssh_packet_service_accept, // SSH2_MSG_SERVICE_ACCEPT 6 - NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, // 7-19 + ssh_packet_ext_info, // SSH2_MSG_EXT_INFO 7 + NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, // 8-19 ssh_packet_kexinit, // SSH2_MSG_KEXINIT 20 ssh_packet_newkeys, // SSH2_MSG_NEWKEYS 21 NULL, NULL, NULL, NULL, NULL, NULL, NULL, diff --git a/src/packet_cb.c b/src/packet_cb.c index ecf327ef..c3a1997f 100644 --- a/src/packet_cb.c +++ b/src/packet_cb.c @@ -270,3 +270,55 @@ SSH_PACKET_CALLBACK(ssh_packet_service_accept){ return SSH_PACKET_USED; } + +/** + * @internal + * @brief handles a SSH2_MSG_EXT_INFO packet defined in RFC 8308 + * + */ +SSH_PACKET_CALLBACK(ssh_packet_ext_info) +{ + int rc; + uint32_t nr_extensions = 0; + uint32_t i; + (void)type; + (void)user; + + SSH_LOG(SSH_LOG_PACKET, "Received SSH_MSG_EXT_INFO"); + + rc = ssh_buffer_get_u32(packet, &nr_extensions); + if (rc == 0) { + SSH_LOG(SSH_LOG_PACKET, "Failed to read number of extensions"); + return SSH_PACKET_USED; + } + nr_extensions = ntohl(nr_extensions); + SSH_LOG(SSH_LOG_PACKET, "Follows %u extensions", nr_extensions); + + for (i = 0; i < nr_extensions; i++) { + char *name = NULL; + char *value = NULL; + int cmp; + + rc = ssh_buffer_unpack(packet, "ss", &name, &value); + if (rc != SSH_OK) { + SSH_LOG(SSH_LOG_PACKET, "Error reading extension name-value pair"); + return SSH_PACKET_USED; + } + + cmp = strcmp(name, "server-sig-algs"); + if (cmp == 0) { + /* TODO check for NULL bytes */ + SSH_LOG(SSH_LOG_PACKET, "Extension: %s=<%s>", name, value); + if (ssh_match_group(value, "rsa-sha2-512")) { + session->extensions |= SSH_EXT_SIG_RSA_SHA512; + } + if (ssh_match_group(value, "rsa-sha2-256")) { + session->extensions |= SSH_EXT_SIG_RSA_SHA256; + } + } + free(name); + free(value); + } + + return SSH_PACKET_USED; +}