vx32

Local 9vx git repository for patches.
git clone git://r-36.net/vx32
Log | Files | 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