AC_CACHE_SAVE
+AC_ARG_ENABLE(legacy-protocol,
+ AS_HELP_STRING([--disable-legacy-protocol], [disable support for the legacy (tinc 1.0) protocol]),
+ [ AS_IF([test "x$enable_legacy_protocol" = "xno"],
+ [ AC_DEFINE(DISABLE_LEGACY, 1, [Disable support for the legacy (tinc 1.0) protocol]) ])
+ ]
+)
+
dnl These are defined in files in m4/
dnl AC_ARG_WITH(libgcrypt, AC_HELP_STRING([--with-libgcrypt], [enable use of libgcrypt instead of OpenSSL])], [])
+dnl AC_ARG_WITH(openssl, AC_HELP_STRING([--without-openssl], [disable support for OpenSSL])], [])
tinc_CURSES
tinc_READLINE
tinc_ZLIB
tinc_LZO
-if test -n "$with_libgcrypt"; then
- gcrypt=true
- tinc_LIBGCRYPT
-else
- openssl=true
- tinc_OPENSSL
+if test "x$enable_legacy_protocol" != "xno"; then
+ if test -n "$with_libgcrypt"; then
+ gcrypt=true
+ tinc_LIBGCRYPT
+ else
+ openssl=true
+ tinc_OPENSSL
+ fi
fi
-
+
AM_CONDITIONAL(OPENSSL, test -n "$openssl")
AM_CONDITIONAL(GCRYPT, test -n "$gcrypt")
utils.c utils.h \
xalloc.h \
version.c version.h \
+ ed25519/ecdh.c \
+ ed25519/ecdsa.c \
$(ed25519_SOURCES) \
$(chacha_poly1305_SOURCES)
top.c top.h \
utils.c utils.h \
version.c version.h \
+ ed25519/ecdh.c \
+ ed25519/ecdsa.c \
+ ed25519/ecdsagen.c \
$(ed25519_SOURCES) \
$(chacha_poly1305_SOURCES)
sptps.c sptps.h \
sptps_test.c \
utils.c utils.h \
+ ed25519/ecdh.c \
+ ed25519/ecdsa.c \
$(ed25519_SOURCES) \
$(chacha_poly1305_SOURCES)
sptps_keypair_SOURCES = \
sptps_keypair.c \
utils.c utils.h \
+ ed25519/ecdsagen.c \
$(ed25519_SOURCES)
sptps_speed_SOURCES = \
sptps.c sptps.h \
sptps_speed.c \
utils.c utils.h \
+ ed25519/ecdh.c \
+ ed25519/ecdsa.c \
+ ed25519/ecdsagen.c \
$(ed25519_SOURCES) \
$(chacha_poly1305_SOURCES)
openssl/cipher.c \
openssl/crypto.c \
openssl/digest.c openssl/digest.h \
- ed25519/ecdh.c \
- ed25519/ecdsa.c \
openssl/prf.c \
openssl/rsa.c
tinc_SOURCES += \
openssl/cipher.c \
openssl/crypto.c \
openssl/digest.c openssl/digest.h \
- ed25519/ecdh.c \
- ed25519/ecdsa.c \
- ed25519/ecdsagen.c \
openssl/prf.c \
openssl/rsa.c \
openssl/rsagen.c
sptps_test_SOURCES += \
openssl/crypto.c \
openssl/digest.c openssl/digest.h \
- ed25519/ecdh.c \
- ed25519/ecdsa.c \
openssl/prf.c
sptps_keypair_SOURCES += \
- openssl/crypto.c \
- ed25519/ecdsagen.c
+ openssl/crypto.c
sptps_speed_SOURCES += \
openssl/crypto.c \
openssl/digest.c openssl/digest.h \
- ed25519/ecdh.c \
- ed25519/ecdsa.c \
- ed25519/ecdsagen.c \
openssl/prf.c
-endif
-
-if GCRYPT
+elif GCRYPT
tincd_SOURCES += \
gcrypt/cipher.c \
gcrypt/crypto.c \
gcrypt/digest.c gcrypt/digest.h \
- gcrypt/ecdh.c \
- gcrypt/ecdsa.c \
gcrypt/prf.c \
gcrypt/rsa.c
tinc_SOURCES += \
gcrypt/cipher.c \
gcrypt/crypto.c \
gcrypt/digest.c gcrypt/digest.h \
- gcrypt/ecdh.c \
- gcrypt/ecdsa.c \
- gcrypt/ecdsagen.c \
gcrypt/prf.c \
gcrypt/rsa.c \
gcrypt/rsagen.c
gcrypt/cipher.c \
gcrypt/crypto.c \
gcrypt/digest.c gcrypt/digest.h \
- gcrypt/ecdh.c \
- gcrypt/ecdsa.c \
gcrypt/prf.c
+sptps_keypair_SOURCES += \
+ openssl/crypto.c
+sptps_speed_SOURCES += \
+ openssl/crypto.c \
+ openssl/digest.c openssl/digest.h \
+ openssl/prf.c
+else
+tincd_SOURCES += \
+ nolegacy/crypto.c \
+ nolegacy/prf.c
+tinc_SOURCES += \
+ nolegacy/crypto.c \
+ nolegacy/prf.c
+sptps_test_SOURCES += \
+ nolegacy/crypto.c \
+ nolegacy/prf.c
+sptps_keypair_SOURCES += \
+ nolegacy/crypto.c
+sptps_speed_SOURCES += \
+ nolegacy/crypto.c \
+ nolegacy/prf.c
endif
tinc_LDADD = $(READLINE_LIBS) $(CURSES_LIBS)
#define CIPHER_MAX_IV_SIZE 16
#define CIPHER_MAX_KEY_SIZE 32
+#ifndef DISABLE_LEGACY
+
typedef struct cipher cipher_t;
extern cipher_t *cipher_open_by_name(const char *) __attribute__ ((__malloc__));
extern bool cipher_active(const cipher_t *);
#endif
+
+#endif
if(!c)
return;
+#ifndef DISABLE_LEGACY
cipher_close(c->incipher);
digest_close(c->indigest);
cipher_close(c->outcipher);
digest_close(c->outdigest);
+ rsa_free(c->rsa);
+#endif
sptps_stop(&c->sptps);
ecdsa_free(c->ecdsa);
- rsa_free(c->rsa);
free(c->hischallenge);
struct node_t *node; /* node associated with the other end */
struct edge_t *edge; /* edge associated with this connection */
+#ifndef DISABLE_LEGACY
rsa_t *rsa; /* his public RSA key */
- ecdsa_t *ecdsa; /* his public ECDSA key */
cipher_t *incipher; /* Cipher he will use to send data to us */
cipher_t *outcipher; /* Cipher we will use to send data to him */
digest_t *indigest;
digest_t *outdigest;
+#endif
+
+ ecdsa_t *ecdsa; /* his public ECDSA key */
sptps_t sptps;
int inmaclength;
#define DIGEST_MAX_SIZE 64
+#ifndef DISABLE_LEGACY
+
typedef struct digest digest_t;
extern digest_t *digest_open_by_name(const char *name, int maclength) __attribute__ ((__malloc__));
extern bool digest_active(const digest_t *);
#endif
+
+#endif
#include "utils.h"
#include "xalloc.h"
+#include "ed25519/sha512.h"
+
int addressfamily = AF_UNSPEC;
static void scan_for_hostname(const char *filename, char **hostname, char **port) {
}
}
- char hash[25];
-
xasprintf(&filename, "%s" SLASH "invitations", confbase);
if(mkdir(filename, 0700) && errno != EEXIST) {
fprintf(stderr, "Could not create directory %s: %s\n", filename, strerror(errno));
return 1;
// Create a hash of the key.
+ char hash[64];
char *fingerprint = ecdsa_get_base64_public_key(key);
- digest_t *digest = digest_open_by_name("sha256", 18);
- if(!digest)
- abort();
- digest_create(digest, fingerprint, strlen(fingerprint), hash);
+ sha512(fingerprint, strlen(fingerprint), hash);
b64encode_urlsafe(hash, hash, 18);
// Create a random cookie for this invitation.
// Create a filename that doesn't reveal the cookie itself
char buf[18 + strlen(fingerprint)];
- char cookiehash[25];
+ char cookiehash[64];
memcpy(buf, cookie, 18);
memcpy(buf + 18, fingerprint, sizeof buf - 18);
- digest_create(digest, buf, sizeof buf, cookiehash);
+ sha512(buf, sizeof buf, cookiehash);
b64encode_urlsafe(cookiehash, cookiehash, 18);
b64encode_urlsafe(cookie, cookie, 18);
sptps_send_record(&sptps, 1, b64key, strlen(b64key));
free(b64key);
+ ecdsa_free(key);
-
+#ifndef DISABLE_LEGACY
rsa_t *rsa = rsa_generate(2048, 0x1001);
xasprintf(&filename, "%s" SLASH "rsa_key.priv", confbase);
f = fopenmask(filename, "w", 0600);
rsa_write_pem_public_key(rsa, fh);
fclose(fh);
- ecdsa_free(key);
rsa_free(rsa);
+#endif
check_port(name);
// Check if the hash of the key he gave us matches the hash in the URL.
char *fingerprint = line + 2;
- digest_t *digest = digest_open_by_name("sha256", 18);
- if(!digest)
- abort();
- char hishash[18];
- if(!digest_create(digest, fingerprint, strlen(fingerprint), hishash)) {
+ char hishash[64];
+ if(sha512(fingerprint, strlen(fingerprint), hishash)) {
fprintf(stderr, "Could not create digest\n%s\n", line + 2);
return 1;
}
/* Add our data to buffer */
if(c->status.encryptout) {
+#ifdef DISABLE_LEGACY
+ return false;
+#else
size_t outlen = length;
if(!cipher_encrypt(c->outcipher, buffer, length, buffer_prepare(&c->outbuf, length), &outlen, false) || outlen != length) {
c->name, c->hostname);
return false;
}
+#endif
} else {
buffer_add(&c->outbuf, buffer, length);
}
inlen -= endp - bufp;
bufp = endp;
} else {
+#ifdef DISABLE_LEGACY
+ return false;
+#else
size_t outlen = inlen;
if(!cipher_decrypt(c->incipher, bufp, inlen, buffer_prepare(&c->inbuf, inlen), &outlen, false) || inlen != outlen) {
}
inlen = 0;
+#endif
}
while(c->inbuf.len) {
if(n->status.sptps)
return sptps_verify_datagram(&n->sptps, DATA(inpkt), inpkt->len);
+#ifdef DISABLE_LEGACY
+ return false;
+#else
if(!digest_active(n->indigest) || inpkt->len < sizeof(seqno_t) + digest_length(n->indigest))
return false;
return digest_verify(n->indigest, SEQNO(inpkt), inpkt->len - digest_length(n->indigest), DATA(inpkt) + inpkt->len - digest_length(n->indigest));
+#endif
}
static bool receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
return true;
}
+#ifdef DISABLE_LEGACY
+ return false;
+#else
if(!n->status.validkey) {
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Got packet from %s (%s) but he hasn't got our key yet", n->name, n->hostname);
return false;
else
receive_packet(n, inpkt);
return true;
+#endif
}
void receive_tcppacket(connection_t *c, const char *buffer, int len) {
if(n->status.sptps)
return send_sptps_packet(n, origpkt);
+#ifdef DISABLE_LEGACY
+ return;
+#else
/* Make sure we have a valid key */
if(!n->status.validkey) {
end:
origpkt->len = origlen;
+#endif
}
static bool send_sptps_data_priv(node_t *to, node_t *from, int type, const void *data, size_t len) {
return c->ecdsa;
}
+#ifndef DISABLE_LEGACY
bool read_rsa_public_key(connection_t *c) {
if(ecdsa_active(c->ecdsa))
return true;
free(fname);
return c->rsa;
}
+#endif
static bool read_ecdsa_private_key(void) {
FILE *fp;
return invitation_key;
}
+#ifndef DISABLE_LEGACY
static bool read_rsa_private_key(void) {
FILE *fp;
char *fname;
free(fname);
return myself->connection->rsa;
}
+#endif
static timeout_t keyexpire_timeout;
myself->options |= PROT_MINOR << 24;
+#ifdef DISABLE_LEGACY
+ experimental = read_ecdsa_private_key();
+ if(!experimental) {
+ logger(DEBUG_ALWAYS, LOG_ERR, "No private key available, cannot start tinc!");
+ return false;
+ }
+#else
if(!get_config_bool(lookup_config(config_tree, "ExperimentalProtocol"), &experimental)) {
experimental = read_ecdsa_private_key();
if(!experimental)
return false;
}
}
+#endif
/* Ensure myport is numeric */
sptps_replaywin = replaywin;
}
+#ifndef DISABLE_LEGACY
/* Generate packet encryption key */
if(!get_config_string(lookup_config(config_tree, "Cipher"), &cipher))
}
free(digest);
+#endif
/* Compression */
c->status.connecting = true;
c->name = xstrdup(outgoing->name);
+#ifndef DISABLE_LEGACY
c->outcipher = myself->connection->outcipher;
c->outdigest = myself->connection->outdigest;
+#endif
c->outmaclength = myself->connection->outmaclength;
c->outcompression = myself->connection->outcompression;
c->last_ping_time = now.tv_sec;
c = new_connection();
c->name = xstrdup("<unknown>");
+#ifndef DISABLE_LEGACY
c->outcipher = myself->connection->outcipher;
c->outdigest = myself->connection->outdigest;
+#endif
c->outmaclength = myself->connection->outmaclength;
c->outcompression = myself->connection->outcompression;
#include "utils.h"
#include "xalloc.h"
-static digest_t *sha256;
+#include "ed25519/sha512.h"
splay_tree_t *node_tree;
static splay_tree_t *node_id_tree;
}
void init_nodes(void) {
- sha256 = digest_open_by_name("sha256", sizeof(node_id_t));
-
node_tree = splay_alloc_tree((splay_compare_t) node_compare, (splay_action_t) free_node);
node_id_tree = splay_alloc_tree((splay_compare_t) node_id_compare, NULL);
node_udp_cache = hash_alloc(0x100, sizeof(sockaddr_t));
hash_free(node_udp_cache);
splay_delete_tree(node_id_tree);
splay_delete_tree(node_tree);
-
- digest_close(sha256);
}
node_t *new_node(void) {
sockaddrfree(&n->address);
+#ifndef DISABLE_LEGACY
cipher_close(n->incipher);
digest_close(n->indigest);
cipher_close(n->outcipher);
digest_close(n->outdigest);
+#endif
ecdsa_free(n->ecdsa);
sptps_stop(&n->sptps);
}
void node_add(node_t *n) {
- digest_create(sha256, n->name, strlen(n->name), &n->id);
+ unsigned char buf[64];
+ sha512(n->name, strlen(n->name),buf);
+ memcpy(&n->id, buf, sizeof n->id);
splay_insert(node_tree, n);
splay_insert(node_id_tree, n);
sprintf(id + 2 * c, "%02hhx", n->id.x[c]);
id[sizeof id - 1] = 0;
send_request(c, "%d %d %s %s %s %d %d %d %d %x %x %s %s %d %hd %hd %hd %ld", CONTROL, REQ_DUMP_NODES,
- n->name, id, n->hostname ?: "unknown port unknown", cipher_get_nid(n->outcipher),
- digest_get_nid(n->outdigest), (int)digest_length(n->outdigest), n->outcompression,
- n->options, bitfield_to_int(&n->status, sizeof n->status), n->nexthop ? n->nexthop->name : "-",
- n->via ? n->via->name ?: "-" : "-", n->distance, n->mtu, n->minmtu, n->maxmtu, (long)n->last_state_change);
+ n->name, id, n->hostname ?: "unknown port unknown",
+#ifdef DISABLE_LEGACY
+ 0, 0, 0,
+#else
+ cipher_get_nid(n->outcipher), digest_get_nid(n->outdigest), (int)digest_length(n->outdigest),
+#endif
+ n->outcompression, n->options, bitfield_to_int(&n->status, sizeof n->status),
+ n->nexthop ? n->nexthop->name : "-", n->via ? n->via->name ?: "-" : "-", n->distance,
+ n->mtu, n->minmtu, n->maxmtu, (long)n->last_state_change);
}
return send_request(c, "%d %d", CONTROL, REQ_DUMP_NODES);
ecdsa_t *ecdsa; /* His public ECDSA key */
sptps_t sptps;
+#ifndef DISABLE_LEGACY
cipher_t *incipher; /* Cipher for UDP packets */
digest_t *indigest; /* Digest for UDP packets */
cipher_t *outcipher; /* Cipher for UDP packets */
digest_t *outdigest; /* Digest for UDP packets */
+#endif
int incompression; /* Compressionlevel, 0 = no compression */
int outcompression; /* Compressionlevel, 0 = no compression */
#include "utils.h"
#include "xalloc.h"
+#include "ed25519/sha512.h"
+
ecdsa_t *invitation_key = NULL;
static bool send_proxyrequest(connection_t *c) {
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];
+ char cookie[64];
memcpy(hashbuf, data, 18);
memcpy(hashbuf + 18, fingerprint, sizeof hashbuf - 18);
- digest_create(digest, hashbuf, sizeof hashbuf, cookie);
+ sha512(hashbuf, sizeof hashbuf, cookie);
b64encode_urlsafe(cookie, cookie, 18);
- digest_close(digest);
free(fingerprint);
char filename[PATH_MAX], usedname[PATH_MAX];
}
bool send_metakey(connection_t *c) {
+#ifdef DISABLE_LEGACY
+ return false;
+#else
if(!myself->connection->rsa) {
logger(DEBUG_CONNECTIONS, LOG_ERR, "Peer %s (%s) uses legacy protocol which we don't support", c->name, c->hostname);
return false;
c->status.encryptout = true;
return result;
+#endif
}
bool metakey_h(connection_t *c, const char *request) {
+#ifdef DISABLE_LEGACY
+ return false;
+#else
if(!myself->connection->rsa)
return false;
c->allow_request = CHALLENGE;
return send_challenge(c);
+#endif
}
bool send_challenge(connection_t *c) {
+#ifdef DISABLE_LEGACY
+ return false;
+#else
const size_t len = rsa_size(c->rsa);
char buffer[len * 2 + 1];
/* Send the challenge */
return send_request(c, "%d %s", CHALLENGE, buffer);
+#endif
}
bool challenge_h(connection_t *c, const char *request) {
+#ifdef DISABLE_LEGACY
+ return false;
+#else
if(!myself->connection->rsa)
return false;
c->allow_request = CHAL_REPLY;
return send_request(c, "%d %s", CHAL_REPLY, buffer);
+#endif
}
bool chal_reply_h(connection_t *c, const char *request) {
+#ifdef DISABLE_LEGACY
+ return false;
+#else
char hishash[MAX_STRING_SIZE];
if(sscanf(request, "%*d " MAX_STRING, hishash) != 1) {
c->allow_request = ACK;
return send_ack(c);
+#endif
}
static bool send_upgrade(connection_t *c) {
+#ifdef DISABLE_LEGACY
+ return false;
+#else
/* Special case when protocol_minor is 1: the other end is Ed25519 capable,
* but doesn't know our key yet. So send it now. */
bool result = send_request(c, "%d %s", ACK, pubkey);
free(pubkey);
return result;
+#endif
}
bool send_ack(connection_t *c) {
if(to->status.sptps)
abort();
+#ifdef DISABLE_LEGACY
+ return false;
+#else
size_t keylen = myself->incipher ? cipher_keylength(myself->incipher) : 1;
char key[keylen * 2 + 1];
digest_get_nid(to->indigest),
(int)digest_length(to->indigest),
to->incompression);
+#endif
}
bool ans_key_h(connection_t *c, const char *request) {
return send_request(to->nexthop->connection, "%s", request);
}
+#ifndef DISABLE_LEGACY
/* Don't use key material until every check has passed. */
cipher_close(from->outcipher);
digest_close(from->outdigest);
+#endif
from->status.validkey = false;
if(compression < 0 || compression > 11) {
return true;
}
+#ifdef DISABLE_LEGACY
+ logger(DEBUG_ALWAYS, LOG_ERR, "Node %s (%) uses legacy protocol!", from->name, from->hostname);
+ return false;
+#else
/* Check and lookup cipher and digest algorithms */
if(cipher) {
send_mtu_probe(from);
return true;
+#endif
}
" restart [tincd options] Restart tincd.\n"
" reload Partially reload configuration of running tincd.\n"
" pid Show PID of currently running tincd.\n"
+#ifdef DISABLE_LEGACY
+ " generate-keys Generate a new Ed25519 public/private keypair.\n"
+#else
" generate-keys [bits] Generate new RSA and Ed25519 public/private keypairs.\n"
" generate-rsa-keys [bits] Generate a new RSA public/private keypair.\n"
+#endif
" generate-ed25519-keys Generate a new Ed25519 public/private keypair.\n"
" dump Dump a list of one of the following things:\n"
" [reachable] nodes - all known nodes in the VPN\n"
return true;
}
+#ifndef DISABLE_LEGACY
/*
Generate a public/private RSA keypair, and ask for a file to store
them in.
return true;
}
+#endif
char buffer[4096];
size_t blen = 0;
fprintf(f, "Name = %s\n", name);
fclose(f);
- if(!rsa_keygen(2048, false) || !ed25519_keygen(false))
+#ifndef DISABLE_LEGACY
+ if(!rsa_keygen(2048, false))
+ return 1;
+#endif
+
+ if(!ed25519_keygen(false))
return 1;
check_port(name);
}
static int cmd_generate_keys(int argc, char *argv[]) {
+#ifdef DISABLE_LEGACY
+ if(argc > 1) {
+#else
if(argc > 2) {
+#endif
fprintf(stderr, "Too many arguments!\n");
return 1;
}
if(!name)
name = get_my_name(false);
- return !(rsa_keygen(argc > 1 ? atoi(argv[1]) : 2048, true) && ed25519_keygen(true));
+#ifndef DISABLE_LEGACY
+ if(!rsa_keygen(argc > 1 ? atoi(argv[1]) : 2048, true)
+ return 1;
+#endif
+
+ if(!ed25519_keygen(true))
+ return 1;
+
+ return 0;
}
+#ifndef DISABLE_LEGACY
static int cmd_generate_rsa_keys(int argc, char *argv[]) {
if(argc > 2) {
fprintf(stderr, "Too many arguments!\n");
return !rsa_keygen(argc > 1 ? atoi(argv[1]) : 2048, true);
}
+#endif
static int cmd_generate_ed25519_keys(int argc, char *argv[]) {
if(argc > 1) {
{"set", cmd_config},
{"init", cmd_init},
{"generate-keys", cmd_generate_keys},
+#ifndef DISABLE_LEGACY
{"generate-rsa-keys", cmd_generate_rsa_keys},
+#endif
{"generate-ed25519-keys", cmd_generate_ed25519_keys},
{"help", cmd_help},
{"version", cmd_version},