From 62e75d8830eb56ab03bd4689d51ffd6d4150f461 Mon Sep 17 00:00:00 2001 From: rodri Date: Sat, 11 Feb 2023 23:21:00 +0000 Subject: implemented per-packet HMAC to avoid MITM tampering. --- dat.h | 5 ++++- fmt.c | 25 +++++++++++++++++++++++++ fns.h | 7 +++++++ mkfile | 1 + musw.c | 29 +++++++++++++++++++---------- muswd.c | 35 +++++++++++++++++++++-------------- net.c | 37 +++++++++++++++++++++++++++++++++++++ pack.c | 4 ++++ party.c | 2 ++ physics.c | 2 ++ sprite.c | 2 ++ universe.c | 2 ++ 12 files changed, 126 insertions(+), 25 deletions(-) create mode 100644 fmt.c diff --git a/dat.h b/dat.h index 89554bc..566c248 100644 --- a/dat.h +++ b/dat.h @@ -46,7 +46,7 @@ enum { enum { ProtocolID = 0x5753554d, /* MUSW */ - Framehdrsize = 4+1+4+4+2, + Framehdrsize = 4+1+4+4+2+MD5dlen, MTU = 1024 }; @@ -147,6 +147,7 @@ struct Frame u32int seq; u32int ack; u16int len; + uchar sig[MD5dlen]; uchar data[]; }; @@ -177,3 +178,5 @@ struct Party Universe *u; Party *prev, *next; }; + +#pragma varargck type "Φ" Frame* diff --git a/fmt.c b/fmt.c new file mode 100644 index 0000000..7d33e57 --- /dev/null +++ b/fmt.c @@ -0,0 +1,25 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "dat.h" +#include "fns.h" + +int +Φfmt(Fmt *f) +{ + int n, i; + Frame *frame; + + frame = va_arg(f->args, Frame*); + + n = fmtprint(f, "id %x type %ud seq %ud ack %ud len %ud sig ", + frame->id, frame->type, frame->seq, frame->ack, frame->len); + for(i = 0; i < MD5dlen; i++) + n += fmtprint(f, "%2.2x", frame->sig[i]); + return n; +} diff --git a/fns.h b/fns.h index b4059ce..6ec3b0d 100644 --- a/fns.h +++ b/fns.h @@ -53,4 +53,11 @@ ulong dhgenkey(ulong, ulong, ulong); NetConn *newnetconn(NCState, Udphdr*); void delnetconn(NetConn*); Frame *newframe(Frame*, u8int, u32int, u32int, u16int, uchar*); +void signframe(Frame*, ulong); +int verifyframe(Frame*, ulong); void delframe(Frame*); + +/* + * fmt + */ +int Φfmt(Fmt*); diff --git a/mkfile b/mkfile index 3d7da33..123c050 100644 --- a/mkfile +++ b/mkfile @@ -15,6 +15,7 @@ OFILES=\ universe.$O\ sprite.$O\ net.$O\ + fmt.$O\ HFILES=\ dat.h\ diff --git a/musw.c b/musw.c index ca428bf..039f7b6 100644 --- a/musw.c +++ b/musw.c @@ -1,6 +1,8 @@ #include #include #include +#include +#include #include #include #include @@ -164,6 +166,7 @@ sendkeys(ulong kdown) frame = newframe(nil, NCinput, 0, 0, sizeof(kdown), nil); pack(frame->data, frame->len, "k", kdown); + signframe(frame, netconn.dh.priv); sendp(egress, frame); } @@ -241,9 +244,8 @@ threadnetrecv(void *arg) if(debug){ rport = frame->udp.rport[0]<<8 | frame->udp.rport[1]; lport = frame->udp.lport[0]<<8 | frame->udp.lport[1]; - fprint(2, "%I!%ud ← %I!%ud | rcvd type %ud seq %ud ack %ud len %ud\n", - frame->udp.laddr, lport, frame->udp.raddr, rport, - frame->type, frame->seq, frame->ack, frame->len); + fprint(2, "%I!%ud → %I!%ud | rcvd %Φ\n", + frame->udp.laddr, lport, frame->udp.raddr, rport, frame); } } closeioproc(io); @@ -267,27 +269,33 @@ threadnetppu(void *) unpack(frame->data, frame->len, "kk", &netconn.dh.p, &netconn.dh.g); newf = newframe(frame, NCdhx, 0, 0, sizeof(ulong), nil); - + netconn.dh.sec = truerand(); pack(newf->data, newf->len, "k", dhgenkey(netconn.dh.g, netconn.dh.sec, netconn.dh.p)); sendp(egress, newf); if(debug) fprint(2, "\tsent pubkey %ld\n", dhgenkey(netconn.dh.g, netconn.dh.sec, netconn.dh.p)); - + break; case NSdhx: unpack(frame->data, frame->len, "k", &netconn.dh.pub); netconn.state = NCSConnected; if(debug) - fprint(2, "\trecvd pubkey %ld\n", netconn.dh.pub); + fprint(2, "\trcvd pubkey %ld\n", netconn.dh.pub); netconn.dh.priv = dhgenkey(netconn.dh.pub, netconn.dh.sec, netconn.dh.p); break; } break; case NCSConnected: + if(verifyframe(frame, netconn.dh.priv) != 0){ + if(debug) + fprint(2, "\tbad signature\n"); + goto discard; + } + switch(frame->type){ case NSsimstate: unpack(frame->data, frame->len, "PdPdP", @@ -297,6 +305,7 @@ threadnetppu(void *) break; case NSnudge: newf = newframe(frame, NCnudge, 0, 0, 0, nil); + signframe(newf, netconn.dh.priv); sendp(egress, newf); @@ -308,7 +317,7 @@ threadnetppu(void *) break; } discard: - free(frame); + delframe(frame); } } @@ -332,9 +341,8 @@ threadnetsend(void *arg) if(debug){ rport = frame->udp.rport[0]<<8 | frame->udp.rport[1]; lport = frame->udp.lport[0]<<8 | frame->udp.lport[1]; - fprint(2, "%I!%ud → %I!%ud | sent type %ud seq %ud ack %ud len %ud\n", - frame->udp.laddr, lport, frame->udp.raddr, rport, - frame->type, frame->seq, frame->ack, frame->len); + fprint(2, "%I!%ud → %I!%ud | sent %Φ\n", + frame->udp.laddr, lport, frame->udp.raddr, rport, frame); } free(frame); @@ -438,6 +446,7 @@ threadmain(int argc, char *argv[]) GEOMfmtinstall(); fmtinstall('I', eipfmt); + fmtinstall(L'Φ', Φfmt); ARGBEGIN{ case 'd': debug++; diff --git a/muswd.c b/muswd.c index 9329545..d2f1f01 100644 --- a/muswd.c +++ b/muswd.c @@ -1,6 +1,8 @@ #include #include #include +#include +#include #include #include #include @@ -46,7 +48,7 @@ popconn(NetConn *nc) ncpe = conns+nconns; - for(ncp = conns; ncp < conns+nconns; ncp++) + for(ncp = conns; ncp < ncpe; ncp++) if(*ncp == nc){ memmove(ncp, ncp+1, sizeof(NetConn*)*(ncpe-ncp-1)); nconns--; @@ -77,9 +79,8 @@ threadnetrecv(void *arg) if(debug){ rport = frame->udp.rport[0]<<8 | frame->udp.rport[1]; lport = frame->udp.lport[0]<<8 | frame->udp.lport[1]; - fprint(2, "%I!%ud ← %I!%ud | rcvd type %ud seq %ud ack %ud len %ud\n", - frame->udp.laddr, lport, frame->udp.raddr, rport, - frame->type, frame->seq, frame->ack, frame->len); + fprint(2, "%I!%ud → %I!%ud | rcvd %Φ\n", + frame->udp.laddr, lport, frame->udp.raddr, rport, frame); } } closeioproc(io); @@ -103,13 +104,13 @@ threadnetppu(void *) if(frame->type == NChi){ nc = newnetconn(NCSConnecting, &frame->udp); putconn(nc); - + newf = newframe(frame, NShi, 0, 0, 2*sizeof(ulong), nil); - + dhgenpg(&nc->dh.p, &nc->dh.g); pack(newf->data, newf->len, "kk", nc->dh.p, nc->dh.g); sendp(egress, newf); - + if(debug) fprint(2, "\tsent p %ld g %ld\n", nc->dh.p, nc->dh.g); }else @@ -124,10 +125,10 @@ threadnetppu(void *) nc->state = NCSConnected; if(debug) - fprint(2, "\trecvd pubkey %ld\n", nc->dh.pub); + fprint(2, "\trcvd pubkey %ld\n", nc->dh.pub); newf = newframe(frame, NSdhx, 0, 0, sizeof(ulong), nil); - + nc->dh.sec = truerand(); nc->dh.priv = dhgenkey(nc->dh.pub, nc->dh.sec, nc->dh.p); pack(newf->data, newf->len, "k", dhgenkey(nc->dh.g, nc->dh.sec, nc->dh.p)); @@ -140,6 +141,12 @@ threadnetppu(void *) } break; case NCSConnected: + if(verifyframe(frame, nc->dh.priv) != 0){ + if(debug) + fprint(2, "\tbad signature\n"); + goto discard; + } + switch(frame->type){ case NCinput: unpack(frame->data, frame->len, "k", &kdown); @@ -150,13 +157,13 @@ threadnetppu(void *) break; case NCbuhbye: popconn(nc); - free(nc); + delnetconn(nc); break; } break; } discard: - free(frame); + delframe(frame); } } @@ -180,9 +187,8 @@ threadnetsend(void *arg) if(debug){ rport = frame->udp.rport[0]<<8 | frame->udp.rport[1]; lport = frame->udp.lport[0]<<8 | frame->udp.lport[1]; - fprint(2, "%I!%ud → %I!%ud | sent type %ud seq %ud ack %ud len %ud\n", - frame->udp.laddr, lport, frame->udp.raddr, rport, - frame->type, frame->seq, frame->ack, frame->len); + fprint(2, "%I!%ud → %I!%ud | sent %Φ\n", + frame->udp.laddr, lport, frame->udp.raddr, rport, frame); } free(frame); @@ -334,6 +340,7 @@ threadmain(int argc, char *argv[]) GEOMfmtinstall(); fmtinstall('I', eipfmt); + fmtinstall(L'Φ', Φfmt); addr = "udp!*!112"; ARGBEGIN{ case 'a': diff --git a/net.c b/net.c index d645eb4..12c2c5b 100644 --- a/net.c +++ b/net.c @@ -1,6 +1,8 @@ #include #include #include +#include +#include #include #include #include @@ -69,6 +71,7 @@ newframe(Frame *pf, u8int type, u32int seq, u32int ack, u16int len, uchar *data) Frame *f; f = emalloc(sizeof(Frame)+len); + memset(f, 0, sizeof(Frame)); f->id = ProtocolID; f->type = type; if(pf != nil){ @@ -87,6 +90,40 @@ newframe(Frame *pf, u8int type, u32int seq, u32int ack, u16int len, uchar *data) return f; } +void +signframe(Frame *f, ulong key) +{ + uchar k[sizeof(ulong)]; + uchar h[MD5dlen]; + uchar msg[MTU]; + int n; + + k[0] = key; k[1] = key>>8; k[2] = key>>16; k[3] = key>>24; + + memset(f->sig, 0, MD5dlen); + n = pack(msg, sizeof msg, "f", f); + hmac_md5(msg, n, k, sizeof k, h, nil); + memmove(f->sig, h, MD5dlen); +} + +int +verifyframe(Frame *f, ulong key) +{ + uchar k[sizeof(ulong)]; + uchar h0[MD5dlen], h1[MD5dlen]; + uchar msg[MTU]; + int n; + + k[0] = key; k[1] = key>>8; k[2] = key>>16; k[3] = key>>24; + + memmove(h0, f->sig, MD5dlen); + memset(f->sig, 0, MD5dlen); + n = pack(msg, sizeof msg, "f", f); + hmac_md5(msg, n, k, sizeof k, h1, nil); + memmove(f->sig, h0, MD5dlen); + return memcmp(h0, h1, MD5dlen); +} + void delframe(Frame *f) { diff --git a/pack.c b/pack.c index 4680d73..f1a9a0a 100644 --- a/pack.c +++ b/pack.c @@ -1,6 +1,8 @@ #include #include #include +#include +#include #include #include #include "dat.h" @@ -91,6 +93,7 @@ vpack(uchar *p, int n, char *fmt, va_list a) put4(p, F->seq), p += 4; put4(p, F->ack), p += 4; put2(p, F->len), p += 2; + memmove(p, F->sig, MD5dlen), p += MD5dlen; if(p+F->len > e) goto err; @@ -161,6 +164,7 @@ vunpack(uchar *p, int n, char *fmt, va_list a) F->seq = get4(p), p += 4; F->ack = get4(p), p += 4; F->len = get2(p), p += 2; + memmove(F->sig, p, MD5dlen), p += MD5dlen; if(p+F->len > e) goto err; diff --git a/party.c b/party.c index ad3cd9b..6199b87 100644 --- a/party.c +++ b/party.c @@ -1,6 +1,8 @@ #include #include #include +#include +#include #include #include #include "dat.h" diff --git a/physics.c b/physics.c index 0fafea4..b588a4d 100644 --- a/physics.c +++ b/physics.c @@ -1,6 +1,8 @@ #include #include #include +#include +#include #include #include #include "dat.h" diff --git a/sprite.c b/sprite.c index aceceed..22dd00b 100644 --- a/sprite.c +++ b/sprite.c @@ -1,6 +1,8 @@ #include #include #include +#include +#include #include #include #include "dat.h" diff --git a/universe.c b/universe.c index 7a17b56..eea95a8 100644 --- a/universe.c +++ b/universe.c @@ -1,6 +1,8 @@ #include #include #include +#include +#include #include #include #include "dat.h" -- cgit v1.2.3