Use SPTPS when ExperimentalProtocol is enabled.

This commit is contained in:
Guus Sliepen 2012-02-25 18:25:21 +01:00
parent efd21e232d
commit 65d6f023c4
9 changed files with 92 additions and 112 deletions

View file

@ -8,7 +8,7 @@ tincd_SOURCES = \
utils.c getopt.c getopt1.c list.c splay_tree.c dropin.c fake-getaddrinfo.c fake-getnameinfo.c \ utils.c getopt.c getopt1.c list.c splay_tree.c dropin.c fake-getaddrinfo.c fake-getnameinfo.c \
buffer.c conf.c connection.c control.c edge.c graph.c logger.c meta.c net.c net_packet.c net_setup.c \ buffer.c conf.c connection.c control.c edge.c graph.c logger.c meta.c net.c net_packet.c net_setup.c \
net_socket.c netutl.c node.c process.c protocol.c protocol_auth.c protocol_edge.c protocol_misc.c \ net_socket.c netutl.c node.c process.c protocol.c protocol_auth.c protocol_edge.c protocol_misc.c \
protocol_key.c protocol_subnet.c route.c subnet.c tincd.c \ protocol_key.c protocol_subnet.c route.c sptps.c subnet.c tincd.c \
dummy_device.c raw_socket_device.c dummy_device.c raw_socket_device.c
if UML if UML
@ -31,7 +31,7 @@ nodist_tincctl_SOURCES = \
sptps_test_SOURCES = \ sptps_test_SOURCES = \
logger.c cipher.c crypto.c ecdh.c ecdsa.c digest.c prf.c \ logger.c cipher.c crypto.c ecdh.c ecdsa.c digest.c prf.c \
sptps.c sptps_test.c sptps.c sptps_test.c utils.c
if TUNEMU if TUNEMU
tincd_SOURCES += bsd/tunemu.c tincd_SOURCES += bsd/tunemu.c

View file

@ -69,7 +69,7 @@ void free_connection(connection_t *c) {
cipher_close(&c->outcipher); cipher_close(&c->outcipher);
digest_close(&c->outdigest); digest_close(&c->outdigest);
ecdh_free(&c->ecdh); stop_sptps(&c->sptps);
ecdsa_free(&c->ecdsa); ecdsa_free(&c->ecdsa);
rsa_free(&c->rsa); rsa_free(&c->rsa);

View file

@ -26,6 +26,7 @@
#include "digest.h" #include "digest.h"
#include "rsa.h" #include "rsa.h"
#include "splay_tree.h" #include "splay_tree.h"
#include "sptps.h"
#define OPTION_INDIRECT 0x0001 #define OPTION_INDIRECT 0x0001
#define OPTION_TCPONLY 0x0002 #define OPTION_TCPONLY 0x0002
@ -73,11 +74,11 @@ typedef struct connection_t {
rsa_t rsa; /* his public RSA key */ rsa_t rsa; /* his public RSA key */
ecdsa_t ecdsa; /* his public ECDSA key */ ecdsa_t ecdsa; /* his public ECDSA key */
ecdsa_t ecdh; /* state for ECDH key exchange */
cipher_t incipher; /* Cipher he will use to send data to us */ cipher_t incipher; /* Cipher he will use to send data to us */
cipher_t outcipher; /* Cipher we will use to send data to him */ cipher_t outcipher; /* Cipher we will use to send data to him */
digest_t indigest; digest_t indigest;
digest_t outdigest; digest_t outdigest;
sptps_t sptps;
int inmaclength; int inmaclength;
int outmaclength; int outmaclength;

View file

@ -31,6 +31,22 @@
#include "utils.h" #include "utils.h"
#include "xalloc.h" #include "xalloc.h"
bool send_meta_sptps(void *handle, const char *buffer, size_t length) {
connection_t *c = handle;
if(!c) {
logger(LOG_ERR, "send_meta_sptps() called with NULL pointer!");
abort();
}
logger(LOG_DEBUG, "send_meta_sptps(%s, %p, %zu)", c->name, buffer, length);
buffer_add(&c->outbuf, buffer, length);
event_add(&c->outevent, NULL);
return true;
}
bool send_meta(connection_t *c, const char *buffer, int length) { bool send_meta(connection_t *c, const char *buffer, int length) {
if(!c) { if(!c) {
logger(LOG_ERR, "send_meta() called with NULL pointer!"); logger(LOG_ERR, "send_meta() called with NULL pointer!");
@ -40,6 +56,9 @@ bool send_meta(connection_t *c, const char *buffer, int length) {
ifdebug(META) logger(LOG_DEBUG, "Sending %d bytes of metadata to %s (%s)", length, ifdebug(META) logger(LOG_DEBUG, "Sending %d bytes of metadata to %s (%s)", length,
c->name, c->hostname); c->name, c->hostname);
if(c->protocol_minor >= 2)
return send_record(&c->sptps, 0, buffer, length);
/* Add our data to buffer */ /* Add our data to buffer */
if(c->status.encryptout) { if(c->status.encryptout) {
size_t outlen = length; size_t outlen = length;
@ -71,6 +90,41 @@ void broadcast_meta(connection_t *from, const char *buffer, int length) {
} }
} }
bool receive_meta_sptps(void *handle, uint8_t type, const char *data, uint16_t length) {
connection_t *c = handle;
if(!c) {
logger(LOG_ERR, "receive_meta_sptps() called with NULL pointer!");
abort();
}
logger(LOG_DEBUG, "receive_meta_sptps(%s, %d, %p, %hu)", c->name, type, data, length);
if(type == SPTPS_HANDSHAKE) {
if(c->allow_request == ACK)
return send_ack(c);
else
return true;
}
if(!data)
return true;
/* Are we receiving a TCPpacket? */
if(c->tcplen) {
if(length != c->tcplen)
return false;
receive_tcppacket(c, data, length);
c->tcplen = 0;
return true;
}
/* Otherwise we are waiting for a request */
return receive_request(c, data);
}
bool receive_meta(connection_t *c) { bool receive_meta(connection_t *c) {
int inlen; int inlen;
char inbuf[MAXBUFSIZE]; char inbuf[MAXBUFSIZE];
@ -107,6 +161,11 @@ bool receive_meta(connection_t *c) {
} }
do { do {
if(c->protocol_minor >= 2) {
logger(LOG_DEBUG, "Receiving %d bytes of SPTPS data", inlen);
return receive_data(&c->sptps, bufp, inlen);
}
if(!c->status.decryptin) { if(!c->status.decryptin) {
endp = memchr(bufp, '\n', inlen); endp = memchr(bufp, '\n', inlen);
if(endp) if(endp)

View file

@ -24,6 +24,8 @@
#include "connection.h" #include "connection.h"
extern bool send_meta(struct connection_t *, const char *, int); extern bool send_meta(struct connection_t *, const char *, int);
extern bool send_meta_sptps(void *, const char *, size_t);
extern bool receive_meta_sptps(void *, uint8_t, const char *, uint16_t);
extern void broadcast_meta(struct connection_t *, const char *, int); extern void broadcast_meta(struct connection_t *, const char *, int);
extern bool receive_meta(struct connection_t *); extern bool receive_meta(struct connection_t *);

View file

@ -31,12 +31,14 @@
#include "edge.h" #include "edge.h"
#include "graph.h" #include "graph.h"
#include "logger.h" #include "logger.h"
#include "meta.h"
#include "net.h" #include "net.h"
#include "netutl.h" #include "netutl.h"
#include "node.h" #include "node.h"
#include "prf.h" #include "prf.h"
#include "protocol.h" #include "protocol.h"
#include "rsa.h" #include "rsa.h"
#include "sptps.h"
#include "utils.h" #include "utils.h"
#include "xalloc.h" #include "xalloc.h"
@ -122,9 +124,10 @@ bool id_h(connection_t *c, char *request) {
return false; return false;
} }
if(experimental && c->protocol_minor >= 2) if(experimental && c->protocol_minor >= 2) {
if(!read_ecdsa_public_key(c)) if(!read_ecdsa_public_key(c))
return false; return false;
}
} else { } else {
if(c->protocol_minor && !ecdsa_active(&c->ecdsa)) if(c->protocol_minor && !ecdsa_active(&c->ecdsa))
c->protocol_minor = 1; c->protocol_minor = 1;
@ -132,30 +135,19 @@ bool id_h(connection_t *c, char *request) {
c->allow_request = METAKEY; c->allow_request = METAKEY;
if(c->protocol_minor >= 2) if(c->protocol_minor >= 2) {
return send_metakey_ec(c); c->allow_request = ACK;
char label[25 + strlen(myself->name) + strlen(c->name)];
if(c->outgoing)
snprintf(label, sizeof label, "tinc TCP key expansion %s %s", myself->name, c->name);
else else
snprintf(label, sizeof label, "tinc TCP key expansion %s %s", c->name, myself->name);
return start_sptps(&c->sptps, c, c->outgoing, myself->connection->ecdsa, c->ecdsa, label, sizeof label, send_meta_sptps, receive_meta_sptps);
} else {
return send_metakey(c); return send_metakey(c);
} }
bool send_metakey_ec(connection_t *c) {
logger(LOG_DEBUG, "Sending ECDH metakey to %s", c->name);
size_t siglen = ecdsa_size(&myself->connection->ecdsa);
char key[(ECDH_SIZE + siglen) * 2 + 1];
// TODO: include nonce? Use relevant parts of SSH or TLS protocol
if(!ecdh_generate_public(&c->ecdh, key))
return false;
if(!ecdsa_sign(&myself->connection->ecdsa, key, ECDH_SIZE, key + ECDH_SIZE))
return false;
b64encode(key, key, ECDH_SIZE + siglen);
return send_request(c, "%d %s", METAKEY, key);
} }
bool send_metakey(connection_t *c) { bool send_metakey(connection_t *c) {
@ -223,84 +215,7 @@ bool send_metakey(connection_t *c) {
return result; return result;
} }
static bool metakey_ec_h(connection_t *c, const char *request) {
size_t siglen = ecdsa_size(&c->ecdsa);
char key[MAX_STRING_SIZE];
logger(LOG_DEBUG, "Got ECDH metakey from %s", c->name);
if(sscanf(request, "%*d " MAX_STRING, key) != 1) {
logger(LOG_ERR, "Got bad %s from %s (%s)", "METAKEY", c->name, c->hostname);
return false;
}
int inlen = b64decode(key, key, sizeof key);
if(inlen != (ECDH_SIZE + siglen)) {
logger(LOG_ERR, "Possible intruder %s (%s): %s", c->name, c->hostname, "wrong keylength");
return false;
}
if(!ecdsa_verify(&c->ecdsa, key, ECDH_SIZE, key + ECDH_SIZE)) {
logger(LOG_ERR, "Possible intruder %s (%s): %s", c->name, c->hostname, "invalid ECDSA signature");
return false;
}
char shared[ECDH_SHARED_SIZE];
if(!ecdh_compute_shared(&c->ecdh, key, shared))
return false;
/* Update our crypto end */
if(!cipher_open_by_name(&c->incipher, "aes-256-ofb"))
return false;
if(!digest_open_by_name(&c->indigest, "sha512", -1))
return false;
if(!cipher_open_by_name(&c->outcipher, "aes-256-ofb"))
return false;
if(!digest_open_by_name(&c->outdigest, "sha512", -1))
return false;
size_t mykeylen = cipher_keylength(&c->incipher);
size_t hiskeylen = cipher_keylength(&c->outcipher);
char *mykey;
char *hiskey;
char *seed;
if(strcmp(myself->name, c->name) < 0) {
mykey = key;
hiskey = key + mykeylen * 2;
xasprintf(&seed, "tinc TCP key expansion %s %s", myself->name, c->name);
} else {
mykey = key + hiskeylen * 2;
hiskey = key;
xasprintf(&seed, "tinc TCP key expansion %s %s", c->name, myself->name);
}
if(!prf(shared, ECDH_SHARED_SIZE, seed, strlen(seed), key, hiskeylen * 2 + mykeylen * 2))
return false;
free(seed);
cipher_set_key(&c->incipher, mykey, false);
digest_set_key(&c->indigest, mykey + mykeylen, mykeylen);
cipher_set_key(&c->outcipher, hiskey, true);
digest_set_key(&c->outdigest, hiskey + hiskeylen, hiskeylen);
c->status.decryptin = true;
c->status.encryptout = true;
c->allow_request = CHALLENGE;
return send_challenge(c);
}
bool metakey_h(connection_t *c, char *request) { bool metakey_h(connection_t *c, char *request) {
if(c->protocol_minor >= 2)
return metakey_ec_h(c, request);
char hexkey[MAX_STRING_SIZE]; char hexkey[MAX_STRING_SIZE];
int cipher, digest, maclength, compression; int cipher, digest, maclength, compression;
size_t len = rsa_size(&myself->connection->rsa); size_t len = rsa_size(&myself->connection->rsa);
@ -355,7 +270,7 @@ bool metakey_h(connection_t *c, char *request) {
} }
bool send_challenge(connection_t *c) { bool send_challenge(connection_t *c) {
size_t len = c->protocol_minor >= 2 ? ECDH_SIZE : rsa_size(&c->rsa); size_t len = rsa_size(&c->rsa);
char buffer[len * 2 + 1]; char buffer[len * 2 + 1];
if(!c->hischallenge) if(!c->hischallenge)
@ -376,7 +291,7 @@ bool send_challenge(connection_t *c) {
bool challenge_h(connection_t *c, char *request) { bool challenge_h(connection_t *c, char *request) {
char buffer[MAX_STRING_SIZE]; char buffer[MAX_STRING_SIZE];
size_t len = c->protocol_minor >= 2 ? ECDH_SIZE : rsa_size(&myself->connection->rsa); size_t len = rsa_size(&myself->connection->rsa);
size_t digestlen = digest_length(&c->indigest); size_t digestlen = digest_length(&c->indigest);
char digest[digestlen]; char digest[digestlen];
@ -434,7 +349,7 @@ bool chal_reply_h(connection_t *c, char *request) {
/* Verify the hash */ /* Verify the hash */
if(!digest_verify(&c->outdigest, c->hischallenge, c->protocol_minor >= 2 ? ECDH_SIZE : rsa_size(&c->rsa), hishash)) { if(!digest_verify(&c->outdigest, c->hischallenge, rsa_size(&c->rsa), hishash)) {
logger(LOG_ERR, "Possible intruder %s (%s): %s", c->name, c->hostname, "wrong challenge reply"); logger(LOG_ERR, "Possible intruder %s (%s): %s", c->name, c->hostname, "wrong challenge reply");
return false; return false;
} }

View file

@ -27,9 +27,6 @@
#include "prf.h" #include "prf.h"
#include "sptps.h" #include "sptps.h"
char *logfilename;
#include "utils.c"
/* /*
Nonce MUST be exchanged first (done) Nonce MUST be exchanged first (done)
Signatures MUST be done over both nonces, to guarantee the signature is fresh Signatures MUST be done over both nonces, to guarantee the signature is fresh
@ -60,7 +57,6 @@ static bool error(sptps_t *s, int s_errno, const char *msg) {
// Send a record (private version, accepts all record types, handles encryption and authentication). // Send a record (private version, accepts all record types, handles encryption and authentication).
static bool send_record_priv(sptps_t *s, uint8_t type, const char *data, uint16_t len) { static bool send_record_priv(sptps_t *s, uint8_t type, const char *data, uint16_t len) {
char buffer[len + 23UL]; char buffer[len + 23UL];
//char ciphertext[len + 19];
// Create header with sequence number, length and record type // Create header with sequence number, length and record type
uint32_t seqno = htonl(s->outseqno++); uint32_t seqno = htonl(s->outseqno++);
@ -326,6 +322,7 @@ static bool receive_handshake(sptps_t *s, const char *data, uint16_t len) {
// We expect a handshake message to indicate transition to the new keys. // We expect a handshake message to indicate transition to the new keys.
if(!receive_ack(s, data, len)) if(!receive_ack(s, data, len))
return false; return false;
s->receive_record(s->handle, SPTPS_HANDSHAKE, NULL, 0);
s->state = SPTPS_SECONDARY_KEX; s->state = SPTPS_SECONDARY_KEX;
return true; return true;
// TODO: split ACK into a VERify and ACK? // TODO: split ACK into a VERify and ACK?

View file

@ -17,6 +17,9 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#ifndef __SPTPS_H__
#define __SPTPS_H__
#include "system.h" #include "system.h"
#include "cipher.h" #include "cipher.h"
@ -78,3 +81,5 @@ extern bool stop_sptps(sptps_t *s);
extern bool send_record(sptps_t *s, uint8_t type, const char *data, uint16_t len); extern bool send_record(sptps_t *s, uint8_t type, const char *data, uint16_t len);
extern bool receive_data(sptps_t *s, const char *data, size_t len); extern bool receive_data(sptps_t *s, const char *data, size_t len);
extern bool force_kex(sptps_t *s); extern bool force_kex(sptps_t *s);
#endif

View file

@ -25,6 +25,7 @@
#include "sptps.h" #include "sptps.h"
#include "utils.h" #include "utils.h"
char *logfilename;
ecdsa_t mykey, hiskey; ecdsa_t mykey, hiskey;
static bool send_data(void *handle, const char *data, size_t len) { static bool send_data(void *handle, const char *data, size_t len) {