mirror of
https://github.com/nmap/nmap.git
synced 2025-12-06 04:31:29 +00:00
280 lines
12 KiB
C
280 lines
12 KiB
C
/***************************************************************************
|
|
* nsock_ssl.c -- This contains functions that relate somewhat exclusively *
|
|
* to SSL (over TCP) support in nsock. Where SSL support is incidental, *
|
|
* it is often in other files where code can be more easily shared between *
|
|
* the SSL and NonSSL paths. *
|
|
* *
|
|
***********************IMPORTANT NSOCK LICENSE TERMS***********************
|
|
* *
|
|
* The nsock parallel socket event library is (C) 1999-2022 Nmap Software *
|
|
* LLC This library is free software; you may redistribute and/or *
|
|
* modify it under the terms of the GNU General Public License as *
|
|
* published by the Free Software Foundation; Version 2. This guarantees *
|
|
* your right to use, modify, and redistribute this software under certain *
|
|
* conditions. If this license is unacceptable to you, Nmap Software LLC *
|
|
* may be willing to sell alternative licenses (contact sales@nmap.com ). *
|
|
* *
|
|
* As a special exception to the GPL terms, Nmap Software LLC grants *
|
|
* permission to link the code of this program with any version of the *
|
|
* OpenSSL library which is distributed under a license identical to that *
|
|
* listed in the included docs/licenses/OpenSSL.txt file, and distribute *
|
|
* linked combinations including the two. You must obey the GNU GPL in all *
|
|
* respects for all of the code used other than OpenSSL. If you modify *
|
|
* this file, you may extend this exception to your version of the file, *
|
|
* but you are not obligated to do so. *
|
|
* *
|
|
* If you received these files with a written license agreement stating *
|
|
* terms other than the (GPL) terms above, then that alternative license *
|
|
* agreement takes precedence over this comment. *
|
|
* *
|
|
* Source is provided to this software because we believe users have a *
|
|
* right to know exactly what a program is going to do before they run it. *
|
|
* This also allows you to audit the software for security holes. *
|
|
* *
|
|
* Source code also allows you to port Nmap to new platforms, fix bugs, *
|
|
* and add new features. You are highly encouraged to send your changes *
|
|
* to the dev@nmap.org mailing list for possible incorporation into the *
|
|
* main distribution. By sending these changes to Fyodor or one of the *
|
|
* Insecure.Org development mailing lists, or checking them into the Nmap *
|
|
* source code repository, it is understood (unless you specify otherwise) *
|
|
* that you are offering the Nmap Project (Nmap Software LLC) the *
|
|
* unlimited, non-exclusive right to reuse, modify, and relicense the *
|
|
* code. Nmap will always be available Open Source, but this is important *
|
|
* because the inability to relicense code has caused devastating problems *
|
|
* for other Free Software projects (such as KDE and NASM). We also *
|
|
* occasionally relicense the code to third parties as discussed above. *
|
|
* If you wish to specify special license conditions of your *
|
|
* contributions, just say so when you send them. *
|
|
* *
|
|
* This program is distributed in the hope that it will be useful, but *
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
|
* General Public License v2.0 for more details *
|
|
* (http://www.gnu.org/licenses/gpl-2.0.html). *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
/* $Id$ */
|
|
|
|
|
|
#include "nsock.h"
|
|
#include "nsock_internal.h"
|
|
#include "nsock_log.h"
|
|
#include "nsock_ssl.h"
|
|
#include "netutils.h"
|
|
|
|
#if HAVE_OPENSSL
|
|
#if OPENSSL_API_LEVEL >= 30000
|
|
#include <openssl/provider.h>
|
|
#endif
|
|
|
|
/* Disallow anonymous ciphers (Diffie-Hellman key agreement), low bit-strength
|
|
* ciphers, export-crippled ciphers, and MD5. Prefer ciphers in decreasing order
|
|
* of key size. The cipher list is taken from the book Network Security with
|
|
* OpenSSL. To see exactly what ciphers are enabled, use the command
|
|
* openssl ciphers -v '...'
|
|
* where ... is the string below. */
|
|
#define CIPHERS_SECURE "ALL:!aNULL:!eNULL:!LOW:!EXP:!RC4:!MD5:@STRENGTH"
|
|
|
|
/* This list of ciphers is for speed and compatibility, not security. Any cipher
|
|
* is accepted, and the list is sorted by speed based on Brian Hatch's
|
|
* (bri@ifokr.org) tests on an Pentium 686 against the ciphers listed. */
|
|
#define CIPHERS_FAST "RC4-SHA:RC4-MD5:NULL-SHA:EXP-DES-CBC-SHA:EXP-EDH-RSA-DES-CBC-SHA:EXP-RC4-MD5:NULL-MD5:EDH-RSA-DES-CBC-SHA:EXP-RC2-CBC-MD5:EDH-RSA-DES-CBC3-SHA:EXP-ADH-RC4-MD5:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:EXP-ADH-DES-CBC-SHA:ADH-AES256-SHA:ADH-DES-CBC-SHA:ADH-RC4-MD5:AES256-SHA:DES-CBC-SHA:DES-CBC3-SHA:ADH-DES-CBC3-SHA:AES128-SHA:ADH-AES128-SHA:eNULL:ALL"
|
|
|
|
extern struct timeval nsock_tod;
|
|
#define NSOCK_SSL_STATE_UNINITIALIZED -1
|
|
#define NSOCK_SSL_STATE_INITIALIZED 1
|
|
#define NSOCK_SSL_STATE_ATEXIT 0
|
|
static int nsock_ssl_state = NSOCK_SSL_STATE_UNINITIALIZED;
|
|
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined LIBRESSL_VERSION_NUMBER
|
|
static void nsock_ssl_atexit(void)
|
|
{
|
|
nsock_ssl_state = NSOCK_SSL_STATE_ATEXIT;
|
|
}
|
|
#endif
|
|
void nsp_ssl_cleanup(struct npool *nsp)
|
|
{
|
|
if (nsock_ssl_state != NSOCK_SSL_STATE_ATEXIT)
|
|
{
|
|
if (nsp->sslctx != NULL)
|
|
SSL_CTX_free(nsp->sslctx);
|
|
#ifdef HAVE_DTLS_CLIENT_METHOD
|
|
if (nsp->dtlsctx != NULL)
|
|
SSL_CTX_free(nsp->dtlsctx);
|
|
#endif
|
|
}
|
|
nsp->sslctx = NULL;
|
|
#ifdef HAVE_DTLS_CLIENT_METHOD
|
|
nsp->dtlsctx = NULL;
|
|
#endif
|
|
}
|
|
|
|
static SSL_CTX *ssl_init_helper(const SSL_METHOD *method) {
|
|
SSL_CTX *ctx;
|
|
|
|
if (nsock_ssl_state == NSOCK_SSL_STATE_UNINITIALIZED)
|
|
{
|
|
nsock_ssl_state = NSOCK_SSL_STATE_INITIALIZED;
|
|
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined LIBRESSL_VERSION_NUMBER
|
|
SSL_load_error_strings();
|
|
SSL_library_init();
|
|
#else
|
|
OPENSSL_atexit(nsock_ssl_atexit);
|
|
#if OPENSSL_API_LEVEL >= 30000
|
|
if (NULL == OSSL_PROVIDER_load(NULL, "legacy"))
|
|
{
|
|
nsock_log_error("OpenSSL legacy provider failed to load.\n");
|
|
}
|
|
if (NULL == OSSL_PROVIDER_load(NULL, "default"))
|
|
{
|
|
nsock_log_error("OpenSSL default provider failed to load.\n");
|
|
}
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
ctx = SSL_CTX_new(method);
|
|
if (!ctx) {
|
|
fatal("OpenSSL failed to create a new SSL_CTX: %s",
|
|
ERR_error_string(ERR_get_error(), NULL));
|
|
}
|
|
|
|
/* Our SSL* will always have the SSL_SESSION* inside it, so we neither need to
|
|
* use nor waste memory for the session cache. (Use '1' because '0' means
|
|
* 'infinite'.) */
|
|
SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF|SSL_SESS_CACHE_NO_AUTO_CLEAR);
|
|
SSL_CTX_sess_set_cache_size(ctx, 1);
|
|
SSL_CTX_set_timeout(ctx, 3600); /* pretty unnecessary */
|
|
|
|
return ctx;
|
|
}
|
|
|
|
/* Create an SSL_CTX and do initialization that is common to all init modes. */
|
|
static SSL_CTX *ssl_init_common() {
|
|
return ssl_init_helper(SSLv23_client_method());
|
|
}
|
|
|
|
/* Initializes an Nsock pool to create SSL connections. This sets an internal
|
|
* SSL_CTX, which is like a template that sets options for all connections that
|
|
* are made from it. The connections made from this context will use only secure
|
|
* ciphers but no server certificate verification is done. Returns the SSL_CTX
|
|
* so you can set your own options. */
|
|
static nsock_ssl_ctx nsock_pool_ssl_init_helper(SSL_CTX *ctx, int flags) {
|
|
char rndbuf[128];
|
|
|
|
/* Get_random_bytes may or may not provide high-quality randomness. Add it to
|
|
* the entropy pool without increasing the entropy estimate (third argument of
|
|
* RAND_add is 0). We rely on OpenSSL's entropy gathering, called implicitly
|
|
* by RAND_status, to give us what we need, or else bail out if it fails. */
|
|
get_random_bytes(rndbuf, sizeof(rndbuf));
|
|
RAND_add(rndbuf, sizeof(rndbuf), 0);
|
|
|
|
if (!(flags & NSOCK_SSL_MAX_SPEED)) {
|
|
if (!RAND_status())
|
|
fatal("%s: Failed to seed OpenSSL PRNG"
|
|
" (RAND_status returned false).", __func__);
|
|
}
|
|
|
|
/* SSL_OP_ALL sets bug-compatibility for pretty much everything.
|
|
* SSL_OP_NO_SSLv2 disables the less-secure SSLv2 while allowing us to use the
|
|
* SSLv2-compatible SSLv23_client_method. */
|
|
SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
|
|
SSL_CTX_clear_options(ctx, SSL_OP_NO_SSLv2);
|
|
SSL_CTX_set_options(ctx, flags & NSOCK_SSL_MAX_SPEED ?
|
|
SSL_OP_ALL : SSL_OP_ALL|SSL_OP_NO_SSLv2);
|
|
|
|
if (!SSL_CTX_set_cipher_list(ctx, flags & NSOCK_SSL_MAX_SPEED ?
|
|
CIPHERS_FAST : CIPHERS_SECURE))
|
|
fatal("Unable to set OpenSSL cipher list: %s",
|
|
ERR_error_string(ERR_get_error(), NULL));
|
|
|
|
return ctx;
|
|
}
|
|
|
|
nsock_ssl_ctx nsock_pool_ssl_init(nsock_pool ms_pool, int flags) {
|
|
struct npool *ms = (struct npool *)ms_pool;
|
|
|
|
if (ms->sslctx == NULL)
|
|
ms->sslctx = ssl_init_common();
|
|
return nsock_pool_ssl_init_helper(ms->sslctx, flags);
|
|
}
|
|
|
|
#ifdef HAVE_DTLS_CLIENT_METHOD
|
|
|
|
/* Create an SSL_CTX and do initialisation, creating a DTLS client */
|
|
static SSL_CTX *dtls_init_common() {
|
|
return ssl_init_helper(DTLS_client_method());
|
|
}
|
|
|
|
/* Initializes an Nsock pool to create DTLS connections. Very much similar to
|
|
* nsock_pool_ssl_init, just with DTLS. */
|
|
nsock_ssl_ctx nsock_pool_dtls_init(nsock_pool ms_pool, int flags) {
|
|
SSL_CTX *dtls_ctx = NULL;
|
|
struct npool *ms = (struct npool *)ms_pool;
|
|
|
|
if (ms->dtlsctx == NULL)
|
|
ms->dtlsctx = dtls_init_common();
|
|
dtls_ctx = (SSL_CTX *) nsock_pool_ssl_init_helper(ms->dtlsctx, flags);
|
|
|
|
/* Don't add padding or the ClientHello will fragment and not connect properly. */
|
|
SSL_CTX_clear_options(dtls_ctx, SSL_OP_TLSEXT_PADDING);
|
|
|
|
if (!SSL_CTX_set_cipher_list(dtls_ctx, "DEFAULT"))
|
|
fatal("Unable to set OpenSSL cipher list: %s",
|
|
ERR_error_string(ERR_get_error(), NULL));
|
|
|
|
return dtls_ctx;
|
|
}
|
|
|
|
#else /* OpenSSL Version does not support DTLS */
|
|
|
|
nsock_ssl_ctx nsock_pool_dtls_init(nsock_pool ms_pool, int flags) {
|
|
fatal("%s called with no OpenSSL DTLS support", __func__);
|
|
}
|
|
|
|
#endif
|
|
|
|
/* Check server certificate verification, after a connection is established. We
|
|
* check first that a certificate was even offered, then call
|
|
* SSL_get_verify_result to get the overall status of verification. (Just
|
|
* calling SSL_get_verify_result is not enough because that function returns
|
|
* X509_V_OK when 0 certificates are presented.) If the verification mode of the
|
|
* SSL object is SSL_VERIFY_NONE, or if OpenSSL is disabled, this function
|
|
* always returns true. */
|
|
int nsi_ssl_post_connect_verify(const nsock_iod nsockiod) {
|
|
struct niod *iod = (struct niod *)nsockiod;
|
|
|
|
assert(iod->ssl != NULL);
|
|
if (SSL_get_verify_mode(iod->ssl) != SSL_VERIFY_NONE) {
|
|
X509 *cert;
|
|
|
|
cert = SSL_get_peer_certificate(iod->ssl);
|
|
if (cert == NULL)
|
|
/* No certificate presented. */
|
|
return 0;
|
|
|
|
X509_free(cert);
|
|
|
|
if (SSL_get_verify_result(iod->ssl) != X509_V_OK)
|
|
/* Something wrong with verification. */
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
#else /* NOT HAVE_OPENSSL */
|
|
|
|
nsock_ssl_ctx nsock_pool_ssl_init(nsock_pool ms_pool, int flags) {
|
|
fatal("%s called with no OpenSSL support", __func__);
|
|
}
|
|
|
|
nsock_ssl_ctx nsock_pool_dtls_init(nsock_pool ms_pool, int flags) {
|
|
fatal("%s called with no OpenSSL support", __func__);
|
|
}
|
|
|
|
int nsi_ssl_post_connect_verify(const nsock_iod nsockiod) {
|
|
return 1;
|
|
}
|
|
|
|
#endif
|