]> git.saurik.com Git - apple/xnu.git/blame - bsd/netinet6/ah_core.c
xnu-124.13.tar.gz
[apple/xnu.git] / bsd / netinet6 / ah_core.c
CommitLineData
1c79356b
A
1/*
2 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the project nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30/*
31 * RFC1826/2402 authentication header.
32 */
33#define _IP_VHL
34#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__)
35#include "opt_inet.h"
36#if __NetBSD__ /*XXX*/
37#include "opt_ipsec.h"
38#endif
39#endif
40
41/* Some of operating systems have standard crypto checksum library */
42#if __NetBSD__
43#define HAVE_MD5
44#define HAVE_SHA1
45#endif
46#if defined(__FreeBSD__) || defined(__APPLE__)
47#define HAVE_MD5 1
48#endif
49
50#include <sys/param.h>
51#include <sys/systm.h>
52#include <sys/malloc.h>
53#include <sys/mbuf.h>
54#include <sys/domain.h>
55#include <sys/protosw.h>
56#include <sys/socket.h>
57#include <sys/socketvar.h>
58#include <sys/errno.h>
59#include <sys/time.h>
60#include <sys/kernel.h>
61#include <sys/syslog.h>
62
63#include <net/if.h>
64#include <net/route.h>
65
66#include <netinet/in.h>
67#include <netinet/in_systm.h>
68#include <netinet/ip.h>
69#include <netinet/in_var.h>
70
71#if INET6
72#include <netinet/ip6.h>
73#include <netinet6/ip6_var.h>
74#include <netinet/icmp6.h>
75#endif
76
77#include <netinet6/ipsec.h>
78#include <netinet6/ah.h>
79#if IPSEC_ESP
80#include <netinet6/esp.h>
81#endif
82#include <net/pfkeyv2.h>
83#include <netkey/keydb.h>
84#if HAVE_MD5
85#include <sys/md5.h>
86#else
87#include <crypto/md5.h>
88#endif
89#if HAVE_SHA1
90#include <sys/sha1.h>
91#define SHA1_RESULTLEN 20
92#else
93#include <crypto/sha1.h>
94#endif
95
96#include <net/net_osdep.h>
97
98#define HMACSIZE 16
99
100static int ah_sumsiz_1216 __P((struct secasvar *));
101static int ah_sumsiz_zero __P((struct secasvar *));
102static int ah_none_mature __P((struct secasvar *));
103static void ah_none_init __P((struct ah_algorithm_state *,
104 struct secasvar *));
105static void ah_none_loop __P((struct ah_algorithm_state *, caddr_t, size_t));
106static void ah_none_result __P((struct ah_algorithm_state *, caddr_t));
107static int ah_keyed_md5_mature __P((struct secasvar *));
108static void ah_keyed_md5_init __P((struct ah_algorithm_state *,
109 struct secasvar *));
110static void ah_keyed_md5_loop __P((struct ah_algorithm_state *, caddr_t,
111 size_t));
112static void ah_keyed_md5_result __P((struct ah_algorithm_state *, caddr_t));
113static int ah_keyed_sha1_mature __P((struct secasvar *));
114static void ah_keyed_sha1_init __P((struct ah_algorithm_state *,
115 struct secasvar *));
116static void ah_keyed_sha1_loop __P((struct ah_algorithm_state *, caddr_t,
117 size_t));
118static void ah_keyed_sha1_result __P((struct ah_algorithm_state *, caddr_t));
119static int ah_hmac_md5_mature __P((struct secasvar *));
120static void ah_hmac_md5_init __P((struct ah_algorithm_state *,
121 struct secasvar *));
122static void ah_hmac_md5_loop __P((struct ah_algorithm_state *, caddr_t,
123 size_t));
124static void ah_hmac_md5_result __P((struct ah_algorithm_state *, caddr_t));
125static int ah_hmac_sha1_mature __P((struct secasvar *));
126static void ah_hmac_sha1_init __P((struct ah_algorithm_state *,
127 struct secasvar *));
128static void ah_hmac_sha1_loop __P((struct ah_algorithm_state *, caddr_t,
129 size_t));
130static void ah_hmac_sha1_result __P((struct ah_algorithm_state *, caddr_t));
131
132static void ah_update_mbuf __P((struct mbuf *, int, int, struct ah_algorithm *,
133 struct ah_algorithm_state *));
134
135/* checksum algorithms */
136/* NOTE: The order depends on SADB_AALG_x in net/pfkeyv2.h */
137struct ah_algorithm ah_algorithms[] = {
138 { 0, 0, 0, 0, 0, 0, },
139 { ah_sumsiz_1216, ah_hmac_md5_mature, 128, 128,
140 ah_hmac_md5_init, ah_hmac_md5_loop, ah_hmac_md5_result, },
141 { ah_sumsiz_1216, ah_hmac_sha1_mature, 160, 160,
142 ah_hmac_sha1_init, ah_hmac_sha1_loop, ah_hmac_sha1_result, },
143 { ah_sumsiz_1216, ah_keyed_md5_mature, 128, 128,
144 ah_keyed_md5_init, ah_keyed_md5_loop, ah_keyed_md5_result, },
145 { ah_sumsiz_1216, ah_keyed_sha1_mature, 160, 160,
146 ah_keyed_sha1_init, ah_keyed_sha1_loop, ah_keyed_sha1_result, },
147 { ah_sumsiz_zero, ah_none_mature, 0, 2048,
148 ah_none_init, ah_none_loop, ah_none_result, },
149};
150
151static int
152ah_sumsiz_1216(sav)
153 struct secasvar *sav;
154{
155 if (!sav)
156 return -1;
157 if (sav->flags & SADB_X_EXT_OLD)
158 return 16;
159 else
160 return 12;
161}
162
163static int
164ah_sumsiz_zero(sav)
165 struct secasvar *sav;
166{
167 if (!sav)
168 return -1;
169 return 0;
170}
171
172static int
173ah_none_mature(sav)
174 struct secasvar *sav;
175{
176 if (sav->sah->saidx.proto == IPPROTO_AH) {
177 ipseclog((LOG_ERR,
178 "ah_none_mature: protocol and algorithm mismatch.\n"));
179 return 1;
180 }
181 return 0;
182}
183
184static void
185ah_none_init(state, sav)
186 struct ah_algorithm_state *state;
187 struct secasvar *sav;
188{
189 state->foo = NULL;
190}
191
192static void
193ah_none_loop(state, addr, len)
194 struct ah_algorithm_state *state;
195 caddr_t addr;
196 size_t len;
197{
198}
199
200static void
201ah_none_result(state, addr)
202 struct ah_algorithm_state *state;
203 caddr_t addr;
204{
205}
206
207static int
208ah_keyed_md5_mature(sav)
209 struct secasvar *sav;
210{
211 /* anything is okay */
212 return 0;
213}
214
215static void
216ah_keyed_md5_init(state, sav)
217 struct ah_algorithm_state *state;
218 struct secasvar *sav;
219{
220 if (!state)
221 panic("ah_keyed_md5_init: what?");
222
223 state->sav = sav;
224 state->foo = (void *)_MALLOC(sizeof(MD5_CTX), M_TEMP, M_NOWAIT);
225 if (state->foo == NULL)
226 panic("ah_keyed_md5_init: what?");
227 MD5Init((MD5_CTX *)state->foo);
228 if (state->sav) {
229 MD5Update((MD5_CTX *)state->foo,
230 (u_int8_t *)_KEYBUF(state->sav->key_auth),
231 (u_int)_KEYLEN(state->sav->key_auth));
232
233 {
234 /*
235 * Pad after the key.
236 * We cannot simply use md5_pad() since the function
237 * won't update the total length.
238 */
239 size_t padlen;
240 size_t keybitlen;
241 u_int8_t buf[32];
242
243 if (_KEYLEN(state->sav->key_auth) < 56)
244 padlen = 64 - 8 - _KEYLEN(state->sav->key_auth);
245 else
246 padlen = 64 + 64 - 8 - _KEYLEN(state->sav->key_auth);
247 keybitlen = _KEYLEN(state->sav->key_auth);
248 keybitlen *= 8;
249
250 buf[0] = 0x80;
251 MD5Update((MD5_CTX *)state->foo, &buf[0], 1);
252 padlen--;
253
254 bzero(buf, sizeof(buf));
255 while (sizeof(buf) < padlen) {
256 MD5Update((MD5_CTX *)state->foo, &buf[0], sizeof(buf));
257 padlen -= sizeof(buf);
258 }
259 if (padlen) {
260 MD5Update((MD5_CTX *)state->foo, &buf[0], padlen);
261 }
262
263 buf[0] = (keybitlen >> 0) & 0xff;
264 buf[1] = (keybitlen >> 8) & 0xff;
265 buf[2] = (keybitlen >> 16) & 0xff;
266 buf[3] = (keybitlen >> 24) & 0xff;
267 MD5Update((MD5_CTX *)state->foo, buf, 8);
268 }
269 }
270}
271
272static void
273ah_keyed_md5_loop(state, addr, len)
274 struct ah_algorithm_state *state;
275 caddr_t addr;
276 size_t len;
277{
278 if (!state)
279 panic("ah_keyed_md5_loop: what?");
280
281 MD5Update((MD5_CTX *)state->foo, addr, len);
282}
283
284static void
285ah_keyed_md5_result(state, addr)
286 struct ah_algorithm_state *state;
287 caddr_t addr;
288{
289 u_char digest[16];
290
291 if (!state)
292 panic("ah_keyed_md5_result: what?");
293
294 if (state->sav) {
295 MD5Update((MD5_CTX *)state->foo,
296 (u_int8_t *)_KEYBUF(state->sav->key_auth),
297 (u_int)_KEYLEN(state->sav->key_auth));
298 }
299 MD5Final(&digest[0], (MD5_CTX *)state->foo);
300 _FREE(state->foo, M_TEMP);
301 bcopy(&digest[0], (void *)addr, sizeof(digest));
302}
303
304static int
305ah_keyed_sha1_mature(sav)
306 struct secasvar *sav;
307{
308 struct ah_algorithm *algo;
309
310 if (!sav->key_auth) {
311 ipseclog((LOG_ERR, "ah_keyed_sha1_mature: no key is given.\n"));
312 return 1;
313 }
314 algo = &ah_algorithms[sav->alg_auth];
315 if (sav->key_auth->sadb_key_bits < algo->keymin
316 || algo->keymax < sav->key_auth->sadb_key_bits) {
317 ipseclog((LOG_ERR,
318 "ah_keyed_sha1_mature: invalid key length %d.\n",
319 sav->key_auth->sadb_key_bits));
320 return 1;
321 }
322
323 return 0;
324}
325
326static void
327ah_keyed_sha1_init(state, sav)
328 struct ah_algorithm_state *state;
329 struct secasvar *sav;
330{
331 SHA1_CTX *ctxt;
332
333 if (!state)
334 panic("ah_keyed_sha1_init: what?");
335
336 state->sav = sav;
337 state->foo = (void *)_MALLOC(sizeof(SHA1_CTX), M_TEMP, M_NOWAIT);
338 if (!state->foo)
339 panic("ah_keyed_sha1_init: what?");
340
341 ctxt = (SHA1_CTX *)state->foo;
342 SHA1Init(ctxt);
343
344 if (state->sav) {
345 SHA1Update(ctxt, (u_int8_t *)_KEYBUF(state->sav->key_auth),
346 (u_int)_KEYLEN(state->sav->key_auth));
347
348 {
349 /*
350 * Pad after the key.
351 */
352 size_t padlen;
353 size_t keybitlen;
354 u_int8_t buf[32];
355
356 if (_KEYLEN(state->sav->key_auth) < 56)
357 padlen = 64 - 8 - _KEYLEN(state->sav->key_auth);
358 else
359 padlen = 64 + 64 - 8 - _KEYLEN(state->sav->key_auth);
360 keybitlen = _KEYLEN(state->sav->key_auth);
361 keybitlen *= 8;
362
363 buf[0] = 0x80;
364 SHA1Update(ctxt, &buf[0], 1);
365 padlen--;
366
367 bzero(buf, sizeof(buf));
368 while (sizeof(buf) < padlen) {
369 SHA1Update(ctxt, &buf[0], sizeof(buf));
370 padlen -= sizeof(buf);
371 }
372 if (padlen) {
373 SHA1Update(ctxt, &buf[0], padlen);
374 }
375
376 buf[0] = (keybitlen >> 0) & 0xff;
377 buf[1] = (keybitlen >> 8) & 0xff;
378 buf[2] = (keybitlen >> 16) & 0xff;
379 buf[3] = (keybitlen >> 24) & 0xff;
380 SHA1Update(ctxt, buf, 8);
381 }
382 }
383}
384
385static void
386ah_keyed_sha1_loop(state, addr, len)
387 struct ah_algorithm_state *state;
388 caddr_t addr;
389 size_t len;
390{
391 SHA1_CTX *ctxt;
392
393 if (!state || !state->foo)
394 panic("ah_keyed_sha1_loop: what?");
395 ctxt = (SHA1_CTX *)state->foo;
396
397 SHA1Update(ctxt, (caddr_t)addr, (size_t)len);
398}
399
400static void
401ah_keyed_sha1_result(state, addr)
402 struct ah_algorithm_state *state;
403 caddr_t addr;
404{
405 u_char digest[SHA1_RESULTLEN]; /* SHA-1 generates 160 bits */
406 SHA1_CTX *ctxt;
407
408 if (!state || !state->foo)
409 panic("ah_keyed_sha1_result: what?");
410 ctxt = (SHA1_CTX *)state->foo;
411
412 if (state->sav) {
413 SHA1Update(ctxt, (u_int8_t *)_KEYBUF(state->sav->key_auth),
414 (u_int)_KEYLEN(state->sav->key_auth));
415 }
416 SHA1Final((caddr_t)&digest[0], ctxt);
417 bcopy(&digest[0], (void *)addr, HMACSIZE);
418
419 _FREE(state->foo, M_TEMP);
420}
421
422static int
423ah_hmac_md5_mature(sav)
424 struct secasvar *sav;
425{
426 struct ah_algorithm *algo;
427
428 if (!sav->key_auth) {
429 ipseclog((LOG_ERR, "ah_hmac_md5_mature: no key is given.\n"));
430 return 1;
431 }
432 algo = &ah_algorithms[sav->alg_auth];
433 if (sav->key_auth->sadb_key_bits < algo->keymin
434 || algo->keymax < sav->key_auth->sadb_key_bits) {
435 ipseclog((LOG_ERR,
436 "ah_hmac_md5_mature: invalid key length %d.\n",
437 sav->key_auth->sadb_key_bits));
438 return 1;
439 }
440
441 return 0;
442}
443
444static void
445ah_hmac_md5_init(state, sav)
446 struct ah_algorithm_state *state;
447 struct secasvar *sav;
448{
449 u_char *ipad;
450 u_char *opad;
451 u_char tk[16];
452 u_char *key;
453 size_t keylen;
454 size_t i;
455 MD5_CTX *ctxt;
456
457 if (!state)
458 panic("ah_hmac_md5_init: what?");
459
460 state->sav = sav;
461 state->foo = (void *)_MALLOC(64 + 64 + sizeof(MD5_CTX), M_TEMP, M_NOWAIT);
462 if (!state->foo)
463 panic("ah_hmac_md5_init: what?");
464
465 ipad = (u_char *)state->foo;
466 opad = (u_char *)(ipad + 64);
467 ctxt = (MD5_CTX *)(opad + 64);
468
469 /* compress the key if necessery */
470 if (64 < _KEYLEN(state->sav->key_auth)) {
471 MD5Init(ctxt);
472 MD5Update(ctxt, _KEYBUF(state->sav->key_auth),
473 _KEYLEN(state->sav->key_auth));
474 MD5Final(&tk[0], ctxt);
475 key = &tk[0];
476 keylen = 16;
477 } else {
478 key = _KEYBUF(state->sav->key_auth);
479 keylen = _KEYLEN(state->sav->key_auth);
480 }
481
482 bzero(ipad, 64);
483 bzero(opad, 64);
484 bcopy(key, ipad, keylen);
485 bcopy(key, opad, keylen);
486 for (i = 0; i < 64; i++) {
487 ipad[i] ^= 0x36;
488 opad[i] ^= 0x5c;
489 }
490
491 MD5Init(ctxt);
492 MD5Update(ctxt, ipad, 64);
493}
494
495static void
496ah_hmac_md5_loop(state, addr, len)
497 struct ah_algorithm_state *state;
498 caddr_t addr;
499 size_t len;
500{
501 MD5_CTX *ctxt;
502
503 if (!state || !state->foo)
504 panic("ah_hmac_md5_loop: what?");
505 ctxt = (MD5_CTX *)(((caddr_t)state->foo) + 128);
506 MD5Update(ctxt, addr, len);
507}
508
509static void
510ah_hmac_md5_result(state, addr)
511 struct ah_algorithm_state *state;
512 caddr_t addr;
513{
514 u_char digest[16];
515 u_char *ipad;
516 u_char *opad;
517 MD5_CTX *ctxt;
518
519 if (!state || !state->foo)
520 panic("ah_hmac_md5_result: what?");
521
522 ipad = (u_char *)state->foo;
523 opad = (u_char *)(ipad + 64);
524 ctxt = (MD5_CTX *)(opad + 64);
525
526 MD5Final(&digest[0], ctxt);
527
528 MD5Init(ctxt);
529 MD5Update(ctxt, opad, 64);
530 MD5Update(ctxt, &digest[0], sizeof(digest));
531 MD5Final(&digest[0], ctxt);
532
533 bcopy(&digest[0], (void *)addr, HMACSIZE);
534
535 _FREE(state->foo, M_TEMP);
536}
537
538static int
539ah_hmac_sha1_mature(sav)
540 struct secasvar *sav;
541{
542 struct ah_algorithm *algo;
543
544 if (!sav->key_auth) {
545 ipseclog((LOG_ERR, "ah_hmac_sha1_mature: no key is given.\n"));
546 return 1;
547 }
548 algo = &ah_algorithms[sav->alg_auth];
549 if (sav->key_auth->sadb_key_bits < algo->keymin
550 || algo->keymax < sav->key_auth->sadb_key_bits) {
551 ipseclog((LOG_ERR,
552 "ah_hmac_sha1_mature: invalid key length %d.\n",
553 sav->key_auth->sadb_key_bits));
554 return 1;
555 }
556
557 return 0;
558}
559
560static void
561ah_hmac_sha1_init(state, sav)
562 struct ah_algorithm_state *state;
563 struct secasvar *sav;
564{
565 u_char *ipad;
566 u_char *opad;
567 SHA1_CTX *ctxt;
568 u_char tk[SHA1_RESULTLEN]; /* SHA-1 generates 160 bits */
569 u_char *key;
570 size_t keylen;
571 size_t i;
572
573 if (!state)
574 panic("ah_hmac_sha1_init: what?");
575
576 state->sav = sav;
577 state->foo = (void *)_MALLOC(64 + 64 + sizeof(SHA1_CTX),
578 M_TEMP, M_NOWAIT);
579 if (!state->foo)
580 panic("ah_hmac_sha1_init: what?");
581
582 ipad = (u_char *)state->foo;
583 opad = (u_char *)(ipad + 64);
584 ctxt = (SHA1_CTX *)(opad + 64);
585
586 /* compress the key if necessery */
587 if (64 < _KEYLEN(state->sav->key_auth)) {
588 SHA1Init(ctxt);
589 SHA1Update(ctxt, _KEYBUF(state->sav->key_auth),
590 _KEYLEN(state->sav->key_auth));
591 SHA1Final(&tk[0], ctxt);
592 key = &tk[0];
593 keylen = SHA1_RESULTLEN;
594 } else {
595 key = _KEYBUF(state->sav->key_auth);
596 keylen = _KEYLEN(state->sav->key_auth);
597 }
598
599 bzero(ipad, 64);
600 bzero(opad, 64);
601 bcopy(key, ipad, keylen);
602 bcopy(key, opad, keylen);
603 for (i = 0; i < 64; i++) {
604 ipad[i] ^= 0x36;
605 opad[i] ^= 0x5c;
606 }
607
608 SHA1Init(ctxt);
609 SHA1Update(ctxt, ipad, 64);
610}
611
612static void
613ah_hmac_sha1_loop(state, addr, len)
614 struct ah_algorithm_state *state;
615 caddr_t addr;
616 size_t len;
617{
618 SHA1_CTX *ctxt;
619
620 if (!state || !state->foo)
621 panic("ah_hmac_sha1_loop: what?");
622
623 ctxt = (SHA1_CTX *)(((u_char *)state->foo) + 128);
624 SHA1Update(ctxt, (caddr_t)addr, (size_t)len);
625}
626
627static void
628ah_hmac_sha1_result(state, addr)
629 struct ah_algorithm_state *state;
630 caddr_t addr;
631{
632 u_char digest[SHA1_RESULTLEN]; /* SHA-1 generates 160 bits */
633 u_char *ipad;
634 u_char *opad;
635 SHA1_CTX *ctxt;
636
637 if (!state || !state->foo)
638 panic("ah_hmac_sha1_result: what?");
639
640 ipad = (u_char *)state->foo;
641 opad = (u_char *)(ipad + 64);
642 ctxt = (SHA1_CTX *)(opad + 64);
643
644 SHA1Final((caddr_t)&digest[0], ctxt);
645
646 SHA1Init(ctxt);
647 SHA1Update(ctxt, opad, 64);
648 SHA1Update(ctxt, (caddr_t)&digest[0], sizeof(digest));
649 SHA1Final((caddr_t)&digest[0], ctxt);
650
651 bcopy(&digest[0], (void *)addr, HMACSIZE);
652
653 _FREE(state->foo, M_TEMP);
654}
655
656/*------------------------------------------------------------*/
657
658/*
659 * go generate the checksum.
660 */
661static void
662ah_update_mbuf(m, off, len, algo, algos)
663 struct mbuf *m;
664 int off;
665 int len;
666 struct ah_algorithm *algo;
667 struct ah_algorithm_state *algos;
668{
669 struct mbuf *n;
670 int tlen;
671
672 /* easy case first */
673 if (off + len <= m->m_len) {
674 (algo->update)(algos, mtod(m, caddr_t) + off, len);
675 return;
676 }
677
678 for (n = m; n; n = n->m_next) {
679 if (off < n->m_len)
680 break;
681
682 off -= n->m_len;
683 }
684
685 if (!n)
686 panic("ah_update_mbuf: wrong offset specified");
687
688 for (/*nothing*/; n && len > 0; n = n->m_next) {
689 if (n->m_len == 0)
690 continue;
691 if (n->m_len - off < len)
692 tlen = n->m_len - off;
693 else
694 tlen = len;
695
696 (algo->update)(algos, mtod(n, caddr_t) + off, tlen);
697
698 len -= tlen;
699 off = 0;
700 }
701}
702
703/*
704 * Go generate the checksum. This function won't modify the mbuf chain
705 * except AH itself.
706 *
707 * NOTE: the function does not free mbuf on failure.
708 * Don't use m_copy(), it will try to share cluster mbuf by using refcnt.
709 */
710int
711ah4_calccksum(m, ahdat, algo, sav)
712 struct mbuf *m;
713 caddr_t ahdat;
714 struct ah_algorithm *algo;
715 struct secasvar *sav;
716{
717 int off;
718 int hdrtype;
719 size_t advancewidth;
720 struct ah_algorithm_state algos;
721 u_char sumbuf[AH_MAXSUMSIZE];
722 int error = 0;
723 int ahseen;
724 struct mbuf *n = NULL;
725
726 if ((m->m_flags & M_PKTHDR) == 0)
727 return EINVAL;
728
729 ahseen = 0;
730 hdrtype = -1; /*dummy, it is called IPPROTO_IP*/
731
732 off = 0;
733
734 (algo->init)(&algos, sav);
735
736 advancewidth = 0; /*safety*/
737
738again:
739 /* gory. */
740 switch (hdrtype) {
741 case -1: /*first one only*/
742 {
743 /*
744 * copy ip hdr, modify to fit the AH checksum rule,
745 * then take a checksum.
746 */
747 struct ip iphdr;
748 size_t hlen;
749
750 m_copydata(m, off, sizeof(iphdr), (caddr_t)&iphdr);
751#ifdef _IP_VHL
752 hlen = IP_VHL_HL(iphdr.ip_vhl) << 2;
753#else
754 hlen = iphdr.ip_hl << 2;
755#endif
756 iphdr.ip_ttl = 0;
757 iphdr.ip_sum = htons(0);
758 if (ip4_ah_cleartos)
759 iphdr.ip_tos = 0;
760 iphdr.ip_off = htons(ntohs(iphdr.ip_off) & ip4_ah_offsetmask);
761 (algo->update)(&algos, (caddr_t)&iphdr, sizeof(struct ip));
762
763 if (hlen != sizeof(struct ip)) {
764 u_char *p;
765 int i, l, skip;
766
767 if (hlen > MCLBYTES) {
768 error = EMSGSIZE;
769 goto fail;
770 }
771 MGET(n, M_DONTWAIT, MT_DATA);
772 if (n && hlen > MLEN) {
773 MCLGET(n, M_DONTWAIT);
774 if ((n->m_flags & M_EXT) == 0) {
775 m_free(n);
776 n = NULL;
777 }
778 }
779 if (n == NULL) {
780 error = ENOBUFS;
781 goto fail;
782 }
783 m_copydata(m, off, hlen, mtod(n, caddr_t));
784
785 /*
786 * IP options processing.
787 * See RFC2402 appendix A.
788 */
789 p = mtod(n, u_char *);
790 i = sizeof(struct ip);
791 while (i < hlen) {
792 skip = 1;
793 switch (p[i + IPOPT_OPTVAL]) {
794 case IPOPT_EOL:
795 case IPOPT_NOP:
796 l = 1;
797 skip = 0;
798 break;
799 case IPOPT_SECURITY: /* 0x82 */
800 case 0x85: /* Extended security */
801 case 0x86: /* Commercial security */
802 case 0x94: /* Router alert */
803 case 0x95: /* RFC1770 */
804 l = p[i + IPOPT_OLEN];
805 skip = 0;
806 break;
807 default:
808 l = p[i + IPOPT_OLEN];
809 skip = 1;
810 break;
811 }
812 if (l <= 0 || hlen - i < l) {
813 ipseclog((LOG_ERR,
814 "ah4_calccksum: invalid IP option "
815 "(type=%02x len=%02x)\n",
816 p[i + IPOPT_OPTVAL],
817 p[i + IPOPT_OLEN]));
818 m_free(n);
819 n = NULL;
820 error = EINVAL;
821 goto fail;
822 }
823 if (skip)
824 bzero(p + i, l);
825 if (p[i + IPOPT_OPTVAL] == IPOPT_EOL)
826 break;
827 i += l;
828 }
829 p = mtod(n, u_char *) + sizeof(struct ip);
830 (algo->update)(&algos, p, hlen - sizeof(struct ip));
831
832 m_free(n);
833 n = NULL;
834 }
835
836 hdrtype = (iphdr.ip_p) & 0xff;
837 advancewidth = hlen;
838 break;
839 }
840
841 case IPPROTO_AH:
842 {
843 struct ah ah;
844 int siz;
845 int hdrsiz;
846 int totlen;
847
848 m_copydata(m, off, sizeof(ah), (caddr_t)&ah);
849 hdrsiz = (sav->flags & SADB_X_EXT_OLD)
850 ? sizeof(struct ah)
851 : sizeof(struct newah);
852 siz = (*algo->sumsiz)(sav);
853 totlen = (ah.ah_len + 2) << 2;
854
855 /*
856 * special treatment is necessary for the first one, not others
857 */
858 if (!ahseen) {
859 if (totlen > m->m_pkthdr.len - off ||
860 totlen > MCLBYTES) {
861 error = EMSGSIZE;
862 goto fail;
863 }
864 MGET(n, M_DONTWAIT, MT_DATA);
865 if (n && totlen > MLEN) {
866 MCLGET(n, M_DONTWAIT);
867 if ((n->m_flags & M_EXT) == 0) {
868 m_free(n);
869 n = NULL;
870 }
871 }
872 if (n == NULL) {
873 error = ENOBUFS;
874 goto fail;
875 }
876 m_copydata(m, off, totlen, mtod(n, caddr_t));
877 n->m_len = totlen;
878 bzero(mtod(n, caddr_t) + hdrsiz, siz);
879 (algo->update)(&algos, mtod(n, caddr_t), n->m_len);
880 m_free(n);
881 n = NULL;
882 } else
883 ah_update_mbuf(m, off, totlen, algo, &algos);
884 ahseen++;
885
886 hdrtype = ah.ah_nxt;
887 advancewidth = totlen;
888 break;
889 }
890
891 default:
892 ah_update_mbuf(m, off, m->m_pkthdr.len - off, algo, &algos);
893 advancewidth = m->m_pkthdr.len - off;
894 break;
895 }
896
897 off += advancewidth;
898 if (off < m->m_pkthdr.len)
899 goto again;
900
901 (algo->result)(&algos, &sumbuf[0]);
902 bcopy(&sumbuf[0], ahdat, (*algo->sumsiz)(sav));
903
904 if (n)
905 m_free(n);
906 return error;
907
908fail:
909 if (n)
910 m_free(n);
911 return error;
912}
913
914#if INET6
915/*
916 * Go generate the checksum. This function won't modify the mbuf chain
917 * except AH itself.
918 *
919 * NOTE: the function does not free mbuf on failure.
920 * Don't use m_copy(), it will try to share cluster mbuf by using refcnt.
921 */
922int
923ah6_calccksum(m, ahdat, algo, sav)
924 struct mbuf *m;
925 caddr_t ahdat;
926 struct ah_algorithm *algo;
927 struct secasvar *sav;
928{
929 int newoff, off;
930 int proto, nxt;
931 struct mbuf *n = NULL;
932 int error;
933 int ahseen;
934 struct ah_algorithm_state algos;
935 u_char sumbuf[AH_MAXSUMSIZE];
936
937 if ((m->m_flags & M_PKTHDR) == 0)
938 return EINVAL;
939
940 (algo->init)(&algos, sav);
941
942 off = 0;
943 proto = IPPROTO_IPV6;
944 nxt = -1;
945 ahseen = 0;
946
947 again:
948 newoff = ip6_nexthdr(m, off, proto, &nxt);
949 if (newoff < 0)
950 newoff = m->m_pkthdr.len;
951 else if (newoff <= off) {
952 error = EINVAL;
953 goto fail;
954 }
955
956 switch (proto) {
957 case IPPROTO_IPV6:
958 /*
959 * special treatment is necessary for the first one, not others
960 */
961 if (off == 0) {
962 struct ip6_hdr ip6copy;
963
964 if (newoff - off != sizeof(struct ip6_hdr)) {
965 error = EINVAL;
966 goto fail;
967 }
968
969 m_copydata(m, off, newoff - off, (caddr_t)&ip6copy);
970 /* RFC2402 */
971 ip6copy.ip6_flow = 0;
972 ip6copy.ip6_vfc &= ~IPV6_VERSION_MASK;
973 ip6copy.ip6_vfc |= IPV6_VERSION;
974 ip6copy.ip6_hlim = 0;
975 if (IN6_IS_ADDR_LINKLOCAL(&ip6copy.ip6_src))
976 ip6copy.ip6_src.s6_addr16[1] = 0x0000;
977 if (IN6_IS_ADDR_LINKLOCAL(&ip6copy.ip6_dst))
978 ip6copy.ip6_dst.s6_addr16[1] = 0x0000;
979 (algo->update)(&algos, (caddr_t)&ip6copy,
980 sizeof(struct ip6_hdr));
981 } else {
982 newoff = m->m_pkthdr.len;
983 ah_update_mbuf(m, off, m->m_pkthdr.len - off, algo,
984 &algos);
985 }
986 break;
987
988 case IPPROTO_AH:
989 {
990 int siz;
991 int hdrsiz;
992
993 hdrsiz = (sav->flags & SADB_X_EXT_OLD)
994 ? sizeof(struct ah)
995 : sizeof(struct newah);
996 siz = (*algo->sumsiz)(sav);
997
998 /*
999 * special treatment is necessary for the first one, not others
1000 */
1001 if (!ahseen) {
1002 if (newoff - off > MCLBYTES) {
1003 error = EMSGSIZE;
1004 goto fail;
1005 }
1006 MGET(n, M_DONTWAIT, MT_DATA);
1007 if (n && newoff - off > MLEN) {
1008 MCLGET(n, M_DONTWAIT);
1009 if ((n->m_flags & M_EXT) == 0) {
1010 m_free(n);
1011 n = NULL;
1012 }
1013 }
1014 if (n == NULL) {
1015 error = ENOBUFS;
1016 goto fail;
1017 }
1018 m_copydata(m, off, newoff - off, mtod(n, caddr_t));
1019 n->m_len = newoff - off;
1020 bzero(mtod(n, caddr_t) + hdrsiz, siz);
1021 (algo->update)(&algos, mtod(n, caddr_t), n->m_len);
1022 m_free(n);
1023 n = NULL;
1024 } else
1025 ah_update_mbuf(m, off, newoff - off, algo, &algos);
1026 ahseen++;
1027 break;
1028 }
1029
1030 case IPPROTO_HOPOPTS:
1031 case IPPROTO_DSTOPTS:
1032 {
1033 struct ip6_ext *ip6e;
1034 int hdrlen, optlen;
1035 u_int8_t *p, *optend, *optp;
1036
1037 if (newoff - off > MCLBYTES) {
1038 error = EMSGSIZE;
1039 goto fail;
1040 }
1041 MGET(n, M_DONTWAIT, MT_DATA);
1042 if (n && newoff - off > MLEN) {
1043 MCLGET(n, M_DONTWAIT);
1044 if ((n->m_flags & M_EXT) == 0) {
1045 m_free(n);
1046 n = NULL;
1047 }
1048 }
1049 if (n == NULL) {
1050 error = ENOBUFS;
1051 goto fail;
1052 }
1053 m_copydata(m, off, newoff - off, mtod(n, caddr_t));
1054 n->m_len = newoff - off;
1055
1056 ip6e = mtod(n, struct ip6_ext *);
1057 hdrlen = (ip6e->ip6e_len + 1) << 3;
1058 if (newoff - off < hdrlen) {
1059 error = EINVAL;
1060 m_free(n);
1061 n = NULL;
1062 goto fail;
1063 }
1064 p = mtod(n, u_int8_t *);
1065 optend = p + hdrlen;
1066
1067 /*
1068 * ICV calculation for the options header including all
1069 * options. This part is a little tricky since there are
1070 * two type of options; mutable and immutable. We try to
1071 * null-out mutable ones here.
1072 */
1073 optp = p + 2;
1074 while (optp < optend) {
1075 if (optp[0] == IP6OPT_PAD1)
1076 optlen = 1;
1077 else {
1078 if (optp + 2 > optend) {
1079 error = EINVAL;
1080 m_free(n);
1081 n = NULL;
1082 goto fail;
1083 }
1084 optlen = optp[1] + 2;
1085
1086 if (optp[0] & IP6OPT_MUTABLE)
1087 bzero(optp + 2, optlen - 2);
1088 }
1089
1090 optp += optlen;
1091 }
1092
1093 (algo->update)(&algos, mtod(n, caddr_t), n->m_len);
1094 m_free(n);
1095 n = NULL;
1096 break;
1097 }
1098
1099 case IPPROTO_ROUTING:
1100 /*
1101 * For an input packet, we can just calculate `as is'.
1102 * For an output packet, we assume ip6_output have already
1103 * made packet how it will be received at the final
1104 * destination.
1105 */
1106 /* FALLTHROUGH */
1107
1108 default:
1109 ah_update_mbuf(m, off, newoff - off, algo, &algos);
1110 break;
1111 }
1112
1113 if (newoff < m->m_pkthdr.len) {
1114 proto = nxt;
1115 off = newoff;
1116 goto again;
1117 }
1118
1119 (algo->result)(&algos, &sumbuf[0]);
1120 bcopy(&sumbuf[0], ahdat, (*algo->sumsiz)(sav));
1121
1122 /* just in case */
1123 if (n)
1124 m_free(n);
1125 return 0;
1126fail:
1127 /* just in case */
1128 if (n)
1129 m_free(n);
1130 return error;
1131}
1132#endif