From bbeab00f46a6c856573fe0d2b9b85bce35728403 Mon Sep 17 00:00:00 2001
From: Guus Sliepen <guus@tinc-vpn.org>
Date: Mon, 11 Jul 2011 21:54:01 +0200
Subject: [PATCH] Require ExperimentalProtocol = yes for new features, update
 documentation.

---
 configure.in        |  4 ++--
 doc/tinc.conf.5.in  | 15 +++++++++++++++
 doc/tincctl.8.in    |  6 +++++-
 src/net_setup.c     |  4 +++-
 src/protocol.c      |  1 +
 src/protocol.h      |  1 +
 src/protocol_auth.c | 19 +++++++++++++------
 src/protocol_key.c  |  8 ++++----
 8 files changed, 44 insertions(+), 14 deletions(-)

diff --git a/configure.in b/configure.in
index 394a077a..36729a65 100644
--- a/configure.in
+++ b/configure.in
@@ -157,10 +157,10 @@ tinc_LZO
 
 if test "$with_libgcrypt" = yes; then
 	AM_PATH_LIBGCRYPT([1.4.0], [], [])
-    	ln -sf gcrypt/cipher.c gcrypt/cipher.h gcrypt/crypto.c gcrypt/crypto.h gcrypt/digest.c gcrypt/digest.h gcrypt/rsa.c gcrypt/rsa.h gcrypt/rsagen.c gcrypt/rsagen.h src/
+    	ln -sf gcrypt/*.c gcrypt/*.h src/
 else
 	tinc_OPENSSL
-    	ln -sf openssl/cipher.c openssl/cipher.h openssl/crypto.c openssl/crypto.h openssl/digest.c openssl/digest.h openssl/rsa.c openssl/rsa.h openssl/rsagen.c openssl/rsagen.h src/
+    	ln -sf openssl/*.c openssl/*.h src/
 fi
 	
 
diff --git a/doc/tinc.conf.5.in b/doc/tinc.conf.5.in
index ce690308..a44f27cc 100644
--- a/doc/tinc.conf.5.in
+++ b/doc/tinc.conf.5.in
@@ -212,6 +212,21 @@ but which would have to be forwarded by an intermediate node, are dropped instea
 When combined with the IndirectData option,
 packets for nodes for which we do not have a meta connection with are also dropped.
 
+.It Va ECDSAPrivateKeyFile Li = Ar filename Po Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /ecdsa_key.priv Pc
+The file in which the private ECDSA key of this tinc daemon resides.
+This is only used if
+.Va ExperimentalProtocol
+is enabled.
+
+.It Va ExperimentalProtocol Li = yes | no Po no Pc Bq experimental
+When this option is enabled, experimental protocol enhancements will be used.
+Ephemeral ECDH will be used for key exchanges,
+and ECDSA will be used instead of RSA for authentication.
+When enabled, an ECDSA key must have been generated before with
+.Nm tincctl generate-ecdsa-keys .
+The experimental protocol may change at any time,
+and there is no guarantee that tinc will run stable when it is used.
+
 .It Va Forwarding Li = off | internal | kernel Po internal Pc Bq experimental
 This option selects the way indirect packets are forwarded.
 .Bl -tag -width indent
diff --git a/doc/tincctl.8.in b/doc/tincctl.8.in
index bcccc597..bbc8dba6 100644
--- a/doc/tincctl.8.in
+++ b/doc/tincctl.8.in
@@ -59,10 +59,14 @@ will be made.
 Shows the PID of the currently running
 .Xr tincd 8 .
 .It generate-keys Op bits
+Generate both RSA and ECDSA keypairs (see below) and exit.
+.It generate-ecdsa-keys
+Generate public/private ECDSA keypair and exit.
+.It generate-rsa-keys Op bits
 Generate public/private RSA keypair and exit.
 If
 .Ar bits
-is omitted, the default length will be 1024 bits.
+is omitted, the default length will be 2048 bits.
 When saving keys to existing files, tinc will not delete the old keys;
 you have to remove them manually.
 .It dump nodes
diff --git a/src/net_setup.c b/src/net_setup.c
index 1796c4bb..f3de53a2 100644
--- a/src/net_setup.c
+++ b/src/net_setup.c
@@ -339,7 +339,9 @@ static bool setup_myself(void) {
 	read_config_file(config_tree, fname);
 	free(fname);
 
-	if(!read_ecdsa_private_key())
+	get_config_bool(lookup_config(config_tree, "ExperimentalProtocol"), &experimental);
+
+	if(experimental && !read_ecdsa_private_key())
 		return false;
 
 	if(!read_rsa_private_key())
diff --git a/src/protocol.c b/src/protocol.c
index 650c5129..63163a0f 100644
--- a/src/protocol.c
+++ b/src/protocol.c
@@ -30,6 +30,7 @@
 
 bool tunnelserver = false;
 bool strictsubnets = false;
+bool experimental = false;
 
 /* Jumptable for the request handlers */
 
diff --git a/src/protocol.h b/src/protocol.h
index 191229ad..2c97641d 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -54,6 +54,7 @@ typedef struct past_request_t {
 
 extern bool tunnelserver;
 extern bool strictsubnets;
+extern bool experimental;
 
 /* Maximum size of strings in a request.
  * scanf terminates %2048s with a NUL character,
diff --git a/src/protocol_auth.c b/src/protocol_auth.c
index 70062f3f..21a4b7e1 100644
--- a/src/protocol_auth.c
+++ b/src/protocol_auth.c
@@ -43,12 +43,16 @@
 bool send_id(connection_t *c) {
 	gettimeofday(&c->start, NULL);
 
-	int minor = myself->connection->protocol_minor;
-	if(c->config_tree && !read_ecdsa_public_key(c))
-		minor = 1;
+	int minor = 0;
 
-	return send_request(c, "%d %s %d.%d", ID, myself->connection->name,
-						myself->connection->protocol_major, minor);
+	if(experimental) {
+		if(c->config_tree && !read_ecdsa_public_key(c))
+			minor = 1;
+		else
+			minor = myself->connection->protocol_minor;
+	}
+
+	return send_request(c, "%d %s %d.%d", ID, myself->connection->name, myself->connection->protocol_major, minor);
 }
 
 bool id_h(connection_t *c, char *request) {
@@ -115,7 +119,7 @@ bool id_h(connection_t *c, char *request) {
 			return false;
 		}
 
-		if(c->protocol_minor >= 2)
+		if(experimental && c->protocol_minor >= 2)
 			if(!read_ecdsa_public_key(c))
 				return false;
 	} else {
@@ -123,6 +127,9 @@ bool id_h(connection_t *c, char *request) {
 			c->protocol_minor = 1;
 	}
 
+	if(!experimental)
+		c->protocol_minor = 0;
+
 	c->allow_request = METAKEY;
 
 	if(c->protocol_minor >= 2)
diff --git a/src/protocol_key.c b/src/protocol_key.c
index 4b2047a7..0ae95681 100644
--- a/src/protocol_key.c
+++ b/src/protocol_key.c
@@ -84,7 +84,7 @@ bool key_changed_h(connection_t *c, char *request) {
 }
 
 bool send_req_key(node_t *to) {
-	return send_request(to->nexthop->connection, "%d %s %s 1", REQ_KEY, myself->name, to->name);
+	return send_request(to->nexthop->connection, "%d %s %s %d", REQ_KEY, myself->name, to->name, experimental ? 1 : 0);
 }
 
 bool req_key_h(connection_t *c, char *request) {
@@ -123,7 +123,7 @@ bool req_key_h(connection_t *c, char *request) {
 	/* Check if this key request is for us */
 
 	if(to == myself) {			/* Yes, send our own key back */
-		if(kx_version > 0) {
+		if(experimental && kx_version >= 1) {
 			logger(LOG_DEBUG, "Got ECDH key request from %s", from->name);
 			from->status.ecdh = true;
 		}
@@ -161,7 +161,7 @@ bool send_ans_key_ecdh(node_t *to) {
 }
 
 bool send_ans_key(node_t *to) {
-	if(to->status.ecdh)
+	if(experimental && to->status.ecdh)
 		return send_ans_key_ecdh(to);
 
 	size_t keylen = cipher_keylength(&myself->incipher);
@@ -280,7 +280,7 @@ bool ans_key_h(connection_t *c, char *request) {
 
 	/* ECDH or old-style key exchange? */
 	
-	if(!strncmp(key, "ECDH:", 5)) {
+	if(experimental && !strncmp(key, "ECDH:", 5)) {
 		keylen = (strlen(key) - 5) / 2;
 
 		if(keylen != ECDH_SIZE) {
-- 
2.39.5