From 1a1067587a7e018b3177ea0ad82cf3f1915f52d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Jos=C3=A9=20Nicola?= Date: Tue, 8 Feb 2022 09:26:49 +0100 Subject: [PATCH] Add flag to set cipher suite preferences on a TLS session (#1020) * Add the definitions to set preferences which can't be set via the priority string * Extend open_stream_conenction_ext() to receive the new bit flag variable for setting cipher suite preferences on a TLS session * Forward the flag variable to set the TLS preferences or use NO_PRIORITY_FLAGS, as required for each case. * Catch the GNUTLS_E_DH_PRIME_UNACCEPTABLE error during the handshake and return -2 to allow caller functions to handle this especial case. * Handle the case GNUTLS_E_DH_PRIME_UNACCEPTABLE error. Retry with a lower prime bits number. For this, use the new bit flag variable. What: Currently, when the scanner opens a TLS session, cipher suite preferences can be set only via the priority string. Other preferences can be set via functions. This PR extends the open_stream_connection_ext() function to accept a flag which allows to set other preferences (e.g. the number of bits, for use in a Diffie-Hellman key exchange) Jira: SC-441 Why: nasl_builtin_find_service.c fails to detect SSL/TLS service because, in this particular case, the server sends a prime of 512 bits, and the client limit is 1008 (set with the NORMAL priority). This PR handles this error and set a new minimum (128) and retries to open the TLS connection. How: sudo openvas-nasl -X -B -d -i $PLUGINSPATH -t TARGET find_service.nasl --kb="Ports/tcp/443=1" --debug-tls=9 [19893] (1) FFDHE groups advertised, but server didn't support it; falling back to server's choice [19893] (2) Received a prime of 512 bits, limit is 1008 lib misc-Message: 03:36:31.165: replace key FindService/CnxTime1000/443 -> 45 lib misc-Message: 03:36:31.166: set key Transports/TCP/443 -> 1 lib misc-Message: 03:36:51.279: set key Services/unknown -> 443 With the PR: [19263] (1) FFDHE groups advertised, but server didn't support it; falling back to server's choice [19263] (2) Received a prime of 512 bits, limit is 1008 lib misc-Message: 03:19:20.218: [19263] gnutls_handshake: The Diffie-Hellman prime sent by the server is not acceptable (not long enough). [19263] (1) Note that the security level of the Diffie-Hellman key exchange has been lowered to 128 bits and this may allow decryption of the session data lib misc-Message: 03:37:38.525: replace key FindService/RwTime1000/443 -> 101 lib misc-Message: 03:37:38.525: replace key FindService/tcp/443/get_http -> HTTP/1.0 200 OK Date: Sat, 01 Jan 2011 00:00:53 GMT Server: Embedded HTTP Server. Connection: close Content-Length: 107 Last-Modified: Fri, 28 Feb 2014 14:53:02 GMT Content-Type: text/html lib misc-Message: 03:37:38.525: set key Services/www -> 443 lib misc-Message: 03:37:38.525: replace key Known/tcp/443 -> www lib misc-Message: 03:37:38.525: replace key www/banner/443 -> HTTP/1.0 200 OK Date: Sat, 01 Jan 2011 00:00:53 GMT Server: Embedded HTTP Server. Connection: close Content-Length: 107 Last-Modified: Fri, 28 Feb 2014 14:53:02 GMT Content-Type: text/html (cherry picked from commit 8186bb6dce564c2d6da1124c0208120bbd438762) --- misc/network.c | 69 +++++++++++++++++++++++++------- misc/network.h | 7 +++- nasl/nasl_builtin_find_service.c | 11 ++++- nasl/nasl_socket.c | 4 +- 4 files changed, 72 insertions(+), 19 deletions(-) diff --git a/misc/network.c b/misc/network.c index 2e7ddfccb..f58aa5c1d 100644 --- a/misc/network.c +++ b/misc/network.c @@ -402,7 +402,7 @@ ovas_get_tlssession_from_connection (int fd) */ static int set_gnutls_protocol (gnutls_session_t session, openvas_encaps_t encaps, - const char *priority) + const char *priority, unsigned int flags) { const char *priorities; const char *errloc; @@ -445,6 +445,11 @@ set_gnutls_protocol (gnutls_session_t session, openvas_encaps_t encaps, return -1; } + /* Set extra priorities from flags. + Only for encaps == OPENVAS_ENCAPS_TLScustom. */ + if (encaps == OPENVAS_ENCAPS_TLScustom && flags & INSECURE_DH_PRIME_BITS) + gnutls_dh_set_prime_bits (session, 128); + return 0; } @@ -560,10 +565,28 @@ is_ip_address (const char *str) return inet_pton (AF_INET6, str, &(sa6.sin6_addr)) == 1; } +/** + * @brief Open an TLS/SSL connection. + * + * @param fp File structure for a the openvas connection + * @param cert The certificate. + * @param key The key + * @param passwd The password + * @param cafile The CA file + * @param hostname Targets hostname + * @param flags Extra options which can not be set via the priority string + * Supported flags are: + * - NO_PRIORITY_FLAGS + * - INSECURE_DH_PRIME_BITS + * + * @return 1 on success. -1 on general error or timeout. -2 if DH prime bits on + * server side are lower than minimum allowed. + * + */ static int open_SSL_connection (openvas_connection *fp, const char *cert, const char *key, const char *passwd, const char *cafile, - const char *hostname) + const char *hostname, unsigned int flags) { int ret, err, d; time_t tictac; @@ -584,7 +607,8 @@ open_SSL_connection (openvas_connection *fp, const char *cert, const char *key, * OPENVAS_ENCAPS_SSLv2, so it should never end up calling * open_SSL_connection with OPENVAS_ENCAPS_SSLv2. */ - if (set_gnutls_protocol (fp->tls_session, fp->transport, fp->priority) < 0) + if (set_gnutls_protocol (fp->tls_session, fp->transport, fp->priority, flags) + < 0) return -1; if (hostname && !is_ip_address (hostname)) @@ -636,8 +660,17 @@ open_SSL_connection (openvas_connection *fp, const char *cert, const char *key, if (err == 0) return 1; - if (err != GNUTLS_E_INTERRUPTED && err != GNUTLS_E_AGAIN - && err != GNUTLS_E_WARNING_ALERT_RECEIVED) + /* Set min number of bits for Deffie-Hellman prime + to force a connection to a legacy server. */ + if (err == GNUTLS_E_DH_PRIME_UNACCEPTABLE + && fp->transport == OPENVAS_ENCAPS_TLScustom) + { + g_message ("[%d] gnutls_handshake: %s", getpid (), + gnutls_strerror (err)); + return -2; + } + else if (err != GNUTLS_E_INTERRUPTED && err != GNUTLS_E_AGAIN + && err != GNUTLS_E_WARNING_ALERT_RECEIVED) { g_debug ("[%d] gnutls_handshake: %s", getpid (), gnutls_strerror (err)); @@ -811,7 +844,9 @@ socket_negotiate_ssl (int fd, openvas_encaps_t transport, fp->transport = transport; fp->priority = NULL; - if (open_SSL_connection (fp, cert, key, passwd, cafile, hostname) <= 0) + if (open_SSL_connection (fp, cert, key, passwd, cafile, hostname, + NO_PRIORITY_FLAGS) + <= 0) { g_free (hostname); g_free (cert); @@ -1002,14 +1037,16 @@ socket_get_ssl_ciphersuite (int fd) } /* Extended version of open_stream_connection to allow passing a - priority string. + priority string and a bit flag variable for setting extra options + which can't be set via the priority string. ABI_BREAK_NOTE: Merge this with open_stream_connection. */ int open_stream_connection_ext (struct script_infos *args, unsigned int port, - int transport, int timeout, const char *priority) + int transport, int timeout, const char *priority, + int flags) { - int fd; + int fd, ret; openvas_connection *fp; char *cert = NULL; char *key = NULL; @@ -1032,6 +1069,7 @@ open_stream_connection_ext (struct script_infos *args, unsigned int port, if (timeout == -2) timeout = TIMEOUT; + ret = -1; switch (transport) { case OPENVAS_ENCAPS_IP: @@ -1053,13 +1091,13 @@ open_stream_connection_ext (struct script_infos *args, unsigned int port, errno = EINVAL; g_free (hostname_aux); - return -1; + return ret; } if ((fd = get_connection_fd ()) < 0) { g_free (hostname_aux); - return -1; + return ret; } fp = OVAS_CONNECTION_FROM_FD (fd); @@ -1080,7 +1118,6 @@ open_stream_connection_ext (struct script_infos *args, unsigned int port, kb_t kb = plug_get_kb (args); switch (transport) { - int ret; char buf[1024]; case OPENVAS_ENCAPS_IP: @@ -1106,7 +1143,8 @@ open_stream_connection_ext (struct script_infos *args, unsigned int port, if (kb_item_get_int (kb, buf) <= 0) hostname = hostname_aux; - ret = open_SSL_connection (fp, cert, key, passwd, cafile, hostname); + ret = + open_SSL_connection (fp, cert, key, passwd, cafile, hostname, flags); g_free (cert); g_free (key); g_free (passwd); @@ -1122,7 +1160,7 @@ open_stream_connection_ext (struct script_infos *args, unsigned int port, failed: release_connection_fd (fd, 0); - return -1; + return ret; } int @@ -1130,7 +1168,8 @@ open_stream_connection (struct script_infos *args, unsigned int port, int transport, int timeout) { return open_stream_connection_ext (args, port, transport, timeout, - "NORMAL:+ARCFOUR-128:%COMPAT"); + "NORMAL:+ARCFOUR-128:%COMPAT", + NO_PRIORITY_FLAGS); } /* Same as open_stream_auto_encaps but allows to force auto detection diff --git a/misc/network.h b/misc/network.h index 361fcf711..564c7fe01 100644 --- a/misc/network.h +++ b/misc/network.h @@ -57,6 +57,11 @@ typedef enum openvas_encaps #define IS_ENCAPS_SSL(x) \ ((x) >= OPENVAS_ENCAPS_SSLv23 && (x) <= OPENVAS_ENCAPS_TLScustom) +/* Define FLAGS for setting other priorities in + open_stream_connection_ext */ +#define NO_PRIORITY_FLAGS 0 +#define INSECURE_DH_PRIME_BITS (1 << 0) // 1 + /* Plugin specific network functions */ int open_sock_tcp (struct script_infos *, unsigned int, int); @@ -84,7 +89,7 @@ open_stream_connection (struct script_infos *, unsigned int, int, int); int open_stream_connection_ext (struct script_infos *, unsigned int, int, int, - const char *); + const char *, int); int open_stream_auto_encaps_ext (struct script_infos *, unsigned int port, diff --git a/nasl/nasl_builtin_find_service.c b/nasl/nasl_builtin_find_service.c index 092155bdc..d8e11fca0 100644 --- a/nasl/nasl_builtin_find_service.c +++ b/nasl/nasl_builtin_find_service.c @@ -1608,7 +1608,16 @@ plugin_do_run (struct script_infos *desc, GSList *h, int test_ssl) trp = OPENVAS_ENCAPS_IP; gettimeofday (&tv1, NULL); cnx = open_stream_connection (desc, port, trp, cnx_timeout); - if (cnx < 0 && test_ssl) + if (cnx == -2 && test_ssl) + { + unsigned int flags = INSECURE_DH_PRIME_BITS; + + gettimeofday (&tv1, NULL); + cnx = open_stream_connection_ext ( + desc, port, trp, cnx_timeout, "NORMAL:+ARCFOUR-128:%COMPAT", + flags); + } + else if (cnx < 0 && test_ssl) { trp = OPENVAS_ENCAPS_IP; gettimeofday (&tv1, NULL); diff --git a/nasl/nasl_socket.c b/nasl/nasl_socket.c index a408a0780..dd19dc96f 100644 --- a/nasl/nasl_socket.c +++ b/nasl/nasl_socket.c @@ -465,8 +465,8 @@ nasl_open_sock_tcp_bufsz (lex_ctxt *lexic, int bufsz) else if (transport == 0) soc = open_stream_auto_encaps_ext (script_infos, port, to, 1); else - soc = - open_stream_connection_ext (script_infos, port, transport, to, priority); + soc = open_stream_connection_ext (script_infos, port, transport, to, + priority, NO_PRIORITY_FLAGS); if (bufsz > 0 && soc >= 0) { if (stream_set_buffer (soc, bufsz) < 0)