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