esp.c - vx32 - Local 9vx git repository for patches.
 (HTM) git clone git://r-36.net/vx32
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
       esp.c (19612B)
       ---
            1 /*
            2  * Encapsulating Security Payload for IPsec for IPv4, rfc1827.
            3  *        currently only implements tunnel mode.
            4  * TODO: update to match rfc4303.
            5  */
            6 #include        "u.h"
            7 #include        "lib.h"
            8 #include        "mem.h"
            9 #include        "dat.h"
           10 #include        "fns.h"
           11 #include        "error.h"
           12 
           13 #include        "ip.h"
           14 #include        "ipv6.h"
           15 #include        "libsec.h"
           16 
           17 typedef struct Esphdr Esphdr;
           18 typedef struct Esp4hdr Esp4hdr;
           19 typedef struct Esp6hdr Esp6hdr;
           20 typedef struct Esptail Esptail;
           21 typedef struct Userhdr Userhdr;
           22 typedef struct Esppriv Esppriv;
           23 typedef struct Espcb Espcb;
           24 typedef struct Algorithm Algorithm;
           25 
           26 enum
           27 {
           28         IP_ESPPROTO        = 50,        /* IP v4 and v6 protocol number */
           29         Esp4hdrlen        = IP4HDR + 8,
           30         Esp6hdrlen        = IP6HDR + 8,
           31 
           32         Esptaillen        = 2,        /* does not include pad or auth data */
           33         Userhdrlen        = 4,        /* user-visible header size - if enabled */
           34 };
           35 
           36 struct Esphdr
           37 {
           38         uchar        espspi[4];        /* Security parameter index */
           39         uchar        espseq[4];        /* Sequence number */
           40 };
           41 
           42 /*
           43  * tunnel-mode layout:                IP | ESP | TCP/UDP | user data.
           44  * transport-mode layout is:        ESP | IP | TCP/UDP | user data.
           45  */
           46 struct Esp4hdr
           47 {
           48         /* ipv4 header */
           49         uchar        vihl;                /* Version and header length */
           50         uchar        tos;                /* Type of service */
           51         uchar        length[2];        /* packet length */
           52         uchar        id[2];                /* Identification */
           53         uchar        frag[2];        /* Fragment information */
           54         uchar        Unused;
           55         uchar        espproto;        /* Protocol */
           56         uchar        espplen[2];        /* Header plus data length */
           57         uchar        espsrc[4];        /* Ip source */
           58         uchar        espdst[4];        /* Ip destination */
           59 
           60         /* Esphdr; */
           61         uchar        espspi[4];        /* Security parameter index */
           62         uchar        espseq[4];        /* Sequence number */
           63 };
           64 
           65 /* tunnel-mode layout */
           66 struct Esp6hdr
           67 {
           68         /* Ip6hdr; */
           69         uchar        vcf[4];                /* version:4, traffic class:8, flow label:20 */
           70         uchar        ploadlen[2];        /* payload length: packet length - 40 */
           71         uchar        proto;                /* next header type */
           72         uchar        ttl;                /* hop limit */
           73         uchar        src[IPaddrlen];
           74         uchar        dst[IPaddrlen];
           75 
           76         /* Esphdr; */
           77         uchar        espspi[4];        /* Security parameter index */
           78         uchar        espseq[4];        /* Sequence number */
           79 };
           80 
           81 struct Esptail
           82 {
           83         uchar        pad;
           84         uchar        nexthdr;
           85 };
           86 
           87 /* header as seen by the user */
           88 struct Userhdr
           89 {
           90         uchar        nexthdr;        /* next protocol */
           91         uchar        unused[3];
           92 };
           93 
           94 struct Esppriv
           95 {
           96         ulong        in;
           97         ulong        inerrors;
           98 };
           99 
          100 /*
          101  *  protocol specific part of Conv
          102  */
          103 struct Espcb
          104 {
          105         int        incoming;
          106         int        header;                /* user user level header */
          107         ulong        spi;
          108         ulong        seq;                /* last seq sent */
          109         ulong        window;                /* for replay attacks */
          110         char        *espalg;
          111         void        *espstate;        /* other state for esp */
          112         int        espivlen;        /* in bytes */
          113         int        espblklen;
          114         int        (*cipher)(Espcb*, uchar *buf, int len);
          115         char        *ahalg;
          116         void        *ahstate;        /* other state for esp */
          117         int        ahlen;                /* auth data length in bytes */
          118         int        ahblklen;
          119         int        (*auth)(Espcb*, uchar *buf, int len, uchar *hash);
          120 };
          121 
          122 struct Algorithm
          123 {
          124         char         *name;
          125         int        keylen;                /* in bits */
          126         void        (*init)(Espcb*, char* name, uchar *key, int keylen);
          127 };
          128 
          129 static        Conv* convlookup(Proto *esp, ulong spi);
          130 static        char *setalg(Espcb *ecb, char **f, int n, Algorithm *alg);
          131 static        void espkick(void *x);
          132 
          133 static        void nullespinit(Espcb*, char*, uchar *key, int keylen);
          134 static        void desespinit(Espcb *ecb, char *name, uchar *k, int n);
          135 
          136 static        void nullahinit(Espcb*, char*, uchar *key, int keylen);
          137 static        void shaahinit(Espcb*, char*, uchar *key, int keylen);
          138 static        void md5ahinit(Espcb*, char*, uchar *key, int keylen);
          139 
          140 static Algorithm espalg[] =
          141 {
          142         "null",                        0,        nullespinit,
          143 //        "des3_cbc",                192,        des3espinit,        /* rfc2451 */
          144 //        "aes_128_cbc",                128,        aescbcespinit,        /* rfc3602 */
          145 //        "aes_ctr",                128,        aesctrespinit,        /* rfc3686 */
          146         "des_56_cbc",                64,        desespinit,        /* rfc2405, deprecated */
          147 //        "rc4_128",                128,        rc4espinit,        /* gone in rfc4305 */
          148         nil,                        0,        nil,
          149 };
          150 
          151 static Algorithm ahalg[] =
          152 {
          153         "null",                        0,        nullahinit,
          154         "hmac_sha1_96",                128,        shaahinit,        /* rfc2404 */
          155 //        "aes_xcbc_mac_96",        128,        aesahinit,        /* rfc3566 */
          156         "hmac_md5_96",                128,        md5ahinit,        /* rfc2403 */
          157         nil,                        0,        nil,
          158 };
          159 
          160 static char*
          161 espconnect(Conv *c, char **argv, int argc)
          162 {
          163         char *p, *pp;
          164         char *e = nil;
          165         ulong spi;
          166         Espcb *ecb = (Espcb*)c->ptcl;
          167 
          168         switch(argc) {
          169         default:
          170                 e = "bad args to connect";
          171                 break;
          172         case 2:
          173                 p = strchr(argv[1], '!');
          174                 if(p == nil){
          175                         e = "malformed address";
          176                         break;
          177                 }
          178                 *p++ = 0;
          179                 parseip(c->raddr, argv[1]);
          180                 findlocalip(c->p->f, c->laddr, c->raddr);
          181                 ecb->incoming = 0;
          182                 ecb->seq = 0;
          183                 if(strcmp(p, "*") == 0) {
          184                         QLOCK(c->p);
          185                         for(;;) {
          186                                 spi = nrand(1<<16) + 256;
          187                                 if(convlookup(c->p, spi) == nil)
          188                                         break;
          189                         }
          190                         QUNLOCK(c->p);
          191                         ecb->spi = spi;
          192                         ecb->incoming = 1;
          193                         qhangup(c->wq, nil);
          194                 } else {
          195                         spi = strtoul(p, &pp, 10);
          196                         if(pp == p) {
          197                                 e = "malformed address";
          198                                 break;
          199                         }
          200                         ecb->spi = spi;
          201                         qhangup(c->rq, nil);
          202                 }
          203                 nullespinit(ecb, "null", nil, 0);
          204                 nullahinit(ecb, "null", nil, 0);
          205         }
          206         Fsconnected(c, e);
          207 
          208         return e;
          209 }
          210 
          211 
          212 static int
          213 espstate(Conv *c, char *state, int n)
          214 {
          215         return snprint(state, n, "%s", c->inuse?"Open\n":"Closed\n");
          216 }
          217 
          218 static void
          219 espcreate(Conv *c)
          220 {
          221         c->rq = qopen(64*1024, Qmsg, 0, 0);
          222         c->wq = qopen(64*1024, Qkick, espkick, c);
          223 }
          224 
          225 static void
          226 espclose(Conv *c)
          227 {
          228         Espcb *ecb;
          229 
          230         qclose(c->rq);
          231         qclose(c->wq);
          232         qclose(c->eq);
          233         ipmove(c->laddr, IPnoaddr);
          234         ipmove(c->raddr, IPnoaddr);
          235 
          236         ecb = (Espcb*)c->ptcl;
          237         free(ecb->espstate);
          238         free(ecb->ahstate);
          239         memset(ecb, 0, sizeof(Espcb));
          240 }
          241 
          242 static int
          243 ipvers(Conv *c)
          244 {
          245         if((memcmp(c->raddr, v4prefix, IPv4off) == 0 &&
          246             memcmp(c->laddr, v4prefix, IPv4off) == 0) ||
          247             ipcmp(c->raddr, IPnoaddr) == 0)
          248                 return V4;
          249         else
          250                 return V6;
          251 }
          252 
          253 static void
          254 espkick(void *x)
          255 {
          256         Conv *c = x;
          257         Esp4hdr *eh4;
          258         Esp6hdr *eh6;
          259         Esptail *et;
          260         Userhdr *uh;
          261         Espcb *ecb;
          262         Block *bp;
          263         int nexthdr, payload, pad, align, version, hdrlen, iphdrlen;
          264         uchar *auth;
          265 
          266         version = ipvers(c);
          267         iphdrlen = version == V4? IP4HDR: IP6HDR;
          268         hdrlen =   version == V4? Esp4hdrlen: Esp6hdrlen;
          269 
          270         bp = qget(c->wq);
          271         if(bp == nil)
          272                 return;
          273 
          274         QLOCK(c);
          275         ecb = c->ptcl;
          276 
          277         if(ecb->header) {
          278                 /* make sure the message has a User header */
          279                 bp = pullupblock(bp, Userhdrlen);
          280                 if(bp == nil) {
          281                         QUNLOCK(c);
          282                         return;
          283                 }
          284                 uh = (Userhdr*)bp->rp;
          285                 nexthdr = uh->nexthdr;
          286                 bp->rp += Userhdrlen;
          287         } else {
          288                 nexthdr = 0;        /* what should this be? */
          289         }
          290 
          291         payload = BLEN(bp) + ecb->espivlen;
          292 
          293         /* Make space to fit ip header */
          294         bp = padblock(bp, hdrlen + ecb->espivlen);
          295 
          296         align = 4;
          297         if(ecb->espblklen > align)
          298                 align = ecb->espblklen;
          299         if(align % ecb->ahblklen != 0)
          300                 panic("espkick: ahblklen is important after all");
          301         pad = (align-1) - (payload + Esptaillen-1)%align;
          302 
          303         /*
          304          * Make space for tail
          305          * this is done by calling padblock with a negative size
          306          * Padblock does not change bp->wp!
          307          */
          308         bp = padblock(bp, -(pad+Esptaillen+ecb->ahlen));
          309         bp->wp += pad+Esptaillen+ecb->ahlen;
          310 
          311         eh4 = (Esp4hdr *)bp->rp;
          312         eh6 = (Esp6hdr *)bp->rp;
          313         et = (Esptail*)(bp->rp + hdrlen + payload + pad);
          314 
          315         /* fill in tail */
          316         et->pad = pad;
          317         et->nexthdr = nexthdr;
          318 
          319         ecb->cipher(ecb, bp->rp + hdrlen, payload + pad + Esptaillen);
          320         auth = bp->rp + hdrlen + payload + pad + Esptaillen;
          321 
          322         /* fill in head */
          323         if (version == V4) {
          324                 eh4->vihl = IP_VER4;
          325                 hnputl(eh4->espspi, ecb->spi);
          326                 hnputl(eh4->espseq, ++ecb->seq);
          327                 v6tov4(eh4->espsrc, c->laddr);
          328                 v6tov4(eh4->espdst, c->raddr);
          329                 eh4->espproto = IP_ESPPROTO;
          330                 eh4->frag[0] = 0;
          331                 eh4->frag[1] = 0;
          332         } else {
          333                 eh6->vcf[0] = IP_VER6;
          334                 hnputl(eh6->espspi, ecb->spi);
          335                 hnputl(eh6->espseq, ++ecb->seq);
          336                 ipmove(eh6->src, c->laddr);
          337                 ipmove(eh6->dst, c->raddr);
          338                 eh6->proto = IP_ESPPROTO;
          339         }
          340 
          341         ecb->auth(ecb, bp->rp + iphdrlen, (hdrlen - iphdrlen) +
          342                 payload + pad + Esptaillen, auth);
          343 
          344         QUNLOCK(c);
          345         /* print("esp: pass down: %uld\n", BLEN(bp)); */
          346         if (version == V4)
          347                 ipoput4(c->p->f, bp, 0, c->ttl, c->tos, c);
          348         else
          349                 ipoput6(c->p->f, bp, 0, c->ttl, c->tos, c);
          350 }
          351 
          352 void
          353 espiput(Proto *esp, Ipifc* _, Block *bp)
          354 {
          355         Esp4hdr *eh4;
          356         Esp6hdr *eh6;
          357         Esptail *et;
          358         Userhdr *uh;
          359         Conv *c;
          360         Espcb *ecb;
          361         uchar raddr[IPaddrlen], laddr[IPaddrlen];
          362         Fs *f;
          363         uchar *auth, *espspi;
          364         ulong spi;
          365         int payload, nexthdr, version, hdrlen;
          366 
          367         f = esp->f;
          368         if (bp == nil || BLEN(bp) == 0) {
          369                 /* get enough to identify the IP version */
          370                 bp = pullupblock(bp, IP4HDR);
          371                 if(bp == nil) {
          372                         netlog(f, Logesp, "esp: short packet\n");
          373                         return;
          374                 }
          375         }
          376         eh4 = (Esp4hdr*)bp->rp;
          377         version = ((eh4->vihl & 0xf0) == IP_VER4? V4: V6);
          378         hdrlen = version == V4? Esp4hdrlen: Esp6hdrlen;
          379 
          380         bp = pullupblock(bp, hdrlen + Esptaillen);
          381         if(bp == nil) {
          382                 netlog(f, Logesp, "esp: short packet\n");
          383                 return;
          384         }
          385 
          386         if (version == V4) {
          387                 eh4 = (Esp4hdr*)bp->rp;
          388                 spi = nhgetl(eh4->espspi);
          389                 v4tov6(raddr, eh4->espsrc);
          390                 v4tov6(laddr, eh4->espdst);
          391         } else {
          392                 eh6 = (Esp6hdr*)bp->rp;
          393                 spi = nhgetl(eh6->espspi);
          394                 ipmove(raddr, eh6->src);
          395                 ipmove(laddr, eh6->dst);
          396         }
          397 
          398         QLOCK(esp);
          399         /* Look for a conversation structure for this port */
          400         c = convlookup(esp, spi);
          401         if(c == nil) {
          402                 QUNLOCK(esp);
          403                 netlog(f, Logesp, "esp: no conv %I -> %I!%d\n", raddr,
          404                         laddr, spi);
          405                 icmpnoconv(f, bp);
          406                 freeblist(bp);
          407                 return;
          408         }
          409 
          410         QLOCK(c);
          411         QUNLOCK(esp);
          412 
          413         ecb = c->ptcl;
          414         /* too hard to do decryption/authentication on block lists */
          415         if(bp->next)
          416                 bp = concatblock(bp);
          417 
          418         if(BLEN(bp) < hdrlen + ecb->espivlen + Esptaillen + ecb->ahlen) {
          419                 QUNLOCK(c);
          420                 netlog(f, Logesp, "esp: short block %I -> %I!%d\n", raddr,
          421                         laddr, spi);
          422                 freeb(bp);
          423                 return;
          424         }
          425 
          426         auth = bp->wp - ecb->ahlen;
          427         espspi = version == V4? ((Esp4hdr*)bp->rp)->espspi:
          428                                 ((Esp6hdr*)bp->rp)->espspi;
          429         if(!ecb->auth(ecb, espspi, auth - espspi, auth)) {
          430                 QUNLOCK(c);
          431 print("esp: bad auth %I -> %I!%ld\n", raddr, laddr, spi);
          432                 netlog(f, Logesp, "esp: bad auth %I -> %I!%d\n", raddr,
          433                         laddr, spi);
          434                 freeb(bp);
          435                 return;
          436         }
          437 
          438         payload = BLEN(bp) - hdrlen - ecb->ahlen;
          439         if(payload <= 0 || payload % 4 != 0 || payload % ecb->espblklen != 0) {
          440                 QUNLOCK(c);
          441                 netlog(f, Logesp, "esp: bad length %I -> %I!%d payload=%d BLEN=%d\n",
          442                         raddr, laddr, spi, payload, BLEN(bp));
          443                 freeb(bp);
          444                 return;
          445         }
          446         if(!ecb->cipher(ecb, bp->rp + hdrlen, payload)) {
          447                 QUNLOCK(c);
          448 print("esp: cipher failed %I -> %I!%ld: %s\n", raddr, laddr, spi, up->errstr);
          449                 netlog(f, Logesp, "esp: cipher failed %I -> %I!%d: %s\n", raddr,
          450                         laddr, spi, up->errstr);
          451                 freeb(bp);
          452                 return;
          453         }
          454 
          455         payload -= Esptaillen;
          456         et = (Esptail*)(bp->rp + hdrlen + payload);
          457         payload -= et->pad + ecb->espivlen;
          458         nexthdr = et->nexthdr;
          459         if(payload <= 0) {
          460                 QUNLOCK(c);
          461                 netlog(f, Logesp, "esp: short packet after decrypt %I -> %I!%d\n",
          462                         raddr, laddr, spi);
          463                 freeb(bp);
          464                 return;
          465         }
          466 
          467         /* trim packet */
          468         bp->rp += hdrlen + ecb->espivlen;
          469         bp->wp = bp->rp + payload;
          470         if(ecb->header) {
          471                 /* assume Userhdrlen < Esp4hdrlen < Esp6hdrlen */
          472                 bp->rp -= Userhdrlen;
          473                 uh = (Userhdr*)bp->rp;
          474                 memset(uh, 0, Userhdrlen);
          475                 uh->nexthdr = nexthdr;
          476         }
          477 
          478         if(qfull(c->rq)){
          479                 netlog(f, Logesp, "esp: qfull %I -> %I.%uld\n", raddr,
          480                         laddr, spi);
          481                 freeblist(bp);
          482         }else {
          483 //                print("esp: pass up: %uld\n", BLEN(bp));
          484                 qpass(c->rq, bp);
          485         }
          486 
          487         QUNLOCK(c);
          488 }
          489 
          490 char*
          491 espctl(Conv *c, char **f, int n)
          492 {
          493         Espcb *ecb = c->ptcl;
          494         char *e = nil;
          495 
          496         if(strcmp(f[0], "esp") == 0)
          497                 e = setalg(ecb, f, n, espalg);
          498         else if(strcmp(f[0], "ah") == 0)
          499                 e = setalg(ecb, f, n, ahalg);
          500         else if(strcmp(f[0], "header") == 0)
          501                 ecb->header = 1;
          502         else if(strcmp(f[0], "noheader") == 0)
          503                 ecb->header = 0;
          504         else
          505                 e = "unknown control request";
          506         return e;
          507 }
          508 
          509 void
          510 espadvise(Proto *esp, Block *bp, char *msg)
          511 {
          512         Esp4hdr *h;
          513         Conv *c;
          514         ulong spi;
          515 
          516         h = (Esp4hdr*)(bp->rp);
          517 
          518         spi = nhgets(h->espspi);
          519         QLOCK(esp);
          520         c = convlookup(esp, spi);
          521         if(c != nil) {
          522                 qhangup(c->rq, msg);
          523                 qhangup(c->wq, msg);
          524         }
          525         QUNLOCK(esp);
          526         freeblist(bp);
          527 }
          528 
          529 int
          530 espstats(Proto *esp, char *buf, int len)
          531 {
          532         Esppriv *upriv;
          533 
          534         upriv = esp->priv;
          535         return snprint(buf, len, "%lud %lud\n",
          536                 upriv->in,
          537                 upriv->inerrors);
          538 }
          539 
          540 static int
          541 esplocal(Conv *c, char *buf, int len)
          542 {
          543         Espcb *ecb = c->ptcl;
          544         int n;
          545 
          546         QLOCK(c);
          547         if(ecb->incoming)
          548                 n = snprint(buf, len, "%I!%uld\n", c->laddr, ecb->spi);
          549         else
          550                 n = snprint(buf, len, "%I\n", c->laddr);
          551         QUNLOCK(c);
          552         return n;
          553 }
          554 
          555 static int
          556 espremote(Conv *c, char *buf, int len)
          557 {
          558         Espcb *ecb = c->ptcl;
          559         int n;
          560 
          561         QLOCK(c);
          562         if(ecb->incoming)
          563                 n = snprint(buf, len, "%I\n", c->raddr);
          564         else
          565                 n = snprint(buf, len, "%I!%uld\n", c->raddr, ecb->spi);
          566         QUNLOCK(c);
          567         return n;
          568 }
          569 
          570 static        Conv*
          571 convlookup(Proto *esp, ulong spi)
          572 {
          573         Conv *c, **p;
          574         Espcb *ecb;
          575 
          576         for(p=esp->conv; *p; p++){
          577                 c = *p;
          578                 ecb = c->ptcl;
          579                 if(ecb->incoming && ecb->spi == spi)
          580                         return c;
          581         }
          582         return nil;
          583 }
          584 
          585 static char *
          586 setalg(Espcb *ecb, char **f, int n, Algorithm *alg)
          587 {
          588         uchar *key;
          589         int c, i, nbyte, nchar;
          590 
          591         if(n < 2)
          592                 return "bad format";
          593         for(; alg->name; alg++)
          594                 if(strcmp(f[1], alg->name) == 0)
          595                         break;
          596         if(alg->name == nil)
          597                 return "unknown algorithm";
          598 
          599         if(n != 3)
          600                 return "bad format";
          601         nbyte = (alg->keylen + 7) >> 3;
          602         nchar = strlen(f[2]);
          603         for(i=0; i<nchar; i++) {
          604                 c = f[2][i];
          605                 if(c >= '0' && c <= '9')
          606                         f[2][i] -= '0';
          607                 else if(c >= 'a' && c <= 'f')
          608                         f[2][i] -= 'a'-10;
          609                 else if(c >= 'A' && c <= 'F')
          610                         f[2][i] -= 'A'-10;
          611                 else
          612                         return "bad character in key";
          613         }
          614         key = smalloc(nbyte);
          615         for(i=0; i<nchar && i*2<nbyte; i++) {
          616                 c = f[2][nchar-i-1];
          617                 if(i&1)
          618                         c <<= 4;
          619                 key[i>>1] |= c;
          620         }
          621 
          622         alg->init(ecb, alg->name, key, alg->keylen);
          623         free(key);
          624         return nil;
          625 }
          626 
          627 static int
          628 nullcipher(Espcb* _, uchar* __, int ___)
          629 {
          630         return 1;
          631 }
          632 
          633 static void
          634 nullespinit(Espcb *ecb, char *name, uchar* _, int __)
          635 {
          636         ecb->espalg = name;
          637         ecb->espblklen = 1;
          638         ecb->espivlen = 0;
          639         ecb->cipher = nullcipher;
          640 }
          641 
          642 static int
          643 nullauth(Espcb* _, uchar* __, int ___, uchar* ____)
          644 {
          645         return 1;
          646 }
          647 
          648 static void
          649 nullahinit(Espcb *ecb, char *name, uchar* _, int __)
          650 {
          651         ecb->ahalg = name;
          652         ecb->ahblklen = 1;
          653         ecb->ahlen = 0;
          654         ecb->auth = nullauth;
          655 }
          656 
          657 void
          658 seanq_hmac_sha1(uchar hash[SHA1dlen], uchar *t, long tlen, uchar *key, long klen)
          659 {
          660         uchar ipad[65], opad[65];
          661         int i;
          662         DigestState *digest;
          663         uchar innerhash[SHA1dlen];
          664 
          665         for(i=0; i<64; i++){
          666                 ipad[i] = 0x36;
          667                 opad[i] = 0x5c;
          668         }
          669         ipad[64] = opad[64] = 0;
          670         for(i=0; i<klen; i++){
          671                 ipad[i] ^= key[i];
          672                 opad[i] ^= key[i];
          673         }
          674         digest = sha1(ipad, 64, nil, nil);
          675         sha1(t, tlen, innerhash, digest);
          676         digest = sha1(opad, 64, nil, nil);
          677         sha1(innerhash, SHA1dlen, hash, digest);
          678 }
          679 
          680 static int
          681 shaauth(Espcb *ecb, uchar *t, int tlen, uchar *auth)
          682 {
          683         uchar hash[SHA1dlen];
          684         int r;
          685 
          686         memset(hash, 0, SHA1dlen);
          687         seanq_hmac_sha1(hash, t, tlen, (uchar*)ecb->ahstate, 16);
          688         r = memcmp(auth, hash, ecb->ahlen) == 0;
          689         memmove(auth, hash, ecb->ahlen);
          690         return r;
          691 }
          692 
          693 static void
          694 shaahinit(Espcb *ecb, char *name, uchar *key, int klen)
          695 {
          696         if(klen != 128)
          697                 panic("shaahinit: bad keylen");
          698         klen >>= 8;                /* convert to bytes */
          699 
          700         ecb->ahalg = name;
          701         ecb->ahblklen = 1;
          702         ecb->ahlen = 12;
          703         ecb->auth = shaauth;
          704         ecb->ahstate = smalloc(klen);
          705         memmove(ecb->ahstate, key, klen);
          706 }
          707 
          708 void
          709 seanq_hmac_md5(uchar hash[MD5dlen], uchar *t, long tlen, uchar *key, long klen)
          710 {
          711         uchar ipad[65], opad[65];
          712         int i;
          713         DigestState *digest;
          714         uchar innerhash[MD5dlen];
          715 
          716         for(i=0; i<64; i++){
          717                 ipad[i] = 0x36;
          718                 opad[i] = 0x5c;
          719         }
          720         ipad[64] = opad[64] = 0;
          721         for(i=0; i<klen; i++){
          722                 ipad[i] ^= key[i];
          723                 opad[i] ^= key[i];
          724         }
          725         digest = md5(ipad, 64, nil, nil);
          726         md5(t, tlen, innerhash, digest);
          727         digest = md5(opad, 64, nil, nil);
          728         md5(innerhash, MD5dlen, hash, digest);
          729 }
          730 
          731 static int
          732 md5auth(Espcb *ecb, uchar *t, int tlen, uchar *auth)
          733 {
          734         uchar hash[MD5dlen];
          735         int r;
          736 
          737         memset(hash, 0, MD5dlen);
          738         seanq_hmac_md5(hash, t, tlen, (uchar*)ecb->ahstate, 16);
          739         r = memcmp(auth, hash, ecb->ahlen) == 0;
          740         memmove(auth, hash, ecb->ahlen);
          741         return r;
          742 }
          743 
          744 static void
          745 md5ahinit(Espcb *ecb, char *name, uchar *key, int klen)
          746 {
          747         if(klen != 128)
          748                 panic("md5ahinit: bad keylen");
          749         klen >>= 3;                /* convert to bytes */
          750 
          751         ecb->ahalg = name;
          752         ecb->ahblklen = 1;
          753         ecb->ahlen = 12;
          754         ecb->auth = md5auth;
          755         ecb->ahstate = smalloc(klen);
          756         memmove(ecb->ahstate, key, klen);
          757 }
          758 
          759 static int
          760 descipher(Espcb *ecb, uchar *p, int n)
          761 {
          762         uchar tmp[8];
          763         uchar *pp, *tp, *ip, *eip, *ep;
          764         DESstate *ds = ecb->espstate;
          765 
          766         ep = p + n;
          767         if(ecb->incoming) {
          768                 memmove(ds->ivec, p, 8);
          769                 p += 8;
          770                 while(p < ep){
          771                         memmove(tmp, p, 8);
          772                         block_cipher(ds->expanded, p, 1);
          773                         tp = tmp;
          774                         ip = ds->ivec;
          775                         for(eip = ip+8; ip < eip; ){
          776                                 *p++ ^= *ip;
          777                                 *ip++ = *tp++;
          778                         }
          779                 }
          780         } else {
          781                 memmove(p, ds->ivec, 8);
          782                 for(p += 8; p < ep; p += 8){
          783                         pp = p;
          784                         ip = ds->ivec;
          785                         for(eip = ip+8; ip < eip; )
          786                                 *pp++ ^= *ip++;
          787                         block_cipher(ds->expanded, p, 0);
          788                         memmove(ds->ivec, p, 8);
          789                 }
          790         }
          791         return 1;
          792 }
          793 
          794 static void
          795 desespinit(Espcb *ecb, char *name, uchar *k, int n)
          796 {
          797         uchar key[8], ivec[8];
          798         int i;
          799 
          800         /* bits to bytes */
          801         n = (n+7)>>3;
          802         if(n > 8)
          803                 n = 8;
          804         memset(key, 0, sizeof(key));
          805         memmove(key, k, n);
          806         for(i=0; i<8; i++)
          807                 ivec[i] = nrand(256);
          808         ecb->espalg = name;
          809         ecb->espblklen = 8;
          810         ecb->espivlen = 8;
          811         ecb->cipher = descipher;
          812         ecb->espstate = smalloc(sizeof(DESstate));
          813         setupDESstate(ecb->espstate, key, ivec);
          814 }
          815 
          816 void
          817 espinit(Fs *fs)
          818 {
          819         Proto *esp;
          820 
          821         esp = smalloc(sizeof(Proto));
          822         esp->priv = smalloc(sizeof(Esppriv));
          823         esp->name = "esp";
          824         esp->connect = espconnect;
          825         esp->announce = nil;
          826         esp->ctl = espctl;
          827         esp->state = espstate;
          828         esp->create = espcreate;
          829         esp->close = espclose;
          830         esp->rcv = espiput;
          831         esp->advise = espadvise;
          832         esp->stats = espstats;
          833         esp->local = esplocal;
          834         esp->remote = espremote;
          835         esp->ipproto = IP_ESPPROTO;
          836         esp->nc = Nchans;
          837         esp->ptclsize = sizeof(Espcb);
          838 
          839         Fsproto(fs, esp);
          840 }
          841 
          842 
          843 #ifdef notdef
          844 enum {
          845         RC4forward= 10*1024*1024,        /* maximum skip forward */
          846         RC4back = 100*1024,        /* maximum look back */
          847 };
          848 
          849 typedef struct Esprc4 Esprc4;
          850 struct Esprc4
          851 {
          852         ulong        cseq;                /* current byte sequence number */
          853         RC4state current;
          854 
          855         int        ovalid;                /* old is valid */
          856         ulong        lgseq;                /* last good sequence */
          857         ulong        oseq;                /* old byte sequence number */
          858         RC4state old;
          859 };
          860 
          861 static void rc4espinit(Espcb *ecb, char *name, uchar *k, int n);
          862 
          863 static int
          864 rc4cipher(Espcb *ecb, uchar *p, int n)
          865 {
          866         Esprc4 *esprc4;
          867         RC4state tmpstate;
          868         ulong seq;
          869         long d, dd;
          870 
          871         if(n < 4)
          872                 return 0;
          873 
          874         esprc4 = ecb->espstate;
          875         if(ecb->incoming) {
          876                 seq = nhgetl(p);
          877                 p += 4;
          878                 n -= 4;
          879                 d = seq-esprc4->cseq;
          880                 if(d == 0) {
          881                         rc4(&esprc4->current, p, n);
          882                         esprc4->cseq += n;
          883                         if(esprc4->ovalid) {
          884                                 dd = esprc4->cseq - esprc4->lgseq;
          885                                 if(dd > RC4back)
          886                                         esprc4->ovalid = 0;
          887                         }
          888                 } else if(d > 0) {
          889 print("esp rc4cipher: missing packet: %uld %ld\n", seq, d); /* this link is hosed */
          890                         if(d > RC4forward) {
          891                                 strcpy(up->errstr, "rc4cipher: skipped too much");
          892                                 return 0;
          893                         }
          894                         esprc4->lgseq = seq;
          895                         if(!esprc4->ovalid) {
          896                                 esprc4->ovalid = 1;
          897                                 esprc4->oseq = esprc4->cseq;
          898                                 memmove(&esprc4->old, &esprc4->current,
          899                                         sizeof(RC4state));
          900                         }
          901                         rc4skip(&esprc4->current, d);
          902                         rc4(&esprc4->current, p, n);
          903                         esprc4->cseq = seq+n;
          904                 } else {
          905 print("esp rc4cipher: reordered packet: %uld %ld\n", seq, d);
          906                         dd = seq - esprc4->oseq;
          907                         if(!esprc4->ovalid || -d > RC4back || dd < 0) {
          908                                 strcpy(up->errstr, "rc4cipher: too far back");
          909                                 return 0;
          910                         }
          911                         memmove(&tmpstate, &esprc4->old, sizeof(RC4state));
          912                         rc4skip(&tmpstate, dd);
          913                         rc4(&tmpstate, p, n);
          914                         return 1;
          915                 }
          916 
          917                 /* move old state up */
          918                 if(esprc4->ovalid) {
          919                         dd = esprc4->cseq - RC4back - esprc4->oseq;
          920                         if(dd > 0) {
          921                                 rc4skip(&esprc4->old, dd);
          922                                 esprc4->oseq += dd;
          923                         }
          924                 }
          925         } else {
          926                 hnputl(p, esprc4->cseq);
          927                 p += 4;
          928                 n -= 4;
          929                 rc4(&esprc4->current, p, n);
          930                 esprc4->cseq += n;
          931         }
          932         return 1;
          933 }
          934 
          935 static void
          936 rc4espinit(Espcb *ecb, char *name, uchar *k, int n)
          937 {
          938         Esprc4 *esprc4;
          939 
          940         /* bits to bytes */
          941         n = (n+7)>>3;
          942         esprc4 = smalloc(sizeof(Esprc4));
          943         memset(esprc4, 0, sizeof(Esprc4));
          944         setupRC4state(&esprc4->current, k, n);
          945         ecb->espalg = name;
          946         ecb->espblklen = 4;
          947         ecb->espivlen = 4;
          948         ecb->cipher = rc4cipher;
          949         ecb->espstate = esprc4;
          950 }
          951 #endif