From 85379ff44990f56c4db4e43545453ed64c21a40c Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Fri, 15 Oct 1999 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 1999-10-15 --- port/devaudio.c | 1 + port/devsdp.c | 783 +++++++++++++++++++++++++++++++++++------------- 2 files changed, 580 insertions(+), 204 deletions(-) diff --git a/port/devaudio.c b/port/devaudio.c index 6dfdeb9892ee4ee50ac10bc2fad95475519f912f..ff6f03ffc4a362bb50a1b7526ad8feb0ff008be7 100644 --- a/port/devaudio.c +++ b/port/devaudio.c @@ -743,6 +743,7 @@ audioinit(void) case 2: case 5: case 7: + case 9: case 10: break; default: diff --git a/port/devsdp.c b/port/devsdp.c index e3d258b389d921d100300bcd0103adfa2f9dce6d..0a5f7bd9458ac3c10d3143c5aa6ce9ac2a1d2f72 100644 --- a/port/devsdp.c +++ b/port/devsdp.c @@ -17,7 +17,6 @@ typedef struct Sdp Sdp; typedef struct Conv Conv; typedef struct OneWay OneWay; typedef struct Stats Stats; -typedef struct ConnectPkt ConnectPkt; typedef struct AckPkt AckPkt; typedef struct Algorithm Algorithm; @@ -43,7 +42,7 @@ enum Nfs= 4, // number of file systems MaxRetries= 8, KeepAlive = 60, // keep alive in seconds - KeyLength= 32, + SecretLength= 32, // a secret per direction SeqMax = (1<<24), SeqWindow = 32, }; @@ -78,6 +77,8 @@ struct OneWay ulong seq; ulong window; + uchar secret[SecretLength]; + QLock controllk; Rendez controlready; Block *controlpkt; // control channel @@ -93,7 +94,7 @@ struct OneWay int (*auth)(OneWay*, uchar *buf, int len); void *compstate; - int (*comp)(OneWay*, uchar *dst, uchar *src, int n); + int (*comp)(OneWay*, int subtype, Block **); }; // conv states @@ -137,7 +138,6 @@ struct Conv { char owner[NAMELEN]; /* protections */ int perm; - uchar masterkey[KeyLength]; char *authname; char *ciphername; char *compname; @@ -160,10 +160,13 @@ struct Sdp { enum { TConnect, TControl, - TControlAck, TData, - TThwackC, - TThwackU, + TCompData, +}; + +enum { + ControlMesg, + ControlAck, }; enum { @@ -174,15 +177,6 @@ enum { ConReset, }; -struct ConnectPkt -{ - uchar type; // always zero = connection packet - uchar op; - uchar pad[2]; - uchar dialid[4]; - uchar acceptid[4]; -}; - struct AckPkt { uchar cseq[4]; @@ -222,31 +216,6 @@ static Dirtab convdirtab[]={ "rstats", {Qrstats}, 0, 0444, }; -#ifdef XXX -static Algorithm cipheralg[] = -{ - "null", 0, nullcipherinit, - "des_56_cbc", 7, descipherinit, - "rc4_128", 16, rc4cipherinit, - nil, 0, nil, -}; - -static Algorithm authalg[] = -{ - "null", 0, nullauthinit, - "hmac_sha_96", 16, shaauthinit, - "hmac_md5_96", 16, md5authinit, - nil, 0, nil, -}; - -static Algorithm compalg[] = -{ - "null", 0, nullcompinit, - "thwack", 0, thwackcompinit, - nil, 0, nil, -}; -#endif - static int m2p[] = { [OREAD] 4, [OWRITE] 2, @@ -287,17 +256,55 @@ static void onewaycleanup(OneWay *ow); static int readready(void *a); static int controlread(); static Block *conviput(Conv *c, Block *b, int control); -static void conviput2(Conv *c, Block *b); +static void conviconnect(Conv *c, int op, Block *b); +static void convicontrol(Conv *c, int op, Block *b); +static Block *convicomp(Conv *c, int op, Block *b); static void writecontrol(Conv *c, void *p, int n, int wait); static Block *readcontrol(Conv *c, int n); static Block *readdata(Conv *c, int n); static long writedata(Conv *c, Block *b); -static void convoput(Conv *c, int type, Block *b); -static void convoput2(Conv *c, int op, ulong dialid, ulong acceptid); +static void convoput(Conv *c, int type, int subtype, Block *b); +static void convoconnect(Conv *c, int op, ulong dialid, ulong acceptid); static void convreader(void *a); static void convopenchan(Conv *c, char *path); static void convstats(Conv *c, int local, char *buf, int n); +static void setalg(Conv *c, char *name, Algorithm *tab); +static void setsecret(OneWay *cc, char *secret); + +static void nullcipherinit(Conv*c, char *name, int keylen); +static void descipherinit(Conv*c, char *name, int keylen); +static void rc4cipherinit(Conv*c, char *name, int keylen); +static void nullauthinit(Conv*c, char *name, int keylen); +static void shaauthinit(Conv*c, char *name, int keylen); +static void md5authinit(Conv*c, char *name, int keylen); +static void nullcompinit(Conv*c, char *name, int keylen); +static void thwackcompinit(Conv*c, char *name, int keylen); + +static Algorithm cipheralg[] = +{ + "null", 0, nullcipherinit, + "des_56_cbc", 7, descipherinit, + "rc4_128", 16, rc4cipherinit, + nil, 0, nil, +}; + +static Algorithm authalg[] = +{ + "null", 0, nullauthinit, + "hmac_sha_96", 16, shaauthinit, + "hmac_md5_96", 16, md5authinit, + nil, 0, nil, +}; + +static Algorithm compalg[] = +{ + "null", 0, nullcompinit, + "thwack", 0, thwackcompinit, + nil, 0, nil, +}; + + static void sdpinit(void) { @@ -597,6 +604,26 @@ sdpwrite(Chan *ch, void *a, long n, vlong off) if(cb->nf != 2) error("usage: drop permil"); c->drop = atoi(cb->f[1]); + } else if(strcmp(arg0, "cipher") == 0) { + if(cb->nf != 2) + error("usage: cipher alg"); + setalg(c, cb->f[1], cipheralg); + } else if(strcmp(arg0, "auth") == 0) { + if(cb->nf != 2) + error("usage: auth alg"); + setalg(c, cb->f[1], authalg); + } else if(strcmp(arg0, "comp") == 0) { + if(cb->nf != 2) + error("usage: comp alg"); + setalg(c, cb->f[1], compalg); + } else if(strcmp(arg0, "insecret") == 0) { + if(cb->nf != 2) + error("usage: insecret secret"); + setsecret(&c->in, cb->f[1]); + } else if(strcmp(arg0, "outsecret") == 0) { + if(cb->nf != 2) + error("usage: outsecret secret"); + setsecret(&c->out, cb->f[1]); } else error("unknown control request"); poperror(); @@ -739,7 +766,7 @@ convretryinit(Conv *c) c->retries = 0; // +2 to avoid rounding effects. c->timeout = TK2SEC(m->ticks) + 2; -}; +} // assume c is locked static int @@ -750,7 +777,7 @@ print("convretry: %s: %d\n", convstatename[c->state], c->retries); if(c->retries > MaxRetries) { print("convretry: giving up\n"); if(reset) - convoput2(c, ConReset, c->dialid, c->acceptid); + convoconnect(c, ConReset, c->dialid, c->acceptid); convsetstate(c, CClosed); return 0; } @@ -773,17 +800,17 @@ convtimer(Conv *c, ulong sec) switch(c->state) { case CDial: if(convretry(c, 1)) - convoput2(c, ConOpenRequest, c->dialid, 0); + convoconnect(c, ConOpenRequest, c->dialid, 0); break; case CAccept: if(convretry(c, 1)) - convoput2(c, ConOpenAck, c->dialid, c->acceptid); + convoconnect(c, ConOpenAck, c->dialid, c->acceptid); break; case COpen: b = c->out.controlpkt; if(b != nil) { if(convretry(c, 1)) - convoput(c, TControl, copyblock(b, blocklen(b))); + convoput(c, TControl, ControlMesg, copyblock(b, blocklen(b))); break; } @@ -802,13 +829,13 @@ print("sending keep alive: %ld\n", sec - c->lastrecv); c->out.controlpkt = b; convretryinit(c); if(!waserror()) { - convoput(c, TControl, copyblock(b, blocklen(b))); + convoput(c, TControl, ControlMesg, copyblock(b, blocklen(b))); poperror(); } break; case CLocalClose: if(convretry(c, 0)) - convoput2(c, ConClose, c->dialid, c->acceptid); + convoconnect(c, ConClose, c->dialid, c->acceptid); break; case CRemoteClose: case CClosed: @@ -878,30 +905,39 @@ print("convsetstate %s -> %s\n", convstatename[c->state], convstatename[state]); assert(c->state == CInit); c->dialid = (rand()<<16) + rand(); convretryinit(c); - convoput2(c, ConOpenRequest, c->dialid, 0); + convoconnect(c, ConOpenRequest, c->dialid, 0); break; case CAccept: assert(c->state == CInit); c->acceptid = (rand()<<16) + rand(); convretryinit(c); - convoput2(c, ConOpenAck, c->dialid, c->acceptid); + convoconnect(c, ConOpenAck, c->dialid, c->acceptid); break; case COpen: assert(c->state == CDial || c->state == CAccept); if(c->state == CDial) { convretryinit(c); - convoput2(c, ConOpenAckAck, c->dialid, c->acceptid); + convoconnect(c, ConOpenAckAck, c->dialid, c->acceptid); + hnputl(c->in.secret, c->acceptid); + hnputl(c->in.secret+4, c->dialid); + hnputl(c->out.secret, c->dialid); + hnputl(c->out.secret+4, c->acceptid); + } else { + hnputl(c->in.secret, c->dialid); + hnputl(c->in.secret+4, c->acceptid); + hnputl(c->out.secret, c->acceptid); + hnputl(c->out.secret+4, c->dialid); } - // setup initial key and auth method + md5authinit(c, "hmac_md5_96", 16); break; case CLocalClose: assert(c->state == CAccept || c->state == COpen); convretryinit(c); - convoput2(c, ConClose, c->dialid, c->acceptid); + convoconnect(c, ConClose, c->dialid, c->acceptid); break; case CRemoteClose: wakeup(&c->in.controlready); - convoput2(c, ConReset, c->dialid, c->acceptid); + convoconnect(c, ConReset, c->dialid, c->acceptid); break; case CClosed: wakeup(&c->in.controlready); @@ -938,7 +974,6 @@ print("CClosed -> ref = %d\n", c->ref); c->timeout = ~0; c->retries = 0; c->drop = 0; - memset(c->masterkey, 0, sizeof(c->masterkey)); onewaycleanup(&c->in); onewaycleanup(&c->out); memset(&c->lstats, 0, sizeof(Stats)); @@ -1046,7 +1081,7 @@ convack(Conv *c) hnputl(ack->inReorder, s->inReorder); hnputl(ack->inBadAuth, s->inBadAuth); hnputl(ack->inBadSeq, s->inBadSeq); - convoput(c, TControlAck, b); + convoput(c, TControl, ControlAck, b); } @@ -1054,12 +1089,9 @@ convack(Conv *c) static Block * conviput(Conv *c, Block *b, int control) { - int type, n; - ulong seq, seqwrap, cseq; + int type, subtype; + ulong seq, seqwrap; long seqdiff; - AckPkt *ack; - ulong mseq, mask; - Block *bb; c->lstats.inPackets++; @@ -1068,14 +1100,16 @@ conviput(Conv *c, Block *b, int control) return nil; } - type = b->rp[0]; + type = b->rp[0] >> 4; + subtype = type & 0xf; + b->rp += 1; if(type == TConnect) { - conviput2(c, b); + conviconnect(c, subtype, b); return nil; } - seq = (b->rp[1]<<16) + (b->rp[2]<<8) + b->rp[3]; - b->rp += 4; + seq = (b->rp[0]<<16) + (b->rp[1]<<8) + b->rp[2]; + b->rp += 3; seqwrap = c->in.seqwrap; seqdiff = seq - c->in.seq; @@ -1107,7 +1141,16 @@ print("dup sequence number: %ld (%ld %ld)\n", seq, c->in.seqwrap, seqdiff); // ok the sequence number looks ok if(0) print("coniput seq=%ulx\n", seq); - // auth + if(c->in.auth != 0) { + if(!(*c->in.auth)(&c->in, b->rp-4, BLEN(b)+4)) { +print("bad auth\n"); + c->lstats.inBadAuth++; + freeb(b); + return nil; + } + b->wp -= c->in.authlen; + } + // decrypt // ok the packet is good @@ -1132,92 +1175,20 @@ print("missing packets: %ld-%ld\n", seq - SeqWindow - seqdiff+1, seq-SeqWindow); switch(type) { case TControl: - if(BLEN(b) < 4) - break; - cseq = nhgetl(b->rp); - if(cseq == c->in.controlseq) { -print("duplicate control packet: %ulx\n", cseq); - // duplicate control packet - freeb(b); - if(c->in.controlpkt == nil) - convack(c); - return nil; - } - - if(cseq != c->in.controlseq+1) - break; - c->in.controlseq = cseq; - b->rp += 4; - if(BLEN(b) == 0) { - // just a ping - freeb(b); - convack(c); - } else { - c->in.controlpkt = b; -if(0) print("recv %ld size=%ld\n", cseq, BLEN(b)); - wakeup(&c->in.controlready); - } - return nil; - case TControlAck: - if(BLEN(b) != sizeof(AckPkt)) - break; - ack = (AckPkt*)(b->rp); - cseq = nhgetl(ack->cseq); - if(cseq != c->out.controlseq) { -print("ControlAck expected %ulx got %ulx\n", c->out.controlseq, cseq); - break; - } - c->rstats.outPackets = nhgetl(ack->outPackets); - c->rstats.outDataPackets = nhgetl(ack->outDataPackets); - c->rstats.outDataBytes = nhgetl(ack->outDataBytes); - c->rstats.outCompDataBytes = nhgetl(ack->outCompDataBytes); - c->rstats.inPackets = nhgetl(ack->inPackets); - c->rstats.inDataPackets = nhgetl(ack->inDataPackets); - c->rstats.inDataBytes = nhgetl(ack->inDataBytes); - c->rstats.inCompDataBytes = nhgetl(ack->inCompDataBytes); - c->rstats.inMissing = nhgetl(ack->inMissing); - c->rstats.inDup = nhgetl(ack->inDup); - c->rstats.inReorder = nhgetl(ack->inReorder); - c->rstats.inBadAuth = nhgetl(ack->inBadAuth); - c->rstats.inBadSeq = nhgetl(ack->inBadSeq); - freeb(b); - freeb(c->out.controlpkt); - c->out.controlpkt = nil; - c->timeout = c->lastrecv + KeepAlive; - wakeup(&c->out.controlready); + convicontrol(c, subtype, b); return nil; case TData: c->lstats.inDataPackets++; c->lstats.inDataBytes += BLEN(b); - c->lstats.inCompDataBytes += BLEN(b); if(control) break; return b; - case TThwackU: + case TCompData: c->lstats.inDataPackets++; c->lstats.inCompDataBytes += BLEN(b); - mask = b->rp[0]; - mseq = (b->rp[1]<<16) | (b->rp[2]<<8) | b->rp[3]; - b->rp += 4; - thwackack(c->out.compstate, mseq, mask); - c->lstats.inDataBytes += BLEN(b); - if(control) - break; - return b; - case TThwackC: - c->lstats.inDataPackets++; - c->lstats.inCompDataBytes += BLEN(b); - bb = b; - b = allocb(ThwMaxBlock); - n = unthwack(c->in.compstate, b->wp, ThwMaxBlock, bb->rp, BLEN(bb), seq); - freeb(bb); - if(n < 0) - break; - b->wp += n; - mask = b->rp[0]; - mseq = (b->rp[1]<<16) | (b->rp[2]<<8) | b->rp[3]; - thwackack(c->out.compstate, mseq, mask); - b->rp += 4; + b = convicomp(c, subtype, b); + if(b == nil); + return nil; c->lstats.inDataBytes += BLEN(b); if(control) break; @@ -1230,21 +1201,20 @@ print("droping packet %d n=%ld\n", type, BLEN(b)); // assume hold conv lock static void -conviput2(Conv *c, Block *b) +conviconnect(Conv *c, int subtype, Block *b) { - ConnectPkt *con; ulong dialid; ulong acceptid; - if(BLEN(b) != sizeof(ConnectPkt)) { + if(BLEN(b) != 8) { freeb(b); return; } - con = (ConnectPkt*)b->rp; - dialid = nhgetl(con->dialid); - acceptid = nhgetl(con->acceptid); + dialid = nhgetl(b->rp); + acceptid = nhgetl(b->rp + 4); + freeb(b); -print("conviput2: %s: %d %uld %uld\n", convstatename[c->state], con->op, dialid, acceptid); +print("conviconnect: %s: %d %uld %uld\n", convstatename[c->state], subtype, dialid, acceptid); switch(c->state) { default: @@ -1259,14 +1229,15 @@ print("conviput2: %s: %d %uld %uld\n", convstatename[c->state], con->op, dialid, case COpen: case CLocalClose: case CRemoteClose: - if(dialid != c->dialid || acceptid != c->acceptid) + if(dialid != c->dialid + || subtype != ConOpenRequest && acceptid != c->acceptid) goto Reset; break; case CClosed: goto Reset; } - switch(con->op) { + switch(subtype) { case ConOpenRequest: switch(c->state) { case CInit: @@ -1287,7 +1258,7 @@ print("conviput2: %s: %d %uld %uld\n", convstatename[c->state], con->op, dialid, return; case COpen: // duplicate that we have to ack - convoput2(c, ConOpenAckAck, acceptid, dialid); + convoconnect(c, ConOpenAckAck, acceptid, dialid); return; } break; @@ -1302,7 +1273,7 @@ print("conviput2: %s: %d %uld %uld\n", convstatename[c->state], con->op, dialid, } break; case ConClose: - convoput2(c, ConReset, dialid, acceptid); + convoconnect(c, ConReset, dialid, acceptid); switch(c->state) { case CInit: case CDial: @@ -1316,7 +1287,7 @@ print("conviput2: %s: %d %uld %uld\n", convstatename[c->state], con->op, dialid, case CRemoteClose: return; } - return; + break; case ConReset: switch(c->state) { case CInit: @@ -1329,12 +1300,89 @@ print("conviput2: %s: %d %uld %uld\n", convstatename[c->state], con->op, dialid, case CRemoteClose: return; } - return; + break; } Reset: // invalid connection message - reset to sender -print("invalid conviput2 - sending reset\n"); - convoput2(c, ConReset, dialid, acceptid); +print("invalid conviconnect - sending reset\n"); + convoconnect(c, ConReset, dialid, acceptid); +} + +static void +convicontrol(Conv *c, int subtype, Block *b) +{ + ulong cseq; + AckPkt *ack; + + if(BLEN(b) < 4) + return; + cseq = nhgetl(b->rp); + + switch(subtype){ + case ControlMesg: + if(cseq == c->in.controlseq) { +print("duplicate control packet: %ulx\n", cseq); + // duplicate control packet + freeb(b); + if(c->in.controlpkt == nil) + convack(c); + return; + } + + if(cseq != c->in.controlseq+1) + return; + c->in.controlseq = cseq; + b->rp += 4; + if(BLEN(b) == 0) { + // just a ping + freeb(b); + convack(c); + } else { + c->in.controlpkt = b; +if(0) print("recv %ld size=%ld\n", cseq, BLEN(b)); + wakeup(&c->in.controlready); + } + return; + case ControlAck: + if(cseq != c->out.controlseq) { +print("ControlAck expected %ulx got %ulx\n", c->out.controlseq, cseq); + return; + } + if(BLEN(b) < sizeof(AckPkt)) + return; + ack = (AckPkt*)(b->rp); + c->rstats.outPackets = nhgetl(ack->outPackets); + c->rstats.outDataPackets = nhgetl(ack->outDataPackets); + c->rstats.outDataBytes = nhgetl(ack->outDataBytes); + c->rstats.outCompDataBytes = nhgetl(ack->outCompDataBytes); + c->rstats.inPackets = nhgetl(ack->inPackets); + c->rstats.inDataPackets = nhgetl(ack->inDataPackets); + c->rstats.inDataBytes = nhgetl(ack->inDataBytes); + c->rstats.inCompDataBytes = nhgetl(ack->inCompDataBytes); + c->rstats.inMissing = nhgetl(ack->inMissing); + c->rstats.inDup = nhgetl(ack->inDup); + c->rstats.inReorder = nhgetl(ack->inReorder); + c->rstats.inBadAuth = nhgetl(ack->inBadAuth); + c->rstats.inBadSeq = nhgetl(ack->inBadSeq); + freeb(b); + freeb(c->out.controlpkt); + c->out.controlpkt = nil; + c->timeout = c->lastrecv + KeepAlive; + wakeup(&c->out.controlready); + return; + } +} + +static Block* +convicomp(Conv *c, int subtype, Block *b) +{ + if(c->in.comp == nil) { + freeb(b); + return nil; + } + if((*c->in.comp)(&c->in, subtype, &b) < 0) + return nil; + return b; } // c is locked @@ -1356,13 +1404,13 @@ convwriteblock(Conv *c, Block *b) // assume hold conv lock static void -convoput(Conv *c, int type, Block *b) +convoput(Conv *c, int type, int subtype, Block *b) { // try and compress c->lstats.outPackets++; /* Make space to fit sdp header */ b = padblock(b, 4 + c->out.cipherivlen); - b->rp[0] = type; + b->rp[0] = (type << 4) | subtype; c->out.seq++; if(c->out.seq == (1<<24)) { c->out.seq = 0; @@ -1374,29 +1422,31 @@ convoput(Conv *c, int type, Block *b) // encrypt // auth + if(c->out.auth) { + b = padblock(b, -c->out.authlen); + b->wp += c->out.authlen; + (*c->out.auth)(&c->out, b->rp, BLEN(b)); + } convwriteblock(c, b); } // assume hold conv lock static void -convoput2(Conv *c, int op, ulong dialid, ulong acceptid) +convoconnect(Conv *c, int op, ulong dialid, ulong acceptid) { Block *b; - ConnectPkt *con; c->lstats.outPackets++; if(c->chan == nil) { print("chan = nil\n"); error("no channel attached"); } - b = allocb(sizeof(ConnectPkt)); - con = (ConnectPkt*)b->wp; - b->wp += sizeof(ConnectPkt); - con->type = TConnect; - con->op = op; - hnputl(con->dialid, dialid); - hnputl(con->acceptid, acceptid); + b = allocb(9); + b->wp[0] = (TConnect << 4) | op; + hnputl(b->wp+1, dialid); + hnputl(b->wp+5, acceptid); + b->wp += 9; convwriteblock(c, b); } @@ -1525,7 +1575,6 @@ writecontrol(Conv *c, void *p, int n, int wait) { Block *b; - qlock(&c->out.controllk); qlock(c); if(waserror()) { @@ -1541,7 +1590,7 @@ writecontrol(Conv *c, void *p, int n, int wait) b->wp += 4+n; c->out.controlpkt = b; convretryinit(c); - convoput(c, TControl, copyblock(b, blocklen(b))); + convoput(c, TControl, ControlMesg, copyblock(b, blocklen(b))); if(wait) writewait(c); poperror(); @@ -1574,9 +1623,7 @@ readdata(Conv *c, int n) static long writedata(Conv *c, Block *b) { - int n, nn; - ulong seq; - Block *bb; + int n; qlock(c); if(waserror()) { @@ -1593,34 +1640,12 @@ writedata(Conv *c, Block *b) c->lstats.outDataPackets++; c->lstats.outDataBytes += n; - if(0) { - c->lstats.outCompDataBytes += n; - convoput(c, TData, b); - poperror(); - qunlock(c); - return n; - } - b = padblock(b, 4); - b->rp[0] = (c->in.window>>1) & 0xff; - b->rp[1] = c->in.seq>>16; - b->rp[2] = c->in.seq>>8; - b->rp[3] = c->in.seq; - - // must generate same value as convoput - seq = (c->out.seq + 1) & (SeqMax-1); - - bb = allocb(BLEN(b)); - nn = thwack(c->out.compstate, bb->wp, b->rp, BLEN(b), seq); - if(nn < 0) { + if(c->out.comp != nil) { + int subtype = (*c->out.comp)(&c->out, 0, &b); c->lstats.outCompDataBytes += BLEN(b); - convoput(c, TThwackU, b); - freeb(bb); - } else { - c->lstats.outCompDataBytes += nn; - bb->wp += nn; - convoput(c, TThwackC, bb); - freeb(b); - } + convoput(c, TCompData, subtype, b); + } else + convoput(c, TData, 0, b); poperror(); qunlock(c); @@ -1663,3 +1688,353 @@ print("convreader exiting\n"); qunlock(c); pexit("hangup", 1); } + + +/* ciphers, authenticators, and compressors */ + +static void +setalg(Conv *c, char *name, Algorithm *alg) +{ + for(; alg->name; alg++) + if(strcmp(name, alg->name) == 0) + break; + if(alg->name == nil) + error("unknown algorithm"); + + alg->init(c, alg->name, alg->keylen); +} + +static void +setsecret(OneWay *ow, char *secret) +{ + char *p; + int i, c; + + i = 0; + memset(ow->secret, 0, sizeof(ow->secret)); + for(p=secret; *p; p++) { + if(i >= sizeof(ow->secret)*2) + break; + c = *p; + if(c >= '0' && c <= '9') + c -= '0'; + else if(c >= 'a' && c <= 'f') + c -= 'a'-10; + else if(c >= 'A' && c <= 'F') + c -= 'A'-10; + else + error("bad character in secret"); + if((i&1) == 0) + c <<= 4; + ow->secret[i>>1] |= c; + i++; + } +} + +static void +setkey(uchar *key, int n, OneWay *ow, char *prefix) +{ + uchar ibuf[SHAdlen], obuf[MD5dlen], salt[10]; + int i, round = 0; + + while(n > 0){ + for(i=0; isecret, sizeof(ow->secret), nil, nil)); + i = (n sizeof salt) + panic("setkey: you ask too much"); + } +} + + +static void +cipherfree(Conv *c) +{ + if(c->ciphername) { + free(c->ciphername); + c->ciphername = nil; + } + if(c->in.cipherstate) { + free(c->in.cipherstate); + c->in.cipherstate = nil; + } + if(c->out.cipherstate) { + free(c->out.cipherstate); + c->out.cipherstate = nil; + } + c->in.cipher = nil; +} + +static void +authfree(Conv *c) +{ + if(c->authname) { + free(c->authname); + c->authname = nil; + } + if(c->in.authstate) { + free(c->in.authstate); + c->in.authstate = nil; + } + if(c->out.authstate) { + free(c->out.authstate); + c->out.authstate = nil; + } + c->in.auth = nil; +} + +static void +compfree(Conv *c) +{ + if(c->compname) { + free(c->compname); + c->compname = nil; + } + if(c->in.compstate) { + free(c->in.compstate); + c->in.compstate = nil; + } + if(c->out.compstate) { + free(c->out.compstate); + c->out.compstate = nil; + } + c->in.comp = nil; +} + + +static void +nullcipherinit(Conv *c, char *, int) +{ + cipherfree(c); +} + +static int +desencrypt(OneWay *ow, uchar *p, int n) +{ + uchar *pp, *ip, *eip, *ep; + DESstate *ds = ow->cipherstate; + + ep = p + n; + memmove(p, ds->ivec, 8); + for(p += 8; p < ep; p += 8){ + pp = p; + ip = ds->ivec; + for(eip = ip+8; ip < eip; ) + *pp++ ^= *ip++; + block_cipher(ds->expanded, p, 0); + memmove(ds->ivec, p, 8); + } + return 1; +} + +static int +desdecrypt(OneWay *ow, uchar *p, int n) +{ + uchar tmp[8]; + uchar *tp, *ip, *eip, *ep; + DESstate *ds = ow->cipherstate; + + ep = p + n; + memmove(ds->ivec, p, 8); + p += 8; + while(p < ep){ + memmove(tmp, p, 8); + block_cipher(ds->expanded, p, 1); + tp = tmp; + ip = ds->ivec; + for(eip = ip+8; ip < eip; ){ + *p++ ^= *ip; + *ip++ = *tp++; + } + } + return 1; +} + +static void +descipherinit(Conv *c, char *name, int n) +{ + uchar key[8]; + uchar ivec[8]; + int i; + + cipherfree(c); + c->ciphername = malloc(strlen(name)+1); + strcpy(c->ciphername, name); + + if(n > sizeof(key)) + n = sizeof(key); + + /* in */ + memset(key, 0, sizeof(key)); + setkey(key, n, &c->in, "cipher"); + memset(ivec, 0, sizeof(ivec)); + c->in.cipherblklen = 8; + c->in.cipherivlen = 8; + c->in.cipher = desdecrypt; + c->in.cipherstate = smalloc(sizeof(DESstate)); + setupDESstate(c->in.cipherstate, key, ivec); + + /* out */ + memset(key, 0, sizeof(key)); + setkey(key, n, &c->out, "cipher"); + for(i=0; i<8; i++) + ivec[i] = nrand(256); + c->out.cipherblklen = 8; + c->out.cipherivlen = 8; + c->out.cipher = desencrypt; + c->out.cipherstate = smalloc(sizeof(DESstate)); + setupDESstate(c->out.cipherstate, key, ivec); +} + +static void +rc4cipherinit(Conv *c, char *name, int keylen) +{ +} + +static void +nullauthinit(Conv *c, char *name, int keylen) +{ + authfree(c); +} + +static void +shaauthinit(Conv *c, char *name, int keylen) +{ + authfree(c); +} + +static void +hmac_md5(uchar hash[MD5dlen], ulong wrap, uchar *t, long tlen, uchar *key, long klen) +{ + uchar ipad[65], opad[65], wbuf[4]; + int i; + DigestState *digest; + uchar innerhash[MD5dlen]; + + for(i=0; i<64; i++){ + ipad[i] = 0x36; + opad[i] = 0x5c; + } + ipad[64] = opad[64] = 0; + for(i=0; iauthlen) + return 0; + tlen -= ow->authlen; + + memset(hash, 0, MD5dlen); + hmac_md5(hash, ow->seqwrap, t, tlen, (uchar*)ow->authstate, 16); + r = memcmp(t+tlen, hash, ow->authlen) == 0; + memmove(t+tlen, hash, ow->authlen); + return r; +} + +static void +md5authinit(Conv *c, char *name, int keylen) +{ + authfree(c); + + c->authname = malloc(strlen(name)+1); + strcpy(c->authname, name); + + if(keylen > 16) + keylen = 16; + + /* in */ + c->in.authstate = smalloc(16); + memset(c->in.authstate, 0, 16); + setkey(c->in.authstate, keylen, &c->in, "auth"); + c->in.authlen = 12; + c->in.auth = md5auth; + + /* out */ + c->out.authstate = smalloc(16); + memset(c->out.authstate, 0, 16); + setkey(c->out.authstate, keylen, &c->out, "auth"); + c->out.authlen = 12; + c->out.auth = md5auth; +} + +static void +nullcompinit(Conv *c, char *name, int keylen) +{ +} + +static void +thwackcompinit(Conv *c, char *name, int keylen) +{ +} + + +#ifdef XXX + case TThwackU: + mask = b->rp[0]; + mseq = (b->rp[1]<<16) | (b->rp[2]<<8) | b->rp[3]; + b->rp += 4; + thwackack(c->out.compstate, mseq, mask); + c->lstats.inDataBytes += BLEN(b); + if(control) + break; + return b; + case TThwackC: + c->lstats.inDataPackets++; + c->lstats.inCompDataBytes += BLEN(b); + bb = b; + b = allocb(ThwMaxBlock); + n = unthwack(c->in.compstate, b->wp, ThwMaxBlock, bb->rp, BLEN(bb), seq); + freeb(bb); + if(n < 0) + break; + b->wp += n; + mask = b->rp[0]; + mseq = (b->rp[1]<<16) | (b->rp[2]<<8) | b->rp[3]; + thwackack(c->out.compstate, mseq, mask); + b->rp += 4; + c->lstats.inDataBytes += BLEN(b); + if(control) + break; + return b; + } + b = padblock(b, 4); + b->rp[0] = (c->in.window>>1) & 0xff; + b->rp[1] = c->in.seq>>16; + b->rp[2] = c->in.seq>>8; + b->rp[3] = c->in.seq; + + // must generate same value as convoput + seq = (c->out.seq + 1) & (SeqMax-1); + + bb = allocb(BLEN(b)); + nn = thwack(c->out.compstate, bb->wp, b->rp, BLEN(b), seq); + if(nn < 0) { + c->lstats.outCompDataBytes += BLEN(b); + convoput(c, TThwackU, b); + freeb(bb); + } else { + c->lstats.outCompDataBytes += nn; + bb->wp += nn; + convoput(c, TThwackC, bb); + freeb(b); + } +#endif