ec_sslwrap.c (ettercap-0.8.3) | : | ec_sslwrap.c (ettercap-0.8.3.1) | ||
---|---|---|---|---|
skipping to change at line 56 | skipping to change at line 56 | |||
#include <pthread.h> | #include <pthread.h> | |||
// XXX - check if we have poll.h | // XXX - check if we have poll.h | |||
#ifdef HAVE_SYS_POLL_H | #ifdef HAVE_SYS_POLL_H | |||
#include <sys/poll.h> | #include <sys/poll.h> | |||
#endif | #endif | |||
/* don't include kerberos. RH sux !! */ | /* don't include kerberos. RH sux !! */ | |||
#define OPENSSL_NO_KRB5 1 | #define OPENSSL_NO_KRB5 1 | |||
#include <openssl/ssl.h> | #include <openssl/ssl.h> | |||
#ifdef DEBUG | ||||
#include <openssl/err.h> | ||||
#endif | ||||
#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) | #if (OPENSSL_VERSION_NUMBER >= 0x10100000L) | |||
#define HAVE_OPAQUE_RSA_DSA_DH 1 /* since 1.1.0 -pre5 */ | #define HAVE_OPAQUE_RSA_DSA_DH 1 /* since 1.1.0 -pre5 */ | |||
#endif | #endif | |||
#if (OPENSSL_VERSION_NUMBER >= 0x10002000L) | ||||
#define HAVE_OPENSSL_1_0_2 | ||||
#endif | ||||
#if (OPENSSL_VERSION_NUMBER <= 0x100020700L) | ||||
/* prior 1.0.2g TLS_client_method macro wasn't available */ | ||||
#define TLS_client_method SSLv23_client_method | ||||
#define TLS_server_method SSLv23_server_method | ||||
#endif | ||||
#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) | ||||
#define HAVE_OPENSSL_1_1_0 | ||||
#endif | ||||
#if (OPENSSL_VERSION_NUMBER >= 0x10101000L) | ||||
#define HAVE_OPENSSL_1_1_1 | ||||
#endif | ||||
#define BREAK_ON_ERROR(x,y,z) do { \ | #define BREAK_ON_ERROR(x,y,z) do { \ | |||
if (x == -E_INVALID) { \ | if (x == -E_INVALID) { \ | |||
SAFE_FREE(z.DATA.disp_data); \ | SAFE_FREE(z.DATA.disp_data); \ | |||
sslw_initialize_po(&z, z.DATA.data); \ | sslw_initialize_po(&z, z.DATA.data); \ | |||
z.len = 64; \ | z.len = 64; \ | |||
z.L4.flags = TH_RST; \ | z.L4.flags = TH_RST; \ | |||
packet_disp_data(&z, z.DATA.data, z.DATA.len); \ | packet_disp_data(&z, z.DATA.data, z.DATA.len); \ | |||
sslw_parse_packet(y, SSL_SERVER, &z); \ | sslw_parse_packet(y, SSL_SERVER, &z); \ | |||
sslw_wipe_connection(y); \ | sslw_wipe_connection(y); \ | |||
SAFE_FREE(z.DATA.data); \ | SAFE_FREE(z.DATA.data); \ | |||
skipping to change at line 97 | skipping to change at line 118 | |||
LIST_ENTRY (listen_entry) next; | LIST_ENTRY (listen_entry) next; | |||
}; | }; | |||
struct accepted_entry { | struct accepted_entry { | |||
int32 fd[2]; /* 0->Client, 1->Server */ | int32 fd[2]; /* 0->Client, 1->Server */ | |||
u_int16 port[2]; | u_int16 port[2]; | |||
struct ip_addr ip[2]; | struct ip_addr ip[2]; | |||
SSL *ssl[2]; | SSL *ssl[2]; | |||
u_char status; | u_char status; | |||
X509 *cert; | X509 *cert; | |||
#ifdef HAVE_OPENSSL_1_1_1 | ||||
unsigned int tls_handshake_state; | ||||
#define SSL_CLIENTHELLO_INTERCEPTED 1 | ||||
char *hostname; | ||||
#endif | ||||
#define SSL_CLIENT 0 | #define SSL_CLIENT 0 | |||
#define SSL_SERVER 1 | #define SSL_SERVER 1 | |||
}; | }; | |||
/* Session identifier | /* Session identifier | |||
* It has to be of even length for session hash matching */ | * It has to be of even length for session hash matching */ | |||
struct sslw_ident { | struct sslw_ident { | |||
u_int32 magic; | u_int32 magic; | |||
#define SSLW_MAGIC 0x0501e77e | #define SSLW_MAGIC 0x0501e77e | |||
struct ip_addr L3_src; | struct ip_addr L3_src; | |||
u_int16 L4_src; | u_int16 L4_src; | |||
u_int16 L4_dst; | u_int16 L4_dst; | |||
}; | }; | |||
#define SSLW_IDENT_LEN sizeof(struct sslw_ident) | #define SSLW_IDENT_LEN sizeof(struct sslw_ident) | |||
#define SSLW_RETRY 500 | #define SSLW_RETRY 500 | |||
#define SSLW_WAIT 10 /* 10 milliseconds */ | #define SSLW_WAIT 10 /* 10 milliseconds */ | |||
#define TSLEEP (50*1000) /* 50 milliseconds */ | #define TSLEEP (50*1000) /* 50 milliseconds */ | |||
#ifdef HAVE_OPENSSL_1_1_0 | ||||
static SSL_CONF_CTX *ssl_conf_client, *ssl_conf_server; | ||||
#endif | ||||
static SSL_CTX *ssl_ctx_client, *ssl_ctx_server; | static SSL_CTX *ssl_ctx_client, *ssl_ctx_server; | |||
static EVP_PKEY *global_pk; | static EVP_PKEY *global_pk; | |||
static u_int16 number_of_services; | static u_int16 number_of_services; | |||
static struct pollfd *poll_fd = NULL; | static struct pollfd *poll_fd = NULL; | |||
static EC_THREAD_FUNC(sslw_child); | static EC_THREAD_FUNC(sslw_child); | |||
static int sslw_is_ssl(struct packet_object *po); | static int sslw_is_ssl(struct packet_object *po); | |||
static int sslw_connect_server(struct accepted_entry *ae); | static int sslw_connect_server(struct accepted_entry *ae); | |||
static int sslw_sync_conn(struct accepted_entry *ae); | static int sslw_sync_conn(struct accepted_entry *ae); | |||
static int sslw_get_peer(struct accepted_entry *ae); | static int sslw_get_peer(struct accepted_entry *ae); | |||
skipping to change at line 142 | skipping to change at line 171 | |||
static void sslw_initialize_po(struct packet_object *po, u_char *p_data); | static void sslw_initialize_po(struct packet_object *po, u_char *p_data); | |||
static int sslw_match(void *id_sess, void *id_curr); | static int sslw_match(void *id_sess, void *id_curr); | |||
static void sslw_create_session(struct ec_session **s, struct packet_object *po) ; | static void sslw_create_session(struct ec_session **s, struct packet_object *po) ; | |||
static size_t sslw_create_ident(void **i, struct packet_object *po); | static size_t sslw_create_ident(void **i, struct packet_object *po); | |||
static void sslw_hook_handled(struct packet_object *po); | static void sslw_hook_handled(struct packet_object *po); | |||
static X509 *sslw_create_selfsigned(X509 *serv_cert); | static X509 *sslw_create_selfsigned(X509 *serv_cert); | |||
static void ssl_wrap_fini(void); | static void ssl_wrap_fini(void); | |||
static int sslw_ssl_connect(SSL *ssl_sk); | static int sslw_ssl_connect(SSL *ssl_sk); | |||
static int sslw_ssl_accept(SSL *ssl_sk); | static int sslw_ssl_accept(SSL *ssl_sk); | |||
static int sslw_remove_sts(struct packet_object *po); | static int sslw_remove_sts(struct packet_object *po); | |||
#ifdef HAVE_OPENSSL_1_1_1 | ||||
static int sslw_clienthello_cb(SSL *ssl_sk, int *alert, void *arg); | ||||
static char* sslw_get_clienthello_sni(SSL *ssl); | ||||
#endif | ||||
/*******************************************/ | /*******************************************/ | |||
/* | /* | |||
* Register a new ssl wrapper | * Register a new ssl wrapper | |||
*/ | */ | |||
void sslw_dissect_add(char *name, u_int32 port, FUNC_DECODER_PTR(decoder), u_cha r status) | void sslw_dissect_add(char *name, u_int32 port, FUNC_DECODER_PTR(decoder), u_cha r status) | |||
{ | { | |||
struct listen_entry *le; | struct listen_entry *le; | |||
skipping to change at line 242 | skipping to change at line 275 | |||
close(le->fd); | close(le->fd); | |||
#ifdef WITH_IPV6 | #ifdef WITH_IPV6 | |||
close(le->fd6); | close(le->fd6); | |||
#endif | #endif | |||
LIST_REMOVE(le, next); | LIST_REMOVE(le, next); | |||
SAFE_FREE(le); | SAFE_FREE(le); | |||
} | } | |||
SSL_CTX_free(ssl_ctx_server); | SSL_CTX_free(ssl_ctx_server); | |||
SSL_CTX_free(ssl_ctx_client); | SSL_CTX_free(ssl_ctx_client); | |||
#ifdef HAVE_OPENSSL_1_1_0 | ||||
SSL_CONF_CTX_free(ssl_conf_client); | ||||
SSL_CONF_CTX_free(ssl_conf_server); | ||||
#endif | ||||
/* remove redirects */ | /* remove redirects */ | |||
ec_redirect_cleanup(); | ec_redirect_cleanup(); | |||
} | } | |||
/* | /* | |||
* SSL thread main function. | * SSL thread main function. | |||
*/ | */ | |||
EC_THREAD_FUNC(sslw_start) | EC_THREAD_FUNC(sslw_start) | |||
skipping to change at line 383 | skipping to change at line 420 | |||
(po->L4.flags & TH_SYN) && | (po->L4.flags & TH_SYN) && | |||
!(po->L4.flags & TH_ACK) ) { | !(po->L4.flags & TH_ACK) ) { | |||
sslw_create_session(&s, PACKET); | sslw_create_session(&s, PACKET); | |||
#ifndef OS_LINUX | #ifndef OS_LINUX | |||
/* Remember the real destination IP */ | /* Remember the real destination IP */ | |||
memcpy(s->data, &po->L3.dst, sizeof(struct ip_addr)); | memcpy(s->data, &po->L3.dst, sizeof(struct ip_addr)); | |||
session_put(s); | session_put(s); | |||
#else | #else | |||
SAFE_FREE(s); /* Just get rid of it */ | SAFE_FREE(s); /* Just get rid of it */ | |||
#endif | #endif | |||
} else /* Pass only the SYN for conntrack */ | } else /* Pass only the SYN for conntrack */ | |||
po->flags |= PO_IGNORE; | po->flags |= PO_IGNORE; | |||
} | } | |||
/* | /* | |||
* Check if this packet is for ssl wrappers | * Check if this packet is for ssl wrappers | |||
*/ | */ | |||
static int sslw_is_ssl(struct packet_object *po) | static int sslw_is_ssl(struct packet_object *po) | |||
{ | { | |||
struct listen_entry *le; | ||||
/* If it's already coming from ssl wrapper | /* If it's already coming from ssl wrapper | |||
* or the connection is not TCP */ | * or the connection is not TCP */ | |||
if (po->flags & PO_FROMSSL || po->L4.proto != NL_TYPE_TCP) | if (po->flags & PO_FROMSSL || po->L4.proto != NL_TYPE_TCP) | |||
return 0; | return 0; | |||
LIST_FOREACH(le, &listen_ports, next) { | /* check if packet matches one of the registered redirects */ | |||
if (ntohs(po->L4.dst) == le->sslw_port || | if (ec_redirect_lookup(po) == E_SUCCESS) | |||
ntohs(po->L4.src) == le->sslw_port) | return 1; | |||
return 1; | ||||
} | ||||
return 0; | return 0; | |||
} | } | |||
/* | /* | |||
* Bind all registered wrappers to free ports | * Bind all registered wrappers to free ports | |||
* and isnert redirects. | * and isnert redirects. | |||
*/ | */ | |||
static void sslw_bind_wrapper(void) | static void sslw_bind_wrapper(void) | |||
{ | { | |||
u_int16 bind_port = EC_MAGIC_16; | u_int16 bind_port = EC_MAGIC_16; | |||
skipping to change at line 471 | skipping to change at line 505 | |||
bind_port, strerror(errno)); | bind_port, strerror(errno)); | |||
if(listen(le->fd6, 100) == -1) | if(listen(le->fd6, 100) == -1) | |||
FATAL_ERROR("Unable to accept connections for IPv6 socket"); | FATAL_ERROR("Unable to accept connections for IPv6 socket"); | |||
#else | #else | |||
/* properly init fd even if unused - necessary for select call */ | /* properly init fd even if unused - necessary for select call */ | |||
le->fd6 = 0; | le->fd6 = 0; | |||
#endif | #endif | |||
if (ec_redirect(EC_REDIR_ACTION_INSERT, le->name, | if (ec_redirect(EC_REDIR_ACTION_INSERT, le->name, | |||
EC_REDIR_PROTO_IPV4, NULL, NULL, | EC_REDIR_PROTO_IPV4, NULL, | |||
le->sslw_port, le->redir_port) != E_SUCCESS) | le->sslw_port, le->redir_port) != E_SUCCESS) | |||
FATAL_ERROR("Can't insert firewall redirects"); | FATAL_ERROR("Can't insert firewall redirects"); | |||
#ifdef WITH_IPV6 | #ifdef WITH_IPV6 | |||
if (ec_redirect(EC_REDIR_ACTION_INSERT, le->name, | if (ec_redirect(EC_REDIR_ACTION_INSERT, le->name, | |||
EC_REDIR_PROTO_IPV6, NULL, NULL, | EC_REDIR_PROTO_IPV6, NULL, | |||
le->sslw_port, le->redir_port) != E_SUCCESS) | le->sslw_port, le->redir_port) != E_SUCCESS) | |||
FATAL_ERROR("Can't insert firewall redirects"); | FATAL_ERROR("Can't insert firewall redirects"); | |||
#endif | #endif | |||
} | } | |||
} | } | |||
/* | /* | |||
* Create TCP a connection to the real SSL server | * Create TCP a connection to the real SSL server | |||
*/ | */ | |||
skipping to change at line 531 | skipping to change at line 565 | |||
return -E_INVALID; | return -E_INVALID; | |||
/* sleep a quirk of time... */ | /* sleep a quirk of time... */ | |||
ec_usleep(TSLEEP); | ec_usleep(TSLEEP); | |||
} while(loops--); | } while(loops--); | |||
return -E_INVALID; | return -E_INVALID; | |||
} | } | |||
/* | /* | |||
* ClientHello Callback to intercept SSL handshake after ClientHello | ||||
*/ | ||||
#ifdef HAVE_OPENSSL_1_1_1 | ||||
static int sslw_clienthello_cb(SSL *ssl, int *alert, void *arg) | ||||
{ | ||||
(void) alert; | ||||
struct accepted_entry *ae; | ||||
ae = (struct accepted_entry *)arg; | ||||
/* extract hostname value from SNI extension */ | ||||
ae->hostname = sslw_get_clienthello_sni(ssl); | ||||
if (ae->tls_handshake_state != SSL_CLIENTHELLO_INTERCEPTED) { | ||||
ae->tls_handshake_state = SSL_CLIENTHELLO_INTERCEPTED; | ||||
/* suspend client side TLS handshake */ | ||||
return SSL_CLIENT_HELLO_RETRY; | ||||
} | ||||
return SSL_CLIENT_HELLO_SUCCESS; | ||||
} | ||||
static char* sslw_get_clienthello_sni(SSL *ssl) | ||||
{ | ||||
const unsigned char* sni; | ||||
size_t len; | ||||
uint8_t sni_type; | ||||
uint16_t val_len; | ||||
// uint16_t sni_len; | ||||
if (SSL_client_hello_get0_ext(ssl, TLSEXT_TYPE_server_name, &sni, &len)) { | ||||
if (len > 5) { | ||||
// sni_len = sni[0] << 8 | sni[1]; | ||||
sni_type = sni[2]; | ||||
val_len = sni[3] << 8 | sni[4]; | ||||
if (sni_type == TLSEXT_NAMETYPE_host_name) | ||||
return strndup(sni+5, val_len); | ||||
} | ||||
} | ||||
return NULL; | ||||
} | ||||
#endif | ||||
/* | ||||
* Perform a blocking SSL_accept with a | * Perform a blocking SSL_accept with a | |||
* configurable timeout on a non-blocing socket | * configurable timeout on a non-blocing socket | |||
*/ | */ | |||
static int sslw_ssl_accept(SSL *ssl_sk) | static int sslw_ssl_accept(SSL *ssl_sk) | |||
{ | { | |||
int loops = (EC_GBL_CONF->connect_timeout * 10e5) / TSLEEP; | int loops = (EC_GBL_CONF->connect_timeout * 10e5) / TSLEEP; | |||
int ret, ssl_err; | int ret, ssl_err; | |||
do { | do { | |||
/* accept the ssl connection */ | /* accept the ssl connection */ | |||
if ( (ret = SSL_accept(ssl_sk)) == 1) | if ( (ret = SSL_accept(ssl_sk)) == 1) | |||
return E_SUCCESS; | return E_SUCCESS; | |||
ssl_err = SSL_get_error(ssl_sk, ret); | ssl_err = SSL_get_error(ssl_sk, ret); | |||
/* there was an error... */ | #ifdef HAVE_OPENSSL_1_1_1 | |||
if (ssl_err != SSL_ERROR_WANT_READ && ssl_err != SSL_ERROR_WANT_WRITE) | /* return successfully if handshake has been suspended by callback */ | |||
if (ssl_err == SSL_ERROR_WANT_CLIENT_HELLO_CB) | ||||
return E_SUCCESS; | ||||
#endif | ||||
/* there was an error... but only if it's not just pending further progre | ||||
ss */ | ||||
if (ssl_err != SSL_ERROR_WANT_READ && ssl_err != SSL_ERROR_WANT_WRITE) { | ||||
#ifdef DEBUG | ||||
char error_msg[256], *error; | ||||
error = ERR_error_string(ERR_get_error(), error_msg); | ||||
DEBUG_MSG("sslw_ssl_accept(): SSL_accept() failed with '%s'", error); | ||||
#endif | ||||
return -E_INVALID; | return -E_INVALID; | |||
} | ||||
/* sleep a quirk of time... */ | /* sleep a quirk of time... */ | |||
ec_usleep(TSLEEP); | ec_usleep(TSLEEP); | |||
} while(loops--); | } while(loops--); | |||
return -E_INVALID; | return -E_INVALID; | |||
} | } | |||
/* | /* | |||
* Create an SSL connection to the real server. | * Create an SSL connection to the real server. | |||
* Grab server certificate and create a fake one | * Grab server certificate and create a fake one | |||
* for the poor client. | * for the poor client. | |||
* Then accept the SSL connection from the client. | * Then accept the SSL connection from the client. | |||
*/ | */ | |||
static int sslw_sync_ssl(struct accepted_entry *ae) | static int sslw_sync_ssl(struct accepted_entry *ae) | |||
{ | { | |||
X509 *server_cert; | X509 *server_cert; | |||
#ifdef HAVE_OPENSSL_1_1_1 | ||||
/* Set a Callback for the SSL client context to pause the Client Handshake */ | ||||
SSL_CTX_set_client_hello_cb(ssl_ctx_client, sslw_clienthello_cb, (void*)ae); | ||||
#endif | ||||
ae->ssl[SSL_SERVER] = SSL_new(ssl_ctx_server); | ae->ssl[SSL_SERVER] = SSL_new(ssl_ctx_server); | |||
SSL_set_connect_state(ae->ssl[SSL_SERVER]); | SSL_set_connect_state(ae->ssl[SSL_SERVER]); | |||
SSL_set_fd(ae->ssl[SSL_SERVER], ae->fd[SSL_SERVER]); | SSL_set_fd(ae->ssl[SSL_SERVER], ae->fd[SSL_SERVER]); | |||
ae->ssl[SSL_CLIENT] = SSL_new(ssl_ctx_client); | ae->ssl[SSL_CLIENT] = SSL_new(ssl_ctx_client); | |||
SSL_set_fd(ae->ssl[SSL_CLIENT], ae->fd[SSL_CLIENT]); | SSL_set_fd(ae->ssl[SSL_CLIENT], ae->fd[SSL_CLIENT]); | |||
#ifdef HAVE_OPENSSL_1_1_1 | ||||
/* Begin SSL handshake to extract SNI - then suspend by callback */ | ||||
if (sslw_ssl_accept(ae->ssl[SSL_CLIENT]) != E_SUCCESS) | ||||
return -E_INVALID; | ||||
if (ae->hostname) | ||||
/* set SNI for server-side connection */ | ||||
SSL_set_tlsext_host_name(ae->ssl[SSL_SERVER], ae->hostname); | ||||
#endif | ||||
/* Connect to actual SSL server */ | ||||
if (sslw_ssl_connect(ae->ssl[SSL_SERVER]) != E_SUCCESS) | if (sslw_ssl_connect(ae->ssl[SSL_SERVER]) != E_SUCCESS) | |||
return -E_INVALID; | return -E_INVALID; | |||
/* Extract certificate from actual SSL server */ | ||||
/* XXX - NULL cypher can give no certificate */ | /* XXX - NULL cypher can give no certificate */ | |||
if ( (server_cert = SSL_get_peer_certificate(ae->ssl[SSL_SERVER])) == NULL) { | if ( (server_cert = SSL_get_peer_certificate(ae->ssl[SSL_SERVER])) == NULL) { | |||
DEBUG_MSG("Can't get peer certificate"); | DEBUG_MSG("Can't get peer certificate"); | |||
return -E_INVALID; | return -E_INVALID; | |||
} | } | |||
if (!EC_GBL_OPTIONS->ssl_cert) { | if (!EC_GBL_OPTIONS->ssl_cert) { | |||
/* Create the fake certificate */ | /* Create the fake certificate based on actual certificate */ | |||
ae->cert = sslw_create_selfsigned(server_cert); | ae->cert = sslw_create_selfsigned(server_cert); | |||
X509_free(server_cert); | X509_free(server_cert); | |||
if (ae->cert == NULL) | if (ae->cert == NULL) | |||
return -E_INVALID; | return -E_INVALID; | |||
SSL_use_certificate(ae->ssl[SSL_CLIENT], ae->cert); | /* use faked certificate for further SSL client connection */ | |||
SSL_use_certificate(ae->ssl[SSL_CLIENT], ae->cert); | ||||
} | } | |||
/* continue SSL handshake with SSL client */ | ||||
if (sslw_ssl_accept(ae->ssl[SSL_CLIENT]) != E_SUCCESS) | if (sslw_ssl_accept(ae->ssl[SSL_CLIENT]) != E_SUCCESS) | |||
return -E_INVALID; | return -E_INVALID; | |||
#ifdef HAVE_OPENSSL_1_1_1 | ||||
/* TLS handshake done - SNI hostname not longer required: free */ | ||||
SAFE_FREE(ae->hostname); | ||||
#endif | ||||
return E_SUCCESS; | return E_SUCCESS; | |||
} | } | |||
/* | /* | |||
* Take the IP address of the server | * Take the IP address of the server | |||
* that the client wants to talk to. | * that the client wants to talk to. | |||
*/ | */ | |||
static int sslw_get_peer(struct accepted_entry *ae) | static int sslw_get_peer(struct accepted_entry *ae) | |||
{ | { | |||
skipping to change at line 897 | skipping to change at line 1014 | |||
/* | /* | |||
* Allocate the data buffer and initialize | * Allocate the data buffer and initialize | |||
* fake headers. Headers len is set to 0. | * fake headers. Headers len is set to 0. | |||
* XXX - Be sure to not modify these len. | * XXX - Be sure to not modify these len. | |||
*/ | */ | |||
memset(po, 0, sizeof(struct packet_object)); | memset(po, 0, sizeof(struct packet_object)); | |||
if (p_data == NULL) { | if (p_data == NULL) { | |||
SAFE_CALLOC(po->DATA.data, 1, UINT16_MAX); | SAFE_CALLOC(po->DATA.data, 1, UINT16_MAX); | |||
} else { | } else { | |||
if (po->DATA.data != p_data) { | if (po->DATA.data != p_data) { | |||
SAFE_FREE(po->DATA.data); | SAFE_FREE(po->DATA.data); | |||
po->DATA.data = p_data; | po->DATA.data = p_data; | |||
} | } | |||
} | } | |||
po->L2.header = po->DATA.data; | po->L2.header = po->DATA.data; | |||
po->L3.header = po->DATA.data; | po->L3.header = po->DATA.data; | |||
po->L3.options = po->DATA.data; | po->L3.options = po->DATA.data; | |||
po->L4.header = po->DATA.data; | po->L4.header = po->DATA.data; | |||
po->L4.options = po->DATA.data; | po->L4.options = po->DATA.data; | |||
po->fwd_packet = po->DATA.data; | po->fwd_packet = po->DATA.data; | |||
po->packet = po->DATA.data; | po->packet = po->DATA.data; | |||
skipping to change at line 922 | skipping to change at line 1039 | |||
po->L4.proto = NL_TYPE_TCP; | po->L4.proto = NL_TYPE_TCP; | |||
} | } | |||
/* | /* | |||
* Create a self-signed certificate | * Create a self-signed certificate | |||
*/ | */ | |||
static X509 *sslw_create_selfsigned(X509 *server_cert) | static X509 *sslw_create_selfsigned(X509 *server_cert) | |||
{ | { | |||
X509 *out_cert; | X509 *out_cert; | |||
X509_EXTENSION *ext; | X509_EXTENSION *ext; | |||
const EVP_MD *md; | ||||
int index = 0; | int index = 0; | |||
if ((out_cert = X509_new()) == NULL) | if ((out_cert = X509_new()) == NULL) | |||
return NULL; | return NULL; | |||
/* Set out public key, real server name... */ | /* Set out public key, real server name... */ | |||
X509_set_version(out_cert, X509_get_version(server_cert)); | X509_set_version(out_cert, X509_get_version(server_cert)); | |||
ASN1_INTEGER_set(X509_get_serialNumber(out_cert), EC_MAGIC_32); | ASN1_INTEGER_set(X509_get_serialNumber(out_cert), EC_MAGIC_32); | |||
X509_set_notBefore(out_cert, X509_get_notBefore(server_cert)); | X509_set_notBefore(out_cert, X509_get_notBefore(server_cert)); | |||
X509_set_notAfter(out_cert, X509_get_notAfter(server_cert)); | X509_set_notAfter(out_cert, X509_get_notAfter(server_cert)); | |||
skipping to change at line 959 | skipping to change at line 1077 | |||
os->data[8] = 0x7e; | os->data[8] = 0x7e; | |||
X509_EXTENSION_set_data (ext, os); | X509_EXTENSION_set_data (ext, os); | |||
#else | #else | |||
ext->value->data[7] = 0xe7; | ext->value->data[7] = 0xe7; | |||
ext->value->data[8] = 0x7e; | ext->value->data[8] = 0x7e; | |||
#endif | #endif | |||
X509_add_ext(out_cert, ext, -1); | X509_add_ext(out_cert, ext, -1); | |||
} | } | |||
} | } | |||
/* take over SAN extension from peer certificate */ | ||||
index = X509_get_ext_by_NID(server_cert, NID_subject_alt_name, index); | ||||
if (index >= 0) { | ||||
X509_add_ext(out_cert, X509_get_ext(server_cert, index), -1); | ||||
} | ||||
/* grab digest algorithm from peer certificate */ | ||||
md = EVP_get_digestbynid(X509_get_signature_nid(server_cert)); | ||||
if (md == NULL) { | ||||
DEBUG_MSG("Error determining message digest algorithm for signing."); | ||||
/* Falling back to SHA256 signing algorithm which is the default in TLS1.3 | ||||
*/ | ||||
md = EVP_sha256(); | ||||
} | ||||
/* Self-sign our certificate */ | /* Self-sign our certificate */ | |||
if (!X509_sign(out_cert, global_pk, EVP_sha1())) { | if (!X509_sign(out_cert, global_pk, md)) { | |||
X509_free(out_cert); | X509_free(out_cert); | |||
DEBUG_MSG("Error self-signing X509"); | DEBUG_MSG("Error self-signing X509"); | |||
return NULL; | return NULL; | |||
} | } | |||
return out_cert; | return out_cert; | |||
} | } | |||
/* | /* | |||
* Initialize SSL stuff | * Initialize SSL stuff | |||
*/ | */ | |||
static void sslw_init(void) | static void sslw_init(void) | |||
{ | { | |||
SSL *dummy_ssl=NULL; | SSL *dummy_ssl=NULL; | |||
#ifndef HAVE_OPENSSL_1_1_0 | ||||
SSL_library_init(); | SSL_library_init(); | |||
#endif | ||||
/* Create the two global CTX */ | /* Create the two global CTX */ | |||
ssl_ctx_client = SSL_CTX_new(SSLv23_server_method()); | ssl_ctx_client = SSL_CTX_new(TLS_server_method()); | |||
ssl_ctx_server = SSL_CTX_new(SSLv23_client_method()); | ssl_ctx_server = SSL_CTX_new(TLS_client_method()); | |||
ON_ERROR(ssl_ctx_client, NULL, "Could not create client SSL CTX"); | ON_ERROR(ssl_ctx_client, NULL, "Could not create client SSL CTX"); | |||
ON_ERROR(ssl_ctx_server, NULL, "Could not create server SSL CTX"); | ON_ERROR(ssl_ctx_server, NULL, "Could not create server SSL CTX"); | |||
#ifdef HAVE_OPENSSL_1_0_2 | ||||
SSL_CTX_set_ecdh_auto(ssl_ctx_client, 1); | ||||
SSL_CTX_set_ecdh_auto(ssl_ctx_server, 1); | ||||
#endif | ||||
#ifdef HAVE_OPENSSL_1_1_0 | ||||
ssl_conf_client = SSL_CONF_CTX_new(); | ||||
ssl_conf_server = SSL_CONF_CTX_new(); | ||||
SSL_CONF_CTX_set_flags(ssl_conf_client, SSL_CONF_FLAG_FILE); | ||||
SSL_CONF_CTX_set_flags(ssl_conf_server, SSL_CONF_FLAG_FILE); | ||||
SSL_CONF_CTX_set_ssl_ctx(ssl_conf_client, ssl_ctx_client); | ||||
SSL_CONF_CTX_set_ssl_ctx(ssl_conf_server, ssl_ctx_server); | ||||
/* Backward compatibility for older TLS versions and ciphers */ | ||||
SSL_CONF_cmd(ssl_conf_client, "MinProtocol", "TLSv1"); | ||||
SSL_CONF_cmd(ssl_conf_server, "MinProtocol", "TLSv1"); | ||||
SSL_CONF_cmd(ssl_conf_client, "CipherString", "DEFAULT"); | ||||
SSL_CONF_cmd(ssl_conf_server, "CipherString", "DEFAULT"); | ||||
#endif | ||||
if(EC_GBL_OPTIONS->ssl_pkey) { | if(EC_GBL_OPTIONS->ssl_pkey) { | |||
/* Get our private key from the file specified from cmd-line */ | /* Get our private key from the file specified from cmd-line */ | |||
DEBUG_MSG("Using custom private key %s", EC_GBL_OPTIONS->ssl_pkey); | DEBUG_MSG("Using custom private key %s", EC_GBL_OPTIONS->ssl_pkey); | |||
if (SSL_CTX_use_PrivateKey_file(ssl_ctx_client, EC_GBL_OPTIONS->ssl_pkey, | if (SSL_CTX_use_PrivateKey_file(ssl_ctx_client, | |||
SSL_FILETYPE_PEM) == 0) { | EC_GBL_OPTIONS->ssl_pkey, SSL_FILETYPE_PEM) == 0) { | |||
FATAL_ERROR("Can't open \"%s\" file : %s", EC_GBL_OPTIONS->ssl_pk | FATAL_ERROR("Can't open \"%s\" file : %s", | |||
ey, strerror(errno)); | EC_GBL_OPTIONS->ssl_pkey, strerror(errno)); | |||
} | } | |||
if (EC_GBL_OPTIONS->ssl_cert) { | if (EC_GBL_OPTIONS->ssl_cert) { | |||
if (SSL_CTX_use_certificate_file(ssl_ctx_client, EC_GBL_OPTIONS-> | if (SSL_CTX_use_certificate_file(ssl_ctx_client, | |||
ssl_cert, SSL_FILETYPE_PEM) == 0) { | EC_GBL_OPTIONS->ssl_cert, SSL_FILETYPE_PEM) == 0) { | |||
FATAL_ERROR("Can't open \"%s\" file : %s", EC_GBL_OPTIONS | FATAL_ERROR("Can't open \"%s\" file : %s", | |||
->ssl_cert, strerror(errno)); | EC_GBL_OPTIONS->ssl_cert, strerror(errno)); | |||
} | } | |||
if (!SSL_CTX_check_private_key(ssl_ctx_client)) { | if (!SSL_CTX_check_private_key(ssl_ctx_client)) { | |||
FATAL_ERROR("Certificate \"%s\" does not match private ke | FATAL_ERROR("Certificate \"%s\" does not match private key \"%s\"", | |||
y \"%s\"", EC_GBL_OPTIONS->ssl_cert, EC_GBL_OPTIONS->ssl_pkey); | EC_GBL_OPTIONS->ssl_cert, EC_GBL_OPTIONS->ssl_pkey); | |||
} | } | |||
} | } | |||
} else { | } else { | |||
/* Get our private key from our cert file */ | /* Get our private key from our cert file */ | |||
if (SSL_CTX_use_PrivateKey_file(ssl_ctx_client, INSTALL_DATADIR "/" PROGR | if (SSL_CTX_use_PrivateKey_file(ssl_ctx_client, | |||
AM "/" CERT_FILE, SSL_FILETYPE_PEM) == 0) { | INSTALL_DATADIR"/"PROGRAM"/"CERT_FILE, SSL_FILETYPE_PEM) == 0) { | |||
DEBUG_MSG("sslw -- SSL_CTX_use_PrivateKey_file -- trying ./share/ | DEBUG_MSG("sslw -- SSL_CTX_use_PrivateKey_file -- trying ./share/%s" | |||
%s", CERT_FILE); | , | |||
CERT_FILE); | ||||
if (SSL_CTX_use_PrivateKey_file(ssl_ctx_client, "./share/" CERT_F | ||||
ILE, SSL_FILETYPE_PEM) == 0) | if (SSL_CTX_use_PrivateKey_file(ssl_ctx_client, | |||
FATAL_ERROR("Can't open \"./share/%s\" file : %s", CERT_F | "./share/" CERT_FILE, SSL_FILETYPE_PEM) == 0) | |||
ILE, strerror(errno)); | FATAL_ERROR("Can't open \"./share/%s\" file : %s", | |||
} | CERT_FILE, strerror(errno)); | |||
} | ||||
} | } | |||
dummy_ssl = SSL_new(ssl_ctx_client); | dummy_ssl = SSL_new(ssl_ctx_client); | |||
if ( (global_pk = SSL_get_privatekey(dummy_ssl)) == NULL ) | if ( (global_pk = SSL_get_privatekey(dummy_ssl)) == NULL ) | |||
FATAL_ERROR("Can't get private key from file"); | FATAL_ERROR("Can't get private key from file"); | |||
SSL_free(dummy_ssl); | SSL_free(dummy_ssl); | |||
} | } | |||
/* | /* | |||
skipping to change at line 1099 | skipping to change at line 1263 | |||
/* Should we poll both fd's instead of guessing and sleeping? */ | /* Should we poll both fd's instead of guessing and sleeping? */ | |||
if (!data_read) | if (!data_read) | |||
ec_usleep(3000); // 3ms | ec_usleep(3000); // 3ms | |||
} | } | |||
return NULL; | return NULL; | |||
} | } | |||
static int sslw_remove_sts(struct packet_object *po) | static int sslw_remove_sts(struct packet_object *po) | |||
{ | { | |||
u_char *ptr; | u_char *ptr; | |||
u_char *end; | u_char *end; | |||
u_char *h_end; | u_char *h_end; | |||
size_t len = po->DATA.len; | size_t len = po->DATA.len; | |||
size_t slen = strlen("\r\nStrict-Transport-Security:"); | size_t slen = strlen("\r\nStrict-Transport-Security:"); | |||
if (!memmem(po->DATA.data, po->DATA.len, "\r\nStrict-Transport-Security:" | if (!memmem(po->DATA.data, po->DATA.len, "\r\nStrict-Transport-Security:", sl | |||
, slen)) { | en)) { | |||
return -E_NOTFOUND; | return -E_NOTFOUND; | |||
} | } | |||
ptr = po->DATA.data; | ptr = po->DATA.data; | |||
end = ptr + po->DATA.len; | end = ptr + po->DATA.len; | |||
len = end - ptr; | len = end - ptr; | |||
ptr = (u_char*)memmem(ptr, len, "\r\nStrict-Transport-Security:", slen); | ptr = (u_char*)memmem(ptr, len, "\r\nStrict-Transport-Security:", slen); | |||
ptr += 2; | ptr += 2; | |||
h_end = (u_char*)memmem(ptr, len, "\r\n", 2); | h_end = (u_char*)memmem(ptr, len, "\r\n", 2); | |||
h_end += 2; | h_end += 2; | |||
size_t before_header = ptr - po->DATA.data; | size_t before_header = ptr - po->DATA.data; | |||
size_t header_length = h_end - ptr; | size_t header_length = h_end - ptr; | |||
size_t new_len = 0; | size_t new_len = 0; | |||
u_char *new_html; | u_char *new_html; | |||
SAFE_CALLOC(new_html, len, sizeof(u_char)); | SAFE_CALLOC(new_html, len, sizeof(u_char)); | |||
BUG_IF(new_html == NULL); | BUG_IF(new_html == NULL); | |||
memcpy(new_html, po->DATA.data, before_header); | memcpy(new_html, po->DATA.data, before_header); | |||
new_len += before_header; | new_len += before_header; | |||
memcpy(new_html+new_len, h_end, (len - header_length) - before_header); | memcpy(new_html+new_len, h_end, (len - header_length) - before_header); | |||
new_len += (len - header_length) - before_header; | new_len += (len - header_length) - before_header; | |||
memset(po->DATA.data, '\0', po->DATA.len); | memset(po->DATA.data, '\0', po->DATA.len); | |||
memcpy(po->DATA.data, new_html, new_len); | memcpy(po->DATA.data, new_html, new_len); | |||
po->DATA.len = new_len; | po->DATA.len = new_len; | |||
po->flags |= PO_MODIFIED; | po->flags |= PO_MODIFIED; | |||
return E_SUCCESS; | return E_SUCCESS; | |||
} | } | |||
/*******************************************/ | /*******************************************/ | |||
/* Sessions' stuff for ssl packets */ | /* Sessions' stuff for ssl packets */ | |||
static size_t sslw_create_ident(void **i, struct packet_object *po) | static size_t sslw_create_ident(void **i, struct packet_object *po) | |||
{ | { | |||
struct sslw_ident *ident; | struct sslw_ident *ident; | |||
End of changes. 47 change blocks. | ||||
85 lines changed or deleted | 243 lines changed or added |