From: Guus Sliepen Date: Sat, 25 Feb 2012 17:25:21 +0000 (+0100) Subject: Use SPTPS when ExperimentalProtocol is enabled. X-Git-Tag: release-1.1pre3~150 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=65d6f023c46ac3a087f59b60762f87c869783f21;p=oweals%2Ftinc.git Use SPTPS when ExperimentalProtocol is enabled. --- diff --git a/src/Makefile.am b/src/Makefile.am index ba8b347..255ce34 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 \ 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 \ - 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 if UML @@ -31,7 +31,7 @@ nodist_tincctl_SOURCES = \ sptps_test_SOURCES = \ 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 tincd_SOURCES += bsd/tunemu.c diff --git a/src/connection.c b/src/connection.c index 9587819..b61609a 100644 --- a/src/connection.c +++ b/src/connection.c @@ -69,7 +69,7 @@ void free_connection(connection_t *c) { cipher_close(&c->outcipher); digest_close(&c->outdigest); - ecdh_free(&c->ecdh); + stop_sptps(&c->sptps); ecdsa_free(&c->ecdsa); rsa_free(&c->rsa); diff --git a/src/connection.h b/src/connection.h index 20e0076..2d84ace 100644 --- a/src/connection.h +++ b/src/connection.h @@ -26,6 +26,7 @@ #include "digest.h" #include "rsa.h" #include "splay_tree.h" +#include "sptps.h" #define OPTION_INDIRECT 0x0001 #define OPTION_TCPONLY 0x0002 @@ -73,11 +74,11 @@ typedef struct connection_t { rsa_t rsa; /* his public RSA 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 outcipher; /* Cipher we will use to send data to him */ digest_t indigest; digest_t outdigest; + sptps_t sptps; int inmaclength; int outmaclength; diff --git a/src/meta.c b/src/meta.c index 29dd824..baa4c2e 100644 --- a/src/meta.c +++ b/src/meta.c @@ -31,6 +31,22 @@ #include "utils.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) { if(!c) { 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, c->name, c->hostname); + if(c->protocol_minor >= 2) + return send_record(&c->sptps, 0, buffer, length); + /* Add our data to buffer */ if(c->status.encryptout) { 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) { int inlen; char inbuf[MAXBUFSIZE]; @@ -107,6 +161,11 @@ bool receive_meta(connection_t *c) { } 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) { endp = memchr(bufp, '\n', inlen); if(endp) diff --git a/src/meta.h b/src/meta.h index bc81a6a..011aff5 100644 --- a/src/meta.h +++ b/src/meta.h @@ -24,6 +24,8 @@ #include "connection.h" 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 bool receive_meta(struct connection_t *); diff --git a/src/protocol_auth.c b/src/protocol_auth.c index a542ca9..65e9634 100644 --- a/src/protocol_auth.c +++ b/src/protocol_auth.c @@ -31,12 +31,14 @@ #include "edge.h" #include "graph.h" #include "logger.h" +#include "meta.h" #include "net.h" #include "netutl.h" #include "node.h" #include "prf.h" #include "protocol.h" #include "rsa.h" +#include "sptps.h" #include "utils.h" #include "xalloc.h" @@ -122,9 +124,10 @@ bool id_h(connection_t *c, char *request) { return false; } - if(experimental && c->protocol_minor >= 2) + if(experimental && c->protocol_minor >= 2) { if(!read_ecdsa_public_key(c)) return false; + } } else { if(c->protocol_minor && !ecdsa_active(&c->ecdsa)) c->protocol_minor = 1; @@ -132,30 +135,19 @@ bool id_h(connection_t *c, char *request) { c->allow_request = METAKEY; - if(c->protocol_minor >= 2) - return send_metakey_ec(c); - else - 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(c->protocol_minor >= 2) { + c->allow_request = ACK; + char label[25 + strlen(myself->name) + strlen(c->name)]; - if(!ecdsa_sign(&myself->connection->ecdsa, key, ECDH_SIZE, key + ECDH_SIZE)) - return false; + if(c->outgoing) + snprintf(label, sizeof label, "tinc TCP key expansion %s %s", myself->name, c->name); + else + snprintf(label, sizeof label, "tinc TCP key expansion %s %s", c->name, myself->name); - b64encode(key, key, ECDH_SIZE + siglen); - - return send_request(c, "%d %s", METAKEY, key); + 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); + } } bool send_metakey(connection_t *c) { @@ -223,84 +215,7 @@ bool send_metakey(connection_t *c) { 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) { - if(c->protocol_minor >= 2) - return metakey_ec_h(c, request); - char hexkey[MAX_STRING_SIZE]; int cipher, digest, maclength, compression; 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) { - 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]; if(!c->hischallenge) @@ -376,7 +291,7 @@ bool send_challenge(connection_t *c) { bool challenge_h(connection_t *c, char *request) { 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); char digest[digestlen]; @@ -434,7 +349,7 @@ bool chal_reply_h(connection_t *c, char *request) { /* 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"); return false; } diff --git a/src/sptps.c b/src/sptps.c index 6668763..5088d65 100644 --- a/src/sptps.c +++ b/src/sptps.c @@ -27,9 +27,6 @@ #include "prf.h" #include "sptps.h" -char *logfilename; -#include "utils.c" - /* Nonce MUST be exchanged first (done) 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). static bool send_record_priv(sptps_t *s, uint8_t type, const char *data, uint16_t len) { char buffer[len + 23UL]; - //char ciphertext[len + 19]; // Create header with sequence number, length and record type 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. if(!receive_ack(s, data, len)) return false; + s->receive_record(s->handle, SPTPS_HANDSHAKE, NULL, 0); s->state = SPTPS_SECONDARY_KEX; return true; // TODO: split ACK into a VERify and ACK? diff --git a/src/sptps.h b/src/sptps.h index f0d2592..17dfa9c 100644 --- a/src/sptps.h +++ b/src/sptps.h @@ -17,6 +17,9 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#ifndef __SPTPS_H__ +#define __SPTPS_H__ + #include "system.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 receive_data(sptps_t *s, const char *data, size_t len); extern bool force_kex(sptps_t *s); + +#endif diff --git a/src/sptps_test.c b/src/sptps_test.c index 866159e..6ab7dac 100644 --- a/src/sptps_test.c +++ b/src/sptps_test.c @@ -25,6 +25,7 @@ #include "sptps.h" #include "utils.h" +char *logfilename; ecdsa_t mykey, hiskey; static bool send_data(void *handle, const char *data, size_t len) {