Beispiel #1
0
/** finish the ssl init.
 * Creates the SSL context + internal tls_extra_data and sets
 * extra_data to it.
 * Separated from tls_tcpconn_init to allow delayed ssl context
 * init (from the "child" process and not from the main one).
 * WARNING: the connection should be already locked.
 * @return 0 on success, -1 on errror.
 */
static int tls_complete_init(struct tcp_connection* c)
{
	tls_domain_t* dom;
	struct tls_extra_data* data = 0;
	tls_domains_cfg_t* cfg;
	enum tls_conn_states state;
	str *sname = NULL;
	str *srvid = NULL;

	if (LOW_MEM_NEW_CONNECTION_TEST()){
		ERR("tls: ssl bug #1491 workaround: not enough memory for safe"
				" operation: shm=%lu threshold1=%d\n", shm_available_safe(),
				cfg_get(tls, tls_cfg, low_mem_threshold1));
		goto error2;
	}
	     /* Get current TLS configuration and increase reference
	      * count immediately.
	      */

	LM_DBG("completing tls connection initialization\n");

	lock_get(tls_domains_cfg_lock);
	cfg = *tls_domains_cfg;

	     /* Increment the reference count in the configuration structure, this
	      * is to ensure that, while on the garbage queue, the configuration does
	      * not get deleted if there are still connection referencing its SSL_CTX
	      */
	atomic_inc(&cfg->ref_count);
	lock_release(tls_domains_cfg_lock);

	if (c->flags & F_CONN_PASSIVE) {
		state=S_TLS_ACCEPTING;
		dom = tls_lookup_cfg(cfg, TLS_DOMAIN_SRV,
								&c->rcv.dst_ip, c->rcv.dst_port, 0, 0);
	} else {
		state=S_TLS_CONNECTING;
		sname = tls_get_connect_server_name();
		srvid = tls_get_connect_server_id();
		dom = tls_lookup_cfg(cfg, TLS_DOMAIN_CLI,
						&c->rcv.dst_ip, c->rcv.dst_port, sname, srvid);
	}
	if (unlikely(c->state<0)) {
		BUG("Invalid connection (state %d)\n", c->state);
		goto error;
	}
	DBG("Using initial TLS domain %s (dom %p ctx %p sn [%s])\n",
			tls_domain_str(dom), dom, dom->ctx[process_no],
			ZSW(dom->server_name.s));

	data = (struct tls_extra_data*)shm_malloc(sizeof(struct tls_extra_data));
	if (!data) {
		ERR("Not enough shared memory left\n");
		goto error;
	}
	memset(data, '\0', sizeof(struct tls_extra_data));
	data->ssl = SSL_new(dom->ctx[process_no]);
	data->rwbio = tls_BIO_new_mbuf(0, 0);
	data->cfg = cfg;
	data->state = state;

	if (unlikely(data->ssl == 0 || data->rwbio == 0)) {
		TLS_ERR("Failed to create SSL or BIO structure:");
		if (data->ssl)
			SSL_free(data->ssl);
		if (data->rwbio)
			BIO_free(data->rwbio);
		goto error;
	}

#ifndef OPENSSL_NO_TLSEXT
	if (sname!=NULL) {
		if(!SSL_set_tlsext_host_name(data->ssl, sname->s)) {
			if (data->ssl)
				SSL_free(data->ssl);
			if (data->rwbio)
				BIO_free(data->rwbio);
			goto error;
		}
		LM_DBG("outbound TLS server name set to: %s\n", sname->s);
	}
#endif

#if OPENSSL_VERSION_NUMBER < 0x010100000L
#ifdef TLS_KSSL_WORKARROUND
	 /* if needed apply workaround for openssl bug #1467 */
	if (data->ssl->kssl_ctx && openssl_kssl_malloc_bug){
		kssl_ctx_free(data->ssl->kssl_ctx);
		data->ssl->kssl_ctx=0;
	}
#endif
#endif
	SSL_set_bio(data->ssl, data->rwbio, data->rwbio);
	c->extra_data = data;

	/* link the extra data struct inside ssl connection*/
	SSL_set_app_data(data->ssl, data);
	return 0;

 error:
	atomic_dec(&cfg->ref_count);
	if (data) shm_free(data);
 error2:
	return -1;
}
Beispiel #2
0
/*
 * Called when new tcp connection is accepted or connected, create ssl
 * data structures here, there is no need to acquire any lock, because the
 * connection is being created by a new process and on other process has
 * access to it yet, this is called before adding the tcp_connection
 * structure into the hash
 */
int
tls_tcpconn_init(struct tcp_connection *c, int sock)
{
	struct tls_domain *dom;

	struct usr_avp *avp;
	int_str val;

	/*
	* new connection within a single process, no lock necessary
	*/
	LM_DBG("entered: Creating a whole new ssl connection\n");

	/*
	* do everything tcpconn_new wouldn't do when TLS
	*/
	c->type = PROTO_TLS;
	c->rcv.proto = PROTO_TLS;
	c->flags = 0;
	c->timeout = get_ticks() + DEFAULT_TCP_CONNECTION_LIFETIME;

	if (c->state == S_CONN_ACCEPT) {
		LM_DBG("looking up socket based TLS server "
			"domain [%s:%d]\n", ip_addr2a(&c->rcv.dst_ip), c->rcv.dst_port);
		dom = tls_find_server_domain(&c->rcv.dst_ip, c->rcv.dst_port);
		if (dom) {
			LM_DBG("found socket based TLS server domain "
				"[%s:%d]\n", ip_addr2a(&dom->addr), dom->port);
				c->extra_data = SSL_new(dom->ctx);
		} else {
			LM_ERR("no TLS server domain found\n");
			return -1;
		}
	} else if (c->state == S_CONN_CONNECT) {
		avp = NULL;
		if (tls_client_domain_avp > 0) {
			avp = search_first_avp(0, tls_client_domain_avp, &val, 0);
		} else {
			LM_DBG("name based TLS client domains are disabled\n");
		}
		if (!avp) {
			LM_DBG("no TLS client doman AVP set, looking "
				"for socket based TLS client domain\n");
			dom = tls_find_client_domain(&c->rcv.src_ip, c->rcv.src_port);
			if (dom) {
				LM_DBG("found socket based TLS client domain "
					"[%s:%d]\n", ip_addr2a(&dom->addr), dom->port);
					c->extra_data = SSL_new(dom->ctx);
			} else {
				LM_ERR("no TLS client domain found\n");
				return -1;
			}
		} else {
			LM_DBG("TLS client domain AVP found = '%.*s'\n",
				val.s.len, ZSW(val.s.s));
			dom = tls_find_client_domain_name(val.s);
			if (dom) {
				LM_DBG("found name based TLS client domain "
					"'%.*s'\n", val.s.len, ZSW(val.s.s));
				c->extra_data = SSL_new(dom->ctx);
			} else {
				LM_DBG("no name based TLS client domain found, "
					"trying socket based TLS client domains\n");
				dom = tls_find_client_domain(&c->rcv.src_ip, c->rcv.src_port);
				if (dom) {
					LM_DBG("found socket based TLS client domain [%s:%d]\n",
					ip_addr2a(&dom->addr), dom->port);
					c->extra_data = SSL_new(dom->ctx);
				} else {
					LM_ERR("no TLS client domain found\n");
					return -1;
				}
			}
		}
	} else {
		LM_ERR("invalid connection state (bug in TCP code)\n");
		return -1;
	}
	if (!c->extra_data) {
		LM_ERR("failed to create SSL structure\n");
		return -1;
	}

#ifndef OPENSSL_NO_KRB5
	if ( ((SSL *)c->extra_data)->kssl_ctx ) {
		kssl_ctx_free( ((SSL *)c->extra_data)->kssl_ctx );
		((SSL *)c->extra_data)->kssl_ctx = 0;
	}
#endif

	if (c->state == S_CONN_ACCEPT) {
		LM_DBG("Setting in ACCEPT mode (server)\n");
		SSL_set_accept_state((SSL *) c->extra_data);
	} else if (c->state == S_CONN_CONNECT) {
		LM_DBG("Setting in CONNECT mode (client)\n");
		SSL_set_connect_state((SSL *) c->extra_data);
	}
	return 0;
}
Beispiel #3
0
/*
 * Wrapper around SSL_accept, returns -1 on error, 0 on success
 */
static int tls_accept(struct tcp_connection *c, short *poll_events)
{
	int ret, err;
	SSL *ssl;
	X509* cert;

	if ( (c->proto_flags&F_TLS_DO_ACCEPT)==0 ) {
		LM_BUG("invalid connection state (bug in TLS code)\n");
		return -1;
	}

	ssl = (SSL *) c->extra_data;
#ifndef OPENSSL_NO_KRB5
	if ( ssl->kssl_ctx==NULL )
		ssl->kssl_ctx = kssl_ctx_new( );
#endif
	ret = SSL_accept(ssl);
#ifndef OPENSSL_NO_KRB5
	if ( ssl->kssl_ctx ) {
		kssl_ctx_free( ssl->kssl_ctx );
		ssl->kssl_ctx = 0;
	}
#endif
	if (ret > 0) {
		LM_INFO("New TLS connection from %s:%d accepted\n",
			ip_addr2a(&c->rcv.src_ip), c->rcv.src_port);
		/* TLS accept done, reset the flag */
		c->proto_flags &= ~F_TLS_DO_ACCEPT;

		LM_DBG("new TLS connection from %s:%d using %s %s %d\n",
			ip_addr2a(&c->rcv.src_ip), c->rcv.src_port,
			SSL_get_cipher_version(ssl), SSL_get_cipher_name(ssl),
			SSL_get_cipher_bits(ssl, 0) );
		LM_DBG("local socket: %s:%d\n",
			ip_addr2a(&c->rcv.dst_ip), c->rcv.dst_port );
		cert = SSL_get_peer_certificate(ssl);
		if (cert != 0) {
			tls_dump_cert_info("tls_accept: client TLS certificate", cert);
			if (SSL_get_verify_result(ssl) != X509_V_OK) {
				LM_WARN("TLS client certificate verification failed\n");
				tls_dump_verification_failure(SSL_get_verify_result(ssl));
			}
			X509_free(cert);
		} else {
			LM_INFO("Client did not present a TLS certificate\n");
		}
		cert = SSL_get_certificate(ssl);
		if (cert != 0) {
			tls_dump_cert_info("tls_accept: local TLS server certificate",
				cert);
		} else {
			/* this should not happen, servers always present a cert */
			LM_ERR("local TLS server domain has no certificate\n");
		}
		return 0;
	} else {
		err = SSL_get_error(ssl, ret);
		switch (err) {
			case SSL_ERROR_ZERO_RETURN:
				LM_INFO("TLS connection from %s:%d accept failed cleanly\n",
					ip_addr2a(&c->rcv.src_ip), c->rcv.src_port);
				c->state = S_CONN_BAD;
				return -1;
			case SSL_ERROR_WANT_READ:
				if (poll_events)
					*poll_events = POLLIN;
				return 0;
			case SSL_ERROR_WANT_WRITE:
				if (poll_events)
					*poll_events = POLLOUT;
				return 0;
			default:
				c->state = S_CONN_BAD;
				if (errno == 0) {
					LM_ERR("New TLS connection from %s:%d failed to accept:"
						" rejected by client\n",
						ip_addr2a(&c->rcv.src_ip), c->rcv.src_port);
				} else {
					LM_ERR("New TLS connection from %s:%d failed to accept\n",
						ip_addr2a(&c->rcv.src_ip), c->rcv.src_port);
					LM_ERR("TLS error: (ret=%d, err=%d, errno=%d/%s):\n",
						ret, err, errno, strerror(errno));
					tls_print_errstack();
				}
				return -1;
		}
	}

	LM_BUG("bug\n");
	return -1;
}
Beispiel #4
0
static int tls_conn_init(struct tcp_connection* c)
{
	struct tls_domain *dom;

	struct usr_avp *avp;
	int_str val;

	/*
	* new connection within a single process, no lock necessary
	*/
	LM_DBG("entered: Creating a whole new ssl connection\n");

	if ( c->flags&F_CONN_ACCEPTED ) {
		/* connection created as a result of an accept -> server */
		c->proto_flags = F_TLS_DO_ACCEPT;
		LM_DBG("looking up socket based TLS server "
			"domain [%s:%d]\n", ip_addr2a(&c->rcv.dst_ip), c->rcv.dst_port);
		dom = tls_find_server_domain(&c->rcv.dst_ip, c->rcv.dst_port);
		if (dom) {
			LM_DBG("found socket based TLS server domain "
				"[%s:%d]\n", ip_addr2a(&dom->addr), dom->port);
				c->extra_data = SSL_new(dom->ctx);
		} else {
			LM_ERR("no TLS server domain found\n");
			return -1;
		}
	} else {
		/* connection created as a result of a connect -> client */
		avp = NULL;
		c->proto_flags = F_TLS_DO_CONNECT;
		if (tls_client_domain_avp > 0) {
			avp = search_first_avp(0, tls_client_domain_avp, &val, 0);
		} else {
			LM_DBG("name based TLS client domains are disabled\n");
		}
		if (!avp) {
			LM_DBG("no TLS client doman AVP set, looking "
				"for socket based TLS client domain\n");
			dom = tls_find_client_domain(&c->rcv.src_ip, c->rcv.src_port);
			if (dom) {
				LM_DBG("found socket based TLS client domain "
					"[%s:%d]\n", ip_addr2a(&dom->addr), dom->port);
					c->extra_data = SSL_new(dom->ctx);
			} else {
				LM_ERR("no TLS client domain found\n");
				return -1;
			}
		} else {
			LM_DBG("TLS client domain AVP found = '%.*s'\n",
				val.s.len, ZSW(val.s.s));
			dom = tls_find_client_domain_name(val.s);
			if (dom) {
				LM_DBG("found name based TLS client domain "
					"'%.*s'\n", val.s.len, ZSW(val.s.s));
				c->extra_data = SSL_new(dom->ctx);
			} else {
				LM_DBG("no name based TLS client domain found, "
					"trying socket based TLS client domains\n");
				dom = tls_find_client_domain(&c->rcv.src_ip, c->rcv.src_port);
				if (dom) {
					LM_DBG("found socket based TLS client domain [%s:%d]\n",
					ip_addr2a(&dom->addr), dom->port);
					c->extra_data = SSL_new(dom->ctx);
				} else {
					LM_ERR("no TLS client domain found\n");
					return -1;
				}
			}
		}
	}
	if (!c->extra_data) {
		LM_ERR("failed to create SSL structure\n");
		return -1;
	}

#ifndef OPENSSL_NO_KRB5
	if ( ((SSL *)c->extra_data)->kssl_ctx ) {
		kssl_ctx_free( ((SSL *)c->extra_data)->kssl_ctx );
		((SSL *)c->extra_data)->kssl_ctx = 0;
	}
#endif

	if ( c->proto_flags & F_TLS_DO_ACCEPT ) {
		LM_DBG("Setting in ACCEPT mode (server)\n");
		SSL_set_accept_state((SSL *) c->extra_data);
	} else {
		LM_DBG("Setting in CONNECT mode (client)\n");
		SSL_set_connect_state((SSL *) c->extra_data);
	}
	return 0;
}