[PATCH] chunk: Update protocol to support in-band SSL negotiation

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



commit 0df0e18e7fdf2674e4a22f0ca8e57a157dad6ca9
Author: Jeff Garzik <jeff@xxxxxxxxxx>
Date:   Fri Mar 5 10:04:00 2010 -0500

    Protocol: replace SSL/no-SSL split ports with in-band SSL negotiation
    
    Initiating SSL immediately upon connection, based on incoming TCP
    connection port, is a relic of poor HTTP design and should not have
    been carried over to chunk protocol.  Modern protocols (SMTP, IMAP,
    etc.) all support binding to a single port, and then negotiating
    SSL/TLS based on a command from the client.
    
    Change chunk protocol such that clients must issue a CHO_START_TLS
    command at the beginning of the TCP connection, if they wish
    encryption.
    
    Signed-off-by: Jeff Garzik <jgarzik@xxxxxxxxxx>

diff --git a/doc/setup.txt b/doc/setup.txt
index a5e7c66..5ef7225 100644
--- a/doc/setup.txt
+++ b/doc/setup.txt
@@ -27,14 +27,6 @@ _cld._udp.phx2.ex.com has SRV record 10 50 8081 maika.phx2.ex.com.
 		<Port>8082</Port>
 	</Listen>
 
-   You can also set the interface and the encryption:
-
-	<Listen>
-		<Node>192.168.1.24</Node>
-		<Port>18082</Port>
-		<Encrypt>true</Encrypt>
-	</Listen>
-
    For clouds and their many cheap nodes with one Ethernet it usually is
    not a great idea to specify interfaces, since they often use IPv6 or
    acquire IP addresses from DHCP. So, just specify a port.
diff --git a/include/chunk_msg.h b/include/chunk_msg.h
index 154201d..a25fcb5 100644
--- a/include/chunk_msg.h
+++ b/include/chunk_msg.h
@@ -32,16 +32,22 @@ enum {
 };
 
 enum chunksrv_ops {
-	CHO_NOP			= 0,
-	CHO_GET			= 1,
-	CHO_GET_META		= 2,
-	CHO_PUT			= 3,
-	CHO_DEL			= 4,
-	CHO_LIST		= 5,
-	CHO_LOGIN		= 6,
-	CHO_TABLE_OPEN		= 7,
-	CHO_CHECK_START		= 8,
-	CHO_CHECK_STATUS	= 9,
+	CHO_NOP			= 0,	/* No-op (ping server) */
+	CHO_GET			= 1,	/* GET object */
+	CHO_GET_META		= 2,	/* GET object metadata */
+	CHO_PUT			= 3,	/* PUT object */
+	CHO_DEL			= 4,	/* Delete object */
+	CHO_LIST		= 5,	/* List objects */
+	CHO_LOGIN		= 6,	/* Login as user */
+	CHO_TABLE_OPEN		= 7,	/* Open table */
+	CHO_CHECK_START		= 8,	/* Begin self-check */
+	CHO_CHECK_STATUS	= 9,	/* Query self-check status */
+
+	/* START-TLS is special.  It MUST be the first request of a TCP
+	 * cxn, and no chunkd-specific response is returned.  The SSL
+	 * functions' success/failure is sufficient indication.
+	 */
+	CHO_START_TLS		= 10,	/* Encrypt all subsequent msgs */
 };
 
 enum chunk_errcode {
diff --git a/lib/chunkdc.c b/lib/chunkdc.c
index e9e0e0f..9c1e967 100644
--- a/lib/chunkdc.c
+++ b/lib/chunkdc.c
@@ -191,6 +191,27 @@ static bool stc_login(struct st_client *stc)
 	return true;
 }
 
+static bool stc_start_tls_cmd(struct st_client *stc)
+{
+	struct chunksrv_req *req = (struct chunksrv_req *) stc->req_buf;
+
+	if (stc->verbose)
+		fprintf(stderr, "libstc: START-TLS\n");
+
+	/* initialize request */
+	req_init(stc, req);
+	req->op = CHO_START_TLS;
+	strcpy(req->sig, "START-TLS");
+
+	/* write request */
+	if (!net_write(stc, req, req_len(req)))
+		return false;
+
+	/* no response - SSL negotiation begins immediately */
+
+	return true;
+}
+
 struct st_client *stc_new(const char *service_host, int port,
 			  const char *user, const char *secret_key,
 			  bool use_ssl)
@@ -253,6 +274,9 @@ struct st_client *stc_new(const char *service_host, int port,
 		goto err_out;
 
 	if (use_ssl) {
+		if (!stc_start_tls_cmd(stc))
+			goto err_out;
+
 		stc->ssl_ctx = SSL_CTX_new(TLSv1_client_method());
 		if (!stc->ssl_ctx)
 			goto err_out;
@@ -266,7 +290,8 @@ struct st_client *stc_new(const char *service_host, int port,
 		if (!SSL_set_fd(stc->ssl, stc->fd))
 			goto err_out_ssl;
 
-		if (SSL_connect(stc->ssl) <= 0)
+		rc = SSL_connect(stc->ssl);
+		if (rc <= 0)
 			goto err_out_ssl;
 	}
 
@@ -276,9 +301,15 @@ struct st_client *stc_new(const char *service_host, int port,
 	return stc;
 
 err_out_ssl:
-	SSL_free(stc->ssl);
+	if (stc->ssl) {
+		SSL_free(stc->ssl);
+		stc->ssl = NULL;
+	}
 err_out_ctx:
-	SSL_CTX_free(stc->ssl_ctx);
+	if (stc->ssl_ctx) {
+		SSL_CTX_free(stc->ssl_ctx);
+		stc->ssl_ctx = NULL;
+	}
 err_out:
 	close(stc->fd);
 	stc_free(stc);
diff --git a/server/chunkd.h b/server/chunkd.h
index 42bcb21..cd83f7b 100644
--- a/server/chunkd.h
+++ b/server/chunkd.h
@@ -102,6 +102,7 @@ struct client {
 	SSL			*ssl;
 	bool			read_want_write;
 	bool			write_want_read;
+	bool			first_req;
 
 	struct list_head	write_q;	/* list of async writes */
 	bool			writing;
@@ -150,7 +151,6 @@ struct listen_cfg {
 	char			*node;
 	char			*port;
 	char			*port_file;
-	bool			encrypt;
 };
 
 struct geo {
diff --git a/server/cldu.c b/server/cldu.c
index 9c27138..dbcf11d 100644
--- a/server/cldu.c
+++ b/server/cldu.c
@@ -540,11 +540,9 @@ static int cldu_make_ffile(char **ret, struct cld_session *sp)
 
 		rc = asprintf(&str,
 			" <Socket>\r\n"
-			"  <Type>%s</Type>\r\n"
 			"  <Host>%s</Host>\r\n"
 			"  <Port>%s</Port>\r\n"
 			" </Socket>\r\n",
-			cfg->encrypt ? "chunk-ssl" : "chunk",
 			host,
 			cfg->port);
 		if (rc == -1) {
diff --git a/server/config.c b/server/config.c
index 69b5e9b..0422239 100644
--- a/server/config.c
+++ b/server/config.c
@@ -398,16 +398,6 @@ static void cfg_elm_end (GMarkupParseContext *context,
 		}
 	}
 
-	else if (cc->in_listen && cc->text &&
-		 !strcmp(element_name, "Encrypt")) {
-		if (!strcasecmp(cc->text, "yes") ||
-		    !strcasecmp(cc->text, "true"))
-			cc->tmp_listen.encrypt = true;
-
-		free(cc->text);
-		cc->text = NULL;
-	}
-
 	else if (!strcmp(element_name, "Group") && cc->text) {
 		free(chunkd_srv.group);
 		chunkd_srv.group = cc->text;
diff --git a/server/server.c b/server/server.c
index 0d83311..4d9a09e 100644
--- a/server/server.c
+++ b/server/server.c
@@ -357,7 +357,7 @@ static void cli_free(struct client *cli)
 	free(cli);
 }
 
-static struct client *cli_alloc(bool use_ssl)
+static struct client *cli_alloc(void)
 {
 	struct client *cli;
 
@@ -366,18 +366,10 @@ static struct client *cli_alloc(bool use_ssl)
 	if (!cli)
 		return NULL;
 
-	if (use_ssl) {
-		cli->ssl = SSL_new(ssl_ctx);
-		if (!cli->ssl) {
-			applog(LOG_ERR, "SSL_new failed");
-			free(cli);
-			return NULL;
-		}
-	}
-
 	cli->state = evt_read_fixed;
 	INIT_LIST_HEAD(&cli->write_q);
 	cli->req_ptr = &cli->creq;
+	cli->first_req = true;
 
 	return cli;
 }
@@ -1038,6 +1030,7 @@ static const char *op2str(enum chunksrv_ops op)
 	case CHO_TABLE_OPEN:	return "CHO_TABLE_OPEN";
 	case CHO_CHECK_START:	return "CHO_CHECK_START";
 	case CHO_CHECK_STATUS:	return "CHO_CHECK_STATUS";
+	case CHO_START_TLS:	return "CHO_START_TLS";
 
 	default:
 		return "BUG/UNKNOWN!";
@@ -1082,7 +1075,8 @@ static bool cli_evt_exec_req(struct client *cli, unsigned int events)
 
 	cli->state = evt_recycle;
 
-	if (G_UNLIKELY((!logged_in) && (req->op != CHO_LOGIN))) {
+	if (G_UNLIKELY((!logged_in) && (req->op != CHO_LOGIN) &&
+		       (req->op != CHO_START_TLS))) {
 		cli->state = evt_dispose;
 		return true;
 	}
@@ -1142,11 +1136,37 @@ static bool cli_evt_exec_req(struct client *cli, unsigned int events)
 	case CHO_CHECK_STATUS:
 		rcb = chk_status(cli);
 		break;
+	case CHO_START_TLS:
+		if (!cli->first_req) {
+			cli->state = evt_dispose;
+			rcb = true;
+		} else {
+			cli->ssl = SSL_new(ssl_ctx);
+			if (!cli->ssl) {
+				applog(LOG_ERR, "SSL_new failed");
+				cli->state = evt_dispose;
+				rcb = true;
+				break;
+			}
+
+			if (!SSL_set_fd(cli->ssl, cli->fd)) {
+				applog(LOG_ERR, "SSL_set_fd failed");
+				cli->state = evt_dispose;
+				rcb = true;
+				break;
+			}
+
+			cli->state = evt_ssl_accept;
+			rcb = true;
+		}
+		break;
 	default:
 		rcb = cli_err(cli, che_InvalidURI, true);
 		break;
 	}
 
+	cli->first_req = false;
+
 out:
 	return rcb;
 
@@ -1220,7 +1240,7 @@ static bool cli_evt_ssl_accept(struct client *cli, unsigned int events)
 
 	rc = SSL_accept(cli->ssl);
 	if (rc > 0) {
-		cli->state = evt_read_fixed;
+		cli->state = evt_recycle;
 		return true;
 	}
 
@@ -1236,6 +1256,8 @@ static bool cli_evt_ssl_accept(struct client *cli, unsigned int events)
 		return false;
 	}
 
+	applog(LOG_ERR, "SSL_accept returned %d", rc);
+
 out:
 	cli->state = evt_dispose;
 	return true;
@@ -1294,10 +1316,10 @@ static bool tcp_srv_event(int fd, short events, void *userdata)
 	socklen_t addrlen = sizeof(struct sockaddr_in6);
 	struct client *cli;
 	char host[64];
-	int rc, on = 1;
+	int on = 1;
 	struct server_poll *sp;
 
-	cli = cli_alloc(sock->cfg->encrypt);
+	cli = cli_alloc();
 	if (!cli) {
 		applog(LOG_ERR, "out of memory");
 		return false;	/* end main loop; terminate server */
@@ -1321,32 +1343,6 @@ static bool tcp_srv_event(int fd, short events, void *userdata)
 		applog(LOG_WARNING, "TCP_NODELAY failed: %s",
 		       strerror(errno));
 
-	if (sock->cfg->encrypt) {
-		if (!SSL_set_fd(cli->ssl, cli->fd))
-			goto err_out_fd;
-
-		rc = SSL_accept(cli->ssl);
-		if (rc <= 0) {
-			rc = SSL_get_error(cli->ssl, rc);
-			if (rc == SSL_ERROR_WANT_READ)
-				cli->state = evt_ssl_accept;
-			else if (rc == SSL_ERROR_WANT_WRITE) {
-				cli->state = evt_ssl_accept;
-				cli->read_want_write = true;
-			}
-			else {
-				unsigned long e = ERR_get_error();
-				char estr[121] = "(none?)";
-
-				if (e)
-					ERR_error_string(e, estr);
-				applog(LOG_WARNING, "%s SSL error %s",
-				       cli->addr_host, estr);
-				goto err_out_fd;
-			}
-		}
-	}
-
 	sp = calloc(1, sizeof(*sp));
 	if (!sp)
 		goto err_out_fd;
@@ -1356,11 +1352,6 @@ static bool tcp_srv_event(int fd, short events, void *userdata)
 	sp->cb = tcp_cli_event;
 	sp->userdata = cli;
 
-	if (cli->read_want_write) {
-		cli->writing = true;
-		sp->events |= POLLOUT;
-	}
-
 	g_hash_table_insert(chunkd_srv.fd_info, GINT_TO_POINTER(cli->fd), sp);
 
 	/* pretty-print incoming cxn info */
diff --git a/test/auth.c b/test/auth.c
index 78b1f8b..e4bfaf0 100644
--- a/test/auth.c
+++ b/test/auth.c
@@ -43,7 +43,7 @@ static void test(bool do_encrypt)
 	size_t len = 0;
 	void *mem;
 
-	port = stc_readport(do_encrypt ? TEST_PORTFILE_SSL : TEST_PORTFILE);
+	port = stc_readport(TEST_PORTFILE);
 	OK(port > 0);
 
 	stc1 = stc_new(TEST_HOST, port, TEST_USER, TEST_USER_KEY, do_encrypt);
diff --git a/test/basic-object.c b/test/basic-object.c
index c4d803a..92ec8c8 100644
--- a/test/basic-object.c
+++ b/test/basic-object.c
@@ -41,7 +41,7 @@ static void test(bool do_encrypt)
 	size_t len = 0;
 	void *mem;
 
-	port = stc_readport(do_encrypt ? TEST_PORTFILE_SSL : TEST_PORTFILE);
+	port = stc_readport(TEST_PORTFILE);
 	OK(port > 0);
 
 	stc = stc_new(TEST_HOST, port, TEST_USER, TEST_USER_KEY, do_encrypt);
diff --git a/test/it-works.c b/test/it-works.c
index 597c58b..a3c01ee 100644
--- a/test/it-works.c
+++ b/test/it-works.c
@@ -35,7 +35,7 @@ static void test(bool ssl)
 	int port;
 	bool rcb;
 
-	port = stc_readport(ssl ? TEST_PORTFILE_SSL : TEST_PORTFILE);
+	port = stc_readport(TEST_PORTFILE);
 	OK(port > 0);
 
 	stc = stc_new(TEST_HOST, port, TEST_USER, TEST_USER_KEY, ssl);
diff --git a/test/large-object.c b/test/large-object.c
index 5188aad..d1a031e 100644
--- a/test/large-object.c
+++ b/test/large-object.c
@@ -108,7 +108,7 @@ static void test(bool do_encrypt)
 
 	memset(data, 0xdeadbeef, sizeof(data));
 
-	port = stc_readport(do_encrypt ? TEST_PORTFILE_SSL : TEST_PORTFILE);
+	port = stc_readport(TEST_PORTFILE);
 	OK(port > 0);
 
 	stc = stc_new(TEST_HOST, port, TEST_USER, TEST_USER_KEY, do_encrypt);
diff --git a/test/lotsa-objects.c b/test/lotsa-objects.c
index 048c1c3..d7dd95c 100644
--- a/test/lotsa-objects.c
+++ b/test/lotsa-objects.c
@@ -47,7 +47,7 @@ static void test(int n_objects, bool do_encrypt)
 	char *k;
 	struct timeval ta, tb;
 
-	port = stc_readport(do_encrypt ? TEST_PORTFILE_SSL : TEST_PORTFILE);
+	port = stc_readport(TEST_PORTFILE);
 	OK(port > 0);
 
 	stc = stc_new(TEST_HOST, port, TEST_USER, TEST_USER_KEY, do_encrypt);
diff --git a/test/nop.c b/test/nop.c
index 526b8c0..bd89a7b 100644
--- a/test/nop.c
+++ b/test/nop.c
@@ -42,7 +42,7 @@ static void test(int n_nops, bool do_encrypt)
 	int i;
 	struct timeval ta, tb;
 
-	port = stc_readport(do_encrypt ? TEST_PORTFILE_SSL : TEST_PORTFILE);
+	port = stc_readport(TEST_PORTFILE);
 	OK(port > 0);
 
 	stc = stc_new(TEST_HOST, port, TEST_USER, TEST_USER_KEY, do_encrypt);
diff --git a/test/server-test.cfg b/test/server-test.cfg
index d98fca4..29b69e2 100644
--- a/test/server-test.cfg
+++ b/test/server-test.cfg
@@ -10,12 +10,6 @@
 	<PortFile>chunkd.port</PortFile>
 </Listen>
 
-<Listen>
-	<Port>auto</Port>
-	<PortFile>chunkd-ssl.port</PortFile>
-	<Encrypt>true</Encrypt>
-</Listen>
-
 <PID>chunkd.pid</PID>
 
 <Path>data/chunk</Path>
diff --git a/test/test.h b/test/test.h
index 75aa250..cc4111f 100644
--- a/test/test.h
+++ b/test/test.h
@@ -36,7 +36,6 @@
 
 #define TEST_PORTFILE_CLD	"cld.port"
 #define TEST_PORTFILE		"chunkd.port"
-#define TEST_PORTFILE_SSL	"chunkd-ssl.port"
 
 #define TEST_CHUNKD_CFG		"server-test.cfg"
 
--
To unsubscribe from this list: send the line "unsubscribe hail-devel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Fedora Clound]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux