2 #include "../port/lib.h"
6 #include "../port/error.h"
12 typedef struct Esphdr Esphdr;
13 typedef struct Esptail Esptail;
14 typedef struct Userhdr Userhdr;
15 typedef struct Esppriv Esppriv;
16 typedef struct Espcb Espcb;
17 typedef struct Algorithm Algorithm;
18 typedef struct Esprc4 Esprc4;
20 #define DPRINT if(0)print
25 EsphdrSize = 28, // includes IP header
26 IphdrSize = 20, // options have been striped
27 EsptailSize = 2, // does not include pad or auth data
28 UserhdrSize = 4, // user visable header size - if enabled
34 uchar vihl; /* Version and header length */
35 uchar tos; /* Type of service */
36 uchar length[2]; /* packet length */
37 uchar id[2]; /* Identification */
38 uchar frag[2]; /* Fragment information */
40 uchar espproto; /* Protocol */
41 uchar espplen[2]; /* Header plus data length */
42 uchar espsrc[4]; /* Ip source */
43 uchar espdst[4]; /* Ip destination */
46 uchar espspi[4]; /* Security parameter index */
47 uchar espseq[4]; /* Sequence number */
56 /* header as seen by the user */
59 uchar nexthdr; // next protocol
70 * protocol specific part of Conv
75 int header; // user user level header
77 ulong seq; // last seq sent
78 ulong window; // for replay attacks
80 void *espstate; // other state for esp
81 int espivlen; // in bytes
83 int (*cipher)(Espcb*, uchar *buf, int len);
85 void *ahstate; // other state for esp
86 int ahlen; // auth data length in bytes
88 int (*auth)(Espcb*, uchar *buf, int len, uchar *hash);
94 int keylen; // in bits
95 void (*init)(Espcb*, char* name, uchar *key, int keylen);
100 RC4forward = 10*1024*1024, // maximum skip forward
101 RC4back = 100*1024, // maximum look back
106 ulong cseq; // current byte sequence number
109 int ovalid; // old is valid
110 ulong lgseq; // last good sequence
111 ulong oseq; // old byte sequence number
115 static Conv* convlookup(Proto *esp, ulong spi);
116 static char *setalg(Espcb *ecb, char **f, int n, Algorithm *alg);
117 static void nullespinit(Espcb*, char*, uchar *key, int keylen);
118 static void nullahinit(Espcb*, char*, uchar *key, int keylen);
119 static void shaahinit(Espcb*, char*, uchar *key, int keylen);
120 static void md5ahinit(Espcb*, char*, uchar *key, int keylen);
121 static void desespinit(Espcb *ecb, char *name, uchar *k, int n);
122 static void rc4espinit(Espcb *ecb, char *name, uchar *k, int n);
123 static void espkick(void *x);
125 static Algorithm espalg[] =
127 "null", 0, nullespinit,
128 "des_56_cbc", 64, desespinit,
129 "rc4_128", 128, rc4espinit,
133 static Algorithm ahalg[] =
135 "null", 0, nullahinit,
136 "hmac_sha1_96", 128, shaahinit,
137 "hmac_md5_96", 128, md5ahinit,
142 espconnect(Conv *c, char **argv, int argc)
147 Espcb *ecb = (Espcb*)c->ptcl;
151 e = "bad args to connect";
154 p = strchr(argv[1], '!');
156 e = "malformed address";
160 parseip(c->raddr, argv[1]);
161 findlocalip(c->p->f, c->laddr, c->raddr);
164 if(strcmp(p, "*") == 0) {
167 spi = nrand(1<<16) + 256;
168 if(convlookup(c->p, spi) == nil)
176 spi = strtoul(p, &pp, 10);
178 e = "malformed address";
184 nullespinit(ecb, "null", nil, 0);
185 nullahinit(ecb, "null", nil, 0);
194 espstate(Conv *c, char *state, int n)
196 return snprint(state, n, "%s", c->inuse?"Open\n":"Closed\n");
202 c->rq = qopen(64*1024, Qmsg, 0, 0);
203 c->wq = qopen(64*1024, Qkick, espkick, c);
214 ipmove(c->laddr, IPnoaddr);
215 ipmove(c->raddr, IPnoaddr);
217 ecb = (Espcb*)c->ptcl;
220 memset(ecb, 0, sizeof(Espcb));
246 /* make sure the message has a User header */
247 bp = pullupblock(bp, UserhdrSize);
252 uh = (Userhdr*)bp->rp;
253 nexthdr = uh->nexthdr;
254 bp->rp += UserhdrSize;
256 nexthdr = 0; // what should this be?
259 payload = BLEN(bp) + ecb->espivlen;
261 /* Make space to fit ip header */
262 bp = padblock(bp, EsphdrSize + ecb->espivlen);
265 if(ecb->espblklen > align)
266 align = ecb->espblklen;
267 if(align % ecb->ahblklen != 0)
268 panic("espkick: ahblklen is important after all");
269 pad = (align-1) - (payload + EsptailSize-1)%align;
272 * Make space for tail
273 * this is done by calling padblock with a negative size
274 * Padblock does not change bp->wp!
276 bp = padblock(bp, -(pad+EsptailSize+ecb->ahlen));
277 bp->wp += pad+EsptailSize+ecb->ahlen;
279 eh = (Esphdr *)(bp->rp);
280 et = (Esptail*)(bp->rp + EsphdrSize + payload + pad);
284 et->nexthdr = nexthdr;
286 ecb->cipher(ecb, bp->rp+EsphdrSize, payload+pad+EsptailSize);
287 auth = bp->rp + EsphdrSize + payload + pad + EsptailSize;
291 hnputl(eh->espspi, ecb->spi);
292 hnputl(eh->espseq, ++ecb->seq);
293 v6tov4(eh->espsrc, c->laddr);
294 v6tov4(eh->espdst, c->raddr);
295 eh->espproto = IP_ESPPROTO;
299 ecb->auth(ecb, bp->rp+IphdrSize, (EsphdrSize-IphdrSize)+payload+pad+EsptailSize, auth);
302 //print("esp: pass down: %uld\n", BLEN(bp));
303 ipoput4(c->p->f, bp, 0, c->ttl, c->tos, c);
307 espiput(Proto *esp, Ipifc*, Block *bp)
314 uchar raddr[IPaddrlen], laddr[IPaddrlen];
318 int payload, nexthdr;
322 bp = pullupblock(bp, EsphdrSize+EsptailSize);
324 netlog(f, Logesp, "esp: short packet\n");
328 eh = (Esphdr*)(bp->rp);
329 spi = nhgetl(eh->espspi);
330 v4tov6(raddr, eh->espsrc);
331 v4tov6(laddr, eh->espdst);
334 /* Look for a conversation structure for this port */
335 c = convlookup(esp, spi);
338 netlog(f, Logesp, "esp: no conv %I -> %I!%d\n", raddr,
349 // too hard to do decryption/authentication on block lists
351 bp = concatblock(bp);
353 if(BLEN(bp) < EsphdrSize + ecb->espivlen + EsptailSize + ecb->ahlen) {
355 netlog(f, Logesp, "esp: short block %I -> %I!%d\n", raddr,
361 eh = (Esphdr*)(bp->rp);
362 auth = bp->wp - ecb->ahlen;
363 if(!ecb->auth(ecb, eh->espspi, auth-eh->espspi, auth)) {
365 print("esp: bad auth %I -> %I!%ld\n", raddr, laddr, spi);
366 netlog(f, Logesp, "esp: bad auth %I -> %I!%d\n", raddr,
372 payload = BLEN(bp)-EsphdrSize-ecb->ahlen;
373 if(payload<=0 || payload%4 != 0 || payload%ecb->espblklen!=0) {
375 netlog(f, Logesp, "esp: bad length %I -> %I!%d payload=%d BLEN=%d\n", raddr,
376 laddr, spi, payload, BLEN(bp));
380 if(!ecb->cipher(ecb, bp->rp+EsphdrSize, payload)) {
382 print("esp: cipher failed %I -> %I!%ld: %r\n", raddr, laddr, spi);
383 netlog(f, Logesp, "esp: cipher failed %I -> %I!%d: %r\n", raddr,
389 payload -= EsptailSize;
390 et = (Esptail*)(bp->rp + EsphdrSize + payload);
391 payload -= et->pad + ecb->espivlen;
392 nexthdr = et->nexthdr;
395 netlog(f, Logesp, "esp: short packet after decrypt %I -> %I!%d\n", raddr,
402 bp->rp += EsphdrSize + ecb->espivlen;
403 bp->wp = bp->rp + payload;
405 // assume UserhdrSize < EsphdrSize
406 bp->rp -= UserhdrSize;
407 uh = (Userhdr*)bp->rp;
408 memset(uh, 0, UserhdrSize);
409 uh->nexthdr = nexthdr;
413 netlog(f, Logesp, "esp: qfull %I -> %I.%uld\n", raddr,
417 //print("esp: pass up: %uld\n", BLEN(bp));
425 espctl(Conv *c, char **f, int n)
427 Espcb *ecb = c->ptcl;
430 if(strcmp(f[0], "esp") == 0)
431 e = setalg(ecb, f, n, espalg);
432 else if(strcmp(f[0], "ah") == 0)
433 e = setalg(ecb, f, n, ahalg);
434 else if(strcmp(f[0], "header") == 0)
436 else if(strcmp(f[0], "noheader") == 0)
439 e = "unknown control request";
444 espadvise(Proto *esp, Block *bp, char *msg)
450 h = (Esphdr*)(bp->rp);
452 spi = nhgets(h->espspi);
454 c = convlookup(esp, spi);
464 espstats(Proto *esp, char *buf, int len)
469 return snprint(buf, len, "%lu %lu\n",
475 esplocal(Conv *c, char *buf, int len)
477 Espcb *ecb = c->ptcl;
482 n = snprint(buf, len, "%I!%lu\n", c->laddr, ecb->spi);
484 n = snprint(buf, len, "%I\n", c->laddr);
490 espremote(Conv *c, char *buf, int len)
492 Espcb *ecb = c->ptcl;
497 n = snprint(buf, len, "%I\n", c->raddr);
499 n = snprint(buf, len, "%I!%uld\n", c->raddr, ecb->spi);
505 convlookup(Proto *esp, ulong spi)
510 for(p=esp->conv; *p; p++){
513 if(ecb->incoming && ecb->spi == spi)
520 setalg(Espcb *ecb, char **f, int n, Algorithm *alg)
528 for(; alg->name; alg++)
529 if(strcmp(f[1], alg->name) == 0)
532 return "unknown algorithm";
536 nbyte = (alg->keylen + 7) >> 3;
537 nchar = strlen(f[2]);
538 for(i=0; i<nchar; i++) {
540 if(c >= '0' && c <= '9')
542 else if(c >= 'a' && c <= 'f')
544 else if(c >= 'A' && c <= 'F')
547 return "bad character in key";
549 key = smalloc(nbyte);
550 for(i=0; i<nchar && i*2<nbyte; i++) {
557 alg->init(ecb, alg->name, key, alg->keylen);
563 nullcipher(Espcb*, uchar*, int)
569 nullespinit(Espcb *ecb, char *name, uchar*, int)
574 ecb->cipher = nullcipher;
578 nullauth(Espcb*, uchar*, int, uchar*)
584 nullahinit(Espcb *ecb, char *name, uchar*, int)
589 ecb->auth = nullauth;
593 seanq_hmac_sha1(uchar hash[SHA1dlen], uchar *t, long tlen, uchar *key, long klen)
595 uchar ipad[65], opad[65];
598 uchar innerhash[SHA1dlen];
604 ipad[64] = opad[64] = 0;
605 for(i=0; i<klen; i++){
609 digest = sha1(ipad, 64, nil, nil);
610 sha1(t, tlen, innerhash, digest);
611 digest = sha1(opad, 64, nil, nil);
612 sha1(innerhash, SHA1dlen, hash, digest);
616 shaauth(Espcb *ecb, uchar *t, int tlen, uchar *auth)
618 uchar hash[SHA1dlen];
621 memset(hash, 0, SHA1dlen);
622 seanq_hmac_sha1(hash, t, tlen, (uchar*)ecb->ahstate, 16);
623 r = memcmp(auth, hash, ecb->ahlen) == 0;
624 memmove(auth, hash, ecb->ahlen);
629 shaahinit(Espcb *ecb, char *name, uchar *key, int klen)
632 panic("shaahinit: bad keylen");
633 klen >>= 8; // convert to bytes
639 ecb->ahstate = smalloc(klen);
640 memmove(ecb->ahstate, key, klen);
644 seanq_hmac_md5(uchar hash[MD5dlen], uchar *t, long tlen, uchar *key, long klen)
646 uchar ipad[65], opad[65];
649 uchar innerhash[MD5dlen];
655 ipad[64] = opad[64] = 0;
656 for(i=0; i<klen; i++){
660 digest = md5(ipad, 64, nil, nil);
661 md5(t, tlen, innerhash, digest);
662 digest = md5(opad, 64, nil, nil);
663 md5(innerhash, MD5dlen, hash, digest);
667 md5auth(Espcb *ecb, uchar *t, int tlen, uchar *auth)
672 memset(hash, 0, MD5dlen);
673 seanq_hmac_md5(hash, t, tlen, (uchar*)ecb->ahstate, 16);
674 r = memcmp(auth, hash, ecb->ahlen) == 0;
675 memmove(auth, hash, ecb->ahlen);
680 md5ahinit(Espcb *ecb, char *name, uchar *key, int klen)
683 panic("md5ahinit: bad keylen");
684 klen >>= 3; // convert to bytes
691 ecb->ahstate = smalloc(klen);
692 memmove(ecb->ahstate, key, klen);
696 descipher(Espcb *ecb, uchar *p, int n)
699 uchar *pp, *tp, *ip, *eip, *ep;
700 DESstate *ds = ecb->espstate;
704 memmove(ds->ivec, p, 8);
708 block_cipher(ds->expanded, p, 1);
711 for(eip = ip+8; ip < eip; ){
717 memmove(p, ds->ivec, 8);
718 for(p += 8; p < ep; p += 8){
721 for(eip = ip+8; ip < eip; )
723 block_cipher(ds->expanded, p, 0);
724 memmove(ds->ivec, p, 8);
731 desespinit(Espcb *ecb, char *name, uchar *k, int n)
741 memset(key, 0, sizeof(key));
744 ivec[i] = nrand(256);
748 ecb->cipher = descipher;
749 ecb->espstate = smalloc(sizeof(DESstate));
750 setupDESstate(ecb->espstate, key, ivec);
754 rc4cipher(Espcb *ecb, uchar *p, int n)
764 esprc4 = ecb->espstate;
769 d = seq-esprc4->cseq;
771 rc4(&esprc4->current, p, n);
774 dd = esprc4->cseq - esprc4->lgseq;
779 print("missing packet: %uld %ld\n", seq, d);
780 // this link is hosed
782 strcpy(up->errstr, "rc4cipher: skipped too much");
786 if(!esprc4->ovalid) {
788 esprc4->oseq = esprc4->cseq;
789 memmove(&esprc4->old, &esprc4->current, sizeof(RC4state));
791 rc4skip(&esprc4->current, d);
792 rc4(&esprc4->current, p, n);
793 esprc4->cseq = seq+n;
795 print("reordered packet: %uld %ld\n", seq, d);
796 dd = seq - esprc4->oseq;
797 if(!esprc4->ovalid || -d > RC4back || dd < 0) {
798 strcpy(up->errstr, "rc4cipher: too far back");
801 memmove(&tmpstate, &esprc4->old, sizeof(RC4state));
802 rc4skip(&tmpstate, dd);
803 rc4(&tmpstate, p, n);
809 dd = esprc4->cseq - RC4back - esprc4->oseq;
811 rc4skip(&esprc4->old, dd);
816 hnputl(p, esprc4->cseq);
819 rc4(&esprc4->current, p, n);
826 rc4espinit(Espcb *ecb, char *name, uchar *k, int n)
832 esprc4 = smalloc(sizeof(Esprc4));
833 memset(esprc4, 0, sizeof(Esprc4));
834 setupRC4state(&esprc4->current, k, n);
838 ecb->cipher = rc4cipher;
839 ecb->espstate = esprc4;
847 esp = smalloc(sizeof(Proto));
848 esp->priv = smalloc(sizeof(Esppriv));
850 esp->connect = espconnect;
853 esp->state = espstate;
854 esp->create = espcreate;
855 esp->close = espclose;
857 esp->advise = espadvise;
858 esp->stats = espstats;
859 esp->local = esplocal;
860 esp->remote = espremote;
861 esp->ipproto = IP_ESPPROTO;
863 esp->ptclsize = sizeof(Espcb);