From d6fb2c556c9ec6d09bc59bb24fddaeebb9d83ca9 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Tue, 15 Jun 1999 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 1999-06-15 --- ip/esp.c | 119 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 117 insertions(+), 2 deletions(-) diff --git a/ip/esp.c b/ip/esp.c index f86d38b010948e244a67bf474e365f19a7c0cd6f..166d4e82aa67706057ce2b26426008725b79c98e 100644 --- a/ip/esp.c +++ b/ip/esp.c @@ -15,6 +15,7 @@ typedef struct Userhdr Userhdr; typedef struct Esppriv Esppriv; typedef struct Espcb Espcb; typedef struct Algorithm Algorithm; +typedef struct Esprc4 Esprc4; #define DPRINT if(0)print @@ -94,6 +95,23 @@ struct Algorithm void (*init)(Espcb*, char* name, uchar *key, int keylen); }; + +enum { + RC4forward = 10*1024*1024, // maximum skip forward + RC4back = 100*1024, // maximum look back +}; + +struct Esprc4 +{ + ulong cseq; // current byte sequence number + RC4state current; + + int ovalid; // old is valid + ulong lgseq; // last good sequence + ulong oseq; // old byte sequence number + RC4state old; +}; + static Conv* convlookup(Proto *esp, ulong spi); static char *setalg(Espcb *ecb, char **f, int n, Algorithm *alg); static void nullespinit(Espcb*, char*, uchar *key, int keylen); @@ -101,11 +119,13 @@ static void nullahinit(Espcb*, char*, uchar *key, int keylen); static void shaahinit(Espcb*, char*, uchar *key, int keylen); static void md5ahinit(Espcb*, char*, uchar *key, int keylen); static void desespinit(Espcb *ecb, char *name, uchar *k, int n); +static void rc4espinit(Espcb *ecb, char *name, uchar *k, int n); static Algorithm espalg[] = { "null", 0, nullespinit, "des_56_cbc", 64, desespinit, + "rc4_128", 128, rc4espinit, nil, 0, nil, }; @@ -358,7 +378,14 @@ print("esp: bad auth %I -> %I!%ld\n", raddr, laddr, spi); freeb(bp); return; } - ecb->cipher(ecb, bp->rp+EsphdrSize, payload); + if(!ecb->cipher(ecb, bp->rp+EsphdrSize, payload)) { + qunlock(esp); +print("esp: cipher failed %I -> %I!%ld: %r\n", raddr, laddr, spi); + netlog(f, Logesp, "esp: cipher failed %I -> %I!%d: %r\n", raddr, + laddr, spi); + freeb(bp); + return; + } payload -= EsptailSize; et = (Esptail*)(bp->rp + EsphdrSize + payload); @@ -477,7 +504,6 @@ espremote(Conv *c, char *buf, int len) return n; } -// should have esp locked static Conv* convlookup(Proto *esp, ulong spi) { @@ -726,6 +752,95 @@ desespinit(Espcb *ecb, char *name, uchar *k, int n) ecb->espstate = smalloc(sizeof(DESstate)); setupDESstate(ecb->espstate, key, ivec); } + +static int +rc4cipher(Espcb *ecb, uchar *p, int n) +{ + Esprc4 *esprc4; + RC4state tmpstate; + ulong seq; + long d, dd; + + if(n < 4) + return 0; + + esprc4 = ecb->espstate; + if(ecb->incoming) { + seq = nhgetl(p); + p += 4; + n -= 4; + d = seq-esprc4->cseq; + if(d == 0) { + rc4(&esprc4->current, p, n); + esprc4->cseq += n; + if(esprc4->ovalid) { + dd = esprc4->cseq - esprc4->lgseq; + if(dd > RC4back) + esprc4->ovalid = 0; + } + } else if(d > 0) { +print("missing packet: %ld\n", d); + // this link is hosed + if(d > RC4forward) { + strcpy(up->error, "rc4cipher: skipped too much"); + return 0; + } + esprc4->lgseq = seq; + if(!esprc4->ovalid) { + esprc4->ovalid = 1; + esprc4->oseq = esprc4->cseq; + memmove(&esprc4->old, &esprc4->current, sizeof(RC4state)); + } + rc4skip(&esprc4->current, d); + rc4(&esprc4->current, p, n); + esprc4->cseq = seq+n; + } else { + dd = seq - esprc4->oseq; + if(!esprc4->ovalid || -d > RC4back || dd < 0) { + strcpy(up->error, "rc4cipher: too far back"); + return 0; + } +print("reordered packet: %uld\n", seq); + memmove(&tmpstate, &esprc4->old, sizeof(RC4state)); + rc4skip(&tmpstate, dd); + rc4(&tmpstate, p, n); + return 1; + } + + // move old state up + if(esprc4->ovalid) { + dd = esprc4->cseq - RC4back - esprc4->oseq; + if(dd > 0) { + rc4skip(&esprc4->old, dd); + esprc4->oseq += dd; + } + } + } else { + hnputl(p, esprc4->cseq); + p += 4; + n -= 4; + rc4(&esprc4->current, p, n); + esprc4->cseq += n; + } + return 1; +} + +static void +rc4espinit(Espcb *ecb, char *name, uchar *k, int n) +{ + Esprc4 *esprc4; + + // bits to bytes + n = (n+7)>>3; + esprc4 = smalloc(sizeof(Esprc4)); + memset(esprc4, 0, sizeof(Esprc4)); + setupRC4state(&esprc4->current, k, n); + ecb->espalg = name; + ecb->espblklen = 4; + ecb->espivlen = 4; + ecb->cipher = rc4cipher; + ecb->espstate = esprc4; +} void espinit(Fs *fs)