Added excessive debug output to sptps

This commit is contained in:
thorkill 2015-12-10 17:08:03 +01:00
parent c94214500f
commit 1dd8033ea5
7 changed files with 107 additions and 27 deletions

View file

@ -31,7 +31,7 @@ libed25519_la_SOURCES = \
ed25519/precomp_data.h \ ed25519/precomp_data.h \
ed25519/sc.c ed25519/sc.h \ ed25519/sc.c ed25519/sc.h \
ed25519/sha512.c ed25519/sha512.h \ ed25519/sha512.c ed25519/sha512.h \
ed25519/ecdsa.c \ ed25519/ecdsa.c \
ed25519/sign.c \ ed25519/sign.c \
ed25519/verify.c ed25519/verify.c

View file

@ -249,8 +249,12 @@ static void check_reachability(void) {
n->status.validkey = false; n->status.validkey = false;
if(n->status.sptps) { if(n->status.sptps) {
sptps_stop(&n->sptps); sptps_t *s = &n->sptps;
n->status.waitingforkey = false; if (s->handle) {
logger(DEBUG_ALWAYS, LOG_INFO, "Sptps active with: %s state: %d/%d", n->name, s->state, s->outstate);
sptps_stop(&n->sptps);
n->status.waitingforkey = false;
}
} }
n->last_req_key = 0; n->last_req_key = 0;

View file

@ -127,12 +127,15 @@ static void sptps_logger(sptps_t *s, int s_errno, const char *format, va_list ap
if(message[len - 1] == '\n') if(message[len - 1] == '\n')
message[--len] = 0; message[--len] = 0;
len += snprintf(message + len, sizeof message - len,
" i: %d UDP: %d", s->initiator, s->datagram);
// WARNING: s->handle can point to a connection_t or a node_t, // WARNING: s->handle can point to a connection_t or a node_t,
// but both types have the name and hostname fields at the same offsets. // but both types have the name and hostname fields at the same offsets.
connection_t *c = s->handle; connection_t *c = s->handle;
if(c) if(c)
snprintf(message + len, sizeof message - len, snprintf(message + len, sizeof message - len,
" from %s (%s) [errno: %d]", c->name, c->hostname, s_errno); " %s %s (%s) [errno: %d]", s->initiator ? "to" : "from", c->name, c->hostname, s_errno);
} }
real_logger(DEBUG_ALWAYS, LOG_ERR, message); real_logger(DEBUG_ALWAYS, LOG_ERR, message);

View file

@ -1192,6 +1192,14 @@ static void try_tx_sptps(node_t *n, bool mtu) {
if(n->connection && ((myself->options | n->options) & OPTION_TCPONLY)) if(n->connection && ((myself->options | n->options) & OPTION_TCPONLY))
return; return;
if (n->sptps.initiator && n->sptps.state != SPTPS_SECONDARY_KEX) {
logger(DEBUG_ALWAYS, LOG_INFO, "%s:%d : with %s i: %d u: %d s: %d o: %d", __FUNCTION__, __LINE__,
n->name,
n->sptps.initiator, n->sptps.datagram,
n->sptps.state, n->sptps.outstate);
return;
}
/* Otherwise, try to do SPTPS authentication with n if necessary. */ /* Otherwise, try to do SPTPS authentication with n if necessary. */
try_sptps(n); try_sptps(n);

View file

@ -185,9 +185,9 @@ static bool finalize_invitation(connection_t *c, const char *data, uint16_t len)
char *address, *port; char *address, *port;
xasprintf(&envp[0], "NETNAME=%s", netname ? : ""); xasprintf(&envp[0], "NETNAME=%s", netname ? : "");
xasprintf(&envp[1], "DEVICE=%s", device ? : ""); xasprintf(&envp[1], "DEVICE=%s", device ? : "");
xasprintf(&envp[2], "INTERFACE=%s", iface ? : ""); xasprintf(&envp[2], "INTERFACE=%s", iface ? : "");
xasprintf(&envp[3], "NODE=%s", c->name); xasprintf(&envp[3], "NODE=%s", c->name);
sockaddr2str(&c->address, &address, &port); sockaddr2str(&c->address, &address, &port);
xasprintf(&envp[4], "REMOTEADDRESS=%s", address); xasprintf(&envp[4], "REMOTEADDRESS=%s", address);
xasprintf(&envp[5], "NAME=%s", myself->name); xasprintf(&envp[5], "NAME=%s", myself->name);
@ -297,7 +297,7 @@ bool id_h(connection_t *c, const char *request) {
c->status.control = true; c->status.control = true;
c->allow_request = CONTROL; c->allow_request = CONTROL;
c->last_ping_time = now; c->last_ping_time = now;
c->last_ping_time.tv_sec += 3600; c->last_ping_time.tv_sec += 3600;
free(c->name); free(c->name);
c->name = xstrdup("<control>"); c->name = xstrdup("<control>");
@ -405,7 +405,9 @@ bool id_h(connection_t *c, const char *request) {
else else
snprintf(label, sizeof label, "tinc TCP key expansion %s %s", c->name, myself->name); snprintf(label, sizeof label, "tinc TCP key expansion %s %s", c->name, myself->name);
return sptps_start(&c->sptps, c, c->outgoing, false, myself->connection->ecdsa, c->ecdsa, label, sizeof label, send_meta_sptps, receive_meta_sptps); return sptps_start(&c->sptps, c, c->outgoing ? true : false, false,
myself->connection->ecdsa, c->ecdsa, label, sizeof label,
send_meta_sptps, receive_meta_sptps);
} else { } else {
return send_metakey(c); return send_metakey(c);
} }

View file

@ -210,7 +210,7 @@ static bool req_key_ext_h(connection_t *c, const char *request, node_t *from, no
} }
if(from->sptps.label) if(from->sptps.label)
logger(DEBUG_ALWAYS, LOG_DEBUG, "Got REQ_KEY from %s while we already started a SPTPS session!", from->name); error(from->sptps, "Got REQ_KEY while we already started a SPTPS session!");
char buf[MAX_STRING_SIZE]; char buf[MAX_STRING_SIZE];
int len; int len;

View file

@ -29,8 +29,13 @@
#include "prf.h" #include "prf.h"
#include "sptps.h" #include "sptps.h"
#include <execinfo.h>
unsigned int sptps_replaywin = 16; unsigned int sptps_replaywin = 16;
void backtrace_cb(sptps_t *s);
/* /*
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
@ -136,11 +141,13 @@ static bool send_record_priv(sptps_t *s, uint8_t type, const void *data, uint16_
// Send an application record. // Send an application record.
bool sptps_send_record(sptps_t *s, uint8_t type, const void *data, uint16_t len) { bool sptps_send_record(sptps_t *s, uint8_t type, const void *data, uint16_t len) {
// Sanity checks: application cannot send data before handshake is finished, // Sanity checks: application cannot send data before handshake is finished,
// and only record types 0..127 are allowed. // and only record types 0..127 are allowed.
if(!s->outstate) if(!s->outstate) {
return error(s, EINVAL, "Handshake phase not finished yet"); //backtrace_cb(s);
return error(s, EINVAL, "Handshake phase not finished yet %x", s->outstate);
}
if(type >= SPTPS_HANDSHAKE) if(type >= SPTPS_HANDSHAKE)
return error(s, EINVAL, "Invalid application record type"); return error(s, EINVAL, "Invalid application record type");
@ -150,10 +157,12 @@ bool sptps_send_record(sptps_t *s, uint8_t type, const void *data, uint16_t len)
// Send a Key EXchange record, containing a random nonce and an ECDHE public key. // Send a Key EXchange record, containing a random nonce and an ECDHE public key.
static bool send_kex(sptps_t *s) { static bool send_kex(sptps_t *s) {
size_t keylen = ECDH_SIZE; size_t keylen = ECDH_SIZE;
// Make room for our KEX message, which we will keep around since send_sig() needs it. // Make room for our KEX message, which we will keep around since send_sig() needs it.
if(s->mykex) if(s->mykex) {
warning(s, "%s@%d: %x/%x\n", __FUNCTION__, __LINE__, s->state, s->outstate);
return false; return false;
}
s->mykex = realloc(s->mykex, 1 + 32 + keylen); s->mykex = realloc(s->mykex, 1 + 32 + keylen);
if(!s->mykex) if(!s->mykex)
return error(s, errno, strerror(errno)); return error(s, errno, strerror(errno));
@ -238,6 +247,7 @@ static bool send_ack(sptps_t *s) {
// Receive an ACKnowledgement record. // Receive an ACKnowledgement record.
static bool receive_ack(sptps_t *s, const char *data, uint16_t len) { static bool receive_ack(sptps_t *s, const char *data, uint16_t len) {
UNUSED(data); UNUSED(data);
if(len) if(len)
return error(s, EIO, "Invalid ACK record length"); return error(s, EIO, "Invalid ACK record length");
@ -258,6 +268,7 @@ static bool receive_ack(sptps_t *s, const char *data, uint16_t len) {
// Receive a Key EXchange record, respond by sending a SIG record. // Receive a Key EXchange record, respond by sending a SIG record.
static bool receive_kex(sptps_t *s, const char *data, uint16_t len) { static bool receive_kex(sptps_t *s, const char *data, uint16_t len) {
// Verify length of the HELLO record // Verify length of the HELLO record
if(len != 1 + 32 + ECDH_SIZE) if(len != 1 + 32 + ECDH_SIZE)
return error(s, EIO, "Invalid KEX record length"); return error(s, EIO, "Invalid KEX record length");
@ -267,6 +278,7 @@ static bool receive_kex(sptps_t *s, const char *data, uint16_t len) {
// Make a copy of the KEX message, send_sig() and receive_sig() need it // Make a copy of the KEX message, send_sig() and receive_sig() need it
if(s->hiskex) if(s->hiskex)
return error(s, EINVAL, "Received a second KEX message before first has been processed"); return error(s, EINVAL, "Received a second KEX message before first has been processed");
s->hiskex = realloc(s->hiskex, len); s->hiskex = realloc(s->hiskex, len);
if(!s->hiskex) if(!s->hiskex)
return error(s, errno, strerror(errno)); return error(s, errno, strerror(errno));
@ -301,11 +313,14 @@ static bool receive_sig(sptps_t *s, const char *data, uint16_t len) {
char shared[ECDH_SHARED_SIZE]; char shared[ECDH_SHARED_SIZE];
if(!ecdh_compute_shared(s->ecdh, s->hiskex + 1 + 32, shared)) if(!ecdh_compute_shared(s->ecdh, s->hiskex + 1 + 32, shared))
return error(s, EINVAL, "Failed to compute ECDH shared secret"); return error(s, EINVAL, "Failed to compute ECDH shared secret");
s->ecdh = NULL; s->ecdh = NULL;
// Generate key material from shared secret. // Generate key material from shared secret.
if(!generate_key_material(s, shared, sizeof shared)) if(!generate_key_material(s, shared, sizeof shared)) {
warning(s, "%s@%d: %x/%x\n", __FUNCTION__, __LINE__, s->state, s->outstate);
return false; return false;
}
free(s->mykex); free(s->mykex);
free(s->hiskex); free(s->hiskex);
@ -314,8 +329,10 @@ static bool receive_sig(sptps_t *s, const char *data, uint16_t len) {
s->hiskex = NULL; s->hiskex = NULL;
// Send cipher change record // Send cipher change record
if(s->outstate && !send_ack(s)) if(s->outstate && !send_ack(s)) {
warning(s, "%s@%d: %x/%x\n", __FUNCTION__, __LINE__, s->state, s->outstate);
return false; return false;
}
// TODO: only set new keys after ACK has been set/received // TODO: only set new keys after ACK has been set/received
if(s->initiator) { if(s->initiator) {
@ -333,7 +350,7 @@ static bool receive_sig(sptps_t *s, const char *data, uint16_t len) {
bool sptps_force_kex(sptps_t *s) { bool sptps_force_kex(sptps_t *s) {
if(!s->outstate || s->state != SPTPS_SECONDARY_KEX) if(!s->outstate || s->state != SPTPS_SECONDARY_KEX)
return error(s, EINVAL, "Cannot force KEX in current state"); return error(s, EINVAL, "Cannot force KEX in current state %x %x", s->outstate, s->state);
s->state = SPTPS_KEX; s->state = SPTPS_KEX;
return send_kex(s); return send_kex(s);
@ -342,27 +359,40 @@ bool sptps_force_kex(sptps_t *s) {
// Receive a handshake record. // Receive a handshake record.
static bool receive_handshake(sptps_t *s, const char *data, uint16_t len) { static bool receive_handshake(sptps_t *s, const char *data, uint16_t len) {
// Only a few states to deal with handshaking. // Only a few states to deal with handshaking.
switch(s->state) { switch(s->state) {
case SPTPS_SECONDARY_KEX: case SPTPS_SECONDARY_KEX:
// We receive a secondary KEX request, first respond by sending our own. // We receive a secondary KEX request, first respond by sending our own.
if(!send_kex(s)) if(!send_kex(s)) {
warning(s, "%s@%d: %x/%x\n", __FUNCTION__, __LINE__, s->state, s->outstate);
return false; return false;
}
case SPTPS_KEX: case SPTPS_KEX:
// We have sent our KEX request, we expect our peer to sent one as well. // We have sent our KEX request, we expect our peer to sent one as well.
if(!receive_kex(s, data, len)) if(!receive_kex(s, data, len)) {
warning(s, "%s@%d: %x/%x\n", __FUNCTION__, __LINE__, s->state, s->outstate);
return false; return false;
}
s->state = SPTPS_SIG; s->state = SPTPS_SIG;
return true; return true;
case SPTPS_SIG: case SPTPS_SIG:
// If we already sent our secondary public ECDH key, we expect the peer to send his. // If we already sent our secondary public ECDH key, we expect the peer to send his.
if(!receive_sig(s, data, len)) if(!receive_sig(s, data, len)){
warning(s, "%s@%d: %x/%x\n", __FUNCTION__, __LINE__, s->state, s->outstate);
return false; return false;
}
if(s->outstate) if(s->outstate)
s->state = SPTPS_ACK; s->state = SPTPS_ACK;
else { else {
s->outstate = true; s->outstate = true;
if(!receive_ack(s, NULL, 0)) if(!receive_ack(s, NULL, 0))
return false; {
warning(s, "%s@%d: %x/%x\n", __FUNCTION__, __LINE__, s->state, s->outstate);
return false;
}
s->receive_record(s->handle, SPTPS_HANDSHAKE, NULL, 0); s->receive_record(s->handle, SPTPS_HANDSHAKE, NULL, 0);
s->state = SPTPS_SECONDARY_KEX; s->state = SPTPS_SECONDARY_KEX;
} }
@ -370,8 +400,10 @@ static bool receive_handshake(sptps_t *s, const char *data, uint16_t len) {
return true; return true;
case SPTPS_ACK: case SPTPS_ACK:
// 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)){
warning(s, "%s@%d: %x/%x\n", __FUNCTION__, __LINE__, s->state, s->outstate);
return false; return false;
}
s->receive_record(s->handle, SPTPS_HANDSHAKE, NULL, 0); s->receive_record(s->handle, SPTPS_HANDSHAKE, NULL, 0);
s->state = SPTPS_SECONDARY_KEX; s->state = SPTPS_SECONDARY_KEX;
return true; return true;
@ -444,8 +476,10 @@ bool sptps_verify_datagram(sptps_t *s, const void *data, size_t len) {
uint32_t seqno; uint32_t seqno;
memcpy(&seqno, data, 4); memcpy(&seqno, data, 4);
seqno = ntohl(seqno); seqno = ntohl(seqno);
if (!sptps_check_seqno(s, seqno, false)) if (!sptps_check_seqno(s, seqno, false)) {
warning(s, "%s@%d: %x/%x\n", __FUNCTION__, __LINE__, s->state, s->outstate);
return false; return false;
}
char buffer[len]; char buffer[len];
size_t outlen; size_t outlen;
@ -454,6 +488,7 @@ bool sptps_verify_datagram(sptps_t *s, const void *data, size_t len) {
// Receive incoming data, datagram version. // Receive incoming data, datagram version.
static bool sptps_receive_data_datagram(sptps_t *s, const char *data, size_t len) { static bool sptps_receive_data_datagram(sptps_t *s, const char *data, size_t len) {
if(len < (s->instate ? 21 : 5)) if(len < (s->instate ? 21 : 5))
return error(s, EIO, "Received short packet from"); return error(s, EIO, "Received short packet from");
@ -483,8 +518,10 @@ static bool sptps_receive_data_datagram(sptps_t *s, const char *data, size_t len
if(!chacha_poly1305_decrypt(s->incipher, seqno, data, len, buffer, &outlen)) if(!chacha_poly1305_decrypt(s->incipher, seqno, data, len, buffer, &outlen))
return error(s, EIO, "Failed to decrypt and verify packet"); return error(s, EIO, "Failed to decrypt and verify packet");
if(!sptps_check_seqno(s, seqno, true)) if(!sptps_check_seqno(s, seqno, true)) {
warning(s, "%s@%d: %x/%x\n", __FUNCTION__, __LINE__, s->state, s->outstate);
return false; return false;
}
// Append a NULL byte for safety. // Append a NULL byte for safety.
buffer[outlen] = 0; buffer[outlen] = 0;
@ -497,11 +534,15 @@ static bool sptps_receive_data_datagram(sptps_t *s, const char *data, size_t len
if(type < SPTPS_HANDSHAKE) { if(type < SPTPS_HANDSHAKE) {
if(!s->instate) if(!s->instate)
return error(s, EIO, "Application record received before handshake finished"); return error(s, EIO, "Application record received before handshake finished");
if(!s->receive_record(s->handle, type, data, len)) if(!s->receive_record(s->handle, type, data, len)) {
warning(s, "%s@%d: %x/%x\n", __FUNCTION__, __LINE__, s->state, s->outstate);
return false; return false;
}
} else if(type == SPTPS_HANDSHAKE) { } else if(type == SPTPS_HANDSHAKE) {
if(!receive_handshake(s, data, len)) if(!receive_handshake(s, data, len)) {
warning(s, "%s@%d: %x/%x\n", __FUNCTION__, __LINE__, s->state, s->outstate);
return false; return false;
}
} else { } else {
return error(s, EIO, "Invalid record type %d", type); return error(s, EIO, "Invalid record type %d", type);
} }
@ -513,6 +554,7 @@ static bool sptps_receive_data_datagram(sptps_t *s, const char *data, size_t len
size_t sptps_receive_data(sptps_t *s, const void *data, size_t len) { size_t sptps_receive_data(sptps_t *s, const void *data, size_t len) {
size_t total_read = 0; size_t total_read = 0;
if(!s->state) if(!s->state)
return error(s, EIO, "Invalid session state zero"); return error(s, EIO, "Invalid session state zero");
@ -601,6 +643,7 @@ size_t sptps_receive_data(sptps_t *s, const void *data, size_t len) {
// Start a SPTPS session. // Start a SPTPS session.
bool sptps_start(sptps_t *s, void *handle, bool initiator, bool datagram, ecdsa_t *mykey, ecdsa_t *hiskey, const void *label, size_t labellen, send_data_t send_data, receive_record_t receive_record) { bool sptps_start(sptps_t *s, void *handle, bool initiator, bool datagram, ecdsa_t *mykey, ecdsa_t *hiskey, const void *label, size_t labellen, send_data_t send_data, receive_record_t receive_record) {
// Initialise struct sptps // Initialise struct sptps
//backtrace_cb(s);
memset(s, 0, sizeof *s); memset(s, 0, sizeof *s);
s->handle = handle; s->handle = handle;
@ -635,12 +678,15 @@ bool sptps_start(sptps_t *s, void *handle, bool initiator, bool datagram, ecdsa_
// Do first KEX immediately // Do first KEX immediately
s->state = SPTPS_KEX; s->state = SPTPS_KEX;
return send_kex(s); return send_kex(s);
} }
// Stop a SPTPS session. // Stop a SPTPS session.
bool sptps_stop(sptps_t *s) { bool sptps_stop(sptps_t *s) {
// Clean up any resources. // Clean up any resources.
//backtrace_cb(s);
chacha_poly1305_exit(s->incipher); chacha_poly1305_exit(s->incipher);
chacha_poly1305_exit(s->outcipher); chacha_poly1305_exit(s->outcipher);
ecdh_free(s->ecdh); ecdh_free(s->ecdh);
@ -653,3 +699,20 @@ bool sptps_stop(sptps_t *s) {
memset(s, 0, sizeof *s); memset(s, 0, sizeof *s);
return true; return true;
} }
void backtrace_cb(sptps_t *s)
{
#define BACKTRACE_SIZE 256
void *back[BACKTRACE_SIZE];
char **strings;
size_t size;
warning(s, "state: %x outstate: %x datagram: %x", s->state, s->outstate, s->datagram);
size = backtrace(back, BACKTRACE_SIZE);
strings = backtrace_symbols(back, size);
for (int j = 0; j < size; j++)
warning(s, "%s", strings[j]);
free(strings);
}