jcs's openbsd hax
openbsd
1/* $OpenBSD: ip_ah.c,v 1.179 2025/12/11 05:06:02 dlg Exp $ */
2/*
3 * The authors of this code are John Ioannidis (ji@tla.org),
4 * Angelos D. Keromytis (kermit@csd.uch.gr) and
5 * Niels Provos (provos@physnet.uni-hamburg.de).
6 *
7 * The original version of this code was written by John Ioannidis
8 * for BSD/OS in Athens, Greece, in November 1995.
9 *
10 * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
11 * by Angelos D. Keromytis.
12 *
13 * Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis
14 * and Niels Provos.
15 *
16 * Additional features in 1999 by Angelos D. Keromytis and Niklas Hallqvist.
17 *
18 * Copyright (c) 1995, 1996, 1997, 1998, 1999 by John Ioannidis,
19 * Angelos D. Keromytis and Niels Provos.
20 * Copyright (c) 1999 Niklas Hallqvist.
21 * Copyright (c) 2001 Angelos D. Keromytis.
22 *
23 * Permission to use, copy, and modify this software with or without fee
24 * is hereby granted, provided that this entire notice is included in
25 * all copies of any software which is or includes a copy or
26 * modification of this software.
27 * You may use this code under the GNU public license if you so wish. Please
28 * contribute changes back to the authors under this freer than GPL license
29 * so that we may further the use of strong encryption without limitations to
30 * all.
31 *
32 * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
33 * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
34 * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
35 * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
36 * PURPOSE.
37 */
38
39#include "pfsync.h"
40
41#include <sys/param.h>
42#include <sys/systm.h>
43#include <sys/mbuf.h>
44#include <sys/socket.h>
45
46#include <net/if.h>
47#include <net/if_var.h>
48#include <net/bpf.h>
49
50#include <netinet/in.h>
51#include <netinet/ip.h>
52
53#ifdef INET6
54#include <netinet/ip6.h>
55#endif /* INET6 */
56
57#include <netinet/ip_ipsp.h>
58#include <netinet/ip_ah.h>
59#include <net/pfkeyv2.h>
60#include <net/if_enc.h>
61
62#if NPFSYNC > 0
63#include <net/pfvar.h>
64#include <net/if_pfsync.h>
65#endif /* NPFSYNC > 0 */
66
67#include <crypto/cryptodev.h>
68#include <crypto/xform.h>
69
70#include "bpfilter.h"
71
72#ifdef ENCDEBUG
73#define DPRINTF(fmt, args...) \
74 do { \
75 if (atomic_load_int(&encdebug)) \
76 printf("%s: " fmt "\n", __func__, ## args); \
77 } while (0)
78#else
79#define DPRINTF(fmt, args...) \
80 do { } while (0)
81#endif
82
83int ah_massage_headers(struct mbuf **, int, int, int, int);
84
85const unsigned char ipseczeroes[IPSEC_ZEROES_SIZE]; /* zeroes! */
86
87
88/*
89 * ah_attach() is called from the transformation initialization code.
90 */
91int
92ah_attach(void)
93{
94 return 0;
95}
96
97/*
98 * ah_init() is called when an SPI is being set up.
99 */
100int
101ah_init(struct tdb *tdbp, const struct xformsw *xsp, struct ipsecinit *ii)
102{
103 const struct auth_hash *thash = NULL;
104 struct cryptoini cria, crin;
105 int error;
106
107 /* Authentication operation. */
108 switch (ii->ii_authalg) {
109 case SADB_AALG_MD5HMAC:
110 thash = &auth_hash_hmac_md5_96;
111 break;
112
113 case SADB_AALG_SHA1HMAC:
114 thash = &auth_hash_hmac_sha1_96;
115 break;
116
117 case SADB_X_AALG_RIPEMD160HMAC:
118 thash = &auth_hash_hmac_ripemd_160_96;
119 break;
120
121 case SADB_X_AALG_SHA2_256:
122 thash = &auth_hash_hmac_sha2_256_128;
123 break;
124
125 case SADB_X_AALG_SHA2_384:
126 thash = &auth_hash_hmac_sha2_384_192;
127 break;
128
129 case SADB_X_AALG_SHA2_512:
130 thash = &auth_hash_hmac_sha2_512_256;
131 break;
132
133 default:
134 DPRINTF("unsupported authentication algorithm %d specified",
135 ii->ii_authalg);
136 return EINVAL;
137 }
138
139 if (ii->ii_authkeylen != thash->keysize && thash->keysize != 0) {
140 DPRINTF("keylength %d doesn't match algorithm %s keysize (%d)",
141 ii->ii_authkeylen, thash->name, thash->keysize);
142 return EINVAL;
143 }
144
145 tdbp->tdb_xform = xsp;
146 tdbp->tdb_authalgxform = thash;
147 tdbp->tdb_rpl = AH_HMAC_INITIAL_RPL;
148
149 DPRINTF("initialized TDB with hash algorithm %s", thash->name);
150
151 tdbp->tdb_amxkeylen = ii->ii_authkeylen;
152 tdbp->tdb_amxkey = malloc(tdbp->tdb_amxkeylen, M_XDATA, M_WAITOK);
153
154 memcpy(tdbp->tdb_amxkey, ii->ii_authkey, tdbp->tdb_amxkeylen);
155
156 /* Initialize crypto session. */
157 memset(&cria, 0, sizeof(cria));
158 cria.cri_alg = tdbp->tdb_authalgxform->type;
159 cria.cri_klen = ii->ii_authkeylen * 8;
160 cria.cri_key = ii->ii_authkey;
161
162 if ((tdbp->tdb_wnd > 0) && (tdbp->tdb_flags & TDBF_ESN)) {
163 memset(&crin, 0, sizeof(crin));
164 crin.cri_alg = CRYPTO_ESN;
165 cria.cri_next = &crin;
166 }
167
168 KERNEL_LOCK();
169 error = crypto_newsession(&tdbp->tdb_cryptoid, &cria, 0);
170 KERNEL_UNLOCK();
171 return error;
172}
173
174/*
175 * Paranoia.
176 */
177int
178ah_zeroize(struct tdb *tdbp)
179{
180 int error;
181
182 if (tdbp->tdb_amxkey) {
183 explicit_bzero(tdbp->tdb_amxkey, tdbp->tdb_amxkeylen);
184 free(tdbp->tdb_amxkey, M_XDATA, tdbp->tdb_amxkeylen);
185 tdbp->tdb_amxkey = NULL;
186 }
187
188 KERNEL_LOCK();
189 error = crypto_freesession(tdbp->tdb_cryptoid);
190 KERNEL_UNLOCK();
191 tdbp->tdb_cryptoid = 0;
192 return error;
193}
194
195/*
196 * Massage IPv4/IPv6 headers for AH processing.
197 */
198int
199ah_massage_headers(struct mbuf **mp, int af, int skip, int alg, int out)
200{
201 struct mbuf *m = *mp;
202 unsigned char *ptr;
203 int off, count, error;
204 struct ip *ip;
205#ifdef INET6
206 struct ip6_ext *ip6e;
207 struct ip6_hdr ip6;
208 int ad, alloc, nxt, noff;
209#endif /* INET6 */
210
211 switch (af) {
212 case AF_INET:
213 /*
214 * This is the least painful way of dealing with IPv4 header
215 * and option processing -- just make sure they're in
216 * contiguous memory.
217 */
218 m = *mp = m_pullup(m, skip);
219 if (m == NULL) {
220 DPRINTF("m_pullup() failed");
221 ahstat_inc(ahs_hdrops);
222 error = ENOBUFS;
223 goto drop;
224 }
225
226 /* Fix the IP header */
227 ip = mtod(m, struct ip *);
228 ip->ip_tos = 0;
229 ip->ip_ttl = 0;
230 ip->ip_sum = 0;
231 ip->ip_off = 0;
232
233 ptr = mtod(m, unsigned char *);
234
235 /* IPv4 option processing */
236 for (off = sizeof(struct ip); off < skip;) {
237 if (ptr[off] != IPOPT_EOL && ptr[off] != IPOPT_NOP &&
238 off + 1 >= skip) {
239 DPRINTF("illegal IPv4 option length "
240 "for option %d",
241 ptr[off]);
242 ahstat_inc(ahs_hdrops);
243 error = EINVAL;
244 goto drop;
245 }
246
247 switch (ptr[off]) {
248 case IPOPT_EOL:
249 off = skip; /* End the loop. */
250 break;
251
252 case IPOPT_NOP:
253 off++;
254 break;
255
256 case IPOPT_SECURITY: /* 0x82 */
257 case 0x85: /* Extended security. */
258 case 0x86: /* Commercial security. */
259 case 0x94: /* Router alert */
260 case 0x95: /* RFC1770 */
261 /* Sanity check for option length. */
262 if (ptr[off + 1] < 2) {
263 DPRINTF("illegal IPv4 option length "
264 "for option %d",
265 ptr[off]);
266 ahstat_inc(ahs_hdrops);
267 error = EINVAL;
268 goto drop;
269 }
270
271 off += ptr[off + 1];
272 break;
273
274 case IPOPT_LSRR:
275 case IPOPT_SSRR:
276 /* Sanity check for option length. */
277 if (ptr[off + 1] < 2) {
278 DPRINTF("illegal IPv4 option length "
279 "for option %d",
280 ptr[off]);
281 ahstat_inc(ahs_hdrops);
282 error = EINVAL;
283 goto drop;
284 }
285
286 /*
287 * On output, if we have either of the
288 * source routing options, we should
289 * swap the destination address of the
290 * IP header with the last address
291 * specified in the option, as that is
292 * what the destination's IP header
293 * will look like.
294 */
295 if (out &&
296 ptr[off + 1] >= 2 + sizeof(struct in_addr))
297 memcpy(&ip->ip_dst,
298 ptr + off + ptr[off + 1] -
299 sizeof(struct in_addr),
300 sizeof(struct in_addr));
301
302 /* FALLTHROUGH */
303 default:
304 /* Sanity check for option length. */
305 if (ptr[off + 1] < 2) {
306 DPRINTF("illegal IPv4 option length "
307 "for option %d",
308 ptr[off]);
309 ahstat_inc(ahs_hdrops);
310 error = EINVAL;
311 goto drop;
312 }
313
314 /* Zeroize all other options. */
315 count = ptr[off + 1];
316 memset(ptr + off, 0, count);
317 off += count;
318 break;
319 }
320
321 /* Sanity check. */
322 if (off > skip) {
323 DPRINTF("malformed IPv4 options header");
324 ahstat_inc(ahs_hdrops);
325 error = EINVAL;
326 goto drop;
327 }
328 }
329
330 break;
331
332#ifdef INET6
333 case AF_INET6: /* Ugly... */
334 /* Copy and "cook" the IPv6 header. */
335 m_copydata(m, 0, sizeof(ip6), &ip6);
336
337 /* We don't do IPv6 Jumbograms. */
338 if (ip6.ip6_plen == 0) {
339 DPRINTF("unsupported IPv6 jumbogram");
340 ahstat_inc(ahs_hdrops);
341 error = EMSGSIZE;
342 goto drop;
343 }
344
345 ip6.ip6_flow = 0;
346 ip6.ip6_hlim = 0;
347 ip6.ip6_vfc &= ~IPV6_VERSION_MASK;
348 ip6.ip6_vfc |= IPV6_VERSION;
349
350 /* Scoped address handling. */
351 if (IN6_IS_SCOPE_EMBED(&ip6.ip6_src))
352 ip6.ip6_src.s6_addr16[1] = 0;
353 if (IN6_IS_SCOPE_EMBED(&ip6.ip6_dst))
354 ip6.ip6_dst.s6_addr16[1] = 0;
355
356 /* Done with IPv6 header. */
357 error = m_copyback(m, 0, sizeof(struct ip6_hdr), &ip6,
358 M_NOWAIT);
359 if (error) {
360 DPRINTF("m_copyback no memory");
361 ahstat_inc(ahs_hdrops);
362 goto drop;
363 }
364
365 /* Let's deal with the remaining headers (if any). */
366 if (skip > sizeof(struct ip6_hdr)) {
367 if (m->m_len <= skip) {
368 ptr = malloc(skip - sizeof(struct ip6_hdr),
369 M_XDATA, M_NOWAIT);
370 if (ptr == NULL) {
371 DPRINTF("failed to allocate "
372 "memory for IPv6 headers");
373 ahstat_inc(ahs_hdrops);
374 error = ENOBUFS;
375 goto drop;
376 }
377
378 /*
379 * Copy all the protocol headers after
380 * the IPv6 header.
381 */
382 m_copydata(m, sizeof(struct ip6_hdr),
383 skip - sizeof(struct ip6_hdr), ptr);
384 alloc = 1;
385 } else {
386 /* No need to allocate memory. */
387 ptr = mtod(m, unsigned char *) +
388 sizeof(struct ip6_hdr);
389 alloc = 0;
390 }
391 } else
392 break;
393
394 nxt = ip6.ip6_nxt; /* Next header type. */
395
396 for (off = 0; off + sizeof(struct ip6_hdr) < skip;) {
397 if (off + sizeof(struct ip6_hdr) +
398 sizeof(struct ip6_ext) > skip)
399 goto error6;
400 ip6e = (struct ip6_ext *)(ptr + off);
401
402 switch (nxt) {
403 case IPPROTO_HOPOPTS:
404 case IPPROTO_DSTOPTS:
405 noff = off + ((ip6e->ip6e_len + 1) << 3);
406
407 /* Sanity check. */
408 if (noff + sizeof(struct ip6_hdr) > skip)
409 goto error6;
410
411 /*
412 * Zero out mutable options.
413 */
414 for (count = off + sizeof(struct ip6_ext);
415 count < noff;) {
416 if (ptr[count] == IP6OPT_PAD1) {
417 count++;
418 continue; /* Skip padding. */
419 }
420
421 if (count + 2 > noff)
422 goto error6;
423 ad = ptr[count + 1] + 2;
424 if (count + ad > noff)
425 goto error6;
426
427 /* If mutable option, zeroize. */
428 if (ptr[count] & IP6OPT_MUTABLE)
429 memset(ptr + count, 0, ad);
430
431 count += ad;
432 }
433
434 if (count != noff)
435 goto error6;
436 break;
437
438 case IPPROTO_ROUTING:
439 /*
440 * Always include routing headers in
441 * computation.
442 */
443 {
444 struct ip6_rthdr *rh;
445
446 rh = (struct ip6_rthdr *)(ptr + off);
447 /*
448 * must adjust content to make it look like
449 * its final form (as seen at the final
450 * destination).
451 * we only know how to massage type 0 routing
452 * header.
453 */
454 if (out && rh->ip6r_type == IPV6_RTHDR_TYPE_0) {
455 struct ip6_rthdr0 *rh0;
456 struct in6_addr *addr, finaldst;
457 int i;
458
459 rh0 = (struct ip6_rthdr0 *)rh;
460 addr = (struct in6_addr *)(rh0 + 1);
461
462 for (i = 0; i < rh0->ip6r0_segleft; i++)
463 if (IN6_IS_SCOPE_EMBED(&addr[i]))
464 addr[i].s6_addr16[1] = 0;
465
466 finaldst = addr[rh0->ip6r0_segleft - 1];
467 memmove(&addr[1], &addr[0],
468 sizeof(struct in6_addr) *
469 (rh0->ip6r0_segleft - 1));
470
471 m_copydata(m, 0, sizeof(ip6), &ip6);
472 addr[0] = ip6.ip6_dst;
473 ip6.ip6_dst = finaldst;
474 error = m_copyback(m, 0, sizeof(ip6),
475 &ip6, M_NOWAIT);
476 if (error) {
477 if (alloc)
478 free(ptr, M_XDATA, 0);
479 ahstat_inc(ahs_hdrops);
480 goto drop;
481 }
482 rh0->ip6r0_segleft = 0;
483 }
484 break;
485 }
486
487 default:
488 DPRINTF("unexpected IPv6 header type %d", off);
489error6:
490 if (alloc)
491 free(ptr, M_XDATA, 0);
492 ahstat_inc(ahs_hdrops);
493 error = EINVAL;
494 goto drop;
495 }
496
497 /* Advance. */
498 off += ((ip6e->ip6e_len + 1) << 3);
499 nxt = ip6e->ip6e_nxt;
500 }
501
502 /* Copyback and free, if we allocated. */
503 if (alloc) {
504 error = m_copyback(m, sizeof(struct ip6_hdr),
505 skip - sizeof(struct ip6_hdr), ptr, M_NOWAIT);
506 free(ptr, M_XDATA, 0);
507 if (error) {
508 ahstat_inc(ahs_hdrops);
509 goto drop;
510 }
511 }
512
513 break;
514#endif /* INET6 */
515 }
516
517 return 0;
518
519 drop:
520 m_freemp(mp);
521 return error;
522}
523
524/*
525 * ah_input() gets called to verify that an input packet
526 * passes authentication.
527 */
528int
529ah_input(struct mbuf **mp, struct tdb *tdb, int skip, int protoff,
530 struct netstack *ns)
531{
532 const struct auth_hash *ahx = tdb->tdb_authalgxform;
533 struct mbuf *m = *mp, *m1, *m0;
534 struct cryptodesc *crda = NULL;
535 struct cryptop *crp = NULL;
536 int roff;
537 uint32_t btsx, esn;
538 uint8_t *ptr = NULL;
539 uint8_t hl;
540 int error, rplen;
541 uint64_t ibytes;
542#ifdef ENCDEBUG
543 char buf[INET6_ADDRSTRLEN];
544#endif
545 uint8_t calc[AH_ALEN_MAX];
546
547 rplen = AH_FLENGTH + sizeof(u_int32_t);
548
549 /* Save the AH header, we use it throughout. */
550 m_copydata(m, skip + offsetof(struct ah, ah_hl), sizeof(u_int8_t), &hl);
551
552 /* Replay window checking, if applicable. */
553 if (tdb->tdb_wnd > 0) {
554 m_copydata(m, skip + offsetof(struct ah, ah_rpl),
555 sizeof(u_int32_t), &btsx);
556 btsx = ntohl(btsx);
557
558 switch (checkreplaywindow(tdb, tdb->tdb_rpl, btsx, &esn, 0)) {
559 case 0: /* All's well. */
560 break;
561 case 1:
562 DPRINTF("replay counter wrapped for SA %s/%08x",
563 ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),
564 ntohl(tdb->tdb_spi));
565 ahstat_inc(ahs_wrap);
566 goto drop;
567 case 2:
568 DPRINTF("old packet received in SA %s/%08x",
569 ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),
570 ntohl(tdb->tdb_spi));
571 ahstat_inc(ahs_replay);
572 goto drop;
573 case 3:
574 DPRINTF("duplicate packet received in SA %s/%08x",
575 ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),
576 ntohl(tdb->tdb_spi));
577 ahstat_inc(ahs_replay);
578 goto drop;
579 default:
580 DPRINTF("bogus value from checkreplaywindow() "
581 "in SA %s/%08x",
582 ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),
583 ntohl(tdb->tdb_spi));
584 ahstat_inc(ahs_replay);
585 goto drop;
586 }
587 }
588
589 /* Verify AH header length. */
590 if (hl * sizeof(u_int32_t) != ahx->authsize + rplen - AH_FLENGTH) {
591 DPRINTF("bad authenticator length %ld for packet in SA %s/%08x",
592 hl * sizeof(u_int32_t),
593 ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),
594 ntohl(tdb->tdb_spi));
595 ahstat_inc(ahs_badauthl);
596 goto drop;
597 }
598 if (skip + ahx->authsize + rplen > m->m_pkthdr.len) {
599 DPRINTF("bad mbuf length %d (expecting %d) for packet "
600 "in SA %s/%08x",
601 m->m_pkthdr.len, skip + ahx->authsize + rplen,
602 ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),
603 ntohl(tdb->tdb_spi));
604 ahstat_inc(ahs_badauthl);
605 goto drop;
606 }
607
608 /* Update the counters. */
609 ibytes = (m->m_pkthdr.len - skip - hl * sizeof(u_int32_t));
610 tdb->tdb_cur_bytes += ibytes;
611 tdbstat_add(tdb, tdb_ibytes, ibytes);
612 ahstat_add(ahs_ibytes, ibytes);
613
614 /* Hard expiration. */
615 if ((tdb->tdb_flags & TDBF_BYTES) &&
616 (tdb->tdb_cur_bytes >= tdb->tdb_exp_bytes)) {
617 ipsecstat_inc(ipsec_exctdb);
618 pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_HARD);
619 tdb_delete(tdb);
620 goto drop;
621 }
622
623 /* Notify on expiration. */
624 mtx_enter(&tdb->tdb_mtx);
625 if ((tdb->tdb_flags & TDBF_SOFT_BYTES) &&
626 (tdb->tdb_cur_bytes >= tdb->tdb_soft_bytes)) {
627 tdb->tdb_flags &= ~TDBF_SOFT_BYTES; /* Turn off checking */
628 mtx_leave(&tdb->tdb_mtx);
629 /* may sleep in solock() for the pfkey socket */
630 pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_SOFT);
631 } else
632 mtx_leave(&tdb->tdb_mtx);
633
634 /* Get crypto descriptors. */
635 crp = crypto_getreq(1);
636 if (crp == NULL) {
637 DPRINTF("failed to acquire crypto descriptors");
638 ahstat_inc(ahs_crypto);
639 goto drop;
640 }
641
642 crda = &crp->crp_desc[0];
643
644 crda->crd_skip = 0;
645 crda->crd_len = m->m_pkthdr.len;
646 crda->crd_inject = skip + rplen;
647
648 /* Authentication operation. */
649 crda->crd_alg = ahx->type;
650 crda->crd_key = tdb->tdb_amxkey;
651 crda->crd_klen = tdb->tdb_amxkeylen * 8;
652
653 if ((tdb->tdb_wnd > 0) && (tdb->tdb_flags & TDBF_ESN)) {
654 esn = htonl(esn);
655 memcpy(crda->crd_esn, &esn, 4);
656 crda->crd_flags |= CRD_F_ESN;
657 }
658
659 /* Allocate IPsec-specific opaque crypto info. */
660 ptr = malloc(skip + rplen + ahx->authsize, M_XDATA, M_NOWAIT | M_ZERO);
661 if (ptr == NULL) {
662 DPRINTF("failed to allocate buffer");
663 ahstat_inc(ahs_crypto);
664 goto drop;
665 }
666
667 /*
668 * Save the authenticator, the skipped portion of the packet,
669 * and the AH header.
670 */
671 m_copydata(m, 0, skip + rplen + ahx->authsize, ptr);
672
673 /* Zeroize the authenticator on the packet. */
674 m_copyback(m, skip + rplen, ahx->authsize, ipseczeroes, M_NOWAIT);
675
676 /* "Massage" the packet headers for crypto processing. */
677 error = ah_massage_headers(mp, tdb->tdb_dst.sa.sa_family, skip,
678 ahx->type, 0);
679 /* callee may change or free mbuf */
680 m = *mp;
681 if (error)
682 goto drop;
683
684 /* Crypto operation descriptor. */
685 crp->crp_ilen = m->m_pkthdr.len; /* Total input length. */
686 crp->crp_flags = CRYPTO_F_IMBUF;
687 crp->crp_buf = (caddr_t)m;
688 crp->crp_sid = tdb->tdb_cryptoid;
689
690 while ((error = crypto_invoke(crp)) == EAGAIN) {
691 /* Reset the session ID */
692 if (tdb->tdb_cryptoid != 0)
693 tdb->tdb_cryptoid = crp->crp_sid;
694 }
695 if (error) {
696 DPRINTF("crypto error %d", error);
697 ipsecstat_inc(ipsec_noxform);
698 goto drop;
699 }
700
701 /* Release the crypto descriptors */
702 crypto_freereq(crp);
703 crp = NULL;
704
705 /* Copy authenticator off the packet. */
706 m_copydata(m, skip + rplen, ahx->authsize, calc);
707
708 /* Verify authenticator. */
709 if (timingsafe_bcmp(ptr + skip + rplen, calc, ahx->authsize)) {
710 DPRINTF("authentication failed for packet in SA %s/%08x",
711 ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),
712 ntohl(tdb->tdb_spi));
713 ahstat_inc(ahs_badauth);
714 goto drop;
715 }
716
717 /* Fix the Next Protocol field. */
718 ptr[protoff] = ptr[skip];
719
720 /* Copyback the saved (uncooked) network headers. */
721 m_copyback(m, 0, skip, ptr, M_NOWAIT);
722
723 free(ptr, M_XDATA, 0);
724 ptr = NULL;
725
726 /* Replay window checking, if applicable. */
727 if (tdb->tdb_wnd > 0) {
728 m_copydata(m, skip + offsetof(struct ah, ah_rpl),
729 sizeof(u_int32_t), &btsx);
730 btsx = ntohl(btsx);
731
732 switch (checkreplaywindow(tdb, tdb->tdb_rpl, btsx, &esn, 1)) {
733 case 0: /* All's well. */
734#if NPFSYNC > 0
735 pfsync_update_tdb(tdb,0);
736#endif
737 break;
738 case 1:
739 DPRINTF("replay counter wrapped for SA %s/%08x",
740 ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),
741 ntohl(tdb->tdb_spi));
742 ahstat_inc(ahs_wrap);
743 goto drop;
744 case 2:
745 DPRINTF("old packet received in SA %s/%08x",
746 ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),
747 ntohl(tdb->tdb_spi));
748 ahstat_inc(ahs_replay);
749 goto drop;
750 case 3:
751 DPRINTF("duplicate packet received in SA %s/%08x",
752 ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),
753 ntohl(tdb->tdb_spi));
754 ahstat_inc(ahs_replay);
755 goto drop;
756 default:
757 DPRINTF("bogus value from checkreplaywindow() "
758 "in SA %s/%08x",
759 ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),
760 ntohl(tdb->tdb_spi));
761 ahstat_inc(ahs_replay);
762 goto drop;
763 }
764 }
765
766 /* Record the beginning of the AH header. */
767 m1 = m_getptr(m, skip, &roff);
768 if (m1 == NULL) {
769 DPRINTF("bad mbuf chain for packet in SA %s/%08x",
770 ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),
771 ntohl(tdb->tdb_spi));
772 ahstat_inc(ahs_hdrops);
773 goto drop;
774 }
775
776 /* Remove the AH header from the mbuf. */
777 if (roff == 0) {
778 /*
779 * The AH header was conveniently at the beginning of
780 * the mbuf.
781 */
782 m_adj(m1, rplen + ahx->authsize);
783 /*
784 * If m1 is the first mbuf, it has set M_PKTHDR and m_adj()
785 * has already adjusted the packet header length for us.
786 */
787 if (m1 != m)
788 m->m_pkthdr.len -= rplen + ahx->authsize;
789 } else
790 if (roff + rplen + ahx->authsize >= m1->m_len) {
791 int adjlen;
792
793 /*
794 * Part or all of the AH header is at the end
795 * of this mbuf, so first let's remove the
796 * remainder of the AH header from the
797 * beginning of the remainder of the mbuf
798 * chain, if any.
799 */
800 if (roff + rplen + ahx->authsize > m1->m_len) {
801 adjlen = roff + rplen + ahx->authsize -
802 m1->m_len;
803 /* Adjust the next mbuf by the remainder. */
804 m_adj(m1->m_next, adjlen);
805
806 /*
807 * The second mbuf is guaranteed not
808 * to have a pkthdr...
809 */
810 m->m_pkthdr.len -= adjlen;
811 }
812
813 /* Now, let's unlink the mbuf chain for a second... */
814 m0 = m1->m_next;
815 m1->m_next = NULL;
816
817 /*
818 * ...and trim the end of the first part of
819 * the chain...sick
820 */
821 adjlen = m1->m_len - roff;
822 m_adj(m1, -adjlen);
823 /*
824 * If m1 is the first mbuf, it has set M_PKTHDR and
825 * m_adj() has already adjusted the packet header len.
826 */
827 if (m1 != m)
828 m->m_pkthdr.len -= adjlen;
829
830 /* Finally, let's relink. */
831 m1->m_next = m0;
832 } else {
833 /*
834 * The AH header lies in the "middle" of the
835 * mbuf...do an overlapping copy of the
836 * remainder of the mbuf over the ESP header.
837 */
838 bcopy(mtod(m1, u_char *) + roff + rplen +
839 ahx->authsize, mtod(m1, u_char *) + roff,
840 m1->m_len - (roff + rplen + ahx->authsize));
841 m1->m_len -= rplen + ahx->authsize;
842 m->m_pkthdr.len -= rplen + ahx->authsize;
843 }
844
845 return ipsec_common_input_cb(mp, tdb, skip, protoff, ns);
846
847 drop:
848 free(ptr, M_XDATA, 0);
849 m_freemp(mp);
850 crypto_freereq(crp);
851 return IPPROTO_DONE;
852}
853
854/*
855 * AH output routine, called by ipsp_process_packet().
856 */
857int
858ah_output(struct mbuf *m, struct tdb *tdb, int skip, int protoff)
859{
860 const struct auth_hash *ahx = tdb->tdb_authalgxform;
861 struct cryptodesc *crda;
862 struct mbuf *mi;
863 struct cryptop *crp = NULL;
864 uint64_t replay64;
865 uint16_t iplen;
866 int error, rplen, roff;
867 uint8_t *ptr = NULL;
868 uint8_t prot;
869 struct ah *ah;
870#if NBPFILTER > 0
871 struct ifnet *encif;
872#ifdef ENCDEBUG
873 char buf[INET6_ADDRSTRLEN];
874#endif
875
876 if ((encif = enc_getif(tdb->tdb_rdomain, tdb->tdb_tap)) != NULL) {
877 encif->if_opackets++;
878 encif->if_obytes += m->m_pkthdr.len;
879
880 if (encif->if_bpf) {
881 struct enchdr hdr = {
882 .af = htonl(tdb->tdb_dst.sa.sa_family),
883 .spi = tdb->tdb_spi,
884 .flags = htonl(M_AUTH),
885 };
886
887 bpf_mtap_hdr(encif->if_bpf, (char *)&hdr,
888 ENC_HDRLEN, m, BPF_DIRECTION_OUT);
889 }
890 }
891#endif
892
893 ahstat_inc(ahs_output);
894
895 /*
896 * Check for replay counter wrap-around in automatic (not
897 * manual) keying.
898 */
899 if ((tdb->tdb_rpl == 0) && (tdb->tdb_wnd > 0)) {
900 DPRINTF("SA %s/%08x should have expired",
901 ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),
902 ntohl(tdb->tdb_spi));
903 ahstat_inc(ahs_wrap);
904 error = EINVAL;
905 goto drop;
906 }
907
908 rplen = AH_FLENGTH + sizeof(u_int32_t);
909
910 switch (tdb->tdb_dst.sa.sa_family) {
911 case AF_INET:
912 /* Check for IP maximum packet size violations. */
913 if (rplen + ahx->authsize + m->m_pkthdr.len > IP_MAXPACKET) {
914 DPRINTF("packet in SA %s/%08x got too big",
915 ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),
916 ntohl(tdb->tdb_spi));
917 ahstat_inc(ahs_toobig);
918 error = EMSGSIZE;
919 goto drop;
920 }
921 break;
922
923#ifdef INET6
924 case AF_INET6:
925 /* Check for IPv6 maximum packet size violations. */
926 if (rplen + ahx->authsize + m->m_pkthdr.len > IPV6_MAXPACKET) {
927 DPRINTF("packet in SA %s/%08x got too big",
928 ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),
929 ntohl(tdb->tdb_spi));
930 ahstat_inc(ahs_toobig);
931 error = EMSGSIZE;
932 goto drop;
933 }
934 break;
935#endif /* INET6 */
936
937 default:
938 DPRINTF("unknown/unsupported protocol family %d, SA %s/%08x",
939 tdb->tdb_dst.sa.sa_family,
940 ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),
941 ntohl(tdb->tdb_spi));
942 ahstat_inc(ahs_nopf);
943 error = EPFNOSUPPORT;
944 goto drop;
945 }
946
947 /* Update the counters. */
948 tdb->tdb_cur_bytes += m->m_pkthdr.len - skip;
949 ahstat_add(ahs_obytes, m->m_pkthdr.len - skip);
950
951 /* Hard expiration. */
952 if ((tdb->tdb_flags & TDBF_BYTES) &&
953 (tdb->tdb_cur_bytes >= tdb->tdb_exp_bytes)) {
954 ipsecstat_inc(ipsec_exctdb);
955 pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_HARD);
956 tdb_delete(tdb);
957 error = EINVAL;
958 goto drop;
959 }
960
961 /* Notify on expiration. */
962 mtx_enter(&tdb->tdb_mtx);
963 if ((tdb->tdb_flags & TDBF_SOFT_BYTES) &&
964 (tdb->tdb_cur_bytes >= tdb->tdb_soft_bytes)) {
965 tdb->tdb_flags &= ~TDBF_SOFT_BYTES; /* Turn off checking */
966 mtx_leave(&tdb->tdb_mtx);
967 /* may sleep in solock() for the pfkey socket */
968 pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_SOFT);
969 } else
970 mtx_leave(&tdb->tdb_mtx);
971
972 /*
973 * Loop through mbuf chain; if we find a readonly mbuf,
974 * copy the packet.
975 */
976 mi = m;
977 while (mi != NULL && !M_READONLY(mi))
978 mi = mi->m_next;
979
980 if (mi != NULL) {
981 struct mbuf *n = m_dup_pkt(m, 0, M_DONTWAIT);
982
983 if (n == NULL) {
984 ahstat_inc(ahs_hdrops);
985 error = ENOBUFS;
986 goto drop;
987 }
988
989 m_freem(m);
990 m = n;
991 }
992
993 /* Inject AH header. */
994 mi = m_makespace(m, skip, rplen + ahx->authsize, &roff);
995 if (mi == NULL) {
996 DPRINTF("failed to inject AH header for SA %s/%08x",
997 ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),
998 ntohl(tdb->tdb_spi));
999 ahstat_inc(ahs_hdrops);
1000 error = ENOBUFS;
1001 goto drop;
1002 }
1003
1004 /*
1005 * The AH header is guaranteed by m_makespace() to be in
1006 * contiguous memory, at 'roff' of the returned mbuf.
1007 */
1008 ah = (struct ah *)(mtod(mi, caddr_t) + roff);
1009
1010 /* Initialize the AH header. */
1011 m_copydata(m, protoff, sizeof(u_int8_t), &ah->ah_nh);
1012 ah->ah_hl = (rplen + ahx->authsize - AH_FLENGTH) / sizeof(u_int32_t);
1013 ah->ah_rv = 0;
1014 ah->ah_spi = tdb->tdb_spi;
1015
1016 /* Zeroize authenticator. */
1017 m_copyback(m, skip + rplen, ahx->authsize, ipseczeroes, M_NOWAIT);
1018
1019 replay64 = tdb->tdb_rpl++;
1020 ah->ah_rpl = htonl((u_int32_t)replay64);
1021#if NPFSYNC > 0
1022 pfsync_update_tdb(tdb,1);
1023#endif
1024
1025 /* Get crypto descriptors. */
1026 crp = crypto_getreq(1);
1027 if (crp == NULL) {
1028 DPRINTF("failed to acquire crypto descriptors");
1029 ahstat_inc(ahs_crypto);
1030 error = ENOBUFS;
1031 goto drop;
1032 }
1033
1034 crda = &crp->crp_desc[0];
1035
1036 crda->crd_skip = 0;
1037 crda->crd_inject = skip + rplen;
1038 crda->crd_len = m->m_pkthdr.len;
1039
1040 /* Authentication operation. */
1041 crda->crd_alg = ahx->type;
1042 crda->crd_key = tdb->tdb_amxkey;
1043 crda->crd_klen = tdb->tdb_amxkeylen * 8;
1044
1045 if ((tdb->tdb_wnd > 0) && (tdb->tdb_flags & TDBF_ESN)) {
1046 u_int32_t esn;
1047
1048 esn = htonl((u_int32_t)(replay64 >> 32));
1049 memcpy(crda->crd_esn, &esn, 4);
1050 crda->crd_flags |= CRD_F_ESN;
1051 }
1052
1053 ptr = malloc(skip, M_XDATA, M_NOWAIT | M_ZERO);
1054 if (ptr == NULL) {
1055 DPRINTF("failed to allocate buffer");
1056 ahstat_inc(ahs_crypto);
1057 error = ENOBUFS;
1058 goto drop;
1059 }
1060
1061 /* Save the skipped portion of the packet. */
1062 m_copydata(m, 0, skip, ptr);
1063
1064 /*
1065 * Fix IP header length on the header used for
1066 * authentication. We don't need to fix the original
1067 * header length as it will be fixed by our caller.
1068 */
1069 switch (tdb->tdb_dst.sa.sa_family) {
1070 case AF_INET:
1071 memcpy((caddr_t) &iplen, ((caddr_t)ptr) +
1072 offsetof(struct ip, ip_len), sizeof(u_int16_t));
1073 iplen = htons(ntohs(iplen) + rplen + ahx->authsize);
1074 m_copyback(m, offsetof(struct ip, ip_len),
1075 sizeof(u_int16_t), &iplen, M_NOWAIT);
1076 break;
1077
1078#ifdef INET6
1079 case AF_INET6:
1080 memcpy((caddr_t) &iplen, ((caddr_t)ptr) +
1081 offsetof(struct ip6_hdr, ip6_plen), sizeof(u_int16_t));
1082 iplen = htons(ntohs(iplen) + rplen + ahx->authsize);
1083 m_copyback(m, offsetof(struct ip6_hdr, ip6_plen),
1084 sizeof(u_int16_t), &iplen, M_NOWAIT);
1085 break;
1086#endif /* INET6 */
1087 }
1088
1089 /* Fix the Next Header field in saved header. */
1090 ptr[protoff] = IPPROTO_AH;
1091
1092 /* Update the Next Protocol field in the IP header. */
1093 prot = IPPROTO_AH;
1094 m_copyback(m, protoff, sizeof(u_int8_t), &prot, M_NOWAIT);
1095
1096 /* "Massage" the packet headers for crypto processing. */
1097 error = ah_massage_headers(&m, tdb->tdb_dst.sa.sa_family, skip,
1098 ahx->type, 1);
1099 if (error) {
1100 /* mbuf was freed by callee. */
1101 m = NULL;
1102 goto drop;
1103 }
1104
1105 /* Crypto operation descriptor. */
1106 crp->crp_ilen = m->m_pkthdr.len; /* Total input length. */
1107 crp->crp_flags = CRYPTO_F_IMBUF;
1108 crp->crp_buf = (caddr_t)m;
1109 crp->crp_sid = tdb->tdb_cryptoid;
1110
1111 while ((error = crypto_invoke(crp)) == EAGAIN) {
1112 /* Reset the session ID */
1113 if (tdb->tdb_cryptoid != 0)
1114 tdb->tdb_cryptoid = crp->crp_sid;
1115 }
1116 if (error) {
1117 DPRINTF("crypto error %d", error);
1118 ipsecstat_inc(ipsec_noxform);
1119 goto drop;
1120 }
1121
1122 /* Release the crypto descriptors */
1123 crypto_freereq(crp);
1124 crp = NULL;
1125
1126 /*
1127 * Copy original headers (with the new protocol number) back
1128 * in place.
1129 */
1130 m_copyback(m, 0, skip, ptr, M_NOWAIT);
1131 free(ptr, M_XDATA, 0);
1132 ptr = NULL;
1133
1134 /* Call the IPsec input callback. */
1135 error = ipsp_process_done(m, tdb);
1136 if (error)
1137 ahstat_inc(ahs_outfail);
1138 return error;
1139
1140 drop:
1141 free(ptr, M_XDATA, 0);
1142 m_freem(m);
1143 crypto_freereq(crp);
1144 return error;
1145}