X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/1c79356b52d46aa6b508fb032f5ae709b1f2897b..d190cdc3f5544636abb56dc1874be391d3e1b148:/bsd/netinet6/ah_core.c diff --git a/bsd/netinet6/ah_core.c b/bsd/netinet6/ah_core.c index af0762142..b072b692e 100644 --- a/bsd/netinet6/ah_core.c +++ b/bsd/netinet6/ah_core.c @@ -1,3 +1,34 @@ +/* + * Copyright (c) 2008-2016 Apple Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ + */ + +/* $FreeBSD: src/sys/netinet6/ah_core.c,v 1.2.2.4 2001/07/03 11:01:49 ume Exp $ */ +/* $KAME: ah_core.c,v 1.44 2001/03/12 11:24:39 itojun Exp $ */ + /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. @@ -30,22 +61,8 @@ /* * RFC1826/2402 authentication header. */ -#define _IP_VHL -#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__) -#include "opt_inet.h" -#if __NetBSD__ /*XXX*/ -#include "opt_ipsec.h" -#endif -#endif -/* Some of operating systems have standard crypto checksum library */ -#if __NetBSD__ -#define HAVE_MD5 -#define HAVE_SHA1 -#endif -#if defined(__FreeBSD__) || defined(__APPLE__) -#define HAVE_MD5 1 -#endif +/* TODO: have shared routines for hmac-* algorithms */ #include #include @@ -57,7 +74,6 @@ #include #include #include -#include #include #include @@ -75,82 +91,143 @@ #endif #include +#if INET6 +#include +#endif #include +#if INET6 +#include +#endif #if IPSEC_ESP #include +#if INET6 +#include +#endif #endif #include #include -#if HAVE_MD5 -#include -#else -#include -#endif -#if HAVE_SHA1 -#include -#define SHA1_RESULTLEN 20 -#else -#include -#endif +#include +#include +#include #include #define HMACSIZE 16 -static int ah_sumsiz_1216 __P((struct secasvar *)); -static int ah_sumsiz_zero __P((struct secasvar *)); -static int ah_none_mature __P((struct secasvar *)); -static void ah_none_init __P((struct ah_algorithm_state *, - struct secasvar *)); -static void ah_none_loop __P((struct ah_algorithm_state *, caddr_t, size_t)); -static void ah_none_result __P((struct ah_algorithm_state *, caddr_t)); -static int ah_keyed_md5_mature __P((struct secasvar *)); -static void ah_keyed_md5_init __P((struct ah_algorithm_state *, - struct secasvar *)); -static void ah_keyed_md5_loop __P((struct ah_algorithm_state *, caddr_t, - size_t)); -static void ah_keyed_md5_result __P((struct ah_algorithm_state *, caddr_t)); -static int ah_keyed_sha1_mature __P((struct secasvar *)); -static void ah_keyed_sha1_init __P((struct ah_algorithm_state *, - struct secasvar *)); -static void ah_keyed_sha1_loop __P((struct ah_algorithm_state *, caddr_t, - size_t)); -static void ah_keyed_sha1_result __P((struct ah_algorithm_state *, caddr_t)); -static int ah_hmac_md5_mature __P((struct secasvar *)); -static void ah_hmac_md5_init __P((struct ah_algorithm_state *, - struct secasvar *)); -static void ah_hmac_md5_loop __P((struct ah_algorithm_state *, caddr_t, - size_t)); -static void ah_hmac_md5_result __P((struct ah_algorithm_state *, caddr_t)); -static int ah_hmac_sha1_mature __P((struct secasvar *)); -static void ah_hmac_sha1_init __P((struct ah_algorithm_state *, - struct secasvar *)); -static void ah_hmac_sha1_loop __P((struct ah_algorithm_state *, caddr_t, - size_t)); -static void ah_hmac_sha1_result __P((struct ah_algorithm_state *, caddr_t)); - -static void ah_update_mbuf __P((struct mbuf *, int, int, struct ah_algorithm *, - struct ah_algorithm_state *)); - -/* checksum algorithms */ -/* NOTE: The order depends on SADB_AALG_x in net/pfkeyv2.h */ -struct ah_algorithm ah_algorithms[] = { - { 0, 0, 0, 0, 0, 0, }, - { ah_sumsiz_1216, ah_hmac_md5_mature, 128, 128, - ah_hmac_md5_init, ah_hmac_md5_loop, ah_hmac_md5_result, }, - { ah_sumsiz_1216, ah_hmac_sha1_mature, 160, 160, - ah_hmac_sha1_init, ah_hmac_sha1_loop, ah_hmac_sha1_result, }, - { ah_sumsiz_1216, ah_keyed_md5_mature, 128, 128, - ah_keyed_md5_init, ah_keyed_md5_loop, ah_keyed_md5_result, }, - { ah_sumsiz_1216, ah_keyed_sha1_mature, 160, 160, - ah_keyed_sha1_init, ah_keyed_sha1_loop, ah_keyed_sha1_result, }, - { ah_sumsiz_zero, ah_none_mature, 0, 2048, - ah_none_init, ah_none_loop, ah_none_result, }, -}; +static int ah_sumsiz_1216(struct secasvar *); +static int ah_sumsiz_zero(struct secasvar *); +static int ah_none_mature(struct secasvar *); +static int ah_none_init(struct ah_algorithm_state *, struct secasvar *); +static void ah_none_loop(struct ah_algorithm_state *, caddr_t, size_t); +static void ah_none_result(struct ah_algorithm_state *, caddr_t, size_t); +static int ah_keyed_md5_mature(struct secasvar *); +static int ah_keyed_md5_init(struct ah_algorithm_state *, struct secasvar *); +static void ah_keyed_md5_loop(struct ah_algorithm_state *, caddr_t, size_t); +static void ah_keyed_md5_result(struct ah_algorithm_state *, caddr_t, size_t); +static int ah_keyed_sha1_mature(struct secasvar *); +static int ah_keyed_sha1_init(struct ah_algorithm_state *, struct secasvar *); +static void ah_keyed_sha1_loop(struct ah_algorithm_state *, caddr_t, size_t); +static void ah_keyed_sha1_result(struct ah_algorithm_state *, caddr_t, size_t); +static int ah_hmac_md5_mature(struct secasvar *); +static int ah_hmac_md5_init(struct ah_algorithm_state *, struct secasvar *); +static void ah_hmac_md5_loop(struct ah_algorithm_state *, caddr_t, size_t); +static void ah_hmac_md5_result(struct ah_algorithm_state *, caddr_t, size_t); +static int ah_hmac_sha1_mature(struct secasvar *); +static int ah_hmac_sha1_init(struct ah_algorithm_state *, struct secasvar *); +static void ah_hmac_sha1_loop(struct ah_algorithm_state *, caddr_t, size_t); +static void ah_hmac_sha1_result(struct ah_algorithm_state *, caddr_t, size_t); +#if AH_ALL_CRYPTO +static int ah_sumsiz_sha2_256(struct secasvar *); +static int ah_hmac_sha2_256_mature(struct secasvar *); +static int ah_hmac_sha2_256_init(struct ah_algorithm_state *, + struct secasvar *); +static void ah_hmac_sha2_256_loop(struct ah_algorithm_state *, caddr_t, size_t); +static void ah_hmac_sha2_256_result(struct ah_algorithm_state *, caddr_t, size_t); +static int ah_sumsiz_sha2_384(struct secasvar *); +static int ah_hmac_sha2_384_mature(struct secasvar *); +static int ah_hmac_sha2_384_init(struct ah_algorithm_state *, + struct secasvar *); +static void ah_hmac_sha2_384_loop(struct ah_algorithm_state *, caddr_t, size_t); +static void ah_hmac_sha2_384_result(struct ah_algorithm_state *, caddr_t, size_t); +static int ah_sumsiz_sha2_512(struct secasvar *); +static int ah_hmac_sha2_512_mature(struct secasvar *); +static int ah_hmac_sha2_512_init(struct ah_algorithm_state *, + struct secasvar *); +static void ah_hmac_sha2_512_loop(struct ah_algorithm_state *, caddr_t, size_t); +static void ah_hmac_sha2_512_result(struct ah_algorithm_state *, caddr_t, size_t); +#endif /* AH_ALL_CRYPTO */ + +static void ah_update_mbuf(struct mbuf *, int, int, + const struct ah_algorithm *, struct ah_algorithm_state *); + +const struct ah_algorithm * +ah_algorithm_lookup(int idx) +{ + /* checksum algorithms */ + static struct ah_algorithm hmac_md5 = + { ah_sumsiz_1216, ah_hmac_md5_mature, 128, 128, "hmac-md5", + ah_hmac_md5_init, ah_hmac_md5_loop, + ah_hmac_md5_result, }; + static struct ah_algorithm keyed_md5 = + { ah_sumsiz_1216, ah_keyed_md5_mature, 128, 128, "keyed-md5", + ah_keyed_md5_init, ah_keyed_md5_loop, + ah_keyed_md5_result, }; + static struct ah_algorithm hmac_sha1 = + { ah_sumsiz_1216, ah_hmac_sha1_mature, 160, 160, "hmac-sha1", + ah_hmac_sha1_init, ah_hmac_sha1_loop, + ah_hmac_sha1_result, }; + static struct ah_algorithm keyed_sha1 = + { ah_sumsiz_1216, ah_keyed_sha1_mature, 160, 160, "keyed-sha1", + ah_keyed_sha1_init, ah_keyed_sha1_loop, + ah_keyed_sha1_result, }; + static struct ah_algorithm ah_none = + { ah_sumsiz_zero, ah_none_mature, 0, 2048, "none", + ah_none_init, ah_none_loop, ah_none_result, }; +#if AH_ALL_CRYPTO + static struct ah_algorithm hmac_sha2_256 = + { ah_sumsiz_sha2_256, ah_hmac_sha2_256_mature, 256, 256, + "hmac-sha2-256", + ah_hmac_sha2_256_init, ah_hmac_sha2_256_loop, + ah_hmac_sha2_256_result, }; + static struct ah_algorithm hmac_sha2_384 = + { ah_sumsiz_sha2_384, ah_hmac_sha2_384_mature, 384, 384, + "hmac-sha2-384", + ah_hmac_sha2_384_init, ah_hmac_sha2_384_loop, + ah_hmac_sha2_384_result, }; + static struct ah_algorithm hmac_sha2_512 = + { ah_sumsiz_sha2_512, ah_hmac_sha2_512_mature, 512, 512, + "hmac-sha2-512", + ah_hmac_sha2_512_init, ah_hmac_sha2_512_loop, + ah_hmac_sha2_512_result, }; +#endif /* AH_ALL_CRYPTO */ + + switch (idx) { + case SADB_AALG_MD5HMAC: + return &hmac_md5; + case SADB_AALG_SHA1HMAC: + return &hmac_sha1; + case SADB_X_AALG_MD5: + return &keyed_md5; + case SADB_X_AALG_SHA: + return &keyed_sha1; + case SADB_X_AALG_NULL: + return &ah_none; +#if AH_ALL_CRYPTO + case SADB_X_AALG_SHA2_256: + return &hmac_sha2_256; + case SADB_X_AALG_SHA2_384: + return &hmac_sha2_384; + case SADB_X_AALG_SHA2_512: + return &hmac_sha2_512; +#endif /* AH_ALL_CRYPTO */ + default: + return NULL; + } +} + static int -ah_sumsiz_1216(sav) - struct secasvar *sav; +ah_sumsiz_1216(struct secasvar *sav) { if (!sav) return -1; @@ -161,8 +238,7 @@ ah_sumsiz_1216(sav) } static int -ah_sumsiz_zero(sav) - struct secasvar *sav; +ah_sumsiz_zero(struct secasvar *sav) { if (!sav) return -1; @@ -170,8 +246,7 @@ ah_sumsiz_zero(sav) } static int -ah_none_mature(sav) - struct secasvar *sav; +ah_none_mature(struct secasvar *sav) { if (sav->sah->saidx.proto == IPPROTO_AH) { ipseclog((LOG_ERR, @@ -181,65 +256,65 @@ ah_none_mature(sav) return 0; } -static void -ah_none_init(state, sav) - struct ah_algorithm_state *state; - struct secasvar *sav; +static int +ah_none_init( + struct ah_algorithm_state *state, + __unused struct secasvar *sav) { state->foo = NULL; + return 0; } static void -ah_none_loop(state, addr, len) - struct ah_algorithm_state *state; - caddr_t addr; - size_t len; +ah_none_loop( + __unused struct ah_algorithm_state *state, + __unused caddr_t addr, + __unused size_t len) { } static void -ah_none_result(state, addr) - struct ah_algorithm_state *state; - caddr_t addr; +ah_none_result( + __unused struct ah_algorithm_state *state, + __unused caddr_t addr, + __unused size_t l) { } static int -ah_keyed_md5_mature(sav) - struct secasvar *sav; +ah_keyed_md5_mature( + __unused struct secasvar *sav) { /* anything is okay */ return 0; } -static void -ah_keyed_md5_init(state, sav) - struct ah_algorithm_state *state; - struct secasvar *sav; +static int +ah_keyed_md5_init(struct ah_algorithm_state *state, struct secasvar *sav) { + size_t padlen; + size_t keybitlen; + u_int8_t buf[32] __attribute__((aligned(4))); + 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) - panic("ah_keyed_md5_init: what?"); + 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. */ - size_t padlen; - size_t keybitlen; - u_int8_t buf[32]; - if (_KEYLEN(state->sav->key_auth) < 56) padlen = 64 - 8 - _KEYLEN(state->sav->key_auth); else @@ -265,15 +340,13 @@ ah_keyed_md5_init(state, sav) 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; - caddr_t addr; - size_t len; +ah_keyed_md5_loop(struct ah_algorithm_state *state, caddr_t addr, size_t len) { if (!state) panic("ah_keyed_md5_loop: what?"); @@ -282,11 +355,9 @@ ah_keyed_md5_loop(state, addr, len) } static void -ah_keyed_md5_result(state, addr) - struct ah_algorithm_state *state; - caddr_t addr; +ah_keyed_md5_result(struct ah_algorithm_state *state, caddr_t addr, size_t l) { - u_char digest[16]; + u_char digest[16] __attribute__((aligned(4))); if (!state) panic("ah_keyed_md5_result: what?"); @@ -297,21 +368,26 @@ ah_keyed_md5_result(state, addr) (u_int)_KEYLEN(state->sav->key_auth)); } MD5Final(&digest[0], (MD5_CTX *)state->foo); - _FREE(state->foo, M_TEMP); - bcopy(&digest[0], (void *)addr, sizeof(digest)); + FREE(state->foo, M_TEMP); + bcopy(&digest[0], (void *)addr, sizeof(digest) > l ? l : sizeof(digest)); } static int -ah_keyed_sha1_mature(sav) - struct secasvar *sav; +ah_keyed_sha1_mature(struct secasvar *sav) { - struct ah_algorithm *algo; + const struct ah_algorithm *algo; if (!sav->key_auth) { ipseclog((LOG_ERR, "ah_keyed_sha1_mature: no key is given.\n")); return 1; } - algo = &ah_algorithms[sav->alg_auth]; + + algo = ah_algorithm_lookup(sav->alg_auth); + if (!algo) { + ipseclog((LOG_ERR, "ah_keyed_sha1_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, @@ -323,12 +399,13 @@ ah_keyed_sha1_mature(sav) return 0; } -static void -ah_keyed_sha1_init(state, sav) - struct ah_algorithm_state *state; - struct secasvar *sav; +static int +ah_keyed_sha1_init(struct ah_algorithm_state *state, struct secasvar *sav) { SHA1_CTX *ctxt; + size_t padlen; + size_t keybitlen; + u_int8_t buf[32] __attribute__((aligned(4))); if (!state) panic("ah_keyed_sha1_init: what?"); @@ -336,7 +413,7 @@ ah_keyed_sha1_init(state, sav) state->sav = sav; state->foo = (void *)_MALLOC(sizeof(SHA1_CTX), M_TEMP, M_NOWAIT); if (!state->foo) - panic("ah_keyed_sha1_init: what?"); + return ENOBUFS; ctxt = (SHA1_CTX *)state->foo; SHA1Init(ctxt); @@ -345,14 +422,9 @@ ah_keyed_sha1_init(state, sav) SHA1Update(ctxt, (u_int8_t *)_KEYBUF(state->sav->key_auth), (u_int)_KEYLEN(state->sav->key_auth)); - { /* * Pad after the key. */ - size_t padlen; - size_t keybitlen; - u_int8_t buf[32]; - if (_KEYLEN(state->sav->key_auth) < 56) padlen = 64 - 8 - _KEYLEN(state->sav->key_auth); else @@ -378,15 +450,13 @@ ah_keyed_sha1_init(state, sav) 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; - caddr_t addr; - size_t len; +ah_keyed_sha1_loop(struct ah_algorithm_state *state, caddr_t addr, size_t len) { SHA1_CTX *ctxt; @@ -398,11 +468,9 @@ ah_keyed_sha1_loop(state, addr, len) } static void -ah_keyed_sha1_result(state, addr) - struct ah_algorithm_state *state; - caddr_t addr; +ah_keyed_sha1_result(struct ah_algorithm_state *state, caddr_t addr, size_t l) { - u_char digest[SHA1_RESULTLEN]; /* SHA-1 generates 160 bits */ + u_char digest[SHA1_RESULTLEN] __attribute__((aligned(4))); /* SHA-1 generates 160 bits */ SHA1_CTX *ctxt; if (!state || !state->foo) @@ -414,22 +482,27 @@ ah_keyed_sha1_result(state, addr) (u_int)_KEYLEN(state->sav->key_auth)); } SHA1Final((caddr_t)&digest[0], ctxt); - bcopy(&digest[0], (void *)addr, HMACSIZE); + bcopy(&digest[0], (void *)addr, sizeof(digest) > l ? l : sizeof(digest)); - _FREE(state->foo, M_TEMP); + FREE(state->foo, M_TEMP); } static int -ah_hmac_md5_mature(sav) - struct secasvar *sav; +ah_hmac_md5_mature(struct secasvar *sav) { - struct ah_algorithm *algo; + const struct ah_algorithm *algo; if (!sav->key_auth) { ipseclog((LOG_ERR, "ah_hmac_md5_mature: no key is given.\n")); return 1; } - algo = &ah_algorithms[sav->alg_auth]; + + algo = ah_algorithm_lookup(sav->alg_auth); + if (!algo) { + ipseclog((LOG_ERR, "ah_hmac_md5_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, @@ -441,14 +514,12 @@ ah_hmac_md5_mature(sav) return 0; } -static void -ah_hmac_md5_init(state, sav) - struct ah_algorithm_state *state; - struct secasvar *sav; +static int +ah_hmac_md5_init(struct ah_algorithm_state *state, struct secasvar *sav) { u_char *ipad; u_char *opad; - u_char tk[16]; + u_char tk[16] __attribute__((aligned(4))); u_char *key; size_t keylen; size_t i; @@ -460,11 +531,11 @@ ah_hmac_md5_init(state, sav) state->sav = sav; state->foo = (void *)_MALLOC(64 + 64 + sizeof(MD5_CTX), M_TEMP, M_NOWAIT); if (!state->foo) - panic("ah_hmac_md5_init: what?"); + return ENOBUFS; ipad = (u_char *)state->foo; opad = (u_char *)(ipad + 64); - ctxt = (MD5_CTX *)(opad + 64); + ctxt = (MD5_CTX *)(void *)(opad + 64); /* compress the key if necessery */ if (64 < _KEYLEN(state->sav->key_auth)) { @@ -475,7 +546,7 @@ ah_hmac_md5_init(state, sav) key = &tk[0]; keylen = 16; } else { - key = _KEYBUF(state->sav->key_auth); + key = (u_char *) _KEYBUF(state->sav->key_auth); keylen = _KEYLEN(state->sav->key_auth); } @@ -490,28 +561,25 @@ ah_hmac_md5_init(state, sav) MD5Init(ctxt); MD5Update(ctxt, ipad, 64); + + return 0; } static void -ah_hmac_md5_loop(state, addr, len) - struct ah_algorithm_state *state; - caddr_t addr; - size_t len; +ah_hmac_md5_loop(struct ah_algorithm_state *state, caddr_t addr, size_t len) { MD5_CTX *ctxt; if (!state || !state->foo) panic("ah_hmac_md5_loop: what?"); - ctxt = (MD5_CTX *)(((caddr_t)state->foo) + 128); + ctxt = (MD5_CTX *)(void *)(((caddr_t)state->foo) + 128); MD5Update(ctxt, addr, len); } static void -ah_hmac_md5_result(state, addr) - struct ah_algorithm_state *state; - caddr_t addr; +ah_hmac_md5_result(struct ah_algorithm_state *state, caddr_t addr, size_t l) { - u_char digest[16]; + u_char digest[16] __attribute__((aligned(4))); u_char *ipad; u_char *opad; MD5_CTX *ctxt; @@ -521,7 +589,7 @@ ah_hmac_md5_result(state, addr) ipad = (u_char *)state->foo; opad = (u_char *)(ipad + 64); - ctxt = (MD5_CTX *)(opad + 64); + ctxt = (MD5_CTX *)(void *)(opad + 64); MD5Final(&digest[0], ctxt); @@ -530,22 +598,27 @@ ah_hmac_md5_result(state, addr) MD5Update(ctxt, &digest[0], sizeof(digest)); MD5Final(&digest[0], ctxt); - bcopy(&digest[0], (void *)addr, HMACSIZE); + bcopy(&digest[0], (void *)addr, sizeof(digest) > l ? l : sizeof(digest)); - _FREE(state->foo, M_TEMP); + FREE(state->foo, M_TEMP); } static int -ah_hmac_sha1_mature(sav) - struct secasvar *sav; +ah_hmac_sha1_mature(struct secasvar *sav) { - struct ah_algorithm *algo; + const struct ah_algorithm *algo; if (!sav->key_auth) { ipseclog((LOG_ERR, "ah_hmac_sha1_mature: no key is given.\n")); return 1; } - algo = &ah_algorithms[sav->alg_auth]; + + algo = ah_algorithm_lookup(sav->alg_auth); + if (!algo) { + ipseclog((LOG_ERR, "ah_hmac_sha1_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, @@ -557,15 +630,13 @@ ah_hmac_sha1_mature(sav) return 0; } -static void -ah_hmac_sha1_init(state, sav) - struct ah_algorithm_state *state; - struct secasvar *sav; +static int +ah_hmac_sha1_init(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 tk[SHA1_RESULTLEN] __attribute__((aligned(4))); /* SHA-1 generates 160 bits */ u_char *key; size_t keylen; size_t i; @@ -577,11 +648,11 @@ ah_hmac_sha1_init(state, sav) state->foo = (void *)_MALLOC(64 + 64 + sizeof(SHA1_CTX), M_TEMP, M_NOWAIT); if (!state->foo) - panic("ah_hmac_sha1_init: what?"); + return ENOBUFS; ipad = (u_char *)state->foo; opad = (u_char *)(ipad + 64); - ctxt = (SHA1_CTX *)(opad + 64); + ctxt = (SHA1_CTX *)(void *)(opad + 64); /* compress the key if necessery */ if (64 < _KEYLEN(state->sav->key_auth)) { @@ -592,7 +663,7 @@ ah_hmac_sha1_init(state, sav) key = &tk[0]; keylen = SHA1_RESULTLEN; } else { - key = _KEYBUF(state->sav->key_auth); + key = (u_char *) _KEYBUF(state->sav->key_auth); keylen = _KEYLEN(state->sav->key_auth); } @@ -607,29 +678,26 @@ ah_hmac_sha1_init(state, sav) SHA1Init(ctxt); SHA1Update(ctxt, ipad, 64); + + return 0; } static void -ah_hmac_sha1_loop(state, addr, len) - struct ah_algorithm_state *state; - caddr_t addr; - size_t len; +ah_hmac_sha1_loop(struct ah_algorithm_state *state, caddr_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); + ctxt = (SHA1_CTX *)(void *)(((u_char *)state->foo) + 128); SHA1Update(ctxt, (caddr_t)addr, (size_t)len); } static void -ah_hmac_sha1_result(state, addr) - struct ah_algorithm_state *state; - caddr_t addr; +ah_hmac_sha1_result(struct ah_algorithm_state *state, caddr_t addr, size_t l) { - u_char digest[SHA1_RESULTLEN]; /* SHA-1 generates 160 bits */ + u_char digest[SHA1_RESULTLEN] __attribute__((aligned(4))); /* SHA-1 generates 160 bits */ u_char *ipad; u_char *opad; SHA1_CTX *ctxt; @@ -639,7 +707,7 @@ ah_hmac_sha1_result(state, addr) ipad = (u_char *)state->foo; opad = (u_char *)(ipad + 64); - ctxt = (SHA1_CTX *)(opad + 64); + ctxt = (SHA1_CTX *)(void *)(opad + 64); SHA1Final((caddr_t)&digest[0], ctxt); @@ -648,23 +716,430 @@ ah_hmac_sha1_result(state, addr) SHA1Update(ctxt, (caddr_t)&digest[0], sizeof(digest)); SHA1Final((caddr_t)&digest[0], ctxt); - bcopy(&digest[0], (void *)addr, HMACSIZE); + bcopy(&digest[0], (void *)addr, sizeof(digest) > l ? l : sizeof(digest)); - _FREE(state->foo, M_TEMP); + FREE(state->foo, M_TEMP); } +#if AH_ALL_CRYPTO +static int +ah_sumsiz_sha2_256(struct secasvar *sav) +{ + if (!sav) + return -1; + // return half the output size (in bytes), as per rfc 4868 + return 16; // 256/(8*2) +} + +static int +ah_hmac_sha2_256_mature(struct secasvar *sav) +{ + const struct ah_algorithm *algo; + + if (!sav->key_auth) { + ipseclog((LOG_ERR, + "ah_hmac_sha2_256_mature: no key is given.\n")); + return 1; + } + + algo = ah_algorithm_lookup(sav->alg_auth); + if (!algo) { + ipseclog((LOG_ERR, + "ah_hmac_sha2_256_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_hmac_sha2_256_mature: invalid key length %d.\n", + sav->key_auth->sadb_key_bits)); + return 1; + } + + return 0; +} + +static int +ah_hmac_sha2_256_init(struct ah_algorithm_state *state, struct secasvar *sav) +{ + u_char *ipad; + u_char *opad; + SHA256_CTX *ctxt; + u_char tk[SHA256_DIGEST_LENGTH] __attribute__((aligned(4))); + 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 *)(void *)(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, (const u_int8_t *) _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 = (u_char *) _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(struct ah_algorithm_state *state, + caddr_t addr, + size_t len) +{ + SHA256_CTX *ctxt; + + if (!state || !state->foo) + panic("ah_hmac_sha2_256_loop: what?"); + + ctxt = (SHA256_CTX *)(void *)(((u_char *)state->foo) + 128); + SHA256_Update(ctxt, (const u_int8_t *)addr, (size_t)len); +} + +static void +ah_hmac_sha2_256_result(struct ah_algorithm_state *state, + caddr_t addr, + size_t l) +{ + u_char digest[SHA256_DIGEST_LENGTH] __attribute__((aligned(4))); + 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 *)(void *)(opad + 64); + + SHA256_Final((u_int8_t *)digest, ctxt); + + SHA256_Init(ctxt); + SHA256_Update(ctxt, opad, 64); + SHA256_Update(ctxt, (const u_int8_t *)digest, sizeof(digest)); + SHA256_Final((u_int8_t *)digest, ctxt); + + bcopy(&digest[0], (void *)addr, sizeof(digest) > l ? l : sizeof(digest)); + + FREE(state->foo, M_TEMP); +} + +static int +ah_sumsiz_sha2_384(struct secasvar *sav) +{ + if (!sav) + return -1; + // return half the output size (in bytes), as per rfc 4868 + return 24; // 384/(8*2) +} + +static int +ah_hmac_sha2_384_mature(struct secasvar *sav) +{ + const struct ah_algorithm *algo; + + if (!sav->key_auth) { + ipseclog((LOG_ERR, + "ah_hmac_sha2_384_mature: no key is given.\n")); + return 1; + } + + algo = ah_algorithm_lookup(sav->alg_auth); + if (!algo) { + ipseclog((LOG_ERR, + "ah_hmac_sha2_384_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_hmac_sha2_384_mature: invalid key length %d.\n", + sav->key_auth->sadb_key_bits)); + return 1; + } + + return 0; +} + +static int +ah_hmac_sha2_384_init(struct ah_algorithm_state *state, struct secasvar *sav) +{ + u_char *ipad; + u_char *opad; + SHA384_CTX *ctxt; + u_char tk[SHA384_DIGEST_LENGTH] __attribute__((aligned(4))); + 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(128 + 128 + sizeof(SHA384_CTX), + M_TEMP, M_NOWAIT | M_ZERO); + if (!state->foo) + return ENOBUFS; + + ipad = (u_char *)state->foo; + opad = (u_char *)(ipad + 128); + ctxt = (SHA384_CTX *)(void *)(opad + 128); + + /* compress the key if necessery */ + if (128 < _KEYLEN(state->sav->key_auth)) { + bzero(tk, sizeof(tk)); + bzero(ctxt, sizeof(*ctxt)); + SHA384_Init(ctxt); + SHA384_Update(ctxt, (const u_int8_t *) _KEYBUF(state->sav->key_auth), + _KEYLEN(state->sav->key_auth)); + SHA384_Final(&tk[0], ctxt); + key = &tk[0]; + keylen = sizeof(tk) < 128 ? sizeof(tk) : 128; + } else { + key = (u_char *) _KEYBUF(state->sav->key_auth); + keylen = _KEYLEN(state->sav->key_auth); + } + + bzero(ipad, 128); + bzero(opad, 128); + bcopy(key, ipad, keylen); + bcopy(key, opad, keylen); + for (i = 0; i < 128; i++) { + ipad[i] ^= 0x36; + opad[i] ^= 0x5c; + } + + bzero(ctxt, sizeof(*ctxt)); + SHA384_Init(ctxt); + SHA384_Update(ctxt, ipad, 128); + + return 0; +} + +static void +ah_hmac_sha2_384_loop(struct ah_algorithm_state *state, + caddr_t addr, + size_t len) +{ + SHA384_CTX *ctxt; + + if (!state || !state->foo) + panic("ah_hmac_sha2_384_loop: what?"); + + ctxt = (SHA384_CTX *)(void *)(((u_char *)state->foo) + 256); + SHA384_Update(ctxt, (const u_int8_t *)addr, (size_t)len); +} + +static void +ah_hmac_sha2_384_result(struct ah_algorithm_state *state, + caddr_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 + 128); + ctxt = (SHA384_CTX *)(void *)(opad + 128); + + SHA384_Final((u_int8_t *)digest, ctxt); + + SHA384_Init(ctxt); + SHA384_Update(ctxt, opad, 128); + SHA384_Update(ctxt, (const u_int8_t *)digest, sizeof(digest)); + SHA384_Final((u_int8_t *)digest, ctxt); + + bcopy(&digest[0], (void *)addr, sizeof(digest) > l ? l : sizeof(digest)); + + FREE(state->foo, M_TEMP); +} + +static int +ah_sumsiz_sha2_512(struct secasvar *sav) +{ + if (!sav) + return -1; + // return half the output size (in bytes), as per rfc 4868 + return 32; // 512/(8*2) +} + +static int +ah_hmac_sha2_512_mature(struct secasvar *sav) +{ + const struct ah_algorithm *algo; + + if (!sav->key_auth) { + ipseclog((LOG_ERR, + "ah_hmac_sha2_512_mature: no key is given.\n")); + return 1; + } + + algo = ah_algorithm_lookup(sav->alg_auth); + if (!algo) { + ipseclog((LOG_ERR, + "ah_hmac_sha2_512_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_hmac_sha2_512_mature: invalid key length %d.\n", + sav->key_auth->sadb_key_bits)); + return 1; + } + + return 0; +} + +static int +ah_hmac_sha2_512_init(struct ah_algorithm_state *state, struct secasvar *sav) +{ + u_char *ipad; + u_char *opad; + SHA512_CTX *ctxt; + u_char tk[SHA512_DIGEST_LENGTH] __attribute__((aligned(4))); + 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(128 + 128 + sizeof(SHA512_CTX), + M_TEMP, M_NOWAIT | M_ZERO); + if (!state->foo) + return ENOBUFS; + + ipad = (u_char *)state->foo; + opad = (u_char *)(ipad + 128); + ctxt = (SHA512_CTX *)(void *)(opad + 128); + + /* compress the key if necessery */ + if (128 < _KEYLEN(state->sav->key_auth)) { + bzero(tk, sizeof(tk)); + bzero(ctxt, sizeof(*ctxt)); + SHA512_Init(ctxt); + SHA512_Update(ctxt, (const u_int8_t *) _KEYBUF(state->sav->key_auth), + _KEYLEN(state->sav->key_auth)); + SHA512_Final(&tk[0], ctxt); + key = &tk[0]; + keylen = sizeof(tk) < 128 ? sizeof(tk) : 128; + } else { + key = (u_char *) _KEYBUF(state->sav->key_auth); + keylen = _KEYLEN(state->sav->key_auth); + } + + bzero(ipad, 128); + bzero(opad, 128); + bcopy(key, ipad, keylen); + bcopy(key, opad, keylen); + for (i = 0; i < 128; i++) { + ipad[i] ^= 0x36; + opad[i] ^= 0x5c; + } + + bzero(ctxt, sizeof(*ctxt)); + SHA512_Init(ctxt); + SHA512_Update(ctxt, ipad, 128); + + return 0; +} + +static void +ah_hmac_sha2_512_loop(struct ah_algorithm_state *state, + caddr_t addr, + size_t len) +{ + SHA512_CTX *ctxt; + + if (!state || !state->foo) + panic("ah_hmac_sha2_512_loop: what?"); + + ctxt = (SHA512_CTX *)(void *)(((u_char *)state->foo) + 256); + SHA512_Update(ctxt, (const u_int8_t *) addr, (size_t)len); +} + +static void +ah_hmac_sha2_512_result(struct ah_algorithm_state *state, + caddr_t addr, + size_t l) +{ + u_char digest[SHA512_DIGEST_LENGTH] __attribute__((aligned(4))); + 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 + 128); + ctxt = (SHA512_CTX *)(void *)(opad + 128); + + SHA512_Final((u_int8_t *)digest, ctxt); + + SHA512_Init(ctxt); + SHA512_Update(ctxt, opad, 128); + SHA512_Update(ctxt, (const u_int8_t *)digest, sizeof(digest)); + SHA512_Final((u_int8_t *)digest, ctxt); + + bcopy(&digest[0], (void *)addr, sizeof(digest) > l ? l : sizeof(digest)); + + FREE(state->foo, M_TEMP); +} +#endif /* AH_ALL_CRYPTO */ + /*------------------------------------------------------------*/ /* * go generate the checksum. */ static void -ah_update_mbuf(m, off, len, algo, algos) - struct mbuf *m; - int off; - int len; - struct ah_algorithm *algo; - struct ah_algorithm_state *algos; +ah_update_mbuf(struct mbuf *m,int off, int len, + const struct ah_algorithm *algo, + struct ah_algorithm_state *algos) { struct mbuf *n; int tlen; @@ -700,6 +1175,7 @@ ah_update_mbuf(m, off, len, algo, algos) } } +#if INET /* * Go generate the checksum. This function won't modify the mbuf chain * except AH itself. @@ -708,17 +1184,14 @@ ah_update_mbuf(m, off, len, algo, algos) * Don't use m_copy(), it will try to share cluster mbuf by using refcnt. */ int -ah4_calccksum(m, ahdat, algo, sav) - struct mbuf *m; - caddr_t ahdat; - struct ah_algorithm *algo; - struct secasvar *sav; +ah4_calccksum(struct mbuf *m, caddr_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]; + u_char sumbuf[AH_MAXSUMSIZE] __attribute__((aligned(4))); int error = 0; int ahseen; struct mbuf *n = NULL; @@ -731,7 +1204,9 @@ ah4_calccksum(m, ahdat, algo, sav) off = 0; - (algo->init)(&algos, sav); + error = (algo->init)(&algos, sav); + if (error) + return error; advancewidth = 0; /*safety*/ @@ -748,7 +1223,7 @@ again: size_t hlen; m_copydata(m, off, sizeof(iphdr), (caddr_t)&iphdr); -#ifdef _IP_VHL +#if _IP_VHL hlen = IP_VHL_HL(iphdr.ip_vhl) << 2; #else hlen = iphdr.ip_hl << 2; @@ -789,6 +1264,25 @@ again: 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: @@ -802,21 +1296,24 @@ again: 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 <= 0 || hlen - i < l) { + 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])); - m_free(n); - n = NULL; error = EINVAL; goto fail; } @@ -826,8 +1323,9 @@ again: break; i += l; } + p = mtod(n, u_char *) + sizeof(struct ip); - (algo->update)(&algos, p, hlen - sizeof(struct ip)); + (algo->update)(&algos, (caddr_t)p, hlen - sizeof(struct ip)); m_free(n); n = NULL; @@ -898,7 +1396,12 @@ again: if (off < m->m_pkthdr.len) goto again; - (algo->result)(&algos, &sumbuf[0]); + if (len < (*algo->sumsiz)(sav)) { + error = EINVAL; + goto fail; + } + + (algo->result)(&algos, (caddr_t) &sumbuf[0], sizeof(sumbuf)); bcopy(&sumbuf[0], ahdat, (*algo->sumsiz)(sav)); if (n) @@ -910,6 +1413,7 @@ fail: m_free(n); return error; } +#endif #if INET6 /* @@ -920,11 +1424,8 @@ fail: * Don't use m_copy(), it will try to share cluster mbuf by using refcnt. */ int -ah6_calccksum(m, ahdat, algo, sav) - struct mbuf *m; - caddr_t ahdat; - struct ah_algorithm *algo; - struct secasvar *sav; +ah6_calccksum(struct mbuf *m, caddr_t ahdat, size_t len, + const struct ah_algorithm *algo, struct secasvar *sav) { int newoff, off; int proto, nxt; @@ -932,12 +1433,14 @@ ah6_calccksum(m, ahdat, algo, sav) int error; int ahseen; struct ah_algorithm_state algos; - u_char sumbuf[AH_MAXSUMSIZE]; + u_char sumbuf[AH_MAXSUMSIZE] __attribute__((aligned(4))); if ((m->m_flags & M_PKTHDR) == 0) return EINVAL; - (algo->init)(&algos, sav); + error = (algo->init)(&algos, sav); + if (error) + return error; off = 0; proto = IPPROTO_IPV6; @@ -1116,7 +1619,12 @@ ah6_calccksum(m, ahdat, algo, sav) goto again; } - (algo->result)(&algos, &sumbuf[0]); + if (len < (*algo->sumsiz)(sav)) { + error = EINVAL; + goto fail; + } + + (algo->result)(&algos, (caddr_t) &sumbuf[0], sizeof(sumbuf)); bcopy(&sumbuf[0], ahdat, (*algo->sumsiz)(sav)); /* just in case */