1 | /* $NetBSD: xform_ah.c,v 1.44 2015/03/30 03:51:50 ozaki-r Exp $ */ |
2 | /* $FreeBSD: src/sys/netipsec/xform_ah.c,v 1.1.4.1 2003/01/24 05:11:36 sam Exp $ */ |
3 | /* $OpenBSD: ip_ah.c,v 1.63 2001/06/26 06:18:58 angelos Exp $ */ |
4 | /* |
5 | * The authors of this code are John Ioannidis (ji@tla.org), |
6 | * Angelos D. Keromytis (kermit@csd.uch.gr) and |
7 | * Niels Provos (provos@physnet.uni-hamburg.de). |
8 | * |
9 | * The original version of this code was written by John Ioannidis |
10 | * for BSD/OS in Athens, Greece, in November 1995. |
11 | * |
12 | * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996, |
13 | * by Angelos D. Keromytis. |
14 | * |
15 | * Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis |
16 | * and Niels Provos. |
17 | * |
18 | * Additional features in 1999 by Angelos D. Keromytis and Niklas Hallqvist. |
19 | * |
20 | * Copyright (c) 1995, 1996, 1997, 1998, 1999 by John Ioannidis, |
21 | * Angelos D. Keromytis and Niels Provos. |
22 | * Copyright (c) 1999 Niklas Hallqvist. |
23 | * Copyright (c) 2001 Angelos D. Keromytis. |
24 | * |
25 | * Permission to use, copy, and modify this software with or without fee |
26 | * is hereby granted, provided that this entire notice is included in |
27 | * all copies of any software which is or includes a copy or |
28 | * modification of this software. |
29 | * You may use this code under the GNU public license if you so wish. Please |
30 | * contribute changes back to the authors under this freer than GPL license |
31 | * so that we may further the use of strong encryption without limitations to |
32 | * all. |
33 | * |
34 | * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR |
35 | * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY |
36 | * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE |
37 | * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR |
38 | * PURPOSE. |
39 | */ |
40 | |
41 | #include <sys/cdefs.h> |
42 | __KERNEL_RCSID(0, "$NetBSD: xform_ah.c,v 1.44 2015/03/30 03:51:50 ozaki-r Exp $" ); |
43 | |
44 | #include "opt_inet.h" |
45 | #ifdef __FreeBSD__ |
46 | #include "opt_inet6.h" |
47 | #endif |
48 | #include "opt_ipsec.h" |
49 | |
50 | #include <sys/param.h> |
51 | #include <sys/systm.h> |
52 | #include <sys/mbuf.h> |
53 | #include <sys/socket.h> |
54 | #include <sys/syslog.h> |
55 | #include <sys/kernel.h> |
56 | #include <sys/sysctl.h> |
57 | #include <sys/socketvar.h> /* for softnet_lock */ |
58 | |
59 | #include <net/if.h> |
60 | |
61 | #include <netinet/in.h> |
62 | #include <netinet/in_systm.h> |
63 | #include <netinet/ip.h> |
64 | #include <netinet/ip_ecn.h> |
65 | #include <netinet/ip6.h> |
66 | |
67 | #include <net/route.h> |
68 | #include <netipsec/ipsec.h> |
69 | #include <netipsec/ipsec_private.h> |
70 | #include <netipsec/ah.h> |
71 | #include <netipsec/ah_var.h> |
72 | #include <netipsec/xform.h> |
73 | |
74 | #ifdef INET6 |
75 | #include <netinet6/ip6_var.h> |
76 | #include <netinet6/scope6_var.h> |
77 | #include <netipsec/ipsec6.h> |
78 | # ifdef __FreeBSD__ |
79 | # include <netinet6/ip6_ecn.h> |
80 | # endif |
81 | #endif |
82 | |
83 | #include <netipsec/key.h> |
84 | #include <netipsec/key_debug.h> |
85 | #include <netipsec/ipsec_osdep.h> |
86 | |
87 | #include <opencrypto/cryptodev.h> |
88 | |
89 | /* |
90 | * Return header size in bytes. The old protocol did not support |
91 | * the replay counter; the new protocol always includes the counter. |
92 | */ |
93 | #define HDRSIZE(sav) \ |
94 | (((sav)->flags & SADB_X_EXT_OLD) ? \ |
95 | sizeof (struct ah) : sizeof (struct ah) + sizeof (u_int32_t)) |
96 | /* |
97 | * Return authenticator size in bytes. The old protocol is known |
98 | * to use a fixed 16-byte authenticator. The new algorithm gets |
99 | * this size from the xform but is (currently) always 12. |
100 | */ |
101 | #define AUTHSIZE(sav) \ |
102 | ((sav->flags & SADB_X_EXT_OLD) ? 16 : (sav)->tdb_authalgxform->authsize) |
103 | |
104 | percpu_t *ahstat_percpu; |
105 | |
106 | int ah_enable = 1; /* control flow of packets with AH */ |
107 | int ip4_ah_cleartos = 1; /* clear ip_tos when doing AH calc */ |
108 | |
109 | #ifdef __FreeBSD__ |
110 | SYSCTL_DECL(_net_inet_ah); |
111 | SYSCTL_INT(_net_inet_ah, OID_AUTO, |
112 | ah_enable, CTLFLAG_RW, &ah_enable, 0, "" ); |
113 | SYSCTL_INT(_net_inet_ah, OID_AUTO, |
114 | ah_cleartos, CTLFLAG_RW, &ip4_ah_cleartos, 0, "" ); |
115 | SYSCTL_STRUCT(_net_inet_ah, IPSECCTL_STATS, |
116 | stats, CTLFLAG_RD, &ahstat, ahstat, "" ); |
117 | |
118 | #endif /* __FreeBSD__ */ |
119 | |
120 | static unsigned char ipseczeroes[256]; /* larger than an ip6 extension hdr */ |
121 | |
122 | static int ah_input_cb(struct cryptop*); |
123 | static int ah_output_cb(struct cryptop*); |
124 | |
125 | /* |
126 | * NB: this is public for use by the PF_KEY support. |
127 | */ |
128 | const struct auth_hash * |
129 | ah_algorithm_lookup(int alg) |
130 | { |
131 | if (alg >= AH_ALG_MAX) |
132 | return NULL; |
133 | switch (alg) { |
134 | case SADB_X_AALG_NULL: |
135 | return &auth_hash_null; |
136 | case SADB_AALG_MD5HMAC: |
137 | return &auth_hash_hmac_md5_96; |
138 | case SADB_AALG_SHA1HMAC: |
139 | return &auth_hash_hmac_sha1_96; |
140 | case SADB_X_AALG_RIPEMD160HMAC: |
141 | return &auth_hash_hmac_ripemd_160_96; |
142 | case SADB_X_AALG_MD5: |
143 | return &auth_hash_key_md5; |
144 | case SADB_X_AALG_SHA: |
145 | return &auth_hash_key_sha1; |
146 | case SADB_X_AALG_SHA2_256: |
147 | return &auth_hash_hmac_sha2_256; |
148 | case SADB_X_AALG_SHA2_384: |
149 | return &auth_hash_hmac_sha2_384; |
150 | case SADB_X_AALG_SHA2_512: |
151 | return &auth_hash_hmac_sha2_512; |
152 | case SADB_X_AALG_AES_XCBC_MAC: |
153 | return &auth_hash_aes_xcbc_mac_96; |
154 | } |
155 | return NULL; |
156 | } |
157 | |
158 | size_t |
159 | ah_hdrsiz(const struct secasvar *sav) |
160 | { |
161 | size_t size; |
162 | |
163 | if (sav != NULL) { |
164 | int authsize; |
165 | IPSEC_ASSERT(sav->tdb_authalgxform != NULL, |
166 | ("ah_hdrsiz: null xform" )); |
167 | /*XXX not right for null algorithm--does it matter??*/ |
168 | authsize = AUTHSIZE(sav); |
169 | size = roundup(authsize, sizeof (u_int32_t)) + HDRSIZE(sav); |
170 | } else { |
171 | /* default guess */ |
172 | size = sizeof (struct ah) + sizeof (u_int32_t) + 16; |
173 | } |
174 | return size; |
175 | } |
176 | |
177 | /* |
178 | * NB: public for use by esp_init. |
179 | */ |
180 | int |
181 | ah_init0(struct secasvar *sav, const struct xformsw *xsp, |
182 | struct cryptoini *cria) |
183 | { |
184 | const struct auth_hash *thash; |
185 | int keylen; |
186 | |
187 | thash = ah_algorithm_lookup(sav->alg_auth); |
188 | if (thash == NULL) { |
189 | DPRINTF(("ah_init: unsupported authentication algorithm %u\n" , |
190 | sav->alg_auth)); |
191 | return EINVAL; |
192 | } |
193 | /* |
194 | * Verify the replay state block allocation is consistent with |
195 | * the protocol type. We check here so we can make assumptions |
196 | * later during protocol processing. |
197 | */ |
198 | /* NB: replay state is setup elsewhere (sigh) */ |
199 | if (((sav->flags&SADB_X_EXT_OLD) == 0) ^ (sav->replay != NULL)) { |
200 | DPRINTF(("ah_init: replay state block inconsistency, " |
201 | "%s algorithm %s replay state\n" , |
202 | (sav->flags & SADB_X_EXT_OLD) ? "old" : "new" , |
203 | sav->replay == NULL ? "without" : "with" )); |
204 | return EINVAL; |
205 | } |
206 | if (sav->key_auth == NULL) { |
207 | DPRINTF(("ah_init: no authentication key for %s " |
208 | "algorithm\n" , thash->name)); |
209 | return EINVAL; |
210 | } |
211 | keylen = _KEYLEN(sav->key_auth); |
212 | if (keylen != thash->keysize && thash->keysize != 0) { |
213 | DPRINTF(("ah_init: invalid keylength %d, algorithm " |
214 | "%s requires keysize %d\n" , |
215 | keylen, thash->name, thash->keysize)); |
216 | return EINVAL; |
217 | } |
218 | |
219 | sav->tdb_xform = xsp; |
220 | sav->tdb_authalgxform = thash; |
221 | |
222 | /* Initialize crypto session. */ |
223 | memset(cria, 0, sizeof (*cria)); |
224 | cria->cri_alg = sav->tdb_authalgxform->type; |
225 | cria->cri_klen = _KEYBITS(sav->key_auth); |
226 | cria->cri_key = _KEYBUF(sav->key_auth); |
227 | |
228 | return 0; |
229 | } |
230 | |
231 | /* |
232 | * ah_init() is called when an SPI is being set up. |
233 | */ |
234 | static int |
235 | ah_init(struct secasvar *sav, const struct xformsw *xsp) |
236 | { |
237 | struct cryptoini cria; |
238 | int error; |
239 | |
240 | error = ah_init0(sav, xsp, &cria); |
241 | if (!error) |
242 | error = crypto_newsession(&sav->tdb_cryptoid, |
243 | &cria, crypto_support); |
244 | return error; |
245 | } |
246 | |
247 | /* |
248 | * Paranoia. |
249 | * |
250 | * NB: public for use by esp_zeroize (XXX). |
251 | */ |
252 | int |
253 | ah_zeroize(struct secasvar *sav) |
254 | { |
255 | int err; |
256 | |
257 | if (sav->key_auth) |
258 | memset(_KEYBUF(sav->key_auth), 0, _KEYLEN(sav->key_auth)); |
259 | |
260 | err = crypto_freesession(sav->tdb_cryptoid); |
261 | sav->tdb_cryptoid = 0; |
262 | sav->tdb_authalgxform = NULL; |
263 | sav->tdb_xform = NULL; |
264 | return err; |
265 | } |
266 | |
267 | /* |
268 | * Massage IPv4/IPv6 headers for AH processing. |
269 | */ |
270 | static int |
271 | (struct mbuf **m0, int proto, int skip, int alg, int out) |
272 | { |
273 | struct mbuf *m = *m0; |
274 | unsigned char *ptr; |
275 | int off, count; |
276 | |
277 | #ifdef INET |
278 | struct ip *ip; |
279 | #endif /* INET */ |
280 | |
281 | #ifdef INET6 |
282 | struct ip6_ext *ip6e; |
283 | struct ip6_hdr ip6; |
284 | int alloc, ad, nxt; |
285 | #endif /* INET6 */ |
286 | |
287 | switch (proto) { |
288 | #ifdef INET |
289 | case AF_INET: |
290 | /* |
291 | * This is the least painful way of dealing with IPv4 header |
292 | * and option processing -- just make sure they're in |
293 | * contiguous memory. |
294 | */ |
295 | *m0 = m = m_pullup(m, skip); |
296 | if (m == NULL) { |
297 | DPRINTF(("ah_massage_headers: m_pullup failed\n" )); |
298 | return ENOBUFS; |
299 | } |
300 | |
301 | /* Fix the IP header */ |
302 | ip = mtod(m, struct ip *); |
303 | if (ip4_ah_cleartos) |
304 | ip->ip_tos = 0; |
305 | ip->ip_ttl = 0; |
306 | ip->ip_sum = 0; |
307 | ip->ip_off = htons(ntohs(ip->ip_off) & ip4_ah_offsetmask); |
308 | |
309 | /* |
310 | * On FreeBSD, ip_off and ip_len assumed in host endian; |
311 | * they are converted (if necessary) by ip_input(). |
312 | * On NetBSD, ip_off and ip_len are in network byte order. |
313 | * They must be massaged back to network byte order |
314 | * before verifying the HMAC. Moreover, on FreeBSD, |
315 | * we should add `skip' back into the massaged ip_len |
316 | * (presumably ip_input() deducted it before we got here?) |
317 | * whereas on NetBSD, we should not. |
318 | */ |
319 | #ifdef __FreeBSD__ |
320 | #define TOHOST(x) (x) |
321 | #else |
322 | #define TOHOST(x) (ntohs(x)) |
323 | #endif |
324 | if (!out) { |
325 | u_int16_t inlen = TOHOST(ip->ip_len); |
326 | |
327 | #ifdef __FreeBSD__ |
328 | ip->ip_len = htons(inlen + skip); |
329 | #else /*!__FreeBSD__ */ |
330 | ip->ip_len = htons(inlen); |
331 | #endif /*!__FreeBSD__ */ |
332 | |
333 | if (alg == CRYPTO_MD5_KPDK || alg == CRYPTO_SHA1_KPDK) |
334 | ip->ip_off &= IP_OFF_CONVERT(IP_DF); |
335 | else |
336 | ip->ip_off = 0; |
337 | } else { |
338 | if (alg == CRYPTO_MD5_KPDK || alg == CRYPTO_SHA1_KPDK) |
339 | ip->ip_off &= IP_OFF_CONVERT(IP_DF); |
340 | else |
341 | ip->ip_off = 0; |
342 | } |
343 | |
344 | ptr = mtod(m, unsigned char *); |
345 | |
346 | /* IPv4 option processing */ |
347 | for (off = sizeof(struct ip); off < skip;) { |
348 | if (ptr[off] == IPOPT_EOL || ptr[off] == IPOPT_NOP || |
349 | off + 1 < skip) |
350 | ; |
351 | else { |
352 | DPRINTF(("ah_massage_headers: illegal IPv4 " |
353 | "option length for option %d\n" , |
354 | ptr[off])); |
355 | |
356 | m_freem(m); |
357 | return EINVAL; |
358 | } |
359 | |
360 | switch (ptr[off]) { |
361 | case IPOPT_EOL: |
362 | off = skip; /* End the loop. */ |
363 | break; |
364 | |
365 | case IPOPT_NOP: |
366 | off++; |
367 | break; |
368 | |
369 | case IPOPT_SECURITY: /* 0x82 */ |
370 | case 0x85: /* Extended security. */ |
371 | case 0x86: /* Commercial security. */ |
372 | case 0x94: /* Router alert */ |
373 | case 0x95: /* RFC1770 */ |
374 | /* Sanity check for option length. */ |
375 | if (ptr[off + 1] < 2) { |
376 | DPRINTF(("ah_massage_headers: " |
377 | "illegal IPv4 option length for " |
378 | "option %d\n" , ptr[off])); |
379 | |
380 | m_freem(m); |
381 | return EINVAL; |
382 | } |
383 | |
384 | off += ptr[off + 1]; |
385 | break; |
386 | |
387 | case IPOPT_LSRR: |
388 | case IPOPT_SSRR: |
389 | /* Sanity check for option length. */ |
390 | if (ptr[off + 1] < 2) { |
391 | DPRINTF(("ah_massage_headers: " |
392 | "illegal IPv4 option length for " |
393 | "option %d\n" , ptr[off])); |
394 | |
395 | m_freem(m); |
396 | return EINVAL; |
397 | } |
398 | |
399 | /* |
400 | * On output, if we have either of the |
401 | * source routing options, we should |
402 | * swap the destination address of the |
403 | * IP header with the last address |
404 | * specified in the option, as that is |
405 | * what the destination's IP header |
406 | * will look like. |
407 | */ |
408 | if (out) |
409 | bcopy(ptr + off + ptr[off + 1] - |
410 | sizeof(struct in_addr), |
411 | &(ip->ip_dst), sizeof(struct in_addr)); |
412 | |
413 | /* Fall through */ |
414 | default: |
415 | /* Sanity check for option length. */ |
416 | if (ptr[off + 1] < 2) { |
417 | DPRINTF(("ah_massage_headers: " |
418 | "illegal IPv4 option length for " |
419 | "option %d\n" , ptr[off])); |
420 | m_freem(m); |
421 | return EINVAL; |
422 | } |
423 | |
424 | /* Zeroize all other options. */ |
425 | count = ptr[off + 1]; |
426 | memcpy(ptr + off, ipseczeroes, count); |
427 | off += count; |
428 | break; |
429 | } |
430 | |
431 | /* Sanity check. */ |
432 | if (off > skip) { |
433 | DPRINTF(("ah_massage_headers(): malformed " |
434 | "IPv4 options header\n" )); |
435 | |
436 | m_freem(m); |
437 | return EINVAL; |
438 | } |
439 | } |
440 | |
441 | break; |
442 | #endif /* INET */ |
443 | |
444 | #ifdef INET6 |
445 | case AF_INET6: /* Ugly... */ |
446 | /* Copy and "cook" the IPv6 header. */ |
447 | m_copydata(m, 0, sizeof(ip6), &ip6); |
448 | |
449 | /* We don't do IPv6 Jumbograms. */ |
450 | if (ip6.ip6_plen == 0) { |
451 | DPRINTF(("ah_massage_headers: unsupported IPv6 jumbogram\n" )); |
452 | m_freem(m); |
453 | return EMSGSIZE; |
454 | } |
455 | |
456 | ip6.ip6_flow = 0; |
457 | ip6.ip6_hlim = 0; |
458 | ip6.ip6_vfc &= ~IPV6_VERSION_MASK; |
459 | ip6.ip6_vfc |= IPV6_VERSION; |
460 | |
461 | /* Scoped address handling. */ |
462 | if (IN6_IS_SCOPE_LINKLOCAL(&ip6.ip6_src)) |
463 | ip6.ip6_src.s6_addr16[1] = 0; |
464 | if (IN6_IS_SCOPE_LINKLOCAL(&ip6.ip6_dst)) |
465 | ip6.ip6_dst.s6_addr16[1] = 0; |
466 | |
467 | /* Done with IPv6 header. */ |
468 | m_copyback(m, 0, sizeof(struct ip6_hdr), &ip6); |
469 | |
470 | /* Let's deal with the remaining headers (if any). */ |
471 | if (skip - sizeof(struct ip6_hdr) > 0) { |
472 | if (m->m_len <= skip) { |
473 | ptr = (unsigned char *) malloc( |
474 | skip - sizeof(struct ip6_hdr), |
475 | M_XDATA, M_NOWAIT); |
476 | if (ptr == NULL) { |
477 | DPRINTF(("ah_massage_headers: failed " |
478 | "to allocate memory for IPv6 " |
479 | "headers\n" )); |
480 | m_freem(m); |
481 | return ENOBUFS; |
482 | } |
483 | |
484 | /* |
485 | * Copy all the protocol headers after |
486 | * the IPv6 header. |
487 | */ |
488 | m_copydata(m, sizeof(struct ip6_hdr), |
489 | skip - sizeof(struct ip6_hdr), ptr); |
490 | alloc = 1; |
491 | } else { |
492 | /* No need to allocate memory. */ |
493 | ptr = mtod(m, unsigned char *) + |
494 | sizeof(struct ip6_hdr); |
495 | alloc = 0; |
496 | } |
497 | } else |
498 | break; |
499 | |
500 | nxt = ip6.ip6_nxt & 0xff; /* Next header type. */ |
501 | |
502 | for (off = 0; off < skip - sizeof(struct ip6_hdr);) |
503 | switch (nxt) { |
504 | case IPPROTO_HOPOPTS: |
505 | case IPPROTO_DSTOPTS: |
506 | ip6e = (struct ip6_ext *) (ptr + off); |
507 | |
508 | /* |
509 | * Process the mutable/immutable |
510 | * options -- borrows heavily from the |
511 | * KAME code. |
512 | */ |
513 | for (count = off + sizeof(struct ip6_ext); |
514 | count < off + ((ip6e->ip6e_len + 1) << 3);) { |
515 | if (ptr[count] == IP6OPT_PAD1) { |
516 | count++; |
517 | continue; /* Skip padding. */ |
518 | } |
519 | |
520 | /* Sanity check. */ |
521 | if (count > off + |
522 | ((ip6e->ip6e_len + 1) << 3)) { |
523 | m_freem(m); |
524 | |
525 | /* Free, if we allocated. */ |
526 | if (alloc) |
527 | free(ptr, M_XDATA); |
528 | return EINVAL; |
529 | } |
530 | |
531 | ad = ptr[count + 1]; |
532 | |
533 | /* If mutable option, zeroize. */ |
534 | if (ptr[count] & IP6OPT_MUTABLE) |
535 | memcpy(ptr + count, ipseczeroes, |
536 | ptr[count + 1]); |
537 | |
538 | count += ad; |
539 | |
540 | /* Sanity check. */ |
541 | if (count > |
542 | skip - sizeof(struct ip6_hdr)) { |
543 | m_freem(m); |
544 | |
545 | /* Free, if we allocated. */ |
546 | if (alloc) |
547 | free(ptr, M_XDATA); |
548 | return EINVAL; |
549 | } |
550 | } |
551 | |
552 | /* Advance. */ |
553 | off += ((ip6e->ip6e_len + 1) << 3); |
554 | nxt = ip6e->ip6e_nxt; |
555 | break; |
556 | |
557 | case IPPROTO_ROUTING: |
558 | /* |
559 | * Always include routing headers in |
560 | * computation. |
561 | */ |
562 | { |
563 | struct ip6_rthdr *rh; |
564 | |
565 | ip6e = (struct ip6_ext *) (ptr + off); |
566 | rh = (struct ip6_rthdr *)(ptr + off); |
567 | /* |
568 | * must adjust content to make it look like |
569 | * its final form (as seen at the final |
570 | * destination). |
571 | * we only know how to massage type 0 routing |
572 | * header. |
573 | */ |
574 | if (out && rh->ip6r_type == IPV6_RTHDR_TYPE_0) { |
575 | struct ip6_rthdr0 *rh0; |
576 | struct in6_addr *addr, finaldst; |
577 | int i; |
578 | |
579 | rh0 = (struct ip6_rthdr0 *)rh; |
580 | addr = (struct in6_addr *)(rh0 + 1); |
581 | |
582 | for (i = 0; i < rh0->ip6r0_segleft; i++) |
583 | in6_clearscope(&addr[i]); |
584 | |
585 | finaldst = addr[rh0->ip6r0_segleft - 1]; |
586 | memmove(&addr[1], &addr[0], |
587 | sizeof(struct in6_addr) * |
588 | (rh0->ip6r0_segleft - 1)); |
589 | |
590 | m_copydata(m, 0, sizeof(ip6), &ip6); |
591 | addr[0] = ip6.ip6_dst; |
592 | ip6.ip6_dst = finaldst; |
593 | m_copyback(m, 0, sizeof(ip6), &ip6); |
594 | |
595 | rh0->ip6r0_segleft = 0; |
596 | } |
597 | |
598 | /* advance */ |
599 | off += ((ip6e->ip6e_len + 1) << 3); |
600 | nxt = ip6e->ip6e_nxt; |
601 | break; |
602 | } |
603 | |
604 | default: |
605 | DPRINTF(("ah_massage_headers: unexpected " |
606 | "IPv6 header type %d" , off)); |
607 | if (alloc) |
608 | free(ptr, M_XDATA); |
609 | m_freem(m); |
610 | return EINVAL; |
611 | } |
612 | |
613 | /* Copyback and free, if we allocated. */ |
614 | if (alloc) { |
615 | m_copyback(m, sizeof(struct ip6_hdr), |
616 | skip - sizeof(struct ip6_hdr), ptr); |
617 | free(ptr, M_XDATA); |
618 | } |
619 | |
620 | break; |
621 | #endif /* INET6 */ |
622 | } |
623 | |
624 | return 0; |
625 | } |
626 | |
627 | /* |
628 | * ah_input() gets called to verify that an input packet |
629 | * passes authentication. |
630 | */ |
631 | static int |
632 | ah_input(struct mbuf *m, const struct secasvar *sav, int skip, int protoff) |
633 | { |
634 | const struct auth_hash *ahx; |
635 | struct tdb_ident *tdbi; |
636 | struct tdb_crypto *tc; |
637 | struct m_tag *mtag; |
638 | struct newah *ah; |
639 | int hl, rplen, authsize, error; |
640 | |
641 | struct cryptodesc *crda; |
642 | struct cryptop *crp; |
643 | |
644 | IPSEC_SPLASSERT_SOFTNET("ah_input" ); |
645 | |
646 | IPSEC_ASSERT(sav != NULL, ("ah_input: null SA" )); |
647 | IPSEC_ASSERT(sav->key_auth != NULL, |
648 | ("ah_input: null authentication key" )); |
649 | IPSEC_ASSERT(sav->tdb_authalgxform != NULL, |
650 | ("ah_input: null authentication xform" )); |
651 | |
652 | /* Figure out header size. */ |
653 | rplen = HDRSIZE(sav); |
654 | |
655 | /* XXX don't pullup, just copy header */ |
656 | IP6_EXTHDR_GET(ah, struct newah *, m, skip, rplen); |
657 | if (ah == NULL) { |
658 | DPRINTF(("ah_input: cannot pullup header\n" )); |
659 | AH_STATINC(AH_STAT_HDROPS); /*XXX*/ |
660 | m_freem(m); |
661 | return ENOBUFS; |
662 | } |
663 | |
664 | /* Check replay window, if applicable. */ |
665 | if (sav->replay && !ipsec_chkreplay(ntohl(ah->ah_seq), sav)) { |
666 | AH_STATINC(AH_STAT_REPLAY); |
667 | DPRINTF(("ah_input: packet replay failure: %s\n" , |
668 | ipsec_logsastr(sav))); |
669 | m_freem(m); |
670 | return ENOBUFS; |
671 | } |
672 | |
673 | /* Verify AH header length. */ |
674 | hl = ah->ah_len * sizeof (u_int32_t); |
675 | ahx = sav->tdb_authalgxform; |
676 | authsize = AUTHSIZE(sav); |
677 | if (hl != authsize + rplen - sizeof (struct ah)) { |
678 | DPRINTF(("ah_input: bad authenticator length %u (expecting %lu)" |
679 | " for packet in SA %s/%08lx\n" , |
680 | hl, (u_long) (authsize + rplen - sizeof (struct ah)), |
681 | ipsec_address(&sav->sah->saidx.dst), |
682 | (u_long) ntohl(sav->spi))); |
683 | AH_STATINC(AH_STAT_BADAUTHL); |
684 | m_freem(m); |
685 | return EACCES; |
686 | } |
687 | AH_STATADD(AH_STAT_IBYTES, m->m_pkthdr.len - skip - hl); |
688 | |
689 | /* Get crypto descriptors. */ |
690 | crp = crypto_getreq(1); |
691 | if (crp == NULL) { |
692 | DPRINTF(("ah_input: failed to acquire crypto descriptor\n" )); |
693 | AH_STATINC(AH_STAT_CRYPTO); |
694 | m_freem(m); |
695 | return ENOBUFS; |
696 | } |
697 | |
698 | crda = crp->crp_desc; |
699 | IPSEC_ASSERT(crda != NULL, ("ah_input: null crypto descriptor" )); |
700 | |
701 | crda->crd_skip = 0; |
702 | crda->crd_len = m->m_pkthdr.len; |
703 | crda->crd_inject = skip + rplen; |
704 | |
705 | /* Authentication operation. */ |
706 | crda->crd_alg = ahx->type; |
707 | crda->crd_key = _KEYBUF(sav->key_auth); |
708 | crda->crd_klen = _KEYBITS(sav->key_auth); |
709 | |
710 | /* Find out if we've already done crypto. */ |
711 | for (mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_CRYPTO_DONE, NULL); |
712 | mtag != NULL; |
713 | mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_CRYPTO_DONE, mtag)) { |
714 | tdbi = (struct tdb_ident *) (mtag + 1); |
715 | if (tdbi->proto == sav->sah->saidx.proto && |
716 | tdbi->spi == sav->spi && |
717 | !memcmp(&tdbi->dst, &sav->sah->saidx.dst, |
718 | sizeof (union sockaddr_union))) |
719 | break; |
720 | } |
721 | |
722 | /* Allocate IPsec-specific opaque crypto info. */ |
723 | if (mtag == NULL) { |
724 | tc = (struct tdb_crypto *) malloc(sizeof (struct tdb_crypto) + |
725 | skip + rplen + authsize, M_XDATA, M_NOWAIT|M_ZERO); |
726 | } else { |
727 | /* Hash verification has already been done successfully. */ |
728 | tc = (struct tdb_crypto *) malloc(sizeof (struct tdb_crypto), |
729 | M_XDATA, M_NOWAIT|M_ZERO); |
730 | } |
731 | if (tc == NULL) { |
732 | DPRINTF(("ah_input: failed to allocate tdb_crypto\n" )); |
733 | AH_STATINC(AH_STAT_CRYPTO); |
734 | crypto_freereq(crp); |
735 | m_freem(m); |
736 | return ENOBUFS; |
737 | } |
738 | |
739 | error = m_makewritable(&m, 0, skip + rplen + authsize, M_NOWAIT); |
740 | if (error) { |
741 | m_freem(m); |
742 | DPRINTF(("ah_input: failed to copyback_cow\n" )); |
743 | AH_STATINC(AH_STAT_HDROPS); |
744 | free(tc, M_XDATA); |
745 | crypto_freereq(crp); |
746 | return error; |
747 | } |
748 | |
749 | /* Only save information if crypto processing is needed. */ |
750 | if (mtag == NULL) { |
751 | /* |
752 | * Save the authenticator, the skipped portion of the packet, |
753 | * and the AH header. |
754 | */ |
755 | m_copydata(m, 0, skip + rplen + authsize, (tc + 1)); |
756 | |
757 | /* Zeroize the authenticator on the packet. */ |
758 | m_copyback(m, skip + rplen, authsize, ipseczeroes); |
759 | |
760 | /* "Massage" the packet headers for crypto processing. */ |
761 | error = ah_massage_headers(&m, sav->sah->saidx.dst.sa.sa_family, |
762 | skip, ahx->type, 0); |
763 | if (error != 0) { |
764 | /* NB: mbuf is free'd by ah_massage_headers */ |
765 | AH_STATINC(AH_STAT_HDROPS); |
766 | free(tc, M_XDATA); |
767 | crypto_freereq(crp); |
768 | return error; |
769 | } |
770 | } |
771 | |
772 | /* Crypto operation descriptor. */ |
773 | crp->crp_ilen = m->m_pkthdr.len; /* Total input length. */ |
774 | crp->crp_flags = CRYPTO_F_IMBUF; |
775 | crp->crp_buf = m; |
776 | crp->crp_callback = ah_input_cb; |
777 | crp->crp_sid = sav->tdb_cryptoid; |
778 | crp->crp_opaque = tc; |
779 | |
780 | /* These are passed as-is to the callback. */ |
781 | tc->tc_spi = sav->spi; |
782 | tc->tc_dst = sav->sah->saidx.dst; |
783 | tc->tc_proto = sav->sah->saidx.proto; |
784 | tc->tc_nxt = ah->ah_nxt; |
785 | tc->tc_protoff = protoff; |
786 | tc->tc_skip = skip; |
787 | tc->tc_ptr = mtag; /* Save the mtag we've identified. */ |
788 | |
789 | DPRINTF(("ah: hash over %d bytes, skip %d: " |
790 | "crda len %d skip %d inject %d\n" , |
791 | crp->crp_ilen, tc->tc_skip, |
792 | crda->crd_len, crda->crd_skip, crda->crd_inject)); |
793 | |
794 | if (mtag == NULL) |
795 | return crypto_dispatch(crp); |
796 | else |
797 | return ah_input_cb(crp); |
798 | } |
799 | |
800 | #ifdef INET6 |
801 | #define IPSEC_COMMON_INPUT_CB(m, sav, skip, protoff, mtag) do { \ |
802 | if (saidx->dst.sa.sa_family == AF_INET6) { \ |
803 | error = ipsec6_common_input_cb(m, sav, skip, protoff, mtag); \ |
804 | } else { \ |
805 | error = ipsec4_common_input_cb(m, sav, skip, protoff, mtag); \ |
806 | } \ |
807 | } while (0) |
808 | #else |
809 | #define IPSEC_COMMON_INPUT_CB(m, sav, skip, protoff, mtag) \ |
810 | (error = ipsec4_common_input_cb(m, sav, skip, protoff, mtag)) |
811 | #endif |
812 | |
813 | /* |
814 | * AH input callback from the crypto driver. |
815 | */ |
816 | static int |
817 | ah_input_cb(struct cryptop *crp) |
818 | { |
819 | int rplen, error, skip, protoff; |
820 | unsigned char calc[AH_ALEN_MAX]; |
821 | struct mbuf *m; |
822 | struct tdb_crypto *tc; |
823 | struct m_tag *mtag; |
824 | struct secasvar *sav; |
825 | struct secasindex *saidx; |
826 | u_int8_t nxt; |
827 | char *ptr; |
828 | int s, authsize; |
829 | u_int16_t dport; |
830 | u_int16_t sport; |
831 | |
832 | tc = (struct tdb_crypto *) crp->crp_opaque; |
833 | IPSEC_ASSERT(tc != NULL, ("ah_input_cb: null opaque crypto data area!" )); |
834 | skip = tc->tc_skip; |
835 | nxt = tc->tc_nxt; |
836 | protoff = tc->tc_protoff; |
837 | mtag = (struct m_tag *) tc->tc_ptr; |
838 | m = (struct mbuf *) crp->crp_buf; |
839 | |
840 | |
841 | /* find the source port for NAT-T */ |
842 | nat_t_ports_get(m, &dport, &sport); |
843 | |
844 | s = splsoftnet(); |
845 | mutex_enter(softnet_lock); |
846 | |
847 | sav = KEY_ALLOCSA(&tc->tc_dst, tc->tc_proto, tc->tc_spi, sport, dport); |
848 | if (sav == NULL) { |
849 | AH_STATINC(AH_STAT_NOTDB); |
850 | DPRINTF(("ah_input_cb: SA expired while in crypto\n" )); |
851 | error = ENOBUFS; /*XXX*/ |
852 | goto bad; |
853 | } |
854 | |
855 | saidx = &sav->sah->saidx; |
856 | IPSEC_ASSERT(saidx->dst.sa.sa_family == AF_INET || |
857 | saidx->dst.sa.sa_family == AF_INET6, |
858 | ("ah_input_cb: unexpected protocol family %u" , |
859 | saidx->dst.sa.sa_family)); |
860 | |
861 | /* Check for crypto errors. */ |
862 | if (crp->crp_etype) { |
863 | if (sav->tdb_cryptoid != 0) |
864 | sav->tdb_cryptoid = crp->crp_sid; |
865 | |
866 | if (crp->crp_etype == EAGAIN) { |
867 | mutex_exit(softnet_lock); |
868 | splx(s); |
869 | return crypto_dispatch(crp); |
870 | } |
871 | |
872 | AH_STATINC(AH_STAT_NOXFORM); |
873 | DPRINTF(("ah_input_cb: crypto error %d\n" , crp->crp_etype)); |
874 | error = crp->crp_etype; |
875 | goto bad; |
876 | } else { |
877 | AH_STATINC(AH_STAT_HIST + sav->alg_auth); |
878 | crypto_freereq(crp); /* No longer needed. */ |
879 | crp = NULL; |
880 | } |
881 | |
882 | /* Shouldn't happen... */ |
883 | if (m == NULL) { |
884 | AH_STATINC(AH_STAT_CRYPTO); |
885 | DPRINTF(("ah_input_cb: bogus returned buffer from crypto\n" )); |
886 | error = EINVAL; |
887 | goto bad; |
888 | } |
889 | |
890 | /* Figure out header size. */ |
891 | rplen = HDRSIZE(sav); |
892 | authsize = AUTHSIZE(sav); |
893 | |
894 | if (ipsec_debug) |
895 | memset(calc, 0, sizeof(calc)); |
896 | |
897 | /* Copy authenticator off the packet. */ |
898 | m_copydata(m, skip + rplen, authsize, calc); |
899 | |
900 | /* |
901 | * If we have an mtag, we don't need to verify the authenticator -- |
902 | * it has been verified by an IPsec-aware NIC. |
903 | */ |
904 | if (mtag == NULL) { |
905 | ptr = (char *) (tc + 1); |
906 | |
907 | /* Verify authenticator. */ |
908 | if (!consttime_memequal(ptr + skip + rplen, calc, authsize)) { |
909 | u_int8_t *pppp = ptr + skip+rplen; |
910 | DPRINTF(("ah_input: authentication hash mismatch " \ |
911 | "over %d bytes " \ |
912 | "for packet in SA %s/%08lx:\n" \ |
913 | "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x, " \ |
914 | "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x\n" , |
915 | authsize, |
916 | ipsec_address(&saidx->dst), |
917 | (u_long) ntohl(sav->spi), |
918 | calc[0], calc[1], calc[2], calc[3], |
919 | calc[4], calc[5], calc[6], calc[7], |
920 | calc[8], calc[9], calc[10], calc[11], |
921 | pppp[0], pppp[1], pppp[2], pppp[3], |
922 | pppp[4], pppp[5], pppp[6], pppp[7], |
923 | pppp[8], pppp[9], pppp[10], pppp[11] |
924 | )); |
925 | AH_STATINC(AH_STAT_BADAUTH); |
926 | error = EACCES; |
927 | goto bad; |
928 | } |
929 | |
930 | /* Fix the Next Protocol field. */ |
931 | ((u_int8_t *) ptr)[protoff] = nxt; |
932 | |
933 | /* Copyback the saved (uncooked) network headers. */ |
934 | m_copyback(m, 0, skip, ptr); |
935 | } else { |
936 | /* Fix the Next Protocol field. */ |
937 | m_copyback(m, protoff, sizeof(u_int8_t), &nxt); |
938 | } |
939 | |
940 | free(tc, M_XDATA), tc = NULL; /* No longer needed */ |
941 | |
942 | /* |
943 | * Header is now authenticated. |
944 | */ |
945 | m->m_flags |= M_AUTHIPHDR|M_AUTHIPDGM; |
946 | |
947 | /* |
948 | * Update replay sequence number, if appropriate. |
949 | */ |
950 | if (sav->replay) { |
951 | u_int32_t seq; |
952 | |
953 | m_copydata(m, skip + offsetof(struct newah, ah_seq), |
954 | sizeof (seq), &seq); |
955 | if (ipsec_updatereplay(ntohl(seq), sav)) { |
956 | AH_STATINC(AH_STAT_REPLAY); |
957 | error = ENOBUFS; /*XXX as above*/ |
958 | goto bad; |
959 | } |
960 | } |
961 | |
962 | /* |
963 | * Remove the AH header and authenticator from the mbuf. |
964 | */ |
965 | error = m_striphdr(m, skip, rplen + authsize); |
966 | if (error) { |
967 | DPRINTF(("ah_input_cb: mangled mbuf chain for SA %s/%08lx\n" , |
968 | ipsec_address(&saidx->dst), (u_long) ntohl(sav->spi))); |
969 | |
970 | AH_STATINC(AH_STAT_HDROPS); |
971 | goto bad; |
972 | } |
973 | |
974 | IPSEC_COMMON_INPUT_CB(m, sav, skip, protoff, mtag); |
975 | |
976 | KEY_FREESAV(&sav); |
977 | mutex_exit(softnet_lock); |
978 | splx(s); |
979 | return error; |
980 | bad: |
981 | if (sav) |
982 | KEY_FREESAV(&sav); |
983 | mutex_exit(softnet_lock); |
984 | splx(s); |
985 | if (m != NULL) |
986 | m_freem(m); |
987 | if (tc != NULL) |
988 | free(tc, M_XDATA); |
989 | if (crp != NULL) |
990 | crypto_freereq(crp); |
991 | return error; |
992 | } |
993 | |
994 | /* |
995 | * AH output routine, called by ipsec[46]_process_packet(). |
996 | */ |
997 | static int |
998 | ah_output( |
999 | struct mbuf *m, |
1000 | struct ipsecrequest *isr, |
1001 | struct mbuf **mp, |
1002 | int skip, |
1003 | int protoff |
1004 | ) |
1005 | { |
1006 | const struct secasvar *sav; |
1007 | const struct auth_hash *ahx; |
1008 | struct cryptodesc *crda; |
1009 | struct tdb_crypto *tc; |
1010 | struct mbuf *mi; |
1011 | struct cryptop *crp; |
1012 | u_int16_t iplen; |
1013 | int error, rplen, authsize, maxpacketsize, roff; |
1014 | u_int8_t prot; |
1015 | struct newah *ah; |
1016 | |
1017 | IPSEC_SPLASSERT_SOFTNET("ah_output" ); |
1018 | |
1019 | sav = isr->sav; |
1020 | IPSEC_ASSERT(sav != NULL, ("ah_output: null SA" )); |
1021 | ahx = sav->tdb_authalgxform; |
1022 | IPSEC_ASSERT(ahx != NULL, ("ah_output: null authentication xform" )); |
1023 | |
1024 | AH_STATINC(AH_STAT_OUTPUT); |
1025 | |
1026 | /* Figure out header size. */ |
1027 | rplen = HDRSIZE(sav); |
1028 | |
1029 | /* Check for maximum packet size violations. */ |
1030 | switch (sav->sah->saidx.dst.sa.sa_family) { |
1031 | #ifdef INET |
1032 | case AF_INET: |
1033 | maxpacketsize = IP_MAXPACKET; |
1034 | break; |
1035 | #endif /* INET */ |
1036 | #ifdef INET6 |
1037 | case AF_INET6: |
1038 | maxpacketsize = IPV6_MAXPACKET; |
1039 | break; |
1040 | #endif /* INET6 */ |
1041 | default: |
1042 | DPRINTF(("ah_output: unknown/unsupported protocol " |
1043 | "family %u, SA %s/%08lx\n" , |
1044 | sav->sah->saidx.dst.sa.sa_family, |
1045 | ipsec_address(&sav->sah->saidx.dst), |
1046 | (u_long) ntohl(sav->spi))); |
1047 | AH_STATINC(AH_STAT_NOPF); |
1048 | error = EPFNOSUPPORT; |
1049 | goto bad; |
1050 | } |
1051 | authsize = AUTHSIZE(sav); |
1052 | if (rplen + authsize + m->m_pkthdr.len > maxpacketsize) { |
1053 | DPRINTF(("ah_output: packet in SA %s/%08lx got too big " |
1054 | "(len %u, max len %u)\n" , |
1055 | ipsec_address(&sav->sah->saidx.dst), |
1056 | (u_long) ntohl(sav->spi), |
1057 | rplen + authsize + m->m_pkthdr.len, maxpacketsize)); |
1058 | AH_STATINC(AH_STAT_TOOBIG); |
1059 | error = EMSGSIZE; |
1060 | goto bad; |
1061 | } |
1062 | |
1063 | /* Update the counters. */ |
1064 | AH_STATADD(AH_STAT_OBYTES, m->m_pkthdr.len - skip); |
1065 | |
1066 | m = m_clone(m); |
1067 | if (m == NULL) { |
1068 | DPRINTF(("ah_output: cannot clone mbuf chain, SA %s/%08lx\n" , |
1069 | ipsec_address(&sav->sah->saidx.dst), |
1070 | (u_long) ntohl(sav->spi))); |
1071 | AH_STATINC(AH_STAT_HDROPS); |
1072 | error = ENOBUFS; |
1073 | goto bad; |
1074 | } |
1075 | |
1076 | /* Inject AH header. */ |
1077 | mi = m_makespace(m, skip, rplen + authsize, &roff); |
1078 | if (mi == NULL) { |
1079 | DPRINTF(("ah_output: failed to inject %u byte AH header for SA " |
1080 | "%s/%08lx\n" , |
1081 | rplen + authsize, |
1082 | ipsec_address(&sav->sah->saidx.dst), |
1083 | (u_long) ntohl(sav->spi))); |
1084 | AH_STATINC(AH_STAT_HDROPS); /*XXX differs from openbsd */ |
1085 | error = ENOBUFS; |
1086 | goto bad; |
1087 | } |
1088 | |
1089 | /* |
1090 | * The AH header is guaranteed by m_makespace() to be in |
1091 | * contiguous memory, at roff bytes offset into the returned mbuf. |
1092 | */ |
1093 | ah = (struct newah *)(mtod(mi, char *) + roff); |
1094 | |
1095 | /* Initialize the AH header. */ |
1096 | m_copydata(m, protoff, sizeof(u_int8_t), &ah->ah_nxt); |
1097 | ah->ah_len = (rplen + authsize - sizeof(struct ah)) / sizeof(u_int32_t); |
1098 | ah->ah_reserve = 0; |
1099 | ah->ah_spi = sav->spi; |
1100 | |
1101 | /* Zeroize authenticator. */ |
1102 | m_copyback(m, skip + rplen, authsize, ipseczeroes); |
1103 | |
1104 | /* Insert packet replay counter, as requested. */ |
1105 | if (sav->replay) { |
1106 | if (sav->replay->count == ~0 && |
1107 | (sav->flags & SADB_X_EXT_CYCSEQ) == 0) { |
1108 | DPRINTF(("ah_output: replay counter wrapped for SA " |
1109 | "%s/%08lx\n" , |
1110 | ipsec_address(&sav->sah->saidx.dst), |
1111 | (u_long) ntohl(sav->spi))); |
1112 | AH_STATINC(AH_STAT_WRAP); |
1113 | error = EINVAL; |
1114 | goto bad; |
1115 | } |
1116 | #ifdef IPSEC_DEBUG |
1117 | /* Emulate replay attack when ipsec_replay is TRUE. */ |
1118 | if (!ipsec_replay) |
1119 | #endif |
1120 | sav->replay->count++; |
1121 | ah->ah_seq = htonl(sav->replay->count); |
1122 | } |
1123 | |
1124 | /* Get crypto descriptors. */ |
1125 | crp = crypto_getreq(1); |
1126 | if (crp == NULL) { |
1127 | DPRINTF(("ah_output: failed to acquire crypto descriptors\n" )); |
1128 | AH_STATINC(AH_STAT_CRYPTO); |
1129 | error = ENOBUFS; |
1130 | goto bad; |
1131 | } |
1132 | |
1133 | crda = crp->crp_desc; |
1134 | |
1135 | crda->crd_skip = 0; |
1136 | crda->crd_inject = skip + rplen; |
1137 | crda->crd_len = m->m_pkthdr.len; |
1138 | |
1139 | /* Authentication operation. */ |
1140 | crda->crd_alg = ahx->type; |
1141 | crda->crd_key = _KEYBUF(sav->key_auth); |
1142 | crda->crd_klen = _KEYBITS(sav->key_auth); |
1143 | |
1144 | /* Allocate IPsec-specific opaque crypto info. */ |
1145 | tc = (struct tdb_crypto *) malloc( |
1146 | sizeof(struct tdb_crypto) + skip, M_XDATA, M_NOWAIT|M_ZERO); |
1147 | if (tc == NULL) { |
1148 | crypto_freereq(crp); |
1149 | DPRINTF(("ah_output: failed to allocate tdb_crypto\n" )); |
1150 | AH_STATINC(AH_STAT_CRYPTO); |
1151 | error = ENOBUFS; |
1152 | goto bad; |
1153 | } |
1154 | |
1155 | /* Save the skipped portion of the packet. */ |
1156 | m_copydata(m, 0, skip, (tc + 1)); |
1157 | |
1158 | /* |
1159 | * Fix IP header length on the header used for |
1160 | * authentication. We don't need to fix the original |
1161 | * header length as it will be fixed by our caller. |
1162 | */ |
1163 | switch (sav->sah->saidx.dst.sa.sa_family) { |
1164 | #ifdef INET |
1165 | case AF_INET: |
1166 | bcopy(((char *)(tc + 1)) + |
1167 | offsetof(struct ip, ip_len), |
1168 | &iplen, sizeof(u_int16_t)); |
1169 | iplen = htons(ntohs(iplen) + rplen + authsize); |
1170 | m_copyback(m, offsetof(struct ip, ip_len), |
1171 | sizeof(u_int16_t), &iplen); |
1172 | break; |
1173 | #endif /* INET */ |
1174 | |
1175 | #ifdef INET6 |
1176 | case AF_INET6: |
1177 | bcopy(((char *)(tc + 1)) + |
1178 | offsetof(struct ip6_hdr, ip6_plen), |
1179 | &iplen, sizeof(u_int16_t)); |
1180 | iplen = htons(ntohs(iplen) + rplen + authsize); |
1181 | m_copyback(m, offsetof(struct ip6_hdr, ip6_plen), |
1182 | sizeof(u_int16_t), &iplen); |
1183 | break; |
1184 | #endif /* INET6 */ |
1185 | } |
1186 | |
1187 | /* Fix the Next Header field in saved header. */ |
1188 | ((u_int8_t *) (tc + 1))[protoff] = IPPROTO_AH; |
1189 | |
1190 | /* Update the Next Protocol field in the IP header. */ |
1191 | prot = IPPROTO_AH; |
1192 | m_copyback(m, protoff, sizeof(u_int8_t), &prot); |
1193 | |
1194 | /* "Massage" the packet headers for crypto processing. */ |
1195 | error = ah_massage_headers(&m, sav->sah->saidx.dst.sa.sa_family, |
1196 | skip, ahx->type, 1); |
1197 | if (error != 0) { |
1198 | m = NULL; /* mbuf was free'd by ah_massage_headers. */ |
1199 | free(tc, M_XDATA); |
1200 | crypto_freereq(crp); |
1201 | goto bad; |
1202 | } |
1203 | |
1204 | /* Crypto operation descriptor. */ |
1205 | crp->crp_ilen = m->m_pkthdr.len; /* Total input length. */ |
1206 | crp->crp_flags = CRYPTO_F_IMBUF; |
1207 | crp->crp_buf = m; |
1208 | crp->crp_callback = ah_output_cb; |
1209 | crp->crp_sid = sav->tdb_cryptoid; |
1210 | crp->crp_opaque = tc; |
1211 | |
1212 | /* These are passed as-is to the callback. */ |
1213 | tc->tc_isr = isr; |
1214 | tc->tc_spi = sav->spi; |
1215 | tc->tc_dst = sav->sah->saidx.dst; |
1216 | tc->tc_proto = sav->sah->saidx.proto; |
1217 | tc->tc_skip = skip; |
1218 | tc->tc_protoff = protoff; |
1219 | |
1220 | return crypto_dispatch(crp); |
1221 | bad: |
1222 | if (m) |
1223 | m_freem(m); |
1224 | return (error); |
1225 | } |
1226 | |
1227 | /* |
1228 | * AH output callback from the crypto driver. |
1229 | */ |
1230 | static int |
1231 | ah_output_cb(struct cryptop *crp) |
1232 | { |
1233 | int skip, error; |
1234 | struct tdb_crypto *tc; |
1235 | struct ipsecrequest *isr; |
1236 | struct secasvar *sav; |
1237 | struct mbuf *m; |
1238 | void *ptr; |
1239 | int s, err; |
1240 | |
1241 | tc = (struct tdb_crypto *) crp->crp_opaque; |
1242 | IPSEC_ASSERT(tc != NULL, ("ah_output_cb: null opaque data area!" )); |
1243 | skip = tc->tc_skip; |
1244 | ptr = (tc + 1); |
1245 | m = (struct mbuf *) crp->crp_buf; |
1246 | |
1247 | s = splsoftnet(); |
1248 | mutex_enter(softnet_lock); |
1249 | |
1250 | isr = tc->tc_isr; |
1251 | sav = KEY_ALLOCSA(&tc->tc_dst, tc->tc_proto, tc->tc_spi, 0, 0); |
1252 | if (sav == NULL) { |
1253 | AH_STATINC(AH_STAT_NOTDB); |
1254 | DPRINTF(("ah_output_cb: SA expired while in crypto\n" )); |
1255 | error = ENOBUFS; /*XXX*/ |
1256 | goto bad; |
1257 | } |
1258 | IPSEC_ASSERT(isr->sav == sav, ("ah_output_cb: SA changed\n" )); |
1259 | |
1260 | /* Check for crypto errors. */ |
1261 | if (crp->crp_etype) { |
1262 | if (sav->tdb_cryptoid != 0) |
1263 | sav->tdb_cryptoid = crp->crp_sid; |
1264 | |
1265 | if (crp->crp_etype == EAGAIN) { |
1266 | KEY_FREESAV(&sav); |
1267 | mutex_exit(softnet_lock); |
1268 | splx(s); |
1269 | return crypto_dispatch(crp); |
1270 | } |
1271 | |
1272 | AH_STATINC(AH_STAT_NOXFORM); |
1273 | DPRINTF(("ah_output_cb: crypto error %d\n" , crp->crp_etype)); |
1274 | error = crp->crp_etype; |
1275 | goto bad; |
1276 | } |
1277 | |
1278 | /* Shouldn't happen... */ |
1279 | if (m == NULL) { |
1280 | AH_STATINC(AH_STAT_CRYPTO); |
1281 | DPRINTF(("ah_output_cb: bogus returned buffer from crypto\n" )); |
1282 | error = EINVAL; |
1283 | goto bad; |
1284 | } |
1285 | AH_STATINC(AH_STAT_HIST + sav->alg_auth); |
1286 | |
1287 | /* |
1288 | * Copy original headers (with the new protocol number) back |
1289 | * in place. |
1290 | */ |
1291 | m_copyback(m, 0, skip, ptr); |
1292 | |
1293 | /* No longer needed. */ |
1294 | free(tc, M_XDATA); |
1295 | crypto_freereq(crp); |
1296 | |
1297 | #ifdef IPSEC_DEBUG |
1298 | /* Emulate man-in-the-middle attack when ipsec_integrity is TRUE. */ |
1299 | if (ipsec_integrity) { |
1300 | int alen; |
1301 | |
1302 | /* |
1303 | * Corrupt HMAC if we want to test integrity verification of |
1304 | * the other side. |
1305 | */ |
1306 | alen = AUTHSIZE(sav); |
1307 | m_copyback(m, m->m_pkthdr.len - alen, alen, ipseczeroes); |
1308 | } |
1309 | #endif |
1310 | |
1311 | /* NB: m is reclaimed by ipsec_process_done. */ |
1312 | err = ipsec_process_done(m, isr); |
1313 | KEY_FREESAV(&sav); |
1314 | mutex_exit(softnet_lock); |
1315 | splx(s); |
1316 | return err; |
1317 | bad: |
1318 | if (sav) |
1319 | KEY_FREESAV(&sav); |
1320 | mutex_exit(softnet_lock); |
1321 | splx(s); |
1322 | if (m) |
1323 | m_freem(m); |
1324 | free(tc, M_XDATA); |
1325 | crypto_freereq(crp); |
1326 | return error; |
1327 | } |
1328 | |
1329 | static struct xformsw ah_xformsw = { |
1330 | XF_AH, XFT_AUTH, "IPsec AH" , |
1331 | ah_init, ah_zeroize, ah_input, ah_output, |
1332 | NULL, |
1333 | }; |
1334 | |
1335 | INITFN void |
1336 | ah_attach(void) |
1337 | { |
1338 | ahstat_percpu = percpu_alloc(sizeof(uint64_t) * AH_NSTATS); |
1339 | xform_register(&ah_xformsw); |
1340 | } |
1341 | |
1342 | #ifdef __FreeBSD__ |
1343 | SYSINIT(ah_xform_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_MIDDLE, ah_attach, NULL); |
1344 | #endif |
1345 | |