]> git.meshlink.io Git - meshlink/commitdiff
Automatically exchange ECDSA keys and upgrade to new authentication protocol.
authorGuus Sliepen <guus@tinc-vpn.org>
Sun, 10 Jul 2011 20:34:17 +0000 (22:34 +0200)
committerGuus Sliepen <guus@tinc-vpn.org>
Sun, 10 Jul 2011 20:34:17 +0000 (22:34 +0200)
If we don't have ECDSA keys for the node we connect to, set protocol_minor
to 1, to indicate this to the other end. This will first complete the
old way of authentication with RSA keys, and will then exchange ECDSA keys.
The connection will be terminated right afterwards, and the next attempt
will use ECDSA keys.

src/conf.c
src/conf.h
src/openssl/ecdsa.c
src/openssl/ecdsa.h
src/protocol_auth.c

index 099b77dac1f39778ea8e2902f912bab9118152e5..0bbee092411df4366f543dc800913dcbaed63d43 100644 (file)
@@ -400,6 +400,24 @@ bool read_connection_config(connection_t *c) {
        return x;
 }
 
+bool append_connection_config(const connection_t *c, const char *key, const char *value) {
+       char *fname;
+       xasprintf(&fname, "%s/hosts/%s", confbase, c->name);
+
+       FILE *fp = fopen(fname, "a");
+
+       if(!fp) {
+               logger(LOG_ERR, "Cannot open config file %s: %s", fname, strerror(errno));
+       } else {
+               fprintf(fp, "\n# The following line was automatically added by tinc\n%s = %s\n", key, value);
+               fclose(fp);
+       }
+
+       free(fname);
+
+       return fp;
+}
+
 bool disable_old_keys(FILE *f) {
        char buf[100];
        long pos;
index cc57e82b4a11bfc27d949912b88d3025e775fc89..20fc95e6800293842a995fabaa69e4034f7e9243 100644 (file)
@@ -61,6 +61,7 @@ extern bool read_config_file(splay_tree_t *, const char *);
 extern void read_config_options(splay_tree_t *, const char *);
 extern bool read_server_config(void);
 extern bool read_connection_config(struct connection_t *);
+extern bool append_connection_config(const struct connection_t *, const char *, const char *);
 extern FILE *ask_and_open(const char *, const char *, const char *);
 extern bool is_safe_path(const char *);
 extern bool disable_old_keys(FILE *);
index a4f0f30d259b68355d94d9920d0416249df3c2ea..43464d8835b60c9c37280c682b14e2696965d5f3 100644 (file)
@@ -26,8 +26,8 @@
 #include "ecdsa.h"
 #include "utils.h"
 
-// Set ECDSA keys
-
+// Get and set ECDSA keys
+//
 bool ecdsa_set_base64_public_key(ecdsa_t *ecdsa, const char *p) {
        *ecdsa = EC_KEY_new_by_curve_name(NID_secp521r1);
 
@@ -44,6 +44,18 @@ bool ecdsa_set_base64_public_key(ecdsa_t *ecdsa, const char *p) {
        return true;
 }
 
+char *ecdsa_get_base64_public_key(ecdsa_t *ecdsa) {
+       unsigned char *pubkey = NULL;
+       int len = i2o_ECPublicKey(*ecdsa, &pubkey);
+
+       char *base64 = malloc(len * 4 / 3 + 5);
+       b64encode(pubkey, base64, len);
+
+       free(pubkey);
+
+       return base64;
+}
+
 // Read PEM ECDSA keys
 
 bool ecdsa_read_pem_public_key(ecdsa_t *ecdsa, FILE *fp) {
index cc0e7b02c6642c1bd1fae22a65188adb528fff00..04f9eb980bfb1684344aab91041667f944b7c847 100644 (file)
@@ -25,6 +25,7 @@
 typedef EC_KEY *ecdsa_t;
 
 extern bool ecdsa_set_base64_public_key(ecdsa_t *ecdsa, const char *p);
+extern char *ecdsa_get_base64_public_key(ecdsa_t *ecdsa);
 extern bool ecdsa_read_pem_public_key(ecdsa_t *ecdsa, FILE *fp);
 extern bool ecdsa_read_pem_private_key(ecdsa_t *ecdsa, FILE *fp);
 extern size_t ecdsa_size(ecdsa_t *ecdsa);
index d38814c69d6d3bc40fcf927ab3c73f3801587822..70062f3f59f87ed0d158011fe12bbf4616857d91 100644 (file)
 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;
+
        return send_request(c, "%d %s %d.%d", ID, myself->connection->name,
-                                               myself->connection->protocol_major, myself->connection->protocol_minor);
+                                               myself->connection->protocol_major, minor);
 }
 
 bool id_h(connection_t *c, char *request) {
@@ -110,6 +114,13 @@ bool id_h(connection_t *c, char *request) {
                                   c->name);
                        return false;
                }
+
+               if(c->protocol_minor >= 2)
+                       if(!read_ecdsa_public_key(c))
+                               return false;
+       } else {
+               if(!ecdsa_active(&c->ecdsa))
+                       c->protocol_minor = 1;
        }
 
        c->allow_request = METAKEY;
@@ -121,9 +132,6 @@ bool id_h(connection_t *c, char *request) {
 }
 
 bool send_metakey_ec(connection_t *c) {
-       if(!read_ecdsa_public_key(c))
-               return false;
-
        logger(LOG_DEBUG, "Sending ECDH metakey to %s", c->name);
 
        size_t siglen = ecdsa_size(&myself->connection->ecdsa);
@@ -149,11 +157,6 @@ bool send_metakey_ec(connection_t *c) {
 }
 
 bool send_metakey(connection_t *c) {
-       size_t len = rsa_size(&c->rsa);
-       char key[len];
-       char enckey[len];
-       char hexkey[2 * len + 1];
-
        if(!read_rsa_public_key(c))
                return false;
 
@@ -163,6 +166,11 @@ bool send_metakey(connection_t *c) {
        if(!digest_open_sha1(&c->outdigest, -1))
                return false;
 
+       size_t len = rsa_size(&c->rsa);
+       char key[len];
+       char enckey[len];
+       char hexkey[2 * len + 1];
+
        /* Create a random key */
 
        randomize(key, len);
@@ -451,7 +459,24 @@ bool chal_reply_h(connection_t *c, char *request) {
        return send_ack(c);
 }
 
+static bool send_upgrade(connection_t *c) {
+       /* Special case when protocol_minor is 1: the other end is ECDSA capable,
+        * but doesn't know our key yet. So send it now. */
+
+       char *pubkey = ecdsa_get_base64_public_key(&myself->connection->ecdsa);
+
+       if(!pubkey)
+               return false;
+
+       bool result = send_request(c, "%d %s", ACK, pubkey);
+       free(pubkey);
+       return result;
+}
+
 bool send_ack(connection_t *c) {
+       if(c->protocol_minor == 1)
+               return send_upgrade(c);
+
        /* ACK message contains rest of the information the other end needs
           to create node_t and edge_t structures. */
 
@@ -516,7 +541,29 @@ static void send_everything(connection_t *c) {
        }
 }
 
+static bool upgrade_h(connection_t *c, char *request) {
+       char pubkey[MAX_STRING_SIZE];
+
+       if(sscanf(request, "%*d " MAX_STRING, pubkey) != 1) {
+               logger(LOG_ERR, "Got bad %s from %s (%s)", "ACK", c->name, c->hostname);
+               return false;
+       }
+
+       if(ecdsa_active(&c->ecdsa) || read_ecdsa_public_key(c)) {
+               logger(LOG_INFO, "Already have ECDSA public key from %s (%s), not upgrading.", c->name, c->hostname);
+               return false;
+       }
+
+       logger(LOG_INFO, "Got ECDSA public key from %s (%s), upgrading!", c->name, c->hostname);
+       append_connection_config(c, "ECDSAPublicKey", pubkey);
+       c->allow_request = TERMREQ;
+       return send_termreq(c);
+}
+
 bool ack_h(connection_t *c, char *request) {
+       if(c->protocol_minor == 1)
+               return upgrade_h(c, request);
+
        char hisport[MAX_STRING_SIZE];
        char *hisaddress;
        int weight, mtu;