📄 ah_core.c
字号:
//==========================================================================
//
// src/sys/netinet6/ah_core.c
//
//==========================================================================
//####BSDCOPYRIGHTBEGIN####
//
// -------------------------------------------
//
// Portions of this software may have been derived from OpenBSD,
// FreeBSD or other sources, and are covered by the appropriate
// copyright disclaimers included herein.
//
// Portions created by Red Hat are
// Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
//
// -------------------------------------------
//
//####BSDCOPYRIGHTEND####
//==========================================================================
/* $KAME: ah_core.c,v 1.47 2001/10/29 04:43:08 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 <sys/param.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>
#if !(defined(__FreeBSD__) && __FreeBSD__ >= 4)
#include <sys/kernel.h>
#endif
#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>
#include <netinet6/ah.h>
#ifdef IPSEC_ESP
#include <netinet6/esp.h>
#endif
#include <net/pfkeyv2.h>
#include <netkey/keydb.h>
#ifdef HAVE_MD5
#include <sys/md5.h>
#else
#include <crypto/md5.h>
#endif
#ifdef HAVE_SHA1
#include <sys/sha1.h>
#define SHA1_RESULTLEN 20
#else
#include <crypto/sha1.h>
#endif
#include <crypto/sha2/sha2.h>
#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 int 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 int 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 int 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 int 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 int 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 int ah_hmac_sha2_256_mature __P((struct secasvar *));
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 *, caddr_t,
size_t));
static void ah_hmac_sha2_256_result __P((struct ah_algorithm_state *, caddr_t));
static int ah_hmac_sha2_384_mature __P((struct secasvar *));
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 *, caddr_t,
size_t));
static void ah_hmac_sha2_384_result __P((struct ah_algorithm_state *, caddr_t));
static int ah_hmac_sha2_512_mature __P((struct secasvar *));
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 *, caddr_t,
size_t));
static void ah_hmac_sha2_512_result __P((struct ah_algorithm_state *, caddr_t));
static void ah_update_mbuf __P((struct mbuf *, int, int,
const struct ah_algorithm *, struct ah_algorithm_state *));
const struct ah_algorithm *
ah_algorithm_lookup(idx)
int idx;
{
/* checksum algorithms */
static struct ah_algorithm ah_algorithms[] = {
{ ah_sumsiz_1216, ah_hmac_md5_mature, 128, 128, "hmac-md5",
ah_hmac_md5_init, ah_hmac_md5_loop,
ah_hmac_md5_result, },
{ ah_sumsiz_1216, ah_hmac_sha1_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_keyed_sha1_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_hmac_sha2_256_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_hmac_sha2_384_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_hmac_sha2_512_mature, 512, 512,
"hmac-sha2-512",
ah_hmac_sha2_512_init, ah_hmac_sha2_512_loop,
ah_hmac_sha2_512_result, },
};
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];
default:
return NULL;
}
}
static int
ah_sumsiz_1216(sav)
struct secasvar *sav;
{
if (!sav)
return -1;
if (sav->flags & SADB_X_EXT_OLD)
return 16;
else
return 12;
}
static int
ah_sumsiz_zero(sav)
struct secasvar *sav;
{
if (!sav)
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;
caddr_t addr;
size_t len;
{
}
static void
ah_none_result(state, addr)
struct ah_algorithm_state *state;
caddr_t addr;
{
}
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;
caddr_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)
struct ah_algorithm_state *state;
caddr_t addr;
{
u_char digest[16];
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[0], (MD5_CTX *)state->foo);
free(state->foo, M_TEMP);
bcopy(&digest[0], (void *)addr, sizeof(digest));
}
static int
ah_keyed_sha1_mature(sav)
struct secasvar *sav;
{
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_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,
"ah_keyed_sha1_mature: invalid key length %d.\n",
sav->key_auth->sadb_key_bits));
return 1;
}
return 0;
}
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;
caddr_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, (caddr_t)addr, (size_t)len);
}
static void
ah_keyed_sha1_result(state, addr)
struct ah_algorithm_state *state;
caddr_t addr;
{
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((caddr_t)&digest[0], ctxt);
bcopy(&digest[0], (void *)addr, HMACSIZE);
free(state->foo, M_TEMP);
}
static int
ah_hmac_md5_mature(sav)
struct secasvar *sav;
{
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_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,
"ah_hmac_md5_mature: invalid key length %d.\n",
sav->key_auth->sadb_key_bits));
return 1;
}
return 0;
}
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[16];
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 {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -