after this time, initiate a new
key exchange */
- uint8_t *setupsig; /* Expected signature of incoming MSG1 packets */
- int32_t setupsiglen; /* Allows us to discard packets quickly if
- they are not for us */
bool_t setup_priority; /* Do we have precedence if both sites emit
message 1 simultaneously? */
uint32_t log_events;
type=buf_unprepend_uint32((b)); \
if (type!=(t)) return False; } while(0)
+struct parsedname {
+ int32_t len;
+ uint8_t *name;
+ int32_t extrainfo_len;
+ uint8_t *extrainfo;
+};
+
struct msg {
uint8_t *hashstart;
uint32_t dest;
uint32_t source;
- int32_t remlen;
- uint8_t *remote;
- int32_t loclen;
- uint8_t *local;
+ struct parsedname remote;
+ struct parsedname local;
uint8_t *nR;
uint8_t *nL;
int32_t pklen;
return True;
}
+static bool_t unpick_name(struct buffer_if *msg, struct parsedname *nm)
+{
+ CHECK_AVAIL(msg,2);
+ nm->len=buf_unprepend_uint16(msg);
+ CHECK_AVAIL(msg,nm->len);
+ nm->name=buf_unprepend(msg,nm->len);
+ uint8_t *nul=memchr(nm->name,0,nm->len);
+ if (!nul) {
+ nm->extrainfo_len=0;
+ nm->extrainfo=0;
+ } else {
+ nm->extrainfo=nul+1;
+ nm->extrainfo_len=msg->start-nm->extrainfo;
+ nm->len=nul-nm->name;
+ }
+ return True;
+}
+
static bool_t unpick_msg(struct site *st, uint32_t type,
struct buffer_if *msg, struct msg *m)
{
CHECK_AVAIL(msg,4);
m->source=buf_unprepend_uint32(msg);
CHECK_TYPE(msg,type);
- CHECK_AVAIL(msg,2);
- m->remlen=buf_unprepend_uint16(msg);
- CHECK_AVAIL(msg,m->remlen);
- m->remote=buf_unprepend(msg,m->remlen);
- CHECK_AVAIL(msg,2);
- m->loclen=buf_unprepend_uint16(msg);
- CHECK_AVAIL(msg,m->loclen);
- m->local=buf_unprepend(msg,m->loclen);
+ if (!unpick_name(msg,&m->remote)) return False;
+ if (!unpick_name(msg,&m->local)) return False;
CHECK_AVAIL(msg,NONCELEN);
m->nR=buf_unprepend(msg,NONCELEN);
if (type==LABEL_MSG1) {
return True;
}
+static bool_t name_matches(const struct parsedname *nm, const char *expected)
+{
+ int expected_len=strlen(expected);
+ return
+ nm->len == expected_len &&
+ !memcmp(nm->name, expected, expected_len);
+}
+
static bool_t check_msg(struct site *st, uint32_t type, struct msg *m,
cstring_t *error)
{
/* Check that the site names and our nonce have been sent
back correctly, and then store our peer's nonce. */
- if (memcmp(m->remote,st->remotename,strlen(st->remotename)!=0)) {
+ if (!name_matches(&m->remote,st->remotename)) {
*error="wrong remote site name";
return False;
}
- if (memcmp(m->local,st->localname,strlen(st->localname)!=0)) {
+ if (!name_matches(&m->local,st->localname)) {
*error="wrong local site name";
return False;
}
}
static bool_t process_msg1(struct site *st, struct buffer_if *msg1,
- const struct comm_addr *src)
+ const struct comm_addr *src, struct msg *m)
{
- struct msg m;
-
/* We've already determined we're in an appropriate state to
process an incoming MSG1, and that the MSG1 has correct values
of A and B. */
- if (!unpick_msg(st,LABEL_MSG1,msg1,&m)) return False;
-
transport_record_peer(st,&st->setup_peers,src,"msg1");
- st->setup_session_id=m.source;
- memcpy(st->remoteN,m.nR,NONCELEN);
+ st->setup_session_id=m->source;
+ memcpy(st->remoteN,m->nR,NONCELEN);
return True;
}
return True;
}
-static bool_t decrypt_msg0(struct site *st, struct buffer_if *msg0)
+static bool_t decrypt_msg0(struct site *st, struct buffer_if *msg0,
+ const struct comm_addr *src)
{
cstring_t transform_err, auxkey_err, newkey_err="n/a";
struct msg0 m;
"peer has used new key","auxiliary key",LOG_SEC);
return True;
}
-
- if (problem==2) {
- slog(st,LOG_DROP,"transform: %s (merely skew)",transform_err);
- return False;
- }
+ if (problem==2)
+ goto skew;
buffer_copy(msg0, &st->scratch);
problem = st->auxiliary_key.transform->reverse
}
return True;
}
+ if (problem==2)
+ goto skew;
if (st->state==SITE_SENTMSG5) {
buffer_copy(msg0, &st->scratch);
- if (!st->new_transform->reverse(st->new_transform->st,
- msg0,&newkey_err)) {
+ problem = st->new_transform->reverse(st->new_transform->st,
+ msg0,&newkey_err);
+ if (!problem) {
/* It looks like we didn't get the peer's MSG6 */
/* This is like a cut-down enter_new_state(SITE_RUN) */
slog(st,LOG_STATE,"will enter state RUN (MSG0 with new key)");
activate_new_key(st);
return True; /* do process the data in this packet */
}
+ if (problem==2)
+ goto skew;
}
slog(st,LOG_SEC,"transform: %s (aux: %s, new: %s)",
transform_err,auxkey_err,newkey_err);
initiate_key_setup(st,"incoming message would not decrypt");
+ send_nak(src,m.dest,m.source,m.type,msg0,"message would not decrypt");
+ return False;
+
+ skew:
+ slog(st,LOG_DROP,"transform: %s (merely skew)",transform_err);
return False;
}
{
uint32_t type;
- if (!decrypt_msg0(st,msg0))
+ if (!decrypt_msg0(st,msg0,src))
return False;
CHECK_AVAIL(msg0,4);
static void dump_packet(struct site *st, struct buffer_if *buf,
const struct comm_addr *addr, bool_t incoming)
{
- uint32_t dest=ntohl(*(uint32_t *)buf->start);
- uint32_t source=ntohl(*(uint32_t *)(buf->start+4));
- uint32_t msgtype=ntohl(*(uint32_t *)(buf->start+8));
+ uint32_t dest=get_uint32(buf->start);
+ uint32_t source=get_uint32(buf->start+4);
+ uint32_t msgtype=get_uint32(buf->start+8);
if (st->log_events & LOG_DUMP)
slilog(st->log,M_DEBUG,"%s: %s: %08x<-%08x: %08x:",
initiate_key_setup(st,"outgoing packet");
}
+static bool_t named_for_us(struct site *st, const struct buffer_if *buf_in,
+ uint32_t type, struct msg *m)
+ /* For packets which are identified by the local and remote names.
+ * If it has our name and our peer's name in it it's for us. */
+{
+ struct buffer_if buf[1];
+ buffer_readonly_clone(buf,buf_in);
+ return unpick_msg(st,type,buf,m)
+ && name_matches(&m->remote,st->remotename)
+ && name_matches(&m->local,st->localname);
+}
+
/* This function is called by the communication device to deliver
packets from our peers. */
static bool_t site_incoming(void *sst, struct buffer_if *buf,
if (buf->size < 12) return False;
- uint32_t dest=ntohl(*(uint32_t *)buf->start);
-
- if (dest==0) {
- /* It could be for any site - it should have LABEL_MSG1 and
- might have our name and our peer's name in it */
- if (buf->size<(st->setupsiglen+8+NONCELEN)) return False;
- if (memcmp(buf->start+8,st->setupsig,st->setupsiglen)==0) {
- /* It's addressed to us. Decide what to do about it. */
- dump_packet(st,buf,source,True);
- if (st->state==SITE_RUN || st->state==SITE_RESOLVE ||
- st->state==SITE_WAIT) {
- /* We should definitely process it */
- if (process_msg1(st,buf,source)) {
- slog(st,LOG_SETUP_INIT,"key setup initiated by peer");
+ uint32_t dest=get_uint32(buf->start);
+ uint32_t msgtype=get_uint32(buf->start+8);
+ struct msg named_msg;
+
+ if (msgtype==LABEL_MSG1) {
+ if (!named_for_us(st,buf,msgtype,&named_msg))
+ return False;
+ /* It's a MSG1 addressed to us. Decide what to do about it. */
+ dump_packet(st,buf,source,True);
+ if (st->state==SITE_RUN || st->state==SITE_RESOLVE ||
+ st->state==SITE_WAIT) {
+ /* We should definitely process it */
+ if (process_msg1(st,buf,source,&named_msg)) {
+ slog(st,LOG_SETUP_INIT,"key setup initiated by peer");
+ enter_new_state(st,SITE_SENTMSG2);
+ } else {
+ slog(st,LOG_ERROR,"failed to process incoming msg1");
+ }
+ BUF_FREE(buf);
+ return True;
+ } else if (st->state==SITE_SENTMSG1) {
+ /* We've just sent a message 1! They may have crossed on
+ the wire. If we have priority then we ignore the
+ incoming one, otherwise we process it as usual. */
+ if (st->setup_priority) {
+ BUF_FREE(buf);
+ slog(st,LOG_DUMP,"crossed msg1s; we are higher "
+ "priority => ignore incoming msg1");
+ return True;
+ } else {
+ slog(st,LOG_DUMP,"crossed msg1s; we are lower "
+ "priority => use incoming msg1");
+ if (process_msg1(st,buf,source,&named_msg)) {
+ BUF_FREE(&st->buffer); /* Free our old message 1 */
enter_new_state(st,SITE_SENTMSG2);
} else {
- slog(st,LOG_ERROR,"failed to process incoming msg1");
+ slog(st,LOG_ERROR,"failed to process an incoming "
+ "crossed msg1 (we have low priority)");
}
BUF_FREE(buf);
return True;
- } else if (st->state==SITE_SENTMSG1) {
- /* We've just sent a message 1! They may have crossed on
- the wire. If we have priority then we ignore the
- incoming one, otherwise we process it as usual. */
- if (st->setup_priority) {
- BUF_FREE(buf);
- slog(st,LOG_DUMP,"crossed msg1s; we are higher "
- "priority => ignore incoming msg1");
- return True;
- } else {
- slog(st,LOG_DUMP,"crossed msg1s; we are lower "
- "priority => use incoming msg1");
- if (process_msg1(st,buf,source)) {
- BUF_FREE(&st->buffer); /* Free our old message 1 */
- enter_new_state(st,SITE_SENTMSG2);
- } else {
- slog(st,LOG_ERROR,"failed to process an incoming "
- "crossed msg1 (we have low priority)");
- }
- BUF_FREE(buf);
- return True;
- }
}
- /* The message 1 was received at an unexpected stage of the
- key setup. XXX POLICY - what do we do? */
- slog(st,LOG_UNEXPECTED,"unexpected incoming message 1");
- BUF_FREE(buf);
- return True;
}
- return False; /* Not for us. */
+ /* The message 1 was received at an unexpected stage of the
+ key setup. XXX POLICY - what do we do? */
+ slog(st,LOG_UNEXPECTED,"unexpected incoming message 1");
+ BUF_FREE(buf);
+ return True;
}
if (dest==st->index) {
/* Explicitly addressed to us */
- uint32_t msgtype=ntohl(get_uint32(buf->start+8));
if (msgtype!=LABEL_MSG0) dump_packet(st,buf,source,True);
switch (msgtype) {
- case 0: /* NAK */
+ case LABEL_NAK:
/* If the source is our current peer then initiate a key setup,
because our peer's forgotten the key */
if (get_uint32(buf->start+4)==st->current.remote_session_id) {
/* The information we expect to see in incoming messages of type 1 */
/* fixme: lots of unchecked overflows here, but the results are only
corrupted packets rather than undefined behaviour */
- st->setupsiglen=strlen(st->remotename)+strlen(st->localname)+8;
- st->setupsig=safe_malloc(st->setupsiglen,"site_apply");
- put_uint32(st->setupsig+0,LABEL_MSG1);
- put_uint16(st->setupsig+4,strlen(st->remotename));
- memcpy(&st->setupsig[6],st->remotename,strlen(st->remotename));
- put_uint16(st->setupsig+(6+strlen(st->remotename)),strlen(st->localname));
- memcpy(&st->setupsig[8+strlen(st->remotename)],st->localname,
- strlen(st->localname));
st->setup_priority=(strcmp(st->localname,st->remotename)>0);
buffer_new(&st->buffer,SETUP_BUFFER_LEN);