diff options
Diffstat (limited to 'sys/netinet6')
-rw-r--r-- | sys/netinet6/ah_aesxcbcmac.c | 190 | ||||
-rw-r--r-- | sys/netinet6/ah_core.c | 1644 | ||||
-rw-r--r-- | sys/netinet6/ah_input.c | 1024 | ||||
-rw-r--r-- | sys/netinet6/ah_output.c | 586 | ||||
-rw-r--r-- | sys/netinet6/esp_aesctr.c | 461 | ||||
-rw-r--r-- | sys/netinet6/esp_camellia.c | 93 | ||||
-rw-r--r-- | sys/netinet6/esp_core.c | 1134 | ||||
-rw-r--r-- | sys/netinet6/esp_input.c | 975 | ||||
-rw-r--r-- | sys/netinet6/esp_rijndael.c | 95 | ||||
-rw-r--r-- | sys/netinet6/ipcomp_core.c | 356 | ||||
-rw-r--r-- | sys/netinet6/ipcomp_input.c | 345 | ||||
-rw-r--r-- | sys/netinet6/ipcomp_output.c | 382 | ||||
-rw-r--r-- | sys/netinet6/ipsec.c | 3643 |
13 files changed, 0 insertions, 10928 deletions
diff --git a/sys/netinet6/ah_aesxcbcmac.c b/sys/netinet6/ah_aesxcbcmac.c deleted file mode 100644 index 3c83d33..0000000 --- a/sys/netinet6/ah_aesxcbcmac.c +++ /dev/null @@ -1,190 +0,0 @@ -/* $KAME: ah_aesxcbcmac.c,v 1.6 2003/07/22 02:30:54 itojun Exp $ */ - -/*- - * Copyright (C) 1995, 1996, 1997, 1998 and 2003 WIDE Project. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/socket.h> -#include <sys/queue.h> -#include <sys/malloc.h> -#include <sys/syslog.h> -#include <sys/mbuf.h> - -#include <net/if.h> -#include <net/route.h> - -#include <netinet/in.h> - -#include <netinet6/ipsec.h> -#include <netinet6/ah.h> -#include <netinet6/ah_aesxcbcmac.h> - -#include <netkey/key.h> - -#include <crypto/rijndael/rijndael.h> - -#define AES_BLOCKSIZE 16 - -typedef struct { - u_int8_t e[AES_BLOCKSIZE]; - u_int8_t buf[AES_BLOCKSIZE]; - size_t buflen; - u_int32_t r_k1s[(RIJNDAEL_MAXNR+1)*4]; - u_int32_t r_k2s[(RIJNDAEL_MAXNR+1)*4]; - u_int32_t r_k3s[(RIJNDAEL_MAXNR+1)*4]; - int r_nr; /* key-length-dependent number of rounds */ - u_int8_t k2[AES_BLOCKSIZE]; - u_int8_t k3[AES_BLOCKSIZE]; -} aesxcbc_ctx; - -int -ah_aes_xcbc_mac_init(state, sav) - struct ah_algorithm_state *state; - struct secasvar *sav; -{ - u_int8_t k1seed[AES_BLOCKSIZE] = { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 }; - u_int8_t k2seed[AES_BLOCKSIZE] = { 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2 }; - u_int8_t k3seed[AES_BLOCKSIZE] = { 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3 }; - u_int32_t r_ks[(RIJNDAEL_MAXNR+1)*4]; - aesxcbc_ctx *ctx; - u_int8_t k1[AES_BLOCKSIZE]; - - if (!state) - panic("ah_aes_xcbc_mac_init: what?"); - - state->sav = sav; - state->foo = (void *)malloc(sizeof(aesxcbc_ctx), M_TEMP, M_NOWAIT); - if (!state->foo) - return ENOBUFS; - bzero(state->foo, sizeof(aesxcbc_ctx)); - - ctx = (aesxcbc_ctx *)state->foo; - - if ((ctx->r_nr = rijndaelKeySetupEnc(r_ks, - (char *)_KEYBUF(sav->key_auth), AES_BLOCKSIZE * 8)) == 0) - return -1; - rijndaelEncrypt(r_ks, ctx->r_nr, k1seed, k1); - rijndaelEncrypt(r_ks, ctx->r_nr, k2seed, ctx->k2); - rijndaelEncrypt(r_ks, ctx->r_nr, k3seed, ctx->k3); - if (rijndaelKeySetupEnc(ctx->r_k1s, k1, AES_BLOCKSIZE * 8) == 0) - return -1; - if (rijndaelKeySetupEnc(ctx->r_k2s, ctx->k2, AES_BLOCKSIZE * 8) == 0) - return -1; - if (rijndaelKeySetupEnc(ctx->r_k3s, ctx->k3, AES_BLOCKSIZE * 8) == 0) - return -1; - - return 0; -} - -void -ah_aes_xcbc_mac_loop(state, addr, len) - struct ah_algorithm_state *state; - u_int8_t *addr; - size_t len; -{ - u_int8_t buf[AES_BLOCKSIZE]; - aesxcbc_ctx *ctx; - u_int8_t *ep; - int i; - - if (!state || !state->foo) - panic("ah_aes_xcbc_mac_loop: what?"); - - ctx = (aesxcbc_ctx *)state->foo; - ep = addr + len; - - if (ctx->buflen == sizeof(ctx->buf)) { - for (i = 0; i < sizeof(ctx->e); i++) - ctx->buf[i] ^= ctx->e[i]; - rijndaelEncrypt(ctx->r_k1s, ctx->r_nr, ctx->buf, ctx->e); - ctx->buflen = 0; - } - if (ctx->buflen + len < sizeof(ctx->buf)) { - bcopy(addr, ctx->buf + ctx->buflen, len); - ctx->buflen += len; - return; - } - if (ctx->buflen && ctx->buflen + len > sizeof(ctx->buf)) { - bcopy(addr, ctx->buf + ctx->buflen, - sizeof(ctx->buf) - ctx->buflen); - for (i = 0; i < sizeof(ctx->e); i++) - ctx->buf[i] ^= ctx->e[i]; - rijndaelEncrypt(ctx->r_k1s, ctx->r_nr, ctx->buf, ctx->e); - addr += sizeof(ctx->buf) - ctx->buflen; - ctx->buflen = 0; - } - /* due to the special processing for M[n], "=" case is not included */ - while (addr + AES_BLOCKSIZE < ep) { - bcopy(addr, buf, AES_BLOCKSIZE); - for (i = 0; i < sizeof(buf); i++) - buf[i] ^= ctx->e[i]; - rijndaelEncrypt(ctx->r_k1s, ctx->r_nr, buf, ctx->e); - addr += AES_BLOCKSIZE; - } - if (addr < ep) { - bcopy(addr, ctx->buf + ctx->buflen, ep - addr); - ctx->buflen += ep - addr; - } -} - -void -ah_aes_xcbc_mac_result(state, addr, l) - struct ah_algorithm_state *state; - u_int8_t *addr; - size_t l; -{ - u_char digest[AES_BLOCKSIZE]; - aesxcbc_ctx *ctx; - int i; - - ctx = (aesxcbc_ctx *)state->foo; - - if (ctx->buflen == sizeof(ctx->buf)) { - for (i = 0; i < sizeof(ctx->buf); i++) { - ctx->buf[i] ^= ctx->e[i]; - ctx->buf[i] ^= ctx->k2[i]; - } - rijndaelEncrypt(ctx->r_k1s, ctx->r_nr, ctx->buf, digest); - } else { - for (i = ctx->buflen; i < sizeof(ctx->buf); i++) - ctx->buf[i] = (i == ctx->buflen) ? 0x80 : 0x00; - for (i = 0; i < sizeof(ctx->buf); i++) { - ctx->buf[i] ^= ctx->e[i]; - ctx->buf[i] ^= ctx->k3[i]; - } - rijndaelEncrypt(ctx->r_k1s, ctx->r_nr, ctx->buf, digest); - } - - bcopy(digest, addr, sizeof(digest) > l ? l : sizeof(digest)); - - free(state->foo, M_TEMP); -} diff --git a/sys/netinet6/ah_core.c b/sys/netinet6/ah_core.c deleted file mode 100644 index c36a777..0000000 --- a/sys/netinet6/ah_core.c +++ /dev/null @@ -1,1644 +0,0 @@ -/* $FreeBSD$ */ -/* $KAME: ah_core.c,v 1.59 2003/07/25 10:17:14 itojun Exp $ */ - -/*- - * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * RFC1826/2402 authentication header. - */ - -/* TODO: have shared routines for hmac-* algorithms */ - -#include "opt_inet.h" -#include "opt_inet6.h" -#include "opt_ipsec.h" - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/malloc.h> -#include <sys/mbuf.h> -#include <sys/domain.h> -#include <sys/protosw.h> -#include <sys/socket.h> -#include <sys/socketvar.h> -#include <sys/errno.h> -#include <sys/time.h> -#include <sys/syslog.h> - -#include <net/if.h> -#include <net/route.h> - -#include <netinet/in.h> -#include <netinet/in_systm.h> -#include <netinet/ip.h> -#include <netinet/in_var.h> - -#ifdef INET6 -#include <netinet/ip6.h> -#include <netinet6/ip6_var.h> -#include <netinet6/scope6_var.h> -#include <netinet/icmp6.h> -#endif - -#include <netinet6/ipsec.h> -#ifdef INET6 -#include <netinet6/ipsec6.h> -#endif -#include <netinet6/ah.h> -#ifdef INET6 -#include <netinet6/ah6.h> -#endif -#include <netinet6/ah_aesxcbcmac.h> -#ifdef IPSEC_ESP -#include <netinet6/esp.h> -#ifdef INET6 -#include <netinet6/esp6.h> -#endif -#endif -#include <net/pfkeyv2.h> -#include <netkey/keydb.h> -#include <sys/md5.h> -#define MD5_RESULTLEN 16 -#include <crypto/sha1.h> -#include <crypto/sha2/sha2.h> -#include <opencrypto/rmd160.h> -#define RIPEMD160_RESULTLEN 20 - -static int ah_sumsiz_1216 __P((struct secasvar *)); -static int ah_sumsiz_zero __P((struct secasvar *)); -static int ah_common_mature __P((struct secasvar *)); -static int ah_none_mature __P((struct secasvar *)); -static int ah_none_init __P((struct ah_algorithm_state *, struct secasvar *)); -static void ah_none_loop __P((struct ah_algorithm_state *, u_int8_t *, size_t)); -static void ah_none_result __P((struct ah_algorithm_state *, - u_int8_t *, size_t)); -static int ah_keyed_md5_mature __P((struct secasvar *)); -static int ah_keyed_md5_init __P((struct ah_algorithm_state *, - struct secasvar *)); -static void ah_keyed_md5_loop __P((struct ah_algorithm_state *, u_int8_t *, - size_t)); -static void ah_keyed_md5_result __P((struct ah_algorithm_state *, - u_int8_t *, size_t)); -static int ah_keyed_sha1_init __P((struct ah_algorithm_state *, - struct secasvar *)); -static void ah_keyed_sha1_loop __P((struct ah_algorithm_state *, u_int8_t *, - size_t)); -static void ah_keyed_sha1_result __P((struct ah_algorithm_state *, u_int8_t *, - size_t)); -static int ah_hmac_md5_init __P((struct ah_algorithm_state *, - struct secasvar *)); -static void ah_hmac_md5_loop __P((struct ah_algorithm_state *, u_int8_t *, - size_t)); -static void ah_hmac_md5_result __P((struct ah_algorithm_state *, - u_int8_t *, size_t)); -static int ah_hmac_sha1_init __P((struct ah_algorithm_state *, - struct secasvar *)); -static void ah_hmac_sha1_loop __P((struct ah_algorithm_state *, u_int8_t *, - size_t)); -static void ah_hmac_sha1_result __P((struct ah_algorithm_state *, - u_int8_t *, size_t)); -static int ah_hmac_sha2_256_init __P((struct ah_algorithm_state *, - struct secasvar *)); -static void ah_hmac_sha2_256_loop __P((struct ah_algorithm_state *, u_int8_t *, - size_t)); -static void ah_hmac_sha2_256_result __P((struct ah_algorithm_state *, - u_int8_t *, size_t)); -static int ah_hmac_sha2_384_init __P((struct ah_algorithm_state *, - struct secasvar *)); -static void ah_hmac_sha2_384_loop __P((struct ah_algorithm_state *, u_int8_t *, - size_t)); -static void ah_hmac_sha2_384_result __P((struct ah_algorithm_state *, - u_int8_t *, size_t)); -static int ah_hmac_sha2_512_init __P((struct ah_algorithm_state *, - struct secasvar *)); -static void ah_hmac_sha2_512_loop __P((struct ah_algorithm_state *, u_int8_t *, - size_t)); -static void ah_hmac_sha2_512_result __P((struct ah_algorithm_state *, - u_int8_t *, size_t)); -static int ah_hmac_ripemd160_init __P((struct ah_algorithm_state *, - struct secasvar *)); -static void ah_hmac_ripemd160_loop __P((struct ah_algorithm_state *, u_int8_t *, - size_t)); -static void ah_hmac_ripemd160_result __P((struct ah_algorithm_state *, - u_int8_t *, size_t)); - -static void ah_update_mbuf __P((struct mbuf *, int, int, - const struct ah_algorithm *, struct ah_algorithm_state *)); - -/* checksum algorithms */ -static const struct ah_algorithm ah_algorithms[] = { - { ah_sumsiz_1216, ah_common_mature, 128, 128, "hmac-md5", - ah_hmac_md5_init, ah_hmac_md5_loop, - ah_hmac_md5_result, }, - { ah_sumsiz_1216, ah_common_mature, 160, 160, "hmac-sha1", - ah_hmac_sha1_init, ah_hmac_sha1_loop, - ah_hmac_sha1_result, }, - { ah_sumsiz_1216, ah_keyed_md5_mature, 128, 128, "keyed-md5", - ah_keyed_md5_init, ah_keyed_md5_loop, - ah_keyed_md5_result, }, - { ah_sumsiz_1216, ah_common_mature, 160, 160, "keyed-sha1", - ah_keyed_sha1_init, ah_keyed_sha1_loop, - ah_keyed_sha1_result, }, - { ah_sumsiz_zero, ah_none_mature, 0, 2048, "none", - ah_none_init, ah_none_loop, ah_none_result, }, - { ah_sumsiz_1216, ah_common_mature, 256, 256, - "hmac-sha2-256", - ah_hmac_sha2_256_init, ah_hmac_sha2_256_loop, - ah_hmac_sha2_256_result, }, - { ah_sumsiz_1216, ah_common_mature, 384, 384, - "hmac-sha2-384", - ah_hmac_sha2_384_init, ah_hmac_sha2_384_loop, - ah_hmac_sha2_384_result, }, - { ah_sumsiz_1216, ah_common_mature, 512, 512, - "hmac-sha2-512", - ah_hmac_sha2_512_init, ah_hmac_sha2_512_loop, - ah_hmac_sha2_512_result, }, - { ah_sumsiz_1216, ah_common_mature, 160, 160, - "hmac-ripemd160", - ah_hmac_ripemd160_init, ah_hmac_ripemd160_loop, - ah_hmac_ripemd160_result, }, - { ah_sumsiz_1216, ah_common_mature, 128, 128, - "aes-xcbc-mac", - ah_aes_xcbc_mac_init, ah_aes_xcbc_mac_loop, - ah_aes_xcbc_mac_result, }, - { ah_sumsiz_1216, ah_none_mature, 8, 640, /* bits (RFC 2385) */ - "TCP-MD5", - ah_none_init, ah_none_loop, - ah_none_result, }, -}; - -const struct ah_algorithm * -ah_algorithm_lookup(idx) - int idx; -{ - - switch (idx) { - case SADB_AALG_MD5HMAC: - return &ah_algorithms[0]; - case SADB_AALG_SHA1HMAC: - return &ah_algorithms[1]; - case SADB_X_AALG_MD5: - return &ah_algorithms[2]; - case SADB_X_AALG_SHA: - return &ah_algorithms[3]; - case SADB_X_AALG_NULL: - return &ah_algorithms[4]; - case SADB_X_AALG_SHA2_256: - return &ah_algorithms[5]; - case SADB_X_AALG_SHA2_384: - return &ah_algorithms[6]; - case SADB_X_AALG_SHA2_512: - return &ah_algorithms[7]; - case SADB_X_AALG_RIPEMD160HMAC: - return &ah_algorithms[8]; - case SADB_X_AALG_AES_XCBC_MAC: - return &ah_algorithms[9]; - case SADB_X_AALG_TCP_MD5: - return &ah_algorithms[10]; - default: - return NULL; - } -} - - -static int -ah_sumsiz_1216(sav) - struct secasvar *sav; -{ - if (!sav) - panic("ah_sumsiz_1216: null pointer is passed"); - if (sav->flags & SADB_X_EXT_OLD) - return 16; - else - return 12; -} - -static int -ah_sumsiz_zero(sav) - struct secasvar *sav; -{ - if (!sav) - panic("ah_sumsiz_zero: null pointer is passed"); - return 0; -} - -static int -ah_common_mature(sav) - struct secasvar *sav; -{ - const struct ah_algorithm *algo; - - if (!sav->key_auth) { - ipseclog((LOG_ERR, "ah_common_mature: no key is given.\n")); - return 1; - } - - algo = ah_algorithm_lookup(sav->alg_auth); - if (!algo) { - ipseclog((LOG_ERR, "ah_common_mature: unsupported algorithm.\n")); - return 1; - } - - if (sav->key_auth->sadb_key_bits < algo->keymin || - algo->keymax < sav->key_auth->sadb_key_bits) { - ipseclog((LOG_ERR, - "ah_common_mature: invalid key length %d for %s.\n", - sav->key_auth->sadb_key_bits, algo->name)); - return 1; - } - - return 0; -} - -static int -ah_none_mature(sav) - struct secasvar *sav; -{ - if (sav->sah->saidx.proto == IPPROTO_AH) { - ipseclog((LOG_ERR, - "ah_none_mature: protocol and algorithm mismatch.\n")); - return 1; - } - return 0; -} - -static int -ah_none_init(state, sav) - struct ah_algorithm_state *state; - struct secasvar *sav; -{ - state->foo = NULL; - return 0; -} - -static void -ah_none_loop(state, addr, len) - struct ah_algorithm_state *state; - u_int8_t * addr; - size_t len; -{ -} - -static void -ah_none_result(state, addr, l) - struct ah_algorithm_state *state; - u_int8_t *addr; - size_t l; -{ -} - -static int -ah_keyed_md5_mature(sav) - struct secasvar *sav; -{ - /* anything is okay */ - return 0; -} - -static int -ah_keyed_md5_init(state, sav) - struct ah_algorithm_state *state; - struct secasvar *sav; -{ - size_t padlen; - size_t keybitlen; - u_int8_t buf[32]; - - if (!state) - panic("ah_keyed_md5_init: what?"); - - state->sav = sav; - state->foo = (void *)malloc(sizeof(MD5_CTX), M_TEMP, M_NOWAIT); - if (state->foo == NULL) - return ENOBUFS; - - MD5Init((MD5_CTX *)state->foo); - if (state->sav) { - MD5Update((MD5_CTX *)state->foo, - (u_int8_t *)_KEYBUF(state->sav->key_auth), - (u_int)_KEYLEN(state->sav->key_auth)); - - /* - * Pad after the key. - * We cannot simply use md5_pad() since the function - * won't update the total length. - */ - if (_KEYLEN(state->sav->key_auth) < 56) - padlen = 64 - 8 - _KEYLEN(state->sav->key_auth); - else - padlen = 64 + 64 - 8 - _KEYLEN(state->sav->key_auth); - keybitlen = _KEYLEN(state->sav->key_auth); - keybitlen *= 8; - - buf[0] = 0x80; - MD5Update((MD5_CTX *)state->foo, &buf[0], 1); - padlen--; - - bzero(buf, sizeof(buf)); - while (sizeof(buf) < padlen) { - MD5Update((MD5_CTX *)state->foo, &buf[0], sizeof(buf)); - padlen -= sizeof(buf); - } - if (padlen) { - MD5Update((MD5_CTX *)state->foo, &buf[0], padlen); - } - - buf[0] = (keybitlen >> 0) & 0xff; - buf[1] = (keybitlen >> 8) & 0xff; - buf[2] = (keybitlen >> 16) & 0xff; - buf[3] = (keybitlen >> 24) & 0xff; - MD5Update((MD5_CTX *)state->foo, buf, 8); - } - - return 0; -} - -static void -ah_keyed_md5_loop(state, addr, len) - struct ah_algorithm_state *state; - u_int8_t * addr; - size_t len; -{ - if (!state) - panic("ah_keyed_md5_loop: what?"); - - MD5Update((MD5_CTX *)state->foo, addr, len); -} - -static void -ah_keyed_md5_result(state, addr, l) - struct ah_algorithm_state *state; - u_int8_t *addr; - size_t l; -{ - u_char digest[MD5_RESULTLEN]; - - if (!state) - panic("ah_keyed_md5_result: what?"); - - if (state->sav) { - MD5Update((MD5_CTX *)state->foo, - (u_int8_t *)_KEYBUF(state->sav->key_auth), - (u_int)_KEYLEN(state->sav->key_auth)); - } - MD5Final(digest, (MD5_CTX *)state->foo); - free(state->foo, M_TEMP); - bcopy(digest, addr, sizeof(digest) > l ? l : sizeof(digest)); -} - -static int -ah_keyed_sha1_init(state, sav) - struct ah_algorithm_state *state; - struct secasvar *sav; -{ - SHA1_CTX *ctxt; - size_t padlen; - size_t keybitlen; - u_int8_t buf[32]; - - if (!state) - panic("ah_keyed_sha1_init: what?"); - - state->sav = sav; - state->foo = (void *)malloc(sizeof(SHA1_CTX), M_TEMP, M_NOWAIT); - if (!state->foo) - return ENOBUFS; - - ctxt = (SHA1_CTX *)state->foo; - SHA1Init(ctxt); - - if (state->sav) { - SHA1Update(ctxt, (u_int8_t *)_KEYBUF(state->sav->key_auth), - (u_int)_KEYLEN(state->sav->key_auth)); - - /* - * Pad after the key. - */ - if (_KEYLEN(state->sav->key_auth) < 56) - padlen = 64 - 8 - _KEYLEN(state->sav->key_auth); - else - padlen = 64 + 64 - 8 - _KEYLEN(state->sav->key_auth); - keybitlen = _KEYLEN(state->sav->key_auth); - keybitlen *= 8; - - buf[0] = 0x80; - SHA1Update(ctxt, &buf[0], 1); - padlen--; - - bzero(buf, sizeof(buf)); - while (sizeof(buf) < padlen) { - SHA1Update(ctxt, &buf[0], sizeof(buf)); - padlen -= sizeof(buf); - } - if (padlen) { - SHA1Update(ctxt, &buf[0], padlen); - } - - buf[0] = (keybitlen >> 0) & 0xff; - buf[1] = (keybitlen >> 8) & 0xff; - buf[2] = (keybitlen >> 16) & 0xff; - buf[3] = (keybitlen >> 24) & 0xff; - SHA1Update(ctxt, buf, 8); - } - - return 0; -} - -static void -ah_keyed_sha1_loop(state, addr, len) - struct ah_algorithm_state *state; - u_int8_t * addr; - size_t len; -{ - SHA1_CTX *ctxt; - - if (!state || !state->foo) - panic("ah_keyed_sha1_loop: what?"); - ctxt = (SHA1_CTX *)state->foo; - - SHA1Update(ctxt, (u_int8_t *)addr, (size_t)len); -} - -static void -ah_keyed_sha1_result(state, addr, l) - struct ah_algorithm_state *state; - u_int8_t *addr; - size_t l; -{ - u_char digest[SHA1_RESULTLEN]; /* SHA-1 generates 160 bits */ - SHA1_CTX *ctxt; - - if (!state || !state->foo) - panic("ah_keyed_sha1_result: what?"); - ctxt = (SHA1_CTX *)state->foo; - - if (state->sav) { - SHA1Update(ctxt, (u_int8_t *)_KEYBUF(state->sav->key_auth), - (u_int)_KEYLEN(state->sav->key_auth)); - } - SHA1Final((u_int8_t *)digest, ctxt); - bcopy(digest, addr, sizeof(digest) > l ? l : sizeof(digest)); - - free(state->foo, M_TEMP); -} - -static int -ah_hmac_md5_init(state, sav) - struct ah_algorithm_state *state; - struct secasvar *sav; -{ - u_char *ipad; - u_char *opad; - u_char tk[MD5_RESULTLEN]; - u_char *key; - size_t keylen; - size_t i; - MD5_CTX *ctxt; - - if (!state) - panic("ah_hmac_md5_init: what?"); - - state->sav = sav; - state->foo = (void *)malloc(64 + 64 + sizeof(MD5_CTX), M_TEMP, M_NOWAIT); - if (!state->foo) - return ENOBUFS; - - ipad = (u_char *)state->foo; - opad = (u_char *)(ipad + 64); - ctxt = (MD5_CTX *)(opad + 64); - - /* compress the key if necessery */ - if (64 < _KEYLEN(state->sav->key_auth)) { - MD5Init(ctxt); - MD5Update(ctxt, _KEYBUF(state->sav->key_auth), - _KEYLEN(state->sav->key_auth)); - MD5Final(&tk[0], ctxt); - key = &tk[0]; - keylen = 16; - } else { - key = _KEYBUF(state->sav->key_auth); - keylen = _KEYLEN(state->sav->key_auth); - } - - bzero(ipad, 64); - bzero(opad, 64); - bcopy(key, ipad, keylen); - bcopy(key, opad, keylen); - for (i = 0; i < 64; i++) { - ipad[i] ^= 0x36; - opad[i] ^= 0x5c; - } - - MD5Init(ctxt); - MD5Update(ctxt, ipad, 64); - - return 0; -} - -static void -ah_hmac_md5_loop(state, addr, len) - struct ah_algorithm_state *state; - u_int8_t * addr; - size_t len; -{ - MD5_CTX *ctxt; - - if (!state || !state->foo) - panic("ah_hmac_md5_loop: what?"); - ctxt = (MD5_CTX *)(((u_int8_t *)state->foo) + 128); - MD5Update(ctxt, addr, len); -} - -static void -ah_hmac_md5_result(state, addr, l) - struct ah_algorithm_state *state; - u_int8_t *addr; - size_t l; -{ - u_char digest[MD5_RESULTLEN]; - u_char *ipad; - u_char *opad; - MD5_CTX *ctxt; - - if (!state || !state->foo) - panic("ah_hmac_md5_result: what?"); - - ipad = (u_char *)state->foo; - opad = (u_char *)(ipad + 64); - ctxt = (MD5_CTX *)(opad + 64); - - MD5Final(digest, ctxt); - - MD5Init(ctxt); - MD5Update(ctxt, opad, 64); - MD5Update(ctxt, digest, sizeof(digest)); - MD5Final(digest, ctxt); - - bcopy(digest, addr, sizeof(digest) > l ? l : sizeof(digest)); - - free(state->foo, M_TEMP); -} - -static int -ah_hmac_sha1_init(state, sav) - struct ah_algorithm_state *state; - struct secasvar *sav; -{ - u_char *ipad; - u_char *opad; - SHA1_CTX *ctxt; - u_char tk[SHA1_RESULTLEN]; /* SHA-1 generates 160 bits */ - u_char *key; - size_t keylen; - size_t i; - - if (!state) - panic("ah_hmac_sha1_init: what?"); - - state->sav = sav; - state->foo = (void *)malloc(64 + 64 + sizeof(SHA1_CTX), - M_TEMP, M_NOWAIT); - if (!state->foo) - return ENOBUFS; - - ipad = (u_char *)state->foo; - opad = (u_char *)(ipad + 64); - ctxt = (SHA1_CTX *)(opad + 64); - - /* compress the key if necessery */ - if (64 < _KEYLEN(state->sav->key_auth)) { - SHA1Init(ctxt); - SHA1Update(ctxt, _KEYBUF(state->sav->key_auth), - _KEYLEN(state->sav->key_auth)); - SHA1Final(&tk[0], ctxt); - key = &tk[0]; - keylen = SHA1_RESULTLEN; - } else { - key = _KEYBUF(state->sav->key_auth); - keylen = _KEYLEN(state->sav->key_auth); - } - - bzero(ipad, 64); - bzero(opad, 64); - bcopy(key, ipad, keylen); - bcopy(key, opad, keylen); - for (i = 0; i < 64; i++) { - ipad[i] ^= 0x36; - opad[i] ^= 0x5c; - } - - SHA1Init(ctxt); - SHA1Update(ctxt, ipad, 64); - - return 0; -} - -static void -ah_hmac_sha1_loop(state, addr, len) - struct ah_algorithm_state *state; - u_int8_t * addr; - size_t len; -{ - SHA1_CTX *ctxt; - - if (!state || !state->foo) - panic("ah_hmac_sha1_loop: what?"); - - ctxt = (SHA1_CTX *)(((u_char *)state->foo) + 128); - SHA1Update(ctxt, (u_int8_t *)addr, (size_t)len); -} - -static void -ah_hmac_sha1_result(state, addr, l) - struct ah_algorithm_state *state; - u_int8_t *addr; - size_t l; -{ - u_char digest[SHA1_RESULTLEN]; /* SHA-1 generates 160 bits */ - u_char *ipad; - u_char *opad; - SHA1_CTX *ctxt; - - if (!state || !state->foo) - panic("ah_hmac_sha1_result: what?"); - - ipad = (u_char *)state->foo; - opad = (u_char *)(ipad + 64); - ctxt = (SHA1_CTX *)(opad + 64); - - SHA1Final((u_int8_t *)digest, ctxt); - - SHA1Init(ctxt); - SHA1Update(ctxt, opad, 64); - SHA1Update(ctxt, (u_int8_t *)digest, sizeof(digest)); - SHA1Final((u_int8_t *)digest, ctxt); - - bcopy(digest, addr, sizeof(digest) > l ? l : sizeof(digest)); - - free(state->foo, M_TEMP); -} - -static int -ah_hmac_sha2_256_init(state, sav) - struct ah_algorithm_state *state; - struct secasvar *sav; -{ - u_char *ipad; - u_char *opad; - SHA256_CTX *ctxt; - u_char tk[SHA256_DIGEST_LENGTH]; - u_char *key; - size_t keylen; - size_t i; - - if (!state) - panic("ah_hmac_sha2_256_init: what?"); - - state->sav = sav; - state->foo = (void *)malloc(64 + 64 + sizeof(SHA256_CTX), - M_TEMP, M_NOWAIT); - if (!state->foo) - return ENOBUFS; - - ipad = (u_char *)state->foo; - opad = (u_char *)(ipad + 64); - ctxt = (SHA256_CTX *)(opad + 64); - - /* compress the key if necessery */ - if (64 < _KEYLEN(state->sav->key_auth)) { - bzero(tk, sizeof(tk)); - bzero(ctxt, sizeof(*ctxt)); - SHA256_Init(ctxt); - SHA256_Update(ctxt, _KEYBUF(state->sav->key_auth), - _KEYLEN(state->sav->key_auth)); - SHA256_Final(&tk[0], ctxt); - key = &tk[0]; - keylen = sizeof(tk) < 64 ? sizeof(tk) : 64; - } else { - key = _KEYBUF(state->sav->key_auth); - keylen = _KEYLEN(state->sav->key_auth); - } - - bzero(ipad, 64); - bzero(opad, 64); - bcopy(key, ipad, keylen); - bcopy(key, opad, keylen); - for (i = 0; i < 64; i++) { - ipad[i] ^= 0x36; - opad[i] ^= 0x5c; - } - - bzero(ctxt, sizeof(*ctxt)); - SHA256_Init(ctxt); - SHA256_Update(ctxt, ipad, 64); - - return 0; -} - -static void -ah_hmac_sha2_256_loop(state, addr, len) - struct ah_algorithm_state *state; - u_int8_t *addr; - size_t len; -{ - SHA256_CTX *ctxt; - - if (!state || !state->foo) - panic("ah_hmac_sha2_256_loop: what?"); - - ctxt = (SHA256_CTX *)(((u_char *)state->foo) + 128); - SHA256_Update(ctxt, (caddr_t)addr, (size_t)len); -} - -static void -ah_hmac_sha2_256_result(state, addr, l) - struct ah_algorithm_state *state; - u_int8_t *addr; - size_t l; -{ - u_char digest[SHA256_DIGEST_LENGTH]; - u_char *ipad; - u_char *opad; - SHA256_CTX *ctxt; - - if (!state || !state->foo) - panic("ah_hmac_sha2_256_result: what?"); - - ipad = (u_char *)state->foo; - opad = (u_char *)(ipad + 64); - ctxt = (SHA256_CTX *)(opad + 64); - - SHA256_Final((caddr_t)digest, ctxt); - - bzero(ctxt, sizeof(*ctxt)); - SHA256_Init(ctxt); - SHA256_Update(ctxt, opad, 64); - SHA256_Update(ctxt, (caddr_t)digest, sizeof(digest)); - SHA256_Final((caddr_t)digest, ctxt); - - bcopy(digest, addr, sizeof(digest) > l ? l : sizeof(digest)); - - free(state->foo, M_TEMP); -} - -static int -ah_hmac_sha2_384_init(state, sav) - struct ah_algorithm_state *state; - struct secasvar *sav; -{ - u_char *ipad; - u_char *opad; - SHA384_CTX *ctxt; - u_char tk[SHA384_DIGEST_LENGTH]; - u_char *key; - size_t keylen; - size_t i; - - if (!state) - panic("ah_hmac_sha2_384_init: what?"); - - state->sav = sav; - state->foo = (void *)malloc(64 + 64 + sizeof(SHA384_CTX), - M_TEMP, M_NOWAIT); - if (!state->foo) - return ENOBUFS; - bzero(state->foo, 64 + 64 + sizeof(SHA384_CTX)); - - ipad = (u_char *)state->foo; - opad = (u_char *)(ipad + 64); - ctxt = (SHA384_CTX *)(opad + 64); - - /* compress the key if necessery */ - if (64 < _KEYLEN(state->sav->key_auth)) { - bzero(tk, sizeof(tk)); - bzero(ctxt, sizeof(*ctxt)); - SHA384_Init(ctxt); - SHA384_Update(ctxt, _KEYBUF(state->sav->key_auth), - _KEYLEN(state->sav->key_auth)); - SHA384_Final(&tk[0], ctxt); - key = &tk[0]; - keylen = sizeof(tk) < 64 ? sizeof(tk) : 64; - } else { - key = _KEYBUF(state->sav->key_auth); - keylen = _KEYLEN(state->sav->key_auth); - } - - bzero(ipad, 64); - bzero(opad, 64); - bcopy(key, ipad, keylen); - bcopy(key, opad, keylen); - for (i = 0; i < 64; i++) { - ipad[i] ^= 0x36; - opad[i] ^= 0x5c; - } - - bzero(ctxt, sizeof(*ctxt)); - SHA384_Init(ctxt); - SHA384_Update(ctxt, ipad, 64); - - return 0; -} - -static void -ah_hmac_sha2_384_loop(state, addr, len) - struct ah_algorithm_state *state; - u_int8_t *addr; - size_t len; -{ - SHA384_CTX *ctxt; - - if (!state || !state->foo) - panic("ah_hmac_sha2_384_loop: what?"); - - ctxt = (SHA384_CTX *)(((u_char *)state->foo) + 128); - SHA384_Update(ctxt, (caddr_t)addr, (size_t)len); -} - -static void -ah_hmac_sha2_384_result(state, addr, l) - struct ah_algorithm_state *state; - u_int8_t *addr; - size_t l; -{ - u_char digest[SHA384_DIGEST_LENGTH]; - u_char *ipad; - u_char *opad; - SHA384_CTX *ctxt; - - if (!state || !state->foo) - panic("ah_hmac_sha2_384_result: what?"); - - ipad = (u_char *)state->foo; - opad = (u_char *)(ipad + 64); - ctxt = (SHA384_CTX *)(opad + 64); - - SHA384_Final((caddr_t)digest, ctxt); - - bzero(ctxt, sizeof(*ctxt)); - SHA384_Init(ctxt); - SHA384_Update(ctxt, opad, 64); - SHA384_Update(ctxt, (caddr_t)digest, sizeof(digest)); - SHA384_Final((caddr_t)digest, ctxt); - - bcopy(digest, addr, sizeof(digest) > l ? l : sizeof(digest)); - - free(state->foo, M_TEMP); -} - -static int -ah_hmac_sha2_512_init(state, sav) - struct ah_algorithm_state *state; - struct secasvar *sav; -{ - u_char *ipad; - u_char *opad; - SHA512_CTX *ctxt; - u_char tk[SHA512_DIGEST_LENGTH]; - u_char *key; - size_t keylen; - size_t i; - - if (!state) - panic("ah_hmac_sha2_512_init: what?"); - - state->sav = sav; - state->foo = (void *)malloc(64 + 64 + sizeof(SHA512_CTX), - M_TEMP, M_NOWAIT); - if (!state->foo) - return ENOBUFS; - bzero(state->foo, 64 + 64 + sizeof(SHA512_CTX)); - - ipad = (u_char *)state->foo; - opad = (u_char *)(ipad + 64); - ctxt = (SHA512_CTX *)(opad + 64); - - /* compress the key if necessery */ - if (64 < _KEYLEN(state->sav->key_auth)) { - bzero(tk, sizeof(tk)); - bzero(ctxt, sizeof(*ctxt)); - SHA512_Init(ctxt); - SHA512_Update(ctxt, _KEYBUF(state->sav->key_auth), - _KEYLEN(state->sav->key_auth)); - SHA512_Final(&tk[0], ctxt); - key = &tk[0]; - keylen = sizeof(tk) < 64 ? sizeof(tk) : 64; - } else { - key = _KEYBUF(state->sav->key_auth); - keylen = _KEYLEN(state->sav->key_auth); - } - - bzero(ipad, 64); - bzero(opad, 64); - bcopy(key, ipad, keylen); - bcopy(key, opad, keylen); - for (i = 0; i < 64; i++) { - ipad[i] ^= 0x36; - opad[i] ^= 0x5c; - } - - bzero(ctxt, sizeof(*ctxt)); - SHA512_Init(ctxt); - SHA512_Update(ctxt, ipad, 64); - - return 0; -} - -static void -ah_hmac_sha2_512_loop(state, addr, len) - struct ah_algorithm_state *state; - u_int8_t *addr; - size_t len; -{ - SHA512_CTX *ctxt; - - if (!state || !state->foo) - panic("ah_hmac_sha2_512_loop: what?"); - - ctxt = (SHA512_CTX *)(((u_char *)state->foo) + 128); - SHA512_Update(ctxt, (caddr_t)addr, (size_t)len); -} - -static void -ah_hmac_sha2_512_result(state, addr, l) - struct ah_algorithm_state *state; - u_int8_t *addr; - size_t l; -{ - u_char digest[SHA512_DIGEST_LENGTH]; - u_char *ipad; - u_char *opad; - SHA512_CTX *ctxt; - - if (!state || !state->foo) - panic("ah_hmac_sha2_512_result: what?"); - - ipad = (u_char *)state->foo; - opad = (u_char *)(ipad + 64); - ctxt = (SHA512_CTX *)(opad + 64); - - SHA512_Final((caddr_t)digest, ctxt); - - bzero(ctxt, sizeof(*ctxt)); - SHA512_Init(ctxt); - SHA512_Update(ctxt, opad, 64); - SHA512_Update(ctxt, (caddr_t)digest, sizeof(digest)); - SHA512_Final((caddr_t)digest, ctxt); - - bcopy(digest, addr, sizeof(digest) > l ? l : sizeof(digest)); - - free(state->foo, M_TEMP); -} - -static int -ah_hmac_ripemd160_init(state, sav) - struct ah_algorithm_state *state; - struct secasvar *sav; -{ - u_char *ipad; - u_char *opad; - RMD160_CTX *ctxt; - u_char tk[RIPEMD160_RESULTLEN]; - u_char *key; - size_t keylen; - size_t i; - - if (!state) - panic("ah_hmac_ripemd160_init: what?"); - - state->sav = sav; - state->foo = (void *)malloc(64 + 64 + sizeof(RMD160_CTX), - M_TEMP, M_NOWAIT); - if (!state->foo) - return ENOBUFS; - bzero(state->foo, 64 + 64 + sizeof(RMD160_CTX)); - - ipad = (u_char *)state->foo; - opad = (u_char *)(ipad + 64); - ctxt = (RMD160_CTX *)(opad + 64); - - /* compress the key if necessery */ - if (64 < _KEYLEN(state->sav->key_auth)) { - bzero(tk, sizeof(tk)); - bzero(ctxt, sizeof(*ctxt)); - RMD160Init(ctxt); - RMD160Update(ctxt, _KEYBUF(state->sav->key_auth), - _KEYLEN(state->sav->key_auth)); - RMD160Final(&tk[0], ctxt); - key = &tk[0]; - keylen = sizeof(tk) < 64 ? sizeof(tk) : 64; - } else { - key = _KEYBUF(state->sav->key_auth); - keylen = _KEYLEN(state->sav->key_auth); - } - - bzero(ipad, 64); - bzero(opad, 64); - bcopy(key, ipad, keylen); - bcopy(key, opad, keylen); - for (i = 0; i < 64; i++) { - ipad[i] ^= 0x36; - opad[i] ^= 0x5c; - } - - bzero(ctxt, sizeof(*ctxt)); - RMD160Init(ctxt); - RMD160Update(ctxt, ipad, 64); - - return 0; -} - -static void -ah_hmac_ripemd160_loop(state, addr, len) - struct ah_algorithm_state *state; - u_int8_t *addr; - size_t len; -{ - RMD160_CTX *ctxt; - - if (!state || !state->foo) - panic("ah_hmac_ripemd160_loop: what?"); - - ctxt = (RMD160_CTX *)(((u_char *)state->foo) + 128); - RMD160Update(ctxt, (caddr_t)addr, (size_t)len); -} - -static void -ah_hmac_ripemd160_result(state, addr, l) - struct ah_algorithm_state *state; - u_int8_t *addr; - size_t l; -{ - u_char digest[RIPEMD160_RESULTLEN]; - u_char *ipad; - u_char *opad; - RMD160_CTX *ctxt; - - if (!state || !state->foo) - panic("ah_hmac_ripemd160_result: what?"); - - ipad = (u_char *)state->foo; - opad = (u_char *)(ipad + 64); - ctxt = (RMD160_CTX *)(opad + 64); - - RMD160Final((caddr_t)digest, ctxt); - - bzero(ctxt, sizeof(*ctxt)); - RMD160Init(ctxt); - RMD160Update(ctxt, opad, 64); - RMD160Update(ctxt, (caddr_t)digest, sizeof(digest)); - RMD160Final((caddr_t)digest, ctxt); - - bcopy(digest, addr, sizeof(digest) > l ? l : sizeof(digest)); - - free(state->foo, M_TEMP); -} - -/*------------------------------------------------------------*/ - -/* - * go generate the checksum. - */ -static void -ah_update_mbuf(m, off, len, algo, algos) - struct mbuf *m; - int off; - int len; - const struct ah_algorithm *algo; - struct ah_algorithm_state *algos; -{ - struct mbuf *n; - int tlen; - - /* easy case first */ - if (off + len <= m->m_len) { - (algo->update)(algos, mtod(m, u_int8_t *) + off, len); - return; - } - - for (n = m; n; n = n->m_next) { - if (off < n->m_len) - break; - - off -= n->m_len; - } - - if (!n) - panic("ah_update_mbuf: wrong offset specified"); - - for (/* nothing */; n && len > 0; n = n->m_next) { - if (n->m_len == 0) - continue; - if (n->m_len - off < len) - tlen = n->m_len - off; - else - tlen = len; - - (algo->update)(algos, mtod(n, u_int8_t *) + off, tlen); - - len -= tlen; - off = 0; - } -} - -#ifdef INET -/* - * Go generate the checksum. This function won't modify the mbuf chain - * except AH itself. - * - * NOTE: the function does not free mbuf on failure. - * Don't use m_copy(), it will try to share cluster mbuf by using refcnt. - */ -int -ah4_calccksum(m, ahdat, len, algo, sav) - struct mbuf *m; - u_int8_t * ahdat; - size_t len; - const struct ah_algorithm *algo; - struct secasvar *sav; -{ - int off; - int hdrtype; - size_t advancewidth; - struct ah_algorithm_state algos; - u_char sumbuf[AH_MAXSUMSIZE]; - int error = 0; - int ahseen; - struct mbuf *n = NULL; - - if ((m->m_flags & M_PKTHDR) == 0) - return EINVAL; - - ahseen = 0; - hdrtype = -1; /* dummy, it is called IPPROTO_IP */ - - off = 0; - - error = (algo->init)(&algos, sav); - if (error) - return error; - - advancewidth = 0; /* safety */ - -again: - /* gory. */ - switch (hdrtype) { - case -1: /* first one only */ - { - /* - * copy ip hdr, modify to fit the AH checksum rule, - * then take a checksum. - */ - struct ip iphdr; - size_t hlen; - - m_copydata(m, off, sizeof(iphdr), (caddr_t)&iphdr); -#ifdef _IP_VHL - hlen = IP_VHL_HL(iphdr.ip_vhl) << 2; -#else - hlen = iphdr.ip_hl << 2; -#endif - iphdr.ip_ttl = 0; - iphdr.ip_sum = htons(0); - if (ip4_ah_cleartos) - iphdr.ip_tos = 0; - iphdr.ip_off = htons(ntohs(iphdr.ip_off) & ip4_ah_offsetmask); - (algo->update)(&algos, (u_int8_t *)&iphdr, sizeof(struct ip)); - - if (hlen != sizeof(struct ip)) { - u_char *p; - int i, l, skip; - - if (hlen > MCLBYTES) { - error = EMSGSIZE; - goto fail; - } - MGET(n, M_DONTWAIT, MT_DATA); - if (n && hlen > MLEN) { - MCLGET(n, M_DONTWAIT); - if ((n->m_flags & M_EXT) == 0) { - m_free(n); - n = NULL; - } - } - if (n == NULL) { - error = ENOBUFS; - goto fail; - } - m_copydata(m, off, hlen, mtod(n, caddr_t)); - - /* - * IP options processing. - * See RFC2402 appendix A. - */ - p = mtod(n, u_char *); - i = sizeof(struct ip); - while (i < hlen) { - if (i + IPOPT_OPTVAL >= hlen) { - ipseclog((LOG_ERR, "ah4_calccksum: " - "invalid IP option\n")); - error = EINVAL; - goto fail; - } - if (p[i + IPOPT_OPTVAL] == IPOPT_EOL || - p[i + IPOPT_OPTVAL] == IPOPT_NOP || - i + IPOPT_OLEN < hlen) - ; - else { - ipseclog((LOG_ERR, - "ah4_calccksum: invalid IP option " - "(type=%02x)\n", - p[i + IPOPT_OPTVAL])); - error = EINVAL; - goto fail; - } - - skip = 1; - switch (p[i + IPOPT_OPTVAL]) { - case IPOPT_EOL: - case IPOPT_NOP: - l = 1; - skip = 0; - break; - case IPOPT_SECURITY: /* 0x82 */ - case 0x85: /* Extended security */ - case 0x86: /* Commercial security */ - case 0x94: /* Router alert */ - case 0x95: /* RFC1770 */ - l = p[i + IPOPT_OLEN]; - if (l < 2) - goto invalopt; - skip = 0; - break; - default: - l = p[i + IPOPT_OLEN]; - if (l < 2) - goto invalopt; - skip = 1; - break; - } - if (l < 1 || hlen - i < l) { - invalopt: - ipseclog((LOG_ERR, - "ah4_calccksum: invalid IP option " - "(type=%02x len=%02x)\n", - p[i + IPOPT_OPTVAL], - p[i + IPOPT_OLEN])); - error = EINVAL; - goto fail; - } - if (skip) - bzero(p + i, l); - if (p[i + IPOPT_OPTVAL] == IPOPT_EOL) - break; - i += l; - } - p = mtod(n, u_char *) + sizeof(struct ip); - (algo->update)(&algos, p, hlen - sizeof(struct ip)); - - m_free(n); - n = NULL; - } - - hdrtype = (iphdr.ip_p) & 0xff; - advancewidth = hlen; - break; - } - - case IPPROTO_AH: - { - struct ah ah; - int siz; - int hdrsiz; - int totlen; - - m_copydata(m, off, sizeof(ah), (caddr_t)&ah); - hdrsiz = (sav->flags & SADB_X_EXT_OLD) - ? sizeof(struct ah) - : sizeof(struct newah); - siz = (*algo->sumsiz)(sav); - totlen = (ah.ah_len + 2) << 2; - - /* - * special treatment is necessary for the first one, not others - */ - if (!ahseen) { - if (totlen > m->m_pkthdr.len - off || - totlen > MCLBYTES) { - error = EMSGSIZE; - goto fail; - } - MGET(n, M_DONTWAIT, MT_DATA); - if (n && totlen > MLEN) { - MCLGET(n, M_DONTWAIT); - if ((n->m_flags & M_EXT) == 0) { - m_free(n); - n = NULL; - } - } - if (n == NULL) { - error = ENOBUFS; - goto fail; - } - m_copydata(m, off, totlen, mtod(n, caddr_t)); - n->m_len = totlen; - bzero(mtod(n, u_int8_t *) + hdrsiz, siz); - (algo->update)(&algos, mtod(n, u_int8_t *), n->m_len); - m_free(n); - n = NULL; - } else - ah_update_mbuf(m, off, totlen, algo, &algos); - ahseen++; - - hdrtype = ah.ah_nxt; - advancewidth = totlen; - break; - } - - default: - ah_update_mbuf(m, off, m->m_pkthdr.len - off, algo, &algos); - advancewidth = m->m_pkthdr.len - off; - break; - } - - off += advancewidth; - if (off < m->m_pkthdr.len) - goto again; - - if (len < (*algo->sumsiz)(sav)) { - error = EINVAL; - goto fail; - } - - (algo->result)(&algos, sumbuf, sizeof(sumbuf)); - bcopy(&sumbuf[0], ahdat, (*algo->sumsiz)(sav)); - - if (n) - m_free(n); - return error; - -fail: - if (n) - m_free(n); - return error; -} -#endif - -#ifdef INET6 -/* - * Go generate the checksum. This function won't modify the mbuf chain - * except AH itself. - * - * NOTE: the function does not free mbuf on failure. - * Don't use m_copy(), it will try to share cluster mbuf by using refcnt. - */ -int -ah6_calccksum(m, ahdat, len, algo, sav) - struct mbuf *m; - u_int8_t * ahdat; - size_t len; - const struct ah_algorithm *algo; - struct secasvar *sav; -{ - int newoff, off; - int proto, nxt; - struct mbuf *n = NULL; - int error; - int ahseen; - struct ah_algorithm_state algos; - u_char sumbuf[AH_MAXSUMSIZE]; - - if ((m->m_flags & M_PKTHDR) == 0) - return EINVAL; - - error = (algo->init)(&algos, sav); - if (error) - return error; - - off = 0; - proto = IPPROTO_IPV6; - nxt = -1; - ahseen = 0; - - again: - newoff = ip6_nexthdr(m, off, proto, &nxt); - if (newoff < 0) - newoff = m->m_pkthdr.len; - else if (newoff <= off) { - error = EINVAL; - goto fail; - } - - switch (proto) { - case IPPROTO_IPV6: - /* - * special treatment is necessary for the first one, not others - */ - if (off == 0) { - struct ip6_hdr ip6copy; - - if (newoff - off != sizeof(struct ip6_hdr)) { - error = EINVAL; - goto fail; - } - - m_copydata(m, off, newoff - off, (caddr_t)&ip6copy); - /* RFC2402 */ - ip6copy.ip6_flow = 0; - ip6copy.ip6_vfc &= ~IPV6_VERSION_MASK; - ip6copy.ip6_vfc |= IPV6_VERSION; - ip6copy.ip6_hlim = 0; - in6_clearscope(&ip6copy.ip6_src); /* XXX */ - in6_clearscope(&ip6copy.ip6_dst); /* XXX */ - (algo->update)(&algos, (u_int8_t *)&ip6copy, - sizeof(struct ip6_hdr)); - } else { - newoff = m->m_pkthdr.len; - ah_update_mbuf(m, off, m->m_pkthdr.len - off, algo, - &algos); - } - break; - - case IPPROTO_AH: - { - int siz; - int hdrsiz; - - hdrsiz = (sav->flags & SADB_X_EXT_OLD) - ? sizeof(struct ah) - : sizeof(struct newah); - siz = (*algo->sumsiz)(sav); - - /* - * special treatment is necessary for the first one, not others - */ - if (!ahseen) { - if (newoff - off > MCLBYTES) { - error = EMSGSIZE; - goto fail; - } - MGET(n, M_DONTWAIT, MT_DATA); - if (n && newoff - off > MLEN) { - MCLGET(n, M_DONTWAIT); - if ((n->m_flags & M_EXT) == 0) { - m_free(n); - n = NULL; - } - } - if (n == NULL) { - error = ENOBUFS; - goto fail; - } - m_copydata(m, off, newoff - off, mtod(n, caddr_t)); - n->m_len = newoff - off; - bzero(mtod(n, u_int8_t *) + hdrsiz, siz); - (algo->update)(&algos, mtod(n, u_int8_t *), n->m_len); - m_free(n); - n = NULL; - } else - ah_update_mbuf(m, off, newoff - off, algo, &algos); - ahseen++; - break; - } - - case IPPROTO_HOPOPTS: - case IPPROTO_DSTOPTS: - { - struct ip6_ext *ip6e; - int hdrlen, optlen; - u_int8_t *p, *optend, *optp; - - if (newoff - off > MCLBYTES) { - error = EMSGSIZE; - goto fail; - } - MGET(n, M_DONTWAIT, MT_DATA); - if (n && newoff - off > MLEN) { - MCLGET(n, M_DONTWAIT); - if ((n->m_flags & M_EXT) == 0) { - m_free(n); - n = NULL; - } - } - if (n == NULL) { - error = ENOBUFS; - goto fail; - } - m_copydata(m, off, newoff - off, mtod(n, caddr_t)); - n->m_len = newoff - off; - - ip6e = mtod(n, struct ip6_ext *); - hdrlen = (ip6e->ip6e_len + 1) << 3; - if (newoff - off < hdrlen) { - error = EINVAL; - m_free(n); - n = NULL; - goto fail; - } - p = mtod(n, u_int8_t *); - optend = p + hdrlen; - - /* - * ICV calculation for the options header including all - * options. This part is a little tricky since there are - * two type of options; mutable and immutable. We try to - * null-out mutable ones here. - */ - optp = p + 2; - while (optp < optend) { - if (optp[0] == IP6OPT_PAD1) - optlen = 1; - else { - if (optp + 2 > optend) { - error = EINVAL; - m_free(n); - n = NULL; - goto fail; - } - optlen = optp[1] + 2; - } - - if (optp + optlen > optend) { - error = EINVAL; - m_free(n); - n = NULL; - goto fail; - } - - if (optp[0] & IP6OPT_MUTABLE) - bzero(optp + 2, optlen - 2); - - optp += optlen; - } - - (algo->update)(&algos, mtod(n, u_int8_t *), n->m_len); - m_free(n); - n = NULL; - break; - } - - case IPPROTO_ROUTING: - /* - * For an input packet, we can just calculate `as is'. - * For an output packet, we assume ip6_output have already - * made packet how it will be received at the final - * destination. - */ - /* FALLTHROUGH */ - - default: - ah_update_mbuf(m, off, newoff - off, algo, &algos); - break; - } - - if (newoff < m->m_pkthdr.len) { - proto = nxt; - off = newoff; - goto again; - } - - if (len < (*algo->sumsiz)(sav)) { - error = EINVAL; - goto fail; - } - - (algo->result)(&algos, sumbuf, sizeof(sumbuf)); - bcopy(&sumbuf[0], ahdat, (*algo->sumsiz)(sav)); - - /* just in case */ - if (n) - m_free(n); - return 0; -fail: - /* just in case */ - if (n) - m_free(n); - return error; -} -#endif diff --git a/sys/netinet6/ah_input.c b/sys/netinet6/ah_input.c deleted file mode 100644 index 4a65659..0000000 --- a/sys/netinet6/ah_input.c +++ /dev/null @@ -1,1024 +0,0 @@ -/* $FreeBSD$ */ -/* $KAME: ah_input.c,v 1.67 2002/01/07 11:39:56 kjc Exp $ */ - -/*- - * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * RFC1826/2402 authentication header. - */ - -#include "opt_inet.h" -#include "opt_inet6.h" - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/malloc.h> -#include <sys/mbuf.h> -#include <sys/domain.h> -#include <sys/protosw.h> -#include <sys/socket.h> -#include <sys/errno.h> -#include <sys/time.h> -#include <sys/syslog.h> - -#include <net/if.h> -#include <net/route.h> -#include <net/netisr.h> -#include <machine/cpu.h> - -#include <netinet/in.h> -#include <netinet/in_systm.h> -#include <netinet/in_var.h> -#include <netinet/ip.h> -#include <netinet/ip_var.h> -#include <netinet/ip_ecn.h> -#ifdef INET6 -#include <netinet6/ip6_ecn.h> -#endif - -#ifdef INET6 -#include <netinet/ip6.h> -#include <netinet6/ip6_var.h> -#include <netinet/in_pcb.h> -#include <netinet6/in6_pcb.h> -#include <netinet/icmp6.h> -#include <netinet6/ip6protosw.h> -#endif - -#include <netinet6/ipsec.h> -#ifdef INET6 -#include <netinet6/ipsec6.h> -#endif -#include <netinet6/ah.h> -#ifdef INET6 -#include <netinet6/ah6.h> -#endif -#include <netkey/key.h> -#include <netkey/keydb.h> -#ifdef IPSEC_DEBUG -#include <netkey/key_debug.h> -#else -#define KEYDEBUG(lev,arg) -#endif - -#include <machine/stdarg.h> - -#define IPLEN_FLIPPED - -#ifdef INET -extern struct protosw inetsw[]; - -void -ah4_input(m, off) - struct mbuf *m; - int off; -{ - struct ip *ip; - struct ah *ah; - u_int32_t spi; - const struct ah_algorithm *algo; - size_t siz; - size_t siz1; - u_int8_t cksum[AH_MAXSUMSIZE]; - struct secasvar *sav = NULL; - u_int16_t nxt; - size_t hlen; - size_t stripsiz = 0; - -#ifndef PULLDOWN_TEST - if (m->m_len < off + sizeof(struct newah)) { - m = m_pullup(m, off + sizeof(struct newah)); - if (!m) { - ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup;" - "dropping the packet for simplicity\n")); - ipsecstat.in_inval++; - goto fail; - } - } - - ip = mtod(m, struct ip *); - ah = (struct ah *)(((caddr_t)ip) + off); -#else - ip = mtod(m, struct ip *); - IP6_EXTHDR_GET(ah, struct ah *, m, off, sizeof(struct newah)); - if (ah == NULL) { - ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup;" - "dropping the packet for simplicity\n")); - ipsecstat.in_inval++; - goto fail; - } -#endif - nxt = ah->ah_nxt; -#ifdef _IP_VHL - hlen = IP_VHL_HL(ip->ip_vhl) << 2; -#else - hlen = ip->ip_hl << 2; -#endif - - /* find the sassoc. */ - spi = ah->ah_spi; - - if ((sav = key_allocsa(AF_INET, - (caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst, - IPPROTO_AH, spi)) == 0) { - ipseclog((LOG_WARNING, - "IPv4 AH input: no key association found for spi %u\n", - (u_int32_t)ntohl(spi))); - ipsecstat.in_nosa++; - goto fail; - } - KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP ah4_input called to allocate SA:%p\n", sav)); - if (sav->state != SADB_SASTATE_MATURE - && sav->state != SADB_SASTATE_DYING) { - ipseclog((LOG_DEBUG, - "IPv4 AH input: non-mature/dying SA found for spi %u\n", - (u_int32_t)ntohl(spi))); - ipsecstat.in_badspi++; - goto fail; - } - - algo = ah_algorithm_lookup(sav->alg_auth); - if (!algo) { - ipseclog((LOG_DEBUG, "IPv4 AH input: " - "unsupported authentication algorithm for spi %u\n", - (u_int32_t)ntohl(spi))); - ipsecstat.in_badspi++; - goto fail; - } - - siz = (*algo->sumsiz)(sav); - siz1 = ((siz + 3) & ~(4 - 1)); - - /* - * sanity checks for header, 1. - */ - { - int sizoff; - - sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4; - - /* - * Here, we do not do "siz1 == siz". This is because the way - * RFC240[34] section 2 is written. They do not require truncation - * to 96 bits. - * For example, Microsoft IPsec stack attaches 160 bits of - * authentication data for both hmac-md5 and hmac-sha1. For hmac-sha1, - * 32 bits of padding is attached. - * - * There are two downsides to this specification. - * They have no real harm, however, they leave us fuzzy feeling. - * - if we attach more than 96 bits of authentication data onto AH, - * we will never notice about possible modification by rogue - * intermediate nodes. - * Since extra bits in AH checksum is never used, this constitutes - * no real issue, however, it is wacky. - * - even if the peer attaches big authentication data, we will never - * notice the difference, since longer authentication data will just - * work. - * - * We may need some clarification in the spec. - */ - if (siz1 < siz) { - ipseclog((LOG_NOTICE, "sum length too short in IPv4 AH input " - "(%lu, should be at least %lu): %s\n", - (u_long)siz1, (u_long)siz, - ipsec4_logpacketstr(ip, spi))); - ipsecstat.in_inval++; - goto fail; - } - if ((ah->ah_len << 2) - sizoff != siz1) { - ipseclog((LOG_NOTICE, "sum length mismatch in IPv4 AH input " - "(%d should be %lu): %s\n", - (ah->ah_len << 2) - sizoff, (u_long)siz1, - ipsec4_logpacketstr(ip, spi))); - ipsecstat.in_inval++; - goto fail; - } - if (siz1 > sizeof(cksum)) { - ipseclog((LOG_NOTICE, "sum length too large: %s\n", - ipsec4_logpacketstr(ip, spi))); - ipsecstat.in_inval++; - goto fail; - } - -#ifndef PULLDOWN_TEST - if (m->m_len < off + sizeof(struct ah) + sizoff + siz1) { - m = m_pullup(m, off + sizeof(struct ah) + sizoff + siz1); - if (!m) { - ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup\n")); - ipsecstat.in_inval++; - goto fail; - } - - ip = mtod(m, struct ip *); - ah = (struct ah *)(((caddr_t)ip) + off); - } -#else - IP6_EXTHDR_GET(ah, struct ah *, m, off, - sizeof(struct ah) + sizoff + siz1); - if (ah == NULL) { - ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup\n")); - ipsecstat.in_inval++; - goto fail; - } -#endif - } - - /* - * check for sequence number. - */ - if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) { - if (ipsec_chkreplay(ntohl(((struct newah *)ah)->ah_seq), sav)) - ; /* okey */ - else { - ipsecstat.in_ahreplay++; - ipseclog((LOG_WARNING, - "replay packet in IPv4 AH input: %s %s\n", - ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav))); - goto fail; - } - } - - /* - * alright, it seems sane. now we are going to check the - * cryptographic checksum. - */ - - /* - * some of IP header fields are flipped to the host endian. - * convert them back to network endian. VERY stupid. - */ - ip->ip_len = htons(ip->ip_len + hlen); - ip->ip_off = htons(ip->ip_off); - if (ah4_calccksum(m, cksum, siz1, algo, sav)) { - ipsecstat.in_inval++; - goto fail; - } - ipsecstat.in_ahhist[sav->alg_auth]++; - /* - * flip them back. - */ - ip->ip_len = ntohs(ip->ip_len) - hlen; - ip->ip_off = ntohs(ip->ip_off); - - { - caddr_t sumpos = NULL; - - if (sav->flags & SADB_X_EXT_OLD) { - /* RFC 1826 */ - sumpos = (caddr_t)(ah + 1); - } else { - /* RFC 2402 */ - sumpos = (caddr_t)(((struct newah *)ah) + 1); - } - - if (bcmp(sumpos, cksum, siz) != 0) { - ipseclog((LOG_WARNING, - "checksum mismatch in IPv4 AH input: %s %s\n", - ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav))); - ipsecstat.in_ahauthfail++; - goto fail; - } - } - - m->m_flags |= M_AUTHIPHDR; - m->m_flags |= M_AUTHIPDGM; - -#if 0 - /* - * looks okey, but we need more sanity check. - * XXX should elaborate. - */ - if (ah->ah_nxt == IPPROTO_IPIP || ah->ah_nxt == IPPROTO_IP) { - struct ip *nip; - size_t sizoff; - - sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4; - - if (m->m_len < off + sizeof(struct ah) + sizoff + siz1 + hlen) { - m = m_pullup(m, off + sizeof(struct ah) - + sizoff + siz1 + hlen); - if (!m) { - ipseclog((LOG_DEBUG, - "IPv4 AH input: can't pullup\n")); - ipsecstat.in_inval++; - goto fail; - } - } - - nip = (struct ip *)((u_char *)(ah + 1) + sizoff + siz1); - if (nip->ip_src.s_addr != ip->ip_src.s_addr - || nip->ip_dst.s_addr != ip->ip_dst.s_addr) { - m->m_flags &= ~M_AUTHIPHDR; - m->m_flags &= ~M_AUTHIPDGM; - } - } -#ifdef INET6 - else if (ah->ah_nxt == IPPROTO_IPV6) { - m->m_flags &= ~M_AUTHIPHDR; - m->m_flags &= ~M_AUTHIPDGM; - } -#endif /* INET6 */ -#endif /* 0 */ - - if (m->m_flags & M_AUTHIPHDR - && m->m_flags & M_AUTHIPDGM) { -#if 0 - ipseclog((LOG_DEBUG, - "IPv4 AH input: authentication succeess\n")); -#endif - ipsecstat.in_ahauthsucc++; - } else { - ipseclog((LOG_WARNING, - "authentication failed in IPv4 AH input: %s %s\n", - ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav))); - ipsecstat.in_ahauthfail++; - goto fail; - } - - /* - * update sequence number. - */ - if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) { - if (ipsec_updatereplay(ntohl(((struct newah *)ah)->ah_seq), sav)) { - ipsecstat.in_ahreplay++; - goto fail; - } - } - - /* was it transmitted over the IPsec tunnel SA? */ - if (sav->flags & SADB_X_EXT_OLD) { - /* RFC 1826 */ - stripsiz = sizeof(struct ah) + siz1; - } else { - /* RFC 2402 */ - stripsiz = sizeof(struct newah) + siz1; - } - if (ipsec4_tunnel_validate(m, off + stripsiz, nxt, sav)) { - /* - * strip off all the headers that precedes AH. - * IP xx AH IP' payload -> IP' payload - * - * XXX more sanity checks - * XXX relationship with gif? - */ - u_int8_t tos; - - tos = ip->ip_tos; - m_adj(m, off + stripsiz); - if (m->m_len < sizeof(*ip)) { - m = m_pullup(m, sizeof(*ip)); - if (!m) { - ipsecstat.in_inval++; - goto fail; - } - } - ip = mtod(m, struct ip *); - /* ECN consideration. */ - if (!ip_ecn_egress(ip4_ipsec_ecn, &tos, &ip->ip_tos)) { - ipsecstat.in_inval++; - goto fail; - } - if (!key_checktunnelsanity(sav, AF_INET, - (caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst)) { - ipseclog((LOG_NOTICE, "ipsec tunnel address mismatch " - "in IPv4 AH input: %s %s\n", - ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav))); - ipsecstat.in_inval++; - goto fail; - } - -#if 1 - /* - * Should the inner packet be considered authentic? - * My current answer is: NO. - * - * host1 -- gw1 === gw2 -- host2 - * In this case, gw2 can trust the authenticity of the - * outer packet, but NOT inner. Packet may be altered - * between host1 and gw1. - * - * host1 -- gw1 === host2 - * This case falls into the same scenario as above. - * - * host1 === host2 - * This case is the only case when we may be able to leave - * M_AUTHIPHDR and M_AUTHIPDGM set. - * However, if host1 is wrongly configured, and allows - * attacker to inject some packet with src=host1 and - * dst=host2, you are in risk. - */ - m->m_flags &= ~M_AUTHIPHDR; - m->m_flags &= ~M_AUTHIPDGM; -#endif - - key_sa_recordxfer(sav, m); - if (ipsec_addhist(m, IPPROTO_AH, spi) != 0 || - ipsec_addhist(m, IPPROTO_IPV4, 0) != 0) { - ipsecstat.in_nomem++; - goto fail; - } - - if (netisr_queue(NETISR_IP, m)) { /* (0) on success. */ - ipsecstat.in_inval++; - m = NULL; - goto fail; - } - m = NULL; - nxt = IPPROTO_DONE; - } else { - /* - * strip off AH. - */ - - ip = mtod(m, struct ip *); -#ifndef PULLDOWN_TEST - /* - * We do deep-copy since KAME requires that - * the packet is placed in a single external mbuf. - */ - ovbcopy((caddr_t)ip, (caddr_t)(((u_char *)ip) + stripsiz), off); - m->m_data += stripsiz; - m->m_len -= stripsiz; - m->m_pkthdr.len -= stripsiz; -#else - /* - * even in m_pulldown case, we need to strip off AH so that - * we can compute checksum for multiple AH correctly. - */ - if (m->m_len >= stripsiz + off) { - ovbcopy((caddr_t)ip, ((caddr_t)ip) + stripsiz, off); - m->m_data += stripsiz; - m->m_len -= stripsiz; - m->m_pkthdr.len -= stripsiz; - } else { - /* - * this comes with no copy if the boundary is on - * cluster - */ - struct mbuf *n; - - n = m_split(m, off, M_DONTWAIT); - if (n == NULL) { - /* m is retained by m_split */ - goto fail; - } - m_adj(n, stripsiz); - /* m_cat does not update m_pkthdr.len */ - m->m_pkthdr.len += n->m_pkthdr.len; - m_cat(m, n); - } -#endif - - if (m->m_len < sizeof(*ip)) { - m = m_pullup(m, sizeof(*ip)); - if (m == NULL) { - ipsecstat.in_inval++; - goto fail; - } - } - ip = mtod(m, struct ip *); -#ifdef IPLEN_FLIPPED - ip->ip_len = ip->ip_len - stripsiz; -#else - ip->ip_len = htons(ntohs(ip->ip_len) - stripsiz); -#endif - ip->ip_p = nxt; - /* forget about IP hdr checksum, the check has already been passed */ - - key_sa_recordxfer(sav, m); - if (ipsec_addhist(m, IPPROTO_AH, spi) != 0) { - ipsecstat.in_nomem++; - goto fail; - } - - if (nxt != IPPROTO_DONE) { - if ((inetsw[ip_protox[nxt]].pr_flags & PR_LASTHDR) != 0 && - ipsec4_in_reject(m, NULL)) { - ipsecstat.in_polvio++; - goto fail; - } - (*inetsw[ip_protox[nxt]].pr_input)(m, off); - } else - m_freem(m); - m = NULL; - } - - if (sav) { - KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP ah4_input call free SA:%p\n", sav)); - key_freesav(sav); - } - ipsecstat.in_success++; - return; - -fail: - if (sav) { - KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP ah4_input call free SA:%p\n", sav)); - key_freesav(sav); - } - if (m) - m_freem(m); - return; -} -#endif /* INET */ - -#ifdef INET6 -int -ah6_input(mp, offp, proto) - struct mbuf **mp; - int *offp, proto; -{ - struct mbuf *m = *mp; - int off = *offp; - struct ip6_hdr *ip6; - struct ah *ah; - u_int32_t spi; - const struct ah_algorithm *algo; - size_t siz; - size_t siz1; - u_int8_t cksum[AH_MAXSUMSIZE]; - struct secasvar *sav = NULL; - u_int16_t nxt; - size_t stripsiz = 0; - -#ifndef PULLDOWN_TEST - IP6_EXTHDR_CHECK(m, off, sizeof(struct ah), IPPROTO_DONE); - ah = (struct ah *)(mtod(m, caddr_t) + off); -#else - IP6_EXTHDR_GET(ah, struct ah *, m, off, sizeof(struct newah)); - if (ah == NULL) { - ipseclog((LOG_DEBUG, "IPv6 AH input: can't pullup\n")); - ipsec6stat.in_inval++; - return IPPROTO_DONE; - } -#endif - ip6 = mtod(m, struct ip6_hdr *); - nxt = ah->ah_nxt; - - /* find the sassoc. */ - spi = ah->ah_spi; - - if (ntohs(ip6->ip6_plen) == 0) { - ipseclog((LOG_ERR, "IPv6 AH input: " - "AH with IPv6 jumbogram is not supported.\n")); - ipsec6stat.in_inval++; - goto fail; - } - - if ((sav = key_allocsa(AF_INET6, - (caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst, - IPPROTO_AH, spi)) == 0) { - ipseclog((LOG_WARNING, - "IPv6 AH input: no key association found for spi %u\n", - (u_int32_t)ntohl(spi))); - ipsec6stat.in_nosa++; - goto fail; - } - KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP ah6_input called to allocate SA:%p\n", sav)); - if (sav->state != SADB_SASTATE_MATURE - && sav->state != SADB_SASTATE_DYING) { - ipseclog((LOG_DEBUG, - "IPv6 AH input: non-mature/dying SA found for spi %u; ", - (u_int32_t)ntohl(spi))); - ipsec6stat.in_badspi++; - goto fail; - } - - algo = ah_algorithm_lookup(sav->alg_auth); - if (!algo) { - ipseclog((LOG_DEBUG, "IPv6 AH input: " - "unsupported authentication algorithm for spi %u\n", - (u_int32_t)ntohl(spi))); - ipsec6stat.in_badspi++; - goto fail; - } - - siz = (*algo->sumsiz)(sav); - siz1 = ((siz + 3) & ~(4 - 1)); - - /* - * sanity checks for header, 1. - */ - { - int sizoff; - - sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4; - - /* - * Here, we do not do "siz1 == siz". See ah4_input() for complete - * description. - */ - if (siz1 < siz) { - ipseclog((LOG_NOTICE, "sum length too short in IPv6 AH input " - "(%lu, should be at least %lu): %s\n", - (u_long)siz1, (u_long)siz, - ipsec6_logpacketstr(ip6, spi))); - ipsec6stat.in_inval++; - goto fail; - } - if ((ah->ah_len << 2) - sizoff != siz1) { - ipseclog((LOG_NOTICE, "sum length mismatch in IPv6 AH input " - "(%d should be %lu): %s\n", - (ah->ah_len << 2) - sizoff, (u_long)siz1, - ipsec6_logpacketstr(ip6, spi))); - ipsec6stat.in_inval++; - goto fail; - } - if (siz1 > sizeof(cksum)) { - ipseclog((LOG_NOTICE, "sum length too large: %s\n", - ipsec6_logpacketstr(ip6, spi))); - ipsec6stat.in_inval++; - goto fail; - } - -#ifndef PULLDOWN_TEST - IP6_EXTHDR_CHECK(m, off, sizeof(struct ah) + sizoff + siz1, IPPROTO_DONE); -#else - IP6_EXTHDR_GET(ah, struct ah *, m, off, - sizeof(struct ah) + sizoff + siz1); - if (ah == NULL) { - ipseclog((LOG_NOTICE, "couldn't pullup gather IPv6 AH checksum part")); - ipsec6stat.in_inval++; - m = NULL; - goto fail; - } -#endif - } - - /* - * check for sequence number. - */ - if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) { - if (ipsec_chkreplay(ntohl(((struct newah *)ah)->ah_seq), sav)) - ; /* okey */ - else { - ipsec6stat.in_ahreplay++; - ipseclog((LOG_WARNING, - "replay packet in IPv6 AH input: %s %s\n", - ipsec6_logpacketstr(ip6, spi), - ipsec_logsastr(sav))); - goto fail; - } - } - - /* - * alright, it seems sane. now we are going to check the - * cryptographic checksum. - */ - - if (ah6_calccksum(m, cksum, siz1, algo, sav)) { - ipsec6stat.in_inval++; - goto fail; - } - ipsec6stat.in_ahhist[sav->alg_auth]++; - - { - caddr_t sumpos = NULL; - - if (sav->flags & SADB_X_EXT_OLD) { - /* RFC 1826 */ - sumpos = (caddr_t)(ah + 1); - } else { - /* RFC 2402 */ - sumpos = (caddr_t)(((struct newah *)ah) + 1); - } - - if (bcmp(sumpos, cksum, siz) != 0) { - ipseclog((LOG_WARNING, - "checksum mismatch in IPv6 AH input: %s %s\n", - ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav))); - ipsec6stat.in_ahauthfail++; - goto fail; - } - } - - m->m_flags |= M_AUTHIPHDR; - m->m_flags |= M_AUTHIPDGM; - -#if 0 - /* - * looks okey, but we need more sanity check. - * XXX should elaborate. - */ - if (ah->ah_nxt == IPPROTO_IPV6) { - struct ip6_hdr *nip6; - size_t sizoff; - - sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4; - - IP6_EXTHDR_CHECK(m, off, sizeof(struct ah) + sizoff + siz1 - + sizeof(struct ip6_hdr), IPPROTO_DONE); - - nip6 = (struct ip6_hdr *)((u_char *)(ah + 1) + sizoff + siz1); - if (!IN6_ARE_ADDR_EQUAL(&nip6->ip6_src, &ip6->ip6_src) - || !IN6_ARE_ADDR_EQUAL(&nip6->ip6_dst, &ip6->ip6_dst)) { - m->m_flags &= ~M_AUTHIPHDR; - m->m_flags &= ~M_AUTHIPDGM; - } - } else if (ah->ah_nxt == IPPROTO_IPIP) { - m->m_flags &= ~M_AUTHIPHDR; - m->m_flags &= ~M_AUTHIPDGM; - } else if (ah->ah_nxt == IPPROTO_IP) { - m->m_flags &= ~M_AUTHIPHDR; - m->m_flags &= ~M_AUTHIPDGM; - } -#endif - - if (m->m_flags & M_AUTHIPHDR - && m->m_flags & M_AUTHIPDGM) { -#if 0 - ipseclog((LOG_DEBUG, - "IPv6 AH input: authentication succeess\n")); -#endif - ipsec6stat.in_ahauthsucc++; - } else { - ipseclog((LOG_WARNING, - "authentication failed in IPv6 AH input: %s %s\n", - ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav))); - ipsec6stat.in_ahauthfail++; - goto fail; - } - - /* - * update sequence number. - */ - if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) { - if (ipsec_updatereplay(ntohl(((struct newah *)ah)->ah_seq), sav)) { - ipsec6stat.in_ahreplay++; - goto fail; - } - } - - /* was it transmitted over the IPsec tunnel SA? */ - if (sav->flags & SADB_X_EXT_OLD) { - /* RFC 1826 */ - stripsiz = sizeof(struct ah) + siz1; - } else { - /* RFC 2402 */ - stripsiz = sizeof(struct newah) + siz1; - } - if (ipsec6_tunnel_validate(m, off + stripsiz, nxt, sav)) { - /* - * strip off all the headers that precedes AH. - * IP6 xx AH IP6' payload -> IP6' payload - * - * XXX more sanity checks - * XXX relationship with gif? - */ - u_int32_t flowinfo; /* net endian */ - - flowinfo = ip6->ip6_flow; - m_adj(m, off + stripsiz); - if (m->m_len < sizeof(*ip6)) { - m = m_pullup(m, sizeof(*ip6)); - if (!m) { - ipsec6stat.in_inval++; - goto fail; - } - } - ip6 = mtod(m, struct ip6_hdr *); - /* ECN consideration. */ - if (!ip6_ecn_egress(ip6_ipsec_ecn, &flowinfo, &ip6->ip6_flow)) { - ipsec6stat.in_inval++; - goto fail; - } - if (!key_checktunnelsanity(sav, AF_INET6, - (caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst)) { - ipseclog((LOG_NOTICE, "ipsec tunnel address mismatch " - "in IPv6 AH input: %s %s\n", - ipsec6_logpacketstr(ip6, spi), - ipsec_logsastr(sav))); - ipsec6stat.in_inval++; - goto fail; - } - -#if 1 - /* - * should the inner packet be considered authentic? - * see comment in ah4_input(). - */ - m->m_flags &= ~M_AUTHIPHDR; - m->m_flags &= ~M_AUTHIPDGM; -#endif - - key_sa_recordxfer(sav, m); - if (ipsec_addhist(m, IPPROTO_AH, spi) != 0 || - ipsec_addhist(m, IPPROTO_IPV6, 0) != 0) { - ipsec6stat.in_nomem++; - goto fail; - } - - if (netisr_queue(NETISR_IPV6, m)) { /* (0) on success. */ - ipsec6stat.in_inval++; - m = NULL; - goto fail; - } - m = NULL; - nxt = IPPROTO_DONE; - } else { - /* - * strip off AH. - */ - u_int8_t *prvnxtp; - - /* - * Copy the value of the next header field of AH to the - * next header field of the previous header. - * This is necessary because AH will be stripped off below. - */ - prvnxtp = ip6_get_prevhdr(m, off); /* XXX */ - *prvnxtp = nxt; - - ip6 = mtod(m, struct ip6_hdr *); -#ifndef PULLDOWN_TEST - /* - * We do deep-copy since KAME requires that - * the packet is placed in a single mbuf. - */ - ovbcopy((caddr_t)ip6, ((caddr_t)ip6) + stripsiz, off); - m->m_data += stripsiz; - m->m_len -= stripsiz; - m->m_pkthdr.len -= stripsiz; -#else - /* - * even in m_pulldown case, we need to strip off AH so that - * we can compute checksum for multiple AH correctly. - */ - if (m->m_len >= stripsiz + off) { - ovbcopy((caddr_t)ip6, ((caddr_t)ip6) + stripsiz, off); - m->m_data += stripsiz; - m->m_len -= stripsiz; - m->m_pkthdr.len -= stripsiz; - } else { - /* - * this comes with no copy if the boundary is on - * cluster - */ - struct mbuf *n; - - n = m_split(m, off, M_DONTWAIT); - if (n == NULL) { - /* m is retained by m_split */ - goto fail; - } - m_adj(n, stripsiz); - /* m_cat does not update m_pkthdr.len */ - m->m_pkthdr.len += n->m_pkthdr.len; - m_cat(m, n); - } -#endif - ip6 = mtod(m, struct ip6_hdr *); - /* XXX jumbogram */ - ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - stripsiz); - - key_sa_recordxfer(sav, m); - if (ipsec_addhist(m, IPPROTO_AH, spi) != 0) { - ipsec6stat.in_nomem++; - goto fail; - } - } - - *offp = off; - *mp = m; - - if (sav) { - KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP ah6_input call free SA:%p\n", sav)); - key_freesav(sav); - } - ipsec6stat.in_success++; - return nxt; - -fail: - if (sav) { - KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP ah6_input call free SA:%p\n", sav)); - key_freesav(sav); - } - if (m) - m_freem(m); - return IPPROTO_DONE; -} - -void -ah6_ctlinput(cmd, sa, d) - int cmd; - struct sockaddr *sa; - void *d; -{ - const struct newah *ahp; - struct newah ah; - struct secasvar *sav; - struct ip6_hdr *ip6; - struct mbuf *m; - struct ip6ctlparam *ip6cp = NULL; - int off; - struct sockaddr_in6 *sa6_src, *sa6_dst; - - if (sa->sa_family != AF_INET6 || - sa->sa_len != sizeof(struct sockaddr_in6)) - return; - if ((unsigned)cmd >= PRC_NCMDS) - return; - - /* if the parameter is from icmp6, decode it. */ - if (d != NULL) { - ip6cp = (struct ip6ctlparam *)d; - m = ip6cp->ip6c_m; - ip6 = ip6cp->ip6c_ip6; - off = ip6cp->ip6c_off; - } else { - m = NULL; - ip6 = NULL; - off = 0; /* calm gcc */ - } - - if (ip6) { - /* - * XXX: We assume that when ip6 is non NULL, - * M and OFF are valid. - */ - - /* check if we can safely examine src and dst ports */ - if (m->m_pkthdr.len < off + sizeof(ah)) - return; - - if (m->m_len < off + sizeof(ah)) { - /* - * this should be rare case, - * so we compromise on this copy... - */ - m_copydata(m, off, sizeof(ah), (caddr_t)&ah); - ahp = &ah; - } else - ahp = (struct newah *)(mtod(m, caddr_t) + off); - - if (cmd == PRC_MSGSIZE) { - int valid = 0; - - /* - * Check to see if we have a valid SA corresponding to - * the address in the ICMP message payload. - */ - sa6_src = ip6cp->ip6c_src; - sa6_dst = (struct sockaddr_in6 *)sa; - sav = key_allocsa(AF_INET6, - (caddr_t)&sa6_src->sin6_addr, - (caddr_t)&sa6_dst->sin6_addr, - IPPROTO_AH, ahp->ah_spi); - if (sav) { - if (sav->state == SADB_SASTATE_MATURE || - sav->state == SADB_SASTATE_DYING) - valid++; - key_freesav(sav); - } - - /* XXX Further validation? */ - - /* - * Depending on the value of "valid" and routing table - * size (mtudisc_{hi,lo}wat), we will: - * - recalcurate the new MTU and create the - * corresponding routing entry, or - * - ignore the MTU change notification. - */ - icmp6_mtudisc_update((struct ip6ctlparam *)d, valid); - } - - /* we normally notify single pcb here */ - } else { - /* we normally notify any pcb here */ - } -} -#endif /* INET6 */ diff --git a/sys/netinet6/ah_output.c b/sys/netinet6/ah_output.c deleted file mode 100644 index c58ca0e..0000000 --- a/sys/netinet6/ah_output.c +++ /dev/null @@ -1,586 +0,0 @@ -/* $FreeBSD$ */ -/* $KAME: ah_output.c,v 1.38 2003/09/06 05:15:43 itojun Exp $ */ - -/*- - * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * RFC1826/2402 authentication header. - */ - -#include "opt_inet.h" -#include "opt_inet6.h" - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/mbuf.h> -#include <sys/domain.h> -#include <sys/protosw.h> -#include <sys/socket.h> -#include <sys/socketvar.h> -#include <sys/errno.h> -#include <sys/time.h> -#include <sys/syslog.h> - -#include <net/if.h> -#include <net/route.h> - -#include <netinet/in.h> - -#include <netinet/in_systm.h> -#include <netinet/ip.h> -#include <netinet/in_var.h> - -#ifdef INET6 -#include <netinet/ip6.h> -#include <netinet6/ip6_var.h> -#include <netinet/icmp6.h> -#endif - -#include <netinet6/ipsec.h> -#ifdef INET6 -#include <netinet6/ipsec6.h> -#endif -#include <netinet6/ah.h> -#ifdef INET6 -#include <netinet6/ah6.h> -#endif -#include <netkey/key.h> -#include <netkey/keydb.h> - -#ifdef INET -static struct in_addr *ah4_finaldst __P((struct mbuf *)); -#endif - -/* - * compute AH header size. - * transport mode only. for tunnel mode, we should implement - * virtual interface, and control MTU/MSS by the interface MTU. - */ -size_t -ah_hdrsiz(isr) - struct ipsecrequest *isr; -{ - const struct ah_algorithm *algo; - size_t hdrsiz; - - /* sanity check */ - if (isr == NULL) - panic("ah_hdrsiz: NULL was passed."); - - if (isr->saidx.proto != IPPROTO_AH) - panic("unsupported mode passed to ah_hdrsiz"); - - if (isr->sav == NULL) - goto estimate; - if (isr->sav->state != SADB_SASTATE_MATURE - && isr->sav->state != SADB_SASTATE_DYING) - goto estimate; - - /* we need transport mode AH. */ - algo = ah_algorithm_lookup(isr->sav->alg_auth); - if (!algo) - goto estimate; - - /* - * XXX - * right now we don't calcurate the padding size. simply - * treat the padding size as constant, for simplicity. - * - * XXX variable size padding support - */ - hdrsiz = (((*algo->sumsiz)(isr->sav) + 3) & ~(4 - 1)); - if (isr->sav->flags & SADB_X_EXT_OLD) - hdrsiz += sizeof(struct ah); - else - hdrsiz += sizeof(struct newah); - - return hdrsiz; - - estimate: - /* ASSUMING: - * sizeof(struct newah) > sizeof(struct ah). - * AH_MAXSUMSIZE is multiple of 4. - */ - return sizeof(struct newah) + AH_MAXSUMSIZE; -} - -#ifdef INET -/* - * Modify the packet so that it includes the authentication data. - * The mbuf passed must start with IPv4 header. - * - * assumes that the first mbuf contains IPv4 header + option only. - * the function does not modify m. - */ -int -ah4_output(m, isr) - struct mbuf *m; - struct ipsecrequest *isr; -{ - struct secasvar *sav = isr->sav; - const struct ah_algorithm *algo; - u_int32_t spi; - u_char *ahdrpos; - u_int8_t *ahsumpos = NULL; - size_t hlen = 0; /* IP header+option in bytes */ - size_t plen = 0; /* AH payload size in bytes */ - size_t ahlen = 0; /* plen + sizeof(ah) */ - struct ip *ip; - in_addr_t saveaddr = { 0 }; - struct in_addr *finaldst; - int error; - - /* sanity checks */ - if ((sav->flags & SADB_X_EXT_OLD) == 0 && !sav->replay) { - struct ip *ip; - - ip = mtod(m, struct ip *); - ipseclog((LOG_DEBUG, "ah4_output: internal error: " - "sav->replay is null: %x->%x, SPI=%u\n", - (u_int32_t)ntohl(ip->ip_src.s_addr), - (u_int32_t)ntohl(ip->ip_dst.s_addr), - (u_int32_t)ntohl(sav->spi))); - ipsecstat.out_inval++; - m_freem(m); - return EINVAL; - } - - algo = ah_algorithm_lookup(sav->alg_auth); - if (!algo) { - ipseclog((LOG_ERR, "ah4_output: unsupported algorithm: " - "SPI=%u\n", (u_int32_t)ntohl(sav->spi))); - ipsecstat.out_inval++; - m_freem(m); - return EINVAL; - } - spi = sav->spi; - - /* - * determine the size to grow. - */ - if (sav->flags & SADB_X_EXT_OLD) { - /* RFC 1826 */ - plen = ((*algo->sumsiz)(sav) + 3) & ~(4 - 1); /* XXX pad to 8byte? */ - ahlen = plen + sizeof(struct ah); - } else { - /* RFC 2402 */ - plen = ((*algo->sumsiz)(sav) + 3) & ~(4 - 1); /* XXX pad to 8byte? */ - ahlen = plen + sizeof(struct newah); - } - - /* - * grow the mbuf to accomodate AH. - */ - ip = mtod(m, struct ip *); -#ifdef _IP_VHL - hlen = IP_VHL_HL(ip->ip_vhl) << 2; -#else - hlen = ip->ip_hl << 2; -#endif - - if (m->m_len != hlen) - panic("ah4_output: assumption failed (first mbuf length)"); - if (M_LEADINGSPACE(m->m_next) < ahlen) { - struct mbuf *n; - MGET(n, M_DONTWAIT, MT_DATA); - if (!n) { - ipseclog((LOG_DEBUG, "ENOBUFS in ah4_output %d\n", - __LINE__)); - m_freem(m); - return ENOBUFS; - } - n->m_len = ahlen; - n->m_next = m->m_next; - m->m_next = n; - m->m_pkthdr.len += ahlen; - ahdrpos = mtod(n, u_char *); - } else { - m->m_next->m_len += ahlen; - m->m_next->m_data -= ahlen; - m->m_pkthdr.len += ahlen; - ahdrpos = mtod(m->m_next, u_char *); - } - - ip = mtod(m, struct ip *); /* just to be sure */ - - /* - * initialize AH. - */ - if (sav->flags & SADB_X_EXT_OLD) { - struct ah *ahdr; - - ahdr = (struct ah *)ahdrpos; - ahsumpos = (u_char *)(ahdr + 1); - ahdr->ah_len = plen >> 2; - ahdr->ah_nxt = ip->ip_p; - ahdr->ah_reserve = htons(0); - ahdr->ah_spi = spi; - bzero(ahdr + 1, plen); - } else { - struct newah *ahdr; - - ahdr = (struct newah *)ahdrpos; - ahsumpos = (u_char *)(ahdr + 1); - ahdr->ah_len = (plen >> 2) + 1; /* plus one for seq# */ - ahdr->ah_nxt = ip->ip_p; - ahdr->ah_reserve = htons(0); - ahdr->ah_spi = spi; - if (sav->replay->count == ~0) { - if ((sav->flags & SADB_X_EXT_CYCSEQ) == 0) { - /* XXX Is it noisy ? */ - ipseclog((LOG_WARNING, - "replay counter overflowed. %s\n", - ipsec_logsastr(sav))); - ipsecstat.out_inval++; - m_freem(m); - return EINVAL; - } - } - sav->replay->count++; - /* - * XXX sequence number must not be cycled, if the SA is - * installed by IKE daemon. - */ - ahdr->ah_seq = htonl(sav->replay->count & 0xffffffff); - bzero(ahdr + 1, plen); - } - - /* - * modify IPv4 header. - */ - ip->ip_p = IPPROTO_AH; - if (ahlen < (IP_MAXPACKET - ntohs(ip->ip_len))) - ip->ip_len = htons(ntohs(ip->ip_len) + ahlen); - else { - ipseclog((LOG_ERR, "IPv4 AH output: size exceeds limit\n")); - ipsecstat.out_inval++; - m_freem(m); - return EMSGSIZE; - } - - /* - * If there is source routing option, update destination field in - * the IPv4 header to the final destination. - * Note that we do not need to update source routing option itself - * (as done in IPv4 AH processing -- see ip6_output()), since - * source routing option is not part of the ICV computation. - */ - finaldst = ah4_finaldst(m); - if (finaldst) { - saveaddr = ip->ip_dst.s_addr; - ip->ip_dst.s_addr = finaldst->s_addr; - } - - /* - * calcurate the checksum, based on security association - * and the algorithm specified. - */ - error = ah4_calccksum(m, ahsumpos, plen, algo, sav); - if (error) { - ipseclog((LOG_ERR, - "error after ah4_calccksum, called from ah4_output")); - m_freem(m); - m = NULL; - ipsecstat.out_inval++; - return error; - } - - if (finaldst) { - ip = mtod(m, struct ip *); /* just to make sure */ - ip->ip_dst.s_addr = saveaddr; - } - ipsecstat.out_success++; - ipsecstat.out_ahhist[sav->alg_auth]++; - key_sa_recordxfer(sav, m); - - return 0; -} -#endif - -/* Calculate AH length */ -int -ah_hdrlen(sav) - struct secasvar *sav; -{ - const struct ah_algorithm *algo; - int plen, ahlen; - - algo = ah_algorithm_lookup(sav->alg_auth); - if (!algo) - return 0; - if (sav->flags & SADB_X_EXT_OLD) { - /* RFC 1826 */ - plen = ((*algo->sumsiz)(sav) + 3) & ~(4 - 1); /* XXX pad to 8byte? */ - ahlen = plen + sizeof(struct ah); - } else { - /* RFC 2402 */ - plen = ((*algo->sumsiz)(sav) + 3) & ~(4 - 1); /* XXX pad to 8byte? */ - ahlen = plen + sizeof(struct newah); - } - - return (ahlen); -} - -#ifdef INET6 -/* - * Fill in the Authentication Header and calculate checksum. - */ -int -ah6_output(m, nexthdrp, md, isr) - struct mbuf *m; - u_char *nexthdrp; - struct mbuf *md; - struct ipsecrequest *isr; -{ - struct mbuf *mprev; - struct mbuf *mah; - struct secasvar *sav = isr->sav; - const struct ah_algorithm *algo; - u_int32_t spi; - u_int8_t *ahsumpos = NULL; - size_t plen; /* AH payload size in bytes */ - int error = 0; - int ahlen; - struct ip6_hdr *ip6; - - if (m->m_len < sizeof(struct ip6_hdr)) { - ipseclog((LOG_DEBUG, "ah6_output: first mbuf too short\n")); - m_freem(m); - return EINVAL; - } - - ahlen = ah_hdrlen(sav); - if (ahlen == 0) - return 0; - - for (mprev = m; mprev && mprev->m_next != md; mprev = mprev->m_next) - ; - if (!mprev || mprev->m_next != md) { - ipseclog((LOG_DEBUG, "ah6_output: md is not in chain\n")); - m_freem(m); - return EINVAL; - } - - MGET(mah, M_DONTWAIT, MT_DATA); - if (!mah) { - m_freem(m); - return ENOBUFS; - } - if (ahlen > MLEN) { - MCLGET(mah, M_DONTWAIT); - if ((mah->m_flags & M_EXT) == 0) { - m_free(mah); - m_freem(m); - return ENOBUFS; - } - } - mah->m_len = ahlen; - mah->m_next = md; - mprev->m_next = mah; - m->m_pkthdr.len += ahlen; - - /* fix plen */ - if (m->m_pkthdr.len - sizeof(struct ip6_hdr) > IPV6_MAXPACKET) { - ipseclog((LOG_ERR, - "ah6_output: AH with IPv6 jumbogram is not supported\n")); - m_freem(m); - return EINVAL; - } - ip6 = mtod(m, struct ip6_hdr *); - ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(struct ip6_hdr)); - - if ((sav->flags & SADB_X_EXT_OLD) == 0 && !sav->replay) { - ipseclog((LOG_DEBUG, "ah6_output: internal error: " - "sav->replay is null: SPI=%u\n", - (u_int32_t)ntohl(sav->spi))); - ipsec6stat.out_inval++; - m_freem(m); - return EINVAL; - } - - algo = ah_algorithm_lookup(sav->alg_auth); - if (!algo) { - ipseclog((LOG_ERR, "ah6_output: unsupported algorithm: " - "SPI=%u\n", (u_int32_t)ntohl(sav->spi))); - ipsec6stat.out_inval++; - m_freem(m); - return EINVAL; - } - spi = sav->spi; - - /* - * initialize AH. - */ - if (sav->flags & SADB_X_EXT_OLD) { - struct ah *ahdr = mtod(mah, struct ah *); - - plen = mah->m_len - sizeof(struct ah); - ahsumpos = (u_char *)(ahdr + 1); - ahdr->ah_nxt = *nexthdrp; - *nexthdrp = IPPROTO_AH; - ahdr->ah_len = plen >> 2; - ahdr->ah_reserve = htons(0); - ahdr->ah_spi = spi; - bzero(ahdr + 1, plen); - } else { - struct newah *ahdr = mtod(mah, struct newah *); - - plen = mah->m_len - sizeof(struct newah); - ahsumpos = (u_char *)(ahdr + 1); - ahdr->ah_nxt = *nexthdrp; - *nexthdrp = IPPROTO_AH; - ahdr->ah_len = (plen >> 2) + 1; /* plus one for seq# */ - ahdr->ah_reserve = htons(0); - ahdr->ah_spi = spi; - if (sav->replay->count == ~0) { - if ((sav->flags & SADB_X_EXT_CYCSEQ) == 0) { - /* XXX Is it noisy ? */ - ipseclog((LOG_WARNING, - "replay counter overflowed. %s\n", - ipsec_logsastr(sav))); - ipsec6stat.out_inval++; - m_freem(m); - return EINVAL; - } - } - sav->replay->count++; - /* - * XXX sequence number must not be cycled, if the SA is - * installed by IKE daemon. - */ - ahdr->ah_seq = htonl(sav->replay->count); - bzero(ahdr + 1, plen); - } - - /* - * calcurate the checksum, based on security association - * and the algorithm specified. - */ - error = ah6_calccksum(m, ahsumpos, plen, algo, sav); - if (error) { - ipsec6stat.out_inval++; - m_freem(m); - } else { - ipsec6stat.out_success++; - key_sa_recordxfer(sav, m); - } - ipsec6stat.out_ahhist[sav->alg_auth]++; - - return (error); -} -#endif - -#ifdef INET -/* - * Find the final destination if there is loose/strict source routing option. - * Returns NULL if there's no source routing options. - * Returns NULL on errors too. - * Note that this function will return a pointer INTO the given parameter, - * struct mbuf *m. - * The mbuf must be pulled up toward, at least, ip option part. - */ -static struct in_addr * -ah4_finaldst(m) - struct mbuf *m; -{ - struct ip *ip; - int optlen; - u_char *q; - int i; - int hlen; - - if (!m) - panic("ah4_finaldst: m == NULL"); - ip = mtod(m, struct ip *); - hlen = (ip->ip_hl << 2); - - if (m->m_len < hlen) { - ipseclog((LOG_DEBUG, - "ah4_finaldst: parameter mbuf wrong (not pulled up)\n")); - return NULL; - } - - if (hlen == sizeof(struct ip)) - return NULL; - - optlen = hlen - sizeof(struct ip); - if (optlen < 0) { - ipseclog((LOG_DEBUG, "ah4_finaldst: wrong optlen %d\n", - optlen)); - return NULL; - } - - q = (u_char *)(ip + 1); - i = 0; - while (i < optlen) { - if (i + IPOPT_OPTVAL >= optlen) - return NULL; - if (q[i + IPOPT_OPTVAL] == IPOPT_EOL || - q[i + IPOPT_OPTVAL] == IPOPT_NOP || - i + IPOPT_OLEN < optlen) - ; - else - return NULL; - - switch (q[i + IPOPT_OPTVAL]) { - case IPOPT_EOL: - i = optlen; /* bye */ - break; - case IPOPT_NOP: - i++; - break; - case IPOPT_LSRR: - case IPOPT_SSRR: - if (q[i + IPOPT_OLEN] < 2 + sizeof(struct in_addr) || - optlen - i < q[i + IPOPT_OLEN]) { - ipseclog((LOG_ERR, - "ip_finaldst: invalid IP option " - "(code=%02x len=%02x)\n", - q[i + IPOPT_OPTVAL], q[i + IPOPT_OLEN])); - return NULL; - } - i += q[i + IPOPT_OLEN] - sizeof(struct in_addr); - return (struct in_addr *)(q + i); - default: - if (q[i + IPOPT_OLEN] < 2 || - optlen - i < q[i + IPOPT_OLEN]) { - ipseclog((LOG_ERR, - "ip_finaldst: invalid IP option " - "(code=%02x len=%02x)\n", - q[i + IPOPT_OPTVAL], q[i + IPOPT_OLEN])); - return NULL; - } - i += q[i + IPOPT_OLEN]; - break; - } - } - return NULL; -} -#endif diff --git a/sys/netinet6/esp_aesctr.c b/sys/netinet6/esp_aesctr.c deleted file mode 100644 index a8655bd..0000000 --- a/sys/netinet6/esp_aesctr.c +++ /dev/null @@ -1,461 +0,0 @@ -/* $KAME: esp_aesctr.c,v 1.2 2003/07/20 00:29:37 itojun Exp $ */ - -/*- - * Copyright (C) 1995, 1996, 1997, 1998 and 2003 WIDE Project. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/socket.h> -#include <sys/queue.h> -#include <sys/syslog.h> -#include <sys/mbuf.h> - -#include <net/if.h> -#include <net/route.h> - -#include <netinet/in.h> - -#include <netinet6/ipsec.h> -#include <netinet6/esp.h> -#include <netinet6/esp_aesctr.h> - -#include <netkey/key.h> - -#include <crypto/rijndael/rijndael.h> - -#define AES_BLOCKSIZE 16 - -#define NONCESIZE 4 -union cblock { - struct { - u_int8_t nonce[4]; - u_int8_t iv[8]; - u_int32_t ctr; - } __packed v; - u_int8_t cblock[16]; -}; - -typedef struct { - u_int32_t r_ek[(RIJNDAEL_MAXNR+1)*4]; - int r_nr; /* key-length-dependent number of rounds */ -} aesctr_ctx; - -int -esp_aesctr_mature(sav) - struct secasvar *sav; -{ - int keylen; - const struct esp_algorithm *algo; - - algo = esp_algorithm_lookup(sav->alg_enc); - if (!algo) { - ipseclog((LOG_ERR, - "esp_aeesctr_mature %s: unsupported algorithm.\n", - algo->name)); - return 1; - } - - keylen = sav->key_enc->sadb_key_bits; - if (keylen < algo->keymin || algo->keymax < keylen) { - ipseclog((LOG_ERR, - "esp_aesctr_mature %s: invalid key length %d.\n", - algo->name, sav->key_enc->sadb_key_bits)); - return 1; - } - - /* rijndael key + nonce */ - if (!(keylen == 128 + 32 || keylen == 192 + 32 || keylen == 256 + 32)) { - ipseclog((LOG_ERR, - "esp_aesctr_mature %s: invalid key length %d.\n", - algo->name, keylen)); - return 1; - } - - return 0; -} - -size_t -esp_aesctr_schedlen(algo) - const struct esp_algorithm *algo; -{ - - return sizeof(aesctr_ctx); -} - -int -esp_aesctr_schedule(algo, sav) - const struct esp_algorithm *algo; - struct secasvar *sav; -{ - aesctr_ctx *ctx; - int keylen; - - /* SA key = AES key + nonce */ - keylen = _KEYLEN(sav->key_enc) * 8 - NONCESIZE * 8; - - ctx = (aesctr_ctx *)sav->sched; - if ((ctx->r_nr = rijndaelKeySetupEnc(ctx->r_ek, - (char *)_KEYBUF(sav->key_enc), keylen)) == 0) - return -1; - return 0; -} - -int -esp_aesctr_decrypt(m, off, sav, algo, ivlen) - struct mbuf *m; - size_t off; - struct secasvar *sav; - const struct esp_algorithm *algo; - int ivlen; -{ - struct mbuf *s; - struct mbuf *d, *d0 = NULL, *dp; - int soff, doff; /* offset from the head of chain, to head of this mbuf */ - int sn, dn; /* offset from the head of the mbuf, to meat */ - size_t ivoff, bodyoff; - union cblock cblock; - u_int8_t keystream[AES_BLOCKSIZE], *nonce; - u_int32_t ctr; - u_int8_t *ivp; - u_int8_t sbuf[AES_BLOCKSIZE], *sp, *dst; - struct mbuf *scut; - int scutoff; - int i; - int blocklen; - aesctr_ctx *ctx; - - if (ivlen != sav->ivlen) { - ipseclog((LOG_ERR, "esp_aesctr_decrypt %s: " - "unsupported ivlen %d\n", algo->name, ivlen)); - goto fail; - } - - /* assumes blocklen == padbound */ - blocklen = algo->padbound; - - ivoff = off + sizeof(struct newesp); - bodyoff = off + sizeof(struct newesp) + ivlen; - - /* setup counter block */ - nonce = _KEYBUF(sav->key_enc) + _KEYLEN(sav->key_enc) - NONCESIZE; - bcopy(nonce, cblock.v.nonce, NONCESIZE); - m_copydata(m, ivoff, ivlen, cblock.v.iv); - ctr = 1; - - if (m->m_pkthdr.len < bodyoff) { - ipseclog((LOG_ERR, "esp_aesctr_decrypt %s: bad len %d/%lu\n", - algo->name, m->m_pkthdr.len, (unsigned long)bodyoff)); - goto fail; - } - if ((m->m_pkthdr.len - bodyoff) % blocklen) { - ipseclog((LOG_ERR, "esp_aesctr_decrypt %s: " - "payload length must be multiple of %d\n", - algo->name, blocklen)); - goto fail; - } - - s = m; - d = d0 = dp = NULL; - soff = doff = sn = dn = 0; - ivp = sp = NULL; - - /* skip bodyoff */ - while (soff < bodyoff) { - if (soff + s->m_len > bodyoff) { - sn = bodyoff - soff; - break; - } - - soff += s->m_len; - s = s->m_next; - } - scut = s; - scutoff = sn; - - /* skip over empty mbuf */ - while (s && s->m_len == 0) - s = s->m_next; - - while (soff < m->m_pkthdr.len) { - /* source */ - if (sn + blocklen <= s->m_len) { - /* body is continuous */ - sp = mtod(s, u_int8_t *) + sn; - } else { - /* body is non-continuous */ - m_copydata(s, sn, blocklen, (caddr_t)sbuf); - sp = sbuf; - } - - /* destination */ - if (!d || dn + blocklen > d->m_len) { - if (d) - dp = d; - MGET(d, M_DONTWAIT, MT_DATA); - i = m->m_pkthdr.len - (soff + sn); - if (d && i > MLEN) { - MCLGET(d, M_DONTWAIT); - if ((d->m_flags & M_EXT) == 0) { - m_free(d); - d = NULL; - } - } - if (!d) { - goto nomem; - } - if (!d0) - d0 = d; - if (dp) - dp->m_next = d; - d->m_len = 0; - d->m_len = (M_TRAILINGSPACE(d) / blocklen) * blocklen; - if (d->m_len > i) - d->m_len = i; - dn = 0; - } - - /* put counter into counter block */ - cblock.v.ctr = htonl(ctr); - - /* setup keystream */ - ctx = (aesctr_ctx *)sav->sched; - rijndaelEncrypt(ctx->r_ek, ctx->r_nr, cblock.cblock, keystream); - - bcopy(sp, mtod(d, u_int8_t *) + dn, blocklen); - dst = mtod(d, u_int8_t *) + dn; - for (i = 0; i < blocklen; i++) - dst[i] ^= keystream[i]; - - ctr++; - - sn += blocklen; - dn += blocklen; - - /* find the next source block */ - while (s && sn >= s->m_len) { - sn -= s->m_len; - soff += s->m_len; - s = s->m_next; - } - - /* skip over empty mbuf */ - while (s && s->m_len == 0) - s = s->m_next; - } - - m_freem(scut->m_next); - scut->m_len = scutoff; - scut->m_next = d0; - - /* just in case */ - bzero(&cblock, sizeof(cblock)); - bzero(keystream, sizeof(keystream)); - - return 0; - -fail: - m_freem(m); - if (d0) - m_freem(d0); - return EINVAL; - -nomem: - m_freem(m); - if (d0) - m_freem(d0); - return ENOBUFS; -} - -int -esp_aesctr_encrypt(m, off, plen, sav, algo, ivlen) - struct mbuf *m; - size_t off; - size_t plen; - struct secasvar *sav; - const struct esp_algorithm *algo; - int ivlen; -{ - struct mbuf *s; - struct mbuf *d, *d0, *dp; - int soff, doff; /* offset from the head of chain, to head of this mbuf */ - int sn, dn; /* offset from the head of the mbuf, to meat */ - size_t ivoff, bodyoff; - union cblock cblock; - u_int8_t keystream[AES_BLOCKSIZE], *nonce; - u_int32_t ctr; - u_int8_t sbuf[AES_BLOCKSIZE], *sp, *dst; - struct mbuf *scut; - int scutoff; - int i; - int blocklen; - aesctr_ctx *ctx; - - if (ivlen != sav->ivlen) { - ipseclog((LOG_ERR, "esp_aesctr_encrypt %s: " - "unsupported ivlen %d\n", algo->name, ivlen)); - m_freem(m); - return EINVAL; - } - - /* assumes blocklen == padbound */ - blocklen = algo->padbound; - - ivoff = off + sizeof(struct newesp); - bodyoff = off + sizeof(struct newesp) + ivlen; - - /* put iv into the packet. */ - /* maybe it is better to overwrite dest, not source */ - m_copyback(m, ivoff, ivlen, sav->iv); - - /* setup counter block */ - nonce = _KEYBUF(sav->key_enc) + _KEYLEN(sav->key_enc) - NONCESIZE; - bcopy(nonce, cblock.v.nonce, NONCESIZE); - m_copydata(m, ivoff, ivlen, cblock.v.iv); - ctr = 1; - - if (m->m_pkthdr.len < bodyoff) { - ipseclog((LOG_ERR, "esp_aesctr_encrypt %s: bad len %d/%lu\n", - algo->name, m->m_pkthdr.len, (unsigned long)bodyoff)); - m_freem(m); - return EINVAL; - } - if ((m->m_pkthdr.len - bodyoff) % blocklen) { - ipseclog((LOG_ERR, "esp_aesctr_encrypt %s: " - "payload length must be multiple of %lu\n", - algo->name, (unsigned long)algo->padbound)); - m_freem(m); - return EINVAL; - } - - s = m; - d = d0 = dp = NULL; - soff = doff = sn = dn = 0; - sp = NULL; - - /* skip bodyoff */ - while (soff < bodyoff) { - if (soff + s->m_len > bodyoff) { - sn = bodyoff - soff; - break; - } - - soff += s->m_len; - s = s->m_next; - } - scut = s; - scutoff = sn; - - /* skip over empty mbuf */ - while (s && s->m_len == 0) - s = s->m_next; - - while (soff < m->m_pkthdr.len) { - /* source */ - if (sn + blocklen <= s->m_len) { - /* body is continuous */ - sp = mtod(s, u_int8_t *) + sn; - } else { - /* body is non-continuous */ - m_copydata(s, sn, blocklen, (caddr_t)sbuf); - sp = sbuf; - } - - /* destination */ - if (!d || dn + blocklen > d->m_len) { - if (d) - dp = d; - MGET(d, M_DONTWAIT, MT_DATA); - i = m->m_pkthdr.len - (soff + sn); - if (d && i > MLEN) { - MCLGET(d, M_DONTWAIT); - if ((d->m_flags & M_EXT) == 0) { - m_free(d); - d = NULL; - } - } - if (!d) { - m_freem(m); - if (d0) - m_freem(d0); - return ENOBUFS; - } - if (!d0) - d0 = d; - if (dp) - dp->m_next = d; - d->m_len = 0; - d->m_len = (M_TRAILINGSPACE(d) / blocklen) * blocklen; - if (d->m_len > i) - d->m_len = i; - dn = 0; - } - - /* put counter into counter block */ - cblock.v.ctr = htonl(ctr); - - /* setup keystream */ - ctx = (aesctr_ctx *)sav->sched; - rijndaelEncrypt(ctx->r_ek, ctx->r_nr, cblock.cblock, keystream); - - bcopy(sp, mtod(d, u_int8_t *) + dn, blocklen); - dst = mtod(d, u_int8_t *) + dn; - for (i = 0; i < blocklen; i++) - dst[i] ^= keystream[i]; - - ctr++; - - sn += blocklen; - dn += blocklen; - - /* find the next source block */ - while (s && sn >= s->m_len) { - sn -= s->m_len; - soff += s->m_len; - s = s->m_next; - } - - /* skip over empty mbuf */ - while (s && s->m_len == 0) - s = s->m_next; - } - - m_freem(scut->m_next); - scut->m_len = scutoff; - scut->m_next = d0; - - /* just in case */ - bzero(&cblock, sizeof(cblock)); - bzero(keystream, sizeof(keystream)); - - key_sa_stir_iv(sav); - - return 0; -} diff --git a/sys/netinet6/esp_camellia.c b/sys/netinet6/esp_camellia.c deleted file mode 100644 index b608518..0000000 --- a/sys/netinet6/esp_camellia.c +++ /dev/null @@ -1,93 +0,0 @@ -/* - * - * Copyright (c) 2006 - * NTT (Nippon Telegraph and Telephone Corporation) . All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer as - * the first lines of this file unmodified. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY NTT ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL NTT BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/socket.h> -#include <sys/queue.h> - -#include <net/if.h> -#include <net/route.h> -#include <netinet/in.h> - -#include <netinet6/ipsec.h> -#include <netinet6/esp.h> -#include <netinet6/esp_camellia.h> - -#include <crypto/camellia/camellia.h> - -size_t -esp_camellia_schedlen(algo) - const struct esp_algorithm *algo; -{ - - return sizeof(camellia_ctx); -} - -int -esp_camellia_schedule(algo, sav) - const struct esp_algorithm *algo; - struct secasvar *sav; -{ - camellia_ctx *ctx; - - ctx = (camellia_ctx *)sav->sched; - camellia_set_key(ctx, - (u_char *)_KEYBUF(sav->key_enc), _KEYLEN(sav->key_enc) * 8); - return 0; -} - -int -esp_camellia_blockdecrypt(algo, sav, s, d) - const struct esp_algorithm *algo; - struct secasvar *sav; - u_int8_t *s; - u_int8_t *d; -{ - camellia_ctx *ctx; - - ctx = (camellia_ctx *)sav->sched; - camellia_decrypt(ctx, s, d); - return 0; -} - -int -esp_camellia_blockencrypt(algo, sav, s, d) - const struct esp_algorithm *algo; - struct secasvar *sav; - u_int8_t *s; - u_int8_t *d; -{ - camellia_ctx *ctx; - - ctx = (camellia_ctx *)sav->sched; - camellia_encrypt(ctx, s, d); - return 0; -} diff --git a/sys/netinet6/esp_core.c b/sys/netinet6/esp_core.c deleted file mode 100644 index 7f45236..0000000 --- a/sys/netinet6/esp_core.c +++ /dev/null @@ -1,1134 +0,0 @@ -/* $FreeBSD$ */ -/* $KAME: esp_core.c,v 1.50 2000/11/02 12:27:38 itojun Exp $ */ - -/*- - * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "opt_inet.h" -#include "opt_inet6.h" - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/malloc.h> -#include <sys/mbuf.h> -#include <sys/domain.h> -#include <sys/protosw.h> -#include <sys/socket.h> -#include <sys/errno.h> -#include <sys/time.h> -#include <sys/syslog.h> - -#include <net/if.h> -#include <net/route.h> - -#include <netinet/in.h> -#include <netinet/in_var.h> -#ifdef INET6 -#include <netinet/ip6.h> -#include <netinet6/ip6_var.h> -#include <netinet/icmp6.h> -#endif - -#include <netinet6/ipsec.h> -#ifdef INET6 -#include <netinet6/ipsec6.h> -#endif -#include <netinet6/ah.h> -#ifdef INET6 -#include <netinet6/ah6.h> -#endif -#include <netinet6/esp.h> -#ifdef INET6 -#include <netinet6/esp6.h> -#endif -#include <netinet6/esp_rijndael.h> -#include <netinet6/esp_camellia.h> -#include <netinet6/esp_aesctr.h> -#include <net/pfkeyv2.h> -#include <netkey/keydb.h> -#include <netkey/key.h> - -#include <crypto/des/des.h> -#include <crypto/blowfish/blowfish.h> - -#include <opencrypto/cast.h> -#define cast128_key cast_key -#define cast128_setkey(key, rawkey, keybytes) \ - cast_setkey((key), (rawkey), (keybytes)) -#define cast128_encrypt(key, inblock, outblock) \ - cast_encrypt((key), (inblock), (outblock)) -#define cast128_decrypt(key, inblock, outblock) \ - cast_decrypt((key), (inblock), (outblock)) - -static int esp_null_mature __P((struct secasvar *)); -static int esp_null_decrypt __P((struct mbuf *, size_t, - struct secasvar *, const struct esp_algorithm *, int)); -static int esp_null_encrypt __P((struct mbuf *, size_t, size_t, - struct secasvar *, const struct esp_algorithm *, int)); -static int esp_descbc_mature __P((struct secasvar *)); -static int esp_descbc_ivlen __P((const struct esp_algorithm *, - struct secasvar *)); -static int esp_des_schedule __P((const struct esp_algorithm *, - struct secasvar *)); -static size_t esp_des_schedlen __P((const struct esp_algorithm *)); -static int esp_des_blockdecrypt __P((const struct esp_algorithm *, - struct secasvar *, u_int8_t *, u_int8_t *)); -static int esp_des_blockencrypt __P((const struct esp_algorithm *, - struct secasvar *, u_int8_t *, u_int8_t *)); -static int esp_cbc_mature __P((struct secasvar *)); -static int esp_blowfish_schedule __P((const struct esp_algorithm *, - struct secasvar *)); -static size_t esp_blowfish_schedlen __P((const struct esp_algorithm *)); -static int esp_blowfish_blockdecrypt __P((const struct esp_algorithm *, - struct secasvar *, u_int8_t *, u_int8_t *)); -static int esp_blowfish_blockencrypt __P((const struct esp_algorithm *, - struct secasvar *, u_int8_t *, u_int8_t *)); -static int esp_cast128_schedule __P((const struct esp_algorithm *, - struct secasvar *)); -static size_t esp_cast128_schedlen __P((const struct esp_algorithm *)); -static int esp_cast128_blockdecrypt __P((const struct esp_algorithm *, - struct secasvar *, u_int8_t *, u_int8_t *)); -static int esp_cast128_blockencrypt __P((const struct esp_algorithm *, - struct secasvar *, u_int8_t *, u_int8_t *)); -static int esp_3des_schedule __P((const struct esp_algorithm *, - struct secasvar *)); -static size_t esp_3des_schedlen __P((const struct esp_algorithm *)); -static int esp_3des_blockdecrypt __P((const struct esp_algorithm *, - struct secasvar *, u_int8_t *, u_int8_t *)); -static int esp_3des_blockencrypt __P((const struct esp_algorithm *, - struct secasvar *, u_int8_t *, u_int8_t *)); -static int esp_common_ivlen __P((const struct esp_algorithm *, - struct secasvar *)); -static int esp_cbc_decrypt __P((struct mbuf *, size_t, - struct secasvar *, const struct esp_algorithm *, int)); -static int esp_cbc_encrypt __P((struct mbuf *, size_t, size_t, - struct secasvar *, const struct esp_algorithm *, int)); - -#define MAXIVLEN 16 - -static const struct esp_algorithm esp_algorithms[] = { - { 8, -1, esp_descbc_mature, 64, 64, esp_des_schedlen, - "des-cbc", - esp_descbc_ivlen, esp_cbc_decrypt, - esp_cbc_encrypt, esp_des_schedule, - esp_des_blockdecrypt, esp_des_blockencrypt, }, - { 8, 8, esp_cbc_mature, 192, 192, esp_3des_schedlen, - "3des-cbc", - esp_common_ivlen, esp_cbc_decrypt, - esp_cbc_encrypt, esp_3des_schedule, - esp_3des_blockdecrypt, esp_3des_blockencrypt, }, - { 1, 0, esp_null_mature, 0, 2048, NULL, "null", - esp_common_ivlen, esp_null_decrypt, - esp_null_encrypt, NULL, }, - { 8, 8, esp_cbc_mature, 40, 448, esp_blowfish_schedlen, "blowfish-cbc", - esp_common_ivlen, esp_cbc_decrypt, - esp_cbc_encrypt, esp_blowfish_schedule, - esp_blowfish_blockdecrypt, esp_blowfish_blockencrypt, }, - { 8, 8, esp_cbc_mature, 40, 128, esp_cast128_schedlen, - "cast128-cbc", - esp_common_ivlen, esp_cbc_decrypt, - esp_cbc_encrypt, esp_cast128_schedule, - esp_cast128_blockdecrypt, esp_cast128_blockencrypt, }, - { 16, 16, esp_cbc_mature, 128, 256, esp_rijndael_schedlen, - "rijndael-cbc", - esp_common_ivlen, esp_cbc_decrypt, - esp_cbc_encrypt, esp_rijndael_schedule, - esp_rijndael_blockdecrypt, esp_rijndael_blockencrypt }, - { 16, 8, esp_aesctr_mature, 160, 288, esp_aesctr_schedlen, "aes-ctr", - esp_common_ivlen, esp_aesctr_decrypt, - esp_aesctr_encrypt, esp_aesctr_schedule }, - { 16, 16, esp_cbc_mature, 128, 256, esp_camellia_schedlen, - "camellia-cbc", - esp_common_ivlen, esp_cbc_decrypt, - esp_cbc_encrypt, esp_camellia_schedule, - esp_camellia_blockdecrypt, esp_camellia_blockencrypt }, -}; - -const struct esp_algorithm * -esp_algorithm_lookup(idx) - int idx; -{ - - switch (idx) { - case SADB_EALG_DESCBC: - return &esp_algorithms[0]; - case SADB_EALG_3DESCBC: - return &esp_algorithms[1]; - case SADB_EALG_NULL: - return &esp_algorithms[2]; - case SADB_X_EALG_BLOWFISHCBC: - return &esp_algorithms[3]; - case SADB_X_EALG_CAST128CBC: - return &esp_algorithms[4]; - case SADB_X_EALG_RIJNDAELCBC: - return &esp_algorithms[5]; - case SADB_X_EALG_AESCTR: - return &esp_algorithms[6]; - case SADB_X_EALG_CAMELLIACBC: - return &esp_algorithms[7]; - default: - return NULL; - } -} - -int -esp_max_ivlen() -{ - int idx; - int ivlen; - - ivlen = 0; - for (idx = 0; idx < sizeof(esp_algorithms)/sizeof(esp_algorithms[0]); - idx++) { - if (esp_algorithms[idx].ivlenval > ivlen) - ivlen = esp_algorithms[idx].ivlenval; - } - return ivlen; -} - -int -esp_schedule(algo, sav) - const struct esp_algorithm *algo; - struct secasvar *sav; -{ - int error; - - /* check for key length */ - if (_KEYBITS(sav->key_enc) < algo->keymin || - _KEYBITS(sav->key_enc) > algo->keymax) { - ipseclog((LOG_ERR, - "esp_schedule %s: unsupported key length %d: " - "needs %d to %d bits\n", algo->name, _KEYBITS(sav->key_enc), - algo->keymin, algo->keymax)); - return EINVAL; - } - - /* already allocated */ - if (sav->sched && sav->schedlen != 0) - return 0; - /* no schedule necessary */ - if (!algo->schedule || !algo->schedlen) - return 0; - - sav->schedlen = (*algo->schedlen)(algo); - sav->sched = malloc(sav->schedlen, M_SECA, M_NOWAIT); - if (!sav->sched) { - sav->schedlen = 0; - return ENOBUFS; - } - - error = (*algo->schedule)(algo, sav); - if (error) { - ipseclog((LOG_ERR, "esp_schedule %s: error %d\n", - algo->name, error)); - bzero(sav->sched, sav->schedlen); - free(sav->sched, M_SECA); - sav->sched = NULL; - sav->schedlen = 0; - } - return error; -} - -static int -esp_null_mature(sav) - struct secasvar *sav; -{ - - /* anything is okay */ - return 0; -} - -static int -esp_null_decrypt(m, off, sav, algo, ivlen) - struct mbuf *m; - size_t off; /* offset to ESP header */ - struct secasvar *sav; - const struct esp_algorithm *algo; - int ivlen; -{ - - return 0; /* do nothing */ -} - -static int -esp_null_encrypt(m, off, plen, sav, algo, ivlen) - struct mbuf *m; - size_t off; /* offset to ESP header */ - size_t plen; /* payload length (to be encrypted) */ - struct secasvar *sav; - const struct esp_algorithm *algo; - int ivlen; -{ - - return 0; /* do nothing */ -} - -static int -esp_descbc_mature(sav) - struct secasvar *sav; -{ - const struct esp_algorithm *algo; - - if (!(sav->flags & SADB_X_EXT_OLD) && (sav->flags & SADB_X_EXT_IV4B)) { - ipseclog((LOG_ERR, "esp_cbc_mature: " - "algorithm incompatible with 4 octets IV length\n")); - return 1; - } - - if (!sav->key_enc) { - ipseclog((LOG_ERR, "esp_descbc_mature: no key is given.\n")); - return 1; - } - - algo = esp_algorithm_lookup(sav->alg_enc); - if (!algo) { - ipseclog((LOG_ERR, - "esp_descbc_mature: unsupported algorithm.\n")); - return 1; - } - - if (_KEYBITS(sav->key_enc) < algo->keymin || - _KEYBITS(sav->key_enc) > algo->keymax) { - ipseclog((LOG_ERR, - "esp_descbc_mature: invalid key length %d.\n", - _KEYBITS(sav->key_enc))); - return 1; - } - - /* weak key check */ - if (des_is_weak_key((des_cblock *)_KEYBUF(sav->key_enc))) { - ipseclog((LOG_ERR, - "esp_descbc_mature: weak key was passed.\n")); - return 1; - } - - return 0; -} - -static int -esp_descbc_ivlen(algo, sav) - const struct esp_algorithm *algo; - struct secasvar *sav; -{ - - if (!sav) - return 8; - if ((sav->flags & SADB_X_EXT_OLD) && (sav->flags & SADB_X_EXT_IV4B)) - return 4; - if (!(sav->flags & SADB_X_EXT_OLD) && (sav->flags & SADB_X_EXT_DERIV)) - return 4; - return 8; -} - -static size_t -esp_des_schedlen(algo) - const struct esp_algorithm *algo; -{ - - return sizeof(des_key_schedule); -} - -static int -esp_des_schedule(algo, sav) - const struct esp_algorithm *algo; - struct secasvar *sav; -{ - - if (des_key_sched((des_cblock *)_KEYBUF(sav->key_enc), - *(des_key_schedule *)sav->sched)) - return EINVAL; - else - return 0; -} - -static int -esp_des_blockdecrypt(algo, sav, s, d) - const struct esp_algorithm *algo; - struct secasvar *sav; - u_int8_t *s; - u_int8_t *d; -{ - - /* assumption: d has a good alignment */ - bcopy(s, d, sizeof(DES_LONG) * 2); - des_ecb_encrypt((des_cblock *)d, (des_cblock *)d, - *(des_key_schedule *)sav->sched, DES_DECRYPT); - return 0; -} - -static int -esp_des_blockencrypt(algo, sav, s, d) - const struct esp_algorithm *algo; - struct secasvar *sav; - u_int8_t *s; - u_int8_t *d; -{ - - /* assumption: d has a good alignment */ - bcopy(s, d, sizeof(DES_LONG) * 2); - des_ecb_encrypt((des_cblock *)d, (des_cblock *)d, - *(des_key_schedule *)sav->sched, DES_ENCRYPT); - return 0; -} - -static int -esp_cbc_mature(sav) - struct secasvar *sav; -{ - int keylen; - const struct esp_algorithm *algo; - - if (sav->flags & SADB_X_EXT_OLD) { - ipseclog((LOG_ERR, - "esp_cbc_mature: algorithm incompatible with esp-old\n")); - return 1; - } - if (sav->flags & SADB_X_EXT_DERIV) { - ipseclog((LOG_ERR, - "esp_cbc_mature: algorithm incompatible with derived\n")); - return 1; - } - - if (!sav->key_enc) { - ipseclog((LOG_ERR, "esp_cbc_mature: no key is given.\n")); - return 1; - } - - algo = esp_algorithm_lookup(sav->alg_enc); - if (!algo) { - ipseclog((LOG_ERR, - "esp_cbc_mature %s: unsupported algorithm.\n", algo->name)); - return 1; - } - - keylen = sav->key_enc->sadb_key_bits; - if (keylen < algo->keymin || algo->keymax < keylen) { - ipseclog((LOG_ERR, - "esp_cbc_mature %s: invalid key length %d.\n", - algo->name, sav->key_enc->sadb_key_bits)); - return 1; - } - switch (sav->alg_enc) { - case SADB_EALG_3DESCBC: - /* weak key check */ - if (des_is_weak_key((des_cblock *)_KEYBUF(sav->key_enc)) || - des_is_weak_key((des_cblock *)(_KEYBUF(sav->key_enc) + 8)) || - des_is_weak_key((des_cblock *)(_KEYBUF(sav->key_enc) + 16))) { - ipseclog((LOG_ERR, - "esp_cbc_mature %s: weak key was passed.\n", - algo->name)); - return 1; - } - break; - case SADB_X_EALG_BLOWFISHCBC: - case SADB_X_EALG_CAST128CBC: - break; - case SADB_X_EALG_RIJNDAELCBC: - case SADB_X_EALG_CAMELLIACBC: - /* allows specific key sizes only */ - if (!(keylen == 128 || keylen == 192 || keylen == 256)) { - ipseclog((LOG_ERR, - "esp_cbc_mature %s: invalid key length %d.\n", - algo->name, keylen)); - return 1; - } - break; - } - - return 0; -} - -static size_t -esp_blowfish_schedlen(algo) - const struct esp_algorithm *algo; -{ - - return sizeof(BF_KEY); -} - -static int -esp_blowfish_schedule(algo, sav) - const struct esp_algorithm *algo; - struct secasvar *sav; -{ - - BF_set_key((BF_KEY *)sav->sched, _KEYLEN(sav->key_enc), - _KEYBUF(sav->key_enc)); - return 0; -} - -static int -esp_blowfish_blockdecrypt(algo, sav, s, d) - const struct esp_algorithm *algo; - struct secasvar *sav; - u_int8_t *s; - u_int8_t *d; -{ - - BF_ecb_encrypt(s, d, (BF_KEY *)sav->sched, 0); - return 0; -} - -static int -esp_blowfish_blockencrypt(algo, sav, s, d) - const struct esp_algorithm *algo; - struct secasvar *sav; - u_int8_t *s; - u_int8_t *d; -{ - - BF_ecb_encrypt(s, d, (BF_KEY *)sav->sched, 1); - return 0; -} - -static size_t -esp_cast128_schedlen(algo) - const struct esp_algorithm *algo; -{ - - return sizeof(cast128_key); -} - -static int -esp_cast128_schedule(algo, sav) - const struct esp_algorithm *algo; - struct secasvar *sav; -{ - - cast128_setkey((cast128_key *)sav->sched, _KEYBUF(sav->key_enc), - _KEYLEN(sav->key_enc)); - return 0; -} - -static int -esp_cast128_blockdecrypt(algo, sav, s, d) - const struct esp_algorithm *algo; - struct secasvar *sav; - u_int8_t *s; - u_int8_t *d; -{ - - cast128_decrypt((cast128_key *)sav->sched, s, d); - return 0; -} - -static int -esp_cast128_blockencrypt(algo, sav, s, d) - const struct esp_algorithm *algo; - struct secasvar *sav; - u_int8_t *s; - u_int8_t *d; -{ - - cast128_encrypt((cast128_key *)sav->sched, s, d); - return 0; -} - -static size_t -esp_3des_schedlen(algo) - const struct esp_algorithm *algo; -{ - - return sizeof(des_key_schedule) * 3; -} - -static int -esp_3des_schedule(algo, sav) - const struct esp_algorithm *algo; - struct secasvar *sav; -{ - int error; - des_key_schedule *p; - int i; - u_int8_t *k; - - p = (des_key_schedule *)sav->sched; - k = _KEYBUF(sav->key_enc); - for (i = 0; i < 3; i++) { - error = des_key_sched((des_cblock *)(k + 8 * i), p[i]); - if (error) - return EINVAL; - } - return 0; -} - -static int -esp_3des_blockdecrypt(algo, sav, s, d) - const struct esp_algorithm *algo; - struct secasvar *sav; - u_int8_t *s; - u_int8_t *d; -{ - des_key_schedule *p; - - /* assumption: d has a good alignment */ - p = (des_key_schedule *)sav->sched; - bcopy(s, d, sizeof(DES_LONG) * 2); - des_ecb3_encrypt((des_cblock *)d, (des_cblock *)d, - p[0], p[1], p[2], DES_DECRYPT); - return 0; -} - -static int -esp_3des_blockencrypt(algo, sav, s, d) - const struct esp_algorithm *algo; - struct secasvar *sav; - u_int8_t *s; - u_int8_t *d; -{ - des_key_schedule *p; - - /* assumption: d has a good alignment */ - p = (des_key_schedule *)sav->sched; - bcopy(s, d, sizeof(DES_LONG) * 2); - des_ecb3_encrypt((des_cblock *)d, (des_cblock *)d, - p[0], p[1], p[2], DES_ENCRYPT); - return 0; -} - -static int -esp_common_ivlen(algo, sav) - const struct esp_algorithm *algo; - struct secasvar *sav; -{ - - if (!algo) - panic("esp_common_ivlen: unknown algorithm"); - return algo->ivlenval; -} - -static int -esp_cbc_decrypt(m, off, sav, algo, ivlen) - struct mbuf *m; - size_t off; - struct secasvar *sav; - const struct esp_algorithm *algo; - int ivlen; -{ - struct mbuf *s; - struct mbuf *d, *d0, *dp; - int soff, doff; /* offset from the head of chain, to head of this mbuf */ - int sn, dn; /* offset from the head of the mbuf, to meat */ - size_t ivoff, bodyoff; - u_int8_t iv[MAXIVLEN], *ivp; - u_int8_t sbuf[MAXIVLEN], *sp; - u_int8_t *p, *q; - struct mbuf *scut; - int scutoff; - int i; - int blocklen; - int derived; - - if (ivlen != sav->ivlen || ivlen > sizeof(iv)) { - ipseclog((LOG_ERR, "esp_cbc_decrypt %s: " - "unsupported ivlen %d\n", algo->name, ivlen)); - m_freem(m); - return EINVAL; - } - - /* assumes blocklen == padbound */ - blocklen = algo->padbound; - -#ifdef DIAGNOSTIC - if (blocklen > sizeof(iv)) { - ipseclog((LOG_ERR, "esp_cbc_decrypt %s: " - "unsupported blocklen %d\n", algo->name, blocklen)); - m_freem(m); - return EINVAL; - } -#endif - - if (sav->flags & SADB_X_EXT_OLD) { - /* RFC 1827 */ - ivoff = off + sizeof(struct esp); - bodyoff = off + sizeof(struct esp) + ivlen; - derived = 0; - } else { - /* RFC 2406 */ - if (sav->flags & SADB_X_EXT_DERIV) { - /* - * draft-ietf-ipsec-ciph-des-derived-00.txt - * uses sequence number field as IV field. - */ - ivoff = off + sizeof(struct esp); - bodyoff = off + sizeof(struct esp) + sizeof(u_int32_t); - ivlen = sizeof(u_int32_t); - derived = 1; - } else { - ivoff = off + sizeof(struct newesp); - bodyoff = off + sizeof(struct newesp) + ivlen; - derived = 0; - } - } - - /* grab iv */ - m_copydata(m, ivoff, ivlen, (caddr_t)iv); - - /* extend iv */ - if (ivlen == blocklen) - ; - else if (ivlen == 4 && blocklen == 8) { - bcopy(&iv[0], &iv[4], 4); - iv[4] ^= 0xff; - iv[5] ^= 0xff; - iv[6] ^= 0xff; - iv[7] ^= 0xff; - } else { - ipseclog((LOG_ERR, "esp_cbc_encrypt %s: " - "unsupported ivlen/blocklen: %d %d\n", - algo->name, ivlen, blocklen)); - m_freem(m); - return EINVAL; - } - - if (m->m_pkthdr.len < bodyoff) { - ipseclog((LOG_ERR, "esp_cbc_decrypt %s: bad len %d/%lu\n", - algo->name, m->m_pkthdr.len, (unsigned long)bodyoff)); - m_freem(m); - return EINVAL; - } - if ((m->m_pkthdr.len - bodyoff) % blocklen) { - ipseclog((LOG_ERR, "esp_cbc_decrypt %s: " - "payload length must be multiple of %d\n", - algo->name, blocklen)); - m_freem(m); - return EINVAL; - } - - s = m; - d = d0 = dp = NULL; - soff = doff = sn = dn = 0; - ivp = sp = NULL; - - /* skip bodyoff */ - while (soff < bodyoff) { - if (soff + s->m_len >= bodyoff) { - sn = bodyoff - soff; - break; - } - - soff += s->m_len; - s = s->m_next; - } - scut = s; - scutoff = sn; - - /* skip over empty mbuf */ - while (s && s->m_len == 0) - s = s->m_next; - - while (soff < m->m_pkthdr.len) { - /* source */ - if (sn + blocklen <= s->m_len) { - /* body is continuous */ - sp = mtod(s, u_int8_t *) + sn; - } else { - /* body is non-continuous */ - m_copydata(s, sn, blocklen, sbuf); - sp = sbuf; - } - - /* destination */ - if (!d || dn + blocklen > d->m_len) { - if (d) - dp = d; - MGET(d, M_DONTWAIT, MT_DATA); - i = m->m_pkthdr.len - (soff + sn); - if (d && i > MLEN) { - MCLGET(d, M_DONTWAIT); - if ((d->m_flags & M_EXT) == 0) { - m_free(d); - d = NULL; - } - } - if (!d) { - m_freem(m); - if (d0) - m_freem(d0); - return ENOBUFS; - } - if (!d0) - d0 = d; - if (dp) - dp->m_next = d; - d->m_len = 0; - d->m_len = (M_TRAILINGSPACE(d) / blocklen) * blocklen; - if (d->m_len > i) - d->m_len = i; - dn = 0; - } - - /* decrypt */ - (*algo->blockdecrypt)(algo, sav, sp, mtod(d, u_int8_t *) + dn); - - /* xor */ - p = ivp ? ivp : iv; - q = mtod(d, u_int8_t *) + dn; - for (i = 0; i < blocklen; i++) - q[i] ^= p[i]; - - /* next iv */ - if (sp == sbuf) { - bcopy(sbuf, iv, blocklen); - ivp = NULL; - } else - ivp = sp; - - sn += blocklen; - dn += blocklen; - - /* find the next source block */ - while (s && sn >= s->m_len) { - sn -= s->m_len; - soff += s->m_len; - s = s->m_next; - } - - /* skip over empty mbuf */ - while (s && s->m_len == 0) - s = s->m_next; - } - - m_freem(scut->m_next); - scut->m_len = scutoff; - scut->m_next = d0; - - /* just in case */ - bzero(iv, sizeof(iv)); - bzero(sbuf, sizeof(sbuf)); - - return 0; -} - -static int -esp_cbc_encrypt(m, off, plen, sav, algo, ivlen) - struct mbuf *m; - size_t off; - size_t plen; - struct secasvar *sav; - const struct esp_algorithm *algo; - int ivlen; -{ - struct mbuf *s; - struct mbuf *d, *d0, *dp; - int soff, doff; /* offset from the head of chain, to head of this mbuf */ - int sn, dn; /* offset from the head of the mbuf, to meat */ - size_t ivoff, bodyoff; - u_int8_t iv[MAXIVLEN], *ivp; - u_int8_t sbuf[MAXIVLEN], *sp; - u_int8_t *p, *q; - struct mbuf *scut; - int scutoff; - int i; - int blocklen; - int derived; - - if (ivlen != sav->ivlen || ivlen > sizeof(iv)) { - ipseclog((LOG_ERR, "esp_cbc_encrypt %s: " - "unsupported ivlen %d\n", algo->name, ivlen)); - m_freem(m); - return EINVAL; - } - - /* assumes blocklen == padbound */ - blocklen = algo->padbound; - -#ifdef DIAGNOSTIC - if (blocklen > sizeof(iv)) { - ipseclog((LOG_ERR, "esp_cbc_encrypt %s: " - "unsupported blocklen %d\n", algo->name, blocklen)); - m_freem(m); - return EINVAL; - } -#endif - - if (sav->flags & SADB_X_EXT_OLD) { - /* RFC 1827 */ - ivoff = off + sizeof(struct esp); - bodyoff = off + sizeof(struct esp) + ivlen; - derived = 0; - } else { - /* RFC 2406 */ - if (sav->flags & SADB_X_EXT_DERIV) { - /* - * draft-ietf-ipsec-ciph-des-derived-00.txt - * uses sequence number field as IV field. - */ - ivoff = off + sizeof(struct esp); - bodyoff = off + sizeof(struct esp) + sizeof(u_int32_t); - ivlen = sizeof(u_int32_t); - derived = 1; - } else { - ivoff = off + sizeof(struct newesp); - bodyoff = off + sizeof(struct newesp) + ivlen; - derived = 0; - } - } - - /* put iv into the packet. if we are in derived mode, use seqno. */ - if (derived) - m_copydata(m, ivoff, ivlen, (caddr_t)iv); - else { - bcopy(sav->iv, iv, ivlen); - /* maybe it is better to overwrite dest, not source */ - m_copyback(m, ivoff, ivlen, (caddr_t)iv); - } - - /* extend iv */ - if (ivlen == blocklen) - ; - else if (ivlen == 4 && blocklen == 8) { - bcopy(&iv[0], &iv[4], 4); - iv[4] ^= 0xff; - iv[5] ^= 0xff; - iv[6] ^= 0xff; - iv[7] ^= 0xff; - } else { - ipseclog((LOG_ERR, "esp_cbc_encrypt %s: " - "unsupported ivlen/blocklen: %d %d\n", - algo->name, ivlen, blocklen)); - m_freem(m); - return EINVAL; - } - - if (m->m_pkthdr.len < bodyoff) { - ipseclog((LOG_ERR, "esp_cbc_encrypt %s: bad len %d/%lu\n", - algo->name, m->m_pkthdr.len, (unsigned long)bodyoff)); - m_freem(m); - return EINVAL; - } - if ((m->m_pkthdr.len - bodyoff) % blocklen) { - ipseclog((LOG_ERR, "esp_cbc_encrypt %s: " - "payload length must be multiple of %lu\n", - algo->name, (unsigned long)algo->padbound)); - m_freem(m); - return EINVAL; - } - - s = m; - d = d0 = dp = NULL; - soff = doff = sn = dn = 0; - ivp = sp = NULL; - - /* skip bodyoff */ - while (soff < bodyoff) { - if (soff + s->m_len >= bodyoff) { - sn = bodyoff - soff; - break; - } - - soff += s->m_len; - s = s->m_next; - } - scut = s; - scutoff = sn; - - /* skip over empty mbuf */ - while (s && s->m_len == 0) - s = s->m_next; - - while (soff < m->m_pkthdr.len) { - /* source */ - if (sn + blocklen <= s->m_len) { - /* body is continuous */ - sp = mtod(s, u_int8_t *) + sn; - } else { - /* body is non-continuous */ - m_copydata(s, sn, blocklen, (caddr_t)sbuf); - sp = sbuf; - } - - /* destination */ - if (!d || dn + blocklen > d->m_len) { - if (d) - dp = d; - MGET(d, M_DONTWAIT, MT_DATA); - i = m->m_pkthdr.len - (soff + sn); - if (d && i > MLEN) { - MCLGET(d, M_DONTWAIT); - if ((d->m_flags & M_EXT) == 0) { - m_free(d); - d = NULL; - } - } - if (!d) { - m_freem(m); - if (d0) - m_freem(d0); - return ENOBUFS; - } - if (!d0) - d0 = d; - if (dp) - dp->m_next = d; - d->m_len = 0; - d->m_len = (M_TRAILINGSPACE(d) / blocklen) * blocklen; - if (d->m_len > i) - d->m_len = i; - dn = 0; - } - - /* xor */ - p = ivp ? ivp : iv; - q = sp; - for (i = 0; i < blocklen; i++) - q[i] ^= p[i]; - - /* encrypt */ - (*algo->blockencrypt)(algo, sav, sp, mtod(d, u_int8_t *) + dn); - - /* next iv */ - ivp = mtod(d, u_int8_t *) + dn; - - sn += blocklen; - dn += blocklen; - - /* find the next source block */ - while (s && sn >= s->m_len) { - sn -= s->m_len; - soff += s->m_len; - s = s->m_next; - } - - /* skip over empty mbuf */ - while (s && s->m_len == 0) - s = s->m_next; - } - - m_freem(scut->m_next); - scut->m_len = scutoff; - scut->m_next = d0; - - /* just in case */ - bzero(iv, sizeof(iv)); - bzero(sbuf, sizeof(sbuf)); - - key_sa_stir_iv(sav); - - return 0; -} - -/*------------------------------------------------------------*/ - -/* does not free m0 on error */ -int -esp_auth(m0, skip, length, sav, sum) - struct mbuf *m0; - size_t skip; /* offset to ESP header */ - size_t length; /* payload length */ - struct secasvar *sav; - u_char *sum; -{ - struct mbuf *m; - size_t off; - struct ah_algorithm_state s; - u_char sumbuf[AH_MAXSUMSIZE]; - const struct ah_algorithm *algo; - size_t siz; - int error; - - /* sanity checks */ - if (m0->m_pkthdr.len < skip) { - ipseclog((LOG_DEBUG, "esp_auth: mbuf length < skip\n")); - return EINVAL; - } - if (m0->m_pkthdr.len < skip + length) { - ipseclog((LOG_DEBUG, - "esp_auth: mbuf length < skip + length\n")); - return EINVAL; - } - /* - * length of esp part (excluding authentication data) must be 4n, - * since nexthdr must be at offset 4n+3. - */ - if (length % 4) { - ipseclog((LOG_ERR, "esp_auth: length is not multiple of 4\n")); - return EINVAL; - } - if (!sav) { - ipseclog((LOG_DEBUG, "esp_auth: NULL SA passed\n")); - return EINVAL; - } - algo = ah_algorithm_lookup(sav->alg_auth); - if (!algo) { - ipseclog((LOG_ERR, - "esp_auth: bad ESP auth algorithm passed: %d\n", - sav->alg_auth)); - return EINVAL; - } - - m = m0; - off = 0; - - siz = (((*algo->sumsiz)(sav) + 3) & ~(4 - 1)); - if (sizeof(sumbuf) < siz) { - ipseclog((LOG_DEBUG, - "esp_auth: AH_MAXSUMSIZE is too small: siz=%lu\n", - (u_long)siz)); - return EINVAL; - } - - /* skip the header */ - while (skip) { - if (!m) - panic("mbuf chain?"); - if (m->m_len <= skip) { - skip -= m->m_len; - m = m->m_next; - off = 0; - } else { - off = skip; - skip = 0; - } - } - - error = (*algo->init)(&s, sav); - if (error) - return error; - - while (0 < length) { - if (!m) - panic("mbuf chain?"); - - if (m->m_len - off < length) { - (*algo->update)(&s, mtod(m, u_char *) + off, - m->m_len - off); - length -= m->m_len - off; - m = m->m_next; - off = 0; - } else { - (*algo->update)(&s, mtod(m, u_char *) + off, length); - break; - } - } - (*algo->result)(&s, sumbuf, sizeof(sumbuf)); - bcopy(sumbuf, sum, siz); /* XXX */ - - return 0; -} diff --git a/sys/netinet6/esp_input.c b/sys/netinet6/esp_input.c deleted file mode 100644 index 9cdd108..0000000 --- a/sys/netinet6/esp_input.c +++ /dev/null @@ -1,975 +0,0 @@ -/* $FreeBSD$ */ -/* $KAME: esp_input.c,v 1.62 2002/01/07 11:39:57 kjc Exp $ */ - -/*- - * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * RFC1827/2406 Encapsulated Security Payload. - */ - -#include "opt_inet.h" -#include "opt_inet6.h" - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/mbuf.h> -#include <sys/domain.h> -#include <sys/protosw.h> -#include <sys/socket.h> -#include <sys/errno.h> -#include <sys/time.h> -#include <sys/syslog.h> - -#include <net/if.h> -#include <net/route.h> -#include <net/netisr.h> -#include <machine/cpu.h> - -#include <netinet/in.h> -#include <netinet/in_systm.h> -#include <netinet/ip.h> -#include <netinet/ip_var.h> -#include <netinet/in_var.h> -#include <netinet/ip_ecn.h> -#ifdef INET6 -#include <netinet6/ip6_ecn.h> -#endif - -#ifdef INET6 -#include <netinet/ip6.h> -#include <netinet/in_pcb.h> -#include <netinet6/in6_pcb.h> -#include <netinet6/ip6_var.h> -#include <netinet/icmp6.h> -#include <netinet6/ip6protosw.h> -#endif - -#include <netinet6/ipsec.h> -#ifdef INET6 -#include <netinet6/ipsec6.h> -#endif -#include <netinet6/ah.h> -#ifdef INET6 -#include <netinet6/ah6.h> -#endif -#include <netinet6/esp.h> -#ifdef INET6 -#include <netinet6/esp6.h> -#endif -#include <netkey/key.h> -#include <netkey/keydb.h> -#include <netkey/key_debug.h> - -#include <machine/stdarg.h> - -#define IPLEN_FLIPPED - -#define ESPMAXLEN \ - (sizeof(struct esp) < sizeof(struct newesp) \ - ? sizeof(struct newesp) : sizeof(struct esp)) - -#ifdef INET -extern struct protosw inetsw[]; - -void -esp4_input(m, off) - struct mbuf *m; - int off; -{ - struct ip *ip; - struct esp *esp; - struct esptail esptail; - u_int32_t spi; - struct secasvar *sav = NULL; - size_t taillen; - u_int16_t nxt; - const struct esp_algorithm *algo; - int ivlen; - size_t hlen; - size_t esplen; - - /* sanity check for alignment. */ - if (off % 4 != 0 || m->m_pkthdr.len % 4 != 0) { - ipseclog((LOG_ERR, "IPv4 ESP input: packet alignment problem " - "(off=%d, pktlen=%d)\n", off, m->m_pkthdr.len)); - ipsecstat.in_inval++; - goto bad; - } - - if (m->m_len < off + ESPMAXLEN) { - m = m_pullup(m, off + ESPMAXLEN); - if (!m) { - ipseclog((LOG_DEBUG, - "IPv4 ESP input: can't pullup in esp4_input\n")); - ipsecstat.in_inval++; - goto bad; - } - } - - ip = mtod(m, struct ip *); - esp = (struct esp *)(((u_int8_t *)ip) + off); -#ifdef _IP_VHL - hlen = IP_VHL_HL(ip->ip_vhl) << 2; -#else - hlen = ip->ip_hl << 2; -#endif - - /* find the sassoc. */ - spi = esp->esp_spi; - - if ((sav = key_allocsa(AF_INET, - (caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst, - IPPROTO_ESP, spi)) == 0) { - ipseclog((LOG_WARNING, - "IPv4 ESP input: no key association found for spi %u\n", - (u_int32_t)ntohl(spi))); - ipsecstat.in_nosa++; - goto bad; - } - KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP esp4_input called to allocate SA:%p\n", sav)); - if (sav->state != SADB_SASTATE_MATURE - && sav->state != SADB_SASTATE_DYING) { - ipseclog((LOG_DEBUG, - "IPv4 ESP input: non-mature/dying SA found for spi %u\n", - (u_int32_t)ntohl(spi))); - ipsecstat.in_badspi++; - goto bad; - } - algo = esp_algorithm_lookup(sav->alg_enc); - if (!algo) { - ipseclog((LOG_DEBUG, "IPv4 ESP input: " - "unsupported encryption algorithm for spi %u\n", - (u_int32_t)ntohl(spi))); - ipsecstat.in_badspi++; - goto bad; - } - - /* check if we have proper ivlen information */ - ivlen = sav->ivlen; - if (ivlen < 0) { - ipseclog((LOG_ERR, "inproper ivlen in IPv4 ESP input: %s %s\n", - ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav))); - ipsecstat.in_inval++; - goto bad; - } - - if (!((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay - && (sav->alg_auth && sav->key_auth))) - goto noreplaycheck; - - if (sav->alg_auth == SADB_X_AALG_NULL || - sav->alg_auth == SADB_AALG_NONE) - goto noreplaycheck; - - /* - * check for sequence number. - */ - if (ipsec_chkreplay(ntohl(((struct newesp *)esp)->esp_seq), sav)) - ; /* okey */ - else { - ipsecstat.in_espreplay++; - ipseclog((LOG_WARNING, - "replay packet in IPv4 ESP input: %s %s\n", - ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav))); - goto bad; - } - - /* check ICV */ - { - u_int8_t sum0[AH_MAXSUMSIZE]; - u_int8_t sum[AH_MAXSUMSIZE]; - const struct ah_algorithm *sumalgo; - size_t siz; - - sumalgo = ah_algorithm_lookup(sav->alg_auth); - if (!sumalgo) - goto noreplaycheck; - siz = (((*sumalgo->sumsiz)(sav) + 3) & ~(4 - 1)); - if (m->m_pkthdr.len < off + ESPMAXLEN + siz) { - ipsecstat.in_inval++; - goto bad; - } - if (AH_MAXSUMSIZE < siz) { - ipseclog((LOG_DEBUG, - "internal error: AH_MAXSUMSIZE must be larger than %lu\n", - (u_long)siz)); - ipsecstat.in_inval++; - goto bad; - } - - m_copydata(m, m->m_pkthdr.len - siz, siz, (caddr_t)&sum0[0]); - - if (esp_auth(m, off, m->m_pkthdr.len - off - siz, sav, sum)) { - ipseclog((LOG_WARNING, "auth fail in IPv4 ESP input: %s %s\n", - ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav))); - ipsecstat.in_espauthfail++; - goto bad; - } - - if (bcmp(sum0, sum, siz) != 0) { - ipseclog((LOG_WARNING, "auth fail in IPv4 ESP input: %s %s\n", - ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav))); - ipsecstat.in_espauthfail++; - goto bad; - } - - /* strip off the authentication data */ - m_adj(m, -siz); - ip = mtod(m, struct ip *); -#ifdef IPLEN_FLIPPED - ip->ip_len = ip->ip_len - siz; -#else - ip->ip_len = htons(ntohs(ip->ip_len) - siz); -#endif - m->m_flags |= M_AUTHIPDGM; - ipsecstat.in_espauthsucc++; - } - - /* - * update sequence number. - */ - if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) { - if (ipsec_updatereplay(ntohl(((struct newesp *)esp)->esp_seq), sav)) { - ipsecstat.in_espreplay++; - goto bad; - } - } - -noreplaycheck: - - /* process main esp header. */ - if (sav->flags & SADB_X_EXT_OLD) { - /* RFC 1827 */ - esplen = sizeof(struct esp); - } else { - /* RFC 2406 */ - if (sav->flags & SADB_X_EXT_DERIV) - esplen = sizeof(struct esp); - else - esplen = sizeof(struct newesp); - } - - if (m->m_pkthdr.len < off + esplen + ivlen + sizeof(esptail)) { - ipseclog((LOG_WARNING, - "IPv4 ESP input: packet too short\n")); - ipsecstat.in_inval++; - goto bad; - } - - if (m->m_len < off + esplen + ivlen) { - m = m_pullup(m, off + esplen + ivlen); - if (!m) { - ipseclog((LOG_DEBUG, - "IPv4 ESP input: can't pullup in esp4_input\n")); - ipsecstat.in_inval++; - goto bad; - } - } - - /* - * pre-compute and cache intermediate key - */ - if (esp_schedule(algo, sav) != 0) { - ipsecstat.in_inval++; - goto bad; - } - - /* - * decrypt the packet. - */ - if (!algo->decrypt) - panic("internal error: no decrypt function"); - if ((*algo->decrypt)(m, off, sav, algo, ivlen)) { - /* m is already freed */ - m = NULL; - ipseclog((LOG_ERR, "decrypt fail in IPv4 ESP input: %s\n", - ipsec_logsastr(sav))); - ipsecstat.in_inval++; - goto bad; - } - ipsecstat.in_esphist[sav->alg_enc]++; - - m->m_flags |= M_DECRYPTED; - - /* - * find the trailer of the ESP. - */ - m_copydata(m, m->m_pkthdr.len - sizeof(esptail), sizeof(esptail), - (caddr_t)&esptail); - nxt = esptail.esp_nxt; - taillen = esptail.esp_padlen + sizeof(esptail); - - if (m->m_pkthdr.len < taillen || - m->m_pkthdr.len - taillen < off + esplen + ivlen + sizeof(esptail)) { - ipseclog((LOG_WARNING, - "bad pad length in IPv4 ESP input: %s %s\n", - ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav))); - ipsecstat.in_inval++; - goto bad; - } - - /* strip off the trailing pad area. */ - m_adj(m, -taillen); - -#ifdef IPLEN_FLIPPED - ip->ip_len = ip->ip_len - taillen; -#else - ip->ip_len = htons(ntohs(ip->ip_len) - taillen); -#endif - - /* was it transmitted over the IPsec tunnel SA? */ - if (ipsec4_tunnel_validate(m, off + esplen + ivlen, nxt, sav)) { - /* - * strip off all the headers that precedes ESP header. - * IP4 xx ESP IP4' payload -> IP4' payload - * - * XXX more sanity checks - * XXX relationship with gif? - */ - u_int8_t tos; - - tos = ip->ip_tos; - m_adj(m, off + esplen + ivlen); - if (m->m_len < sizeof(*ip)) { - m = m_pullup(m, sizeof(*ip)); - if (!m) { - ipsecstat.in_inval++; - goto bad; - } - } - ip = mtod(m, struct ip *); - /* ECN consideration. */ - if (!ip_ecn_egress(ip4_ipsec_ecn, &tos, &ip->ip_tos)) { - ipsecstat.in_inval++; - goto bad; - } - if (!key_checktunnelsanity(sav, AF_INET, - (caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst)) { - ipseclog((LOG_ERR, "ipsec tunnel address mismatch " - "in IPv4 ESP input: %s %s\n", - ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav))); - ipsecstat.in_inval++; - goto bad; - } - - key_sa_recordxfer(sav, m); - if (ipsec_addhist(m, IPPROTO_ESP, spi) != 0 || - ipsec_addhist(m, IPPROTO_IPV4, 0) != 0) { - ipsecstat.in_nomem++; - goto bad; - } - - if (netisr_queue(NETISR_IP, m)) { /* (0) on success. */ - ipsecstat.in_inval++; - m = NULL; - goto bad; - } - m = NULL; - nxt = IPPROTO_DONE; - } else { - /* - * strip off ESP header and IV. - * even in m_pulldown case, we need to strip off ESP so that - * we can always compute checksum for AH correctly. - */ - size_t stripsiz; - - stripsiz = esplen + ivlen; - - ip = mtod(m, struct ip *); - ovbcopy((caddr_t)ip, (caddr_t)(((u_char *)ip) + stripsiz), off); - m->m_data += stripsiz; - m->m_len -= stripsiz; - m->m_pkthdr.len -= stripsiz; - - ip = mtod(m, struct ip *); -#ifdef IPLEN_FLIPPED - ip->ip_len = ip->ip_len - stripsiz; -#else - ip->ip_len = htons(ntohs(ip->ip_len) - stripsiz); -#endif - ip->ip_p = nxt; - - key_sa_recordxfer(sav, m); - if (ipsec_addhist(m, IPPROTO_ESP, spi) != 0) { - ipsecstat.in_nomem++; - goto bad; - } - - if (nxt != IPPROTO_DONE) { - if ((inetsw[ip_protox[nxt]].pr_flags & PR_LASTHDR) != 0 && - ipsec4_in_reject(m, NULL)) { - ipsecstat.in_polvio++; - goto bad; - } - (*inetsw[ip_protox[nxt]].pr_input)(m, off); - } else - m_freem(m); - m = NULL; - } - - if (sav) { - KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP esp4_input call free SA:%p\n", sav)); - key_freesav(sav); - } - ipsecstat.in_success++; - return; - -bad: - if (sav) { - KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP esp4_input call free SA:%p\n", sav)); - key_freesav(sav); - } - if (m) - m_freem(m); - return; -} -#endif /* INET */ - -#ifdef INET6 -int -esp6_input(mp, offp, proto) - struct mbuf **mp; - int *offp, proto; -{ - struct mbuf *m = *mp; - int off = *offp; - struct ip6_hdr *ip6; - struct esp *esp; - struct esptail esptail; - u_int32_t spi; - struct secasvar *sav = NULL; - size_t taillen; - u_int16_t nxt; - const struct esp_algorithm *algo; - int ivlen; - size_t esplen; - - /* sanity check for alignment. */ - if (off % 4 != 0 || m->m_pkthdr.len % 4 != 0) { - ipseclog((LOG_ERR, "IPv6 ESP input: packet alignment problem " - "(off=%d, pktlen=%d)\n", off, m->m_pkthdr.len)); - ipsec6stat.in_inval++; - goto bad; - } - -#ifndef PULLDOWN_TEST - IP6_EXTHDR_CHECK(m, off, ESPMAXLEN, IPPROTO_DONE); - esp = (struct esp *)(mtod(m, caddr_t) + off); -#else - IP6_EXTHDR_GET(esp, struct esp *, m, off, ESPMAXLEN); - if (esp == NULL) { - ipsec6stat.in_inval++; - return IPPROTO_DONE; - } -#endif - ip6 = mtod(m, struct ip6_hdr *); - - if (ntohs(ip6->ip6_plen) == 0) { - ipseclog((LOG_ERR, "IPv6 ESP input: " - "ESP with IPv6 jumbogram is not supported.\n")); - ipsec6stat.in_inval++; - goto bad; - } - - /* find the sassoc. */ - spi = esp->esp_spi; - - if ((sav = key_allocsa(AF_INET6, - (caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst, - IPPROTO_ESP, spi)) == 0) { - ipseclog((LOG_WARNING, - "IPv6 ESP input: no key association found for spi %u\n", - (u_int32_t)ntohl(spi))); - ipsec6stat.in_nosa++; - goto bad; - } - KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP esp6_input called to allocate SA:%p\n", sav)); - if (sav->state != SADB_SASTATE_MATURE - && sav->state != SADB_SASTATE_DYING) { - ipseclog((LOG_DEBUG, - "IPv6 ESP input: non-mature/dying SA found for spi %u\n", - (u_int32_t)ntohl(spi))); - ipsec6stat.in_badspi++; - goto bad; - } - algo = esp_algorithm_lookup(sav->alg_enc); - if (!algo) { - ipseclog((LOG_DEBUG, "IPv6 ESP input: " - "unsupported encryption algorithm for spi %u\n", - (u_int32_t)ntohl(spi))); - ipsec6stat.in_badspi++; - goto bad; - } - - /* check if we have proper ivlen information */ - ivlen = sav->ivlen; - if (ivlen < 0) { - ipseclog((LOG_ERR, "inproper ivlen in IPv6 ESP input: %s %s\n", - ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav))); - ipsec6stat.in_badspi++; - goto bad; - } - - if (!((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay - && (sav->alg_auth && sav->key_auth))) - goto noreplaycheck; - - if (sav->alg_auth == SADB_X_AALG_NULL || - sav->alg_auth == SADB_AALG_NONE) - goto noreplaycheck; - - /* - * check for sequence number. - */ - if (ipsec_chkreplay(ntohl(((struct newesp *)esp)->esp_seq), sav)) - ; /* okey */ - else { - ipsec6stat.in_espreplay++; - ipseclog((LOG_WARNING, - "replay packet in IPv6 ESP input: %s %s\n", - ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav))); - goto bad; - } - - /* check ICV */ - { - u_char sum0[AH_MAXSUMSIZE]; - u_char sum[AH_MAXSUMSIZE]; - const struct ah_algorithm *sumalgo; - size_t siz; - - sumalgo = ah_algorithm_lookup(sav->alg_auth); - if (!sumalgo) - goto noreplaycheck; - siz = (((*sumalgo->sumsiz)(sav) + 3) & ~(4 - 1)); - if (m->m_pkthdr.len < off + ESPMAXLEN + siz) { - ipsec6stat.in_inval++; - goto bad; - } - if (AH_MAXSUMSIZE < siz) { - ipseclog((LOG_DEBUG, - "internal error: AH_MAXSUMSIZE must be larger than %lu\n", - (u_long)siz)); - ipsec6stat.in_inval++; - goto bad; - } - - m_copydata(m, m->m_pkthdr.len - siz, siz, (caddr_t)&sum0[0]); - - if (esp_auth(m, off, m->m_pkthdr.len - off - siz, sav, sum)) { - ipseclog((LOG_WARNING, "auth fail in IPv6 ESP input: %s %s\n", - ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav))); - ipsec6stat.in_espauthfail++; - goto bad; - } - - if (bcmp(sum0, sum, siz) != 0) { - ipseclog((LOG_WARNING, "auth fail in IPv6 ESP input: %s %s\n", - ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav))); - ipsec6stat.in_espauthfail++; - goto bad; - } - - /* strip off the authentication data */ - m_adj(m, -siz); - ip6 = mtod(m, struct ip6_hdr *); - ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - siz); - - m->m_flags |= M_AUTHIPDGM; - ipsec6stat.in_espauthsucc++; - } - - /* - * update sequence number. - */ - if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) { - if (ipsec_updatereplay(ntohl(((struct newesp *)esp)->esp_seq), sav)) { - ipsec6stat.in_espreplay++; - goto bad; - } - } - -noreplaycheck: - - /* process main esp header. */ - if (sav->flags & SADB_X_EXT_OLD) { - /* RFC 1827 */ - esplen = sizeof(struct esp); - } else { - /* RFC 2406 */ - if (sav->flags & SADB_X_EXT_DERIV) - esplen = sizeof(struct esp); - else - esplen = sizeof(struct newesp); - } - - if (m->m_pkthdr.len < off + esplen + ivlen + sizeof(esptail)) { - ipseclog((LOG_WARNING, - "IPv6 ESP input: packet too short\n")); - ipsec6stat.in_inval++; - goto bad; - } - -#ifndef PULLDOWN_TEST - IP6_EXTHDR_CHECK(m, off, esplen + ivlen, IPPROTO_DONE); /* XXX */ -#else - IP6_EXTHDR_GET(esp, struct esp *, m, off, esplen + ivlen); - if (esp == NULL) { - ipsec6stat.in_inval++; - m = NULL; - goto bad; - } -#endif - ip6 = mtod(m, struct ip6_hdr *); /* set it again just in case */ - - /* - * pre-compute and cache intermediate key - */ - if (esp_schedule(algo, sav) != 0) { - ipsec6stat.in_inval++; - goto bad; - } - - /* - * decrypt the packet. - */ - if (!algo->decrypt) - panic("internal error: no decrypt function"); - if ((*algo->decrypt)(m, off, sav, algo, ivlen)) { - /* m is already freed */ - m = NULL; - ipseclog((LOG_ERR, "decrypt fail in IPv6 ESP input: %s\n", - ipsec_logsastr(sav))); - ipsec6stat.in_inval++; - goto bad; - } - ipsec6stat.in_esphist[sav->alg_enc]++; - - m->m_flags |= M_DECRYPTED; - - /* - * find the trailer of the ESP. - */ - m_copydata(m, m->m_pkthdr.len - sizeof(esptail), sizeof(esptail), - (caddr_t)&esptail); - nxt = esptail.esp_nxt; - taillen = esptail.esp_padlen + sizeof(esptail); - - if (m->m_pkthdr.len < taillen - || m->m_pkthdr.len - taillen < sizeof(struct ip6_hdr)) { /* ? */ - ipseclog((LOG_WARNING, - "bad pad length in IPv6 ESP input: %s %s\n", - ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav))); - ipsec6stat.in_inval++; - goto bad; - } - - /* strip off the trailing pad area. */ - m_adj(m, -taillen); - - ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - taillen); - - /* was it transmitted over the IPsec tunnel SA? */ - if (ipsec6_tunnel_validate(m, off + esplen + ivlen, nxt, sav)) { - /* - * strip off all the headers that precedes ESP header. - * IP6 xx ESP IP6' payload -> IP6' payload - * - * XXX more sanity checks - * XXX relationship with gif? - */ - u_int32_t flowinfo; /* net endian */ - flowinfo = ip6->ip6_flow; - m_adj(m, off + esplen + ivlen); - if (m->m_len < sizeof(*ip6)) { - m = m_pullup(m, sizeof(*ip6)); - if (!m) { - ipsec6stat.in_inval++; - goto bad; - } - } - ip6 = mtod(m, struct ip6_hdr *); - /* ECN consideration. */ - if (!ip6_ecn_egress(ip6_ipsec_ecn, &flowinfo, &ip6->ip6_flow)) { - ipsec6stat.in_inval++; - goto bad; - } - if (!key_checktunnelsanity(sav, AF_INET6, - (caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst)) { - ipseclog((LOG_ERR, "ipsec tunnel address mismatch " - "in IPv6 ESP input: %s %s\n", - ipsec6_logpacketstr(ip6, spi), - ipsec_logsastr(sav))); - ipsec6stat.in_inval++; - goto bad; - } - - key_sa_recordxfer(sav, m); - if (ipsec_addhist(m, IPPROTO_ESP, spi) != 0 || - ipsec_addhist(m, IPPROTO_IPV6, 0) != 0) { - ipsec6stat.in_nomem++; - goto bad; - } - - if (netisr_queue(NETISR_IPV6, m)) { /* (0) on success. */ - ipsec6stat.in_inval++; - m = NULL; - goto bad; - } - m = NULL; - nxt = IPPROTO_DONE; - } else { - /* - * strip off ESP header and IV. - * even in m_pulldown case, we need to strip off ESP so that - * we can always compute checksum for AH correctly. - */ - size_t stripsiz; - u_int8_t *prvnxtp; - - /* - * Set the next header field of the previous header correctly. - */ - prvnxtp = ip6_get_prevhdr(m, off); /* XXX */ - *prvnxtp = nxt; - - stripsiz = esplen + ivlen; - - ip6 = mtod(m, struct ip6_hdr *); - if (m->m_len >= stripsiz + off) { - ovbcopy((caddr_t)ip6, ((caddr_t)ip6) + stripsiz, off); - m->m_data += stripsiz; - m->m_len -= stripsiz; - m->m_pkthdr.len -= stripsiz; - } else { - /* - * this comes with no copy if the boundary is on - * cluster - */ - struct mbuf *n; - - n = m_split(m, off, M_DONTWAIT); - if (n == NULL) { - /* m is retained by m_split */ - goto bad; - } - m_adj(n, stripsiz); - /* m_cat does not update m_pkthdr.len */ - m->m_pkthdr.len += n->m_pkthdr.len; - m_cat(m, n); - } - -#ifndef PULLDOWN_TEST - /* - * KAME requires that the packet to be contiguous on the - * mbuf. We need to make that sure. - * this kind of code should be avoided. - * XXX other conditions to avoid running this part? - */ - if (m->m_len != m->m_pkthdr.len) { - struct mbuf *n = NULL; - int maxlen; - - MGETHDR(n, M_DONTWAIT, MT_HEADER); - maxlen = MHLEN; - if (n) - M_MOVE_PKTHDR(n, m); - if (n && n->m_pkthdr.len > maxlen) { - MCLGET(n, M_DONTWAIT); - maxlen = MCLBYTES; - if ((n->m_flags & M_EXT) == 0) { - m_free(n); - n = NULL; - } - } - if (!n) { - printf("esp6_input: mbuf allocation failed\n"); - goto bad; - } - - if (n->m_pkthdr.len <= maxlen) { - m_copydata(m, 0, n->m_pkthdr.len, mtod(n, caddr_t)); - n->m_len = n->m_pkthdr.len; - n->m_next = NULL; - m_freem(m); - } else { - m_copydata(m, 0, maxlen, mtod(n, caddr_t)); - n->m_len = maxlen; - n->m_next = m; - m_adj(m, maxlen); - } - m = n; - } -#endif - - ip6 = mtod(m, struct ip6_hdr *); - ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - stripsiz); - - key_sa_recordxfer(sav, m); - if (ipsec_addhist(m, IPPROTO_ESP, spi) != 0) { - ipsec6stat.in_nomem++; - goto bad; - } - } - - *offp = off; - *mp = m; - - if (sav) { - KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP esp6_input call free SA:%p\n", sav)); - key_freesav(sav); - } - ipsec6stat.in_success++; - return nxt; - -bad: - if (sav) { - KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP esp6_input call free SA:%p\n", sav)); - key_freesav(sav); - } - if (m) - m_freem(m); - return IPPROTO_DONE; -} - -void -esp6_ctlinput(cmd, sa, d) - int cmd; - struct sockaddr *sa; - void *d; -{ - const struct newesp *espp; - struct newesp esp; - struct ip6ctlparam *ip6cp = NULL, ip6cp1; - struct secasvar *sav; - struct ip6_hdr *ip6; - struct mbuf *m; - int off; - struct sockaddr_in6 *sa6_src, *sa6_dst; - - if (sa->sa_family != AF_INET6 || - sa->sa_len != sizeof(struct sockaddr_in6)) - return; - if ((unsigned)cmd >= PRC_NCMDS) - return; - - /* if the parameter is from icmp6, decode it. */ - if (d != NULL) { - ip6cp = (struct ip6ctlparam *)d; - m = ip6cp->ip6c_m; - ip6 = ip6cp->ip6c_ip6; - off = ip6cp->ip6c_off; - } else { - m = NULL; - ip6 = NULL; - off = 0; /* calm gcc */ - } - - if (ip6) { - /* - * Notify the error to all possible sockets via pfctlinput2. - * Since the upper layer information (such as protocol type, - * source and destination ports) is embedded in the encrypted - * data and might have been cut, we can't directly call - * an upper layer ctlinput function. However, the pcbnotify - * function will consider source and destination addresses - * as well as the flow info value, and may be able to find - * some PCB that should be notified. - * Although pfctlinput2 will call esp6_ctlinput(), there is - * no possibility of an infinite loop of function calls, - * because we don't pass the inner IPv6 header. - */ - bzero(&ip6cp1, sizeof(ip6cp1)); - ip6cp1.ip6c_src = ip6cp->ip6c_src; - pfctlinput2(cmd, sa, (void *)&ip6cp1); - - /* - * Then go to special cases that need ESP header information. - * XXX: We assume that when ip6 is non NULL, - * M and OFF are valid. - */ - - /* check if we can safely examine src and dst ports */ - if (m->m_pkthdr.len < off + sizeof(esp)) - return; - - if (m->m_len < off + sizeof(esp)) { - /* - * this should be rare case, - * so we compromise on this copy... - */ - m_copydata(m, off, sizeof(esp), (caddr_t)&esp); - espp = &esp; - } else - espp = (struct newesp*)(mtod(m, caddr_t) + off); - - if (cmd == PRC_MSGSIZE) { - int valid = 0; - - /* - * Check to see if we have a valid SA corresponding to - * the address in the ICMP message payload. - */ - sa6_src = ip6cp->ip6c_src; - sa6_dst = (struct sockaddr_in6 *)sa; - sav = key_allocsa(AF_INET6, - (caddr_t)&sa6_src->sin6_addr, - (caddr_t)&sa6_dst->sin6_addr, - IPPROTO_ESP, espp->esp_spi); - if (sav) { - if (sav->state == SADB_SASTATE_MATURE || - sav->state == SADB_SASTATE_DYING) - valid++; - key_freesav(sav); - } - - /* XXX Further validation? */ - - /* - * Depending on the value of "valid" and routing table - * size (mtudisc_{hi,lo}wat), we will: - * - recalcurate the new MTU and create the - * corresponding routing entry, or - * - ignore the MTU change notification. - */ - icmp6_mtudisc_update((struct ip6ctlparam *)d, valid); - } - } else { - /* we normally notify any pcb here */ - } -} -#endif /* INET6 */ diff --git a/sys/netinet6/esp_rijndael.c b/sys/netinet6/esp_rijndael.c deleted file mode 100644 index 97d52d3..0000000 --- a/sys/netinet6/esp_rijndael.c +++ /dev/null @@ -1,95 +0,0 @@ -/* $FreeBSD$ */ -/* $KAME: esp_rijndael.c,v 1.14 2003/08/28 08:23:20 itojun Exp $ */ - -/*- - * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/socket.h> -#include <sys/queue.h> - -#include <net/if.h> -#include <net/route.h> -#include <netinet/in.h> - -#include <netinet6/ipsec.h> -#include <netinet6/esp.h> -#include <netinet6/esp_rijndael.h> - -#include <crypto/rijndael/rijndael.h> - -size_t -esp_rijndael_schedlen(algo) - const struct esp_algorithm *algo; -{ - - return sizeof(rijndael_ctx); -} - -int -esp_rijndael_schedule(algo, sav) - const struct esp_algorithm *algo; - struct secasvar *sav; -{ - rijndael_ctx *ctx; - - ctx = (rijndael_ctx *)sav->sched; - rijndael_set_key(ctx, - (u_char *)_KEYBUF(sav->key_enc), _KEYLEN(sav->key_enc) * 8); - return 0; -} - -int -esp_rijndael_blockdecrypt(algo, sav, s, d) - const struct esp_algorithm *algo; - struct secasvar *sav; - u_int8_t *s; - u_int8_t *d; -{ - rijndael_ctx *ctx; - - ctx = (rijndael_ctx *)sav->sched; - rijndael_decrypt(ctx, s, d); - return 0; -} - -int -esp_rijndael_blockencrypt(algo, sav, s, d) - const struct esp_algorithm *algo; - struct secasvar *sav; - u_int8_t *s; - u_int8_t *d; -{ - rijndael_ctx *ctx; - - ctx = (rijndael_ctx *)sav->sched; - rijndael_encrypt(ctx, s, d); - return 0; -} diff --git a/sys/netinet6/ipcomp_core.c b/sys/netinet6/ipcomp_core.c deleted file mode 100644 index 66367b5..0000000 --- a/sys/netinet6/ipcomp_core.c +++ /dev/null @@ -1,356 +0,0 @@ -/* $FreeBSD$ */ -/* $KAME: ipcomp_core.c,v 1.25 2001/07/26 06:53:17 jinmei Exp $ */ - -/*- - * Copyright (C) 1999 WIDE Project. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * RFC2393 IP payload compression protocol (IPComp). - */ - -#include "opt_inet.h" -#include "opt_inet6.h" - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/malloc.h> -#include <sys/mbuf.h> -#include <sys/domain.h> -#include <sys/protosw.h> -#include <sys/socket.h> -#include <sys/errno.h> -#include <sys/time.h> -#include <sys/syslog.h> -#include <sys/queue.h> - -#include <net/if.h> -#include <net/route.h> -#include <netinet/in.h> -#include <net/netisr.h> -#include <net/zlib.h> -#include <machine/cpu.h> - -#include <netinet6/ipcomp.h> -#ifdef INET6 -#include <netinet6/ipcomp6.h> -#endif -#include <netinet6/ipsec.h> -#ifdef INET6 -#include <netinet6/ipsec6.h> -#endif - -#include <machine/stdarg.h> - -static void *deflate_alloc __P((void *, u_int, u_int)); -static void deflate_free __P((void *, void *)); -static int deflate_common __P((struct mbuf *, struct mbuf *, size_t *, int)); -static int deflate_compress __P((struct mbuf *, struct mbuf *, size_t *)); -static int deflate_decompress __P((struct mbuf *, struct mbuf *, size_t *)); - -/* - * We need to use default window size (2^15 = 32Kbytes as of writing) for - * inbound case. Otherwise we get interop problem. - * Use negative value to avoid Adler32 checksum. This is an undocumented - * feature in zlib (see ipsec wg mailing list archive in January 2000). - */ -static int deflate_policy = Z_DEFAULT_COMPRESSION; -static int deflate_window_out = -12; -static const int deflate_window_in = -1 * MAX_WBITS; /* don't change it */ -static int deflate_memlevel = MAX_MEM_LEVEL; - -static const struct ipcomp_algorithm ipcomp_algorithms[] = { - { deflate_compress, deflate_decompress, 90 }, -}; - -const struct ipcomp_algorithm * -ipcomp_algorithm_lookup(idx) - int idx; -{ - - if (idx == SADB_X_CALG_DEFLATE) - return &ipcomp_algorithms[0]; - return NULL; -} - -static void * -deflate_alloc(aux, items, siz) - void *aux; - u_int items; - u_int siz; -{ - void *ptr; - ptr = malloc(items * siz, M_TEMP, M_NOWAIT); - return ptr; -} - -static void -deflate_free(aux, ptr) - void *aux; - void *ptr; -{ - free(ptr, M_TEMP); -} - -static int -deflate_common(m, md, lenp, mode) - struct mbuf *m; - struct mbuf *md; - size_t *lenp; - int mode; /* 0: compress 1: decompress */ -{ - struct mbuf *mprev; - struct mbuf *p; - struct mbuf *n = NULL, *n0 = NULL, **np; - z_stream zs; - int error = 0; - int zerror; - size_t offset; - -#define MOREBLOCK() \ -do { \ - /* keep the reply buffer into our chain */ \ - if (n) { \ - n->m_len = zs.total_out - offset; \ - offset = zs.total_out; \ - *np = n; \ - np = &n->m_next; \ - n = NULL; \ - } \ - \ - /* get a fresh reply buffer */ \ - MGET(n, M_DONTWAIT, MT_DATA); \ - if (n) { \ - MCLGET(n, M_DONTWAIT); \ - } \ - if (!n) { \ - error = ENOBUFS; \ - goto fail; \ - } \ - n->m_len = 0; \ - n->m_len = M_TRAILINGSPACE(n); \ - n->m_next = NULL; \ - /* \ - * if this is the first reply buffer, reserve \ - * region for ipcomp header. \ - */ \ - if (*np == NULL) { \ - n->m_len -= sizeof(struct ipcomp); \ - n->m_data += sizeof(struct ipcomp); \ - } \ - \ - zs.next_out = mtod(n, u_int8_t *); \ - zs.avail_out = n->m_len; \ -} while (/*CONSTCOND*/ 0) - - for (mprev = m; mprev && mprev->m_next != md; mprev = mprev->m_next) - ; - if (!mprev) - panic("md is not in m in deflate_common"); - - bzero(&zs, sizeof(zs)); - zs.zalloc = deflate_alloc; - zs.zfree = deflate_free; - - zerror = mode ? inflateInit2(&zs, deflate_window_in) - : deflateInit2(&zs, deflate_policy, Z_DEFLATED, - deflate_window_out, deflate_memlevel, - Z_DEFAULT_STRATEGY); - if (zerror != Z_OK) { - error = ENOBUFS; - goto fail; - } - - n0 = n = NULL; - np = &n0; - offset = 0; - zerror = 0; - p = md; - while (p && p->m_len == 0) { - p = p->m_next; - } - - /* input stream and output stream are available */ - while (p && zs.avail_in == 0) { - /* get input buffer */ - if (p && zs.avail_in == 0) { - zs.next_in = mtod(p, u_int8_t *); - zs.avail_in = p->m_len; - p = p->m_next; - while (p && p->m_len == 0) { - p = p->m_next; - } - } - - /* get output buffer */ - if (zs.next_out == NULL || zs.avail_out == 0) { - MOREBLOCK(); - } - - zerror = mode ? inflate(&zs, Z_NO_FLUSH) - : deflate(&zs, Z_NO_FLUSH); - - if (zerror == Z_STREAM_END) - ; /* once more. */ - else if (zerror == Z_OK) { - /* inflate: Z_OK can indicate the end of decode */ - if (mode && !p && zs.avail_out != 0) - goto terminate; - else - ; /* once more. */ - } else { - if (zs.msg) { - ipseclog((LOG_ERR, "ipcomp_%scompress: " - "%sflate(Z_NO_FLUSH): %s\n", - mode ? "de" : "", mode ? "in" : "de", - zs.msg)); - } else { - ipseclog((LOG_ERR, "ipcomp_%scompress: " - "%sflate(Z_NO_FLUSH): unknown error (%d)\n", - mode ? "de" : "", mode ? "in" : "de", - zerror)); - } - mode ? inflateEnd(&zs) : deflateEnd(&zs); - error = EINVAL; - goto fail; - } - } - - if (zerror == Z_STREAM_END) - goto terminate; - - /* termination */ - while (1) { - /* get output buffer */ - if (zs.next_out == NULL || zs.avail_out == 0) { - MOREBLOCK(); - } - - zerror = mode ? inflate(&zs, Z_SYNC_FLUSH) - : deflate(&zs, Z_FINISH); - - if (zerror == Z_STREAM_END) - break; - else if (zerror == Z_OK) { - if (mode && zs.avail_out != 0) - goto terminate; - else - ; /* once more. */ - } else { - if (zs.msg) { - ipseclog((LOG_ERR, "ipcomp_%scompress: " - "%sflate(Z_FINISH): %s\n", - mode ? "de" : "", mode ? "in" : "de", - zs.msg)); - } else { - ipseclog((LOG_ERR, "ipcomp_%scompress: " - "%sflate(Z_FINISH): unknown error (%d)\n", - mode ? "de" : "", mode ? "in" : "de", - zerror)); - } - mode ? inflateEnd(&zs) : deflateEnd(&zs); - error = EINVAL; - goto fail; - } - } - -terminate: - zerror = mode ? inflateEnd(&zs) : deflateEnd(&zs); - if (zerror != Z_OK) { - if (zs.msg) { - ipseclog((LOG_ERR, "ipcomp_%scompress: " - "%sflateEnd: %s\n", - mode ? "de" : "", mode ? "in" : "de", - zs.msg)); - } else { - ipseclog((LOG_ERR, "ipcomp_%scompress: " - "%sflateEnd: unknown error (%d)\n", - mode ? "de" : "", mode ? "in" : "de", - zerror)); - } - error = EINVAL; - goto fail; - } - /* keep the final reply buffer into our chain */ - if (n) { - n->m_len = zs.total_out - offset; - offset = zs.total_out; - *np = n; - np = &n->m_next; - n = NULL; - } - - /* switch the mbuf to the new one */ - mprev->m_next = n0; - m_freem(md); - *lenp = zs.total_out; - - return 0; - -fail: - if (m) - m_freem(m); - if (n) - m_freem(n); - if (n0) - m_freem(n0); - return error; -#undef MOREBLOCK -} - -static int -deflate_compress(m, md, lenp) - struct mbuf *m; - struct mbuf *md; - size_t *lenp; -{ - if (!m) - panic("m == NULL in deflate_compress"); - if (!md) - panic("md == NULL in deflate_compress"); - if (!lenp) - panic("lenp == NULL in deflate_compress"); - - return deflate_common(m, md, lenp, 0); -} - -static int -deflate_decompress(m, md, lenp) - struct mbuf *m; - struct mbuf *md; - size_t *lenp; -{ - if (!m) - panic("m == NULL in deflate_decompress"); - if (!md) - panic("md == NULL in deflate_decompress"); - if (!lenp) - panic("lenp == NULL in deflate_decompress"); - - return deflate_common(m, md, lenp, 1); -} diff --git a/sys/netinet6/ipcomp_input.c b/sys/netinet6/ipcomp_input.c deleted file mode 100644 index abdebb2..0000000 --- a/sys/netinet6/ipcomp_input.c +++ /dev/null @@ -1,345 +0,0 @@ -/* $FreeBSD$ */ -/* $KAME: ipcomp_input.c,v 1.25 2001/03/01 09:12:09 itojun Exp $ */ - -/*- - * Copyright (C) 1999 WIDE Project. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * RFC2393 IP payload compression protocol (IPComp). - */ - -#include "opt_inet.h" -#include "opt_inet6.h" - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/mbuf.h> -#include <sys/domain.h> -#include <sys/protosw.h> -#include <sys/socket.h> -#include <sys/errno.h> -#include <sys/time.h> -#include <sys/syslog.h> - -#include <net/if.h> -#include <net/route.h> -#include <net/netisr.h> -#include <net/zlib.h> -#include <machine/cpu.h> - -#include <netinet/in.h> -#include <netinet/in_systm.h> -#include <netinet/in_var.h> -#include <netinet/ip.h> -#include <netinet/ip_var.h> -#include <netinet/ip_ecn.h> - -#ifdef INET6 -#include <netinet/ip6.h> -#include <netinet6/ip6_var.h> -#endif -#include <netinet6/ipcomp.h> -#ifdef INET6 -#include <netinet6/ipcomp6.h> -#endif - -#include <netinet6/ipsec.h> -#ifdef INET6 -#include <netinet6/ipsec6.h> -#endif -#include <netkey/key.h> -#include <netkey/keydb.h> - -#include <machine/stdarg.h> - -#define IPLEN_FLIPPED - -#ifdef INET -extern struct protosw inetsw[]; - -void -ipcomp4_input(m, off) - struct mbuf *m; - int off; -{ - struct mbuf *md; - struct ip *ip; - struct ipcomp *ipcomp; - const struct ipcomp_algorithm *algo; - u_int16_t cpi; /* host order */ - u_int16_t nxt; - size_t hlen; - int error; - size_t newlen, olen; - struct secasvar *sav = NULL; - - if (m->m_pkthdr.len < off + sizeof(struct ipcomp)) { - ipseclog((LOG_DEBUG, "IPv4 IPComp input: assumption failed " - "(packet too short)\n")); - ipsecstat.in_inval++; - goto fail; - } - - md = m_pulldown(m, off, sizeof(*ipcomp), NULL); - if (!md) { - m = NULL; /* already freed */ - ipseclog((LOG_DEBUG, "IPv4 IPComp input: assumption failed " - "(pulldown failure)\n")); - ipsecstat.in_inval++; - goto fail; - } - ipcomp = mtod(md, struct ipcomp *); - ip = mtod(m, struct ip *); - nxt = ipcomp->comp_nxt; -#ifdef _IP_VHL - hlen = IP_VHL_HL(ip->ip_vhl) << 2; -#else - hlen = ip->ip_hl << 2; -#endif - - cpi = ntohs(ipcomp->comp_cpi); - - if (cpi >= IPCOMP_CPI_NEGOTIATE_MIN) { - sav = key_allocsa(AF_INET, (caddr_t)&ip->ip_src, - (caddr_t)&ip->ip_dst, IPPROTO_IPCOMP, htonl(cpi)); - if (sav != NULL - && (sav->state == SADB_SASTATE_MATURE - || sav->state == SADB_SASTATE_DYING)) { - cpi = sav->alg_enc; /* XXX */ - /* other parameters to look at? */ - } - } - algo = ipcomp_algorithm_lookup(cpi); - if (!algo) { - ipseclog((LOG_WARNING, "IPv4 IPComp input: unknown cpi %u\n", - cpi)); - ipsecstat.in_nosa++; - goto fail; - } - - /* chop ipcomp header */ - ipcomp = NULL; - md->m_data += sizeof(struct ipcomp); - md->m_len -= sizeof(struct ipcomp); - m->m_pkthdr.len -= sizeof(struct ipcomp); -#ifdef IPLEN_FLIPPED - ip->ip_len -= sizeof(struct ipcomp); -#else - ip->ip_len = htons(ntohs(ip->ip_len) - sizeof(struct ipcomp)); -#endif - - olen = m->m_pkthdr.len; - newlen = m->m_pkthdr.len - off; - error = (*algo->decompress)(m, m->m_next, &newlen); - if (error != 0) { - if (error == EINVAL) - ipsecstat.in_inval++; - else if (error == ENOBUFS) - ipsecstat.in_nomem++; - m = NULL; - goto fail; - } - ipsecstat.in_comphist[cpi]++; - - /* - * returning decompressed packet onto icmp is meaningless. - * mark it decrypted to prevent icmp from attaching original packet. - */ - m->m_flags |= M_DECRYPTED; - - m->m_pkthdr.len = off + newlen; - ip = mtod(m, struct ip *); - { - size_t len; -#ifdef IPLEN_FLIPPED - len = ip->ip_len; -#else - len = ntohs(ip->ip_len); -#endif - /* - * be careful about underflow. also, do not assign exact value - * as ip_len is manipulated differently on *BSDs. - */ - len += m->m_pkthdr.len; - len -= olen; - if (len & ~0xffff) { - /* packet too big after decompress */ - ipsecstat.in_inval++; - goto fail; - } -#ifdef IPLEN_FLIPPED - ip->ip_len = len & 0xffff; -#else - ip->ip_len = htons(len & 0xffff); -#endif - ip->ip_p = nxt; - } - - if (sav) { - key_sa_recordxfer(sav, m); - if (ipsec_addhist(m, IPPROTO_IPCOMP, (u_int32_t)cpi) != 0) { - ipsecstat.in_nomem++; - goto fail; - } - key_freesav(sav); - sav = NULL; - } - - if (nxt != IPPROTO_DONE) { - if ((inetsw[ip_protox[nxt]].pr_flags & PR_LASTHDR) != 0 && - ipsec4_in_reject(m, NULL)) { - ipsecstat.in_polvio++; - goto fail; - } - (*inetsw[ip_protox[nxt]].pr_input)(m, off); - } else - m_freem(m); - m = NULL; - - ipsecstat.in_success++; - return; - -fail: - if (sav) - key_freesav(sav); - if (m) - m_freem(m); - return; -} -#endif /* INET */ - -#ifdef INET6 -int -ipcomp6_input(mp, offp, proto) - struct mbuf **mp; - int *offp, proto; -{ - struct mbuf *m, *md; - int off; - struct ip6_hdr *ip6; - struct ipcomp *ipcomp; - const struct ipcomp_algorithm *algo; - u_int16_t cpi; /* host order */ - u_int16_t nxt; - int error; - size_t newlen; - struct secasvar *sav = NULL; - u_int8_t *prvnxtp; - - m = *mp; - off = *offp; - - md = m_pulldown(m, off, sizeof(*ipcomp), NULL); - if (!md) { - m = NULL; /* already freed */ - ipseclog((LOG_DEBUG, "IPv6 IPComp input: assumption failed " - "(pulldown failure)\n")); - ipsec6stat.in_inval++; - goto fail; - } - ipcomp = mtod(md, struct ipcomp *); - ip6 = mtod(m, struct ip6_hdr *); - nxt = ipcomp->comp_nxt; - - cpi = ntohs(ipcomp->comp_cpi); - - if (cpi >= IPCOMP_CPI_NEGOTIATE_MIN) { - sav = key_allocsa(AF_INET6, (caddr_t)&ip6->ip6_src, - (caddr_t)&ip6->ip6_dst, IPPROTO_IPCOMP, htonl(cpi)); - if (sav != NULL - && (sav->state == SADB_SASTATE_MATURE - || sav->state == SADB_SASTATE_DYING)) { - cpi = sav->alg_enc; /* XXX */ - /* other parameters to look at? */ - } - } - algo = ipcomp_algorithm_lookup(cpi); - if (!algo) { - ipseclog((LOG_WARNING, "IPv6 IPComp input: unknown cpi %u; " - "dropping the packet for simplicity\n", cpi)); - ipsec6stat.in_nosa++; - goto fail; - } - - /* chop ipcomp header */ - ipcomp = NULL; - md->m_data += sizeof(struct ipcomp); - md->m_len -= sizeof(struct ipcomp); - m->m_pkthdr.len -= sizeof(struct ipcomp); - - newlen = m->m_pkthdr.len - off; - error = (*algo->decompress)(m, md, &newlen); - if (error != 0) { - if (error == EINVAL) - ipsec6stat.in_inval++; - else if (error == ENOBUFS) - ipsec6stat.in_nomem++; - m = NULL; - goto fail; - } - ipsec6stat.in_comphist[cpi]++; - m->m_pkthdr.len = off + newlen; - - /* - * returning decompressed packet onto icmp is meaningless. - * mark it decrypted to prevent icmp from attaching original packet. - */ - m->m_flags |= M_DECRYPTED; - - /* update next header field */ - prvnxtp = ip6_get_prevhdr(m, off); - *prvnxtp = nxt; - - /* - * no need to adjust payload length, as all the IPv6 protocols - * look at m->m_pkthdr.len - */ - - if (sav) { - key_sa_recordxfer(sav, m); - if (ipsec_addhist(m, IPPROTO_IPCOMP, (u_int32_t)cpi) != 0) { - ipsec6stat.in_nomem++; - goto fail; - } - key_freesav(sav); - sav = NULL; - } - *offp = off; - *mp = m; - ipsec6stat.in_success++; - return nxt; - -fail: - if (m) - m_freem(m); - if (sav) - key_freesav(sav); - return IPPROTO_DONE; -} -#endif /* INET6 */ diff --git a/sys/netinet6/ipcomp_output.c b/sys/netinet6/ipcomp_output.c deleted file mode 100644 index 3a89311..0000000 --- a/sys/netinet6/ipcomp_output.c +++ /dev/null @@ -1,382 +0,0 @@ -/* $FreeBSD$ */ -/* $KAME: ipcomp_output.c,v 1.25 2002/06/09 14:44:00 itojun Exp $ */ - -/*- - * Copyright (C) 1999 WIDE Project. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * RFC2393 IP payload compression protocol (IPComp). - */ - -#include "opt_inet.h" -#include "opt_inet6.h" - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/malloc.h> -#include <sys/mbuf.h> -#include <sys/domain.h> -#include <sys/protosw.h> -#include <sys/socket.h> -#include <sys/errno.h> -#include <sys/time.h> -#include <sys/syslog.h> - -#include <net/if.h> -#include <net/route.h> -#include <net/netisr.h> -#include <net/zlib.h> -#include <machine/cpu.h> - -#include <netinet/in.h> -#include <netinet/in_systm.h> -#include <netinet/in_var.h> -#include <netinet/ip.h> -#include <netinet/ip_var.h> -#include <netinet/ip_ecn.h> - -#ifdef INET6 -#include <netinet/ip6.h> -#include <netinet6/ip6_var.h> -#endif -#include <netinet6/ipcomp.h> -#ifdef INET6 -#include <netinet6/ipcomp6.h> -#endif - -#include <netinet6/ipsec.h> -#ifdef INET6 -#include <netinet6/ipsec6.h> -#endif -#include <netkey/key.h> -#include <netkey/keydb.h> - -#include <machine/stdarg.h> - -static int ipcomp_output __P((struct mbuf *, u_char *, struct mbuf *, - struct ipsecrequest *, int)); - -/* - * Modify the packet so that the payload is compressed. - * The mbuf (m) must start with IPv4 or IPv6 header. - * On failure, free the given mbuf and return non-zero. - * - * on invocation: - * m nexthdrp md - * v v v - * IP ......... payload - * during the encryption: - * m nexthdrp mprev md - * v v v v - * IP ............... ipcomp payload - * <-----><-----> - * complen plen - * <-> hlen - * <-----------------> compoff - */ -static int -ipcomp_output(m, nexthdrp, md, isr, af) - struct mbuf *m; - u_char *nexthdrp; - struct mbuf *md; - struct ipsecrequest *isr; - int af; -{ - struct mbuf *n; - struct mbuf *md0; - struct mbuf *mcopy; - struct mbuf *mprev; - struct ipcomp *ipcomp; - struct secasvar *sav = isr->sav; - const struct ipcomp_algorithm *algo; - u_int16_t cpi; /* host order */ - size_t plen0, plen; /* payload length to be compressed */ - size_t compoff; - int afnumber; - int error = 0; - struct ipsecstat *stat; - - switch (af) { -#ifdef INET - case AF_INET: - afnumber = 4; - stat = &ipsecstat; - break; -#endif -#ifdef INET6 - case AF_INET6: - afnumber = 6; - stat = &ipsec6stat; - break; -#endif - default: - ipseclog((LOG_ERR, "ipcomp_output: unsupported af %d\n", af)); - return 0; /* no change at all */ - } - - /* grab parameters */ - algo = ipcomp_algorithm_lookup(sav->alg_enc); - if ((ntohl(sav->spi) & ~0xffff) != 0 || !algo) { - stat->out_inval++; - m_freem(m); - return EINVAL; - } - if ((sav->flags & SADB_X_EXT_RAWCPI) == 0) - cpi = sav->alg_enc; - else - cpi = ntohl(sav->spi) & 0xffff; - - /* compute original payload length */ - plen = 0; - for (n = md; n; n = n->m_next) - plen += n->m_len; - - /* if the payload is short enough, we don't need to compress */ - if (plen < algo->minplen) - return 0; - - /* - * retain the original packet for two purposes: - * (1) we need to backout our changes when compression is not necessary. - * (2) byte lifetime computation should use the original packet. - * see RFC2401 page 23. - * compromise two m_copym(). we will be going through every byte of - * the payload during compression process anyways. - */ - mcopy = m_copym(m, 0, M_COPYALL, M_DONTWAIT); - if (mcopy == NULL) { - error = ENOBUFS; - return 0; - } - md0 = m_copym(md, 0, M_COPYALL, M_DONTWAIT); - if (md0 == NULL) { - m_freem(mcopy); - error = ENOBUFS; - return 0; - } - plen0 = plen; - - /* make the packet over-writable */ - for (mprev = m; mprev && mprev->m_next != md; mprev = mprev->m_next) - ; - if (mprev == NULL || mprev->m_next != md) { - ipseclog((LOG_DEBUG, "ipcomp%d_output: md is not in chain\n", - afnumber)); - stat->out_inval++; - m_freem(m); - m_freem(md0); - m_freem(mcopy); - return EINVAL; - } - mprev->m_next = NULL; - if ((md = ipsec_copypkt(md)) == NULL) { - m_freem(m); - m_freem(md0); - m_freem(mcopy); - error = ENOBUFS; - goto fail; - } - mprev->m_next = md; - - /* compress data part */ - if ((*algo->compress)(m, md, &plen) || mprev->m_next == NULL) { - ipseclog((LOG_ERR, "packet compression failure\n")); - m = NULL; - m_freem(md0); - m_freem(mcopy); - stat->out_inval++; - error = EINVAL; - goto fail; - } - stat->out_comphist[sav->alg_enc]++; - md = mprev->m_next; - - /* - * if the packet became bigger, meaningless to use IPComp. - * we've only wasted our cpu time. - */ - if (plen0 < plen) { - m_freem(md); - m_freem(mcopy); - mprev->m_next = md0; - return 0; - } - - /* - * no need to backout change beyond here. - */ - m_freem(md0); - md0 = NULL; - - m->m_pkthdr.len -= plen0; - m->m_pkthdr.len += plen; - - { - /* - * insert IPComp header. - */ -#ifdef INET - struct ip *ip = NULL; -#endif -#ifdef INET6 - struct ip6_hdr *ip6 = NULL; -#endif - size_t hlen = 0; /* ip header len */ - size_t complen = sizeof(struct ipcomp); - - switch (af) { -#ifdef INET - case AF_INET: - ip = mtod(m, struct ip *); -#ifdef _IP_VHL - hlen = IP_VHL_HL(ip->ip_vhl) << 2; -#else - hlen = ip->ip_hl << 2; -#endif - break; -#endif -#ifdef INET6 - case AF_INET6: - ip6 = mtod(m, struct ip6_hdr *); - hlen = sizeof(*ip6); - break; -#endif - } - - compoff = m->m_pkthdr.len - plen; - - /* - * grow the mbuf to accomodate ipcomp header. - * before: IP ... payload - * after: IP ... ipcomp payload - */ - if (M_LEADINGSPACE(md) < complen) { - MGET(n, M_DONTWAIT, MT_DATA); - if (!n) { - m_freem(m); - error = ENOBUFS; - goto fail; - } - n->m_len = complen; - mprev->m_next = n; - n->m_next = md; - m->m_pkthdr.len += complen; - ipcomp = mtod(n, struct ipcomp *); - } else { - md->m_len += complen; - md->m_data -= complen; - m->m_pkthdr.len += complen; - ipcomp = mtod(md, struct ipcomp *); - } - - bzero(ipcomp, sizeof(*ipcomp)); - ipcomp->comp_nxt = *nexthdrp; - *nexthdrp = IPPROTO_IPCOMP; - ipcomp->comp_cpi = htons(cpi); - switch (af) { -#ifdef INET - case AF_INET: - if (compoff + complen + plen < IP_MAXPACKET) - ip->ip_len = htons(compoff + complen + plen); - else { - ipseclog((LOG_ERR, - "IPv4 ESP output: size exceeds limit\n")); - ipsecstat.out_inval++; - m_freem(m); - error = EMSGSIZE; - goto fail; - } - break; -#endif -#ifdef INET6 - case AF_INET6: - /* total packet length will be computed in ip6_output() */ - break; -#endif - } - } - - if (!m) { - ipseclog((LOG_DEBUG, - "NULL mbuf after compression in ipcomp%d_output", - afnumber)); - stat->out_inval++; - } - stat->out_success++; - - /* compute byte lifetime against original packet */ - key_sa_recordxfer(sav, mcopy); - m_freem(mcopy); - - return 0; - -fail: -#if 1 - return error; -#else - panic("something bad in ipcomp_output"); -#endif -} - -#ifdef INET -int -ipcomp4_output(m, isr) - struct mbuf *m; - struct ipsecrequest *isr; -{ - struct ip *ip; - if (m->m_len < sizeof(struct ip)) { - ipseclog((LOG_DEBUG, "ipcomp4_output: first mbuf too short\n")); - ipsecstat.out_inval++; - m_freem(m); - return 0; - } - ip = mtod(m, struct ip *); - /* XXX assumes that m->m_next points to payload */ - return ipcomp_output(m, &ip->ip_p, m->m_next, isr, AF_INET); -} -#endif /* INET */ - -#ifdef INET6 -int -ipcomp6_output(m, nexthdrp, md, isr) - struct mbuf *m; - u_char *nexthdrp; - struct mbuf *md; - struct ipsecrequest *isr; -{ - if (m->m_len < sizeof(struct ip6_hdr)) { - ipseclog((LOG_DEBUG, "ipcomp6_output: first mbuf too short\n")); - ipsec6stat.out_inval++; - m_freem(m); - return 0; - } - return ipcomp_output(m, nexthdrp, md, isr, AF_INET6); -} -#endif /* INET6 */ diff --git a/sys/netinet6/ipsec.c b/sys/netinet6/ipsec.c deleted file mode 100644 index 294711e..0000000 --- a/sys/netinet6/ipsec.c +++ /dev/null @@ -1,3643 +0,0 @@ -/* $FreeBSD$ */ -/* $KAME: ipsec.c,v 1.207 2004/01/13 03:30:42 itojun Exp $ */ - -/*- - * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * IPsec controller part. - */ - -#include "opt_inet.h" -#include "opt_inet6.h" -#include "opt_ipsec.h" - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/malloc.h> -#include <sys/mbuf.h> -#include <sys/domain.h> -#include <sys/priv.h> -#include <sys/protosw.h> -#include <sys/socket.h> -#include <sys/socketvar.h> -#include <sys/errno.h> -#include <sys/time.h> -#include <sys/kernel.h> -#include <sys/syslog.h> -#include <sys/sysctl.h> -#include <sys/proc.h> - -#include <net/if.h> -#include <net/route.h> - -#include <netinet/in.h> -#include <netinet/in_systm.h> -#include <netinet/ip.h> -#include <netinet/ip_var.h> -#include <netinet/in_var.h> -#include <netinet/udp.h> -#include <netinet/udp_var.h> -#include <netinet/ip_ecn.h> -#ifdef INET6 -#include <netinet6/ip6_ecn.h> -#endif -#include <netinet/tcp.h> -#include <netinet/udp.h> - -#include <netinet/ip6.h> -#ifdef INET6 -#include <netinet6/ip6_var.h> -#include <netinet6/scope6_var.h> -#endif -#include <netinet/in_pcb.h> -#ifdef INET6 -#include <netinet/icmp6.h> -#endif - -#include <netinet6/ipsec.h> -#ifdef INET6 -#include <netinet6/ipsec6.h> -#endif -#include <netinet6/ah.h> -#ifdef INET6 -#include <netinet6/ah6.h> -#endif -#ifdef IPSEC_ESP -#include <netinet6/esp.h> -#ifdef INET6 -#include <netinet6/esp6.h> -#endif -#endif -#include <netinet6/ipcomp.h> -#ifdef INET6 -#include <netinet6/ipcomp6.h> -#endif -#include <netkey/key.h> -#include <netkey/keydb.h> -#include <netkey/key_debug.h> - -#include <machine/in_cksum.h> - -#ifdef IPSEC_DEBUG -int ipsec_debug = 1; -#else -int ipsec_debug = 0; -#endif - -NET_NEEDS_GIANT("ipsec"); - -struct ipsecstat ipsecstat; -int ip4_ah_cleartos = 1; -int ip4_ah_offsetmask = 0; /* maybe IP_DF? */ -int ip4_ipsec_dfbit = 0; /* DF bit on encap. 0: clear 1: set 2: copy */ -int ip4_esp_trans_deflev = IPSEC_LEVEL_USE; -int ip4_esp_net_deflev = IPSEC_LEVEL_USE; -int ip4_ah_trans_deflev = IPSEC_LEVEL_USE; -int ip4_ah_net_deflev = IPSEC_LEVEL_USE; -struct secpolicy *ip4_def_policy; -int ip4_ipsec_ecn = 0; /* ECN ignore(-1)/forbidden(0)/allowed(1) */ -int ip4_esp_randpad = -1; - -static int sp_cachegen = 1; /* cache generation # */ - -SYSCTL_DECL(_net_inet_ipsec); -#ifdef INET6 -SYSCTL_DECL(_net_inet6_ipsec6); -#endif - -/* net.inet.ipsec */ -SYSCTL_STRUCT(_net_inet_ipsec, IPSECCTL_STATS, - stats, CTLFLAG_RD, &ipsecstat, ipsecstat, ""); -#if 0 -SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_POLICY, - def_policy, CTLFLAG_RW, &ip4_def_policy->policy, 0, ""); -#endif -SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_ESP_TRANSLEV, esp_trans_deflev, - CTLFLAG_RW, &ip4_esp_trans_deflev, 0, ""); -SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_ESP_NETLEV, esp_net_deflev, - CTLFLAG_RW, &ip4_esp_net_deflev, 0, ""); -SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_AH_TRANSLEV, ah_trans_deflev, - CTLFLAG_RW, &ip4_ah_trans_deflev, 0, ""); -SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_AH_NETLEV, ah_net_deflev, - CTLFLAG_RW, &ip4_ah_net_deflev, 0, ""); -SYSCTL_INT(_net_inet_ipsec, IPSECCTL_AH_CLEARTOS, - ah_cleartos, CTLFLAG_RW, &ip4_ah_cleartos, 0, ""); -SYSCTL_INT(_net_inet_ipsec, IPSECCTL_AH_OFFSETMASK, - ah_offsetmask, CTLFLAG_RW, &ip4_ah_offsetmask, 0, ""); -SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DFBIT, - dfbit, CTLFLAG_RW, &ip4_ipsec_dfbit, 0, ""); -SYSCTL_INT(_net_inet_ipsec, IPSECCTL_ECN, - ecn, CTLFLAG_RW, &ip4_ipsec_ecn, 0, ""); -SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEBUG, - debug, CTLFLAG_RW, &ipsec_debug, 0, ""); -SYSCTL_INT(_net_inet_ipsec, IPSECCTL_ESP_RANDPAD, - esp_randpad, CTLFLAG_RW, &ip4_esp_randpad, 0, ""); - -#ifdef INET6 -struct ipsecstat ipsec6stat; -int ip6_esp_trans_deflev = IPSEC_LEVEL_USE; -int ip6_esp_net_deflev = IPSEC_LEVEL_USE; -int ip6_ah_trans_deflev = IPSEC_LEVEL_USE; -int ip6_ah_net_deflev = IPSEC_LEVEL_USE; -struct secpolicy *ip6_def_policy; -int ip6_ipsec_ecn = 0; /* ECN ignore(-1)/forbidden(0)/allowed(1) */ -int ip6_esp_randpad = -1; - -/* net.inet6.ipsec6 */ -SYSCTL_STRUCT(_net_inet6_ipsec6, IPSECCTL_STATS, - stats, CTLFLAG_RD, &ipsec6stat, ipsecstat, ""); -#if 0 -SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_POLICY, - def_policy, CTLFLAG_RW, &ip6_def_policy->policy, 0, ""); -#endif -SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_ESP_TRANSLEV, esp_trans_deflev, - CTLFLAG_RW, &ip6_esp_trans_deflev, 0, ""); -SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_ESP_NETLEV, esp_net_deflev, - CTLFLAG_RW, &ip6_esp_net_deflev, 0, ""); -SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_AH_TRANSLEV, ah_trans_deflev, - CTLFLAG_RW, &ip6_ah_trans_deflev, 0, ""); -SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_AH_NETLEV, ah_net_deflev, - CTLFLAG_RW, &ip6_ah_net_deflev, 0, ""); -SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_ECN, - ecn, CTLFLAG_RW, &ip6_ipsec_ecn, 0, ""); -SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEBUG, - debug, CTLFLAG_RW, &ipsec_debug, 0, ""); -SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_ESP_RANDPAD, - esp_randpad, CTLFLAG_RW, &ip6_esp_randpad, 0, ""); -#endif /* INET6 */ - -static struct secpolicy *ipsec_checkpcbcache __P((struct mbuf *, - struct inpcbpolicy *, int)); -static int ipsec_fillpcbcache __P((struct inpcbpolicy *, struct mbuf *, - struct secpolicy *, int)); -static int ipsec_invalpcbcache __P((struct inpcbpolicy *, int)); -static int ipsec_setspidx_mbuf - __P((struct secpolicyindex *, int, struct mbuf *, int)); -static int ipsec_setspidx __P((struct mbuf *, struct secpolicyindex *, int)); -static void ipsec4_get_ulp __P((struct mbuf *, struct secpolicyindex *, int)); -static int ipsec4_setspidx_ipaddr __P((struct mbuf *, struct secpolicyindex *)); -#ifdef INET6 -static void ipsec6_get_ulp __P((struct mbuf *, struct secpolicyindex *, int)); -static int ipsec6_setspidx_ipaddr __P((struct mbuf *, struct secpolicyindex *)); -#endif -static struct inpcbpolicy *ipsec_newpcbpolicy __P((void)); -static void ipsec_delpcbpolicy __P((struct inpcbpolicy *)); -#if 0 -static int ipsec_deepcopy_pcbpolicy __P((struct inpcbpolicy *)); -#endif -static struct secpolicy *ipsec_deepcopy_policy __P((struct secpolicy *)); -static int ipsec_set_policy - __P((struct secpolicy **, int, caddr_t, size_t, int)); -static int ipsec_get_policy __P((struct secpolicy *, struct mbuf **)); -static void vshiftl __P((unsigned char *, int, int)); -static int ipsec_in_reject __P((struct secpolicy *, struct mbuf *)); -static size_t ipsec_hdrsiz __P((struct secpolicy *)); -#ifdef INET -static struct mbuf *ipsec4_splithdr __P((struct mbuf *)); -#endif -#ifdef INET6 -static struct mbuf *ipsec6_splithdr __P((struct mbuf *)); -#endif -#ifdef INET -static int ipsec4_encapsulate __P((struct mbuf *, struct secasvar *)); -#endif -#ifdef INET6 -static int ipsec6_encapsulate __P((struct mbuf *, struct secasvar *)); -#endif -static struct ipsecaux *ipsec_addaux __P((struct mbuf *)); -static struct ipsecaux *ipsec_findaux __P((struct mbuf *)); -static void ipsec_optaux __P((struct mbuf *, struct ipsecaux *)); -#ifdef INET -static int ipsec4_checksa __P((struct ipsecrequest *, - struct ipsec_output_state *)); -#endif -#ifdef INET6 -static int ipsec6_checksa __P((struct ipsecrequest *, - struct ipsec_output_state *, int)); -#endif - -/* - * try to validate and use cached policy on a pcb. - */ -static struct secpolicy * -ipsec_checkpcbcache(m, pcbsp, dir) - struct mbuf *m; - struct inpcbpolicy *pcbsp; - int dir; -{ - struct secpolicyindex spidx; - struct timeval mono_time; - - microtime(&mono_time); - - switch (dir) { - case IPSEC_DIR_INBOUND: - case IPSEC_DIR_OUTBOUND: - case IPSEC_DIR_ANY: - break; - default: - return NULL; - } -#ifdef DIAGNOSTIC - if (dir >= sizeof(pcbsp->cache)/sizeof(pcbsp->cache[0])) - panic("dir too big in ipsec_checkpcbcache"); -#endif - /* SPD table change invalidates all the caches */ - if (pcbsp->cachegen[dir] == 0 || sp_cachegen > pcbsp->cachegen[dir]) { - ipsec_invalpcbcache(pcbsp, dir); - return NULL; - } - if (!pcbsp->cache[dir]) - return NULL; - if (pcbsp->cache[dir]->state != IPSEC_SPSTATE_ALIVE) { - ipsec_invalpcbcache(pcbsp, dir); - return NULL; - } - if ((pcbsp->cacheflags & IPSEC_PCBSP_CONNECTED) == 0) { - if (!pcbsp->cache[dir]) - return NULL; - if (ipsec_setspidx(m, &spidx, 1) != 0) - return NULL; - if (bcmp(&pcbsp->cacheidx[dir], &spidx, sizeof(spidx))) { - if (!pcbsp->cache[dir]->spidx || - !key_cmpspidx_withmask(pcbsp->cache[dir]->spidx, - &spidx)) - return NULL; - pcbsp->cacheidx[dir] = spidx; - } - } else { - /* - * The pcb is connected, and the L4 code is sure that: - * - outgoing side uses inp_[lf]addr - * - incoming side looks up policy after inpcb lookup - * and address pair is known to be stable. We do not need - * to generate spidx again, nor check the address match again. - * - * For IPv4/v6 SOCK_STREAM sockets, this assumption holds - * and there are calls to ipsec_pcbconn() from in_pcbconnect(). - */ - } - - pcbsp->cache[dir]->lastused = mono_time.tv_sec; - pcbsp->cache[dir]->refcnt++; - KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP ipsec_checkpcbcache cause refcnt++:%d SP:%p\n", - pcbsp->cache[dir]->refcnt, pcbsp->cache[dir])); - return pcbsp->cache[dir]; -} - -static int -ipsec_fillpcbcache(pcbsp, m, sp, dir) - struct inpcbpolicy *pcbsp; - struct mbuf *m; - struct secpolicy *sp; - int dir; -{ - - switch (dir) { - case IPSEC_DIR_INBOUND: - case IPSEC_DIR_OUTBOUND: - break; - default: - return EINVAL; - } -#ifdef DIAGNOSTIC - if (dir >= sizeof(pcbsp->cache)/sizeof(pcbsp->cache[0])) - panic("dir too big in ipsec_checkpcbcache"); -#endif - - if (pcbsp->cache[dir]) - key_freesp(pcbsp->cache[dir]); - pcbsp->cache[dir] = NULL; - if (ipsec_setspidx(m, &pcbsp->cacheidx[dir], 1) != 0) { - return EINVAL; - } - pcbsp->cache[dir] = sp; - if (pcbsp->cache[dir]) { - pcbsp->cache[dir]->refcnt++; - KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP ipsec_fillpcbcache cause refcnt++:%d SP:%p\n", - pcbsp->cache[dir]->refcnt, pcbsp->cache[dir])); - } - pcbsp->cachegen[dir] = sp_cachegen; - - return 0; -} - -static int -ipsec_invalpcbcache(pcbsp, dir) - struct inpcbpolicy *pcbsp; - int dir; -{ - int i; - - for (i = IPSEC_DIR_INBOUND; i <= IPSEC_DIR_OUTBOUND; i++) { - if (dir != IPSEC_DIR_ANY && i != dir) - continue; - if (pcbsp->cache[i]) - key_freesp(pcbsp->cache[i]); - pcbsp->cache[i] = NULL; - pcbsp->cachegen[i] = 0; - bzero(&pcbsp->cacheidx[i], sizeof(pcbsp->cacheidx[i])); - } - return 0; -} - -int -ipsec_pcbconn(pcbsp) - struct inpcbpolicy *pcbsp; -{ - - pcbsp->cacheflags |= IPSEC_PCBSP_CONNECTED; - ipsec_invalpcbcache(pcbsp, IPSEC_DIR_ANY); - return 0; -} - -int -ipsec_pcbdisconn(pcbsp) - struct inpcbpolicy *pcbsp; -{ - - pcbsp->cacheflags &= ~IPSEC_PCBSP_CONNECTED; - ipsec_invalpcbcache(pcbsp, IPSEC_DIR_ANY); - return 0; -} - -int -ipsec_invalpcbcacheall() -{ - - sp_cachegen++; - return 0; -} - -/* - * For OUTBOUND packet having a socket. Searching SPD for packet, - * and return a pointer to SP. - * OUT: NULL: no apropreate SP found, the following value is set to error. - * 0 : bypass - * EACCES : discard packet. - * ENOENT : ipsec_acquire() in progress, maybe. - * others : error occured. - * others: a pointer to SP - * - * NOTE: IPv6 mapped adddress concern is implemented here. - */ -struct secpolicy * -ipsec4_getpolicybypcb(m, dir, inp, error) - struct mbuf *m; - u_int dir; - struct inpcb *inp; - int *error; -{ - struct inpcbpolicy *pcbsp = NULL; - struct secpolicy *currsp = NULL; /* policy on socket */ - struct secpolicy *kernsp = NULL; /* policy on kernel */ - struct secpolicyindex spidx; - u_int16_t tag; - - /* sanity check */ - if (m == NULL || inp == NULL || error == NULL) - panic("ipsec4_getpolicybypcb: NULL pointer was passed."); - - pcbsp = inp->inp_sp; - -#ifdef DIAGNOSTIC - if (pcbsp == NULL) - panic("ipsec4_getpolicybypcb: pcbsp is NULL."); -#endif - - tag = 0; - - /* if we have a cached entry, and if it is still valid, use it. */ - ipsecstat.spdcachelookup++; - currsp = ipsec_checkpcbcache(m, pcbsp, dir); - if (currsp) { - *error = 0; - return currsp; - } - ipsecstat.spdcachemiss++; - - switch (dir) { - case IPSEC_DIR_INBOUND: - currsp = pcbsp->sp_in; - break; - case IPSEC_DIR_OUTBOUND: - currsp = pcbsp->sp_out; - break; - default: - panic("ipsec4_getpolicybypcb: illegal direction."); - } - - /* sanity check */ - if (currsp == NULL) - panic("ipsec4_getpolicybypcb: currsp is NULL."); - - /* when privileged socket */ - if (pcbsp->priv) { - switch (currsp->policy) { - case IPSEC_POLICY_BYPASS: - currsp->refcnt++; - *error = 0; - ipsec_fillpcbcache(pcbsp, m, currsp, dir); - return currsp; - - case IPSEC_POLICY_ENTRUST: - /* look for a policy in SPD */ - if (ipsec_setspidx_mbuf(&spidx, AF_INET, m, 1) == 0 && - (kernsp = key_allocsp(tag, &spidx, dir)) != NULL) { - /* SP found */ - KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP ipsec4_getpolicybypcb called " - "to allocate SP:%p\n", kernsp)); - *error = 0; - ipsec_fillpcbcache(pcbsp, m, kernsp, dir); - return kernsp; - } - - /* no SP found */ - ip4_def_policy->refcnt++; - *error = 0; - ipsec_fillpcbcache(pcbsp, m, ip4_def_policy, dir); - return ip4_def_policy; - - case IPSEC_POLICY_IPSEC: - currsp->refcnt++; - *error = 0; - ipsec_fillpcbcache(pcbsp, m, currsp, dir); - return currsp; - - default: - ipseclog((LOG_ERR, "ipsec4_getpolicybypcb: " - "Invalid policy for PCB %d\n", currsp->policy)); - *error = EINVAL; - return NULL; - } - /* NOTREACHED */ - } - - /* when non-privileged socket */ - /* look for a policy in SPD */ - if (ipsec_setspidx_mbuf(&spidx, AF_INET, m, 1) == 0 && - (kernsp = key_allocsp(tag, &spidx, dir)) != NULL) { - /* SP found */ - KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP ipsec4_getpolicybypcb called " - "to allocate SP:%p\n", kernsp)); - *error = 0; - ipsec_fillpcbcache(pcbsp, m, kernsp, dir); - return kernsp; - } - - /* no SP found */ - switch (currsp->policy) { - case IPSEC_POLICY_BYPASS: - ipseclog((LOG_ERR, "ipsec4_getpolicybypcb: " - "Illegal policy for non-privileged defined %d\n", - currsp->policy)); - *error = EINVAL; - return NULL; - - case IPSEC_POLICY_ENTRUST: - ip4_def_policy->refcnt++; - *error = 0; - ipsec_fillpcbcache(pcbsp, m, ip4_def_policy, dir); - return ip4_def_policy; - - case IPSEC_POLICY_IPSEC: - currsp->refcnt++; - *error = 0; - ipsec_fillpcbcache(pcbsp, m, currsp, dir); - return currsp; - - default: - ipseclog((LOG_ERR, "ipsec4_getpolicybypcb: " - "Invalid policy for PCB %d\n", currsp->policy)); - *error = EINVAL; - return NULL; - } - /* NOTREACHED */ -} - -/* - * For FORWADING packet or OUTBOUND without a socket. Searching SPD for packet, - * and return a pointer to SP. - * OUT: positive: a pointer to the entry for security policy leaf matched. - * NULL: no apropreate SP found, the following value is set to error. - * 0 : bypass - * EACCES : discard packet. - * ENOENT : ipsec_acquire() in progress, maybe. - * others : error occured. - */ -struct secpolicy * -ipsec4_getpolicybyaddr(m, dir, flag, error) - struct mbuf *m; - u_int dir; - int flag; - int *error; -{ - struct secpolicy *sp = NULL; - u_int16_t tag; - - /* sanity check */ - if (m == NULL || error == NULL) - panic("ipsec4_getpolicybyaddr: NULL pointer was passed."); - - /* get a policy entry matched with the packet */ - { - struct secpolicyindex spidx; - - bzero(&spidx, sizeof(spidx)); - - /* make an index to look for a policy */ - *error = ipsec_setspidx_mbuf(&spidx, AF_INET, m, - (flag & IP_FORWARDING) ? 0 : 1); - - if (*error != 0) - return NULL; - - tag = 0; - - sp = key_allocsp(tag, &spidx, dir); - } - - /* SP found */ - if (sp != NULL) { - KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP ipsec4_getpolicybyaddr called " - "to allocate SP:%p\n", sp)); - *error = 0; - return sp; - } - - /* no SP found */ - ip4_def_policy->refcnt++; - *error = 0; - return ip4_def_policy; -} - -#ifdef INET6 -/* - * For OUTBOUND packet having a socket. Searching SPD for packet, - * and return a pointer to SP. - * OUT: NULL: no apropreate SP found, the following value is set to error. - * 0 : bypass - * EACCES : discard packet. - * ENOENT : ipsec_acquire() in progress, maybe. - * others : error occured. - * others: a pointer to SP - */ -struct secpolicy * -ipsec6_getpolicybypcb(m, dir, inp, error) - struct mbuf *m; - u_int dir; - struct inpcb *inp; - int *error; -{ - struct inpcbpolicy *pcbsp = NULL; - struct secpolicy *currsp = NULL; /* policy on socket */ - struct secpolicy *kernsp = NULL; /* policy on kernel */ - struct secpolicyindex spidx; - u_int16_t tag; - - /* sanity check */ - if (m == NULL || inp == NULL || error == NULL) - panic("ipsec6_getpolicybypcb: NULL pointer was passed."); - -#ifdef DIAGNOSTIC - if ((inp->inp_vflag & INP_IPV6PROTO) == 0) - panic("ipsec6_getpolicybypcb: socket domain != inet6"); -#endif - - pcbsp = inp->in6p_sp; - -#ifdef DIAGNOSTIC - if (pcbsp == NULL) - panic("ipsec6_getpolicybypcb: pcbsp is NULL."); -#endif - - tag = 0; - - /* if we have a cached entry, and if it is still valid, use it. */ - ipsec6stat.spdcachelookup++; - currsp = ipsec_checkpcbcache(m, pcbsp, dir); - if (currsp) { - *error = 0; - return currsp; - } - ipsec6stat.spdcachemiss++; - - switch (dir) { - case IPSEC_DIR_INBOUND: - currsp = pcbsp->sp_in; - break; - case IPSEC_DIR_OUTBOUND: - currsp = pcbsp->sp_out; - break; - default: - panic("ipsec6_getpolicybypcb: illegal direction."); - } - - /* sanity check */ - if (currsp == NULL) - panic("ipsec6_getpolicybypcb: currsp is NULL."); - - /* when privileged socket */ - if (pcbsp->priv) { - switch (currsp->policy) { - case IPSEC_POLICY_BYPASS: - currsp->refcnt++; - *error = 0; - ipsec_fillpcbcache(pcbsp, m, currsp, dir); - return currsp; - - case IPSEC_POLICY_ENTRUST: - /* look for a policy in SPD */ - if (ipsec_setspidx_mbuf(&spidx, AF_INET6, m, 1) == 0 && - (kernsp = key_allocsp(tag, &spidx, dir)) != NULL) { - /* SP found */ - KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP ipsec6_getpolicybypcb called " - "to allocate SP:%p\n", kernsp)); - *error = 0; - ipsec_fillpcbcache(pcbsp, m, kernsp, dir); - return kernsp; - } - - /* no SP found */ - ip6_def_policy->refcnt++; - *error = 0; - ipsec_fillpcbcache(pcbsp, m, ip6_def_policy, dir); - return ip6_def_policy; - - case IPSEC_POLICY_IPSEC: - currsp->refcnt++; - *error = 0; - ipsec_fillpcbcache(pcbsp, m, currsp, dir); - return currsp; - - default: - ipseclog((LOG_ERR, "ipsec6_getpolicybypcb: " - "Invalid policy for PCB %d\n", currsp->policy)); - *error = EINVAL; - return NULL; - } - /* NOTREACHED */ - } - - /* when non-privileged socket */ - /* look for a policy in SPD */ - if (ipsec_setspidx_mbuf(&spidx, AF_INET6, m, 1) == 0 && - (kernsp = key_allocsp(tag, &spidx, dir)) != NULL) { - /* SP found */ - KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP ipsec6_getpolicybypcb called " - "to allocate SP:%p\n", kernsp)); - *error = 0; - ipsec_fillpcbcache(pcbsp, m, kernsp, dir); - return kernsp; - } - - /* no SP found */ - switch (currsp->policy) { - case IPSEC_POLICY_BYPASS: - ipseclog((LOG_ERR, "ipsec6_getpolicybypcb: " - "Illegal policy for non-privileged defined %d\n", - currsp->policy)); - *error = EINVAL; - return NULL; - - case IPSEC_POLICY_ENTRUST: - ip6_def_policy->refcnt++; - *error = 0; - ipsec_fillpcbcache(pcbsp, m, ip6_def_policy, dir); - return ip6_def_policy; - - case IPSEC_POLICY_IPSEC: - currsp->refcnt++; - *error = 0; - ipsec_fillpcbcache(pcbsp, m, currsp, dir); - return currsp; - - default: - ipseclog((LOG_ERR, - "ipsec6_policybysock: Invalid policy for PCB %d\n", - currsp->policy)); - *error = EINVAL; - return NULL; - } - /* NOTREACHED */ -} - -/* - * For FORWADING packet or OUTBOUND without a socket. Searching SPD for packet, - * and return a pointer to SP. - * `flag' means that packet is to be forwarded whether or not. - * flag = 1: forwad - * OUT: positive: a pointer to the entry for security policy leaf matched. - * NULL: no apropreate SP found, the following value is set to error. - * 0 : bypass - * EACCES : discard packet. - * ENOENT : ipsec_acquire() in progress, maybe. - * others : error occured. - */ -#ifndef IP_FORWARDING -#define IP_FORWARDING 1 -#endif - -struct secpolicy * -ipsec6_getpolicybyaddr(m, dir, flag, error) - struct mbuf *m; - u_int dir; - int flag; - int *error; -{ - struct secpolicy *sp = NULL; - u_int16_t tag; - - /* sanity check */ - if (m == NULL || error == NULL) - panic("ipsec6_getpolicybyaddr: NULL pointer was passed."); - - /* get a policy entry matched with the packet */ - { - struct secpolicyindex spidx; - - bzero(&spidx, sizeof(spidx)); - - /* make an index to look for a policy */ - *error = ipsec_setspidx_mbuf(&spidx, AF_INET6, m, - (flag & IP_FORWARDING) ? 0 : 1); - - if (*error != 0) - return NULL; - - tag = 0; - - sp = key_allocsp(tag, &spidx, dir); - } - - /* SP found */ - if (sp != NULL) { - KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP ipsec6_getpolicybyaddr called " - "to allocate SP:%p\n", sp)); - *error = 0; - return sp; - } - - /* no SP found */ - ip6_def_policy->refcnt++; - *error = 0; - return ip6_def_policy; -} -#endif /* INET6 */ - -/* - * set IP address into spidx from mbuf. - * When Forwarding packet and ICMP echo reply, this function is used. - * - * IN: get the followings from mbuf. - * protocol family, src, dst, next protocol - * OUT: - * 0: success. - * other: failure, and set errno. - */ -int -ipsec_setspidx_mbuf(spidx, family, m, needport) - struct secpolicyindex *spidx; - int family; - struct mbuf *m; - int needport; -{ - int error; - - /* sanity check */ - if (spidx == NULL || m == NULL) - panic("ipsec_setspidx_mbuf: NULL pointer was passed."); - - bzero(spidx, sizeof(*spidx)); - - error = ipsec_setspidx(m, spidx, needport); - if (error) - goto bad; - - return 0; - - bad: - /* XXX initialize */ - bzero(spidx, sizeof(*spidx)); - return EINVAL; -} - -/* - * configure security policy index (src/dst/proto/sport/dport) - * by looking at the content of mbuf. - * the caller is responsible for error recovery (like clearing up spidx). - */ -static int -ipsec_setspidx(m, spidx, needport) - struct mbuf *m; - struct secpolicyindex *spidx; - int needport; -{ - struct ip *ip = NULL; - struct ip ipbuf; - u_int v; - struct mbuf *n; - int len; - int error; - - if (m == NULL) - panic("ipsec_setspidx: m == 0 passed."); - - bzero(spidx, sizeof(*spidx)); - - /* - * validate m->m_pkthdr.len. we see incorrect length if we - * mistakenly call this function with inconsistent mbuf chain - * (like 4.4BSD tcp/udp processing). XXX should we panic here? - */ - len = 0; - for (n = m; n; n = n->m_next) - len += n->m_len; - if (m->m_pkthdr.len != len) { - KEYDEBUG(KEYDEBUG_IPSEC_DUMP, - printf("ipsec_setspidx: " - "total of m_len(%d) != pkthdr.len(%d), " - "ignored.\n", - len, m->m_pkthdr.len)); - return EINVAL; - } - - if (m->m_pkthdr.len < sizeof(struct ip)) { - KEYDEBUG(KEYDEBUG_IPSEC_DUMP, - printf("ipsec_setspidx: " - "pkthdr.len(%d) < sizeof(struct ip), ignored.\n", - m->m_pkthdr.len)); - return EINVAL; - } - - if (m->m_len >= sizeof(*ip)) - ip = mtod(m, struct ip *); - else { - m_copydata(m, 0, sizeof(ipbuf), (caddr_t)&ipbuf); - ip = &ipbuf; - } -#ifdef _IP_VHL - v = _IP_VHL_V(ip->ip_vhl); -#else - v = ip->ip_v; -#endif - switch (v) { - case 4: - error = ipsec4_setspidx_ipaddr(m, spidx); - if (error) - return error; - ipsec4_get_ulp(m, spidx, needport); - return 0; -#ifdef INET6 - case 6: - if (m->m_pkthdr.len < sizeof(struct ip6_hdr)) { - KEYDEBUG(KEYDEBUG_IPSEC_DUMP, - printf("ipsec_setspidx: " - "pkthdr.len(%d) < sizeof(struct ip6_hdr), " - "ignored.\n", m->m_pkthdr.len)); - return EINVAL; - } - error = ipsec6_setspidx_ipaddr(m, spidx); - if (error) - return error; - ipsec6_get_ulp(m, spidx, needport); - return 0; -#endif - default: - KEYDEBUG(KEYDEBUG_IPSEC_DUMP, - printf("ipsec_setspidx: " - "unknown IP version %u, ignored.\n", v)); - return EINVAL; - } -} - -static void -ipsec4_get_ulp(m, spidx, needport) - struct mbuf *m; - struct secpolicyindex *spidx; - int needport; -{ - struct ip ip; - struct ip6_ext ip6e; - u_int8_t nxt; - int off; - struct tcphdr th; - struct udphdr uh; - - /* sanity check */ - if (m == NULL) - panic("ipsec4_get_ulp: NULL pointer was passed."); - if (m->m_pkthdr.len < sizeof(ip)) - panic("ipsec4_get_ulp: too short"); - - /* set default */ - spidx->ul_proto = IPSEC_ULPROTO_ANY; - ((struct sockaddr_in *)&spidx->src)->sin_port = IPSEC_PORT_ANY; - ((struct sockaddr_in *)&spidx->dst)->sin_port = IPSEC_PORT_ANY; - - m_copydata(m, 0, sizeof(ip), (caddr_t)&ip); - /* ip_input() flips it into host endian XXX need more checking */ - if (ip.ip_off & (IP_MF | IP_OFFMASK)) - return; - - nxt = ip.ip_p; -#ifdef _IP_VHL - off = _IP_VHL_HL(ip->ip_vhl) << 2; -#else - off = ip.ip_hl << 2; -#endif - while (off < m->m_pkthdr.len) { - switch (nxt) { - case IPPROTO_TCP: - spidx->ul_proto = nxt; - if (!needport) - return; - if (off + sizeof(struct tcphdr) > m->m_pkthdr.len) - return; - m_copydata(m, off, sizeof(th), (caddr_t)&th); - ((struct sockaddr_in *)&spidx->src)->sin_port = - th.th_sport; - ((struct sockaddr_in *)&spidx->dst)->sin_port = - th.th_dport; - return; - case IPPROTO_UDP: - spidx->ul_proto = nxt; - if (!needport) - return; - if (off + sizeof(struct udphdr) > m->m_pkthdr.len) - return; - m_copydata(m, off, sizeof(uh), (caddr_t)&uh); - ((struct sockaddr_in *)&spidx->src)->sin_port = - uh.uh_sport; - ((struct sockaddr_in *)&spidx->dst)->sin_port = - uh.uh_dport; - return; - case IPPROTO_AH: - if (off + sizeof(ip6e) > m->m_pkthdr.len) - return; - m_copydata(m, off, sizeof(ip6e), (caddr_t)&ip6e); - off += (ip6e.ip6e_len + 2) << 2; - nxt = ip6e.ip6e_nxt; - break; - case IPPROTO_ICMP: - default: - /* XXX intermediate headers??? */ - spidx->ul_proto = nxt; - return; - } - } -} - -/* assumes that m is sane */ -static int -ipsec4_setspidx_ipaddr(m, spidx) - struct mbuf *m; - struct secpolicyindex *spidx; -{ - struct ip *ip = NULL; - struct ip ipbuf; - struct sockaddr_in *sin; - - if (m->m_len >= sizeof(*ip)) - ip = mtod(m, struct ip *); - else { - m_copydata(m, 0, sizeof(ipbuf), (caddr_t)&ipbuf); - ip = &ipbuf; - } - - sin = (struct sockaddr_in *)&spidx->src; - bzero(sin, sizeof(*sin)); - sin->sin_family = AF_INET; - sin->sin_len = sizeof(struct sockaddr_in); - bcopy(&ip->ip_src, &sin->sin_addr, sizeof(ip->ip_src)); - spidx->prefs = sizeof(struct in_addr) << 3; - - sin = (struct sockaddr_in *)&spidx->dst; - bzero(sin, sizeof(*sin)); - sin->sin_family = AF_INET; - sin->sin_len = sizeof(struct sockaddr_in); - bcopy(&ip->ip_dst, &sin->sin_addr, sizeof(ip->ip_dst)); - spidx->prefd = sizeof(struct in_addr) << 3; - return 0; -} - -#ifdef INET6 -static void -ipsec6_get_ulp(m, spidx, needport) - struct mbuf *m; - struct secpolicyindex *spidx; - int needport; -{ - int off, nxt; - struct tcphdr th; - struct udphdr uh; - struct icmp6_hdr ih; - - /* sanity check */ - if (m == NULL) - panic("ipsec6_get_ulp: NULL pointer was passed."); - - KEYDEBUG(KEYDEBUG_IPSEC_DUMP, - printf("ipsec6_get_ulp:\n"); kdebug_mbuf(m)); - - /* set default */ - spidx->ul_proto = IPSEC_ULPROTO_ANY; - ((struct sockaddr_in6 *)&spidx->src)->sin6_port = IPSEC_PORT_ANY; - ((struct sockaddr_in6 *)&spidx->dst)->sin6_port = IPSEC_PORT_ANY; - - nxt = -1; - off = ip6_lasthdr(m, 0, IPPROTO_IPV6, &nxt); - if (off < 0 || m->m_pkthdr.len < off) - return; - - switch (nxt) { - case IPPROTO_TCP: - spidx->ul_proto = nxt; - if (!needport) - break; - if (off + sizeof(struct tcphdr) > m->m_pkthdr.len) - break; - m_copydata(m, off, sizeof(th), (caddr_t)&th); - ((struct sockaddr_in6 *)&spidx->src)->sin6_port = th.th_sport; - ((struct sockaddr_in6 *)&spidx->dst)->sin6_port = th.th_dport; - break; - case IPPROTO_UDP: - spidx->ul_proto = nxt; - if (!needport) - break; - if (off + sizeof(struct udphdr) > m->m_pkthdr.len) - break; - m_copydata(m, off, sizeof(uh), (caddr_t)&uh); - ((struct sockaddr_in6 *)&spidx->src)->sin6_port = uh.uh_sport; - ((struct sockaddr_in6 *)&spidx->dst)->sin6_port = uh.uh_dport; - break; - case IPPROTO_ICMPV6: - spidx->ul_proto = nxt; - if (off + sizeof(struct icmp6_hdr) > m->m_pkthdr.len) - break; - m_copydata(m, off, sizeof(ih), (caddr_t)&ih); - ((struct sockaddr_in6 *)&spidx->src)->sin6_port = - htons((u_int16_t)ih.icmp6_type); - ((struct sockaddr_in6 *)&spidx->dst)->sin6_port = - htons((u_int16_t)ih.icmp6_code); - break; - default: - /* XXX intermediate headers??? */ - spidx->ul_proto = nxt; - break; - } -} - -/* assumes that m is sane */ -static int -ipsec6_setspidx_ipaddr(m, spidx) - struct mbuf *m; - struct secpolicyindex *spidx; -{ - struct ip6_hdr *ip6 = NULL; - struct ip6_hdr ip6buf; - struct sockaddr_in6 *sin6; - - if (m->m_len >= sizeof(*ip6)) - ip6 = mtod(m, struct ip6_hdr *); - else { - m_copydata(m, 0, sizeof(ip6buf), (caddr_t)&ip6buf); - ip6 = &ip6buf; - } - - sin6 = (struct sockaddr_in6 *)&spidx->src; - bzero(sin6, sizeof(*sin6)); - sin6->sin6_family = AF_INET6; - sin6->sin6_len = sizeof(struct sockaddr_in6); - sin6->sin6_addr = ip6->ip6_src; - spidx->prefs = sizeof(struct in6_addr) << 3; - - sin6 = (struct sockaddr_in6 *)&spidx->dst; - bzero(sin6, sizeof(*sin6)); - sin6->sin6_family = AF_INET6; - sin6->sin6_len = sizeof(struct sockaddr_in6); - sin6->sin6_addr = ip6->ip6_dst; - spidx->prefd = sizeof(struct in6_addr) << 3; - - return 0; -} -#endif - -static struct inpcbpolicy * -ipsec_newpcbpolicy() -{ - struct inpcbpolicy *p; - - p = (struct inpcbpolicy *)malloc(sizeof(*p), M_SECA, M_NOWAIT); - return p; -} - -static void -ipsec_delpcbpolicy(p) - struct inpcbpolicy *p; -{ - - free(p, M_SECA); -} - -/* initialize policy in PCB */ -int -ipsec_init_pcbpolicy(so, pcb_sp) - struct socket *so; - struct inpcbpolicy **pcb_sp; -{ - struct inpcbpolicy *new; - static int initialized = 0; - static struct secpolicy *in = NULL, *out = NULL; - - /* sanity check. */ - if (so == NULL || pcb_sp == NULL) - panic("ipsec_init_pcbpolicy: NULL pointer was passed."); - - if (!initialized) { - if ((in = key_newsp(0)) == NULL) - return ENOBUFS; - if ((out = key_newsp(0)) == NULL) { - key_freesp(in); - in = NULL; - return ENOBUFS; - } - - in->state = IPSEC_SPSTATE_ALIVE; - in->policy = IPSEC_POLICY_ENTRUST; - in->dir = IPSEC_DIR_INBOUND; - in->readonly = 1; - in->persist = 1; - in->so = NULL; - - out->state = IPSEC_SPSTATE_ALIVE; - out->policy = IPSEC_POLICY_ENTRUST; - out->dir = IPSEC_DIR_OUTBOUND; - out->readonly = 1; - out->persist = 1; - out->so = NULL; - - initialized++; - } - - new = ipsec_newpcbpolicy(); - if (new == NULL) { - ipseclog((LOG_DEBUG, "ipsec_init_pcbpolicy: No more memory.\n")); - return ENOBUFS; - } - bzero(new, sizeof(*new)); - - /* - * XXXRW: Can we avoid caching the privilege decision here, and - * instead cache the credential? - */ - if (so->so_cred != NULL && priv_check_cred(so->so_cred, - PRIV_NETINET_IPSEC, 0) == 0) - new->priv = 1; - else - new->priv = 0; - - new->sp_in = in; - new->sp_in->refcnt++; - new->sp_out = out; - new->sp_out->refcnt++; - - *pcb_sp = new; - - return 0; -} - -/* copy old ipsec policy into new */ -int -ipsec_copy_pcbpolicy(old, new) - struct inpcbpolicy *old, *new; -{ - - if (new->sp_in) - key_freesp(new->sp_in); - if (old->sp_in->policy == IPSEC_POLICY_IPSEC) - new->sp_in = ipsec_deepcopy_policy(old->sp_in); - else { - new->sp_in = old->sp_in; - new->sp_in->refcnt++; - } - - if (new->sp_out) - key_freesp(new->sp_out); - if (old->sp_out->policy == IPSEC_POLICY_IPSEC) - new->sp_out = ipsec_deepcopy_policy(old->sp_out); - else { - new->sp_out = old->sp_out; - new->sp_out->refcnt++; - } - - new->priv = old->priv; - - return 0; -} - -#if 0 -static int -ipsec_deepcopy_pcbpolicy(pcb_sp) - struct inpcbpolicy *pcb_sp; -{ - struct secpolicy *sp; - - sp = ipsec_deepcopy_policy(pcb_sp->sp_in); - if (sp) { - key_freesp(pcb_sp->sp_in); - pcb_sp->sp_in = sp; - } else - return ENOBUFS; - - sp = ipsec_deepcopy_policy(pcb_sp->sp_out); - if (sp) { - key_freesp(pcb_sp->sp_out); - pcb_sp->sp_out = sp; - } else - return ENOBUFS; - - return 0; -} -#endif - -/* deep-copy a policy in PCB */ -static struct secpolicy * -ipsec_deepcopy_policy(src) - struct secpolicy *src; -{ - struct ipsecrequest *newchain = NULL; - struct ipsecrequest *p; - struct ipsecrequest **q; - struct ipsecrequest *r; - struct secpolicy *dst; - - if (src == NULL) - return NULL; - - dst = key_newsp(0); - if (dst == NULL) - return NULL; - - /* - * deep-copy IPsec request chain. This is required since struct - * ipsecrequest is not reference counted. - */ - q = &newchain; - for (p = src->req; p; p = p->next) { - *q = (struct ipsecrequest *)malloc(sizeof(struct ipsecrequest), - M_SECA, M_NOWAIT); - if (*q == NULL) - goto fail; - bzero(*q, sizeof(**q)); - (*q)->next = NULL; - - (*q)->saidx.proto = p->saidx.proto; - (*q)->saidx.mode = p->saidx.mode; - (*q)->level = p->level; - (*q)->saidx.reqid = p->saidx.reqid; - - bcopy(&p->saidx.src, &(*q)->saidx.src, sizeof((*q)->saidx.src)); - bcopy(&p->saidx.dst, &(*q)->saidx.dst, sizeof((*q)->saidx.dst)); - - (*q)->sav = NULL; - (*q)->sp = dst; - - q = &((*q)->next); - } - - if (src->spidx) - if (keydb_setsecpolicyindex(dst, src->spidx) != 0) - goto fail; - - dst->req = newchain; - dst->state = src->state; - dst->policy = src->policy; - dst->dir = src->dir; - dst->so = src->so; - /* do not touch the refcnt fields */ - - return dst; - -fail: - for (p = newchain; p; p = r) { - r = p->next; - free(p, M_SECA); - p = NULL; - } - key_freesp(dst); - return NULL; -} - -/* set policy and ipsec request if present. */ -static int -ipsec_set_policy(spp, optname, request, len, priv) - struct secpolicy **spp; - int optname; - caddr_t request; - size_t len; - int priv; -{ - struct sadb_x_policy *xpl; - struct secpolicy *newsp = NULL; - int error; - - /* sanity check. */ - if (spp == NULL || *spp == NULL || request == NULL) - return EINVAL; - if (len < sizeof(*xpl)) - return EINVAL; - xpl = (struct sadb_x_policy *)request; - - KEYDEBUG(KEYDEBUG_IPSEC_DUMP, - printf("ipsec_set_policy: passed policy\n"); - kdebug_sadb_x_policy((struct sadb_ext *)xpl)); - - /* check policy type */ - /* ipsec_set_policy() accepts IPSEC, ENTRUST and BYPASS. */ - if (xpl->sadb_x_policy_type == IPSEC_POLICY_DISCARD || - xpl->sadb_x_policy_type == IPSEC_POLICY_NONE) - return EINVAL; - - /* check privileged socket */ - if (priv == 0 && xpl->sadb_x_policy_type == IPSEC_POLICY_BYPASS) - return EACCES; - - /* allocation new SP entry */ - if ((newsp = key_msg2sp(xpl, len, &error)) == NULL) - return error; - - newsp->state = IPSEC_SPSTATE_ALIVE; - - /* clear old SP and set new SP */ - key_freesp(*spp); - *spp = newsp; - KEYDEBUG(KEYDEBUG_IPSEC_DUMP, - printf("ipsec_set_policy: new policy\n"); - kdebug_secpolicy(newsp)); - - return 0; -} - -static int -ipsec_get_policy(sp, mp) - struct secpolicy *sp; - struct mbuf **mp; -{ - - /* sanity check. */ - if (sp == NULL || mp == NULL) - return EINVAL; - - *mp = key_sp2msg(sp); - if (!*mp) { - ipseclog((LOG_DEBUG, "ipsec_get_policy: No more memory.\n")); - return ENOBUFS; - } - - (*mp)->m_type = MT_DATA; - KEYDEBUG(KEYDEBUG_IPSEC_DUMP, - printf("ipsec_get_policy:\n"); - kdebug_mbuf(*mp)); - - return 0; -} - -int -ipsec4_set_policy(inp, optname, request, len, priv) - struct inpcb *inp; - int optname; - caddr_t request; - size_t len; - int priv; -{ - struct sadb_x_policy *xpl; - struct secpolicy **spp; - - /* sanity check. */ - if (inp == NULL || request == NULL) - return EINVAL; - if (len < sizeof(*xpl)) - return EINVAL; - xpl = (struct sadb_x_policy *)request; - - /* select direction */ - switch (xpl->sadb_x_policy_dir) { - case IPSEC_DIR_INBOUND: - spp = &inp->inp_sp->sp_in; - break; - case IPSEC_DIR_OUTBOUND: - spp = &inp->inp_sp->sp_out; - break; - default: - ipseclog((LOG_ERR, "ipsec4_set_policy: invalid direction=%u\n", - xpl->sadb_x_policy_dir)); - return EINVAL; - } - - ipsec_invalpcbcache(inp->inp_sp, IPSEC_DIR_ANY); - return ipsec_set_policy(spp, optname, request, len, priv); -} - -int -ipsec4_get_policy(inp, request, len, mp) - struct inpcb *inp; - caddr_t request; - size_t len; - struct mbuf **mp; -{ - struct sadb_x_policy *xpl; - struct secpolicy *sp; - - /* sanity check. */ - if (inp == NULL || request == NULL || mp == NULL) - return EINVAL; - if (inp->inp_sp == NULL) - panic("policy in PCB is NULL"); - if (len < sizeof(*xpl)) - return EINVAL; - xpl = (struct sadb_x_policy *)request; - - /* select direction */ - switch (xpl->sadb_x_policy_dir) { - case IPSEC_DIR_INBOUND: - sp = inp->inp_sp->sp_in; - break; - case IPSEC_DIR_OUTBOUND: - sp = inp->inp_sp->sp_out; - break; - default: - ipseclog((LOG_ERR, "ipsec4_get_policy: invalid direction=%u\n", - xpl->sadb_x_policy_dir)); - return EINVAL; - } - - return ipsec_get_policy(sp, mp); -} - -/* delete policy in PCB */ -int -ipsec4_delete_pcbpolicy(inp) - struct inpcb *inp; -{ - /* sanity check. */ - if (inp == NULL) - panic("ipsec4_delete_pcbpolicy: NULL pointer was passed."); - - if (inp->inp_sp == NULL) - return 0; - - if (inp->inp_sp->sp_in != NULL) { - key_freesp(inp->inp_sp->sp_in); - inp->inp_sp->sp_in = NULL; - } - - if (inp->inp_sp->sp_out != NULL) { - key_freesp(inp->inp_sp->sp_out); - inp->inp_sp->sp_out = NULL; - } - - ipsec_invalpcbcache(inp->inp_sp, IPSEC_DIR_ANY); - - ipsec_delpcbpolicy(inp->inp_sp); - inp->inp_sp = NULL; - - return 0; -} - -#ifdef INET6 -int -ipsec6_set_policy(in6p, optname, request, len, priv) - struct in6pcb *in6p; - int optname; - caddr_t request; - size_t len; - int priv; -{ - struct sadb_x_policy *xpl; - struct secpolicy **spp; - - /* sanity check. */ - if (in6p == NULL || request == NULL) - return EINVAL; - if (len < sizeof(*xpl)) - return EINVAL; - xpl = (struct sadb_x_policy *)request; - - /* select direction */ - switch (xpl->sadb_x_policy_dir) { - case IPSEC_DIR_INBOUND: - spp = &in6p->in6p_sp->sp_in; - break; - case IPSEC_DIR_OUTBOUND: - spp = &in6p->in6p_sp->sp_out; - break; - default: - ipseclog((LOG_ERR, "ipsec6_set_policy: invalid direction=%u\n", - xpl->sadb_x_policy_dir)); - return EINVAL; - } - - ipsec_invalpcbcache(in6p->in6p_sp, IPSEC_DIR_ANY); - return ipsec_set_policy(spp, optname, request, len, priv); -} - -int -ipsec6_get_policy(in6p, request, len, mp) - struct in6pcb *in6p; - caddr_t request; - size_t len; - struct mbuf **mp; -{ - struct sadb_x_policy *xpl; - struct secpolicy *sp; - - /* sanity check. */ - if (in6p == NULL || request == NULL || mp == NULL) - return EINVAL; - if (in6p->in6p_sp == NULL) - panic("policy in PCB is NULL"); - if (len < sizeof(*xpl)) - return EINVAL; - xpl = (struct sadb_x_policy *)request; - - /* select direction */ - switch (xpl->sadb_x_policy_dir) { - case IPSEC_DIR_INBOUND: - sp = in6p->in6p_sp->sp_in; - break; - case IPSEC_DIR_OUTBOUND: - sp = in6p->in6p_sp->sp_out; - break; - default: - ipseclog((LOG_ERR, "ipsec6_get_policy: invalid direction=%u\n", - xpl->sadb_x_policy_dir)); - return EINVAL; - } - - return ipsec_get_policy(sp, mp); -} - -int -ipsec6_delete_pcbpolicy(in6p) - struct in6pcb *in6p; -{ - /* sanity check. */ - if (in6p == NULL) - panic("ipsec6_delete_pcbpolicy: NULL pointer was passed."); - - if (in6p->in6p_sp == NULL) - return 0; - - if (in6p->in6p_sp->sp_in != NULL) { - key_freesp(in6p->in6p_sp->sp_in); - in6p->in6p_sp->sp_in = NULL; - } - - if (in6p->in6p_sp->sp_out != NULL) { - key_freesp(in6p->in6p_sp->sp_out); - in6p->in6p_sp->sp_out = NULL; - } - - ipsec_invalpcbcache(in6p->in6p_sp, IPSEC_DIR_ANY); - - ipsec_delpcbpolicy(in6p->in6p_sp); - in6p->in6p_sp = NULL; - - return 0; -} -#endif - -/* - * return current level. - * Either IPSEC_LEVEL_USE or IPSEC_LEVEL_REQUIRE are always returned. - */ -u_int -ipsec_get_reqlevel(isr, af) - struct ipsecrequest *isr; - int af; -{ - u_int level = 0; - u_int esp_trans_deflev, esp_net_deflev, ah_trans_deflev, ah_net_deflev; - - /* sanity check */ - if (isr == NULL || isr->sp == NULL) - panic("ipsec_get_reqlevel: NULL pointer is passed."); - - /* set default level */ - switch (af) { -#ifdef INET - case AF_INET: - esp_trans_deflev = ip4_esp_trans_deflev; - esp_net_deflev = ip4_esp_net_deflev; - ah_trans_deflev = ip4_ah_trans_deflev; - ah_net_deflev = ip4_ah_net_deflev; - break; -#endif -#ifdef INET6 - case AF_INET6: - esp_trans_deflev = ip6_esp_trans_deflev; - esp_net_deflev = ip6_esp_net_deflev; - ah_trans_deflev = ip6_ah_trans_deflev; - ah_net_deflev = ip6_ah_net_deflev; - break; -#endif /* INET6 */ - default: - panic("key_get_reqlevel: Unknown family. %d", - ((struct sockaddr *)&isr->sp->spidx->src)->sa_family); - } - - /* set level */ - switch (isr->level) { - case IPSEC_LEVEL_DEFAULT: - switch (isr->saidx.proto) { - case IPPROTO_ESP: - if (isr->saidx.mode == IPSEC_MODE_TUNNEL) - level = esp_net_deflev; - else - level = esp_trans_deflev; - break; - case IPPROTO_AH: - if (isr->saidx.mode == IPSEC_MODE_TUNNEL) - level = ah_net_deflev; - else - level = ah_trans_deflev; - break; - case IPPROTO_IPCOMP: - /* - * we don't really care, as IPcomp document says that - * we shouldn't compress small packets - */ - level = IPSEC_LEVEL_USE; - break; - default: - panic("ipsec_get_reqlevel: " - "Illegal protocol defined %u\n", - isr->saidx.proto); - } - break; - - case IPSEC_LEVEL_USE: - case IPSEC_LEVEL_REQUIRE: - level = isr->level; - break; - case IPSEC_LEVEL_UNIQUE: - level = IPSEC_LEVEL_REQUIRE; - break; - - default: - panic("ipsec_get_reqlevel: Illegal IPsec level %u", - isr->level); - } - - return level; -} - -/* - * Check AH/ESP integrity. - * OUT: - * 0: valid - * 1: invalid - */ -static int -ipsec_in_reject(sp, m) - struct secpolicy *sp; - struct mbuf *m; -{ - struct ipsecrequest *isr; - u_int level; - int need_auth, need_conf, need_icv; - - KEYDEBUG(KEYDEBUG_IPSEC_DATA, - printf("ipsec_in_reject: using SP\n"); - kdebug_secpolicy(sp)); - - /* check policy */ - switch (sp->policy) { - case IPSEC_POLICY_DISCARD: - return 1; - case IPSEC_POLICY_BYPASS: - case IPSEC_POLICY_NONE: - return 0; - - case IPSEC_POLICY_IPSEC: - break; - - case IPSEC_POLICY_ENTRUST: - default: - panic("ipsec_in_reject: Invalid policy found. %d", sp->policy); - } - - need_auth = 0; - need_conf = 0; - need_icv = 0; - - /* XXX should compare policy against ipsec header history */ - - for (isr = sp->req; isr != NULL; isr = isr->next) { - /* get current level */ - level = ipsec_get_reqlevel(isr, AF_INET); - - switch (isr->saidx.proto) { - case IPPROTO_ESP: - if (level == IPSEC_LEVEL_REQUIRE) { - need_conf++; - - if (isr->sav != NULL - && isr->sav->flags == SADB_X_EXT_NONE - && isr->sav->alg_auth != SADB_AALG_NONE) - need_icv++; - } - break; - case IPPROTO_AH: - if (level == IPSEC_LEVEL_REQUIRE) { - need_auth++; - need_icv++; - } - break; - case IPPROTO_IPCOMP: - /* - * we don't really care, as IPcomp document says that - * we shouldn't compress small packets, IPComp policy - * should always be treated as being in "use" level. - */ - break; - } - } - - KEYDEBUG(KEYDEBUG_IPSEC_DUMP, - printf("ipsec_in_reject: auth:%d conf:%d icv:%d m_flags:%x\n", - need_auth, need_conf, need_icv, m->m_flags)); - - if ((need_conf && !(m->m_flags & M_DECRYPTED)) - || (!need_auth && need_icv && !(m->m_flags & M_AUTHIPDGM)) - || (need_auth && !(m->m_flags & M_AUTHIPHDR))) - return 1; - - return 0; -} - -/* - * Check AH/ESP integrity. - * This function is called from tcp_input(), udp_input(), - * and {ah,esp}4_input for tunnel mode - */ -int -ipsec4_in_reject(m, inp) - struct mbuf *m; - struct inpcb *inp; -{ - struct secpolicy *sp = NULL; - int error; - int result; - - /* sanity check */ - if (m == NULL) - return 0; /* XXX should be panic ? */ - - /* get SP for this packet. - * When we are called from ip_forward(), we call - * ipsec4_getpolicybyaddr() with IP_FORWARDING flag. - */ - if (inp == NULL) - sp = ipsec4_getpolicybyaddr(m, IPSEC_DIR_INBOUND, - IP_FORWARDING, &error); - else - sp = ipsec4_getpolicybypcb(m, IPSEC_DIR_INBOUND, inp, &error); - - /* XXX should be panic ? -> No, there may be error. */ - if (sp == NULL) - return 0; - - result = ipsec_in_reject(sp, m); - KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP ipsec4_in_reject call free SP:%p\n", sp)); - key_freesp(sp); - - return result; -} - -#ifdef INET6 -/* - * Check AH/ESP integrity. - * This function is called from tcp6_input(), udp6_input(), - * and {ah,esp}6_input for tunnel mode - */ -int -ipsec6_in_reject(m, in6p) - struct mbuf *m; - struct in6pcb *in6p; -{ - struct secpolicy *sp = NULL; - int error; - int result; - - /* sanity check */ - if (m == NULL) - return 0; /* XXX should be panic ? */ - - /* get SP for this packet. - * When we are called from ip_forward(), we call - * ipsec6_getpolicybyaddr() with IP_FORWARDING flag. - */ - if (in6p == NULL) - sp = ipsec6_getpolicybyaddr(m, IPSEC_DIR_INBOUND, - IP_FORWARDING, &error); - else - sp = ipsec6_getpolicybypcb(m, IPSEC_DIR_INBOUND, in6p, &error); - - if (sp == NULL) - return 0; /* XXX should be panic ? */ - - result = ipsec_in_reject(sp, m); - KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP ipsec6_in_reject call free SP:%p\n", sp)); - key_freesp(sp); - - return result; -} -#endif - -/* - * compute the byte size to be occupied by IPsec header. - * in case it is tunneled, it includes the size of outer IP header. - * NOTE: SP passed is free in this function. - */ -static size_t -ipsec_hdrsiz(sp) - struct secpolicy *sp; -{ - struct ipsecrequest *isr; - size_t siz, clen; - - KEYDEBUG(KEYDEBUG_IPSEC_DATA, - printf("ipsec_hdrsiz: using SP\n"); - kdebug_secpolicy(sp)); - - /* check policy */ - switch (sp->policy) { - case IPSEC_POLICY_DISCARD: - case IPSEC_POLICY_BYPASS: - case IPSEC_POLICY_NONE: - return 0; - - case IPSEC_POLICY_IPSEC: - break; - - case IPSEC_POLICY_ENTRUST: - default: - panic("ipsec_hdrsiz: Invalid policy found. %d", sp->policy); - } - - siz = 0; - - for (isr = sp->req; isr != NULL; isr = isr->next) { - - clen = 0; - - switch (isr->saidx.proto) { - case IPPROTO_ESP: -#ifdef IPSEC_ESP - clen = esp_hdrsiz(isr); -#else - clen = 0; /* XXX */ -#endif - break; - case IPPROTO_AH: - clen = ah_hdrsiz(isr); - break; - case IPPROTO_IPCOMP: - clen = sizeof(struct ipcomp); - break; - } - - if (isr->saidx.mode == IPSEC_MODE_TUNNEL) { - switch (((struct sockaddr *)&isr->saidx.dst)->sa_family) { - case AF_INET: - clen += sizeof(struct ip); - break; -#ifdef INET6 - case AF_INET6: - clen += sizeof(struct ip6_hdr); - break; -#endif - default: - ipseclog((LOG_ERR, "ipsec_hdrsiz: " - "unknown AF %d in IPsec tunnel SA\n", - ((struct sockaddr *)&isr->saidx.dst)->sa_family)); - break; - } - } - siz += clen; - } - - return siz; -} - -/* This function is called from ip_forward() and ipsec4_hdrsize_tcp(). */ -size_t -ipsec4_hdrsiz(m, dir, inp) - struct mbuf *m; - u_int dir; - struct inpcb *inp; -{ - struct secpolicy *sp = NULL; - int error; - size_t size; - - /* sanity check */ - if (m == NULL) - return 0; /* XXX should be panic ? */ -#if 0 - /* this is possible in TIME_WAIT state */ - if (inp != NULL && inp->inp_socket == NULL) - panic("ipsec4_hdrsize: why is socket NULL but there is PCB."); -#endif - - /* get SP for this packet. - * When we are called from ip_forward(), we call - * ipsec4_getpolicybyaddr() with IP_FORWARDING flag. - */ - if (inp == NULL) - sp = ipsec4_getpolicybyaddr(m, dir, IP_FORWARDING, &error); - else - sp = ipsec4_getpolicybypcb(m, dir, inp, &error); - - if (sp == NULL) - return 0; /* XXX should be panic ? */ - - size = ipsec_hdrsiz(sp); - KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP ipsec4_hdrsiz call free SP:%p\n", sp)); - KEYDEBUG(KEYDEBUG_IPSEC_DATA, - printf("ipsec4_hdrsiz: size:%lu.\n", (unsigned long)size)); - key_freesp(sp); - - return size; -} - -#ifdef INET6 -/* This function is called from ipsec6_hdrsize_tcp(), - * and maybe from ip6_forward.() - */ -size_t -ipsec6_hdrsiz(m, dir, in6p) - struct mbuf *m; - u_int dir; - struct in6pcb *in6p; -{ - struct secpolicy *sp = NULL; - int error; - size_t size; - - /* sanity check */ - if (m == NULL) - return 0; /* XXX should be panic ? */ -#if 0 - /* this is possible in TIME_WAIT state */ - if (in6p != NULL && in6p->in6p_socket == NULL) - panic("ipsec6_hdrsize: why is socket NULL but there is PCB."); -#endif - - /* get SP for this packet */ - /* XXX Is it right to call with IP_FORWARDING. */ - if (in6p == NULL) - sp = ipsec6_getpolicybyaddr(m, dir, IP_FORWARDING, &error); - else - sp = ipsec6_getpolicybypcb(m, dir, in6p, &error); - - if (sp == NULL) - return 0; - size = ipsec_hdrsiz(sp); - KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP ipsec6_hdrsiz call free SP:%p\n", sp)); - KEYDEBUG(KEYDEBUG_IPSEC_DATA, - printf("ipsec6_hdrsiz: size:%lu.\n", (unsigned long)size)); - key_freesp(sp); - - return size; -} -#endif /* INET6 */ - -#ifdef INET -/* - * encapsulate for ipsec tunnel. - * ip->ip_src must be fixed later on. - */ -static int -ipsec4_encapsulate(m, sav) - struct mbuf *m; - struct secasvar *sav; -{ - struct ip *oip; - struct ip *ip; - size_t hlen; - size_t plen; - - /* can't tunnel between different AFs */ - if (((struct sockaddr *)&sav->sah->saidx.src)->sa_family - != ((struct sockaddr *)&sav->sah->saidx.dst)->sa_family - || ((struct sockaddr *)&sav->sah->saidx.src)->sa_family != AF_INET) { - m_freem(m); - return EINVAL; - } -#if 0 - /* XXX if the dst is myself, perform nothing. */ - if (key_ismyaddr((struct sockaddr *)&sav->sah->saidx.dst)) { - m_freem(m); - return EINVAL; - } -#endif - - if (m->m_len < sizeof(*ip)) - panic("ipsec4_encapsulate: assumption failed (first mbuf length)"); - - ip = mtod(m, struct ip *); -#ifdef _IP_VHL - hlen = _IP_VHL_HL(ip->ip_vhl) << 2; -#else - hlen = ip->ip_hl << 2; -#endif - - if (m->m_len != hlen) - panic("ipsec4_encapsulate: assumption failed (first mbuf length)"); - - /* generate header checksum */ - ip->ip_sum = 0; -#ifdef _IP_VHL - if (ip->ip_vhl == IP_VHL_BORING) - ip->ip_sum = in_cksum_hdr(ip); - else - ip->ip_sum = in_cksum(m, hlen); -#else - ip->ip_sum = in_cksum(m, hlen); -#endif - - plen = m->m_pkthdr.len; - - /* - * grow the mbuf to accomodate the new IPv4 header. - * NOTE: IPv4 options will never be copied. - */ - if (M_LEADINGSPACE(m->m_next) < hlen) { - struct mbuf *n; - MGET(n, M_DONTWAIT, MT_DATA); - if (!n) { - m_freem(m); - return ENOBUFS; - } - n->m_len = hlen; - n->m_next = m->m_next; - m->m_next = n; - m->m_pkthdr.len += hlen; - oip = mtod(n, struct ip *); - } else { - m->m_next->m_len += hlen; - m->m_next->m_data -= hlen; - m->m_pkthdr.len += hlen; - oip = mtod(m->m_next, struct ip *); - } - ip = mtod(m, struct ip *); - ovbcopy((caddr_t)ip, (caddr_t)oip, hlen); - m->m_len = sizeof(struct ip); - m->m_pkthdr.len -= (hlen - sizeof(struct ip)); - - /* construct new IPv4 header. see RFC 2401 5.1.2.1 */ - /* ECN consideration. */ - ip_ecn_ingress(ip4_ipsec_ecn, &ip->ip_tos, &oip->ip_tos); -#ifdef _IP_VHL - ip->ip_vhl = IP_MAKE_VHL(IPVERSION, sizeof(struct ip) >> 2); -#else - ip->ip_hl = sizeof(struct ip) >> 2; -#endif - ip->ip_off &= htons(~IP_OFFMASK); - ip->ip_off &= htons(~IP_MF); - switch (ip4_ipsec_dfbit) { - case 0: /* clear DF bit */ - ip->ip_off &= htons(~IP_DF); - break; - case 1: /* set DF bit */ - ip->ip_off |= htons(IP_DF); - break; - default: /* copy DF bit */ - break; - } - ip->ip_p = IPPROTO_IPIP; - if (plen + sizeof(struct ip) < IP_MAXPACKET) - ip->ip_len = htons(plen + sizeof(struct ip)); - else { - ipseclog((LOG_ERR, "IPv4 ipsec: size exceeds limit: " - "leave ip_len as is (invalid packet)\n")); - } - ip->ip_id = ip_newid(); - bcopy(&((struct sockaddr_in *)&sav->sah->saidx.src)->sin_addr, - &ip->ip_src, sizeof(ip->ip_src)); - bcopy(&((struct sockaddr_in *)&sav->sah->saidx.dst)->sin_addr, - &ip->ip_dst, sizeof(ip->ip_dst)); - ip->ip_ttl = IPDEFTTL; - - /* XXX Should ip_src be updated later ? */ - - return 0; -} -#endif /* INET */ - -#ifdef INET6 -static int -ipsec6_encapsulate(m, sav) - struct mbuf *m; - struct secasvar *sav; -{ - struct sockaddr_in6 sa6; - struct ip6_hdr *oip6; - struct ip6_hdr *ip6; - size_t plen; - int error; - - /* can't tunnel between different AFs */ - if (((struct sockaddr *)&sav->sah->saidx.src)->sa_family - != ((struct sockaddr *)&sav->sah->saidx.dst)->sa_family - || ((struct sockaddr *)&sav->sah->saidx.src)->sa_family != AF_INET6) { - m_freem(m); - return EINVAL; - } -#if 0 - /* XXX if the dst is myself, perform nothing. */ - if (key_ismyaddr((struct sockaddr *)&sav->sah->saidx.dst)) { - m_freem(m); - return EINVAL; - } -#endif - - plen = m->m_pkthdr.len; - - /* - * grow the mbuf to accomodate the new IPv6 header. - */ - if (m->m_len != sizeof(struct ip6_hdr)) - panic("ipsec6_encapsulate: assumption failed (first mbuf length)"); - if (M_LEADINGSPACE(m->m_next) < sizeof(struct ip6_hdr)) { - struct mbuf *n; - MGET(n, M_DONTWAIT, MT_DATA); - if (!n) { - m_freem(m); - return ENOBUFS; - } - n->m_len = sizeof(struct ip6_hdr); - n->m_next = m->m_next; - m->m_next = n; - m->m_pkthdr.len += sizeof(struct ip6_hdr); - oip6 = mtod(n, struct ip6_hdr *); - } else { - m->m_next->m_len += sizeof(struct ip6_hdr); - m->m_next->m_data -= sizeof(struct ip6_hdr); - m->m_pkthdr.len += sizeof(struct ip6_hdr); - oip6 = mtod(m->m_next, struct ip6_hdr *); - } - ip6 = mtod(m, struct ip6_hdr *); - ovbcopy((caddr_t)ip6, (caddr_t)oip6, sizeof(struct ip6_hdr)); - - /* XXX: Fake scoped addresses */ - in6_clearscope(&oip6->ip6_src); - in6_clearscope(&oip6->ip6_dst); - - /* construct new IPv6 header. see RFC 2401 5.1.2.2 */ - /* ECN consideration. */ - ip6_ecn_ingress(ip6_ipsec_ecn, &ip6->ip6_flow, &oip6->ip6_flow); - if (plen < IPV6_MAXPACKET - sizeof(struct ip6_hdr)) - ip6->ip6_plen = htons(plen); - else { - /* ip6->ip6_plen will be updated in ip6_output() */ - } - ip6->ip6_nxt = IPPROTO_IPV6; - - sa6 = *(struct sockaddr_in6 *)&sav->sah->saidx.src; - if ((error = sa6_embedscope(&sa6, 0)) != 0) - return (error); - ip6->ip6_src = sa6.sin6_addr; - - sa6 = *(struct sockaddr_in6 *)&sav->sah->saidx.dst; - if ((error = sa6_embedscope(&sa6, 0)) != 0) - return (error); - ip6->ip6_dst = sa6.sin6_addr; - - ip6->ip6_hlim = IPV6_DEFHLIM; - - /* XXX Should ip6_src be updated later ? */ - - return 0; -} -#endif /* INET6 */ - -/* - * Check the variable replay window. - * ipsec_chkreplay() performs replay check before ICV verification. - * ipsec_updatereplay() updates replay bitmap. This must be called after - * ICV verification (it also performs replay check, which is usually done - * beforehand). - * 0 (zero) is returned if packet disallowed, 1 if packet permitted. - * - * based on RFC 2401. - * - * XXX need to update for 64bit sequence number - 2401bis - */ -int -ipsec_chkreplay(seq, sav) - u_int32_t seq; - struct secasvar *sav; -{ - const struct secreplay *replay; - u_int32_t diff; - int fr; - u_int32_t wsizeb; /* constant: bits of window size */ - int frlast; /* constant: last frame */ - - /* sanity check */ - if (sav == NULL) - panic("ipsec_chkreplay: NULL pointer was passed."); - - replay = sav->replay; - - if (replay->wsize == 0) - return 1; /* no need to check replay. */ - - /* constant */ - frlast = replay->wsize - 1; - wsizeb = replay->wsize << 3; - - /* sequence number of 0 is invalid */ - if (seq == 0) - return 0; - - /* first time is always okay */ - if (replay->count == 0) - return 1; - - if (seq > replay->lastseq) { - /* larger sequences are okay */ - return 1; - } else { - /* seq is equal or less than lastseq. */ - diff = replay->lastseq - seq; - - /* over range to check, i.e. too old or wrapped */ - if (diff >= wsizeb) - return 0; - - fr = frlast - diff / 8; - - /* this packet already seen ? */ - if (replay->bitmap[fr] & (1 << (diff % 8))) - return 0; - - /* out of order but good */ - return 1; - } -} - -/* - * check replay counter whether to update or not. - * OUT: 0: OK - * 1: NG - * XXX need to update for 64bit sequence number - 2401bis - */ -int -ipsec_updatereplay(seq, sav) - u_int32_t seq; - struct secasvar *sav; -{ - struct secreplay *replay; - u_int64_t diff; - int fr; - u_int32_t wsizeb; /* constant: bits of window size */ - int frlast; /* constant: last frame */ - - /* sanity check */ - if (sav == NULL) - panic("ipsec_chkreplay: NULL pointer was passed."); - - replay = sav->replay; - - if (replay->wsize == 0) - goto ok; /* no need to check replay. */ - - /* constant */ - frlast = replay->wsize - 1; - wsizeb = replay->wsize << 3; - - /* sequence number of 0 is invalid */ - if (seq == 0) - return 1; - - /* first time */ - if (replay->count == 0) { - replay->lastseq = seq; - bzero(replay->bitmap, replay->wsize); - replay->bitmap[frlast] = 1; - goto ok; - } - - if (seq > replay->lastseq) { - /* seq is larger than lastseq. */ - diff = seq - replay->lastseq; - - /* new larger sequence number */ - if (diff < wsizeb) { - /* In window */ - /* set bit for this packet */ - vshiftl(replay->bitmap, diff, replay->wsize); - replay->bitmap[frlast] |= 1; - } else { - /* this packet has a "way larger" */ - bzero(replay->bitmap, replay->wsize); - replay->bitmap[frlast] = 1; - } - replay->lastseq = seq; - - /* larger is good */ - } else { - /* seq is equal or less than lastseq. */ - diff = replay->lastseq - seq; - - /* over range to check, i.e. too old or wrapped */ - if (diff >= wsizeb) - return 1; - - fr = frlast - diff / 8; - - /* this packet already seen ? */ - if (replay->bitmap[fr] & (1 << (diff % 8))) - return 1; - - /* mark as seen */ - replay->bitmap[fr] |= (1 << (diff % 8)); - - /* out of order but good */ - } - -ok: - if (replay->count == 0xffffffff) { - - /* set overflow flag */ - replay->overflow++; - - /* don't increment, no more packets accepted */ - if ((sav->flags & SADB_X_EXT_CYCSEQ) == 0) - return 1; - - ipseclog((LOG_WARNING, "replay counter made %d cycle. %s\n", - replay->overflow, ipsec_logsastr(sav))); - } - - replay->count++; - - return 0; -} - -/* - * shift variable length buffer to left. - * IN: bitmap: pointer to the buffer - * nbit: the number of to shift. - * wsize: buffer size (bytes). - */ -static void -vshiftl(bitmap, nbit, wsize) - unsigned char *bitmap; - int nbit, wsize; -{ - int s, j, i; - unsigned char over; - - for (j = 0; j < nbit; j += 8) { - s = (nbit - j < 8) ? (nbit - j): 8; - bitmap[0] <<= s; - for (i = 1; i < wsize; i++) { - over = (bitmap[i] >> (8 - s)); - bitmap[i] <<= s; - bitmap[i - 1] |= over; - } - } - - return; -} - -const char * -ipsec4_logpacketstr(ip, spi) - struct ip *ip; - u_int32_t spi; -{ - static char buf[256]; - char *p; - u_int8_t *s, *d; - - s = (u_int8_t *)(&ip->ip_src); - d = (u_int8_t *)(&ip->ip_dst); - - p = buf; - snprintf(buf, sizeof(buf), "packet(SPI=%u ", (u_int32_t)ntohl(spi)); - while (*p) - p++; - snprintf(p, sizeof(buf) - (p - buf), "src=%u.%u.%u.%u", - s[0], s[1], s[2], s[3]); - while (*p) - p++; - snprintf(p, sizeof(buf) - (p - buf), " dst=%u.%u.%u.%u", - d[0], d[1], d[2], d[3]); - while (*p) - p++; - snprintf(p, sizeof(buf) - (p - buf), ")"); - - return buf; -} - -#ifdef INET6 -const char * -ipsec6_logpacketstr(ip6, spi) - struct ip6_hdr *ip6; - u_int32_t spi; -{ - static char buf[256]; - char ip6buf[INET6_ADDRSTRLEN]; - char *p; - - p = buf; - snprintf(buf, sizeof(buf), "packet(SPI=%u ", (u_int32_t)ntohl(spi)); - while (*p) - p++; - snprintf(p, sizeof(buf) - (p - buf), "src=%s", - ip6_sprintf(ip6buf, &ip6->ip6_src)); - while (*p) - p++; - snprintf(p, sizeof(buf) - (p - buf), " dst=%s", - ip6_sprintf(ip6buf, &ip6->ip6_dst)); - while (*p) - p++; - snprintf(p, sizeof(buf) - (p - buf), ")"); - - return buf; -} -#endif /* INET6 */ - -const char * -ipsec_logsastr(sav) - struct secasvar *sav; -{ - static char buf[256]; - char *p; - struct secasindex *saidx = &sav->sah->saidx; - - /* validity check */ - if (((struct sockaddr *)&sav->sah->saidx.src)->sa_family - != ((struct sockaddr *)&sav->sah->saidx.dst)->sa_family) - panic("ipsec_logsastr: family mismatched."); - - p = buf; - snprintf(buf, sizeof(buf), "SA(SPI=%u ", (u_int32_t)ntohl(sav->spi)); - while (*p) - p++; - if (((struct sockaddr *)&saidx->src)->sa_family == AF_INET) { - u_int8_t *s, *d; - s = (u_int8_t *)&((struct sockaddr_in *)&saidx->src)->sin_addr; - d = (u_int8_t *)&((struct sockaddr_in *)&saidx->dst)->sin_addr; - snprintf(p, sizeof(buf) - (p - buf), - "src=%d.%d.%d.%d dst=%d.%d.%d.%d", - s[0], s[1], s[2], s[3], d[0], d[1], d[2], d[3]); - } -#ifdef INET6 - else if (((struct sockaddr *)&saidx->src)->sa_family == AF_INET6) { - char ip6buf[INET6_ADDRSTRLEN]; - snprintf(p, sizeof(buf) - (p - buf), - "src=%s", - ip6_sprintf(ip6buf, - &((struct sockaddr_in6 *)&saidx->src)->sin6_addr)); - while (*p) - p++; - snprintf(p, sizeof(buf) - (p - buf), - " dst=%s", - ip6_sprintf(ip6buf, - &((struct sockaddr_in6 *)&saidx->dst)->sin6_addr)); - } -#endif - while (*p) - p++; - snprintf(p, sizeof(buf) - (p - buf), ")"); - - return buf; -} - -void -ipsec_dumpmbuf(m) - struct mbuf *m; -{ - int totlen; - int i; - u_char *p; - - totlen = 0; - printf("---\n"); - while (m) { - p = mtod(m, u_char *); - for (i = 0; i < m->m_len; i++) { - printf("%02x ", p[i]); - totlen++; - if (totlen % 16 == 0) - printf("\n"); - } - m = m->m_next; - } - if (totlen % 16 != 0) - printf("\n"); - printf("---\n"); -} - -#ifdef INET -static int -ipsec4_checksa(isr, state) - struct ipsecrequest *isr; - struct ipsec_output_state *state; -{ - struct ip *ip; - struct secasindex saidx; - struct sockaddr_in *sin; - - /* make SA index for search proper SA */ - ip = mtod(state->m, struct ip *); - bcopy(&isr->saidx, &saidx, sizeof(saidx)); - saidx.mode = isr->saidx.mode; - saidx.reqid = isr->saidx.reqid; - sin = (struct sockaddr_in *)&saidx.src; - if (sin->sin_len == 0) { - sin->sin_len = sizeof(*sin); - sin->sin_family = AF_INET; - sin->sin_port = IPSEC_PORT_ANY; - bcopy(&ip->ip_src, &sin->sin_addr, sizeof(sin->sin_addr)); - } - sin = (struct sockaddr_in *)&saidx.dst; - if (sin->sin_len == 0) { - sin->sin_len = sizeof(*sin); - sin->sin_family = AF_INET; - sin->sin_port = IPSEC_PORT_ANY; - bcopy(&ip->ip_dst, &sin->sin_addr, sizeof(sin->sin_addr)); - } - - return key_checkrequest(isr, &saidx); -} -/* - * IPsec output logic for IPv4. - */ -int -ipsec4_output(state, sp, flags) - struct ipsec_output_state *state; - struct secpolicy *sp; - int flags; -{ - struct ip *ip = NULL; - struct ipsecrequest *isr = NULL; - int s; - int error; - struct sockaddr_in *dst4; - - if (!state) - panic("state == NULL in ipsec4_output"); - if (!state->m) - panic("state->m == NULL in ipsec4_output"); - if (!state->ro) - panic("state->ro == NULL in ipsec4_output"); - if (!state->dst) - panic("state->dst == NULL in ipsec4_output"); - state->encap = 0; - - KEYDEBUG(KEYDEBUG_IPSEC_DATA, - printf("ipsec4_output: applyed SP\n"); - kdebug_secpolicy(sp)); - - for (isr = sp->req; isr != NULL; isr = isr->next) { - -#if 0 /* give up to check restriction of transport mode */ - /* XXX but should be checked somewhere */ - /* - * some of the IPsec operation must be performed only in - * originating case. - */ - if (isr->saidx.mode == IPSEC_MODE_TRANSPORT - && (flags & IP_FORWARDING)) - continue; -#endif - error = ipsec4_checksa(isr, state); - if (error != 0) { - /* - * IPsec processing is required, but no SA found. - * I assume that key_acquire() had been called - * to get/establish the SA. Here I discard - * this packet because it is responsibility for - * upper layer to retransmit the packet. - */ - ipsecstat.out_nosa++; - goto bad; - } - - /* validity check */ - if (isr->sav == NULL) { - switch (ipsec_get_reqlevel(isr, AF_INET)) { - case IPSEC_LEVEL_USE: - continue; - case IPSEC_LEVEL_REQUIRE: - /* must be not reached here. */ - panic("ipsec4_output: no SA found, but required."); - } - } - - /* - * If there is no valid SA, we give up to process any - * more. In such a case, the SA's status is changed - * from DYING to DEAD after allocating. If a packet - * send to the receiver by dead SA, the receiver can - * not decode a packet because SA has been dead. - */ - if (isr->sav->state != SADB_SASTATE_MATURE - && isr->sav->state != SADB_SASTATE_DYING) { - ipsecstat.out_nosa++; - error = EINVAL; - goto bad; - } - - /* - * There may be the case that SA status will be changed when - * we are refering to one. So calling splsoftnet(). - */ - s = splnet(); - - if (isr->saidx.mode == IPSEC_MODE_TUNNEL) { - /* - * build IPsec tunnel. - */ - /* XXX should be processed with other familiy */ - if (((struct sockaddr *)&isr->sav->sah->saidx.src)->sa_family != AF_INET) { - ipseclog((LOG_ERR, "ipsec4_output: " - "family mismatched between inner and outer spi=%u\n", - (u_int32_t)ntohl(isr->sav->spi))); - splx(s); - error = EAFNOSUPPORT; - goto bad; - } - - state->m = ipsec4_splithdr(state->m); - if (!state->m) { - splx(s); - error = ENOMEM; - goto bad; - } - error = ipsec4_encapsulate(state->m, isr->sav); - splx(s); - if (error) { - state->m = NULL; - goto bad; - } - ip = mtod(state->m, struct ip *); - - state->ro = &isr->sav->sah->sa_route; - state->dst = (struct sockaddr *)&state->ro->ro_dst; - dst4 = (struct sockaddr_in *)state->dst; - if (state->ro->ro_rt - && ((state->ro->ro_rt->rt_flags & RTF_UP) == 0 - || dst4->sin_addr.s_addr != ip->ip_dst.s_addr)) { - RTFREE(state->ro->ro_rt); - state->ro->ro_rt = NULL; - } - if (state->ro->ro_rt == 0) { - dst4->sin_family = AF_INET; - dst4->sin_len = sizeof(*dst4); - dst4->sin_addr = ip->ip_dst; - rtalloc(state->ro); - } - if (state->ro->ro_rt == 0) { - ipstat.ips_noroute++; - error = EHOSTUNREACH; - goto bad; - } - - /* adjust state->dst if tunnel endpoint is offlink */ - if (state->ro->ro_rt->rt_flags & RTF_GATEWAY) { - state->dst = (struct sockaddr *)state->ro->ro_rt->rt_gateway; - dst4 = (struct sockaddr_in *)state->dst; - } - - state->encap++; - } else - splx(s); - - state->m = ipsec4_splithdr(state->m); - if (!state->m) { - error = ENOMEM; - goto bad; - } - switch (isr->saidx.proto) { - case IPPROTO_ESP: -#ifdef IPSEC_ESP - if ((error = esp4_output(state->m, isr)) != 0) { - state->m = NULL; - goto bad; - } - break; -#else - m_freem(state->m); - state->m = NULL; - error = EINVAL; - goto bad; -#endif - case IPPROTO_AH: - if ((error = ah4_output(state->m, isr)) != 0) { - state->m = NULL; - goto bad; - } - break; - case IPPROTO_IPCOMP: - if ((error = ipcomp4_output(state->m, isr)) != 0) { - state->m = NULL; - goto bad; - } - break; - default: - ipseclog((LOG_ERR, - "ipsec4_output: unknown ipsec protocol %d\n", - isr->saidx.proto)); - m_freem(state->m); - state->m = NULL; - error = EINVAL; - goto bad; - } - - if (state->m == 0) { - error = ENOMEM; - goto bad; - } - ip = mtod(state->m, struct ip *); - } - - return 0; - -bad: - m_freem(state->m); - state->m = NULL; - return error; -} -#endif - -#ifdef INET6 -static int -ipsec6_checksa(isr, state, tunnel) - struct ipsecrequest *isr; - struct ipsec_output_state *state; - int tunnel; -{ - struct ip6_hdr *ip6; - struct secasindex saidx; - struct sockaddr_in6 *sin6; - - if (isr->saidx.mode == IPSEC_MODE_TUNNEL) { -#ifdef DIAGNOSTIC - if (!tunnel) - panic("ipsec6_checksa/inconsistent tunnel attribute"); -#endif - /* When tunnel mode, SA peers must be specified. */ - return key_checkrequest(isr, &isr->saidx); - } - - /* make SA index for search proper SA */ - ip6 = mtod(state->m, struct ip6_hdr *); - if (tunnel) { - bzero(&saidx, sizeof(saidx)); - saidx.proto = isr->saidx.proto; - } else - bcopy(&isr->saidx, &saidx, sizeof(saidx)); - saidx.mode = isr->saidx.mode; - saidx.reqid = isr->saidx.reqid; - sin6 = (struct sockaddr_in6 *)&saidx.src; - if (sin6->sin6_len == 0 || tunnel) { - sin6->sin6_len = sizeof(*sin6); - sin6->sin6_family = AF_INET6; - sin6->sin6_port = IPSEC_PORT_ANY; - sin6->sin6_addr = ip6->ip6_src; - } - sin6 = (struct sockaddr_in6 *)&saidx.dst; - if (sin6->sin6_len == 0 || tunnel) { - sin6->sin6_len = sizeof(*sin6); - sin6->sin6_family = AF_INET6; - sin6->sin6_port = IPSEC_PORT_ANY; - sin6->sin6_addr = ip6->ip6_dst; - } - - return key_checkrequest(isr, &saidx); -} - -/* - * IPsec output logic for IPv6, transport mode. - */ -int -ipsec6_output_trans(state, nexthdrp, mprev, sp, flags, tun) - struct ipsec_output_state *state; - u_char *nexthdrp; - struct mbuf *mprev; - struct secpolicy *sp; - int flags; - int *tun; -{ - struct ip6_hdr *ip6; - struct ipsecrequest *isr = NULL; - int error = 0; - int plen; - - if (!state) - panic("state == NULL in ipsec6_output_trans"); - if (!state->m) - panic("state->m == NULL in ipsec6_output_trans"); - if (!nexthdrp) - panic("nexthdrp == NULL in ipsec6_output_trans"); - if (!mprev) - panic("mprev == NULL in ipsec6_output_trans"); - if (!sp) - panic("sp == NULL in ipsec6_output_trans"); - if (!tun) - panic("tun == NULL in ipsec6_output_trans"); - - KEYDEBUG(KEYDEBUG_IPSEC_DATA, - printf("ipsec6_output_trans: applyed SP\n"); - kdebug_secpolicy(sp)); - - *tun = 0; - for (isr = sp->req; isr; isr = isr->next) { - if (isr->saidx.mode == IPSEC_MODE_TUNNEL) { - /* the rest will be handled by ipsec6_output_tunnel() */ - break; - } - - error = ipsec6_checksa(isr, state, 0); - if (error == EIO) - goto bad; - if (error == ENOENT) { - /* - * IPsec processing is required, but no SA found. - * I assume that key_acquire() had been called - * to get/establish the SA. Here I discard - * this packet because it is responsibility for - * upper layer to retransmit the packet. - */ - ipsec6stat.out_nosa++; - - /* - * Notify the fact that the packet is discarded - * to ourselves. I believe this is better than - * just silently discarding. (jinmei@kame.net) - * XXX: should we restrict the error to TCP packets? - * XXX: should we directly notify sockets via - * pfctlinputs? - * - * Noone have initialized rcvif until this point, - * so clear it. - */ - if ((state->m->m_flags & M_PKTHDR) != 0) - state->m->m_pkthdr.rcvif = NULL; - icmp6_error(state->m, ICMP6_DST_UNREACH, - ICMP6_DST_UNREACH_ADMIN, 0); - state->m = NULL; /* icmp6_error freed the mbuf */ - goto bad; - } - - /* validity check */ - if (isr->sav == NULL) { - switch (ipsec_get_reqlevel(isr, AF_INET6)) { - case IPSEC_LEVEL_USE: - continue; - case IPSEC_LEVEL_REQUIRE: - /* must be not reached here. */ - panic("ipsec6_output_trans: no SA found, but required."); - } - } - - /* - * If there is no valid SA, we give up to process. - * see same place at ipsec4_output(). - */ - if (isr->sav->state != SADB_SASTATE_MATURE - && isr->sav->state != SADB_SASTATE_DYING) { - ipsec6stat.out_nosa++; - error = EINVAL; - goto bad; - } - - switch (isr->saidx.proto) { - case IPPROTO_ESP: -#ifdef IPSEC_ESP - error = esp6_output(state->m, nexthdrp, mprev->m_next, isr); -#else - m_freem(state->m); - error = EINVAL; -#endif - break; - case IPPROTO_AH: - error = ah6_output(state->m, nexthdrp, mprev->m_next, isr); - break; - case IPPROTO_IPCOMP: - error = ipcomp6_output(state->m, nexthdrp, mprev->m_next, isr); - break; - default: - ipseclog((LOG_ERR, "ipsec6_output_trans: " - "unknown ipsec protocol %d\n", isr->saidx.proto)); - m_freem(state->m); - ipsec6stat.out_inval++; - error = EINVAL; - break; - } - if (error) { - state->m = NULL; - goto bad; - } - plen = state->m->m_pkthdr.len - sizeof(struct ip6_hdr); - if (plen > IPV6_MAXPACKET) { - ipseclog((LOG_ERR, "ipsec6_output_trans: " - "IPsec with IPv6 jumbogram is not supported\n")); - ipsec6stat.out_inval++; - error = EINVAL; /* XXX */ - goto bad; - } - ip6 = mtod(state->m, struct ip6_hdr *); - ip6->ip6_plen = htons(plen); - } - - /* if we have more to go, we need a tunnel mode processing */ - if (isr != NULL) - *tun = 1; - - return 0; - -bad: - m_freem(state->m); - state->m = NULL; - return error; -} - -/* - * IPsec output logic for IPv6, tunnel mode. - */ -int -ipsec6_output_tunnel(state, sp, flags) - struct ipsec_output_state *state; - struct secpolicy *sp; - int flags; -{ - struct ip6_hdr *ip6; - struct ipsecrequest *isr = NULL; - int error = 0; - int plen; - struct sockaddr_in6 *dst6; - int s; - - if (!state) - panic("state == NULL in ipsec6_output_tunnel"); - if (!state->m) - panic("state->m == NULL in ipsec6_output_tunnel"); - if (!sp) - panic("sp == NULL in ipsec6_output_tunnel"); - - KEYDEBUG(KEYDEBUG_IPSEC_DATA, - printf("ipsec6_output_tunnel: applyed SP\n"); - kdebug_secpolicy(sp)); - - /* - * transport mode ipsec (before the 1st tunnel mode) is already - * processed by ipsec6_output_trans(). - */ - for (isr = sp->req; isr; isr = isr->next) { - if (isr->saidx.mode == IPSEC_MODE_TUNNEL) - break; - } - - for (/* already initialized */; isr; isr = isr->next) { - error = ipsec6_checksa(isr, state, 1); - if (error == EIO) - goto bad; - if (error == ENOENT) { - /* - * IPsec processing is required, but no SA found. - * I assume that key_acquire() had been called - * to get/establish the SA. Here I discard - * this packet because it is responsibility for - * upper layer to retransmit the packet. - */ - ipsec6stat.out_nosa++; - error = ENOENT; - goto bad; - } - - /* validity check */ - if (isr->sav == NULL) { - switch (ipsec_get_reqlevel(isr, AF_INET6)) { - case IPSEC_LEVEL_USE: - continue; - case IPSEC_LEVEL_REQUIRE: - /* must be not reached here. */ - panic("ipsec6_output_tunnel: no SA found, but required."); - } - } - - /* - * If there is no valid SA, we give up to process. - * see same place at ipsec4_output(). - */ - if (isr->sav->state != SADB_SASTATE_MATURE - && isr->sav->state != SADB_SASTATE_DYING) { - ipsec6stat.out_nosa++; - error = EINVAL; - goto bad; - } - - /* - * There may be the case that SA status will be changed when - * we are refering to one. So calling splsoftnet(). - */ - s = splnet(); - - if (isr->saidx.mode == IPSEC_MODE_TUNNEL) { - /* - * build IPsec tunnel. - */ - /* XXX should be processed with other familiy */ - if (((struct sockaddr *)&isr->sav->sah->saidx.src)->sa_family != AF_INET6) { - ipseclog((LOG_ERR, "ipsec6_output_tunnel: " - "family mismatched between inner and outer, spi=%u\n", - (u_int32_t)ntohl(isr->sav->spi))); - splx(s); - ipsec6stat.out_inval++; - error = EAFNOSUPPORT; - goto bad; - } - - state->m = ipsec6_splithdr(state->m); - if (!state->m) { - splx(s); - ipsec6stat.out_nomem++; - error = ENOMEM; - goto bad; - } - error = ipsec6_encapsulate(state->m, isr->sav); - splx(s); - if (error) { - state->m = 0; - goto bad; - } - ip6 = mtod(state->m, struct ip6_hdr *); - - state->ro = &isr->sav->sah->sa_route; - state->dst = (struct sockaddr *)&state->ro->ro_dst; - dst6 = (struct sockaddr_in6 *)state->dst; - if (state->ro->ro_rt && - (!(state->ro->ro_rt->rt_flags & RTF_UP) || - !IN6_ARE_ADDR_EQUAL(&dst6->sin6_addr, - &ip6->ip6_dst))) { - RTFREE(state->ro->ro_rt); - state->ro->ro_rt = NULL; - } - if (state->ro->ro_rt == 0) { - bzero(dst6, sizeof(*dst6)); - dst6->sin6_family = AF_INET6; - dst6->sin6_len = sizeof(*dst6); - dst6->sin6_addr = ip6->ip6_dst; - rtalloc(state->ro); - } - if (state->ro->ro_rt == 0) { - ip6stat.ip6s_noroute++; - ipsec6stat.out_noroute++; - error = EHOSTUNREACH; - goto bad; - } - - /* adjust state->dst if tunnel endpoint is offlink */ - if (state->ro->ro_rt->rt_flags & RTF_GATEWAY) { - state->dst = (struct sockaddr *)state->ro->ro_rt->rt_gateway; - dst6 = (struct sockaddr_in6 *)state->dst; - } - } else - splx(s); - - state->m = ipsec6_splithdr(state->m); - if (!state->m) { - ipsec6stat.out_nomem++; - error = ENOMEM; - goto bad; - } - ip6 = mtod(state->m, struct ip6_hdr *); - switch (isr->saidx.proto) { - case IPPROTO_ESP: -#ifdef IPSEC_ESP - error = esp6_output(state->m, &ip6->ip6_nxt, - state->m->m_next, isr); -#else - m_freem(state->m); - error = EINVAL; -#endif - break; - case IPPROTO_AH: - error = ah6_output(state->m, &ip6->ip6_nxt, - state->m->m_next, isr); - break; - case IPPROTO_IPCOMP: - /* XXX code should be here */ - /* FALLTHROUGH */ - default: - ipseclog((LOG_ERR, "ipsec6_output_tunnel: " - "unknown ipsec protocol %d\n", isr->saidx.proto)); - m_freem(state->m); - ipsec6stat.out_inval++; - error = EINVAL; - break; - } - if (error) { - state->m = NULL; - goto bad; - } - plen = state->m->m_pkthdr.len - sizeof(struct ip6_hdr); - if (plen > IPV6_MAXPACKET) { - ipseclog((LOG_ERR, "ipsec6_output_tunnel: " - "IPsec with IPv6 jumbogram is not supported\n")); - ipsec6stat.out_inval++; - error = EINVAL; /* XXX */ - goto bad; - } - ip6 = mtod(state->m, struct ip6_hdr *); - ip6->ip6_plen = htons(plen); - } - - return 0; - -bad: - m_freem(state->m); - state->m = NULL; - return error; -} -#endif /* INET6 */ - -#ifdef INET -/* - * Chop IP header and option off from the payload. - */ -static struct mbuf * -ipsec4_splithdr(m) - struct mbuf *m; -{ - struct mbuf *mh; - struct ip *ip; - int hlen; - - if (m->m_len < sizeof(struct ip)) - panic("ipsec4_splithdr: first mbuf too short"); - ip = mtod(m, struct ip *); -#ifdef _IP_VHL - hlen = _IP_VHL_HL(ip->ip_vhl) << 2; -#else - hlen = ip->ip_hl << 2; -#endif - if (m->m_len > hlen) { - MGETHDR(mh, M_DONTWAIT, MT_HEADER); - if (!mh) { - m_freem(m); - return NULL; - } - M_MOVE_PKTHDR(mh, m); - MH_ALIGN(mh, hlen); - m->m_len -= hlen; - m->m_data += hlen; - mh->m_next = m; - m = mh; - m->m_len = hlen; - bcopy((caddr_t)ip, mtod(m, caddr_t), hlen); - } else if (m->m_len < hlen) { - m = m_pullup(m, hlen); - if (!m) - return NULL; - } - return m; -} -#endif - -#ifdef INET6 -static struct mbuf * -ipsec6_splithdr(m) - struct mbuf *m; -{ - struct mbuf *mh; - struct ip6_hdr *ip6; - int hlen; - - if (m->m_len < sizeof(struct ip6_hdr)) - panic("ipsec6_splithdr: first mbuf too short"); - ip6 = mtod(m, struct ip6_hdr *); - hlen = sizeof(struct ip6_hdr); - if (m->m_len > hlen) { - MGETHDR(mh, M_DONTWAIT, MT_HEADER); - if (!mh) { - m_freem(m); - return NULL; - } - M_MOVE_PKTHDR(mh, m); - MH_ALIGN(mh, hlen); - m->m_len -= hlen; - m->m_data += hlen; - mh->m_next = m; - m = mh; - m->m_len = hlen; - bcopy((caddr_t)ip6, mtod(m, caddr_t), hlen); - } else if (m->m_len < hlen) { - m = m_pullup(m, hlen); - if (!m) - return NULL; - } - return m; -} -#endif - -/* validate inbound IPsec tunnel packet. */ -int -ipsec4_tunnel_validate(m, off, nxt0, sav) - struct mbuf *m; /* no pullup permitted, m->m_len >= ip */ - int off; - u_int nxt0; - struct secasvar *sav; -{ - u_int8_t nxt = nxt0 & 0xff; - struct sockaddr_in *sin; - struct sockaddr_in osrc, odst, isrc, idst; - int hlen; - struct secpolicy *sp; - struct ip *oip; - -#ifdef DIAGNOSTIC - if (m->m_len < sizeof(struct ip)) - panic("too short mbuf on ipsec4_tunnel_validate"); -#endif - if (nxt != IPPROTO_IPV4) - return 0; - if (m->m_pkthdr.len < off + sizeof(struct ip)) - return 0; - /* do not decapsulate if the SA is for transport mode only */ - if (sav->sah->saidx.mode == IPSEC_MODE_TRANSPORT) - return 0; - - oip = mtod(m, struct ip *); - hlen = oip->ip_hl << 2; - if (hlen != sizeof(struct ip)) - return 0; - - /* AF_INET6 should be supported, but at this moment we don't. */ - sin = (struct sockaddr_in *)&sav->sah->saidx.dst; - if (sin->sin_family != AF_INET) - return 0; - if (bcmp(&oip->ip_dst, &sin->sin_addr, sizeof(oip->ip_dst)) != 0) - return 0; - - /* XXX slow */ - bzero(&osrc, sizeof(osrc)); - bzero(&odst, sizeof(odst)); - bzero(&isrc, sizeof(isrc)); - bzero(&idst, sizeof(idst)); - osrc.sin_family = odst.sin_family = isrc.sin_family = idst.sin_family = - AF_INET; - osrc.sin_len = odst.sin_len = isrc.sin_len = idst.sin_len = - sizeof(struct sockaddr_in); - osrc.sin_addr = oip->ip_src; - odst.sin_addr = oip->ip_dst; - m_copydata(m, off + offsetof(struct ip, ip_src), sizeof(isrc.sin_addr), - (caddr_t)&isrc.sin_addr); - m_copydata(m, off + offsetof(struct ip, ip_dst), sizeof(idst.sin_addr), - (caddr_t)&idst.sin_addr); - - /* - * RFC2401 5.2.1 (b): (assume that we are using tunnel mode) - * - if the inner destination is multicast address, there can be - * multiple permissible inner source address. implementation - * may want to skip verification of inner source address against - * SPD selector. - * - if the inner protocol is ICMP, the packet may be an error report - * from routers on the other side of the VPN cloud (R in the - * following diagram). in this case, we cannot verify inner source - * address against SPD selector. - * me -- gw === gw -- R -- you - * - * we consider the first bullet to be users responsibility on SPD entry - * configuration (if you need to encrypt multicast traffic, set - * the source range of SPD selector to 0.0.0.0/0, or have explicit - * address ranges for possible senders). - * the second bullet is not taken care of (yet). - * - * therefore, we do not do anything special about inner source. - */ - - sp = key_gettunnel((struct sockaddr *)&osrc, (struct sockaddr *)&odst, - (struct sockaddr *)&isrc, (struct sockaddr *)&idst); - /* - * when there is no suitable inbound policy for the packet of the ipsec - * tunnel mode, the kernel never decapsulate the tunneled packet - * as the ipsec tunnel mode even when the system wide policy is "none". - * then the kernel leaves the generic tunnel module to process this - * packet. if there is no rule of the generic tunnel, the packet - * is rejected and the statistics will be counted up. - */ - if (!sp) - return 0; - key_freesp(sp); - - return 1; -} - -#ifdef INET6 -/* validate inbound IPsec tunnel packet. */ -int -ipsec6_tunnel_validate(m, off, nxt0, sav) - struct mbuf *m; /* no pullup permitted, m->m_len >= ip */ - int off; - u_int nxt0; - struct secasvar *sav; -{ - u_int8_t nxt = nxt0 & 0xff; - struct sockaddr_in6 *sin6; - struct sockaddr_in6 osrc, odst, isrc, idst; - struct secpolicy *sp; - struct ip6_hdr *oip6; - -#ifdef DIAGNOSTIC - if (m->m_len < sizeof(struct ip6_hdr)) - panic("too short mbuf on ipsec6_tunnel_validate"); -#endif - if (nxt != IPPROTO_IPV6) - return 0; - if (m->m_pkthdr.len < off + sizeof(struct ip6_hdr)) - return 0; - /* do not decapsulate if the SA is for transport mode only */ - if (sav->sah->saidx.mode == IPSEC_MODE_TRANSPORT) - return 0; - - oip6 = mtod(m, struct ip6_hdr *); - - /* AF_INET should be supported, but at this moment we don't. */ - sin6 = (struct sockaddr_in6 *)&sav->sah->saidx.dst; - if (sin6->sin6_family != AF_INET6) - return 0; - if (!IN6_ARE_ADDR_EQUAL(&oip6->ip6_dst, &sin6->sin6_addr)) - return 0; - - /* XXX slow */ - bzero(&osrc, sizeof(osrc)); - bzero(&odst, sizeof(odst)); - bzero(&isrc, sizeof(isrc)); - bzero(&idst, sizeof(idst)); - osrc.sin6_family = odst.sin6_family = isrc.sin6_family = - idst.sin6_family = AF_INET6; - osrc.sin6_len = odst.sin6_len = isrc.sin6_len = idst.sin6_len = - sizeof(struct sockaddr_in6); - osrc.sin6_addr = oip6->ip6_src; - odst.sin6_addr = oip6->ip6_dst; - m_copydata(m, off + offsetof(struct ip6_hdr, ip6_src), - sizeof(isrc.sin6_addr), (caddr_t)&isrc.sin6_addr); - m_copydata(m, off + offsetof(struct ip6_hdr, ip6_dst), - sizeof(idst.sin6_addr), (caddr_t)&idst.sin6_addr); - - /* - * regarding to inner source address validation, see a long comment - * in ipsec4_tunnel_validate. - */ - - sp = key_gettunnel((struct sockaddr *)&osrc, (struct sockaddr *)&odst, - (struct sockaddr *)&isrc, (struct sockaddr *)&idst); - if (!sp) - return 0; - key_freesp(sp); - - return 1; -} -#endif - -/* - * Make a mbuf chain for encryption. - * If the original mbuf chain contains a mbuf with a cluster, - * allocate a new cluster and copy the data to the new cluster. - * XXX: this hack is inefficient, but is necessary to handle cases - * of TCP retransmission... - */ -struct mbuf * -ipsec_copypkt(m) - struct mbuf *m; -{ - struct mbuf *n, **mpp, *mnew; - - for (n = m, mpp = &m; n; n = n->m_next) { - if (n->m_flags & M_EXT) { - /* - * Make a copy only if there is more than one - * references to the cluster. - * XXX: is this approach effective? - */ - if (!M_WRITABLE(n)) { - int remain, copied; - struct mbuf *mm; - - if (n->m_flags & M_PKTHDR) { - MGETHDR(mnew, M_DONTWAIT, MT_HEADER); - if (mnew == NULL) - goto fail; - M_MOVE_PKTHDR(mnew, n); - } - else { - MGET(mnew, M_DONTWAIT, MT_DATA); - if (mnew == NULL) - goto fail; - } - mnew->m_len = 0; - mm = mnew; - - /* - * Copy data. If we don't have enough space to - * store the whole data, allocate a cluster - * or additional mbufs. - * XXX: we don't use m_copyback(), since the - * function does not use clusters and thus is - * inefficient. - */ - remain = n->m_len; - copied = 0; - while (1) { - int len; - struct mbuf *mn; - - if (remain <= (mm->m_flags & M_PKTHDR ? MHLEN : MLEN)) - len = remain; - else { /* allocate a cluster */ - MCLGET(mm, M_DONTWAIT); - if (!(mm->m_flags & M_EXT)) { - m_free(mm); - goto fail; - } - len = remain < MCLBYTES ? - remain : MCLBYTES; - } - - bcopy(n->m_data + copied, mm->m_data, - len); - - copied += len; - remain -= len; - mm->m_len = len; - - if (remain <= 0) /* completed? */ - break; - - /* need another mbuf */ - MGETHDR(mn, M_DONTWAIT, MT_HEADER); - if (mn == NULL) - goto fail; - mn->m_pkthdr.rcvif = NULL; - mm->m_next = mn; - mm = mn; - } - - /* adjust chain */ - mm->m_next = m_free(n); - n = mm; - *mpp = mnew; - mpp = &n->m_next; - - continue; - } - } - *mpp = n; - mpp = &n->m_next; - } - - return (m); - fail: - m_freem(m); - return (NULL); -} - -static struct ipsecaux * -ipsec_addaux(m) - struct mbuf *m; -{ - struct m_tag *mtag; - - mtag = m_tag_find(m, PACKET_TAG_IPSEC_HISTORY, NULL); - if (mtag == NULL) { - mtag = m_tag_get(PACKET_TAG_IPSEC_HISTORY, - sizeof(struct ipsecaux), M_NOWAIT); - if (mtag != NULL) - m_tag_prepend(m, mtag); - } - if (mtag == NULL) - return NULL; /* ENOBUFS */ - /* XXX is this necessary? */ - bzero((void *)(mtag + 1), sizeof(struct ipsecaux)); - return mtag ? (struct ipsecaux *)(mtag + 1) : NULL; -} - -static struct ipsecaux * -ipsec_findaux(m) - struct mbuf *m; -{ - struct m_tag *mtag; - - mtag = m_tag_find(m, PACKET_TAG_IPSEC_HISTORY, NULL); - return mtag ? (struct ipsecaux *)(mtag + 1) : NULL; -} - -void -ipsec_delaux(m) - struct mbuf *m; -{ - struct m_tag *mtag; - - mtag = m_tag_find(m, PACKET_TAG_IPSEC_HISTORY, NULL); - if (mtag != NULL) - m_tag_delete(m, mtag); -} - -/* if the aux buffer is unnecessary, nuke it. */ -static void -ipsec_optaux(m, aux) - struct mbuf *m; - struct ipsecaux *aux; -{ - - if (aux == NULL) - return; - ipsec_delaux(m); -} - -int -ipsec_addhist(m, proto, spi) - struct mbuf *m; - int proto; - u_int32_t spi; -{ - struct ipsecaux *aux; - - aux = ipsec_addaux(m); - if (aux == NULL) - return ENOBUFS; - aux->hdrs++; - return 0; -} - -int -ipsec_getnhist(m) - struct mbuf *m; -{ - struct ipsecaux *aux; - - aux = ipsec_findaux(m); - if (aux == NULL) - return 0; - return aux->hdrs; -} - -void -ipsec_clearhist(m) - struct mbuf *m; -{ - struct ipsecaux *aux; - - aux = ipsec_findaux(m); - ipsec_optaux(m, aux); -} |