File: | netinet/ip_ah.c |
Warning: | line 654, column 9 1st function call argument is an uninitialized value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: ip_ah.c,v 1.173 2021/12/23 22:35:11 bluhm 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 | #include <netinet/ip_var.h> | |||
53 | ||||
54 | #ifdef INET61 | |||
55 | #include <netinet/ip6.h> | |||
56 | #endif /* INET6 */ | |||
57 | ||||
58 | #include <netinet/ip_ipsp.h> | |||
59 | #include <netinet/ip_ah.h> | |||
60 | #include <net/pfkeyv2.h> | |||
61 | #include <net/if_enc.h> | |||
62 | ||||
63 | #if NPFSYNC1 > 0 | |||
64 | #include <net/pfvar.h> | |||
65 | #include <net/if_pfsync.h> | |||
66 | #endif /* NPFSYNC > 0 */ | |||
67 | ||||
68 | #include <crypto/cryptodev.h> | |||
69 | #include <crypto/xform.h> | |||
70 | ||||
71 | #include "bpfilter.h" | |||
72 | ||||
73 | #ifdef ENCDEBUG | |||
74 | #define DPRINTF(fmt, args...)do { } while (0) \ | |||
75 | do { \ | |||
76 | if (encdebug) \ | |||
77 | printf("%s: " fmt "\n", __func__, ## args); \ | |||
78 | } while (0) | |||
79 | #else | |||
80 | #define DPRINTF(fmt, args...)do { } while (0) \ | |||
81 | do { } while (0) | |||
82 | #endif | |||
83 | ||||
84 | int ah_massage_headers(struct mbuf **, int, int, int, int); | |||
85 | ||||
86 | const unsigned char ipseczeroes[IPSEC_ZEROES_SIZE256]; /* zeroes! */ | |||
87 | ||||
88 | ||||
89 | /* | |||
90 | * ah_attach() is called from the transformation initialization code. | |||
91 | */ | |||
92 | int | |||
93 | ah_attach(void) | |||
94 | { | |||
95 | return 0; | |||
96 | } | |||
97 | ||||
98 | /* | |||
99 | * ah_init() is called when an SPI is being set up. | |||
100 | */ | |||
101 | int | |||
102 | ah_init(struct tdb *tdbp, const struct xformsw *xsp, struct ipsecinit *ii) | |||
103 | { | |||
104 | const struct auth_hash *thash = NULL((void *)0); | |||
105 | struct cryptoini cria, crin; | |||
106 | int error; | |||
107 | ||||
108 | /* Authentication operation. */ | |||
109 | switch (ii->ii_authalg) { | |||
110 | case SADB_AALG_MD5HMAC2: | |||
111 | thash = &auth_hash_hmac_md5_96; | |||
112 | break; | |||
113 | ||||
114 | case SADB_AALG_SHA1HMAC3: | |||
115 | thash = &auth_hash_hmac_sha1_96; | |||
116 | break; | |||
117 | ||||
118 | case SADB_X_AALG_RIPEMD160HMAC8: | |||
119 | thash = &auth_hash_hmac_ripemd_160_96; | |||
120 | break; | |||
121 | ||||
122 | case SADB_X_AALG_SHA2_2565: | |||
123 | thash = &auth_hash_hmac_sha2_256_128; | |||
124 | break; | |||
125 | ||||
126 | case SADB_X_AALG_SHA2_3846: | |||
127 | thash = &auth_hash_hmac_sha2_384_192; | |||
128 | break; | |||
129 | ||||
130 | case SADB_X_AALG_SHA2_5127: | |||
131 | thash = &auth_hash_hmac_sha2_512_256; | |||
132 | break; | |||
133 | ||||
134 | default: | |||
135 | DPRINTF("unsupported authentication algorithm %d specified",do { } while (0) | |||
136 | ii->ii_authalg)do { } while (0); | |||
137 | return EINVAL22; | |||
138 | } | |||
139 | ||||
140 | if (ii->ii_authkeylen != thash->keysize && thash->keysize != 0) { | |||
141 | DPRINTF("keylength %d doesn't match algorithm %s keysize (%d)",do { } while (0) | |||
142 | ii->ii_authkeylen, thash->name, thash->keysize)do { } while (0); | |||
143 | return EINVAL22; | |||
144 | } | |||
145 | ||||
146 | tdbp->tdb_xform = xsp; | |||
147 | tdbp->tdb_authalgxform = thash; | |||
148 | tdbp->tdb_rpl = AH_HMAC_INITIAL_RPL1; | |||
149 | ||||
150 | DPRINTF("initialized TDB with hash algorithm %s", thash->name)do { } while (0); | |||
151 | ||||
152 | tdbp->tdb_amxkeylen = ii->ii_authkeylen; | |||
153 | tdbp->tdb_amxkey = malloc(tdbp->tdb_amxkeylen, M_XDATA76, M_WAITOK0x0001); | |||
154 | ||||
155 | memcpy(tdbp->tdb_amxkey, ii->ii_authkey, tdbp->tdb_amxkeylen)__builtin_memcpy((tdbp->tdb_amxkey), (ii->ii_authkey), ( tdbp->tdb_amxkeylen)); | |||
156 | ||||
157 | /* Initialize crypto session. */ | |||
158 | memset(&cria, 0, sizeof(cria))__builtin_memset((&cria), (0), (sizeof(cria))); | |||
159 | cria.cri_alg = tdbp->tdb_authalgxform->type; | |||
160 | cria.cri_klen = ii->ii_authkeylen * 8; | |||
161 | cria.cri_key = ii->ii_authkey; | |||
162 | ||||
163 | if ((tdbp->tdb_wnd > 0) && (tdbp->tdb_flags & TDBF_ESN0x100000)) { | |||
164 | memset(&crin, 0, sizeof(crin))__builtin_memset((&crin), (0), (sizeof(crin))); | |||
165 | crin.cri_alg = CRYPTO_ESN23; | |||
166 | cria.cri_next = &crin; | |||
167 | } | |||
168 | ||||
169 | KERNEL_LOCK()_kernel_lock(); | |||
170 | error = crypto_newsession(&tdbp->tdb_cryptoid, &cria, 0); | |||
171 | KERNEL_UNLOCK()_kernel_unlock(); | |||
172 | return error; | |||
173 | } | |||
174 | ||||
175 | /* | |||
176 | * Paranoia. | |||
177 | */ | |||
178 | int | |||
179 | ah_zeroize(struct tdb *tdbp) | |||
180 | { | |||
181 | int error; | |||
182 | ||||
183 | if (tdbp->tdb_amxkey) { | |||
184 | explicit_bzero(tdbp->tdb_amxkey, tdbp->tdb_amxkeylen); | |||
185 | free(tdbp->tdb_amxkey, M_XDATA76, tdbp->tdb_amxkeylen); | |||
186 | tdbp->tdb_amxkey = NULL((void *)0); | |||
187 | } | |||
188 | ||||
189 | KERNEL_LOCK()_kernel_lock(); | |||
190 | error = crypto_freesession(tdbp->tdb_cryptoid); | |||
191 | KERNEL_UNLOCK()_kernel_unlock(); | |||
192 | tdbp->tdb_cryptoid = 0; | |||
193 | return error; | |||
194 | } | |||
195 | ||||
196 | /* | |||
197 | * Massage IPv4/IPv6 headers for AH processing. | |||
198 | */ | |||
199 | int | |||
200 | ah_massage_headers(struct mbuf **mp, int af, int skip, int alg, int out) | |||
201 | { | |||
202 | struct mbuf *m = *mp; | |||
203 | unsigned char *ptr; | |||
204 | int off, count, error; | |||
205 | struct ip *ip; | |||
206 | #ifdef INET61 | |||
207 | struct ip6_ext *ip6e; | |||
208 | struct ip6_hdr ip6; | |||
209 | int ad, alloc, nxt, noff; | |||
210 | #endif /* INET6 */ | |||
211 | ||||
212 | switch (af) { | |||
213 | case AF_INET2: | |||
214 | /* | |||
215 | * This is the least painful way of dealing with IPv4 header | |||
216 | * and option processing -- just make sure they're in | |||
217 | * contiguous memory. | |||
218 | */ | |||
219 | m = *mp = m_pullup(m, skip); | |||
220 | if (m == NULL((void *)0)) { | |||
221 | DPRINTF("m_pullup() failed")do { } while (0); | |||
222 | ahstat_inc(ahs_hdrops); | |||
223 | error = ENOBUFS55; | |||
224 | goto drop; | |||
225 | } | |||
226 | ||||
227 | /* Fix the IP header */ | |||
228 | ip = mtod(m, struct ip *)((struct ip *)((m)->m_hdr.mh_data)); | |||
229 | ip->ip_tos = 0; | |||
230 | ip->ip_ttl = 0; | |||
231 | ip->ip_sum = 0; | |||
232 | ip->ip_off = 0; | |||
233 | ||||
234 | ptr = mtod(m, unsigned char *)((unsigned char *)((m)->m_hdr.mh_data)); | |||
235 | ||||
236 | /* IPv4 option processing */ | |||
237 | for (off = sizeof(struct ip); off < skip;) { | |||
238 | if (ptr[off] != IPOPT_EOL0 && ptr[off] != IPOPT_NOP1 && | |||
239 | off + 1 >= skip) { | |||
240 | DPRINTF("illegal IPv4 option length "do { } while (0) | |||
241 | "for option %d",do { } while (0) | |||
242 | ptr[off])do { } while (0); | |||
243 | ahstat_inc(ahs_hdrops); | |||
244 | error = EINVAL22; | |||
245 | goto drop; | |||
246 | } | |||
247 | ||||
248 | switch (ptr[off]) { | |||
249 | case IPOPT_EOL0: | |||
250 | off = skip; /* End the loop. */ | |||
251 | break; | |||
252 | ||||
253 | case IPOPT_NOP1: | |||
254 | off++; | |||
255 | break; | |||
256 | ||||
257 | case IPOPT_SECURITY130: /* 0x82 */ | |||
258 | case 0x85: /* Extended security. */ | |||
259 | case 0x86: /* Commercial security. */ | |||
260 | case 0x94: /* Router alert */ | |||
261 | case 0x95: /* RFC1770 */ | |||
262 | /* Sanity check for option length. */ | |||
263 | if (ptr[off + 1] < 2) { | |||
264 | DPRINTF("illegal IPv4 option length "do { } while (0) | |||
265 | "for option %d",do { } while (0) | |||
266 | ptr[off])do { } while (0); | |||
267 | ahstat_inc(ahs_hdrops); | |||
268 | error = EINVAL22; | |||
269 | goto drop; | |||
270 | } | |||
271 | ||||
272 | off += ptr[off + 1]; | |||
273 | break; | |||
274 | ||||
275 | case IPOPT_LSRR131: | |||
276 | case IPOPT_SSRR137: | |||
277 | /* Sanity check for option length. */ | |||
278 | if (ptr[off + 1] < 2) { | |||
279 | DPRINTF("illegal IPv4 option length "do { } while (0) | |||
280 | "for option %d",do { } while (0) | |||
281 | ptr[off])do { } while (0); | |||
282 | ahstat_inc(ahs_hdrops); | |||
283 | error = EINVAL22; | |||
284 | goto drop; | |||
285 | } | |||
286 | ||||
287 | /* | |||
288 | * On output, if we have either of the | |||
289 | * source routing options, we should | |||
290 | * swap the destination address of the | |||
291 | * IP header with the last address | |||
292 | * specified in the option, as that is | |||
293 | * what the destination's IP header | |||
294 | * will look like. | |||
295 | */ | |||
296 | if (out && | |||
297 | ptr[off + 1] >= 2 + sizeof(struct in_addr)) | |||
298 | memcpy(&ip->ip_dst,__builtin_memcpy((&ip->ip_dst), (ptr + off + ptr[off + 1] - sizeof(struct in_addr)), (sizeof(struct in_addr))) | |||
299 | ptr + off + ptr[off + 1] -__builtin_memcpy((&ip->ip_dst), (ptr + off + ptr[off + 1] - sizeof(struct in_addr)), (sizeof(struct in_addr))) | |||
300 | sizeof(struct in_addr),__builtin_memcpy((&ip->ip_dst), (ptr + off + ptr[off + 1] - sizeof(struct in_addr)), (sizeof(struct in_addr))) | |||
301 | sizeof(struct in_addr))__builtin_memcpy((&ip->ip_dst), (ptr + off + ptr[off + 1] - sizeof(struct in_addr)), (sizeof(struct in_addr))); | |||
302 | ||||
303 | /* FALLTHROUGH */ | |||
304 | default: | |||
305 | /* Sanity check for option length. */ | |||
306 | if (ptr[off + 1] < 2) { | |||
307 | DPRINTF("illegal IPv4 option length "do { } while (0) | |||
308 | "for option %d",do { } while (0) | |||
309 | ptr[off])do { } while (0); | |||
310 | ahstat_inc(ahs_hdrops); | |||
311 | error = EINVAL22; | |||
312 | goto drop; | |||
313 | } | |||
314 | ||||
315 | /* Zeroize all other options. */ | |||
316 | count = ptr[off + 1]; | |||
317 | memset(ptr + off, 0, count)__builtin_memset((ptr + off), (0), (count)); | |||
318 | off += count; | |||
319 | break; | |||
320 | } | |||
321 | ||||
322 | /* Sanity check. */ | |||
323 | if (off > skip) { | |||
324 | DPRINTF("malformed IPv4 options header")do { } while (0); | |||
325 | ahstat_inc(ahs_hdrops); | |||
326 | error = EINVAL22; | |||
327 | goto drop; | |||
328 | } | |||
329 | } | |||
330 | ||||
331 | break; | |||
332 | ||||
333 | #ifdef INET61 | |||
334 | case AF_INET624: /* Ugly... */ | |||
335 | /* Copy and "cook" the IPv6 header. */ | |||
336 | m_copydata(m, 0, sizeof(ip6), &ip6); | |||
337 | ||||
338 | /* We don't do IPv6 Jumbograms. */ | |||
339 | if (ip6.ip6_plenip6_ctlun.ip6_un1.ip6_un1_plen == 0) { | |||
340 | DPRINTF("unsupported IPv6 jumbogram")do { } while (0); | |||
341 | ahstat_inc(ahs_hdrops); | |||
342 | error = EMSGSIZE40; | |||
343 | goto drop; | |||
344 | } | |||
345 | ||||
346 | ip6.ip6_flowip6_ctlun.ip6_un1.ip6_un1_flow = 0; | |||
347 | ip6.ip6_hlimip6_ctlun.ip6_un1.ip6_un1_hlim = 0; | |||
348 | ip6.ip6_vfcip6_ctlun.ip6_un2_vfc &= ~IPV6_VERSION_MASK0xf0; | |||
349 | ip6.ip6_vfcip6_ctlun.ip6_un2_vfc |= IPV6_VERSION0x60; | |||
350 | ||||
351 | /* Scoped address handling. */ | |||
352 | if (IN6_IS_SCOPE_EMBED(&ip6.ip6_src)(((((&ip6.ip6_src)->__u6_addr.__u6_addr8[0] == 0xfe) && (((&ip6.ip6_src)->__u6_addr.__u6_addr8[1] & 0xc0) == 0x80))) || ((((&ip6.ip6_src)->__u6_addr.__u6_addr8 [0] == 0xff) && (((&ip6.ip6_src)->__u6_addr.__u6_addr8 [1] & 0x0f) == 0x02))) || ((((&ip6.ip6_src)->__u6_addr .__u6_addr8[0] == 0xff) && (((&ip6.ip6_src)->__u6_addr .__u6_addr8[1] & 0x0f) == 0x01))))) | |||
353 | ip6.ip6_src.s6_addr16__u6_addr.__u6_addr16[1] = 0; | |||
354 | if (IN6_IS_SCOPE_EMBED(&ip6.ip6_dst)(((((&ip6.ip6_dst)->__u6_addr.__u6_addr8[0] == 0xfe) && (((&ip6.ip6_dst)->__u6_addr.__u6_addr8[1] & 0xc0) == 0x80))) || ((((&ip6.ip6_dst)->__u6_addr.__u6_addr8 [0] == 0xff) && (((&ip6.ip6_dst)->__u6_addr.__u6_addr8 [1] & 0x0f) == 0x02))) || ((((&ip6.ip6_dst)->__u6_addr .__u6_addr8[0] == 0xff) && (((&ip6.ip6_dst)->__u6_addr .__u6_addr8[1] & 0x0f) == 0x01))))) | |||
355 | ip6.ip6_dst.s6_addr16__u6_addr.__u6_addr16[1] = 0; | |||
356 | ||||
357 | /* Done with IPv6 header. */ | |||
358 | error = m_copyback(m, 0, sizeof(struct ip6_hdr), &ip6, | |||
359 | M_NOWAIT0x0002); | |||
360 | if (error) { | |||
361 | DPRINTF("m_copyback no memory")do { } while (0); | |||
362 | ahstat_inc(ahs_hdrops); | |||
363 | goto drop; | |||
364 | } | |||
365 | ||||
366 | /* Let's deal with the remaining headers (if any). */ | |||
367 | if (skip - sizeof(struct ip6_hdr) > 0) { | |||
368 | if (m->m_lenm_hdr.mh_len <= skip) { | |||
369 | ptr = malloc(skip - sizeof(struct ip6_hdr), | |||
370 | M_XDATA76, M_NOWAIT0x0002); | |||
371 | if (ptr == NULL((void *)0)) { | |||
372 | DPRINTF("failed to allocate "do { } while (0) | |||
373 | "memory for IPv6 headers")do { } while (0); | |||
374 | ahstat_inc(ahs_hdrops); | |||
375 | error = ENOBUFS55; | |||
376 | goto drop; | |||
377 | } | |||
378 | ||||
379 | /* | |||
380 | * Copy all the protocol headers after | |||
381 | * the IPv6 header. | |||
382 | */ | |||
383 | m_copydata(m, sizeof(struct ip6_hdr), | |||
384 | skip - sizeof(struct ip6_hdr), ptr); | |||
385 | alloc = 1; | |||
386 | } else { | |||
387 | /* No need to allocate memory. */ | |||
388 | ptr = mtod(m, unsigned char *)((unsigned char *)((m)->m_hdr.mh_data)) + | |||
389 | sizeof(struct ip6_hdr); | |||
390 | alloc = 0; | |||
391 | } | |||
392 | } else | |||
393 | break; | |||
394 | ||||
395 | nxt = ip6.ip6_nxtip6_ctlun.ip6_un1.ip6_un1_nxt; /* Next header type. */ | |||
396 | ||||
397 | for (off = 0; off < skip - sizeof(struct ip6_hdr);) { | |||
398 | if (off + sizeof(struct ip6_ext) > | |||
399 | skip - sizeof(struct ip6_hdr)) | |||
400 | goto error6; | |||
401 | ip6e = (struct ip6_ext *)(ptr + off); | |||
402 | ||||
403 | switch (nxt) { | |||
404 | case IPPROTO_HOPOPTS0: | |||
405 | case IPPROTO_DSTOPTS60: | |||
406 | noff = off + ((ip6e->ip6e_len + 1) << 3); | |||
407 | ||||
408 | /* Sanity check. */ | |||
409 | if (noff > skip - sizeof(struct ip6_hdr)) | |||
410 | goto error6; | |||
411 | ||||
412 | /* | |||
413 | * Zero out mutable options. | |||
414 | */ | |||
415 | for (count = off + sizeof(struct ip6_ext); | |||
416 | count < noff;) { | |||
417 | if (ptr[count] == IP6OPT_PAD10x00) { | |||
418 | count++; | |||
419 | continue; /* Skip padding. */ | |||
420 | } | |||
421 | ||||
422 | if (count + 2 > noff) | |||
423 | goto error6; | |||
424 | ad = ptr[count + 1] + 2; | |||
425 | if (count + ad > noff) | |||
426 | goto error6; | |||
427 | ||||
428 | /* If mutable option, zeroize. */ | |||
429 | if (ptr[count] & IP6OPT_MUTABLE0x20) | |||
430 | memset(ptr + count, 0, ad)__builtin_memset((ptr + count), (0), (ad)); | |||
431 | ||||
432 | count += ad; | |||
433 | } | |||
434 | ||||
435 | if (count != noff) | |||
436 | goto error6; | |||
437 | break; | |||
438 | ||||
439 | case IPPROTO_ROUTING43: | |||
440 | /* | |||
441 | * Always include routing headers in | |||
442 | * computation. | |||
443 | */ | |||
444 | { | |||
445 | struct ip6_rthdr *rh; | |||
446 | ||||
447 | rh = (struct ip6_rthdr *)(ptr + off); | |||
448 | /* | |||
449 | * must adjust content to make it look like | |||
450 | * its final form (as seen at the final | |||
451 | * destination). | |||
452 | * we only know how to massage type 0 routing | |||
453 | * header. | |||
454 | */ | |||
455 | if (out && rh->ip6r_type == IPV6_RTHDR_TYPE_00) { | |||
456 | struct ip6_rthdr0 *rh0; | |||
457 | struct in6_addr *addr, finaldst; | |||
458 | int i; | |||
459 | ||||
460 | rh0 = (struct ip6_rthdr0 *)rh; | |||
461 | addr = (struct in6_addr *)(rh0 + 1); | |||
462 | ||||
463 | for (i = 0; i < rh0->ip6r0_segleft; i++) | |||
464 | if (IN6_IS_SCOPE_EMBED(&addr[i])(((((&addr[i])->__u6_addr.__u6_addr8[0] == 0xfe) && (((&addr[i])->__u6_addr.__u6_addr8[1] & 0xc0) == 0x80 ))) || ((((&addr[i])->__u6_addr.__u6_addr8[0] == 0xff) && (((&addr[i])->__u6_addr.__u6_addr8[1] & 0x0f) == 0x02))) || ((((&addr[i])->__u6_addr.__u6_addr8 [0] == 0xff) && (((&addr[i])->__u6_addr.__u6_addr8 [1] & 0x0f) == 0x01))))) | |||
465 | addr[i].s6_addr16__u6_addr.__u6_addr16[1] = 0; | |||
466 | ||||
467 | finaldst = addr[rh0->ip6r0_segleft - 1]; | |||
468 | memmove(&addr[1], &addr[0],__builtin_memmove((&addr[1]), (&addr[0]), (sizeof(struct in6_addr) * (rh0->ip6r0_segleft - 1))) | |||
469 | sizeof(struct in6_addr) *__builtin_memmove((&addr[1]), (&addr[0]), (sizeof(struct in6_addr) * (rh0->ip6r0_segleft - 1))) | |||
470 | (rh0->ip6r0_segleft - 1))__builtin_memmove((&addr[1]), (&addr[0]), (sizeof(struct in6_addr) * (rh0->ip6r0_segleft - 1))); | |||
471 | ||||
472 | m_copydata(m, 0, sizeof(ip6), &ip6); | |||
473 | addr[0] = ip6.ip6_dst; | |||
474 | ip6.ip6_dst = finaldst; | |||
475 | error = m_copyback(m, 0, sizeof(ip6), | |||
476 | &ip6, M_NOWAIT0x0002); | |||
477 | if (error) { | |||
478 | if (alloc) | |||
479 | free(ptr, M_XDATA76, 0); | |||
480 | ahstat_inc(ahs_hdrops); | |||
481 | goto drop; | |||
482 | } | |||
483 | rh0->ip6r0_segleft = 0; | |||
484 | } | |||
485 | break; | |||
486 | } | |||
487 | ||||
488 | default: | |||
489 | DPRINTF("unexpected IPv6 header type %d", off)do { } while (0); | |||
490 | error6: | |||
491 | if (alloc) | |||
492 | free(ptr, M_XDATA76, 0); | |||
493 | ahstat_inc(ahs_hdrops); | |||
494 | error = EINVAL22; | |||
495 | goto drop; | |||
496 | } | |||
497 | ||||
498 | /* Advance. */ | |||
499 | off += ((ip6e->ip6e_len + 1) << 3); | |||
500 | nxt = ip6e->ip6e_nxt; | |||
501 | } | |||
502 | ||||
503 | /* Copyback and free, if we allocated. */ | |||
504 | if (alloc) { | |||
505 | error = m_copyback(m, sizeof(struct ip6_hdr), | |||
506 | skip - sizeof(struct ip6_hdr), ptr, M_NOWAIT0x0002); | |||
507 | free(ptr, M_XDATA76, 0); | |||
508 | if (error) { | |||
509 | ahstat_inc(ahs_hdrops); | |||
510 | goto drop; | |||
511 | } | |||
512 | } | |||
513 | ||||
514 | break; | |||
515 | #endif /* INET6 */ | |||
516 | } | |||
517 | ||||
518 | return 0; | |||
519 | ||||
520 | drop: | |||
521 | m_freemp(mp); | |||
522 | return error; | |||
523 | } | |||
524 | ||||
525 | /* | |||
526 | * ah_input() gets called to verify that an input packet | |||
527 | * passes authentication. | |||
528 | */ | |||
529 | int | |||
530 | ah_input(struct mbuf **mp, struct tdb *tdb, int skip, int protoff) | |||
531 | { | |||
532 | const struct auth_hash *ahx = tdb->tdb_authalgxform; | |||
533 | struct mbuf *m = *mp, *m1, *m0; | |||
534 | struct cryptodesc *crda = NULL((void *)0); | |||
535 | struct cryptop *crp = NULL((void *)0); | |||
536 | int roff; | |||
537 | uint32_t btsx, esn; | |||
| ||||
538 | uint8_t *ptr = NULL((void *)0); | |||
539 | uint8_t hl; | |||
540 | int error, rplen; | |||
541 | uint64_t ibytes; | |||
542 | #ifdef ENCDEBUG | |||
543 | char buf[INET6_ADDRSTRLEN46]; | |||
544 | #endif | |||
545 | uint8_t calc[AH_ALEN_MAX64]; | |||
546 | ||||
547 | rplen = AH_FLENGTH8 + sizeof(u_int32_t); | |||
548 | ||||
549 | /* Save the AH header, we use it throughout. */ | |||
550 | m_copydata(m, skip + offsetof(struct ah, ah_hl)__builtin_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)__builtin_offsetof(struct ah, ah_rpl), | |||
555 | sizeof(u_int32_t), &btsx); | |||
556 | btsx = ntohl(btsx)(__uint32_t)(__builtin_constant_p(btsx) ? (__uint32_t)(((__uint32_t )(btsx) & 0xff) << 24 | ((__uint32_t)(btsx) & 0xff00 ) << 8 | ((__uint32_t)(btsx) & 0xff0000) >> 8 | ((__uint32_t)(btsx) & 0xff000000) >> 24) : __swap32md (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",do { } while (0) | |||
563 | ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),do { } while (0) | |||
564 | ntohl(tdb->tdb_spi))do { } while (0); | |||
565 | ahstat_inc(ahs_wrap); | |||
566 | goto drop; | |||
567 | case 2: | |||
568 | DPRINTF("old packet received in SA %s/%08x",do { } while (0) | |||
569 | ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),do { } while (0) | |||
570 | ntohl(tdb->tdb_spi))do { } while (0); | |||
571 | ahstat_inc(ahs_replay); | |||
572 | goto drop; | |||
573 | case 3: | |||
574 | DPRINTF("duplicate packet received in SA %s/%08x",do { } while (0) | |||
575 | ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),do { } while (0) | |||
576 | ntohl(tdb->tdb_spi))do { } while (0); | |||
577 | ahstat_inc(ahs_replay); | |||
578 | goto drop; | |||
579 | default: | |||
580 | DPRINTF("bogus value from checkreplaywindow() "do { } while (0) | |||
581 | "in SA %s/%08x",do { } while (0) | |||
582 | ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),do { } while (0) | |||
583 | ntohl(tdb->tdb_spi))do { } while (0); | |||
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_FLENGTH8) { | |||
591 | DPRINTF("bad authenticator length %ld for packet in SA %s/%08x",do { } while (0) | |||
592 | hl * sizeof(u_int32_t),do { } while (0) | |||
593 | ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),do { } while (0) | |||
594 | ntohl(tdb->tdb_spi))do { } while (0); | |||
595 | ahstat_inc(ahs_badauthl); | |||
596 | goto drop; | |||
597 | } | |||
598 | if (skip + ahx->authsize + rplen > m->m_pkthdrM_dat.MH.MH_pkthdr.len) { | |||
599 | DPRINTF("bad mbuf length %d (expecting %d) for packet "do { } while (0) | |||
600 | "in SA %s/%08x",do { } while (0) | |||
601 | m->m_pkthdr.len, skip + ahx->authsize + rplen,do { } while (0) | |||
602 | ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),do { } while (0) | |||
603 | ntohl(tdb->tdb_spi))do { } while (0); | |||
604 | ahstat_inc(ahs_badauthl); | |||
605 | goto drop; | |||
606 | } | |||
607 | ||||
608 | /* Update the counters. */ | |||
609 | ibytes = (m->m_pkthdrM_dat.MH.MH_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_BYTES0x00004) && | |||
616 | (tdb->tdb_cur_bytes >= tdb->tdb_exp_bytes)) { | |||
617 | ipsecstat_inc(ipsec_exctdb); | |||
618 | pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_HARD3); | |||
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_BYTES0x00100) && | |||
626 | (tdb->tdb_cur_bytes >= tdb->tdb_soft_bytes)) { | |||
627 | tdb->tdb_flags &= ~TDBF_SOFT_BYTES0x00100; /* 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_SOFT4); | |||
631 | } else | |||
632 | mtx_leave(&tdb->tdb_mtx); | |||
633 | ||||
634 | /* Get crypto descriptors. */ | |||
635 | crp = crypto_getreq(1); | |||
636 | if (crp == NULL((void *)0)) { | |||
637 | DPRINTF("failed to acquire crypto descriptors")do { } while (0); | |||
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_pkthdrM_dat.MH.MH_pkthdr.len; | |||
646 | crda->crd_inject = skip + rplen; | |||
647 | ||||
648 | /* Authentication operation. */ | |||
649 | crda->crd_algCRD_INI.cri_alg = ahx->type; | |||
650 | crda->crd_keyCRD_INI.cri_key = tdb->tdb_amxkey; | |||
651 | crda->crd_klenCRD_INI.cri_klen = tdb->tdb_amxkeylen * 8; | |||
652 | ||||
653 | if ((tdb->tdb_wnd > 0) && (tdb->tdb_flags & TDBF_ESN0x100000)) { | |||
654 | esn = htonl(esn)(__uint32_t)(__builtin_constant_p(esn) ? (__uint32_t)(((__uint32_t )(esn) & 0xff) << 24 | ((__uint32_t)(esn) & 0xff00 ) << 8 | ((__uint32_t)(esn) & 0xff0000) >> 8 | ((__uint32_t)(esn) & 0xff000000) >> 24) : __swap32md (esn)); | |||
| ||||
655 | memcpy(crda->crd_esn, &esn, 4)__builtin_memcpy((crda->CRD_INI.u.esn), (&esn), (4)); | |||
656 | crda->crd_flags |= CRD_F_ESN0x20; | |||
657 | } | |||
658 | ||||
659 | /* Allocate IPsec-specific opaque crypto info. */ | |||
660 | ptr = malloc(skip + rplen + ahx->authsize, M_XDATA76, M_NOWAIT0x0002 | M_ZERO0x0008); | |||
661 | if (ptr == NULL((void *)0)) { | |||
662 | DPRINTF("failed to allocate buffer")do { } while (0); | |||
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_NOWAIT0x0002); | |||
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_pkthdrM_dat.MH.MH_pkthdr.len; /* Total input length. */ | |||
686 | crp->crp_flags = CRYPTO_F_IMBUF0x0001 | CRYPTO_F_MPSAFE0x0004; | |||
687 | crp->crp_buf = (caddr_t)m; | |||
688 | crp->crp_sid = tdb->tdb_cryptoid; | |||
689 | ||||
690 | while ((error = crypto_invoke(crp)) == EAGAIN35) { | |||
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)do { } while (0); | |||
697 | ipsecstat_inc(ipsec_noxform); | |||
698 | goto drop; | |||
699 | } | |||
700 | ||||
701 | /* Release the crypto descriptors */ | |||
702 | crypto_freereq(crp); | |||
703 | crp = NULL((void *)0); | |||
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",do { } while (0) | |||
711 | ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),do { } while (0) | |||
712 | ntohl(tdb->tdb_spi))do { } while (0); | |||
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_NOWAIT0x0002); | |||
722 | ||||
723 | free(ptr, M_XDATA76, 0); | |||
724 | ptr = NULL((void *)0); | |||
725 | ||||
726 | /* Replay window checking, if applicable. */ | |||
727 | if (tdb->tdb_wnd > 0) { | |||
728 | m_copydata(m, skip + offsetof(struct ah, ah_rpl)__builtin_offsetof(struct ah, ah_rpl), | |||
729 | sizeof(u_int32_t), &btsx); | |||
730 | btsx = ntohl(btsx)(__uint32_t)(__builtin_constant_p(btsx) ? (__uint32_t)(((__uint32_t )(btsx) & 0xff) << 24 | ((__uint32_t)(btsx) & 0xff00 ) << 8 | ((__uint32_t)(btsx) & 0xff0000) >> 8 | ((__uint32_t)(btsx) & 0xff000000) >> 24) : __swap32md (btsx)); | |||
731 | ||||
732 | switch (checkreplaywindow(tdb, tdb->tdb_rpl, btsx, &esn, 1)) { | |||
733 | case 0: /* All's well. */ | |||
734 | #if NPFSYNC1 > 0 | |||
735 | pfsync_update_tdb(tdb,0); | |||
736 | #endif | |||
737 | break; | |||
738 | case 1: | |||
739 | DPRINTF("replay counter wrapped for SA %s/%08x",do { } while (0) | |||
740 | ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),do { } while (0) | |||
741 | ntohl(tdb->tdb_spi))do { } while (0); | |||
742 | ahstat_inc(ahs_wrap); | |||
743 | goto drop; | |||
744 | case 2: | |||
745 | DPRINTF("old packet received in SA %s/%08x",do { } while (0) | |||
746 | ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),do { } while (0) | |||
747 | ntohl(tdb->tdb_spi))do { } while (0); | |||
748 | ahstat_inc(ahs_replay); | |||
749 | goto drop; | |||
750 | case 3: | |||
751 | DPRINTF("duplicate packet received in SA %s/%08x",do { } while (0) | |||
752 | ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),do { } while (0) | |||
753 | ntohl(tdb->tdb_spi))do { } while (0); | |||
754 | ahstat_inc(ahs_replay); | |||
755 | goto drop; | |||
756 | default: | |||
757 | DPRINTF("bogus value from checkreplaywindow() "do { } while (0) | |||
758 | "in SA %s/%08x",do { } while (0) | |||
759 | ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),do { } while (0) | |||
760 | ntohl(tdb->tdb_spi))do { } while (0); | |||
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((void *)0)) { | |||
769 | DPRINTF("bad mbuf chain for packet in SA %s/%08x",do { } while (0) | |||
770 | ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),do { } while (0) | |||
771 | ntohl(tdb->tdb_spi))do { } while (0); | |||
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_pkthdrM_dat.MH.MH_pkthdr.len -= rplen + ahx->authsize; | |||
789 | } else | |||
790 | if (roff + rplen + ahx->authsize >= m1->m_lenm_hdr.mh_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_lenm_hdr.mh_len) { | |||
801 | adjlen = roff + rplen + ahx->authsize - | |||
802 | m1->m_lenm_hdr.mh_len; | |||
803 | /* Adjust the next mbuf by the remainder. */ | |||
804 | m_adj(m1->m_nextm_hdr.mh_next, adjlen); | |||
805 | ||||
806 | /* | |||
807 | * The second mbuf is guaranteed not | |||
808 | * to have a pkthdr... | |||
809 | */ | |||
810 | m->m_pkthdrM_dat.MH.MH_pkthdr.len -= adjlen; | |||
811 | } | |||
812 | ||||
813 | /* Now, let's unlink the mbuf chain for a second... */ | |||
814 | m0 = m1->m_nextm_hdr.mh_next; | |||
815 | m1->m_nextm_hdr.mh_next = NULL((void *)0); | |||
816 | ||||
817 | /* | |||
818 | * ...and trim the end of the first part of | |||
819 | * the chain...sick | |||
820 | */ | |||
821 | adjlen = m1->m_lenm_hdr.mh_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_pkthdrM_dat.MH.MH_pkthdr.len -= adjlen; | |||
829 | ||||
830 | /* Finally, let's relink. */ | |||
831 | m1->m_nextm_hdr.mh_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 *)((u_char *)((m1)->m_hdr.mh_data)) + roff + rplen + | |||
839 | ahx->authsize, mtod(m1, u_char *)((u_char *)((m1)->m_hdr.mh_data)) + roff, | |||
840 | m1->m_lenm_hdr.mh_len - (roff + rplen + ahx->authsize)); | |||
841 | m1->m_lenm_hdr.mh_len -= rplen + ahx->authsize; | |||
842 | m->m_pkthdrM_dat.MH.MH_pkthdr.len -= rplen + ahx->authsize; | |||
843 | } | |||
844 | ||||
845 | return ipsec_common_input_cb(mp, tdb, skip, protoff); | |||
846 | ||||
847 | drop: | |||
848 | free(ptr, M_XDATA76, 0); | |||
849 | m_freemp(mp); | |||
850 | crypto_freereq(crp); | |||
851 | return IPPROTO_DONE257; | |||
852 | } | |||
853 | ||||
854 | /* | |||
855 | * AH output routine, called by ipsp_process_packet(). | |||
856 | */ | |||
857 | int | |||
858 | ah_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((void *)0); | |||
864 | uint64_t replay64; | |||
865 | uint16_t iplen; | |||
866 | int error, rplen, roff; | |||
867 | uint8_t *ptr = NULL((void *)0); | |||
868 | uint8_t prot; | |||
869 | struct ah *ah; | |||
870 | #if NBPFILTER1 > 0 | |||
871 | struct ifnet *encif; | |||
872 | #ifdef ENCDEBUG | |||
873 | char buf[INET6_ADDRSTRLEN46]; | |||
874 | #endif | |||
875 | ||||
876 | if ((encif = enc_getif(tdb->tdb_rdomain, tdb->tdb_tap)) != NULL((void *)0)) { | |||
877 | encif->if_opacketsif_data.ifi_opackets++; | |||
878 | encif->if_obytesif_data.ifi_obytes += m->m_pkthdrM_dat.MH.MH_pkthdr.len; | |||
879 | ||||
880 | if (encif->if_bpf) { | |||
881 | struct enchdr hdr; | |||
882 | ||||
883 | memset(&hdr, 0, sizeof(hdr))__builtin_memset((&hdr), (0), (sizeof(hdr))); | |||
884 | ||||
885 | hdr.af = tdb->tdb_dst.sa.sa_family; | |||
886 | hdr.spi = tdb->tdb_spi; | |||
887 | hdr.flags |= M_AUTH0x0800; | |||
888 | ||||
889 | bpf_mtap_hdr(encif->if_bpf, (char *)&hdr, | |||
890 | ENC_HDRLEN12, m, BPF_DIRECTION_OUT(1 << 1)); | |||
891 | } | |||
892 | } | |||
893 | #endif | |||
894 | ||||
895 | ahstat_inc(ahs_output); | |||
896 | ||||
897 | /* | |||
898 | * Check for replay counter wrap-around in automatic (not | |||
899 | * manual) keying. | |||
900 | */ | |||
901 | if ((tdb->tdb_rpl == 0) && (tdb->tdb_wnd > 0)) { | |||
902 | DPRINTF("SA %s/%08x should have expired",do { } while (0) | |||
903 | ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),do { } while (0) | |||
904 | ntohl(tdb->tdb_spi))do { } while (0); | |||
905 | ahstat_inc(ahs_wrap); | |||
906 | error = EINVAL22; | |||
907 | goto drop; | |||
908 | } | |||
909 | ||||
910 | rplen = AH_FLENGTH8 + sizeof(u_int32_t); | |||
911 | ||||
912 | switch (tdb->tdb_dst.sa.sa_family) { | |||
913 | case AF_INET2: | |||
914 | /* Check for IP maximum packet size violations. */ | |||
915 | if (rplen + ahx->authsize + m->m_pkthdrM_dat.MH.MH_pkthdr.len > IP_MAXPACKET65535) { | |||
916 | DPRINTF("packet in SA %s/%08x got too big",do { } while (0) | |||
917 | ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),do { } while (0) | |||
918 | ntohl(tdb->tdb_spi))do { } while (0); | |||
919 | ahstat_inc(ahs_toobig); | |||
920 | error = EMSGSIZE40; | |||
921 | goto drop; | |||
922 | } | |||
923 | break; | |||
924 | ||||
925 | #ifdef INET61 | |||
926 | case AF_INET624: | |||
927 | /* Check for IPv6 maximum packet size violations. */ | |||
928 | if (rplen + ahx->authsize + m->m_pkthdrM_dat.MH.MH_pkthdr.len > IPV6_MAXPACKET65535) { | |||
929 | DPRINTF("packet in SA %s/%08x got too big",do { } while (0) | |||
930 | ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),do { } while (0) | |||
931 | ntohl(tdb->tdb_spi))do { } while (0); | |||
932 | ahstat_inc(ahs_toobig); | |||
933 | error = EMSGSIZE40; | |||
934 | goto drop; | |||
935 | } | |||
936 | break; | |||
937 | #endif /* INET6 */ | |||
938 | ||||
939 | default: | |||
940 | DPRINTF("unknown/unsupported protocol family %d, SA %s/%08x",do { } while (0) | |||
941 | tdb->tdb_dst.sa.sa_family,do { } while (0) | |||
942 | ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),do { } while (0) | |||
943 | ntohl(tdb->tdb_spi))do { } while (0); | |||
944 | ahstat_inc(ahs_nopf); | |||
945 | error = EPFNOSUPPORT46; | |||
946 | goto drop; | |||
947 | } | |||
948 | ||||
949 | /* Update the counters. */ | |||
950 | tdb->tdb_cur_bytes += m->m_pkthdrM_dat.MH.MH_pkthdr.len - skip; | |||
951 | ahstat_add(ahs_obytes, m->m_pkthdrM_dat.MH.MH_pkthdr.len - skip); | |||
952 | ||||
953 | /* Hard expiration. */ | |||
954 | if ((tdb->tdb_flags & TDBF_BYTES0x00004) && | |||
955 | (tdb->tdb_cur_bytes >= tdb->tdb_exp_bytes)) { | |||
956 | ipsecstat_inc(ipsec_exctdb); | |||
957 | pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_HARD3); | |||
958 | tdb_delete(tdb); | |||
959 | error = EINVAL22; | |||
960 | goto drop; | |||
961 | } | |||
962 | ||||
963 | /* Notify on expiration. */ | |||
964 | mtx_enter(&tdb->tdb_mtx); | |||
965 | if ((tdb->tdb_flags & TDBF_SOFT_BYTES0x00100) && | |||
966 | (tdb->tdb_cur_bytes >= tdb->tdb_soft_bytes)) { | |||
967 | tdb->tdb_flags &= ~TDBF_SOFT_BYTES0x00100; /* Turn off checking */ | |||
968 | mtx_leave(&tdb->tdb_mtx); | |||
969 | /* may sleep in solock() for the pfkey socket */ | |||
970 | pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_SOFT4); | |||
971 | } else | |||
972 | mtx_leave(&tdb->tdb_mtx); | |||
973 | ||||
974 | /* | |||
975 | * Loop through mbuf chain; if we find a readonly mbuf, | |||
976 | * copy the packet. | |||
977 | */ | |||
978 | mi = m; | |||
979 | while (mi != NULL((void *)0) && !M_READONLY(mi)(((mi)->m_hdr.mh_flags & 0x0001) != 0 && (((mi )->m_hdr.mh_flags & 0x0008) == 0 || ((mi)->M_dat.MH .MH_dat.MH_ext.ext_nextref != (mi))))) | |||
980 | mi = mi->m_nextm_hdr.mh_next; | |||
981 | ||||
982 | if (mi != NULL((void *)0)) { | |||
983 | struct mbuf *n = m_dup_pkt(m, 0, M_DONTWAIT0x0002); | |||
984 | ||||
985 | if (n == NULL((void *)0)) { | |||
986 | ahstat_inc(ahs_hdrops); | |||
987 | error = ENOBUFS55; | |||
988 | goto drop; | |||
989 | } | |||
990 | ||||
991 | m_freem(m); | |||
992 | m = n; | |||
993 | } | |||
994 | ||||
995 | /* Inject AH header. */ | |||
996 | mi = m_makespace(m, skip, rplen + ahx->authsize, &roff); | |||
997 | if (mi == NULL((void *)0)) { | |||
998 | DPRINTF("failed to inject AH header for SA %s/%08x",do { } while (0) | |||
999 | ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),do { } while (0) | |||
1000 | ntohl(tdb->tdb_spi))do { } while (0); | |||
1001 | ahstat_inc(ahs_hdrops); | |||
1002 | error = ENOBUFS55; | |||
1003 | goto drop; | |||
1004 | } | |||
1005 | ||||
1006 | /* | |||
1007 | * The AH header is guaranteed by m_makespace() to be in | |||
1008 | * contiguous memory, at 'roff' of the returned mbuf. | |||
1009 | */ | |||
1010 | ah = (struct ah *)(mtod(mi, caddr_t)((caddr_t)((mi)->m_hdr.mh_data)) + roff); | |||
1011 | ||||
1012 | /* Initialize the AH header. */ | |||
1013 | m_copydata(m, protoff, sizeof(u_int8_t), &ah->ah_nh); | |||
1014 | ah->ah_hl = (rplen + ahx->authsize - AH_FLENGTH8) / sizeof(u_int32_t); | |||
1015 | ah->ah_rv = 0; | |||
1016 | ah->ah_spi = tdb->tdb_spi; | |||
1017 | ||||
1018 | /* Zeroize authenticator. */ | |||
1019 | m_copyback(m, skip + rplen, ahx->authsize, ipseczeroes, M_NOWAIT0x0002); | |||
1020 | ||||
1021 | replay64 = tdb->tdb_rpl++; | |||
1022 | ah->ah_rpl = htonl((u_int32_t)replay64)(__uint32_t)(__builtin_constant_p((u_int32_t)replay64) ? (__uint32_t )(((__uint32_t)((u_int32_t)replay64) & 0xff) << 24 | ((__uint32_t)((u_int32_t)replay64) & 0xff00) << 8 | ((__uint32_t)((u_int32_t)replay64) & 0xff0000) >> 8 | ((__uint32_t)((u_int32_t)replay64) & 0xff000000) >> 24) : __swap32md((u_int32_t)replay64)); | |||
1023 | #if NPFSYNC1 > 0 | |||
1024 | pfsync_update_tdb(tdb,1); | |||
1025 | #endif | |||
1026 | ||||
1027 | /* Get crypto descriptors. */ | |||
1028 | crp = crypto_getreq(1); | |||
1029 | if (crp == NULL((void *)0)) { | |||
1030 | DPRINTF("failed to acquire crypto descriptors")do { } while (0); | |||
1031 | ahstat_inc(ahs_crypto); | |||
1032 | error = ENOBUFS55; | |||
1033 | goto drop; | |||
1034 | } | |||
1035 | ||||
1036 | crda = &crp->crp_desc[0]; | |||
1037 | ||||
1038 | crda->crd_skip = 0; | |||
1039 | crda->crd_inject = skip + rplen; | |||
1040 | crda->crd_len = m->m_pkthdrM_dat.MH.MH_pkthdr.len; | |||
1041 | ||||
1042 | /* Authentication operation. */ | |||
1043 | crda->crd_algCRD_INI.cri_alg = ahx->type; | |||
1044 | crda->crd_keyCRD_INI.cri_key = tdb->tdb_amxkey; | |||
1045 | crda->crd_klenCRD_INI.cri_klen = tdb->tdb_amxkeylen * 8; | |||
1046 | ||||
1047 | if ((tdb->tdb_wnd > 0) && (tdb->tdb_flags & TDBF_ESN0x100000)) { | |||
1048 | u_int32_t esn; | |||
1049 | ||||
1050 | esn = htonl((u_int32_t)(replay64 >> 32))(__uint32_t)(__builtin_constant_p((u_int32_t)(replay64 >> 32)) ? (__uint32_t)(((__uint32_t)((u_int32_t)(replay64 >> 32)) & 0xff) << 24 | ((__uint32_t)((u_int32_t)(replay64 >> 32)) & 0xff00) << 8 | ((__uint32_t)((u_int32_t )(replay64 >> 32)) & 0xff0000) >> 8 | ((__uint32_t )((u_int32_t)(replay64 >> 32)) & 0xff000000) >> 24) : __swap32md((u_int32_t)(replay64 >> 32))); | |||
1051 | memcpy(crda->crd_esn, &esn, 4)__builtin_memcpy((crda->CRD_INI.u.esn), (&esn), (4)); | |||
1052 | crda->crd_flags |= CRD_F_ESN0x20; | |||
1053 | } | |||
1054 | ||||
1055 | ptr = malloc(skip, M_XDATA76, M_NOWAIT0x0002 | M_ZERO0x0008); | |||
1056 | if (ptr == NULL((void *)0)) { | |||
1057 | DPRINTF("failed to allocate buffer")do { } while (0); | |||
1058 | ahstat_inc(ahs_crypto); | |||
1059 | error = ENOBUFS55; | |||
1060 | goto drop; | |||
1061 | } | |||
1062 | ||||
1063 | /* Save the skipped portion of the packet. */ | |||
1064 | m_copydata(m, 0, skip, ptr); | |||
1065 | ||||
1066 | /* | |||
1067 | * Fix IP header length on the header used for | |||
1068 | * authentication. We don't need to fix the original | |||
1069 | * header length as it will be fixed by our caller. | |||
1070 | */ | |||
1071 | switch (tdb->tdb_dst.sa.sa_family) { | |||
1072 | case AF_INET2: | |||
1073 | memcpy((caddr_t) &iplen, ((caddr_t)ptr) +__builtin_memcpy(((caddr_t) &iplen), (((caddr_t)ptr) + __builtin_offsetof (struct ip, ip_len)), (sizeof(u_int16_t))) | |||
1074 | offsetof(struct ip, ip_len), sizeof(u_int16_t))__builtin_memcpy(((caddr_t) &iplen), (((caddr_t)ptr) + __builtin_offsetof (struct ip, ip_len)), (sizeof(u_int16_t))); | |||
1075 | iplen = htons(ntohs(iplen) + rplen + ahx->authsize)(__uint16_t)(__builtin_constant_p((__uint16_t)(__builtin_constant_p (iplen) ? (__uint16_t)(((__uint16_t)(iplen) & 0xffU) << 8 | ((__uint16_t)(iplen) & 0xff00U) >> 8) : __swap16md (iplen)) + rplen + ahx->authsize) ? (__uint16_t)(((__uint16_t )((__uint16_t)(__builtin_constant_p(iplen) ? (__uint16_t)(((__uint16_t )(iplen) & 0xffU) << 8 | ((__uint16_t)(iplen) & 0xff00U) >> 8) : __swap16md(iplen)) + rplen + ahx-> authsize) & 0xffU) << 8 | ((__uint16_t)((__uint16_t )(__builtin_constant_p(iplen) ? (__uint16_t)(((__uint16_t)(iplen ) & 0xffU) << 8 | ((__uint16_t)(iplen) & 0xff00U ) >> 8) : __swap16md(iplen)) + rplen + ahx->authsize ) & 0xff00U) >> 8) : __swap16md((__uint16_t)(__builtin_constant_p (iplen) ? (__uint16_t)(((__uint16_t)(iplen) & 0xffU) << 8 | ((__uint16_t)(iplen) & 0xff00U) >> 8) : __swap16md (iplen)) + rplen + ahx->authsize)); | |||
1076 | m_copyback(m, offsetof(struct ip, ip_len)__builtin_offsetof(struct ip, ip_len), | |||
1077 | sizeof(u_int16_t), &iplen, M_NOWAIT0x0002); | |||
1078 | break; | |||
1079 | ||||
1080 | #ifdef INET61 | |||
1081 | case AF_INET624: | |||
1082 | memcpy((caddr_t) &iplen, ((caddr_t)ptr) +__builtin_memcpy(((caddr_t) &iplen), (((caddr_t)ptr) + __builtin_offsetof (struct ip6_hdr, ip6_ctlun.ip6_un1.ip6_un1_plen)), (sizeof(u_int16_t ))) | |||
1083 | offsetof(struct ip6_hdr, ip6_plen), sizeof(u_int16_t))__builtin_memcpy(((caddr_t) &iplen), (((caddr_t)ptr) + __builtin_offsetof (struct ip6_hdr, ip6_ctlun.ip6_un1.ip6_un1_plen)), (sizeof(u_int16_t ))); | |||
1084 | iplen = htons(ntohs(iplen) + rplen + ahx->authsize)(__uint16_t)(__builtin_constant_p((__uint16_t)(__builtin_constant_p (iplen) ? (__uint16_t)(((__uint16_t)(iplen) & 0xffU) << 8 | ((__uint16_t)(iplen) & 0xff00U) >> 8) : __swap16md (iplen)) + rplen + ahx->authsize) ? (__uint16_t)(((__uint16_t )((__uint16_t)(__builtin_constant_p(iplen) ? (__uint16_t)(((__uint16_t )(iplen) & 0xffU) << 8 | ((__uint16_t)(iplen) & 0xff00U) >> 8) : __swap16md(iplen)) + rplen + ahx-> authsize) & 0xffU) << 8 | ((__uint16_t)((__uint16_t )(__builtin_constant_p(iplen) ? (__uint16_t)(((__uint16_t)(iplen ) & 0xffU) << 8 | ((__uint16_t)(iplen) & 0xff00U ) >> 8) : __swap16md(iplen)) + rplen + ahx->authsize ) & 0xff00U) >> 8) : __swap16md((__uint16_t)(__builtin_constant_p (iplen) ? (__uint16_t)(((__uint16_t)(iplen) & 0xffU) << 8 | ((__uint16_t)(iplen) & 0xff00U) >> 8) : __swap16md (iplen)) + rplen + ahx->authsize)); | |||
1085 | m_copyback(m, offsetof(struct ip6_hdr, ip6_plen)__builtin_offsetof(struct ip6_hdr, ip6_ctlun.ip6_un1.ip6_un1_plen ), | |||
1086 | sizeof(u_int16_t), &iplen, M_NOWAIT0x0002); | |||
1087 | break; | |||
1088 | #endif /* INET6 */ | |||
1089 | } | |||
1090 | ||||
1091 | /* Fix the Next Header field in saved header. */ | |||
1092 | ptr[protoff] = IPPROTO_AH51; | |||
1093 | ||||
1094 | /* Update the Next Protocol field in the IP header. */ | |||
1095 | prot = IPPROTO_AH51; | |||
1096 | m_copyback(m, protoff, sizeof(u_int8_t), &prot, M_NOWAIT0x0002); | |||
1097 | ||||
1098 | /* "Massage" the packet headers for crypto processing. */ | |||
1099 | error = ah_massage_headers(&m, tdb->tdb_dst.sa.sa_family, skip, | |||
1100 | ahx->type, 1); | |||
1101 | if (error) { | |||
1102 | /* mbuf was freed by callee. */ | |||
1103 | m = NULL((void *)0); | |||
1104 | goto drop; | |||
1105 | } | |||
1106 | ||||
1107 | /* Crypto operation descriptor. */ | |||
1108 | crp->crp_ilen = m->m_pkthdrM_dat.MH.MH_pkthdr.len; /* Total input length. */ | |||
1109 | crp->crp_flags = CRYPTO_F_IMBUF0x0001 | CRYPTO_F_MPSAFE0x0004; | |||
1110 | crp->crp_buf = (caddr_t)m; | |||
1111 | crp->crp_sid = tdb->tdb_cryptoid; | |||
1112 | ||||
1113 | while ((error = crypto_invoke(crp)) == EAGAIN35) { | |||
1114 | /* Reset the session ID */ | |||
1115 | if (tdb->tdb_cryptoid != 0) | |||
1116 | tdb->tdb_cryptoid = crp->crp_sid; | |||
1117 | } | |||
1118 | if (error) { | |||
1119 | DPRINTF("crypto error %d", error)do { } while (0); | |||
1120 | ipsecstat_inc(ipsec_noxform); | |||
1121 | goto drop; | |||
1122 | } | |||
1123 | ||||
1124 | /* Release the crypto descriptors */ | |||
1125 | crypto_freereq(crp); | |||
1126 | crp = NULL((void *)0); | |||
1127 | ||||
1128 | /* | |||
1129 | * Copy original headers (with the new protocol number) back | |||
1130 | * in place. | |||
1131 | */ | |||
1132 | m_copyback(m, 0, skip, ptr, M_NOWAIT0x0002); | |||
1133 | free(ptr, M_XDATA76, 0); | |||
1134 | ptr = NULL((void *)0); | |||
1135 | ||||
1136 | /* Call the IPsec input callback. */ | |||
1137 | error = ipsp_process_done(m, tdb); | |||
1138 | if (error) | |||
1139 | ahstat_inc(ahs_outfail); | |||
1140 | return error; | |||
1141 | ||||
1142 | drop: | |||
1143 | free(ptr, M_XDATA76, 0); | |||
1144 | m_freem(m); | |||
1145 | crypto_freereq(crp); | |||
1146 | return error; | |||
1147 | } |