Ensure the invitation filenames do not reveal the secret cookie.
[tinc] / src / protocol_auth.c
index 05724d6..d69c8ab 100644 (file)
@@ -174,6 +174,7 @@ static bool finalize_invitation(connection_t *c, const char *data, uint16_t len)
        fclose(f);
 
        logger(DEBUG_CONNECTIONS, LOG_INFO, "Key succesfully received from %s (%s)", c->name, c->hostname);
+       sptps_send_record(&c->sptps, 2, data, 0);
        return true;
 }
 
@@ -189,8 +190,19 @@ static bool receive_invitation_sptps(void *handle, uint8_t type, const char *dat
        if(type != 0 || len != 18 || c->status.invitation_used)
                return false;
 
+       // Recover the filename from the cookie and the key
+       digest_t *digest = digest_open_by_name("sha256", 18);
+       if(!digest)
+               abort();
+       char *fingerprint = ecdsa_get_base64_public_key(invitation_key);
+       char hashbuf[18 + strlen(fingerprint)];
        char cookie[25];
-       b64encode_urlsafe(data, cookie, 18);
+       memcpy(hashbuf, data, 18);
+       memcpy(hashbuf + 18, fingerprint, sizeof hashbuf - 18);
+       digest_create(digest, hashbuf, sizeof hashbuf, cookie);
+       b64encode_urlsafe(cookie, cookie, 18);
+       digest_close(digest);
+       free(fingerprint);
 
        char filename[PATH_MAX], usedname[PATH_MAX];
        snprintf(filename, sizeof filename, "%s" SLASH "invitations" SLASH "%s", confbase, cookie);
@@ -324,7 +336,7 @@ bool id_h(connection_t *c, const char *request) {
 
        if(c->protocol_major != myself->connection->protocol_major) {
                logger(DEBUG_ALWAYS, LOG_ERR, "Peer %s (%s) uses incompatible version %d.%d",
-                          c->name, c->hostname, c->protocol_major, c->protocol_minor);
+                       c->name, c->hostname, c->protocol_major, c->protocol_minor);
                return false;
        }
 
@@ -346,15 +358,21 @@ bool id_h(connection_t *c, const char *request) {
                        return false;
                }
 
-               if(experimental && c->protocol_minor >= 2) {
-                       if(!read_ecdsa_public_key(c))
-                               return false;
-               }
+               if(experimental)
+                       read_ecdsa_public_key(c);
        } else {
                if(c->protocol_minor && !ecdsa_active(c->ecdsa))
                        c->protocol_minor = 1;
        }
 
+       /* Forbid version rollback for nodes whose ECDSA key we know */
+
+       if(ecdsa_active(c->ecdsa) && c->protocol_minor < 2) {
+               logger(DEBUG_ALWAYS, LOG_ERR, "Peer %s (%s) tries to roll back protocol version to %d.%d",
+                       c->name, c->hostname, c->protocol_major, c->protocol_minor);
+               return false;
+       }
+
        c->allow_request = METAKEY;
 
        if(c->protocol_minor >= 2) {