| 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 | } |