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