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