Example #1
0
/** wrapper around SSL_connect, using SSL return convention.
 * It will also log critical errors and certificate debugging info.
 * @param c - tcp connection with tls (extra_data must be a filled
 *            tcp_extra_data structure). The state must be S_TLS_CONNECTING.
 * @param error  set to the error reason (SSL_ERROR_*).
 *            Note that it can be SSL_ERROR_NONE while the return is < 0
 *            ("internal" error, not at the SSL level, see below).
 * @return >=1 on success, 0 and <0 on error. 0 means the underlying SSL
 *           connection was closed/shutdown. < 0 is returned for any
 *           SSL_ERROR (including  WANT_READ or WANT_WRITE), but also
 *           for internal non SSL related errors (in this case -2 is
 *           returned and error==SSL_ERROR_NONE).
 *
 */
int tls_connect(struct tcp_connection *c, int* error)
{
	SSL *ssl;
	int ret;
	X509* cert;
	struct tls_extra_data* tls_c;
	int tls_log;

	*error = SSL_ERROR_NONE;
	tls_c=(struct tls_extra_data*)c->extra_data;
	ssl=tls_c->ssl;
	
	if (unlikely(tls_c->state != S_TLS_CONNECTING)) {
		BUG("Invalid connection state %d (bug in TLS code)\n", tls_c->state);
		goto err;
	}
	ret = SSL_connect(ssl);
	if (unlikely(ret == 1)) {
		DBG("TLS connect successful\n");
		tls_c->state = S_TLS_ESTABLISHED;
		tls_log = cfg_get(tls, tls_cfg, log);
		LOG(tls_log, "tls_connect: new connection to %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)
		    );
		LOG(tls_log, "tls_connect: sending 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_connect: server certificate", cert);
			if (SSL_get_verify_result(ssl) != X509_V_OK) {
				LOG(tls_log, "WARNING: tls_connect: server certificate "
				    "verification failed!!!\n");
				tls_dump_verification_failure(SSL_get_verify_result(ssl));
			}
			X509_free(cert);
		} else {
			/* this should not happen, servers always present a cert */
			LOG(tls_log, "tls_connect: server did not "
							"present a certificate\n");
		}
		tls_run_event_routes(c);
	} else { /* 0 or < 0 */
		*error = SSL_get_error(ssl, ret);
	}
	return ret;
err:
	/* internal non openssl related errors */
	return -2;
}
Example #2
0
/** wrapper around SSL_accept, usin SSL return convention.
 * It will also log critical errors and certificate debugging info.
 * @param c - tcp connection with tls (extra_data must be a filled
 *            tcp_extra_data structure). The state must be S_TLS_ACCEPTING.
 * @param error  set to the error reason (SSL_ERROR_*).
 *            Note that it can be SSL_ERROR_NONE while the return is < 0
 *            ("internal" error, not at the SSL level, see below).
 * @return >=1 on success, 0 and <0 on error. 0 means the underlying SSL
 *           connection was closed/shutdown.  < 0 is returned for any
 *           SSL_ERROR (including  WANT_READ or WANT_WRITE), but also
 *           for internal non SSL related errors (in this case -2 is
 *           returned and error==SSL_ERROR_NONE).
 *
 */
int tls_accept(struct tcp_connection *c, int* error)
{
	int ret;
	SSL *ssl;
	X509* cert;
	struct tls_extra_data* tls_c;
	int tls_log;

	*error = SSL_ERROR_NONE;
	tls_c=(struct tls_extra_data*)c->extra_data;
	ssl=tls_c->ssl;
	
	if (unlikely(tls_c->state != S_TLS_ACCEPTING)) {
		BUG("Invalid connection state %d (bug in TLS code)\n", tls_c->state);
		goto err;
	}
	ret = SSL_accept(ssl);
	if (unlikely(ret == 1)) {
		DBG("TLS accept successful\n");
		tls_c->state = S_TLS_ESTABLISHED;
		tls_log = cfg_get(tls, tls_cfg, log);
		LOG(tls_log, "tls_accept: new 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)
		    );
		LOG(tls_log, "tls_accept: 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 certificate", cert);
			if (SSL_get_verify_result(ssl) != X509_V_OK) {
				LOG(tls_log, "WARNING: tls_accept: client certificate "
				    "verification failed!!!\n");
				tls_dump_verification_failure(SSL_get_verify_result(ssl));
			}
			X509_free(cert);
		} else {
			LOG(tls_log, "tls_accept: client did not present a certificate\n");
		}
	} else { /* ret == 0 or < 0 */
		*error = SSL_get_error(ssl, ret);
	}
	return ret;
err:
	/* internal non openssl related errors */
	return -2;
}
Example #3
0
/*
 * wrapper around SSL_connect, returns 0 on success, -1 on error
 */
static int tls_connect(struct tcp_connection *c, short *poll_events)
{
	int ret, err;
	SSL *ssl;
	X509* cert;

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

	ssl = (SSL *) c->extra_data;

	ret = SSL_connect(ssl);
	if (ret > 0) {
		LM_INFO("New TLS connection to %s:%d established\n",
			ip_addr2a(&c->rcv.src_ip), c->rcv.src_port);
		c->proto_flags &= ~F_TLS_DO_CONNECT;
		LM_DBG("new TLS connection to %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("sending 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_connect: server TLS certificate", cert);
			if (SSL_get_verify_result(ssl) != X509_V_OK) {
				LM_WARN("TLS server certificate verification failed\n");
				tls_dump_verification_failure(SSL_get_verify_result(ssl));
			}
			X509_free(cert);
		} else {
			/* this should not happen, servers always present a cert */
			LM_ERR("server did not present a TLS certificate\n");
		}
		cert = SSL_get_certificate(ssl);
		if (cert != 0) {
			tls_dump_cert_info("tls_connect: local TLS client certificate",
				cert);
		} else {
			LM_INFO("local TLS client domain does not have a certificate\n");
		}
		return 0;
	} else {
		err = SSL_get_error(ssl, ret);
		switch (err) {
			case SSL_ERROR_ZERO_RETURN:
				LM_INFO("New TLS connection to %s:%d 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;
			case SSL_ERROR_SYSCALL:
				LM_ERR("SSL_ERROR_SYSCALL err=%s(%d)\n",
					strerror(errno), errno);
			default:
				LM_ERR("New TLS connection to %s:%d failed\n",
					ip_addr2a(&c->rcv.src_ip), c->rcv.src_port);
				LM_ERR("TLS error: %d (ret=%d) err=%s(%d)\n",
					err,ret,strerror(errno), errno);
				c->state = S_CONN_BAD;
				tls_print_errstack();
				return -1;
		}
	}

	LM_BUG("bug\n");
	return -1;
}
Example #4
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;
}