コード例 #1
0
static int
tls_accept(void *ctx, void **newctxp)
{
	struct tls_ctx *tlsctx = ctx;
	struct tls_ctx *newtlsctx;
	struct proto_conn *sock, *tcp;
	pid_t pid;
	int error;

	PJDLOG_ASSERT(tlsctx != NULL);
	PJDLOG_ASSERT(tlsctx->tls_magic == TLS_CTX_MAGIC);
	PJDLOG_ASSERT(tlsctx->tls_side == TLS_SIDE_SERVER_LISTEN);

	if (proto_connect(NULL, "socketpair://", -1, &sock) == -1)
		return (errno);

	/* Accept TCP connection. */
	if (proto_accept(tlsctx->tls_tcp, &tcp) == -1) {
		error = errno;
		proto_close(sock);
		return (error);
	}

	pid = fork();
	switch (pid) {
	case -1:
		/* Failure. */
		error = errno;
		proto_close(sock);
		return (error);
	case 0:
		/* Child. */
		pjdlog_prefix_set("[TLS sandbox] (server) ");
#ifdef HAVE_SETPROCTITLE
		setproctitle("[TLS sandbox] (server) ");
#endif
		/* Close listen socket. */
		proto_close(tlsctx->tls_tcp);
		tls_call_exec_server(sock, tcp);
		/* NOTREACHED */
		PJDLOG_ABORT("Unreachable.");
	default:
		/* Parent. */
		newtlsctx = calloc(1, sizeof(*tlsctx));
		if (newtlsctx == NULL) {
			error = errno;
			proto_close(sock);
			proto_close(tcp);
			(void)kill(pid, SIGKILL);
			return (error);
		}
		proto_local_address(tcp, newtlsctx->tls_laddr,
		    sizeof(newtlsctx->tls_laddr));
		PJDLOG_ASSERT(strncmp(newtlsctx->tls_laddr, "tcp://", 6) == 0);
		bcopy("tls://", newtlsctx->tls_laddr, 6);
		*strrchr(newtlsctx->tls_laddr, ':') = '\0';
		proto_remote_address(tcp, newtlsctx->tls_raddr,
		    sizeof(newtlsctx->tls_raddr));
		PJDLOG_ASSERT(strncmp(newtlsctx->tls_raddr, "tcp://", 6) == 0);
		bcopy("tls://", newtlsctx->tls_raddr, 6);
		*strrchr(newtlsctx->tls_raddr, ':') = '\0';
		proto_close(tcp);
		proto_recv(sock, NULL, 0);
		newtlsctx->tls_sock = sock;
		newtlsctx->tls_tcp = NULL;
		newtlsctx->tls_wait_called = true;
		newtlsctx->tls_side = TLS_SIDE_SERVER_WORK;
		newtlsctx->tls_magic = TLS_CTX_MAGIC;
		*newctxp = newtlsctx;
		return (0);
	}
}
コード例 #2
0
static void
tls_exec_client(const char *user, int startfd, const char *srcaddr,
    const char *dstaddr, const char *fingerprint, const char *defport,
    int timeout, int debuglevel)
{
	struct proto_conn *tcp;
	char *saddr, *daddr;
	SSL_CTX *sslctx;
	SSL *ssl;
	long ret;
	int sockfd, tcpfd;
	uint8_t connected;

	pjdlog_debug_set(debuglevel);
	pjdlog_prefix_set("[TLS sandbox] (client) ");
#ifdef HAVE_SETPROCTITLE
	setproctitle("[TLS sandbox] (client) ");
#endif
	proto_set("tcp:port", defport);

	sockfd = startfd;

	/* Change tls:// to tcp://. */
	if (srcaddr == NULL) {
		saddr = NULL;
	} else {
		saddr = strdup(srcaddr);
		if (saddr == NULL)
			pjdlog_exitx(EX_TEMPFAIL, "Unable to allocate memory.");
		bcopy("tcp://", saddr, 6);
	}
	daddr = strdup(dstaddr);
	if (daddr == NULL)
		pjdlog_exitx(EX_TEMPFAIL, "Unable to allocate memory.");
	bcopy("tcp://", daddr, 6);

	/* Establish TCP connection. */
	if (proto_connect(saddr, daddr, timeout, &tcp) == -1)
		exit(EX_TEMPFAIL);

	SSL_load_error_strings();
	SSL_library_init();

	/*
	 * TODO: On FreeBSD we could move this below sandbox() once libc and
	 *       libcrypto use sysctl kern.arandom to obtain random data
	 *       instead of /dev/urandom and friends.
	 */
	sslctx = SSL_CTX_new(TLSv1_client_method());
	if (sslctx == NULL)
		pjdlog_exitx(EX_TEMPFAIL, "SSL_CTX_new() failed.");

	if (sandbox(user, true, "proto_tls client: %s", dstaddr) != 0)
		pjdlog_exitx(EX_CONFIG, "Unable to sandbox TLS client.");
	pjdlog_debug(1, "Privileges successfully dropped.");

	SSL_CTX_set_options(sslctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);

	/* Load CA certs. */
	/* TODO */
	//SSL_CTX_load_verify_locations(sslctx, cacerts_file, NULL);

	ssl = SSL_new(sslctx);
	if (ssl == NULL)
		pjdlog_exitx(EX_TEMPFAIL, "SSL_new() failed.");

	tcpfd = proto_descriptor(tcp);

	block(tcpfd);

	if (SSL_set_fd(ssl, tcpfd) != 1)
		pjdlog_exitx(EX_TEMPFAIL, "SSL_set_fd() failed.");

	ret = SSL_connect(ssl);
	ssl_check_error(ssl, (int)ret);

	nonblock(sockfd);
	nonblock(tcpfd);

	tls_certificate_verify(ssl, fingerprint);

	/*
	 * The following byte is send to make proto_connect_wait() to work.
	 */
	connected = 1;
	for (;;) {
		switch (send(sockfd, &connected, sizeof(connected), 0)) {
		case -1:
			if (errno == EINTR || errno == ENOBUFS)
				continue;
			if (errno == EAGAIN) {
				(void)wait_for_fd(sockfd, -1);
				continue;
			}
			pjdlog_exit(EX_TEMPFAIL, "send() failed");
		case 0:
			pjdlog_debug(1, "Connection terminated.");
			exit(0);
		case 1:
			break;
		}
		break;
	}

	tls_loop(sockfd, ssl);
}
コード例 #3
0
static int
tls_connect(const char *srcaddr, const char *dstaddr, int timeout, void **ctxp)
{
	struct tls_ctx *tlsctx;
	struct proto_conn *sock;
	pid_t pid;
	int error;

	PJDLOG_ASSERT(srcaddr == NULL || srcaddr[0] != '\0');
	PJDLOG_ASSERT(dstaddr != NULL);
	PJDLOG_ASSERT(timeout >= -1);
	PJDLOG_ASSERT(ctxp != NULL);

	if (strncmp(dstaddr, "tls://", 6) != 0)
		return (-1);
	if (srcaddr != NULL && strncmp(srcaddr, "tls://", 6) != 0)
		return (-1);

	if (proto_connect(NULL, "socketpair://", -1, &sock) == -1)
		return (errno);

#if 0
	/*
	 * We use rfork() with the following flags to disable SIGCHLD
	 * delivery upon the sandbox process exit.
	 */
	pid = rfork(RFFDG | RFPROC | RFTSIGZMB | RFTSIGFLAGS(0));
#else
	/*
	 * We don't use rfork() to be able to log information about sandbox
	 * process exiting.
	 */
	pid = fork();
#endif
	switch (pid) {
	case -1:
		/* Failure. */
		error = errno;
		proto_close(sock);
		return (error);
	case 0:
		/* Child. */
		pjdlog_prefix_set("[TLS sandbox] (client) ");
#ifdef HAVE_SETPROCTITLE
		setproctitle("[TLS sandbox] (client) ");
#endif
		tls_call_exec_client(sock, srcaddr, dstaddr, timeout);
		/* NOTREACHED */
	default:
		/* Parent. */
		tlsctx = calloc(1, sizeof(*tlsctx));
		if (tlsctx == NULL) {
			error = errno;
			proto_close(sock);
			(void)kill(pid, SIGKILL);
			return (error);
		}
		proto_send(sock, NULL, 0);
		tlsctx->tls_sock = sock;
		tlsctx->tls_tcp = NULL;
		tlsctx->tls_side = TLS_SIDE_CLIENT;
		tlsctx->tls_wait_called = false;
		tlsctx->tls_magic = TLS_CTX_MAGIC;
		if (timeout >= 0) {
			error = tls_connect_wait(tlsctx, timeout);
			if (error != 0) {
				(void)kill(pid, SIGKILL);
				tls_close(tlsctx);
				return (error);
			}
		}
		*ctxp = tlsctx;
		return (0);
	}
}
コード例 #4
0
ファイル: proto.c プロジェクト: noahwilliamsson/sslprobe
static int proto_finish(connection_t *c) {
	test_t *test = (test_t *)connection_priv(c);

	/* Copy last connection error, if any */
	test->error = c->error;

	if(test->version == 2)
		return 0;

	if(test->alert_level == 2) do {
		if(test->alert_desc == 40 && !test->test_cs_preference) {
			/* Have handshake failure (no shared ciphers) */
			if(test->num_ciphers < 2) {
				/* Need at least two supported cipher suites */
				test->has_cs_preference = -1;
				break;
			}

			/**
			 * Test if server has cipher preference by sending two
			 * of the previously selected ciphers in reverse order
			 */
			test->test_cs_preference = 1;
		}
		else if(test->alert_desc == 47 && !test->bugfix_limit_cs) {
			test->bugfix_limit_cs = 128;
			fprintf(stderr, "%s" TAG "Server alerts with "
				"'Illegal parameter', retrying with "
				"limited ciphersuite\n", proto_ver(c));
		}
		else if(test->alert_desc == 47 && !test->bugfix_broken_tlsext) {
			test->bugfix_broken_tlsext = 1;
			fprintf(stderr, "%s" TAG "Server alerts with "
				"'Illegal parameter', retrying with "
				"no TLS extensions\n", proto_ver(c));
		}
		else
			break;

		/* Retry with more limited cipher suite list */
		test->state = X_ACCEPTED;
		test->error = 0;
		test->hs_type = 0;
		test->alert_level = 0;
		test->alert_desc = 0;

		if(proto_connect(c->ai, c->hostname, test) < 0) {
			fprintf(stderr, "%s" TAG "Connection probe failed\n",
				proto_ver(c));
			return -1;
		}

		return 0;
	} while(0);

	/**
	 * Stop testing ciphers on servers which forces ciphers
	 * upon us that wasn't present in our ClientHello.
	 * Also stop if we've tested cipher suite preferences.
	 */
	if(test->bugfix_forced_cs || test->test_cs_preference) {

		return 0;
	}

	if(test->state == X_DONE && test->alert_level == 0) {
		/**
		 * This connection succeeded with its cipher suite so do another
		 * connection with this and previous cipher suites excluded.
		 * This will continue until the server responds with an ALERT
		 * which usually indicates the presented cipher suite doesn't
		 * contain any common ciphers.
		 */
		test->state = X_ACCEPTED;
		test->error = 0;
		test->hs_type = 0;

		if(proto_connect(c->ai, c->hostname, test) < 0) {
			fprintf(stderr, "%s" TAG "Connection probe failed\n",
				proto_ver(c));
			return -1;
		}
	}

	return 0;
}