diff options
author | shin <shin@FreeBSD.org> | 1999-12-22 19:13:38 +0000 |
---|---|---|
committer | shin <shin@FreeBSD.org> | 1999-12-22 19:13:38 +0000 |
commit | 50ba589c666f7d356304339b9cfc7fc9d173ad8d (patch) | |
tree | 46d6ae7c9680a93ce1c3a13378cef283df9f6544 | |
parent | e396740391e7e60805bda6799ac3397d1fc8c539 (diff) | |
download | FreeBSD-src-50ba589c666f7d356304339b9cfc7fc9d173ad8d.zip FreeBSD-src-50ba589c666f7d356304339b9cfc7fc9d173ad8d.tar.gz |
IPSEC support in the kernel.
pr_input() routines prototype is also changed to support IPSEC and IPV6
chained protocol headers.
Reviewed by: freebsd-arch, cvs-committers
Obtained from: KAME project
101 files changed, 22401 insertions, 3800 deletions
diff --git a/sys/conf/NOTES b/sys/conf/NOTES index 36b49cb..c67e6f2 100644 --- a/sys/conf/NOTES +++ b/sys/conf/NOTES @@ -367,6 +367,10 @@ options ROOTDEVNAME=\"da0s2e\" # options INET #Internet communications protocols options INET6 #IPv6 communications protocols +options IPSEC #IP security +options IPSEC_ESP #IP security (crypto; define w/ IPSEC) +options IPSEC_IPV6FWD #IP security tunnel for IPv6 +options IPSEC_DEBUG #debug for IP security options IPX #IPX/SPX communications protocols options IPXIP #IPX in IP encapsulation (not available) diff --git a/sys/conf/files b/sys/conf/files index 57b413d..4c0f129 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -63,6 +63,19 @@ cam/scsi/scsi_pass.c optional pass cam/scsi/scsi_scan.c optional scan cam/scsi/scsi_target.c optional targ cam/scsi/scsi_targ_bh.c optional targbh +crypto/sha1.c optional ipsec +crypto/des/des_cbc.c optional ipsec +crypto/des/des_ecb.c optional ipsec +crypto/des/des_setkey.c optional ipsec +crypto/des/des_3cbc.c optional ipsec +crypto/blowfish/bf_cbc.c optional ipsec +crypto/blowfish/bf_cbc_m.c optional ipsec +crypto/blowfish/bf_enc.c optional ipsec +crypto/blowfish/bf_skey.c optional ipsec +crypto/cast128/cast128.c optional ipsec +crypto/cast128/cast128_cbc.c optional ipsec +crypto/rc5/rc5.c optional ipsec +crypto/rc5/rc5_cbc.c optional ipsec ddb/db_access.c optional ddb ddb/db_kld.c optional ddb ddb/db_aout.c optional ddb @@ -607,6 +620,8 @@ netinet/in.c optional inet netinet/in_pcb.c optional inet netinet/in_proto.c optional inet netinet/in_rmx.c optional inet +netinet/ip_ecn.c optional inet +netinet/ip_ecn.c optional inet6 netinet/ip_divert.c optional ipdivert netinet/ip_dummynet.c optional dummynet netinet/ip_flow.c optional inet @@ -632,6 +647,13 @@ netinet/ip_auth.c optional ipfilter inet netinet/ip_proxy.c optional ipfilter inet netinet/ip_log.c optional ipfilter inet netinet/mlfk_ipl.c optional ipfilter inet +netinet6/ah_core.c optional ipsec +netinet6/ah_input.c optional ipsec +netinet6/ah_output.c optional ipsec +netinet6/esp_core.c optional ipsec +netinet6/esp_input.c optional ipsec +netinet6/esp_output.c optional ipsec +netinet6/ipsec.c optional ipsec netinet6/dest6.c optional inet6 netinet6/frag6.c optional inet6 netinet6/icmp6.c optional inet6 @@ -664,8 +686,9 @@ netipx/ipx_tun.c optional ipx netipx/ipx_usrreq.c optional ipx netipx/spx_debug.c optional ipx netipx/spx_usrreq.c optional ipx -netkey/key.c optional key -netkey/key_debug.c optional key_debug +netkey/key.c optional ipsec +netkey/key_debug.c optional ipsec +netkey/keysock.c optional ipsec netnatm/natm.c optional natm netnatm/natm_pcb.c optional natm netnatm/natm_proto.c optional natm diff --git a/sys/conf/options b/sys/conf/options index 8b62b35..0ffb8f6 100644 --- a/sys/conf/options +++ b/sys/conf/options @@ -231,6 +231,10 @@ BRIDGE opt_bdg.h MROUTING opt_mrouting.h INET opt_inet.h INET6 opt_inet6.h +IPSEC opt_ipsec.h +IPSEC_ESP opt_ipsec.h +IPSEC_DEBUG opt_ipsec.h +IPSEC_IPV6FWD opt_ipsec.h IPDIVERT DUMMYNET opt_ipdn.h IPFILTER opt_ipfilter.h diff --git a/sys/crypto/blowfish/bf_cbc.c b/sys/crypto/blowfish/bf_cbc.c new file mode 100644 index 0000000..47092cb --- /dev/null +++ b/sys/crypto/blowfish/bf_cbc.c @@ -0,0 +1,150 @@ +/* crypto/bf/bf_cbc.c */ +/* Copyright (C) 1995-1997 Eric Young (eay@mincom.oz.au) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@mincom.oz.au). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@mincom.oz.au). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@mincom.oz.au)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@mincom.oz.au)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 AUTHOR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + * + * $FreeBSD$ + */ + +#include <crypto/blowfish/blowfish.h> +#include <crypto/blowfish/bf_locl.h> + +void BF_cbc_encrypt(in, out, length, ks, iv, encrypt) +unsigned char *in; +unsigned char *out; +long length; +BF_KEY *ks; +unsigned char *iv; +int encrypt; + { + register BF_LONG tin0,tin1; + register BF_LONG tout0,tout1,xor0,xor1; + register long l=length; + BF_LONG tin[2]; + + if (encrypt) + { + n2l(iv,tout0); + n2l(iv,tout1); + iv-=8; + for (l-=8; l>=0; l-=8) + { + n2l(in,tin0); + n2l(in,tin1); + tin0^=tout0; + tin1^=tout1; + tin[0]=tin0; + tin[1]=tin1; + BF_encrypt(tin,ks,BF_ENCRYPT); + tout0=tin[0]; + tout1=tin[1]; + l2n(tout0,out); + l2n(tout1,out); + } + if (l != -8) + { + n2ln(in,tin0,tin1,l+8); + tin0^=tout0; + tin1^=tout1; + tin[0]=tin0; + tin[1]=tin1; + BF_encrypt(tin,ks,BF_ENCRYPT); + tout0=tin[0]; + tout1=tin[1]; + l2n(tout0,out); + l2n(tout1,out); + } + l2n(tout0,iv); + l2n(tout1,iv); + } + else + { + n2l(iv,xor0); + n2l(iv,xor1); + iv-=8; + for (l-=8; l>=0; l-=8) + { + n2l(in,tin0); + n2l(in,tin1); + tin[0]=tin0; + tin[1]=tin1; + BF_encrypt(tin,ks,BF_DECRYPT); + tout0=tin[0]^xor0; + tout1=tin[1]^xor1; + l2n(tout0,out); + l2n(tout1,out); + xor0=tin0; + xor1=tin1; + } + if (l != -8) + { + n2l(in,tin0); + n2l(in,tin1); + tin[0]=tin0; + tin[1]=tin1; + BF_encrypt(tin,ks,BF_DECRYPT); + tout0=tin[0]^xor0; + tout1=tin[1]^xor1; + l2nn(tout0,tout1,out,l+8); + xor0=tin0; + xor1=tin1; + } + l2n(xor0,iv); + l2n(xor1,iv); + } + tin0=tin1=tout0=tout1=xor0=xor1=0; + tin[0]=tin[1]=0; + } + diff --git a/sys/crypto/blowfish/bf_cbc_m.c b/sys/crypto/blowfish/bf_cbc_m.c new file mode 100644 index 0000000..5180233 --- /dev/null +++ b/sys/crypto/blowfish/bf_cbc_m.c @@ -0,0 +1,341 @@ +/* + * heavily modified to accept mbuf, by Jun-ichiro itojun Itoh + * <itojun@itojun.org>, 1997. + */ +/* crypto/bf/bf_cbc.c */ +/* Copyright (C) 1995-1997 Eric Young (eay@mincom.oz.au) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@mincom.oz.au). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@mincom.oz.au). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@mincom.oz.au)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@mincom.oz.au)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 AUTHOR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + * + * $FreeBSD$ + */ + +#include <sys/param.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/systm.h> + +#include <crypto/blowfish/blowfish.h> +#include <crypto/blowfish/bf_locl.h> + +#define panic(x) {printf(x); return;} + +void BF_cbc_encrypt_m(m0, skip, length, key, iv, mode) + struct mbuf *m0; + int skip; + int length; + BF_KEY *key; + unsigned char *iv; + int mode; +{ + u_int8_t inbuf[8], outbuf[8]; + struct mbuf *m; + size_t off; + register BF_LONG tin0, tin1; + register BF_LONG tout0, tout1; + BF_LONG tin[2]; + + /* sanity checks */ + if (m0->m_pkthdr.len < skip) { + printf("mbuf length < skip\n"); + return; + } + if (m0->m_pkthdr.len < length) { + printf("mbuf length < encrypt length\n"); + return; + } + if (m0->m_pkthdr.len < skip + length) { + printf("mbuf length < skip + encrypt length\n"); + return; + } + if (length % 8) { + printf("length is not multiple of 8\n"); + return; + } + + m = m0; + off = 0; + + /* skip over the header */ + while (skip) { + if (!m) + panic("mbuf chain?\n"); + if (m->m_len <= skip) { + skip -= m->m_len; + m = m->m_next; + off = 0; + } else { + off = skip; + skip = 0; + } + } + + /* initialize */ + tin0 = tin1 = tout0 = tout1 = 0; + tin[0] = tin[1] = 0; + + if (mode == BF_ENCRYPT) { + u_int8_t *in, *out; + + n2l(iv, tout0); + n2l(iv, tout1); + + while (0 < length) { + if (!m) + panic("mbuf chain?\n"); + + /* + * copy the source into input buffer. + * don't update off or m, since we need to use them * later. + */ + if (off + 8 <= m->m_len) + bcopy(mtod(m, u_int8_t *) + off, &inbuf[0], 8); + else { + struct mbuf *n; + size_t noff; + u_int8_t *p; + u_int8_t *in; + + n = m; + noff = off; + p = mtod(n, u_int8_t *) + noff; + + in = &inbuf[0]; + while (in - &inbuf[0] < 8) { + if (!p) + panic("mbuf chain?\n"); + + *in++ = *p++; + noff++; + if (noff < n->m_len) + continue; + do { + n = n->m_next; + } while (n && ! n->m_len); + noff = 0; + if (n) + p = mtod(n, u_int8_t *) + noff; + else + p = NULL; + } + } + + in = &inbuf[0]; + out = &outbuf[0]; + n2l(in, tin0); + n2l(in, tin1); + + tin0 ^= tout0; tin[0] = tin0; + tin1 ^= tout1; tin[1] = tin1; + BF_encrypt(tin, key, BF_ENCRYPT); + tout0 = tin[0]; l2n(tout0, out); + tout1 = tin[1]; l2n(tout1, out); + + /* + * copy the output buffer into the result. + * need to update off and m. + */ + if (off + 8 < m->m_len) { + bcopy(&outbuf[0], mtod(m, u_int8_t *) + off, 8); + off += 8; + } else if (off + 8 == m->m_len) { + bcopy(&outbuf[0], mtod(m, u_int8_t *) + off, 8); + do { + m = m->m_next; + } while (m && ! m->m_len); + off = 0; + } else { + struct mbuf *n; + size_t noff; + u_int8_t *p; + u_int8_t *out; + + n = m; + noff = off; + p = mtod(n, u_int8_t *) + noff; + + out = &outbuf[0]; + while (out - &outbuf[0] < 8) { + if (!p) + panic("mbuf chain?"); + *p++ = *out++; + noff++; + if (noff < n->m_len) + continue; + do { + n = n->m_next; + } while (n && ! n->m_len); + noff = 0; + if (n) + p = mtod(n, u_int8_t *) + noff; + else + p = NULL; + } + + m = n; + off = noff; + } + + length -= 8; + } + } else if (mode == BF_DECRYPT) { + register BF_LONG xor0, xor1; + u_int8_t *in, *out; + + xor0 = xor1 = 0; + n2l(iv, xor0); + n2l(iv, xor1); + + while (0 < length) { + if (!m) + panic("mbuf chain?\n"); + + /* + * copy the source into input buffer. + * don't update off or m, since we need to use them * later. + */ + if (off + 8 <= m->m_len) + bcopy(mtod(m, u_int8_t *) + off, &inbuf[0], 8); + else { + struct mbuf *n; + size_t noff; + u_int8_t *p; + u_int8_t *in; + + n = m; + noff = off; + p = mtod(n, u_int8_t *) + noff; + + in = &inbuf[0]; + while (in - &inbuf[0] < 8) { + if (!p) + panic("mbuf chain?\n"); + *in++ = *p++; + noff++; + if (noff < n->m_len) + continue; + do { + n = n->m_next; + } while (n && ! n->m_len); + noff = 0; + if (n) + p = mtod(n, u_int8_t *) + noff; + else + p = NULL; + } + } + + in = &inbuf[0]; + out = &outbuf[0]; + n2l(in, tin0); tin[0] = tin0; + n2l(in, tin1); tin[1] = tin1; + BF_encrypt(tin, key, BF_DECRYPT); + tout0 = tin[0] ^ xor0; + tout1 = tin[1] ^ xor1; + l2n(tout0, out); + l2n(tout1, out); + xor0 = tin0; + xor1 = tin1; + + + /* + * copy the output buffer into the result. + * need to update off and m. + */ + if (off + 8 < m->m_len) { + bcopy(&outbuf[0], mtod(m, u_int8_t *) + off, 8); + off += 8; + } else if (off + 8 == m->m_len) { + bcopy(&outbuf[0], mtod(m, u_int8_t *) + off, 8); + do { + m = m->m_next; + } while (m && ! m->m_len); + off = 0; + } else { + struct mbuf *n; + size_t noff; + u_int8_t *p; + u_int8_t *out; + + n = m; + noff = off; + p = mtod(n, u_int8_t *) + noff; + + out = &outbuf[0]; + while (out - &outbuf[0] < 8) { + if (!p) + panic("mbuf chain?\n"); + *p++ = *out++; + noff++; + if (noff < n->m_len) + continue; + do { + n = n->m_next; + } while (n && ! n->m_len); + noff = 0; + if (n) + p = mtod(n, u_int8_t *) + noff; + else + p = NULL; + } + + m = n; + off = noff; + } + + length -= 8; + } + } +} diff --git a/sys/crypto/blowfish/bf_enc.c b/sys/crypto/blowfish/bf_enc.c new file mode 100644 index 0000000..b24e538 --- /dev/null +++ b/sys/crypto/blowfish/bf_enc.c @@ -0,0 +1,142 @@ +/* crypto/bf/bf_enc.c */ +/* Copyright (C) 1995-1997 Eric Young (eay@mincom.oz.au) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@mincom.oz.au). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@mincom.oz.au). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@mincom.oz.au)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@mincom.oz.au)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 AUTHOR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + * + * $FreeBSD$ + */ + +#include <crypto/blowfish/blowfish.h> +#include <crypto/blowfish/bf_locl.h> + +/* Blowfish as implemented from 'Blowfish: Springer-Verlag paper' + * (From LECTURE NOTES IN COIMPUTER SCIENCE 809, FAST SOFTWARE ENCRYPTION, + * CAMBRIDGE SECURITY WORKSHOP, CAMBRIDGE, U.K., DECEMBER 9-11, 1993) + */ + +#if (BF_ROUNDS != 16) && (BF_ROUNDS != 20) +If you set BF_ROUNDS to some value other than 16 or 20, you will have +to modify the code. +#endif + +void BF_encrypt(data,key,encrypt) +BF_LONG *data; +BF_KEY *key; +int encrypt; + { + register BF_LONG l,r,*p,*s; + + p=key->P; + s= &(key->S[0]); + l=data[0]; + r=data[1]; + + if (encrypt) + { + l^=p[0]; + BF_ENC(r,l,s,p[ 1]); + BF_ENC(l,r,s,p[ 2]); + BF_ENC(r,l,s,p[ 3]); + BF_ENC(l,r,s,p[ 4]); + BF_ENC(r,l,s,p[ 5]); + BF_ENC(l,r,s,p[ 6]); + BF_ENC(r,l,s,p[ 7]); + BF_ENC(l,r,s,p[ 8]); + BF_ENC(r,l,s,p[ 9]); + BF_ENC(l,r,s,p[10]); + BF_ENC(r,l,s,p[11]); + BF_ENC(l,r,s,p[12]); + BF_ENC(r,l,s,p[13]); + BF_ENC(l,r,s,p[14]); + BF_ENC(r,l,s,p[15]); + BF_ENC(l,r,s,p[16]); +#if BF_ROUNDS == 20 + BF_ENC(r,l,s,p[17]); + BF_ENC(l,r,s,p[18]); + BF_ENC(r,l,s,p[19]); + BF_ENC(l,r,s,p[20]); +#endif + r^=p[BF_ROUNDS+1]; + } + else + { + l^=p[BF_ROUNDS+1]; +#if BF_ROUNDS == 20 + BF_ENC(r,l,s,p[20]); + BF_ENC(l,r,s,p[19]); + BF_ENC(r,l,s,p[18]); + BF_ENC(l,r,s,p[17]); +#endif + BF_ENC(r,l,s,p[16]); + BF_ENC(l,r,s,p[15]); + BF_ENC(r,l,s,p[14]); + BF_ENC(l,r,s,p[13]); + BF_ENC(r,l,s,p[12]); + BF_ENC(l,r,s,p[11]); + BF_ENC(r,l,s,p[10]); + BF_ENC(l,r,s,p[ 9]); + BF_ENC(r,l,s,p[ 8]); + BF_ENC(l,r,s,p[ 7]); + BF_ENC(r,l,s,p[ 6]); + BF_ENC(l,r,s,p[ 5]); + BF_ENC(r,l,s,p[ 4]); + BF_ENC(l,r,s,p[ 3]); + BF_ENC(r,l,s,p[ 2]); + BF_ENC(l,r,s,p[ 1]); + r^=p[0]; + } + data[1]=l&0xffffffff; + data[0]=r&0xffffffff; + } diff --git a/sys/crypto/blowfish/bf_locl.h b/sys/crypto/blowfish/bf_locl.h new file mode 100644 index 0000000..e0b62f1 --- /dev/null +++ b/sys/crypto/blowfish/bf_locl.h @@ -0,0 +1,217 @@ +/* crypto/bf/bf_local.h */ +/* Copyright (C) 1995-1997 Eric Young (eay@mincom.oz.au) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@mincom.oz.au). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@mincom.oz.au). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@mincom.oz.au)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@mincom.oz.au)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 AUTHOR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + * + * $FreeBSD$ + */ +/* WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING + * + * Always modify bf_locl.org since bf_locl.h is automatically generated from + * it during SSLeay configuration. + * + * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING + */ + +#undef c2l +#define c2l(c,l) (l =((unsigned long)(*((c)++))) , \ + l|=((unsigned long)(*((c)++)))<< 8L, \ + l|=((unsigned long)(*((c)++)))<<16L, \ + l|=((unsigned long)(*((c)++)))<<24L) + +/* NOTE - c is not incremented as per c2l */ +#undef c2ln +#define c2ln(c,l1,l2,n) { \ + c+=n; \ + l1=l2=0; \ + switch (n) { \ + case 8: l2 =((unsigned long)(*(--(c))))<<24L; \ + case 7: l2|=((unsigned long)(*(--(c))))<<16L; \ + case 6: l2|=((unsigned long)(*(--(c))))<< 8L; \ + case 5: l2|=((unsigned long)(*(--(c)))); \ + case 4: l1 =((unsigned long)(*(--(c))))<<24L; \ + case 3: l1|=((unsigned long)(*(--(c))))<<16L; \ + case 2: l1|=((unsigned long)(*(--(c))))<< 8L; \ + case 1: l1|=((unsigned long)(*(--(c)))); \ + } \ + } + +#undef l2c +#define l2c(l,c) (*((c)++)=(unsigned char)(((l) )&0xff), \ + *((c)++)=(unsigned char)(((l)>> 8L)&0xff), \ + *((c)++)=(unsigned char)(((l)>>16L)&0xff), \ + *((c)++)=(unsigned char)(((l)>>24L)&0xff)) + +/* NOTE - c is not incremented as per l2c */ +#undef l2cn +#define l2cn(l1,l2,c,n) { \ + c+=n; \ + switch (n) { \ + case 8: *(--(c))=(unsigned char)(((l2)>>24L)&0xff); \ + case 7: *(--(c))=(unsigned char)(((l2)>>16L)&0xff); \ + case 6: *(--(c))=(unsigned char)(((l2)>> 8L)&0xff); \ + case 5: *(--(c))=(unsigned char)(((l2) )&0xff); \ + case 4: *(--(c))=(unsigned char)(((l1)>>24L)&0xff); \ + case 3: *(--(c))=(unsigned char)(((l1)>>16L)&0xff); \ + case 2: *(--(c))=(unsigned char)(((l1)>> 8L)&0xff); \ + case 1: *(--(c))=(unsigned char)(((l1) )&0xff); \ + } \ + } + +/* NOTE - c is not incremented as per n2l */ +#define n2ln(c,l1,l2,n) { \ + c+=n; \ + l1=l2=0; \ + switch (n) { \ + case 8: l2 =((unsigned long)(*(--(c)))) ; \ + case 7: l2|=((unsigned long)(*(--(c))))<< 8; \ + case 6: l2|=((unsigned long)(*(--(c))))<<16; \ + case 5: l2|=((unsigned long)(*(--(c))))<<24; \ + case 4: l1 =((unsigned long)(*(--(c)))) ; \ + case 3: l1|=((unsigned long)(*(--(c))))<< 8; \ + case 2: l1|=((unsigned long)(*(--(c))))<<16; \ + case 1: l1|=((unsigned long)(*(--(c))))<<24; \ + } \ + } + +/* NOTE - c is not incremented as per l2n */ +#define l2nn(l1,l2,c,n) { \ + c+=n; \ + switch (n) { \ + case 8: *(--(c))=(unsigned char)(((l2) )&0xff); \ + case 7: *(--(c))=(unsigned char)(((l2)>> 8)&0xff); \ + case 6: *(--(c))=(unsigned char)(((l2)>>16)&0xff); \ + case 5: *(--(c))=(unsigned char)(((l2)>>24)&0xff); \ + case 4: *(--(c))=(unsigned char)(((l1) )&0xff); \ + case 3: *(--(c))=(unsigned char)(((l1)>> 8)&0xff); \ + case 2: *(--(c))=(unsigned char)(((l1)>>16)&0xff); \ + case 1: *(--(c))=(unsigned char)(((l1)>>24)&0xff); \ + } \ + } + +#undef n2l +#define n2l(c,l) (l =((unsigned long)(*((c)++)))<<24L, \ + l|=((unsigned long)(*((c)++)))<<16L, \ + l|=((unsigned long)(*((c)++)))<< 8L, \ + l|=((unsigned long)(*((c)++)))) + +#undef l2n +#define l2n(l,c) (*((c)++)=(unsigned char)(((l)>>24L)&0xff), \ + *((c)++)=(unsigned char)(((l)>>16L)&0xff), \ + *((c)++)=(unsigned char)(((l)>> 8L)&0xff), \ + *((c)++)=(unsigned char)(((l) )&0xff)) + +/* This is actually a big endian algorithm, the most significate byte + * is used to lookup array 0 */ + +/* use BF_PTR2 for intel boxes, + * BF_PTR for sparc and MIPS/SGI + * use nothing for Alpha and HP. + */ +#if !defined(BF_PTR) && !defined(BF_PTR2) +#undef BF_PTR +#endif + +#define BF_M 0x3fc +#define BF_0 22L +#define BF_1 14L +#define BF_2 6L +#define BF_3 2L /* left shift */ + +#if defined(BF_PTR2) + +/* This is basically a special pentium verson */ +#define BF_ENC(LL,R,S,P) \ + { \ + BF_LONG t,u,v; \ + u=R>>BF_0; \ + v=R>>BF_1; \ + u&=BF_M; \ + v&=BF_M; \ + t= *(BF_LONG *)((unsigned char *)&(S[ 0])+u); \ + u=R>>BF_2; \ + t+= *(BF_LONG *)((unsigned char *)&(S[256])+v); \ + v=R<<BF_3; \ + u&=BF_M; \ + v&=BF_M; \ + t^= *(BF_LONG *)((unsigned char *)&(S[512])+u); \ + LL^=P; \ + t+= *(BF_LONG *)((unsigned char *)&(S[768])+v); \ + LL^=t; \ + } + +#elif defined(BF_PTR) + +/* This is normally very good */ + +#define BF_ENC(LL,R,S,P) \ + LL^=P; \ + LL^= (((*(BF_LONG *)((unsigned char *)&(S[ 0])+((R>>BF_0)&BF_M))+ \ + *(BF_LONG *)((unsigned char *)&(S[256])+((R>>BF_1)&BF_M)))^ \ + *(BF_LONG *)((unsigned char *)&(S[512])+((R>>BF_2)&BF_M)))+ \ + *(BF_LONG *)((unsigned char *)&(S[768])+((R<<BF_3)&BF_M))); +#else + +/* This will always work, even on 64 bit machines and strangly enough, + * on the Alpha it is faster than the pointer versions (both 32 and 64 + * versions of BF_LONG) */ + +#define BF_ENC(LL,R,S,P) \ + LL^=P; \ + LL^=((( S[ (R>>24L) ] + \ + S[0x0100+((R>>16L)&0xff)])^ \ + S[0x0200+((R>> 8L)&0xff)])+ \ + S[0x0300+((R )&0xff)])&0xffffffff; +#endif diff --git a/sys/crypto/blowfish/bf_pi.h b/sys/crypto/blowfish/bf_pi.h new file mode 100644 index 0000000..1a397e8 --- /dev/null +++ b/sys/crypto/blowfish/bf_pi.h @@ -0,0 +1,327 @@ +/* crypto/bf/bf_pi.h */ +/* Copyright (C) 1995-1997 Eric Young (eay@mincom.oz.au) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@mincom.oz.au). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@mincom.oz.au). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@mincom.oz.au)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@mincom.oz.au)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 AUTHOR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + * + * $FreeBSD$ + */ + +static BF_KEY bf_init= { + { + 0x243f6a88L, 0x85a308d3L, 0x13198a2eL, 0x03707344L, + 0xa4093822L, 0x299f31d0L, 0x082efa98L, 0xec4e6c89L, + 0x452821e6L, 0x38d01377L, 0xbe5466cfL, 0x34e90c6cL, + 0xc0ac29b7L, 0xc97c50ddL, 0x3f84d5b5L, 0xb5470917L, + 0x9216d5d9L, 0x8979fb1b + },{ + 0xd1310ba6L, 0x98dfb5acL, 0x2ffd72dbL, 0xd01adfb7L, + 0xb8e1afedL, 0x6a267e96L, 0xba7c9045L, 0xf12c7f99L, + 0x24a19947L, 0xb3916cf7L, 0x0801f2e2L, 0x858efc16L, + 0x636920d8L, 0x71574e69L, 0xa458fea3L, 0xf4933d7eL, + 0x0d95748fL, 0x728eb658L, 0x718bcd58L, 0x82154aeeL, + 0x7b54a41dL, 0xc25a59b5L, 0x9c30d539L, 0x2af26013L, + 0xc5d1b023L, 0x286085f0L, 0xca417918L, 0xb8db38efL, + 0x8e79dcb0L, 0x603a180eL, 0x6c9e0e8bL, 0xb01e8a3eL, + 0xd71577c1L, 0xbd314b27L, 0x78af2fdaL, 0x55605c60L, + 0xe65525f3L, 0xaa55ab94L, 0x57489862L, 0x63e81440L, + 0x55ca396aL, 0x2aab10b6L, 0xb4cc5c34L, 0x1141e8ceL, + 0xa15486afL, 0x7c72e993L, 0xb3ee1411L, 0x636fbc2aL, + 0x2ba9c55dL, 0x741831f6L, 0xce5c3e16L, 0x9b87931eL, + 0xafd6ba33L, 0x6c24cf5cL, 0x7a325381L, 0x28958677L, + 0x3b8f4898L, 0x6b4bb9afL, 0xc4bfe81bL, 0x66282193L, + 0x61d809ccL, 0xfb21a991L, 0x487cac60L, 0x5dec8032L, + 0xef845d5dL, 0xe98575b1L, 0xdc262302L, 0xeb651b88L, + 0x23893e81L, 0xd396acc5L, 0x0f6d6ff3L, 0x83f44239L, + 0x2e0b4482L, 0xa4842004L, 0x69c8f04aL, 0x9e1f9b5eL, + 0x21c66842L, 0xf6e96c9aL, 0x670c9c61L, 0xabd388f0L, + 0x6a51a0d2L, 0xd8542f68L, 0x960fa728L, 0xab5133a3L, + 0x6eef0b6cL, 0x137a3be4L, 0xba3bf050L, 0x7efb2a98L, + 0xa1f1651dL, 0x39af0176L, 0x66ca593eL, 0x82430e88L, + 0x8cee8619L, 0x456f9fb4L, 0x7d84a5c3L, 0x3b8b5ebeL, + 0xe06f75d8L, 0x85c12073L, 0x401a449fL, 0x56c16aa6L, + 0x4ed3aa62L, 0x363f7706L, 0x1bfedf72L, 0x429b023dL, + 0x37d0d724L, 0xd00a1248L, 0xdb0fead3L, 0x49f1c09bL, + 0x075372c9L, 0x80991b7bL, 0x25d479d8L, 0xf6e8def7L, + 0xe3fe501aL, 0xb6794c3bL, 0x976ce0bdL, 0x04c006baL, + 0xc1a94fb6L, 0x409f60c4L, 0x5e5c9ec2L, 0x196a2463L, + 0x68fb6fafL, 0x3e6c53b5L, 0x1339b2ebL, 0x3b52ec6fL, + 0x6dfc511fL, 0x9b30952cL, 0xcc814544L, 0xaf5ebd09L, + 0xbee3d004L, 0xde334afdL, 0x660f2807L, 0x192e4bb3L, + 0xc0cba857L, 0x45c8740fL, 0xd20b5f39L, 0xb9d3fbdbL, + 0x5579c0bdL, 0x1a60320aL, 0xd6a100c6L, 0x402c7279L, + 0x679f25feL, 0xfb1fa3ccL, 0x8ea5e9f8L, 0xdb3222f8L, + 0x3c7516dfL, 0xfd616b15L, 0x2f501ec8L, 0xad0552abL, + 0x323db5faL, 0xfd238760L, 0x53317b48L, 0x3e00df82L, + 0x9e5c57bbL, 0xca6f8ca0L, 0x1a87562eL, 0xdf1769dbL, + 0xd542a8f6L, 0x287effc3L, 0xac6732c6L, 0x8c4f5573L, + 0x695b27b0L, 0xbbca58c8L, 0xe1ffa35dL, 0xb8f011a0L, + 0x10fa3d98L, 0xfd2183b8L, 0x4afcb56cL, 0x2dd1d35bL, + 0x9a53e479L, 0xb6f84565L, 0xd28e49bcL, 0x4bfb9790L, + 0xe1ddf2daL, 0xa4cb7e33L, 0x62fb1341L, 0xcee4c6e8L, + 0xef20cadaL, 0x36774c01L, 0xd07e9efeL, 0x2bf11fb4L, + 0x95dbda4dL, 0xae909198L, 0xeaad8e71L, 0x6b93d5a0L, + 0xd08ed1d0L, 0xafc725e0L, 0x8e3c5b2fL, 0x8e7594b7L, + 0x8ff6e2fbL, 0xf2122b64L, 0x8888b812L, 0x900df01cL, + 0x4fad5ea0L, 0x688fc31cL, 0xd1cff191L, 0xb3a8c1adL, + 0x2f2f2218L, 0xbe0e1777L, 0xea752dfeL, 0x8b021fa1L, + 0xe5a0cc0fL, 0xb56f74e8L, 0x18acf3d6L, 0xce89e299L, + 0xb4a84fe0L, 0xfd13e0b7L, 0x7cc43b81L, 0xd2ada8d9L, + 0x165fa266L, 0x80957705L, 0x93cc7314L, 0x211a1477L, + 0xe6ad2065L, 0x77b5fa86L, 0xc75442f5L, 0xfb9d35cfL, + 0xebcdaf0cL, 0x7b3e89a0L, 0xd6411bd3L, 0xae1e7e49L, + 0x00250e2dL, 0x2071b35eL, 0x226800bbL, 0x57b8e0afL, + 0x2464369bL, 0xf009b91eL, 0x5563911dL, 0x59dfa6aaL, + 0x78c14389L, 0xd95a537fL, 0x207d5ba2L, 0x02e5b9c5L, + 0x83260376L, 0x6295cfa9L, 0x11c81968L, 0x4e734a41L, + 0xb3472dcaL, 0x7b14a94aL, 0x1b510052L, 0x9a532915L, + 0xd60f573fL, 0xbc9bc6e4L, 0x2b60a476L, 0x81e67400L, + 0x08ba6fb5L, 0x571be91fL, 0xf296ec6bL, 0x2a0dd915L, + 0xb6636521L, 0xe7b9f9b6L, 0xff34052eL, 0xc5855664L, + 0x53b02d5dL, 0xa99f8fa1L, 0x08ba4799L, 0x6e85076aL, + 0x4b7a70e9L, 0xb5b32944L, 0xdb75092eL, 0xc4192623L, + 0xad6ea6b0L, 0x49a7df7dL, 0x9cee60b8L, 0x8fedb266L, + 0xecaa8c71L, 0x699a17ffL, 0x5664526cL, 0xc2b19ee1L, + 0x193602a5L, 0x75094c29L, 0xa0591340L, 0xe4183a3eL, + 0x3f54989aL, 0x5b429d65L, 0x6b8fe4d6L, 0x99f73fd6L, + 0xa1d29c07L, 0xefe830f5L, 0x4d2d38e6L, 0xf0255dc1L, + 0x4cdd2086L, 0x8470eb26L, 0x6382e9c6L, 0x021ecc5eL, + 0x09686b3fL, 0x3ebaefc9L, 0x3c971814L, 0x6b6a70a1L, + 0x687f3584L, 0x52a0e286L, 0xb79c5305L, 0xaa500737L, + 0x3e07841cL, 0x7fdeae5cL, 0x8e7d44ecL, 0x5716f2b8L, + 0xb03ada37L, 0xf0500c0dL, 0xf01c1f04L, 0x0200b3ffL, + 0xae0cf51aL, 0x3cb574b2L, 0x25837a58L, 0xdc0921bdL, + 0xd19113f9L, 0x7ca92ff6L, 0x94324773L, 0x22f54701L, + 0x3ae5e581L, 0x37c2dadcL, 0xc8b57634L, 0x9af3dda7L, + 0xa9446146L, 0x0fd0030eL, 0xecc8c73eL, 0xa4751e41L, + 0xe238cd99L, 0x3bea0e2fL, 0x3280bba1L, 0x183eb331L, + 0x4e548b38L, 0x4f6db908L, 0x6f420d03L, 0xf60a04bfL, + 0x2cb81290L, 0x24977c79L, 0x5679b072L, 0xbcaf89afL, + 0xde9a771fL, 0xd9930810L, 0xb38bae12L, 0xdccf3f2eL, + 0x5512721fL, 0x2e6b7124L, 0x501adde6L, 0x9f84cd87L, + 0x7a584718L, 0x7408da17L, 0xbc9f9abcL, 0xe94b7d8cL, + 0xec7aec3aL, 0xdb851dfaL, 0x63094366L, 0xc464c3d2L, + 0xef1c1847L, 0x3215d908L, 0xdd433b37L, 0x24c2ba16L, + 0x12a14d43L, 0x2a65c451L, 0x50940002L, 0x133ae4ddL, + 0x71dff89eL, 0x10314e55L, 0x81ac77d6L, 0x5f11199bL, + 0x043556f1L, 0xd7a3c76bL, 0x3c11183bL, 0x5924a509L, + 0xf28fe6edL, 0x97f1fbfaL, 0x9ebabf2cL, 0x1e153c6eL, + 0x86e34570L, 0xeae96fb1L, 0x860e5e0aL, 0x5a3e2ab3L, + 0x771fe71cL, 0x4e3d06faL, 0x2965dcb9L, 0x99e71d0fL, + 0x803e89d6L, 0x5266c825L, 0x2e4cc978L, 0x9c10b36aL, + 0xc6150ebaL, 0x94e2ea78L, 0xa5fc3c53L, 0x1e0a2df4L, + 0xf2f74ea7L, 0x361d2b3dL, 0x1939260fL, 0x19c27960L, + 0x5223a708L, 0xf71312b6L, 0xebadfe6eL, 0xeac31f66L, + 0xe3bc4595L, 0xa67bc883L, 0xb17f37d1L, 0x018cff28L, + 0xc332ddefL, 0xbe6c5aa5L, 0x65582185L, 0x68ab9802L, + 0xeecea50fL, 0xdb2f953bL, 0x2aef7dadL, 0x5b6e2f84L, + 0x1521b628L, 0x29076170L, 0xecdd4775L, 0x619f1510L, + 0x13cca830L, 0xeb61bd96L, 0x0334fe1eL, 0xaa0363cfL, + 0xb5735c90L, 0x4c70a239L, 0xd59e9e0bL, 0xcbaade14L, + 0xeecc86bcL, 0x60622ca7L, 0x9cab5cabL, 0xb2f3846eL, + 0x648b1eafL, 0x19bdf0caL, 0xa02369b9L, 0x655abb50L, + 0x40685a32L, 0x3c2ab4b3L, 0x319ee9d5L, 0xc021b8f7L, + 0x9b540b19L, 0x875fa099L, 0x95f7997eL, 0x623d7da8L, + 0xf837889aL, 0x97e32d77L, 0x11ed935fL, 0x16681281L, + 0x0e358829L, 0xc7e61fd6L, 0x96dedfa1L, 0x7858ba99L, + 0x57f584a5L, 0x1b227263L, 0x9b83c3ffL, 0x1ac24696L, + 0xcdb30aebL, 0x532e3054L, 0x8fd948e4L, 0x6dbc3128L, + 0x58ebf2efL, 0x34c6ffeaL, 0xfe28ed61L, 0xee7c3c73L, + 0x5d4a14d9L, 0xe864b7e3L, 0x42105d14L, 0x203e13e0L, + 0x45eee2b6L, 0xa3aaabeaL, 0xdb6c4f15L, 0xfacb4fd0L, + 0xc742f442L, 0xef6abbb5L, 0x654f3b1dL, 0x41cd2105L, + 0xd81e799eL, 0x86854dc7L, 0xe44b476aL, 0x3d816250L, + 0xcf62a1f2L, 0x5b8d2646L, 0xfc8883a0L, 0xc1c7b6a3L, + 0x7f1524c3L, 0x69cb7492L, 0x47848a0bL, 0x5692b285L, + 0x095bbf00L, 0xad19489dL, 0x1462b174L, 0x23820e00L, + 0x58428d2aL, 0x0c55f5eaL, 0x1dadf43eL, 0x233f7061L, + 0x3372f092L, 0x8d937e41L, 0xd65fecf1L, 0x6c223bdbL, + 0x7cde3759L, 0xcbee7460L, 0x4085f2a7L, 0xce77326eL, + 0xa6078084L, 0x19f8509eL, 0xe8efd855L, 0x61d99735L, + 0xa969a7aaL, 0xc50c06c2L, 0x5a04abfcL, 0x800bcadcL, + 0x9e447a2eL, 0xc3453484L, 0xfdd56705L, 0x0e1e9ec9L, + 0xdb73dbd3L, 0x105588cdL, 0x675fda79L, 0xe3674340L, + 0xc5c43465L, 0x713e38d8L, 0x3d28f89eL, 0xf16dff20L, + 0x153e21e7L, 0x8fb03d4aL, 0xe6e39f2bL, 0xdb83adf7L, + 0xe93d5a68L, 0x948140f7L, 0xf64c261cL, 0x94692934L, + 0x411520f7L, 0x7602d4f7L, 0xbcf46b2eL, 0xd4a20068L, + 0xd4082471L, 0x3320f46aL, 0x43b7d4b7L, 0x500061afL, + 0x1e39f62eL, 0x97244546L, 0x14214f74L, 0xbf8b8840L, + 0x4d95fc1dL, 0x96b591afL, 0x70f4ddd3L, 0x66a02f45L, + 0xbfbc09ecL, 0x03bd9785L, 0x7fac6dd0L, 0x31cb8504L, + 0x96eb27b3L, 0x55fd3941L, 0xda2547e6L, 0xabca0a9aL, + 0x28507825L, 0x530429f4L, 0x0a2c86daL, 0xe9b66dfbL, + 0x68dc1462L, 0xd7486900L, 0x680ec0a4L, 0x27a18deeL, + 0x4f3ffea2L, 0xe887ad8cL, 0xb58ce006L, 0x7af4d6b6L, + 0xaace1e7cL, 0xd3375fecL, 0xce78a399L, 0x406b2a42L, + 0x20fe9e35L, 0xd9f385b9L, 0xee39d7abL, 0x3b124e8bL, + 0x1dc9faf7L, 0x4b6d1856L, 0x26a36631L, 0xeae397b2L, + 0x3a6efa74L, 0xdd5b4332L, 0x6841e7f7L, 0xca7820fbL, + 0xfb0af54eL, 0xd8feb397L, 0x454056acL, 0xba489527L, + 0x55533a3aL, 0x20838d87L, 0xfe6ba9b7L, 0xd096954bL, + 0x55a867bcL, 0xa1159a58L, 0xcca92963L, 0x99e1db33L, + 0xa62a4a56L, 0x3f3125f9L, 0x5ef47e1cL, 0x9029317cL, + 0xfdf8e802L, 0x04272f70L, 0x80bb155cL, 0x05282ce3L, + 0x95c11548L, 0xe4c66d22L, 0x48c1133fL, 0xc70f86dcL, + 0x07f9c9eeL, 0x41041f0fL, 0x404779a4L, 0x5d886e17L, + 0x325f51ebL, 0xd59bc0d1L, 0xf2bcc18fL, 0x41113564L, + 0x257b7834L, 0x602a9c60L, 0xdff8e8a3L, 0x1f636c1bL, + 0x0e12b4c2L, 0x02e1329eL, 0xaf664fd1L, 0xcad18115L, + 0x6b2395e0L, 0x333e92e1L, 0x3b240b62L, 0xeebeb922L, + 0x85b2a20eL, 0xe6ba0d99L, 0xde720c8cL, 0x2da2f728L, + 0xd0127845L, 0x95b794fdL, 0x647d0862L, 0xe7ccf5f0L, + 0x5449a36fL, 0x877d48faL, 0xc39dfd27L, 0xf33e8d1eL, + 0x0a476341L, 0x992eff74L, 0x3a6f6eabL, 0xf4f8fd37L, + 0xa812dc60L, 0xa1ebddf8L, 0x991be14cL, 0xdb6e6b0dL, + 0xc67b5510L, 0x6d672c37L, 0x2765d43bL, 0xdcd0e804L, + 0xf1290dc7L, 0xcc00ffa3L, 0xb5390f92L, 0x690fed0bL, + 0x667b9ffbL, 0xcedb7d9cL, 0xa091cf0bL, 0xd9155ea3L, + 0xbb132f88L, 0x515bad24L, 0x7b9479bfL, 0x763bd6ebL, + 0x37392eb3L, 0xcc115979L, 0x8026e297L, 0xf42e312dL, + 0x6842ada7L, 0xc66a2b3bL, 0x12754cccL, 0x782ef11cL, + 0x6a124237L, 0xb79251e7L, 0x06a1bbe6L, 0x4bfb6350L, + 0x1a6b1018L, 0x11caedfaL, 0x3d25bdd8L, 0xe2e1c3c9L, + 0x44421659L, 0x0a121386L, 0xd90cec6eL, 0xd5abea2aL, + 0x64af674eL, 0xda86a85fL, 0xbebfe988L, 0x64e4c3feL, + 0x9dbc8057L, 0xf0f7c086L, 0x60787bf8L, 0x6003604dL, + 0xd1fd8346L, 0xf6381fb0L, 0x7745ae04L, 0xd736fcccL, + 0x83426b33L, 0xf01eab71L, 0xb0804187L, 0x3c005e5fL, + 0x77a057beL, 0xbde8ae24L, 0x55464299L, 0xbf582e61L, + 0x4e58f48fL, 0xf2ddfda2L, 0xf474ef38L, 0x8789bdc2L, + 0x5366f9c3L, 0xc8b38e74L, 0xb475f255L, 0x46fcd9b9L, + 0x7aeb2661L, 0x8b1ddf84L, 0x846a0e79L, 0x915f95e2L, + 0x466e598eL, 0x20b45770L, 0x8cd55591L, 0xc902de4cL, + 0xb90bace1L, 0xbb8205d0L, 0x11a86248L, 0x7574a99eL, + 0xb77f19b6L, 0xe0a9dc09L, 0x662d09a1L, 0xc4324633L, + 0xe85a1f02L, 0x09f0be8cL, 0x4a99a025L, 0x1d6efe10L, + 0x1ab93d1dL, 0x0ba5a4dfL, 0xa186f20fL, 0x2868f169L, + 0xdcb7da83L, 0x573906feL, 0xa1e2ce9bL, 0x4fcd7f52L, + 0x50115e01L, 0xa70683faL, 0xa002b5c4L, 0x0de6d027L, + 0x9af88c27L, 0x773f8641L, 0xc3604c06L, 0x61a806b5L, + 0xf0177a28L, 0xc0f586e0L, 0x006058aaL, 0x30dc7d62L, + 0x11e69ed7L, 0x2338ea63L, 0x53c2dd94L, 0xc2c21634L, + 0xbbcbee56L, 0x90bcb6deL, 0xebfc7da1L, 0xce591d76L, + 0x6f05e409L, 0x4b7c0188L, 0x39720a3dL, 0x7c927c24L, + 0x86e3725fL, 0x724d9db9L, 0x1ac15bb4L, 0xd39eb8fcL, + 0xed545578L, 0x08fca5b5L, 0xd83d7cd3L, 0x4dad0fc4L, + 0x1e50ef5eL, 0xb161e6f8L, 0xa28514d9L, 0x6c51133cL, + 0x6fd5c7e7L, 0x56e14ec4L, 0x362abfceL, 0xddc6c837L, + 0xd79a3234L, 0x92638212L, 0x670efa8eL, 0x406000e0L, + 0x3a39ce37L, 0xd3faf5cfL, 0xabc27737L, 0x5ac52d1bL, + 0x5cb0679eL, 0x4fa33742L, 0xd3822740L, 0x99bc9bbeL, + 0xd5118e9dL, 0xbf0f7315L, 0xd62d1c7eL, 0xc700c47bL, + 0xb78c1b6bL, 0x21a19045L, 0xb26eb1beL, 0x6a366eb4L, + 0x5748ab2fL, 0xbc946e79L, 0xc6a376d2L, 0x6549c2c8L, + 0x530ff8eeL, 0x468dde7dL, 0xd5730a1dL, 0x4cd04dc6L, + 0x2939bbdbL, 0xa9ba4650L, 0xac9526e8L, 0xbe5ee304L, + 0xa1fad5f0L, 0x6a2d519aL, 0x63ef8ce2L, 0x9a86ee22L, + 0xc089c2b8L, 0x43242ef6L, 0xa51e03aaL, 0x9cf2d0a4L, + 0x83c061baL, 0x9be96a4dL, 0x8fe51550L, 0xba645bd6L, + 0x2826a2f9L, 0xa73a3ae1L, 0x4ba99586L, 0xef5562e9L, + 0xc72fefd3L, 0xf752f7daL, 0x3f046f69L, 0x77fa0a59L, + 0x80e4a915L, 0x87b08601L, 0x9b09e6adL, 0x3b3ee593L, + 0xe990fd5aL, 0x9e34d797L, 0x2cf0b7d9L, 0x022b8b51L, + 0x96d5ac3aL, 0x017da67dL, 0xd1cf3ed6L, 0x7c7d2d28L, + 0x1f9f25cfL, 0xadf2b89bL, 0x5ad6b472L, 0x5a88f54cL, + 0xe029ac71L, 0xe019a5e6L, 0x47b0acfdL, 0xed93fa9bL, + 0xe8d3c48dL, 0x283b57ccL, 0xf8d56629L, 0x79132e28L, + 0x785f0191L, 0xed756055L, 0xf7960e44L, 0xe3d35e8cL, + 0x15056dd4L, 0x88f46dbaL, 0x03a16125L, 0x0564f0bdL, + 0xc3eb9e15L, 0x3c9057a2L, 0x97271aecL, 0xa93a072aL, + 0x1b3f6d9bL, 0x1e6321f5L, 0xf59c66fbL, 0x26dcf319L, + 0x7533d928L, 0xb155fdf5L, 0x03563482L, 0x8aba3cbbL, + 0x28517711L, 0xc20ad9f8L, 0xabcc5167L, 0xccad925fL, + 0x4de81751L, 0x3830dc8eL, 0x379d5862L, 0x9320f991L, + 0xea7a90c2L, 0xfb3e7bceL, 0x5121ce64L, 0x774fbe32L, + 0xa8b6e37eL, 0xc3293d46L, 0x48de5369L, 0x6413e680L, + 0xa2ae0810L, 0xdd6db224L, 0x69852dfdL, 0x09072166L, + 0xb39a460aL, 0x6445c0ddL, 0x586cdecfL, 0x1c20c8aeL, + 0x5bbef7ddL, 0x1b588d40L, 0xccd2017fL, 0x6bb4e3bbL, + 0xdda26a7eL, 0x3a59ff45L, 0x3e350a44L, 0xbcb4cdd5L, + 0x72eacea8L, 0xfa6484bbL, 0x8d6612aeL, 0xbf3c6f47L, + 0xd29be463L, 0x542f5d9eL, 0xaec2771bL, 0xf64e6370L, + 0x740e0d8dL, 0xe75b1357L, 0xf8721671L, 0xaf537d5dL, + 0x4040cb08L, 0x4eb4e2ccL, 0x34d2466aL, 0x0115af84L, + 0xe1b00428L, 0x95983a1dL, 0x06b89fb4L, 0xce6ea048L, + 0x6f3f3b82L, 0x3520ab82L, 0x011a1d4bL, 0x277227f8L, + 0x611560b1L, 0xe7933fdcL, 0xbb3a792bL, 0x344525bdL, + 0xa08839e1L, 0x51ce794bL, 0x2f32c9b7L, 0xa01fbac9L, + 0xe01cc87eL, 0xbcc7d1f6L, 0xcf0111c3L, 0xa1e8aac7L, + 0x1a908749L, 0xd44fbd9aL, 0xd0dadecbL, 0xd50ada38L, + 0x0339c32aL, 0xc6913667L, 0x8df9317cL, 0xe0b12b4fL, + 0xf79e59b7L, 0x43f5bb3aL, 0xf2d519ffL, 0x27d9459cL, + 0xbf97222cL, 0x15e6fc2aL, 0x0f91fc71L, 0x9b941525L, + 0xfae59361L, 0xceb69cebL, 0xc2a86459L, 0x12baa8d1L, + 0xb6c1075eL, 0xe3056a0cL, 0x10d25065L, 0xcb03a442L, + 0xe0ec6e0eL, 0x1698db3bL, 0x4c98a0beL, 0x3278e964L, + 0x9f1f9532L, 0xe0d392dfL, 0xd3a0342bL, 0x8971f21eL, + 0x1b0a7441L, 0x4ba3348cL, 0xc5be7120L, 0xc37632d8L, + 0xdf359f8dL, 0x9b992f2eL, 0xe60b6f47L, 0x0fe3f11dL, + 0xe54cda54L, 0x1edad891L, 0xce6279cfL, 0xcd3e7e6fL, + 0x1618b166L, 0xfd2c1d05L, 0x848fd2c5L, 0xf6fb2299L, + 0xf523f357L, 0xa6327623L, 0x93a83531L, 0x56cccd02L, + 0xacf08162L, 0x5a75ebb5L, 0x6e163697L, 0x88d273ccL, + 0xde966292L, 0x81b949d0L, 0x4c50901bL, 0x71c65614L, + 0xe6c6c7bdL, 0x327a140aL, 0x45e1d006L, 0xc3f27b9aL, + 0xc9aa53fdL, 0x62a80f00L, 0xbb25bfe2L, 0x35bdd2f6L, + 0x71126905L, 0xb2040222L, 0xb6cbcf7cL, 0xcd769c2bL, + 0x53113ec0L, 0x1640e3d3L, 0x38abbd60L, 0x2547adf0L, + 0xba38209cL, 0xf746ce76L, 0x77afa1c5L, 0x20756060L, + 0x85cbfe4eL, 0x8ae88dd8L, 0x7aaaf9b0L, 0x4cf9aa7eL, + 0x1948c25cL, 0x02fb8a8cL, 0x01c36ae4L, 0xd6ebe1f9L, + 0x90d4f869L, 0xa65cdea0L, 0x3f09252dL, 0xc208e69fL, + 0xb74e6132L, 0xce77e25bL, 0x578fdfe3L, 0x3ac372e6L, + } + }; + diff --git a/sys/crypto/blowfish/bf_skey.c b/sys/crypto/blowfish/bf_skey.c new file mode 100644 index 0000000..04729e1 --- /dev/null +++ b/sys/crypto/blowfish/bf_skey.c @@ -0,0 +1,122 @@ +/* crypto/bf/bf_skey.c */ +/* Copyright (C) 1995-1997 Eric Young (eay@mincom.oz.au) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@mincom.oz.au). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@mincom.oz.au). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@mincom.oz.au)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@mincom.oz.au)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 AUTHOR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + * + * $FreeBSD$ + */ + +#include <sys/types.h> +#include <sys/time.h> +#include <sys/systm.h> +#include <crypto/blowfish/blowfish.h> +#include <crypto/blowfish/bf_locl.h> +#include <crypto/blowfish/bf_pi.h> + +void BF_set_key(key,len,data) +BF_KEY *key; +int len; +unsigned char *data; + { + int i; + BF_LONG *p,ri,in[2]; + unsigned char *d,*end; + + + memcpy((char *)key,(char *)&bf_init,sizeof(BF_KEY)); + p=key->P; + + if (len > ((BF_ROUNDS+2)*4)) len=(BF_ROUNDS+2)*4; + + d=data; + end= &(data[len]); + for (i=0; i<(BF_ROUNDS+2); i++) + { + ri= *(d++); + if (d >= end) d=data; + + ri<<=8; + ri|= *(d++); + if (d >= end) d=data; + + ri<<=8; + ri|= *(d++); + if (d >= end) d=data; + + ri<<=8; + ri|= *(d++); + if (d >= end) d=data; + + p[i]^=ri; + } + + in[0]=0L; + in[1]=0L; + for (i=0; i<(BF_ROUNDS+2); i+=2) + { + BF_encrypt(in,key,BF_ENCRYPT); + p[i ]=in[0]; + p[i+1]=in[1]; + } + + p=key->S; + for (i=0; i<4*256; i+=2) + { + BF_encrypt(in,key,BF_ENCRYPT); + p[i ]=in[0]; + p[i+1]=in[1]; + } + } + diff --git a/sys/crypto/blowfish/blowfish.h b/sys/crypto/blowfish/blowfish.h new file mode 100644 index 0000000..d8e6d91 --- /dev/null +++ b/sys/crypto/blowfish/blowfish.h @@ -0,0 +1,124 @@ +/* crypto/bf/blowfish.h */ +/* Copyright (C) 1995-1997 Eric Young (eay@mincom.oz.au) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@mincom.oz.au). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@mincom.oz.au). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@mincom.oz.au)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@mincom.oz.au)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 AUTHOR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + * + * $FreeBSD$ + */ + +#ifndef HEADER_BLOWFISH_H +#define HEADER_BLOWFISH_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define BF_ENCRYPT 1 +#define BF_DECRYPT 0 + +/* If you make this 'unsigned int' the pointer variants will work on + * the Alpha, otherwise they will not. Strangly using the '8 byte' + * BF_LONG and the default 'non-pointer' inner loop is the best configuration + * for the Alpha */ +#define BF_LONG unsigned long + +#define BF_ROUNDS 16 +#define BF_BLOCK 8 + +typedef struct bf_key_st + { + BF_LONG P[BF_ROUNDS+2]; + BF_LONG S[4*256]; + } BF_KEY; + +#ifndef NOPROTO + +void BF_set_key(BF_KEY *key, int len, unsigned char *data); +void BF_ecb_encrypt(unsigned char *in,unsigned char *out,BF_KEY *key, + int encrypt); +void BF_encrypt(BF_LONG *data,BF_KEY *key,int encrypt); +void BF_cbc_encrypt(unsigned char *in, unsigned char *out, long length, + BF_KEY *ks, unsigned char *iv, int encrypt); +void BF_cfb64_encrypt(unsigned char *in, unsigned char *out, long length, + BF_KEY *schedule, unsigned char *ivec, int *num, int encrypt); +void BF_ofb64_encrypt(unsigned char *in, unsigned char *out, long length, + BF_KEY *schedule, unsigned char *ivec, int *num); +char *BF_options(void); + +/* added by itojun */ +struct mbuf; +void BF_cbc_encrypt_m(struct mbuf *, int, int, BF_KEY *, + unsigned char *, int); + +#else + +void BF_set_key(); +void BF_ecb_encrypt(); +void BF_encrypt(); +void BF_cbc_encrypt(); +void BF_cfb64_encrypt(); +void BF_ofb64_encrypt(); +char *BF_options(); + +/* added by itojun */ +void BF_cbc_encrypt_m(); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/sys/crypto/cast128/cast128.c b/sys/crypto/cast128/cast128.c new file mode 100644 index 0000000..72ed733 --- /dev/null +++ b/sys/crypto/cast128/cast128.c @@ -0,0 +1,873 @@ +/* + * heavily modified by Tomomi Suzuki <suzuki@grelot.elec.ryukoku.ac.jp> + */ +/* + * The CAST-128 Encryption Algorithm (RFC 2144) + * + * original implementation <Hideo "Sir MaNMOS" Morisita> + * 1997/08/21 + */ +/* + * Copyright (C) 1997 Hideo "Sir MANMOS" Morishita + * 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. + * + * THIS SOFTWARE IS PROVIDED BY Hideo "Sir MaNMOS" Morishita ``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 Hideo "Sir MaNMOS" Morishita 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 <crypto/cast128/cast128.h> +#include <crypto/cast128/cast128_subkey.h> + + +static u_int32_t S1[]; +static u_int32_t S2[]; +static u_int32_t S3[]; +static u_int32_t S4[]; +static u_int32_t S5[]; +static u_int32_t S6[]; +static u_int32_t S7[]; +static u_int32_t S8[]; + + +/* + * Step 1 + */ +void set_cast128_subkey(u_int32_t *subkey, u_int8_t *key) +{ + u_int32_t buf[8]; /* for x0x1x2x3, x4x5x6x7 ..., z0z1z2z3, ... */ + + buf[0] = (key[ 0] << 24) | (key[ 1] << 16) | (key[ 2] << 8) + | key[ 3]; + buf[1] = (key[ 4] << 24) | (key[ 5] << 16) | (key[ 6] << 8) + | key[ 7]; + buf[2] = (key[ 8] << 24) | (key[ 9] << 16) | (key[10] << 8) + | key[11]; + buf[3] = (key[12] << 24) | (key[13] << 16) | (key[14] << 8) + | key[15]; + + /* masking subkey */ + z0z1z2z3 = x0x1x2x3 ^ S5[xD] ^ S6[xF] ^ S7[xC] ^ S8[xE] ^ S7[x8]; + z4z5z6z7 = x8x9xAxB ^ S5[z0] ^ S6[z2] ^ S7[z1] ^ S8[z3] ^ S8[xA]; + z8z9zAzB = xCxDxExF ^ S5[z7] ^ S6[z6] ^ S7[z5] ^ S8[z4] ^ S5[x9]; + zCzDzEzF = x4x5x6x7 ^ S5[zA] ^ S6[z9] ^ S7[zB] ^ S8[z8] ^ S6[xB]; + subkey[0] = S5[z8] ^ S6[z9] ^ S7[z7] ^ S8[z6] ^ S5[z2]; + subkey[1] = S5[zA] ^ S6[zB] ^ S7[z5] ^ S8[z4] ^ S6[z6]; + subkey[2] = S5[zC] ^ S6[zD] ^ S7[z3] ^ S8[z2] ^ S7[z9]; + subkey[3] = S5[zE] ^ S6[zF] ^ S7[z1] ^ S8[z0] ^ S8[zC]; + + x0x1x2x3 = z8z9zAzB ^ S5[z5] ^ S6[z7] ^ S7[z4] ^ S8[z6] ^ S7[z0]; + x4x5x6x7 = z0z1z2z3 ^ S5[x0] ^ S6[x2] ^ S7[x1] ^ S8[x3] ^ S8[z2]; + x8x9xAxB = z4z5z6z7 ^ S5[x7] ^ S6[x6] ^ S7[x5] ^ S8[x4] ^ S5[z1]; + xCxDxExF = zCzDzEzF ^ S5[xA] ^ S6[x9] ^ S7[xB] ^ S8[x8] ^ S6[z3]; + subkey[4] = S5[x3] ^ S6[x2] ^ S7[xC] ^ S8[xD] ^ S5[x8]; + subkey[5] = S5[x1] ^ S6[x0] ^ S7[xE] ^ S8[xF] ^ S6[xD]; + subkey[6] = S5[x7] ^ S6[x6] ^ S7[x8] ^ S8[x9] ^ S7[x3]; + subkey[7] = S5[x5] ^ S6[x4] ^ S7[xA] ^ S8[xB] ^ S8[x7]; + + z0z1z2z3 = x0x1x2x3 ^ S5[xD] ^ S6[xF] ^ S7[xC] ^ S8[xE] ^ S7[x8]; + z4z5z6z7 = x8x9xAxB ^ S5[z0] ^ S6[z2] ^ S7[z1] ^ S8[z3] ^ S8[xA]; + z8z9zAzB = xCxDxExF ^ S5[z7] ^ S6[z6] ^ S7[z5] ^ S8[z4] ^ S5[x9]; + zCzDzEzF = x4x5x6x7 ^ S5[zA] ^ S6[z9] ^ S7[zB] ^ S8[z8] ^ S6[xB]; + subkey[8] = S5[z3] ^ S6[z2] ^ S7[zC] ^ S8[zD] ^ S5[z9]; + subkey[9] = S5[z1] ^ S6[z0] ^ S7[zE] ^ S8[zF] ^ S6[zC]; + subkey[10] = S5[z7] ^ S6[z6] ^ S7[z8] ^ S8[z9] ^ S7[z2]; + subkey[11] = S5[z5] ^ S6[z4] ^ S7[zA] ^ S8[zB] ^ S8[z6]; + + x0x1x2x3 = z8z9zAzB ^ S5[z5] ^ S6[z7] ^ S7[z4] ^ S8[z6] ^ S7[z0]; + x4x5x6x7 = z0z1z2z3 ^ S5[x0] ^ S6[x2] ^ S7[x1] ^ S8[x3] ^ S8[z2]; + x8x9xAxB = z4z5z6z7 ^ S5[x7] ^ S6[x6] ^ S7[x5] ^ S8[x4] ^ S5[z1]; + xCxDxExF = zCzDzEzF ^ S5[xA] ^ S6[x9] ^ S7[xB] ^ S8[x8] ^ S6[z3]; + subkey[12] = S5[x8] ^ S6[x9] ^ S7[x7] ^ S8[x6] ^ S5[x3]; + subkey[13] = S5[xA] ^ S6[xB] ^ S7[x5] ^ S8[x4] ^ S6[x7]; + subkey[14] = S5[xC] ^ S6[xD] ^ S7[x3] ^ S8[x2] ^ S7[x8]; + subkey[15] = S5[xE] ^ S6[xF] ^ S7[x1] ^ S8[x0] ^ S8[xD]; + + /* rotate subkey (least significast 5 bits) */ + z0z1z2z3 = x0x1x2x3 ^ S5[xD] ^ S6[xF] ^ S7[xC] ^ S8[xE] ^ S7[x8]; + z4z5z6z7 = x8x9xAxB ^ S5[z0] ^ S6[z2] ^ S7[z1] ^ S8[z3] ^ S8[xA]; + z8z9zAzB = xCxDxExF ^ S5[z7] ^ S6[z6] ^ S7[z5] ^ S8[z4] ^ S5[x9]; + zCzDzEzF = x4x5x6x7 ^ S5[zA] ^ S6[z9] ^ S7[zB] ^ S8[z8] ^ S6[xB]; + subkey[16] = (S5[z8] ^ S6[z9] ^ S7[z7] ^ S8[z6] ^ S5[z2]) & 0x1f; + subkey[17] = (S5[zA] ^ S6[zB] ^ S7[z5] ^ S8[z4] ^ S6[z6]) & 0x1f; + subkey[18] = (S5[zC] ^ S6[zD] ^ S7[z3] ^ S8[z2] ^ S7[z9]) & 0x1f; + subkey[19] = (S5[zE] ^ S6[zF] ^ S7[z1] ^ S8[z0] ^ S8[zC]) & 0x1f; + + x0x1x2x3 = z8z9zAzB ^ S5[z5] ^ S6[z7] ^ S7[z4] ^ S8[z6] ^ S7[z0]; + x4x5x6x7 = z0z1z2z3 ^ S5[x0] ^ S6[x2] ^ S7[x1] ^ S8[x3] ^ S8[z2]; + x8x9xAxB = z4z5z6z7 ^ S5[x7] ^ S6[x6] ^ S7[x5] ^ S8[x4] ^ S5[z1]; + xCxDxExF = zCzDzEzF ^ S5[xA] ^ S6[x9] ^ S7[xB] ^ S8[x8] ^ S6[z3]; + subkey[20] = (S5[x3] ^ S6[x2] ^ S7[xC] ^ S8[xD] ^ S5[x8]) & 0x1f; + subkey[21] = (S5[x1] ^ S6[x0] ^ S7[xE] ^ S8[xF] ^ S6[xD]) & 0x1f; + subkey[22] = (S5[x7] ^ S6[x6] ^ S7[x8] ^ S8[x9] ^ S7[x3]) & 0x1f; + subkey[23] = (S5[x5] ^ S6[x4] ^ S7[xA] ^ S8[xB] ^ S8[x7]) & 0x1f; + + z0z1z2z3 = x0x1x2x3 ^ S5[xD] ^ S6[xF] ^ S7[xC] ^ S8[xE] ^ S7[x8]; + z4z5z6z7 = x8x9xAxB ^ S5[z0] ^ S6[z2] ^ S7[z1] ^ S8[z3] ^ S8[xA]; + z8z9zAzB = xCxDxExF ^ S5[z7] ^ S6[z6] ^ S7[z5] ^ S8[z4] ^ S5[x9]; + zCzDzEzF = x4x5x6x7 ^ S5[zA] ^ S6[z9] ^ S7[zB] ^ S8[z8] ^ S6[xB]; + subkey[24] = (S5[z3] ^ S6[z2] ^ S7[zC] ^ S8[zD] ^ S5[z9]) & 0x1f; + subkey[25] = (S5[z1] ^ S6[z0] ^ S7[zE] ^ S8[zF] ^ S6[zC]) & 0x1f; + subkey[26] = (S5[z7] ^ S6[z6] ^ S7[z8] ^ S8[z9] ^ S7[z2]) & 0x1f; + subkey[27] = (S5[z5] ^ S6[z4] ^ S7[zA] ^ S8[zB] ^ S8[z6]) & 0x1f; + + x0x1x2x3 = z8z9zAzB ^ S5[z5] ^ S6[z7] ^ S7[z4] ^ S8[z6] ^ S7[z0]; + x4x5x6x7 = z0z1z2z3 ^ S5[x0] ^ S6[x2] ^ S7[x1] ^ S8[x3] ^ S8[z2]; + x8x9xAxB = z4z5z6z7 ^ S5[x7] ^ S6[x6] ^ S7[x5] ^ S8[x4] ^ S5[z1]; + xCxDxExF = zCzDzEzF ^ S5[xA] ^ S6[x9] ^ S7[xB] ^ S8[x8] ^ S6[z3]; + subkey[28] = (S5[x8] ^ S6[x9] ^ S7[x7] ^ S8[x6] ^ S5[x3]) & 0x1f; + subkey[29] = (S5[xA] ^ S6[xB] ^ S7[x5] ^ S8[x4] ^ S6[x7]) & 0x1f; + subkey[30] = (S5[xC] ^ S6[xD] ^ S7[x3] ^ S8[x2] ^ S7[x8]) & 0x1f; + subkey[31] = (S5[xE] ^ S6[xF] ^ S7[x1] ^ S8[x0] ^ S8[xD]) & 0x1f; +} + + +#define CAST128_TYPE1(rc, d, km, kr) { \ + u_int32_t x = circular_leftshift(((km)+(d)), (kr)); \ + (rc) = ((S1[byte0(x)] ^ S2[byte1(x)]) - S3[byte2(x)]) + S4[byte3(x)]; \ +} + +#define CAST128_TYPE2(rc, d, km, kr) { \ + u_int32_t x = circular_leftshift(((km)^(d)), (kr)); \ + (rc) = ((S1[byte0(x)] - S2[byte1(x)]) + S3[byte2(x)]) ^ S4[byte3(x)]; \ +} + +#define CAST128_TYPE3(rc, d, km, kr) { \ + u_int32_t x = circular_leftshift(((km)-(d)), (kr)); \ + (rc) = ((S1[byte0(x)] + S2[byte1(x)]) ^ S3[byte2(x)]) - S4[byte3(x)]; \ +} + + +void cast128_encrypt_round16(u_int8_t *c, const u_int8_t *m, + u_int32_t *subkey) +{ + u_int32_t l; /* left 32bit */ + u_int32_t r; /* right 32bit */ + u_int32_t br; /* backup right 32bit */ + u_int32_t rc; /* result code of CAST128_TYPE?() */ + u_int32_t *km, *kr; + + /* Step 2 */ + l = (m[0] << 24) | (m[1] << 16) | (m[2] << 8) | m[3]; + r = (m[4] << 24) | (m[5] << 16) | (m[6] << 8) | m[7]; + + /* Step 3 */ + km = subkey; + kr = subkey + 16; + + br = r; CAST128_TYPE1(rc, r, *km, *kr); r = l ^ rc; l = br; km++; kr++; + br = r; CAST128_TYPE2(rc, r, *km, *kr); r = l ^ rc; l = br; km++; kr++; + br = r; CAST128_TYPE3(rc, r, *km, *kr); r = l ^ rc; l = br; km++; kr++; + br = r; CAST128_TYPE1(rc, r, *km, *kr); r = l ^ rc; l = br; km++; kr++; + br = r; CAST128_TYPE2(rc, r, *km, *kr); r = l ^ rc; l = br; km++; kr++; + br = r; CAST128_TYPE3(rc, r, *km, *kr); r = l ^ rc; l = br; km++; kr++; + br = r; CAST128_TYPE1(rc, r, *km, *kr); r = l ^ rc; l = br; km++; kr++; + br = r; CAST128_TYPE2(rc, r, *km, *kr); r = l ^ rc; l = br; km++; kr++; + br = r; CAST128_TYPE3(rc, r, *km, *kr); r = l ^ rc; l = br; km++; kr++; + br = r; CAST128_TYPE1(rc, r, *km, *kr); r = l ^ rc; l = br; km++; kr++; + br = r; CAST128_TYPE2(rc, r, *km, *kr); r = l ^ rc; l = br; km++; kr++; + br = r; CAST128_TYPE3(rc, r, *km, *kr); r = l ^ rc; l = br; km++; kr++; + br = r; CAST128_TYPE1(rc, r, *km, *kr); r = l ^ rc; l = br; km++; kr++; + br = r; CAST128_TYPE2(rc, r, *km, *kr); r = l ^ rc; l = br; km++; kr++; + br = r; CAST128_TYPE3(rc, r, *km, *kr); r = l ^ rc; l = br; km++; kr++; + br = r; CAST128_TYPE1(rc, r, *km, *kr); r = l ^ rc; l = br; + + /* Step 4 */ + c[0] = (r >> 24) & 0xff; + c[1] = (r >> 16) & 0xff; + c[2] = (r >> 8) & 0xff; + c[3] = r & 0xff; + c[4] = (l >> 24) & 0xff; + c[5] = (l >> 16) & 0xff; + c[6] = (l >> 8) & 0xff; + c[7] = l & 0xff; +} + + +void cast128_decrypt_round16(u_int8_t *m, const u_int8_t *c, + u_int32_t *subkey) +{ + u_int32_t l; /* left 32bit */ + u_int32_t r; /* right 32bit */ + u_int32_t bl; /* backup left 32bit */ + u_int32_t rc; /* result code of CAST128_TYPE?() */ + u_int32_t *km, *kr; + + /* Step 2 */ + r = (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | c[3]; + l = (c[4] << 24) | (c[5] << 16) | (c[6] << 8) | c[7]; + + /* Step 3 */ + km = subkey + 15; + kr = subkey + 31; + + bl = l; CAST128_TYPE1(rc, l, *km, *kr); l = r ^ rc; r = bl; km--; kr--; + bl = l; CAST128_TYPE3(rc, l, *km, *kr); l = r ^ rc; r = bl; km--; kr--; + bl = l; CAST128_TYPE2(rc, l, *km, *kr); l = r ^ rc; r = bl; km--; kr--; + bl = l; CAST128_TYPE1(rc, l, *km, *kr); l = r ^ rc; r = bl; km--; kr--; + bl = l; CAST128_TYPE3(rc, l, *km, *kr); l = r ^ rc; r = bl; km--; kr--; + bl = l; CAST128_TYPE2(rc, l, *km, *kr); l = r ^ rc; r = bl; km--; kr--; + bl = l; CAST128_TYPE1(rc, l, *km, *kr); l = r ^ rc; r = bl; km--; kr--; + bl = l; CAST128_TYPE3(rc, l, *km, *kr); l = r ^ rc; r = bl; km--; kr--; + bl = l; CAST128_TYPE2(rc, l, *km, *kr); l = r ^ rc; r = bl; km--; kr--; + bl = l; CAST128_TYPE1(rc, l, *km, *kr); l = r ^ rc; r = bl; km--; kr--; + bl = l; CAST128_TYPE3(rc, l, *km, *kr); l = r ^ rc; r = bl; km--; kr--; + bl = l; CAST128_TYPE2(rc, l, *km, *kr); l = r ^ rc; r = bl; km--; kr--; + bl = l; CAST128_TYPE1(rc, l, *km, *kr); l = r ^ rc; r = bl; km--; kr--; + bl = l; CAST128_TYPE3(rc, l, *km, *kr); l = r ^ rc; r = bl; km--; kr--; + bl = l; CAST128_TYPE2(rc, l, *km, *kr); l = r ^ rc; r = bl; km--; kr--; + bl = l; CAST128_TYPE1(rc, l, *km, *kr); l = r ^ rc; r = bl; + + /* Step 4 */ + m[0] = (l >> 24) & 0xff; + m[1] = (l >> 16) & 0xff; + m[2] = (l >> 8) & 0xff; + m[3] = l & 0xff; + m[4] = (r >> 24) & 0xff; + m[5] = (r >> 16) & 0xff; + m[6] = (r >> 8) & 0xff; + m[7] = r & 0xff; +} + + +void cast128_encrypt_round12(u_int8_t *c, const u_int8_t *m, + u_int32_t *subkey) +{ + u_int32_t l; /* left 32bit */ + u_int32_t r; /* right 32bit */ + u_int32_t br; /* backup right 32bit */ + u_int32_t rc; /* result code of CAST128_TYPE?() */ + u_int32_t *km, *kr; + + /* Step 2 */ + l = (m[0] << 24) | (m[1] << 16) | (m[2] << 8) | m[3]; + r = (m[4] << 24) | (m[5] << 16) | (m[6] << 8) | m[7]; + + /* Step 3 */ + km = subkey; + kr = subkey + 16; + + br = r; CAST128_TYPE1(rc, r, *km, *kr); r = l ^ rc; l = br; km++; kr++; + br = r; CAST128_TYPE2(rc, r, *km, *kr); r = l ^ rc; l = br; km++; kr++; + br = r; CAST128_TYPE3(rc, r, *km, *kr); r = l ^ rc; l = br; km++; kr++; + br = r; CAST128_TYPE1(rc, r, *km, *kr); r = l ^ rc; l = br; km++; kr++; + br = r; CAST128_TYPE2(rc, r, *km, *kr); r = l ^ rc; l = br; km++; kr++; + br = r; CAST128_TYPE3(rc, r, *km, *kr); r = l ^ rc; l = br; km++; kr++; + br = r; CAST128_TYPE1(rc, r, *km, *kr); r = l ^ rc; l = br; km++; kr++; + br = r; CAST128_TYPE2(rc, r, *km, *kr); r = l ^ rc; l = br; km++; kr++; + br = r; CAST128_TYPE3(rc, r, *km, *kr); r = l ^ rc; l = br; km++; kr++; + br = r; CAST128_TYPE1(rc, r, *km, *kr); r = l ^ rc; l = br; km++; kr++; + br = r; CAST128_TYPE2(rc, r, *km, *kr); r = l ^ rc; l = br; km++; kr++; + br = r; CAST128_TYPE3(rc, r, *km, *kr); r = l ^ rc; l = br; + + /* Step 4 */ + c[0] = (r >> 24) & 0xff; + c[1] = (r >> 16) & 0xff; + c[2] = (r >> 8) & 0xff; + c[3] = r & 0xff; + c[4] = (l >> 24) & 0xff; + c[5] = (l >> 16) & 0xff; + c[6] = (l >> 8) & 0xff; + c[7] = l & 0xff; +} + + +void cast128_decrypt_round12(u_int8_t *m, const u_int8_t *c, + u_int32_t *subkey) +{ + u_int32_t l; /* left 32bit */ + u_int32_t r; /* right 32bit */ + u_int32_t bl; /* backup left 32bit */ + u_int32_t rc; /* result code of CAST128_TYPE?() */ + u_int32_t *km, *kr; + + /* Step 2 */ + r = (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | c[3]; + l = (c[4] << 24) | (c[5] << 16) | (c[6] << 8) | c[7]; + + /* Step 3 */ + km = subkey + 11; + kr = subkey + 27; + + bl = l; CAST128_TYPE3(rc, l, *km, *kr); l = r ^ rc; r = bl; km--; kr--; + bl = l; CAST128_TYPE2(rc, l, *km, *kr); l = r ^ rc; r = bl; km--; kr--; + bl = l; CAST128_TYPE1(rc, l, *km, *kr); l = r ^ rc; r = bl; km--; kr--; + bl = l; CAST128_TYPE3(rc, l, *km, *kr); l = r ^ rc; r = bl; km--; kr--; + bl = l; CAST128_TYPE2(rc, l, *km, *kr); l = r ^ rc; r = bl; km--; kr--; + bl = l; CAST128_TYPE1(rc, l, *km, *kr); l = r ^ rc; r = bl; km--; kr--; + bl = l; CAST128_TYPE3(rc, l, *km, *kr); l = r ^ rc; r = bl; km--; kr--; + bl = l; CAST128_TYPE2(rc, l, *km, *kr); l = r ^ rc; r = bl; km--; kr--; + bl = l; CAST128_TYPE1(rc, l, *km, *kr); l = r ^ rc; r = bl; km--; kr--; + bl = l; CAST128_TYPE3(rc, l, *km, *kr); l = r ^ rc; r = bl; km--; kr--; + bl = l; CAST128_TYPE2(rc, l, *km, *kr); l = r ^ rc; r = bl; km--; kr--; + bl = l; CAST128_TYPE1(rc, l, *km, *kr); l = r ^ rc; r = bl; + + /* Step 4 */ + m[0] = (l >> 24) & 0xff; + m[1] = (l >> 16) & 0xff; + m[2] = (l >> 8) & 0xff; + m[3] = l & 0xff; + m[4] = (r >> 24) & 0xff; + m[5] = (r >> 16) & 0xff; + m[6] = (r >> 8) & 0xff; + m[7] = r & 0xff; +} + + +static u_int32_t S1[] = { + 0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a, + 0x1e213f2f, 0x9c004dd3, 0x6003e540, 0xcf9fc949, + 0xbfd4af27, 0x88bbbdb5, 0xe2034090, 0x98d09675, + 0x6e63a0e0, 0x15c361d2, 0xc2e7661d, 0x22d4ff8e, + 0x28683b6f, 0xc07fd059, 0xff2379c8, 0x775f50e2, + 0x43c340d3, 0xdf2f8656, 0x887ca41a, 0xa2d2bd2d, + 0xa1c9e0d6, 0x346c4819, 0x61b76d87, 0x22540f2f, + 0x2abe32e1, 0xaa54166b, 0x22568e3a, 0xa2d341d0, + 0x66db40c8, 0xa784392f, 0x004dff2f, 0x2db9d2de, + 0x97943fac, 0x4a97c1d8, 0x527644b7, 0xb5f437a7, + 0xb82cbaef, 0xd751d159, 0x6ff7f0ed, 0x5a097a1f, + 0x827b68d0, 0x90ecf52e, 0x22b0c054, 0xbc8e5935, + 0x4b6d2f7f, 0x50bb64a2, 0xd2664910, 0xbee5812d, + 0xb7332290, 0xe93b159f, 0xb48ee411, 0x4bff345d, + 0xfd45c240, 0xad31973f, 0xc4f6d02e, 0x55fc8165, + 0xd5b1caad, 0xa1ac2dae, 0xa2d4b76d, 0xc19b0c50, + 0x882240f2, 0x0c6e4f38, 0xa4e4bfd7, 0x4f5ba272, + 0x564c1d2f, 0xc59c5319, 0xb949e354, 0xb04669fe, + 0xb1b6ab8a, 0xc71358dd, 0x6385c545, 0x110f935d, + 0x57538ad5, 0x6a390493, 0xe63d37e0, 0x2a54f6b3, + 0x3a787d5f, 0x6276a0b5, 0x19a6fcdf, 0x7a42206a, + 0x29f9d4d5, 0xf61b1891, 0xbb72275e, 0xaa508167, + 0x38901091, 0xc6b505eb, 0x84c7cb8c, 0x2ad75a0f, + 0x874a1427, 0xa2d1936b, 0x2ad286af, 0xaa56d291, + 0xd7894360, 0x425c750d, 0x93b39e26, 0x187184c9, + 0x6c00b32d, 0x73e2bb14, 0xa0bebc3c, 0x54623779, + 0x64459eab, 0x3f328b82, 0x7718cf82, 0x59a2cea6, + 0x04ee002e, 0x89fe78e6, 0x3fab0950, 0x325ff6c2, + 0x81383f05, 0x6963c5c8, 0x76cb5ad6, 0xd49974c9, + 0xca180dcf, 0x380782d5, 0xc7fa5cf6, 0x8ac31511, + 0x35e79e13, 0x47da91d0, 0xf40f9086, 0xa7e2419e, + 0x31366241, 0x051ef495, 0xaa573b04, 0x4a805d8d, + 0x548300d0, 0x00322a3c, 0xbf64cddf, 0xba57a68e, + 0x75c6372b, 0x50afd341, 0xa7c13275, 0x915a0bf5, + 0x6b54bfab, 0x2b0b1426, 0xab4cc9d7, 0x449ccd82, + 0xf7fbf265, 0xab85c5f3, 0x1b55db94, 0xaad4e324, + 0xcfa4bd3f, 0x2deaa3e2, 0x9e204d02, 0xc8bd25ac, + 0xeadf55b3, 0xd5bd9e98, 0xe31231b2, 0x2ad5ad6c, + 0x954329de, 0xadbe4528, 0xd8710f69, 0xaa51c90f, + 0xaa786bf6, 0x22513f1e, 0xaa51a79b, 0x2ad344cc, + 0x7b5a41f0, 0xd37cfbad, 0x1b069505, 0x41ece491, + 0xb4c332e6, 0x032268d4, 0xc9600acc, 0xce387e6d, + 0xbf6bb16c, 0x6a70fb78, 0x0d03d9c9, 0xd4df39de, + 0xe01063da, 0x4736f464, 0x5ad328d8, 0xb347cc96, + 0x75bb0fc3, 0x98511bfb, 0x4ffbcc35, 0xb58bcf6a, + 0xe11f0abc, 0xbfc5fe4a, 0xa70aec10, 0xac39570a, + 0x3f04442f, 0x6188b153, 0xe0397a2e, 0x5727cb79, + 0x9ceb418f, 0x1cacd68d, 0x2ad37c96, 0x0175cb9d, + 0xc69dff09, 0xc75b65f0, 0xd9db40d8, 0xec0e7779, + 0x4744ead4, 0xb11c3274, 0xdd24cb9e, 0x7e1c54bd, + 0xf01144f9, 0xd2240eb1, 0x9675b3fd, 0xa3ac3755, + 0xd47c27af, 0x51c85f4d, 0x56907596, 0xa5bb15e6, + 0x580304f0, 0xca042cf1, 0x011a37ea, 0x8dbfaadb, + 0x35ba3e4a, 0x3526ffa0, 0xc37b4d09, 0xbc306ed9, + 0x98a52666, 0x5648f725, 0xff5e569d, 0x0ced63d0, + 0x7c63b2cf, 0x700b45e1, 0xd5ea50f1, 0x85a92872, + 0xaf1fbda7, 0xd4234870, 0xa7870bf3, 0x2d3b4d79, + 0x42e04198, 0x0cd0ede7, 0x26470db8, 0xf881814c, + 0x474d6ad7, 0x7c0c5e5c, 0xd1231959, 0x381b7298, + 0xf5d2f4db, 0xab838653, 0x6e2f1e23, 0x83719c9e, + 0xbd91e046, 0x9a56456e, 0xdc39200c, 0x20c8c571, + 0x962bda1c, 0xe1e696ff, 0xb141ab08, 0x7cca89b9, + 0x1a69e783, 0x02cc4843, 0xa2f7c579, 0x429ef47d, + 0x427b169c, 0x5ac9f049, 0xdd8f0f00, 0x5c8165bf, +}; + +static u_int32_t S2[] = { + 0x1f201094, 0xef0ba75b, 0x69e3cf7e, 0x393f4380, + 0xfe61cf7a, 0xeec5207a, 0x55889c94, 0x72fc0651, + 0xada7ef79, 0x4e1d7235, 0xd55a63ce, 0xde0436ba, + 0x99c430ef, 0x5f0c0794, 0x18dcdb7d, 0xa1d6eff3, + 0xa0b52f7b, 0x59e83605, 0xee15b094, 0xe9ffd909, + 0xdc440086, 0xef944459, 0xba83ccb3, 0xe0c3cdfb, + 0xd1da4181, 0x3b092ab1, 0xf997f1c1, 0xa5e6cf7b, + 0x01420ddb, 0xe4e7ef5b, 0x25a1ff41, 0xe180f806, + 0x1fc41080, 0x179bee7a, 0xd37ac6a9, 0xfe5830a4, + 0x98de8b7f, 0x77e83f4e, 0x79929269, 0x24fa9f7b, + 0xe113c85b, 0xacc40083, 0xd7503525, 0xf7ea615f, + 0x62143154, 0x0d554b63, 0x5d681121, 0xc866c359, + 0x3d63cf73, 0xcee234c0, 0xd4d87e87, 0x5c672b21, + 0x071f6181, 0x39f7627f, 0x361e3084, 0xe4eb573b, + 0x602f64a4, 0xd63acd9c, 0x1bbc4635, 0x9e81032d, + 0x2701f50c, 0x99847ab4, 0xa0e3df79, 0xba6cf38c, + 0x10843094, 0x2537a95e, 0xf46f6ffe, 0xa1ff3b1f, + 0x208cfb6a, 0x8f458c74, 0xd9e0a227, 0x4ec73a34, + 0xfc884f69, 0x3e4de8df, 0xef0e0088, 0x3559648d, + 0x8a45388c, 0x1d804366, 0x721d9bfd, 0xa58684bb, + 0xe8256333, 0x844e8212, 0x128d8098, 0xfed33fb4, + 0xce280ae1, 0x27e19ba5, 0xd5a6c252, 0xe49754bd, + 0xc5d655dd, 0xeb667064, 0x77840b4d, 0xa1b6a801, + 0x84db26a9, 0xe0b56714, 0x21f043b7, 0xe5d05860, + 0x54f03084, 0x066ff472, 0xa31aa153, 0xdadc4755, + 0xb5625dbf, 0x68561be6, 0x83ca6b94, 0x2d6ed23b, + 0xeccf01db, 0xa6d3d0ba, 0xb6803d5c, 0xaf77a709, + 0x33b4a34c, 0x397bc8d6, 0x5ee22b95, 0x5f0e5304, + 0x81ed6f61, 0x20e74364, 0xb45e1378, 0xde18639b, + 0x881ca122, 0xb96726d1, 0x8049a7e8, 0x22b7da7b, + 0x5e552d25, 0x5272d237, 0x79d2951c, 0xc60d894c, + 0x488cb402, 0x1ba4fe5b, 0xa4b09f6b, 0x1ca815cf, + 0xa20c3005, 0x8871df63, 0xb9de2fcb, 0x0cc6c9e9, + 0x0beeff53, 0xe3214517, 0xb4542835, 0x9f63293c, + 0xee41e729, 0x6e1d2d7c, 0x50045286, 0x1e6685f3, + 0xf33401c6, 0x30a22c95, 0x31a70850, 0x60930f13, + 0x73f98417, 0xa1269859, 0xec645c44, 0x52c877a9, + 0xcdff33a6, 0xa02b1741, 0x7cbad9a2, 0x2180036f, + 0x50d99c08, 0xcb3f4861, 0xc26bd765, 0x64a3f6ab, + 0x80342676, 0x25a75e7b, 0xe4e6d1fc, 0x20c710e6, + 0xcdf0b680, 0x17844d3b, 0x31eef84d, 0x7e0824e4, + 0x2ccb49eb, 0x846a3bae, 0x8ff77888, 0xee5d60f6, + 0x7af75673, 0x2fdd5cdb, 0xa11631c1, 0x30f66f43, + 0xb3faec54, 0x157fd7fa, 0xef8579cc, 0xd152de58, + 0xdb2ffd5e, 0x8f32ce19, 0x306af97a, 0x02f03ef8, + 0x99319ad5, 0xc242fa0f, 0xa7e3ebb0, 0xc68e4906, + 0xb8da230c, 0x80823028, 0xdcdef3c8, 0xd35fb171, + 0x088a1bc8, 0xbec0c560, 0x61a3c9e8, 0xbca8f54d, + 0xc72feffa, 0x22822e99, 0x82c570b4, 0xd8d94e89, + 0x8b1c34bc, 0x301e16e6, 0x273be979, 0xb0ffeaa6, + 0x61d9b8c6, 0x00b24869, 0xb7ffce3f, 0x08dc283b, + 0x43daf65a, 0xf7e19798, 0x7619b72f, 0x8f1c9ba4, + 0xdc8637a0, 0x16a7d3b1, 0x9fc393b7, 0xa7136eeb, + 0xc6bcc63e, 0x1a513742, 0xef6828bc, 0x520365d6, + 0x2d6a77ab, 0x3527ed4b, 0x821fd216, 0x095c6e2e, + 0xdb92f2fb, 0x5eea29cb, 0x145892f5, 0x91584f7f, + 0x5483697b, 0x2667a8cc, 0x85196048, 0x8c4bacea, + 0x833860d4, 0x0d23e0f9, 0x6c387e8a, 0x0ae6d249, + 0xb284600c, 0xd835731d, 0xdcb1c647, 0xac4c56ea, + 0x3ebd81b3, 0x230eabb0, 0x6438bc87, 0xf0b5b1fa, + 0x8f5ea2b3, 0xfc184642, 0x0a036b7a, 0x4fb089bd, + 0x649da589, 0xa345415e, 0x5c038323, 0x3e5d3bb9, + 0x43d79572, 0x7e6dd07c, 0x06dfdf1e, 0x6c6cc4ef, + 0x7160a539, 0x73bfbe70, 0x83877605, 0x4523ecf1, +}; + +static u_int32_t S3[] = { + 0x8defc240, 0x25fa5d9f, 0xeb903dbf, 0xe810c907, + 0x47607fff, 0x369fe44b, 0x8c1fc644, 0xaececa90, + 0xbeb1f9bf, 0xeefbcaea, 0xe8cf1950, 0x51df07ae, + 0x920e8806, 0xf0ad0548, 0xe13c8d83, 0x927010d5, + 0x11107d9f, 0x07647db9, 0xb2e3e4d4, 0x3d4f285e, + 0xb9afa820, 0xfade82e0, 0xa067268b, 0x8272792e, + 0x553fb2c0, 0x489ae22b, 0xd4ef9794, 0x125e3fbc, + 0x21fffcee, 0x825b1bfd, 0x9255c5ed, 0x1257a240, + 0x4e1a8302, 0xbae07fff, 0x528246e7, 0x8e57140e, + 0x3373f7bf, 0x8c9f8188, 0xa6fc4ee8, 0xc982b5a5, + 0xa8c01db7, 0x579fc264, 0x67094f31, 0xf2bd3f5f, + 0x40fff7c1, 0x1fb78dfc, 0x8e6bd2c1, 0x437be59b, + 0x99b03dbf, 0xb5dbc64b, 0x638dc0e6, 0x55819d99, + 0xa197c81c, 0x4a012d6e, 0xc5884a28, 0xccc36f71, + 0xb843c213, 0x6c0743f1, 0x8309893c, 0x0feddd5f, + 0x2f7fe850, 0xd7c07f7e, 0x02507fbf, 0x5afb9a04, + 0xa747d2d0, 0x1651192e, 0xaf70bf3e, 0x58c31380, + 0x5f98302e, 0x727cc3c4, 0x0a0fb402, 0x0f7fef82, + 0x8c96fdad, 0x5d2c2aae, 0x8ee99a49, 0x50da88b8, + 0x8427f4a0, 0x1eac5790, 0x796fb449, 0x8252dc15, + 0xefbd7d9b, 0xa672597d, 0xada840d8, 0x45f54504, + 0xfa5d7403, 0xe83ec305, 0x4f91751a, 0x925669c2, + 0x23efe941, 0xa903f12e, 0x60270df2, 0x0276e4b6, + 0x94fd6574, 0x927985b2, 0x8276dbcb, 0x02778176, + 0xf8af918d, 0x4e48f79e, 0x8f616ddf, 0xe29d840e, + 0x842f7d83, 0x340ce5c8, 0x96bbb682, 0x93b4b148, + 0xef303cab, 0x984faf28, 0x779faf9b, 0x92dc560d, + 0x224d1e20, 0x8437aa88, 0x7d29dc96, 0x2756d3dc, + 0x8b907cee, 0xb51fd240, 0xe7c07ce3, 0xe566b4a1, + 0xc3e9615e, 0x3cf8209d, 0x6094d1e3, 0xcd9ca341, + 0x5c76460e, 0x00ea983b, 0xd4d67881, 0xfd47572c, + 0xf76cedd9, 0xbda8229c, 0x127dadaa, 0x438a074e, + 0x1f97c090, 0x081bdb8a, 0x93a07ebe, 0xb938ca15, + 0x97b03cff, 0x3dc2c0f8, 0x8d1ab2ec, 0x64380e51, + 0x68cc7bfb, 0xd90f2788, 0x12490181, 0x5de5ffd4, + 0xdd7ef86a, 0x76a2e214, 0xb9a40368, 0x925d958f, + 0x4b39fffa, 0xba39aee9, 0xa4ffd30b, 0xfaf7933b, + 0x6d498623, 0x193cbcfa, 0x27627545, 0x825cf47a, + 0x61bd8ba0, 0xd11e42d1, 0xcead04f4, 0x127ea392, + 0x10428db7, 0x8272a972, 0x9270c4a8, 0x127de50b, + 0x285ba1c8, 0x3c62f44f, 0x35c0eaa5, 0xe805d231, + 0x428929fb, 0xb4fcdf82, 0x4fb66a53, 0x0e7dc15b, + 0x1f081fab, 0x108618ae, 0xfcfd086d, 0xf9ff2889, + 0x694bcc11, 0x236a5cae, 0x12deca4d, 0x2c3f8cc5, + 0xd2d02dfe, 0xf8ef5896, 0xe4cf52da, 0x95155b67, + 0x494a488c, 0xb9b6a80c, 0x5c8f82bc, 0x89d36b45, + 0x3a609437, 0xec00c9a9, 0x44715253, 0x0a874b49, + 0xd773bc40, 0x7c34671c, 0x02717ef6, 0x4feb5536, + 0xa2d02fff, 0xd2bf60c4, 0xd43f03c0, 0x50b4ef6d, + 0x07478cd1, 0x006e1888, 0xa2e53f55, 0xb9e6d4bc, + 0xa2048016, 0x97573833, 0xd7207d67, 0xde0f8f3d, + 0x72f87b33, 0xabcc4f33, 0x7688c55d, 0x7b00a6b0, + 0x947b0001, 0x570075d2, 0xf9bb88f8, 0x8942019e, + 0x4264a5ff, 0x856302e0, 0x72dbd92b, 0xee971b69, + 0x6ea22fde, 0x5f08ae2b, 0xaf7a616d, 0xe5c98767, + 0xcf1febd2, 0x61efc8c2, 0xf1ac2571, 0xcc8239c2, + 0x67214cb8, 0xb1e583d1, 0xb7dc3e62, 0x7f10bdce, + 0xf90a5c38, 0x0ff0443d, 0x606e6dc6, 0x60543a49, + 0x5727c148, 0x2be98a1d, 0x8ab41738, 0x20e1be24, + 0xaf96da0f, 0x68458425, 0x99833be5, 0x600d457d, + 0x282f9350, 0x8334b362, 0xd91d1120, 0x2b6d8da0, + 0x642b1e31, 0x9c305a00, 0x52bce688, 0x1b03588a, + 0xf7baefd5, 0x4142ed9c, 0xa4315c11, 0x83323ec5, + 0xdfef4636, 0xa133c501, 0xe9d3531c, 0xee353783, +}; + +static u_int32_t S4[] = { + 0x9db30420, 0x1fb6e9de, 0xa7be7bef, 0xd273a298, + 0x4a4f7bdb, 0x64ad8c57, 0x85510443, 0xfa020ed1, + 0x7e287aff, 0xe60fb663, 0x095f35a1, 0x79ebf120, + 0xfd059d43, 0x6497b7b1, 0xf3641f63, 0x241e4adf, + 0x28147f5f, 0x4fa2b8cd, 0xc9430040, 0x0cc32220, + 0xfdd30b30, 0xc0a5374f, 0x1d2d00d9, 0x24147b15, + 0xee4d111a, 0x0fca5167, 0x71ff904c, 0x2d195ffe, + 0x1a05645f, 0x0c13fefe, 0x081b08ca, 0x05170121, + 0x80530100, 0xe83e5efe, 0xac9af4f8, 0x7fe72701, + 0xd2b8ee5f, 0x06df4261, 0xbb9e9b8a, 0x7293ea25, + 0xce84ffdf, 0xf5718801, 0x3dd64b04, 0xa26f263b, + 0x7ed48400, 0x547eebe6, 0x446d4ca0, 0x6cf3d6f5, + 0x2649abdf, 0xaea0c7f5, 0x36338cc1, 0x503f7e93, + 0xd3772061, 0x11b638e1, 0x72500e03, 0xf80eb2bb, + 0xabe0502e, 0xec8d77de, 0x57971e81, 0xe14f6746, + 0xc9335400, 0x6920318f, 0x081dbb99, 0xffc304a5, + 0x4d351805, 0x7f3d5ce3, 0xa6c866c6, 0x5d5bcca9, + 0xdaec6fea, 0x9f926f91, 0x9f46222f, 0x3991467d, + 0xa5bf6d8e, 0x1143c44f, 0x43958302, 0xd0214eeb, + 0x022083b8, 0x3fb6180c, 0x18f8931e, 0x281658e6, + 0x26486e3e, 0x8bd78a70, 0x7477e4c1, 0xb506e07c, + 0xf32d0a25, 0x79098b02, 0xe4eabb81, 0x28123b23, + 0x69dead38, 0x1574ca16, 0xdf871b62, 0x211c40b7, + 0xa51a9ef9, 0x0014377b, 0x041e8ac8, 0x09114003, + 0xbd59e4d2, 0xe3d156d5, 0x4fe876d5, 0x2f91a340, + 0x557be8de, 0x00eae4a7, 0x0ce5c2ec, 0x4db4bba6, + 0xe756bdff, 0xdd3369ac, 0xec17b035, 0x06572327, + 0x99afc8b0, 0x56c8c391, 0x6b65811c, 0x5e146119, + 0x6e85cb75, 0xbe07c002, 0xc2325577, 0x893ff4ec, + 0x5bbfc92d, 0xd0ec3b25, 0xb7801ab7, 0x8d6d3b24, + 0x20c763ef, 0xc366a5fc, 0x9c382880, 0x0ace3205, + 0xaac9548a, 0xeca1d7c7, 0x041afa32, 0x1d16625a, + 0x6701902c, 0x9b757a54, 0x31d477f7, 0x9126b031, + 0x36cc6fdb, 0xc70b8b46, 0xd9e66a48, 0x56e55a79, + 0x026a4ceb, 0x52437eff, 0x2f8f76b4, 0x0df980a5, + 0x8674cde3, 0xedda04eb, 0x17a9be04, 0x2c18f4df, + 0xb7747f9d, 0xab2af7b4, 0xefc34d20, 0x2e096b7c, + 0x1741a254, 0xe5b6a035, 0x213d42f6, 0x2c1c7c26, + 0x61c2f50f, 0x6552daf9, 0xd2c231f8, 0x25130f69, + 0xd8167fa2, 0x0418f2c8, 0x001a96a6, 0x0d1526ab, + 0x63315c21, 0x5e0a72ec, 0x49bafefd, 0x187908d9, + 0x8d0dbd86, 0x311170a7, 0x3e9b640c, 0xcc3e10d7, + 0xd5cad3b6, 0x0caec388, 0xf73001e1, 0x6c728aff, + 0x71eae2a1, 0x1f9af36e, 0xcfcbd12f, 0xc1de8417, + 0xac07be6b, 0xcb44a1d8, 0x8b9b0f56, 0x013988c3, + 0xb1c52fca, 0xb4be31cd, 0xd8782806, 0x12a3a4e2, + 0x6f7de532, 0x58fd7eb6, 0xd01ee900, 0x24adffc2, + 0xf4990fc5, 0x9711aac5, 0x001d7b95, 0x82e5e7d2, + 0x109873f6, 0x00613096, 0xc32d9521, 0xada121ff, + 0x29908415, 0x7fbb977f, 0xaf9eb3db, 0x29c9ed2a, + 0x5ce2a465, 0xa730f32c, 0xd0aa3fe8, 0x8a5cc091, + 0xd49e2ce7, 0x0ce454a9, 0xd60acd86, 0x015f1919, + 0x77079103, 0xdea03af6, 0x78a8565e, 0xdee356df, + 0x21f05cbe, 0x8b75e387, 0xb3c50651, 0xb8a5c3ef, + 0xd8eeb6d2, 0xe523be77, 0xc2154529, 0x2f69efdf, + 0xafe67afb, 0xf470c4b2, 0xf3e0eb5b, 0xd6cc9876, + 0x39e4460c, 0x1fda8538, 0x1987832f, 0xca007367, + 0xa99144f8, 0x296b299e, 0x492fc295, 0x9266beab, + 0xb5676e69, 0x9bd3ddda, 0xdf7e052f, 0xdb25701c, + 0x1b5e51ee, 0xf65324e6, 0x6afce36c, 0x0316cc04, + 0x8644213e, 0xb7dc59d0, 0x7965291f, 0xccd6fd43, + 0x41823979, 0x932bcdf6, 0xb657c34d, 0x4edfd282, + 0x7ae5290c, 0x3cb9536b, 0x851e20fe, 0x9833557e, + 0x13ecf0b0, 0xd3ffb372, 0x3f85c5c1, 0x0aef7ed2, +}; + +static u_int32_t S5[] = { + 0x7ec90c04, 0x2c6e74b9, 0x9b0e66df, 0xa6337911, + 0xb86a7fff, 0x1dd358f5, 0x44dd9d44, 0x1731167f, + 0x08fbf1fa, 0xe7f511cc, 0xd2051b00, 0x735aba00, + 0x2ab722d8, 0x386381cb, 0xacf6243a, 0x69befd7a, + 0xe6a2e77f, 0xf0c720cd, 0xc4494816, 0xccf5c180, + 0x38851640, 0x15b0a848, 0xe68b18cb, 0x4caadeff, + 0x5f480a01, 0x0412b2aa, 0x259814fc, 0x41d0efe2, + 0x4e40b48d, 0x248eb6fb, 0x8dba1cfe, 0x41a99b02, + 0x1a550a04, 0xba8f65cb, 0x7251f4e7, 0x95a51725, + 0xc106ecd7, 0x97a5980a, 0xc539b9aa, 0x4d79fe6a, + 0xf2f3f763, 0x68af8040, 0xed0c9e56, 0x11b4958b, + 0xe1eb5a88, 0x8709e6b0, 0xd7e07156, 0x4e29fea7, + 0x6366e52d, 0x02d1c000, 0xc4ac8e05, 0x9377f571, + 0x0c05372a, 0x578535f2, 0x2261be02, 0xd642a0c9, + 0xdf13a280, 0x74b55bd2, 0x682199c0, 0xd421e5ec, + 0x53fb3ce8, 0xc8adedb3, 0x28a87fc9, 0x3d959981, + 0x5c1ff900, 0xfe38d399, 0x0c4eff0b, 0x062407ea, + 0xaa2f4fb1, 0x4fb96976, 0x90c79505, 0xb0a8a774, + 0xef55a1ff, 0xe59ca2c2, 0xa6b62d27, 0xe66a4263, + 0xdf65001f, 0x0ec50966, 0xdfdd55bc, 0x29de0655, + 0x911e739a, 0x17af8975, 0x32c7911c, 0x89f89468, + 0x0d01e980, 0x524755f4, 0x03b63cc9, 0x0cc844b2, + 0xbcf3f0aa, 0x87ac36e9, 0xe53a7426, 0x01b3d82b, + 0x1a9e7449, 0x64ee2d7e, 0xcddbb1da, 0x01c94910, + 0xb868bf80, 0x0d26f3fd, 0x9342ede7, 0x04a5c284, + 0x636737b6, 0x50f5b616, 0xf24766e3, 0x8eca36c1, + 0x136e05db, 0xfef18391, 0xfb887a37, 0xd6e7f7d4, + 0xc7fb7dc9, 0x3063fcdf, 0xb6f589de, 0xec2941da, + 0x26e46695, 0xb7566419, 0xf654efc5, 0xd08d58b7, + 0x48925401, 0xc1bacb7f, 0xe5ff550f, 0xb6083049, + 0x5bb5d0e8, 0x87d72e5a, 0xab6a6ee1, 0x223a66ce, + 0xc62bf3cd, 0x9e0885f9, 0x68cb3e47, 0x086c010f, + 0xa21de820, 0xd18b69de, 0xf3f65777, 0xfa02c3f6, + 0x407edac3, 0xcbb3d550, 0x1793084d, 0xb0d70eba, + 0x0ab378d5, 0xd951fb0c, 0xded7da56, 0x4124bbe4, + 0x94ca0b56, 0x0f5755d1, 0xe0e1e56e, 0x6184b5be, + 0x580a249f, 0x94f74bc0, 0xe327888e, 0x9f7b5561, + 0xc3dc0280, 0x05687715, 0x646c6bd7, 0x44904db3, + 0x66b4f0a3, 0xc0f1648a, 0x697ed5af, 0x49e92ff6, + 0x309e374f, 0x2cb6356a, 0x85808573, 0x4991f840, + 0x76f0ae02, 0x083be84d, 0x28421c9a, 0x44489406, + 0x736e4cb8, 0xc1092910, 0x8bc95fc6, 0x7d869cf4, + 0x134f616f, 0x2e77118d, 0xb31b2be1, 0xaa90b472, + 0x3ca5d717, 0x7d161bba, 0x9cad9010, 0xaf462ba2, + 0x9fe459d2, 0x45d34559, 0xd9f2da13, 0xdbc65487, + 0xf3e4f94e, 0x176d486f, 0x097c13ea, 0x631da5c7, + 0x445f7382, 0x175683f4, 0xcdc66a97, 0x70be0288, + 0xb3cdcf72, 0x6e5dd2f3, 0x20936079, 0x459b80a5, + 0xbe60e2db, 0xa9c23101, 0xeba5315c, 0x224e42f2, + 0x1c5c1572, 0xf6721b2c, 0x1ad2fff3, 0x8c25404e, + 0x324ed72f, 0x4067b7fd, 0x0523138e, 0x5ca3bc78, + 0xdc0fd66e, 0x75922283, 0x784d6b17, 0x58ebb16e, + 0x44094f85, 0x3f481d87, 0xfcfeae7b, 0x77b5ff76, + 0x8c2302bf, 0xaaf47556, 0x5f46b02a, 0x2b092801, + 0x3d38f5f7, 0x0ca81f36, 0x52af4a8a, 0x66d5e7c0, + 0xdf3b0874, 0x95055110, 0x1b5ad7a8, 0xf61ed5ad, + 0x6cf6e479, 0x20758184, 0xd0cefa65, 0x88f7be58, + 0x4a046826, 0x0ff6f8f3, 0xa09c7f70, 0x5346aba0, + 0x5ce96c28, 0xe176eda3, 0x6bac307f, 0x376829d2, + 0x85360fa9, 0x17e3fe2a, 0x24b79767, 0xf5a96b20, + 0xd6cd2595, 0x68ff1ebf, 0x7555442c, 0xf19f06be, + 0xf9e0659a, 0xeeb9491d, 0x34010718, 0xbb30cab8, + 0xe822fe15, 0x88570983, 0x750e6249, 0xda627e55, + 0x5e76ffa8, 0xb1534546, 0x6d47de08, 0xefe9e7d4, +}; + +static u_int32_t S6[] = { + 0xf6fa8f9d, 0x2cac6ce1, 0x4ca34867, 0xe2337f7c, + 0x95db08e7, 0x016843b4, 0xeced5cbc, 0x325553ac, + 0xbf9f0960, 0xdfa1e2ed, 0x83f0579d, 0x63ed86b9, + 0x1ab6a6b8, 0xde5ebe39, 0xf38ff732, 0x8989b138, + 0x33f14961, 0xc01937bd, 0xf506c6da, 0xe4625e7e, + 0xa308ea99, 0x4e23e33c, 0x79cbd7cc, 0x48a14367, + 0xa3149619, 0xfec94bd5, 0xa114174a, 0xeaa01866, + 0xa084db2d, 0x09a8486f, 0xa888614a, 0x2900af98, + 0x01665991, 0xe1992863, 0xc8f30c60, 0x2e78ef3c, + 0xd0d51932, 0xcf0fec14, 0xf7ca07d2, 0xd0a82072, + 0xfd41197e, 0x9305a6b0, 0xe86be3da, 0x74bed3cd, + 0x372da53c, 0x4c7f4448, 0xdab5d440, 0x6dba0ec3, + 0x083919a7, 0x9fbaeed9, 0x49dbcfb0, 0x4e670c53, + 0x5c3d9c01, 0x64bdb941, 0x2c0e636a, 0xba7dd9cd, + 0xea6f7388, 0xe70bc762, 0x35f29adb, 0x5c4cdd8d, + 0xf0d48d8c, 0xb88153e2, 0x08a19866, 0x1ae2eac8, + 0x284caf89, 0xaa928223, 0x9334be53, 0x3b3a21bf, + 0x16434be3, 0x9aea3906, 0xefe8c36e, 0xf890cdd9, + 0x80226dae, 0xc340a4a3, 0xdf7e9c09, 0xa694a807, + 0x5b7c5ecc, 0x221db3a6, 0x9a69a02f, 0x68818a54, + 0xceb2296f, 0x53c0843a, 0xfe893655, 0x25bfe68a, + 0xb4628abc, 0xcf222ebf, 0x25ac6f48, 0xa9a99387, + 0x53bddb65, 0xe76ffbe7, 0xe967fd78, 0x0ba93563, + 0x8e342bc1, 0xe8a11be9, 0x4980740d, 0xc8087dfc, + 0x8de4bf99, 0xa11101a0, 0x7fd37975, 0xda5a26c0, + 0xe81f994f, 0x9528cd89, 0xfd339fed, 0xb87834bf, + 0x5f04456d, 0x22258698, 0xc9c4c83b, 0x2dc156be, + 0x4f628daa, 0x57f55ec5, 0xe2220abe, 0xd2916ebf, + 0x4ec75b95, 0x24f2c3c0, 0x42d15d99, 0xcd0d7fa0, + 0x7b6e27ff, 0xa8dc8af0, 0x7345c106, 0xf41e232f, + 0x35162386, 0xe6ea8926, 0x3333b094, 0x157ec6f2, + 0x372b74af, 0x692573e4, 0xe9a9d848, 0xf3160289, + 0x3a62ef1d, 0xa787e238, 0xf3a5f676, 0x74364853, + 0x20951063, 0x4576698d, 0xb6fad407, 0x592af950, + 0x36f73523, 0x4cfb6e87, 0x7da4cec0, 0x6c152daa, + 0xcb0396a8, 0xc50dfe5d, 0xfcd707ab, 0x0921c42f, + 0x89dff0bb, 0x5fe2be78, 0x448f4f33, 0x754613c9, + 0x2b05d08d, 0x48b9d585, 0xdc049441, 0xc8098f9b, + 0x7dede786, 0xc39a3373, 0x42410005, 0x6a091751, + 0x0ef3c8a6, 0x890072d6, 0x28207682, 0xa9a9f7be, + 0xbf32679d, 0xd45b5b75, 0xb353fd00, 0xcbb0e358, + 0x830f220a, 0x1f8fb214, 0xd372cf08, 0xcc3c4a13, + 0x8cf63166, 0x061c87be, 0x88c98f88, 0x6062e397, + 0x47cf8e7a, 0xb6c85283, 0x3cc2acfb, 0x3fc06976, + 0x4e8f0252, 0x64d8314d, 0xda3870e3, 0x1e665459, + 0xc10908f0, 0x513021a5, 0x6c5b68b7, 0x822f8aa0, + 0x3007cd3e, 0x74719eef, 0xdc872681, 0x073340d4, + 0x7e432fd9, 0x0c5ec241, 0x8809286c, 0xf592d891, + 0x08a930f6, 0x957ef305, 0xb7fbffbd, 0xc266e96f, + 0x6fe4ac98, 0xb173ecc0, 0xbc60b42a, 0x953498da, + 0xfba1ae12, 0x2d4bd736, 0x0f25faab, 0xa4f3fceb, + 0xe2969123, 0x257f0c3d, 0x9348af49, 0x361400bc, + 0xe8816f4a, 0x3814f200, 0xa3f94043, 0x9c7a54c2, + 0xbc704f57, 0xda41e7f9, 0xc25ad33a, 0x54f4a084, + 0xb17f5505, 0x59357cbe, 0xedbd15c8, 0x7f97c5ab, + 0xba5ac7b5, 0xb6f6deaf, 0x3a479c3a, 0x5302da25, + 0x653d7e6a, 0x54268d49, 0x51a477ea, 0x5017d55b, + 0xd7d25d88, 0x44136c76, 0x0404a8c8, 0xb8e5a121, + 0xb81a928a, 0x60ed5869, 0x97c55b96, 0xeaec991b, + 0x29935913, 0x01fdb7f1, 0x088e8dfa, 0x9ab6f6f5, + 0x3b4cbf9f, 0x4a5de3ab, 0xe6051d35, 0xa0e1d855, + 0xd36b4cf1, 0xf544edeb, 0xb0e93524, 0xbebb8fbd, + 0xa2d762cf, 0x49c92f54, 0x38b5f331, 0x7128a454, + 0x48392905, 0xa65b1db8, 0x851c97bd, 0xd675cf2f, +}; + +static u_int32_t S7[] = { + 0x85e04019, 0x332bf567, 0x662dbfff, 0xcfc65693, + 0x2a8d7f6f, 0xab9bc912, 0xde6008a1, 0x2028da1f, + 0x0227bce7, 0x4d642916, 0x18fac300, 0x50f18b82, + 0x2cb2cb11, 0xb232e75c, 0x4b3695f2, 0xb28707de, + 0xa05fbcf6, 0xcd4181e9, 0xe150210c, 0xe24ef1bd, + 0xb168c381, 0xfde4e789, 0x5c79b0d8, 0x1e8bfd43, + 0x4d495001, 0x38be4341, 0x913cee1d, 0x92a79c3f, + 0x089766be, 0xbaeeadf4, 0x1286becf, 0xb6eacb19, + 0x2660c200, 0x7565bde4, 0x64241f7a, 0x8248dca9, + 0xc3b3ad66, 0x28136086, 0x0bd8dfa8, 0x356d1cf2, + 0x107789be, 0xb3b2e9ce, 0x0502aa8f, 0x0bc0351e, + 0x166bf52a, 0xeb12ff82, 0xe3486911, 0xd34d7516, + 0x4e7b3aff, 0x5f43671b, 0x9cf6e037, 0x4981ac83, + 0x334266ce, 0x8c9341b7, 0xd0d854c0, 0xcb3a6c88, + 0x47bc2829, 0x4725ba37, 0xa66ad22b, 0x7ad61f1e, + 0x0c5cbafa, 0x4437f107, 0xb6e79962, 0x42d2d816, + 0x0a961288, 0xe1a5c06e, 0x13749e67, 0x72fc081a, + 0xb1d139f7, 0xf9583745, 0xcf19df58, 0xbec3f756, + 0xc06eba30, 0x07211b24, 0x45c28829, 0xc95e317f, + 0xbc8ec511, 0x38bc46e9, 0xc6e6fa14, 0xbae8584a, + 0xad4ebc46, 0x468f508b, 0x7829435f, 0xf124183b, + 0x821dba9f, 0xaff60ff4, 0xea2c4e6d, 0x16e39264, + 0x92544a8b, 0x009b4fc3, 0xaba68ced, 0x9ac96f78, + 0x06a5b79a, 0xb2856e6e, 0x1aec3ca9, 0xbe838688, + 0x0e0804e9, 0x55f1be56, 0xe7e5363b, 0xb3a1f25d, + 0xf7debb85, 0x61fe033c, 0x16746233, 0x3c034c28, + 0xda6d0c74, 0x79aac56c, 0x3ce4e1ad, 0x51f0c802, + 0x98f8f35a, 0x1626a49f, 0xeed82b29, 0x1d382fe3, + 0x0c4fb99a, 0xbb325778, 0x3ec6d97b, 0x6e77a6a9, + 0xcb658b5c, 0xd45230c7, 0x2bd1408b, 0x60c03eb7, + 0xb9068d78, 0xa33754f4, 0xf430c87d, 0xc8a71302, + 0xb96d8c32, 0xebd4e7be, 0xbe8b9d2d, 0x7979fb06, + 0xe7225308, 0x8b75cf77, 0x11ef8da4, 0xe083c858, + 0x8d6b786f, 0x5a6317a6, 0xfa5cf7a0, 0x5dda0033, + 0xf28ebfb0, 0xf5b9c310, 0xa0eac280, 0x08b9767a, + 0xa3d9d2b0, 0x79d34217, 0x021a718d, 0x9ac6336a, + 0x2711fd60, 0x438050e3, 0x069908a8, 0x3d7fedc4, + 0x826d2bef, 0x4eeb8476, 0x488dcf25, 0x36c9d566, + 0x28e74e41, 0xc2610aca, 0x3d49a9cf, 0xbae3b9df, + 0xb65f8de6, 0x92aeaf64, 0x3ac7d5e6, 0x9ea80509, + 0xf22b017d, 0xa4173f70, 0xdd1e16c3, 0x15e0d7f9, + 0x50b1b887, 0x2b9f4fd5, 0x625aba82, 0x6a017962, + 0x2ec01b9c, 0x15488aa9, 0xd716e740, 0x40055a2c, + 0x93d29a22, 0xe32dbf9a, 0x058745b9, 0x3453dc1e, + 0xd699296e, 0x496cff6f, 0x1c9f4986, 0xdfe2ed07, + 0xb87242d1, 0x19de7eae, 0x053e561a, 0x15ad6f8c, + 0x66626c1c, 0x7154c24c, 0xea082b2a, 0x93eb2939, + 0x17dcb0f0, 0x58d4f2ae, 0x9ea294fb, 0x52cf564c, + 0x9883fe66, 0x2ec40581, 0x763953c3, 0x01d6692e, + 0xd3a0c108, 0xa1e7160e, 0xe4f2dfa6, 0x693ed285, + 0x74904698, 0x4c2b0edd, 0x4f757656, 0x5d393378, + 0xa132234f, 0x3d321c5d, 0xc3f5e194, 0x4b269301, + 0xc79f022f, 0x3c997e7e, 0x5e4f9504, 0x3ffafbbd, + 0x76f7ad0e, 0x296693f4, 0x3d1fce6f, 0xc61e45be, + 0xd3b5ab34, 0xf72bf9b7, 0x1b0434c0, 0x4e72b567, + 0x5592a33d, 0xb5229301, 0xcfd2a87f, 0x60aeb767, + 0x1814386b, 0x30bcc33d, 0x38a0c07d, 0xfd1606f2, + 0xc363519b, 0x589dd390, 0x5479f8e6, 0x1cb8d647, + 0x97fd61a9, 0xea7759f4, 0x2d57539d, 0x569a58cf, + 0xe84e63ad, 0x462e1b78, 0x6580f87e, 0xf3817914, + 0x91da55f4, 0x40a230f3, 0xd1988f35, 0xb6e318d2, + 0x3ffa50bc, 0x3d40f021, 0xc3c0bdae, 0x4958c24c, + 0x518f36b2, 0x84b1d370, 0x0fedce83, 0x878ddada, + 0xf2a279c7, 0x94e01be8, 0x90716f4b, 0x954b8aa3, +}; + +static u_int32_t S8[] = { + 0xe216300d, 0xbbddfffc, 0xa7ebdabd, 0x35648095, + 0x7789f8b7, 0xe6c1121b, 0x0e241600, 0x052ce8b5, + 0x11a9cfb0, 0xe5952f11, 0xece7990a, 0x9386d174, + 0x2a42931c, 0x76e38111, 0xb12def3a, 0x37ddddfc, + 0xde9adeb1, 0x0a0cc32c, 0xbe197029, 0x84a00940, + 0xbb243a0f, 0xb4d137cf, 0xb44e79f0, 0x049eedfd, + 0x0b15a15d, 0x480d3168, 0x8bbbde5a, 0x669ded42, + 0xc7ece831, 0x3f8f95e7, 0x72df191b, 0x7580330d, + 0x94074251, 0x5c7dcdfa, 0xabbe6d63, 0xaa402164, + 0xb301d40a, 0x02e7d1ca, 0x53571dae, 0x7a3182a2, + 0x12a8ddec, 0xfdaa335d, 0x176f43e8, 0x71fb46d4, + 0x38129022, 0xce949ad4, 0xb84769ad, 0x965bd862, + 0x82f3d055, 0x66fb9767, 0x15b80b4e, 0x1d5b47a0, + 0x4cfde06f, 0xc28ec4b8, 0x57e8726e, 0x647a78fc, + 0x99865d44, 0x608bd593, 0x6c200e03, 0x39dc5ff6, + 0x5d0b00a3, 0xae63aff2, 0x7e8bd632, 0x70108c0c, + 0xbbd35049, 0x2998df04, 0x980cf42a, 0x9b6df491, + 0x9e7edd53, 0x06918548, 0x58cb7e07, 0x3b74ef2e, + 0x522fffb1, 0xd24708cc, 0x1c7e27cd, 0xa4eb215b, + 0x3cf1d2e2, 0x19b47a38, 0x424f7618, 0x35856039, + 0x9d17dee7, 0x27eb35e6, 0xc9aff67b, 0x36baf5b8, + 0x09c467cd, 0xc18910b1, 0xe11dbf7b, 0x06cd1af8, + 0x7170c608, 0x2d5e3354, 0xd4de495a, 0x64c6d006, + 0xbcc0c62c, 0x3dd00db3, 0x708f8f34, 0x77d51b42, + 0x264f620f, 0x24b8d2bf, 0x15c1b79e, 0x46a52564, + 0xf8d7e54e, 0x3e378160, 0x7895cda5, 0x859c15a5, + 0xe6459788, 0xc37bc75f, 0xdb07ba0c, 0x0676a3ab, + 0x7f229b1e, 0x31842e7b, 0x24259fd7, 0xf8bef472, + 0x835ffcb8, 0x6df4c1f2, 0x96f5b195, 0xfd0af0fc, + 0xb0fe134c, 0xe2506d3d, 0x4f9b12ea, 0xf215f225, + 0xa223736f, 0x9fb4c428, 0x25d04979, 0x34c713f8, + 0xc4618187, 0xea7a6e98, 0x7cd16efc, 0x1436876c, + 0xf1544107, 0xbedeee14, 0x56e9af27, 0xa04aa441, + 0x3cf7c899, 0x92ecbae6, 0xdd67016d, 0x151682eb, + 0xa842eedf, 0xfdba60b4, 0xf1907b75, 0x20e3030f, + 0x24d8c29e, 0xe139673b, 0xefa63fb8, 0x71873054, + 0xb6f2cf3b, 0x9f326442, 0xcb15a4cc, 0xb01a4504, + 0xf1e47d8d, 0x844a1be5, 0xbae7dfdc, 0x42cbda70, + 0xcd7dae0a, 0x57e85b7a, 0xd53f5af6, 0x20cf4d8c, + 0xcea4d428, 0x79d130a4, 0x3486ebfb, 0x33d3cddc, + 0x77853b53, 0x37effcb5, 0xc5068778, 0xe580b3e6, + 0x4e68b8f4, 0xc5c8b37e, 0x0d809ea2, 0x398feb7c, + 0x132a4f94, 0x43b7950e, 0x2fee7d1c, 0x223613bd, + 0xdd06caa2, 0x37df932b, 0xc4248289, 0xacf3ebc3, + 0x5715f6b7, 0xef3478dd, 0xf267616f, 0xc148cbe4, + 0x9052815e, 0x5e410fab, 0xb48a2465, 0x2eda7fa4, + 0xe87b40e4, 0xe98ea084, 0x5889e9e1, 0xefd390fc, + 0xdd07d35b, 0xdb485694, 0x38d7e5b2, 0x57720101, + 0x730edebc, 0x5b643113, 0x94917e4f, 0x503c2fba, + 0x646f1282, 0x7523d24a, 0xe0779695, 0xf9c17a8f, + 0x7a5b2121, 0xd187b896, 0x29263a4d, 0xba510cdf, + 0x81f47c9f, 0xad1163ed, 0xea7b5965, 0x1a00726e, + 0x11403092, 0x00da6d77, 0x4a0cdd61, 0xad1f4603, + 0x605bdfb0, 0x9eedc364, 0x22ebe6a8, 0xcee7d28a, + 0xa0e736a0, 0x5564a6b9, 0x10853209, 0xc7eb8f37, + 0x2de705ca, 0x8951570f, 0xdf09822b, 0xbd691a6c, + 0xaa12e4f2, 0x87451c0f, 0xe0f6a27a, 0x3ada4819, + 0x4cf1764f, 0x0d771c2b, 0x67cdb156, 0x350d8384, + 0x5938fa0f, 0x42399ef3, 0x36997b07, 0x0e84093d, + 0x4aa93e61, 0x8360d87b, 0x1fa98b0c, 0x1149382c, + 0xe97625a5, 0x0614d1b7, 0x0e25244b, 0x0c768347, + 0x589e8d82, 0x0d2059d1, 0xa466bb1e, 0xf8da0a82, + 0x04f19130, 0xba6e4ec0, 0x99265164, 0x1ee7230d, + 0x50b2ad80, 0xeaee6801, 0x8db2a283, 0xea8bf59e, +}; + diff --git a/sys/crypto/cast128/cast128.h b/sys/crypto/cast128/cast128.h new file mode 100644 index 0000000..31c0397 --- /dev/null +++ b/sys/crypto/cast128/cast128.h @@ -0,0 +1,62 @@ +/* + * heavily modified by Tomomi Suzuki <suzuki@grelot.elec.ryukoku.ac.jp> + */ +/* + * The CAST-128 Encryption Algorithm (RFC 2144) + * + * original implementation <Hideo "Sir MaNMOS" Morisita> + * 1997/08/21 + */ +/* + * Copyright (C) 1997 Hideo "Sir MANMOS" Morishita + * 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. + * + * THIS SOFTWARE IS PROVIDED BY Hideo "Sir MaNMOS" Morishita ``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 Hideo "Sir MaNMOS" Morishita 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$ + */ + +#ifndef RFC2144_CAST_128_H +#define RFC2144_CAST_128_H + +#include <sys/param.h> +#include <sys/mbuf.h> + + +#define CAST128_ENCRYPT 1 +#define CAST128_DECRYPT 0 + + +extern void set_cast128_subkey __P((u_int32_t *, u_int8_t *)); +extern void cast128_encrypt_round16 __P((u_int8_t *, const u_int8_t *, + u_int32_t *)); +extern void cast128_decrypt_round16 __P((u_int8_t *, const u_int8_t *, + u_int32_t *)); +extern void cast128_encrypt_round12 __P((u_int8_t *, const u_int8_t *, + u_int32_t *)); +extern void cast128_decrypt_round12 __P((u_int8_t *, const u_int8_t *, + u_int32_t *)); +extern void cast128_cbc_process __P((struct mbuf *, size_t, size_t, + u_int32_t *, u_int8_t *, size_t, int)); + +#endif + diff --git a/sys/crypto/cast128/cast128_cbc.c b/sys/crypto/cast128/cast128_cbc.c new file mode 100644 index 0000000..1dfe2d8 --- /dev/null +++ b/sys/crypto/cast128/cast128_cbc.c @@ -0,0 +1,219 @@ +/* + * 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. + * + * $FreeBSD$ + */ +/* + * based on sys/crypto/des/des_cbc.c, rewrote by Tomomi Suzuki + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <crypto/cast128/cast128.h> + + +void +cast128_cbc_process(m0, skip, length, subkey, iv, keylen, mode) + struct mbuf *m0; + size_t skip; + size_t length; + u_int32_t *subkey; + u_int8_t *iv; + size_t keylen; + int mode; +{ + struct mbuf *m; + u_int8_t inbuf[8], outbuf[8]; + size_t off; + + /* sanity check */ + if (m0->m_pkthdr.len < skip) { + printf("cast128_cbc_process: mbuf length < skip\n"); + return; + } + if (m0->m_pkthdr.len < length) { + printf("cast128_cbc_process: mbuf length < encrypt length\n"); + return; + } + if (m0->m_pkthdr.len < skip + length) { + printf("cast128_cbc_process: " + "mbuf length < skip + encrypt length\n"); + return; + } + if (length % 8) { + printf("cast128_cbc_process: length is not multiple of 8\n"); + return; + } + + m = m0; + off = 0; + + /* skip over the header */ + while (skip) { + if (!m) + panic("cast128_cbc_process: mbuf chain?\n"); + if (m->m_len <= skip) { + skip -= m->m_len; + m = m->m_next; + off = 0; + } else { + off = skip; + skip = 0; + } + } + + /* copy iv into outbuf for XOR (encrypt) */ + bcopy(iv, outbuf, 8); + + /* + * encrypt/decrypt packet + */ + while (length > 0) { + int i; + + if (!m) + panic("cast128_cbc_process: mbuf chain?\n"); + + /* + * copy the source into input buffer. + * don't update off or m, since we need to use them + * later. + */ + if (off + 8 <= m->m_len) + bcopy(mtod(m, u_int8_t *)+off, inbuf, 8); + else { + struct mbuf *n; + size_t noff; + u_int8_t *p, *in; + + n = m; + noff = off; + p = mtod(n, u_int8_t *) + noff; + + in = inbuf; + while (in - inbuf < 8) { + if (!p) { + panic("cast128_cbc_process: " + "mbuf chain?\n"); + } + *in++ = *p++; + noff++; + if (noff < n->m_len) + continue; + do { + n = n->m_next; + } while (n && !n->m_len); + noff = 0; + if (n) + p = mtod(n, u_int8_t *); + else + p = NULL; + } + } + + /* encrypt/decrypt */ + switch (mode) { + case CAST128_ENCRYPT: + /* XOR */ + for (i = 0; i < 8; i++) + inbuf[i] ^= outbuf[i]; + + /* encrypt */ + if (keylen <= 80/8) + cast128_encrypt_round12(outbuf, inbuf, subkey); + else + cast128_encrypt_round16(outbuf, inbuf, subkey); + break; + + case CAST128_DECRYPT: + /* decrypt */ + if (keylen <= 80/8) + cast128_decrypt_round12(outbuf, inbuf, subkey); + else + cast128_decrypt_round16(outbuf, inbuf, subkey); + + /* XOR */ + for (i = 0; i < 8; i++) + outbuf[i] ^= iv[i]; + + /* copy inbuf into iv for next XOR */ + bcopy(inbuf, iv, 8); + break; + } + + /* + * copy the output buffer into the result. + * need to update off and m. + */ + if (off + 8 < m->m_len) { + bcopy(outbuf, mtod(m, u_int8_t *) + off, 8); + off += 8; + } else if (off + 8 == m->m_len) { + bcopy(outbuf, mtod(m, u_int8_t *) + off, 8); + do { + m = m->m_next; + } while (m && !m->m_len); + off = 0; + } else { + struct mbuf *n; + size_t noff; + u_int8_t *p, *out; + + n = m; + noff = off; + p = mtod(n, u_int8_t *) + noff; + + out = outbuf; + while (out - outbuf < 8) { + if (!p) { + panic("cast128_cbc_process: " + "mbuf chain?\n"); + } + *p++ = *out++; + noff++; + if (noff < n->m_len) + continue; + do { + n = n->m_next; + } while (n && !n->m_len); + noff = 0; + if (n) + p = mtod(n, u_int8_t *); + else + p = NULL; + } + + m = n; + off = noff; + } + + length -= 8; + } +} + diff --git a/sys/crypto/cast128/cast128_subkey.h b/sys/crypto/cast128/cast128_subkey.h new file mode 100644 index 0000000..3fd0103 --- /dev/null +++ b/sys/crypto/cast128/cast128_subkey.h @@ -0,0 +1,91 @@ +/* + * heavily modified by Tomomi Suzuki <suzuki@grelot.elec.ryukoku.ac.jp> + */ +/* + * The CAST-128 Encryption Algorithm (RFC 2144) + * + * original implementation <Hideo "Sir MaNMOS" Morisita> + * 1997/08/21 + */ +/* + * Copyright (C) 1997 Hideo "Sir MANMOS" Morishita + * 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. + * + * THIS SOFTWARE IS PROVIDED BY Hideo "Sir MaNMOS" Morishita ``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 Hideo "Sir MaNMOS" Morishita 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$ + */ + +#ifndef RFC2144_CAST_128_SUBKEY_H +#define RFC2144_CAST_128_SUBKEY_H + +#define x0x1x2x3 buf[0] +#define x4x5x6x7 buf[1] +#define x8x9xAxB buf[2] +#define xCxDxExF buf[3] +#define z0z1z2z3 buf[4] +#define z4z5z6z7 buf[5] +#define z8z9zAzB buf[6] +#define zCzDzEzF buf[7] + +#define byte0(x) (((x) >> 24)) +#define byte1(x) (((x) >> 16) & 0xff) +#define byte2(x) (((x) >> 8) & 0xff) +#define byte3(x) (((x)) & 0xff) + +#define x0 byte0(buf[0]) +#define x1 byte1(buf[0]) +#define x2 byte2(buf[0]) +#define x3 byte3(buf[0]) +#define x4 byte0(buf[1]) +#define x5 byte1(buf[1]) +#define x6 byte2(buf[1]) +#define x7 byte3(buf[1]) +#define x8 byte0(buf[2]) +#define x9 byte1(buf[2]) +#define xA byte2(buf[2]) +#define xB byte3(buf[2]) +#define xC byte0(buf[3]) +#define xD byte1(buf[3]) +#define xE byte2(buf[3]) +#define xF byte3(buf[3]) +#define z0 byte0(buf[4]) +#define z1 byte1(buf[4]) +#define z2 byte2(buf[4]) +#define z3 byte3(buf[4]) +#define z4 byte0(buf[5]) +#define z5 byte1(buf[5]) +#define z6 byte2(buf[5]) +#define z7 byte3(buf[5]) +#define z8 byte0(buf[6]) +#define z9 byte1(buf[6]) +#define zA byte2(buf[6]) +#define zB byte3(buf[6]) +#define zC byte0(buf[7]) +#define zD byte1(buf[7]) +#define zE byte2(buf[7]) +#define zF byte3(buf[7]) + +#define circular_leftshift(x, y) ( ((x) << (y)) | ((x) >> (32-(y))) ) + +#endif + diff --git a/sys/crypto/des/des.h b/sys/crypto/des/des.h new file mode 100644 index 0000000..16a8129 --- /dev/null +++ b/sys/crypto/des/des.h @@ -0,0 +1,280 @@ +/* lib/des/des.h */ +/* Copyright (C) 1995-1996 Eric Young (eay@mincom.oz.au) + * All rights reserved. + * + * This file is part of an SSL implementation written + * by Eric Young (eay@mincom.oz.au). + * The implementation was written so as to conform with Netscapes SSL + * specification. This library and applications are + * FREE FOR COMMERCIAL AND NON-COMMERCIAL USE + * as long as the following conditions are aheared to. + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. If this code is used in a product, + * Eric Young should be given attribution as the author of the parts used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Eric Young (eay@mincom.oz.au) + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 AUTHOR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + * + * $FreeBSD$ + */ + +#ifndef HEADER_DES_H +#define HEADER_DES_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* If this is set to 'unsigned int' on a DEC Alpha, this gives about a + * %20 speed up (longs are 8 bytes, int's are 4). */ +#ifndef DES_LONG +#define DES_LONG unsigned long +#endif + +typedef unsigned char des_cblock[8]; +typedef struct des_ks_struct + { + union { + des_cblock _; + /* make sure things are correct size on machines with + * 8 byte longs */ + DES_LONG pad[2]; + } ks; +#undef _ +#define _ ks._ + } des_key_schedule[16]; + +#define DES_KEY_SZ (sizeof(des_cblock)) +#define DES_SCHEDULE_SZ (sizeof(des_key_schedule)) + +#define DES_ENCRYPT 1 +#define DES_DECRYPT 0 + +#define DES_CBC_MODE 0 +#define DES_PCBC_MODE 1 + +#define des_ecb2_encrypt(i,o,k1,k2,e) \ + des_ecb3_encrypt((i),(o),(k1),(k2),(k1),(e)) + +#define des_ede2_cbc_encrypt(i,o,l,k1,k2,iv,e) \ + des_ede3_cbc_encrypt((i),(o),(l),(k1),(k2),(k1),(iv),(e)) + +#define des_ede2_cfb64_encrypt(i,o,l,k1,k2,iv,n,e) \ + des_ede3_cfb64_encrypt((i),(o),(l),(k1),(k2),(k1),(iv),(n),(e)) + +#define des_ede2_ofb64_encrypt(i,o,l,k1,k2,iv,n) \ + des_ede3_ofb64_encrypt((i),(o),(l),(k1),(k2),(k1),(iv),(n)) + +#define C_Block des_cblock +#define Key_schedule des_key_schedule +#ifdef KERBEROS +#define ENCRYPT DES_ENCRYPT +#define DECRYPT DES_DECRYPT +#endif +#define KEY_SZ DES_KEY_SZ +#define string_to_key des_string_to_key +#define read_pw_string des_read_pw_string +#define random_key des_random_key +#define pcbc_encrypt des_pcbc_encrypt +#define set_key des_set_key +#define key_sched des_key_sched +#define ecb_encrypt des_ecb_encrypt +#define cbc_encrypt des_cbc_encrypt +#define ncbc_encrypt des_ncbc_encrypt +#define xcbc_encrypt des_xcbc_encrypt +#define cbc_cksum des_cbc_cksum +#define quad_cksum des_quad_cksum + +/* For compatibility with the MIT lib - eay 20/05/92 */ +typedef des_key_schedule bit_64; +#define des_fixup_key_parity des_set_odd_parity +#define des_check_key_parity check_parity + +extern int des_check_key; /* defaults to false */ +extern int des_rw_mode; /* defaults to DES_PCBC_MODE */ + +/* The next line is used to disable full ANSI prototypes, if your + * compiler has problems with the prototypes, make sure this line always + * evaluates to true :-) */ +#if defined(MSDOS) || defined(__STDC__) +#undef NOPROTO +#endif +#ifndef NOPROTO +char *des_options(void); +void des_ecb3_encrypt(des_cblock *input,des_cblock *output, + des_key_schedule ks1,des_key_schedule ks2, + des_key_schedule ks3, int enc); +DES_LONG des_cbc_cksum(des_cblock *input,des_cblock *output, + long length,des_key_schedule schedule,des_cblock *ivec); +/* +void des_cbc_encrypt(des_cblock *input,des_cblock *output,long length, + des_key_schedule schedule,des_cblock *ivec,int enc); +*/ +void des_cbc_encrypt(struct mbuf *, size_t, size_t, + des_key_schedule schedule,des_cblock *ivec, int enc); +void des_ncbc_encrypt(des_cblock *input,des_cblock *output,long length, + des_key_schedule schedule,des_cblock *ivec,int enc); +void des_xcbc_encrypt(des_cblock *input,des_cblock *output,long length, + des_key_schedule schedule,des_cblock *ivec, + des_cblock *inw,des_cblock *outw,int enc); +void des_3cbc_encrypt(des_cblock *input,des_cblock *output,long length, + des_key_schedule sk1,des_key_schedule sk2, + des_cblock *ivec1,des_cblock *ivec2,int enc); +extern void des_3cbc_process(struct mbuf *, size_t, size_t, + des_key_schedule *schedule, des_cblock *ivec, int mode); +void des_cfb_encrypt(unsigned char *in,unsigned char *out,int numbits, + long length,des_key_schedule schedule,des_cblock *ivec,int enc); +void des_ecb_encrypt(des_cblock *input,des_cblock *output, + des_key_schedule ks,int enc); +void des_encrypt(DES_LONG *data,des_key_schedule ks, int enc); +void des_encrypt2(DES_LONG *data,des_key_schedule ks, int enc); +void des_ede3_cbc_encrypt(des_cblock *input, des_cblock *output, + long length, des_key_schedule ks1, des_key_schedule ks2, + des_key_schedule ks3, des_cblock *ivec, int enc); +void des_ede3_cfb64_encrypt(unsigned char *in, unsigned char *out, + long length, des_key_schedule ks1, des_key_schedule ks2, + des_key_schedule ks3, des_cblock *ivec, int *num, int encrypt); +void des_ede3_ofb64_encrypt(unsigned char *in, unsigned char *out, + long length, des_key_schedule ks1, des_key_schedule ks2, + des_key_schedule ks3, des_cblock *ivec, int *num); + +int des_enc_read(int fd,char *buf,int len,des_key_schedule sched, + des_cblock *iv); +int des_enc_write(int fd,char *buf,int len,des_key_schedule sched, + des_cblock *iv); +#ifdef PERL5 +char *des_crypt(const char *buf,const char *salt); +#else +/* some stupid compilers complain because I have declared char instead + * of const char */ +#if 1 +char *crypt(const char *buf,const char *salt); +#else +char *crypt(); +#endif +#endif +void des_ofb_encrypt(unsigned char *in,unsigned char *out, + int numbits,long length,des_key_schedule schedule,des_cblock *ivec); +void des_pcbc_encrypt(des_cblock *input,des_cblock *output,long length, + des_key_schedule schedule,des_cblock *ivec,int enc); +DES_LONG des_quad_cksum(des_cblock *input,des_cblock *output, + long length,int out_count,des_cblock *seed); +void des_random_seed(des_cblock key); +void des_random_key(des_cblock ret); +int des_read_password(des_cblock *key,char *prompt,int verify); +int des_read_2passwords(des_cblock *key1,des_cblock *key2, + char *prompt,int verify); +int des_read_pw_string(char *buf,int length,char *prompt,int verify); +void des_set_odd_parity(des_cblock *key); +int des_is_weak_key(des_cblock *key); +int des_set_key(des_cblock *key,des_key_schedule schedule); +int des_key_sched(des_cblock *key,des_key_schedule schedule); +void des_string_to_key(char *str,des_cblock *key); +void des_string_to_2keys(char *str,des_cblock *key1,des_cblock *key2); +void des_cfb64_encrypt(unsigned char *in, unsigned char *out, long length, + des_key_schedule schedule, des_cblock *ivec, int *num, int enc); +void des_ofb64_encrypt(unsigned char *in, unsigned char *out, long length, + des_key_schedule schedule, des_cblock *ivec, int *num); + +/* Extra functions from Mark Murray <mark@grondar.za> */ +/* +void des_cblock_print_file(des_cblock *cb, FILE *fp); +*/ +/* The following functions are not in the normal unix build or the + * SSLeay build. When using the SSLeay build, use RAND_seed() + * and RAND_bytes() instead. */ +int des_new_random_key(des_cblock *key); +void des_init_random_number_generator(des_cblock *key); +void des_set_random_generator_seed(des_cblock *key); +void des_set_sequence_number(des_cblock new_sequence_number); +void des_generate_random_block(des_cblock *block); + +#else + +char *des_options(); +void des_ecb3_encrypt(); +DES_LONG des_cbc_cksum(); +void des_cbc_encrypt(); +void des_ncbc_encrypt(); +void des_xcbc_encrypt(); +void des_3cbc_encrypt(); +void des_cfb_encrypt(); +void des_ede3_cfb64_encrypt(); +void des_ede3_ofb64_encrypt(); +void des_ecb_encrypt(); +void des_encrypt(); +void des_encrypt2(); +void des_ede3_cbc_encrypt(); +int des_enc_read(); +int des_enc_write(); +#ifdef PERL5 +char *des_crypt(); +#else +char *crypt(); +#endif +void des_ofb_encrypt(); +void des_pcbc_encrypt(); +DES_LONG des_quad_cksum(); +void des_random_seed(); +void des_random_key(); +int des_read_password(); +int des_read_2passwords(); +int des_read_pw_string(); +void des_set_odd_parity(); +int des_is_weak_key(); +int des_set_key(); +int des_key_sched(); +void des_string_to_key(); +void des_string_to_2keys(); +void des_cfb64_encrypt(); +void des_ofb64_encrypt(); + +/* Extra functions from Mark Murray <mark@grondar.za> */ +void des_cblock_print_file(); +/* The following functions are not in the normal unix build or the + * SSLeay build. When using the SSLeay build, use RAND_seed() + * and RAND_bytes() instead. */ +#ifdef FreeBSD +int des_new_random_key(); +void des_init_random_number_generator(); +void des_set_random_generator_seed(); +void des_set_sequence_number(); +void des_generate_random_block(); +#endif + +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/sys/crypto/des/des_3cbc.c b/sys/crypto/des/des_3cbc.c new file mode 100644 index 0000000..7ddb06c --- /dev/null +++ b/sys/crypto/des/des_3cbc.c @@ -0,0 +1,246 @@ +/* + * 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. + * + * $FreeBSD$ + */ +/* + * based on sys/crypto/des/des_cbc.c, rewrote by Tomomi Suzuki + */ +#include <crypto/des/des_locl.h> + + +void des_3cbc_process(m0, skip, length, schedule, ivec, mode) + struct mbuf *m0; + size_t skip; + size_t length; + des_key_schedule *schedule; + des_cblock (*ivec); + int mode; +{ + u_int8_t inbuf[8], outbuf[8]; + struct mbuf *m; + size_t off; + DES_LONG tin0, tin1; + DES_LONG tout0, tout1; + DES_LONG tin[2]; + DES_LONG xor0 = 0, xor1 = 0; + u_int8_t *iv; + u_int8_t *in, *out; + + /* sanity check */ + if (m0->m_pkthdr.len < skip) { + printf("des_3cbc_process: mbuf length < skip\n"); + return; + } + if (m0->m_pkthdr.len < length) { + printf("des_3cbc_process: mbuf length < encrypt length\n"); + return; + } + if (m0->m_pkthdr.len < skip + length) { + printf("des_3cbc_process: mbuf length < " + "skip + encrypt length\n"); + return; + } + if (length % 8) { + printf("des_3cbc_process: length(%lu) is not multiple of 8\n", + (u_long)length); + return; + } + + m = m0; + off = 0; + + /* skip over the header */ + while (skip) { + if (!m) + panic("des_3cbc_process: mbuf chain?\n"); + if (m->m_len <= skip) { + skip -= m->m_len; + m = m->m_next; + off = 0; + } else { + off = skip; + skip = 0; + } + } + + /* initialize */ + tin0 = tin1 = tout0 = tout1 = 0; + tin[0] = tin[1] = 0; + + switch (mode) { + case DES_ENCRYPT: + iv = (u_int8_t *)ivec; + c2l(iv, tout0); + c2l(iv, tout1); + break; + case DES_DECRYPT: + xor0 = xor1 = 0; + iv = (u_int8_t *)ivec; + c2l(iv, xor0); + c2l(iv, xor1); + break; + } + + /* + * encrypt/decrypt packet + */ + while (length > 0) { + if (!m) + panic("des_3cbc_process: mbuf chain?\n"); + + /* + * copy the source into input buffer. + * don't update off or m, since we need to use them + * later. + */ + if (off + 8 <= m->m_len) + bcopy(mtod(m, u_int8_t *) + off, &inbuf[0], 8); + else { + struct mbuf *n; + size_t noff; + u_int8_t *p; + u_int8_t *in; + + n = m; + noff = off; + p = mtod(n, u_int8_t *) + noff; + + in = &inbuf[0]; + while (in - &inbuf[0] < 8) { + if (!p) { + panic("des_3cbc_process: " + "mbuf chain?\n"); + } + *in++ = *p++; + noff++; + if (noff < n->m_len) + continue; + do { + n = n->m_next; + } while (n && !n->m_len); + noff = 0; + if (n) + p = mtod(n, u_int8_t *) + noff; + else + p = NULL; + } + } + + /* encrypt/decrypt */ + switch (mode) { + case DES_ENCRYPT: + in = &inbuf[0]; + out = &outbuf[0]; + c2l(in, tin0); + c2l(in, tin1); + + /* XOR */ + tin0 ^= tout0; tin[0] = tin0; + tin1 ^= tout1; tin[1] = tin1; + + des_encrypt((DES_LONG *)tin, schedule[0], DES_ENCRYPT); + des_encrypt((DES_LONG *)tin, schedule[1], DES_DECRYPT); + des_encrypt((DES_LONG *)tin, schedule[2], DES_ENCRYPT); + + tout0 = tin[0]; l2c(tout0, out); + tout1 = tin[1]; l2c(tout1, out); + break; + case DES_DECRYPT: + in = &inbuf[0]; + out = &outbuf[0]; + c2l(in, tin0); tin[0] = tin0; + c2l(in, tin1); tin[1] = tin1; + + des_encrypt((DES_LONG *)tin, schedule[2], DES_DECRYPT); + des_encrypt((DES_LONG *)tin, schedule[1], DES_ENCRYPT); + des_encrypt((DES_LONG *)tin, schedule[0], DES_DECRYPT); + + /* XOR */ + tout0 = tin[0] ^ xor0; + tout1 = tin[1] ^ xor1; + l2c(tout0, out); + l2c(tout1, out); + + /* for next iv */ + xor0 = tin0; + xor1 = tin1; + break; + } + + /* + * copy the output buffer int the result. + * need to update off and m. + */ + if (off + 8 < m->m_len) { + bcopy(&outbuf[0], mtod(m, u_int8_t *) + off, 8); + off += 8; + } else if (off + 8 == m->m_len) { + bcopy(&outbuf[0], mtod(m, u_int8_t *) + off, 8); + do { + m = m->m_next; + } while (m && !m->m_len); + off = 0; + } else { + struct mbuf *n; + size_t noff; + u_int8_t *p; + u_int8_t *out; + + n = m; + noff = off; + p = mtod(n, u_int8_t *) + noff; + + out = &outbuf[0]; + while (out - &outbuf[0] < 8) { + if (!p) { + panic("des_3cbc_process: " + "mbuf chain?\n"); + } + *p++ = *out++; + noff++; + if (noff < n->m_len) + continue; + do { + n = n->m_next; + } while (n && !n->m_len); + noff = 0; + if (n) + p = mtod(n, u_int8_t *) + noff; + else + p = NULL; + } + + m = n; + off = noff; + } + + length -= 8; + } +} + diff --git a/sys/crypto/des/des_cbc.c b/sys/crypto/des/des_cbc.c new file mode 100644 index 0000000..665352a --- /dev/null +++ b/sys/crypto/des/des_cbc.c @@ -0,0 +1,328 @@ +/* + * heavily modified by Yoshifumi Nishida <nishida@sfc.wide.ad.jp>. + * then, completely rewrote by Jun-ichiro itojun Itoh <itojun@itojun.org>, + * 1997. + */ +/* crypto/des/cbc_enc.c */ +/* Copyright (C) 1995-1996 Eric Young (eay@mincom.oz.au) + * All rights reserved. + * + * This file is part of an SSL implementation written + * by Eric Young (eay@mincom.oz.au). + * The implementation was written so as to conform with Netscapes SSL + * specification. This library and applications are + * FREE FOR COMMERCIAL AND NON-COMMERCIAL USE + * as long as the following conditions are aheared to. + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. If this code is used in a product, + * Eric Young should be given attribution as the author of the parts used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Eric Young (eay@mincom.oz.au) + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 AUTHOR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + * + * $FreeBSD$ + */ + +#include <crypto/des/des_locl.h> + +#define panic(x) {printf(x); return;} + +void des_cbc_encrypt(m0, skip, length, schedule, ivec, mode) + struct mbuf *m0; + size_t skip; + size_t length; + des_key_schedule schedule; + des_cblock (*ivec); + int mode; +{ + u_int8_t inbuf[8], outbuf[8]; + struct mbuf *m; + size_t off; + register DES_LONG tin0, tin1; + register DES_LONG tout0, tout1; + DES_LONG tin[2]; + u_int8_t *iv; + + /* sanity checks */ + if (m0->m_pkthdr.len < skip) { + printf("mbuf length < skip\n"); + return; + } + if (m0->m_pkthdr.len < length) { + printf("mbuf length < encrypt length\n"); + return; + } + if (m0->m_pkthdr.len < skip + length) { + printf("mbuf length < skip + encrypt length\n"); + return; + } + if (length % 8) { + printf("length is not multiple of 8\n"); + return; + } + + m = m0; + off = 0; + + /* skip over the header */ + while (skip) { + if (!m) + panic("mbuf chain?\n"); + if (m->m_len <= skip) { + skip -= m->m_len; + m = m->m_next; + off = 0; + } else { + off = skip; + skip = 0; + } + } + + /* initialize */ + tin0 = tin1 = tout0 = tout1 = 0; + tin[0] = tin[1] = 0; + + if (mode == DES_ENCRYPT) { + u_int8_t *in, *out; + + iv = (u_int8_t *)ivec; + c2l(iv, tout0); + c2l(iv, tout1); + + while (0 < length) { + if (!m) + panic("mbuf chain?\n"); + + /* + * copy the source into input buffer. + * don't update off or m, since we need to use them * later. + */ + if (off + 8 <= m->m_len) + bcopy(mtod(m, u_int8_t *) + off, &inbuf[0], 8); + else { + struct mbuf *n; + size_t noff; + u_int8_t *p; + u_int8_t *in; + + n = m; + noff = off; + p = mtod(n, u_int8_t *) + noff; + + in = &inbuf[0]; + while (in - &inbuf[0] < 8) { + if (!p) + panic("mbuf chain?\n"); + + *in++ = *p++; + noff++; + if (noff < n->m_len) + continue; + do { + n = n->m_next; + } while (n && ! n->m_len); + noff = 0; + if (n) + p = mtod(n, u_int8_t *) + noff; + else + p = NULL; + } + } + + in = &inbuf[0]; + out = &outbuf[0]; + c2l(in, tin0); + c2l(in, tin1); + + tin0 ^= tout0; tin[0] = tin0; + tin1 ^= tout1; tin[1] = tin1; + des_encrypt((DES_LONG *)tin, schedule, DES_ENCRYPT); + tout0 = tin[0]; l2c(tout0, out); + tout1 = tin[1]; l2c(tout1, out); + + /* + * copy the output buffer into the result. + * need to update off and m. + */ + if (off + 8 < m->m_len) { + bcopy(&outbuf[0], mtod(m, u_int8_t *) + off, 8); + off += 8; + } else if (off + 8 == m->m_len) { + bcopy(&outbuf[0], mtod(m, u_int8_t *) + off, 8); + do { + m = m->m_next; + } while (m && ! m->m_len); + off = 0; + } else { + struct mbuf *n; + size_t noff; + u_int8_t *p; + u_int8_t *out; + + n = m; + noff = off; + p = mtod(n, u_int8_t *) + noff; + + out = &outbuf[0]; + while (out - &outbuf[0] < 8) { + if (!p) + panic("mbuf chain?"); + *p++ = *out++; + noff++; + if (noff < n->m_len) + continue; + do { + n = n->m_next; + } while (n && ! n->m_len); + noff = 0; + if (n) + p = mtod(n, u_int8_t *) + noff; + else + p = NULL; + } + + m = n; + off = noff; + } + + length -= 8; + } + } else if (mode == DES_DECRYPT) { + register DES_LONG xor0, xor1; + u_int8_t *in, *out; + + xor0 = xor1 = 0; + iv = (u_int8_t *)ivec; + c2l(iv, xor0); + c2l(iv, xor1); + + while (0 < length) { + if (!m) + panic("mbuf chain?\n"); + + /* + * copy the source into input buffer. + * don't update off or m, since we need to use them * later. + */ + if (off + 8 <= m->m_len) + bcopy(mtod(m, u_int8_t *) + off, &inbuf[0], 8); + else { + struct mbuf *n; + size_t noff; + u_int8_t *p; + u_int8_t *in; + + n = m; + noff = off; + p = mtod(n, u_int8_t *) + noff; + + in = &inbuf[0]; + while (in - &inbuf[0] < 8) { + if (!p) + panic("mbuf chain?\n"); + *in++ = *p++; + noff++; + if (noff < n->m_len) + continue; + do { + n = n->m_next; + } while (n && ! n->m_len); + noff = 0; + if (n) + p = mtod(n, u_int8_t *) + noff; + else + p = NULL; + } + } + + in = &inbuf[0]; + out = &outbuf[0]; + c2l(in, tin0); tin[0] = tin0; + c2l(in, tin1); tin[1] = tin1; + des_encrypt((DES_LONG *)tin, schedule, DES_DECRYPT); + tout0 = tin[0] ^ xor0; + tout1 = tin[1] ^ xor1; + l2c(tout0, out); + l2c(tout1, out); + xor0 = tin0; + xor1 = tin1; + + + /* + * copy the output buffer into the result. + * need to update off and m. + */ + if (off + 8 < m->m_len) { + bcopy(&outbuf[0], mtod(m, u_int8_t *) + off, 8); + off += 8; + } else if (off + 8 == m->m_len) { + bcopy(&outbuf[0], mtod(m, u_int8_t *) + off, 8); + do { + m = m->m_next; + } while (m && ! m->m_len); + off = 0; + } else { + struct mbuf *n; + size_t noff; + u_int8_t *p; + u_int8_t *out; + + n = m; + noff = off; + p = mtod(n, u_int8_t *) + noff; + + out = &outbuf[0]; + while (out - &outbuf[0] < 8) { + if (!p) + panic("mbuf chain?\n"); + *p++ = *out++; + noff++; + if (noff < n->m_len) + continue; + do { + n = n->m_next; + } while (n && ! n->m_len); + noff = 0; + if (n) + p = mtod(n, u_int8_t *) + noff; + else + p = NULL; + } + + m = n; + off = noff; + } + + length -= 8; + } + } +} diff --git a/sys/crypto/des/des_ecb.c b/sys/crypto/des/des_ecb.c new file mode 100644 index 0000000..9e74d6c --- /dev/null +++ b/sys/crypto/des/des_ecb.c @@ -0,0 +1,231 @@ +/* crypto/des/ecb_enc.c */ +/* Copyright (C) 1995-1996 Eric Young (eay@mincom.oz.au) + * All rights reserved. + * + * This file is part of an SSL implementation written + * by Eric Young (eay@mincom.oz.au). + * The implementation was written so as to conform with Netscapes SSL + * specification. This library and applications are + * FREE FOR COMMERCIAL AND NON-COMMERCIAL USE + * as long as the following conditions are aheared to. + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. If this code is used in a product, + * Eric Young should be given attribution as the author of the parts used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Eric Young (eay@mincom.oz.au) + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 AUTHOR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + * + * $FreeBSD$ + */ + +#include <crypto/des/des_locl.h> +#include <crypto/des/spr.h> + +char *libdes_version="libdes v 3.24 - 20-Apr-1996 - eay"; +char *DES_version="DES part of SSLeay 0.6.4 30-Aug-1996"; + +char *des_options() + { +#ifdef DES_PTR + if (sizeof(DES_LONG) != sizeof(long)) + return("des(ptr,int)"); + else + return("des(ptr,long)"); +#else + if (sizeof(DES_LONG) != sizeof(long)) + return("des(idx,int)"); + else + return("des(idx,long)"); +#endif + } + + +void des_ecb_encrypt(input, output, ks, encrypt) +des_cblock (*input); +des_cblock (*output); +des_key_schedule ks; +int encrypt; + { + register DES_LONG l; + register unsigned char *in,*out; + DES_LONG ll[2]; + + in=(unsigned char *)input; + out=(unsigned char *)output; + c2l(in,l); ll[0]=l; + c2l(in,l); ll[1]=l; + des_encrypt(ll,ks,encrypt); + l=ll[0]; l2c(l,out); + l=ll[1]; l2c(l,out); + l=ll[0]=ll[1]=0; + } + +void des_encrypt(data, ks, encrypt) +DES_LONG *data; +des_key_schedule ks; +int encrypt; + { + register DES_LONG l,r,t,u; +#ifdef DES_PTR + register unsigned char *des_SP=(unsigned char *)des_SPtrans; +#endif +#ifdef undef + union fudge { + DES_LONG l; + unsigned short s[2]; + unsigned char c[4]; + } U,T; +#endif + register int i; + register DES_LONG *s; + + u=data[0]; + r=data[1]; + + IP(u,r); + /* Things have been modified so that the initial rotate is + * done outside the loop. This required the + * des_SPtrans values in sp.h to be rotated 1 bit to the right. + * One perl script later and things have a 5% speed up on a sparc2. + * Thanks to Richard Outerbridge <71755.204@CompuServe.COM> + * for pointing this out. */ + l=(r<<1)|(r>>31); + r=(u<<1)|(u>>31); + + /* clear the top bits on machines with 8byte longs */ + l&=0xffffffffL; + r&=0xffffffffL; + + s=(DES_LONG *)ks; + /* I don't know if it is worth the effort of loop unrolling the + * inner loop + */ + if (encrypt) + { + for (i=0; i<32; i+=8) + { + D_ENCRYPT(l,r,i+0); /* 1 */ + D_ENCRYPT(r,l,i+2); /* 2 */ + D_ENCRYPT(l,r,i+4); /* 3 */ + D_ENCRYPT(r,l,i+6); /* 4 */ + } + } + else + { + for (i=30; i>0; i-=8) + { + D_ENCRYPT(l,r,i-0); /* 16 */ + D_ENCRYPT(r,l,i-2); /* 15 */ + D_ENCRYPT(l,r,i-4); /* 14 */ + D_ENCRYPT(r,l,i-6); /* 13 */ + } + } + l=(l>>1)|(l<<31); + r=(r>>1)|(r<<31); + /* clear the top bits on machines with 8byte longs */ + l&=0xffffffffL; + r&=0xffffffffL; + + FP(r,l); + data[0]=l; + data[1]=r; + l=r=t=u=0; + } + +void des_encrypt2(data, ks, encrypt) +DES_LONG *data; +des_key_schedule ks; +int encrypt; + { + register DES_LONG l,r,t,u; +#ifdef DES_PTR + register unsigned char *des_SP=(unsigned char *)des_SPtrans; +#endif +#ifdef undef + union fudge { + DES_LONG l; + unsigned short s[2]; + unsigned char c[4]; + } U,T; +#endif + register int i; + register DES_LONG *s; + + u=data[0]; + r=data[1]; + + /* Things have been modified so that the initial rotate is + * done outside the loop. This required the + * des_SPtrans values in sp.h to be rotated 1 bit to the right. + * One perl script later and things have a 5% speed up on a sparc2. + * Thanks to Richard Outerbridge <71755.204@CompuServe.COM> + * for pointing this out. */ + l=(r<<1)|(r>>31); + r=(u<<1)|(u>>31); + + /* clear the top bits on machines with 8byte longs */ + l&=0xffffffffL; + r&=0xffffffffL; + + s=(DES_LONG *)ks; + /* I don't know if it is worth the effort of loop unrolling the + * inner loop */ + if (encrypt) + { + for (i=0; i<32; i+=8) + { + D_ENCRYPT(l,r,i+0); /* 1 */ + D_ENCRYPT(r,l,i+2); /* 2 */ + D_ENCRYPT(l,r,i+4); /* 3 */ + D_ENCRYPT(r,l,i+6); /* 4 */ + } + } + else + { + for (i=30; i>0; i-=8) + { + D_ENCRYPT(l,r,i-0); /* 16 */ + D_ENCRYPT(r,l,i-2); /* 15 */ + D_ENCRYPT(l,r,i-4); /* 14 */ + D_ENCRYPT(r,l,i-6); /* 13 */ + } + } + l=(l>>1)|(l<<31); + r=(r>>1)|(r<<31); + /* clear the top bits on machines with 8byte longs */ + l&=0xffffffffL; + r&=0xffffffffL; + + data[0]=l; + data[1]=r; + l=r=t=u=0; + } diff --git a/sys/crypto/des/des_locl.h b/sys/crypto/des/des_locl.h new file mode 100644 index 0000000..4f23984 --- /dev/null +++ b/sys/crypto/des/des_locl.h @@ -0,0 +1,347 @@ +/* lib/des/des_locl.h */ +/* Copyright (C) 1995-1996 Eric Young (eay@mincom.oz.au) + * All rights reserved. + * + * This file is part of an SSL implementation written + * by Eric Young (eay@mincom.oz.au). + * The implementation was written so as to conform with Netscapes SSL + * specification. This library and applications are + * FREE FOR COMMERCIAL AND NON-COMMERCIAL USE + * as long as the following conditions are aheared to. + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. If this code is used in a product, + * Eric Young should be given attribution as the author of the parts used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Eric Young (eay@mincom.oz.au) + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 AUTHOR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + * + * $FreeBSD$ + */ +/* WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING + * + * Always modify des_locl.org since des_locl.h is automatically generated from + * it during SSLeay configuration. + * + * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING + */ + +#include <sys/param.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/systm.h> + +#ifndef HEADER_DES_LOCL_H +#define HEADER_DES_LOCL_H + +#if defined(WIN32) || defined(WIN16) +#ifndef MSDOS +#define MSDOS +#endif +#endif + +/* +#include <stdio.h> +#include <stdlib.h> +#ifndef MSDOS +#include <unistd.h> +#endif +*/ +#include <crypto/des/des.h> + +/* the following is tweaked from a config script, that is why it is a + * protected undef/define */ +#ifndef DES_PTR +#undef DES_PTR +#endif + +#ifdef MSDOS /* Visual C++ 2.1 (Windows NT/95) */ +#include <stdlib.h> +#include <errno.h> +#include <time.h> +#include <io.h> +#ifndef RAND +#define RAND +#endif +#undef NOPROTO +#endif + +#if !defined(KERNEL) && (defined(__STDC__) || defined(VMS) || defined(M_XENIX) || defined(MSDOS)) +#ifndef __NetBSD__ +#include <string.h> +#endif +#endif + +#ifdef __NetBSD__ +#include <sys/systm.h> +#endif + +#ifndef RAND +#define RAND +#endif + +#ifdef linux +#undef RAND +#endif + +#ifdef MSDOS +#define getpid() 2 +#define RAND +#undef NOPROTO +#endif + +#if defined(NOCONST) +#define const +#endif + +#ifdef __STDC__ +#undef NOPROTO +#endif + +#ifdef RAND +#define srandom(s) srand(s) +#define random rand +#endif + +#define ITERATIONS 16 +#define HALF_ITERATIONS 8 + +/* used in des_read and des_write */ +#define MAXWRITE (1024*16) +#define BSIZE (MAXWRITE+4) + +#define c2l(c,l) (l =((DES_LONG)(*((c)++))) , \ + l|=((DES_LONG)(*((c)++)))<< 8L, \ + l|=((DES_LONG)(*((c)++)))<<16L, \ + l|=((DES_LONG)(*((c)++)))<<24L) + +/* NOTE - c is not incremented as per c2l */ +#define c2ln(c,l1,l2,n) { \ + c+=n; \ + l1=l2=0; \ + switch (n) { \ + case 8: l2 =((DES_LONG)(*(--(c))))<<24L; \ + case 7: l2|=((DES_LONG)(*(--(c))))<<16L; \ + case 6: l2|=((DES_LONG)(*(--(c))))<< 8L; \ + case 5: l2|=((DES_LONG)(*(--(c)))); \ + case 4: l1 =((DES_LONG)(*(--(c))))<<24L; \ + case 3: l1|=((DES_LONG)(*(--(c))))<<16L; \ + case 2: l1|=((DES_LONG)(*(--(c))))<< 8L; \ + case 1: l1|=((DES_LONG)(*(--(c)))); \ + } \ + } + +#define l2c(l,c) (*((c)++)=(unsigned char)(((l) )&0xff), \ + *((c)++)=(unsigned char)(((l)>> 8L)&0xff), \ + *((c)++)=(unsigned char)(((l)>>16L)&0xff), \ + *((c)++)=(unsigned char)(((l)>>24L)&0xff)) + +/* replacements for htonl and ntohl since I have no idea what to do + * when faced with machines with 8 byte longs. */ +#define HDRSIZE 4 + +#define n2l(c,l) (l =((DES_LONG)(*((c)++)))<<24L, \ + l|=((DES_LONG)(*((c)++)))<<16L, \ + l|=((DES_LONG)(*((c)++)))<< 8L, \ + l|=((DES_LONG)(*((c)++)))) + +#define l2n(l,c) (*((c)++)=(unsigned char)(((l)>>24L)&0xff), \ + *((c)++)=(unsigned char)(((l)>>16L)&0xff), \ + *((c)++)=(unsigned char)(((l)>> 8L)&0xff), \ + *((c)++)=(unsigned char)(((l) )&0xff)) + +/* NOTE - c is not incremented as per l2c */ +#define l2cn(l1,l2,c,n) { \ + c+=n; \ + switch (n) { \ + case 8: *(--(c))=(unsigned char)(((l2)>>24L)&0xff); \ + case 7: *(--(c))=(unsigned char)(((l2)>>16L)&0xff); \ + case 6: *(--(c))=(unsigned char)(((l2)>> 8L)&0xff); \ + case 5: *(--(c))=(unsigned char)(((l2) )&0xff); \ + case 4: *(--(c))=(unsigned char)(((l1)>>24L)&0xff); \ + case 3: *(--(c))=(unsigned char)(((l1)>>16L)&0xff); \ + case 2: *(--(c))=(unsigned char)(((l1)>> 8L)&0xff); \ + case 1: *(--(c))=(unsigned char)(((l1) )&0xff); \ + } \ + } + +#if defined(WIN32) +#define ROTATE(a,n) (_lrotr(a,n)) +#else +#define ROTATE(a,n) (((a)>>(n))+((a)<<(32-(n)))) +#endif + +/* The changes to this macro may help or hinder, depending on the + * compiler and the achitecture. gcc2 always seems to do well :-). + * Inspired by Dana How <how@isl.stanford.edu> + * DO NOT use the alternative version on machines with 8 byte longs. + * It does not seem to work on the Alpha, even when DES_LONG is 4 + * bytes, probably an issue of accessing non-word aligned objects :-( */ +#ifdef DES_PTR + +#define D_ENCRYPT(L,R,S) { \ + u=((R^s[S ])<<2); \ + t= R^s[S+1]; \ + t=ROTATE(t,2); \ + L^= (\ + *(DES_LONG *)((unsigned char *)des_SP+0x100+((t )&0xfc))+ \ + *(DES_LONG *)((unsigned char *)des_SP+0x300+((t>> 8)&0xfc))+ \ + *(DES_LONG *)((unsigned char *)des_SP+0x500+((t>>16)&0xfc))+ \ + *(DES_LONG *)((unsigned char *)des_SP+0x700+((t>>24)&0xfc))+ \ + *(DES_LONG *)((unsigned char *)des_SP +((u )&0xfc))+ \ + *(DES_LONG *)((unsigned char *)des_SP+0x200+((u>> 8)&0xfc))+ \ + *(DES_LONG *)((unsigned char *)des_SP+0x400+((u>>16)&0xfc))+ \ + *(DES_LONG *)((unsigned char *)des_SP+0x600+((u>>24)&0xfc))); } +#else /* original version */ +#ifdef undef +#define D_ENCRYPT(L,R,S) \ + U.l=R^s[S+1]; \ + T.s[0]=((U.s[0]>>4)|(U.s[1]<<12))&0x3f3f; \ + T.s[1]=((U.s[1]>>4)|(U.s[0]<<12))&0x3f3f; \ + U.l=(R^s[S ])&0x3f3f3f3fL; \ + L^= des_SPtrans[1][(T.c[0])]| \ + des_SPtrans[3][(T.c[1])]| \ + des_SPtrans[5][(T.c[2])]| \ + des_SPtrans[7][(T.c[3])]| \ + des_SPtrans[0][(U.c[0])]| \ + des_SPtrans[2][(U.c[1])]| \ + des_SPtrans[4][(U.c[2])]| \ + des_SPtrans[6][(U.c[3])]; +#else +#define D_ENCRYPT(Q,R,S) {\ + u=(R^s[S ]); \ + t=R^s[S+1]; \ + t=ROTATE(t,4); \ + Q^= des_SPtrans[1][(t )&0x3f]| \ + des_SPtrans[3][(t>> 8L)&0x3f]| \ + des_SPtrans[5][(t>>16L)&0x3f]| \ + des_SPtrans[7][(t>>24L)&0x3f]| \ + des_SPtrans[0][(u )&0x3f]| \ + des_SPtrans[2][(u>> 8L)&0x3f]| \ + des_SPtrans[4][(u>>16L)&0x3f]| \ + des_SPtrans[6][(u>>24L)&0x3f]; } +#endif +#endif + + /* IP and FP + * The problem is more of a geometric problem that random bit fiddling. + 0 1 2 3 4 5 6 7 62 54 46 38 30 22 14 6 + 8 9 10 11 12 13 14 15 60 52 44 36 28 20 12 4 + 16 17 18 19 20 21 22 23 58 50 42 34 26 18 10 2 + 24 25 26 27 28 29 30 31 to 56 48 40 32 24 16 8 0 + + 32 33 34 35 36 37 38 39 63 55 47 39 31 23 15 7 + 40 41 42 43 44 45 46 47 61 53 45 37 29 21 13 5 + 48 49 50 51 52 53 54 55 59 51 43 35 27 19 11 3 + 56 57 58 59 60 61 62 63 57 49 41 33 25 17 9 1 + + The output has been subject to swaps of the form + 0 1 -> 3 1 but the odd and even bits have been put into + 2 3 2 0 + different words. The main trick is to remember that + t=((l>>size)^r)&(mask); + r^=t; + l^=(t<<size); + can be used to swap and move bits between words. + + So l = 0 1 2 3 r = 16 17 18 19 + 4 5 6 7 20 21 22 23 + 8 9 10 11 24 25 26 27 + 12 13 14 15 28 29 30 31 + becomes (for size == 2 and mask == 0x3333) + t = 2^16 3^17 -- -- l = 0 1 16 17 r = 2 3 18 19 + 6^20 7^21 -- -- 4 5 20 21 6 7 22 23 + 10^24 11^25 -- -- 8 9 24 25 10 11 24 25 + 14^28 15^29 -- -- 12 13 28 29 14 15 28 29 + + Thanks for hints from Richard Outerbridge - he told me IP&FP + could be done in 15 xor, 10 shifts and 5 ands. + When I finally started to think of the problem in 2D + I first got ~42 operations without xors. When I remembered + how to use xors :-) I got it to its final state. + */ +#define PERM_OP(a,b,t,n,m) ((t)=((((a)>>(n))^(b))&(m)),\ + (b)^=(t),\ + (a)^=((t)<<(n))) + +#define IP(l,r) \ + { \ + register DES_LONG tt; \ + PERM_OP(r,l,tt, 4,0x0f0f0f0fL); \ + PERM_OP(l,r,tt,16,0x0000ffffL); \ + PERM_OP(r,l,tt, 2,0x33333333L); \ + PERM_OP(l,r,tt, 8,0x00ff00ffL); \ + PERM_OP(r,l,tt, 1,0x55555555L); \ + } + +#define FP(l,r) \ + { \ + register DES_LONG tt; \ + PERM_OP(l,r,tt, 1,0x55555555L); \ + PERM_OP(r,l,tt, 8,0x00ff00ffL); \ + PERM_OP(l,r,tt, 2,0x33333333L); \ + PERM_OP(r,l,tt,16,0x0000ffffL); \ + PERM_OP(l,r,tt, 4,0x0f0f0f0fL); \ + } +#endif + + +/* +#define mbuf2char(i_mbuf, i_index, in) \ + { \ + register int i; \ + struct mbuf *m; \ + char *buf; \ + m = i_mbuf; \ + for (i = 0; i < 8; i ++){ \ + if (i_index + i == m->m_len){ \ + m = m->m_next; \ + } \ + buf = mtod(m, char *); \ + in[i] = *(buf + i); \ + } + + +#define char2mbuf(o_mbuf, o_index, out) \ + { \ + register int i; \ + struct mbuf *m; \ + char *buf; \ + m = o_mbuf; \ + for (i = 0; i < 8; i ++){ \ + if (i_index + i == m->m_len){ \ + m = m->m_next; \ + } \ + buf = mtod(m, char *); \ + *(buf + i) = out[i]; \ + } +*/ + diff --git a/sys/crypto/des/des_setkey.c b/sys/crypto/des/des_setkey.c new file mode 100644 index 0000000..9747b52 --- /dev/null +++ b/sys/crypto/des/des_setkey.c @@ -0,0 +1,238 @@ +/* crypto/des/set_key.c */ +/* Copyright (C) 1995-1996 Eric Young (eay@mincom.oz.au) + * All rights reserved. + * + * This file is part of an SSL implementation written + * by Eric Young (eay@mincom.oz.au). + * The implementation was written so as to conform with Netscapes SSL + * specification. This library and applications are + * FREE FOR COMMERCIAL AND NON-COMMERCIAL USE + * as long as the following conditions are aheared to. + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. If this code is used in a product, + * Eric Young should be given attribution as the author of the parts used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Eric Young (eay@mincom.oz.au) + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 AUTHOR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + * + * $FreeBSD$ + */ + +/* set_key.c v 1.4 eay 24/9/91 + * 1.4 Speed up by 400% :-) + * 1.3 added register declarations. + * 1.2 unrolled make_key_sched a bit more + * 1.1 added norm_expand_bits + * 1.0 First working version + */ +#include <crypto/des/des_locl.h> +#include <crypto/des/podd.h> +#include <crypto/des/sk.h> + +#ifndef NOPROTO +static int check_parity(des_cblock (*key)); +#else +static int check_parity(); +#endif + +int des_check_key=0; + +void des_set_odd_parity(key) +des_cblock (*key); + { + int i; + + for (i=0; i<DES_KEY_SZ; i++) + (*key)[i]=odd_parity[(*key)[i]]; + } + +static int check_parity(key) +des_cblock (*key); + { + int i; + + for (i=0; i<DES_KEY_SZ; i++) + { + if ((*key)[i] != odd_parity[(*key)[i]]) + return(0); + } + return(1); + } + +/* Weak and semi week keys as take from + * %A D.W. Davies + * %A W.L. Price + * %T Security for Computer Networks + * %I John Wiley & Sons + * %D 1984 + * Many thanks to smb@ulysses.att.com (Steven Bellovin) for the reference + * (and actual cblock values). + */ +#define NUM_WEAK_KEY 16 +static des_cblock weak_keys[NUM_WEAK_KEY]={ + /* weak keys */ + {0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01}, + {0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE}, + {0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F}, + {0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0}, + /* semi-weak keys */ + {0x01,0xFE,0x01,0xFE,0x01,0xFE,0x01,0xFE}, + {0xFE,0x01,0xFE,0x01,0xFE,0x01,0xFE,0x01}, + {0x1F,0xE0,0x1F,0xE0,0x0E,0xF1,0x0E,0xF1}, + {0xE0,0x1F,0xE0,0x1F,0xF1,0x0E,0xF1,0x0E}, + {0x01,0xE0,0x01,0xE0,0x01,0xF1,0x01,0xF1}, + {0xE0,0x01,0xE0,0x01,0xF1,0x01,0xF1,0x01}, + {0x1F,0xFE,0x1F,0xFE,0x0E,0xFE,0x0E,0xFE}, + {0xFE,0x1F,0xFE,0x1F,0xFE,0x0E,0xFE,0x0E}, + {0x01,0x1F,0x01,0x1F,0x01,0x0E,0x01,0x0E}, + {0x1F,0x01,0x1F,0x01,0x0E,0x01,0x0E,0x01}, + {0xE0,0xFE,0xE0,0xFE,0xF1,0xFE,0xF1,0xFE}, + {0xFE,0xE0,0xFE,0xE0,0xFE,0xF1,0xFE,0xF1}}; + +int des_is_weak_key(key) +des_cblock (*key); + { + int i; + + for (i=0; i<NUM_WEAK_KEY; i++) + /* Added == 0 to comparision, I obviously don't run + * this section very often :-(, thanks to + * engineering@MorningStar.Com for the fix + * eay 93/06/29 */ +/* + if (memcmp(weak_keys[i],key,sizeof(key)) == 0) return(1); +*/ + if (bcmp(weak_keys[i],key,sizeof(key)) == 0) return(1); + return(0); + } + +/* NOW DEFINED IN des_local.h + * See ecb_encrypt.c for a pseudo description of these macros. + * #define PERM_OP(a,b,t,n,m) ((t)=((((a)>>(n))^(b))&(m)),\ + * (b)^=(t),\ + * (a)=((a)^((t)<<(n)))) + */ + +#define HPERM_OP(a,t,n,m) ((t)=((((a)<<(16-(n)))^(a))&(m)),\ + (a)=(a)^(t)^(t>>(16-(n)))) + +/* return 0 if key parity is odd (correct), + * return -1 if key parity error, + * return -2 if illegal weak key. + */ +int des_set_key(key, schedule) +des_cblock (*key); +des_key_schedule schedule; + { + static int shifts2[16]={0,0,1,1,1,1,1,1,0,1,1,1,1,1,1,0}; + register DES_LONG c,d,t,s; + register unsigned char *in; + register DES_LONG *k; + register int i; + + if (des_check_key) + { + if (!check_parity(key)) + return(-1); + + if (des_is_weak_key(key)) + return(-2); + } + + k=(DES_LONG *)schedule; + in=(unsigned char *)key; + + c2l(in,c); + c2l(in,d); + + /* do PC1 in 60 simple operations */ +/* PERM_OP(d,c,t,4,0x0f0f0f0fL); + HPERM_OP(c,t,-2, 0xcccc0000L); + HPERM_OP(c,t,-1, 0xaaaa0000L); + HPERM_OP(c,t, 8, 0x00ff0000L); + HPERM_OP(c,t,-1, 0xaaaa0000L); + HPERM_OP(d,t,-8, 0xff000000L); + HPERM_OP(d,t, 8, 0x00ff0000L); + HPERM_OP(d,t, 2, 0x33330000L); + d=((d&0x00aa00aaL)<<7L)|((d&0x55005500L)>>7L)|(d&0xaa55aa55L); + d=(d>>8)|((c&0xf0000000L)>>4); + c&=0x0fffffffL; */ + + /* I now do it in 47 simple operations :-) + * Thanks to John Fletcher (john_fletcher@lccmail.ocf.llnl.gov) + * for the inspiration. :-) */ + PERM_OP (d,c,t,4,0x0f0f0f0fL); + HPERM_OP(c,t,-2,0xcccc0000L); + HPERM_OP(d,t,-2,0xcccc0000L); + PERM_OP (d,c,t,1,0x55555555L); + PERM_OP (c,d,t,8,0x00ff00ffL); + PERM_OP (d,c,t,1,0x55555555L); + d= (((d&0x000000ffL)<<16L)| (d&0x0000ff00L) | + ((d&0x00ff0000L)>>16L)|((c&0xf0000000L)>>4L)); + c&=0x0fffffffL; + + for (i=0; i<ITERATIONS; i++) + { + if (shifts2[i]) + { c=((c>>2L)|(c<<26L)); d=((d>>2L)|(d<<26L)); } + else + { c=((c>>1L)|(c<<27L)); d=((d>>1L)|(d<<27L)); } + c&=0x0fffffffL; + d&=0x0fffffffL; + /* could be a few less shifts but I am to lazy at this + * point in time to investigate */ + s= des_skb[0][ (c )&0x3f ]| + des_skb[1][((c>> 6)&0x03)|((c>> 7L)&0x3c)]| + des_skb[2][((c>>13)&0x0f)|((c>>14L)&0x30)]| + des_skb[3][((c>>20)&0x01)|((c>>21L)&0x06) | + ((c>>22L)&0x38)]; + t= des_skb[4][ (d )&0x3f ]| + des_skb[5][((d>> 7L)&0x03)|((d>> 8L)&0x3c)]| + des_skb[6][ (d>>15L)&0x3f ]| + des_skb[7][((d>>21L)&0x0f)|((d>>22L)&0x30)]; + + /* table contained 0213 4657 */ + *(k++)=((t<<16L)|(s&0x0000ffffL))&0xffffffffL; + s= ((s>>16L)|(t&0xffff0000L)); + + s=(s<<4L)|(s>>28L); + *(k++)=s&0xffffffffL; + } + return(0); + } + +int des_key_sched(key, schedule) +des_cblock (*key); +des_key_schedule schedule; + { + return(des_set_key(key,schedule)); + } diff --git a/sys/crypto/des/podd.h b/sys/crypto/des/podd.h new file mode 100644 index 0000000..a0efc55 --- /dev/null +++ b/sys/crypto/des/podd.h @@ -0,0 +1,66 @@ +/* crypto/des/podd.h */ +/* Copyright (C) 1995-1996 Eric Young (eay@mincom.oz.au) + * All rights reserved. + * + * This file is part of an SSL implementation written + * by Eric Young (eay@mincom.oz.au). + * The implementation was written so as to conform with Netscapes SSL + * specification. This library and applications are + * FREE FOR COMMERCIAL AND NON-COMMERCIAL USE + * as long as the following conditions are aheared to. + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. If this code is used in a product, + * Eric Young should be given attribution as the author of the parts used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Eric Young (eay@mincom.oz.au) + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 AUTHOR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + * + * $FreeBSD$ + */ + +static const unsigned char odd_parity[256]={ + 1, 1, 2, 2, 4, 4, 7, 7, 8, 8, 11, 11, 13, 13, 14, 14, + 16, 16, 19, 19, 21, 21, 22, 22, 25, 25, 26, 26, 28, 28, 31, 31, + 32, 32, 35, 35, 37, 37, 38, 38, 41, 41, 42, 42, 44, 44, 47, 47, + 49, 49, 50, 50, 52, 52, 55, 55, 56, 56, 59, 59, 61, 61, 62, 62, + 64, 64, 67, 67, 69, 69, 70, 70, 73, 73, 74, 74, 76, 76, 79, 79, + 81, 81, 82, 82, 84, 84, 87, 87, 88, 88, 91, 91, 93, 93, 94, 94, + 97, 97, 98, 98,100,100,103,103,104,104,107,107,109,109,110,110, +112,112,115,115,117,117,118,118,121,121,122,122,124,124,127,127, +128,128,131,131,133,133,134,134,137,137,138,138,140,140,143,143, +145,145,146,146,148,148,151,151,152,152,155,155,157,157,158,158, +161,161,162,162,164,164,167,167,168,168,171,171,173,173,174,174, +176,176,179,179,181,181,182,182,185,185,186,186,188,188,191,191, +193,193,194,194,196,196,199,199,200,200,203,203,205,205,206,206, +208,208,211,211,213,213,214,214,217,217,218,218,220,220,223,223, +224,224,227,227,229,229,230,230,233,233,234,234,236,236,239,239, +241,241,242,242,244,244,247,247,248,248,251,251,253,253,254,254}; diff --git a/sys/crypto/des/sk.h b/sys/crypto/des/sk.h new file mode 100644 index 0000000..1a1469c --- /dev/null +++ b/sys/crypto/des/sk.h @@ -0,0 +1,195 @@ +/* crypto/des/sk.h */ +/* Copyright (C) 1995-1996 Eric Young (eay@mincom.oz.au) + * All rights reserved. + * + * This file is part of an SSL implementation written + * by Eric Young (eay@mincom.oz.au). + * The implementation was written so as to conform with Netscapes SSL + * specification. This library and applications are + * FREE FOR COMMERCIAL AND NON-COMMERCIAL USE + * as long as the following conditions are aheared to. + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. If this code is used in a product, + * Eric Young should be given attribution as the author of the parts used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Eric Young (eay@mincom.oz.au) + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 AUTHOR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + * + * $FreeBSD$ + */ + +static const DES_LONG des_skb[8][64]={ +{ +/* for C bits (numbered as per FIPS 46) 1 2 3 4 5 6 */ +0x00000000L,0x00000010L,0x20000000L,0x20000010L, +0x00010000L,0x00010010L,0x20010000L,0x20010010L, +0x00000800L,0x00000810L,0x20000800L,0x20000810L, +0x00010800L,0x00010810L,0x20010800L,0x20010810L, +0x00000020L,0x00000030L,0x20000020L,0x20000030L, +0x00010020L,0x00010030L,0x20010020L,0x20010030L, +0x00000820L,0x00000830L,0x20000820L,0x20000830L, +0x00010820L,0x00010830L,0x20010820L,0x20010830L, +0x00080000L,0x00080010L,0x20080000L,0x20080010L, +0x00090000L,0x00090010L,0x20090000L,0x20090010L, +0x00080800L,0x00080810L,0x20080800L,0x20080810L, +0x00090800L,0x00090810L,0x20090800L,0x20090810L, +0x00080020L,0x00080030L,0x20080020L,0x20080030L, +0x00090020L,0x00090030L,0x20090020L,0x20090030L, +0x00080820L,0x00080830L,0x20080820L,0x20080830L, +0x00090820L,0x00090830L,0x20090820L,0x20090830L, +},{ +/* for C bits (numbered as per FIPS 46) 7 8 10 11 12 13 */ +0x00000000L,0x02000000L,0x00002000L,0x02002000L, +0x00200000L,0x02200000L,0x00202000L,0x02202000L, +0x00000004L,0x02000004L,0x00002004L,0x02002004L, +0x00200004L,0x02200004L,0x00202004L,0x02202004L, +0x00000400L,0x02000400L,0x00002400L,0x02002400L, +0x00200400L,0x02200400L,0x00202400L,0x02202400L, +0x00000404L,0x02000404L,0x00002404L,0x02002404L, +0x00200404L,0x02200404L,0x00202404L,0x02202404L, +0x10000000L,0x12000000L,0x10002000L,0x12002000L, +0x10200000L,0x12200000L,0x10202000L,0x12202000L, +0x10000004L,0x12000004L,0x10002004L,0x12002004L, +0x10200004L,0x12200004L,0x10202004L,0x12202004L, +0x10000400L,0x12000400L,0x10002400L,0x12002400L, +0x10200400L,0x12200400L,0x10202400L,0x12202400L, +0x10000404L,0x12000404L,0x10002404L,0x12002404L, +0x10200404L,0x12200404L,0x10202404L,0x12202404L, +},{ +/* for C bits (numbered as per FIPS 46) 14 15 16 17 19 20 */ +0x00000000L,0x00000001L,0x00040000L,0x00040001L, +0x01000000L,0x01000001L,0x01040000L,0x01040001L, +0x00000002L,0x00000003L,0x00040002L,0x00040003L, +0x01000002L,0x01000003L,0x01040002L,0x01040003L, +0x00000200L,0x00000201L,0x00040200L,0x00040201L, +0x01000200L,0x01000201L,0x01040200L,0x01040201L, +0x00000202L,0x00000203L,0x00040202L,0x00040203L, +0x01000202L,0x01000203L,0x01040202L,0x01040203L, +0x08000000L,0x08000001L,0x08040000L,0x08040001L, +0x09000000L,0x09000001L,0x09040000L,0x09040001L, +0x08000002L,0x08000003L,0x08040002L,0x08040003L, +0x09000002L,0x09000003L,0x09040002L,0x09040003L, +0x08000200L,0x08000201L,0x08040200L,0x08040201L, +0x09000200L,0x09000201L,0x09040200L,0x09040201L, +0x08000202L,0x08000203L,0x08040202L,0x08040203L, +0x09000202L,0x09000203L,0x09040202L,0x09040203L, +},{ +/* for C bits (numbered as per FIPS 46) 21 23 24 26 27 28 */ +0x00000000L,0x00100000L,0x00000100L,0x00100100L, +0x00000008L,0x00100008L,0x00000108L,0x00100108L, +0x00001000L,0x00101000L,0x00001100L,0x00101100L, +0x00001008L,0x00101008L,0x00001108L,0x00101108L, +0x04000000L,0x04100000L,0x04000100L,0x04100100L, +0x04000008L,0x04100008L,0x04000108L,0x04100108L, +0x04001000L,0x04101000L,0x04001100L,0x04101100L, +0x04001008L,0x04101008L,0x04001108L,0x04101108L, +0x00020000L,0x00120000L,0x00020100L,0x00120100L, +0x00020008L,0x00120008L,0x00020108L,0x00120108L, +0x00021000L,0x00121000L,0x00021100L,0x00121100L, +0x00021008L,0x00121008L,0x00021108L,0x00121108L, +0x04020000L,0x04120000L,0x04020100L,0x04120100L, +0x04020008L,0x04120008L,0x04020108L,0x04120108L, +0x04021000L,0x04121000L,0x04021100L,0x04121100L, +0x04021008L,0x04121008L,0x04021108L,0x04121108L, +},{ +/* for D bits (numbered as per FIPS 46) 1 2 3 4 5 6 */ +0x00000000L,0x10000000L,0x00010000L,0x10010000L, +0x00000004L,0x10000004L,0x00010004L,0x10010004L, +0x20000000L,0x30000000L,0x20010000L,0x30010000L, +0x20000004L,0x30000004L,0x20010004L,0x30010004L, +0x00100000L,0x10100000L,0x00110000L,0x10110000L, +0x00100004L,0x10100004L,0x00110004L,0x10110004L, +0x20100000L,0x30100000L,0x20110000L,0x30110000L, +0x20100004L,0x30100004L,0x20110004L,0x30110004L, +0x00001000L,0x10001000L,0x00011000L,0x10011000L, +0x00001004L,0x10001004L,0x00011004L,0x10011004L, +0x20001000L,0x30001000L,0x20011000L,0x30011000L, +0x20001004L,0x30001004L,0x20011004L,0x30011004L, +0x00101000L,0x10101000L,0x00111000L,0x10111000L, +0x00101004L,0x10101004L,0x00111004L,0x10111004L, +0x20101000L,0x30101000L,0x20111000L,0x30111000L, +0x20101004L,0x30101004L,0x20111004L,0x30111004L, +},{ +/* for D bits (numbered as per FIPS 46) 8 9 11 12 13 14 */ +0x00000000L,0x08000000L,0x00000008L,0x08000008L, +0x00000400L,0x08000400L,0x00000408L,0x08000408L, +0x00020000L,0x08020000L,0x00020008L,0x08020008L, +0x00020400L,0x08020400L,0x00020408L,0x08020408L, +0x00000001L,0x08000001L,0x00000009L,0x08000009L, +0x00000401L,0x08000401L,0x00000409L,0x08000409L, +0x00020001L,0x08020001L,0x00020009L,0x08020009L, +0x00020401L,0x08020401L,0x00020409L,0x08020409L, +0x02000000L,0x0A000000L,0x02000008L,0x0A000008L, +0x02000400L,0x0A000400L,0x02000408L,0x0A000408L, +0x02020000L,0x0A020000L,0x02020008L,0x0A020008L, +0x02020400L,0x0A020400L,0x02020408L,0x0A020408L, +0x02000001L,0x0A000001L,0x02000009L,0x0A000009L, +0x02000401L,0x0A000401L,0x02000409L,0x0A000409L, +0x02020001L,0x0A020001L,0x02020009L,0x0A020009L, +0x02020401L,0x0A020401L,0x02020409L,0x0A020409L, +},{ +/* for D bits (numbered as per FIPS 46) 16 17 18 19 20 21 */ +0x00000000L,0x00000100L,0x00080000L,0x00080100L, +0x01000000L,0x01000100L,0x01080000L,0x01080100L, +0x00000010L,0x00000110L,0x00080010L,0x00080110L, +0x01000010L,0x01000110L,0x01080010L,0x01080110L, +0x00200000L,0x00200100L,0x00280000L,0x00280100L, +0x01200000L,0x01200100L,0x01280000L,0x01280100L, +0x00200010L,0x00200110L,0x00280010L,0x00280110L, +0x01200010L,0x01200110L,0x01280010L,0x01280110L, +0x00000200L,0x00000300L,0x00080200L,0x00080300L, +0x01000200L,0x01000300L,0x01080200L,0x01080300L, +0x00000210L,0x00000310L,0x00080210L,0x00080310L, +0x01000210L,0x01000310L,0x01080210L,0x01080310L, +0x00200200L,0x00200300L,0x00280200L,0x00280300L, +0x01200200L,0x01200300L,0x01280200L,0x01280300L, +0x00200210L,0x00200310L,0x00280210L,0x00280310L, +0x01200210L,0x01200310L,0x01280210L,0x01280310L, +},{ +/* for D bits (numbered as per FIPS 46) 22 23 24 25 27 28 */ +0x00000000L,0x04000000L,0x00040000L,0x04040000L, +0x00000002L,0x04000002L,0x00040002L,0x04040002L, +0x00002000L,0x04002000L,0x00042000L,0x04042000L, +0x00002002L,0x04002002L,0x00042002L,0x04042002L, +0x00000020L,0x04000020L,0x00040020L,0x04040020L, +0x00000022L,0x04000022L,0x00040022L,0x04040022L, +0x00002020L,0x04002020L,0x00042020L,0x04042020L, +0x00002022L,0x04002022L,0x00042022L,0x04042022L, +0x00000800L,0x04000800L,0x00040800L,0x04040800L, +0x00000802L,0x04000802L,0x00040802L,0x04040802L, +0x00002800L,0x04002800L,0x00042800L,0x04042800L, +0x00002802L,0x04002802L,0x00042802L,0x04042802L, +0x00000820L,0x04000820L,0x00040820L,0x04040820L, +0x00000822L,0x04000822L,0x00040822L,0x04040822L, +0x00002820L,0x04002820L,0x00042820L,0x04042820L, +0x00002822L,0x04002822L,0x00042822L,0x04042822L, +}}; diff --git a/sys/crypto/des/spr.h b/sys/crypto/des/spr.h new file mode 100644 index 0000000..c340f58 --- /dev/null +++ b/sys/crypto/des/spr.h @@ -0,0 +1,195 @@ +/* crypto/des/spr.h */ +/* Copyright (C) 1995-1996 Eric Young (eay@mincom.oz.au) + * All rights reserved. + * + * This file is part of an SSL implementation written + * by Eric Young (eay@mincom.oz.au). + * The implementation was written so as to conform with Netscapes SSL + * specification. This library and applications are + * FREE FOR COMMERCIAL AND NON-COMMERCIAL USE + * as long as the following conditions are aheared to. + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. If this code is used in a product, + * Eric Young should be given attribution as the author of the parts used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Eric Young (eay@mincom.oz.au) + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 AUTHOR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + * + * $FreeBSD$ + */ + +static const DES_LONG des_SPtrans[8][64]={ +{ +/* nibble 0 */ +0x00820200L, 0x00020000L, 0x80800000L, 0x80820200L, +0x00800000L, 0x80020200L, 0x80020000L, 0x80800000L, +0x80020200L, 0x00820200L, 0x00820000L, 0x80000200L, +0x80800200L, 0x00800000L, 0x00000000L, 0x80020000L, +0x00020000L, 0x80000000L, 0x00800200L, 0x00020200L, +0x80820200L, 0x00820000L, 0x80000200L, 0x00800200L, +0x80000000L, 0x00000200L, 0x00020200L, 0x80820000L, +0x00000200L, 0x80800200L, 0x80820000L, 0x00000000L, +0x00000000L, 0x80820200L, 0x00800200L, 0x80020000L, +0x00820200L, 0x00020000L, 0x80000200L, 0x00800200L, +0x80820000L, 0x00000200L, 0x00020200L, 0x80800000L, +0x80020200L, 0x80000000L, 0x80800000L, 0x00820000L, +0x80820200L, 0x00020200L, 0x00820000L, 0x80800200L, +0x00800000L, 0x80000200L, 0x80020000L, 0x00000000L, +0x00020000L, 0x00800000L, 0x80800200L, 0x00820200L, +0x80000000L, 0x80820000L, 0x00000200L, 0x80020200L, +},{ +/* nibble 1 */ +0x10042004L, 0x00000000L, 0x00042000L, 0x10040000L, +0x10000004L, 0x00002004L, 0x10002000L, 0x00042000L, +0x00002000L, 0x10040004L, 0x00000004L, 0x10002000L, +0x00040004L, 0x10042000L, 0x10040000L, 0x00000004L, +0x00040000L, 0x10002004L, 0x10040004L, 0x00002000L, +0x00042004L, 0x10000000L, 0x00000000L, 0x00040004L, +0x10002004L, 0x00042004L, 0x10042000L, 0x10000004L, +0x10000000L, 0x00040000L, 0x00002004L, 0x10042004L, +0x00040004L, 0x10042000L, 0x10002000L, 0x00042004L, +0x10042004L, 0x00040004L, 0x10000004L, 0x00000000L, +0x10000000L, 0x00002004L, 0x00040000L, 0x10040004L, +0x00002000L, 0x10000000L, 0x00042004L, 0x10002004L, +0x10042000L, 0x00002000L, 0x00000000L, 0x10000004L, +0x00000004L, 0x10042004L, 0x00042000L, 0x10040000L, +0x10040004L, 0x00040000L, 0x00002004L, 0x10002000L, +0x10002004L, 0x00000004L, 0x10040000L, 0x00042000L, +},{ +/* nibble 2 */ +0x41000000L, 0x01010040L, 0x00000040L, 0x41000040L, +0x40010000L, 0x01000000L, 0x41000040L, 0x00010040L, +0x01000040L, 0x00010000L, 0x01010000L, 0x40000000L, +0x41010040L, 0x40000040L, 0x40000000L, 0x41010000L, +0x00000000L, 0x40010000L, 0x01010040L, 0x00000040L, +0x40000040L, 0x41010040L, 0x00010000L, 0x41000000L, +0x41010000L, 0x01000040L, 0x40010040L, 0x01010000L, +0x00010040L, 0x00000000L, 0x01000000L, 0x40010040L, +0x01010040L, 0x00000040L, 0x40000000L, 0x00010000L, +0x40000040L, 0x40010000L, 0x01010000L, 0x41000040L, +0x00000000L, 0x01010040L, 0x00010040L, 0x41010000L, +0x40010000L, 0x01000000L, 0x41010040L, 0x40000000L, +0x40010040L, 0x41000000L, 0x01000000L, 0x41010040L, +0x00010000L, 0x01000040L, 0x41000040L, 0x00010040L, +0x01000040L, 0x00000000L, 0x41010000L, 0x40000040L, +0x41000000L, 0x40010040L, 0x00000040L, 0x01010000L, +},{ +/* nibble 3 */ +0x00100402L, 0x04000400L, 0x00000002L, 0x04100402L, +0x00000000L, 0x04100000L, 0x04000402L, 0x00100002L, +0x04100400L, 0x04000002L, 0x04000000L, 0x00000402L, +0x04000002L, 0x00100402L, 0x00100000L, 0x04000000L, +0x04100002L, 0x00100400L, 0x00000400L, 0x00000002L, +0x00100400L, 0x04000402L, 0x04100000L, 0x00000400L, +0x00000402L, 0x00000000L, 0x00100002L, 0x04100400L, +0x04000400L, 0x04100002L, 0x04100402L, 0x00100000L, +0x04100002L, 0x00000402L, 0x00100000L, 0x04000002L, +0x00100400L, 0x04000400L, 0x00000002L, 0x04100000L, +0x04000402L, 0x00000000L, 0x00000400L, 0x00100002L, +0x00000000L, 0x04100002L, 0x04100400L, 0x00000400L, +0x04000000L, 0x04100402L, 0x00100402L, 0x00100000L, +0x04100402L, 0x00000002L, 0x04000400L, 0x00100402L, +0x00100002L, 0x00100400L, 0x04100000L, 0x04000402L, +0x00000402L, 0x04000000L, 0x04000002L, 0x04100400L, +},{ +/* nibble 4 */ +0x02000000L, 0x00004000L, 0x00000100L, 0x02004108L, +0x02004008L, 0x02000100L, 0x00004108L, 0x02004000L, +0x00004000L, 0x00000008L, 0x02000008L, 0x00004100L, +0x02000108L, 0x02004008L, 0x02004100L, 0x00000000L, +0x00004100L, 0x02000000L, 0x00004008L, 0x00000108L, +0x02000100L, 0x00004108L, 0x00000000L, 0x02000008L, +0x00000008L, 0x02000108L, 0x02004108L, 0x00004008L, +0x02004000L, 0x00000100L, 0x00000108L, 0x02004100L, +0x02004100L, 0x02000108L, 0x00004008L, 0x02004000L, +0x00004000L, 0x00000008L, 0x02000008L, 0x02000100L, +0x02000000L, 0x00004100L, 0x02004108L, 0x00000000L, +0x00004108L, 0x02000000L, 0x00000100L, 0x00004008L, +0x02000108L, 0x00000100L, 0x00000000L, 0x02004108L, +0x02004008L, 0x02004100L, 0x00000108L, 0x00004000L, +0x00004100L, 0x02004008L, 0x02000100L, 0x00000108L, +0x00000008L, 0x00004108L, 0x02004000L, 0x02000008L, +},{ +/* nibble 5 */ +0x20000010L, 0x00080010L, 0x00000000L, 0x20080800L, +0x00080010L, 0x00000800L, 0x20000810L, 0x00080000L, +0x00000810L, 0x20080810L, 0x00080800L, 0x20000000L, +0x20000800L, 0x20000010L, 0x20080000L, 0x00080810L, +0x00080000L, 0x20000810L, 0x20080010L, 0x00000000L, +0x00000800L, 0x00000010L, 0x20080800L, 0x20080010L, +0x20080810L, 0x20080000L, 0x20000000L, 0x00000810L, +0x00000010L, 0x00080800L, 0x00080810L, 0x20000800L, +0x00000810L, 0x20000000L, 0x20000800L, 0x00080810L, +0x20080800L, 0x00080010L, 0x00000000L, 0x20000800L, +0x20000000L, 0x00000800L, 0x20080010L, 0x00080000L, +0x00080010L, 0x20080810L, 0x00080800L, 0x00000010L, +0x20080810L, 0x00080800L, 0x00080000L, 0x20000810L, +0x20000010L, 0x20080000L, 0x00080810L, 0x00000000L, +0x00000800L, 0x20000010L, 0x20000810L, 0x20080800L, +0x20080000L, 0x00000810L, 0x00000010L, 0x20080010L, +},{ +/* nibble 6 */ +0x00001000L, 0x00000080L, 0x00400080L, 0x00400001L, +0x00401081L, 0x00001001L, 0x00001080L, 0x00000000L, +0x00400000L, 0x00400081L, 0x00000081L, 0x00401000L, +0x00000001L, 0x00401080L, 0x00401000L, 0x00000081L, +0x00400081L, 0x00001000L, 0x00001001L, 0x00401081L, +0x00000000L, 0x00400080L, 0x00400001L, 0x00001080L, +0x00401001L, 0x00001081L, 0x00401080L, 0x00000001L, +0x00001081L, 0x00401001L, 0x00000080L, 0x00400000L, +0x00001081L, 0x00401000L, 0x00401001L, 0x00000081L, +0x00001000L, 0x00000080L, 0x00400000L, 0x00401001L, +0x00400081L, 0x00001081L, 0x00001080L, 0x00000000L, +0x00000080L, 0x00400001L, 0x00000001L, 0x00400080L, +0x00000000L, 0x00400081L, 0x00400080L, 0x00001080L, +0x00000081L, 0x00001000L, 0x00401081L, 0x00400000L, +0x00401080L, 0x00000001L, 0x00001001L, 0x00401081L, +0x00400001L, 0x00401080L, 0x00401000L, 0x00001001L, +},{ +/* nibble 7 */ +0x08200020L, 0x08208000L, 0x00008020L, 0x00000000L, +0x08008000L, 0x00200020L, 0x08200000L, 0x08208020L, +0x00000020L, 0x08000000L, 0x00208000L, 0x00008020L, +0x00208020L, 0x08008020L, 0x08000020L, 0x08200000L, +0x00008000L, 0x00208020L, 0x00200020L, 0x08008000L, +0x08208020L, 0x08000020L, 0x00000000L, 0x00208000L, +0x08000000L, 0x00200000L, 0x08008020L, 0x08200020L, +0x00200000L, 0x00008000L, 0x08208000L, 0x00000020L, +0x00200000L, 0x00008000L, 0x08000020L, 0x08208020L, +0x00008020L, 0x08000000L, 0x00000000L, 0x00208000L, +0x08200020L, 0x08008020L, 0x08008000L, 0x00200020L, +0x08208000L, 0x00000020L, 0x00200020L, 0x08008000L, +0x08208020L, 0x00200000L, 0x08200000L, 0x08000020L, +0x00208000L, 0x00008020L, 0x08008020L, 0x08200000L, +0x00000020L, 0x08208000L, 0x00208020L, 0x00000000L, +0x08000000L, 0x08200020L, 0x00008000L, 0x00208020L, +}}; diff --git a/sys/crypto/hmac_md5.c b/sys/crypto/hmac_md5.c new file mode 100644 index 0000000..5302dbe --- /dev/null +++ b/sys/crypto/hmac_md5.c @@ -0,0 +1,98 @@ +/* + * 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. + * + * $FreeBSD$ + */ + +/* + * Based on sample code appeared on RFC2104. + */ + +#include <sys/types.h> +#include <sys/cdefs.h> +#include <sys/time.h> +#include <sys/systm.h> +#include <crypto/md5.h> + +#include <crypto/hmac_md5.h> + +void +hmac_md5(src0, srclen, key0, keylen, digest) + caddr_t src0; + size_t srclen; + caddr_t key0; + size_t keylen; + caddr_t digest; +{ + u_int8_t *src; + u_int8_t *key; + u_int8_t tk[16]; + u_int8_t ipad[65]; + u_int8_t opad[65]; + size_t i; + + src = (u_int8_t *)src0; + key = (u_int8_t *)key0; + + /* + * compress the key into 16bytes, if key is too long. + */ + if (64 < keylen) { + md5_init(); + md5_loop(key, keylen); + md5_pad(); + md5_result(&tk[0]); + key = &tk[0]; + keylen = 16; + } + + /* + * + */ + bzero(&ipad[0], sizeof ipad); + bzero(&opad[0], sizeof opad); + bcopy(key, &ipad[0], keylen); + bcopy(key, &opad[0], keylen); + + for (i = 0; i < 64; i++) { + ipad[i] ^= 0x36; + opad[i] ^= 0x5c; + } + + md5_init(); + md5_loop(&ipad[0], 64); + md5_loop(src, srclen); + md5_pad(); + md5_result((u_int8_t *)digest); + + md5_init(); + md5_loop(&opad[0], 64); + md5_loop((u_int8_t *)digest, 16); + md5_pad(); + md5_result((u_int8_t *)digest); +} diff --git a/sys/crypto/hmac_md5.h b/sys/crypto/hmac_md5.h new file mode 100644 index 0000000..86558fc --- /dev/null +++ b/sys/crypto/hmac_md5.h @@ -0,0 +1,37 @@ +/* + * 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. + * + * $FreeBSD$ + */ + +#ifndef _NETINET6_HMAC_MD5_H_ +#define _NETINET6_HMAC_MD5_H_ + +extern void hmac_md5 __P((caddr_t, size_t, caddr_t, size_t, caddr_t)); + +#endif /* ! _NETINET6_HMAC_MD5_H_*/ diff --git a/sys/crypto/md5.c b/sys/crypto/md5.c new file mode 100644 index 0000000..211c89b --- /dev/null +++ b/sys/crypto/md5.c @@ -0,0 +1,307 @@ +/* + * 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. + * + * $FreeBSD$ + */ + +#include <sys/types.h> +#include <sys/cdefs.h> +#include <sys/time.h> +#include <sys/systm.h> +#include <crypto/md5.h> + +#define SHIFT(X, s) (((X) << (s)) | ((X) >> (32 - (s)))) + +#define F(X, Y, Z) (((X) & (Y)) | ((~X) & (Z))) +#define G(X, Y, Z) (((X) & (Z)) | ((Y) & (~Z))) +#define H(X, Y, Z) ((X) ^ (Y) ^ (Z)) +#define I(X, Y, Z) ((Y) ^ ((X) | (~Z))) + +#define ROUND1(a, b, c, d, k, s, i) { \ + (a) = (a) + F((b), (c), (d)) + X[(k)] + T[(i)]; \ + (a) = SHIFT((a), (s)); \ + (a) = (b) + (a); \ +} + +#define ROUND2(a, b, c, d, k, s, i) { \ + (a) = (a) + G((b), (c), (d)) + X[(k)] + T[(i)]; \ + (a) = SHIFT((a), (s)); \ + (a) = (b) + (a); \ +} + +#define ROUND3(a, b, c, d, k, s, i) { \ + (a) = (a) + H((b), (c), (d)) + X[(k)] + T[(i)]; \ + (a) = SHIFT((a), (s)); \ + (a) = (b) + (a); \ +} + +#define ROUND4(a, b, c, d, k, s, i) { \ + (a) = (a) + I((b), (c), (d)) + X[(k)] + T[(i)]; \ + (a) = SHIFT((a), (s)); \ + (a) = (b) + (a); \ +} + +#define Sa 7 +#define Sb 12 +#define Sc 17 +#define Sd 22 + +#define Se 5 +#define Sf 9 +#define Sg 14 +#define Sh 20 + +#define Si 4 +#define Sj 11 +#define Sk 16 +#define Sl 23 + +#define Sm 6 +#define Sn 10 +#define So 15 +#define Sp 21 + +#define MD5_A0 0x67452301 +#define MD5_B0 0xefcdab89 +#define MD5_C0 0x98badcfe +#define MD5_D0 0x10325476 + +/* Integer part of 4294967296 times abs(sin(i)), where i is in radians. */ +static const u_int32_t T[65] = { + 0, + 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, + + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, + 0xd62f105d, 0x2441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, + + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05, + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391, +}; + +static const u_int8_t md5_paddat[MD5_BUFLEN] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static void md5_calc __P((u_int8_t *, md5_ctxt *)); + +void md5_init(ctxt) + md5_ctxt *ctxt; +{ + ctxt->md5_n = 0; + ctxt->md5_i = 0; + ctxt->md5_sta = MD5_A0; + ctxt->md5_stb = MD5_B0; + ctxt->md5_stc = MD5_C0; + ctxt->md5_std = MD5_D0; + bzero(ctxt->md5_buf, sizeof(ctxt->md5_buf)); +} + +void md5_loop(ctxt, input, len) + md5_ctxt *ctxt; + u_int8_t *input; + u_int len; /* number of bytes */ +{ + u_int gap, i; + + ctxt->md5_n += len * 8; /* byte to bit */ + gap = MD5_BUFLEN - ctxt->md5_i; + + if (len >= gap) { + bcopy((void *)input, (void *)(ctxt->md5_buf + ctxt->md5_i), + gap); + md5_calc(ctxt->md5_buf, ctxt); + + for (i = gap; i + MD5_BUFLEN <= len; i += MD5_BUFLEN) { + md5_calc((u_int8_t *)(input + i), ctxt); + } + + ctxt->md5_i = len - i; + bcopy((void *)(input + i), (void *)ctxt->md5_buf, ctxt->md5_i); + } else { + bcopy((void *)input, (void *)(ctxt->md5_buf + ctxt->md5_i), + len); + ctxt->md5_i += len; + } +} + +void md5_pad(ctxt) + md5_ctxt *ctxt; +{ + u_int gap; + + /* Don't count up padding. Keep md5_n. */ + gap = MD5_BUFLEN - ctxt->md5_i; + if (gap > 8) { + bcopy((void *)md5_paddat, + (void *)(ctxt->md5_buf + ctxt->md5_i), + gap - sizeof(ctxt->md5_n)); + } else { + /* including gap == 8 */ + bcopy((void *)md5_paddat, (void *)(ctxt->md5_buf + ctxt->md5_i), + gap); + md5_calc(ctxt->md5_buf, ctxt); + bcopy((void *)(md5_paddat + gap), + (void *)ctxt->md5_buf, + MD5_BUFLEN - sizeof(ctxt->md5_n)); + } + + /* 8 byte word */ +#if BYTE_ORDER == LITTLE_ENDIAN + bcopy(&ctxt->md5_n8[0], &ctxt->md5_buf[56], 8); +#endif +#if BYTE_ORDER == BIG_ENDIAN + ctxt->md5_buf[56] = ctxt->md5_n8[7]; + ctxt->md5_buf[57] = ctxt->md5_n8[6]; + ctxt->md5_buf[58] = ctxt->md5_n8[5]; + ctxt->md5_buf[59] = ctxt->md5_n8[4]; + ctxt->md5_buf[60] = ctxt->md5_n8[3]; + ctxt->md5_buf[61] = ctxt->md5_n8[2]; + ctxt->md5_buf[62] = ctxt->md5_n8[1]; + ctxt->md5_buf[63] = ctxt->md5_n8[0]; +#endif + + md5_calc(ctxt->md5_buf, ctxt); +} + +void md5_result(digest, ctxt) + u_int8_t *digest; + md5_ctxt *ctxt; +{ + /* 4 byte words */ +#if BYTE_ORDER == LITTLE_ENDIAN + bcopy(&ctxt->md5_st8[0], digest, 16); +#endif +#if BYTE_ORDER == BIG_ENDIAN + digest[ 0] = ctxt->md5_st8[ 3]; digest[ 1] = ctxt->md5_st8[ 2]; + digest[ 2] = ctxt->md5_st8[ 1]; digest[ 3] = ctxt->md5_st8[ 0]; + digest[ 4] = ctxt->md5_st8[ 7]; digest[ 5] = ctxt->md5_st8[ 6]; + digest[ 6] = ctxt->md5_st8[ 5]; digest[ 7] = ctxt->md5_st8[ 4]; + digest[ 8] = ctxt->md5_st8[11]; digest[ 9] = ctxt->md5_st8[10]; + digest[10] = ctxt->md5_st8[ 9]; digest[11] = ctxt->md5_st8[ 8]; + digest[12] = ctxt->md5_st8[15]; digest[13] = ctxt->md5_st8[14]; + digest[14] = ctxt->md5_st8[13]; digest[15] = ctxt->md5_st8[12]; +#endif +} + +#if BYTE_ORDER == BIG_ENDIAN +u_int32_t X[16]; +#endif + +static void md5_calc(b64, ctxt) + u_int8_t *b64; + md5_ctxt *ctxt; +{ + u_int32_t A = ctxt->md5_sta; + u_int32_t B = ctxt->md5_stb; + u_int32_t C = ctxt->md5_stc; + u_int32_t D = ctxt->md5_std; +#if BYTE_ORDER == LITTLE_ENDIAN + u_int32_t *X = (u_int32_t *)b64; +#endif +#if BYTE_ORDER == BIG_ENDIAN + /* 4 byte words */ + /* what a brute force but fast! */ + u_int8_t *y = (u_int8_t *)X; + y[ 0] = b64[ 3]; y[ 1] = b64[ 2]; y[ 2] = b64[ 1]; y[ 3] = b64[ 0]; + y[ 4] = b64[ 7]; y[ 5] = b64[ 6]; y[ 6] = b64[ 5]; y[ 7] = b64[ 4]; + y[ 8] = b64[11]; y[ 9] = b64[10]; y[10] = b64[ 9]; y[11] = b64[ 8]; + y[12] = b64[15]; y[13] = b64[14]; y[14] = b64[13]; y[15] = b64[12]; + y[16] = b64[19]; y[17] = b64[18]; y[18] = b64[17]; y[19] = b64[16]; + y[20] = b64[23]; y[21] = b64[22]; y[22] = b64[21]; y[23] = b64[20]; + y[24] = b64[27]; y[25] = b64[26]; y[26] = b64[25]; y[27] = b64[24]; + y[28] = b64[31]; y[29] = b64[30]; y[30] = b64[29]; y[31] = b64[28]; + y[32] = b64[35]; y[33] = b64[34]; y[34] = b64[33]; y[35] = b64[32]; + y[36] = b64[39]; y[37] = b64[38]; y[38] = b64[37]; y[39] = b64[36]; + y[40] = b64[43]; y[41] = b64[42]; y[42] = b64[41]; y[43] = b64[40]; + y[44] = b64[47]; y[45] = b64[46]; y[46] = b64[45]; y[47] = b64[44]; + y[48] = b64[51]; y[49] = b64[50]; y[50] = b64[49]; y[51] = b64[48]; + y[52] = b64[55]; y[53] = b64[54]; y[54] = b64[53]; y[55] = b64[52]; + y[56] = b64[59]; y[57] = b64[58]; y[58] = b64[57]; y[59] = b64[56]; + y[60] = b64[63]; y[61] = b64[62]; y[62] = b64[61]; y[63] = b64[60]; +#endif + + ROUND1(A, B, C, D, 0, Sa, 1); ROUND1(D, A, B, C, 1, Sb, 2); + ROUND1(C, D, A, B, 2, Sc, 3); ROUND1(B, C, D, A, 3, Sd, 4); + ROUND1(A, B, C, D, 4, Sa, 5); ROUND1(D, A, B, C, 5, Sb, 6); + ROUND1(C, D, A, B, 6, Sc, 7); ROUND1(B, C, D, A, 7, Sd, 8); + ROUND1(A, B, C, D, 8, Sa, 9); ROUND1(D, A, B, C, 9, Sb, 10); + ROUND1(C, D, A, B, 10, Sc, 11); ROUND1(B, C, D, A, 11, Sd, 12); + ROUND1(A, B, C, D, 12, Sa, 13); ROUND1(D, A, B, C, 13, Sb, 14); + ROUND1(C, D, A, B, 14, Sc, 15); ROUND1(B, C, D, A, 15, Sd, 16); + + ROUND2(A, B, C, D, 1, Se, 17); ROUND2(D, A, B, C, 6, Sf, 18); + ROUND2(C, D, A, B, 11, Sg, 19); ROUND2(B, C, D, A, 0, Sh, 20); + ROUND2(A, B, C, D, 5, Se, 21); ROUND2(D, A, B, C, 10, Sf, 22); + ROUND2(C, D, A, B, 15, Sg, 23); ROUND2(B, C, D, A, 4, Sh, 24); + ROUND2(A, B, C, D, 9, Se, 25); ROUND2(D, A, B, C, 14, Sf, 26); + ROUND2(C, D, A, B, 3, Sg, 27); ROUND2(B, C, D, A, 8, Sh, 28); + ROUND2(A, B, C, D, 13, Se, 29); ROUND2(D, A, B, C, 2, Sf, 30); + ROUND2(C, D, A, B, 7, Sg, 31); ROUND2(B, C, D, A, 12, Sh, 32); + + ROUND3(A, B, C, D, 5, Si, 33); ROUND3(D, A, B, C, 8, Sj, 34); + ROUND3(C, D, A, B, 11, Sk, 35); ROUND3(B, C, D, A, 14, Sl, 36); + ROUND3(A, B, C, D, 1, Si, 37); ROUND3(D, A, B, C, 4, Sj, 38); + ROUND3(C, D, A, B, 7, Sk, 39); ROUND3(B, C, D, A, 10, Sl, 40); + ROUND3(A, B, C, D, 13, Si, 41); ROUND3(D, A, B, C, 0, Sj, 42); + ROUND3(C, D, A, B, 3, Sk, 43); ROUND3(B, C, D, A, 6, Sl, 44); + ROUND3(A, B, C, D, 9, Si, 45); ROUND3(D, A, B, C, 12, Sj, 46); + ROUND3(C, D, A, B, 15, Sk, 47); ROUND3(B, C, D, A, 2, Sl, 48); + + ROUND4(A, B, C, D, 0, Sm, 49); ROUND4(D, A, B, C, 7, Sn, 50); + ROUND4(C, D, A, B, 14, So, 51); ROUND4(B, C, D, A, 5, Sp, 52); + ROUND4(A, B, C, D, 12, Sm, 53); ROUND4(D, A, B, C, 3, Sn, 54); + ROUND4(C, D, A, B, 10, So, 55); ROUND4(B, C, D, A, 1, Sp, 56); + ROUND4(A, B, C, D, 8, Sm, 57); ROUND4(D, A, B, C, 15, Sn, 58); + ROUND4(C, D, A, B, 6, So, 59); ROUND4(B, C, D, A, 13, Sp, 60); + ROUND4(A, B, C, D, 4, Sm, 61); ROUND4(D, A, B, C, 11, Sn, 62); + ROUND4(C, D, A, B, 2, So, 63); ROUND4(B, C, D, A, 9, Sp, 64); + + ctxt->md5_sta += A; + ctxt->md5_stb += B; + ctxt->md5_stc += C; + ctxt->md5_std += D; +} diff --git a/sys/crypto/md5.h b/sys/crypto/md5.h new file mode 100644 index 0000000..61eb2ac --- /dev/null +++ b/sys/crypto/md5.h @@ -0,0 +1,75 @@ +/* + * 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. + * + * $FreeBSD$ + */ + +#ifndef _NETINET6_MD5_H_ +#define _NETINET6_MD5_H_ + +#define MD5_BUFLEN 64 + +typedef struct { + union { + u_int32_t md5_state32[4]; + u_int8_t md5_state8[16]; + } md5_st; + +#define md5_sta md5_st.md5_state32[0] +#define md5_stb md5_st.md5_state32[1] +#define md5_stc md5_st.md5_state32[2] +#define md5_std md5_st.md5_state32[3] +#define md5_st8 md5_st.md5_state8 + + union { + u_int64_t md5_count64; + u_int8_t md5_count8[8]; + } md5_count; +#define md5_n md5_count.md5_count64 +#define md5_n8 md5_count.md5_count8 + + u_int md5_i; + u_int8_t md5_buf[MD5_BUFLEN]; +} md5_ctxt; + +extern void md5_init __P((md5_ctxt *)); +extern void md5_loop __P((md5_ctxt *, u_int8_t *, u_int)); +extern void md5_pad __P((md5_ctxt *)); +extern void md5_result __P((u_int8_t *, md5_ctxt *)); + +/* compatibility */ +#define MD5_CTX md5_ctxt +#define MD5Init(x) md5_init((x)) +#define MD5Update(x, y, z) md5_loop((x), (y), (z)) +#define MD5Final(x, y) \ +do { \ + md5_pad((y)); \ + md5_result((x), (y)); \ +} while (0) + +#endif /* ! _NETINET6_MD5_H_*/ diff --git a/sys/crypto/rc5/rc5.c b/sys/crypto/rc5/rc5.c new file mode 100644 index 0000000..52ccdd1 --- /dev/null +++ b/sys/crypto/rc5/rc5.c @@ -0,0 +1,218 @@ +/* + * 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. + * + * $FreeBSD$ + */ +#include <crypto/rc5/rc5.h> + + +void +set_rc5_expandkey(e_key, key, keylen, rounds) + RC5_WORD *e_key; + u_int8_t *key; + size_t keylen; + int rounds; +{ + int i, j, k, LL, t, T; + RC5_WORD L[256/WW]; + RC5_WORD A, B; + + LL = (keylen + WW - 1) / WW; + + bzero(L, sizeof(RC5_WORD)*LL); + + for (i = 0; i < keylen; i++) { + t = (key[i] & 0xff) << (8*(i%4)); + L[i/WW] = L[i/WW] + t; + } + + T = 2 * (rounds + 1); + e_key[0] = Pw; + for (i = 1; i < T; i++) + e_key[i] = e_key[i-1] + Qw; + + i = j = 0; + A = B = 0; + if (LL > T) + k = 3 * LL; + else + k = 3 * T; + + for (; k > 0; k--) { + A = ROTL(e_key[i]+A+B, 3, W); + e_key[i] = A; + B = ROTL(L[j]+A+B, A+B, W); + L[j] = B; + + i = (i + 1) % T; + j = (j + 1) % LL; + } +} + + +/* + * + */ +void +rc5_encrypt_round16(out, in, e_key) + u_int8_t *out; + const u_int8_t *in; + const RC5_WORD *e_key; +{ + RC5_WORD A, B; + const RC5_WORD *e_keyA, *e_keyB; + + A = in[0] & 0xff; + A += (in[1] & 0xff) << 8; + A += (in[2] & 0xff) << 16; + A += (in[3] & 0xff) << 24; + B = in[4] & 0xff; + B += (in[5] & 0xff) << 8; + B += (in[6] & 0xff) << 16; + B += (in[7] & 0xff) << 24; + + e_keyA = e_key; + e_keyB = e_key + 1; + + A += *e_keyA; e_keyA += 2; + B += *e_keyB; e_keyB += 2; + + A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2; + B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2; + A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2; + B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2; + A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2; + B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2; + A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2; + B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2; /* round 4 */ + A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2; + B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2; + A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2; + B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2; + A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2; + B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2; + A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2; + B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2; /* round 8 */ + A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2; + B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2; + A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2; + B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2; + A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2; + B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2; + A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2; + B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2; /* round 12 */ + A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2; + B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2; + A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2; + B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2; + A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2; + B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2; + A = ROTL(A^B, B, W) + *e_keyA; e_keyA += 2; + B = ROTL(B^A, A, W) + *e_keyB; e_keyB += 2; /* round 16 */ + + out[0] = A & 0xff; + out[1] = (A >> 8) & 0xff; + out[2] = (A >> 16) & 0xff; + out[3] = (A >> 24) & 0xff; + out[4] = B & 0xff; + out[5] = (B >> 8) & 0xff; + out[6] = (B >> 16) & 0xff; + out[7] = (B >> 24) & 0xff; +} + + +/* + * + */ +void +rc5_decrypt_round16(out, in, e_key) + u_int8_t *out; + const u_int8_t *in; + const RC5_WORD *e_key; +{ + RC5_WORD A, B; + const RC5_WORD *e_keyA, *e_keyB; + + A = in[0] & 0xff; + A += (in[1] & 0xff) << 8; + A += (in[2] & 0xff) << 16; + A += (in[3] & 0xff) << 24; + B = in[4] & 0xff; + B += (in[5] & 0xff) << 8; + B += (in[6] & 0xff) << 16; + B += (in[7] & 0xff) << 24; + + e_keyA = e_key + 2*16; + e_keyB = e_key + 2*16 + 1; + + B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2; + A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2; + B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2; + A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2; + B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2; + A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2; + B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2; + A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2; /* round 4 */ + B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2; + A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2; + B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2; + A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2; + B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2; + A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2; + B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2; + A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2; /* round 8 */ + B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2; + A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2; + B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2; + A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2; + B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2; + A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2; + B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2; + A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2; /* round 12 */ + B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2; + A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2; + B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2; + A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2; + B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2; + A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2; + B = ROTR(B-*e_keyB, A, W) ^ A; e_keyB -= 2; + A = ROTR(A-*e_keyA, B, W) ^ B; e_keyA -= 2; /* round 16 */ + + B = B - *e_keyB; + A = A - *e_keyA; + + out[0] = A & 0xff; + out[1] = (A >> 8) & 0xff; + out[2] = (A >> 16) & 0xff; + out[3] = (A >> 24) & 0xff; + out[4] = B & 0xff; + out[5] = (B >> 8) & 0xff; + out[6] = (B >> 16) & 0xff; + out[7] = (B >> 24) & 0xff; +} + diff --git a/sys/crypto/rc5/rc5.h b/sys/crypto/rc5/rc5.h new file mode 100644 index 0000000..20c235b --- /dev/null +++ b/sys/crypto/rc5/rc5.h @@ -0,0 +1,86 @@ +/* + * 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. + * + * $FreeBSD$ + */ + +#ifndef _RFC2040_RC5_H_ +#define _RFC2040_RC5_H_ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/mbuf.h> + +/* + * if RC5_WORD change, W also may be changed. + */ +typedef u_int32_t RC5_WORD; + +#define W (32) +#define WW (W / 8) +#define ROT_MASK (W - 1) +#define BB ((2 * W) / 8) + +#define SHLL(x, s) ((RC5_WORD)((x) << ((s)&ROT_MASK))) +#define SHLR(x, s, w) ((RC5_WORD)((x) >> ((w)-((s)&ROT_MASK)))) +#define SHRL(x, s, w) ((RC5_WORD)((x) << ((w)-((s)&ROT_MASK)))) +#define SHRR(x, s) ((RC5_WORD)((x) >> ((s)&ROT_MASK))) + +#define ROTL(x, s, w) ((RC5_WORD)(SHLL((x), (s))|SHLR((x), (s), (w)))) +#define ROTR(x, s, w) ((RC5_WORD)(SHRL((x), (s), (w))|SHRR((x), (s)))) + +#define P16 0xb7e1 +#define Q16 0x9e37 +#define P32 0xb7e15163 +#define Q32 0x9e3779b9 +#define P64 0xb7e151628aed2a6b +#define Q64 0x9e3779b97f4a7c15 + +#if W == 16 +#define Pw P16 +#define Qw Q16 +#elif W == 32 +#define Pw P32 +#define Qw Q32 +#elif W == 64 +#define Pw P64 +#define Qw Q64 +#endif + +#define RC5_ENCRYPT 1 +#define RC5_DECRYPT 0 + +extern void set_rc5_expandkey __P((RC5_WORD *, u_int8_t *, size_t, int)); +extern void rc5_encrypt_round16 __P((u_int8_t *, const u_int8_t *, + const RC5_WORD *)); +extern void rc5_decrypt_round16 __P((u_int8_t *, const u_int8_t *, + const RC5_WORD *)); +extern void rc5_cbc_process __P((struct mbuf *, size_t, size_t, RC5_WORD *, + u_int8_t *, int)); + +#endif diff --git a/sys/crypto/rc5/rc5_cbc.c b/sys/crypto/rc5/rc5_cbc.c new file mode 100644 index 0000000..c588eda --- /dev/null +++ b/sys/crypto/rc5/rc5_cbc.c @@ -0,0 +1,211 @@ +/* + * 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. + * + * $FreeBSD$ + */ +/* + * based on sys/crypto/des/des_cbc.c, rewrote by Tomomi Suzuki + */ +#include <crypto/rc5/rc5.h> + + +void +rc5_cbc_process(m0, skip, length, e_key, iv, mode) + struct mbuf *m0; + size_t skip; + size_t length; + RC5_WORD *e_key; + u_int8_t *iv; + int mode; +{ + u_int8_t inbuf[8], outbuf[8]; + struct mbuf *m; + size_t off; + + /* sanity check */ + if (m0->m_pkthdr.len < skip) { + printf("rc5_cbc_process: mbuf length < skip\n"); + return; + } + if (m0->m_pkthdr.len < length) { + printf("rc5_cbc_process: mbuf length < encrypt length\n"); + return; + } + if (m0->m_pkthdr.len < skip + length) { + printf("rc5_cbc_process: mbuf length < " + "skip + encrypt length\n"); + return; + } + if (length % 8) { + printf("rc5_cbc_process: length(%lu)is not multipleof 8\n", + (u_long)length); + return; + } + + m = m0; + off = 0; + + /* skip over the header */ + while (skip) { + if (!m) + panic("rc5_cbc_process: mbuf chain?\n"); + if (m->m_len <= skip) { + skip -= m->m_len; + m = m->m_next; + off = 0; + } else { + off = skip; + skip = 0; + } + } + + /* copy iv into outbuf for XOR (encrypt) */ + bcopy(iv, outbuf, 8); + + /* + * encrypt/decrypt packet + */ + while (length > 0) { + int i; + + if (!m) + panic("rc5_cbc_process: mbuf chain?\n"); + + /* + * copy the source into input buffer. + * don't update off or m, since we need to use them + * later. + */ + if (off + 8 <= m->m_len) + bcopy(mtod(m, u_int8_t *) + off, &inbuf[0], 8); + else { + struct mbuf *n; + size_t noff; + u_int8_t *p; + u_int8_t *in; + + n = m; + noff = off; + p = mtod(n, u_int8_t *) + noff; + + in = &inbuf[0]; + while (in - &inbuf[0] < 8) { + if (!p) { + panic("rc5_cbc_process: " + "mbuf chain?\n"); + } + *in++ = *p++; + noff++; + if (noff < n->m_len) + continue; + do { + n = n->m_next; + } while (n && !n->m_len); + noff = 0; + if (n) + p = mtod(n, u_int8_t *) + noff; + else + p = NULL; + } + } + + /* encrypt/decrypt */ + switch (mode) { + case RC5_ENCRYPT: + /* XOR */ + for (i = 0; i < 8; i++) + inbuf[i] ^= outbuf[i]; + + /* encrypt */ + rc5_encrypt_round16(outbuf, inbuf, e_key); + break; + + case RC5_DECRYPT: + /* decrypt */ + rc5_decrypt_round16(outbuf, inbuf, e_key); + + /* XOR */ + for (i = 0; i < 8; i++) + outbuf[i] ^= iv[i]; + + /* copy inbuf into iv for next XOR */ + bcopy(inbuf, iv, 8); + break; + } + + /* + * copy the output buffer into the result. + * need to update off and m. + */ + if (off + 8 < m->m_len) { + bcopy(&outbuf[0], mtod(m, u_int8_t *) + off, 8); + off += 8; + } else if (off + 8 == m->m_len) { + bcopy(&outbuf[0], mtod(m, u_int8_t *) + off, 8); + do { + m = m->m_next; + } while (m && !m->m_len); + off = 0; + } else { + struct mbuf *n; + size_t noff; + u_int8_t *p; + u_int8_t *out; + + n = m; + noff = off; + p = mtod(n, u_int8_t *) + noff; + + out = &outbuf[0]; + while (out - &outbuf[0] < 8) { + if (!p) { + panic("rc5_cbc_process: " + "mbuf chain?\n"); + } + *p++ = *out++; + noff++; + if (noff < n->m_len) + continue; + do { + n = n->m_next; + } while (n && !n->m_len); + noff = 0; + if (n) + p = mtod(n, u_int8_t *) + noff; + else + p = NULL; + } + + m = n; + off = noff; + } + + length -= 8; + } +} + diff --git a/sys/crypto/sha1.c b/sys/crypto/sha1.c new file mode 100644 index 0000000..5b1c02d --- /dev/null +++ b/sys/crypto/sha1.c @@ -0,0 +1,275 @@ +/* + * 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. + * + * $FreeBSD$ + */ +/* + * FIPS pub 180-1: Secure Hash Algorithm (SHA-1) + * based on: http://csrc.nist.gov/fips/fip180-1.txt + * implemented by Jun-ichiro itojun Itoh <itojun@itojun.org> + */ + +#include <sys/types.h> +#include <sys/cdefs.h> +#include <sys/time.h> +#include <sys/systm.h> + +#include <crypto/sha1.h> + +/* sanity check */ +#if BYTE_ORDER != BIG_ENDIAN +# if BYTE_ORDER != LITTLE_ENDIAN +# define unsupported 1 +# endif +#endif + +#ifndef unsupported + +/* constant table */ +static u_int32_t _K[] = { 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6 }; +#define K(t) _K[(t) / 20] + +#define F0(b, c, d) (((b) & (c)) | ((~(b)) & (d))) +#define F1(b, c, d) (((b) ^ (c)) ^ (d)) +#define F2(b, c, d) (((b) & (c)) | ((b) & (d)) | ((c) & (d))) +#define F3(b, c, d) (((b) ^ (c)) ^ (d)) + +#define S(n, x) (((x) << (n)) | ((x) >> (32 - n))) + +#define H(n) (ctxt->h.b32[(n)]) +#define COUNT (ctxt->count) +#define BCOUNT (ctxt->c.b64[0] / 8) +#define W(n) (ctxt->m.b32[(n)]) + +#define PUTBYTE(x) { \ + ctxt->m.b8[(COUNT % 64)] = (x); \ + COUNT++; \ + COUNT %= 64; \ + ctxt->c.b64[0] += 8; \ + if (COUNT % 64 == 0) \ + sha1_step(ctxt); \ + } + +#define PUTPAD(x) { \ + ctxt->m.b8[(COUNT % 64)] = (x); \ + COUNT++; \ + COUNT %= 64; \ + if (COUNT % 64 == 0) \ + sha1_step(ctxt); \ + } + +static void sha1_step __P((struct sha1_ctxt *)); + +static void +sha1_step(ctxt) + struct sha1_ctxt *ctxt; +{ + u_int32_t a, b, c, d, e; + size_t t, s; + u_int32_t tmp; + +#if BYTE_ORDER == LITTLE_ENDIAN + struct sha1_ctxt tctxt; + bcopy(&ctxt->m.b8[0], &tctxt.m.b8[0], 64); + ctxt->m.b8[0] = tctxt.m.b8[3]; ctxt->m.b8[1] = tctxt.m.b8[2]; + ctxt->m.b8[2] = tctxt.m.b8[1]; ctxt->m.b8[3] = tctxt.m.b8[0]; + ctxt->m.b8[4] = tctxt.m.b8[7]; ctxt->m.b8[5] = tctxt.m.b8[6]; + ctxt->m.b8[6] = tctxt.m.b8[5]; ctxt->m.b8[7] = tctxt.m.b8[4]; + ctxt->m.b8[8] = tctxt.m.b8[11]; ctxt->m.b8[9] = tctxt.m.b8[10]; + ctxt->m.b8[10] = tctxt.m.b8[9]; ctxt->m.b8[11] = tctxt.m.b8[8]; + ctxt->m.b8[12] = tctxt.m.b8[15]; ctxt->m.b8[13] = tctxt.m.b8[14]; + ctxt->m.b8[14] = tctxt.m.b8[13]; ctxt->m.b8[15] = tctxt.m.b8[12]; + ctxt->m.b8[16] = tctxt.m.b8[19]; ctxt->m.b8[17] = tctxt.m.b8[18]; + ctxt->m.b8[18] = tctxt.m.b8[17]; ctxt->m.b8[19] = tctxt.m.b8[16]; + ctxt->m.b8[20] = tctxt.m.b8[23]; ctxt->m.b8[21] = tctxt.m.b8[22]; + ctxt->m.b8[22] = tctxt.m.b8[21]; ctxt->m.b8[23] = tctxt.m.b8[20]; + ctxt->m.b8[24] = tctxt.m.b8[27]; ctxt->m.b8[25] = tctxt.m.b8[26]; + ctxt->m.b8[26] = tctxt.m.b8[25]; ctxt->m.b8[27] = tctxt.m.b8[24]; + ctxt->m.b8[28] = tctxt.m.b8[31]; ctxt->m.b8[29] = tctxt.m.b8[30]; + ctxt->m.b8[30] = tctxt.m.b8[29]; ctxt->m.b8[31] = tctxt.m.b8[28]; + ctxt->m.b8[32] = tctxt.m.b8[35]; ctxt->m.b8[33] = tctxt.m.b8[34]; + ctxt->m.b8[34] = tctxt.m.b8[33]; ctxt->m.b8[35] = tctxt.m.b8[32]; + ctxt->m.b8[36] = tctxt.m.b8[39]; ctxt->m.b8[37] = tctxt.m.b8[38]; + ctxt->m.b8[38] = tctxt.m.b8[37]; ctxt->m.b8[39] = tctxt.m.b8[36]; + ctxt->m.b8[40] = tctxt.m.b8[43]; ctxt->m.b8[41] = tctxt.m.b8[42]; + ctxt->m.b8[42] = tctxt.m.b8[41]; ctxt->m.b8[43] = tctxt.m.b8[40]; + ctxt->m.b8[44] = tctxt.m.b8[47]; ctxt->m.b8[45] = tctxt.m.b8[46]; + ctxt->m.b8[46] = tctxt.m.b8[45]; ctxt->m.b8[47] = tctxt.m.b8[44]; + ctxt->m.b8[48] = tctxt.m.b8[51]; ctxt->m.b8[49] = tctxt.m.b8[50]; + ctxt->m.b8[50] = tctxt.m.b8[49]; ctxt->m.b8[51] = tctxt.m.b8[48]; + ctxt->m.b8[52] = tctxt.m.b8[55]; ctxt->m.b8[53] = tctxt.m.b8[54]; + ctxt->m.b8[54] = tctxt.m.b8[53]; ctxt->m.b8[55] = tctxt.m.b8[52]; + ctxt->m.b8[56] = tctxt.m.b8[59]; ctxt->m.b8[57] = tctxt.m.b8[58]; + ctxt->m.b8[58] = tctxt.m.b8[57]; ctxt->m.b8[59] = tctxt.m.b8[56]; + ctxt->m.b8[60] = tctxt.m.b8[63]; ctxt->m.b8[61] = tctxt.m.b8[62]; + ctxt->m.b8[62] = tctxt.m.b8[61]; ctxt->m.b8[63] = tctxt.m.b8[60]; +#endif + + a = H(0); b = H(1); c = H(2); d = H(3); e = H(4); + + for (t = 0; t < 20; t++) { + s = t & 0x0f; + if (t >= 16) { + W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^ W((s+2) & 0x0f) ^ W(s)); + } + tmp = S(5, a) + F0(b, c, d) + e + W(s) + K(t); + e = d; d = c; c = S(30, b); b = a; a = tmp; + } + for (t = 20; t < 40; t++) { + s = t & 0x0f; + W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^ W((s+2) & 0x0f) ^ W(s)); + tmp = S(5, a) + F1(b, c, d) + e + W(s) + K(t); + e = d; d = c; c = S(30, b); b = a; a = tmp; + } + for (t = 40; t < 60; t++) { + s = t & 0x0f; + W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^ W((s+2) & 0x0f) ^ W(s)); + tmp = S(5, a) + F2(b, c, d) + e + W(s) + K(t); + e = d; d = c; c = S(30, b); b = a; a = tmp; + } + for (t = 60; t < 80; t++) { + s = t & 0x0f; + W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^ W((s+2) & 0x0f) ^ W(s)); + tmp = S(5, a) + F3(b, c, d) + e + W(s) + K(t); + e = d; d = c; c = S(30, b); b = a; a = tmp; + } + + H(0) = H(0) + a; + H(1) = H(1) + b; + H(2) = H(2) + c; + H(3) = H(3) + d; + H(4) = H(4) + e; + + bzero(&ctxt->m.b8[0], 64); +} + +/*------------------------------------------------------------*/ + +void +sha1_init(ctxt) + struct sha1_ctxt *ctxt; +{ + bzero(ctxt, sizeof(struct sha1_ctxt)); + H(0) = 0x67452301; + H(1) = 0xefcdab89; + H(2) = 0x98badcfe; + H(3) = 0x10325476; + H(4) = 0xc3d2e1f0; +} + +void +sha1_pad(ctxt) + struct sha1_ctxt *ctxt; +{ + size_t padlen; /*pad length in bytes*/ + size_t padstart; + + PUTPAD(0x80); + + padstart = COUNT % 64; + padlen = 64 - padstart; + if (padlen < 8) { + bzero(&ctxt->m.b8[padstart], padlen); + COUNT += padlen; + COUNT %= 64; + sha1_step(ctxt); + padstart = COUNT % 64; /* should be 0 */ + padlen = 64 - padstart; /* should be 64 */ + } + bzero(&ctxt->m.b8[padstart], padlen - 8); + COUNT += (padlen - 8); + COUNT %= 64; +#if BYTE_ORDER == BIG_ENDIAN + PUTPAD(ctxt->c.b8[0]); PUTPAD(ctxt->c.b8[1]); + PUTPAD(ctxt->c.b8[2]); PUTPAD(ctxt->c.b8[3]); + PUTPAD(ctxt->c.b8[4]); PUTPAD(ctxt->c.b8[5]); + PUTPAD(ctxt->c.b8[6]); PUTPAD(ctxt->c.b8[7]); +#else + PUTPAD(ctxt->c.b8[7]); PUTPAD(ctxt->c.b8[6]); + PUTPAD(ctxt->c.b8[5]); PUTPAD(ctxt->c.b8[4]); + PUTPAD(ctxt->c.b8[3]); PUTPAD(ctxt->c.b8[2]); + PUTPAD(ctxt->c.b8[1]); PUTPAD(ctxt->c.b8[0]); +#endif +} + +void +sha1_loop(ctxt, input0, len) + struct sha1_ctxt *ctxt; + caddr_t input0; + size_t len; +{ + u_int8_t *input; + size_t gaplen; + size_t gapstart; + size_t off; + size_t copysiz; + + input = (u_int8_t *)input0; + off = 0; + + while (off < len) { + gapstart = COUNT % 64; + gaplen = 64 - gapstart; + + copysiz = (gaplen < len - off) ? gaplen : len - off; + bcopy(&input[off], &ctxt->m.b8[gapstart], copysiz); + COUNT += copysiz; + COUNT %= 64; + ctxt->c.b64[0] += copysiz * 8; + if (COUNT % 64 == 0) + sha1_step(ctxt); + off += copysiz; + } +} + +void +sha1_result(ctxt, digest0) + struct sha1_ctxt *ctxt; + caddr_t digest0; +{ + u_int8_t *digest; + + digest = (u_int8_t *)digest0; + sha1_pad(ctxt); +#if BYTE_ORDER == BIG_ENDIAN + bcopy(&ctxt->h.b8[0], digest, 20); +#else + digest[0] = ctxt->h.b8[3]; digest[1] = ctxt->h.b8[2]; + digest[2] = ctxt->h.b8[1]; digest[3] = ctxt->h.b8[0]; + digest[4] = ctxt->h.b8[7]; digest[5] = ctxt->h.b8[6]; + digest[6] = ctxt->h.b8[5]; digest[7] = ctxt->h.b8[4]; + digest[8] = ctxt->h.b8[11]; digest[9] = ctxt->h.b8[10]; + digest[10] = ctxt->h.b8[9]; digest[11] = ctxt->h.b8[8]; + digest[12] = ctxt->h.b8[15]; digest[13] = ctxt->h.b8[14]; + digest[14] = ctxt->h.b8[13]; digest[15] = ctxt->h.b8[12]; + digest[16] = ctxt->h.b8[19]; digest[17] = ctxt->h.b8[18]; + digest[18] = ctxt->h.b8[17]; digest[19] = ctxt->h.b8[16]; +#endif +} + +#endif /*unsupported*/ diff --git a/sys/crypto/sha1.h b/sys/crypto/sha1.h new file mode 100644 index 0000000..05fdf27 --- /dev/null +++ b/sys/crypto/sha1.h @@ -0,0 +1,71 @@ +/* + * 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. + * + * $FreeBSD$ + */ +/* + * FIPS pub 180-1: Secure Hash Algorithm (SHA-1) + * based on: http://csrc.nist.gov/fips/fip180-1.txt + * implemented by Jun-ichiro itojun Itoh <itojun@itojun.org> + */ + +#ifndef _NETINET6_SHA1_H_ +#define _NETINET6_SHA1_H_ + +struct sha1_ctxt { + union { + u_int8_t b8[20]; + u_int32_t b32[5]; + } h; + union { + u_int8_t b8[8]; + u_int64_t b64[1]; + } c; + union { + u_int8_t b8[64]; + u_int32_t b32[16]; + } m; + u_int8_t count; +}; + +#if defined(KERNEL) || defined(_KERNEL) +extern void sha1_init __P((struct sha1_ctxt *)); +extern void sha1_pad __P((struct sha1_ctxt *)); +extern void sha1_loop __P((struct sha1_ctxt *, caddr_t, size_t)); +extern void sha1_result __P((struct sha1_ctxt *, caddr_t)); + +/* compatibilty with other SHA1 source codes */ +typedef struct sha1_ctxt SHA1_CTX; +#define SHA1Init(x) sha1_init((x)) +#define SHA1Update(x, y, z) sha1_loop((x), (y), (z)) +#define SHA1Final(x, y) sha1_result((y), (x)) +#endif + +#define SHA1_RESULTLEN (160/8) + +#endif /*_NETINET6_SHA1_H_*/ diff --git a/sys/i386/conf/LINT b/sys/i386/conf/LINT index 36b49cb..c67e6f2 100644 --- a/sys/i386/conf/LINT +++ b/sys/i386/conf/LINT @@ -367,6 +367,10 @@ options ROOTDEVNAME=\"da0s2e\" # options INET #Internet communications protocols options INET6 #IPv6 communications protocols +options IPSEC #IP security +options IPSEC_ESP #IP security (crypto; define w/ IPSEC) +options IPSEC_IPV6FWD #IP security tunnel for IPv6 +options IPSEC_DEBUG #debug for IP security options IPX #IPX/SPX communications protocols options IPXIP #IPX in IP encapsulation (not available) diff --git a/sys/i386/conf/NOTES b/sys/i386/conf/NOTES index 36b49cb..c67e6f2 100644 --- a/sys/i386/conf/NOTES +++ b/sys/i386/conf/NOTES @@ -367,6 +367,10 @@ options ROOTDEVNAME=\"da0s2e\" # options INET #Internet communications protocols options INET6 #IPv6 communications protocols +options IPSEC #IP security +options IPSEC_ESP #IP security (crypto; define w/ IPSEC) +options IPSEC_IPV6FWD #IP security tunnel for IPv6 +options IPSEC_DEBUG #debug for IP security options IPX #IPX/SPX communications protocols options IPXIP #IPX in IP encapsulation (not available) diff --git a/sys/net/bridge.c b/sys/net/bridge.c index eeb54ec..2ca06c2 100644 --- a/sys/net/bridge.c +++ b/sys/net/bridge.c @@ -575,7 +575,8 @@ bdg_forward (struct mbuf **m0, struct ifnet *dst) * pass the pkt to dummynet. Need to include m, dst, rule. * Dummynet consumes the packet in all cases. */ - dummynet_io((off & 0xffff), DN_TO_BDG_FWD, m, dst, NULL, 0, rule); + dummynet_io((off & 0xffff), DN_TO_BDG_FWD, m, dst, NULL, 0, rule, + 0); if (canfree) /* dummynet has consumed the original one */ *m0 = NULL ; return 0 ; diff --git a/sys/net/route.c b/sys/net/route.c index 45e0e39..f2b187f 100644 --- a/sys/net/route.c +++ b/sys/net/route.c @@ -1077,4 +1077,5 @@ rtinit(ifa, cmd, flags) return (error); } -SYSINIT(route, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY, route_init, 0); +/* This must be before ip6_init2(), which is now SI_ORDER_MIDDLE */ +SYSINIT(route, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD, route_init, 0); diff --git a/sys/netinet/igmp.c b/sys/netinet/igmp.c index 83cc650..37f2cc7 100644 --- a/sys/netinet/igmp.c +++ b/sys/netinet/igmp.c @@ -146,10 +146,11 @@ find_rti(ifp) } void -igmp_input(m, iphlen) +igmp_input(m, off, proto) register struct mbuf *m; - register int iphlen; + int off, proto; { + register int iphlen = off; register struct igmp *igmp; register struct ip *ip; register int igmplen; @@ -335,7 +336,7 @@ igmp_input(m, iphlen) * Pass all valid IGMP packets up to any process(es) listening * on a raw IGMP socket. */ - rip_input(m, iphlen); + rip_input(m, off, proto); } void diff --git a/sys/netinet/igmp_var.h b/sys/netinet/igmp_var.h index 0dd330fb..d22cd51 100644 --- a/sys/netinet/igmp_var.h +++ b/sys/netinet/igmp_var.h @@ -86,7 +86,7 @@ struct igmpstat { #define IGMP_AGE_THRESHOLD 540 void igmp_init __P((void)); -void igmp_input __P((struct mbuf *, int)); +void igmp_input __P((struct mbuf *, int, int)); void igmp_joingroup __P((struct in_multi *)); void igmp_leavegroup __P((struct in_multi *)); void igmp_fasttimo __P((void)); diff --git a/sys/netinet/in.c b/sys/netinet/in.c index 4562672..b638143 100644 --- a/sys/netinet/in.c +++ b/sys/netinet/in.c @@ -44,6 +44,7 @@ #include <sys/sysctl.h> #include <net/if.h> +#include <net/if_types.h> #include <net/route.h> #include <netinet/in.h> @@ -51,8 +52,18 @@ #include <netinet/igmp_var.h> +#include "gif.h" +#if NGIF > 0 +#include <net/if_gif.h> +#endif + static MALLOC_DEFINE(M_IPMADDR, "in_multi", "internet multicast address"); +static int in_mask2len __P((struct in_addr *)); +static void in_len2mask __P((struct in_addr *, int)); +static int in_lifaddr_ioctl __P((struct socket *, u_long, caddr_t, + struct ifnet *, struct proc *)); + static void in_socktrim __P((struct sockaddr_in *)); static int in_ifinit __P((struct ifnet *, struct in_ifaddr *, struct sockaddr_in *, int)); @@ -130,6 +141,44 @@ struct sockaddr_in *ap; } } +static int +in_mask2len(mask) + struct in_addr *mask; +{ + int x, y; + u_char *p; + + p = (u_char *)mask; + for (x = 0; x < sizeof(*mask); x++) { + if (p[x] != 0xff) + break; + } + y = 0; + if (x < sizeof(*mask)) { + for (y = 0; y < 8; y++) { + if ((p[x] & (0x80 >> y)) == 0) + break; + } + } + return x * 8 + y; +} + +static void +in_len2mask(mask, len) + struct in_addr *mask; + int len; +{ + int i; + u_char *p; + + p = (u_char *)mask; + bzero(mask, sizeof(*mask)); + for (i = 0; i < len / 8; i++) + p[i] = 0xff; + if (len % 8) + p[i] = (0xff00 >> (len % 8)) & 0xff; +} + static int in_interfaces; /* number of external internet interfaces */ /* @@ -154,6 +203,32 @@ in_control(so, cmd, data, ifp, p) int error, hostIsNew, maskIsNew, s; u_long i; +#if NGIF > 0 + if (ifp && ifp->if_type == IFT_GIF) { + switch (cmd) { + case SIOCSIFPHYADDR: + if (p && + (error = suser(p)) != 0) + return(error); + case SIOCGIFPSRCADDR: + case SIOCGIFPDSTADDR: + return gif_ioctl(ifp, cmd, data); + } + } +#endif + + switch (cmd) { + case SIOCALIFADDR: + case SIOCDLIFADDR: + if (p && (error = suser(p)) != 0) + return error; + /*fall through*/ + case SIOCGLIFADDR: + if (!ifp) + return EINVAL; + return in_lifaddr_ioctl(so, cmd, data, ifp, p); + } + /* * Find address for this interface, if it exists. * @@ -364,6 +439,184 @@ in_control(so, cmd, data, ifp, p) } /* + * SIOC[GAD]LIFADDR. + * SIOCGLIFADDR: get first address. (?!?) + * SIOCGLIFADDR with IFLR_PREFIX: + * get first address that matches the specified prefix. + * SIOCALIFADDR: add the specified address. + * SIOCALIFADDR with IFLR_PREFIX: + * EINVAL since we can't deduce hostid part of the address. + * SIOCDLIFADDR: delete the specified address. + * SIOCDLIFADDR with IFLR_PREFIX: + * delete the first address that matches the specified prefix. + * return values: + * EINVAL on invalid parameters + * EADDRNOTAVAIL on prefix match failed/specified address not found + * other values may be returned from in_ioctl() + */ +static int +in_lifaddr_ioctl(so, cmd, data, ifp, p) + struct socket *so; + u_long cmd; + caddr_t data; + struct ifnet *ifp; + struct proc *p; +{ + struct if_laddrreq *iflr = (struct if_laddrreq *)data; + struct ifaddr *ifa; + + /* sanity checks */ + if (!data || !ifp) { + panic("invalid argument to in_lifaddr_ioctl"); + /*NOTRECHED*/ + } + + switch (cmd) { + case SIOCGLIFADDR: + /* address must be specified on GET with IFLR_PREFIX */ + if ((iflr->flags & IFLR_PREFIX) == 0) + break; + /*FALLTHROUGH*/ + case SIOCALIFADDR: + case SIOCDLIFADDR: + /* address must be specified on ADD and DELETE */ + if (iflr->addr.__ss_family != AF_INET) + return EINVAL; + if (iflr->addr.__ss_len != sizeof(struct sockaddr_in)) + return EINVAL; + /* XXX need improvement */ + if (iflr->dstaddr.__ss_family + && iflr->dstaddr.__ss_family != AF_INET) + return EINVAL; + if (iflr->dstaddr.__ss_family + && iflr->dstaddr.__ss_len != sizeof(struct sockaddr_in)) + return EINVAL; + break; + default: /*shouldn't happen*/ + return EOPNOTSUPP; + } + if (sizeof(struct in_addr) * 8 < iflr->prefixlen) + return EINVAL; + + switch (cmd) { + case SIOCALIFADDR: + { + struct in_aliasreq ifra; + + if (iflr->flags & IFLR_PREFIX) + return EINVAL; + + /* copy args to in_aliasreq, perform ioctl(SIOCAIFADDR_IN6). */ + bzero(&ifra, sizeof(ifra)); + bcopy(iflr->iflr_name, ifra.ifra_name, + sizeof(ifra.ifra_name)); + + bcopy(&iflr->addr, &ifra.ifra_addr, iflr->addr.__ss_len); + + if (iflr->dstaddr.__ss_family) { /*XXX*/ + bcopy(&iflr->dstaddr, &ifra.ifra_dstaddr, + iflr->dstaddr.__ss_len); + } + + ifra.ifra_mask.sin_family = AF_INET; + ifra.ifra_mask.sin_len = sizeof(struct sockaddr_in); + in_len2mask(&ifra.ifra_mask.sin_addr, iflr->prefixlen); + + return in_control(so, SIOCAIFADDR, (caddr_t)&ifra, ifp, p); + } + case SIOCGLIFADDR: + case SIOCDLIFADDR: + { + struct in_ifaddr *ia; + struct in_addr mask, candidate, match; + struct sockaddr_in *sin; + int cmp; + + bzero(&mask, sizeof(mask)); + if (iflr->flags & IFLR_PREFIX) { + /* lookup a prefix rather than address. */ + in_len2mask(&mask, iflr->prefixlen); + + sin = (struct sockaddr_in *)&iflr->addr; + match.s_addr = sin->sin_addr.s_addr; + match.s_addr &= mask.s_addr; + + /* if you set extra bits, that's wrong */ + if (match.s_addr != sin->sin_addr.s_addr) + return EINVAL; + + cmp = 1; + } else { + if (cmd == SIOCGLIFADDR) { + /* on getting an address, take the 1st match */ + cmp = 0; /*XXX*/ + } else { + /* on deleting an address, do exact match */ + in_len2mask(&mask, 32); + sin = (struct sockaddr_in *)&iflr->addr; + match.s_addr = sin->sin_addr.s_addr; + + cmp = 1; + } + } + + TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + if (ifa->ifa_addr->sa_family != AF_INET6) + continue; + if (!cmp) + break; + candidate.s_addr = ((struct sockaddr_in *)&ifa->ifa_addr)->sin_addr.s_addr; + candidate.s_addr &= mask.s_addr; + if (candidate.s_addr == match.s_addr) + break; + } + if (!ifa) + return EADDRNOTAVAIL; + ia = (struct in_ifaddr *)ifa; + + if (cmd == SIOCGLIFADDR) { + /* fill in the if_laddrreq structure */ + bcopy(&ia->ia_addr, &iflr->addr, ia->ia_addr.sin_len); + + if ((ifp->if_flags & IFF_POINTOPOINT) != 0) { + bcopy(&ia->ia_dstaddr, &iflr->dstaddr, + ia->ia_dstaddr.sin_len); + } else + bzero(&iflr->dstaddr, sizeof(iflr->dstaddr)); + + iflr->prefixlen = + in_mask2len(&ia->ia_sockmask.sin_addr); + + iflr->flags = 0; /*XXX*/ + + return 0; + } else { + struct in_aliasreq ifra; + + /* fill in_aliasreq and do ioctl(SIOCDIFADDR_IN6) */ + bzero(&ifra, sizeof(ifra)); + bcopy(iflr->iflr_name, ifra.ifra_name, + sizeof(ifra.ifra_name)); + + bcopy(&ia->ia_addr, &ifra.ifra_addr, + ia->ia_addr.sin_len); + if ((ifp->if_flags & IFF_POINTOPOINT) != 0) { + bcopy(&ia->ia_dstaddr, &ifra.ifra_dstaddr, + ia->ia_dstaddr.sin_len); + } + bcopy(&ia->ia_sockmask, &ifra.ifra_dstaddr, + ia->ia_sockmask.sin_len); + + return in_control(so, SIOCDIFADDR, (caddr_t)&ifra, + ifp, p); + } + } + } + + return EOPNOTSUPP; /*just for safety*/ +} + +/* * Delete any existing route for an interface. */ void diff --git a/sys/netinet/in.h b/sys/netinet/in.h index 9e8a652..15a182c 100644 --- a/sys/netinet/in.h +++ b/sys/netinet/in.h @@ -419,7 +419,7 @@ struct ip_mreq { #define IPCTL_STATS 12 /* ipstat structure */ #define IPCTL_ACCEPTSOURCEROUTE 13 /* may accept source routed packets */ #define IPCTL_FASTFORWARDING 14 /* use fast IP forwarding code */ -#define IPCTL_KEEPFAITH 15 +#define IPCTL_KEEPFAITH 15 /* FAITH IPv4->IPv6 translater ctl */ #define IPCTL_GIF_TTL 16 /* default TTL for gif encap packet */ #define IPCTL_MAXID 17 diff --git a/sys/netinet/in_gif.c b/sys/netinet/in_gif.c index 6aa3673..021c800 100644 --- a/sys/netinet/in_gif.c +++ b/sys/netinet/in_gif.c @@ -52,11 +52,14 @@ #include <netinet/in.h> #include <netinet/in_systm.h> #include <netinet/ip.h> +#ifdef INET6 +#include <netinet/ip6.h> +#endif #include <netinet/ip_var.h> #include <netinet/in_gif.h> - +#include <netinet/ip_ecn.h> #ifdef INET6 -#include <netinet/ip6.h> +#include <netinet6/ip6_ecn.h> #endif #ifdef MROUTING @@ -168,6 +171,8 @@ in_gif_output(ifp, family, m, rt) /* version will be set in ip_output() */ iphdr.ip_ttl = ip_gif_ttl; iphdr.ip_len = m->m_pkthdr.len + sizeof(struct ip); + if (ifp->if_flags & IFF_LINK1) + ip_ecn_ingress(ECN_ALLOWED, &iphdr.ip_tos, &tos); /* prepend new IP header */ M_PREPEND(m, sizeof(struct ip), M_DONTWAIT); @@ -200,33 +205,18 @@ in_gif_output(ifp, family, m, rt) } } -#ifdef IPSEC - m->m_pkthdr.rcvif = NULL; -#endif /*IPSEC*/ error = ip_output(m, 0, &sc->gif_ro, 0, 0); return(error); } void -#if __STDC__ -in_gif_input(struct mbuf *m, ...) -#else -in_gif_input(m, va_alist) - struct mbuf *m; - va_dcl -#endif +in_gif_input(struct mbuf *m, int off, int proto) { - int off, proto; struct gif_softc *sc; struct ifnet *gifp = NULL; struct ip *ip; int i, af; - va_list ap; - - va_start(ap, m); - off = va_arg(ap, int); - proto = va_arg(ap, int); - va_end(ap); + u_int8_t otos; ip = mtod(m, struct ip *); @@ -262,7 +252,7 @@ in_gif_input(m, va_alist) #ifdef MROUTING /* for backward compatibility */ if (proto == IPPROTO_IPV4) { - ipip_input(m, off); + ipip_input(m, off, proto); return; } #endif /*MROUTING*/ @@ -271,6 +261,7 @@ in_gif_input(m, va_alist) return; } + otos = ip->ip_tos; m_adj(m, off); switch (proto) { @@ -284,12 +275,15 @@ in_gif_input(m, va_alist) return; } ip = mtod(m, struct ip *); + if (gifp->if_flags & IFF_LINK1) + ip_ecn_egress(ECN_ALLOWED, &otos, &ip->ip_tos); break; } #ifdef INET6 case IPPROTO_IPV6: { struct ip6_hdr *ip6; + u_int8_t itos; af = AF_INET6; if (m->m_len < sizeof(*ip6)) { m = m_pullup(m, sizeof(*ip6)); @@ -297,7 +291,11 @@ in_gif_input(m, va_alist) return; } ip6 = mtod(m, struct ip6_hdr *); + itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; + if (gifp->if_flags & IFF_LINK1) + ip_ecn_egress(ECN_ALLOWED, &otos, &itos); ip6->ip6_flow &= ~htonl(0xff << 20); + ip6->ip6_flow |= htonl((u_int32_t)itos << 20); break; } #endif /* INET6 */ diff --git a/sys/netinet/in_gif.h b/sys/netinet/in_gif.h index b874524..dcba361 100644 --- a/sys/netinet/in_gif.h +++ b/sys/netinet/in_gif.h @@ -36,7 +36,7 @@ extern int ip_gif_ttl; -void in_gif_input __P((struct mbuf *, ...)); +void in_gif_input __P((struct mbuf *, int off, int proto)); int in_gif_output __P((struct ifnet *, int, struct mbuf *, struct rtentry *)); #endif /*_NETINET_IN_GIF_H_*/ diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c index b3f6d61..2ac79ef 100644 --- a/sys/netinet/in_pcb.c +++ b/sys/netinet/in_pcb.c @@ -34,6 +34,7 @@ * $FreeBSD$ */ +#include "opt_ipsec.h" #include "opt_inet6.h" #include <sys/param.h> diff --git a/sys/netinet/in_proto.c b/sys/netinet/in_proto.c index b9a9e4a..e3243f8 100644 --- a/sys/netinet/in_proto.c +++ b/sys/netinet/in_proto.c @@ -36,6 +36,8 @@ #include "opt_ipdivert.h" #include "opt_ipx.h" +#include "opt_ipsec.h" +#include "opt_inet6.h" #include <sys/param.h> #include <sys/kernel.h> @@ -59,10 +61,21 @@ #include <netinet/tcp_var.h> #include <netinet/udp.h> #include <netinet/udp_var.h> + +#include <netinet/ipprotosw.h> + /* * TCP/IP protocol family: IP, ICMP, UDP, TCP. */ +#ifdef IPSEC +#include <netinet6/ipsec.h> +#include <netinet6/ah.h> +#ifdef IPSEC_ESP +#include <netinet6/esp.h> +#endif +#endif /* IPSEC */ + #include "gif.h" #if NGIF > 0 #include <netinet/in_gif.h> @@ -80,7 +93,7 @@ extern struct domain inetdomain; static struct pr_usrreqs nousrreqs; -struct protosw inetsw[] = { +struct ipprotosw inetsw[] = { { 0, &inetdomain, 0, 0, 0, 0, 0, 0, 0, @@ -124,6 +137,22 @@ struct protosw inetsw[] = { 0, 0, 0, 0, &rip_usrreqs }, +#ifdef IPSEC +{ SOCK_RAW, &inetdomain, IPPROTO_AH, PR_ATOMIC|PR_ADDR, + ah4_input, 0, 0, 0, + 0, + 0, 0, 0, 0, + &nousrreqs +}, +#ifdef IPSEC_ESP +{ SOCK_RAW, &inetdomain, IPPROTO_ESP, PR_ATOMIC|PR_ADDR, + esp4_input, 0, 0, 0, + 0, + 0, 0, 0, 0, + &nousrreqs +}, +#endif +#endif /* IPSEC */ #if NGIF > 0 { SOCK_RAW, &inetdomain, IPPROTO_IPV4, PR_ATOMIC|PR_ADDR, in_gif_input, 0, 0, 0, @@ -199,7 +228,8 @@ extern int in_inithead __P((void **, int)); struct domain inetdomain = { AF_INET, "internet", 0, 0, 0, - inetsw, &inetsw[sizeof(inetsw)/sizeof(inetsw[0])], 0, + (struct protosw *)inetsw, + (struct protosw *)&inetsw[sizeof(inetsw)/sizeof(inetsw[0])], 0, in_inithead, 32, sizeof(struct sockaddr_in) }; @@ -213,6 +243,9 @@ SYSCTL_NODE(_net_inet, IPPROTO_ICMP, icmp, CTLFLAG_RW, 0, "ICMP"); SYSCTL_NODE(_net_inet, IPPROTO_UDP, udp, CTLFLAG_RW, 0, "UDP"); SYSCTL_NODE(_net_inet, IPPROTO_TCP, tcp, CTLFLAG_RW, 0, "TCP"); SYSCTL_NODE(_net_inet, IPPROTO_IGMP, igmp, CTLFLAG_RW, 0, "IGMP"); +#ifdef IPSEC +SYSCTL_NODE(_net_inet, IPPROTO_AH, ipsec, CTLFLAG_RW, 0, "IPSEC"); +#endif /* IPSEC */ SYSCTL_NODE(_net_inet, IPPROTO_RAW, raw, CTLFLAG_RW, 0, "RAW"); #ifdef IPDIVERT SYSCTL_NODE(_net_inet, IPPROTO_DIVERT, div, CTLFLAG_RW, 0, "DIVERT"); diff --git a/sys/netinet/ip.h b/sys/netinet/ip.h index 0b6f1b6..7f92ba7 100644 --- a/sys/netinet/ip.h +++ b/sys/netinet/ip.h @@ -89,6 +89,10 @@ struct ip { #define IPTOS_THROUGHPUT 0x08 #define IPTOS_RELIABILITY 0x04 #define IPTOS_MINCOST 0x02 +/* ECN bits proposed by Sally Floyd */ +#define IPTOS_CE 0x01 /* congestion experienced */ +#define IPTOS_ECT 0x02 /* ECN-capable transport */ + /* * Definitions for IP precedence (also in ip_tos) (hopefully unused) diff --git a/sys/netinet/ip_divert.c b/sys/netinet/ip_divert.c index a2b76b3..5c2cd76 100644 --- a/sys/netinet/ip_divert.c +++ b/sys/netinet/ip_divert.c @@ -36,6 +36,7 @@ #include "opt_inet.h" #include "opt_ipfw.h" #include "opt_ipdivert.h" +#include "opt_ipsec.h" #ifndef INET #error "IPDIVERT requires INET." @@ -126,7 +127,7 @@ div_init(void) * with that protocol number to enter the system from the outside. */ void -div_input(struct mbuf *m, int hlen) +div_input(struct mbuf *m, int off, int proto) { ipstat.ips_noproto++; m_freem(m); @@ -296,7 +297,8 @@ div_output(so, m, addr, control) ipstat.ips_rawout++; /* XXX */ error = ip_output(m, inp->inp_options, &inp->inp_route, (so->so_options & SO_DONTROUTE) | - IP_ALLOWBROADCAST | IP_RAWOUTPUT, inp->inp_moptions); + IP_ALLOWBROADCAST | IP_RAWOUTPUT | IP_SOCKINMRCVIF, + inp->inp_moptions); } else { struct ifaddr *ifa; @@ -344,20 +346,27 @@ div_attach(struct socket *so, int proto, struct proc *p) if (p && (error = suser(p)) != 0) return error; + error = soreserve(so, div_sendspace, div_recvspace); + if (error) + return error; s = splnet(); error = in_pcballoc(so, &divcbinfo, p); splx(s); if (error) return error; - error = soreserve(so, div_sendspace, div_recvspace); - if (error) - return error; inp = (struct inpcb *)so->so_pcb; inp->inp_ip_p = proto; inp->inp_flags |= INP_HDRINCL; /* The socket is always "connected" because we always know "where" to send the packet */ so->so_state |= SS_ISCONNECTED; +#ifdef IPSEC + error = ipsec_init_policy(so, &inp->inp_sp); + if (error != 0) { + in_pcbdetach(inp); + return error; + } +#endif /*IPSEC*/ return 0; } @@ -414,7 +423,7 @@ div_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, struct mbuf *control, struct proc *p) { /* Packet must have a header (but that's about it) */ - if (m->m_len < sizeof (struct ip) || + if (m->m_len < sizeof (struct ip) && (m = m_pullup(m, sizeof (struct ip))) == 0) { ipstat.ips_toosmall++; m_freem(m); diff --git a/sys/netinet/ip_dummynet.c b/sys/netinet/ip_dummynet.c index 401e24d..9791a7f 100644 --- a/sys/netinet/ip_dummynet.c +++ b/sys/netinet/ip_dummynet.c @@ -220,7 +220,7 @@ dn_move(struct dn_pipe *pipe, int immediate) struct route *ro = &(pkt->ro) ; (void)ip_output((struct mbuf *)pkt, (struct mbuf *)pkt->ifp, - ro, pkt->dn_dst, NULL); + ro, pkt->flags, NULL); rt_unref (ro->ro_rt) ; } break ; @@ -290,7 +290,7 @@ int dummynet_io(int pipe_nr, int dir, struct mbuf *m, struct ifnet *ifp, struct route *ro, struct sockaddr_in *dst, - struct ip_fw_chain *rule) + struct ip_fw_chain *rule, int flags) { struct dn_pkt *pkt; struct dn_pipe *pipe; @@ -359,6 +359,12 @@ dummynet_io(int pipe_nr, int dir, dst = (struct sockaddr_in *)&(pkt->ro.ro_dst) ; pkt->dn_dst = dst; /* XXX this can't be right! */ + /* + * 'flags' also need to be kept for later packet treatment + * such as IPSEC. IPSEC consider sending packet's m->m_pkthdr.rcvif + * as 'socket *' at ip_output(), if IP_SOCKINMRCVIF is set. + */ + pkt->flags = flags; } if (pipe->r.head == NULL) pipe->r.head = pkt; diff --git a/sys/netinet/ip_dummynet.h b/sys/netinet/ip_dummynet.h index 55d9614..2c0e8b9 100644 --- a/sys/netinet/ip_dummynet.h +++ b/sys/netinet/ip_dummynet.h @@ -44,6 +44,7 @@ struct dn_pkt { int delay; /* stays queued until delay=0 */ struct ifnet *ifp; /* interface, for ip_output */ struct route ro; /* route, for ip_output. MUST COPY */ + int flags; /* flags, for ip_output */ #ifdef DUMMYNET_DEBUG struct timeval beg, mid; /* testing only */ @@ -109,7 +110,7 @@ void dn_rule_delete(void *r); /* used in ip_fw.c */ int dummynet_io(int pipe, int dir, struct mbuf *m, struct ifnet *ifp, struct route *ro, struct sockaddr_in * dst, - struct ip_fw_chain *rule); + struct ip_fw_chain *rule, int flags); #endif /* KERNEL */ #endif /* _IP_DUMMYNET_H */ diff --git a/sys/netinet/ip_ecn.c b/sys/netinet/ip_ecn.c new file mode 100644 index 0000000..7a1657f --- /dev/null +++ b/sys/netinet/ip_ecn.c @@ -0,0 +1,149 @@ +/* + * 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. + * + * $Id: ip_ecn.c,v 1.2 1999/07/30 12:17:15 itojun Exp $ + * $FreeBSD$ + */ +/* + * ECN consideration on tunnel ingress/egress operation. + * http://www.aciri.org/floyd/papers/draft-ipsec-ecn-00.txt + */ + +#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/errno.h> + +#ifdef INET +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#endif + +#ifdef INET6 +#ifndef INET +#include <netinet/in.h> +#endif +#include <netinet/ip6.h> +#endif + +#include <netinet/ip_ecn.h> +#ifdef INET6 +#include <netinet6/ip6_ecn.h> +#endif + +/* + * modify outer ECN (TOS) field on ingress operation (tunnel encapsulation). + * call it after you've done the default initialization/copy for the outer. + */ +void +ip_ecn_ingress(mode, outer, inner) + int mode; + u_int8_t *outer; + u_int8_t *inner; +{ + if (!outer || !inner) + panic("NULL pointer passed to ip_ecn_ingress"); + + switch (mode) { + case ECN_ALLOWED: /* ECN allowed */ + *outer &= ~IPTOS_CE; + break; + case ECN_FORBIDDEN: /* ECN forbidden */ + *outer &= ~(IPTOS_ECT | IPTOS_CE); + break; + case ECN_NOCARE: /* no consideration to ECN */ + break; + } +} + +/* + * modify inner ECN (TOS) field on egress operation (tunnel decapsulation). + * call it after you've done the default initialization/copy for the inner. + */ +void +ip_ecn_egress(mode, outer, inner) + int mode; + u_int8_t *outer; + u_int8_t *inner; +{ + if (!outer || !inner) + panic("NULL pointer passed to ip_ecn_egress"); + + switch (mode) { + case ECN_ALLOWED: + if (*outer & IPTOS_CE) + *inner |= IPTOS_CE; + break; + case ECN_FORBIDDEN: /* ECN forbidden */ + case ECN_NOCARE: /* no consideration to ECN */ + break; + } +} + +#ifdef INET6 +void +ip6_ecn_ingress(mode, outer, inner) + int mode; + u_int32_t *outer; + u_int32_t *inner; +{ + u_int8_t outer8, inner8; + + if (!outer || !inner) + panic("NULL pointer passed to ip6_ecn_ingress"); + + outer8 = (ntohl(*outer) >> 20) & 0xff; + inner8 = (ntohl(*inner) >> 20) & 0xff; + ip_ecn_ingress(mode, &outer8, &inner8); + *outer &= ~htonl(0xff << 20); + *outer |= htonl((u_int32_t)outer8 << 20); +} + +void +ip6_ecn_egress(mode, outer, inner) + int mode; + u_int32_t *outer; + u_int32_t *inner; +{ + u_int8_t outer8, inner8; + + if (!outer || !inner) + panic("NULL pointer passed to ip6_ecn_egress"); + + outer8 = (ntohl(*outer) >> 20) & 0xff; + inner8 = (ntohl(*inner) >> 20) & 0xff; + ip_ecn_egress(mode, &outer8, &inner8); + *inner &= ~htonl(0xff << 20); + *inner |= htonl((u_int32_t)inner8 << 20); +} +#endif diff --git a/sys/netinet/ip_ecn.h b/sys/netinet/ip_ecn.h new file mode 100644 index 0000000..4a0bfd5 --- /dev/null +++ b/sys/netinet/ip_ecn.h @@ -0,0 +1,44 @@ +/* + * 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. + * + * $Id: ip_ecn.h,v 1.2 1999/08/19 12:57:44 itojun Exp $ + * $FreeBSD$ + */ +/* + * ECN consideration on tunnel ingress/egress operation. + * http://www.aciri.org/floyd/papers/draft-ipsec-ecn-00.txt + */ + +#define ECN_ALLOWED 1 /* ECN allowed */ +#define ECN_FORBIDDEN 0 /* ECN forbidden */ +#define ECN_NOCARE (-1) /* no consideration to ECN */ + +#if defined(KERNEL) || defined(_KERNEL) +extern void ip_ecn_ingress __P((int, u_int8_t *, u_int8_t *)); +extern void ip_ecn_egress __P((int, u_int8_t *, u_int8_t *)); +#endif diff --git a/sys/netinet/ip_icmp.c b/sys/netinet/ip_icmp.c index 145699b..76ff004 100644 --- a/sys/netinet/ip_icmp.c +++ b/sys/netinet/ip_icmp.c @@ -34,6 +34,8 @@ * $FreeBSD$ */ +#include "opt_ipsec.h" + #include <sys/param.h> #include <sys/systm.h> #include <sys/mbuf.h> @@ -55,6 +57,16 @@ #include <netinet/ip_var.h> #include <netinet/icmp_var.h> +#ifdef IPSEC +#include <netinet6/ipsec.h> +#include <netkey/key.h> +#endif + +#include "faith.h" +#if defined(NFAITH) && NFAITH > 0 +#include <net/if_types.h> +#endif + /* * ICMP routines: error generation, receive packet processing, and * routines to turnaround packets back to the originator, and @@ -219,10 +231,11 @@ static struct sockaddr_in icmpgw = { sizeof (struct sockaddr_in), AF_INET }; * Process a received ICMP message. */ void -icmp_input(m, hlen) +icmp_input(m, off, proto) register struct mbuf *m; - int hlen; + int off, proto; { + int hlen = off; register struct icmp *icp; register struct ip *ip = mtod(m, struct ip *); int icmplen = ip->ip_len; @@ -263,12 +276,36 @@ icmp_input(m, hlen) m->m_len += hlen; m->m_data -= hlen; +#if defined(NFAITH) && 0 < NFAITH + if (m->m_pkthdr.rcvif && m->m_pkthdr.rcvif->if_type == IFT_FAITH) { + /* + * Deliver very specific ICMP type only. + */ + switch (icp->icmp_type) { + case ICMP_UNREACH: + case ICMP_TIMXCEED: + break; + default: + goto freeit; + } + } +#endif + #ifdef ICMPPRINTFS if (icmpprintfs) printf("icmp_input, type %d code %d\n", icp->icmp_type, icp->icmp_code); #endif +#ifdef IPSEC + /* drop it if it does not match the policy */ + /* XXX Is there meaning of check in here ? */ + if (ipsec4_in_reject(m, NULL)) { + ipsecstat.in_polvio++; + goto freeit; + } +#endif + /* * Message type specific processing. */ @@ -394,6 +431,10 @@ icmp_input(m, hlen) } #endif + /* + * XXX if the packet contains [IPv4 AH TCP], we can't make a + * notification to TCP layer. + */ ctlfunc = inetsw[ip_protox[icp->icmp_ip.ip_p]].pr_ctlinput; if (ctlfunc) (*ctlfunc)(code, (struct sockaddr *)&icmpsrc, @@ -518,6 +559,9 @@ reflect: (struct sockaddr *)0, RTF_GATEWAY | RTF_HOST, (struct sockaddr *)&icmpgw, (struct rtentry **)0); pfctlinput(PRC_REDIRECT_HOST, (struct sockaddr *)&icmpsrc); +#ifdef IPSEC + key_sa_routechange((struct sockaddr *)&icmpsrc); +#endif break; /* @@ -535,7 +579,7 @@ reflect: } raw: - rip_input(m, hlen); + rip_input(m, off, proto); return; freeit: diff --git a/sys/netinet/ip_icmp.h b/sys/netinet/ip_icmp.h index c8fd55f..201c3fc 100644 --- a/sys/netinet/ip_icmp.h +++ b/sys/netinet/ip_icmp.h @@ -186,7 +186,7 @@ struct icmp { #ifdef KERNEL void icmp_error __P((struct mbuf *, int, int, n_long, struct ifnet *)); -void icmp_input __P((struct mbuf *, int)); +void icmp_input __P((struct mbuf *, int, int)); #endif #endif diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c index a202a8b..be6d25d 100644 --- a/sys/netinet/ip_input.c +++ b/sys/netinet/ip_input.c @@ -42,6 +42,7 @@ #include "opt_ipdivert.h" #include "opt_ipfilter.h" #include "opt_ipstealth.h" +#include "opt_ipsec.h" #include <stddef.h> @@ -72,10 +73,27 @@ #include <netinet/ip_icmp.h> #include <machine/in_cksum.h> +#include <netinet/ipprotosw.h> + #include <sys/socketvar.h> #include <netinet/ip_fw.h> +#ifdef IPSEC +#include <netinet6/ipsec.h> +#include <netkey/key.h> +#ifdef IPSEC_DEBUG +#include <netkey/key_debug.h> +#else +#define KEYDEBUG(lev,arg) +#endif +#endif + +#include "faith.h" +#if defined(NFAITH) && NFAITH > 0 +#include <net/if_types.h> +#endif + #ifdef DUMMYNET #include <netinet/ip_dummynet.h> #endif @@ -104,12 +122,18 @@ static int ip_acceptsourceroute = 0; SYSCTL_INT(_net_inet_ip, IPCTL_ACCEPTSOURCEROUTE, accept_sourceroute, CTLFLAG_RW, &ip_acceptsourceroute, 0, "Enable accepting source routed IP packets"); + +static int ip_keepfaith = 0; +SYSCTL_INT(_net_inet_ip, IPCTL_KEEPFAITH, keepfaith, CTLFLAG_RW, + &ip_keepfaith, 0, + "Enable packet capture for FAITH IPv4->IPv6 translater daemon"); + #ifdef DIAGNOSTIC static int ipprintfs = 0; #endif extern struct domain inetdomain; -extern struct protosw inetsw[]; +extern struct ipprotosw inetsw[]; u_char ip_protox[IPPROTO_MAX]; static int ipqmaxlen = IFQ_MAXLEN; struct in_ifaddrhead in_ifaddrhead; /* first inet address */ @@ -181,10 +205,10 @@ static int ip_dooptions __P((struct mbuf *)); static void ip_forward __P((struct mbuf *, int)); static void ip_freef __P((struct ipq *)); #ifdef IPDIVERT -static struct ip *ip_reass __P((struct mbuf *, +static struct mbuf *ip_reass __P((struct mbuf *, struct ipq *, struct ipq *, u_int32_t *, u_int16_t *)); #else -static struct ip *ip_reass __P((struct mbuf *, struct ipq *, struct ipq *)); +static struct mbuf *ip_reass __P((struct mbuf *, struct ipq *, struct ipq *)); #endif static struct in_ifaddr *ip_rtaddr __P((struct in_addr)); static void ipintr __P((void)); @@ -196,17 +220,17 @@ static void ipintr __P((void)); void ip_init() { - register struct protosw *pr; + register struct ipprotosw *pr; register int i; TAILQ_INIT(&in_ifaddrhead); - pr = pffindproto(PF_INET, IPPROTO_RAW, SOCK_RAW); + pr = (struct ipprotosw *)pffindproto(PF_INET, IPPROTO_RAW, SOCK_RAW); if (pr == 0) panic("ip_init"); for (i = 0; i < IPPROTO_MAX; i++) ip_protox[i] = pr - inetsw; - for (pr = inetdomain.dom_protosw; - pr < inetdomain.dom_protoswNPROTOSW; pr++) + for (pr = (struct ipprotosw *)inetdomain.dom_protosw; + pr < (struct ipprotosw *)inetdomain.dom_protoswNPROTOSW; pr++) if (pr->pr_domain->dom_family == PF_INET && pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW) ip_protox[pr->pr_protocol] = pr - inetsw; @@ -387,7 +411,8 @@ iphack: #ifdef DUMMYNET if ((i & IP_FW_PORT_DYNT_FLAG) != 0) { /* Send packet to the appropriate pipe */ - dummynet_io(i&0xffff,DN_TO_IP_IN,m,NULL,NULL,0, rule); + dummynet_io(i&0xffff,DN_TO_IP_IN,m,NULL,NULL,0, rule, + 0); return; } #endif @@ -523,6 +548,19 @@ pass: if (ip->ip_dst.s_addr == INADDR_ANY) goto ours; +#if defined(NFAITH) && 0 < NFAITH + /* + * FAITH(Firewall Aided Internet Translator) + */ + if (m->m_pkthdr.rcvif && m->m_pkthdr.rcvif->if_type == IFT_FAITH) { + if (ip_keepfaith) { + if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_ICMP) + goto ours; + } + m_freem(m); + return; + } +#endif /* * Not for us; forward if possible and desirable. */ @@ -546,6 +584,11 @@ ours: * but it's not worth the time; just let them time out.) */ if (ip->ip_off & (IP_MF | IP_OFFMASK | IP_RF)) { + +#if 0 /* + * Reassembly should be able to treat a mbuf cluster, for later + * operation of contiguous protocol headers on the cluster. (KAME) + */ if (m->m_flags & M_EXT) { /* XXX */ if ((m = m_pullup(m, hlen)) == 0) { ipstat.ips_toosmall++; @@ -556,6 +599,7 @@ ours: } ip = mtod(m, struct ip *); } +#endif sum = IPREASS_HASH(ip->ip_src.s_addr, ip->ip_id); /* * Look for queue of fragments @@ -616,12 +660,12 @@ found: ipstat.ips_fragments++; m->m_pkthdr.header = ip; #ifdef IPDIVERT - ip = ip_reass(m, + m = ip_reass(m, fp, &ipq[sum], &divert_info, &divert_cookie); #else - ip = ip_reass(m, fp, &ipq[sum]); + m = ip_reass(m, fp, &ipq[sum]); #endif - if (ip == 0) { + if (m == 0) { #ifdef IPFIREWALL_FORWARD ip_fw_fwd_addr = NULL; #endif @@ -630,7 +674,7 @@ found: /* Get the length of the reassembled packets header */ hlen = IP_VHL_HL(ip->ip_vhl) << 2; ipstat.ips_reassembled++; - m = dtom(ip); + ip = mtod(m, struct ip *); #ifdef IPDIVERT /* Restore original checksum before diverting packet */ if (divert_info != 0) { @@ -689,11 +733,15 @@ found: * Switch out to protocol's input routine. */ ipstat.ips_delivered++; - (*inetsw[ip_protox[ip->ip_p]].pr_input)(m, hlen); + { + int off = hlen, nh = ip->ip_p; + + (*inetsw[ip_protox[ip->ip_p]].pr_input)(m, off, nh); #ifdef IPFIREWALL_FORWARD ip_fw_fwd_addr = NULL; /* tcp needed it */ #endif return; + } bad: #ifdef IPFIREWALL_FORWARD ip_fw_fwd_addr = NULL; @@ -731,7 +779,7 @@ NETISR_SET(NETISR_IP, ipintr); * tells us if we need to divert or tee the packet we're building. */ -static struct ip * +static struct mbuf * #ifdef IPDIVERT ip_reass(m, fp, where, divinfo, divcookie) #else @@ -801,7 +849,7 @@ ip_reass(m, fp, where) if (i > 0) { if (i >= ip->ip_len) goto dropfrag; - m_adj(dtom(ip), i); + m_adj(m, i); ip->ip_off += i; ip->ip_len -= i; } @@ -908,11 +956,11 @@ inserted: /* some debugging cruft by sklower, below, will go away soon */ if (m->m_flags & M_PKTHDR) { /* XXX this should be done elsewhere */ register int plen = 0; - for (t = m; m; m = m->m_next) - plen += m->m_len; - t->m_pkthdr.len = plen; + for (t = m; t; t = t->m_next) + plen += t->m_len; + m->m_pkthdr.len = plen; } - return (ip); + return (m); dropfrag: #ifdef IPDIVERT @@ -1399,6 +1447,9 @@ ip_forward(m, srcrt) struct mbuf *mcopy; n_long dest; struct ifnet *destifp; +#ifdef IPSEC + struct ifnet dummyifp; +#endif dest = 0; #ifdef DIAGNOSTIC @@ -1523,8 +1574,61 @@ ip_forward(m, srcrt) case EMSGSIZE: type = ICMP_UNREACH; code = ICMP_UNREACH_NEEDFRAG; +#ifndef IPSEC if (ipforward_rt.ro_rt) destifp = ipforward_rt.ro_rt->rt_ifp; +#else + /* + * If the packet is routed over IPsec tunnel, tell the + * originator the tunnel MTU. + * tunnel MTU = if MTU - sizeof(IP) - ESP/AH hdrsiz + * XXX quickhack!!! + */ + if (ipforward_rt.ro_rt) { + struct secpolicy *sp = NULL; + int ipsecerror; + int ipsechdr; + struct route *ro; + + sp = ipsec4_getpolicybyaddr(mcopy, + IPSEC_DIR_OUTBOUND, + IP_FORWARDING, + &ipsecerror); + + if (sp == NULL) + destifp = ipforward_rt.ro_rt->rt_ifp; + else { + /* count IPsec header size */ + ipsechdr = ipsec4_hdrsiz(mcopy, + IPSEC_DIR_OUTBOUND, + NULL); + + /* + * find the correct route for outer IPv4 + * header, compute tunnel MTU. + * + * XXX BUG ALERT + * The "dummyifp" code relies upon the fact + * that icmp_error() touches only ifp->if_mtu. + */ + /*XXX*/ + destifp = NULL; + if (sp->req != NULL + && sp->req->sav != NULL + && sp->req->sav->sah != NULL) { + ro = &sp->req->sav->sah->sa_route; + if (ro->ro_rt && ro->ro_rt->rt_ifp) { + dummyifp.if_mtu = + ro->ro_rt->rt_ifp->if_mtu; + dummyifp.if_mtu -= ipsechdr; + destifp = &dummyifp; + } + } + + key_freesp(sp); + } + } +#endif /*IPSEC*/ ipstat.ips_cantfrag++; break; diff --git a/sys/netinet/ip_mroute.c b/sys/netinet/ip_mroute.c index 20aa381..378102d 100644 --- a/sys/netinet/ip_mroute.c +++ b/sys/netinet/ip_mroute.c @@ -117,9 +117,10 @@ _mrt_ioctl(int req, caddr_t data, struct proc *p) int (*mrt_ioctl)(int, caddr_t, struct proc *) = _mrt_ioctl; void -rsvp_input(m, iphlen) /* XXX must fixup manually */ +rsvp_input(m, off, proto) /* XXX must fixup manually */ struct mbuf *m; - int iphlen; + int off; + int proto; { /* Can still get packets with rsvp_on = 0 if there is a local member * of the group to which the RSVP packet is addressed. But in this @@ -133,15 +134,15 @@ rsvp_input(m, iphlen) /* XXX must fixup manually */ if (ip_rsvpd != NULL) { if (rsvpdebug) printf("rsvp_input: Sending packet up old-style socket\n"); - rip_input(m, iphlen); + rip_input(m, off, proto); return; } /* Drop the packet */ m_freem(m); } -void ipip_input(struct mbuf *m, int iphlen) { /* XXX must fixup manually */ - rip_input(m, iphlen); +void ipip_input(struct mbuf *m, int off, int proto) { /* XXX must fixup manually */ + rip_input(m, off, proto); } int (*legal_vif_num)(int) = 0; @@ -1609,12 +1610,13 @@ encap_send(ip, vifp, m) */ void #ifdef MROUTE_LKM -X_ipip_input(m, iphlen) +X_ipip_input(m, off, proto) #else -ipip_input(m, iphlen) +ipip_input(m, off, proto) #endif register struct mbuf *m; - int iphlen; + int off; + int proto; { struct ifnet *ifp = m->m_pkthdr.rcvif; register struct ip *ip = mtod(m, struct ip *); @@ -1624,7 +1626,7 @@ ipip_input(m, iphlen) register struct vif *vifp; if (!have_encap_tunnel) { - rip_input(m, iphlen); + rip_input(m, off, proto); return; } /* @@ -2119,9 +2121,10 @@ ip_rsvp_force_done(so) } void -rsvp_input(m, iphlen) +rsvp_input(m, off, proto) struct mbuf *m; - int iphlen; + int off; + int proto; { int vifi; register struct ip *ip = mtod(m, struct ip *); @@ -2147,7 +2150,7 @@ rsvp_input(m, iphlen) if (ip_rsvpd != NULL) { if (rsvpdebug) printf("rsvp_input: Sending packet up old-style socket\n"); - rip_input(m, iphlen); + rip_input(m, off, proto); /* xxx */ return; } diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c index 2ed22e6..52bfdb9 100644 --- a/sys/netinet/ip_output.c +++ b/sys/netinet/ip_output.c @@ -40,6 +40,7 @@ #include "opt_ipdn.h" #include "opt_ipdivert.h" #include "opt_ipfilter.h" +#include "opt_ipsec.h" #include <sys/param.h> #include <sys/systm.h> @@ -49,6 +50,7 @@ #include <sys/protosw.h> #include <sys/socket.h> #include <sys/socketvar.h> +#include <sys/proc.h> #include <net/if.h> #include <net/route.h> @@ -60,6 +62,8 @@ #include <netinet/in_var.h> #include <netinet/ip_var.h> +#include "faith.h" + #ifdef vax #include <machine/mtpr.h> #endif @@ -67,6 +71,16 @@ static MALLOC_DEFINE(M_IPMOPTS, "ip_moptions", "internet multicast options"); +#ifdef IPSEC +#include <netinet6/ipsec.h> +#include <netkey/key.h> +#ifdef IPSEC_DEBUG +#include <netkey/key_debug.h> +#else +#define KEYDEBUG(lev,arg) +#endif +#endif /*IPSEC*/ + #include <netinet/ip_fw.h> #ifdef DUMMYNET @@ -123,6 +137,11 @@ ip_output(m0, opt, ro, flags, imo) struct sockaddr_in *dst; struct in_ifaddr *ia; int isbroadcast; +#ifdef IPSEC + struct route iproute; + struct socket *so; + struct secpolicy *sp = NULL; +#endif u_int16_t divert_cookie; /* firewall cookie */ #ifdef IPFIREWALL_FORWARD int fwd_rewrite_src = 0; @@ -136,6 +155,32 @@ ip_output(m0, opt, ro, flags, imo) #else divert_cookie = 0; #endif + +#ifdef IPSEC + /* + * NOTE: If IP_SOCKINMRCVIF flag is set, 'socket *' is kept in + * m->m_pkthdr.rcvif for later IPSEC check. In this case, + * m->m_pkthdr will be NULL cleared after the contents is saved in + * 'so'. + * NULL clearance of rcvif should be natural because the packet should + * have been sent from my own socket and has no rcvif in this case. + * It is also necessary because someone might consider it as + * 'ifnet *', and cause SEGV. + */ + if ((flags & IP_SOCKINMRCVIF) != 0) { +#if defined(IPFIREWALL) && defined(DUMMYNET) + if (m->m_type == MT_DUMMYNET) { + so = (struct socket *)m->m_next->m_pkthdr.rcvif; + m->m_next->m_pkthdr.rcvif = NULL; + } else +#endif + { + so = (struct socket *)m->m_pkthdr.rcvif; + m->m_pkthdr.rcvif = NULL; + } + } else + so = NULL; +#endif /*IPSEC*/ #if defined(IPFIREWALL) && defined(DUMMYNET) /* @@ -151,13 +196,12 @@ ip_output(m0, opt, ro, flags, imo) * they are used to hold ifp, dst and NULL, respectively. */ rule = (struct ip_fw_chain *)(m->m_data) ; + dst = (struct sockaddr_in *)((struct dn_pkt *)m)->dn_dst; m0 = m = m->m_next ; ip = mtod(m, struct ip *); - dst = (struct sockaddr_in *)flags ; ifp = (struct ifnet *)opt; hlen = IP_VHL_HL(ip->ip_vhl) << 2 ; opt = NULL ; - flags = 0 ; /* XXX is this correct ? */ goto sendit; } else rule = NULL ; @@ -455,7 +499,8 @@ sendit: * XXX note: if the ifp or ro entry are deleted * while a pkt is in dummynet, we are in trouble! */ - dummynet_io(off & 0xffff, DN_TO_IP_OUT, m,ifp,ro,dst,rule); + dummynet_io(off & 0xffff, DN_TO_IP_OUT, m,ifp,ro,dst,rule, + flags); goto done; } #endif @@ -597,6 +642,125 @@ sendit: } pass: +#ifdef IPSEC + /* get SP for this packet */ + if (so == NULL) + sp = ipsec4_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND, flags, &error); + else + sp = ipsec4_getpolicybysock(m, IPSEC_DIR_OUTBOUND, so, &error); + + if (sp == NULL) { + ipsecstat.out_inval++; + goto bad; + } + + error = 0; + + /* check policy */ + switch (sp->policy) { + case IPSEC_POLICY_DISCARD: + /* + * This packet is just discarded. + */ + ipsecstat.out_polvio++; + goto bad; + + case IPSEC_POLICY_BYPASS: + case IPSEC_POLICY_NONE: + /* no need to do IPsec. */ + goto skip_ipsec; + + case IPSEC_POLICY_IPSEC: + if (sp->req == NULL) { + /* XXX should be panic ? */ + printf("ip_output: No IPsec request specified.\n"); + error = EINVAL; + goto bad; + } + break; + + case IPSEC_POLICY_ENTRUST: + default: + printf("ip_output: Invalid policy found. %d\n", sp->policy); + } + + ip->ip_len = htons((u_short)ip->ip_len); + ip->ip_off = htons((u_short)ip->ip_off); + ip->ip_sum = 0; + + { + struct ipsec_output_state state; + bzero(&state, sizeof(state)); + state.m = m; + if (flags & IP_ROUTETOIF) { + state.ro = &iproute; + bzero(&iproute, sizeof(iproute)); + } else + state.ro = ro; + state.dst = (struct sockaddr *)dst; + + error = ipsec4_output(&state, sp, flags); + + m = state.m; + if (flags & IP_ROUTETOIF) { + /* + * if we have tunnel mode SA, we may need to ignore + * IP_ROUTETOIF. + */ + if (state.ro != &iproute || state.ro->ro_rt != NULL) { + flags &= ~IP_ROUTETOIF; + ro = state.ro; + } + } else + ro = state.ro; + dst = (struct sockaddr_in *)state.dst; + if (error) { + /* mbuf is already reclaimed in ipsec4_output. */ + m0 = NULL; + switch (error) { + case EHOSTUNREACH: + case ENETUNREACH: + case EMSGSIZE: + case ENOBUFS: + case ENOMEM: + break; + default: + printf("ip4_output (ipsec): error code %d\n", error); + /*fall through*/ + case ENOENT: + /* don't show these error codes to the user */ + error = 0; + break; + } + goto bad; + } + } + + /* be sure to update variables that are affected by ipsec4_output() */ + ip = mtod(m, struct ip *); +#ifdef _IP_VHL + hlen = IP_VHL_HL(ip->ip_vhl) << 2; +#else + hlen = ip->ip_hl << 2; +#endif + if (ro->ro_rt == NULL) { + if ((flags & IP_ROUTETOIF) == 0) { + printf("ip_output: " + "can't update route after IPsec processing\n"); + error = EHOSTUNREACH; /*XXX*/ + goto bad; + } + } else { + /* nobody uses ia beyond here */ + ifp = ro->ro_rt->rt_ifp; + } + + /* make it flipped, again. */ + ip->ip_len = ntohs((u_short)ip->ip_len); + ip->ip_off = ntohs((u_short)ip->ip_off); +skip_ipsec: +#endif /*IPSEC*/ + /* * If small enough for interface, can just send directly. */ @@ -724,6 +888,17 @@ sendorfree: ipstat.ips_fragmented++; } done: +#ifdef IPSEC + if (ro == &iproute && ro->ro_rt) { + RTFREE(ro->ro_rt); + ro->ro_rt = NULL; + } + if (sp != NULL) { + KEYDEBUG(KEYDEBUG_IPSEC_STAMP, + printf("DP ip_output call free SP:%p\n", sp)); + key_freesp(sp); + } +#endif /* IPSEC */ return (error); bad: m_freem(m0); @@ -868,6 +1043,9 @@ ip_ctloutput(so, sopt) case IP_RECVRETOPTS: case IP_RECVDSTADDR: case IP_RECVIF: +#if defined(NFAITH) && NFAITH > 0 + case IP_FAITH: +#endif error = sooptcopyin(sopt, &optval, sizeof optval, sizeof optval); if (error) @@ -902,6 +1080,12 @@ ip_ctloutput(so, sopt) case IP_RECVIF: OPTSET(INP_RECVIF); break; + +#if defined(NFAITH) && NFAITH > 0 + case IP_FAITH: + OPTSET(INP_FAITH); + break; +#endif } break; #undef OPTSET @@ -943,6 +1127,28 @@ ip_ctloutput(so, sopt) } break; +#ifdef IPSEC + case IP_IPSEC_POLICY: + { + caddr_t req; + int priv; + struct mbuf *m; + int optname; + + if ((error = soopt_getm(sopt, &m)) != 0) /* XXX */ + break; + if ((error = soopt_mcopyin(sopt, m)) != 0) /* XXX */ + break; + priv = (sopt->sopt_p != NULL && + suser(sopt->sopt_p) != 0) ? 0 : 1; + req = mtod(m, caddr_t); + optname = sopt->sopt_name; + error = ipsec4_set_policy(inp, optname, req, priv); + m_freem(m); + break; + } +#endif /*IPSEC*/ + default: error = ENOPROTOOPT; break; @@ -969,6 +1175,9 @@ ip_ctloutput(so, sopt) case IP_RECVDSTADDR: case IP_RECVIF: case IP_PORTRANGE: +#if defined(NFAITH) && NFAITH > 0 + case IP_FAITH: +#endif switch (sopt->sopt_name) { case IP_TOS: @@ -1005,6 +1214,12 @@ ip_ctloutput(so, sopt) else optval = 0; break; + +#if defined(NFAITH) && NFAITH > 0 + case IP_FAITH: + optval = OPTBIT(INP_FAITH); + break; +#endif } error = sooptcopyout(sopt, &optval, sizeof optval); break; @@ -1018,6 +1233,22 @@ ip_ctloutput(so, sopt) error = ip_getmoptions(sopt, inp->inp_moptions); break; +#ifdef IPSEC + case IP_IPSEC_POLICY: + { + struct mbuf *m; + caddr_t req = NULL; + + if (m != 0) + req = mtod(m, caddr_t); + error = ipsec4_get_policy(sotoinpcb(so), req, &m); + if (error == 0) + error = soopt_mcopyout(sopt, m); /* XXX */ + m_freem(m); + break; + } +#endif /*IPSEC*/ + default: error = ENOPROTOOPT; break; diff --git a/sys/netinet/ip_var.h b/sys/netinet/ip_var.h index c56a340..2c438d6 100644 --- a/sys/netinet/ip_var.h +++ b/sys/netinet/ip_var.h @@ -131,6 +131,9 @@ struct ipstat { #define IP_RAWOUTPUT 0x2 /* raw ip header exists */ #define IP_ROUTETOIF SO_DONTROUTE /* bypass routing tables */ #define IP_ALLOWBROADCAST SO_BROADCAST /* can send broadcast packets */ +#define IP_SOCKINMRCVIF 0x100 /* IPSEC hack; + * socket pointer in sending + * packet's m_pkthdr.rcvif */ struct ip; struct inpcb; @@ -166,10 +169,10 @@ void ip_stripoptions __P((struct mbuf *, struct mbuf *)); int rip_ctloutput __P((struct socket *, struct sockopt *)); void rip_ctlinput __P((int, struct sockaddr *, void *)); void rip_init __P((void)); -void rip_input __P((struct mbuf *, int)); +void rip_input __P((struct mbuf *, int, int)); int rip_output __P((struct mbuf *, struct socket *, u_long)); -void ipip_input __P((struct mbuf *, int)); -void rsvp_input __P((struct mbuf *, int)); +void ipip_input __P((struct mbuf *, int, int)); +void rsvp_input __P((struct mbuf *, int, int)); int ip_rsvp_init __P((struct socket *)); int ip_rsvp_done __P((void)); int ip_rsvp_vif_init __P((struct socket *, struct sockopt *)); @@ -178,7 +181,7 @@ void ip_rsvp_force_done __P((struct socket *)); #ifdef IPDIVERT void div_init __P((void)); -void div_input __P((struct mbuf *, int)); +void div_input __P((struct mbuf *, int, int)); void divert_packet __P((struct mbuf *, int, int)); extern struct pr_usrreqs div_usrreqs; extern u_int16_t ip_divert_cookie; diff --git a/sys/netinet/ipprotosw.h b/sys/netinet/ipprotosw.h new file mode 100644 index 0000000..0ecb64d --- /dev/null +++ b/sys/netinet/ipprotosw.h @@ -0,0 +1,103 @@ +/* + * Copyright (C) 1995, 1996, 1997, 1998, and 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. + */ + +/*- + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)protosw.h 8.1 (Berkeley) 6/2/93 + * $FreeBSD$ + */ + +#ifndef _NETINET_IPPROTOSW_H_ +#define _NETINET_IPPROTOSW_H_ + +/* Forward declare these structures referenced from prototypes below. */ +struct mbuf; +struct proc; +struct sockaddr; +struct socket; +struct sockopt; + +struct ipprotosw { + short pr_type; /* socket type used for */ + struct domain *pr_domain; /* domain protocol a member of */ + short pr_protocol; /* protocol number */ + short pr_flags; /* see below */ +/* protocol-protocol hooks */ + void (*pr_input) __P((struct mbuf *, int off, int proto)); + /* input to protocol (from below) */ + int (*pr_output) __P((struct mbuf *m, struct socket *so)); + /* output to protocol (from above) */ + void (*pr_ctlinput)__P((int, struct sockaddr *, void *)); + /* control input (from below) */ + int (*pr_ctloutput)__P((struct socket *, struct sockopt *)); + /* control output (from above) */ +/* user-protocol hook */ + void *pr_ousrreq; +/* utility hooks */ + void (*pr_init) __P((void)); /* initialization hook */ + void (*pr_fasttimo) __P((void)); + /* fast timeout (200ms) */ + void (*pr_slowtimo) __P((void)); + /* slow timeout (500ms) */ + void (*pr_drain) __P((void)); + /* flush any excess space possible */ + struct pr_usrreqs *pr_usrreqs; /* supersedes pr_usrreq() */ +}; + +#endif /* !_NETINET_IPPROTOSW_H_ */ diff --git a/sys/netinet/raw_ip.c b/sys/netinet/raw_ip.c index ba36bd3..a3ddb23 100644 --- a/sys/netinet/raw_ip.c +++ b/sys/netinet/raw_ip.c @@ -34,6 +34,9 @@ * $FreeBSD$ */ +#include "opt_inet6.h" +#include "opt_ipsec.h" + #include <sys/param.h> #include <sys/systm.h> #include <sys/kernel.h> @@ -61,6 +64,10 @@ #include <netinet/ip_fw.h> +#ifdef IPSEC +#include <netinet6/ipsec.h> +#endif /*IPSEC*/ + #include "opt_ipdn.h" #ifdef DUMMYNET #include <netinet/ip_dummynet.h> @@ -105,9 +112,9 @@ static struct sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET }; * mbuf chain. */ void -rip_input(m, iphlen) +rip_input(m, off, proto) struct mbuf *m; - int iphlen; + int off, proto; { register struct ip *ip = mtod(m, struct ip *); register struct inpcb *inp; @@ -115,8 +122,12 @@ rip_input(m, iphlen) struct mbuf *opts = 0; ripsrc.sin_addr = ip->ip_src; - for (inp = ripcb.lh_first; inp != NULL; inp = inp->inp_list.le_next) { - if (inp->inp_ip_p && inp->inp_ip_p != ip->ip_p) + LIST_FOREACH(inp, &ripcb, inp_list) { +#ifdef INET6 + if ((inp->inp_vflag & INP_IPV4) == 0) + continue; +#endif + if (inp->inp_ip_p && inp->inp_ip_p != proto) continue; if (inp->inp_laddr.s_addr && inp->inp_laddr.s_addr != ip->ip_dst.s_addr) @@ -215,7 +226,13 @@ rip_output(m, so, dst) flags |= IP_RAWOUTPUT; ipstat.ips_rawout++; } - return (ip_output(m, inp->inp_options, &inp->inp_route, flags, + +#ifdef IPSEC + m->m_pkthdr.rcvif = (struct ifnet *)so; /*XXX*/ +#endif /*IPSEC*/ + + return (ip_output(m, inp->inp_options, &inp->inp_route, + flags | IP_SOCKINMRCVIF, inp->inp_moptions)); } @@ -431,16 +448,24 @@ rip_attach(struct socket *so, int proto, struct proc *p) if (p && (error = suser(p)) != 0) return error; + error = soreserve(so, rip_sendspace, rip_recvspace); + if (error) + return error; s = splnet(); error = in_pcballoc(so, &ripcbinfo, p); splx(s); if (error) return error; - error = soreserve(so, rip_sendspace, rip_recvspace); - if (error) - return error; inp = (struct inpcb *)so->so_pcb; + inp->inp_vflag |= INP_IPV4; inp->inp_ip_p = proto; +#ifdef IPSEC + error = ipsec_init_policy(so, &inp->inp_sp); + if (error != 0) { + in_pcbdetach(inp); + return error; + } +#endif /*IPSEC*/ return 0; } diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c index 33a478c..9605f7f 100644 --- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -273,10 +273,11 @@ present: * protocol specification dated September, 1981 very closely. */ void -tcp_input(m, iphlen) +tcp_input(m, off0, proto) register struct mbuf *m; - int iphlen; + int off0, proto; { + int iphlen = off0; register struct tcpiphdr *ti; register struct inpcb *inp; u_char *optp = NULL; diff --git a/sys/netinet/tcp_reass.c b/sys/netinet/tcp_reass.c index 33a478c..9605f7f 100644 --- a/sys/netinet/tcp_reass.c +++ b/sys/netinet/tcp_reass.c @@ -273,10 +273,11 @@ present: * protocol specification dated September, 1981 very closely. */ void -tcp_input(m, iphlen) +tcp_input(m, off0, proto) register struct mbuf *m; - int iphlen; + int off0, proto; { + int iphlen = off0; register struct tcpiphdr *ti; register struct inpcb *inp; u_char *optp = NULL; diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c index 7d7f71f..d3aea36 100644 --- a/sys/netinet/tcp_usrreq.c +++ b/sys/netinet/tcp_usrreq.c @@ -34,6 +34,7 @@ * $FreeBSD$ */ +#include "opt_ipsec.h" #include "opt_tcpdebug.h" #include <sys/param.h> @@ -63,6 +64,10 @@ #include <netinet/tcp_debug.h> #endif +#ifdef IPSEC +#include <netinet6/ipsec.h> +#endif /*IPSEC*/ + /* * TCP protocol interface to socket abstraction. */ @@ -731,6 +736,13 @@ tcp_attach(so, p) if (error) return (error); inp = sotoinpcb(so); +#ifdef IPSEC + error = ipsec_init_policy(so, &inp->inp_sp); + if (error) { + in_pcbdetach(inp); + return (error); + } +#endif /*IPSEC*/ inp->inp_vflag |= INP_IPV4; tp = tcp_newtcpcb(inp); if (tp == 0) { diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h index 0258b77..9c24732 100644 --- a/sys/netinet/tcp_var.h +++ b/sys/netinet/tcp_var.h @@ -361,7 +361,7 @@ void tcp_fasttimo __P((void)); struct rmxp_tao * tcp_gettaocache __P((struct inpcb *)); void tcp_init __P((void)); -void tcp_input __P((struct mbuf *, int)); +void tcp_input __P((struct mbuf *, int, int)); void tcp_mss __P((struct tcpcb *, int)); int tcp_mssopt __P((struct tcpcb *)); void tcp_mtudisc __P((struct inpcb *, int)); diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c index bc854de..2ed9a36 100644 --- a/sys/netinet/udp_usrreq.c +++ b/sys/netinet/udp_usrreq.c @@ -34,6 +34,7 @@ * $FreeBSD$ */ +#include "opt_ipsec.h" #include "opt_inet6.h" #include <sys/param.h> @@ -705,7 +706,8 @@ udp_output(inp, m, addr, control, p) #endif /*IPSEC*/ error = ip_output(m, inp->inp_options, &inp->inp_route, - inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST), + (inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST)) + | IP_SOCKINMRCVIF, inp->inp_moptions); if (addr) { diff --git a/sys/netinet6/ah.h b/sys/netinet6/ah.h new file mode 100644 index 0000000..2786272 --- /dev/null +++ b/sys/netinet6/ah.h @@ -0,0 +1,88 @@ +/* + * 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. + * + * $FreeBSD$ + */ + +/* + * RFC1826/2402 authentication header. + */ + +#ifndef _NETINET6_AH_H_ +#define _NETINET6_AH_H_ + +struct secasvar; + +struct ah { + u_int8_t ah_nxt; /* Next Header */ + u_int8_t ah_len; /* Length of data, in 32bit */ + u_int16_t ah_reserve; /* Reserved for future use */ + u_int32_t ah_spi; /* Security parameter index */ + /* variable size, 32bit bound*/ /* Authentication data */ +}; + +struct newah { + u_int8_t ah_nxt; /* Next Header */ + u_int8_t ah_len; /* Length of data + 1, in 32bit */ + u_int16_t ah_reserve; /* Reserved for future use */ + u_int32_t ah_spi; /* Security parameter index */ + u_int32_t ah_seq; /* Sequence number field */ + /* variable size, 32bit bound*/ /* Authentication data */ +}; + +struct ah_algorithm_state { + struct secasvar *sav; + void* foo; /*per algorithm data - maybe*/ +}; + +struct ah_algorithm { + int (*sumsiz) __P((struct secasvar *)); + int (*mature) __P((struct secasvar *)); + int keymin; /* in bits */ + int keymax; /* in bits */ + void (*init) __P((struct ah_algorithm_state *, struct secasvar *)); + void (*update) __P((struct ah_algorithm_state *, caddr_t, size_t)); + void (*result) __P((struct ah_algorithm_state *, caddr_t)); +}; + +#define AH_MAXSUMSIZE 16 + +#ifdef KERNEL +extern struct ah_algorithm ah_algorithms[]; + +/* cksum routines */ +extern int ah_hdrlen __P((struct secasvar *)); + +extern size_t ah_hdrsiz __P((struct ipsecrequest *)); +extern void ah4_input __P((struct mbuf *, int, int)); +extern int ah4_output __P((struct mbuf *, struct ipsecrequest *)); +extern int ah4_calccksum __P((struct mbuf *, caddr_t, + struct ah_algorithm *, struct secasvar *)); +#endif /*KERNEL*/ + +#endif /*_NETINET6_AH_H_*/ diff --git a/sys/netinet6/ah6.h b/sys/netinet6/ah6.h new file mode 100644 index 0000000..9ae83a9 --- /dev/null +++ b/sys/netinet6/ah6.h @@ -0,0 +1,49 @@ +/* + * 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. + * + * $FreeBSD$ + */ + +/* + * RFC1826/2402 authentication header. + */ + +#ifndef _NETINET6_AH6_H_ +#define _NETINET6_AH6_H_ + +#ifdef KERNEL +struct secasvar; + +extern int ah6_input __P((struct mbuf **, int *, int)); +extern int ah6_output __P((struct mbuf *, u_char *, struct mbuf *, + struct ipsecrequest *)); +extern int ah6_calccksum __P((struct mbuf *, caddr_t, + struct ah_algorithm *, struct secasvar *)); +#endif /*KERNEL*/ + +#endif /*_NETINET6_AH6_H_*/ diff --git a/sys/netinet6/ah_core.c b/sys/netinet6/ah_core.c new file mode 100644 index 0000000..e30bf2a --- /dev/null +++ b/sys/netinet6/ah_core.c @@ -0,0 +1,1125 @@ +/* + * 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. + * + * $FreeBSD$ + */ + +/* + * RFC1826/2402 authentication header. + */ + +#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/kernel.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> +#include <netinet/in_pcb.h> + +#ifdef INET6 +#include <netinet6/ip6.h> +#include <netinet6/ip6_var.h> +#include <netinet6/icmp6.h> +#endif + +#include <netinet6/ipsec.h> +#include <netinet6/ah.h> +#ifdef INET6 +#include <netinet6/ipsec6.h> +#include <netinet6/ah6.h> +#endif +#ifdef IPSEC_ESP +#include <netinet6/esp.h> +#ifdef INET6 +#include <netinet6/esp6.h> +#endif +#endif +#include <net/pfkeyv2.h> +#include <netkey/key_var.h> +#include <netkey/keydb.h> +#include <sys/md5.h> +#include <crypto/sha1.h> + +#include <net/net_osdep.h> + +#define HMACSIZE 16 + +#ifdef INET6 +#define ZEROBUFLEN 256 +static char zerobuf[ZEROBUFLEN]; +#endif + +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)); + +/* checksum algorithms */ +/* NOTE: The order depends on SADB_AALG_x in netkey/keyv2.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(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) { + printf("ah_none_mature: protocol and algorithm mismatch.\n"); + return 1; + } + return 0; +} + +static void +ah_none_init(state, sav) + struct ah_algorithm_state *state; + struct secasvar *sav; +{ + state->foo = NULL; +} + +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 void +ah_keyed_md5_init(state, sav) + struct ah_algorithm_state *state; + struct secasvar *sav; +{ + 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?"); + 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 + 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); + } + } +} + +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; +{ + struct ah_algorithm *algo; + + if (!sav->key_auth) { + printf("esp_keyed_sha1_mature: no key is given.\n"); + return 1; + } + algo = &ah_algorithms[sav->alg_auth]; + if (sav->key_auth->sadb_key_bits < algo->keymin + || algo->keymax < sav->key_auth->sadb_key_bits) { + printf("ah_keyed_sha1_mature: invalid key length %d.\n", + sav->key_auth->sadb_key_bits); + return 1; + } + + return 0; +} + +static void +ah_keyed_sha1_init(state, sav) + struct ah_algorithm_state *state; + struct secasvar *sav; +{ + SHA1_CTX *ctxt; + + 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) + panic("ah_keyed_sha1_init: what?"); + + 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. + */ + 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 + 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); + } + } +} + +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; + + sha1_loop(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; +{ + struct ah_algorithm *algo; + + if (!sav->key_auth) { + printf("esp_hmac_md5_mature: no key is given.\n"); + return 1; + } + algo = &ah_algorithms[sav->alg_auth]; + if (sav->key_auth->sadb_key_bits < algo->keymin + || algo->keymax < sav->key_auth->sadb_key_bits) { + printf("ah_hmac_md5_mature: invalid key length %d.\n", + sav->key_auth->sadb_key_bits); + return 1; + } + + return 0; +} + +static void +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) + panic("ah_hmac_md5_init: what?"); + + 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); +} + +static void +ah_hmac_md5_loop(state, addr, len) + 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); + MD5Update(ctxt, addr, len); +} + +static void +ah_hmac_md5_result(state, addr) + struct ah_algorithm_state *state; + caddr_t addr; +{ + u_char digest[16]; + 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[0], ctxt); + + MD5Init(ctxt); + MD5Update(ctxt, opad, 64); + MD5Update(ctxt, &digest[0], sizeof(digest)); + MD5Final(&digest[0], ctxt); + + bcopy(&digest[0], (void *)addr, HMACSIZE); + + free(state->foo, M_TEMP); +} + +static int +ah_hmac_sha1_mature(sav) + struct secasvar *sav; +{ + struct ah_algorithm *algo; + + if (!sav->key_auth) { + printf("esp_hmac_sha1_mature: no key is given.\n"); + return 1; + } + algo = &ah_algorithms[sav->alg_auth]; + if (sav->key_auth->sadb_key_bits < algo->keymin + || algo->keymax < sav->key_auth->sadb_key_bits) { + printf("ah_hmac_sha1_mature: invalid key length %d.\n", + sav->key_auth->sadb_key_bits); + return 1; + } + + return 0; +} + +static void +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) + panic("ah_hmac_sha1_init: what?"); + + 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); +} + +static void +ah_hmac_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_hmac_sha1_loop: what?"); + + ctxt = (SHA1_CTX *)(((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; +{ + 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((caddr_t)&digest[0], ctxt); + + SHA1Init(ctxt); + SHA1Update(ctxt, opad, 64); + SHA1Update(ctxt, (caddr_t)&digest[0], sizeof(digest)); + SHA1Final((caddr_t)&digest[0], ctxt); + + bcopy(&digest[0], (void *)addr, HMACSIZE); + + free(state->foo, M_TEMP); +} + +/*------------------------------------------------------------*/ + +/* + * go generate the checksum. + */ +int +ah4_calccksum(m0, ahdat, algo, sav) + struct mbuf *m0; + caddr_t ahdat; + struct ah_algorithm *algo; + struct secasvar *sav; +{ + struct mbuf *m; + int hdrtype; + u_char *p; + size_t advancewidth; + struct ah_algorithm_state algos; + int tlen; + u_char sumbuf[AH_MAXSUMSIZE]; + int error = 0; + + hdrtype = -1; /*dummy, it is called IPPROTO_IP*/ + + m = m0; + + p = mtod(m, u_char *); + + (algo->init)(&algos, sav); + + advancewidth = 0; /*safety*/ + +again: + /* gory. */ + switch (hdrtype) { + case -1: /*first one*/ + { + /* + * copy ip hdr, modify to fit the AH checksum rule, + * then take a checksum. + * XXX need to care about source routing... jesus. + */ + struct ip iphdr; + size_t hlen; + + bcopy((caddr_t)p, (caddr_t)&iphdr, sizeof(struct ip)); +#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, (caddr_t)&iphdr, sizeof(struct ip)); + + if (hlen != sizeof(struct ip)) { + u_char *p; + int i, j; + int l, skip; + u_char dummy[4]; + + /* + * IP options processing. + * See RFC2402 appendix A. + */ + bzero(dummy, sizeof(dummy)); + p = mtod(m, u_char *); + i = sizeof(struct ip); + while (i < hlen) { + 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]; + skip = 0; + break; + default: + l = p[i + IPOPT_OLEN]; + skip = 1; + break; + } + if (l <= 0 || hlen - i < l) { + printf("ah4_input: invalid IP option " + "(type=%02x len=%02x)\n", + p[i + IPOPT_OPTVAL], + p[i + IPOPT_OLEN]); + break; + } + if (skip) { + for (j = 0; j < l / sizeof(dummy); j++) + (algo->update)(&algos, dummy, sizeof(dummy)); + + (algo->update)(&algos, dummy, l % sizeof(dummy)); + } else + (algo->update)(&algos, p + i, l); + if (p[i + IPOPT_OPTVAL] == IPOPT_EOL) + break; + i += l; + } + } + + hdrtype = (iphdr.ip_p) & 0xff; + advancewidth = hlen; + break; + } + + case IPPROTO_AH: + { + u_char dummy[4]; + int siz; + int hdrsiz; + + hdrsiz = (sav->flags & SADB_X_EXT_OLD) ? + sizeof(struct ah) : sizeof(struct newah); + + (algo->update)(&algos, p, hdrsiz); + + /* key data region. */ + siz = (*algo->sumsiz)(sav); + bzero(&dummy[0], sizeof(dummy)); + while (sizeof(dummy) <= siz) { + (algo->update)(&algos, dummy, sizeof(dummy)); + siz -= sizeof(dummy); + } + /* can't happen, but just in case */ + if (siz) + (algo->update)(&algos, dummy, siz); + + /* padding region, just in case */ + siz = (((struct ah *)p)->ah_len << 2) - (*algo->sumsiz)(sav); + if ((sav->flags & SADB_X_EXT_OLD) == 0) + siz -= 4; /* sequence number field */ + if (0 < siz) { + /* RFC 1826 */ + (algo->update)(&algos, p + hdrsiz + (*algo->sumsiz)(sav), + siz); + } + + hdrtype = ((struct ah *)p)->ah_nxt; + advancewidth = hdrsiz; + advancewidth += ((struct ah *)p)->ah_len << 2; + if ((sav->flags & SADB_X_EXT_OLD) == 0) + advancewidth -= 4; /* sequence number field */ + break; + } + + default: + printf("ah4_calccksum: unexpected hdrtype=%x; " + "treating rest as payload\n", hdrtype); + /*fall through*/ + case IPPROTO_ICMP: + case IPPROTO_IGMP: + case IPPROTO_IPIP: +#ifdef INET6 + case IPPROTO_IPV6: + case IPPROTO_ICMPV6: +#endif + case IPPROTO_UDP: + case IPPROTO_TCP: + case IPPROTO_ESP: + while (m) { + tlen = m->m_len - (p - mtod(m, u_char *)); + (algo->update)(&algos, p, tlen); + m = m->m_next; + p = m ? mtod(m, u_char *) : NULL; + } + + advancewidth = 0; /*loop finished*/ + break; + } + + if (advancewidth) { + /* is it safe? */ + while (m && advancewidth) { + tlen = m->m_len - (p - mtod(m, u_char *)); + if (advancewidth < tlen) { + p += advancewidth; + advancewidth = 0; + } else { + advancewidth -= tlen; + m = m->m_next; + if (m) + p = mtod(m, u_char *); + else { + printf("ERR: hit the end-of-mbuf...\n"); + p = NULL; + } + } + } + + if (m) + goto again; + } + + /* for HMAC algorithms... */ + (algo->result)(&algos, &sumbuf[0]); + bcopy(&sumbuf[0], ahdat, (*algo->sumsiz)(sav)); + + return error; +} + +#ifdef INET6 +/* + * go generate the checksum. This function won't modify the mbuf chain + * except AH itself. + */ +int +ah6_calccksum(m0, ahdat, algo, sav) + struct mbuf *m0; + caddr_t ahdat; + struct ah_algorithm *algo; + struct secasvar *sav; +{ + struct mbuf *m; + int hdrtype; + u_char *p; + size_t advancewidth; + struct ah_algorithm_state algos; + int tlen; + int error = 0; + u_char sumbuf[AH_MAXSUMSIZE]; + int nest; + + hdrtype = -1; /*dummy, it is called IPPROTO_IPV6 */ + + m = m0; + + p = mtod(m, u_char *); + + (algo->init)(&algos, sav); + + advancewidth = 0; /*safety*/ + nest = 0; + +again: + if (ip6_hdrnestlimit && (++nest > ip6_hdrnestlimit)) { + ip6stat.ip6s_toomanyhdr++; + error = EINVAL; /*XXX*/ + goto bad; + } + + /* gory. */ + switch (hdrtype) { + case -1: /*first one*/ + { + struct ip6_hdr ip6copy; + + bcopy(p, &ip6copy, sizeof(struct ip6_hdr)); + /* RFC2402 */ + ip6copy.ip6_flow = 0; + ip6copy.ip6_vfc = IPV6_VERSION; + ip6copy.ip6_hlim = 0; + if (IN6_IS_ADDR_LINKLOCAL(&ip6copy.ip6_src)) + ip6copy.ip6_src.s6_addr16[1] = 0x0000; + if (IN6_IS_ADDR_LINKLOCAL(&ip6copy.ip6_dst)) + ip6copy.ip6_dst.s6_addr16[1] = 0x0000; + (algo->update)(&algos, (caddr_t)&ip6copy, + sizeof(struct ip6_hdr)); + hdrtype = (((struct ip6_hdr *)p)->ip6_nxt) & 0xff; + advancewidth = sizeof(struct ip6_hdr); + break; + } + + case IPPROTO_AH: + { + u_char dummy[4]; + int siz; + int hdrsiz; + + hdrsiz = (sav->flags & SADB_X_EXT_OLD) ? + sizeof(struct ah) : sizeof(struct newah); + + (algo->update)(&algos, p, hdrsiz); + + /* key data region. */ + siz = (*algo->sumsiz)(sav); + bzero(&dummy[0], 4); + while (4 <= siz) { + (algo->update)(&algos, dummy, 4); + siz -= 4; + } + /* can't happen, but just in case */ + if (siz) + (algo->update)(&algos, dummy, siz); + + /* padding region, just in case */ + siz = (((struct ah *)p)->ah_len << 2) - (*algo->sumsiz)(sav); + if ((sav->flags & SADB_X_EXT_OLD) == 0) + siz -= 4; /* sequence number field */ + if (0 < siz) { + (algo->update)(&algos, p + hdrsiz + (*algo->sumsiz)(sav), + siz); + } + + hdrtype = ((struct ah *)p)->ah_nxt; + advancewidth = hdrsiz; + advancewidth += ((struct ah *)p)->ah_len << 2; + if ((sav->flags & SADB_X_EXT_OLD) == 0) + advancewidth -= 4; /* sequence number field */ + break; + } + + case IPPROTO_HOPOPTS: + case IPPROTO_DSTOPTS: + { + int hdrlen, optlen; + u_int8_t *optp, *lastp = p, *optend, opt; + + tlen = m->m_len - (p - mtod(m, u_char *)); + /* We assume all the options is contained in a single mbuf */ + if (tlen < sizeof(struct ip6_ext)) { + error = EINVAL; + goto bad; + } + hdrlen = (((struct ip6_ext *)p)->ip6e_len + 1) << 3; + hdrtype = (int)((struct ip6_ext *)p)->ip6e_nxt; + if (tlen < hdrlen) { + error = EINVAL; + goto bad; + } + 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. Our approach + * is to calculate ICV for a consecutive immutable options + * at once. Here is an example. In the following figure, + * suppose that we've calculated ICV from the top of the + * header to MutableOpt1, which is a mutable option. + * lastp points to the end of MutableOpt1. Some immutable + * options follows MutableOpt1, and we encounter a new + * mutable option; MutableOpt2. optp points to the head + * of MutableOpt2. In this situation, uncalculated immutable + * field is the field from lastp to optp+2 (note that the + * type and the length fields are considered as immutable + * even in a mutable option). So we first calculate ICV + * for the field as immutable, then calculate from optp+2 + * to the end of MutableOpt2, whose length is optlen-2, + * where optlen is the length of MutableOpt2. Finally, + * lastp is updated to point to the end of MutableOpt2 + * for further calculation. The updated point is shown as + * lastp' in the figure. + * <------ optlen -----> + * -----------+-------------------+---+---+-----------+ + * MutableOpt1|ImmutableOptions...|typ|len|MutableOpt2| + * -----------+-------------------+---+---+-----------+ + * ^ ^ ^ + * lastp optp optp+2 + * <---- optp + 2 - lastp -----><-optlen-2-> + * ^ + * lastp' + */ + for (optp = p + 2; optp < optend; optp += optlen) { + opt = optp[0]; + if (opt == IP6OPT_PAD1) { + optlen = 1; + } else { + if (optp + 2 > optend) { + error = EINVAL; /* malformed option */ + goto bad; + } + optlen = optp[1] + 2; + if (opt & IP6OPT_MUTABLE) { + /* + * ICV calc. for the (consecutive) + * immutable field followd by the + * option. + */ + (algo->update)(&algos, lastp, + optp + 2 - lastp); + if (optlen - 2 > ZEROBUFLEN) { + error = EINVAL; /* XXX */ + goto bad; + } + /* + * ICV calc. for the mutable + * option using an all-0 buffer. + */ + (algo->update)(&algos, zerobuf, + optlen - 2); + lastp = optp + optlen; + } + } + } + /* + * Wrap up the calulation; compute ICV for the consecutive + * immutable options at the end of the header(if any). + */ + (algo->update)(&algos, lastp, p + hdrlen - lastp); + advancewidth = hdrlen; + 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. + * So we'll only check if the header is malformed. + */ + int hdrlen; + + tlen = m->m_len - (p - mtod(m, u_char *)); + /* We assume all the options is contained in a single mbuf */ + if (tlen < sizeof(struct ip6_ext)) { + error = EINVAL; + goto bad; + } + hdrlen = (((struct ip6_ext *)p)->ip6e_len + 1) << 3; + hdrtype = (int)((struct ip6_ext *)p)->ip6e_nxt; + if (tlen < hdrlen) { + error = EINVAL; + goto bad; + } + advancewidth = hdrlen; + (algo->update)(&algos, p, hdrlen); + break; + } + default: + printf("ah6_calccksum: unexpected hdrtype=%x; " + "treating rest as payload\n", hdrtype); + /*fall through*/ + case IPPROTO_ICMP: + case IPPROTO_IGMP: + case IPPROTO_IPIP: /*?*/ + case IPPROTO_IPV6: + case IPPROTO_ICMPV6: + case IPPROTO_UDP: + case IPPROTO_TCP: + case IPPROTO_ESP: + while (m) { + tlen = m->m_len - (p - mtod(m, u_char *)); + (algo->update)(&algos, p, tlen); + m = m->m_next; + p = m ? mtod(m, u_char *) : NULL; + } + + advancewidth = 0; /*loop finished*/ + break; + } + + if (advancewidth) { + /* is it safe? */ + while (m && advancewidth) { + tlen = m->m_len - (p - mtod(m, u_char *)); + if (advancewidth < tlen) { + p += advancewidth; + advancewidth = 0; + } else { + advancewidth -= tlen; + m = m->m_next; + if (m) + p = mtod(m, u_char *); + else { + printf("ERR: hit the end-of-mbuf...\n"); + p = NULL; + } + } + } + + if (m) + goto again; + } + + /* for HMAC algorithms... */ + (algo->result)(&algos, &sumbuf[0]); + bcopy(&sumbuf[0], ahdat, (*algo->sumsiz)(sav)); + + return(0); + + bad: + return(error); +} +#endif diff --git a/sys/netinet6/ah_input.c b/sys/netinet6/ah_input.c new file mode 100644 index 0000000..8f42814 --- /dev/null +++ b/sys/netinet6/ah_input.c @@ -0,0 +1,708 @@ +/* + * 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. + * + * $FreeBSD$ + */ + +/* + * RFC1826/2402 authentication header. + */ + +#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/errno.h> +#include <sys/time.h> +#include <sys/kernel.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 <netinet6/ip6.h> +#include <netinet6/ip6_var.h> +#include <netinet6/icmp6.h> +#endif + +#include <netinet6/ipsec.h> +#include <netinet6/ah.h> +#ifdef INET6 +#include <netinet6/ipsec6.h> +#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 <netinet/ipprotosw.h> + +#include <machine/stdarg.h> + +#include <net/net_osdep.h> + +#ifdef INET +extern struct ipprotosw inetsw[]; + +void +ah4_input(m, off, proto) + struct mbuf *m; + int off, proto; +{ + struct ip *ip; + struct ah *ah; + u_int32_t spi; + struct ah_algorithm *algo; + size_t siz; + size_t siz1; + u_char *cksum; + struct secasvar *sav = NULL; + u_int16_t nxt; + size_t hlen; + int s; + + if (m->m_len < off + sizeof(struct newah)) { + m = m_pullup(m, off + sizeof(struct newah)); + if (!m) { + printf("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); + 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) { + printf("IPv4 AH input: no key association found for spi %u;" + "dropping the packet for simplicity\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) { + printf("IPv4 AH input: non-mature/dying SA found for spi %u; " + "dropping the packet for simplicity\n", + (u_int32_t)ntohl(spi)); + ipsecstat.in_badspi++; + goto fail; + } + if (sav->alg_auth == SADB_AALG_NONE) { + printf("IPv4 AH input: unspecified authentication algorithm " + "for spi %u;" + "dropping the packet for simplicity\n", + (u_int32_t)ntohl(spi)); + ipsecstat.in_badspi++; + goto fail; + } + + algo = &ah_algorithms[sav->alg_auth]; + + 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; + + if ((ah->ah_len << 2) - sizoff != siz1) { + log(LOG_NOTICE, "sum length mismatch in IPv4 AH input " + "(%d should be %u): %s\n", + (ah->ah_len << 2) - sizoff, (unsigned int)siz1, + ipsec4_logpacketstr(ip, spi)); + ipsecstat.in_inval++; + goto fail; + } + + if (m->m_len < off + sizeof(struct ah) + sizoff + siz1) { + m = m_pullup(m, off + sizeof(struct ah) + sizoff + siz1); + if (!m) { + printf("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); + } + } + + /* + * 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++; + log(LOG_AUTH, "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. + */ + cksum = malloc(siz1, M_TEMP, M_NOWAIT); + if (!cksum) { + printf("IPv4 AH input: couldn't alloc temporary region for cksum\n"); + ipsecstat.in_inval++; + goto fail; + } + + { + /* + * 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_id = htons(ip->ip_id); + ip->ip_off = htons(ip->ip_off); + if (ah4_calccksum(m, (caddr_t)cksum, algo, sav)) { + free(cksum, M_TEMP); + ipsecstat.in_inval++; + goto fail; + } + ipsecstat.in_ahhist[sav->alg_auth]++; + /* + * flip them back. + */ + ip->ip_len = ntohs(ip->ip_len) - hlen; + ip->ip_id = ntohs(ip->ip_id); + 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) { + log(LOG_AUTH, "checksum mismatch in IPv4 AH input: %s %s\n", + ipsec4_logpacketstr(ip, spi), + ipsec_logsastr(sav)); + free(cksum, M_TEMP); + ipsecstat.in_ahauthfail++; + goto fail; + } + } + + free(cksum, M_TEMP); + + m->m_flags |= M_AUTHIPHDR; + m->m_flags |= M_AUTHIPDGM; + + /* M_AUTH related flags might be cleared here in the future */ + + if (m->m_flags & M_AUTHIPHDR + && m->m_flags & M_AUTHIPDGM) { + ipsecstat.in_ahauthsucc++; + } else { + log(LOG_AUTH, "authentication failed in IPv4 AH input: %s %s\n", + ipsec4_logpacketstr(ip, spi), + ipsec_logsastr(sav)); + ipsecstat.in_ahauthfail++; + } + + /* + * update sequence number. + */ + if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) { + (void)ipsec_updatereplay(ntohl(((struct newah *)ah)->ah_seq), sav); + } + + /* was it transmitted over the IPsec tunnel SA? */ + if (ipsec4_tunnel_validate(ip, nxt, sav) && nxt == IPPROTO_IPV4) { + /* + * strip off all the headers that precedes AH. + * IP xx AH IP' payload -> IP' payload + * + * XXX more sanity checks + * XXX relationship with gif? + */ + size_t stripsiz = 0; + u_int8_t tos; + + tos = ip->ip_tos; + if (sav->flags & SADB_X_EXT_OLD) { + /* RFC 1826 */ + stripsiz = sizeof(struct ah) + siz1; + } else { + /* RFC 2402 */ + stripsiz = sizeof(struct newah) + siz1; + } + 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. */ + ip_ecn_egress(ip4_ipsec_ecn, &tos, &ip->ip_tos); + if (!key_checktunnelsanity(sav, AF_INET, + (caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst)) { + log(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; + } + + /* + * 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; + + key_sa_recordxfer(sav, m); + + s = splimp(); + if (IF_QFULL(&ipintrq)) { + ipsecstat.in_inval++; + goto fail; + } + IF_ENQUEUE(&ipintrq, m); + m = NULL; + schednetisr(NETISR_IP); /*can be skipped but to make sure*/ + splx(s); + nxt = IPPROTO_DONE; + } else { + /* + * strip off AH. + * We do deep-copy since KAME requires that + * the packet is placed in a single external mbuf. + */ + size_t stripsiz = 0; + + if (sav->flags & SADB_X_EXT_OLD) { + /* RFC 1826 */ + stripsiz = sizeof(struct ah) + siz1; + } else { + /* RFC 2402 */ + stripsiz = sizeof(struct newah) + siz1; + } + + 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 *); + /*ip_len is in host endian*/ + ip->ip_len = ip->ip_len - stripsiz; + ip->ip_p = nxt; + /* forget about IP hdr checksum, the check has already been passed */ + + if (nxt != IPPROTO_DONE) + (*inetsw[ip_protox[nxt]].pr_input)(m, off, nxt); + 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; + struct ah_algorithm *algo; + size_t siz; + size_t siz1; + u_char *cksum; + struct secasvar *sav = NULL; + u_int16_t nxt; + int s; + + IP6_EXTHDR_CHECK(m, off, sizeof(struct ah), IPPROTO_DONE); + + ip6 = mtod(m, struct ip6_hdr *); + ah = (struct ah *)(((caddr_t)ip6) + off); + + nxt = ah->ah_nxt; + + /* find the sassoc. */ + spi = ah->ah_spi; + + if (ntohs(ip6->ip6_plen) == 0) { + printf("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) { + printf("IPv6 AH input: no key association found for spi %u;" + "dropping the packet for simplicity\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) { + printf("IPv6 AH input: non-mature/dying SA found for spi %u; " + "dropping the packet for simplicity\n", + (u_int32_t)ntohl(spi)); + ipsec6stat.in_badspi++; + goto fail; + } + if (sav->alg_auth == SADB_AALG_NONE) { + printf("IPv6 AH input: unspecified authentication algorithm " + "for spi %u;" + "dropping the packet for simplicity\n", + (u_int32_t)ntohl(spi)); + ipsec6stat.in_badspi++; + goto fail; + } + + algo = &ah_algorithms[sav->alg_auth]; + + 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; + + if ((ah->ah_len << 2) - sizoff != siz1) { + log(LOG_NOTICE, "sum length mismatch in IPv6 AH input " + "(%d should be %u): %s\n", + (ah->ah_len << 2) - sizoff, (unsigned int)siz1, + ipsec6_logpacketstr(ip6, spi)); + ipsec6stat.in_inval++; + goto fail; + } + IP6_EXTHDR_CHECK(m, off, sizeof(struct ah) + sizoff + siz1, IPPROTO_DONE); + } + + /* + * 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++; + log(LOG_AUTH, "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. + */ + cksum = malloc(siz1, M_TEMP, M_NOWAIT); + if (!cksum) { + printf("IPv6 AH input: couldn't alloc temporary region for cksum\n"); + ipsec6stat.in_inval++; + goto fail; + } + + if (ah6_calccksum(m, (caddr_t)cksum, algo, sav)) { + free(cksum, M_TEMP); + 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) { + log(LOG_AUTH, "checksum mismatch in IPv6 AH input: %s %s\n", + ipsec6_logpacketstr(ip6, spi), + ipsec_logsastr(sav)); + free(cksum, M_TEMP); + ipsec6stat.in_ahauthfail++; + goto fail; + } + } + + free(cksum, M_TEMP); + + m->m_flags |= M_AUTHIPHDR; + m->m_flags |= M_AUTHIPDGM; + + /* M_AUTH related flags might be cleared here in the future */ + + if (m->m_flags & M_AUTHIPHDR + && m->m_flags & M_AUTHIPDGM) { + ipsec6stat.in_ahauthsucc++; + } else { + log(LOG_AUTH, "authentication failed in IPv6 AH input: %s %s\n", + ipsec6_logpacketstr(ip6, spi), + ipsec_logsastr(sav)); + ipsec6stat.in_ahauthfail++; + } + + /* + * update sequence number. + */ + if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) { + (void)ipsec_updatereplay(ntohl(((struct newah *)ah)->ah_seq), sav); + } + + /* was it transmitted over the IPsec tunnel SA? */ + if (ipsec6_tunnel_validate(ip6, nxt, sav) && nxt == IPPROTO_IPV6) { + /* + * strip off all the headers that precedes AH. + * IP6 xx AH IP6' payload -> IP6' payload + * + * XXX more sanity checks + * XXX relationship with gif? + */ + size_t stripsiz = 0; + u_int32_t flowinfo; /*net endian*/ + + flowinfo = ip6->ip6_flow; + if (sav->flags & SADB_X_EXT_OLD) { + /* RFC 1826 */ + stripsiz = sizeof(struct ah) + siz1; + } else { + /* RFC 2402 */ + stripsiz = sizeof(struct newah) + siz1; + } + m_adj(m, off + stripsiz); + if (m->m_len < sizeof(*ip6)) { + /* + * m_pullup is prohibited in KAME IPv6 input processing + * but there's no other way! + */ + m = m_pullup(m, sizeof(*ip6)); + if (!m) { + ipsec6stat.in_inval++; + goto fail; + } + } + ip6 = mtod(m, struct ip6_hdr *); + /* ECN consideration. */ + ip6_ecn_egress(ip6_ipsec_ecn, &flowinfo, &ip6->ip6_flow); + if (!key_checktunnelsanity(sav, AF_INET6, + (caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst)) { + log(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; + } + + /* + * should the inner packet be considered authentic? + * see comment in ah4_input(). + */ + m->m_flags &= ~M_AUTHIPHDR; + m->m_flags &= ~M_AUTHIPDGM; + + key_sa_recordxfer(sav, m); + + s = splimp(); + if (IF_QFULL(&ip6intrq)) { + ipsec6stat.in_inval++; + goto fail; + } + IF_ENQUEUE(&ip6intrq, m); + m = NULL; + schednetisr(NETISR_IPV6); /*can be skipped but to make sure*/ + splx(s); + nxt = IPPROTO_DONE; + } else { + /* + * strip off AH. + * We do deep-copy since KAME requires that + * the packet is placed in a single mbuf. + */ + size_t stripsiz = 0; + char *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; + + if (sav->flags & SADB_X_EXT_OLD) { + /* RFC 1826 */ + stripsiz = sizeof(struct ah) + siz1; + } else { + /* RFC 2402 */ + stripsiz = sizeof(struct newah) + siz1; + } + + ip6 = mtod(m, struct ip6_hdr *); + ovbcopy((caddr_t)ip6, (caddr_t)(((u_char *)ip6) + stripsiz), + off); + m->m_data += stripsiz; + m->m_len -= stripsiz; + m->m_pkthdr.len -= stripsiz; + + ip6 = mtod(m, struct ip6_hdr *); + ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - stripsiz); + + key_sa_recordxfer(sav, m); + } + + *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; +} +#endif /* INET6 */ diff --git a/sys/netinet6/ah_output.c b/sys/netinet6/ah_output.c new file mode 100644 index 0000000..0cb3279 --- /dev/null +++ b/sys/netinet6/ah_output.c @@ -0,0 +1,532 @@ +/* + * 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. + * + * $FreeBSD$ + */ + +/* + * RFC1826/2402 authentication header. + */ + +#include "opt_inet6.h" +#include "opt_ipsec.h" + +#define ahdprintf(x) printf x + +#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/kernel.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> +#include <netinet/in_pcb.h> + +#ifdef INET6 +#include <netinet6/ip6.h> +#include <netinet6/ip6_var.h> +#include <netinet6/icmp6.h> +#endif + +#include <netinet6/ipsec.h> +#include <netinet6/ah.h> +#ifdef INET6 +#include <netinet6/ipsec6.h> +#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 <net/net_osdep.h> + +static struct in_addr *ah4_finaldst __P((struct mbuf *)); + +/* + * 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; +{ + struct ah_algorithm *algo; + size_t hdrsiz; + + /* sanity check */ + if (isr == NULL) + panic("ah_hdrsiz: NULL was passed.\n"); + + if (isr->saidx.proto != IPPROTO_AH) + panic("unsupported mode passed to ah_hdrsiz"); + + if (isr->sav == NULL) + goto contrive; + if (isr->sav->state != SADB_SASTATE_MATURE + && isr->sav->state != SADB_SASTATE_DYING) + goto contrive; + + /* we need transport mode AH. */ + algo = &ah_algorithms[isr->sav->alg_auth]; + if (!algo) + goto contrive; + + /* + * 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; + + contrive: + /* ASSUMING: + * sizeof(struct newah) > sizeof(struct ah). + * 16 = (16 + 3) & ~(4 - 1). + */ + return sizeof(struct newah) + 16; +} + +/* + * 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; + struct ah_algorithm *algo; + u_int32_t spi; + u_char *ahdrpos; + u_char *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; + struct in_addr dst; + 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 *); + printf("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_algorithms[sav->alg_auth]; + 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) { + printf("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; + 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); + } + + /* + * 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 { + printf("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) { + dst.s_addr = 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, (caddr_t)ahsumpos, algo, sav); + if (error) { + printf("error after ah4_calccksum, called from ah4_output"); + m = NULL; + ipsecstat.out_inval++; + return error; + } + + if (finaldst) { + ip = mtod(m, struct ip *); /*just to make sure*/ + ip->ip_dst.s_addr = dst.s_addr; + } + ipsecstat.out_success++; + ipsecstat.out_ahhist[sav->alg_auth]++; + key_sa_recordxfer(sav, m); + + return 0; +} + +/* Calculate AH length */ +int +ah_hdrlen(sav) + struct secasvar *sav; +{ + struct ah_algorithm *algo; + int plen, ahlen; + + algo = &ah_algorithms[sav->alg_auth]; + 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; + struct ah_algorithm *algo; + u_int32_t spi; + u_char *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)) { + printf("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) { + printf("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) { + printf("ip6_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) { + printf("ah6_output: internal error: " + "sav->replay is null: SPI=%u\n", + (u_int32_t)ntohl(sav->spi)); + ipsec6stat.out_inval++; + return 0; /* no change at all */ + } + + algo = &ah_algorithms[sav->alg_auth]; + 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; + 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, (caddr_t)ahsumpos, algo, sav); + if (error) + ipsec6stat.out_inval++; + else + ipsec6stat.out_success++; + ipsec6stat.out_ahhist[sav->alg_auth]++; + key_sa_recordxfer(sav, m); + + return(error); +} +#endif + +/* + * 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) { + printf("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) { + printf("ah4_finaldst: wrong optlen %d\n", optlen); + return NULL; + } + + q = (u_char *)(ip + 1); + i = 0; + while (i < optlen) { + 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] <= 0 + || optlen - i < q[i + IPOPT_OLEN]) { + printf("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] <= 0 + || optlen - i < q[i + IPOPT_OLEN]) { + printf("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; +} diff --git a/sys/netinet6/esp.h b/sys/netinet6/esp.h new file mode 100644 index 0000000..595aff1 --- /dev/null +++ b/sys/netinet6/esp.h @@ -0,0 +1,99 @@ +/* + * 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. + * + * $FreeBSD$ + */ + +/* + * RFC1827/2406 Encapsulated Security Payload. + */ + +#ifndef _NETINET6_ESP_H_ +#define _NETINET6_ESP_H_ + +struct secasvar; + +struct esp { + u_int32_t esp_spi; /* ESP */ + /*variable size, 32bit bound*/ /* Initialization Vector */ + /*variable size*/ /* Payload data */ + /*variable size*/ /* padding */ + /*8bit*/ /* pad size */ + /*8bit*/ /* next header */ + /*8bit*/ /* next header */ + /*variable size, 32bit bound*/ /* Authentication data (new IPsec) */ +}; + +struct newesp { + u_int32_t esp_spi; /* ESP */ + u_int32_t esp_seq; /* Sequence number */ + /*variable size*/ /* (IV and) Payload data */ + /*variable size*/ /* padding */ + /*8bit*/ /* pad size */ + /*8bit*/ /* next header */ + /*8bit*/ /* next header */ + /*variable size, 32bit bound*/ /* Authentication data */ +}; + +struct esptail { + u_int8_t esp_padlen; /* pad length */ + u_int8_t esp_nxt; /* Next header */ + /*variable size, 32bit bound*/ /* Authentication data (new IPsec)*/ +}; + +struct esp_algorithm_state { + struct secasvar *sav; + void* foo; /*per algorithm data - maybe*/ +}; + +/* XXX yet to be defined */ +struct esp_algorithm { + size_t padbound; /* pad boundary, in byte */ + int (*mature) __P((struct secasvar *)); + int keymin; /* in bits */ + int keymax; /* in bits */ + int (*ivlen) __P((struct secasvar *)); + int (*decrypt) __P((struct mbuf *, size_t, + struct secasvar *, struct esp_algorithm *, int)); + int (*encrypt) __P((struct mbuf *, size_t, size_t, + struct secasvar *, struct esp_algorithm *, int)); +}; + +#ifdef KERNEL +extern struct esp_algorithm esp_algorithms[]; + +/* crypt routines */ +extern int esp4_output __P((struct mbuf *, struct ipsecrequest *)); +extern void esp4_input __P((struct mbuf *, int, int)); +extern size_t esp_hdrsiz __P((struct ipsecrequest *)); +#endif /*KERNEL*/ + +extern int esp_auth __P((struct mbuf *, size_t, size_t, + struct secasvar *, u_char *)); + +#endif /*_NETINET6_ESP_H_*/ diff --git a/sys/netinet6/esp6.h b/sys/netinet6/esp6.h new file mode 100644 index 0000000..e206376 --- /dev/null +++ b/sys/netinet6/esp6.h @@ -0,0 +1,45 @@ +/* + * 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. + * + * $FreeBSD$ + */ + +/* + * RFC1827/2406 Encapsulated Security Payload. + */ + +#ifndef _NETINET6_ESP6_H_ +#define _NETINET6_ESP6_H_ + +#ifdef KERNEL +extern int esp6_output __P((struct mbuf *, u_char *, struct mbuf *, + struct ipsecrequest *)); +extern int esp6_input __P((struct mbuf **, int *, int)); +#endif /*KERNEL*/ + +#endif /*_NETINET6_ESP6_H_*/ diff --git a/sys/netinet6/esp_core.c b/sys/netinet6/esp_core.c new file mode 100644 index 0000000..8eb007e --- /dev/null +++ b/sys/netinet6/esp_core.c @@ -0,0 +1,1236 @@ +/* + * 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. + * + * $FreeBSD$ + */ + +#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/errno.h> +#include <sys/time.h> +#include <sys/kernel.h> + +#include <net/if.h> +#include <net/route.h> + +#include <netinet/in.h> +#include <netinet/in_var.h> +#ifdef INET6 +#include <netinet6/ip6.h> +#include <netinet6/ip6_var.h> +#include <netinet6/icmp6.h> +#endif + +#include <netinet6/ipsec.h> +#include <netinet6/ah.h> +#ifdef INET6 +#include <netinet6/ipsec6.h> +#include <netinet6/ah6.h> +#endif +#ifdef IPSEC_ESP +#include <netinet6/esp.h> +#ifdef INET6 +#include <netinet6/esp6.h> +#endif +#endif +#include <net/pfkeyv2.h> +#include <netkey/key_var.h> +#include <netkey/keydb.h> +#include <crypto/des/des.h> +#include <crypto/blowfish/blowfish.h> +#include <crypto/cast128/cast128.h> +#include <crypto/rc5/rc5.h> + +#include <net/net_osdep.h> + +static int esp_null_mature __P((struct secasvar *)); +static int esp_null_ivlen __P((struct secasvar *)); +static int esp_null_decrypt __P((struct mbuf *, size_t, + struct secasvar *, struct esp_algorithm *, int)); +static int esp_null_encrypt __P((struct mbuf *, size_t, size_t, + struct secasvar *, struct esp_algorithm *, int)); +static int esp_descbc_mature __P((struct secasvar *)); +static int esp_descbc_ivlen __P((struct secasvar *)); +static int esp_descbc_decrypt __P((struct mbuf *, size_t, + struct secasvar *, struct esp_algorithm *, int)); +static int esp_descbc_encrypt __P((struct mbuf *, size_t, size_t, + struct secasvar *, struct esp_algorithm *, int)); +static int esp_cbc_mature __P((struct secasvar *)); +static int esp_blowfish_cbc_decrypt __P((struct mbuf *, size_t, + struct secasvar *, struct esp_algorithm *, int)); +static int esp_blowfish_cbc_encrypt __P((struct mbuf *, size_t, + size_t, struct secasvar *, struct esp_algorithm *, int)); +static int esp_blowfish_cbc_ivlen __P((struct secasvar *)); +static int esp_cast128cbc_ivlen __P((struct secasvar *)); +static int esp_cast128cbc_decrypt __P((struct mbuf *, size_t, + struct secasvar *, struct esp_algorithm *, int)); +static int esp_cast128cbc_encrypt __P((struct mbuf *, size_t, size_t, + struct secasvar *, struct esp_algorithm *, int)); +static int esp_3descbc_ivlen __P((struct secasvar *)); +static int esp_3descbc_decrypt __P((struct mbuf *, size_t, + struct secasvar *, struct esp_algorithm *, int)); +static int esp_3descbc_encrypt __P((struct mbuf *, size_t, size_t, + struct secasvar *, struct esp_algorithm *, int)); +static int esp_rc5cbc_ivlen __P((struct secasvar *)); +static int esp_rc5cbc_decrypt __P((struct mbuf *, size_t, + struct secasvar *, struct esp_algorithm *, int)); +static int esp_rc5cbc_encrypt __P((struct mbuf *, size_t, size_t, + struct secasvar *, struct esp_algorithm *, int)); +static void esp_increment_iv __P((struct secasvar *)); +static caddr_t mbuf_find_offset __P((struct mbuf *, size_t, size_t)); + +/* NOTE: The order depends on SADB_EALG_x in netkey/keyv2.h */ +struct esp_algorithm esp_algorithms[] = { + { 0, 0, 0, 0, 0, 0, 0, }, + { 8, esp_descbc_mature, 64, 64, + esp_descbc_ivlen, esp_descbc_decrypt, esp_descbc_encrypt, }, + { 8, esp_cbc_mature, 192, 192, + esp_3descbc_ivlen, esp_3descbc_decrypt, esp_3descbc_encrypt, }, + { 1, esp_null_mature, 0, 2048, + esp_null_ivlen, esp_null_decrypt, esp_null_encrypt, }, + { 8, esp_cbc_mature, 40, 448, + esp_blowfish_cbc_ivlen, esp_blowfish_cbc_decrypt, + esp_blowfish_cbc_encrypt, }, + { 8, esp_cbc_mature, 40, 128, + esp_cast128cbc_ivlen, esp_cast128cbc_decrypt, + esp_cast128cbc_encrypt, }, + { 8, esp_cbc_mature, 40, 2040, + esp_rc5cbc_ivlen, esp_rc5cbc_decrypt, esp_rc5cbc_encrypt, }, +}; + +/* + * mbuf assumption: foo_encrypt() assumes that IV part is placed in a single + * mbuf, not across multiple mbufs. + */ + +static int +esp_null_mature(sav) + struct secasvar *sav; +{ + /* anything is okay */ + return 0; +} + +static int +esp_null_ivlen(sav) + struct secasvar *sav; +{ + 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; + 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; + struct esp_algorithm *algo; + int ivlen; +{ + return 0; /* do nothing */ +} + +static int +esp_descbc_mature(sav) + struct secasvar *sav; +{ + struct esp_algorithm *algo; + + if (!(sav->flags & SADB_X_EXT_OLD) && (sav->flags & SADB_X_EXT_IV4B)) { + printf("esp_cbc_mature: algorithm incompatible with 4 octets IV length\n"); + return 1; + } + + if (!sav->key_enc) { + printf("esp_descbc_mature: no key is given.\n"); + return 1; + } + algo = &esp_algorithms[sav->alg_enc]; + if (_KEYBITS(sav->key_enc) < algo->keymin + || algo->keymax < _KEYBITS(sav->key_enc)) { + printf("esp_descbc_mature: invalid key length %d.\n", + _KEYBITS(sav->key_enc)); + return 1; + } + + /* weak key check */ + if (des_is_weak_key((C_Block *)_KEYBUF(sav->key_enc))) { + printf("esp_descbc_mature: weak key was passed.\n"); + return 1; + } + + return 0; +} + +static int +esp_descbc_ivlen(sav) + struct secasvar *sav; +{ + if (sav && (sav->flags & SADB_X_EXT_OLD) && (sav->flags & SADB_X_EXT_IV4B)) + return 4; + + if (sav && !(sav->flags & SADB_X_EXT_OLD) && (sav->flags & SADB_X_EXT_DERIV)) + return 4; + else + return 8; +} + +static int +esp_descbc_decrypt(m, off, sav, algo, ivlen) + struct mbuf *m; + size_t off; /* offset to ESP header */ + struct secasvar *sav; + struct esp_algorithm *algo; + int ivlen; +{ + size_t ivoff = 0; + size_t bodyoff = 0; + u_int8_t *iv; + size_t plen; + u_int8_t tiv[8]; + int derived; + + derived = 0; + /* sanity check */ + if (ivlen != sav->ivlen) { + printf("esp_descbc_decrypt: bad ivlen %d/%d\n", + ivlen, sav->ivlen); + return EINVAL; + } + if (_KEYBITS(sav->key_enc) < algo->keymin + || algo->keymax < _KEYBITS(sav->key_enc)) { + printf("esp_descbc_decrypt: bad keylen %d\n", + _KEYBITS(sav->key_enc)); + return EINVAL; + } + + 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. + * This draft has been deleted, but you can get from + * ftp://ftp.kame.net/pub/internet-drafts/. + */ + 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; + } + } + if (ivlen == 4) { + iv = &tiv[0]; + m_copydata(m, ivoff, 4, &tiv[0]); + m_copydata(m, ivoff, 4, &tiv[4]); + tiv[4] ^= 0xff; + tiv[5] ^= 0xff; + tiv[6] ^= 0xff; + tiv[7] ^= 0xff; + } else if (ivlen == 8) { + iv = &tiv[0]; + m_copydata(m, ivoff, 8, &tiv[0]); + } else { + printf("esp_descbc_decrypt: unsupported ivlen %d\n", ivlen); + return EINVAL; + } + + plen = m->m_pkthdr.len; + if (plen < bodyoff) + panic("esp_descbc_decrypt: too short packet: len=%lu", + (u_long)plen); + plen -= bodyoff; + + if (plen % 8) { + printf("esp_descbc_decrypt: " + "payload length must be multiple of 8\n"); + return EINVAL; + } + + { + int deserr; + des_key_schedule ks; + + deserr = des_key_sched((C_Block *)_KEYBUF(sav->key_enc), ks); + if (deserr != 0) { + printf("esp_descbc_decrypt: key error %d\n", deserr); + return EINVAL; + } + + des_cbc_encrypt(m, bodyoff, plen, ks, (C_Block *)iv, DES_DECRYPT); + + /* for safety */ + bzero(&ks, sizeof(des_key_schedule)); + } + + /* for safety */ + bzero(&tiv[0], sizeof(tiv)); + + return 0; +} + +static int +esp_descbc_encrypt(m, off, plen, sav, algo, ivlen) + struct mbuf *m; + size_t off; /* offset to ESP header */ + size_t plen; /* payload length (to be decrypted) */ + struct secasvar *sav; + struct esp_algorithm *algo; + int ivlen; +{ + size_t ivoff = 0; + size_t bodyoff = 0; + u_int8_t *iv; + u_int8_t tiv[8]; + int derived; + + derived = 0; + + /* sanity check */ + if (plen % 8) { + printf("esp_descbc_encrypt: " + "payload length must be multiple of 8\n"); + return EINVAL; + } + if (sav->ivlen != ivlen) { + printf("esp_descbc_encrypt: bad ivlen %d/%d\n", + ivlen, sav->ivlen); + return EINVAL; + } + if (_KEYBITS(sav->key_enc) < algo->keymin + || algo->keymax < _KEYBITS(sav->key_enc)) { + printf("esp_descbc_encrypt: bad keylen %d\n", + _KEYBITS(sav->key_enc)); + return EINVAL; + } + + if (sav->flags & SADB_X_EXT_OLD) { + /* RFC 1827 */ + /* + * draft-ietf-ipsec-ciph-des-derived-00.txt + * uses sequence number field as IV field. + * This draft has been deleted, see above. + */ + 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. + * This draft has been deleted, see above. + */ + 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; + } + } + + if (m->m_pkthdr.len < bodyoff) + panic("assumption failed: mbuf too short"); + iv = mbuf_find_offset(m, ivoff, ivlen); + if (!iv) + panic("assumption failed: bad mbuf chain"); + if (ivlen == 4) { + if (!derived) { + bcopy(sav->iv, &tiv[0], 4); + bcopy(sav->iv, &tiv[4], 4); + tiv[4] ^= 0xff; + tiv[5] ^= 0xff; + tiv[6] ^= 0xff; + tiv[7] ^= 0xff; + bcopy(&tiv[0], iv, 4); + iv = &tiv[0]; + } else { + bcopy(iv, &tiv[0], 4); + bcopy(iv, &tiv[4], 4); + tiv[4] ^= 0xff; + tiv[5] ^= 0xff; + tiv[6] ^= 0xff; + tiv[7] ^= 0xff; + iv = &tiv[0]; + } + } else if (ivlen == 8) + bcopy((caddr_t)sav->iv, (caddr_t)iv, ivlen); + else { + printf("esp_descbc_encrypt: unsupported ivlen %d\n", ivlen); + return EINVAL; + } + + { + int deserr; + des_key_schedule ks; + + deserr = des_key_sched((C_Block *)_KEYBUF(sav->key_enc), ks); + if (deserr != 0) { + printf("esp_descbc_encrypt: key error %d\n", deserr); + return EINVAL; + } + + des_cbc_encrypt(m, bodyoff, plen, ks, (C_Block *)iv, DES_ENCRYPT); + + /* for safety */ + bzero(&ks, sizeof(des_key_schedule)); + } + + esp_increment_iv(sav); + + /* for safety */ + bzero(&tiv[0], sizeof(tiv)); + + return 0; +} + +static int +esp_cbc_mature(sav) + struct secasvar *sav; +{ + int keylen; + struct esp_algorithm *algo; + + if (sav->flags & SADB_X_EXT_OLD) { + printf("esp_cbc_mature: algorithm incompatible with esp-old\n"); + return 1; + } + if (sav->flags & SADB_X_EXT_DERIV) { + printf("esp_cbc_mature: algorithm incompatible with derived\n"); + return 1; + } + + if (!sav->key_enc) { + printf("esp_cbc_mature: no key is given.\n"); + return 1; + } + algo = &esp_algorithms[sav->alg_enc]; + keylen = sav->key_enc->sadb_key_bits; + if (keylen < algo->keymin || algo->keymax < keylen) { + printf("esp_cbc_mature: invalid key length %d.\n", + sav->key_enc->sadb_key_bits); + return 1; + } + switch (sav->alg_enc) { + case SADB_EALG_3DESCBC: + /* weak key check */ + if (des_is_weak_key((C_Block *)_KEYBUF(sav->key_enc)) + || des_is_weak_key((C_Block *)(_KEYBUF(sav->key_enc) + 8)) + || des_is_weak_key((C_Block *)(_KEYBUF(sav->key_enc) + 16))) { + printf("esp_cbc_mature: weak key was passed.\n"); + return 1; + } + break; + case SADB_EALG_BLOWFISHCBC: + case SADB_EALG_CAST128CBC: + case SADB_EALG_RC5CBC: + break; + } + + return 0; +} + +static int +esp_blowfish_cbc_decrypt(m, off, sav, algo, ivlen) + struct mbuf *m; + size_t off; /* offset to ESP header */ + struct secasvar *sav; + struct esp_algorithm *algo; + int ivlen; +{ + size_t ivoff; + size_t bodyoff; + u_int8_t *iv; + u_int8_t tiv[8]; + size_t plen; + static BF_KEY key; /* made static to avoid kernel stack overflow */ + int s; + + /* sanity check */ + if (sav->ivlen != ivlen) { + printf("esp_blowfish_cbc_decrypt: bad ivlen %d/%d\n", + ivlen, sav->ivlen); + return EINVAL; + } + if (_KEYBITS(sav->key_enc) < algo->keymin + || algo->keymax < _KEYBITS(sav->key_enc)) { + printf("esp_blowfish_cbc_decrypt: unsupported key length %d: " + "need %d to %d bits\n", _KEYBITS(sav->key_enc), + algo->keymin, algo->keymax); + return EINVAL; + } + if (sav->flags & SADB_X_EXT_OLD) { + printf("esp_blowfish_cbc_decrypt: unsupported ESP version\n"); + return EINVAL; + } + if (ivlen != 8) { + printf("esp_blowfish_cbc_decrypt: unsupported ivlen %d " + "(this should never happen)\n", ivlen); + return EINVAL; + } + + ivoff = off + sizeof(struct newesp); + bodyoff = off + sizeof(struct newesp) + ivlen; + iv = &tiv[0]; + m_copydata(m, ivoff, 8, &tiv[0]); + + plen = m->m_pkthdr.len; + if (plen < bodyoff) + panic("esp_blowfish_cbc_decrypt: too short packet: len=%lu", + (u_long)plen); + plen -= bodyoff; + + if (plen % 8) { + printf("esp_blowfish_cbc_decrypt: " + "payload length must be multiple of 8\n"); + return EINVAL; + } + + s = splnet(); /* XXX correct? */ + + BF_set_key(&key, _KEYBITS(sav->key_enc) / 8, _KEYBUF(sav->key_enc)); + BF_cbc_encrypt_m(m, bodyoff, plen, &key, iv, BF_DECRYPT); + + /* for safety */ + bzero(&key, sizeof(BF_KEY)); + + splx(s); + + /* for safety */ + bzero(&tiv[0], sizeof(tiv)); + + return 0; +} + +static int +esp_blowfish_cbc_encrypt(m, off, plen, sav, algo, ivlen) + struct mbuf *m; + size_t off; /* offset to ESP header */ + size_t plen; /* payload length (to be decrypted) */ + struct secasvar *sav; + struct esp_algorithm *algo; + int ivlen; +{ + size_t ivoff; + size_t bodyoff; + u_int8_t *iv; + static BF_KEY key; /* made static to avoid kernel stack overflow */ + int s; + + /* sanity check */ + if (plen % 8) { + printf("esp_blowfish_cbc_encrypt: " + "payload length must be multiple of 8\n"); + return EINVAL; + } + if (sav->ivlen != ivlen) { + printf("esp_blowfish_cbc_encrypt: bad ivlen %d/%d\n", + ivlen, sav->ivlen); + return EINVAL; + } + if (_KEYBITS(sav->key_enc) < algo->keymin + || algo->keymax < _KEYBITS(sav->key_enc)) { + printf("esp_blowfish_cbc_encrypt: unsupported key length %d: " + "need %d to %d bits\n", _KEYBITS(sav->key_enc), + algo->keymin, algo->keymax); + return EINVAL; + } + if (sav->flags & SADB_X_EXT_OLD) { + printf("esp_blowfish_cbc_encrypt: unsupported ESP version\n"); + return EINVAL; + } + if (ivlen != 8) { + printf("esp_blowfish_cbc_encrypt: unsupported ivlen %d " + "(this should never happen)\n", ivlen); + return EINVAL; + } + + ivoff = off + sizeof(struct newesp); + bodyoff = off + sizeof(struct newesp) + ivlen; + + if (m->m_pkthdr.len < bodyoff) + panic("assumption failed: mbuf too short"); + iv = mbuf_find_offset(m, ivoff, ivlen); + if (!iv) + panic("assumption failed: bad mbuf chain"); + + bcopy((caddr_t)sav->iv, (caddr_t)iv, ivlen); + + s = splnet(); /* XXX correct? */ + + BF_set_key(&key, _KEYBITS(sav->key_enc) / 8, _KEYBUF(sav->key_enc)); + BF_cbc_encrypt_m(m, bodyoff, plen, &key, iv, BF_ENCRYPT); + + /* for safety */ + bzero(&key, sizeof(BF_KEY)); + + splx(s); + + esp_increment_iv(sav); + + return 0; +} + +static int +esp_blowfish_cbc_ivlen(sav) + struct secasvar *sav; +{ + return 8; +} + +static int +esp_cast128cbc_ivlen(sav) + struct secasvar *sav; +{ + return 8; +} + +static int +esp_cast128cbc_decrypt(m, off, sav, algo, ivlen) + struct mbuf *m; + size_t off; + struct secasvar *sav; + struct esp_algorithm *algo; + int ivlen; +{ + size_t ivoff; + size_t bodyoff; + u_int8_t iv[8]; + size_t plen; + + /* sanity check */ + if (ivlen != sav->ivlen) { + printf("esp_cast128cbc_decrypt: bad ivlen %d/%d\n", + ivlen, sav->ivlen); + return EINVAL; + } + if (_KEYBITS(sav->key_enc) < algo->keymin + || _KEYBITS(sav->key_enc) > algo->keymax) { + printf("esp_cast128cbc_decrypt: unsupported key length %d: " + "need %d to %d bits\n", _KEYBITS(sav->key_enc), + algo->keymin, algo->keymax); + return EINVAL; + } + if (sav->flags & SADB_X_EXT_OLD) { + printf("esp_cast128cbc_decrypt: unsupported ESP version\n"); + return EINVAL; + } + if (ivlen != 8) { + printf("esp_cast128cbc_decrypt: unsupported ivlen %d " + "(this should never happen)\n", ivlen); + return EINVAL; + } + + ivoff = off + sizeof(struct newesp); + bodyoff = off + sizeof(struct newesp) + ivlen; + + /* copy mbuf's IV into iv */ + m_copydata(m, ivoff, 8, iv); + + plen = m->m_pkthdr.len; + if (plen < bodyoff) { + panic("esp_cast128cbc_decrypt: too short packet: len=%lu\n", + (u_long)plen); + } + plen -= bodyoff; + + if (plen % 8) { + printf("esp_cast128cbc_decrypt: " + "payload length must be multiple of 8\n"); + return EINVAL; + } + + /* decrypt */ + { + u_int8_t key[16]; + u_int32_t subkey[32]; + + bzero(key, sizeof(key)); + bcopy(_KEYBUF(sav->key_enc), key, _KEYLEN(sav->key_enc)); + + set_cast128_subkey(subkey, key); + cast128_cbc_process(m, bodyoff, plen, subkey, iv, + _KEYBITS(sav->key_enc) / 8, CAST128_DECRYPT); + + /* for safety */ + bzero(subkey, sizeof(subkey)); + bzero(key, sizeof(key)); + } + + return 0; +} + +static int +esp_cast128cbc_encrypt(m, off, plen, sav, algo, ivlen) + struct mbuf *m; + size_t off; + size_t plen; + struct secasvar *sav; + struct esp_algorithm *algo; + int ivlen; +{ + size_t ivoff; + size_t bodyoff; + u_int8_t *iv; + + /* sanity check */ + if (plen % 8) { + printf("esp_cast128cbc_encrypt: " + "payload length must be multiple of 8\n"); + return EINVAL; + } + if (sav->ivlen != ivlen) { + printf("esp_cast128cbc_encrypt: bad ivlen %d/%d\n", + ivlen, sav->ivlen); + return EINVAL; + } + if (_KEYBITS(sav->key_enc) < algo->keymin + || _KEYBITS(sav->key_enc) > algo->keymax) { + printf("esp_cast128cbc_encrypt: unsupported key length %d: " + "needs %d to %d bits\n", _KEYBITS(sav->key_enc), + algo->keymin, algo->keymax); + return EINVAL; + } + if (sav->flags & SADB_X_EXT_OLD) { + printf("esp_cast128cbc_encrypt: unsupported ESP version\n"); + return EINVAL; + } + if (ivlen != 8) { + printf("esp_cast128cbc_encrypt: unsupported ivlen %d " + "(this should never happen)\n", ivlen); + return EINVAL; + } + + ivoff = off + sizeof(struct newesp); + bodyoff = off + sizeof(struct newesp) + ivlen; + + if (m->m_pkthdr.len < bodyoff) + panic("assumption failed: mbuf too short"); + iv = mbuf_find_offset(m, ivoff, ivlen); + if (!iv) + panic("assumption failed: bad mbuf chain"); + + bcopy(sav->iv, iv, ivlen); + + /* encrypt */ + { + u_int8_t key[16]; + u_int32_t subkey[32]; + + bzero(key, sizeof(key)); + bcopy(_KEYBUF(sav->key_enc), key, _KEYLEN(sav->key_enc)); + + set_cast128_subkey(subkey, key); + cast128_cbc_process(m, bodyoff, plen, subkey, iv, + _KEYBITS(sav->key_enc) / 8, CAST128_ENCRYPT); + + /* for safety */ + bzero(subkey, sizeof(subkey)); + bzero(key, sizeof(key)); + } + + esp_increment_iv(sav); + + return 0; +} + +static int +esp_3descbc_ivlen(sav) + struct secasvar *sav; +{ + return 8; +} + +static int +esp_3descbc_decrypt(m, off, sav, algo, ivlen) + struct mbuf *m; + size_t off; + struct secasvar *sav; + struct esp_algorithm *algo; + int ivlen; +{ + size_t ivoff; + size_t bodyoff; + u_int8_t *iv; + size_t plen; + u_int8_t tiv[8]; + + /* sanity check */ + if (ivlen != sav->ivlen) { + printf("esp_3descbc_decrypt: bad ivlen %d/%d\n", + ivlen, sav->ivlen); + return EINVAL; + } + if (_KEYBITS(sav->key_enc) < algo->keymin + || algo->keymax < _KEYBITS(sav->key_enc)) { + printf("esp_3descbc_decrypt: bad keylen %d\n", + _KEYBITS(sav->key_enc)); + return EINVAL; + } + if (sav->flags & SADB_X_EXT_OLD) { + printf("esp_3descbc_decrypt: unsupported ESP version\n"); + return EINVAL; + } + if (ivlen != 8) { + printf("esp_3descbc_decrypt: unsupported ivlen %d " + "(this should never happen)\n", ivlen); + return EINVAL; + } + + ivoff = off + sizeof(struct newesp); + bodyoff = off + sizeof(struct newesp) + ivlen; + iv = &tiv[0]; + m_copydata(m, ivoff, 8, &tiv[0]); + + plen = m->m_pkthdr.len; + if (plen < bodyoff) + panic("esp_3descbc_decrypt: too short packet: len=%lu", + (u_long)plen); + + plen -= bodyoff; + + if (plen % 8) { + printf("esp_3descbc_decrypt: " + "payload length must be multiple of 8\n"); + return EINVAL; + } + + /* decrypt packet */ + { + int deserr[3]; + des_key_schedule ks[3]; + + deserr[0] = des_key_sched((C_Block *)_KEYBUF(sav->key_enc),ks[0]); + deserr[1] = des_key_sched((C_Block *)(_KEYBUF(sav->key_enc) + 8), ks[1]); + deserr[2] = des_key_sched((C_Block *)(_KEYBUF(sav->key_enc) + 16), ks[2]); + if ((deserr[0] != 0) || (deserr[1] != 0) || (deserr[2] != 0)) { + printf("esp_3descbc_decrypt: key error %d/%d/%d\n", + deserr[0], deserr[1], deserr[2]); + return EINVAL; + } + + des_3cbc_process(m, bodyoff, plen, ks, (C_Block *)iv, DES_DECRYPT); + + /* for safety */ + bzero(ks[0], sizeof(des_key_schedule)*3); + } + + /* for safety */ + bzero(&tiv[0], sizeof(tiv)); + + return 0; +} + +static int +esp_3descbc_encrypt(m, off, plen, sav, algo, ivlen) + struct mbuf *m; + size_t off; + size_t plen; + struct secasvar *sav; + struct esp_algorithm *algo; + int ivlen; +{ + size_t ivoff; + size_t bodyoff; + u_int8_t *iv; + + /* sanity check */ + if (plen % 8) { + printf("esp_3descbc_encrypt: " + "payload length must be multiple of 8\n"); + return EINVAL; + } + if (sav->ivlen != ivlen) { + printf("esp_3descbc_encrypt: bad ivlen %d/%d\n", + ivlen, sav->ivlen); + return EINVAL; + } + if (_KEYBITS(sav->key_enc) < algo->keymin + || algo->keymax < _KEYBITS(sav->key_enc)) { + printf("esp_3descbc_encrypt: bad keylen %d\n", + _KEYBITS(sav->key_enc)); + return EINVAL; + } + if (sav->flags & SADB_X_EXT_OLD) { + printf("esp_3descbc_encrypt: unsupported ESP version\n"); + return EINVAL; + } + if (ivlen != 8) { + printf("esp_3descbc_encrypt: unsupported ivlen %d " + "(this should never happen)\n", ivlen); + return EINVAL; + } + + ivoff = off + sizeof(struct newesp); + bodyoff = off + sizeof(struct newesp) + ivlen; + + if (m->m_pkthdr.len < bodyoff) + panic("assumption failed: mbuf too short"); + iv = mbuf_find_offset(m, ivoff, ivlen); + if (!iv) + panic("assumption failed: bad mbuf chain"); + + bcopy((caddr_t)sav->iv, (caddr_t)iv, ivlen); + + /* encrypt packet */ + { + int deserr[3]; + des_key_schedule ks[3]; + + deserr[0] = des_key_sched((C_Block *)_KEYBUF(sav->key_enc), ks[0]); + deserr[1] = des_key_sched((C_Block *)(_KEYBUF(sav->key_enc) + 8), ks[1]); + deserr[2] = des_key_sched((C_Block *)(_KEYBUF(sav->key_enc) + 16), ks[2]); + if ((deserr[0] != 0) || (deserr[1] != 0) || (deserr[2] != 0)) { + printf("esp_3descbc_encrypt: key error %d/%d/%d\n", + deserr[0], deserr[1], deserr[2]); + return EINVAL; + } + + des_3cbc_process(m, bodyoff, plen, ks, (C_Block *)iv, DES_ENCRYPT); + + /* for safety */ + bzero(ks[0], sizeof(des_key_schedule)*3); + } + + esp_increment_iv(sav); + + return 0; +} + +static int +esp_rc5cbc_ivlen(sav) + struct secasvar *sav; +{ + return 8; +} + +static int +esp_rc5cbc_decrypt(m, off, sav, algo, ivlen) + struct mbuf *m; + size_t off; + struct secasvar *sav; + struct esp_algorithm *algo; + int ivlen; +{ + size_t ivoff; + size_t bodyoff; + u_int8_t iv[8]; + size_t plen; + + /* sanity check */ + if (sav->ivlen != ivlen) { + printf("esp_rc5cbc_decrypt: bad ivlen %d/%d\n", + ivlen, sav->ivlen); + return EINVAL; + } + if ((_KEYBITS(sav->key_enc) < 40) || (_KEYBITS(sav->key_enc) > 2040)) { + printf("esp_rc5cbc_decrypt: unsupported key length %d: " + "need 40 to 2040 bit\n", _KEYBITS(sav->key_enc)); + return EINVAL; + } + if (sav->flags & SADB_X_EXT_OLD) { + printf("esp_rc5cbc_decrypt: unsupported ESP version\n"); + return EINVAL; + } + if (ivlen != 8) { + printf("esp_rc5cbc_decrypt: unsupported ivlen %d " + "(this should never happen)\n", ivlen); + return EINVAL; + } + + ivoff = off + sizeof(struct newesp); + bodyoff = off + sizeof(struct newesp) + ivlen; + + /* copy mbuf's IV into iv */ + m_copydata(m, ivoff, 8, iv); + + plen = m->m_pkthdr.len; + if (plen < bodyoff) { + panic("esp_rc5cbc_decrypt: too short packet: len=%lu", + (u_long)plen); + } + plen -= bodyoff; + + if (plen % 8) { + printf("esp_rc5cbc_decrypt: " + "payload length must be multiple of 8\n"); + return EINVAL; + } + + /* decrypt */ + { + RC5_WORD e_key[34]; + + set_rc5_expandkey(e_key, _KEYBUF(sav->key_enc), + _KEYBITS(sav->key_enc) / 8, 16); + rc5_cbc_process(m, bodyoff, plen, e_key, iv, RC5_DECRYPT); + + /* for safety */ + bzero(e_key, sizeof(e_key)); + } + + return 0; +} + +static int +esp_rc5cbc_encrypt(m, off, plen, sav, algo, ivlen) + struct mbuf *m; + size_t off; + size_t plen; + struct secasvar *sav; + struct esp_algorithm *algo; + int ivlen; +{ + size_t ivoff; + size_t bodyoff; + u_int8_t *iv; + + /* sanity check */ + if (plen % 8) { + printf("esp_rc5cbc_encrypt: " + "payload length must be multiple of 8\n"); + return EINVAL; + } + if (sav->ivlen != ivlen) { + printf("esp_rc5cbc_encrypt: bad ivlen %d/%d\n", + ivlen, sav->ivlen); + return EINVAL; + } + if (_KEYBITS(sav->key_enc) < algo->keymin + || _KEYBITS(sav->key_enc) > algo->keymax) { + printf("esp_rc5cbc_encrypt: unsupported key length %d: " + "need %d to %d bits\n", _KEYBITS(sav->key_enc), + algo->keymin, algo->keymax); + return EINVAL; + } + if (sav->flags & SADB_X_EXT_OLD) { + printf("esp_rc5cbc_encrypt: unsupported ESP version\n"); + return EINVAL; + } + if (ivlen != 8) { + printf("esp_rc5cbc_encrypt: unsupported ivlen %d " + "(this should never happen)\n", ivlen); + return EINVAL; + } + + ivoff = off + sizeof(struct newesp); + bodyoff = off + sizeof(struct newesp) + ivlen; + + if (m->m_pkthdr.len < bodyoff) + panic("assumption failed: mbuf too short"); + iv = mbuf_find_offset(m, ivoff, ivlen); + if (!iv) + panic("assumption failed: bad mbuf chain"); + + bcopy(sav->iv, iv, ivlen); + + /* encrypt */ + { + RC5_WORD e_key[34]; + + set_rc5_expandkey(e_key, _KEYBUF(sav->key_enc), + _KEYBITS(sav->key_enc) / 8, 16); + rc5_cbc_process(m, bodyoff, plen, e_key, iv, RC5_ENCRYPT); + + /* for safety */ + bzero(e_key, sizeof(e_key)); + } + + esp_increment_iv(sav); + + return 0; +} + +/* + * increment iv. + */ +static void +esp_increment_iv(sav) + struct secasvar *sav; +{ + u_int8_t *x; + u_int8_t y; + int i; + + y = time_second & 0xff; + + if (!y) y++; + x = (u_int8_t *)sav->iv; + for (i = 0; i < sav->ivlen; i++) { + *x = (*x + y) & 0xff; + x++; + } +} + +static caddr_t +mbuf_find_offset(m, off, len) + struct mbuf *m; + size_t off; + size_t len; +{ + struct mbuf *n; + size_t cnt; + + if (m->m_pkthdr.len < off || m->m_pkthdr.len < off + len) + return (caddr_t)NULL; + cnt = 0; + for (n = m; n; n = n->m_next) { + if (cnt + n->m_len <= off) { + cnt += n->m_len; + continue; + } + if (cnt <= off && off < cnt + n->m_len + && cnt <= off + len && off + len <= cnt + n->m_len) { + return mtod(n, caddr_t) + off - cnt; + } else + return (caddr_t)NULL; + } + return (caddr_t)NULL; +} + +/*------------------------------------------------------------*/ + +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]; + struct ah_algorithm *algo; + size_t siz; + + /* sanity checks */ + if (m0->m_pkthdr.len < skip) { + printf("esp_auth: mbuf length < skip\n"); + return EINVAL; + } + if (m0->m_pkthdr.len < skip + length) { + printf("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) { + printf("esp_auth: length is not multiple of 4\n"); + return EINVAL; + } + if (!sav) { + printf("esp_auth: NULL SA passed\n"); + return EINVAL; + } + if (!sav->alg_auth) { + printf("esp_auth: bad ESP auth algorithm passed: %d\n", sav->alg_auth); + return EINVAL; + } + + m = m0; + off = 0; + + algo = &ah_algorithms[sav->alg_auth]; + siz = (((*algo->sumsiz)(sav) + 3) & ~(4 - 1)); + if (sizeof(sumbuf) < siz) { + printf("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; + } + } + + (*algo->init)(&s, sav); + 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); + bcopy(sumbuf, sum, siz); /*XXX*/ + + return 0; +} diff --git a/sys/netinet6/esp_input.c b/sys/netinet6/esp_input.c new file mode 100644 index 0000000..d09ba27 --- /dev/null +++ b/sys/netinet6/esp_input.c @@ -0,0 +1,984 @@ +/* + * 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. + * + * $FreeBSD$ + */ + +/* + * RFC1827/2406 Encapsulated Security Payload. + */ + +#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/errno.h> +#include <sys/time.h> +#include <sys/kernel.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 <netinet6/ip6.h> +#include <netinet6/ip6_var.h> +#include <netinet6/icmp6.h> +#endif + +#include <netinet6/ipsec.h> +#include <netinet6/ah.h> +#ifdef INET6 +#include <netinet6/ipsec6.h> +#include <netinet6/ah6.h> +#endif +#ifdef IPSEC_ESP +#include <netinet6/esp.h> +#ifdef INET6 +#include <netinet6/esp6.h> +#endif +#endif +#include <netkey/key.h> +#include <netkey/keydb.h> +#ifdef IPSEC_DEBUG +#include <netkey/key_debug.h> +#else +#define KEYDEBUG(lev,arg) +#endif + +#include <netinet/ipprotosw.h> + +#include <machine/stdarg.h> + +#include <net/net_osdep.h> + +#ifdef INET +extern struct ipprotosw inetsw[]; + +void +esp4_input(m, off, proto) + struct mbuf *m; + int off, proto; + +{ + struct ip *ip; + struct esp *esp; + struct esptail *esptail; + u_int32_t spi; + struct secasvar *sav = NULL; + size_t taillen; + u_int16_t nxt; + struct esp_algorithm *algo; + int ivlen; + size_t hlen; + size_t esplen; + int s; + + /* sanity check for alignment. */ + if (off % 4 != 0 || m->m_pkthdr.len % 4 != 0) { + printf("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 + sizeof(struct esp)) { + m = m_pullup(m, off + sizeof(struct esp)); + if (!m) { + printf("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) { + printf("IPv4 ESP input: no key association found for spi %u;" + "dropping the packet for simplicity\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) { + printf("IPv4 ESP input: non-mature/dying SA found for spi %u; " + "dropping the packet for simplicity\n", + (u_int32_t)ntohl(spi)); + ipsecstat.in_badspi++; + goto bad; + } + if (sav->alg_enc == SADB_EALG_NONE) { + printf("IPv4 ESP input: unspecified encryption algorithm " + "for spi %u;" + "dropping the packet for simplicity\n", + (u_int32_t)ntohl(spi)); + ipsecstat.in_badspi++; + goto bad; + } + + algo = &esp_algorithms[sav->alg_enc]; /*XXX*/ + + /* check if we have proper ivlen information */ + ivlen = sav->ivlen; + if (ivlen < 0) { + log(LOG_NOTICE, "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_AALG_NULL) + goto noreplaycheck; + + /* + * check for sequence number. + */ + if (ipsec_chkreplay(ntohl(((struct newesp *)esp)->esp_seq), sav)) + ; /*okey*/ + else { + ipsecstat.in_espreplay++; + log(LOG_AUTH, "replay packet in IPv4 ESP input: %s %s\n", + ipsec4_logpacketstr(ip, spi), + ipsec_logsastr(sav)); + goto bad; + } + + /* check ICV */ + { + struct mbuf *n; + int len; + u_char sum0[AH_MAXSUMSIZE]; + u_char sum[AH_MAXSUMSIZE]; + struct ah_algorithm *sumalgo; + size_t siz; + + sumalgo = &ah_algorithms[sav->alg_auth]; + siz = (((*sumalgo->sumsiz)(sav) + 3) & ~(4 - 1)); + if (AH_MAXSUMSIZE < siz) { + printf("internal error: AH_MAXSUMSIZE must be larger than %lu\n", + (u_long)siz); + ipsecstat.in_inval++; + goto bad; + } + + n = m; + len = m->m_pkthdr.len; + len -= siz; + while (n && 0 < len) { + if (len < n->m_len) + break; + len -= n->m_len; + n = n->m_next; + } + if (!n) { + printf("mbuf chain problem?\n"); + ipsecstat.in_inval++; + goto bad; + } + m_copydata(n, len, siz, &sum0[0]); + + if (esp_auth(m, off, m->m_pkthdr.len - off - siz, sav, sum)) { + log(LOG_AUTH, "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) { + log(LOG_AUTH, "auth fail in IPv4 ESP input: %s %s\n", + ipsec4_logpacketstr(ip, spi), + ipsec_logsastr(sav)); + ipsecstat.in_espauthfail++; + goto bad; + } + + /* strip off */ + m->m_pkthdr.len -= siz; + n->m_len -= siz; + ip = mtod(m, struct ip *); + ip->ip_len = ip->ip_len - siz; + m->m_flags |= M_AUTHIPDGM; + ipsecstat.in_espauthsucc++; + } + + /* + * update sequence number. + */ + if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) { + (void)ipsec_updatereplay(ntohl(((struct newesp *)esp)->esp_seq), sav); + } + +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_len < off + esplen + ivlen) { + m = m_pullup(m, off + esplen + ivlen); + if (!m) { + printf("IPv4 ESP input: can't pullup in esp4_input\n"); + 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)) { + log(LOG_AUTH, "decrypt fail in IPv4 ESP input: %s %s\n", + ipsec4_logpacketstr(ip, spi), + ipsec_logsastr(sav)); + ipsecstat.in_inval++; + goto bad; + } + ipsecstat.in_esphist[sav->alg_enc]++; + + m->m_flags |= M_DECRYPTED; + } + +#ifdef garbled_data_found_on_mbuf_after_packet + { + /* + * For simplicity, we'll trim the packet so that there's no extra + * part appended after IP packet. + * This is rare case for some odd drivers, so there should be no + * performance hit. + */ + + /* + * Note that, in ip_input, ip_len was already flipped and header + * length was subtracted from ip_len. + */ + if (m->m_pkthdr.len != hlen + ip->ip_len) + { + size_t siz; + struct mbuf *n; + + siz = hlen + ip->ip_len; + + /* find the final mbuf */ + for (n = m; n; n = n->m_next) { + if (n->m_len < siz) + siz -= n->m_len; + else + break; + } + if (!n) { + printf("invalid packet\n"); + ipsecstat.in_inval++; + goto bad; + } + + /* trim the final mbuf */ + if (n->m_len < siz) { + printf("invalid size: %d %d\n", n->m_len, siz); + ipsecstat.in_inval++; + goto bad; + } + n->m_len = siz; + + /* dispose the rest of the packet */ + m_freem(n->m_next); + n->m_next = NULL; + + m->m_pkthdr.len = hlen + ip->ip_len; + } + } +#endif + + { + /* + * find the trailer of the ESP. + */ + struct mbuf *n; /*the last mbuf on the mbuf chain, m_len > 0 */ + struct mbuf *o; /*the last mbuf on the mbuf chain */ + + o = m; + n = NULL; + while (o) { + if (0 < o->m_len) + n = o; + o = o->m_next; + } + if (!n || n->m_len < sizeof(struct esptail)) { + printf("IPv4 ESP input: assertion on pad part failed; " + "dropping the packet\n"); + ipsecstat.in_inval++; + goto bad; + } + + esptail = (struct esptail *) + (mtod(n, u_int8_t *) + n->m_len - sizeof(struct esptail)); + nxt = esptail->esp_nxt; + taillen = esptail->esp_padlen + 2; + + if (m->m_pkthdr.len < taillen + || m->m_pkthdr.len - taillen < hlen) { /*?*/ + log(LOG_NOTICE, "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. + */ + if (taillen < n->m_len) { + /* trailing pad data is included in the last mbuf item. */ + n->m_len -= taillen; + m->m_pkthdr.len -= taillen; + } else { + /* trailing pad data spans on multiple mbuf item. */ + size_t siz; + + siz = m->m_pkthdr.len; + if (siz < taillen) { + log(LOG_NOTICE, "bad packet length in IPv4 ESP input: %s %s\n", + ipsec4_logpacketstr(ip, spi), + ipsec_logsastr(sav)); + ipsecstat.in_inval++; + goto bad; + } + siz -= taillen; + + /* find the final mbuf */ + for (n = m; n; n = n->m_next) { + if (n->m_len < siz) + siz -= n->m_len; + else + break; + } + if (!n) { + printf("invalid packet\n"); + ipsecstat.in_inval++; + goto bad; + } + + /* trim the final mbuf */ + if (n->m_len < siz) { + printf("invalid size: %d %lu\n", n->m_len, (u_long)siz); + ipsecstat.in_inval++; + goto bad; + } + n->m_len = siz; + + /* dispose the rest of the packet */ + m_freem(n->m_next); + n->m_next = NULL; + + m->m_pkthdr.len -= taillen; + } + + ip->ip_len = ip->ip_len - taillen; + } + + /* was it transmitted over the IPsec tunnel SA? */ + if (ipsec4_tunnel_validate(ip, nxt, sav) && nxt == IPPROTO_IPV4) { + /* + * strip off all the headers that precedes ESP header. + * IP4 xx ESP IP4' payload -> IP4' payload + * + * XXX more sanity checks + * XXX relationship with gif? + */ + struct ip oip; /* for debug */ + u_int8_t tos; + + tos = ip->ip_tos; + bcopy(mtod(m, struct ip *), &oip, sizeof(oip)); /* for debug */ + 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. */ + ip_ecn_egress(ip4_ipsec_ecn, &tos, &ip->ip_tos); + if (!key_checktunnelsanity(sav, AF_INET, + (caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst)) { + log(LOG_NOTICE, "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); + + s = splimp(); + if (IF_QFULL(&ipintrq)) { + ipsecstat.in_inval++; + goto bad; + } + IF_ENQUEUE(&ipintrq, m); + m = NULL; + schednetisr(NETISR_IP); /*can be skipped but to make sure*/ + splx(s); + nxt = IPPROTO_DONE; + } else { + /* + * strip off ESP header and IV. + * We do deep-copy since KAME requires packet to be placed + * in a single mbuf. + */ + 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 *); + ip->ip_len = ip->ip_len - stripsiz; + ip->ip_p = nxt; + + key_sa_recordxfer(sav, m); + + if (nxt != IPPROTO_DONE) + (*inetsw[ip_protox[nxt]].pr_input)(m, off, nxt); + 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; + struct esp_algorithm *algo; + int ivlen; + size_t esplen; + int s; + + /* sanity check for alignment. */ + if (off % 4 != 0 || m->m_pkthdr.len % 4 != 0) { + printf("IPv6 ESP input: packet alignment problem " + "(off=%d, pktlen=%d)\n", off, m->m_pkthdr.len); + ipsec6stat.in_inval++; + goto bad; + } + + IP6_EXTHDR_CHECK(m, off, sizeof(struct esp), IPPROTO_DONE); + + ip6 = mtod(m, struct ip6_hdr *); + esp = (struct esp *)(((u_int8_t *)ip6) + off); + + if (ntohs(ip6->ip6_plen) == 0) { + printf("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) { + printf("IPv6 ESP input: no key association found for spi %u;" + "dropping the packet for simplicity\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) { + printf("IPv6 ESP input: non-mature/dying SA found for spi %u; " + "dropping the packet for simplicity\n", + (u_int32_t)ntohl(spi)); + ipsec6stat.in_badspi++; + goto bad; + } + if (sav->alg_enc == SADB_EALG_NONE) { + printf("IPv6 ESP input: unspecified encryption algorithm " + "for spi %u;" + "dropping the packet for simplicity\n", + (u_int32_t)ntohl(spi)); + ipsec6stat.in_badspi++; + goto bad; + } + + algo = &esp_algorithms[sav->alg_enc]; /*XXX*/ + + /* check if we have proper ivlen information */ + ivlen = sav->ivlen; + if (ivlen < 0) { + log(LOG_NOTICE, "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_AALG_NULL) + goto noreplaycheck; + + /* + * check for sequence number. + */ + if (ipsec_chkreplay(ntohl(((struct newesp *)esp)->esp_seq), sav)) + ; /*okey*/ + else { + ipsec6stat.in_espreplay++; + log(LOG_AUTH, "replay packet in IPv6 ESP input: %s %s\n", + ipsec6_logpacketstr(ip6, spi), + ipsec_logsastr(sav)); + goto bad; + } + + /* check ICV */ + { + struct mbuf *n; + size_t len; + u_char sum0[AH_MAXSUMSIZE]; + u_char sum[AH_MAXSUMSIZE]; + struct ah_algorithm *sumalgo; + size_t siz; + + sumalgo = &ah_algorithms[sav->alg_auth]; + siz = (((*sumalgo->sumsiz)(sav) + 3) & ~(4 - 1)); + if (AH_MAXSUMSIZE < siz) { + printf("internal error: AH_MAXSUMSIZE must be larger than %lu\n", + (u_long)siz); + ipsec6stat.in_inval++; + goto bad; + } + + n = m; + len = m->m_pkthdr.len; + len -= siz; /*XXX*/ + while (n && 0 < len) { + if (len < n->m_len) + break; + len -= n->m_len; + n = n->m_next; + } + if (!n) { + printf("mbuf chain problem?\n"); + ipsec6stat.in_inval++; + goto bad; + } + m_copydata(n, len, siz, &sum0[0]); + + if (esp_auth(m, off, m->m_pkthdr.len - off - siz, sav, sum)) { + log(LOG_AUTH, "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) { + log(LOG_AUTH, "auth fail in IPv6 ESP input: %s %s\n", + ipsec6_logpacketstr(ip6, spi), + ipsec_logsastr(sav)); + ipsec6stat.in_espauthfail++; + goto bad; + } + + /* strip off */ + m->m_pkthdr.len -= siz; + n->m_len -= 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) { + (void)ipsec_updatereplay(ntohl(((struct newesp *)esp)->esp_seq), sav); + } + +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); + } + + IP6_EXTHDR_CHECK(m, off, esplen + ivlen, IPPROTO_DONE); /*XXX*/ + + /* + * decrypt the packet. + */ + if (!algo->decrypt) + panic("internal error: no decrypt function"); + if ((*algo->decrypt)(m, off, sav, algo, ivlen)) { + log(LOG_AUTH, "decrypt fail in IPv6 ESP input: %s %s\n", + ipsec6_logpacketstr(ip6, spi), + ipsec_logsastr(sav)); + ipsec6stat.in_inval++; + goto bad; + } + ipsec6stat.in_esphist[sav->alg_enc]++; + + m->m_flags |= M_DECRYPTED; + +#ifdef garbled_data_found_on_mbuf_after_packet + { + /* + * For simplicity, we'll trim the packet so that there's no extra + * part appended after IP packet. + * This is rare case for some odd drivers, so there should be no + * performance hit. + */ + + /* + * Note that, in ip_input, ip_len was already flipped and header + * length was subtracted from ip_len. + */ + if (m->m_pkthdr.len != hlen + ip->ip_len) + { + size_t siz; + struct mbuf *n; + + siz = hlen + ip->ip_len; + + /* find the final mbuf */ + for (n = m; n; n = n->m_next) { + if (n->m_len < siz) + siz -= n->m_len; + else + break; + } + if (!n) { + printf("invalid packet\n"); + ipsec6stat.in_inval++; + goto bad; + } + + /* trim the final mbuf */ + if (n->m_len < siz) { + printf("invalid size: %d %d\n", n->m_len, siz); + ipsec6stat.in_inval++; + goto bad; + } + n->m_len = siz; + + /* dispose the rest of the packet */ + m_freem(n->m_next); + n->m_next = NULL; + + m->m_pkthdr.len = hlen + ip->ip_len; + } + } +#endif + + { + /* + * find the trailer of the ESP. + */ + struct mbuf *n; /*the last mbuf on the mbuf chain, m_len > 0 */ + struct mbuf *o; /*the last mbuf on the mbuf chain */ + + o = m; + n = NULL; + while (o) { + if (0 < o->m_len) + n = o; + o = o->m_next; + } + if (!n || n->m_len < sizeof(struct esptail)) { + printf("IPv6 ESP input: assertion on pad part failed; " + "dropping the packet\n"); + ipsec6stat.in_inval++; + goto bad; + } + + esptail = (struct esptail *) + (mtod(n, u_int8_t *) + n->m_len - sizeof(struct esptail)); + nxt = esptail->esp_nxt; + taillen = esptail->esp_padlen + 2; + + if (m->m_pkthdr.len < taillen + || m->m_pkthdr.len - taillen < sizeof(struct ip6_hdr)) { /*?*/ + log(LOG_NOTICE, "bad pad length in IPv6 ESP input: %s %s\n", + ipsec6_logpacketstr(ip6, spi), + ipsec_logsastr(sav)); + ipsec6stat.in_inval++; + goto bad; + } + + /* + * XXX strip off the padding. + */ + if (taillen < n->m_len) { + /* trailing pad data is included in the last mbuf item. */ + n->m_len -= taillen; + m->m_pkthdr.len -= taillen; + } else { + /* trailing pad data spans on multiple mbuf item. */ + size_t siz; + + siz = m->m_pkthdr.len; + if (siz < taillen) { + log(LOG_NOTICE, "bad packet length in IPv6 ESP input: %s %s\n", + ipsec6_logpacketstr(ip6, spi), + ipsec_logsastr(sav)); + ipsec6stat.in_inval++; + goto bad; + } + siz -= taillen; + + /* find the final mbuf */ + for (n = m; n; n = n->m_next) { + if (n->m_len < siz) + siz -= n->m_len; + else + break; + } + if (!n) { + printf("invalid packet\n"); + ipsec6stat.in_inval++; + goto bad; + } + + /* trim the final mbuf */ + if (n->m_len < siz) { + printf("invalid size: %d %lu\n", n->m_len, (u_long)siz); + ipsec6stat.in_inval++; + goto bad; + } + n->m_len = siz; + + /* dispose the rest of the packet */ + m_freem(n->m_next); + n->m_next = NULL; + + m->m_pkthdr.len -= taillen; + } + + ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - taillen); + } + + /* was it transmitted over the IPsec tunnel SA? */ + if (ipsec6_tunnel_validate(ip6, nxt, sav) && nxt == IPPROTO_IPV6) { + /* + * 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_pullup is prohibited in KAME IPv6 input processing + * but there's no other way! + */ + m = m_pullup(m, sizeof(*ip6)); + if (!m) { + ipsec6stat.in_inval++; + goto bad; + } + } + ip6 = mtod(m, struct ip6_hdr *); + /* ECN consideration. */ + ip6_ecn_egress(ip6_ipsec_ecn, &flowinfo, &ip6->ip6_flow); + if (!key_checktunnelsanity(sav, AF_INET6, + (caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst)) { + log(LOG_NOTICE, "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); + + s = splimp(); + if (IF_QFULL(&ip6intrq)) { + ipsec6stat.in_inval++; + goto bad; + } + IF_ENQUEUE(&ip6intrq, m); + m = NULL; + schednetisr(NETISR_IPV6); /*can be skipped but to make sure*/ + splx(s); + nxt = IPPROTO_DONE; + } else { + /* + * strip off ESP header and IV. + * We do deep-copy since KAME requires packet to be placed + * in a single mbuf. + */ + size_t stripsiz; + char *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 *); + ovbcopy((caddr_t)ip6, (caddr_t)(((u_char *)ip6) + stripsiz), + off); + m->m_data += stripsiz; + m->m_len -= stripsiz; + m->m_pkthdr.len -= stripsiz; + + ip6 = mtod(m, struct ip6_hdr *); + ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - stripsiz); + + key_sa_recordxfer(sav, m); + } + + *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; +} +#endif /* INET6 */ diff --git a/sys/netinet6/esp_output.c b/sys/netinet6/esp_output.c new file mode 100644 index 0000000..2386bfd --- /dev/null +++ b/sys/netinet6/esp_output.c @@ -0,0 +1,683 @@ +/* + * 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. + * + * $FreeBSD$ + */ + +#include "opt_inet.h" +#include "opt_inet6.h" +#include "opt_ipsec.h" + +/* + * RFC1827/2406 Encapsulated Security Payload. + */ + +#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/kernel.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> +#include <netinet/in_pcb.h> + +#ifdef INET6 +#include <netinet6/ip6.h> +#include <netinet6/ip6_var.h> +#include <netinet6/icmp6.h> +#endif + +#include <netinet6/ipsec.h> +#include <netinet6/ah.h> +#ifdef INET6 +#include <netinet6/ipsec6.h> +#include <netinet6/ah6.h> +#endif +#ifdef IPSEC_ESP +#include <netinet6/esp.h> +#ifdef INET6 +#include <netinet6/esp6.h> +#endif +#endif +#include <netkey/key.h> +#include <netkey/keydb.h> +#ifdef IPSEC_DEBUG +#include <netkey/key_debug.h> +#else +#define KEYDEBUG(lev,arg) +#endif + +#include <net/net_osdep.h> + +static int esp_output __P((struct mbuf *, u_char *, struct mbuf *, + struct ipsecrequest *, int)); + +/* + * compute ESP header size. + */ +size_t +esp_hdrsiz(isr) + struct ipsecrequest *isr; +{ + struct secasvar *sav; + struct esp_algorithm *algo; + size_t ivlen; + size_t authlen; + size_t hdrsiz; + + /* sanity check */ + if (isr == NULL) + panic("esp_hdrsiz: NULL was passed.\n"); + + sav = isr->sav; + + if (isr->saidx.proto != IPPROTO_ESP) + panic("unsupported mode passed to esp_hdrsiz"); + + if (sav == NULL) + goto contrive; + if (sav->state != SADB_SASTATE_MATURE + && sav->state != SADB_SASTATE_DYING) + goto contrive; + + /* we need transport mode ESP. */ + algo = &esp_algorithms[sav->alg_enc]; + if (!algo) + goto contrive; + ivlen = sav->ivlen; + if (ivlen < 0) + goto contrive; + + /* + * XXX + * right now we don't calcurate the padding size. simply + * treat the padding size as constant, for simplicity. + * + * XXX variable size padding support + */ + if (sav->flags & SADB_X_EXT_OLD) { + /* RFC 1827 */ + hdrsiz = sizeof(struct esp) + ivlen + 9; + } else { + /* RFC 2406 */ + if (sav->replay && sav->alg_auth && sav->key_auth) + authlen = (*ah_algorithms[sav->alg_auth].sumsiz)(sav); + else + authlen = 0; + hdrsiz = sizeof(struct newesp) + ivlen + 9 + authlen; + } + + return hdrsiz; + + contrive: + /* + * ASSUMING: + * sizeof(struct newesp) > sizeof(struct esp). + * 8 = ivlen for CBC mode (RFC2451). + * 9 = (maximum padding length without random Padding length) + * + (Pad Length field) + (Next Header field). + * 16 = maximum ICV we supported. + */ + return sizeof(struct newesp) + 8 + 9 + 16; +} + +/* + * Modify the packet so that the payload is encrypted. + * The mbuf (m) must start with IPv4 or IPv6 header. + * On failure, free the given mbuf and return NULL. + * + * on invocation: + * m nexthdrp md + * v v v + * IP ......... payload + * during the encryption: + * m nexthdrp mprev md + * v v v v + * IP ............... esp iv payload pad padlen nxthdr + * <--><-><------><---------------> + * esplen plen extendsiz + * ivlen + * <-----> esphlen + * <-> hlen + * <-----------------> espoff + */ +static int +esp_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 *mprev; + struct esp *esp; + struct esptail *esptail; + struct secasvar *sav = isr->sav; + struct esp_algorithm *algo; + u_int32_t spi; + u_int8_t nxt = 0; + size_t plen; /*payload length to be encrypted*/ + size_t espoff; + int ivlen; + int afnumber; + size_t extendsiz; + int error = 0; + + switch (af) { +#ifdef INET + case AF_INET: + afnumber = 4; + break; +#endif +#ifdef INET6 + case AF_INET6: + afnumber = 6; + break; +#endif + default: + printf("esp_output: unsupported af %d\n", af); + return 0; /* no change at all */ + } + + /* some sanity check */ + if ((sav->flags & SADB_X_EXT_OLD) == 0 && !sav->replay) { + switch (af) { +#ifdef INET + case AF_INET: + { + struct ip *ip; + + ip = mtod(m, struct ip *); + printf("esp4_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; + } +#endif /*INET*/ +#ifdef INET6 + case AF_INET6: + { + struct ip6_hdr *ip6; + + ip6 = mtod(m, struct ip6_hdr *); + printf("esp6_output: internal error: " + "sav->replay is null: SPI=%u\n", + (u_int32_t)ntohl(sav->spi)); + ipsec6stat.out_inval++; + m_freem(m); + return EINVAL; + } +#endif /*INET6*/ + } + } + + algo = &esp_algorithms[sav->alg_enc]; /*XXX*/ + spi = sav->spi; + ivlen = sav->ivlen; + /* should be okey */ + if (ivlen < 0) { + panic("invalid ivlen"); + } + + { + /* + * insert ESP header. + * XXX inserts ESP header right after IPv4 header. should + * chase the header chain. + * XXX sequential number + */ +#ifdef INET + struct ip *ip = NULL; +#endif +#ifdef INET6 + struct ip6_hdr *ip6 = NULL; +#endif + size_t esplen; /*sizeof(struct esp/newesp)*/ + size_t esphlen; /*sizeof(struct esp/newesp) + ivlen*/ + size_t hlen = 0; /*ip header len*/ + + 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); + } + esphlen = esplen + ivlen; + + for (mprev = m; mprev && mprev->m_next != md; mprev = mprev->m_next) + ; + if (mprev == NULL || mprev->m_next != md) { + printf("esp%d_output: md is not in chain\n", afnumber); + m_freem(m); + return EINVAL; + } + + plen = 0; + for (n = md; n; n = n->m_next) + plen += n->m_len; + + 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 + } + + /* make the packet over-writable */ + mprev->m_next = NULL; + if ((md = ipsec_copypkt(md)) == NULL) { + m_freem(m); + error = ENOBUFS; + goto fail; + } + mprev->m_next = md; + + espoff = m->m_pkthdr.len - plen; + + /* + * grow the mbuf to accomodate ESP header. + * before: IP ... payload + * after: IP ... ESP IV payload + */ + if (M_LEADINGSPACE(md) < esphlen) { + MGET(n, M_DONTWAIT, MT_DATA); + if (!n) { + m_freem(m); + error = ENOBUFS; + goto fail; + } + n->m_len = esphlen; + mprev->m_next = n; + n->m_next = md; + m->m_pkthdr.len += esphlen; + esp = mtod(n, struct esp *); + } else { + md->m_len += esphlen; + md->m_data -= esphlen; + m->m_pkthdr.len += esphlen; + esp = mtod(md, struct esp *); + } + + nxt = *nexthdrp; + *nexthdrp = IPPROTO_ESP; + switch (af) { +#ifdef INET + case AF_INET: + if (esphlen < (IP_MAXPACKET - ntohs(ip->ip_len))) + ip->ip_len = htons(ntohs(ip->ip_len) + esphlen); + else { + printf("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 + } + } + + /* initialize esp header. */ + esp->esp_spi = spi; + if ((sav->flags & SADB_X_EXT_OLD) == 0) { + struct newesp *nesp; + nesp = (struct newesp *)esp; + sav->replay->count++; + /* + * XXX sequence number must not be cycled, if the SA is + * installed by IKE daemon. + */ + nesp->esp_seq = htonl(sav->replay->count); + } + + { + /* + * find the last mbuf. make some room for ESP trailer. + * XXX new-esp authentication data + */ +#ifdef INET + struct ip *ip = NULL; +#endif + size_t padbound; + + if (algo->padbound) + padbound = algo->padbound; + else + padbound = 4; + /* ESP packet, including nxthdr field, must be length of 4n */ + if (padbound < 4) + padbound = 4; + + extendsiz = padbound - (plen % padbound); + if (extendsiz == 1) + extendsiz = padbound + 1; + + n = m; + while (n->m_next) + n = n->m_next; + + /* + * if M_EXT, the external part may be shared among + * two consequtive TCP packets. + */ + if (!(n->m_flags & M_EXT) && extendsiz < M_TRAILINGSPACE(n)) { + switch (sav->flags & SADB_X_EXT_PMASK) { + case SADB_X_EXT_PRAND: + break; + case SADB_X_EXT_PZERO: + bzero((caddr_t)(mtod(n, u_int8_t *) + n->m_len), + extendsiz); + break; + case SADB_X_EXT_PSEQ: + { + int i; + u_char *p; + p = mtod(n, u_char *) + n->m_len; + for (i = 0; i < extendsiz; i++) + p[i] = i + 1; + break; + } + } + n->m_len += extendsiz; + m->m_pkthdr.len += extendsiz; + } else { + struct mbuf *nn; + + MGET(nn, M_DONTWAIT, MT_DATA); + if (!nn) { + printf("esp%d_output: can't alloc mbuf", afnumber); + m_freem(m); + error = ENOBUFS; + goto fail; + } + nn->m_len = extendsiz; + switch (sav->flags & SADB_X_EXT_PMASK) { + case SADB_X_EXT_PRAND: + break; + case SADB_X_EXT_PZERO: + bzero(mtod(nn, caddr_t), extendsiz); + break; + case SADB_X_EXT_PSEQ: + { + int i; + u_char *p; + p = mtod(nn, u_char *); + for (i = 0; i < extendsiz; i++) + p[i] = i + 1; + break; + } + } + nn->m_next = NULL; + n->m_next = nn; + n = nn; + m->m_pkthdr.len += extendsiz; + } + + /* initialize esp trailer. */ + esptail = (struct esptail *) + (mtod(n, u_int8_t *) + n->m_len - sizeof(struct esptail)); + esptail->esp_nxt = nxt; + esptail->esp_padlen = extendsiz - 2; + + /* modify IP header (for ESP header part only) */ + switch (af) { +#ifdef INET + case AF_INET: + ip = mtod(m, struct ip *); + if (extendsiz < (IP_MAXPACKET - ntohs(ip->ip_len))) + ip->ip_len = htons(ntohs(ip->ip_len) + extendsiz); + else { + printf("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 + } + } + + /* + * encrypt the packet, based on security association + * and the algorithm specified. + */ + if (!algo->encrypt) + panic("internal error: no encrypt function"); + if ((*algo->encrypt)(m, espoff, plen + extendsiz, sav, algo, ivlen)) { + printf("packet encryption failure\n"); + m_freem(m); + switch (af) { +#ifdef INET + case AF_INET: + ipsecstat.out_inval++; + break; +#endif +#ifdef INET6 + case AF_INET6: + ipsec6stat.out_inval++; + break; +#endif + } + error = EINVAL; + goto fail; + } + + /* + * calculate ICV if required. + */ + if (!sav->replay) + goto noantireplay; + if (!sav->key_auth) + goto noantireplay; + if (!sav->alg_auth) + goto noantireplay; + { + u_char authbuf[AH_MAXSUMSIZE]; + struct mbuf *n; + u_char *p; + size_t siz; + struct ip *ip; + + siz = (((*ah_algorithms[sav->alg_auth].sumsiz)(sav) + 3) & ~(4 - 1)); + if (AH_MAXSUMSIZE < siz) + panic("assertion failed for AH_MAXSUMSIZE"); + + if (esp_auth(m, espoff, m->m_pkthdr.len - espoff, sav, authbuf)) + goto noantireplay; + + n = m; + while (n->m_next) + n = n->m_next; + + if (!(n->m_flags & M_EXT) && siz < M_TRAILINGSPACE(n)) { /*XXX*/ + n->m_len += siz; + m->m_pkthdr.len += siz; + p = mtod(n, u_char *) + n->m_len - siz; + } else { + struct mbuf *nn; + + MGET(nn, M_DONTWAIT, MT_DATA); + if (!nn) { + printf("can't alloc mbuf in esp%d_output", afnumber); + m_freem(m); + error = ENOBUFS; + goto fail; + } + nn->m_len = siz; + nn->m_next = NULL; + n->m_next = nn; + n = nn; + m->m_pkthdr.len += siz; + p = mtod(nn, u_char *); + } + bcopy(authbuf, p, siz); + + /* modify IP header (for ESP header part only) */ + switch (af) { +#ifdef INET + case AF_INET: + ip = mtod(m, struct ip *); + if (siz < (IP_MAXPACKET - ntohs(ip->ip_len))) + ip->ip_len = htons(ntohs(ip->ip_len) + siz); + else { + printf("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 + } + } + +noantireplay: + if (!m) + printf("NULL mbuf after encryption in esp%d_output", afnumber); + else { + switch (af) { +#ifdef INET + case AF_INET: + ipsecstat.out_success++; + break; +#endif +#ifdef INET6 + case AF_INET6: + ipsec6stat.out_success++; + break; +#endif + } + } + switch (af) { +#ifdef INET + case AF_INET: + ipsecstat.out_esphist[sav->alg_enc]++; + break; +#endif +#ifdef INET6 + case AF_INET6: + ipsec6stat.out_esphist[sav->alg_enc]++; + break; +#endif + } + key_sa_recordxfer(sav, m); + return 0; + +fail: +#if 1 + return error; +#else + panic("something bad in esp_output"); +#endif +} + +#ifdef INET +int +esp4_output(m, isr) + struct mbuf *m; + struct ipsecrequest *isr; +{ + struct ip *ip; + if (m->m_len < sizeof(struct ip)) { + printf("esp4_output: first mbuf too short\n"); + m_freem(m); + return NULL; + } + ip = mtod(m, struct ip *); + /* XXX assumes that m->m_next points to payload */ + return esp_output(m, &ip->ip_p, m->m_next, isr, AF_INET); +} +#endif /*INET*/ + +#ifdef INET6 +int +esp6_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)) { + printf("esp6_output: first mbuf too short\n"); + m_freem(m); + return NULL; + } + return esp_output(m, nexthdrp, md, isr, AF_INET6); +} +#endif /*INET6*/ diff --git a/sys/netinet6/icmp6.c b/sys/netinet6/icmp6.c index f7d03cd..02c2219 100644 --- a/sys/netinet6/icmp6.c +++ b/sys/netinet6/icmp6.c @@ -64,7 +64,7 @@ * @(#)ip_icmp.c 8.2 (Berkeley) 1/4/94 */ -#include "opt_key.h" +#include "opt_ipsec.h" #include <sys/param.h> #include <sys/systm.h> @@ -96,15 +96,15 @@ #ifdef IPSEC #include <netinet6/ipsec.h> +#include <netinet6/ah.h> #include <netinet6/ipsec6.h> +#include <netinet6/ah6.h> #include <netkey/key.h> -#ifdef KEY_DEBUG +#ifdef IPSEC_DEBUG #include <netkey/key_debug.h> #else -#define DPRINTF(lev,arg) -#define DDO(lev, stmt) -#define DP(x, y, z) -#endif /* KEY_DEBUG */ +#define KEYDEBUG(lev,arg) +#endif #endif /* IPSEC */ #include "faith.h" @@ -1285,9 +1285,6 @@ icmp6_reflect(m, off) */ m->m_flags &= ~(M_BCAST|M_MCAST); -#ifdef IPSEC - m->m_pkthdr.rcvif = NULL; -#endif /*IPSEC*/ #ifdef COMPAT_RFC1885 ip6_output(m, NULL, &icmp6_reflect_rt, 0, NULL, &outif); @@ -1725,9 +1722,6 @@ noredhdropt:; = in6_cksum(m, IPPROTO_ICMPV6, sizeof(*ip6), ntohs(ip6->ip6_plen)); /* send the packet to outside... */ -#ifdef IPSEC - m->m_pkthdr.rcvif = NULL; -#endif /*IPSEC*/ ip6_output(m, NULL, NULL, 0, NULL, &outif); if (outif) { icmp6_ifstat_inc(outif, ifs6_out_msg); diff --git a/sys/netinet6/icmp6.h b/sys/netinet6/icmp6.h index 2fdb28b..c67e961 100644 --- a/sys/netinet6/icmp6.h +++ b/sys/netinet6/icmp6.h @@ -386,8 +386,8 @@ struct rr_pco_use { /* use prefix part */ u_int32_t rpu_flags; struct in6_addr rpu_prefix; }; -#define ICMP6_RR_PCOUSE_RAFLAGS_ONLINK 0x20 -#define ICMP6_RR_PCOUSE_RAFLAGS_AUTO 0x10 +#define ICMP6_RR_PCOUSE_RAFLAGS_ONLINK 0x80 +#define ICMP6_RR_PCOUSE_RAFLAGS_AUTO 0x40 #if BYTE_ORDER == BIG_ENDIAN #define ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME 0x80000000 diff --git a/sys/netinet6/in6_gif.c b/sys/netinet6/in6_gif.c index dd7cd2f..35c4088 100644 --- a/sys/netinet6/in6_gif.c +++ b/sys/netinet6/in6_gif.c @@ -55,6 +55,8 @@ #include <netinet6/ip6_var.h> #include <netinet6/in6_gif.h> #include <netinet6/ip6.h> +#include <netinet/ip_ecn.h> +#include <netinet6/ip6_ecn.h> #include <net/if_gif.h> @@ -73,6 +75,7 @@ in6_gif_output(ifp, family, m, rt) struct sockaddr_in6 *sin6_dst = (struct sockaddr_in6 *)sc->gif_pdst; struct ip6_hdr *ip6; int proto; + u_int8_t itos, otos; if (sin6_src == NULL || sin6_dst == NULL || sin6_src->sin6_family != AF_INET6 || @@ -94,6 +97,7 @@ in6_gif_output(ifp, family, m, rt) return ENOBUFS; } ip = mtod(m, struct ip *); + itos = ip->ip_tos; break; } #endif @@ -107,6 +111,7 @@ in6_gif_output(ifp, family, m, rt) return ENOBUFS; } ip6 = mtod(m, struct ip6_hdr *); + itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; break; } default: @@ -153,6 +158,11 @@ in6_gif_output(ifp, family, m, rt) return ENETUNREACH; } } + if (ifp->if_flags & IFF_LINK1) { + otos = 0; + ip_ecn_ingress(ECN_ALLOWED, &otos, &itos); + ip6->ip6_flow |= htonl((u_int32_t)otos << 20); + } if (dst->sin6_family != sin6_dst->sin6_family || !IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &sin6_dst->sin6_addr)) { @@ -175,9 +185,6 @@ in6_gif_output(ifp, family, m, rt) } } -#ifdef IPSEC - m->m_pkthdr.rcvif = NULL; -#endif /*IPSEC*/ return(ip6_output(m, 0, &sc->gif_ro6, 0, 0, NULL)); } @@ -191,6 +198,7 @@ int in6_gif_input(mp, offp, proto) struct ip6_hdr *ip6; int i; int af = 0; + u_int32_t otos; ip6 = mtod(m, struct ip6_hdr *); @@ -222,7 +230,8 @@ int in6_gif_input(mp, offp, proto) ip6stat.ip6s_nogif++; return IPPROTO_DONE; } - + + otos = ip6->ip6_flow; m_adj(m, *offp); switch (proto) { @@ -230,13 +239,17 @@ int in6_gif_input(mp, offp, proto) case IPPROTO_IPV4: { struct ip *ip; + u_int8_t otos8; af = AF_INET; + otos8 = (ntohl(otos) >> 20) & 0xff; if (m->m_len < sizeof(*ip)) { m = m_pullup(m, sizeof(*ip)); if (!m) return IPPROTO_DONE; } ip = mtod(m, struct ip *); + if (gifp->if_flags & IFF_LINK1) + ip_ecn_egress(ECN_ALLOWED, &otos8, &ip->ip_tos); break; } #endif /* INET */ @@ -250,6 +263,8 @@ int in6_gif_input(mp, offp, proto) return IPPROTO_DONE; } ip6 = mtod(m, struct ip6_hdr *); + if (gifp->if_flags & IFF_LINK1) + ip6_ecn_egress(ECN_ALLOWED, &otos, &ip6->ip6_flow); break; } default: diff --git a/sys/netinet6/in6_pcb.c b/sys/netinet6/in6_pcb.c index 89db824..acc155e 100644 --- a/sys/netinet6/in6_pcb.c +++ b/sys/netinet6/in6_pcb.c @@ -65,7 +65,7 @@ * $FreeBSD$ */ -#include "opt_key.h" +#include "opt_ipsec.h" #include <sys/param.h> #include <sys/systm.h> @@ -99,15 +99,15 @@ #ifdef IPSEC #include <netinet6/ipsec.h> +#include <netinet6/ah.h> #include <netinet6/ipsec6.h> +#include <netinet6/ah6.h> #include <netkey/key.h> -#ifdef KEY_DEBUG +#ifdef IPSEC_DEBUG #include <netkey/key_debug.h> #else -#define DPRINTF(lev,arg) -#define DDO(lev, stmt) -#define DP(x, y, z) -#endif /* KEY_DEBUG */ +#define KEYDEBUG(lev,arg) +#endif /* IPSEC_DEBUG */ #endif /* IPSEC */ struct in6_addr zeroin6_addr; diff --git a/sys/netinet6/in6_proto.c b/sys/netinet6/in6_proto.c index 3f59ec2..60c3fcf 100644 --- a/sys/netinet6/in6_proto.c +++ b/sys/netinet6/in6_proto.c @@ -64,6 +64,8 @@ * @(#)in_proto.c 8.1 (Berkeley) 6/10/93 */ +#include "opt_ipsec.h" + #include <sys/param.h> #include <sys/socket.h> #include <sys/socketvar.h> @@ -102,12 +104,13 @@ #ifdef IPSEC #include <netinet6/ipsec.h> -#include <netinet6/ipsec6.h> #include <netinet6/ah.h> +#include <netinet6/ipsec6.h> +#include <netinet6/ah6.h> #ifdef IPSEC_ESP #include <netinet6/esp.h> +#include <netinet6/esp6.h> #endif -#include <netinet6/ipcomp.h> #endif /*IPSEC*/ #include <netinet6/ip6protosw.h> @@ -186,12 +189,6 @@ struct ip6protosw inet6sw[] = { &nousrreqs, }, #endif -{ SOCK_RAW, &inet6domain, IPPROTO_IPCOMP, PR_ATOMIC|PR_ADDR, - ipcomp6_input, 0, 0, 0, - 0, - 0, 0, 0, 0, - &nousrreqs, -}, #endif /* IPSEC */ #if NGIF > 0 { SOCK_RAW, &inet6domain, IPPROTO_IPV4, PR_ATOMIC|PR_ADDR, diff --git a/sys/netinet6/ip6.h b/sys/netinet6/ip6.h index 1dacb10..9ebd51e 100644 --- a/sys/netinet6/ip6.h +++ b/sys/netinet6/ip6.h @@ -75,12 +75,16 @@ struct ip6_hdr { union { struct ip6_hdrctl { - u_int32_t ip6_un1_flow; /* 20 bits of flow-ID */ + u_int32_t ip6_un1_flow; /* 4 bits version, + * 8 bits traffic + * class, + * 20 bits flow-ID */ u_int16_t ip6_un1_plen; /* payload length */ u_int8_t ip6_un1_nxt; /* next header */ u_int8_t ip6_un1_hlim; /* hop limit */ } ip6_un1; - u_int8_t ip6_un2_vfc; /* 4 bits version, 4 bits class */ + u_int8_t ip6_un2_vfc; /* 4 bits version, + * top 4 bits trafic class */ } ip6_ctlun; struct in6_addr ip6_src; /* source address */ struct in6_addr ip6_dst; /* destination address */ diff --git a/sys/netinet6/ip6_ecn.h b/sys/netinet6/ip6_ecn.h new file mode 100644 index 0000000..cafe9a5 --- /dev/null +++ b/sys/netinet6/ip6_ecn.h @@ -0,0 +1,43 @@ +/* + * 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. + * + * $Id: ip_ecn.h,v 1.2 1999/08/19 12:57:44 itojun Exp $ + * $FreeBSD$ + */ +/* + * ECN consideration on tunnel ingress/egress operation. + * http://www.aciri.org/floyd/papers/draft-ipsec-ecn-00.txt + */ + +#if defined(KERNEL) || defined(_KERNEL) +extern void ip6_ecn_ingress __P((int, u_int32_t *, u_int32_t *)); +extern void ip6_ecn_egress __P((int, u_int32_t *, u_int32_t *)); +#endif + + + diff --git a/sys/netinet6/ip6_forward.c b/sys/netinet6/ip6_forward.c index 46b3188..2eaf6f5 100644 --- a/sys/netinet6/ip6_forward.c +++ b/sys/netinet6/ip6_forward.c @@ -29,7 +29,7 @@ * $FreeBSD$ */ -#include "opt_key.h" +#include "opt_ipsec.h" #include <sys/param.h> #include <sys/systm.h> @@ -57,13 +57,11 @@ #include <netinet6/ipsec.h> #include <netinet6/ipsec6.h> #include <netkey/key.h> -#ifdef KEY_DEBUG +#ifdef IPSEC_DEBUG #include <netkey/key_debug.h> #else -#define DPRINTF(lev,arg) -#define DDO(lev, stmt) -#define DP(x, y, z) -#endif /* KEY_DEBUG */ +#define KEYDEBUG(lev,arg) +#endif #endif /* IPSEC_IPV6FWD */ #ifdef IPV6FIREWALL diff --git a/sys/netinet6/ip6_fw.h b/sys/netinet6/ip6_fw.h deleted file mode 100644 index a356ac3..0000000 --- a/sys/netinet6/ip6_fw.h +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Copyright (c) 1993 Daniel Boulet - * Copyright (c) 1994 Ugen J.S.Antsilevich - * - * Redistribution and use in source forms, with and without modification, - * are permitted provided that this entire comment appears intact. - * - * Redistribution in binary form may occur without any restrictions. - * Obviously, it would be nice if you gave credit where credit is due - * but requiring it would be too onerous. - * - * This software is provided ``AS IS'' without any warranties of any kind. - * - * $Id: ip6_fw.h,v 1.1 1999/08/06 14:10:09 itojun Exp $ - * $FreeBSD$ - */ - -#ifndef _IP6_FW_H -#define _IP6_FW_H - -#include <net/if.h> - -/* - * This union structure identifies an interface, either explicitly - * by name or implicitly by IP address. The flags IP_FW_F_IIFNAME - * and IP_FW_F_OIFNAME say how to interpret this structure. An - * interface unit number of -1 matches any unit number, while an - * IP address of 0.0.0.0 indicates matches any interface. - * - * The receive and transmit interfaces are only compared against the - * the packet if the corresponding bit (IP_FW_F_IIFACE or IP_FW_F_OIFACE) - * is set. Note some packets lack a receive or transmit interface - * (in which case the missing "interface" never matches). - */ - -union ip6_fw_if { - struct in6_addr fu_via_ip6; /* Specified by IPv6 address */ - struct { /* Specified by interface name */ -#define FW_IFNLEN IFNAMSIZ - char name[FW_IFNLEN]; - short unit; /* -1 means match any unit */ - } fu_via_if; -}; - -/* - * Format of an IP firewall descriptor - * - * fw_src, fw_dst, fw_smsk, fw_dmsk are always stored in network byte order. - * fw_flg and fw_n*p are stored in host byte order (of course). - * Port numbers are stored in HOST byte order. - * Warning: setsockopt() will fail if sizeof(struct ip_fw) > MLEN (108) - */ - -struct ip6_fw { - u_long fw_pcnt,fw_bcnt; /* Packet and byte counters */ - struct in6_addr fw_src, fw_dst; /* Source and destination IPv6 addr */ - /* Mask for src and dest IPv6 addr */ - struct in6_addr fw_smsk, fw_dmsk; - u_short fw_number; /* Rule number */ - u_short fw_flg; /* Flags word */ -#define IPV6_FW_MAX_PORTS 10 /* A reasonable maximum */ - /* Array of port numbers to match */ - u_short fw_pts[IPV6_FW_MAX_PORTS]; - u_char fw_ip6opt,fw_ip6nopt; /* IPv6 options set/unset */ - u_char fw_tcpf,fw_tcpnf; /* TCP flags set/unset */ -#define IPV6_FW_ICMPTYPES_DIM (32 / (sizeof(unsigned) * 8)) - /* ICMP types bitmap */ - unsigned fw_icmp6types[IPV6_FW_ICMPTYPES_DIM]; - long timestamp; /* timestamp (tv_sec) of last match */ - /* Incoming and outgoing interfaces */ - union ip6_fw_if fw_in_if, fw_out_if; - union { - u_short fu_divert_port; /* Divert/tee port (options IP6DIVERT) */ - u_short fu_skipto_rule; /* SKIPTO command rule number */ - u_short fu_reject_code; /* REJECT response code */ - } fw_un; - u_char fw_prot; /* IPv6 protocol */ - u_char fw_nports; /* N'of src ports and # of dst ports */ - /* in ports array (dst ports follow */ - /* src ports; max of 10 ports in all; */ - /* count of 0 means match all ports) */ -}; - -#define IPV6_FW_GETNSRCP(rule) ((rule)->fw_nports & 0x0f) -#define IPV6_FW_SETNSRCP(rule, n) do { \ - (rule)->fw_nports &= ~0x0f; \ - (rule)->fw_nports |= (n); \ - } while (0) -#define IPV6_FW_GETNDSTP(rule) ((rule)->fw_nports >> 4) -#define IPV6_FW_SETNDSTP(rule, n) do { \ - (rule)->fw_nports &= ~0xf0; \ - (rule)->fw_nports |= (n) << 4;\ - } while (0) - -#define fw_divert_port fw_un.fu_divert_port -#define fw_skipto_rule fw_un.fu_skipto_rule -#define fw_reject_code fw_un.fu_reject_code - -struct ip6_fw_chain { - LIST_ENTRY(ip6_fw_chain) chain; - struct ip6_fw *rule; -}; - -/* - * Values for "flags" field . - */ -#define IPV6_FW_F_IN 0x0001 /* Check inbound packets */ -#define IPV6_FW_F_OUT 0x0002 /* Check outbound packets */ -#define IPV6_FW_F_IIFACE 0x0004 /* Apply inbound interface test */ -#define IPV6_FW_F_OIFACE 0x0008 /* Apply outbound interface test */ - -#define IPV6_FW_F_COMMAND 0x0070 /* Mask for type of chain entry: */ -#define IPV6_FW_F_DENY 0x0000 /* This is a deny rule */ -#define IPV6_FW_F_REJECT 0x0010 /* Deny and send a response packet */ -#define IPV6_FW_F_ACCEPT 0x0020 /* This is an accept rule */ -#define IPV6_FW_F_COUNT 0x0030 /* This is a count rule */ -#define IPV6_FW_F_DIVERT 0x0040 /* This is a divert rule */ -#define IPV6_FW_F_TEE 0x0050 /* This is a tee rule */ -#define IPV6_FW_F_SKIPTO 0x0060 /* This is a skipto rule */ - -#define IPV6_FW_F_PRN 0x0080 /* Print if this rule matches */ - -#define IPV6_FW_F_SRNG 0x0100 /* The first two src ports are a min * - * and max range (stored in host byte * - * order). */ - -#define IPV6_FW_F_DRNG 0x0200 /* The first two dst ports are a min * - * and max range (stored in host byte * - * order). */ - -/* In interface by name/unit (not IP) */ -#define IPV6_FW_F_IIFNAME 0x0400 -/* Out interface by name/unit (not IP) */ -#define IPV6_FW_F_OIFNAME 0x0800 - -#define IPV6_FW_F_INVSRC 0x1000 /* Invert sense of src check */ -#define IPV6_FW_F_INVDST 0x2000 /* Invert sense of dst check */ - -#define IPV6_FW_F_FRAG 0x4000 /* Fragment */ - -#define IPV6_FW_F_ICMPBIT 0x8000 /* ICMP type bitmap is valid */ - -#define IPV6_FW_F_MASK 0xFFFF /* All possible flag bits mask */ - -/* - * For backwards compatibility with rules specifying "via iface" but - * not restricted to only "in" or "out" packets, we define this combination - * of bits to represent this configuration. - */ - -#define IF6_FW_F_VIAHACK (IPV6_FW_F_IN|IPV6_FW_F_OUT|IPV6_FW_F_IIFACE|\ - IPV6_FW_F_OIFACE) - -/* - * Definitions for REJECT response codes. - * Values less than 256 correspond to ICMP unreachable codes. - */ -#define IPV6_FW_REJECT_RST 0x0100 /* TCP packets: send RST */ - -/* - * Definitions for IPv6 option names. - */ -#define IPV6_FW_IP6OPT_HOPOPT 0x01 -#define IPV6_FW_IP6OPT_ROUTE 0x02 -#define IPV6_FW_IP6OPT_FRAG 0x04 -#define IPV6_FW_IP6OPT_ESP 0x08 -#define IPV6_FW_IP6OPT_AH 0x10 -#define IPV6_FW_IP6OPT_NONXT 0x20 -#define IPV6_FW_IP6OPT_OPTS 0x40 - -/* - * Definitions for TCP flags. - */ -#define IPV6_FW_TCPF_FIN TH_FIN -#define IPV6_FW_TCPF_SYN TH_SYN -#define IPV6_FW_TCPF_RST TH_RST -#define IPV6_FW_TCPF_PSH TH_PUSH -#define IPV6_FW_TCPF_ACK TH_ACK -#define IPV6_FW_TCPF_URG TH_URG -#define IPV6_FW_TCPF_ESTAB 0x40 - -/* - * Main firewall chains definitions and global var's definitions. - */ -#ifdef _KERNEL - -/* - * Function definitions. - */ -void ip6_fw_init(void); - -/* Firewall hooks */ -struct ip6_hdr; -typedef int ip6_fw_chk_t __P((struct ip6_hdr**, struct ifnet*, - u_short *, struct mbuf**)); -typedef int ip6_fw_ctl_t __P((int, struct mbuf**)); -extern ip6_fw_chk_t *ip6_fw_chk_ptr; -extern ip6_fw_ctl_t *ip6_fw_ctl_ptr; - -#endif /* _KERNEL */ - -#endif /* _IP6_FW_H */ diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c index 105b4bc..42930bd 100644 --- a/sys/netinet6/ip6_input.c +++ b/sys/netinet6/ip6_input.c @@ -64,6 +64,8 @@ * @(#)ip_input.c 8.2 (Berkeley) 1/4/94 */ +#include "opt_ipsec.h" + #include <sys/param.h> #include <sys/systm.h> #include <sys/malloc.h> @@ -209,7 +211,8 @@ ip6_init2(dummy) } /* cheat */ -SYSINIT(netinet6init2, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD, ip6_init2, NULL); +/* This must be after route_init(), which is now SI_ORDER_THIRD */ +SYSINIT(netinet6init2, SI_SUB_PROTO_DOMAIN, SI_ORDER_MIDDLE, ip6_init2, NULL); /* * IP6 input interrupt handling. Just pass the packet to ip6_input. diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c index c5876f9..12f0f53 100644 --- a/sys/netinet6/ip6_output.c +++ b/sys/netinet6/ip6_output.c @@ -64,7 +64,7 @@ * @(#)ip_output.c 8.3 (Berkeley) 1/21/94 */ -#include "opt_key.h" +#include "opt_ipsec.h" #include <sys/param.h> #include <sys/malloc.h> @@ -92,13 +92,11 @@ #include <netinet6/ipsec.h> #include <netinet6/ipsec6.h> #include <netkey/key.h> -#ifdef KEY_DEBUG +#ifdef IPSEC_DEBUG #include <netkey/key_debug.h> #else -#define DPRINTF(lev,arg) -#define DDO(lev, stmt) -#define DP(x, y, z) -#endif /* KEY_DEBUG */ +#define KEYDEBUG(lev,arg) +#endif #endif /* IPSEC */ #include "loop.h" @@ -166,8 +164,11 @@ ip6_output(m0, opt, ro, flags, im6o, ifpp) struct secpolicy *sp = NULL; /* for AH processing. stupid to have "socket" variable in IP layer... */ - so = (struct socket *)m->m_pkthdr.rcvif; - m->m_pkthdr.rcvif = NULL; + if ((flags & IPV6_SOCKINMRCVIF) != 0) { + so = (struct socket *)m->m_pkthdr.rcvif; + m->m_pkthdr.rcvif = NULL; + } else + so = NULL; ip6 = mtod(m, struct ip6_hdr *); #endif /* IPSEC */ @@ -1321,9 +1322,11 @@ ip6_ctloutput(so, sopt) caddr_t req = NULL; struct mbuf *m; - if (error = soopt_getm(sopt, &m)) /* XXX */ + if ((error = soopt_getm(sopt, &m)) + != 0) /* XXX */ break; - if (error = soopt_mcopyin(sopt, m)) /* XXX */ + if ((error = soopt_mcopyin(sopt, m)) + != 0) /* XXX */ break; if (m != 0) req = mtod(m, caddr_t); @@ -1345,9 +1348,11 @@ ip6_ctloutput(so, sopt) if (ip6_fw_ctl_ptr == NULL) return EINVAL; - if (error = soopt_getm(sopt, &m)) /* XXX */ + if ((error = soopt_getm(sopt, &m)) + != 0) /* XXX */ break; - if (error = soopt_mcopyin(sopt, m)) /* XXX */ + if ((error = soopt_mcopyin(sopt, m)) + != 0) /* XXX */ break; error = (*ip6_fw_ctl_ptr)(optname, mp); m = *mp; diff --git a/sys/netinet6/ip6_var.h b/sys/netinet6/ip6_var.h index 21df4f7..2e70bcb 100644 --- a/sys/netinet6/ip6_var.h +++ b/sys/netinet6/ip6_var.h @@ -173,6 +173,9 @@ struct ip6stat { /* flags passed to ip6_output as last parameter */ #define IPV6_DADOUTPUT 0x01 /* DAD */ #define IPV6_FORWARDING 0x02 /* most of IPv6 header exists */ +#define IPV6_SOCKINMRCVIF 0x100 /* IPSEC hack; + * socket pointer in sending + * packet's m_pkthdr.rcvif */ extern struct ip6stat ip6stat; /* statistics */ extern u_int32_t ip6_id; /* fragment identifier */ diff --git a/sys/netinet6/ipsec.c b/sys/netinet6/ipsec.c new file mode 100644 index 0000000..9047ea3 --- /dev/null +++ b/sys/netinet6/ipsec.c @@ -0,0 +1,3061 @@ +/* + * 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. + * + * $FreeBSD$ + */ + +/* + * 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/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/in_pcb.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 + +#ifdef INET6 +#include <netinet6/ip6.h> +#include <netinet6/in6_pcb.h> +#include <netinet6/ip6_var.h> +#include <netinet6/icmp6.h> +#endif /*INET6*/ + +#include <netinet6/ipsec.h> +#include <netinet6/ah.h> +#ifdef INET6 +#include <netinet6/ipsec6.h> +#include <netinet6/ah6.h> +#endif +#ifdef IPSEC_ESP +#include <netinet6/esp.h> +#ifdef INET6 +#include <netinet6/esp6.h> +#endif +#endif + +#include <netkey/key.h> +#include <netkey/key_var.h> +#include <netkey/keydb.h> +#ifdef IPSEC_DEBUG +#include <netkey/key_debug.h> +#else +#define KEYDEBUG(lev,arg) +#endif + +struct ipsecstat ipsecstat; +int ip4_inbound_call_ike = 0; +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) */ + +/* net.inet.ipsec */ +SYSCTL_STRUCT(_net_inet_ipsec, IPSECCTL_STATS, + stats, CTLFLAG_RD, &ipsecstat, ipsecstat, ""); +SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_POLICY, + def_policy, CTLFLAG_RW, &ip4_def_policy.policy, 0, ""); +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_INBOUND_CALL_IKE, + inbound_call_ike, CTLFLAG_RW, &ip4_inbound_call_ike, 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, ""); + +#ifdef INET6 +struct ipsecstat ipsec6stat; +int ip6_inbound_call_ike = 0; +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) */ + +/* net.inet6.ipsec6 */ +SYSCTL_STRUCT(_net_inet6_ipsec6, IPSECCTL_STATS, + stats, CTLFLAG_RD, &ipsec6stat, ipsecstat, ""); +SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_POLICY, + def_policy, CTLFLAG_RW, &ip6_def_policy.policy, 0, ""); +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_INBOUND_CALL_IKE, + inbound_call_ike, CTLFLAG_RW, &ip6_inbound_call_ike, 0, ""); +SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_ECN, + ecn, CTLFLAG_RW, &ip6_ipsec_ecn, 0, ""); +#endif /* INET6 */ + +static int ipsec_setspidx_mbuf + __P((struct secpolicyindex *, u_int, u_int, struct mbuf *)); +static void ipsec4_setspidx_inpcb __P((struct mbuf *, struct inpcb *pcb)); +static void ipsec4_setspidx_ipaddr __P((struct mbuf *, struct secpolicyindex *)); +#ifdef INET6 +static u_int16_t ipsec6_get_ulp __P((struct mbuf *m)); +static void ipsec6_setspidx_in6pcb __P((struct mbuf *, struct in6pcb *pcb)); +static void ipsec6_setspidx_ipaddr __P((struct mbuf *, struct secpolicyindex *)); +#endif +static struct secpolicy *ipsec_deepcopy_policy __P((struct secpolicy *src)); +static int ipsec_set_policy __P((struct secpolicy **pcb_sp, + int optname, caddr_t request, int priv)); +static int ipsec_get_policy __P((struct secpolicy *pcb_sp, struct mbuf **mp)); +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 *)); +static struct mbuf *ipsec4_splithdr __P((struct mbuf *)); +#ifdef INET6 +static struct mbuf *ipsec6_splithdr __P((struct mbuf *)); +#endif +static int ipsec4_encapsulate __P((struct mbuf *, struct secasvar *)); +#ifdef INET6 +static int ipsec6_encapsulate __P((struct mbuf *, struct secasvar *)); +#endif + +#define KMALLOC(p, t, n) \ + ((p) = (t) malloc((unsigned long)(n), M_SECA, M_NOWAIT)) +#define KFREE(p) \ + free((caddr_t)(p), M_SECA); + +/* + * 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_getpolicybysock(m, dir, so, error) + struct mbuf *m; + u_int dir; + struct socket *so; + int *error; +{ + struct inpcbpolicy *pcbsp = NULL; + struct secpolicy *currsp = NULL; /* policy on socket */ + struct secpolicy *kernsp = NULL; /* policy on kernel */ + + /* sanity check */ + if (m == NULL || so == NULL || error == NULL) + panic("ipsec4_getpolicybysock: NULL pointer was passed.\n"); + + switch (so->so_proto->pr_domain->dom_family) { + case AF_INET: + /* set spidx in pcb */ + ipsec4_setspidx_inpcb(m, sotoinpcb(so)); + pcbsp = sotoinpcb(so)->inp_sp; + break; +#ifdef INET6 + case AF_INET6: + /* set spidx in pcb */ + ipsec6_setspidx_in6pcb(m, sotoin6pcb(so)); + pcbsp = sotoin6pcb(so)->in6p_sp; + break; +#endif + default: + panic("ipsec4_getpolicybysock: unsupported address family\n"); + } + + /* sanity check */ + if (pcbsp == NULL) + panic("ipsec4_getpolicybysock: pcbsp is NULL.\n"); + + KEYDEBUG(KEYDEBUG_IPSEC_DATA, + printf("send: priv=%d ", pcbsp->priv); + if (so->so_cred) + printf("cr_uid=%d\n", so->so_cred->cr_uid); + ); + switch (dir) { + case IPSEC_DIR_INBOUND: + currsp = pcbsp->sp_in; + break; + case IPSEC_DIR_OUTBOUND: + currsp = pcbsp->sp_out; + break; + default: + panic("ipsec4_getpolicybysock: illegal direction.\n"); + } + + /* sanity check */ + if (currsp == NULL) + panic("ipsec4_getpolicybysock: currsp is NULL.\n"); + + /* when privilieged socket */ + if (pcbsp->priv) { + switch (currsp->policy) { + case IPSEC_POLICY_BYPASS: + currsp->refcnt++; + *error = 0; + return currsp; + + case IPSEC_POLICY_ENTRUST: + /* look for a policy in SPD */ + kernsp = key_allocsp(&currsp->spidx, dir); + + /* SP found */ + if (kernsp != NULL) { + KEYDEBUG(KEYDEBUG_IPSEC_STAMP, + printf("DP ipsec4_getpolicybysock called " + "to allocate SP:%p\n", kernsp)); + *error = 0; + return kernsp; + } + + /* no SP found */ + if (ip4_def_policy.policy != IPSEC_POLICY_DISCARD + && ip4_def_policy.policy != IPSEC_POLICY_NONE) { + printf("fixed system default policy:%d->%d\n", + ip4_def_policy.policy, + IPSEC_POLICY_NONE); + ip4_def_policy.policy = IPSEC_POLICY_NONE; + } + ip4_def_policy.refcnt++; + *error = 0; + return &ip4_def_policy; + + case IPSEC_POLICY_IPSEC: + currsp->refcnt++; + *error = 0; + return currsp; + + default: + printf("ipsec4_getpolicybysock: " + "Invalid policy for PCB %d\n", + currsp->policy); + *error = EINVAL; + return NULL; + } + /* NOTREACHED */ + } + + /* when non-privilieged socket */ + /* look for a policy in SPD */ + kernsp = key_allocsp(&currsp->spidx, dir); + + /* SP found */ + if (kernsp != NULL) { + KEYDEBUG(KEYDEBUG_IPSEC_STAMP, + printf("DP ipsec4_getpolicybysock called " + "to allocate SP:%p\n", kernsp)); + *error = 0; + return kernsp; + } + + /* no SP found */ + switch (currsp->policy) { + case IPSEC_POLICY_BYPASS: + printf("ipsec4_getpolicybysock: " + "Illegal policy for non-priviliged defined %d\n", + currsp->policy); + *error = EINVAL; + return NULL; + + case IPSEC_POLICY_ENTRUST: + if (ip4_def_policy.policy != IPSEC_POLICY_DISCARD + && ip4_def_policy.policy != IPSEC_POLICY_NONE) { + printf("fixed system default policy:%d->%d\n", + ip4_def_policy.policy, + IPSEC_POLICY_NONE); + ip4_def_policy.policy = IPSEC_POLICY_NONE; + } + ip4_def_policy.refcnt++; + *error = 0; + return &ip4_def_policy; + + case IPSEC_POLICY_IPSEC: + currsp->refcnt++; + *error = 0; + return currsp; + + default: + printf("ipsec4_getpolicybysock: " + "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; + + /* sanity check */ + if (m == NULL || error == NULL) + panic("ipsec4_getpolicybyaddr: NULL pointer was passed.\n"); + + { + struct secpolicyindex spidx; + + bzero(&spidx, sizeof(spidx)); + + /* make a index to look for a policy */ + if ((flag & IP_FORWARDING) == IP_FORWARDING) { + /* Case: IP forwarding */ + *error = ipsec_setspidx_mbuf(&spidx, dir, AF_INET, m); + } else { + /* Case: ICMP echo reply */ + *error = ipsec_setspidx_mbuf(&spidx, dir, AF_INET, m); + } + + if (*error != 0) + return NULL; + + sp = key_allocsp(&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 */ + if (ip4_def_policy.policy != IPSEC_POLICY_DISCARD + && ip4_def_policy.policy != IPSEC_POLICY_NONE) { + printf("fixed system default policy:%d->%d\n", + ip4_def_policy.policy, + IPSEC_POLICY_NONE); + ip4_def_policy.policy = IPSEC_POLICY_NONE; + } + 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_getpolicybysock(m, dir, so, error) + struct mbuf *m; + u_int dir; + struct socket *so; + int *error; +{ + struct inpcbpolicy *pcbsp = NULL; + struct secpolicy *currsp = NULL; /* policy on socket */ + struct secpolicy *kernsp = NULL; /* policy on kernel */ + + /* sanity check */ + if (m == NULL || so == NULL || error == NULL) + panic("ipsec6_getpolicybysock: NULL pointer was passed.\n"); + + /* set spidx in pcb */ + ipsec6_setspidx_in6pcb(m, sotoin6pcb(so)); + + pcbsp = sotoin6pcb(so)->in6p_sp; + + /* sanity check */ + if (pcbsp == NULL) + panic("ipsec6_getpolicybysock: pcbsp is NULL.\n"); + + switch (dir) { + case IPSEC_DIR_INBOUND: + currsp = pcbsp->sp_in; + break; + case IPSEC_DIR_OUTBOUND: + currsp = pcbsp->sp_out; + break; + default: + panic("ipsec6_getpolicybysock: illegal direction.\n"); + } + + /* sanity check */ + if (currsp == NULL) + panic("ipsec6_getpolicybysock: currsp is NULL.\n"); + + /* when privilieged socket */ + if (pcbsp->priv) { + switch (currsp->policy) { + case IPSEC_POLICY_BYPASS: + currsp->refcnt++; + *error = 0; + return currsp; + + case IPSEC_POLICY_ENTRUST: + /* look for a policy in SPD */ + kernsp = key_allocsp(&currsp->spidx, dir); + + /* SP found */ + if (kernsp != NULL) { + KEYDEBUG(KEYDEBUG_IPSEC_STAMP, + printf("DP ipsec6_getpolicybysock called " + "to allocate SP:%p\n", kernsp)); + *error = 0; + return kernsp; + } + + /* no SP found */ + if (ip6_def_policy.policy != IPSEC_POLICY_DISCARD + && ip6_def_policy.policy != IPSEC_POLICY_NONE) { + printf("fixed system default policy:%d->%d\n", + ip6_def_policy.policy, + IPSEC_POLICY_NONE); + ip6_def_policy.policy = IPSEC_POLICY_NONE; + } + ip6_def_policy.refcnt++; + *error = 0; + return &ip6_def_policy; + + case IPSEC_POLICY_IPSEC: + currsp->refcnt++; + *error = 0; + return currsp; + + default: + printf("ipsec6_getpolicybysock: " + "Invalid policy for PCB %d\n", + currsp->policy); + *error = EINVAL; + return NULL; + } + /* NOTREACHED */ + } + + /* when non-privilieged socket */ + /* look for a policy in SPD */ + kernsp = key_allocsp(&currsp->spidx, dir); + + /* SP found */ + if (kernsp != NULL) { + KEYDEBUG(KEYDEBUG_IPSEC_STAMP, + printf("DP ipsec6_getpolicybysock called " + "to allocate SP:%p\n", kernsp)); + *error = 0; + return kernsp; + } + + /* no SP found */ + switch (currsp->policy) { + case IPSEC_POLICY_BYPASS: + printf("ipsec6_getpolicybysock: " + "Illegal policy for non-priviliged defined %d\n", + currsp->policy); + *error = EINVAL; + return NULL; + + case IPSEC_POLICY_ENTRUST: + if (ip6_def_policy.policy != IPSEC_POLICY_DISCARD + && ip6_def_policy.policy != IPSEC_POLICY_NONE) { + printf("fixed system default policy:%d->%d\n", + ip6_def_policy.policy, + IPSEC_POLICY_NONE); + ip6_def_policy.policy = IPSEC_POLICY_NONE; + } + ip6_def_policy.refcnt++; + *error = 0; + return &ip6_def_policy; + + case IPSEC_POLICY_IPSEC: + currsp->refcnt++; + *error = 0; + return currsp; + + default: + printf("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; + + /* sanity check */ + if (m == NULL || error == NULL) + panic("ipsec6_getpolicybyaddr: NULL pointer was passed.\n"); + + { + struct secpolicyindex spidx; + + bzero(&spidx, sizeof(spidx)); + + /* make a index to look for a policy */ + if ((flag & IP_FORWARDING) == IP_FORWARDING) { + /* Case: IP forwarding */ + *error = ipsec_setspidx_mbuf(&spidx, dir, AF_INET6, m); + } else { + /* Case: ICMP echo reply */ + *error = ipsec_setspidx_mbuf(&spidx, dir, AF_INET6, m); + } + + if (*error != 0) + return NULL; + + sp = key_allocsp(&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 */ + if (ip6_def_policy.policy != IPSEC_POLICY_DISCARD + && ip6_def_policy.policy != IPSEC_POLICY_NONE) { + printf("fixed system default policy:%d->%d\n", + ip6_def_policy.policy, + IPSEC_POLICY_NONE); + ip6_def_policy.policy = IPSEC_POLICY_NONE; + } + 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, dir, family, m) + struct secpolicyindex *spidx; + u_int dir, family; + struct mbuf *m; +{ + /* sanity check */ + if (spidx == NULL || m == NULL) + panic("ipsec_setspidx_mbuf: NULL pointer was passed.\n"); + + KEYDEBUG(KEYDEBUG_IPSEC_DUMP, + printf("ipsec_setspidx_mbuf: begin\n"); kdebug_mbuf(m)); + + /* initialize */ + bzero(spidx, sizeof(*spidx)); + + spidx->dir = dir; + spidx->src.__ss_len = spidx->dst.__ss_len = _SALENBYAF(family); + spidx->src.__ss_family = spidx->dst.__ss_family = family; + spidx->prefs = spidx->prefd = _INALENBYAF(family) << 3; + + { + /* sanity check for packet length. */ + struct mbuf *n; + int tlen; + + tlen = 0; + for (n = m; n; n = n->m_next) + tlen += n->m_len; + if (m->m_pkthdr.len != tlen) { + KEYDEBUG(KEYDEBUG_IPSEC_DUMP, + printf("ipsec_setspidx_mbuf: " + "total of m_len(%d) != pkthdr.len(%d), " + "ignored.\n", + tlen, m->m_pkthdr.len)); + goto bad; + } + } + + switch (family) { + case AF_INET: + { + struct ip *ip; + struct ip ipbuf; + + /* sanity check 1 for minimum ip header length */ + if (m->m_pkthdr.len < sizeof(struct ip)) { + KEYDEBUG(KEYDEBUG_IPSEC_DUMP, + printf("ipsec_setspidx_mbuf: " + "pkthdr.len(%d) < sizeof(struct ip), " + "ignored.\n", + m->m_pkthdr.len)); + goto bad; + } + + /* + * get IPv4 header packet. usually the mbuf is contiguous + * and we need no copies. + */ + if (m->m_len >= sizeof(*ip)) + ip = mtod(m, struct ip *); + else { + m_copydata(m, 0, sizeof(ipbuf), (caddr_t)&ipbuf); + ip = &ipbuf; + } + + /* some more checks on IPv4 header. */ + bcopy(&ip->ip_src, _INADDRBYSA(&spidx->src), + sizeof(ip->ip_src)); + bcopy(&ip->ip_dst, _INADDRBYSA(&spidx->dst), + sizeof(ip->ip_dst)); + + spidx->ul_proto = ip->ip_p; + _INPORTBYSA(&spidx->src) = IPSEC_PORT_ANY; + _INPORTBYSA(&spidx->dst) = IPSEC_PORT_ANY; + break; + } + +#ifdef INET6 + case AF_INET6: + { + struct ip6_hdr *ip6_hdr; + struct ip6_hdr ip6buf; + + /* sanity check 1 for minimum ip header length */ + if (m->m_pkthdr.len < sizeof(struct ip6_hdr)) { + KEYDEBUG(KEYDEBUG_IPSEC_DUMP, + printf("ipsec_setspidx_mbuf: " + "pkthdr.len(%d) < sizeof(struct ip6_hdr), " + "ignored.\n", + m->m_pkthdr.len)); + goto bad; + } + + /* + * get IPv6 header packet. usually the mbuf is contiguous + * and we need no copies. + */ + if (m->m_len >= sizeof(*ip6_hdr)) + ip6_hdr = mtod(m, struct ip6_hdr *); + else { + m_copydata(m, 0, sizeof(ip6buf), (caddr_t)&ip6buf); + ip6_hdr = &ip6buf; + } + + /* some more checks on IPv4 header. */ + if ((ip6_hdr->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) { + KEYDEBUG(KEYDEBUG_IPSEC_DUMP, + printf("ipsec_setspidx_mbuf: " + "wrong ip version on packet " + "(expected IPv6), ignored.\n")); + goto bad; + } + + bcopy(&ip6_hdr->ip6_src, _INADDRBYSA(&spidx->src), + sizeof(ip6_hdr->ip6_src)); + bcopy(&ip6_hdr->ip6_dst, _INADDRBYSA(&spidx->dst), + sizeof(ip6_hdr->ip6_dst)); + + spidx->ul_proto = ipsec6_get_ulp(m); + _INPORTBYSA(&spidx->src) = IPSEC_PORT_ANY; + _INPORTBYSA(&spidx->dst) = IPSEC_PORT_ANY; + break; + } +#endif /* INET6 */ + default: + panic("ipsec_secsecidx: no supported family passed.\n"); + } + + KEYDEBUG(KEYDEBUG_IPSEC_DUMP, + printf("ipsec_setspidx_mbuf: end\n"); + kdebug_secpolicyindex(spidx)); + + return 0; + + bad: + /* XXX initialize */ + bzero(spidx, sizeof(*spidx)); + return EINVAL; +} + +#ifdef INET6 +/* + * Get the number of upper layer protocol. + * Assumed all extension headers are in single mbuf. + */ +static u_int16_t +ipsec6_get_ulp(m) + struct mbuf *m; +{ + struct ip6_hdr *ip6; + struct ip6_ext *ip6e; + int off, nxt; + int len; + + /* sanity check */ + if (m == NULL) + panic("ipsec6_get_ulp: NULL pointer was passed.\n"); + + KEYDEBUG(KEYDEBUG_IPSEC_DUMP, + printf("ipsec6_get_ulp:\n"); kdebug_mbuf(m)); + + ip6 = mtod(m, struct ip6_hdr *); + nxt = ip6->ip6_nxt; + off = sizeof(struct ip6_hdr); + len = m->m_len; + + while (off < len) { + ip6e = (struct ip6_ext *)((caddr_t) ip6 + off); + if (m->m_len < off + sizeof(*ip6e)) { + printf("ipsec6_get_ulp: all exthdr are not " + "in single mbuf.\n"); + return IPSEC_PORT_ANY; + } + + switch(nxt) { + case IPPROTO_TCP: + case IPPROTO_UDP: + case IPPROTO_ICMPV6: + return nxt; + case IPPROTO_FRAGMENT: + off += sizeof(struct ip6_frag); + break; + case IPPROTO_AH: + off += (ip6e->ip6e_len + 2) << 2; + break; + default: + switch (nxt) { + case IPPROTO_HOPOPTS: + case IPPROTO_ROUTING: + case IPPROTO_ESP: + case IPPROTO_NONE: + case IPPROTO_DSTOPTS: + break; + default: + return nxt; /* XXX */ + } + off += (ip6e->ip6e_len + 1) << 3; + break; + } + nxt = ip6e->ip6e_nxt; + } + + return IPSEC_PORT_ANY; +} +#endif + +static void +ipsec4_setspidx_inpcb(m, pcb) + struct mbuf *m; + struct inpcb *pcb; +{ + struct secpolicyindex *spidx; + + /* sanity check */ + if (pcb == NULL) + panic("ipsec4_setspidx_inpcb: no PCB found.\n"); + if (pcb->inp_sp == NULL) + panic("ipsec4_setspidx_inpcb: no inp_sp found.\n"); + if (pcb->inp_sp->sp_out ==NULL || pcb->inp_sp->sp_in == NULL) + panic("ipsec4_setspidx_inpcb: no sp_in/out found.\n"); + + bzero(&pcb->inp_sp->sp_in->spidx, sizeof(*spidx)); + bzero(&pcb->inp_sp->sp_out->spidx, sizeof(*spidx)); + + spidx = &pcb->inp_sp->sp_in->spidx; + spidx->dir = IPSEC_DIR_INBOUND; + spidx->src.__ss_len = spidx->dst.__ss_len = _SALENBYAF(AF_INET); + spidx->src.__ss_family = spidx->dst.__ss_family = AF_INET; + spidx->prefs = _INALENBYAF(AF_INET) << 3; + spidx->prefd = _INALENBYAF(AF_INET) << 3; + spidx->ul_proto = pcb->inp_socket->so_proto->pr_protocol; + _INPORTBYSA(&spidx->src) = pcb->inp_fport; + _INPORTBYSA(&spidx->dst) = pcb->inp_lport; + ipsec4_setspidx_ipaddr(m, spidx); + + spidx = &pcb->inp_sp->sp_out->spidx; + spidx->dir = IPSEC_DIR_OUTBOUND; + spidx->src.__ss_len = spidx->dst.__ss_len = _SALENBYAF(AF_INET); + spidx->src.__ss_family = spidx->dst.__ss_family = AF_INET; + spidx->prefs = _INALENBYAF(AF_INET) << 3; + spidx->prefd = _INALENBYAF(AF_INET) << 3; + spidx->ul_proto = pcb->inp_socket->so_proto->pr_protocol; + _INPORTBYSA(&spidx->src) = pcb->inp_lport; + _INPORTBYSA(&spidx->dst) = pcb->inp_fport; + ipsec4_setspidx_ipaddr(m, spidx); + + return; +} + +static void +ipsec4_setspidx_ipaddr(m, spidx) + struct mbuf *m; + struct secpolicyindex *spidx; +{ + struct ip *ip = NULL; + + /* sanity check 1 for minimum ip header length */ + if (m == NULL) + panic("ipsec4_setspidx_in6pcb: m == 0 passed.\n"); + + if (m->m_pkthdr.len < sizeof(struct ip)) { + KEYDEBUG(KEYDEBUG_IPSEC_DUMP, + printf("ipsec4_setspidx_ipaddr: " + "pkthdr.len(%d) < sizeof(struct ip), " + "ignored.\n", + m->m_pkthdr.len)); + return; + } + + if (m->m_len >= sizeof(*ip)) + ip = mtod(m, struct ip *); + else { + struct ip ipbuf; + + m_copydata(m, 0, sizeof(ipbuf), (caddr_t)&ipbuf); + ip = &ipbuf; + } + + bcopy(&ip->ip_src, _INADDRBYSA(&spidx->src), sizeof(ip->ip_src)); + bcopy(&ip->ip_dst, _INADDRBYSA(&spidx->dst), sizeof(ip->ip_dst)); + + return; +} + +#ifdef INET6 +static void +ipsec6_setspidx_in6pcb(m, pcb) + struct mbuf *m; + struct in6pcb *pcb; +{ + struct secpolicyindex *spidx; + + /* sanity check */ + if (pcb == NULL) + panic("ipsec6_setspidx_in6pcb: no PCB found.\n"); + if (pcb->in6p_sp == NULL) + panic("ipsec6_setspidx_in6pcb: no in6p_sp found.\n"); + if (pcb->in6p_sp->sp_out ==NULL || pcb->in6p_sp->sp_in == NULL) + panic("ipsec6_setspidx_in6pcb: no sp_in/out found.\n"); + + bzero(&pcb->in6p_sp->sp_in->spidx, sizeof(*spidx)); + bzero(&pcb->in6p_sp->sp_out->spidx, sizeof(*spidx)); + + spidx = &pcb->in6p_sp->sp_in->spidx; + spidx->dir = IPSEC_DIR_INBOUND; + spidx->src.__ss_len = spidx->dst.__ss_len = _SALENBYAF(AF_INET6); + spidx->src.__ss_family = spidx->dst.__ss_family = AF_INET6; + spidx->prefs = _INALENBYAF(AF_INET6) << 3; + spidx->prefd = _INALENBYAF(AF_INET6) << 3; + spidx->ul_proto = pcb->in6p_socket->so_proto->pr_protocol; + _INPORTBYSA(&spidx->src) = pcb->in6p_fport; + _INPORTBYSA(&spidx->dst) = pcb->in6p_lport; + ipsec6_setspidx_ipaddr(m, spidx); + + spidx = &pcb->in6p_sp->sp_out->spidx; + spidx->dir = IPSEC_DIR_OUTBOUND; + spidx->src.__ss_len = spidx->dst.__ss_len = _SALENBYAF(AF_INET6); + spidx->src.__ss_family = spidx->dst.__ss_family = AF_INET6; + spidx->prefs = _INALENBYAF(AF_INET6) << 3; + spidx->prefd = _INALENBYAF(AF_INET6) << 3; + spidx->ul_proto = pcb->in6p_socket->so_proto->pr_protocol; + _INPORTBYSA(&spidx->src) = pcb->in6p_lport; + _INPORTBYSA(&spidx->dst) = pcb->in6p_fport; + ipsec6_setspidx_ipaddr(m, spidx); + + return; +} + +static void +ipsec6_setspidx_ipaddr(m, spidx) + struct mbuf *m; + struct secpolicyindex *spidx; +{ + struct ip6_hdr *ip6_hdr = NULL; + + /* sanity check 1 for minimum ip header length */ + if (m == NULL) + panic("ipsec6_setspidx_in6pcb: m == 0 passed.\n"); + + if (m->m_pkthdr.len < sizeof(struct ip6_hdr)) { + KEYDEBUG(KEYDEBUG_IPSEC_DUMP, + printf("ipsec6_setspidx_ipaddr: " + "pkthdr.len(%d) < sizeof(struct ip6_hdr), " + "ignored.\n", + m->m_pkthdr.len)); + return; + } + + if (m->m_len >= sizeof(*ip6_hdr)) + ip6_hdr = mtod(m, struct ip6_hdr *); + else { + struct ip6_hdr ip6buf; + + m_copydata(m, 0, sizeof(ip6buf), (caddr_t)&ip6buf); + ip6_hdr = &ip6buf; + } + + if ((ip6_hdr->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) { + KEYDEBUG(KEYDEBUG_IPSEC_DUMP, + printf("ipsec_setspidx_mbuf: " + "wrong ip version on packet " + "(expected IPv6), ignored.\n")); + return; + } + + bcopy(&ip6_hdr->ip6_src, _INADDRBYSA(&spidx->src), + sizeof(ip6_hdr->ip6_src)); + bcopy(&ip6_hdr->ip6_dst, _INADDRBYSA(&spidx->dst), + sizeof(ip6_hdr->ip6_dst)); + + return; +} +#endif + +/* initialize policy in PCB */ +int +ipsec_init_policy(so, pcb_sp) + struct socket *so; + struct inpcbpolicy **pcb_sp; +{ + struct inpcbpolicy *new; + + /* sanity check. */ + if (so == NULL || pcb_sp == NULL) + panic("ipsec_init_policy: NULL pointer was passed.\n"); + + KMALLOC(new, struct inpcbpolicy *, sizeof(*new)); + if (new == NULL) { + printf("ipsec_init_policy: No more memory.\n"); + return ENOBUFS; + } + bzero(new, sizeof(*new)); + + if (so->so_cred != 0 && so->so_cred->cr_uid == 0) + new->priv = 1; + else + new->priv = 0; + + KEYDEBUG(KEYDEBUG_IPSEC_DATA, + printf("init: priv=%d ", new->priv); + if (so->so_cred) + printf("cr_uid=%d\n", so->so_cred->cr_uid); + else + printf("so_cred is NULL\n"); + ); + + if ((new->sp_in = key_newsp()) == NULL) { + KFREE(new); + return ENOBUFS; + } + new->sp_in->state = IPSEC_SPSTATE_ALIVE; + new->sp_in->policy = IPSEC_POLICY_ENTRUST; + + if ((new->sp_out = key_newsp()) == NULL) { + key_freesp(new->sp_in); + KFREE(new); + return ENOBUFS; + } + new->sp_out->state = IPSEC_SPSTATE_ALIVE; + new->sp_out->policy = IPSEC_POLICY_ENTRUST; + + *pcb_sp = new; + + return 0; +} + +/* copy old ipsec policy into new */ +int +ipsec_copy_policy(old, new) + struct inpcbpolicy *old, *new; +{ + struct secpolicy *sp; + + sp = ipsec_deepcopy_policy(old->sp_in); + if (sp) { + key_freesp(new->sp_in); + new->sp_in = sp; + } else + return ENOBUFS; + + sp = ipsec_deepcopy_policy(old->sp_out); + if (sp) { + key_freesp(new->sp_out); + new->sp_out = sp; + } else + return ENOBUFS; + + new->priv = old->priv; + + return 0; +} + +/* 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; + + dst = key_newsp(); + if (src == NULL || 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) { + KMALLOC(*q, struct ipsecrequest *, sizeof(struct ipsecrequest)); + 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; + + 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); + } + + dst->req = newchain; + dst->state = src->state; + dst->policy = src->policy; + /* do not touch the refcnt fields */ + + return dst; + +fail: + for (p = newchain; p; p = r) { + r = p->next; + KFREE(p); + p = NULL; + } + return NULL; +} + +/* set policy and ipsec request if present. */ +static int +ipsec_set_policy(pcb_sp, optname, request, priv) + struct secpolicy **pcb_sp; + int optname; + caddr_t request; + int priv; +{ + struct sadb_x_policy *xpl = (struct sadb_x_policy *)request; + struct secpolicy *newsp = NULL; + + /* sanity check. */ + if (pcb_sp == NULL || *pcb_sp == NULL || xpl == NULL) + return EINVAL; + + 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)) == NULL) + return EINVAL; /* maybe ENOBUFS */ + + newsp->state = IPSEC_SPSTATE_ALIVE; + + /* clear old SP and set new SP */ + key_freesp(*pcb_sp); + *pcb_sp = newsp; + KEYDEBUG(KEYDEBUG_IPSEC_DUMP, + printf("ipsec_set_policy: new policy\n"); + kdebug_secpolicy(newsp)); + + return 0; +} + +static int +ipsec_get_policy(pcb_sp, mp) + struct secpolicy *pcb_sp; + struct mbuf **mp; +{ + struct sadb_x_policy *xpl; + + /* sanity check. */ + if (pcb_sp == NULL || mp == NULL) + return EINVAL; + + if ((xpl = key_sp2msg(pcb_sp)) == NULL) { + printf("ipsec_get_policy: No more memory.\n"); + return ENOBUFS; + } + + *mp = m_get(M_WAIT, MT_DATA); + (*mp)->m_len = PFKEY_EXTLEN(xpl); + m_copyback((*mp), 0, PFKEY_EXTLEN(xpl), (caddr_t)xpl); + KEYDEBUG(KEYDEBUG_IPSEC_DUMP, + printf("ipsec_get_policy:\n"); + kdebug_mbuf(*mp)); + + KFREE(xpl); + + return 0; +} + +int +ipsec4_set_policy(inp, optname, request, priv) + struct inpcb *inp; + int optname; + caddr_t request; + int priv; +{ + struct sadb_x_policy *xpl = (struct sadb_x_policy *)request; + struct secpolicy **pcb_sp; + + /* sanity check. */ + if (inp == NULL || request == NULL) + return EINVAL; + + /* select direction */ + switch (xpl->sadb_x_policy_dir) { + case IPSEC_DIR_INBOUND: + pcb_sp = &inp->inp_sp->sp_in; + break; + case IPSEC_DIR_OUTBOUND: + pcb_sp = &inp->inp_sp->sp_out; + break; + default: + printf("ipsec4_set_policy: invalid direction=%u\n", + xpl->sadb_x_policy_dir); + return EINVAL; + } + + return ipsec_set_policy(pcb_sp, optname, request, priv); +} + +int +ipsec4_get_policy(inp, request, mp) + struct inpcb *inp; + caddr_t request; + struct mbuf **mp; +{ + struct sadb_x_policy *xpl = (struct sadb_x_policy *)request; + struct secpolicy *pcb_sp; + + /* sanity check. */ + if (inp == NULL || request == NULL || mp == NULL) + return EINVAL; + + /* select direction */ + switch (xpl->sadb_x_policy_dir) { + case IPSEC_DIR_INBOUND: + pcb_sp = inp->inp_sp->sp_in; + break; + case IPSEC_DIR_OUTBOUND: + pcb_sp = inp->inp_sp->sp_out; + break; + default: + printf("ipsec6_set_policy: invalid direction=%u\n", + xpl->sadb_x_policy_dir); + return EINVAL; + } + + return ipsec_get_policy(pcb_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.\n"); + + 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; + } + + KFREE(inp->inp_sp); + inp->inp_sp = NULL; + + return 0; +} + +#ifdef INET6 +int +ipsec6_set_policy(in6p, optname, request, priv) + struct in6pcb *in6p; + int optname; + caddr_t request; + int priv; +{ + struct sadb_x_policy *xpl = (struct sadb_x_policy *)request; + struct secpolicy **pcb_sp; + + /* sanity check. */ + if (in6p == NULL || request == NULL) + return EINVAL; + + /* select direction */ + switch (xpl->sadb_x_policy_dir) { + case IPSEC_DIR_INBOUND: + pcb_sp = &in6p->in6p_sp->sp_in; + break; + case IPSEC_DIR_OUTBOUND: + pcb_sp = &in6p->in6p_sp->sp_out; + break; + default: + printf("ipsec6_set_policy: invalid direction=%u\n", + xpl->sadb_x_policy_dir); + return EINVAL; + } + + return ipsec_set_policy(pcb_sp, optname, request, priv); +} + +int +ipsec6_get_policy(in6p, request, mp) + struct in6pcb *in6p; + caddr_t request; + struct mbuf **mp; +{ + struct sadb_x_policy *xpl = (struct sadb_x_policy *)request; + struct secpolicy *pcb_sp; + + /* sanity check. */ + if (in6p == NULL || request == NULL || mp == NULL) + return EINVAL; + + /* select direction */ + switch (xpl->sadb_x_policy_dir) { + case IPSEC_DIR_INBOUND: + pcb_sp = in6p->in6p_sp->sp_in; + break; + case IPSEC_DIR_OUTBOUND: + pcb_sp = in6p->in6p_sp->sp_out; + break; + default: + printf("ipsec6_set_policy: invalid direction=%u\n", + xpl->sadb_x_policy_dir); + return EINVAL; + } + + return ipsec_get_policy(pcb_sp, mp); +} + +int +ipsec6_delete_pcbpolicy(in6p) + struct in6pcb *in6p; +{ + /* sanity check. */ + if (in6p == NULL) + panic("ipsec6_delete_pcbpolicy: NULL pointer was passed.\n"); + + 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; + } + + KFREE(in6p->in6p_sp); + in6p->in6p_sp = NULL; + + return 0; +} +#endif + +/* + * return current level. + * IPSEC_LEVEL_USE or IPSEC_LEVEL_REQUIRE are always returned. + */ +u_int +ipsec_get_reqlevel(isr) + struct ipsecrequest *isr; +{ + 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.\n"); + if (isr->sp->spidx.src.__ss_family != isr->sp->spidx.dst.__ss_family) + panic("ipsec_get_reqlevel: family mismatched.\n"); + +#define IPSEC_CHECK_DEFAULT(lev) \ + (((lev) != IPSEC_LEVEL_USE && (lev) != IPSEC_LEVEL_REQUIRE) \ + ? (printf("fixed system default level " #lev ":%d->%d\n", \ + (lev), IPSEC_LEVEL_USE), \ + (lev) = IPSEC_LEVEL_USE) : (lev)) + + /* set default level */ + switch (isr->sp->spidx.src.__ss_family) { +#ifdef INET + case AF_INET: + esp_trans_deflev = IPSEC_CHECK_DEFAULT(ip4_esp_trans_deflev); + esp_net_deflev = IPSEC_CHECK_DEFAULT(ip4_esp_net_deflev); + ah_trans_deflev = IPSEC_CHECK_DEFAULT(ip4_ah_trans_deflev); + ah_net_deflev = IPSEC_CHECK_DEFAULT(ip4_ah_net_deflev); + break; +#endif +#ifdef INET6 + case AF_INET6: + esp_trans_deflev = IPSEC_CHECK_DEFAULT(ip6_esp_trans_deflev); + esp_net_deflev = IPSEC_CHECK_DEFAULT(ip6_esp_net_deflev); + ah_trans_deflev = IPSEC_CHECK_DEFAULT(ip6_ah_trans_deflev); + ah_net_deflev = IPSEC_CHECK_DEFAULT(ip6_ah_net_deflev); + break; +#endif /* INET6 */ + default: + panic("key_get_reqlevel: Unknown family. %d\n", + isr->sp->spidx.src.__ss_family); + } + +#undef IPSEC_CHECK_DEFAULT(lev) + + /* 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; + 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; + + default: + panic("ipsec_get_reqlevel: Illegal IPsec level %u\n", + 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_hdrsiz: Invalid policy found. %d\n", sp->policy); + } + + need_auth = 0; + need_conf = 0; + need_icv = 0; + + for (isr = sp->req; isr != NULL; isr = isr->next) { + + /* get current level */ + level = ipsec_get_reqlevel(isr); + + 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; + } + } + + 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_so(m, so) + struct mbuf *m; + struct socket *so; +{ + 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 (so == NULL) + sp = ipsec4_getpolicybyaddr(m, IPSEC_DIR_INBOUND, IP_FORWARDING, &error); + else + sp = ipsec4_getpolicybysock(m, IPSEC_DIR_INBOUND, so, &error); + + if (sp == NULL) + return 0; /* XXX should be panic ? + * -> No, there may be error. */ + + result = ipsec_in_reject(sp, m); + KEYDEBUG(KEYDEBUG_IPSEC_STAMP, + printf("DP ipsec4_in_reject_so call free SP:%p\n", sp)); + key_freesp(sp); + + return result; +} + +int +ipsec4_in_reject(m, inp) + struct mbuf *m; + struct inpcb *inp; +{ + if (inp == NULL) + return ipsec4_in_reject_so(m, NULL); + else { + if (inp->inp_socket) + return ipsec4_in_reject_so(m, inp->inp_socket); + else + panic("ipsec4_in_reject: invalid inpcb/socket"); + } +} + +#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_so(m, so) + struct mbuf *m; + struct socket *so; +{ + 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 (so == NULL) + sp = ipsec6_getpolicybyaddr(m, IPSEC_DIR_INBOUND, IP_FORWARDING, &error); + else + sp = ipsec6_getpolicybysock(m, IPSEC_DIR_INBOUND, so, &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_so call free SP:%p\n", sp)); + key_freesp(sp); + + return result; +} + +int +ipsec6_in_reject(m, in6p) + struct mbuf *m; + struct in6pcb *in6p; +{ + if (in6p == NULL) + return ipsec6_in_reject_so(m, NULL); + else { + if (in6p->in6p_socket) + return ipsec6_in_reject_so(m, in6p->in6p_socket); + else + panic("ipsec6_in_reject: invalid in6p/socket"); + } +} +#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_in_reject: 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\n", 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; + } + + if (isr->saidx.mode == IPSEC_MODE_TUNNEL) { + switch (isr->saidx.dst.__ss_family) { + case AF_INET: + clen += sizeof(struct ip); + break; +#ifdef INET6 + case AF_INET6: + clen += sizeof(struct ip6_hdr); + break; +#endif + default: + printf("ipsec_hdrsiz: unknown AF %d " + "in IPsec tunnel SA\n", + isr->saidx.dst.__ss_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 (inp != NULL && inp->inp_socket == NULL) + panic("ipsec4_hdrsize: why is socket NULL but there is PCB."); + + /* 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_getpolicybysock(m, dir, inp->inp_socket, &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 shoud be panic ? */ + if (in6p != NULL && in6p->in6p_socket == NULL) + panic("ipsec6_hdrsize: why is socket NULL but there is PCB."); + + /* 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_getpolicybysock(m, dir, in6p->in6p_socket, &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 (sav->sah->saidx.src.__ss_family != sav->sah->saidx.dst.__ss_family + || sav->sah->saidx.src.__ss_family != AF_INET) { + m_freem(m); + return EINVAL; + } + + ip = mtod(m, struct ip *); +#ifdef _IP_VHL + hlen = _IP_VHL_HL(ip->ip_vhl) << 2; +#else + hlen = ip->ip_hl << 2; +#endif + + /* 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->m_len != hlen) + panic("ipsec4_encapsulate: assumption failed (first mbuf length)"); + 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 { + printf("IPv4 ipsec: size exceeds limit: " + "leave ip_len as is (invalid packet)\n"); + } + ip->ip_id = htons(ip_id++); + 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)); + + /* 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 ip6_hdr *oip6; + struct ip6_hdr *ip6; + size_t plen; + + /* can't tunnel between different AFs */ + if (sav->sah->saidx.src.__ss_family != sav->sah->saidx.dst.__ss_family + || sav->sah->saidx.src.__ss_family != AF_INET6) { + m_freem(m); + return EINVAL; + } + + 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)); + + /* Fake link-local scope-class addresses */ + if (IN6_IS_SCOPE_LINKLOCAL(&oip6->ip6_src)) + oip6->ip6_src.s6_addr16[1] = 0; + if (IN6_IS_SCOPE_LINKLOCAL(&oip6->ip6_dst)) + oip6->ip6_dst.s6_addr16[1] = 0; + + /* 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; + bcopy(&((struct sockaddr_in6 *)&sav->sah->saidx.src)->sin6_addr, + &ip6->ip6_src, sizeof(ip6->ip6_src)); + bcopy(&((struct sockaddr_in6 *)&sav->sah->saidx.dst)->sin6_addr, + &ip6->ip6_dst, sizeof(ip6->ip6_dst)); + + /* 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. + */ +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) + printf("ipsec_chkreplay: NULL pointer was passed.\n"); + + 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; + } +} + +int +ipsec_updatereplay(seq, sav) + u_int32_t seq; + struct secasvar *sav; +{ + 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) + printf("ipsec_chkreplay: NULL pointer was passed.\n"); + + 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 0; + + /* 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 0; + + fr = frlast - diff / 8; + + /* this packet already seen ? */ + if ((replay->bitmap)[fr] & (1 << (diff % 8))) + return 0; + + /* mark as seen */ + (replay->bitmap)[fr] |= (1 << (diff % 8)); + + /* out of order but good */ + } + +ok: + if (replay->count == ~0 + && (sav->flags & SADB_X_EXT_CYCSEQ) == 0) { + return 1; /* don't increment, no more packets accepted */ + } + + replay->count++; + + return 1; +} + +/* + * shift variable length bunffer 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); + + snprintf(buf, sizeof(buf), "packet(SPI=%u ", (u_int32_t)ntohl(spi)); + for (p = buf; p && *p; p++) + ; + snprintf(p, sizeof(buf) - (p - buf), "src=%d.%d.%d.%d", + s[0], s[1], s[2], s[3]); + for (/*nothing*/; p && *p; p++) + ; + snprintf(p, sizeof(buf) - (p - buf), " dst=%d.%d.%d.%d", + d[0], d[1], d[2], d[3]); + for (/*nothing*/; p && *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 *p; + + snprintf(buf, sizeof(buf), "packet(SPI=%u ", (u_int32_t)ntohl(spi)); + for (p = buf; p && *p; p++) + ; + snprintf(p, sizeof(buf) - (p - buf), "src=%s", + ip6_sprintf(&ip6->ip6_src)); + for (/*nothing*/; p && *p; p++) + ; + snprintf(p, sizeof(buf) - (p - buf), " dst=%s", + ip6_sprintf(&ip6->ip6_dst)); + for (/*nothing*/; p && *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 (sav->sah->saidx.src.__ss_family != sav->sah->saidx.dst.__ss_family) + panic("ipsec_logsastr: family mismatched.\n"); + + snprintf(buf, sizeof(buf), "SA(SPI=%u ", (u_int32_t)ntohl(sav->spi)); + for (p = buf; p && *p; p++) + ; + if (saidx->src.__ss_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 (saidx->src.__ss_family == AF_INET6) { + snprintf(p, sizeof(buf) - (p - buf), + "src=%s", + ip6_sprintf(&((struct sockaddr_in6 *)&saidx->src)->sin6_addr)); + for (/*nothing*/; p && *p; p++) + ; + snprintf(p, sizeof(buf) - (p - buf), + " dst=%s", + ip6_sprintf(&((struct sockaddr_in6 *)&saidx->dst)->sin6_addr)); + } +#endif + for (/*nothing*/; p && *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"); +} + +/* + * 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; +#ifdef IPSEC_SRCSEL + struct in_ifaddr *ia; +#endif + 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"); + + ip = mtod(state->m, struct ip *); + + KEYDEBUG(KEYDEBUG_IPSEC_DATA, + printf("ipsec4_output: applyed SP\n"); + kdebug_secpolicy(sp)); + + for (isr = sp->req; isr != NULL; isr = isr->next) { + + if ((error = key_checkrequest(isr)) != 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)) { + case IPSEC_LEVEL_USE: + continue; + case IPSEC_LEVEL_REQUIRE: + /* must be not reached here. */ + panic("ipsec4_output: no SA found, but required."); + } + } + + if (isr->sav->state != SADB_SASTATE_MATURE + && isr->sav->state != SADB_SASTATE_DYING) { + /* If there is no valid SA, we give up to process. */ + 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 (isr->sav->sah->saidx.src.__ss_family != AF_INET) { + printf("ipsec4_output: family mismatched " + "between inner and outer spi=%u\n", + (u_int32_t)ntohl(isr->sav->spi)); + splx(s); + error = EAFNOSUPPORT; + goto bad; + } + + ip = mtod(state->m, struct ip *); + + 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); + bzero((caddr_t)state->ro, sizeof (*state->ro)); + } + 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; + } + +#ifdef IPSEC_SRCSEL + /* + * Which address in SA or in routing table should I + * select from ? But I had set from SA at + * ipsec4_encapsulate(). + */ + ia = (struct in_ifaddr *)(state->ro->ro_rt->rt_ifa); + 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; + } + ip->ip_src = IA_SIN(ia)->sin_addr; +#endif + } 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; + default: + printf("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; +} + +#ifdef INET6 +/* + * 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"); + if (!state->m) + panic("state->m == NULL in ipsec6_output"); + if (!nexthdrp) + panic("nexthdrp == NULL in ipsec6_output"); + if (!mprev) + panic("mprev == NULL in ipsec6_output"); + if (!sp) + panic("sp == NULL in ipsec6_output"); + if (!tun) + panic("tun == NULL in ipsec6_output"); + + 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; + } + + if (key_checkrequest(isr) == 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)) { + case IPSEC_LEVEL_USE: + continue; + case IPSEC_LEVEL_REQUIRE: + /* must be not reached here. */ + panic("ipsec6_output_trans: no SA found, but required."); + } + } + + if (isr->sav->state != SADB_SASTATE_MATURE + && isr->sav->state != SADB_SASTATE_DYING) { + /* If there is no valid SA, we give up to process. */ + 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; + default: + printf("ipsec6_output_trans: unknown ipsec protocol %d\n", isr->saidx.proto); + m_freem(state->m); + error = EINVAL; + break; + } + if (error) { + state->m = NULL; + goto bad; + } + plen = state->m->m_pkthdr.len - sizeof(struct ip6_hdr); + if (plen > IPV6_MAXPACKET) { + printf("ipsec6_output: 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; +#ifdef IPSEC_SRCSEL + struct in6_addr *ia6; +#endif + struct sockaddr_in6* dst6; + int s; + + if (!state) + panic("state == NULL in ipsec6_output"); + if (!state->m) + panic("state->m == NULL in ipsec6_output"); + if (!sp) + panic("sp == NULL in ipsec6_output"); + + 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) { + if (key_checkrequest(isr) == 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)) { + case IPSEC_LEVEL_USE: + continue; + case IPSEC_LEVEL_REQUIRE: + /* must be not reached here. */ + panic("ipsec6_output_tunnel: no SA found, but required."); + } + } + + if (isr->sav->state != SADB_SASTATE_MATURE + && isr->sav->state != SADB_SASTATE_DYING) { + /* If there is no valid SA, we give up to process. */ + 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 (isr->sav->sah->saidx.src.__ss_family != AF_INET6) { + printf("ipsec4_output: family mismatched " + "between inner and outer, spi=%u\n", + (u_int32_t)ntohl(isr->sav->spi)); + printf("ipsec6_output_tunnel: family mismatched " + "between inner and outer, spi=%u\n", + (u_int32_t)ntohl(isr->sav->spi)); + splx(s); + error = EAFNOSUPPORT; + goto bad; + } + + ip6 = mtod(state->m, struct ip6_hdr *); + + state->m = ipsec6_splithdr(state->m); + if (!state->m) { + splx(s); + 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) == 0 + || !IN6_ARE_ADDR_EQUAL(&dst6->sin6_addr, &ip6->ip6_dst))) { + RTFREE(state->ro->ro_rt); + bzero((caddr_t)state->ro, sizeof (*state->ro)); + } + 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++; + error = EHOSTUNREACH; + goto bad; + } +#ifdef IPSEC_SRCSEL + /* + * Which address in SA or in routing table should I + * select from ? But I had set from SA at + * ipsec6_encapsulate(). + */ + ia6 = in6_selectsrc(dst6, NULL, NULL, + (struct route_in6 *)state->ro, + NULL, &error); + if (ia6 == NULL) + goto bad; + ip6->ip6_src = *ia6; +#endif + } else + splx(s); + + state->m = ipsec6_splithdr(state->m); + if (!state->m) { + 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; + default: + printf("ipsec6_output_tunnel: unknown ipsec protocol %d\n", isr->saidx.proto); + m_freem(state->m); + error = EINVAL; + break; + } + if (error) { + state->m = NULL; + goto bad; + } + plen = state->m->m_pkthdr.len - sizeof(struct ip6_hdr); + if (plen > IPV6_MAXPACKET) { + printf("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*/ + +/* + * 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_COPY_PKTHDR(mh, m); + MH_ALIGN(mh, hlen); + m->m_flags &= ~M_PKTHDR; + 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; +} + +#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_COPY_PKTHDR(mh, m); + MH_ALIGN(mh, hlen); + m->m_flags &= ~M_PKTHDR; + 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(ip, nxt0, sav) + struct ip *ip; + u_int nxt0; + struct secasvar *sav; +{ + u_int8_t nxt = nxt0 & 0xff; + struct sockaddr_in *sin; + int hlen; + + if (nxt != IPPROTO_IPV4) + return 0; +#ifdef _IP_VHL + hlen = _IP_VHL_HL(ip->ip_vhl) << 2; +#else + hlen = ip->ip_hl << 2; +#endif + if (hlen != sizeof(struct ip)) + return 0; + switch (sav->sah->saidx.dst.__ss_family) { + case AF_INET: + sin = (struct sockaddr_in *)&sav->sah->saidx.dst; + if (bcmp(&ip->ip_dst, &sin->sin_addr, sizeof(ip->ip_dst)) != 0) + return 0; + break; +#ifdef INET6 + case AF_INET6: + /* should be supported, but at this moment we don't. */ + /*FALLTHROUGH*/ +#endif + default: + return 0; + } + + return 1; +} + +#ifdef INET6 +/* validate inbound IPsec tunnel packet. */ +int +ipsec6_tunnel_validate(ip6, nxt0, sav) + struct ip6_hdr *ip6; + u_int nxt0; + struct secasvar *sav; +{ + u_int8_t nxt = nxt0 & 0xff; + struct sockaddr_in6 *sin6; + + if (nxt != IPPROTO_IPV6) + return 0; + switch (sav->sah->saidx.dst.__ss_family) { + case AF_INET6: + sin6 = ((struct sockaddr_in6 *)&sav->sah->saidx.dst); + if (!IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &sin6->sin6_addr)) + return 0; + break; + case AF_INET: + /* should be supported, but at this moment we don't. */ + /*FALLTHROUGH*/ + default: + return 0; + } + + 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 are more than one references + * to the cluster. + * XXX: is this approach effective? + */ + if ( + n->m_ext.ext_free || + mclrefcnt[mtocl(n->m_ext.ext_buf)] > 1 + ) + { + int remain, copied; + struct mbuf *mm; + + if (n->m_flags & M_PKTHDR) { + MGETHDR(mnew, M_DONTWAIT, MT_HEADER); + if (mnew == NULL) + goto fail; + mnew->m_pkthdr = n->m_pkthdr; + mnew->m_flags = n->m_flags & M_COPYFLAGS; + } + 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; + 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); +} diff --git a/sys/netinet6/ipsec.h b/sys/netinet6/ipsec.h index 6fdcba1..ede791b 100644 --- a/sys/netinet6/ipsec.h +++ b/sys/netinet6/ipsec.h @@ -238,6 +238,11 @@ struct ipsecstat { } #ifdef KERNEL + +#ifdef SYSCTL_DECL +SYSCTL_DECL(_net_inet_ipsec); +#endif + struct ipsec_output_state { struct mbuf *m; struct route *ro; @@ -303,6 +308,7 @@ extern struct mbuf *ipsec_copypkt __P((struct mbuf *)); #endif /*KERNEL*/ #ifndef KERNEL + extern caddr_t ipsec_set_policy __P((char *policy, int buflen)); extern int ipsec_get_policylen __P((caddr_t buf)); extern char *ipsec_dump_policy __P((caddr_t buf, char *delimiter)); diff --git a/sys/netinet6/ipsec6.h b/sys/netinet6/ipsec6.h index 61896b3..c4e9924 100644 --- a/sys/netinet6/ipsec6.h +++ b/sys/netinet6/ipsec6.h @@ -38,6 +38,10 @@ #ifdef KERNEL +#ifdef SYSCTL_DECL +SYSCTL_DECL(_net_inet6_ipsec6); +#endif + extern struct ipsecstat ipsec6stat; extern struct secpolicy ip6_def_policy; extern int ip6_esp_trans_deflev; diff --git a/sys/netinet6/mld6.c b/sys/netinet6/mld6.c index 634f61b..f09b38a 100644 --- a/sys/netinet6/mld6.c +++ b/sys/netinet6/mld6.c @@ -68,6 +68,8 @@ * @(#)igmp.c 8.1 (Berkeley) 7/19/93 */ +#include "opt_ipsec.h" + #include <sys/param.h> #include <sys/systm.h> #include <sys/mbuf.h> @@ -391,10 +393,6 @@ mld6_sendpkt(in6m, type, dst) return; } mh->m_next = md; - -#ifdef IPSEC - mh->m_pkthdr.rcvif = NULL; -#endif mh->m_pkthdr.len = sizeof(struct ip6_hdr) + sizeof(struct mld6_hdr); mh->m_len = sizeof(struct ip6_hdr); MH_ALIGN(mh, sizeof(struct ip6_hdr)); diff --git a/sys/netinet6/nd6_nbr.c b/sys/netinet6/nd6_nbr.c index 840f074..9c16e1e 100644 --- a/sys/netinet6/nd6_nbr.c +++ b/sys/netinet6/nd6_nbr.c @@ -29,6 +29,8 @@ * $FreeBSD$ */ +#include "opt_ipsec.h" + #include <sys/param.h> #include <sys/systm.h> #include <sys/malloc.h> @@ -423,9 +425,6 @@ nd6_ns_output(ifp, daddr6, taddr6, ln, dad) nd_ns->nd_ns_cksum = in6_cksum(m, IPPROTO_ICMPV6, sizeof(*ip6), icmp6len); -#ifdef IPSEC - m->m_pkthdr.rcvif = NULL; -#endif /*IPSEC*/ ip6_output(m, NULL, NULL, dad ? IPV6_DADOUTPUT : 0, &im6o, &outif); if (outif) { icmp6_ifstat_inc(outif, ifs6_out_msg); diff --git a/sys/netinet6/raw_ip6.c b/sys/netinet6/raw_ip6.c index 3131e41..9027663 100644 --- a/sys/netinet6/raw_ip6.c +++ b/sys/netinet6/raw_ip6.c @@ -64,6 +64,8 @@ * @(#)raw_ip.c 8.2 (Berkeley) 1/4/94 */ +#include "opt_ipsec.h" + #include <stddef.h> #include <sys/param.h> @@ -140,7 +142,7 @@ rip6_input(mp, offp, proto) init_sin6(&rip6src, m); /* general init */ LIST_FOREACH(in6p, &ripcb, inp_list) { - if ((in6p->in6p_vflag & INP_IPV6) == NULL) + if ((in6p->in6p_vflag & INP_IPV6) == 0) continue; if (in6p->in6p_ip6_nxt && in6p->in6p_ip6_nxt != proto) @@ -328,9 +330,10 @@ rip6_output(m, va_alist) if (in6p->in6p_route.ro_rt) oifp = ifindex2ifnet[in6p->in6p_route.ro_rt->rt_ifp->if_index]; } - - ip6->ip6_flow = in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK; - ip6->ip6_vfc = IPV6_VERSION; + ip6->ip6_flow = (ip6->ip6_flow & ~IPV6_FLOWINFO_MASK) | + (in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK); + ip6->ip6_vfc = (ip6->ip6_vfc & ~IPV6_VERSION_MASK) | + (IPV6_VERSION & IPV6_VERSION_MASK); /* ip6_plen will be filled in ip6_output, so not fill it here. */ ip6->ip6_nxt = in6p->in6p_ip6_nxt; ip6->ip6_hlim = in6_selecthlim(in6p, oifp); @@ -370,8 +373,8 @@ rip6_output(m, va_alist) m->m_pkthdr.rcvif = (struct ifnet *)so; #endif /*IPSEC*/ - error = ip6_output(m, optp, &in6p->in6p_route, 0, in6p->in6p_moptions, - &oifp); + error = ip6_output(m, optp, &in6p->in6p_route, IPV6_SOCKINMRCVIF, + in6p->in6p_moptions, &oifp); if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) { if (oifp) icmp6_ifoutstat_inc(oifp, type, code); @@ -446,11 +449,9 @@ rip6_attach(struct socket *so, int proto, struct proc *p) if (p && (error = suser(p)) != 0) return error; - if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { - error = soreserve(so, rip_sendspace, rip_recvspace); - if (error) - return error; - } + error = soreserve(so, rip_sendspace, rip_recvspace); + if (error) + return error; s = splnet(); error = in_pcballoc(so, &ripcbinfo, p); splx(s); diff --git a/sys/netinet6/udp6_usrreq.c b/sys/netinet6/udp6_usrreq.c index 137c3ee..936bac9 100644 --- a/sys/netinet6/udp6_usrreq.c +++ b/sys/netinet6/udp6_usrreq.c @@ -63,6 +63,8 @@ * $FreeBSD$ */ +#include "opt_ipsec.h" + #include <sys/param.h> #include <sys/kernel.h> #include <sys/malloc.h> @@ -98,6 +100,7 @@ #ifdef IPSEC #include <netinet6/ipsec.h> +#include <netinet6/ipsec6.h> #endif /*IPSEC*/ #include "faith.h" @@ -251,11 +254,10 @@ udp6_input(mp, offp, proto) /* * Check AH/ESP integrity. */ - if (last != NULL && - ipsec6_in_reject_so(m, last->inp_socket)) { + if (ipsec6_in_reject_so(m, last->inp_socket)) ipsec6stat.in_polvio++; /* do not inject data into pcb */ - } else + else #endif /*IPSEC*/ if ((n = m_copy(m, 0, M_COPYALL)) != NULL) { /* @@ -310,7 +312,7 @@ udp6_input(mp, offp, proto) /* * Check AH/ESP integrity. */ - if (last != NULL && ipsec6_in_reject_so(m, last->inp_socket)) { + if (ipsec6_in_reject_so(m, last->inp_socket)) { ipsec6stat.in_polvio++; goto bad; } @@ -358,7 +360,7 @@ udp6_input(mp, offp, proto) /* * Check AH/ESP integrity. */ - if (in6p != NULL && ipsec6_in_reject_so(m, in6p->in6p_socket)) { + if (ipsec6_in_reject_so(m, in6p->in6p_socket)) { ipsec6stat.in_polvio++; goto bad; } @@ -475,7 +477,7 @@ udp6_getcred SYSCTL_HANDLER_ARGS addrs[1].sin6_port, &addrs[0].sin6_addr, addrs[0].sin6_port, 1, NULL); - if (!inp || !inp->inp_socket || !inp->inp_socket->so_cred) { + if (!inp || !inp->inp_socket) { error = ENOENT; goto out; } @@ -556,8 +558,10 @@ udp6_output(in6p, m, addr6, control, p) * Stuff checksum and output datagram. */ ip6 = mtod(m, struct ip6_hdr *); - ip6->ip6_flow = in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK; - ip6->ip6_vfc = IPV6_VERSION; + ip6->ip6_flow = (ip6->ip6_flow & ~IPV6_FLOWINFO_MASK) | + (in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK); + ip6->ip6_vfc = (ip6->ip6_vfc & ~IPV6_VERSION_MASK) | + (IPV6_VERSION & IPV6_VERSION_MASK); /* ip6_plen will be filled in ip6_output. */ ip6->ip6_nxt = IPPROTO_UDP; ip6->ip6_hlim = in6_selecthlim(in6p, @@ -584,7 +588,7 @@ udp6_output(in6p, m, addr6, control, p) m->m_pkthdr.rcvif = (struct ifnet *)in6p->in6p_socket; #endif /*IPSEC*/ error = ip6_output(m, in6p->in6p_outputopts, &in6p->in6p_route, - 0, in6p->in6p_moptions, NULL); + IPV6_SOCKINMRCVIF, in6p->in6p_moptions, NULL); if (addr6) { in6_pcbdisconnect(in6p); diff --git a/sys/netkey/key.c b/sys/netkey/key.c index 0116b2a..d9ec961 100644 --- a/sys/netkey/key.c +++ b/sys/netkey/key.c @@ -1,2558 +1,5316 @@ /* - * modified by Jun-ichiro itojun Itoh <itojun@itojun.org>, 1997 - */ -/*---------------------------------------------------------------------- - key.c : Key Management Engine for BSD - - Copyright 1995 by Bao Phan, Randall Atkinson, & Dan McDonald, - All Rights Reserved. All Rights have been assigned to the US - Naval Research Laboratory (NRL). The NRL Copyright Notice and - License governs distribution and use of this software. - - Patents are pending on this technology. NRL grants a license - to use this technology at no cost under the terms below with - the additional requirement that software, hardware, and - documentation relating to use of this technology must include - the note that: - This product includes technology developed at and - licensed from the Information Technology Division, - US Naval Research Laboratory. - -----------------------------------------------------------------------*/ -/*---------------------------------------------------------------------- -# @(#)COPYRIGHT 1.1a (NRL) 17 August 1995 - -COPYRIGHT NOTICE - -All of the documentation and software included in this software -distribution from the US Naval Research Laboratory (NRL) are -copyrighted by their respective developers. - -This software and documentation were developed at NRL by various -people. Those developers have each copyrighted the portions that they -developed at NRL and have assigned All Rights for those portions to -NRL. Outside the USA, NRL also has copyright on the software -developed at NRL. The affected files all contain specific copyright -notices and those notices must be retained in any derived work. - -NRL LICENSE - -NRL grants permission for redistribution and use in source and binary -forms, with or without modification, of the software and documentation -created at NRL 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. All advertising materials mentioning features or use of this software - must display the following acknowledgement: - - This product includes software developed at the Information - Technology Division, US Naval Research Laboratory. - -4. Neither the name of the NRL nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - -THE SOFTWARE PROVIDED BY NRL IS PROVIDED BY NRL 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 NRL 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. - -The views and conclusions contained in the software and documentation -are those of the authors and should not be interpreted as representing -official policies, either expressed or implied, of the US Naval -Research Laboratory (NRL). - -----------------------------------------------------------------------*/ - -#include "opt_key.h" - -#ifdef KEY + * 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. + * + * $FreeBSD$ + */ + +/* KAME $Id: key.c,v 1.1.6.5.2.19 1999/07/22 14:09:24 itojun Exp $ */ + +/* + * This code is referd to RFC 2367 + */ +#include "opt_inet.h" +#include "opt_inet6.h" +#include "opt_ipsec.h" + +#include <sys/types.h> #include <sys/param.h> #include <sys/systm.h> #include <sys/kernel.h> -#include <sys/domain.h> -#include <sys/malloc.h> #include <sys/mbuf.h> -#include <sys/proc.h> +#include <sys/domain.h> #include <sys/protosw.h> +#include <sys/malloc.h> #include <sys/socket.h> #include <sys/socketvar.h> +#include <sys/sysctl.h> +#include <sys/errno.h> +#include <sys/proc.h> +#include <sys/queue.h> -#include <net/raw_cb.h> #include <net/if.h> -#include <net/if_dl.h> #include <net/route.h> +#include <net/raw_cb.h> #include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> #include <netinet/in_var.h> #include <netinet/in_pcb.h> #ifdef INET6 -#include <netinet6/in6.h> +#include <netinet6/ip6.h> #include <netinet6/in6_var.h> +#include <netinet6/in6_pcb.h> #endif /* INET6 */ +#include <net/pfkeyv2.h> +#include <netkey/key_var.h> +#include <netkey/keydb.h> #include <netkey/key.h> +#include <netkey/keysock.h> +#ifdef IPSEC_DEBUG #include <netkey/key_debug.h> +#else +#define KEYDEBUG(lev,arg) +#endif -static MALLOC_DEFINE(M_SECA, "key mgmt", "security associations, key management"); +#include <netinet6/ipsec.h> +#include <netinet6/ah.h> +#ifdef INET6 +#include <netinet6/ipsec6.h> +#include <netinet6/ah6.h> +#endif +#ifdef IPSEC_ESP +#include <netinet6/esp.h> +#ifdef INET6 +#include <netinet6/esp6.h> +#endif +#endif + +MALLOC_DEFINE(M_SECA, "key mgmt", "security associations, key management"); + +#if defined(IPSEC_DEBUG) +u_int32_t key_debug_level = 0; +#endif /* defined(IPSEC_DEBUG) */ +static u_int key_spi_trycnt = 1000; +static u_int32_t key_spi_minval = 0x100; +static u_int32_t key_spi_maxval = 0x0fffffff; /* XXX */ +static u_int key_int_random = 60; /*interval to initialize randseed,1(m)*/ +static u_int key_larval_lifetime = 30; /* interval to expire acquiring, 30(s)*/ +static int key_blockacq_count = 10; /* counter for blocking SADB_ACQUIRE.*/ +static int key_blockacq_lifetime = 20; /* lifetime for blocking SADB_ACQUIRE.*/ + +static u_int32_t acq_seq = 0; +static int key_tick_init_random = 0; + +static LIST_HEAD(_sptree, secpolicy) sptree[IPSEC_DIR_MAX]; /* SPD */ +static LIST_HEAD(_sahtree, secashead) sahtree; /* SAD */ +static LIST_HEAD(_regtree, secreg) regtree[SADB_SATYPE_MAX + 1]; + /* registed list */ +#ifndef IPSEC_NONBLOCK_ACQUIRE +static LIST_HEAD(_acqtree, secacq) acqtree; /* acquiring list */ +#endif -#define KMALLOC(p, t, n) (p = (t) malloc((unsigned long)(n), M_SECA, M_DONTWAIT)) -#define KFREE(p) free((caddr_t)p, M_SECA); +struct key_cb key_cb; -#define CRITICAL_DCL int critical_s; -#define CRITICAL_START critical_s = splnet() -#define CRITICAL_END splx(critical_s) +/* search order for SAs */ +static u_int saorder_state_valid[] = { + SADB_SASTATE_MATURE, SADB_SASTATE_DYING +}; +static u_int saorder_state_alive[] = { + /* except DEAD */ + SADB_SASTATE_MATURE, SADB_SASTATE_DYING, SADB_SASTATE_LARVAL +}; +static u_int saorder_state_any[] = { + SADB_SASTATE_MATURE, SADB_SASTATE_DYING, + SADB_SASTATE_LARVAL, SADB_SASTATE_DEAD +}; +#if defined(IPSEC_DEBUG) +SYSCTL_INT(_net_key, KEYCTL_DEBUG_LEVEL, debug, CTLFLAG_RW, \ + &key_debug_level, 0, ""); +#endif /* defined(IPSEC_DEBUG) */ + +/* max count of trial for the decision of spi value */ +SYSCTL_INT(_net_key, KEYCTL_SPI_TRY, spi_trycnt, CTLFLAG_RW, \ + &key_spi_trycnt, 0, ""); + +/* minimum spi value to allocate automatically. */ +SYSCTL_INT(_net_key, KEYCTL_SPI_MIN_VALUE, spi_minval, CTLFLAG_RW, \ + &key_spi_minval, 0, ""); + +/* maximun spi value to allocate automatically. */ +SYSCTL_INT(_net_key, KEYCTL_SPI_MAX_VALUE, spi_maxval, CTLFLAG_RW, \ + &key_spi_maxval, 0, ""); + +/* interval to initialize randseed */ +SYSCTL_INT(_net_key, KEYCTL_RANDOM_INT, int_random, CTLFLAG_RW, \ + &key_int_random, 0, ""); + +/* lifetime for larval SA */ +SYSCTL_INT(_net_key, KEYCTL_LARVAL_LIFETIME, larval_lifetime, CTLFLAG_RW, \ + &key_larval_lifetime, 0, ""); + +/* counter for blocking to send SADB_ACQUIRE to IKEd */ +SYSCTL_INT(_net_key, KEYCTL_BLOCKACQ_COUNT, blockacq_count, CTLFLAG_RW, \ + &key_blockacq_count, 0, ""); + +/* lifetime for blocking to send SADB_ACQUIRE to IKEd */ +SYSCTL_INT(_net_key, KEYCTL_BLOCKACQ_LIFETIME, blockacq_lifetime, CTLFLAG_RW, \ + &key_blockacq_lifetime, 0, ""); + +#define __LIST_FOREACH(elm, head, field) \ + for (elm = LIST_FIRST(head); elm; elm = LIST_NEXT(elm, field)) +#define __LIST_CHAINED(elm) \ + (!((elm)->chain.le_next == NULL && (elm)->chain.le_prev == NULL)) + +#define KEY_CHKSASTATE(head, sav, name) { \ + if ((head) != (sav)) { \ + printf("%s: state mismatched (TREE=%d SA=%d)\n", \ + (name), (head), (sav)); \ + continue; \ + } \ +} + +#define KEY_CHKSPDIR(head, sp, name) { \ + if ((head) != (sp)) { \ + printf("%s: direction mismatched (TREE=%d SP=%d), " \ + "anyway continue.\n", \ + (name), (head), (sp)); \ + } \ +} + +#define KMALLOC(p, t, n) \ + ((p) = (t) malloc((unsigned long)(n), M_SECA, M_NOWAIT)) +#define KFREE(p) \ + free((caddr_t)(p), M_SECA); + +#define KEY_NEWBUF(dst, t, src, len) \ + ((dst) = (t)key_newbuf((src), (len))) + +/* + * set parameters into secpolicyindex buffer. + * Must allocate secpolicyindex buffer passed to this function. + */ +#define KEY_SETSECSPIDX(_dir, s, d, ps, pd, ulp, idx) do { \ + bzero((idx), sizeof(struct secpolicyindex)); \ + (idx)->dir = (_dir); \ + (idx)->prefs = (ps); \ + (idx)->prefd = (pd); \ + (idx)->ul_proto = (ulp); \ + bcopy((s), &(idx)->src, ((struct sockaddr *)(s))->sa_len); \ + bcopy((d), &(idx)->dst, ((struct sockaddr *)(d))->sa_len); \ +} while (0) + +/* + * set parameters into secasindex buffer. + * Must allocate secasindex buffer before calling this function. + */ +#define KEY_SETSECASIDX(p, m, s, d, idx) do { \ + bzero((idx), sizeof(struct secasindex)); \ + (idx)->proto = (p); \ + (idx)->mode = (m); \ + bcopy((s), &(idx)->src, ((struct sockaddr *)(s))->sa_len); \ + bcopy((d), &(idx)->dst, ((struct sockaddr *)(d))->sa_len); \ +} while (0) + +/* key statistics */ +struct _keystat { + u_long getspi_count; /* the avarage of count to try to get new SPI */ +} keystat; + +static struct secasvar *key_allocsa_policy __P((struct ipsecrequest *isr)); +static void key_freesp_so __P((struct secpolicy **sp)); +static struct secasvar *key_do_allocsa_policy __P((struct secashead *sah, + u_int state)); +static void key_delsp __P((struct secpolicy *sp)); +static struct secpolicy *key_getsp __P((struct secpolicyindex *spidx)); +static struct sadb_msg *key_spdadd __P((caddr_t *mhp)); +static struct sadb_msg *key_spddelete __P((caddr_t *mhp)); +static struct sadb_msg *key_spdflush __P((caddr_t *mhp)); +static int key_spddump __P((caddr_t *mhp, struct socket *so, int target)); +static u_int key_setdumpsp __P((struct sadb_msg *newmsg, struct secpolicy *sp, + u_int8_t type, u_int32_t seq, u_int32_t pid)); +static u_int key_getspmsglen __P((struct secpolicy *sp)); +static u_int key_getspreqmsglen __P((struct secpolicy *sp)); +static struct secashead *key_newsah __P((struct secasindex *saidx)); +static void key_delsah __P((struct secashead *sah)); +static struct secasvar *key_newsav __P((caddr_t *mhp, struct secashead *sah)); +static void key_delsav __P((struct secasvar *sav)); +static struct secashead *key_getsah __P((struct secasindex *saidx)); +static struct secasvar *key_checkspidup __P((struct secasindex *saidx, + u_int32_t spi)); +static struct secasvar *key_getsavbyspi __P((struct secashead *sah, + u_int32_t spi)); +static int key_setsaval __P((struct secasvar *sav, caddr_t *mhp)); +static u_int key_getmsglen __P((struct secasvar *sav)); +static int key_mature __P((struct secasvar *sav)); +static u_int key_setdumpsa __P((struct sadb_msg *newmsg, struct secasvar *sav, + u_int8_t type, u_int8_t satype, + u_int32_t seq, u_int32_t pid)); +static caddr_t key_setsadbmsg __P((caddr_t buf, u_int8_t type, int tlen, + u_int8_t satype, u_int32_t seq, pid_t pid, + u_int8_t reserved1, u_int8_t reserved2)); +static caddr_t key_setsadbsa __P((caddr_t buf, struct secasvar *sav)); +static caddr_t key_setsadbaddr __P((caddr_t buf, u_int16_t exttype, + struct sockaddr *saddr, u_int8_t prefixlen, u_int16_t ul_proto)); +static caddr_t key_setsadbident + __P((caddr_t buf, u_int16_t exttype, u_int16_t idtype, + caddr_t string, int stringlen, u_int64_t id)); +static caddr_t key_setsadbext __P((caddr_t p, caddr_t ext)); +static void *key_newbuf __P((void *src, u_int len)); #ifdef INET6 -#define MAXHASHKEYLEN (2 * sizeof(int) + 2 * sizeof(struct sockaddr_in6)) -#else -#define MAXHASHKEYLEN (2 * sizeof(int) + 2 * sizeof(struct sockaddr_in)) +static int key_ismyaddr6 __P((caddr_t addr)); #endif +static int key_cmpsaidx_exactly + __P((struct secasindex *saidx0, struct secasindex *saidx1)); +static int key_cmpsaidx_withmode + __P((struct secasindex *saidx0, struct secasindex *saidx1)); +static int key_cmpspidx_exactly + __P((struct secpolicyindex *spidx0, struct secpolicyindex *spidx1)); +static int key_cmpspidx_withmask + __P((struct secpolicyindex *spidx0, struct secpolicyindex *spidx1)); +static int key_bbcmp __P((caddr_t p1, caddr_t p2, u_int bits)); +static u_int16_t key_satype2proto __P((u_int8_t satype)); +static u_int8_t key_proto2satype __P((u_int16_t proto)); + +static struct sadb_msg *key_getspi __P((caddr_t *mhp)); +static u_int32_t key_do_getnewspi __P((struct sadb_spirange *spirange, + struct secasindex *saidx)); +static struct sadb_msg *key_update __P((caddr_t *mhp)); +static struct secasvar *key_getsavbyseq __P((struct secashead *sah, + u_int32_t seq)); +static struct sadb_msg *key_add __P((caddr_t *mhp)); +static struct sadb_msg *key_getmsgbuf_x1 __P((caddr_t *mhp)); +static struct sadb_msg *key_delete __P((caddr_t *mhp)); +static struct sadb_msg *key_get __P((caddr_t *mhp)); +static int key_acquire __P((struct secasindex *saidx, + struct secpolicyindex *spidx)); +static struct secacq *key_newacq __P((struct secasindex *saidx)); +static struct secacq *key_getacq __P((struct secasindex *saidx)); +static struct secacq *key_getacqbyseq __P((u_int32_t seq)); +static struct sadb_msg *key_acquire2 __P((caddr_t *mhp)); +static struct sadb_msg *key_register __P((caddr_t *mhp, struct socket *so)); +static int key_expire __P((struct secasvar *sav)); +static struct sadb_msg *key_flush __P((caddr_t *mhp)); +static int key_dump __P((caddr_t *mhp, struct socket *so, int target)); +static void key_promisc __P((caddr_t *mhp, struct socket *so)); +static int key_sendall __P((struct sadb_msg *msg, u_int len)); +static int key_align __P((struct sadb_msg *msg, caddr_t *mhp)); +static void key_sa_chgstate __P((struct secasvar *sav, u_int8_t state)); +/* %%% IPsec policy management */ +/* + * allocating a SP for OUTBOUND or INBOUND packet. + * Must call key_freesp() later. + * OUT: NULL: not found + * others: found and return the pointer. + */ +struct secpolicy * +key_allocsp(spidx, dir) + struct secpolicyindex *spidx; + u_int dir; +{ + struct secpolicy *sp; + int s; + + /* sanity check */ + if (spidx == NULL) + panic("key_allocsp: NULL pointer is passed.\n"); + + /* check direction */ + switch (dir) { + case IPSEC_DIR_INBOUND: + case IPSEC_DIR_OUTBOUND: + break; + default: + panic("key_allocsp: Invalid direction is passed.\n"); + } + + /* get a SP entry */ + s = splnet(); /*called from softclock()*/ + KEYDEBUG(KEYDEBUG_IPSEC_DATA, + printf("*** objects\n"); + kdebug_secpolicyindex(spidx)); + + __LIST_FOREACH(sp, &sptree[dir], chain) { + KEYDEBUG(KEYDEBUG_IPSEC_DATA, + printf("*** in SPD\n"); + kdebug_secpolicyindex(&sp->spidx)); + + if (sp->state == IPSEC_SPSTATE_DEAD) + continue; + if (key_cmpspidx_withmask(&sp->spidx, spidx)) + goto found; + } + + splx(s); + return NULL; + +found: + /* sanity check */ + KEY_CHKSPDIR(sp->spidx.dir, dir, "key_allocsp"); + + /* found a SPD entry */ + sp->refcnt++; + splx(s); + KEYDEBUG(KEYDEBUG_IPSEC_STAMP, + printf("DP key_allocsp cause refcnt++:%d SP:%p\n", + sp->refcnt, sp)); + + return sp; +} /* - * Not clear whether these values should be - * tweakable at kernel config time. - */ -#define KEYTBLSIZE 61 -#define KEYALLOCTBLSIZE 61 -#define SO2SPITBLSIZE 61 - -/* - * These values should be tweakable... - * perhaps by using sysctl - */ - -#define MAXLARVALTIME 240; /* Lifetime of a larval key table entry */ -#define MAXKEYACQUIRE 1; /* Max number of key acquire messages sent */ - /* per destination address */ -#define MAXACQUIRETIME 15; /* Lifetime of acquire message */ - -/* - * Key engine tables and global variables - */ - -struct key_tblnode keytable[KEYTBLSIZE]; -struct key_allocnode keyalloctbl[KEYALLOCTBLSIZE]; -struct key_so2spinode so2spitbl[SO2SPITBLSIZE]; - -struct keyso_cb keyso_cb; -struct key_tblnode nullkeynode; -struct key_registry *keyregtable; -struct key_acquirelist *key_acquirelist; -u_long maxlarvallifetime = MAXLARVALTIME; -int maxkeyacquire = MAXKEYACQUIRE; -u_long maxacquiretime = MAXACQUIRETIME; - -extern struct sockaddr key_addr; - -#define ROUNDUP(a) \ - ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) -#define ADVANCE(x, n) \ - { x += ROUNDUP(n); } - -static int addrpart_equal __P((struct sockaddr *, struct sockaddr *)); -static int key_gethashval __P((char *, int, int)); -static int key_createkey __P((char *, u_int, struct sockaddr *, - struct sockaddr *, u_int32_t, u_int)); -static struct key_so2spinode *key_sosearch __P((u_int, struct sockaddr *, - struct sockaddr *, struct socket *)); -static void key_deleteacquire __P((u_int, struct sockaddr *)); -static struct key_tblnode *key_search __P((u_int, struct sockaddr *, - struct sockaddr *, u_int32_t, int, struct key_tblnode **)); -static struct key_tblnode *key_addnode __P((int, struct key_secassoc *)); -static int key_alloc __P((u_int, struct sockaddr *, struct sockaddr *, - struct socket *, u_int, struct key_tblnode **)); -static int key_xdata __P((struct key_msghdr *, struct key_msgdata *, int)); -static int key_sendup __P((struct socket *, struct key_msghdr *)); -static void key_init __P((void)); -static int my_addr __P((struct sockaddr *)); -static int key_output __P((struct mbuf *, struct socket *)); -static int key_attach __P((struct socket *, int, struct proc *)); -static int key_detach __P((struct socket *)); -static void key_cbinit __P((void)); - -/*---------------------------------------------------------------------- - * key_secassoc2msghdr(): - * Copy info from a security association into a key message buffer. - * Assume message buffer is sufficiently large to hold all security - * association information including src, dst, from, key and iv. - ----------------------------------------------------------------------*/ + * checking each request entries in SP, and acquire SA if need. + * OUT: 0: there are valid requests. + * ENOENT: policy may be valid, but SA with REQUIRE is on acquiring. + */ int -key_secassoc2msghdr(secassoc, km, keyinfo) - struct key_secassoc *secassoc; - struct key_msghdr *km; - struct key_msgdata *keyinfo; -{ - char *cp; - DPRINTF(IDL_FINISHED, ("Entering key_secassoc2msghdr\n")); - - if ((km == 0) || (keyinfo == 0) || (secassoc == 0)) - return(-1); - - km->type = secassoc->type; - km->vers = secassoc->vers; - km->state = secassoc->state; - km->label = secassoc->label; - km->spi = secassoc->spi; - km->keylen = secassoc->keylen; - km->ekeylen = secassoc->ekeylen; - km->ivlen = secassoc->ivlen; - km->algorithm = secassoc->algorithm; - km->lifetype = secassoc->lifetype; - km->lifetime1 = secassoc->lifetime1; - km->lifetime2 = secassoc->lifetime2; - km->antireplay = secassoc->antireplay; - - /* - * Stuff src/dst/from/key/iv/ekey in buffer after - * the message header. - */ - cp = (char *)(km + 1); - - DPRINTF(IDL_FINISHED, ("sa2msghdr: 1\n")); - keyinfo->src = (struct sockaddr *)cp; - if (secassoc->src->sa_len) { - bcopy(secassoc->src, cp, secassoc->src->sa_len); - ADVANCE(cp, secassoc->src->sa_len); - } else { - bzero(cp, MAX_SOCKADDR_SZ); - ADVANCE(cp, MAX_SOCKADDR_SZ); - } - - DPRINTF(IDL_FINISHED, ("sa2msghdr: 2\n")); - keyinfo->dst = (struct sockaddr *)cp; - if (secassoc->dst->sa_len) { - bcopy(secassoc->dst, cp, secassoc->dst->sa_len); - ADVANCE(cp, secassoc->dst->sa_len); - } else { - bzero(cp, MAX_SOCKADDR_SZ); - ADVANCE(cp, MAX_SOCKADDR_SZ); - } +key_checkrequest(isr) + struct ipsecrequest *isr; +{ + u_int level; + int error; + + /* sanity check */ + if (isr == NULL) + panic("key_checkrequest: NULL pointer is passed.\n"); + + /* check mode */ + switch (isr->saidx.mode) { + case IPSEC_MODE_TRANSPORT: + case IPSEC_MODE_TUNNEL: + break; + case IPSEC_MODE_ANY: + default: + panic("key_checkrequest: Invalid policy defined.\n"); + } - DPRINTF(IDL_FINISHED, ("sa2msghdr: 3\n")); - keyinfo->from = (struct sockaddr *)cp; - if (secassoc->from->sa_len) { - bcopy(secassoc->from, cp, secassoc->from->sa_len); - ADVANCE(cp, secassoc->from->sa_len); - } else { - bzero(cp, MAX_SOCKADDR_SZ); - ADVANCE(cp, MAX_SOCKADDR_SZ); - } + /* get current level */ + level = ipsec_get_reqlevel(isr); - DPRINTF(IDL_FINISHED, ("sa2msghdr: 4\n")); + /* + * We don't allocate new SA if the state of SA in the holder is + * SADB_SASTATE_MATURE, and if this is newer one. + */ + if (isr->sav != NULL) { + /* + * XXX While SA is hanging on policy request(isr), its refcnt + * can not be zero. So isr->sav->sah is valid pointer if + * isr->sav != NULL. But that may not be true in fact. + * There may be missunderstanding by myself. Anyway I set + * zero to isr->sav->sah when isr->sav is flushed. + * I must check to have conviction this issue. + */ + if (isr->sav->sah != NULL + && isr->sav != (struct secasvar *)LIST_FIRST( + &isr->sav->sah->savtree[SADB_SASTATE_MATURE])) { + KEYDEBUG(KEYDEBUG_IPSEC_STAMP, + printf("DP checkrequest calls free SA:%p\n", + isr->sav)); + key_freesav(isr->sav); + } + isr->sav = NULL; + } - keyinfo->key = cp; - keyinfo->keylen = secassoc->keylen; - if (secassoc->keylen) { - bcopy((char *)(secassoc->key), cp, secassoc->keylen); - ADVANCE(cp, secassoc->keylen); - } + /* new SA allocation if no SA found. */ + if (isr->sav == NULL) + isr->sav = key_allocsa_policy(isr); - DPRINTF(IDL_FINISHED, ("sa2msghdr: 5\n")); - keyinfo->iv = cp; - keyinfo->ivlen = secassoc->ivlen; - if (secassoc->ivlen) { - bcopy((char *)(secassoc->iv), cp, secassoc->ivlen); - ADVANCE(cp, secassoc->ivlen); - } + /* When there is SA. */ + if (isr->sav != NULL) + return 0; - DPRINTF(IDL_FINISHED, ("sa2msghdr: 6\n")); - keyinfo->ekey = cp; - keyinfo->ekeylen = secassoc->ekeylen; - if (secassoc->ekeylen) { - bcopy((char *)(secassoc->ekey), cp, secassoc->ekeylen); - ADVANCE(cp, secassoc->ekeylen); - } + /* there is no SA */ + if ((error = key_acquire(&isr->saidx, &isr->sp->spidx)) != 0) { + /* XXX What I do ? */ + printf("key_checkrequest: error %d returned " + "from key_acquire.\n", error); + return error; + } - DDO(IDL_FINISHED,printf("msgbuf(len=%d):\n",(char *)cp - (char *)km)); - DDO(IDL_FINISHED,dump_buf((char *)km, (char *)cp - (char *)km)); - DPRINTF(IDL_FINISHED, ("sa2msghdr: 6\n")); - return(0); + return level == IPSEC_LEVEL_REQUIRE ? ENOENT : 0; } +/* + * allocating a SA for policy entry from SAD. + * NOTE: searching SAD of aliving state. + * OUT: NULL: not found. + * others: found and return the pointer. + */ +static struct secasvar * +key_allocsa_policy(isr) + struct ipsecrequest *isr; +{ + struct secashead *sah; + struct secasvar *sav; + u_int stateidx, state; + + __LIST_FOREACH(sah, &sahtree, chain) { + if (sah->state == SADB_SASTATE_DEAD) + continue; + if (key_cmpsaidx_withmode(&sah->saidx, &isr->saidx)) + goto found; + } -/*---------------------------------------------------------------------- - * key_msghdr2secassoc(): - * Copy info from a key message buffer into a key_secassoc - * structure - ----------------------------------------------------------------------*/ -int -key_msghdr2secassoc(secassoc, km, keyinfo) - struct key_secassoc *secassoc; - struct key_msghdr *km; - struct key_msgdata *keyinfo; -{ - DPRINTF(IDL_FINISHED, ("Entering key_msghdr2secassoc\n")); - - if ((km == 0) || (keyinfo == 0) || (secassoc == 0)) - return(-1); - - secassoc->len = sizeof(*secassoc); - secassoc->type = km->type; - secassoc->vers = km->vers; - secassoc->state = km->state; - secassoc->label = km->label; - secassoc->spi = km->spi; - secassoc->keylen = km->keylen; - secassoc->ekeylen = km->ekeylen; - secassoc->ivlen = km->ivlen; - secassoc->algorithm = km->algorithm; - secassoc->lifetype = km->lifetype; - secassoc->lifetime1 = km->lifetime1; - secassoc->lifetime2 = km->lifetime2; - secassoc->antireplay = km->antireplay; - - if (keyinfo->src) { - KMALLOC(secassoc->src, struct sockaddr *, keyinfo->src->sa_len); - if (!secassoc->src) { - DPRINTF(IDL_ERROR,("msghdr2secassoc: can't allocate mem for src\n")); - return(-1); - } - bcopy((char *)keyinfo->src, (char *)secassoc->src, - keyinfo->src->sa_len); - } else - secassoc->src = NULL; - - if (keyinfo->dst) { - KMALLOC(secassoc->dst, struct sockaddr *, keyinfo->dst->sa_len); - if (!secassoc->dst) { - DPRINTF(IDL_ERROR,("msghdr2secassoc: can't allocate mem for dst\n")); - return(-1); - } - bcopy((char *)keyinfo->dst, (char *)secassoc->dst, - keyinfo->dst->sa_len); - } else - secassoc->dst = NULL; - - if (keyinfo->from) { - KMALLOC(secassoc->from, struct sockaddr *, keyinfo->from->sa_len); - if (!secassoc->from) { - DPRINTF(IDL_ERROR,("msghdr2secassoc: can't allocate mem for from\n")); - return(-1); - } - bcopy((char *)keyinfo->from, (char *)secassoc->from, - keyinfo->from->sa_len); - } else - secassoc->from = NULL; - - /* - * Make copies of key and iv - */ - if (secassoc->ivlen) { - KMALLOC(secassoc->iv, caddr_t, secassoc->ivlen); - if (secassoc->iv == 0) { - DPRINTF(IDL_ERROR,("msghdr2secassoc: can't allocate mem for iv\n")); - return(-1); - } - bcopy((char *)keyinfo->iv, (char *)secassoc->iv, secassoc->ivlen); - } else - secassoc->iv = NULL; - - if (secassoc->keylen) { - KMALLOC(secassoc->key, caddr_t, secassoc->keylen); - if (secassoc->key == 0) { - DPRINTF(IDL_ERROR,("msghdr2secassoc: can't allocate mem for key\n")); - if (secassoc->iv) - KFREE(secassoc->iv); - return(-1); - } - bcopy((char *)keyinfo->key, (char *)secassoc->key, secassoc->keylen); - } else - secassoc->key = NULL; - - if (secassoc->ekeylen) { - KMALLOC(secassoc->ekey, caddr_t, secassoc->ekeylen); - if (secassoc->ekey == 0) { - DPRINTF(IDL_ERROR,("msghdr2secassoc: can't allocate mem for ekey\n")); - if (secassoc->iv) - KFREE(secassoc->iv); - if (secassoc->key) - KFREE(secassoc->key); - return(-1); - } - bcopy((char *)keyinfo->ekey, (char *)secassoc->ekey, secassoc->ekeylen); - } else - secassoc->ekey = NULL; + return NULL; + + found: + + /* search valid state */ + for (stateidx = 0; + stateidx < _ARRAYLEN(saorder_state_valid); + stateidx++) { + + state = saorder_state_valid[stateidx]; + + sav = key_do_allocsa_policy(sah, state); + if (sav != NULL) + return sav; + } - return(0); + return NULL; } +/* + * searching SAD with direction, protocol, mode and state. + * called by key_allocsa_policy(). + * OUT: + * NULL : not found + * others : found, pointer to a SA. + */ +static struct secasvar * +key_do_allocsa_policy(sah, state) + struct secashead *sah; + u_int state; +{ + struct secasvar *sav, *candidate; + + /* initilize */ + candidate = NULL; + + __LIST_FOREACH(sav, &sah->savtree[state], chain) { + + /* sanity check */ + KEY_CHKSASTATE(sav->state, state, "key_do_allocsa_policy"); + + /* initialize */ + if (candidate == NULL) { + candidate = sav; + continue; + } + + /* Which SA is the better ? */ + + /* sanity check 2 */ + if (candidate->lft_c == NULL || sav->lft_c == NULL) { + /*XXX do panic ? */ + printf("key_do_allocsa_policy: " + "lifetime_current is NULL.\n"); + continue; + } + + /* XXX What the best method is to compare ? */ + if (candidate->lft_c->sadb_lifetime_addtime < + sav->lft_c->sadb_lifetime_addtime) { + candidate = sav; + continue; + } + } -/*---------------------------------------------------------------------- - * addrpart_equal(): - * Determine if the address portion of two sockaddrs are equal. - * Currently handles only AF_INET and AF_INET6 address families. - ----------------------------------------------------------------------*/ -static int -addrpart_equal(sa1, sa2) - struct sockaddr *sa1; - struct sockaddr *sa2; -{ - if ((sa1->sa_family != sa2->sa_family) || - (sa1->sa_len != sa2->sa_len)) - return 0; - - switch(sa1->sa_family) { - case AF_INET: - return (((struct sockaddr_in *)sa1)->sin_addr.s_addr == - ((struct sockaddr_in *)sa2)->sin_addr.s_addr); -#ifdef INET6 - case AF_INET6: - return (IN6_ARE_ADDR_EQUAL(&((struct sockaddr_in6 *)sa1)->sin6_addr, - &((struct sockaddr_in6 *)sa2)->sin6_addr)); -#endif /* INET6 */ - } - return(0); + if (candidate) { + candidate->refcnt++; + KEYDEBUG(KEYDEBUG_IPSEC_STAMP, + printf("DP allocsa_policy cause " + "refcnt++:%d SA:%p\n", + candidate->refcnt, candidate)); + } + return candidate; } -/*---------------------------------------------------------------------- - * key_inittables(): - * Allocate space and initialize key engine tables - ----------------------------------------------------------------------*/ -int -key_inittables() -{ - int i; - - KMALLOC(keyregtable, struct key_registry *, sizeof(struct key_registry)); - if (!keyregtable) - return -1; - bzero((char *)keyregtable, sizeof(struct key_registry)); - KMALLOC(key_acquirelist, struct key_acquirelist *, - sizeof(struct key_acquirelist)); - if (!key_acquirelist) - return -1; - bzero((char *)key_acquirelist, sizeof(struct key_acquirelist)); - for (i = 0; i < KEYTBLSIZE; i++) - bzero((char *)&keytable[i], sizeof(struct key_tblnode)); - for (i = 0; i < KEYALLOCTBLSIZE; i++) - bzero((char *)&keyalloctbl[i], sizeof(struct key_allocnode)); - for (i = 0; i < SO2SPITBLSIZE; i++) - bzero((char *)&so2spitbl[i], sizeof(struct key_so2spinode)); - - return 0; -} - -#ifdef notyet -static int -key_freetables() +/* + * allocating a SA entry for a *INBOUND* packet. + * Must call key_freesav() later. + * OUT: positive: pointer to a sav. + * NULL: not found, or error occured. + */ +struct secasvar * +key_allocsa(family, src, dst, proto, spi) + u_int family, proto; + caddr_t src, dst; + u_int32_t spi; { - KFREE(keyregtable); - keyregtable = NULL; - KFREE(key_acquirelist); - key_acquirelist = NULL; - return 0; + struct secashead *sah; + struct secasvar *sav; + u_int stateidx, state; + int s; + + /* sanity check */ + if (src == NULL || dst == NULL) + panic("key_allocsa: NULL pointer is passed.\n"); + + /* + * searching SAD. + * XXX: to be checked internal IP header somewhere. Also when + * IPsec tunnel packet is received. But ESP tunnel mode is + * encrypted so we can't check internal IP header. + */ + s = splnet(); /*called from softclock()*/ + __LIST_FOREACH(sah, &sahtree, chain) { + + /* search valid state */ + for (stateidx = 0; + stateidx < _ARRAYLEN(saorder_state_valid); + stateidx++) { + + state = saorder_state_valid[stateidx]; + __LIST_FOREACH(sav, &sah->savtree[state], chain) { + + /* sanity check */ + KEY_CHKSASTATE(sav->state, state, "key_allocsav"); + if (proto != sav->sah->saidx.proto) + continue; + if (spi != sav->spi) + continue; + + if (key_bbcmp(src, + _INADDRBYSA(&sav->sah->saidx.src), + _INALENBYAF(sav->sah->saidx.src.__ss_family) << 3) + && key_bbcmp(dst, + _INADDRBYSA(&sav->sah->saidx.dst), + _INALENBYAF(sav->sah->saidx.dst.__ss_family) << 3)) + goto found; + } + } + } + + /* not found */ + splx(s); + return NULL; + +found: + sav->refcnt++; + splx(s); + KEYDEBUG(KEYDEBUG_IPSEC_STAMP, + printf("DP allocsa cause refcnt++:%d SA:%p\n", + sav->refcnt, sav)); + return sav; } + +/* + * Must be called after calling key_allocsp(). + * For both the packet without socket and key_freeso(). + */ +void +key_freesp(sp) + struct secpolicy *sp; +{ + /* sanity check */ + if (sp == NULL) + panic("key_freesp: NULL pointer is passed.\n"); + + sp->refcnt--; + KEYDEBUG(KEYDEBUG_IPSEC_STAMP, + printf("DP freesp cause refcnt--:%d SP:%p\n", + sp->refcnt, sp)); + + if (sp->refcnt == 0) + key_delsp(sp); + + return; +} + +/* + * Must be called after calling key_allocsp(). + * For the packet with socket. + */ +void +key_freeso(so) + struct socket *so; +{ + /* sanity check */ + if (so == NULL) + panic("key_freeso: NULL pointer is passed.\n"); + + switch (so->so_proto->pr_domain->dom_family) { +#ifdef INET + case PF_INET: + { + struct inpcb *pcb = sotoinpcb(so); + + /* Does it have a PCB ? */ + if (pcb == NULL) + return; + key_freesp_so(&pcb->inp_sp->sp_in); + key_freesp_so(&pcb->inp_sp->sp_out); + } + break; #endif +#ifdef INET6 + case PF_INET6: + { + struct in6pcb *pcb = sotoin6pcb(so); + + /* Does it have a PCB ? */ + if (pcb == NULL) + return; + key_freesp_so(&pcb->in6p_sp->sp_in); + key_freesp_so(&pcb->in6p_sp->sp_out); + } + break; +#endif /* INET6 */ + default: + printf("key_freeso: unknown address family=%d.\n", + so->so_proto->pr_domain->dom_family); + return; + } -/*---------------------------------------------------------------------- - * key_gethashval(): - * Determine keytable hash value. - ----------------------------------------------------------------------*/ -static int -key_gethashval(buf, len, tblsize) - char *buf; - int len; - int tblsize; -{ - int i, j = 0; - - /* - * Todo: Use word size xor and check for alignment - * and zero pad if necessary. Need to also pick - * a good hash function and table size. - */ - if (len <= 0) { - DPRINTF(IDL_ERROR,("key_gethashval got bogus len!\n")); - return(-1); - } - for(i = 0; i < len; i++) { - j ^= (u_int8_t)(*(buf + i)); - } - return (j % tblsize); + return; } +static void +key_freesp_so(sp) + struct secpolicy **sp; +{ + /* sanity check */ + if (sp == NULL || *sp == NULL) + panic("key_freesp_so: sp == NULL\n"); + + switch ((*sp)->policy) { + case IPSEC_POLICY_IPSEC: + KEYDEBUG(KEYDEBUG_IPSEC_STAMP, + printf("DP freeso calls free SP:%p\n", *sp)); + key_freesp(*sp); + *sp = NULL; + break; + case IPSEC_POLICY_ENTRUST: + case IPSEC_POLICY_BYPASS: + return; + default: + panic("key_freesp_so: Invalid policy found %d", (*sp)->policy); + } -/*---------------------------------------------------------------------- - * key_createkey(): - * Create hash key for hash function - * key is: type+src+dst if keytype = 1 - * type+src+dst+spi if keytype = 0 - * Uses only the address portion of the src and dst sockaddrs to - * form key. Currently handles only AF_INET and AF_INET6 sockaddrs - ----------------------------------------------------------------------*/ -static int -key_createkey(buf, type, src, dst, spi, keytype) - char *buf; - u_int type; - struct sockaddr *src; - struct sockaddr *dst; - u_int32_t spi; - u_int keytype; + return; +} + +/* + * Must be called after calling key_allocsa(). + * This function is called by key_freesp() to free some SA allocated + * for a policy. + */ +void +key_freesav(sav) + struct secasvar *sav; { - char *cp, *p; + /* sanity check */ + if (sav == NULL) + panic("key_freesav: NULL pointer is passed.\n"); - DPRINTF(IDL_FINISHED,("Entering key_createkey\n")); + sav->refcnt--; + KEYDEBUG(KEYDEBUG_IPSEC_STAMP, + printf("DP freesav cause refcnt--:%d SA:%p SPI %d\n", + sav->refcnt, sav, (u_int32_t)ntohl(sav->spi))); - if (!buf || !src || !dst) - return(-1); + if (sav->refcnt == 0) + key_delsav(sav); - cp = buf; - bcopy((char *)&type, cp, sizeof(type)); - cp += sizeof(type); + return; +} -#ifdef INET6 - /* - * Assume only IPv4 and IPv6 addresses. - */ -#define ADDRPART(a) \ - ((a)->sa_family == AF_INET6) ? \ - (char *)&(((struct sockaddr_in6 *)(a))->sin6_addr) : \ - (char *)&(((struct sockaddr_in *)(a))->sin_addr) - -#define ADDRSIZE(a) \ - ((a)->sa_family == AF_INET6) ? sizeof(struct in6_addr) : \ - sizeof(struct in_addr) -#else /* INET6 */ -#define ADDRPART(a) (char *)&(((struct sockaddr_in *)(a))->sin_addr) -#define ADDRSIZE(a) sizeof(struct in_addr) -#endif /* INET6 */ +/* %%% SPD management */ +/* + * free security policy entry. + */ +static void +key_delsp(sp) + struct secpolicy *sp; +{ + int s; - DPRINTF(IDL_FINISHED,("src addr:\n")); - DDO(IDL_FINISHED,dump_smart_sockaddr(src)); - DPRINTF(IDL_FINISHED,("dst addr:\n")); - DDO(IDL_FINISHED,dump_smart_sockaddr(dst)); + /* sanity check */ + if (sp == NULL) + panic("key_delsp: NULL pointer is passed.\n"); - p = ADDRPART(src); - bcopy(p, cp, ADDRSIZE(src)); - cp += ADDRSIZE(src); + sp->state = IPSEC_SPSTATE_DEAD; - p = ADDRPART(dst); - bcopy(p, cp, ADDRSIZE(dst)); - cp += ADDRSIZE(dst); + if (sp->refcnt > 0) + return; /* can't free */ -#undef ADDRPART -#undef ADDRSIZE + s = splnet(); /*called from softclock()*/ + /* remove from SP index */ + if (__LIST_CHAINED(sp)) + LIST_REMOVE(sp, chain); - if (keytype == 0) { - bcopy((char *)&spi, cp, sizeof(spi)); - cp += sizeof(spi); - } + { + struct ipsecrequest *isr = sp->req, *nextisr; + + while (isr != NULL) { + if (isr->sav != NULL) { + KEYDEBUG(KEYDEBUG_IPSEC_STAMP, + printf("DP delsp calls free SA:%p\n", + isr->sav)); + key_freesav(isr->sav); + isr->sav = NULL; + } + + nextisr = isr->next; + KFREE(isr); + isr = nextisr; + } + } + + KFREE(sp); - DPRINTF(IDL_FINISHED,("hash key:\n")); - DDO(IDL_FINISHED, dump_buf(buf, cp - buf)); - return(cp - buf); + splx(s); + + return; } +/* + * search SPD + * OUT: NULL : not found + * others : found, pointer to a SP. + */ +static struct secpolicy * +key_getsp(spidx) + struct secpolicyindex *spidx; +{ + struct secpolicy *sp; + + /* sanity check */ + if (spidx == NULL) + panic("key_getsp: NULL pointer is passed.\n"); + + __LIST_FOREACH(sp, &sptree[spidx->dir], chain) { + if (sp->state == IPSEC_SPSTATE_DEAD) + continue; + if (key_cmpspidx_exactly(spidx, &sp->spidx)) { + sp->refcnt++; + return sp; + } + } -/*---------------------------------------------------------------------- - * key_sosearch(): - * Search the so2spi table for the security association allocated to - * the socket. Returns pointer to a struct key_so2spinode which can - * be used to locate the security association entry in the keytable. - ----------------------------------------------------------------------*/ -static struct key_so2spinode * -key_sosearch(type, src, dst, so) - u_int type; - struct sockaddr *src; - struct sockaddr *dst; - struct socket *so; + return NULL; +} + +struct secpolicy * +key_newsp() { - struct key_so2spinode *np = 0; + struct secpolicy *newsp = NULL; - if (!(src && dst)) { - DPRINTF(IDL_ERROR,("key_sosearch: got null src or dst pointer!\n")); - return(NULL); - } + KMALLOC(newsp, struct secpolicy *, sizeof(*newsp)); + if (newsp == NULL) { + printf("key_newsp: No more memory.\n"); + return NULL; + } + bzero(newsp, sizeof(*newsp)); - for (np = so2spitbl[((u_int32_t)so) % SO2SPITBLSIZE].next; np; np = np->next) { - if ((so == np->socket) && (type == np->keynode->secassoc->type) - && addrpart_equal(src, np->keynode->secassoc->src) - && addrpart_equal(dst, np->keynode->secassoc->dst)) - return(np); - } - return(NULL); + newsp->refcnt = 1; + newsp->req = NULL; + + return newsp; } +/* + * create secpolicy structure from sadb_x_policy structure. + * NOTE: `state', `secpolicyindex' in secpolicy structure are not set, + * so must be set properly later. + */ +struct secpolicy * +key_msg2sp(xpl0) + struct sadb_x_policy *xpl0; +{ + struct secpolicy *newsp; + + /* sanity check */ + if (xpl0 == NULL) + panic("key_msg2sp: NULL pointer was passed.\n"); + + if ((newsp = key_newsp()) == NULL) + return NULL; + + newsp->spidx.dir = xpl0->sadb_x_policy_dir; + newsp->policy = xpl0->sadb_x_policy_type; + + /* check policy */ + switch (xpl0->sadb_x_policy_type) { + case IPSEC_POLICY_DISCARD: + case IPSEC_POLICY_NONE: + case IPSEC_POLICY_ENTRUST: + case IPSEC_POLICY_BYPASS: + newsp->req = NULL; + break; + + case IPSEC_POLICY_IPSEC: + { + int tlen; + struct sadb_x_ipsecrequest *xisr; + struct ipsecrequest **p_isr = &newsp->req; + + /* validity check */ + if (PFKEY_EXTLEN(xpl0) <= sizeof(*xpl0)) { + printf("key_msg2sp: Invalid msg length.\n"); + key_freesp(newsp); + return NULL; + } + + tlen = PFKEY_EXTLEN(xpl0) - sizeof(*xpl0); + xisr = (struct sadb_x_ipsecrequest *)(xpl0 + 1); + + while (tlen > 0) { + + /* length check */ + if (xisr->sadb_x_ipsecrequest_len < sizeof(*xisr)) { + printf("key_msg2sp: " + "invalid ipsecrequest length.\n"); + key_freesp(newsp); + return NULL; + } + + /* allocate request buffer */ + KMALLOC(*p_isr, struct ipsecrequest *, sizeof(**p_isr)); + if ((*p_isr) == NULL) { + printf("key_msg2sp: No more memory.\n"); + key_freesp(newsp); + return NULL; + } + bzero(*p_isr, sizeof(**p_isr)); + + /* set values */ + (*p_isr)->next = NULL; + + switch (xisr->sadb_x_ipsecrequest_proto) { + case IPPROTO_ESP: + case IPPROTO_AH: + break; + default: + printf("key_msg2sp: invalid proto type=%u\n", + xisr->sadb_x_ipsecrequest_proto); + key_freesp(newsp); + return NULL; + } + (*p_isr)->saidx.proto = xisr->sadb_x_ipsecrequest_proto; + + switch (xisr->sadb_x_ipsecrequest_mode) { + case IPSEC_MODE_TRANSPORT: + case IPSEC_MODE_TUNNEL: + break; + case IPSEC_MODE_ANY: + default: + printf("key_msg2sp: invalid mode=%u\n", + xisr->sadb_x_ipsecrequest_mode); + key_freesp(newsp); + return NULL; + } + (*p_isr)->saidx.mode = xisr->sadb_x_ipsecrequest_mode; + + switch (xisr->sadb_x_ipsecrequest_level) { + case IPSEC_LEVEL_DEFAULT: + case IPSEC_LEVEL_USE: + case IPSEC_LEVEL_REQUIRE: + break; + default: + printf("key_msg2sp: invalid level=%u\n", + xisr->sadb_x_ipsecrequest_level); + key_freesp(newsp); + return NULL; + } + (*p_isr)->level = xisr->sadb_x_ipsecrequest_level; + + /* set IP addresses if there */ + if (xisr->sadb_x_ipsecrequest_len > sizeof(*xisr)) { + struct sockaddr *paddr; + + paddr = (struct sockaddr *)(xisr + 1); + + /* validity check */ + if (paddr->sa_len + > sizeof((*p_isr)->saidx.src)) { + printf("key_msg2sp: invalid request " + "address length.\n"); + key_freesp(newsp); + return NULL; + } + bcopy(paddr, &(*p_isr)->saidx.src, + paddr->sa_len); + + paddr = (struct sockaddr *)((caddr_t)paddr + + paddr->sa_len); + + /* validity check */ + if (paddr->sa_len + > sizeof((*p_isr)->saidx.dst)) { + printf("key_msg2sp: invalid request " + "address length.\n"); + key_freesp(newsp); + return NULL; + } + bcopy(paddr, &(*p_isr)->saidx.dst, + paddr->sa_len); + } + + (*p_isr)->sav = NULL; + (*p_isr)->sp = newsp; + + /* initialization for the next. */ + p_isr = &(*p_isr)->next; + tlen -= xisr->sadb_x_ipsecrequest_len; + + /* validity check */ + if (tlen < 0) { + printf("key_msg2sp: becoming tlen < 0.\n"); + key_freesp(newsp); + return NULL; + } + + xisr = (struct sadb_x_ipsecrequest *)((caddr_t)xisr + + xisr->sadb_x_ipsecrequest_len); + } + } + break; + default: + printf("key_msg2sp: invalid policy type.\n"); + key_freesp(newsp); + return NULL; + } + + return newsp; +} -/*---------------------------------------------------------------------- - * key_sodelete(): - * Delete entries from the so2spi table. - * flag = 1 purge all entries - * flag = 0 delete entries with socket pointer matching socket - ----------------------------------------------------------------------*/ -void -key_sodelete(socket, flag) - struct socket *socket; - int flag; +/* + * copy secpolicy struct to sadb_x_policy structure indicated. + */ +struct sadb_x_policy * +key_sp2msg(sp) + struct secpolicy *sp; { - struct key_so2spinode *prevnp, *np; - CRITICAL_DCL + struct sadb_x_policy *xpl; + int tlen; + caddr_t p; - CRITICAL_START; + /* sanity check. */ + if (sp == NULL) + panic("key_sp2msg: NULL pointer was passed.\n"); - DPRINTF(IDL_EVENT,("Entering keysodelete w/so=0x%x flag=%d\n", - (unsigned int)socket,flag)); + tlen = key_getspreqmsglen(sp); - if (flag) { - int i; + KMALLOC(xpl, struct sadb_x_policy *, tlen); + if (xpl == NULL) { + printf("key_sp2msg: No more memory.\n"); + return NULL; + } + bzero(xpl, tlen); + + xpl->sadb_x_policy_len = PFKEY_UNIT64(tlen); + xpl->sadb_x_policy_exttype = SADB_X_EXT_POLICY; + xpl->sadb_x_policy_type = sp->policy; + xpl->sadb_x_policy_dir = sp->spidx.dir; + p = (caddr_t)xpl + sizeof(*xpl); + + /* if is the policy for ipsec ? */ + if (sp->policy == IPSEC_POLICY_IPSEC) { + struct sadb_x_ipsecrequest *xisr; + struct ipsecrequest *isr; + + for (isr = sp->req; isr != NULL; isr = isr->next) { + + xisr = (struct sadb_x_ipsecrequest *)p; + + xisr->sadb_x_ipsecrequest_proto = isr->saidx.proto; + xisr->sadb_x_ipsecrequest_mode = isr->saidx.mode; + xisr->sadb_x_ipsecrequest_level = isr->level; + + p += sizeof(*xisr); + bcopy(&isr->saidx.src, p, isr->saidx.src.__ss_len); + p += isr->saidx.src.__ss_len; + bcopy(&isr->saidx.dst, p, isr->saidx.dst.__ss_len); + p += isr->saidx.src.__ss_len; + + xisr->sadb_x_ipsecrequest_len = + PFKEY_ALIGN8(sizeof(*xisr) + + isr->saidx.src.__ss_len + + isr->saidx.dst.__ss_len); + } + } - for (i = 0; i < SO2SPITBLSIZE; i++) - for(np = so2spitbl[i].next; np; np = np->next) { - KFREE(np); - } - CRITICAL_END; - return; - } + return xpl; +} - prevnp = &so2spitbl[((u_int32_t)socket) % SO2SPITBLSIZE]; - for(np = prevnp->next; np; np = np->next) { - if (np->socket == socket) { - struct socketlist *socklp, *prevsocklp; - - (np->keynode->alloc_count)--; - - /* - * If this socket maps to a unique secassoc, - * we go ahead and delete the secassoc, since it - * can no longer be allocated or used by any other - * socket. - */ - if (np->keynode->secassoc->state & K_UNIQUE) { - if (key_delete(np->keynode->secassoc) != 0) - panic("key_sodelete"); - np = prevnp; - continue; - } +/* + * SADB_SPDADD processing + * add a entry to SP database, when received + * <base, address(SD), policy> + * from the user(?). + * Adding to SP database, + * and send + * <base, address(SD), policy> + * to the socket which was send. + * + * IN: mhp: pointer to the pointer to each header. + * OUT: NULL if fail. + * other if success, return pointer to the message to send. + * + */ +static struct sadb_msg * +key_spdadd(mhp) + caddr_t *mhp; +{ + struct sadb_msg *msg0; + struct sadb_address *src0, *dst0; + struct sadb_x_policy *xpl0; + struct secpolicyindex spidx; + struct secpolicy *newsp; + + /* sanity check */ + if (mhp == NULL || mhp[0] == NULL) + panic("key_spdadd: NULL pointer is passed.\n"); + + msg0 = (struct sadb_msg *)mhp[0]; + + if (mhp[SADB_EXT_ADDRESS_SRC] == NULL + || mhp[SADB_EXT_ADDRESS_DST] == NULL + || mhp[SADB_X_EXT_POLICY] == NULL) { + printf("key_spdadd: invalid message is passed.\n"); + msg0->sadb_msg_errno = EINVAL; + return NULL; + } - /* - * We traverse the socketlist and remove the entry - * for this socket - */ - DPRINTF(IDL_FINISHED,("keysodelete: deleting from socklist...")); - prevsocklp = np->keynode->solist; - for (socklp = prevsocklp->next; socklp; socklp = socklp->next) { - if (socklp->socket == socket) { - prevsocklp->next = socklp->next; - KFREE(socklp); - break; - } - prevsocklp = socklp; - } - DPRINTF(IDL_FINISHED,("done\n")); - prevnp->next = np->next; - KFREE(np); - np = prevnp; + src0 = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC]; + dst0 = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST]; + xpl0 = (struct sadb_x_policy *)mhp[SADB_X_EXT_POLICY]; + + /* make secindex */ + KEY_SETSECSPIDX(xpl0->sadb_x_policy_dir, + src0 + 1, + dst0 + 1, + src0->sadb_address_prefixlen, + dst0->sadb_address_prefixlen, + src0->sadb_address_proto, + &spidx); + + /* checking the direciton. */ + switch (xpl0->sadb_x_policy_dir) { + case IPSEC_DIR_INBOUND: + case IPSEC_DIR_OUTBOUND: + break; + default: + printf("key_spdadd: Invalid SP direction.\n"); + msg0->sadb_msg_errno = EINVAL; + return NULL; + } + + /* Is there SP in SPD ? */ + newsp = key_getsp(&spidx); + if (newsp != NULL) { + key_freesp(newsp); + printf("key_spdadd: a SP entry exists already.\n"); + msg0->sadb_msg_errno = EEXIST; + return NULL; + } + + /* check policy */ + /* key_spdadd() accepts DISCARD, NONE and IPSEC. */ + if (xpl0->sadb_x_policy_type == IPSEC_POLICY_ENTRUST + || xpl0->sadb_x_policy_type == IPSEC_POLICY_BYPASS) { + printf("key_spdadd: Invalid policy type.\n"); + msg0->sadb_msg_errno = EINVAL; + return NULL; + } + + /* allocation new SP entry */ + if ((newsp = key_msg2sp(xpl0)) == NULL) { + msg0->sadb_msg_errno = ENOBUFS; + return NULL; + } + + KEY_SETSECSPIDX(xpl0->sadb_x_policy_dir, + src0 + 1, + dst0 + 1, + src0->sadb_address_prefixlen, + dst0->sadb_address_prefixlen, + src0->sadb_address_proto, + &newsp->spidx); + + newsp->refcnt = 1; /* do not reclaim until I say I do */ + newsp->state = IPSEC_SPSTATE_ALIVE; + LIST_INSERT_HEAD(&sptree[newsp->spidx.dir], newsp, chain); + + { + struct sadb_msg *newmsg; + u_int len; + caddr_t p; + + /* create new sadb_msg to reply. */ + len = sizeof(struct sadb_msg) + + PFKEY_EXTLEN(mhp[SADB_X_EXT_POLICY]) + + PFKEY_EXTLEN(mhp[SADB_EXT_ADDRESS_SRC]) + + PFKEY_EXTLEN(mhp[SADB_EXT_ADDRESS_DST]); + + KMALLOC(newmsg, struct sadb_msg *, len); + if (newmsg == NULL) { + printf("key_spdadd: No more memory.\n"); + msg0->sadb_msg_errno = ENOBUFS; + return NULL; + } + bzero((caddr_t)newmsg, len); + + bcopy((caddr_t)msg0, (caddr_t)newmsg, sizeof(*msg0)); + newmsg->sadb_msg_errno = 0; + newmsg->sadb_msg_len = PFKEY_UNIT64(len); + p = (caddr_t)newmsg + sizeof(*msg0); + + p = key_setsadbext(p, mhp[SADB_X_EXT_POLICY]); + p = key_setsadbext(p, mhp[SADB_EXT_ADDRESS_SRC]); + p = key_setsadbext(p, mhp[SADB_EXT_ADDRESS_DST]); + + return newmsg; } - prevnp = np; - } - CRITICAL_END; } +/* + * SADB_SPDDELETE processing + * receive + * <base, address(SD), policy(*)> + * from the user(?), and set SADB_SASTATE_DEAD, + * and send, + * <base, address(SD), policy(*)> + * to the ikmpd. + * policy(*) including direction of policy. + * + * IN: mhp: pointer to the pointer to each header. + * OUT: other if success, return pointer to the message to send. + * 0 if fail. + */ +static struct sadb_msg * +key_spddelete(mhp) + caddr_t *mhp; +{ + struct sadb_msg *msg0; + struct sadb_address *src0, *dst0; + struct sadb_x_policy *xpl0; + struct secpolicyindex spidx; + struct secpolicy *sp; + + /* sanity check */ + if (mhp == NULL || mhp[0] == NULL) + panic("key_spddelete: NULL pointer is passed.\n"); + + msg0 = (struct sadb_msg *)mhp[0]; + + if (mhp[SADB_EXT_ADDRESS_SRC] == NULL + || mhp[SADB_EXT_ADDRESS_DST] == NULL + || mhp[SADB_X_EXT_POLICY] == NULL) { + printf("key_spddelete: invalid message is passed.\n"); + msg0->sadb_msg_errno = EINVAL; + return NULL; + } + + src0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_SRC]); + dst0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_DST]); + xpl0 = (struct sadb_x_policy *)mhp[SADB_X_EXT_POLICY]; + + /* make secindex */ + KEY_SETSECSPIDX(xpl0->sadb_x_policy_dir, + src0 + 1, + dst0 + 1, + src0->sadb_address_prefixlen, + dst0->sadb_address_prefixlen, + src0->sadb_address_proto, + &spidx); + + /* checking the direciton. */ + switch (xpl0->sadb_x_policy_dir) { + case IPSEC_DIR_INBOUND: + case IPSEC_DIR_OUTBOUND: + break; + default: + printf("key_spddelete: Invalid SP direction.\n"); + msg0->sadb_msg_errno = EINVAL; + return NULL; + } -/*---------------------------------------------------------------------- - * key_deleteacquire(): - * Delete an entry from the key_acquirelist - ----------------------------------------------------------------------*/ -static void -key_deleteacquire(type, target) - u_int type; - struct sockaddr *target; -{ - struct key_acquirelist *ap, *prev; - - prev = key_acquirelist; - for(ap = key_acquirelist->next; ap; ap = ap->next) { - if (addrpart_equal(target, (struct sockaddr *)&(ap->target)) && - (type == ap->type)) { - DPRINTF(IDL_EVENT,("Deleting entry from acquire list!\n")); - prev->next = ap->next; - KFREE(ap); - ap = prev; + /* Is there SP in SPD ? */ + if ((sp = key_getsp(&spidx)) == NULL) { + printf("key_spddelete: no SP found.\n"); + msg0->sadb_msg_errno = ENOENT; + return NULL; + } + + sp->state = IPSEC_SPSTATE_DEAD; + key_freesp(sp); + + { + struct sadb_msg *newmsg; + u_int len; + caddr_t p; + + /* create new sadb_msg to reply. */ + len = sizeof(struct sadb_msg) + + PFKEY_EXTLEN(mhp[SADB_X_EXT_POLICY]) + + PFKEY_EXTLEN(mhp[SADB_EXT_ADDRESS_SRC]) + + PFKEY_EXTLEN(mhp[SADB_EXT_ADDRESS_DST]); + + KMALLOC(newmsg, struct sadb_msg *, len); + if (newmsg == NULL) { + printf("key_spddelete: No more memory.\n"); + msg0->sadb_msg_errno = ENOBUFS; + return NULL; + } + bzero((caddr_t)newmsg, len); + + bcopy((caddr_t)mhp[0], (caddr_t)newmsg, sizeof(*msg0)); + newmsg->sadb_msg_errno = 0; + newmsg->sadb_msg_len = PFKEY_UNIT64(len); + p = (caddr_t)newmsg + sizeof(*msg0); + + p = key_setsadbext(p, mhp[SADB_X_EXT_POLICY]); + p = key_setsadbext(p, mhp[SADB_EXT_ADDRESS_SRC]); + p = key_setsadbext(p, mhp[SADB_EXT_ADDRESS_DST]); + + return newmsg; } - prev = ap; - } } +/* + * SADB_SPDFLUSH processing + * receive + * <base> + * from the user, and free all entries in secpctree. + * and send, + * <base> + * to the user. + * NOTE: what to do is only marking SADB_SASTATE_DEAD. + * + * IN: mhp: pointer to the pointer to each header. + * OUT: other if success, return pointer to the message to send. + * 0 if fail. + */ +static struct sadb_msg * +key_spdflush(mhp) + caddr_t *mhp; +{ + struct sadb_msg *msg0; + struct secpolicy *sp; + u_int dir; -/*---------------------------------------------------------------------- - * key_search(): - * Search the key table for an entry with same type, src addr, dest - * addr, and spi. Returns a pointer to struct key_tblnode if found - * else returns null. - ----------------------------------------------------------------------*/ -static struct key_tblnode * -key_search(type, src, dst, spi, indx, prevkeynode) - u_int type; - struct sockaddr *src; - struct sockaddr *dst; - u_int32_t spi; - int indx; - struct key_tblnode **prevkeynode; -{ - struct key_tblnode *keynode, *prevnode; - - if (indx > KEYTBLSIZE || indx < 0) - return (NULL); - if (!(&keytable[indx])) - return (NULL); - -#define sec_type keynode->secassoc->type -#define sec_spi keynode->secassoc->spi -#define sec_src keynode->secassoc->src -#define sec_dst keynode->secassoc->dst - - prevnode = &keytable[indx]; - for (keynode = keytable[indx].next; keynode; keynode = keynode->next) { - if ((type == sec_type) && (spi == sec_spi) && - addrpart_equal(src, sec_src) - && addrpart_equal(dst, sec_dst)) - break; - prevnode = keynode; - } - *prevkeynode = prevnode; - return(keynode); + /* sanity check */ + if (mhp == NULL || mhp[0] == NULL) + panic("key_spdflush: NULL pointer is passed.\n"); + + msg0 = (struct sadb_msg *)mhp[0]; + + for (dir = 0; dir < IPSEC_DIR_MAX; dir++) { + __LIST_FOREACH(sp, &sptree[dir], chain) { + sp->state = IPSEC_SPSTATE_DEAD; + } + } + + { + struct sadb_msg *newmsg; + u_int len; + + /* create new sadb_msg to reply. */ + len = sizeof(struct sadb_msg); + + KMALLOC(newmsg, struct sadb_msg *, len); + if (newmsg == NULL) { + printf("key_spdflush: No more memory.\n"); + msg0->sadb_msg_errno = ENOBUFS; + return NULL; + } + bzero((caddr_t)newmsg, len); + + bcopy((caddr_t)mhp[0], (caddr_t)newmsg, sizeof(*msg0)); + newmsg->sadb_msg_errno = 0; + newmsg->sadb_msg_len = PFKEY_UNIT64(len); + + return(newmsg); + } } +/* + * SADB_SPDDUMP processing + * receive + * <base> + * from the user, and dump all SP leaves + * and send, + * <base> ..... + * to the ikmpd. + * + * IN: mhp: pointer to the pointer to each header. + * OUT: other if success, return pointer to the message to send. + * 0 if fail. + */ +static int +key_spddump(mhp, so, target) + caddr_t *mhp; + struct socket *so; + int target; +{ + struct sadb_msg *msg0; + struct secpolicy *sp; + int len, cnt, cnt_sanity; + struct sadb_msg *newmsg; + u_int dir; + + /* sanity check */ + if (mhp == NULL || mhp[0] == NULL) + panic("key_spddump: NULL pointer is passed.\n"); + + msg0 = (struct sadb_msg *)mhp[0]; + + /* search SPD entry and get buffer size. */ + cnt = cnt_sanity = 0; + for (dir = 0; dir < IPSEC_DIR_MAX; dir++) { + __LIST_FOREACH(sp, &sptree[dir], chain) { + cnt++; + } + } + + if (cnt == 0) + return ENOENT; + + newmsg = NULL; + for (dir = 0; dir < IPSEC_DIR_MAX; dir++) { + __LIST_FOREACH(sp, &sptree[dir], chain) { + len = key_getspmsglen(sp); + + /* making buffer */ + KMALLOC(newmsg, struct sadb_msg *, len); + if (newmsg == NULL) { + printf("key_spddump: No more memory.\n"); + return ENOBUFS; + } + bzero((caddr_t)newmsg, len); + + --cnt; + (void)key_setdumpsp(newmsg, sp, SADB_X_SPDDUMP, + cnt, msg0->sadb_msg_pid); + + key_sendup(so, newmsg, len, target); + KFREE(newmsg); + newmsg = NULL; + } + } + + return 0; +} -/*---------------------------------------------------------------------- - * key_addnode(): - * Insert a key_tblnode entry into the key table. Returns a pointer - * to the newly created key_tblnode. - ----------------------------------------------------------------------*/ -static struct key_tblnode * -key_addnode(indx, secassoc) - int indx; - struct key_secassoc *secassoc; +static u_int +key_setdumpsp(newmsg, sp, type, seq, pid) + struct sadb_msg *newmsg; + struct secpolicy *sp; + u_int8_t type; + u_int32_t seq, pid; { - struct key_tblnode *keynode; + u_int tlen; + caddr_t p; + + tlen = key_getspmsglen(sp); + + p = key_setsadbmsg((caddr_t)newmsg, type, tlen, + SADB_SATYPE_UNSPEC, seq, pid, + IPSEC_MODE_ANY, sp->refcnt); + + p = key_setsadbaddr(p, + SADB_EXT_ADDRESS_SRC, + (struct sockaddr *)&sp->spidx.src, + sp->spidx.prefs, + sp->spidx.ul_proto); + p = key_setsadbaddr(p, + SADB_EXT_ADDRESS_DST, + (struct sockaddr *)&sp->spidx.dst, + sp->spidx.prefd, + sp->spidx.ul_proto); - DPRINTF(IDL_FINISHED,("Entering key_addnode w/indx=%d secassoc=0x%x\n", - indx, (unsigned int)secassoc)); + { + struct sadb_x_policy *tmp; - if (!(&keytable[indx])) - return(NULL); - if (!secassoc) { - panic("key_addnode: Someone passed in a null secassoc!\n"); - } + if ((tmp = key_sp2msg(sp)) == NULL) { + printf("key_setdumpsp: No more memory.\n"); + return ENOBUFS; + } - KMALLOC(keynode, struct key_tblnode *, sizeof(struct key_tblnode)); - if (keynode == 0) - return(NULL); - bzero((char *)keynode, sizeof(struct key_tblnode)); + /* validity check */ + if (key_getspreqmsglen(sp) != PFKEY_UNUNIT64(tmp->sadb_x_policy_len)) + panic("key_setdumpsp: length mismatch." + "sp:%d msg:%d\n", + key_getspreqmsglen(sp), + PFKEY_UNUNIT64(tmp->sadb_x_policy_len)); - KMALLOC(keynode->solist, struct socketlist *, sizeof(struct socketlist)); - if (keynode->solist == 0) { - KFREE(keynode); - return(NULL); - } - bzero((char *)(keynode->solist), sizeof(struct socketlist)); + bcopy(tmp, p, PFKEY_UNUNIT64(tmp->sadb_x_policy_len)); + KFREE(tmp); + } - keynode->secassoc = secassoc; - keynode->solist->next = NULL; - keynode->next = keytable[indx].next; - keytable[indx].next = keynode; - return(keynode); + return tlen; } +/* get sadb message length for a SP. */ +static u_int +key_getspmsglen(sp) + struct secpolicy *sp; +{ + u_int tlen; -/*---------------------------------------------------------------------- - * key_add(): - * Add a new security association to the key table. Caller is - * responsible for allocating memory for the key_secassoc as - * well as the buffer space for the key, iv. Assumes the security - * association passed in is well-formed. - ----------------------------------------------------------------------*/ -int -key_add(secassoc) - struct key_secassoc *secassoc; -{ - char buf[MAXHASHKEYLEN]; - int len, indx; - int inbound = 0; - int outbound = 0; - struct key_tblnode *keynode, *prevkeynode; - struct key_allocnode *np = NULL; - CRITICAL_DCL - - DPRINTF(IDL_FINISHED, ("Entering key_add w/secassoc=0x%x\n", - (unsigned int)secassoc)); - - if (!secassoc) { - panic("key_add: who the hell is passing me a null pointer"); - } + /* sanity check */ + if (sp == NULL) + panic("key_getspmsglen: NULL pointer is passed.\n"); - /* - * Should we allow a null key to be inserted into the table ? - * or can we use null key to indicate some policy action... - */ + tlen = (sizeof(struct sadb_msg) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(_SALENBYAF(sp->spidx.src.__ss_family)) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(_SALENBYAF(sp->spidx.dst.__ss_family))); -#if 0 - /* - * For esp using des-cbc or tripple-des we call - * des_set_odd_parity. - */ - if (secassoc->key && (secassoc->type == KEY_TYPE_ESP) && - ((secassoc->algorithm == IPSEC_ALGTYPE_ESP_DES_CBC) || - (secassoc->algorithm == IPSEC_ALGTYPE_ESP_3DES))) - des_set_odd_parity(secassoc->key); -#endif /* 0 */ - - /* - * initialization for anti-replay services. - */ - secassoc->sequence = 0; - secassoc->replayright = 0; - secassoc->replaywindow = 0; - - /* - * Check if secassoc with same spi exists before adding - */ - bzero((char *)&buf, sizeof(buf)); - len = key_createkey((char *)&buf, secassoc->type, secassoc->src, - secassoc->dst, secassoc->spi, 0); - indx = key_gethashval((char *)&buf, len, KEYTBLSIZE); - DPRINTF(IDL_FINISHED,("keyadd: keytbl hash position=%d\n", indx)); - keynode = key_search(secassoc->type, secassoc->src, secassoc->dst, - secassoc->spi, indx, &prevkeynode); - if (keynode) { - DPRINTF(IDL_EVENT,("keyadd: secassoc already exists!\n")); - return(-2); - } + tlen += key_getspreqmsglen(sp); + + return tlen; +} + +/* + * get PFKEY message length for security policy and request. + */ +static u_int +key_getspreqmsglen(sp) + struct secpolicy *sp; +{ + u_int tlen; + + tlen = sizeof(struct sadb_x_policy); + + /* if is the policy for ipsec ? */ + if (sp->policy != IPSEC_POLICY_IPSEC) + return tlen; + + /* get length of ipsec requests */ + { + struct ipsecrequest *isr; + int len; + + for (isr = sp->req; isr != NULL; isr = isr->next) { + len = sizeof(struct sadb_x_ipsecrequest) + + isr->saidx.src.__ss_len + + isr->saidx.dst.__ss_len; - inbound = my_addr(secassoc->dst); - outbound = my_addr(secassoc->src); - DPRINTF(IDL_FINISHED,("inbound=%d outbound=%d\n", inbound, outbound)); - - /* - * We allocate mem for an allocation entry if needed. - * This is done here instead of in the allocaton code - * segment so that we can easily recover/cleanup from a - * memory allocation error. - */ - if (outbound || (!inbound && !outbound)) { - KMALLOC(np, struct key_allocnode *, sizeof(struct key_allocnode)); - if (np == 0) { - DPRINTF(IDL_ERROR,("keyadd: can't allocate allocnode!\n")); - return(-1); + tlen += PFKEY_ALIGN8(len); + } } - } - CRITICAL_START; + return tlen; +} - if ((keynode = key_addnode(indx, secassoc)) == NULL) { - DPRINTF(IDL_ERROR,("keyadd: key_addnode failed!\n")); - if (np) - KFREE(np); - CRITICAL_END; - return(-1); - } - DPRINTF(IDL_GROSS_EVENT,("Added new keynode:\n")); - DDO(IDL_FINISHED, dump_keytblnode(keynode)); - DDO(IDL_FINISHED, dump_secassoc(keynode->secassoc)); - - /* - * We add an entry to the allocation table for - * this secassoc if the interfaces are up, - * the secassoc is outbound. In the case - * where the interfaces are not up, we go ahead - * , do it anyways. This wastes an allocation - * entry if the secassoc later turned out to be - * inbound when the interfaces are ifconfig up. - */ - if (outbound || (!inbound && !outbound)) { - len = key_createkey((char *)&buf, secassoc->type, secassoc->src, - secassoc->dst, 0, 1); - indx = key_gethashval((char *)&buf, len, KEYALLOCTBLSIZE); - DPRINTF(IDL_FINISHED,("keyadd: keyalloc hash position=%d\n", indx)); - np->keynode = keynode; - np->next = keyalloctbl[indx].next; - keyalloctbl[indx].next = np; - } - if (inbound) - secassoc->state |= K_INBOUND; - if (outbound) - secassoc->state |= K_OUTBOUND; +/* %%% SAD management */ +/* + * allocating a memory for new SA head, and copy from the values of mhp. + * OUT: NULL : failure due to the lack of memory. + * others : pointer to new SA head. + */ +static struct secashead * +key_newsah(saidx) + struct secasindex *saidx; +{ + struct secashead *newsah; + u_int stateidx; - key_deleteacquire(secassoc->type, secassoc->dst); + /* sanity check */ + if (saidx == NULL) + panic("key_newsaidx: NULL pointer is passed.\n"); - CRITICAL_END; - return 0; + KMALLOC(newsah, struct secashead *, sizeof(struct secashead)); + if (newsah == NULL) { + return NULL; + } + bzero((caddr_t)newsah, sizeof(struct secashead)); + + bcopy(saidx, &newsah->saidx, sizeof(newsah->saidx)); + + for (stateidx = 0; + stateidx < _ARRAYLEN(saorder_state_any); + stateidx++) { + LIST_INIT(&newsah->savtree[saorder_state_any[stateidx]]); + } + + /* add to saidxtree */ + newsah->state = SADB_SASTATE_MATURE; + LIST_INSERT_HEAD(&sahtree, newsah, chain); + + return(newsah); } +/* + * delete SA index and all SA registerd. + */ +static void +key_delsah(sah) + struct secashead *sah; +{ + struct secasvar *sav, *nextsav; + u_int stateidx, state; + int s; + + /* sanity check */ + if (sah == NULL) + panic("key_delsah: NULL pointer is passed.\n"); + + s = splnet(); /*called from softclock()*/ + + /* remove from tree of SA index */ + if (__LIST_CHAINED(sah)) + LIST_REMOVE(sah, chain); + + /* searching all SA registerd in the secindex. */ + for (stateidx = 0; + stateidx < _ARRAYLEN(saorder_state_any); + stateidx++) { + + state = saorder_state_any[stateidx]; + for (sav = (struct secasvar *)LIST_FIRST(&sah->savtree[state]); + sav != NULL; + sav = nextsav) { + + nextsav = LIST_NEXT(sav, chain); + + /* sanity check */ + KEY_CHKSASTATE(state, sav->state, "key_delsah"); + + /* remove back pointer */ + sav->sah = NULL; + + if (sav->refcnt < 0) { + printf("key_delsah: why refcnt < 0 ?, " + "sav->refcnt=%d\n", + sav->refcnt); + } + key_freesav(sav); + sav = NULL; + } + } -/*---------------------------------------------------------------------- - * key_get(): - * Get a security association from the key table. - ----------------------------------------------------------------------*/ -int -key_get(type, src, dst, spi, secassoc) - u_int type; - struct sockaddr *src; - struct sockaddr *dst; - u_int32_t spi; - struct key_secassoc **secassoc; -{ - char buf[MAXHASHKEYLEN]; - struct key_tblnode *keynode, *prevkeynode; - int len, indx; - - bzero(&buf, sizeof(buf)); - *secassoc = NULL; - len = key_createkey((char *)&buf, type, src, dst, spi, 0); - indx = key_gethashval((char *)&buf, len, KEYTBLSIZE); - DPRINTF(IDL_FINISHED,("keyget: indx=%d\n",indx)); - keynode = key_search(type, src, dst, spi, indx, &prevkeynode); - if (keynode) { - DPRINTF(IDL_GROSS_EVENT,("keyget: found it! keynode=0x%x", - (unsigned int)keynode)); - *secassoc = keynode->secassoc; - return(0); - } else - return(-1); /* Not found */ -} - - -/*---------------------------------------------------------------------- - * key_dump(): - * Dump all valid entries in the keytable to a pf_key socket. Each - * security associaiton is sent one at a time in a pf_key message. A - * message with seqno = 0 signifies the end of the dump transaction. - ----------------------------------------------------------------------*/ -int -key_dump(so) - struct socket *so; -{ - int len, i; - int seq = 1; - struct key_msgdata keyinfo; - struct key_msghdr *km; - struct key_tblnode *keynode; - int kmlen; - - /* - * Routine to dump the key table to a routing socket - * Use for debugging only! - */ - - kmlen = sizeof(struct key_msghdr) + 3 * MAX_SOCKADDR_SZ + MAX_KEY_SZ - + MAX_IV_SZ; - KMALLOC(km, struct key_msghdr *, kmlen); - if (!km) - return(ENOBUFS); - - DPRINTF(IDL_FINISHED,("Entering key_dump()")); - /* - * We need to speed this up later. Fortunately, key_dump - * messages are not sent often. - */ - for (i = 0; i < KEYTBLSIZE; i++) { - for (keynode = keytable[i].next; keynode; keynode = keynode->next) { - /* - * We exclude dead/larval/zombie security associations for now - * but it may be useful to also send these up for debugging purposes - */ - if (keynode->secassoc->state & (K_DEAD | K_LARVAL | K_ZOMBIE)) - continue; - - len = (sizeof(struct key_msghdr) + - ROUNDUP(keynode->secassoc->src->sa_len) + - ROUNDUP(keynode->secassoc->dst->sa_len) + - ROUNDUP(keynode->secassoc->from->sa_len) + - ROUNDUP(keynode->secassoc->keylen) + - ROUNDUP(keynode->secassoc->ivlen) + - ROUNDUP(keynode->secassoc->ekeylen)); - - if (kmlen < len) { - KFREE(km); - kmlen = len; - KMALLOC(km, struct key_msghdr *, kmlen); - if (!km) - return(ENOBUFS); - } + if (sah->sa_route.ro_rt) { + RTFREE(sah->sa_route.ro_rt); + sah->sa_route.ro_rt = (struct rtentry *)NULL; + } - if (key_secassoc2msghdr(keynode->secassoc, km, &keyinfo) != 0) - panic("key_dump"); + KFREE(sah); - km->key_msglen = len; - km->key_msgvers = KEY_VERSION; - km->key_msgtype = KEY_DUMP; - km->key_pid = curproc->p_pid; - km->key_seq = seq++; - km->key_errno = 0; + splx(s); + return; +} - key_sendup(so, km); - } - } - bzero((char *)km, sizeof(struct key_msghdr)); - km->key_msglen = sizeof(struct key_msghdr); - km->key_msgvers = KEY_VERSION; - km->key_msgtype = KEY_DUMP; - km->key_pid = curproc->p_pid; - km->key_seq = 0; - km->key_errno = 0; - - key_sendup(so, km); - KFREE(km); - DPRINTF(IDL_FINISHED,("Leaving key_dump()\n")); - return(0); -} - -/*---------------------------------------------------------------------- - * key_delete(): - * Delete a security association from the key table. - ----------------------------------------------------------------------*/ -int -key_delete(secassoc) - struct key_secassoc *secassoc; -{ - char buf[MAXHASHKEYLEN]; - int len, indx; - struct key_tblnode *keynode = 0; - struct key_tblnode *prevkeynode = 0; - struct socketlist *socklp, *deadsocklp; - struct key_so2spinode *np, *prevnp; - struct key_allocnode *ap, *prevap; - CRITICAL_DCL - - DPRINTF(IDL_FINISHED,("Entering key_delete w/secassoc=0x%x\n", - (unsigned int)secassoc)); - - bzero((char *)&buf, sizeof(buf)); - len = key_createkey((char *)&buf, secassoc->type, secassoc->src, - secassoc->dst, secassoc->spi, 0); - indx = key_gethashval((char *)&buf, len, KEYTBLSIZE); - DPRINTF(IDL_FINISHED,("keydelete: keytbl hash position=%d\n", indx)); - keynode = key_search(secassoc->type, secassoc->src, secassoc->dst, - secassoc->spi, indx, &prevkeynode); - - if (keynode) { - CRITICAL_START; - DPRINTF(IDL_GROSS_EVENT,("keydelete: found keynode to delete\n")); - keynode->secassoc->state |= K_DEAD; - - if (keynode->ref_count > 0) { - DPRINTF(IDL_EVENT,("keydelete: secassoc still held, marking for deletion only!\n")); - CRITICAL_END; - return(0); - } +/* + * allocating a new SA with LARVAL state. key_add() and key_getspi() call, + * and copy the values of mhp into new buffer. + * When SAD message type is GETSPI: + * to set sequence number from acq_seq++, + * to set zero to SPI. + * not to call key_setsava(). + * OUT: NULL : fail + * others : pointer to new secasvar. + */ +static struct secasvar * +key_newsav(mhp, sah) + caddr_t *mhp; + struct secashead *sah; +{ + struct secasvar *newsav; + struct sadb_msg *msg0; - prevkeynode->next = keynode->next; - - /* - * Walk the socketlist, delete the - * entries mapping sockets to this secassoc - * from the so2spi table. - */ - DPRINTF(IDL_FINISHED,("keydelete: deleting socklist...")); - for(socklp = keynode->solist->next; socklp; ) { - prevnp = &so2spitbl[((u_int32_t)(socklp->socket)) % SO2SPITBLSIZE]; - for(np = prevnp->next; np; np = np->next) { - if ((np->socket == socklp->socket) && (np->keynode == keynode)) { - prevnp->next = np->next; - KFREE(np); - break; - } - prevnp = np; - } - deadsocklp = socklp; - socklp = socklp->next; - KFREE(deadsocklp); - } - DPRINTF(IDL_FINISHED,("done\n")); - /* - * If an allocation entry exist for this - * secassoc, delete it. - */ - bzero((char *)&buf, sizeof(buf)); - len = key_createkey((char *)&buf, secassoc->type, secassoc->src, - secassoc->dst, 0, 1); - indx = key_gethashval((char *)&buf, len, KEYALLOCTBLSIZE); - DPRINTF(IDL_FINISHED,("keydelete: alloctbl hash position=%d\n", indx)); - prevap = &keyalloctbl[indx]; - for (ap = prevap->next; ap; ap = ap->next) { - if (ap->keynode == keynode) { - prevap->next = ap->next; - KFREE(ap); - break; - } - prevap = ap; - } - - if (keynode->secassoc->iv) - KFREE(keynode->secassoc->iv); - if (keynode->secassoc->key) - KFREE(keynode->secassoc->key); - if (keynode->secassoc->ekey) - KFREE(keynode->secassoc->ekey); - KFREE(keynode->secassoc); - if (keynode->solist) - KFREE(keynode->solist); - KFREE(keynode); - CRITICAL_END; - return(0); - } - return(-1); + /* sanity check */ + if (mhp == NULL || mhp[0] == NULL || sah == NULL) + panic("key_newsa: NULL pointer is passed.\n"); + + msg0 = (struct sadb_msg *)mhp[0]; + + KMALLOC(newsav, struct secasvar *, sizeof(struct secasvar)); + if (newsav == NULL) { + printf("key_newsa: No more memory.\n"); + msg0->sadb_msg_errno = ENOBUFS; + return NULL; + } + bzero((caddr_t)newsav, sizeof(struct secasvar)); + + switch (msg0->sadb_msg_type) { + case SADB_GETSPI: + newsav->spi = 0; + + /* sync sequence number */ + if (msg0->sadb_msg_seq == 0) + newsav->seq = + (acq_seq = (acq_seq == ~0 ? 1 : ++acq_seq)); + else + newsav->seq = msg0->sadb_msg_seq; + break; + + case SADB_ADD: + /* sanity check */ + if (mhp[SADB_EXT_SA] == NULL) { + KFREE(newsav); + printf("key_newsa: invalid message is passed.\n"); + msg0->sadb_msg_errno = EINVAL; + return NULL; + } + newsav->spi = ((struct sadb_sa *)mhp[SADB_EXT_SA])->sadb_sa_spi; + newsav->seq = msg0->sadb_msg_seq; + break; + default: + KFREE(newsav); + msg0->sadb_msg_errno = EINVAL; + return NULL; + } + + /* copy sav values */ + if (msg0->sadb_msg_type != SADB_GETSPI && key_setsaval(newsav, mhp)) { + KFREE(newsav); + /* msg0->sadb_msg_errno is set at key_setsaval. */ + return NULL; + } + + /* reset tick */ + newsav->tick = 0; + + newsav->pid = msg0->sadb_msg_pid; + + /* add to satree */ + newsav->sah = sah; + newsav->refcnt = 1; + newsav->state = SADB_SASTATE_LARVAL; + LIST_INSERT_HEAD(&sah->savtree[SADB_SASTATE_LARVAL], newsav, chain); + + return newsav; } +/* + * free() SA variable entry. + */ +static void +key_delsav(sav) + struct secasvar *sav; +{ + /* sanity check */ + if (sav == NULL) + panic("key_delsav: NULL pointer is passed.\n"); + + if (sav->refcnt > 0) return; /* can't free */ + + /* remove from SA header */ + if (__LIST_CHAINED(sav)) + LIST_REMOVE(sav, chain); + + if (sav->key_auth != NULL) + KFREE(sav->key_auth); + if (sav->key_enc != NULL) + KFREE(sav->key_enc); + if (sav->replay != NULL) { + if (sav->replay->bitmap != NULL) + KFREE(sav->replay->bitmap); + KFREE(sav->replay); + } + if (sav->lft_c != NULL) + KFREE(sav->lft_c); + if (sav->lft_h != NULL) + KFREE(sav->lft_h); + if (sav->lft_s != NULL) + KFREE(sav->lft_s); + if (sav->iv != NULL) + KFREE(sav->iv); +#if notyet + if (sav->misc1 != NULL) + KFREE(sav->misc1); + if (sav->misc2 != NULL) + KFREE(sav->misc2); + if (sav->misc3 != NULL) + KFREE(sav->misc3); +#endif -/*---------------------------------------------------------------------- - * key_flush(): - * Delete all entries from the key table. - ----------------------------------------------------------------------*/ -void -key_flush() + sav->sah = NULL; + /* XXX for making sure. See key_checkrequest(), + * Refcnt may be suspicious. */ + + KFREE(sav); + + return; +} + +/* + * search SAD. + * OUT: + * NULL : not found + * others : found, pointer to a SA. + */ +static struct secashead * +key_getsah(saidx) + struct secasindex *saidx; +{ + struct secashead *sah; + + __LIST_FOREACH(sah, &sahtree, chain) { + if (sah->state == SADB_SASTATE_DEAD) + continue; + if (key_cmpsaidx_exactly(&sah->saidx, saidx)) + return(sah); + } + + return NULL; +} + +/* + * check not to be duplicated SPI. + * NOTE: this function is too slow due to searching all SAD. + * OUT: + * NULL : not found + * others : found, pointer to a SA. + */ +static struct secasvar * +key_checkspidup(saidx, spi) + struct secasindex *saidx; + u_int32_t spi; { - struct key_tblnode *keynode; - int i; -#if 1 - int timo; + struct secashead *sah; + struct secasvar *sav; + + /* check address family */ + if (saidx->src.__ss_family != saidx->src.__ss_family) { + printf("key_checkspidup: address family mismatched.\n"); + return NULL; + } + + /* check all SAD */ + __LIST_FOREACH(sah, &sahtree, chain) { + if (!key_ismyaddr(sah->saidx.dst.__ss_family, + _INADDRBYSA(&sah->saidx.dst))) + continue; + sav = key_getsavbyspi(sah, spi); + if (sav != NULL) + return sav; + } + + return NULL; +} + +/* + * search SAD litmited alive SA, protocol, SPI. + * OUT: + * NULL : not found + * others : found, pointer to a SA. + */ +static struct secasvar * +key_getsavbyspi(sah, spi) + struct secashead *sah; + u_int32_t spi; +{ + struct secasvar *sav; + u_int stateidx, state; + + /* search all status */ + for (stateidx = 0; + stateidx < _ARRAYLEN(saorder_state_alive); + stateidx++) { + + state = saorder_state_alive[stateidx]; + __LIST_FOREACH(sav, &sah->savtree[state], chain) { + + /* sanity check */ + if (sav->state != state) { + printf("key_getsavbyspi: " + "invalid sav->state " + "(queue: %d SA: %d)\n", + state, sav->state); + continue; + } + + if (sav->spi == spi) + return sav; + } + } + + return NULL; +} + +/* + * copy SA values from PF_KEY message except *SPI, SEQ, PID, STATE and TYPE*. + * You must update these if need. + * OUT: 0: success. + * 1: failure. set errno to (mhp[0])->sadb_msg_errno. + */ +static int +key_setsaval(sav, mhp) + struct secasvar *sav; + caddr_t *mhp; +{ + struct sadb_msg *msg0; + int error = 0; + + /* sanity check */ + if (mhp == NULL || mhp[0] == NULL) + panic("key_setsaval: NULL pointer is passed.\n"); + + msg0 = (struct sadb_msg *)mhp[0]; + + /* initialization */ + sav->replay = NULL; + sav->key_auth = NULL; + sav->key_enc = NULL; + sav->iv = NULL; + sav->lft_c = NULL; + sav->lft_h = NULL; + sav->lft_s = NULL; + + /* SA */ + if (mhp[SADB_EXT_SA] != NULL) { + struct sadb_sa *sa0 = (struct sadb_sa *)mhp[SADB_EXT_SA]; + + sav->alg_auth = sa0->sadb_sa_auth; + sav->alg_enc = sa0->sadb_sa_encrypt; + sav->flags = sa0->sadb_sa_flags; + + /* replay window */ + if ((sa0->sadb_sa_flags & SADB_X_EXT_OLD) == 0) { + KMALLOC(sav->replay, struct secreplay *, + sizeof(struct secreplay)); + if (sav->replay == NULL) { + printf("key_setsaval: No more memory.\n"); + error = ENOBUFS; + goto err; + } + bzero(sav->replay, sizeof(struct secreplay)); + + if ((sav->replay->wsize = sa0->sadb_sa_replay) != 0) { + KMALLOC(sav->replay->bitmap, caddr_t, + sav->replay->wsize); + if (sav->replay->bitmap == NULL) { + printf("key_setsaval: " + "No more memory.\n"); + error = ENOBUFS; + goto err; + } + bzero(sav->replay->bitmap, sa0->sadb_sa_replay); + } + } + } + + /* Authentication keys */ + if (mhp[SADB_EXT_KEY_AUTH] != NULL) { + struct sadb_key *key0; + u_int len; + + key0 = (struct sadb_key *)mhp[SADB_EXT_KEY_AUTH]; + len = PFKEY_UNUNIT64(key0->sadb_key_len); + + error = 0; + if (len < sizeof(struct sadb_key)) + error = EINVAL; + switch (msg0->sadb_msg_satype) { + case SADB_SATYPE_AH: + case SADB_SATYPE_ESP: + if (len == sizeof(struct sadb_key) + && sav->alg_auth != SADB_AALG_NULL) { + error = EINVAL; + } + break; + case SADB_X_SATYPE_IPCOMP: + error = EINVAL; + break; + default: + error = EINVAL; + break; + } + if (error) { + printf("key_setsaval: invalid key_auth values.\n"); + goto err; + } + + KEY_NEWBUF(sav->key_auth, struct sadb_key *, key0, len); + if (sav->key_auth == NULL) { + printf("key_setsaval: No more memory.\n"); + error = ENOBUFS; + goto err; + } + + /* make length shift up for kernel*/ + sav->key_auth->sadb_key_len = len; + } + + /* Encryption key */ + if (mhp[SADB_EXT_KEY_ENCRYPT] != NULL) { + struct sadb_key *key0; + u_int len; + + key0 = (struct sadb_key *)mhp[SADB_EXT_KEY_ENCRYPT]; + len = PFKEY_UNUNIT64(key0->sadb_key_len); + + error = 0; + if (len < sizeof(struct sadb_key)) + error = EINVAL; + switch (msg0->sadb_msg_satype) { + case SADB_SATYPE_ESP: + if (len == sizeof(struct sadb_key) + && sav->alg_enc != SADB_EALG_NULL) { + error = EINVAL; + } + break; + case SADB_SATYPE_AH: + error = EINVAL; + break; + case SADB_X_SATYPE_IPCOMP: + break; + default: + error = EINVAL; + break; + } + if (error) { + printf("key_setsatval: invalid key_enc value.\n"); + goto err; + } + + KEY_NEWBUF(sav->key_enc, struct sadb_key *, key0, len); + if (sav->key_enc == NULL) { + printf("key_setsaval: No more memory.\n"); + error = ENOBUFS; + goto err; + } + + /* make length shift up for kernel*/ + sav->key_enc->sadb_key_len = len; + } + + /* set iv */ + sav->ivlen = 0; + + switch (msg0->sadb_msg_satype) { + case SADB_SATYPE_ESP: +#ifdef IPSEC_ESP + { + struct esp_algorithm *algo; + + algo = &esp_algorithms[sav->alg_enc]; + if (algo && algo->ivlen) + sav->ivlen = (*algo->ivlen)(sav); + KMALLOC(sav->iv, caddr_t, sav->ivlen); + if (sav->iv == 0) { + printf("key_setsaval: No more memory.\n"); + error = ENOBUFS; + goto err; + } + /* initialize ? */ + break; + } +#else + break; #endif + case SADB_SATYPE_AH: + break; + default: + printf("key_setsaval: invalid SA type.\n"); + error = EINVAL; + goto err; + } - /* - * This is slow, but simple. - */ - DPRINTF(IDL_FINISHED,("Flushing key table...")); - for (i = 0; i < KEYTBLSIZE; i++) { - timo = 0; - while ((keynode = keytable[i].next)) { - if (key_delete(keynode->secassoc) != 0) - panic("key_flush"); - timo++; - if (10000 < timo) { -printf("key_flush: timo exceeds limit; terminate the loop to prevent hangup\n"); - break; - } + /* reset tick */ + sav->tick = 0; + + /* make lifetime for CURRENT */ + { + struct timeval tv; + + KMALLOC(sav->lft_c, struct sadb_lifetime *, + sizeof(struct sadb_lifetime)); + if (sav->lft_c == NULL) { + printf("key_setsaval: No more memory.\n"); + error = ENOBUFS; + goto err; + } + + microtime(&tv); + + sav->lft_c->sadb_lifetime_len = + PFKEY_UNIT64(sizeof(struct sadb_lifetime)); + sav->lft_c->sadb_lifetime_exttype = SADB_EXT_LIFETIME_CURRENT; + sav->lft_c->sadb_lifetime_allocations = 0; + sav->lft_c->sadb_lifetime_bytes = 0; + sav->lft_c->sadb_lifetime_addtime = tv.tv_sec; + sav->lft_c->sadb_lifetime_usetime = 0; } - } - DPRINTF(IDL_FINISHED,("done\n")); + + /* lifetimes for HARD and SOFT */ + { + struct sadb_lifetime *lft0; + + lft0 = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_HARD]; + if (lft0 != NULL) { + KEY_NEWBUF(sav->lft_h, struct sadb_lifetime *, + lft0, sizeof(*lft0)); + if (sav->lft_h == NULL) { + printf("key_setsaval: No more memory.\n"); + error = ENOBUFS; + goto err; + } + /* to be initialize ? */ + } + + lft0 = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_SOFT]; + if (lft0 != NULL) { + KEY_NEWBUF(sav->lft_s, struct sadb_lifetime *, + lft0, sizeof(*lft0)); + if (sav->lft_s == NULL) { + printf("key_setsaval: No more memory.\n"); + error = ENOBUFS; + goto err; + } + /* to be initialize ? */ + } + } + + msg0->sadb_msg_errno = 0; + return 0; + + err: + /* initialization */ + if (sav->replay != NULL) { + if (sav->replay->bitmap != NULL) + KFREE(sav->replay->bitmap); + KFREE(sav->replay); + } + if (sav->key_auth != NULL) + KFREE(sav->key_auth); + if (sav->key_enc != NULL) + KFREE(sav->key_enc); + if (sav->iv != NULL) + KFREE(sav->iv); + if (sav->lft_c != NULL) + KFREE(sav->lft_c); + if (sav->lft_h != NULL) + KFREE(sav->lft_h); + if (sav->lft_s != NULL) + KFREE(sav->lft_s); + + msg0->sadb_msg_errno = error; + return 1; } +/* + * get message buffer length. + */ +static u_int +key_getmsglen(sav) + struct secasvar *sav; +{ + int len = sizeof(struct sadb_msg); + + len += sizeof(struct sadb_sa); + len += (sizeof(struct sadb_address) + + PFKEY_ALIGN8(_SALENBYAF(sav->sah->saidx.src.__ss_family))); + len += (sizeof(struct sadb_address) + + PFKEY_ALIGN8(_SALENBYAF(sav->sah->saidx.dst.__ss_family))); + + if (sav->key_auth != NULL) + len += sav->key_auth->sadb_key_len; + if (sav->key_enc != NULL) + len += sav->key_enc->sadb_key_len; + + if (sav->lft_c != NULL) + len += sizeof(struct sadb_lifetime); + if (sav->lft_h != NULL) + len += sizeof(struct sadb_lifetime); + if (sav->lft_s != NULL) + len += sizeof(struct sadb_lifetime); + + return len; +} -/*---------------------------------------------------------------------- - * key_getspi(): - * Get a unique spi value for a key management daemon/program. The - * spi value, once assigned, cannot be assigned again (as long as the - * entry with that same spi value remains in the table). - ----------------------------------------------------------------------*/ -int -key_getspi(type, vers, src, dst, lowval, highval, spi) - u_int type; - u_int vers; - struct sockaddr *src; - struct sockaddr *dst; - u_int32_t lowval; - u_int32_t highval; - u_int32_t *spi; -{ - struct key_secassoc *secassoc; - struct key_tblnode *keynode, *prevkeynode; - int count, done, len, indx; - int maxcount = 1000; - u_int32_t val; - char buf[MAXHASHKEYLEN]; - CRITICAL_DCL - - DPRINTF(IDL_EVENT,("Entering getspi w/type=%d,low=%u,high=%u\n", - type, lowval, highval)); - if (!(src && dst)) - return(EINVAL); - - if ((lowval == 0) || (highval == 0)) - return(EINVAL); - - if (lowval > highval) { - u_int32_t temp; - temp = lowval; - lowval = highval; - highval = lowval; - } +/* + * validation with a secasvar entry, and set SADB_SATYPE_MATURE. + * OUT: 0: valid + * other: errno + */ +static int +key_mature(sav) + struct secasvar *sav; +{ + int mature; + int checkmask = 0; /* 2^0: ealg 2^1: aalg 2^2: calg */ + int mustmask = 0; /* 2^0: ealg 2^1: aalg 2^2: calg */ - done = count = 0; - do { - count++; - /* - * This may not be "random enough". - */ - val = lowval + (random() % (highval - lowval + 1)); - - if (lowval == highval) - count = maxcount; - DPRINTF(IDL_FINISHED,("%u ",val)); - if (val) { - DPRINTF(IDL_FINISHED,("\n")); - bzero(&buf, sizeof(buf)); - len = key_createkey((char *)&buf, type, src, dst, val, 0); - indx = key_gethashval((char *)&buf, len, KEYTBLSIZE); - if (!key_search(type, src, dst, val, indx, &prevkeynode)) { - CRITICAL_START; - KMALLOC(secassoc, struct key_secassoc *, sizeof(struct key_secassoc)); - if (secassoc == 0) { - DPRINTF(IDL_ERROR,("key_getspi: can't allocate memory\n")); - CRITICAL_END; - return(ENOBUFS); - } - bzero((char *)secassoc, sizeof(*secassoc)); - - DPRINTF(IDL_FINISHED,("getspi: indx=%d\n",indx)); - secassoc->len = sizeof(struct key_secassoc); - secassoc->type = type; - secassoc->vers = vers; - secassoc->spi = val; - secassoc->state |= K_LARVAL; - if (my_addr(dst)) - secassoc->state |= K_INBOUND; - if (my_addr(src)) - secassoc->state |= K_OUTBOUND; - - KMALLOC(secassoc->src, struct sockaddr *, src->sa_len); - if (!secassoc->src) { - DPRINTF(IDL_ERROR,("key_getspi: can't allocate memory\n")); - KFREE(secassoc); - CRITICAL_END; - return(ENOBUFS); - } - bcopy((char *)src, (char *)secassoc->src, src->sa_len); - KMALLOC(secassoc->dst, struct sockaddr *, dst->sa_len); - if (!secassoc->dst) { - DPRINTF(IDL_ERROR,("key_getspi: can't allocate memory\n")); - KFREE(secassoc->src); - KFREE(secassoc); - CRITICAL_END; - return(ENOBUFS); - } - bcopy((char *)dst, (char *)secassoc->dst, dst->sa_len); - - /* We fill this in with a plausable value now to insure - that other routines don't break. These will get - overwritten later with the correct values. */ -#if 0 -#ifdef INET6 - secassoc->from->sa_family = AF_INET6; - secassoc->from->sa_len = sizeof(struct sockaddr_in6); -#else /* INET6 */ - secassoc->from->sa_family = AF_INET; - secassoc->from->sa_len = sizeof(struct sockaddr_in); -#endif /* INET6 */ + mature = 0; + + /* check SPI value */ + if (ntohl(sav->spi) >= 0 && ntohl(sav->spi) <= 255) { + printf("key_mature: illegal range of SPI %d.\n", sav->spi); + return EINVAL; + } + + /* check satype */ + switch (sav->sah->saidx.proto) { + case IPPROTO_ESP: + /* check flags */ + if ((sav->flags & SADB_X_EXT_OLD) + && (sav->flags & SADB_X_EXT_DERIV)) { + printf("key_mature: " + "invalid flag (derived) given to old-esp.\n"); + return EINVAL; + } + checkmask = 3; + mustmask = 1; + break; + case IPPROTO_AH: + /* check flags */ + if (sav->flags & SADB_X_EXT_DERIV) { + printf("key_mature: " + "invalid flag (derived) given to AH SA.\n"); + return EINVAL; + } + if (sav->alg_enc != SADB_EALG_NONE) { + printf("key_mature: " + "protocol and algorithm mismated.\n"); + return(EINVAL); + } + checkmask = 2; + mustmask = 2; + break; + default: + printf("key_mature: Invalid satype.\n"); + return EPROTONOSUPPORT; + } + + /* check authentication algorithm */ + if ((checkmask & 2) != 0) { + struct ah_algorithm *algo; + int keylen; + + /* XXX: should use algorithm map to check. */ + switch (sav->alg_auth) { + case SADB_AALG_NONE: + case SADB_AALG_MD5HMAC: + case SADB_AALG_SHA1HMAC: + case SADB_AALG_MD5: + case SADB_AALG_SHA: + case SADB_AALG_NULL: + break; + default: + printf("key_mature: " + "unknown authentication algorithm.\n"); + return EINVAL; + } + + /* algorithm-dependent check */ + algo = &ah_algorithms[sav->alg_auth]; + + if (sav->key_auth) + keylen = sav->key_auth->sadb_key_bits; + else + keylen = 0; + if (keylen < algo->keymin || algo->keymax < keylen) { + printf("key_mature: invalid AH key length %d " + "(%d-%d allowed)\n", keylen, + algo->keymin, algo->keymax); + return EINVAL; + } + + if (algo->mature) { + if ((*algo->mature)(sav)) { + /* message generated in per-algorithm function*/ + return EINVAL; + } else + mature = SADB_SATYPE_AH; + } + + if ((mustmask & 2) != 0 && mature != SADB_SATYPE_AH) + return EINVAL; + } + + /* check encryption algorithm */ + if ((checkmask & 1) != 0) { +#ifdef IPSEC_ESP + struct esp_algorithm *algo; + int keylen; + + switch (sav->alg_enc) { + case SADB_EALG_NONE: + case SADB_EALG_DESCBC: + case SADB_EALG_3DESCBC: + case SADB_EALG_NULL: + case SADB_EALG_BLOWFISHCBC: + case SADB_EALG_CAST128CBC: + case SADB_EALG_RC5CBC: + break; + default: + printf("key_mature: unknown encryption algorithm.\n"); + return(EINVAL); + } + + /* algorithm-dependent check */ + algo = &esp_algorithms[sav->alg_enc]; + + if (sav->key_enc) + keylen = sav->key_enc->sadb_key_bits; + else + keylen = 0; + if (keylen < algo->keymin || algo->keymax < keylen) { + printf("key_mature: invalid ESP key length %d " + "(%d-%d allowed)\n", keylen, + algo->keymin, algo->keymax); + return EINVAL; + } + + if (algo->mature) { + if ((*algo->mature)(sav)) { + /* message generated in per-algorithm function*/ + return EINVAL; + } else + mature = SADB_SATYPE_ESP; + } + + if ((mustmask & 1) != 0 && mature != SADB_SATYPE_ESP) + return EINVAL; +#else + printf("key_mature: ESP not supported in this configuration\n"); + return EINVAL; #endif + } - /* - * We need to add code to age these larval key table - * entries so they don't linger forever waiting for - * a KEY_UPDATE message that may not come for various - * reasons. This is another task that key_reaper can - * do once we have it coded. - */ - secassoc->lifetime1 += time_second + maxlarvallifetime; - - if (!(keynode = key_addnode(indx, secassoc))) { - DPRINTF(IDL_ERROR,("key_getspi: can't add node\n")); - CRITICAL_END; - return(ENOBUFS); - } - DPRINTF(IDL_FINISHED,("key_getspi: added node 0x%x\n", - (unsigned int)keynode)); - done++; - CRITICAL_END; - } - } - } while ((count < maxcount) && !done); - DPRINTF(IDL_EVENT,("getspi returns w/spi=%u,count=%d\n",val,count)); - if (done) { - *spi = val; - return(0); - } else { - *spi = 0; - return(EADDRNOTAVAIL); - } + key_sa_chgstate(sav, SADB_SASTATE_MATURE); + + return 0; } +/* + * subroutine for SADB_GET and SADB_DUMP. + * the buf must be allocated sufficent space. + */ +static u_int +key_setdumpsa(newmsg, sav, type, satype, seq, pid) + struct sadb_msg *newmsg; + struct secasvar *sav; + u_int8_t type, satype; + u_int32_t seq, pid; +{ + u_int tlen; + caddr_t p; + int i; + + tlen = key_getmsglen(sav); + + p = key_setsadbmsg((caddr_t)newmsg, type, tlen, + satype, seq, pid, + sav->sah->saidx.mode, sav->refcnt); + + for (i = 1; i <= SADB_EXT_MAX; i++) { + switch (i) { + case SADB_EXT_SA: + p = key_setsadbsa(p, sav); + break; + + case SADB_EXT_ADDRESS_SRC: + p = key_setsadbaddr(p, + SADB_EXT_ADDRESS_SRC, + (struct sockaddr *)&sav->sah->saidx.src, + _INALENBYAF(sav->sah->saidx.src.__ss_family) << 3, + IPSEC_ULPROTO_ANY); + break; + + case SADB_EXT_ADDRESS_DST: + p = key_setsadbaddr(p, + SADB_EXT_ADDRESS_DST, + (struct sockaddr *)&sav->sah->saidx.dst, + _INALENBYAF(sav->sah->saidx.dst.__ss_family) << 3, + IPSEC_ULPROTO_ANY); + break; + + case SADB_EXT_KEY_AUTH: + { + u_int len; + if (sav->key_auth == NULL) break; + len = sav->key_auth->sadb_key_len; /* real length */ + bcopy((caddr_t)sav->key_auth, p, len); + ((struct sadb_ext *)p)->sadb_ext_len = PFKEY_UNIT64(len); + p += len; + } + break; + + case SADB_EXT_KEY_ENCRYPT: + { + u_int len; + if (sav->key_enc == NULL) break; + len = sav->key_enc->sadb_key_len; /* real length */ + bcopy((caddr_t)sav->key_enc, p, len); + ((struct sadb_ext *)p)->sadb_ext_len = PFKEY_UNIT64(len); + p += len; + } + break;; + + case SADB_EXT_LIFETIME_CURRENT: + if (sav->lft_c == NULL) break; + p = key_setsadbext(p, (caddr_t)sav->lft_c); + break; + + case SADB_EXT_LIFETIME_HARD: + if (sav->lft_h == NULL) break; + p = key_setsadbext(p, (caddr_t)sav->lft_h); + break; + + case SADB_EXT_LIFETIME_SOFT: + if (sav->lft_s == NULL) break; + p = key_setsadbext(p, (caddr_t)sav->lft_s); + break; + + case SADB_EXT_IDENTITY_SRC: + case SADB_EXT_IDENTITY_DST: + /* XXX: should we brought from SPD ? */ + case SADB_EXT_SENSITIVITY: + default: + break; + } + } -/*---------------------------------------------------------------------- - * key_update(): - * Update a keytable entry that has an spi value assigned but is - * incomplete (e.g. no key/iv). - ----------------------------------------------------------------------*/ -int -key_update(secassoc) - struct key_secassoc *secassoc; -{ - struct key_tblnode *keynode, *prevkeynode; - struct key_allocnode *np = 0; - u_int8_t newstate; - int len, indx, inbound, outbound; - char buf[MAXHASHKEYLEN]; - CRITICAL_DCL - - bzero(&buf, sizeof(buf)); - len = key_createkey((char *)&buf, secassoc->type, secassoc->src, - secassoc->dst, secassoc->spi, 0); - indx = key_gethashval((char *)&buf, len, KEYTBLSIZE); - if(!(keynode = key_search(secassoc->type, secassoc->src, secassoc->dst, - secassoc->spi, indx, &prevkeynode))) { - return(ESRCH); - } - if (keynode->secassoc->state & K_DEAD) - return(ESRCH); + return tlen; +} - /* Should we also restrict updating of only LARVAL entries ? */ +/* + * set data into sadb_msg. + * `buf' must has been allocated sufficiently. + */ +static caddr_t +key_setsadbmsg(buf, type, tlen, satype, seq, pid, reserved1, reserved2) + caddr_t buf; + u_int8_t type, satype; + u_int16_t tlen; + u_int32_t seq; + pid_t pid; + u_int8_t reserved1; + u_int8_t reserved2; +{ + struct sadb_msg *p; + u_int len; + + p = (struct sadb_msg *)buf; + len = sizeof(struct sadb_msg); + + bzero(p, len); + p->sadb_msg_version = PF_KEY_V2; + p->sadb_msg_type = type; + p->sadb_msg_errno = 0; + p->sadb_msg_satype = satype; + p->sadb_msg_len = PFKEY_UNIT64(tlen); + p->sadb_msg_mode = reserved1; + p->sadb_msg_reserved = reserved2; + p->sadb_msg_seq = seq; + p->sadb_msg_pid = (u_int32_t)pid; + + return(buf + len); +} - CRITICAL_START; +/* + * copy secasvar data into sadb_address. + * `buf' must has been allocated sufficiently. + */ +static caddr_t +key_setsadbsa(buf, sav) + caddr_t buf; + struct secasvar *sav; +{ + struct sadb_sa *p; + u_int len; + + p = (struct sadb_sa *)buf; + len = sizeof(struct sadb_sa); + + bzero(p, len); + p->sadb_sa_len = PFKEY_UNIT64(len); + p->sadb_sa_exttype = SADB_EXT_SA; + p->sadb_sa_spi = sav->spi; + p->sadb_sa_replay = (sav->replay != NULL ? sav->replay->wsize : 0); + p->sadb_sa_state = sav->state; + p->sadb_sa_auth = sav->alg_auth; + p->sadb_sa_encrypt = sav->alg_enc; + p->sadb_sa_flags = sav->flags; + + return(buf + len); +} - inbound = my_addr(secassoc->dst); - outbound = my_addr(secassoc->src); +/* + * set data into sadb_address. + * `buf' must has been allocated sufficiently. + */ +static caddr_t +key_setsadbaddr(buf, exttype, saddr, prefixlen, ul_proto) + caddr_t buf; + u_int16_t exttype; + struct sockaddr *saddr; + u_int8_t prefixlen; + u_int16_t ul_proto; +{ + struct sadb_address *p; + u_int len; - newstate = keynode->secassoc->state; - newstate &= ~K_LARVAL; + p = (struct sadb_address *)buf; + len = sizeof(struct sadb_address) + PFKEY_ALIGN8(saddr->sa_len); - if (inbound) - newstate |= K_INBOUND; - if (outbound) - newstate |= K_OUTBOUND; + bzero(p, len); + p->sadb_address_len = PFKEY_UNIT64(len); + p->sadb_address_exttype = exttype; + p->sadb_address_proto = ul_proto; + p->sadb_address_prefixlen = prefixlen; + p->sadb_address_reserved = 0; - if (outbound || (!inbound && !outbound)) { - KMALLOC(np, struct key_allocnode *, sizeof(struct key_allocnode)); - if (np == 0) { - DPRINTF(IDL_ERROR,("keyupdate: can't allocate allocnode!\n")); - CRITICAL_END; - return(ENOBUFS); - } - } + bcopy(saddr, p + 1, saddr->sa_len); - /* - * Free the old key, iv if they're there. - */ - if (keynode->secassoc->key) - KFREE(keynode->secassoc->key); - if (keynode->secassoc->iv) - KFREE(keynode->secassoc->iv); - if (keynode->secassoc->ekey) - KFREE(keynode->secassoc->ekey); - - /* - * We now copy the secassoc over. We don't need to copy - * the key, iv into new buffers since the calling routine - * does that already. - */ - - *(keynode->secassoc) = *secassoc; - keynode->secassoc->state = newstate; - - /* - * Should we allow a null key to be inserted into the table ? - * or can we use null key to indicate some policy action... - */ - -#if 0 - if (keynode->secassoc->key && - (keynode->secassoc->type == KEY_TYPE_ESP) && - ((keynode->secassoc->algorithm == IPSEC_ALGTYPE_ESP_DES_CBC) || - (keynode->secassoc->algorithm == IPSEC_ALGTYPE_ESP_3DES))) - des_set_odd_parity(keynode->secassoc->key); -#endif /* 0 */ - - /* - * We now add an entry to the allocation table for this - * updated key table entry. - */ - if (outbound || (!inbound && !outbound)) { - len = key_createkey((char *)&buf, secassoc->type, secassoc->src, - secassoc->dst, 0, 1); - indx = key_gethashval((char *)&buf, len, KEYALLOCTBLSIZE); - DPRINTF(IDL_FINISHED,("keyupdate: keyalloc hash position=%d\n", indx)); - np->keynode = keynode; - np->next = keyalloctbl[indx].next; - keyalloctbl[indx].next = np; - } + return(buf + len); +} + +/* + * set data into sadb_ident. + * `buf' must has been allocated sufficiently. + */ +static caddr_t +key_setsadbident(buf, exttype, idtype, string, stringlen, id) + caddr_t buf; + u_int16_t exttype, idtype; + caddr_t string; + int stringlen; + u_int64_t id; +{ + struct sadb_ident *p; + u_int len; + + p = (struct sadb_ident *)buf; + len = sizeof(struct sadb_ident) + PFKEY_ALIGN8(stringlen); - key_deleteacquire(secassoc->type, (struct sockaddr *)&(secassoc->dst)); + bzero(p, len); + p->sadb_ident_len = PFKEY_UNIT64(len); + p->sadb_ident_exttype = exttype; + p->sadb_ident_type = idtype; + p->sadb_ident_reserved = 0; + p->sadb_ident_id = id; - CRITICAL_END; - return(0); + bcopy(string, p + 1, stringlen); + + return(buf + len); } -/*---------------------------------------------------------------------- - * key_register(): - * Register a socket as one capable of acquiring security associations - * for the kernel. - ----------------------------------------------------------------------*/ -int -key_register(socket, type) - struct socket *socket; - u_int type; -{ - struct key_registry *p, *new; - CRITICAL_DCL - - CRITICAL_START; - - DPRINTF(IDL_EVENT,("Entering key_register w/so=0x%x,type=%d\n", - (unsigned int)socket,type)); - - if (!(keyregtable && socket)) - panic("key_register"); - - /* - * Make sure entry is not already in table - */ - for(p = keyregtable->next; p; p = p->next) { - if ((p->type == type) && (p->socket == socket)) { - CRITICAL_END; - return(EEXIST); - } - } +/* + * copy buffer of any sadb extension type into sadb_ext. + * assume that sadb_ext_len shifted down >> 3. + * i.e. shift length up when setting length of extension. + */ +static caddr_t +key_setsadbext(p, ext) + caddr_t p, ext; +{ + u_int len; - KMALLOC(new, struct key_registry *, sizeof(struct key_registry)); - if (new == 0) { - CRITICAL_END; - return(ENOBUFS); - } - new->type = type; - new->socket = socket; - new->next = keyregtable->next; - keyregtable->next = new; - CRITICAL_END; - return(0); -} - -/*---------------------------------------------------------------------- - * key_unregister(): - * Delete entries from the registry list. - * allflag = 1 : delete all entries with matching socket - * allflag = 0 : delete only the entry matching socket, type - ----------------------------------------------------------------------*/ -void -key_unregister(socket, type, allflag) - struct socket *socket; - u_int type; - int allflag; -{ - struct key_registry *p, *prev; - CRITICAL_DCL - - CRITICAL_START; - - DPRINTF(IDL_EVENT,("Entering key_unregister w/so=0x%x,type=%d,flag=%d\n", - (unsigned int)socket, type, allflag)); - - if (!(keyregtable && socket)) - panic("key_register"); - prev = keyregtable; - for(p = keyregtable->next; p; p = p->next) { - if ((allflag && (p->socket == socket)) || - ((p->type == type) && (p->socket == socket))) { - prev->next = p->next; - KFREE(p); - p = prev; - } - prev = p; - } - CRITICAL_END; + len = PFKEY_UNUNIT64(((struct sadb_ext *)ext)->sadb_ext_len); + + bcopy(ext, p, len); + + return(p + len); } +/* %%% utilities */ +/* + * copy a buffer into the new buffer allocated. + */ +static void * +key_newbuf(src, len) + void *src; + u_int len; +{ + caddr_t new; -/*---------------------------------------------------------------------- - * key_acquire(): - * Send a key_acquire message to all registered key mgnt daemons - * capable of acquire security association of type type. - * - * Return: 0 if succesfully called key mgnt. daemon(s) - * -1 if not successfull. - ----------------------------------------------------------------------*/ + KMALLOC(new, caddr_t, len); + if (new == NULL) { + printf("key_newbuf: No more memory.\n"); + return NULL; + } + bcopy((caddr_t)src, new, len); + + return new; +} + +/* compare my own address + * OUT: 1: true, i.e. my address. + * 0: false + */ int -key_acquire(type, src, dst) - u_int type; - struct sockaddr *src; - struct sockaddr *dst; -{ - struct key_registry *p; - struct key_acquirelist *ap, *prevap; - int success = 0, created = 0; - u_int etype; - struct key_msghdr *km = NULL; - int len; - - DPRINTF(IDL_EVENT,("Entering key_acquire()\n")); - - if (!keyregtable || !src || !dst) - return (-1); - - /* - * We first check the acquirelist to see if a key_acquire - * message has been sent for this destination. - */ - etype = type; - prevap = key_acquirelist; - for(ap = key_acquirelist->next; ap; ap = ap->next) { - if (addrpart_equal(dst, ap->target) && - (etype == ap->type)) { - DPRINTF(IDL_EVENT,("acquire message previously sent!\n")); - if (ap->expiretime < time_second) { - DPRINTF(IDL_EVENT,("acquire message has expired!\n")); - ap->count = 0; - break; - } - if (ap->count < maxkeyacquire) { - DPRINTF(IDL_EVENT,("max acquire messages not yet exceeded!\n")); - break; - } - return(0); - } else if (ap->expiretime < time_second) { - /* - * Since we're already looking at the list, we may as - * well delete expired entries as we scan through the list. - * This should really be done by a function like key_reaper() - * but until we code key_reaper(), this is a quick, dirty - * hack. - */ - DPRINTF(IDL_EVENT,("found an expired entry...deleting it!\n")); - prevap->next = ap->next; - KFREE(ap); - ap = prevap; - } - prevap = ap; - } +key_ismyaddr(family, addr) + u_int family; + caddr_t addr; +{ + /* sanity check */ + if (addr == NULL) + panic("key_ismyaddr: NULL pointer is passed.\n"); + + switch (family) { + case AF_INET: + { + struct in_ifaddr *ia; + + for (ia = in_ifaddrhead.tqh_first; ia; + ia = ia->ia_link.tqe_next) + if (bcmp(addr, + (caddr_t)&ia->ia_addr.sin_addr, + _INALENBYAF(family)) == 0) + return 1; + } + break; +#ifdef INET6 + case AF_INET6: + return key_ismyaddr6(addr); +#endif + } - /* - * Scan registry, send KEY_ACQUIRE message to - * appropriate key management daemons. - */ - for(p = keyregtable->next; p; p = p->next) { - if (p->type != type) - continue; - - if (!created) { - len = sizeof(struct key_msghdr) + ROUNDUP(src->sa_len) + - ROUNDUP(dst->sa_len); - KMALLOC(km, struct key_msghdr *, len); - if (!km) { - DPRINTF(IDL_ERROR,("key_acquire: no memory\n")); - return(-1); - } - DPRINTF(IDL_FINISHED,("key_acquire/created: 1\n")); - bzero((char *)km, len); - km->key_msglen = len; - km->key_msgvers = KEY_VERSION; - km->key_msgtype = KEY_ACQUIRE; - km->type = type; - DPRINTF(IDL_FINISHED,("key_acquire/created: 2\n")); - /* - * This is inefficient, slow. - */ - - /* - * We zero out sin_zero here for AF_INET addresses because - * ip_output() currently does not do it for performance reasons. - */ - if (src->sa_family == AF_INET) - bzero((char *)(((struct sockaddr_in *)src)->sin_zero), - sizeof(((struct sockaddr_in *)src)->sin_zero)); - if (dst->sa_family == AF_INET) - bzero((char *)(((struct sockaddr_in *)dst)->sin_zero), - sizeof(((struct sockaddr_in *)dst)->sin_zero)); - - bcopy((char *)src, (char *)(km + 1), src->sa_len); - bcopy((char *)dst, (char *)((int)(km + 1) + ROUNDUP(src->sa_len)), - dst->sa_len); - DPRINTF(IDL_FINISHED,("key_acquire/created: 3\n")); - created++; - } - if (key_sendup(p->socket, km)) - success++; - } + return 0; +} + +#ifdef INET6 +/* + * compare my own address for IPv6. + * 1: ours + * 0: other + * NOTE: derived ip6_input() in KAME. This is necessary to modify more. + */ +#include <netinet6/in6.h> +#include <netinet6/in6_var.h> - if (km) - KFREE(km); - - /* - * Update the acquirelist - */ - if (success) { - if (!ap) { - DPRINTF(IDL_EVENT,("Adding new entry in acquirelist\n")); - KMALLOC(ap, struct key_acquirelist *, - sizeof(struct key_acquirelist) + dst->sa_len); - if (ap == 0) - return(success ? 0 : -1); - bzero((char *)ap, sizeof(struct key_acquirelist)); - ap->target = (struct sockaddr *)(ap + 1); - bcopy((char *)dst, (char *)ap->target, dst->sa_len); - ap->type = etype; - ap->next = key_acquirelist->next; - key_acquirelist->next = ap; - } - DPRINTF(IDL_GROSS_EVENT,("Updating acquire counter, expiration time\n")); - ap->count++; - ap->expiretime = time_second + maxacquiretime; - } - DPRINTF(IDL_EVENT,("key_acquire: done! success=%d\n",success)); - return(success ? 0 : -1); -} - -/*---------------------------------------------------------------------- - * key_alloc(): - * Allocate a security association to a socket. A socket requesting - * unique keying (per-socket keying) is assigned a security assocation - * exclusively for its use. Sockets not requiring unique keying are - * assigned the first security association which may or may not be - * used by another socket. - ----------------------------------------------------------------------*/ static int -key_alloc(type, src, dst, socket, unique_key, keynodep) - u_int type; - struct sockaddr *src; - struct sockaddr *dst; - struct socket *socket; - u_int unique_key; - struct key_tblnode **keynodep; -{ - struct key_tblnode *keynode; - char buf[MAXHASHKEYLEN]; - struct key_allocnode *np, *prevnp; - struct key_so2spinode *newnp; - int len; - int indx; - - DPRINTF(IDL_FINISHED,("Entering key_alloc w/type=%u!\n",type)); - if (!(src && dst)) { - DPRINTF(IDL_ERROR,("key_alloc: received null src or dst!\n")); - return(-1); - } +key_ismyaddr6(addr) + caddr_t addr; +{ + struct in6_addr *a = (struct in6_addr *)addr; + struct in6_ifaddr *ia; + + for (ia = in6_ifaddr; ia; ia = ia->ia_next) { + if (bcmp(addr, (caddr_t)&ia->ia_addr.sin6_addr, + _INALENBYAF(AF_INET6)) == 0) { + return 1; + } + + /* XXX Multicast */ + { + struct in6_multi *in6m = 0; + + IN6_LOOKUP_MULTI(*(struct in6_addr *)addr, ia->ia_ifp, in6m); + if (in6m) + return 1; + } + } - /* - * Search key allocation table - */ - bzero((char *)&buf, sizeof(buf)); - len = key_createkey((char *)&buf, type, src, dst, 0, 1); - indx = key_gethashval((char *)&buf, len, KEYALLOCTBLSIZE); - -#define np_type np->keynode->secassoc->type -#define np_state np->keynode->secassoc->state -#define np_src np->keynode->secassoc->src -#define np_dst np->keynode->secassoc->dst - - prevnp = &keyalloctbl[indx]; - for (np = keyalloctbl[indx].next; np; np = np->next) { - if ((type == np_type) && addrpart_equal(src, np_src) && - addrpart_equal(dst, np_dst) && - !(np_state & (K_LARVAL | K_DEAD | K_UNIQUE))) { - if (!(unique_key)) - break; - if (!(np_state & K_USED)) - break; - } - prevnp = np; - } + /* loopback, just for safety */ + if (IN6_IS_ADDR_LOOPBACK(a)) + return 1; - if (np) { - struct socketlist *newsp; - CRITICAL_DCL + /* XXX anycast */ - CRITICAL_START; + return 0; +} +#endif /*INET6*/ - DPRINTF(IDL_EVENT,("key_alloc: found node to allocate\n")); - keynode = np->keynode; +/* + * compare two secasindex structure exactly. + * IN: + * saidx0: source, it can be in SAD. + * saidx1: object, it can be from SPD. + * OUT: + * 1 : equal + * 0 : not equal + */ +static int +key_cmpsaidx_exactly(saidx0, saidx1) + struct secasindex *saidx0, *saidx1; +{ + /* sanity */ + if (saidx0 == NULL && saidx1 == NULL) + return 1; - KMALLOC(newnp, struct key_so2spinode *, sizeof(struct key_so2spinode)); - if (newnp == 0) { - DPRINTF(IDL_ERROR,("key_alloc: Can't alloc mem for so2spi node!\n")); - CRITICAL_END; - return(ENOBUFS); - } - KMALLOC(newsp, struct socketlist *, sizeof(struct socketlist)); - if (newsp == 0) { - DPRINTF(IDL_ERROR,("key_alloc: Can't alloc mem for socketlist!\n")); - if (newnp) - KFREE(newnp); - CRITICAL_END; - return(ENOBUFS); - } + if (saidx0 == NULL || saidx1 == NULL) + return 0; - /* - * Add a hash entry into the so2spi table to - * map socket to allocated secassoc. - */ - DPRINTF(IDL_FINISHED,("key_alloc: adding entry to so2spi table...")); - newnp->keynode = keynode; - newnp->socket = socket; - newnp->next = so2spitbl[((u_int32_t)socket) % SO2SPITBLSIZE].next; - so2spitbl[((u_int32_t)socket) % SO2SPITBLSIZE].next = newnp; - DPRINTF(IDL_FINISHED,("done\n")); - - if (unique_key) { - /* - * Need to remove the allocation entry - * since the secassoc is now unique, - * can't be allocated to any other socket - */ - DPRINTF(IDL_EVENT,("key_alloc: making keynode unique...")); - keynode->secassoc->state |= K_UNIQUE; - prevnp->next = np->next; - KFREE(np); - DPRINTF(IDL_EVENT,("done\n")); - } - keynode->secassoc->state |= K_USED; - keynode->secassoc->state |= K_OUTBOUND; - keynode->alloc_count++; - - /* - * Add socket to list of socket using secassoc. - */ - DPRINTF(IDL_FINISHED,("key_alloc: adding so to solist...")); - newsp->socket = socket; - newsp->next = keynode->solist->next; - keynode->solist->next = newsp; - DPRINTF(IDL_FINISHED,("done\n")); - *keynodep = keynode; - CRITICAL_END; - return(0); - } - *keynodep = NULL; - return(0); -} - - -/*---------------------------------------------------------------------- - * key_free(): - * Decrement the refcount for a key table entry. If the entry is - * marked dead,, the refcount is zero, we go ahead, delete it. - ----------------------------------------------------------------------*/ -void -key_free(keynode) - struct key_tblnode *keynode; -{ - DPRINTF(IDL_GROSS_EVENT,("Entering key_free w/keynode=0x%x\n", - (unsigned int)keynode)); - if (!keynode) { - DPRINTF(IDL_ERROR,("Warning: key_free got null pointer\n")); - return; - } - (keynode->ref_count)--; - if (keynode->ref_count < 0) { - DPRINTF(IDL_ERROR,("Warning: key_free decremented refcount to %d\n",keynode->ref_count)); - } - if ((keynode->secassoc->state & K_DEAD) && (keynode->ref_count <= 0)) { - DPRINTF(IDL_GROSS_EVENT,("key_free: calling key_delete\n")); - key_delete(keynode->secassoc); - } -} + if (saidx0->proto != saidx1->proto + || saidx0->mode != saidx1->mode) + return 0; -/*---------------------------------------------------------------------- - * getassocbyspi(): - * Get a security association for a given type, src, dst,, spi. - * - * Returns: 0 if sucessfull - * -1 if error/not found - * - * Caller must convert spi to host order. Function assumes spi is - * in host order! - ----------------------------------------------------------------------*/ -int -getassocbyspi(type, src, dst, spi, keyentry) - u_int type; - struct sockaddr *src; - struct sockaddr *dst; - u_int32_t spi; - struct key_tblnode **keyentry; -{ - char buf[MAXHASHKEYLEN]; - int len, indx; - struct key_tblnode *keynode, *prevkeynode = 0; - - DPRINTF(IDL_FINISHED,("Entering getassocbyspi w/type=%u spi=%u\n",type,spi)); - - *keyentry = NULL; - bzero(&buf, sizeof(buf)); - len = key_createkey((char *)&buf, type, src, dst, spi, 0); - indx = key_gethashval((char *)&buf, len, KEYTBLSIZE); - DPRINTF(IDL_FINISHED,("getassocbyspi: indx=%d\n",indx)); - DDO(IDL_FINISHED,dump_sockaddr(src);dump_sockaddr(dst)); - keynode = key_search(type, src, dst, spi, indx, &prevkeynode); - DPRINTF(IDL_FINISHED,("getassocbyspi: keysearch ret=0x%x\n", - (unsigned int)keynode)); - if (keynode && !(keynode->secassoc->state & (K_DEAD | K_LARVAL))) { - DPRINTF(IDL_GROSS_EVENT,("getassocbyspi: found secassoc!\n")); - (keynode->ref_count)++; - keynode->secassoc->state |= K_USED; - *keyentry = keynode; - } else { - DPRINTF(IDL_EVENT,("getassocbyspi: secassoc not found!\n")); - return (-1); - } - return(0); + if (bcmp(&saidx0->src, &saidx1->src, saidx0->src.__ss_len) != 0 + || bcmp(&saidx0->dst, &saidx1->dst, saidx0->dst.__ss_len) != 0) + return 0; + + return 1; } +/* + * compare two secasindex structure with consideration mode. + * don't compare port. + * IN: + * saidx0: source, it is often in SAD. + * saidx1: object, it is often from SPD. + * OUT: + * 1 : equal + * 0 : not equal + */ +static int +key_cmpsaidx_withmode(saidx0, saidx1) + struct secasindex *saidx0, *saidx1; +{ + /* sanity */ + if (saidx0 == NULL && saidx1 == NULL) + return 1; -/*---------------------------------------------------------------------- - * getassocbysocket(): - * Get a security association for a given type, src, dst,, socket. - * If not found, try to allocate one. - * Returns: 0 if successfull - * -1 if error condition/secassoc not found (*keyentry = NULL) - * 1 if secassoc temporarily unavailable (*keynetry = NULL) - * (e.g., key mgnt. daemon(s) called) - ----------------------------------------------------------------------*/ -int -getassocbysocket(type, src, dst, socket, unique_key, keyentry) - u_int type; - struct sockaddr *src; - struct sockaddr *dst; - struct socket *socket; - u_int unique_key; - struct key_tblnode **keyentry; -{ - struct key_tblnode *keynode = 0; - struct key_so2spinode *np; - u_int realtype; - - DPRINTF(IDL_FINISHED,("Entering getassocbysocket w/type=%u so=0x%x\n", - type,(unsigned int)socket)); - - /* - * We treat esp-transport mode, esp-tunnel mode - * as a single type in the keytable. This has a side - * effect that socket using both esp-transport, - * esp-tunnel will use the same security association - * for both modes. Is this a problem? - */ - realtype = type; - if ((np = key_sosearch(type, src, dst, socket))) { - if (np->keynode && np->keynode->secassoc && - !(np->keynode->secassoc->state & (K_DEAD | K_LARVAL))) { - DPRINTF(IDL_FINISHED,("getassocbysocket: found secassoc!\n")); - (np->keynode->ref_count)++; - *keyentry = np->keynode; - return(0); - } - } + if (saidx0 == NULL || saidx1 == NULL) + return 0; - /* - * No secassoc has been allocated to socket, - * so allocate one, if available - */ - DPRINTF(IDL_GROSS_EVENT,("getassocbyso: can't find it, trying to allocate!\n")); - if (key_alloc(realtype, src, dst, socket, unique_key, &keynode) == 0) { - if (keynode) { - DPRINTF(IDL_GROSS_EVENT,("getassocbyso: key_alloc found secassoc!\n")); - keynode->ref_count++; - *keyentry = keynode; - return(0); - } else { - /* - * Kick key mgnt. daemon(s) - * (this should be done in ipsec_output_policy() instead or - * selectively called based on a flag value) - */ - DPRINTF(IDL_FINISHED,("getassocbyso: calling key mgnt daemons!\n")); - *keyentry = NULL; - if (key_acquire(realtype, src, dst) == 0) - return (1); - else - return(-1); + if (saidx0->proto != saidx1->proto + || saidx0->src.__ss_family != saidx1->src.__ss_family + || saidx0->dst.__ss_family != saidx1->dst.__ss_family) + return 0; + + if (saidx0->mode != IPSEC_MODE_ANY + && saidx0->mode != saidx1->mode) + return 0; + + { + int sa_len = _INALENBYAF(saidx0->src.__ss_family); + + if (bcmp(_INADDRBYSA(&saidx0->src), _INADDRBYSA(&saidx1->src), sa_len) + || bcmp(_INADDRBYSA(&saidx0->dst), _INADDRBYSA(&saidx1->dst), sa_len)) + return 0; } - } - *keyentry = NULL; - return(-1); + + return 1; } -/*---------------------------------------------------------------------- - * key_xdata(): - * Parse message buffer for src/dst/from/iv/key if parseflag = 0 - * else parse for src/dst only. - ----------------------------------------------------------------------*/ +/* + * compare two secindex structure exactly. + * IN: + * spidx0: source, it is often in SPD. + * spidx1: object, it is often from PFKEY message. + * OUT: + * 1 : equal + * 0 : not equal + */ static int -key_xdata(km, kip, parseflag) - struct key_msghdr *km; - struct key_msgdata *kip; - int parseflag; +key_cmpspidx_exactly(spidx0, spidx1) + struct secpolicyindex *spidx0, *spidx1; { - char *cp, *cpmax; + /* sanity */ + if (spidx0 == NULL && spidx1 == NULL) + return 1; - if (!km || (km->key_msglen <= 0)) - return (-1); + if (spidx0 == NULL || spidx1 == NULL) + return 0; - cp = (caddr_t)(km + 1); - cpmax = (caddr_t)km + km->key_msglen; + if (spidx0->prefs != spidx1->prefs + || spidx0->prefd != spidx1->prefd + || spidx0->ul_proto != spidx1->ul_proto) + return 0; - /* - * Assumes user process passes message with - * correct word alignment. - */ + if (bcmp(&spidx0->src, &spidx1->src, spidx0->src.__ss_len) != 0 + || bcmp(&spidx0->dst, &spidx1->dst, spidx0->dst.__ss_len) != 0) + return 0; - /* - * Need to clean up this code later. - */ + return 1; +} - /* Grab src addr */ - kip->src = (struct sockaddr *)cp; - if (!kip->src->sa_len) { - DPRINTF(IDL_MAJOR_EVENT,("key_xdata couldn't parse src addr\n")); - return(-1); - } +/* + * compare two secindex structure with mask. + * IN: + * spidx0: source, it is often in SPD. + * spidx1: object, it is often from IP header. + * OUT: + * 1 : equal + * 0 : not equal + */ +static int +key_cmpspidx_withmask(spidx0, spidx1) + struct secpolicyindex *spidx0, *spidx1; +{ + /* sanity */ + if (spidx0 == NULL && spidx1 == NULL) + return 1; - ADVANCE(cp, kip->src->sa_len); + if (spidx0 == NULL || spidx1 == NULL) + return 0; - /* Grab dest addr */ - kip->dst = (struct sockaddr *)cp; - if (!kip->dst->sa_len) { - DPRINTF(IDL_MAJOR_EVENT,("key_xdata couldn't parse dest addr\n")); - return(-1); - } + if (spidx0->src.__ss_family != spidx1->src.__ss_family + || spidx0->dst.__ss_family != spidx1->dst.__ss_family) + return 0; - ADVANCE(cp, kip->dst->sa_len); - if (parseflag == 1) { - kip->from = 0; - kip->key = kip->iv = kip->ekey = 0; - kip->keylen = kip->ivlen = kip->ekeylen = 0; - return(0); - } - - /* Grab from addr */ - kip->from = (struct sockaddr *)cp; - if (!kip->from->sa_len) { - DPRINTF(IDL_MAJOR_EVENT,("key_xdata couldn't parse from addr\n")); - return(-1); - } + /* if spidx.ul_proto == IPSEC_ULPROTO_ANY, ignore. */ + if (spidx0->ul_proto != (u_int16_t)IPSEC_ULPROTO_ANY + && spidx0->ul_proto != spidx1->ul_proto) + return 0; - ADVANCE(cp, kip->from->sa_len); - - /* Grab key */ - if ((kip->keylen = km->keylen)) { - kip->key = cp; - ADVANCE(cp, km->keylen); - } else - kip->key = 0; + if (_INPORTBYSA(&spidx0->src) != IPSEC_PORT_ANY + && _INPORTBYSA(&spidx0->src) != _INPORTBYSA(&spidx1->src)) + return 0; - /* Grab iv */ - if ((kip->ivlen = km->ivlen)) { - kip->iv = cp; - ADVANCE(cp, km->ivlen); - } else - kip->iv = 0; + if (_INPORTBYSA(&spidx0->dst) != IPSEC_PORT_ANY + && _INPORTBYSA(&spidx0->dst) != _INPORTBYSA(&spidx1->dst)) + return 0; - /* Grab ekey */ - if ((kip->ekeylen = km->ekeylen)) { - kip->ekey = cp; - ADVANCE(cp, km->ekeylen); - } else - kip->ekey = 0; + if (!key_bbcmp(_INADDRBYSA(&spidx0->src), + _INADDRBYSA(&spidx1->src), + spidx0->prefs)) + return 0; - return (0); -} + if (!key_bbcmp(_INADDRBYSA(&spidx0->dst), + _INADDRBYSA(&spidx1->dst), + spidx0->prefd)) + return 0; + /* XXX Do we check other field ? e.g. flowinfo, scope_id. */ -int -key_parse(kmp, so, dstfamily) - struct key_msghdr **kmp; - struct socket *so; - int *dstfamily; + return 1; +} + +/* + * compare two buffers with mask. + * IN: + * addr1: source + * addr2: object + * bits: Number of bits to compare + * OUT: + * 1 : equal + * 0 : not equal + */ +static int +key_bbcmp(p1, p2, bits) + register caddr_t p1, p2; + register u_int bits; { - int error = 0, keyerror = 0; - struct key_msgdata keyinfo; - struct key_secassoc *secassoc = NULL; - struct key_msghdr *km = *kmp; + u_int8_t mask; - DPRINTF(IDL_MAJOR_EVENT, ("Entering key_parse\n")); + /* XXX: This could be considerably faster if we compare a word + * at a time, but it is complicated on LSB Endian machines */ -#define senderr(e) \ - { error = (e); goto flush; } + /* Handle null pointers */ + if (p1 == NULL || p2 == NULL) + return (p1 == p2); - if (km->key_msgvers != KEY_VERSION) { - DPRINTF(IDL_CRITICAL,("keyoutput: Unsupported key message version!\n")); - senderr(EPROTONOSUPPORT); - } + while (bits >= 8) { + if (*p1++ != *p2++) + return 0; + bits -= 8; + } - km->key_pid = curproc->p_pid; + if (bits > 0) { + mask = ~((1<<(8-bits))-1); + if ((*p1 & mask) != (*p2 & mask)) + return 0; + } + return 1; /* Match! */ +} - DDO(IDL_MAJOR_EVENT, printf("keymsghdr:\n"); dump_keymsghdr(km)); +/* + * time handler. + * scanning SPD and SAD to check status for each entries, + * and do to remove or to expire. + */ +void +key_timehandler(void) +{ + u_int dir; + int s; - /* - * Parse buffer for src addr, dest addr, from addr, key, iv - */ - bzero((char *)&keyinfo, sizeof(keyinfo)); + s = splnet(); /*called from softclock()*/ - switch (km->key_msgtype) { - case KEY_ADD: - DPRINTF(IDL_MAJOR_EVENT,("key_output got KEY_ADD msg\n")); + /* SPD */ + { + struct secpolicy *sp, *nextsp; - if (key_xdata(km, &keyinfo, 0) < 0) - goto parsefail; + for (dir = 0; dir < IPSEC_DIR_MAX; dir++) { + for (sp = LIST_FIRST(&sptree[dir]); + sp != NULL; + sp = nextsp) { - /* - * Allocate the secassoc structure to insert - * into key table here. - */ - KMALLOC(secassoc, struct key_secassoc *, sizeof(struct key_secassoc)); - if (secassoc == 0) { - DPRINTF(IDL_CRITICAL,("keyoutput: No more memory!\n")); - senderr(ENOBUFS); - } + nextsp = LIST_NEXT(sp, chain); - if (key_msghdr2secassoc(secassoc, km, &keyinfo) < 0) { - DPRINTF(IDL_CRITICAL,("keyoutput: key_msghdr2secassoc failed!\n")); - KFREE(secassoc); - senderr(EINVAL); + if (sp->state == IPSEC_SPSTATE_DEAD) + key_freesp(sp); + } + } } - DPRINTF(IDL_MAJOR_EVENT,("secassoc to add:\n")); - DDO(IDL_MAJOR_EVENT,dump_secassoc(secassoc)); - - if ((keyerror = key_add(secassoc)) != 0) { - DPRINTF(IDL_CRITICAL,("keyoutput: key_add failed\n")); - if (secassoc->key) - KFREE(secassoc->key); - if (secassoc->iv) - KFREE(secassoc->iv); - if (secassoc->ekey) - KFREE(secassoc->ekey); - KFREE(secassoc); - if (keyerror == -2) { - senderr(EEXIST); - } else { - senderr(ENOBUFS); - } + + /* SAD */ + { + struct secashead *sah, *nextsah; + struct secasvar *sav, *nextsav; + + for (sah = LIST_FIRST(&sahtree); + sah != NULL; + sah = nextsah) { + + nextsah = LIST_NEXT(sah, chain); + + /* if sah has been dead, then delete it and process next sah. */ + if (sah->state == SADB_SASTATE_DEAD) { + key_delsah(sah); + continue; + } + + /* if LARVAL entry doesn't become MATURE, delete it. */ + for (sav = LIST_FIRST(&sah->savtree[SADB_SASTATE_LARVAL]); + sav != NULL; + sav = nextsav) { + + nextsav = LIST_NEXT(sav, chain); + + sav->tick++; + + if (key_larval_lifetime < sav->tick) { + key_freesav(sav); + } + } + + /* + * check MATURE entry to start to send expire message + * whether or not. + */ + for (sav = LIST_FIRST(&sah->savtree[SADB_SASTATE_MATURE]); + sav != NULL; + sav = nextsav) { + + nextsav = LIST_NEXT(sav, chain); + + sav->tick++; + + /* we don't need to check. */ + if (sav->lft_s == NULL) + continue; + + /* sanity check */ + if (sav->lft_c == NULL) { + printf("key_timehandler: " + "There is no CURRENT time, why?\n"); + continue; + } + + /* compare SOFT lifetime and tick */ + if (sav->lft_s->sadb_lifetime_addtime != 0 + && sav->lft_s->sadb_lifetime_addtime < sav->tick) { + /* + * check SA to be used whether or not. + * when SA hasn't been used, delete it. + */ + if (sav->lft_c->sadb_lifetime_usetime == 0) { + key_sa_chgstate(sav, SADB_SASTATE_DEAD); + key_freesav(sav); + sav = NULL; + } else { + key_sa_chgstate(sav, SADB_SASTATE_DYING); + /* + * XXX If we keep to send expire + * message in the status of + * DYING. Do remove below code. + */ + key_expire(sav); + } + } + /* check SOFT lifetime by bytes */ + /* + * XXX I don't know the way to delete this SA + * when new SA is installed. Caution when it's + * installed too big lifetime by time. + */ + else if (sav->lft_s->sadb_lifetime_bytes != 0 + && sav->lft_s->sadb_lifetime_bytes < sav->lft_c->sadb_lifetime_bytes) { + + key_sa_chgstate(sav, SADB_SASTATE_DYING); + /* + * XXX If we keep to send expire + * message in the status of + * DYING. Do remove below code. + */ + key_expire(sav); + } + } + + /* check DYING entry to change status to DEAD. */ + for (sav = LIST_FIRST(&sah->savtree[SADB_SASTATE_DYING]); + sav != NULL; + sav = nextsav) { + + nextsav = LIST_NEXT(sav, chain); + + sav->tick++; + + /* we don't need to check. */ + if (sav->lft_h == NULL) + continue; + + /* sanity check */ + if (sav->lft_c == NULL) { + printf("key_timehandler: " + "There is no CURRENT time, why?\n"); + continue; + } + + /* compare HARD lifetime and tick */ + if (sav->lft_h->sadb_lifetime_addtime != 0 + && sav->lft_h->sadb_lifetime_addtime < sav->tick) { + key_sa_chgstate(sav, SADB_SASTATE_DEAD); + key_freesav(sav); + sav = NULL; + } + /* check HARD lifetime by bytes */ + else if (sav->lft_h->sadb_lifetime_bytes != 0 + && sav->lft_h->sadb_lifetime_bytes < sav->lft_c->sadb_lifetime_bytes) { + key_sa_chgstate(sav, SADB_SASTATE_DEAD); + key_freesav(sav); + sav = NULL; + } + } + + /* delete entry in DEAD */ + for (sav = LIST_FIRST(&sah->savtree[SADB_SASTATE_DEAD]); + sav != NULL; + sav = nextsav) { + + nextsav = LIST_NEXT(sav, chain); + + /* sanity check */ + if (sav->state != SADB_SASTATE_DEAD) { + printf("key_timehandler: " + "invalid sav->state " + "(queue: %d SA: %d): " + "kill it anyway\n", + SADB_SASTATE_DEAD, sav->state); + } + + /* + * do not call key_freesav() here. + * sav should already be freed, and sav->refcnt + * shows other references to sav + * (such as from SPD). + */ + } + } } - break; - case KEY_DELETE: - DPRINTF(IDL_MAJOR_EVENT,("key_output got KEY_DELETE msg\n")); - if (key_xdata(km, &keyinfo, 1) < 0) - goto parsefail; +#ifndef IPSEC_NONBLOCK_ACQUIRE + /* ACQ tree */ + { + struct secacq *acq, *nextacq; - KMALLOC(secassoc, struct key_secassoc *, sizeof(struct key_secassoc)); - if (secassoc == 0) { - senderr(ENOBUFS); - } - if (key_msghdr2secassoc(secassoc, km, &keyinfo) < 0) { - KFREE(secassoc); - senderr(EINVAL); - } - if (key_delete(secassoc) != 0) { - if (secassoc->iv) - KFREE(secassoc->iv); - if (secassoc->key) - KFREE(secassoc->key); - if (secassoc->ekey) - KFREE(secassoc->ekey); - KFREE(secassoc); - senderr(ESRCH); - } - if (secassoc->iv) - KFREE(secassoc->iv); - if (secassoc->key) - KFREE(secassoc->key); - if (secassoc->ekey) - KFREE(secassoc->ekey); - KFREE(secassoc); - break; - case KEY_UPDATE: - DPRINTF(IDL_EVENT,("key_output got KEY_UPDATE msg\n")); - - if (key_xdata(km, &keyinfo, 0) < 0) - goto parsefail; - - KMALLOC(secassoc, struct key_secassoc *, sizeof(struct key_secassoc)); - if (secassoc == 0) { - senderr(ENOBUFS); - } - if (key_msghdr2secassoc(secassoc, km, &keyinfo) < 0) { - KFREE(secassoc); - senderr(EINVAL); - } - if ((keyerror = key_update(secassoc)) != 0) { - DPRINTF(IDL_CRITICAL,("Error updating key entry\n")); - if (secassoc->iv) - KFREE(secassoc->iv); - if (secassoc->key) - KFREE(secassoc->key); - if (secassoc->ekey) - KFREE(secassoc->ekey); - KFREE(secassoc); - senderr(keyerror); - } - KFREE(secassoc); - break; - case KEY_GET: - DPRINTF(IDL_EVENT,("key_output got KEY_GET msg\n")); - - if (key_xdata(km, &keyinfo, 1) < 0) - goto parsefail; - - if (key_get(km->type, (struct sockaddr *)keyinfo.src, - (struct sockaddr *)keyinfo.dst, - km->spi, &secassoc) != 0) { - DPRINTF(IDL_EVENT,("keyoutput: can't get key\n")); - senderr(ESRCH); + for (acq = LIST_FIRST(&acqtree); + acq != NULL; + acq = nextacq) { + + nextacq = LIST_NEXT(acq, chain); + + acq->tick++; + + if (key_blockacq_lifetime < acq->tick && __LIST_CHAINED(acq)) { + LIST_REMOVE(acq, chain); + KFREE(acq); + } + } } +#endif - if (secassoc) { - int newlen; - - DPRINTF(IDL_EVENT,("keyoutput: Found secassoc!\n")); - newlen = sizeof(struct key_msghdr) + ROUNDUP(secassoc->src->sa_len) + - ROUNDUP(secassoc->dst->sa_len) + ROUNDUP(secassoc->from->sa_len) + - ROUNDUP(secassoc->keylen) + ROUNDUP(secassoc->ivlen) + - ROUNDUP(secassoc->ekeylen); - DPRINTF(IDL_EVENT,("keyoutput: newlen=%d\n", newlen)); - if (newlen > km->key_msglen) { - struct key_msghdr *newkm; - - DPRINTF(IDL_EVENT,("keyoutput: Allocating new buffer!\n")); - KMALLOC(newkm, struct key_msghdr *, newlen); - if (newkm == 0) { - senderr(ENOBUFS); - } - bcopy((char *)km, (char *)newkm, km->key_msglen); - DPRINTF(IDL_FINISHED,("keyoutput: 1\n")); - KFREE(km); - *kmp = km = newkm; - DPRINTF(IDL_CRITICAL, ("km->key_msglen = %d, newlen = %d\n", - km->key_msglen, newlen)); - km->key_msglen = newlen; - } - DPRINTF(IDL_FINISHED,("keyoutput: 2\n")); - if (key_secassoc2msghdr(secassoc, km, &keyinfo)) { - DPRINTF(IDL_CRITICAL,("keyoutput: Can't create msghdr!\n")); - senderr(EINVAL); + /* initialize random seed */ + if (key_tick_init_random++ > key_int_random) { + key_tick_init_random = 0; + key_srandom(); + } + +#ifndef IPSEC_DEBUG2 + /* do exchange to tick time !! */ + (void)timeout((void *)key_timehandler, (void *)0, 100); +#endif /* IPSEC_DEBUG2 */ + + splx(s); + return; +} + +/* + * to initialize a seed for random() + */ +void +key_srandom() +{ + struct timeval tv; + + microtime(&tv); + srandom(tv.tv_usec); + + return; +} + +/* + * map SADB_SATYPE_* to IPPROTO_*. + * if satype == SADB_SATYPE then satype is mapped to ~0. + * OUT: + * 0: invalid satype. + */ +static u_int16_t +key_satype2proto(satype) + u_int8_t satype; +{ + switch (satype) { + case SADB_SATYPE_UNSPEC: + return IPSEC_PROTO_ANY; + case SADB_SATYPE_AH: + return IPPROTO_AH; + case SADB_SATYPE_ESP: + return IPPROTO_ESP; + default: + return 0; + } + /* NOTREACHED */ +} + +/* + * map IPPROTO_* to SADB_SATYPE_* + * OUT: + * 0: invalid protocol type. + */ +static u_int8_t +key_proto2satype(proto) + u_int16_t proto; +{ + switch (proto) { + case IPPROTO_AH: + return SADB_SATYPE_AH; + case IPPROTO_ESP: + return SADB_SATYPE_ESP; + default: + return 0; + } + /* NOTREACHED */ +} + +/* %%% PF_KEY */ +/* + * SADB_GETSPI processing is to receive + * <base, src address, dst address, (SPI range)> + * from the IKMPd, to assign a unique spi value, to hang on the INBOUND + * tree with the status of LARVAL, and send + * <base, SA(*), address(SD)> + * to the IKMPd. + * + * IN: mhp: pointer to the pointer to each header. + * OUT: NULL if fail. + * other if success, return pointer to the message to send. + */ +static struct sadb_msg * +key_getspi(mhp) + caddr_t *mhp; +{ + struct sadb_msg *msg0; + struct sadb_address *src0, *dst0; + struct secasindex saidx; + struct secashead *newsah; + struct secasvar *newsav; + u_int8_t proto; + u_int32_t spi; + + /* sanity check */ + if (mhp == NULL || mhp[0] == NULL) + panic("key_getspi: NULL pointer is passed.\n"); + + msg0 = (struct sadb_msg *)mhp[0]; + + if (mhp[SADB_EXT_ADDRESS_SRC] == NULL + || mhp[SADB_EXT_ADDRESS_DST] == NULL) { + printf("key_getspi: invalid message is passed.\n"); + msg0->sadb_msg_errno = EINVAL; + return NULL; + } + + src0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_SRC]); + dst0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_DST]); + + /* map satype to proto */ + if ((proto = key_satype2proto(msg0->sadb_msg_satype)) == 0) { + printf("key_getspi: invalid satype is passed.\n"); + msg0->sadb_msg_errno = EINVAL; + return NULL; + } + + KEY_SETSECASIDX(proto, msg0->sadb_msg_mode, src0+1, dst0+1, &saidx); + + /* SPI allocation */ + spi = key_do_getnewspi((struct sadb_spirange *)mhp[SADB_EXT_SPIRANGE], + &saidx); + if (spi == 0) { + msg0->sadb_msg_errno = EEXIST; + return NULL; + } + + /* get a SA index */ + if ((newsah = key_getsah(&saidx)) == NULL) { + + /* create a new SA index */ + if ((newsah = key_newsah(&saidx)) == NULL) { + printf("key_getspi: No more memory.\n"); + msg0->sadb_msg_errno = ENOBUFS; + return NULL; + } + } + + /* get a new SA */ + if ((newsav = key_newsav(mhp, newsah)) == NULL) { + msg0->sadb_msg_errno = ENOBUFS; + /* XXX don't free new SA index allocated in above. */ + return NULL; + } + + /* set spi */ + newsav->spi = htonl(spi); + +#ifndef IPSEC_NONBLOCK_ACQUIRE + /* delete the entry in acqtree */ + if (msg0->sadb_msg_seq != 0) { + struct secacq *acq; + if ((acq = key_getacqbyseq(msg0->sadb_msg_seq)) != NULL) { + /* reset counter in order to deletion by timehander. */ + acq->tick = key_blockacq_lifetime; + acq->count = 0; + } + } +#endif + + { + struct sadb_msg *newmsg; + u_int len; + caddr_t p; + + /* create new sadb_msg to reply. */ + len = sizeof(struct sadb_msg) + + sizeof(struct sadb_sa) + + PFKEY_EXTLEN(mhp[SADB_EXT_ADDRESS_SRC]) + + PFKEY_EXTLEN(mhp[SADB_EXT_ADDRESS_DST]); + + KMALLOC(newmsg, struct sadb_msg *, len); + if (newmsg == NULL) { + printf("key_getspi: No more memory.\n"); + msg0->sadb_msg_errno = ENOBUFS; + return NULL; + } + bzero((caddr_t)newmsg, len); + + bcopy((caddr_t)mhp[0], (caddr_t)newmsg, sizeof(*msg0)); + newmsg->sadb_msg_seq = newsav->seq; + newmsg->sadb_msg_errno = 0; + newmsg->sadb_msg_len = PFKEY_UNIT64(len); + p = (caddr_t)newmsg + sizeof(*msg0); + + { + struct sadb_sa *m_sa; + m_sa = (struct sadb_sa *)p; + m_sa->sadb_sa_len = PFKEY_UNIT64(sizeof(struct sadb_sa)); + m_sa->sadb_sa_exttype = SADB_EXT_SA; + m_sa->sadb_sa_spi = htonl(spi); + p += sizeof(struct sadb_sa); } - DPRINTF(IDL_FINISHED,("keyoutput: 3\n")); - } - break; - case KEY_GETSPI: - DPRINTF(IDL_EVENT,("key_output got KEY_GETSPI msg\n")); - - if (key_xdata(km, &keyinfo, 1) < 0) - goto parsefail; - - if ((keyerror = key_getspi(km->type, km->vers, keyinfo.src, keyinfo.dst, - km->lifetime1, km->lifetime2, - &(km->spi))) != 0) { - DPRINTF(IDL_CRITICAL,("keyoutput: getspi failed error=%d\n", keyerror)); - senderr(keyerror); + + p = key_setsadbext(p, mhp[SADB_EXT_ADDRESS_SRC]); + p = key_setsadbext(p, mhp[SADB_EXT_ADDRESS_DST]); + + return newmsg; } - break; - case KEY_REGISTER: - DPRINTF(IDL_EVENT,("key_output got KEY_REGISTER msg\n")); - key_register(so, km->type); - break; - case KEY_DUMP: - DPRINTF(IDL_EVENT,("key_output got KEY_DUMP msg\n")); - error = key_dump(so); - return(error); - break; - case KEY_FLUSH: - DPRINTF(IDL_EVENT,("key_output got KEY_FLUSH msg\n")); - key_flush(); - break; - default: - DPRINTF(IDL_CRITICAL,("key_output got unsupported msg type=%d\n", - km->key_msgtype)); - senderr(EOPNOTSUPP); - } +} - goto flush; +/* + * allocating new SPI + * called by key_getspi(). + * OUT: + * 0: failure. + * others: success. + */ +static u_int32_t +key_do_getnewspi(spirange, saidx) + struct sadb_spirange *spirange; + struct secasindex *saidx; +{ + u_int32_t newspi; + u_int32_t min, max; + int count = key_spi_trycnt; + + /* set spi range to allocate */ + if (spirange != NULL) { + min = spirange->sadb_spirange_min; + max = spirange->sadb_spirange_max; + } else { + min = key_spi_minval; + max = key_spi_maxval; + } -parsefail: - keyinfo.dst = NULL; - error = EINVAL; + if (min == max) { + if (key_checkspidup(saidx, min) != NULL) { + printf("key_do_getnewspi: SPI %u exists already.\n", min); + return 0; + } -flush: - if (km) - km->key_errno = error; + count--; /* taking one cost. */ + newspi = min; - if (dstfamily) - *dstfamily = keyinfo.dst ? keyinfo.dst->sa_family : 0; + } else { - DPRINTF(IDL_MAJOR_EVENT, ("key_parse exiting with error=%d\n", error)); - return error; + /* init SPI */ + newspi = 0; + + /* when requesting to allocate spi ranged */ + while (count--) { + /* generate pseudo-random SPI value ranged. */ + newspi = min + (random() % ( max - min + 1 )); + + if (key_checkspidup(saidx, newspi) == NULL) + break; + } + + if (count == 0 || newspi == 0) { + printf("key_do_getnewspi: to allocate spi is failed.\n"); + return 0; + } + } + + /* statistics */ + keystat.getspi_count = + (keystat.getspi_count + key_spi_trycnt - count) / 2; + + return newspi; } /* - * Definitions of protocols supported in the KEY domain. + * SADB_UPDATE processing + * receive + * <base, SA, (lifetime(HSC),) address(SD), (address(P),) + * key(AE), (identity(SD),) (sensitivity)> + * from the ikmpd, and update a secasvar entry whose status is SADB_SASTATE_LARVAL. + * and send + * <base, SA, (lifetime(HSC),) address(SD), (address(P),) + * (identity(SD),) (sensitivity)> + * to the ikmpd. + * + * IN: mhp: pointer to the pointer to each header. + * OUT: NULL if fail. + * other if success, return pointer to the message to send. */ +static struct sadb_msg * +key_update(mhp) + caddr_t *mhp; +{ + struct sadb_msg *msg0; + struct sadb_sa *sa0; + struct sadb_address *src0, *dst0; + struct secasindex saidx; + struct secashead *sah; + struct secasvar *sav; + u_int16_t proto; + + /* sanity check */ + if (mhp == NULL || mhp[0] == NULL) + panic("key_update: NULL pointer is passed.\n"); + + msg0 = (struct sadb_msg *)mhp[0]; + + /* map satype to proto */ + if ((proto = key_satype2proto(msg0->sadb_msg_satype)) == 0) { + printf("key_update: invalid satype is passed.\n"); + msg0->sadb_msg_errno = EINVAL; + return NULL; + } -struct sockaddr key_addr = { 2, PF_KEY, }; -struct sockproto key_proto = { PF_KEY, }; + if (mhp[SADB_EXT_SA] == NULL + || mhp[SADB_EXT_ADDRESS_SRC] == NULL + || mhp[SADB_EXT_ADDRESS_DST] == NULL + || (msg0->sadb_msg_satype == SADB_SATYPE_ESP + && mhp[SADB_EXT_KEY_ENCRYPT] == NULL) + || (msg0->sadb_msg_satype == SADB_SATYPE_AH + && mhp[SADB_EXT_KEY_AUTH] == NULL) + || (mhp[SADB_EXT_LIFETIME_HARD] != NULL + && mhp[SADB_EXT_LIFETIME_SOFT] == NULL) + || (mhp[SADB_EXT_LIFETIME_HARD] == NULL + && mhp[SADB_EXT_LIFETIME_SOFT] != NULL)) { + printf("key_update: invalid message is passed.\n"); + msg0->sadb_msg_errno = EINVAL; + return NULL; + } -#define KEYREAPERINT 120 + sa0 = (struct sadb_sa *)mhp[SADB_EXT_SA]; + src0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_SRC]); + dst0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_DST]); -static int -key_sendup(s, km) - struct socket *s; - struct key_msghdr *km; -{ - struct mbuf *m; - - if (!km) - panic("km == NULL in key_sendup\n"); - MGETHDR(m, M_WAIT, MT_DATA); - m->m_len = m->m_pkthdr.len = 0; - m->m_next = 0; - m->m_nextpkt = 0; - m->m_pkthdr.rcvif = 0; - if (km) - m_copyback(m, 0, km->key_msglen, (caddr_t)km); - - if (sbappendaddr(&(s->so_rcv), &key_addr, m, NULL)) { - sorwakeup(s); - return 1; - } else { - if (m) m_freem(m); - } + KEY_SETSECASIDX(proto, msg0->sadb_msg_mode, src0+1, dst0+1, &saidx); + + /* get a SA header */ + if ((sah = key_getsah(&saidx)) == NULL) { + printf("key_update: no SA index found.\n"); + msg0->sadb_msg_errno = ENOENT; + return NULL; + } + + /* find a SA with sequence number. */ + if ((sav = key_getsavbyseq(sah, msg0->sadb_msg_seq)) == NULL) { + printf("key_update: no larval SA with sequence %u exists.\n", + msg0->sadb_msg_seq); + msg0->sadb_msg_errno = ENOENT; + return NULL; + } + + /* validity check */ + if (sav->sah->saidx.proto != proto) { + printf("key_update: protocol mismatched (DB=%u param=%u)\n", + sav->sah->saidx.proto, proto); + msg0->sadb_msg_errno = EINVAL; + return NULL; + } + if (sav->spi != sa0->sadb_sa_spi) { + printf("key_update: SPI mismatched (DB:%u param:%u)\n", + (u_int32_t)ntohl(sav->spi), + (u_int32_t)ntohl(sa0->sadb_sa_spi)); + msg0->sadb_msg_errno = EINVAL; + return NULL; + } + if (sav->pid != msg0->sadb_msg_pid) { + printf("key_update: pid mismatched (DB:%u param:%u)\n", + sav->pid, msg0->sadb_msg_pid); + msg0->sadb_msg_errno = EINVAL; + return NULL; + } + + /* copy sav values */ + if (key_setsaval(sav, mhp)) { + key_freesav(sav); + return NULL; + } + + /* check SA values to be mature. */ + if ((msg0->sadb_msg_errno = key_mature(sav)) != 0) { + key_freesav(sav); + return NULL; + } + + /* + * we must call key_freesav() whenever we leave a function context, + * as we did not allocated a new sav (we updated existing sav). + */ + key_freesav(sav); + sav = NULL; - return(0); + { + struct sadb_msg *newmsg; + + /* set msg buf from mhp */ + if ((newmsg = key_getmsgbuf_x1(mhp)) == NULL) { + printf("key_update: No more memory.\n"); + msg0->sadb_msg_errno = ENOBUFS; + return NULL; + } + return newmsg; + } } -#ifdef notyet -/*---------------------------------------------------------------------- - * key_reaper(): - * Scan key table, nuke unwanted entries - ----------------------------------------------------------------------*/ -static void -key_reaper(whocares) - void *whocares; +/* + * search SAD with sequence for a SA which state is SADB_SASTATE_LARVAL. + * only called by key_update(). + * OUT: + * NULL : not found + * others : found, pointer to a SA. + */ +static struct secasvar * +key_getsavbyseq(sah, seq) + struct secashead *sah; + u_int32_t seq; { - DPRINTF(IDL_GROSS_EVENT,("Entering key_reaper()\n")); + struct secasvar *sav; + u_int state; + + state = SADB_SASTATE_LARVAL; - timeout(key_reaper, NULL, KEYREAPERINT * HZ); + /* search SAD with sequence number ? */ + __LIST_FOREACH(sav, &sah->savtree[state], chain) { + + KEY_CHKSASTATE(state, sav->state, "key_getsabyseq"); + + if (sav->seq == seq) { + sav->refcnt++; + KEYDEBUG(KEYDEBUG_IPSEC_STAMP, + printf("DP key_getsavbyseq cause " + "refcnt++:%d SA:%p\n", + sav->refcnt, sav)); + return sav; + } + } + + return NULL; } -#endif /* notyet */ -/*---------------------------------------------------------------------- - * key_init(): - * Init routine for key socket, key engine - ----------------------------------------------------------------------*/ -static void -key_init() +/* + * SADB_ADD processing + * add a entry to SA database, when received + * <base, SA, (lifetime(HSC),) address(SD), (address(P),) + * key(AE), (identity(SD),) (sensitivity)> + * from the ikmpd, + * and send + * <base, SA, (lifetime(HSC),) address(SD), (address(P),) + * (identity(SD),) (sensitivity)> + * to the ikmpd. + * + * IGNORE identity and sensitivity messages. + * + * IN: mhp: pointer to the pointer to each header. + * OUT: NULL if fail. + * other if success, return pointer to the message to send. + */ +static struct sadb_msg * +key_add(mhp) + caddr_t *mhp; { - DPRINTF(IDL_EVENT,("Called key_init().\n")); - if (key_inittables()) - panic("key_inittables failed!\n"); -#ifdef notyet - timeout(key_reaper, NULL, HZ); -#endif /* notyet */ - bzero((char *)&keyso_cb, sizeof(keyso_cb)); + struct sadb_msg *msg0; + struct sadb_sa *sa0; + struct sadb_address *src0, *dst0; + struct secasindex saidx; + struct secashead *newsah; + struct secasvar *newsav; + u_int16_t proto; + + /* sanity check */ + if (mhp == NULL || mhp[0] == NULL) + panic("key_add: NULL pointer is passed.\n"); + + msg0 = (struct sadb_msg *)mhp[0]; + + /* map satype to proto */ + if ((proto = key_satype2proto(msg0->sadb_msg_satype)) == 0) { + printf("key_add: invalid satype is passed.\n"); + msg0->sadb_msg_errno = EINVAL; + return NULL; + } + + if (mhp[SADB_EXT_SA] == NULL + || mhp[SADB_EXT_ADDRESS_SRC] == NULL + || mhp[SADB_EXT_ADDRESS_DST] == NULL + || (msg0->sadb_msg_satype == SADB_SATYPE_ESP + && mhp[SADB_EXT_KEY_ENCRYPT] == NULL) + || (msg0->sadb_msg_satype == SADB_SATYPE_AH + && mhp[SADB_EXT_KEY_AUTH] == NULL) + || (mhp[SADB_EXT_LIFETIME_HARD] != NULL + && mhp[SADB_EXT_LIFETIME_SOFT] == NULL) + || (mhp[SADB_EXT_LIFETIME_HARD] == NULL + && mhp[SADB_EXT_LIFETIME_SOFT] != NULL)) { + printf("key_add: invalid message is passed.\n"); + msg0->sadb_msg_errno = EINVAL; + return NULL; + } + + sa0 = (struct sadb_sa *)mhp[SADB_EXT_SA]; + src0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_SRC]); + dst0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_DST]); + + KEY_SETSECASIDX(proto, msg0->sadb_msg_mode, src0+1, dst0+1, &saidx); + + /* get a SA header */ + if ((newsah = key_getsah(&saidx)) == NULL) { + + /* create a new SA header */ + if ((newsah = key_newsah(&saidx)) == NULL) { + printf("key_add: No more memory.\n"); + msg0->sadb_msg_errno = ENOBUFS; + return NULL; + } + } + + /* create new SA entry. */ + /* We can create new SA only if SPI is differenct. */ + if (key_getsavbyspi(newsah, sa0->sadb_sa_spi)) { + printf("key_add: SA already exists.\n"); + msg0->sadb_msg_errno = EEXIST; + return NULL; + } + if ((newsav = key_newsav(mhp, newsah)) == NULL) + return NULL; + + /* check SA values to be mature. */ + if ((msg0->sadb_msg_errno = key_mature(newsav)) != NULL) { + key_freesav(newsav); + return NULL; + } + + /* + * don't call key_freesav() here, as we would like to keep the SA + * in the database on success. + */ + + { + struct sadb_msg *newmsg; + + /* set msg buf from mhp */ + if ((newmsg = key_getmsgbuf_x1(mhp)) == NULL) { + printf("key_add: No more memory.\n"); + msg0->sadb_msg_errno = ENOBUFS; + return NULL; + } + + return newmsg; + } } -/*---------------------------------------------------------------------- - * my_addr(): - * Determine if an address belongs to one of my configured interfaces. - * Currently handles only AF_INET, AF_INET6 addresses. - ----------------------------------------------------------------------*/ -static int -my_addr(sa) - struct sockaddr *sa; +static struct sadb_msg * +key_getmsgbuf_x1(mhp) + caddr_t *mhp; { - switch(sa->sa_family) { -#ifdef INET6 - case AF_INET6: { - struct in6_ifaddr *i6a = 0; + struct sadb_msg *msg0; + struct sadb_msg *newmsg; + u_int len; + caddr_t p; + + /* sanity check */ + if (mhp == NULL || mhp[0] == NULL) + panic("key_getmsgbuf_x1: NULL pointer is passed.\n"); + + msg0 = (struct sadb_msg *)mhp[0]; + + /* create new sadb_msg to reply. */ + len = sizeof(struct sadb_msg) + + sizeof(struct sadb_sa) + + PFKEY_EXTLEN(mhp[SADB_EXT_ADDRESS_SRC]) + + PFKEY_EXTLEN(mhp[SADB_EXT_ADDRESS_DST]) + + (mhp[SADB_EXT_LIFETIME_HARD] == NULL + ? 0 : sizeof(struct sadb_lifetime)) + + (mhp[SADB_EXT_LIFETIME_SOFT] == NULL + ? 0 : sizeof(struct sadb_lifetime)); + + KMALLOC(newmsg, struct sadb_msg *, len); + if (newmsg == NULL) + return NULL; + bzero((caddr_t)newmsg, len); + + bcopy((caddr_t)mhp[0], (caddr_t)newmsg, sizeof(*msg0)); + newmsg->sadb_msg_errno = 0; + newmsg->sadb_msg_len = PFKEY_UNIT64(len); + p = (caddr_t)newmsg + sizeof(*msg0); + + p = key_setsadbext(p, mhp[SADB_EXT_SA]); + p = key_setsadbext(p, mhp[SADB_EXT_ADDRESS_SRC]); + p = key_setsadbext(p, mhp[SADB_EXT_ADDRESS_DST]); + + if (mhp[SADB_EXT_LIFETIME_HARD] != NULL) + p = key_setsadbext(p, mhp[SADB_EXT_LIFETIME_HARD]); + + if (mhp[SADB_EXT_LIFETIME_SOFT] != NULL) + p = key_setsadbext(p, mhp[SADB_EXT_LIFETIME_SOFT]); + + return newmsg; +} - for (i6a = in6_ifaddr; i6a; i6a = i6a->ia_next) { /*XXX*/ - if (IN6_ARE_ADDR_EQUAL(&((struct sockaddr_in6 *)sa)->sin6_addr, - &i6a->ia_addr.sin6_addr)) - return(1); - } +/* + * SADB_DELETE processing + * receive + * <base, SA(*), address(SD)> + * from the ikmpd, and set SADB_SASTATE_DEAD, + * and send, + * <base, SA(*), address(SD)> + * to the ikmpd. + * + * IN: mhp: pointer to the pointer to each header. + * OUT: NULL if fail. + * other if success, return pointer to the message to send. + */ +static struct sadb_msg * +key_delete(mhp) + caddr_t *mhp; +{ + struct sadb_msg *msg0; + struct sadb_sa *sa0; + struct sadb_address *src0, *dst0; + struct secasindex saidx; + struct secashead *sah; + struct secasvar *sav; + u_int16_t proto; + + /* sanity check */ + if (mhp == NULL || mhp[0] == NULL) + panic("key_delete: NULL pointer is passed.\n"); + + msg0 = (struct sadb_msg *)mhp[0]; + + /* map satype to proto */ + if ((proto = key_satype2proto(msg0->sadb_msg_satype)) == 0) { + printf("key_delete: invalid satype is passed.\n"); + msg0->sadb_msg_errno = EINVAL; + return NULL; + } + + if (mhp[SADB_EXT_SA] == NULL + || mhp[SADB_EXT_ADDRESS_SRC] == NULL + || mhp[SADB_EXT_ADDRESS_DST] == NULL) { + printf("key_delete: invalid message is passed.\n"); + msg0->sadb_msg_errno = EINVAL; + return NULL; + } + sa0 = (struct sadb_sa *)mhp[SADB_EXT_SA]; + src0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_SRC]); + dst0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_DST]); + + KEY_SETSECASIDX(proto, msg0->sadb_msg_mode, src0+1, dst0+1, &saidx); + + /* get a SA header */ + if ((sah = key_getsah(&saidx)) == NULL) { + printf("key_delete: no SA found.\n"); + msg0->sadb_msg_errno = ENOENT; + return NULL; + } + + /* get a SA with SPI. */ + sav = key_getsavbyspi(sah, sa0->sadb_sa_spi); + if (sav == NULL) { + printf("key_delete: no alive SA found.\n"); + msg0->sadb_msg_errno = ENOENT; + return NULL; + } + + key_sa_chgstate(sav, SADB_SASTATE_DEAD); + key_freesav(sav); + sav = NULL; + + { + struct sadb_msg *newmsg; + u_int len; + caddr_t p; + + /* create new sadb_msg to reply. */ + len = sizeof(struct sadb_msg) + + sizeof(struct sadb_sa) + + PFKEY_EXTLEN(mhp[SADB_EXT_ADDRESS_SRC]) + + PFKEY_EXTLEN(mhp[SADB_EXT_ADDRESS_DST]); + + KMALLOC(newmsg, struct sadb_msg *, len); + if (newmsg == NULL) { + printf("key_delete: No more memory.\n"); + msg0->sadb_msg_errno = ENOBUFS; + return NULL; + } + bzero((caddr_t)newmsg, len); + + bcopy((caddr_t)mhp[0], (caddr_t)newmsg, sizeof(*msg0)); + newmsg->sadb_msg_errno = 0; + newmsg->sadb_msg_len = PFKEY_UNIT64(len); + p = (caddr_t)newmsg + sizeof(*msg0); + + p = key_setsadbext(p, mhp[SADB_EXT_SA]); + p = key_setsadbext(p, mhp[SADB_EXT_ADDRESS_SRC]); + p = key_setsadbext(p, mhp[SADB_EXT_ADDRESS_DST]); + + return newmsg; } - break; -#endif /* INET6 */ - case AF_INET: { - struct in_ifaddr *ia = 0; +} - for (ia = in_ifaddrhead.tqh_first; ia; ia = ia->ia_link.tqe_next) { - if (((struct sockaddr_in *)sa)->sin_addr.s_addr == - ia->ia_addr.sin_addr.s_addr) - return(1); - } +/* + * SADB_GET processing + * receive + * <base, SA(*), address(SD)> + * from the ikmpd, and get a SP and a SA to respond, + * and send, + * <base, SA, (lifetime(HSC),) address(SD), (address(P),) key(AE), + * (identity(SD),) (sensitivity)> + * to the ikmpd. + * + * IN: mhp: pointer to the pointer to each header. + * OUT: NULL if fail. + * other if success, return pointer to the message to send. + */ +static struct sadb_msg * +key_get(mhp) + caddr_t *mhp; +{ + struct sadb_msg *msg0; + struct sadb_sa *sa0; + struct sadb_address *src0, *dst0; + struct secasindex saidx; + struct secashead *sah; + struct secasvar *sav; + u_int16_t proto; + + /* sanity check */ + if (mhp == NULL || mhp[0] == NULL) + panic("key_get: NULL pointer is passed.\n"); + + msg0 = (struct sadb_msg *)mhp[0]; + + /* map satype to proto */ + if ((proto = key_satype2proto(msg0->sadb_msg_satype)) == 0) { + printf("key_get: invalid satype is passed.\n"); + msg0->sadb_msg_errno = EINVAL; + return NULL; + } + + if (mhp[SADB_EXT_SA] == NULL + || mhp[SADB_EXT_ADDRESS_SRC] == NULL + || mhp[SADB_EXT_ADDRESS_DST] == NULL) { + printf("key_get: invalid message is passed.\n"); + msg0->sadb_msg_errno = EINVAL; + return NULL; + } + sa0 = (struct sadb_sa *)mhp[SADB_EXT_SA]; + src0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_SRC]); + dst0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_DST]); + + KEY_SETSECASIDX(proto, msg0->sadb_msg_mode, src0+1, dst0+1, &saidx); + + /* get a SA header */ + if ((sah = key_getsah(&saidx)) == NULL) { + printf("key_get: no SA found.\n"); + msg0->sadb_msg_errno = ENOENT; + return NULL; + } + + /* get a SA with SPI. */ + sav = key_getsavbyspi(sah, sa0->sadb_sa_spi); + if (sav == NULL) { + printf("key_get: no SA with state of mature found.\n"); + msg0->sadb_msg_errno = ENOENT; + return NULL; + } + + { + struct sadb_msg *newmsg; + u_int len; + u_int8_t satype; + + /* map proto to satype */ + if ((satype = key_proto2satype(sah->saidx.proto)) == 0) { + printf("key_get: there was invalid proto in SAD.\n"); + msg0->sadb_msg_errno = EINVAL; + return NULL; + } + + /* calculate a length of message buffer */ + len = key_getmsglen(sav); + + KMALLOC(newmsg, struct sadb_msg *, len); + if (newmsg == NULL) { + printf("key_get: No more memory.\n"); + msg0->sadb_msg_errno = ENOBUFS; + return NULL; + } + + /* create new sadb_msg to reply. */ + (void)key_setdumpsa(newmsg, sav, SADB_GET, + satype, msg0->sadb_msg_seq, msg0->sadb_msg_pid); + + return newmsg; } - break; - } - return(0); } -/*---------------------------------------------------------------------- - * key_output(): - * Process outbound pf_key message. - ----------------------------------------------------------------------*/ +/* + * SADB_ACQUIRE processing called by key_checkrequest() and key_acquire2(). + * send + * <base, SA, address(SD), (address(P)), + * (identity(SD),) (sensitivity,) proposal> + * to KMD, and expect to receive + * <base> with SADB_ACQUIRE if error occured, + * or + * <base, src address, dst address, (SPI range)> with SADB_GETSPI + * from KMD by PF_KEY. + * + * sensitivity is not supported. + * + * OUT: + * 0 : succeed + * others: error number + */ static int -key_output(m, so) - struct mbuf *m; - struct socket *so; +key_acquire(saidx, spidx) + struct secasindex *saidx; + struct secpolicyindex *spidx; { - struct key_msghdr *km = 0; - int len; - int error = 0; - int dstfamily = 0; +#ifndef IPSEC_NONBLOCK_ACQUIRE + struct secacq *newacq; +#endif + u_int8_t satype; + int error; + + /* sanity check */ + if (saidx == NULL || spidx == NULL) + panic("key_acquire: NULL pointer is passed.\n"); + if ((satype = key_proto2satype(saidx->proto)) == 0) + panic("key_acquire: invalid proto is passed.\n"); + +#ifndef IPSEC_NONBLOCK_ACQUIRE + /* + * We never do anything about acquirng SA. There is anather + * solution that kernel blocks to send SADB_ACQUIRE message until + * getting something message from IKEd. In later case, to be + * managed with ACQUIRING list. + */ + /* get a entry to check whether sending message or not. */ + if ((newacq = key_getacq(saidx)) != NULL) { + if (key_blockacq_count < newacq->count) { + /* reset counter and do send message. */ + newacq->count = 0; + } else { + /* increment counter and do nothing. */ + newacq->count++; + return 0; + } + } else { + /* make new entry for blocking to send SADB_ACQUIRE. */ + if ((newacq = key_newacq(saidx)) == NULL) + return ENOBUFS; + + /* add to acqtree */ + LIST_INSERT_HEAD(&acqtree, newacq, chain); + } +#endif - DPRINTF(IDL_EVENT,("key_output() got a message len=%d.\n", m->m_pkthdr.len)); + { + struct sadb_msg *newmsg = NULL; + union sadb_x_ident_id id; + u_int len; + caddr_t p; + + /* create new sadb_msg to reply. */ + len = sizeof(struct sadb_msg) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(saidx->src.__ss_len) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(saidx->dst.__ss_len) + + sizeof(struct sadb_ident) + + PFKEY_ALIGN8(spidx->src.__ss_len) + + sizeof(struct sadb_ident) + + PFKEY_ALIGN8(spidx->dst.__ss_len) + + sizeof(struct sadb_prop) + + sizeof(struct sadb_comb); /* XXX to be multiple */ + + KMALLOC(newmsg, struct sadb_msg *, len); + if (newmsg == 0) { + printf("key_acquire: No more memory.\n"); + return ENOBUFS; + } + bzero((caddr_t)newmsg, len); -#undef senderr -#define senderr(e) \ - { error = (e); if (km) km->key_errno = error; goto flush; } + newmsg->sadb_msg_version = PF_KEY_V2; + newmsg->sadb_msg_type = SADB_ACQUIRE; + newmsg->sadb_msg_errno = 0; + newmsg->sadb_msg_satype = satype; + newmsg->sadb_msg_len = PFKEY_UNIT64(len); - if (m == 0 || ((m->m_len < sizeof(long)) && - (m = m_pullup(m, sizeof(long))) == 0)) { - DPRINTF(IDL_CRITICAL,("key_output can't pullup mbuf\n")); - return (ENOBUFS); - } - if ((m->m_flags & M_PKTHDR) == 0) - panic("key_output"); - - DDO(IDL_FINISHED,dump_mbuf(m)); - - len = m->m_pkthdr.len; - if (len < sizeof(*km) || len != mtod(m, struct key_msghdr *)->key_msglen) { - DPRINTF(IDL_CRITICAL,("keyout: Invalid length field/length mismatch!\n")); - senderr(EINVAL); - } - KMALLOC(km, struct key_msghdr *, len); - if (km == 0) { - DPRINTF(IDL_CRITICAL,("keyoutput: Can't malloc memory!\n")); - senderr(ENOBUFS); - } +#ifndef IPSEC_NONBLOCK_ACQUIRE + newmsg->sadb_msg_seq = newacq->seq; +#else + newmsg->sadb_msg_seq = (acq_seq = (acq_seq == ~0 ? 1 : ++acq_seq)); +#endif - m_copydata(m, 0, len, (caddr_t)km); + newmsg->sadb_msg_pid = 0; + p = (caddr_t)newmsg + sizeof(struct sadb_msg); + + /* set sadb_address for saidx's. */ + p = key_setsadbaddr(p, + SADB_EXT_ADDRESS_SRC, + (struct sockaddr *)&saidx->src, + _INALENBYAF(saidx->src.__ss_family) << 3, + IPSEC_ULPROTO_ANY); + p = key_setsadbaddr(p, + SADB_EXT_ADDRESS_DST, + (struct sockaddr *)&saidx->dst, + _INALENBYAF(saidx->dst.__ss_family) << 3, + IPSEC_ULPROTO_ANY); + + /* set sadb_address for spidx's. */ + id.sadb_x_ident_id_addr.prefix = spidx->prefs; + id.sadb_x_ident_id_addr.ul_proto = spidx->ul_proto; + p = key_setsadbident(p, + SADB_EXT_IDENTITY_SRC, + SADB_X_IDENTTYPE_ADDR, + (caddr_t)&spidx->src, + spidx->src.__ss_len, + *(u_int64_t *)&id); + + id.sadb_x_ident_id_addr.prefix = spidx->prefd; + id.sadb_x_ident_id_addr.ul_proto = spidx->ul_proto; + p = key_setsadbident(p, + SADB_EXT_IDENTITY_DST, + SADB_X_IDENTTYPE_ADDR, + (caddr_t)&spidx->dst, + spidx->dst.__ss_len, + *(u_int64_t *)&id); + + /* create proposal extension */ + /* set combination extension */ + /* XXX: to be defined by proposal database */ + { + struct sadb_prop *prop; + struct sadb_comb *comb; + + prop = (struct sadb_prop *)p; + prop->sadb_prop_len = PFKEY_UNIT64(sizeof(*prop) + sizeof(*comb)); + /* XXX to be multiple */ + prop->sadb_prop_exttype = SADB_EXT_PROPOSAL; + prop->sadb_prop_replay = 32; /* XXX be variable ? */ + p += sizeof(struct sadb_prop); + + comb = (struct sadb_comb *)p; + comb->sadb_comb_auth = SADB_AALG_SHA1HMAC; /* XXX ??? */ + comb->sadb_comb_encrypt = SADB_EALG_DESCBC; /* XXX ??? */ + comb->sadb_comb_flags = 0; + comb->sadb_comb_auth_minbits = 8; /* XXX */ + comb->sadb_comb_auth_maxbits = 1024; /* XXX */ + comb->sadb_comb_encrypt_minbits = 64; /* XXX */ + comb->sadb_comb_encrypt_maxbits = 64; /* XXX */ + comb->sadb_comb_soft_allocations = 0; + comb->sadb_comb_hard_allocations = 0; + comb->sadb_comb_soft_bytes = 0; + comb->sadb_comb_hard_bytes = 0; + comb->sadb_comb_soft_addtime = 0; + comb->sadb_comb_hard_addtime = 0; + comb->sadb_comb_soft_usetime = 0; + comb->sadb_comb_hard_usetime = 0; + + p += sizeof(*comb); + } - km->key_errno = error = key_parse(&km, so, &dstfamily); - DPRINTF(IDL_MAJOR_EVENT, ("Back from key_parse\n")); -flush: - if (km) - key_sendup(so, km); -#if 0 - { - struct rawcb *rp = 0; - struct mbuf *m; - - if ((so->so_options & SO_USELOOPBACK) == 0) { - if (keyso_cb.any_count <= 1) { - if (km) - KFREE(km); - return (error); - } - rp = sotorawcb(so); + error = key_sendall(newmsg, len); + if (error != 0) + printf("key_acquire: key_sendall returned %d\n", error); + return error; } - DPRINTF(IDL_MAJOR_EVENT, ("key_output: foo\n")); - key_proto.sp_protocol = dstfamily; + return 0; +} - if (km) { - m = m_devget(km, len, 0, NULL, NULL); - KFREE(km); - } +#ifndef IPSEC_NONBLOCK_ACQUIRE +static struct secacq * +key_newacq(saidx) + struct secasindex *saidx; +{ + struct secacq *newacq; - DPRINTF(IDL_MAJOR_EVENT, ("key_output: bar\n")); - if (rp) - rp->rcb_proto.sp_family = 0; /* Prevent us from receiving message */ + /* get new entry */ + KMALLOC(newacq, struct secacq *, sizeof(struct secacq)); + if (newacq == NULL) { + printf("key_newacq: No more memory.\n"); + return NULL; + } + bzero(newacq, sizeof(*newacq)); - raw_input(m, &key_proto, &key_addr, &key_addr); + /* copy secindex */ + bcopy(saidx, &newacq->saidx, sizeof(newacq->saidx)); + newacq->seq = (acq_seq == ~0 ? 1 : ++acq_seq); + newacq->tick = 0; + newacq->count = 0; - if (rp) - rp->rcb_proto.sp_family = PF_KEY; - } - DPRINTF(IDL_MAJOR_EVENT, ("key_output: baz\n")); -#endif /* 0 */ - return (error); + return newacq; } +static struct secacq * +key_getacq(saidx) + struct secasindex *saidx; +{ + struct secacq *acq; -/*---------------------------------------------------------------------- - * key_*(): - * Handles protocol requests for pf_key sockets. - ----------------------------------------------------------------------*/ + __LIST_FOREACH(acq, &acqtree, chain) { + if (key_cmpsaidx_exactly(saidx, &acq->saidx)) + return acq; + } -static int -key_attach(struct socket *so, int proto, struct proc *p) + return NULL; +} + +static struct secacq * +key_getacqbyseq(seq) + u_int32_t seq; { - register int error = 0; - register struct rawcb *rp; - int s; + struct secacq *acq; - DPRINTF(IDL_EVENT,("Entering key_attach\n")); + __LIST_FOREACH(acq, &acqtree, chain) { + if (acq->seq == seq) + return acq; + } - MALLOC(rp, struct rawcb *, sizeof(*rp), M_PCB, M_WAITOK); - if (rp) { - bzero(rp, sizeof(*rp)); - so->so_pcb = (caddr_t)rp; - } - s = splnet(); - error = (raw_usrreqs.pru_attach)(so, proto, p); - if (!error) { /* XXX was: if (!so) which didn't make sense */ - splx(s); - return error; - } + return NULL; +} +#endif + +/* + * SADB_ACQUIRE processing, + * in first situation, is receiving + * <base> + * from the ikmpd, and clear sequence of its secasvar entry. + * + * In second situation, is receiving + * <base, address(SD), (address(P),) (identity(SD),) (sensitivity,) proposal> + * from a user land process, and return + * <base, address(SD), (address(P),) (identity(SD),) (sensitivity,) proposal> + * to the socket. + * + * IN: mhp: pointer to the pointer to each header. + * OUT: NULL if fail. + * other if success, return pointer to the message to send. + */ +static struct sadb_msg * +key_acquire2(mhp) + caddr_t *mhp; +{ + struct sadb_msg *msg0; + struct sadb_address *src0, *dst0; + struct secasindex saidx; + struct secashead *sah; + u_int16_t proto; + + /* sanity check */ + if (mhp == NULL || mhp[0] == NULL) + panic("key_acquire2: NULL pointer is passed.\n"); + + msg0 = (struct sadb_msg *)mhp[0]; + + /* + * Error message from KMd. + * We assume that if error was occured in IKEd, the length of PFKEY + * message is equal to the size of sadb_msg structure. + * We return ~0 even if error occured in this function. + */ + if (msg0->sadb_msg_len == PFKEY_UNIT64(sizeof(struct sadb_msg))) { + +#ifndef IPSEC_NONBLOCK_ACQUIRE + struct secacq *acq; + + /* check sequence number */ + if (msg0->sadb_msg_seq == 0) { + printf("key_acquire2: must specify sequence number.\n"); + return (struct sadb_msg *)~0; + } + + if ((acq = key_getacqbyseq(msg0->sadb_msg_seq)) == NULL) { + printf("key_acquire2: " + "invalid sequence number is passed.\n"); + return (struct sadb_msg *)~0; + } + + /* reset acq counter in order to deletion by timehander. */ + acq->tick = key_blockacq_lifetime; + acq->count = 0; +#endif + return (struct sadb_msg *)~0; + /* NOTREACHED */ + } + + /* + * This message is from user land. + */ + + /* map satype to proto */ + if ((proto = key_satype2proto(msg0->sadb_msg_satype)) == 0) { + printf("key_acquire2: invalid satype is passed.\n"); + msg0->sadb_msg_errno = EINVAL; + return NULL; + } + + if (mhp[SADB_EXT_ADDRESS_SRC] == NULL + || mhp[SADB_EXT_ADDRESS_DST] == NULL + || mhp[SADB_EXT_PROPOSAL] == NULL) { + /* error */ + printf("key_acquire2: invalid message is passed.\n"); + msg0->sadb_msg_errno = EINVAL; + return NULL; + } + src0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_SRC]); + dst0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_DST]); + + KEY_SETSECASIDX(proto, msg0->sadb_msg_mode, src0+1, dst0+1, &saidx); + + /* get a SA index */ + if ((sah = key_getsah(&saidx)) != NULL) { + printf("key_acquire2: a SA exists already.\n"); + msg0->sadb_msg_errno = EEXIST; + return NULL; + } + + msg0->sadb_msg_errno = key_acquire(&saidx, NULL); + if (msg0->sadb_msg_errno != 0) { + /* XXX What I do ? */ + printf("key_acquire2: error %d returned " + "from key_acquire.\n", msg0->sadb_msg_errno); + return NULL; + } + + { + struct sadb_msg *newmsg; + u_int len; + + /* create new sadb_msg to reply. */ + len = PFKEY_UNUNIT64(msg0->sadb_msg_len); + + KMALLOC(newmsg, struct sadb_msg *, len); + if (newmsg == NULL) { + printf("key_acquire2: No more memory.\n"); + msg0->sadb_msg_errno = ENOBUFS; + return NULL; + } + bzero((caddr_t)newmsg, len); + + bcopy(mhp[0], (caddr_t)newmsg, len); - rp = sotorawcb(so); /* isn't this redundant? */ - if (rp) { - int af = rp->rcb_proto.sp_protocol; - if (error) { - free((caddr_t)rp, M_PCB); - splx(s); - return error; + return newmsg; } - if (af == AF_INET) - keyso_cb.ip4_count++; -#ifdef INET6 - else if (af == AF_INET6) - keyso_cb.ip6_count++; -#endif /* INET6 */ - keyso_cb.any_count++; -#if 0 /*itojun*/ - rp->rcb_faddr = &key_addr; +} + +/* + * SADB_REGISTER processing. + * If SATYPE_UNSPEC has been passed as satype, only return sabd_supported. + * receive + * <base> + * from the ikmpd, and register a socket to send PF_KEY messages, + * and send + * <base, supported> + * to KMD by PF_KEY. + * If socket is detached, must free from regnode. + * OUT: + * 0 : succeed + * others: error number + */ +static struct sadb_msg * +key_register(mhp, so) + caddr_t *mhp; + struct socket *so; +{ + struct sadb_msg *msg0; + struct secreg *reg, *newreg = 0; + + /* sanity check */ + if (mhp == NULL || so == NULL || mhp[0] == NULL) + panic("key_register: NULL pointer is passed.\n"); + + msg0 = (struct sadb_msg *)mhp[0]; + + /* When SATYPE_UNSPEC is specified, only return sabd_supported. */ + if (msg0->sadb_msg_satype == SADB_SATYPE_UNSPEC) + goto setmsg; + + /* check whether existing or not */ + __LIST_FOREACH(reg, ®tree[msg0->sadb_msg_satype], chain) { + if (reg->so == so) { + printf("key_register: socket exists already.\n"); + msg0->sadb_msg_errno = EEXIST; + return NULL; + } + } + + /* create regnode */ + KMALLOC(newreg, struct secreg *, sizeof(struct secreg)); + if (newreg == NULL) { + printf("key_register: No more memory.\n"); + msg0->sadb_msg_errno = ENOBUFS; + return NULL; + } + bzero((caddr_t)newreg, sizeof(struct secreg)); + + newreg->so = so; + ((struct keycb *)sotorawcb(so))->kp_registered++; + + /* add regnode to regtree. */ + LIST_INSERT_HEAD(®tree[msg0->sadb_msg_satype], newreg, chain); + + setmsg: + { + struct sadb_msg *newmsg; + struct sadb_supported *sup; + u_int len, alen, elen; + caddr_t p; + + /* create new sadb_msg to reply. */ + alen = sizeof(struct sadb_supported) + + ((SADB_AALG_MAX - 1) * sizeof(struct sadb_alg)); + +#ifdef IPSEC_ESP + elen = sizeof(struct sadb_supported) + + ((SADB_EALG_MAX - 1) * sizeof(struct sadb_alg)); #else + elen = 0; +#endif + + len = sizeof(struct sadb_msg) + + alen + + elen; + + KMALLOC(newmsg, struct sadb_msg *, len); + if (newmsg == NULL) { + printf("key_register: No more memory.\n"); + msg0->sadb_msg_errno = ENOBUFS; + return NULL; + } + bzero((caddr_t)newmsg, len); + + bcopy((caddr_t)mhp[0], (caddr_t)newmsg, sizeof(*msg0)); + newmsg->sadb_msg_errno = 0; + newmsg->sadb_msg_len = PFKEY_UNIT64(len); + p = (caddr_t)newmsg + sizeof(*msg0); + + /* for authentication algorithm */ + sup = (struct sadb_supported *)p; + sup->sadb_supported_len = PFKEY_UNIT64(alen); + sup->sadb_supported_exttype = SADB_EXT_SUPPORTED_AUTH; + p += sizeof(*sup); + { - struct mbuf *m; - MGET(m, M_DONTWAIT, MT_DATA); - if (m) { /* XXX but what about sin_len here? -PW */ - rp->rcb_faddr = mtod(m, struct sockaddr *); - bcopy(&key_addr, rp->rcb_faddr, sizeof(struct sockaddr)); - } else - rp->rcb_faddr = NULL; + int i; + struct sadb_alg *alg; + struct ah_algorithm *algo; + + for (i = 1; i < SADB_AALG_MAX; i++) { + algo = &ah_algorithms[i]; + alg = (struct sadb_alg *)p; + alg->sadb_alg_id = i; + alg->sadb_alg_ivlen = 0; + alg->sadb_alg_minbits = algo->keymin; + alg->sadb_alg_maxbits = algo->keymax; + p += sizeof(struct sadb_alg); + } + } + +#ifdef IPSEC_ESP + /* for encryption algorithm */ + sup = (struct sadb_supported *)p; + sup->sadb_supported_len = PFKEY_UNIT64(elen); + sup->sadb_supported_exttype = SADB_EXT_SUPPORTED_ENCRYPT; + p += sizeof(*sup); + + { + int i; + struct sadb_alg *alg; + struct esp_algorithm *algo; + + for (i = 1; i < SADB_EALG_MAX; i++) { + algo = &esp_algorithms[i]; + + alg = (struct sadb_alg *)p; + alg->sadb_alg_id = i; + if (algo && algo->ivlen) { + /* + * give NULL to get the value preferred by algorithm + * XXX SADB_X_EXT_DERIV ? + */ + alg->sadb_alg_ivlen = (*algo->ivlen)(NULL); + } else + alg->sadb_alg_ivlen = 0; + alg->sadb_alg_minbits = algo->keymin; + alg->sadb_alg_maxbits = algo->keymax; + p += sizeof(struct sadb_alg); + } } #endif - soisconnected(so); /* Key socket, like routing socket, must be - connected. */ - /* Possibly set other needed flags/options at creation time in here. */ - so->so_options |= SO_USELOOPBACK; /* Like routing socket, we turn this */ - /* on by default */ + return newmsg; } - splx(s); - return error; } -static int -key_detach(struct socket *so) +/* + * free secreg entry registered. + * XXX: I want to do free a socket marked done SADB_RESIGER to socket. + */ +void +key_freereg(so) + struct socket *so; { - register int error = 0; - register struct rawcb *rp; - int s; + struct secreg *reg; + int i; - DPRINTF(IDL_EVENT,("Entering key_detach\n")); + /* sanity check */ + if (so == NULL) + panic("key_freereg: NULL pointer is passed.\n"); - rp = sotorawcb(so); - if (rp) { - int af = rp->rcb_proto.sp_protocol; - if (af == AF_INET) - keyso_cb.ip4_count--; -#ifdef INET6 - else if (af == AF_INET6) - keyso_cb.ip6_count--; -#endif /* INET6 */ - keyso_cb.any_count--; - } - s = splnet(); - error = (raw_usrreqs.pru_detach)(so); - splx(s); - return error; + /* + * check whether existing or not. + * check all type of SA, because there is a potential that + * one socket is registered to multiple type of SA. + */ + for (i = 0; i <= SADB_SATYPE_MAX; i++) { + __LIST_FOREACH(reg, ®tree[i], chain) { + if (reg->so == so + && __LIST_CHAINED(reg)) { + LIST_REMOVE(reg, chain); + KFREE(reg); + break; + } + } + } + return; } +/* + * SADB_EXPIRE processing + * send + * <base, SA, lifetime(C and one of HS), address(SD)> + * to KMD by PF_KEY. + * NOTE: We send only soft lifetime extension. + * + * OUT: 0 : succeed + * others : error number + */ static int -key_abort(struct socket *so) +key_expire(sav) + struct secasvar *sav; { - DPRINTF(IDL_EVENT,("Entering key_abort\n")); + int s; + int satype; + + /* XXX: Why do we lock ? */ + s = splnet(); /*called from softclock()*/ + + /* sanity check */ + if (sav == NULL) + panic("key_expire: NULL pointer is passed.\n"); + if (sav->sah == NULL) + panic("key_expire: Why was SA index in SA NULL.\n"); + if ((satype = key_proto2satype(sav->sah->saidx.proto)) == 0) + panic("key_expire: invalid proto is passed.\n"); + + { + struct sadb_msg *newmsg = NULL; + u_int len; + caddr_t p; + int error; + + /* create new sadb_msg to reply. */ + len = sizeof(struct sadb_msg) + + sizeof(struct sadb_sa) + + sizeof(struct sadb_lifetime) + + sizeof(struct sadb_lifetime) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(sav->sah->saidx.src.__ss_len) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(sav->sah->saidx.dst.__ss_len); + + KMALLOC(newmsg, struct sadb_msg *, len); + if (newmsg == NULL) { + printf("key_expire: No more memory.\n"); + splx(s); + return ENOBUFS; + } + bzero((caddr_t)newmsg, len); + + /* set msg header */ + p = key_setsadbmsg((caddr_t)newmsg, SADB_EXPIRE, len, + satype, sav->seq, 0, + sav->sah->saidx.mode, sav->refcnt); - return (raw_usrreqs.pru_abort)(so); + /* create SA extension */ + p = key_setsadbsa(p, sav); + + /* create lifetime extension */ + { + struct sadb_lifetime *m_lt = (struct sadb_lifetime *)p; + + m_lt->sadb_lifetime_len = PFKEY_UNIT64(sizeof(struct sadb_lifetime)); + m_lt->sadb_lifetime_exttype = SADB_EXT_LIFETIME_CURRENT; + m_lt->sadb_lifetime_allocations = sav->lft_c->sadb_lifetime_allocations; + m_lt->sadb_lifetime_bytes = sav->lft_c->sadb_lifetime_bytes; + m_lt->sadb_lifetime_addtime = sav->lft_c->sadb_lifetime_addtime; + m_lt->sadb_lifetime_usetime = sav->lft_c->sadb_lifetime_usetime; + p += sizeof(struct sadb_lifetime); + + /* copy SOFT lifetime extension. */ + bcopy(sav->lft_s, p, sizeof(struct sadb_lifetime)); + p += sizeof(struct sadb_lifetime); + } + + /* set sadb_address for source */ + p = key_setsadbaddr(p, + SADB_EXT_ADDRESS_SRC, + (struct sockaddr *)&sav->sah->saidx.src, + _INALENBYAF(sav->sah->saidx.src.__ss_family) << 3, + IPSEC_ULPROTO_ANY); + + /* set sadb_address for destination */ + p = key_setsadbaddr(p, + SADB_EXT_ADDRESS_DST, + (struct sockaddr *)&sav->sah->saidx.dst, + _INALENBYAF(sav->sah->saidx.dst.__ss_family) << 3, + IPSEC_ULPROTO_ANY); + + error = key_sendall(newmsg, len); + splx(s); + return error; + } } -static int -key_bind(struct socket *so, struct sockaddr *nam, struct proc *p) +/* + * SADB_FLUSH processing + * receive + * <base> + * from the ikmpd, and free all entries in secastree. + * and send, + * <base> + * to the ikmpd. + * NOTE: to do is only marking SADB_SASTATE_DEAD. + * + * IN: mhp: pointer to the pointer to each header. + * OUT: NULL if fail. + * other if success, return pointer to the message to send. + */ +static struct sadb_msg * +key_flush(mhp) + caddr_t *mhp; { - DPRINTF(IDL_EVENT,("Entering key_bind\n")); + struct sadb_msg *msg0; + struct secashead *sah, *nextsah; + struct secasvar *sav, *nextsav; + u_int16_t proto; + u_int8_t state; + u_int stateidx; + + /* sanity check */ + if (mhp == NULL || mhp[0] == NULL) + panic("key_flush: NULL pointer is passed.\n"); + + msg0 = (struct sadb_msg *)mhp[0]; + + /* map satype to proto */ + if ((proto = key_satype2proto(msg0->sadb_msg_satype)) == 0) { + printf("key_flush: invalid satype is passed.\n"); + msg0->sadb_msg_errno = EINVAL; + return NULL; + } + + /* no SATYPE specified, i.e. flushing all SA. */ + for (sah = LIST_FIRST(&sahtree); + sah != NULL; + sah = nextsah) { + + nextsah = LIST_NEXT(sah, chain); + + if (msg0->sadb_msg_satype != SADB_SATYPE_UNSPEC + && proto != sah->saidx.proto) + continue; + + for (stateidx = 0; + stateidx < _ARRAYLEN(saorder_state_alive); + stateidx++) { - return (raw_usrreqs.pru_bind)(so, nam, p); + state = saorder_state_any[stateidx]; + for (sav = LIST_FIRST(&sah->savtree[state]); + sav != NULL; + sav = nextsav) { + + nextsav = LIST_NEXT(sav, chain); + + key_sa_chgstate(sav, SADB_SASTATE_DEAD); + } + } + + sah->state = SADB_SASTATE_DEAD; + } + + { + struct sadb_msg *newmsg; + u_int len; + + /* create new sadb_msg to reply. */ + len = sizeof(struct sadb_msg); + + KMALLOC(newmsg, struct sadb_msg *, len); + if (newmsg == NULL) { + printf("key_flush: No more memory.\n"); + msg0->sadb_msg_errno = ENOBUFS; + return NULL; + } + bzero((caddr_t)newmsg, len); + + bcopy((caddr_t)mhp[0], (caddr_t)newmsg, sizeof(*msg0)); + newmsg->sadb_msg_errno = 0; + newmsg->sadb_msg_len = PFKEY_UNIT64(len); + + return newmsg; + } } +/* + * SADB_DUMP processing + * dump all entries including status of DEAD in SAD. + * receive + * <base> + * from the ikmpd, and dump all secasvar leaves + * and send, + * <base> ..... + * to the ikmpd. + * + * IN: mhp: pointer to the pointer to each header. + * OUT: error code. 0 on success. + */ static int -key_connect(struct socket *so, struct sockaddr *nam, struct proc *p) +key_dump(mhp, so, target) + caddr_t *mhp; + struct socket *so; + int target; { - DPRINTF(IDL_EVENT,("Entering key_connect\n")); + struct sadb_msg *msg0; + struct secashead *sah; + struct secasvar *sav; + u_int16_t proto; + u_int stateidx; + u_int8_t satype; + u_int8_t state; + int len, cnt; + struct sadb_msg *newmsg; + + /* sanity check */ + if (mhp == NULL || mhp[0] == NULL) + panic("key_dump: NULL pointer is passed.\n"); + + msg0 = (struct sadb_msg *)mhp[0]; + + /* map satype to proto */ + if ((proto = key_satype2proto(msg0->sadb_msg_satype)) == 0) { + printf("key_dump: invalid satype is passed.\n"); + msg0->sadb_msg_errno = EINVAL; + return NULL; + } + + /* count sav entries to be sent to the userland. */ + cnt = 0; + __LIST_FOREACH(sah, &sahtree, chain) { + + if (msg0->sadb_msg_satype != SADB_SATYPE_UNSPEC + && proto != sah->saidx.proto) + continue; + + for (stateidx = 0; + stateidx < _ARRAYLEN(saorder_state_any); + stateidx++) { + + state = saorder_state_any[stateidx]; + __LIST_FOREACH(sav, &sah->savtree[state], chain) { + cnt++; + } + } + } + + if (cnt == 0) + return ENOENT; + + /* send this to the userland, one at a time. */ + newmsg = NULL; + __LIST_FOREACH(sah, &sahtree, chain) { + + if (msg0->sadb_msg_satype != SADB_SATYPE_UNSPEC + && proto != sah->saidx.proto) + continue; + + /* map proto to satype */ + if ((satype = key_proto2satype(sah->saidx.proto)) == 0) { + printf("key_dump: there was invalid proto in SAD.\n"); + msg0->sadb_msg_errno = EINVAL; + return NULL; + } + + for (stateidx = 0; + stateidx < _ARRAYLEN(saorder_state_any); + stateidx++) { + + state = saorder_state_any[stateidx]; + __LIST_FOREACH(sav, &sah->savtree[state], chain) { + + len = key_getmsglen(sav); + KMALLOC(newmsg, struct sadb_msg *, len); + if (newmsg == NULL) { + printf("key_dump: No more memory.\n"); + return ENOBUFS; + } + bzero((caddr_t)newmsg, len); + + --cnt; + (void)key_setdumpsa(newmsg, sav, SADB_DUMP, + satype, cnt, msg0->sadb_msg_pid); + + key_sendup(so, newmsg, len, target); + KFREE(newmsg); + newmsg = NULL; + } + } + } - return (raw_usrreqs.pru_connect)(so, nam, p); + return 0; +} + +/* + * SADB_X_PROMISC processing + */ +static void +key_promisc(mhp, so) + caddr_t *mhp; + struct socket *so; +{ + struct sadb_msg *msg0; + int olen; + + /* sanity check */ + if (mhp == NULL || mhp[0] == NULL) + panic("key_promisc: NULL pointer is passed.\n"); + + msg0 = (struct sadb_msg *)mhp[0]; + olen = PFKEY_UNUNIT64(msg0->sadb_msg_len); + + if (olen < sizeof(struct sadb_msg)) { + return; + } else if (olen == sizeof(struct sadb_msg)) { + /* enable/disable promisc mode */ + struct keycb *kp; + int target = 0; + + target = KEY_SENDUP_ONE; + + if (so == NULL) { + return; + } + if ((kp = (struct keycb *)sotorawcb(so)) == NULL) { + msg0->sadb_msg_errno = EINVAL; + goto sendorig; + } + msg0->sadb_msg_errno = 0; + if (msg0->sadb_msg_satype == 1 || msg0->sadb_msg_satype == 0) { + kp->kp_promisc = msg0->sadb_msg_satype; + } else { + msg0->sadb_msg_errno = EINVAL; + goto sendorig; + } + + /* send the original message back to everyone */ + msg0->sadb_msg_errno = 0; + target = KEY_SENDUP_ALL; +sendorig: + key_sendup(so, msg0, PFKEY_UNUNIT64(msg0->sadb_msg_len), target); + } else { + /* send packet as is */ + struct sadb_msg *msg; + int len; + + len = olen - sizeof(struct sadb_msg); + KMALLOC(msg, struct sadb_msg *, len); + if (msg == NULL) { + msg0->sadb_msg_errno = ENOBUFS; + key_sendup(so, msg0, PFKEY_UNUNIT64(msg0->sadb_msg_len), + KEY_SENDUP_ONE); /*XXX*/ + } + + /* XXX if sadb_msg_seq is specified, send to specific pid */ + key_sendup(so, msg, len, KEY_SENDUP_ALL); + KFREE(msg); + } } +/* + * send message to the socket. + * OUT: + * 0 : success + * others : fail + */ static int -key_disconnect(struct socket *so) +key_sendall(msg, len) + struct sadb_msg *msg; + u_int len; { - DPRINTF(IDL_EVENT,("Entering key_disconnect\n")); + struct secreg *reg; + int error = 0; + + /* sanity check */ + if (msg == NULL) + panic("key_sendall: NULL pointer is passed.\n"); + + /* search table registerd socket to send a message. */ + __LIST_FOREACH(reg, ®tree[msg->sadb_msg_satype], chain) { + error = key_sendup(reg->so, msg, len, KEY_SENDUP_ONE); + if (error != 0) { + if (error == ENOBUFS) + printf("key_sendall: No more memory.\n"); + else { + printf("key_sendall: key_sendup returned %d\n", + error); + } + KFREE(msg); + return error; + } + } - return (raw_usrreqs.pru_disconnect)(so); + KFREE(msg); + return 0; } -static int -key_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, - struct mbuf *control, struct proc *p) +/* + * parse sadb_msg buffer to process PFKEYv2, + * and create a data to response if needed. + * I think to be dealed with mbuf directly. + * IN: + * msgp : pointer to pointer to a received buffer pulluped. + * This is rewrited to response. + * so : pointer to socket. + * OUT: + * length for buffer to send to user process. + */ +int +key_parse(msgp, so, targetp) + struct sadb_msg **msgp; + struct socket *so; + int *targetp; { - DPRINTF(IDL_EVENT,("Entering key_send\n")); + struct sadb_msg *msg = *msgp, *newmsg = NULL; + caddr_t mhp[SADB_EXT_MAX + 1]; + u_int orglen; + int error; + + /* sanity check */ + if (msg == NULL || so == NULL) + panic("key_parse: NULL pointer is passed.\n"); + + KEYDEBUG(KEYDEBUG_KEY_DUMP, + printf("key_parse: passed sadb_msg\n"); + kdebug_sadb(msg)); + + orglen = PFKEY_UNUNIT64(msg->sadb_msg_len); + + if (targetp) + *targetp = KEY_SENDUP_ONE; + + /* check version */ + if (msg->sadb_msg_version != PF_KEY_V2) { + printf("key_parse: PF_KEY version %u is mismatched.\n", + msg->sadb_msg_version); + return EINVAL; + } + + /* check type */ + if (msg->sadb_msg_type > SADB_MAX) { + printf("key_parse: invalid type %u is passed.\n", + msg->sadb_msg_type); + msg->sadb_msg_errno = EINVAL; + return orglen; + } - return (raw_usrreqs.pru_send)(so, flags, m, nam, control, p); + /* align message. */ + if (key_align(msg, mhp) != 0) { + msg->sadb_msg_errno = EINVAL; + return orglen; + } + + /* check SA type */ + switch (msg->sadb_msg_satype) { + case SADB_SATYPE_UNSPEC: + switch (msg->sadb_msg_type) { + case SADB_GETSPI: + case SADB_UPDATE: + case SADB_ADD: + case SADB_DELETE: + case SADB_GET: + case SADB_ACQUIRE: + case SADB_EXPIRE: + printf("key_parse: must specify satype " + "when msg type=%u.\n", + msg->sadb_msg_type); + msg->sadb_msg_errno = EINVAL; + return orglen; + } + break; + case SADB_SATYPE_AH: + case SADB_SATYPE_ESP: + switch (msg->sadb_msg_type) { + case SADB_X_SPDADD: + case SADB_X_SPDDELETE: + case SADB_X_SPDGET: + case SADB_X_SPDDUMP: + case SADB_X_SPDFLUSH: + printf("key_parse: illegal satype=%u\n", msg->sadb_msg_type); + msg->sadb_msg_errno = EINVAL; + return orglen; + } + break; + case SADB_SATYPE_RSVP: + case SADB_SATYPE_OSPFV2: + case SADB_SATYPE_RIPV2: + case SADB_SATYPE_MIP: + printf("key_parse: type %u isn't supported.\n", + msg->sadb_msg_satype); + msg->sadb_msg_errno = EOPNOTSUPP; + return orglen; + case 1: /* XXX: What does it do ? */ + if (msg->sadb_msg_type == SADB_X_PROMISC) + break; + /*FALLTHROUGH*/ + default: + printf("key_parse: invalid type %u is passed.\n", + msg->sadb_msg_satype); + msg->sadb_msg_errno = EINVAL; + return orglen; + } + + /* check field of upper layer protocol and address family */ + if (mhp[SADB_EXT_ADDRESS_SRC] != NULL + && mhp[SADB_EXT_ADDRESS_DST] != NULL) { + struct sadb_address *src0, *dst0; + u_int prefix; + + src0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_SRC]); + dst0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_DST]); + + /* check upper layer protocol */ + if (src0->sadb_address_proto != dst0->sadb_address_proto) { + printf("key_parse: upper layer protocol mismatched.\n"); + msg->sadb_msg_errno = EINVAL; + return orglen; + } + + /* check family */ + if (PFKEY_ADDR_SADDR(src0)->sa_family + != PFKEY_ADDR_SADDR(dst0)->sa_family) { + printf("key_parse: address family mismatched.\n"); + msg->sadb_msg_errno = EINVAL; + return orglen; + } + + prefix = _INALENBYAF(PFKEY_ADDR_SADDR(src0)->sa_family) << 3; + + /* check max prefixlen */ + if (prefix < src0->sadb_address_prefixlen + || prefix < dst0->sadb_address_prefixlen) { + printf("key_parse: illegal prefixlen.\n"); + msg->sadb_msg_errno = EINVAL; + return orglen; + } + + switch (PFKEY_ADDR_SADDR(src0)->sa_family) { + case AF_INET: + case AF_INET6: + break; + default: + printf("key_parse: invalid address family.\n"); + msg->sadb_msg_errno = EINVAL; + return orglen; + } + + /* + * prefixlen == 0 is valid because there can be a case when + * all addresses are matched. + */ + } + + switch (msg->sadb_msg_type) { + case SADB_GETSPI: + if ((newmsg = key_getspi(mhp)) == NULL) + return orglen; + if (targetp) + *targetp = KEY_SENDUP_ALL; + break; + + case SADB_UPDATE: + if ((newmsg = key_update(mhp)) == NULL) + return orglen; + if (targetp) + *targetp = KEY_SENDUP_ALL; + break; + + case SADB_ADD: + if ((newmsg = key_add(mhp)) == NULL) + return orglen; + if (targetp) + *targetp = KEY_SENDUP_ALL; + break; + + case SADB_DELETE: + if ((newmsg = key_delete(mhp)) == NULL) + return orglen; + if (targetp) + *targetp = KEY_SENDUP_ALL; + break; + + case SADB_GET: + if ((newmsg = key_get(mhp)) == NULL) + return orglen; + break; + + case SADB_ACQUIRE: + if ((newmsg = key_acquire2(mhp)) == NULL) + return orglen; + + if (newmsg == (struct sadb_msg *)~0) { + /* + * It's not need to reply because of the message + * that was reporting an error occured from the KMd. + */ + KFREE(msg); + return 0; + } + break; + + case SADB_REGISTER: + if ((newmsg = key_register(mhp, so)) == NULL) + return orglen; + if (targetp) + *targetp = KEY_SENDUP_REGISTERED; + break; + + case SADB_EXPIRE: + printf("key_parse: why is SADB_EXPIRE received ?\n"); + msg->sadb_msg_errno = EINVAL; + if (targetp) + *targetp = KEY_SENDUP_ALL; + return orglen; + + case SADB_FLUSH: + if ((newmsg = key_flush(mhp)) == NULL) + return orglen; + if (targetp) + *targetp = KEY_SENDUP_ALL; + break; + + case SADB_DUMP: + /* key_dump will call key_sendup() on her own */ + error = key_dump(mhp, so, KEY_SENDUP_ONE); + if (error) { + msg->sadb_msg_errno = error; + return orglen; + } else { + KFREE(msg); + return 0; + } + break; + + case SADB_X_PROMISC: + /* everything is handled in key_promisc() */ + key_promisc(mhp, so); + KFREE(msg); + return 0; /*nothing to reply*/ + + case SADB_X_PCHANGE: + printf("key_parse: SADB_X_PCHANGE isn't supported.\n"); + msg->sadb_msg_errno = EINVAL; + return orglen; + + case SADB_X_SPDADD: + if ((newmsg = key_spdadd(mhp)) == NULL) + return orglen; + if (targetp) + *targetp = KEY_SENDUP_ALL; + break; + + case SADB_X_SPDDELETE: + if ((newmsg = key_spddelete(mhp)) == NULL) + return orglen; + if (targetp) + *targetp = KEY_SENDUP_ALL; + break; + + case SADB_X_SPDDUMP: + /* key_spddump will call key_sendup() on her own */ + error = key_spddump(mhp, so, KEY_SENDUP_ONE); + if (error) { + msg->sadb_msg_errno = error; + return orglen; + } else { + KFREE(msg); + return 0; + } + break; + + + case SADB_X_SPDFLUSH: + if ((newmsg = key_spdflush(mhp)) == NULL) + return orglen; + if (targetp) + *targetp = KEY_SENDUP_ALL; + break; + + default: + msg->sadb_msg_errno = EOPNOTSUPP; + return orglen; + } + + /* switch from old sadb_msg to new one if success. */ + KFREE(msg); + *msgp = newmsg; + + return PFKEY_UNUNIT64((*msgp)->sadb_msg_len); } +/* + * set the pointer to each header into message buffer. + * IN: msg: pointer to message buffer. + * mhp: pointer to the buffer allocated like below: + * caddr_t mhp[SADB_EXT_MAX + 1]; + * OUT: 0: + * EINVAL: + */ static int -key_shutdown(struct socket *so) +key_align(msg, mhp) + struct sadb_msg *msg; + caddr_t *mhp; { - DPRINTF(IDL_EVENT,("Entering key_shutdown\n")); + struct sadb_ext *ext; + int tlen, extlen; + int i; + + /* sanity check */ + if (msg == NULL || mhp == NULL) + panic("key_align: NULL pointer is passed.\n"); + + /* initialize */ + for (i = 0; i < SADB_EXT_MAX + 1; i++) + mhp[i] = NULL; + + mhp[0] = (caddr_t)msg; + + tlen = PFKEY_UNUNIT64(msg->sadb_msg_len) - sizeof(struct sadb_msg); + ext = (struct sadb_ext *)((caddr_t)msg + sizeof(struct sadb_msg)); + + while (tlen > 0) { + /* duplicate check */ + /* XXX Are there duplication either KEY_AUTH or KEY_ENCRYPT ?*/ + if (mhp[ext->sadb_ext_type] != NULL) { + printf("key_align: duplicate ext_type %u is passed.\n", + ext->sadb_ext_type); + return EINVAL; + } + + /* set pointer */ + switch (ext->sadb_ext_type) { + case SADB_EXT_SA: + case SADB_EXT_LIFETIME_CURRENT: + case SADB_EXT_LIFETIME_HARD: + case SADB_EXT_LIFETIME_SOFT: + case SADB_EXT_ADDRESS_SRC: + case SADB_EXT_ADDRESS_DST: + case SADB_EXT_ADDRESS_PROXY: + case SADB_EXT_KEY_AUTH: + /* must to be chek weak keys. */ + case SADB_EXT_KEY_ENCRYPT: + /* must to be chek weak keys. */ + case SADB_EXT_IDENTITY_SRC: + case SADB_EXT_IDENTITY_DST: + case SADB_EXT_SENSITIVITY: + case SADB_EXT_PROPOSAL: + case SADB_EXT_SUPPORTED_AUTH: + case SADB_EXT_SUPPORTED_ENCRYPT: + case SADB_EXT_SPIRANGE: + case SADB_X_EXT_POLICY: + mhp[ext->sadb_ext_type] = (caddr_t)ext; + break; + default: + printf("key_align: invalid ext_type %u is passed.\n", + ext->sadb_ext_type); + return EINVAL; + } + + extlen = PFKEY_UNUNIT64(ext->sadb_ext_len); + tlen -= extlen; + ext = (struct sadb_ext *)((caddr_t)ext + extlen); + } - return (raw_usrreqs.pru_shutdown)(so); + return 0; } -/*---------------------------------------------------------------------- - * key_cbinit(): - * Control block init routine for key socket - ----------------------------------------------------------------------*/ -static void -key_cbinit() +void +key_init() { - /* - * This is equivalent to raw_init for the routing socket. - * The key socket uses the same control block as the routing - * socket. - */ - DPRINTF(IDL_EVENT,("Called key_cbinit().\n")); + int i; + + bzero((caddr_t)&key_cb, sizeof(key_cb)); + + for (i = 0; i < IPSEC_DIR_MAX; i++) { + LIST_INIT(&sptree[i]); + } + + LIST_INIT(&sahtree); + + for (i = 0; i <= SADB_SATYPE_MAX; i++) { + LIST_INIT(®tree[i]); + } + +#ifndef IPSEC_NONBLOCK_ACQUIRE + LIST_INIT(&acqtree); +#endif + + /* system default */ + ip4_def_policy.policy = IPSEC_POLICY_NONE; + ip4_def_policy.refcnt++; /*never reclaim this*/ +#ifdef INET6 + ip6_def_policy.policy = IPSEC_POLICY_NONE; + ip6_def_policy.refcnt++; /*never reclaim this*/ +#endif + +#ifndef IPSEC_DEBUG2 + timeout((void *)key_timehandler, (void *)0, 100); +#endif /*IPSEC_DEBUG2*/ + + /* initialize key statistics */ + keystat.getspi_count = 1; + + printf("IPsec: Initialized Security Association Processing.\n"); + + return; } /* - * Protoswitch entry for pf_key + * XXX: maybe This function is called after INBOUND IPsec processing. + * + * Special check for tunnel-mode packets. + * We must make some checks for consistency between inner and outer IP header. + * + * xxx more checks to be provided */ +int +key_checktunnelsanity(sav, family, src, dst) + struct secasvar *sav; + u_int family; + caddr_t src; + caddr_t dst; +{ + /* sanity check */ + if (sav->sah == NULL) + panic("sav->sah == NULL at key_checktunnelsanity"); -extern struct domain keydomain; /* or at least forward */ - -struct pr_usrreqs key_usrreqs = { - key_abort, pru_accept_notsupp, key_attach, key_bind, key_connect, - pru_connect2_notsupp, in_control, key_detach, key_disconnect, - pru_listen_notsupp, in_setpeeraddr, pru_rcvd_notsupp, - pru_rcvoob_notsupp, key_send, pru_sense_null, key_shutdown, - in_setsockaddr, sosend, soreceive, sopoll -}; + /* XXX: check inner IP header */ + return 1; +} -struct protosw keysw[] = { -{ SOCK_RAW, &keydomain, 0, PR_ATOMIC|PR_ADDR, - 0, key_output, raw_ctlinput, 0, - 0, - key_cbinit, 0, 0, 0, - &key_usrreqs, -}, -}; +#if 0 +#ifdef __FreeBSD__ +#define hostnamelen strlen(hostname) +#endif -struct domain keydomain = - { PF_KEY, "key", key_init, 0, 0, - keysw, &keysw[sizeof(keysw)/sizeof(keysw[0])] }; +/* + * Get FQDN for the host. + * If the administrator configured hostname (by hostname(1)) without + * domain name, returns nothing. + */ +static const char * +key_getfqdn() +{ + int i; + int hasdot; + static char fqdn[MAXHOSTNAMELEN + 1]; + + if (!hostnamelen) + return NULL; + + /* check if it comes with domain name. */ + hasdot = 0; + for (i = 0; i < hostnamelen; i++) { + if (hostname[i] == '.') + hasdot++; + } + if (!hasdot) + return NULL; + + /* NOTE: hostname may not be NUL-terminated. */ + bzero(fqdn, sizeof(fqdn)); + bcopy(hostname, fqdn, hostnamelen); + fqdn[hostnamelen] = '\0'; + return fqdn; +} -#ifdef __FreeBSD__ -DOMAIN_SET(key); +/* + * get username@FQDN for the host/user. + */ +static const char * +key_getuserfqdn() +{ + const char *host; + static char userfqdn[MAXHOSTNAMELEN + MAXLOGNAME + 2]; + struct proc *p = curproc; + char *q; + + if (!p || !p->p_pgrp || !p->p_pgrp->pg_session) + return NULL; + if (!(host = key_getfqdn())) + return NULL; + + /* NOTE: s_login may not be-NUL terminated. */ + bzero(userfqdn, sizeof(userfqdn)); + bcopy(p->p_pgrp->pg_session->s_login, userfqdn, MAXLOGNAME); + userfqdn[MAXLOGNAME] = '\0'; /* safeguard */ + q = userfqdn + strlen(userfqdn); + *q++ = '@'; + bcopy(host, q, strlen(host)); + q += strlen(host); + *q++ = '\0'; + + return userfqdn; +} #endif -#endif /*KEY*/ +/* record data transfer on SA, and update timestamps */ +void +key_sa_recordxfer(sav, m) + struct secasvar *sav; + struct mbuf *m; +{ + if (!sav) + panic("key_sa_recordxfer called with sav == NULL"); + if (!m) + panic("key_sa_recordxfer called with m == NULL"); + if (!sav->lft_c) + return; + + sav->lft_c->sadb_lifetime_bytes += m->m_pkthdr.len; + /* to check bytes lifetime is done in key_timehandler(). */ + + /* + * We use the number of packets as the unit of + * sadb_lifetime_allocations. We increment the variable + * whenever {esp,ah}_{in,out}put is called. + */ + sav->lft_c->sadb_lifetime_allocations++; + /* XXX check for expires? */ + + /* + * NOTE: We record CURRENT sadb_lifetime_usetime by using wall clock, + * in seconds. HARD and SOFT lifetime are measured by the time + * difference (again in seconds) from sadb_lifetime_usetime. + * + * usetime + * v expire expire + * -----+-----+--------+---> t + * <--------------> HARD + * <-----> SOFT + */ + { + struct timeval tv; + microtime(&tv); + sav->lft_c->sadb_lifetime_usetime = tv.tv_sec; + /* XXX check for expires? */ + } + + return; +} + +/* dumb version */ +void +key_sa_routechange(dst) + struct sockaddr *dst; +{ + struct secashead *sah; + struct route *ro; + + __LIST_FOREACH(sah, &sahtree, chain) { + ro = &sah->sa_route; + if (ro->ro_rt && dst->sa_len == ro->ro_dst.sa_len + && bcmp(dst, &ro->ro_dst, dst->sa_len) == 0) { + RTFREE(ro->ro_rt); + ro->ro_rt = (struct rtentry *)NULL; + } + } + + return; +} + +static void +key_sa_chgstate(sav, state) + struct secasvar *sav; + u_int8_t state; +{ + if (sav == NULL) + panic("key_sa_chgstate called with sav == NULL"); + + if (sav->state == state) + return; + + if (__LIST_CHAINED(sav)) + LIST_REMOVE(sav, chain); + + sav->state = state; + LIST_INSERT_HEAD(&sav->sah->savtree[state], sav, chain); +} diff --git a/sys/netkey/key.h b/sys/netkey/key.h index ccd2fc7..ec02403 100644 --- a/sys/netkey/key.h +++ b/sys/netkey/key.h @@ -1,299 +1,78 @@ -/*---------------------------------------------------------------------- - * key.h : Declarations and Definitions for Key Engine for BSD. +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. * - * Copyright 1995 by Bao Phan, Randall Atkinson, & Dan McDonald, - * All Rights Reserved. All rights have been assigned to the US - * Naval Research Laboratory (NRL). The NRL Copyright Notice and - * License Agreement governs distribution and use of this software. + * 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. * - * Patents are pending on this technology. NRL grants a license - * to use this technology at no cost under the terms below with - * the additional requirement that software, hardware, and - * documentation relating to use of this technology must include - * the note that: - * This product includes technology developed at and - * licensed from the Information Technology Division, - * US Naval Research Laboratory. + * 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. * - ----------------------------------------------------------------------*/ -/*---------------------------------------------------------------------- -# @(#)COPYRIGHT 1.1a (NRL) 17 August 1995 - -COPYRIGHT NOTICE - -All of the documentation and software included in this software -distribution from the US Naval Research Laboratory (NRL) are -copyrighted by their respective developers. - -This software and documentation were developed at NRL by various -people. Those developers have each copyrighted the portions that they -developed at NRL and have assigned All Rights for those portions to -NRL. Outside the USA, NRL also has copyright on the software -developed at NRL. The affected files all contain specific copyright -notices and those notices must be retained in any derived work. - -NRL LICENSE - -NRL grants permission for redistribution and use in source and binary -forms, with or without modification, of the software and documentation -created at NRL 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. All advertising materials mentioning features or use of this software - must display the following acknowledgement: - - This product includes software developed at the Information - Technology Division, US Naval Research Laboratory. - -4. Neither the name of the NRL nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - -THE SOFTWARE PROVIDED BY NRL IS PROVIDED BY NRL 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 NRL 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. - -The views and conclusions contained in the software and documentation -are those of the authors and should not be interpreted as representing -official policies, either expressed or implied, of the US Naval -Research Laboratory (NRL). - -----------------------------------------------------------------------*/ - -#ifndef _netkey_key_h -#define _netkey_key_h 1 - -/* - * PF_KEY messages - */ - -#define KEY_ADD 1 -#define KEY_DELETE 2 -#define KEY_UPDATE 3 -#define KEY_GET 4 -#define KEY_ACQUIRE 5 -#define KEY_GETSPI 6 -#define KEY_REGISTER 7 -#define KEY_EXPIRE 8 -#define KEY_DUMP 9 -#define KEY_FLUSH 10 - -#define KEY_VERSION 1 -#define POLICY_VERSION 1 - -#define SECURITY_TYPE_NONE 0 - -#define KEY_TYPE_AH 1 -#define KEY_TYPE_ESP 2 -#define KEY_TYPE_RSVP 3 -#define KEY_TYPE_OSPF 4 -#define KEY_TYPE_RIPV2 5 -#define KEY_TYPE_MIPV4 6 -#define KEY_TYPE_MIPV6 7 -#define KEY_TYPE_MAX 7 - -/* - * Security association state + * $FreeBSD$ */ -#define K_USED 0x1 /* Key used/not used */ -#define K_UNIQUE 0x2 /* Key unique/reusable */ -#define K_LARVAL 0x4 /* SPI assigned, but sa incomplete */ -#define K_ZOMBIE 0x8 /* sa expired but still useable */ -#define K_DEAD 0x10 /* sa marked for deletion, ready for reaping */ -#define K_INBOUND 0x20 /* sa for inbound packets, ie. dst=myhost */ -#define K_OUTBOUND 0x40 /* sa for outbound packets, ie. src=myhost */ - - -#ifndef MAX_SOCKADDR_SZ -#ifdef INET6 -#define MAX_SOCKADDR_SZ (sizeof(struct sockaddr_in6)) -#else /* INET6 */ -#define MAX_SOCKADDR_SZ (sizeof(struct sockaddr_in)) -#endif /* INET6 */ -#endif /* MAX_SOCKADDR_SZ */ - -#ifndef MAX_KEY_SZ -#define MAX_KEY_SZ 16 -#endif /* MAX_KEY_SZ */ - -#ifndef MAX_IV_SZ -#define MAX_IV_SZ 16 -#endif /* MAX_IV_SZ */ - -/* Security association data for IP Security */ -struct key_secassoc { - u_int8_t len; /* Length of the data (for radix) */ - u_int8_t type; /* Type of association */ - u_int8_t vers; /* Version of association (AH/ESP) */ - u_int8_t state; /* State of the association */ - u_int8_t label; /* Sensitivity label (unused) */ - u_int32_t spi; /* SPI */ - u_int8_t keylen; /* Key length */ - u_int8_t ekeylen; /* Extra key length */ - u_int8_t ivlen; /* Initialization vector length */ - u_int8_t algorithm; /* Algorithm switch index */ - u_int8_t lifetype; /* Type of lifetime */ - caddr_t iv; /* Initialization vector */ - caddr_t key; /* Key */ - caddr_t ekey; /* Extra key */ - u_int32_t lifetime1; /* Lifetime value 1 */ - u_int32_t lifetime2; /* Lifetime value 2 */ - struct sockaddr *src; /* Source host address */ - struct sockaddr *dst; /* Destination host address */ - struct sockaddr *from; /* Originator of association */ - - int antireplay; /*anti replay flag*/ - u_int32_t sequence; /*send: sequence number*/ - u_int32_t replayright; /*receive: replay window, right*/ - u_int64_t replaywindow; /*receive: replay window*/ -}; - -/* - * Structure for key message header. PF_KEY message consists of key_msghdr - * followed by src struct sockaddr, dest struct sockaddr, from struct - * sockaddr, key, and iv. Assumes size of key message header less than MHLEN. - */ - -struct key_msghdr { - u_short key_msglen; /* length of message including - * src/dst/from/key/iv */ - u_char key_msgvers; /* key version number */ - u_char key_msgtype; /* key message type, eg. KEY_ADD */ - pid_t key_pid; /* process id of message sender */ - int key_seq; /* message sequence number */ - int key_errno; /* error code */ - u_int8_t type; /* type of security association */ - u_int8_t vers; /* version of sassoc (AH/ESP) */ - u_int8_t state; /* state of security association */ - u_int8_t label; /* sensitivity level */ - u_int8_t pad; /* padding for allignment */ - u_int32_t spi; /* spi value */ - u_int8_t keylen; /* key length */ - u_int8_t ekeylen; /* extra key length */ - u_int8_t ivlen; /* iv length */ - u_int8_t algorithm; /* algorithm identifier */ - u_int8_t lifetype; /* type of lifetime */ - u_int32_t lifetime1; /* lifetime value 1 */ - u_int32_t lifetime2; /* lifetime value 2 */ - - int antireplay; /* anti replay flag */ -}; - -struct key_msgdata { - struct sockaddr *src; /* source host address */ - struct sockaddr *dst; /* destination host address */ - struct sockaddr *from; /* originator of security association */ - caddr_t iv; /* initialization vector */ - caddr_t key; /* key */ - caddr_t ekey; /* extra key */ - int ivlen; /* key length */ - int keylen; /* iv length */ - int ekeylen; /* extra key length */ -}; - -struct policy_msghdr { - u_short policy_msglen; /* message length */ - u_char policy_msgvers; /* message version */ - u_char policy_msgtype; /* message type */ - int policy_seq; /* message sequence number */ - int policy_errno; /* error code */ -}; - -/* - * Key engine table structures - */ - -struct socketlist { - struct socket *socket; /* pointer to socket */ - struct socketlist *next; /* next */ -}; - -struct key_tblnode { - int alloc_count; /* number of sockets allocated to - * secassoc */ - int ref_count; /* number of sockets referencing - * secassoc */ - struct socketlist *solist; /* list of sockets allocated to - * secassoc */ - struct key_secassoc *secassoc; /* security association */ - struct key_tblnode *next; /* next node */ -}; - -struct key_allocnode { - struct key_tblnode *keynode; - struct key_allocnode *next; -}; - -struct key_so2spinode { - struct socket *socket; /* socket pointer */ - struct key_tblnode *keynode; /* pointer to tblnode containing - * secassoc */ - /* info for socket */ - struct key_so2spinode *next; -}; - -struct key_registry { - u_int8_t type; /* secassoc type that key mgnt. daemon can - * acquire */ - struct socket *socket; /* key management daemon socket pointer */ - struct key_registry *next; -}; - -struct key_acquirelist { - u_int8_t type; /* secassoc type to acquire */ - struct sockaddr *target; /* destination address of secassoc */ - u_int32_t count; /* number of acquire messages sent */ - u_long expiretime; /* expiration time for acquire message */ - struct key_acquirelist *next; -}; - -struct keyso_cb { - int ip4_count; -#ifdef INET6 - int ip6_count; -#endif /*INET6*/ - int any_count; /* Sum of above counters */ -}; - -#ifdef KERNEL -extern int key_secassoc2msghdr __P((struct key_secassoc *, struct key_msghdr *, - struct key_msgdata *)); -extern int key_msghdr2secassoc __P((struct key_secassoc *, struct key_msghdr *, - struct key_msgdata *)); -extern int key_inittables __P((void)); -extern void key_sodelete __P((struct socket *, int)); -extern int key_add __P((struct key_secassoc *)); -extern int key_delete __P((struct key_secassoc *)); -extern int key_get __P((u_int, struct sockaddr *, struct sockaddr *, - u_int32_t, struct key_secassoc **)); -extern void key_flush __P((void)); -extern int key_dump __P((struct socket *)); -extern int key_getspi __P((u_int, u_int, struct sockaddr *, struct sockaddr *, - u_int32_t, u_int32_t, u_int32_t *)); -extern int key_update __P((struct key_secassoc *)); -extern int key_register __P((struct socket *, u_int)); -extern void key_unregister __P((struct socket *, u_int, int)); -extern int key_acquire __P((u_int, struct sockaddr *, struct sockaddr *)); -extern int getassocbyspi __P((u_int, struct sockaddr *, struct sockaddr *, - u_int32_t, struct key_tblnode **)); -extern int getassocbysocket __P((u_int, struct sockaddr *, struct sockaddr *, - struct socket *, u_int, struct key_tblnode **)); -extern void key_free __P((struct key_tblnode *)); -extern int key_parse __P((struct key_msghdr ** km, struct socket * so, - int *)); -#endif /* KERNEL */ - -#endif /* _netkey_key_h */ +/* $Id: key.h,v 1.1.6.1.6.1 1999/05/17 17:03:14 itojun Exp $ */ + +#ifndef _NETKEY_KEY_H_ +#define _NETKEY_KEY_H_ + +#if defined(KERNEL) + +extern struct key_cb key_cb; + +struct secpolicy; +struct secpolicyindex; +struct ipsecrequest; +struct secasvar; +struct sockaddr; +struct socket; +struct sadb_msg; +struct sadb_x_policy; + +extern struct secpolicy *key_allocsp __P((struct secpolicyindex *spidx, + u_int dir)); +extern int key_checkrequest __P((struct ipsecrequest *isr)); +extern struct secasvar *key_allocsa __P((u_int family, caddr_t src, caddr_t dst, + u_int proto, u_int32_t spi)); +extern void key_freesp __P((struct secpolicy *sp)); +extern void key_freeso __P((struct socket *so)); +extern void key_freesav __P((struct secasvar *sav)); +extern struct secpolicy *key_newsp __P((void)); +extern struct secpolicy *key_msg2sp __P((struct sadb_x_policy *xpl0)); +extern struct sadb_x_policy *key_sp2msg __P((struct secpolicy *sp)); +extern int key_ismyaddr __P((u_int family, caddr_t addr)); +extern void key_timehandler __P((void)); +extern void key_srandom __P((void)); +extern void key_freereg __P((struct socket *so)); +extern int key_parse __P((struct sadb_msg **msgp, struct socket *so, + int *targetp)); +extern void key_init __P((void)); +extern int key_checktunnelsanity __P((struct secasvar *sav, u_int family, + caddr_t src, caddr_t dst)); +extern void key_sa_recordxfer __P((struct secasvar *sav, struct mbuf *m)); +extern void key_sa_routechange __P((struct sockaddr *dst)); + +#ifdef MALLOC_DECLARE +MALLOC_DECLARE(M_SECA); +#endif /* MALLOC_DECLARE */ + +#endif /* defined(KERNEL) */ +#endif /* _NETKEY_KEY_H_ */ diff --git a/sys/netkey/key_debug.c b/sys/netkey/key_debug.c index b9b2c0f..ad91068 100644 --- a/sys/netkey/key_debug.c +++ b/sys/netkey/key_debug.c @@ -1,759 +1,689 @@ /* - * modified by Jun-ichiro itojun Itoh <itojun@itojun.org>, 1997 - */ -/* - * in6_debug.c -- Insipired by Craig Metz's Net/2 in6_debug.c, but - * not quite as heavyweight (initially, anyway). + * 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. * - * The idea is to have globals here, and dump netinet6/ data structures. + * 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. * - * Copyright 1995 by Dan McDonald, Bao Phan, and Randall Atkinson, - * All Rights Reserved. - * All Rights under this copyright have been assigned to NRL. + * $FreeBSD$ */ -/*---------------------------------------------------------------------- -# @(#)COPYRIGHT 1.1a (NRL) 17 August 1995 - -COPYRIGHT NOTICE - -All of the documentation and software included in this software -distribution from the US Naval Research Laboratory (NRL) are -copyrighted by their respective developers. - -This software and documentation were developed at NRL by various -people. Those developers have each copyrighted the portions that they -developed at NRL and have assigned All Rights for those portions to -NRL. Outside the USA, NRL also has copyright on the software -developed at NRL. The affected files all contain specific copyright -notices and those notices must be retained in any derived work. - -NRL LICENSE - -NRL grants permission for redistribution and use in source and binary -forms, with or without modification, of the software and documentation -created at NRL 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. All advertising materials mentioning features or use of this software - must display the following acknowledgement: - - This product includes software developed at the Information - Technology Division, US Naval Research Laboratory. - -4. Neither the name of the NRL nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - -THE SOFTWARE PROVIDED BY NRL IS PROVIDED BY NRL 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 NRL 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. +/* KAME @(#)$Id: key_debug.c,v 1.1.6.2.4.3 1999/07/06 12:05:13 itojun Exp $ */ -The views and conclusions contained in the software and documentation -are those of the authors and should not be interpreted as representing -official policies, either expressed or implied, of the US Naval -Research Laboratory (NRL). - -----------------------------------------------------------------------*/ - - -#define INET6_DEBUG_C - -#include "opt_key.h" - -#ifdef KEY -#ifdef KEY_DEBUG /*wraps the whole code*/ +#ifdef _KERNEL +# ifndef KERNEL +# define KERNEL +# endif +#endif -/*#include <netkey/osdep_44bsd.h>*/ +#ifdef KERNEL +#include "opt_inet6.h" +#include "opt_ipsec.h" +#endif +#include <sys/types.h> #include <sys/param.h> -#include <sys/socket.h> -#include <sys/mbuf.h> +#ifdef KERNEL #include <sys/systm.h> +#include <sys/mbuf.h> +#endif +#include <sys/socket.h> -#include <net/if.h> -#include <net/if_dl.h> #include <net/route.h> -#include <netinet/in.h> - -#include <netinet/in_systm.h> -#include <netinet/in_pcb.h> +#include <netkey/key_var.h> +#include <netkey/key_debug.h> -#ifdef INET6 +#include <netinet/in.h> #include <netinet6/in6.h> -#include <netinet6/in6_var.h> -#include <netinet6/ip6.h> -#include <netinet6/ip6_var.h> -#include <netinet6/icmp6.h> -#include <netinet6/in6_pcb.h> -#else /* INET6 */ -#if 0 -#include "in6_types.h" +#include <netinet6/ipsec.h> + +#if !defined(KERNEL) +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#endif /* defined(KERNEL) */ + +#if !defined(KERNEL) || (defined(KERNEL) && defined(IPSEC_DEBUG)) + +static void kdebug_sadb_prop __P((struct sadb_ext *)); +static void kdebug_sadb_identity __P((struct sadb_ext *)); +static void kdebug_sadb_supported __P((struct sadb_ext *)); +static void kdebug_sadb_lifetime __P((struct sadb_ext *)); +static void kdebug_sadb_sa __P((struct sadb_ext *)); +static void kdebug_sadb_address __P((struct sadb_ext *)); +static void kdebug_sadb_key __P((struct sadb_ext *)); + +#ifdef KERNEL +static void kdebug_secreplay __P((struct secreplay *)); #endif -#endif /* INET6 */ - -#define SA_LEN 1 -#define SIN_LEN 1 -#ifdef KEY_DEBUG -#include <netkey/key.h> -#include <netkey/key_debug.h> -#endif /* KEY_DEBUG */ -#ifdef IPSEC_DEBUG -#include <netsec/ipsec.h> -#endif /* IPSEC_DEBUG */ - -#if 0 -#include <netinet6/in6_debug.h> +#ifndef KERNEL +#define panic(param) { printf(param); exit(-1); } #endif -/* - * Globals - */ - -/* The following should be sysctl-tweakable. */ - -unsigned int in6_debug_level = IDL_FINISHED + 1; /* 0 is no debugging */ +/* NOTE: host byte order */ -/* - * Functions and macros. - */ - -void in6_debug_init() +/* %%%: about struct sadb_msg */ +void +kdebug_sadb(base) + struct sadb_msg *base; { - /* For now, nothing. */ + struct sadb_ext *ext; + int tlen, extlen; + + /* sanity check */ + if (base == NULL) + panic("kdebug_sadb: NULL pointer was passed.\n"); + + printf("sadb_msg{ version=%u type=%u errno=%u satype=%u\n", + base->sadb_msg_version, base->sadb_msg_type, + base->sadb_msg_errno, base->sadb_msg_satype); + printf(" len=%u mode=%u reserved=%u seq=%u pid=%u }\n", + base->sadb_msg_len, base->sadb_msg_mode, + base->sadb_msg_reserved, base->sadb_msg_seq, base->sadb_msg_pid); + + tlen = PFKEY_UNUNIT64(base->sadb_msg_len) - sizeof(struct sadb_msg); + ext = (struct sadb_ext *)((caddr_t)base + sizeof(struct sadb_msg)); + + while (tlen > 0) { + printf("sadb_ext{ len=%u type=%u }\n", + ext->sadb_ext_len, ext->sadb_ext_type); + + if (ext->sadb_ext_len == 0) { + printf("kdebug_sadb: invalid ext_len=0 was passed.\n"); + return; + } + + switch (ext->sadb_ext_type) { + case SADB_EXT_SA: + kdebug_sadb_sa(ext); + break; + case SADB_EXT_LIFETIME_CURRENT: + case SADB_EXT_LIFETIME_HARD: + case SADB_EXT_LIFETIME_SOFT: + kdebug_sadb_lifetime(ext); + break; + case SADB_EXT_ADDRESS_SRC: + case SADB_EXT_ADDRESS_DST: + case SADB_EXT_ADDRESS_PROXY: + kdebug_sadb_address(ext); + break; + case SADB_EXT_KEY_AUTH: + case SADB_EXT_KEY_ENCRYPT: + kdebug_sadb_key(ext); + break; + case SADB_EXT_IDENTITY_SRC: + case SADB_EXT_IDENTITY_DST: + kdebug_sadb_identity(ext); + break; + case SADB_EXT_SENSITIVITY: + break; + case SADB_EXT_PROPOSAL: + kdebug_sadb_prop(ext); + break; + case SADB_EXT_SUPPORTED_AUTH: + case SADB_EXT_SUPPORTED_ENCRYPT: + kdebug_sadb_supported(ext); + break; + case SADB_EXT_SPIRANGE: + case SADB_X_EXT_KMPRIVATE: + break; + case SADB_X_EXT_POLICY: + kdebug_sadb_x_policy(ext); + break; + default: + printf("kdebug_sadb: invalid ext_type %u was passed.\n", + ext->sadb_ext_type); + return; + } + + extlen = PFKEY_UNUNIT64(ext->sadb_ext_len); + tlen -= extlen; + ext = (struct sadb_ext *)((caddr_t)ext + extlen); + } + + return; } -/*---------------------------------------------------------------------- - * dump_* dumps various data structures. These should be called within - * the context of a DDO() macro. They assume address and port fields - * are in network order. - ----------------------------------------------------------------------*/ - -#ifdef INET6 -/*---------------------------------------------------------------------- - * Dump an IPv6 address. Don't compress 0's out because of debugging. - ----------------------------------------------------------------------*/ -void dump_in6_addr(in6_addr) - struct in6_addr *in6_addr; +static void +kdebug_sadb_prop(ext) + struct sadb_ext *ext; { - u_short *shorts = (u_short *)in6_addr; - int i = 0; - - if (!in6_addr) { - printf("Dereference a NULL in6_addr? I don't think so.\n"); - return; - } - - printf("(conv. for printing) "); - while (i < 7) - printf("%4x:",htons(shorts[i++])); - printf("%4x\n",htons(shorts[7])); + struct sadb_prop *prop = (struct sadb_prop *)ext; + struct sadb_comb *comb; + int len; + + /* sanity check */ + if (ext == NULL) + panic("kdebug_sadb_prop: NULL pointer was passed.\n"); + + len = (PFKEY_UNUNIT64(prop->sadb_prop_len) - sizeof(*prop)) + / sizeof(*comb); + comb = (struct sadb_comb *)(prop + 1); + printf("sadb_prop{ replay=%u\n", prop->sadb_prop_replay); + + while (len--) { + printf("sadb_comb{ auth=%u encrypt=%u " + "flags=0x%04x reserved=0x%08x\n", + comb->sadb_comb_auth, comb->sadb_comb_encrypt, + comb->sadb_comb_flags, comb->sadb_comb_reserved); + + printf(" auth_minbits=%u auth_maxbits=%u " + "encrypt_minbits=%u encrypt_maxbits=%u\n", + comb->sadb_comb_auth_minbits, + comb->sadb_comb_auth_maxbits, + comb->sadb_comb_encrypt_minbits, + comb->sadb_comb_encrypt_maxbits); + + printf(" soft_alloc=%u hard_alloc=%u " + "soft_bytes=%lu hard_bytes=%lu\n", + comb->sadb_comb_soft_allocations, + comb->sadb_comb_hard_allocations, + (unsigned long)comb->sadb_comb_soft_bytes, + (unsigned long)comb->sadb_comb_hard_bytes); + + printf(" soft_alloc=%lu hard_alloc=%lu " + "soft_bytes=%lu hard_bytes=%lu }\n", + (unsigned long)comb->sadb_comb_soft_addtime, + (unsigned long)comb->sadb_comb_hard_addtime, + (unsigned long)comb->sadb_comb_soft_usetime, + (unsigned long)comb->sadb_comb_hard_usetime); + comb++; + } + printf("}\n"); + + return; } -#endif /* INET6 */ -/*---------------------------------------------------------------------- - * Dump and IPv4 address in x.x.x.x form. - ----------------------------------------------------------------------*/ -void dump_in_addr(in_addr) - struct in_addr *in_addr; +static void +kdebug_sadb_identity(ext) + struct sadb_ext *ext; { - u_char *chars = (u_char *)in_addr; - int i = 0; - - if (!in_addr) { - printf("Dereference a NULL in_addr? I don't think so.\n"); - return; - } + struct sadb_ident *id = (struct sadb_ident *)ext; + int len; + + /* sanity check */ + if (ext == NULL) + panic("kdebug_sadb_identity: NULL pointer was passed.\n"); + + len = PFKEY_UNUNIT64(id->sadb_ident_len) - sizeof(*id); + printf("sadb_ident_%s{", + id->sadb_ident_exttype == SADB_EXT_IDENTITY_SRC ? "src" : "dst"); + printf(" type=%d id=%lu", + id->sadb_ident_type, (u_long)id->sadb_ident_id); + if (len) { +#ifdef KERNEL + ipsec_hexdump((caddr_t)(id + 1), len); /*XXX cast ?*/ +#else + char *p, *ep; + printf("\n str=\""); + p = (char *)(id + 1); + ep = p + len; + for (/*nothing*/; *p && p < ep; p++) { + if (isprint(*p)) + printf("%c", *p & 0xff); + else + printf("\\%03o", *p & 0xff); + } +#endif + printf("\""); + } + printf(" }\n"); - while (i < 3) - printf("%d.",chars[i++]); - printf("%d\n",chars[3]); + return; } -#ifdef INET6 -/*---------------------------------------------------------------------- - * Dump an IPv6 socket address. - ----------------------------------------------------------------------*/ -void dump_sockaddr_in6(sin6) - struct sockaddr_in6 *sin6; +static void +kdebug_sadb_supported(ext) + struct sadb_ext *ext; { - if (!sin6) { - printf("Dereference a NULL sockaddr_in6? I don't think so.\n"); - return; - } - - printf("sin6_len = %d, sin6_family = %d, sin6_port = %d (0x%x)\n", - sin6->sin6_len,sin6->sin6_family, htons(sin6->sin6_port), - htons(sin6->sin6_port)); - printf("sin6_flowinfo = 0x%x\n",sin6->sin6_flowinfo); - printf("sin6_addr = "); - dump_in6_addr(&sin6->sin6_addr); + struct sadb_supported *sup = (struct sadb_supported *)ext; + struct sadb_alg *alg; + int len; + + /* sanity check */ + if (ext == NULL) + panic("kdebug_sadb_supported: NULL pointer was passed.\n"); + + len = (PFKEY_UNUNIT64(sup->sadb_supported_len) - sizeof(*sup)) + / sizeof(*alg); + alg = (struct sadb_alg *)(sup + 1); + printf("sadb_sup{\n"); + while (len--) { + printf(" { id=%d ivlen=%d min=%d max=%d }\n", + alg->sadb_alg_id, alg->sadb_alg_ivlen, + alg->sadb_alg_minbits, alg->sadb_alg_maxbits); + alg++; + } + printf("}\n"); + + return; } -#endif /* INET6 */ -/*---------------------------------------------------------------------- - * Dump an IPv4 socket address. - ----------------------------------------------------------------------*/ -void dump_sockaddr_in(sin) - struct sockaddr_in *sin; +static void +kdebug_sadb_lifetime(ext) + struct sadb_ext *ext; { - int i; - - if (!sin) { - printf("Dereference a NULL sockaddr_in? I don't think so.\n"); - return; - } - -#ifdef SIN_LEN - printf("sin_len = %d, ", sin->sin_len); -#endif /* SIN_LEN */ - printf("sin_family = %d, sin_port (conv.) = %d (0x%x)\n", - sin->sin_family, htons(sin->sin_port), - htons(sin->sin_port)); - printf("sin_addr = "); - dump_in_addr(&sin->sin_addr); - printf("sin_zero == "); - for(i=0;i<8;i++) - printf("0x%2x ",sin->sin_zero[i]); - printf("\n"); -} + struct sadb_lifetime *lft = (struct sadb_lifetime *)ext; -/*---------------------------------------------------------------------- - * Dump a generic socket address. Use if no family-specific routine is - * available. - ----------------------------------------------------------------------*/ -void dump_sockaddr(sa) - struct sockaddr *sa; -{ - if (!sa) { - printf("Dereference a NULL sockaddr? I don't think so.\n"); - return; - } - -#ifdef SA_LEN - printf("sa_len = %d, ", sa->sa_len); -#endif /* SA_LEN */ - printf("sa_family = %d", sa->sa_family); -#ifdef SA_LEN - printf(", remaining bytes are:\n"); - { - int i; - for (i = 0; i <sa->sa_len - 2; i++) - printf("0x%2x ",(unsigned char)sa->sa_data[i]); - } -#endif /* SA_LEN */ - printf("\n"); -} + /* sanity check */ + if (ext == NULL) + printf("kdebug_sadb_lifetime: NULL pointer was passed.\n"); -/*---------------------------------------------------------------------- - * Dump a link-layer socket address. (Not that there are user-level link - * layer sockets, but there are plenty of link-layer addresses in the kernel.) - ----------------------------------------------------------------------*/ -void dump_sockaddr_dl(sdl) - struct sockaddr_dl *sdl; -{ - char buf[256]; - - if (!sdl) { - printf("Dereference a NULL sockaddr_dl? I don't think so.\n"); - return; - } - - printf("sdl_len = %d, sdl_family = %d, sdl_index = %d, sdl_type = %d,\n", - sdl->sdl_len, sdl->sdl_family, sdl->sdl_index, sdl->sdl_type); - buf[sdl->sdl_nlen] = 0; - if (sdl->sdl_nlen) - bcopy(sdl->sdl_data,buf,sdl->sdl_nlen); - printf("sdl_nlen = %d, (name = '%s'\n",sdl->sdl_nlen,buf); - printf("sdl_alen = %d, ",sdl->sdl_alen); - if (sdl->sdl_alen) - { - int i; - - printf("(addr = "); - for (i = 0; i<sdl->sdl_alen; i++) - printf("0x%2x ",(unsigned char)sdl->sdl_data[i+sdl->sdl_nlen]); - } - printf("\n"); - printf("sdl_slen = %d, ",sdl->sdl_slen); - if (sdl->sdl_slen) - { - int i; - - printf("(addr = "); - for (i = 0; i<sdl->sdl_slen; i++) - printf("0x%2x ", - (unsigned char)sdl->sdl_data[i+sdl->sdl_nlen+sdl->sdl_alen]); - } - printf("\n"); -} + printf("sadb_lifetime{ alloc=%u, bytes=%u\n", + lft->sadb_lifetime_allocations, + (u_int32_t)lft->sadb_lifetime_bytes); + printf(" addtime=%u, usetime=%u }\n", + (u_int32_t)lft->sadb_lifetime_addtime, + (u_int32_t)lft->sadb_lifetime_usetime); -/*---------------------------------------------------------------------- - * Dump a socket address, calling a family-specific routine if available. - ----------------------------------------------------------------------*/ -void dump_smart_sockaddr(sa) - struct sockaddr *sa; -{ - DPRINTF(IDL_MAJOR_EVENT, ("Entering dump_smart_sockaddr\n")); - if (!sa) { - printf("Dereference a NULL sockaddr? I don't think so.\n"); - return; - } - - switch (sa->sa_family) - { -#ifdef INET6 - case AF_INET6: - dump_sockaddr_in6((struct sockaddr_in6 *)sa); - break; -#endif /* INET6 */ - case AF_INET: - dump_sockaddr_in((struct sockaddr_in *)sa); - break; - case AF_LINK: - dump_sockaddr_dl((struct sockaddr_dl *)sa); - break; - default: - dump_sockaddr(sa); - break; - } + return; } -#ifdef INET6 -/*---------------------------------------------------------------------- - * Dump an IPv6 header. - ----------------------------------------------------------------------*/ -void dump_ipv6(ip6) - struct ip6 *ip6; +static void +kdebug_sadb_sa(ext) + struct sadb_ext *ext; { - if (!ip6) { - printf("Dereference a NULL ip6? I don't think so.\n"); - return; - } - - printf("Vers = %d, pri = 0x%x, flow label = 0x%x\n", - ip6->ip6_v, ip6->ip6_pri, htonl(ip6->ip6_flbl)); - printf("Length (conv) = %d, nexthdr = %d, hoplimit = %d.\n", - htons(ip6->ip6_len),ip6->ip6_nh,ip6->ip6_hlim); - printf("Src: "); - dump_in6_addr(&ip6->ip6_src); - printf("Dst: "); - dump_in6_addr(&ip6->ip6_dst); -} + struct sadb_sa *sa = (struct sadb_sa *)ext; -/*---------------------------------------------------------------------- - * Dump an ICMPv6 header. This function is not very smart beyond the - * type, code, and checksum. - ----------------------------------------------------------------------*/ -void dump_ipv6_icmp(icp) - struct icmp6 *icp; -{ - int i; + /* sanity check */ + if (ext == NULL) + panic("kdebug_sadb_sa: NULL pointer was passed.\n"); - if (!icp) { - printf("Dereference a NULL ipv6_icmp? I don't think so.\n"); - return; - } + printf("sadb_sa{ spi=%u replay=%u state=%u\n", + (u_int32_t)ntohl(sa->sadb_sa_spi), sa->sadb_sa_replay, + sa->sadb_sa_state); + printf(" auth=%u encrypt=%u flags=0x%08x }\n", + sa->sadb_sa_auth, sa->sadb_sa_encrypt, sa->sadb_sa_flags); - printf("type %d, code %d, cksum (conv) = 0x%x\n",icp->icmp6_type, - icp->icmp6_code,htons(icp->icmp6_cksum)); - printf("First four bytes: 0x%x",htonl(icp->icmp6_flags)); - printf("\n"); + return; } -#endif /* INET6 */ -/*---------------------------------------------------------------------- - * Dump only the header fields of a single mbuf. - ----------------------------------------------------------------------*/ -void dump_mbuf_hdr(m) - struct mbuf *m; +static void +kdebug_sadb_address(ext) + struct sadb_ext *ext; { - if (!m) { - printf("Dereference a NULL mbuf? I don't think so.\n"); - return; - } - - printf("Single mbuf at %p\n", (void *)m); - printf("m_len = %d, m_data = %p, m_type = %d\n",m->m_len, - (void *)m->m_data, m->m_type); - printf("m_flags = 0x%x ",m->m_flags); - if (m->m_flags & M_PKTHDR) - printf("m_pkthdr.len = %d, m_pkthdr.rcvif = %p",m->m_pkthdr.len, - (void *)m->m_pkthdr.rcvif); - if (m->m_flags & M_EXT) - printf(" (IS CLUSTER MBUF)"); - printf("\nm_next = %p m_nextpkt = %p\n",(void *)m->m_next, - (void *)m->m_nextpkt); -} + struct sadb_address *addr = (struct sadb_address *)ext; -/*---------------------------------------------------------------------- - * Dump the entire contents of a single mbuf. - ----------------------------------------------------------------------*/ -void dump_mbuf(m) - struct mbuf *m; -{ - int i; + /* sanity check */ + if (ext == NULL) + panic("kdebug_sadb_address: NULL pointer was passed.\n"); - dump_mbuf_hdr(m); - printf("m_data:\n"); - for (i = 0; i < m->m_len; i++) - printf("0x%2x%s",(unsigned char)m->m_data[i] , ((i+1) % 16)?" ":"\n"); - printf((i % 16)?"\n":""); -} + printf("sadb_address{ proto=%u prefixlen=%u reserved=0x%02x%02x }\n", + addr->sadb_address_proto, addr->sadb_address_prefixlen, + ((u_char *)&addr->sadb_address_reserved)[0], + ((u_char *)&addr->sadb_address_reserved)[1]); -/*---------------------------------------------------------------------- - * Dump the contents of an mbuf chain. (WARNING: Lots of text may - * result. - ----------------------------------------------------------------------*/ -void dump_mchain(m) - struct mbuf *m; -{ - struct mbuf *walker; - int i; + kdebug_sockaddr((struct sockaddr *)((caddr_t)ext + sizeof(*addr))); - for (walker = m, i = 0; walker != NULL && (i < 10); - walker = walker->m_next, i++) - dump_mbuf(walker); + return; } -/*---------------------------------------------------------------------- - * Dump an mbuf chain's data in a format similar to tcpdump(8). - ----------------------------------------------------------------------*/ -void dump_tcpdump(m) - struct mbuf *m; +static void +kdebug_sadb_key(ext) + struct sadb_ext *ext; { - int i, j, count; - - for (i = count = 0; m && (i < 10); m = m->m_next, i++) { - for (j = 0; j < m->m_len; j++, count++) { - if (!(count % (2 * 8))) - printf("\n\t\t\t"); - if (!(count % 2)) - printf(" "); - printf("%02x", (u_int8_t)(m->m_data[j])); - } - } + struct sadb_key *key = (struct sadb_key *)ext; + + /* sanity check */ + if (ext == NULL) + panic("kdebug_sadb_key: NULL pointer was passed.\n"); + + printf("sadb_key{ bits=%u reserved=%u\n", + key->sadb_key_bits, key->sadb_key_reserved); + printf(" key="); + + /* sanity check 2 */ + if ((key->sadb_key_bits >> 3) > + (PFKEY_UNUNIT64(key->sadb_key_len) - sizeof(struct sadb_key))) { + printf("kdebug_sadb_key: key length mismatch, bit:%d len:%ld.\n", + key->sadb_key_bits >> 3, + (long)PFKEY_UNUNIT64(key->sadb_key_len) - sizeof(struct sadb_key)); + } + + ipsec_hexdump((caddr_t)key + sizeof(struct sadb_key), + key->sadb_key_bits >> 3); + printf(" }\n"); + return; } -#if 0 -/*---------------------------------------------------------------------- - * Dump an IPv6 header index table, which is terminated by an entry with - * a NULL mbuf pointer. - ----------------------------------------------------------------------*/ -void dump_ihitab(ihi) - struct in6_hdrindex *ihi; +void +kdebug_sadb_x_policy(ext) + struct sadb_ext *ext; { - int i=0; - - if (!ihi) { - printf("Dereference a NULL hdrindex/ihi? I don't think so.\n"); - return; - } - - /* This is dangerous, make sure ihitab was bzeroed. */ - while (ihi[i].ihi_mbuf) - { - printf("ihi_nexthdr = %d, ihi_mbuf = 0x%x.\n",ihi[i].ihi_nexthdr, - ihi[i].ihi_mbuf); - i++; - } + struct sadb_x_policy *xpl = (struct sadb_x_policy *)ext; + struct sockaddr *addr; + + /* sanity check */ + if (ext == NULL) + panic("kdebug_sadb_x_policy: NULL pointer was passed.\n"); + + printf("sadb_x_policy{ type=%u dir=%u reserved=%x }\n", + xpl->sadb_x_policy_type, xpl->sadb_x_policy_dir, + xpl->sadb_x_policy_reserved); + + if (xpl->sadb_x_policy_type == IPSEC_POLICY_IPSEC) { + int tlen; + struct sadb_x_ipsecrequest *xisr; + + tlen = PFKEY_UNUNIT64(xpl->sadb_x_policy_len) - sizeof(*xpl); + xisr = (struct sadb_x_ipsecrequest *)(xpl + 1); + + while (tlen > 0) { + printf(" { len=%u proto=%u mode=%u level=%u\n", + xisr->sadb_x_ipsecrequest_len, + xisr->sadb_x_ipsecrequest_proto, + xisr->sadb_x_ipsecrequest_mode, + xisr->sadb_x_ipsecrequest_level); + + addr = (struct sockaddr *)(xisr + 1); + kdebug_sockaddr(addr); + addr = (struct sockaddr *)((caddr_t)addr + addr->sa_len); + kdebug_sockaddr(addr); + + printf(" }\n"); + + /* prevent infinite loop */ + if (xisr->sadb_x_ipsecrequest_len <= 0) + panic("kdebug_sadb_x_policy: wrong policy struct.\n"); + + tlen -= xisr->sadb_x_ipsecrequest_len; + + xisr = (struct sadb_x_ipsecrequest *)((caddr_t)xisr + + xisr->sadb_x_ipsecrequest_len); + } + + if (tlen != 0) + panic("kdebug_sadb_x_policy: wrong policy struct.\n"); + } + + return; } -#endif /* INET6 */ -/*---------------------------------------------------------------------- - * Dump an interface address. - ----------------------------------------------------------------------*/ -void dump_ifa(ifa) - struct ifaddr *ifa; +#ifdef KERNEL +/* %%%: about SPD and SAD */ +void +kdebug_secpolicy(sp) + struct secpolicy *sp; { - if (ifa == NULL) - { - printf("ifa of NULL.\n"); - return; - } - - printf("ifa_addr: "); - dump_smart_sockaddr(ifa->ifa_addr); - printf("ifa_netmask: "); - dump_smart_sockaddr(ifa->ifa_netmask); + /* sanity check */ + if (sp == NULL) + panic("kdebug_secpolicy: NULL pointer was passed.\n"); + + printf("secpolicy{ refcnt=%u state=%u policy=%u\n", + sp->refcnt, sp->state, sp->policy); + + kdebug_secpolicyindex(&sp->spidx); + + switch (sp->policy) { + case IPSEC_POLICY_DISCARD: + printf(" type=discard }\n"); + break; + case IPSEC_POLICY_NONE: + printf(" type=none }\n"); + break; + case IPSEC_POLICY_IPSEC: + { + struct ipsecrequest *isr; + for (isr = sp->req; isr != NULL; isr = isr->next) { + + printf(" level=%u\n", isr->level); + kdebug_secasindex(&isr->saidx); + + if (isr->sav != NULL) + kdebug_secasv(isr->sav); + } + printf(" }\n"); + } + break; + case IPSEC_POLICY_BYPASS: + printf(" type=bypass }\n"); + break; + case IPSEC_POLICY_ENTRUST: + printf(" type=entrust }\n"); + break; + default: + printf("kdebug_secpolicy: Invalid policy found. %d\n", + sp->policy); + break; + } + + return; } -/*---------------------------------------------------------------------- - * Dump an interface structure. - ----------------------------------------------------------------------*/ -void dump_ifp(ifp) - struct ifnet *ifp; +void +kdebug_secpolicyindex(spidx) + struct secpolicyindex *spidx; { - if (!ifp) { - printf("Dereference a NULL ifnet/ifp? I don't think so.\n"); - return; - } - - printf("Interface name: %s.\n",ifp->if_name); - printf("Interface type: %d. ",ifp->if_type); - printf("MTU: %lu.\n",ifp->if_mtu); + /* sanity check */ + if (spidx == NULL) + panic("kdebug_secpolicyindex: NULL pointer was passed.\n"); + + printf("secpolicyindex{ dir=%u prefs=%u prefd=%u ul_proto=%u\n", + spidx->dir, spidx->prefs, spidx->prefd, spidx->ul_proto); + + ipsec_hexdump((caddr_t)&spidx->src, spidx->src.__ss_len); + printf("\n"); + ipsec_hexdump((caddr_t)&spidx->dst, spidx->dst.__ss_len); + printf("}\n"); + + return; } -/*---------------------------------------------------------------------- - * Dump a route structure (sockaddr/rtentry pair). - ----------------------------------------------------------------------*/ -void dump_route(ro) - struct route *ro; +void +kdebug_secasindex(saidx) + struct secasindex *saidx; { - if (!ro) { - printf("Dereference a NULL route? I don't think so.\n"); - return; - } + /* sanity check */ + if (saidx == NULL) + panic("kdebug_secpolicyindex: NULL pointer was passed.\n"); + + printf("secasindex{ mode=%u proto=%u\n", + saidx->mode, saidx->proto); + + ipsec_hexdump((caddr_t)&saidx->src, saidx->src.__ss_len); + printf("\n"); + ipsec_hexdump((caddr_t)&saidx->dst, saidx->dst.__ss_len); + printf("\n"); - printf("ro_rt = %p, ro_dst is:\n",(void *)ro->ro_rt); - dump_smart_sockaddr(&ro->ro_dst); + return; } -/*---------------------------------------------------------------------- - * Dump a routing entry. - ----------------------------------------------------------------------*/ -void dump_rtentry(rt) - struct rtentry *rt; +void +kdebug_secasv(sav) + struct secasvar *sav; { - if (!rt) { - printf("Dereference a NULL rtentry? I don't think so.\n"); - return; - } - - printf("rt_key is:\n"); - dump_smart_sockaddr(rt_key(rt)); - printf("rt_mask is:\n"); - dump_smart_sockaddr(rt_mask(rt)); - printf("rt_llinfo = %p ",(void *)rt->rt_llinfo); - printf("rt_rmx.rmx_mtu = %lu ",rt->rt_rmx.rmx_mtu); - printf("rt_refcnt = %ld ",rt->rt_refcnt); - printf("rt_flags = 0x%lx\n",rt->rt_flags); - printf("rt_ifp is:\n"); - dump_ifp(rt->rt_ifp); - printf("rt_ifa is:\n"); - dump_ifa(rt->rt_ifa); + /* sanity check */ + if (sav == NULL) + panic("kdebug_secasv: NULL pointer was passed.\n"); + + printf("secas{"); + kdebug_secasindex(&sav->sah->saidx); + + printf(" refcnt=%u state=%u auth=%u enc=%u\n", + sav->refcnt, sav->state, sav->alg_auth, sav->alg_enc); + printf(" spi=%u flags=%u\n", + (u_int32_t)ntohl(sav->spi), sav->flags); + + if (sav->key_auth != NULL) + kdebug_sadb_key((struct sadb_ext *)sav->key_auth); + if (sav->key_enc != NULL) + kdebug_sadb_key((struct sadb_ext *)sav->key_enc); + if (sav->iv != NULL) { + printf(" iv="); + ipsec_hexdump(sav->iv, sav->ivlen ? sav->ivlen : 8); + printf("\n"); + } + + if (sav->replay != NULL) + kdebug_secreplay(sav->replay); + if (sav->lft_c != NULL) + kdebug_sadb_lifetime((struct sadb_ext *)sav->lft_c); + if (sav->lft_h != NULL) + kdebug_sadb_lifetime((struct sadb_ext *)sav->lft_h); + if (sav->lft_s != NULL) + kdebug_sadb_lifetime((struct sadb_ext *)sav->lft_s); + + return; } -/*---------------------------------------------------------------------- - * Dump an Internet v4 protocol control block. - ----------------------------------------------------------------------*/ -void dump_inpcb(inp) - struct inpcb *inp; +static void +kdebug_secreplay(rpl) + struct secreplay *rpl; { - if (!inp) { - printf("Dereference a NULL inpcb? I don't think so.\n"); - return; - } - -#if 0 - printf("inp_next = 0x%x, inp_prev = 0x%x, inp_head = 0x%x.\n", - inp->inp_next, inp->inp_prev, inp->inp_head); -#endif - printf("inp_socket = %p, inp_ppcb = %p\n", - (void *)inp->inp_socket,(void *)inp->inp_ppcb); - printf("faddr:\n"); - dump_in_addr(&inp->inp_faddr); - printf("laddr:\n"); - dump_in_addr(&inp->inp_laddr); - printf("inp_route: "); - dump_route(&inp->inp_route); - printf("inp_ip:"); - printf("<Coming soon.>\n"); - printf("inp_options = %p, inp_moptions{6,} = %p,\n", - (void *)inp->inp_options, (void *)inp->inp_moptions); - printf("inp_flags = 0x%x, inp_fport = %d, inp_lport = %d.\n", - (unsigned)inp->inp_flags,inp->inp_fport, inp->inp_lport); + int len, l; + + /* sanity check */ + if (rpl == NULL) + panic("kdebug_secreplay: NULL pointer was passed.\n"); + + printf(" secreplay{ count=%u wsize=%u seq=%u lastseq=%u", + rpl->count, rpl->wsize, rpl->seq, rpl->lastseq); + + if (rpl->bitmap == NULL) { + printf(" }\n"); + return; + } + + printf("\n bitmap { "); + + for (len = 0; len < rpl->wsize; len++) { + for (l = 7; l >= 0; l--) + printf("%u", (((rpl->bitmap)[len] >> l) & 1) ? 1 : 0); + } + printf(" }\n"); + + return; } -#ifdef INET6 -/*---------------------------------------------------------------------- - * Dump an Internet v6 protocol control block. - ----------------------------------------------------------------------*/ -void dump_in6pcb(in6p) - struct in6pcb *in6p; +void +kdebug_mbufhdr(m) + struct mbuf *m; { - if (!in6p) { - printf("Dereference a NULL in6pcb? I don't think so.\n"); - return; - } - - printf("in6p_next = 0x%x, in6p_prev = 0x%x, in6p_head = 0x%x.\n", - in6p->in6p_next, in6p->in6p_prev, in6p->in6p_head); - printf("in6p_socket = 0x%x, in6p_ppcb\n", - in6p->in6p_socket, in6p->in6p_ppcb); - printf("faddr:\n"); - dump_in6_addr(&in6p->in6p_faddr); - printf("laddr:\n"); - dump_in6_addr(&in6p->in6p_laddr); - printf("in6p_route: "); - dump_route(&in6p->in6p_route); - printf("in6p_ip6:"); - dump_ipv6(&in6p->in6p_ip6); - printf("in6p_options = 0x%x, in6p_moptions{6,} = 0x%x,\n", - in6p->in6p_options, in6p->in6p_moptions); - printf("in6p_flags = 0x%x, in6p_fport = %d, in6p_lport = %d.\n", - (unsigned)in6p->in6p_flags, in6p->in6p_fport, in6p->in6p_lport); + /* sanity check */ + if (m == NULL) + panic("debug_mbufhdr: NULL pointer was passed.\n"); + + printf("mbuf(%p){ m_next:%p m_nextpkt:%p m_data:%p " + "m_len:%d m_type:0x%02x m_flags:0x%02x }\n", + m, m->m_next, m->m_nextpkt, m->m_data, + m->m_len, m->m_type, m->m_flags); + + if (m->m_flags & M_PKTHDR) { + printf(" m_pkthdr{ len:%d rcvif:%p }\n", + m->m_pkthdr.len, m->m_pkthdr.rcvif); + } + if (m->m_flags & M_EXT) { + printf(" m_ext{ ext_buf:%p ext_free:%p " + "ext_size:%u ext_ref:%p }\n", + m->m_ext.ext_buf, m->m_ext.ext_free, + m->m_ext.ext_size, m->m_ext.ext_ref); + } + return; } -#endif /*INET6*/ - -#if 0 -/*---------------------------------------------------------------------- - * Dump an IPv6 discovery queue structure. - ----------------------------------------------------------------------*/ -void dump_discq(dq) - struct discq *dq; + +void +kdebug_mbuf(m0) + struct mbuf *m0; { - if (!dq) { - printf("Dereference a NULL discq? I don't think so.\n"); - return; - } - - printf("dq_next = 0x%x, dq_prev = 0x%x, dq_rt = 0x%x,\n",dq->dq_next, - dq->dq_prev, dq->dq_rt); - printf("dq_queue = 0x%x.\n",dq->dq_queue); - /* Dump first mbuf chain? */ - /*printf("dq_expire = %d (0x%x).\n",dq->dq_expire,dq->dq_expire);*/ + struct mbuf *m = m0; + int i, j; + + kdebug_mbufhdr(m); + printf(" m_data=\n"); + for (j = 0; m; m = m->m_next) { + for (i = 0; i < m->m_len; i++) { + if (i != 0 && i % 32 == 0) printf("\n"); + if (i % 4 == 0) printf(" "); + printf("%02x", mtod(m, u_char *)[i]); + j++; + } + } + + printf("\n"); + + return; } -#endif /* INET6 */ - -/*---------------------------------------------------------------------- - * Dump a data buffer - ----------------------------------------------------------------------*/ -void dump_buf(buf, len) - char *buf; - int len; +#endif /* KERNEL */ + +void +kdebug_sockaddr(addr) + struct sockaddr *addr; { - int i; + /* sanity check */ + if (addr == NULL) + panic("kdebug_sockaddr: NULL pointer was passed.\n"); - printf("buf=0x%x len=%d:\n", (unsigned int)buf, len); - for (i = 0; i < len; i++) { - printf("0x%x ", (u_int8_t)*(buf+i)); - } - printf("\n"); -} + /* NOTE: We deal with port number as host byte order. */ + printf("sockaddr{ len=%u family=%u port=%u\n", + addr->sa_len, addr->sa_family, ntohs(_INPORTBYSA(addr))); +#ifdef INET6 + if (addr->sa_family == PF_INET6) { + struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)addr; + printf(" flowinfo=0x%08x, scope_id=0x%08x\n", + in6->sin6_flowinfo, in6->sin6_scope_id); + } +#endif -/*---------------------------------------------------------------------- - * Dump a key_tblnode structrue - ----------------------------------------------------------------------*/ -void dump_keytblnode(ktblnode) - struct key_tblnode *ktblnode; -{ - if (!ktblnode) { - printf("NULL key table node pointer!\n"); - return; - } - printf("solist=0x%x ", (unsigned int)ktblnode->solist); - printf("secassoc=0x%x ", (unsigned int)ktblnode->secassoc); - printf("next=0x%x\n", (unsigned int)ktblnode->next); -} + ipsec_hexdump(_INADDRBYSA(addr), _INALENBYAF(addr->sa_family)); -/*---------------------------------------------------------------------- - * Dump an ipsec_assoc structure - ----------------------------------------------------------------------*/ -void dump_secassoc(seca) - struct key_secassoc *seca; -{ - u_int8_t *p; - int i; - - if (seca) { - printf("secassoc_len=%u ", seca->len); - printf("secassoc_type=%d ", seca->type); - printf("secassoc_state=0x%x\n", seca->state); - printf("secassoc_label=%u ", seca->label); - printf("secassoc_spi=0x%x ", (unsigned int)seca->spi); - printf("secassoc_keylen=%u\n", seca->keylen); - printf("secassoc_ivlen=%u ", seca->ivlen); - printf("secassoc_algorithm=%u ", seca->algorithm); - printf("secassoc_lifetype=%u\n", seca->lifetype); - printf("secassoc_iv=0x%x:\n", (unsigned int)seca->iv); - p = (u_int8_t *)(seca->iv); - for (i = 0 ; i < seca->ivlen; i++) - printf("0x%x ", *(p + i)); - printf("secassoc_key=0x%x:\n", (unsigned int)seca->key); - p = (u_int8_t *)(seca->key); - for (i = 0 ; i < seca->keylen; i++) - printf("0x%x ", *(p + i)); - printf("secassoc_lifetime1=%u ", (unsigned int)seca->lifetime1); - printf("secassoc_lifetime2=%u\n", (unsigned int)seca->lifetime2); - dump_smart_sockaddr(seca->src); - dump_smart_sockaddr(seca->dst); - dump_smart_sockaddr(seca->from); - } else - printf("can't dump null secassoc pointer!\n"); + printf(" }\n"); + + return; } +#endif /* !defined(KERNEL) || (defined(KERNEL) && defined(IPSEC_DEBUG)) */ -/*---------------------------------------------------------------------- - * Dump a key_msghdr structure - ----------------------------------------------------------------------*/ -void dump_keymsghdr(km) - struct key_msghdr *km; +void +ipsec_bindump(buf, len) + caddr_t buf; + int len; { - if (km) { - printf("key_msglen=%d\n", km->key_msglen); - printf("key_msgvers=%d\n", km->key_msgvers); - printf("key_msgtype=%d\n", km->key_msgtype); - printf("key_pid=%d\n", km->key_pid); - printf("key_seq=%d\n", km->key_seq); - printf("key_errno=%d\n", km->key_errno); - printf("type=0x%x\n", (unsigned int)km->type); - printf("state=0x%x\n", (unsigned int)km->state); - printf("label=0x%x\n", (unsigned int)km->label); - printf("spi=0x%x\n", (unsigned int)km->spi); - printf("keylen=%d\n", km->keylen); - printf("ivlen=%d\n", km->ivlen); - printf("algorithm=%d\n", km->algorithm); - printf("lifetype=0x%x\n", (unsigned int)km->lifetype); - printf("lifetime1=%u\n", (unsigned int)km->lifetime1); - printf("lifetime2=%u\n", (unsigned int)km->lifetime2); - } else - printf("key_msghdr pointer is NULL!\n"); + int i; + + for (i = 0; i < len; i++) + printf("%c", (unsigned char)buf[i]); + + return; } -/*---------------------------------------------------------------------- - * Dump a key_msgdata structure - ----------------------------------------------------------------------*/ -void dump_keymsginfo(kp) - struct key_msgdata *kp; +void +ipsec_hexdump(buf, len) + caddr_t buf; + int len; { - int i; - - if (kp) { - printf("src addr:\n"); - dump_smart_sockaddr(kp->src); - printf("dest addr:\n"); - dump_smart_sockaddr(kp->dst); - printf("from addr:\n"); - dump_smart_sockaddr(kp->from); -#define dumpbuf(a, b) \ - { for (i= 0; i < (b); i++) \ - printf("0x%2x%s", (unsigned char)(*((caddr_t)a+i)),((i+1)%16)?" ":"\n");\ - printf("\n"); } - printf("iv is:\n"); - dumpbuf(kp->iv, kp->ivlen); - printf("key is:\n"); - dumpbuf(kp->key, kp->keylen); -#undef dumpbuf - } else - printf("key_msgdata point is NULL!\n"); + int i; + + for (i = 0; i < len; i++) { + if (i != 0 && i % 32 == 0) printf("\n"); + if (i % 4 == 0) printf(" "); + printf("%02x", (unsigned char)buf[i]); + } + + return; } -#endif /*KEY_DEBUG*/ -#endif /*KEY*/ diff --git a/sys/netkey/key_debug.h b/sys/netkey/key_debug.h index 78bae82..2ce0dc0 100644 --- a/sys/netkey/key_debug.h +++ b/sys/netkey/key_debug.h @@ -1,187 +1,89 @@ /* - * modified by Jun-ichiro itojun Itoh <itojun@itojun.org>, 1997 - */ -/* - * in6_debug.h -- Insipired by Craig Metz's Net/2 in6_debug.h, but - * not quite as heavyweight (initially, anyway). + * 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. * - * In particular, if function exit-entries are to be - * documented, do them in a lightweight fashion. + * 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. * - * Copyright 1995 by Dan McDonald, Bao Phan, and Randall Atkinson, - * All Rights Reserved. - * All Rights under this copyright have been assigned to NRL. + * $FreeBSD$ */ -/*---------------------------------------------------------------------- -# @(#)COPYRIGHT 1.1a (NRL) 17 August 1995 - -COPYRIGHT NOTICE - -All of the documentation and software included in this software -distribution from the US Naval Research Laboratory (NRL) are -copyrighted by their respective developers. +/* $Id: key_debug.h,v 1.1.6.2.6.1 1999/05/17 17:03:16 itojun Exp $ */ -This software and documentation were developed at NRL by various -people. Those developers have each copyrighted the portions that they -developed at NRL and have assigned All Rights for those portions to -NRL. Outside the USA, NRL also has copyright on the software -developed at NRL. The affected files all contain specific copyright -notices and those notices must be retained in any derived work. +#ifndef _NETKEY_KEY_DEBUG_H_ +#define _NETKEY_KEY_DEBUG_H_ -NRL LICENSE +/* debug flags */ +#define KEYDEBUG_STAMP 0x00000001 /* path */ +#define KEYDEBUG_DATA 0x00000002 /* data */ +#define KEYDEBUG_DUMP 0x00000004 /* dump */ -NRL grants permission for redistribution and use in source and binary -forms, with or without modification, of the software and documentation -created at NRL provided that the following conditions are met: +#define KEYDEBUG_KEY 0x00000010 /* key processing */ +#define KEYDEBUG_ALG 0x00000020 /* ciph & auth algorithm */ +#define KEYDEBUG_IPSEC 0x00000040 /* ipsec processing */ -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. All advertising materials mentioning features or use of this software - must display the following acknowledgement: +#define KEYDEBUG_KEY_STAMP (KEYDEBUG_KEY | KEYDEBUG_STAMP) +#define KEYDEBUG_KEY_DATA (KEYDEBUG_KEY | KEYDEBUG_DATA) +#define KEYDEBUG_KEY_DUMP (KEYDEBUG_KEY | KEYDEBUG_DUMP) +#define KEYDEBUG_ALG_STAMP (KEYDEBUG_ALG | KEYDEBUG_STAMP) +#define KEYDEBUG_ALG_DATA (KEYDEBUG_ALG | KEYDEBUG_DATA) +#define KEYDEBUG_ALG_DUMP (KEYDEBUG_ALG | KEYDEBUG_DUMP) +#define KEYDEBUG_IPSEC_STAMP (KEYDEBUG_IPSEC | KEYDEBUG_STAMP) +#define KEYDEBUG_IPSEC_DATA (KEYDEBUG_IPSEC | KEYDEBUG_DATA) +#define KEYDEBUG_IPSEC_DUMP (KEYDEBUG_IPSEC | KEYDEBUG_DUMP) - This product includes software developed at the Information - Technology Division, US Naval Research Laboratory. - -4. Neither the name of the NRL nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - -THE SOFTWARE PROVIDED BY NRL IS PROVIDED BY NRL 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 NRL 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. - -The views and conclusions contained in the software and documentation -are those of the authors and should not be interpreted as representing -official policies, either expressed or implied, of the US Naval -Research Laboratory (NRL). - -----------------------------------------------------------------------*/ +#define KEYDEBUG(lev,arg) if ((key_debug_level & (lev)) == (lev)) { arg; } #ifdef KERNEL +extern u_int32_t key_debug_level; +#endif /*KERNEL*/ -/* IDL_* is IPv6 Debug Level */ - -#define IDL_ALL 0xFFFFFFFE /* Report all messages. */ -#define IDL_NONE 0 /* Report no messages. */ - -#define IDL_CRITICAL 3 -#define IDL_ERROR 7 -#define IDL_MAJOR_EVENT 10 -#define IDL_EVENT 15 -#define IDL_GROSS_EVENT 20 -#define IDL_FINISHED 0xFFFFFFF0 - -/* - * Make sure argument for DPRINTF is in parentheses. - * - * For both DPRINTF and DDO, and attempt was made to make both macros - * be usable as normal C statments. There is a small amount of compiler - * trickery (if-else clauses with effectively null statements), which may - * cause a few compilers to complain. - */ - -#ifdef KEY_DEBUG - -/* - * DPRINTF() is a general printf statement. The "arg" is literally what - * would follow the function name printf, which means it has to be in - * parenthesis. Unlimited arguments can be used this way. - * - * EXAMPLE: - * DPRINTF(IDL_MAJOR_EVENT,("Hello, world. IP version %d.\n",vers)); - */ -#define DPRINTF(lev,arg) \ - if ((lev) < in6_debug_level) { \ - printf arg; \ - } else \ - in6_debug_level = in6_debug_level - -/* - * DDO() executes a series of statements at a certain debug level. The - * "stmt" argument is a statement in the sense of a "statement list" in a - * C grammar. "stmt" does not have to end with a semicolon. - * - * EXAMPLE: - * DDO(IDL_CRITICAL,dump_ipv6(header), dump_inpcb(inp)); - */ -#define DDO(lev,stmt) \ - if ((lev) < in6_debug_level) { \ - stmt ; \ - } else \ - in6_debug_level = in6_debug_level - -/* - * DP() is a shortcut for DPRINTF(). Basically: - * - * DP(lev, var, fmt) == DPRINTF(IDL_lev, ("var = %fmt\n", var)) - * - * It is handy for printing single variables without a lot of typing. - * - * EXAMPLE: - * - * DP(CRITICAL,length,d); - * same as DPRINTF(IDL_CRITICAL, ("length = %d\n", length)) - */ -#define DP(lev, var, fmt) DPRINTF(IDL_ ## lev, (#var " = %" #fmt "\n", var)) - -struct inpcb; - -extern void in6_debug_init __P((void)); -#ifdef INET6 -extern void dump_in6_addr __P((struct in6_addr *)); -#endif -extern void dump_in_addr __P((struct in_addr *)); -#ifdef INET6 -extern void dump_sockaddr_in6 __P((struct sockaddr_in6 *)); -#endif -extern void dump_sockaddr_in __P((struct sockaddr_in *)); -extern void dump_sockaddr __P((struct sockaddr *)); -extern void dump_sockaddr_dl __P((struct sockaddr_dl *)); -extern void dump_smart_sockaddr __P((struct sockaddr *)); -#ifdef INET6 -extern void dump_ipv6 __P((struct ip6 *)); -extern void dump_ipv6_icmp __P((struct icmp6 *)); -#endif /*INET6*/ -extern void dump_mbuf_hdr __P((struct mbuf *)); -extern void dump_mbuf __P((struct mbuf *)); -extern void dump_mchain __P((struct mbuf *)); -extern void dump_tcpdump __P((struct mbuf *)); -extern void dump_ifa __P((struct ifaddr *)); -extern void dump_ifp __P((struct ifnet *)); -extern void dump_route __P((struct route *)); -extern void dump_rtentry __P((struct rtentry *)); -extern void dump_inpcb __P((struct inpcb *)); -#ifdef INET6 -extern void dump_in6pcb __P((struct in6pcb *)); -#endif -extern void dump_buf __P((char *, int)); -extern void dump_keytblnode __P((struct key_tblnode *)); -extern void dump_secassoc __P((struct key_secassoc *)); -extern void dump_keymsghdr __P((struct key_msghdr *)); -extern void dump_keymsginfo __P((struct key_msgdata *)); +struct sadb_msg; +struct sadb_ext; +extern void kdebug_sadb __P((struct sadb_msg *)); +extern void kdebug_sadb_x_policy __P((struct sadb_ext *)); -#else /* ! KEY_DEBUG */ +#ifdef KERNEL +struct secpolicy; +struct secpolicyindex; +struct secasindex; +struct secasvar; +struct secreplay; +struct mbuf; +extern void kdebug_secpolicy __P((struct secpolicy *)); +extern void kdebug_secpolicyindex __P((struct secpolicyindex *)); +extern void kdebug_secasindex __P((struct secasindex *)); +extern void kdebug_secasv __P((struct secasvar *)); +extern void kdebug_mbufhdr __P((struct mbuf *)); +extern void kdebug_mbuf __P((struct mbuf *)); +#endif /*KERNEL*/ -#define DPRINTF(lev,arg) -#define DDO(lev, stmt) -#define DP(x, y, z) +struct sockaddr; +extern void kdebug_sockaddr __P((struct sockaddr *)); -#endif /* KEY_DEBUG */ +extern void ipsec_hexdump __P((caddr_t, int)); +extern void ipsec_bindump __P((caddr_t, int)); -#ifndef INET6_DEBUG_C -extern unsigned int in6_debug_level; -#endif +#endif /* _NETKEY_KEY_DEBUG_H_ */ -#endif /*KERNEL*/ diff --git a/sys/netkey/key_var.h b/sys/netkey/key_var.h index 41750b7..85e4b92 100644 --- a/sys/netkey/key_var.h +++ b/sys/netkey/key_var.h @@ -43,40 +43,12 @@ #define KEYCTL_BLOCKACQ_LIFETIME 8 #define KEYCTL_MAXID 9 -#define KEYCTL_NAMES { \ - { 0, 0 }, \ - { "debug", CTLTYPE_INT }, \ - { "spi_try", CTLTYPE_INT }, \ - { "spi_min_value", CTLTYPE_INT }, \ - { "spi_max_value", CTLTYPE_INT }, \ - { "random_int", CTLTYPE_INT }, \ - { "larval_lifetime", CTLTYPE_INT }, \ - { "blockacq_count", CTLTYPE_INT }, \ - { "blockacq_lifetime", CTLTYPE_INT }, \ -} - -#define KEYCTL_VARS { \ - 0, \ - &key_debug_level, \ - &key_spi_trycnt, \ - &key_spi_minval, \ - &key_spi_maxval, \ - &key_int_random, \ - &key_larval_lifetime, \ - &key_blockacq_count, \ - &key_blockacq_lifetime, \ -} - #define _ARRAYLEN(p) (sizeof(p)/sizeof(p[0])) #define _KEYLEN(key) ((u_int)((key)->sadb_key_bits >> 3)) #define _KEYBITS(key) ((u_int)((key)->sadb_key_bits)) #define _KEYBUF(key) ((caddr_t)((caddr_t)(key) + sizeof(struct sadb_key))) #define _INADDR(in) ((struct sockaddr_in *)(in)) - -/* should not ifdef kernel opt in kernel header file */ -#if !defined(KERNEL) && !defined(_KERNEL) -#if defined(INET6) #define _IN6ADDR(in6) ((struct sockaddr_in6 *)(in6)) #define _SALENBYAF(family) \ (((family) == AF_INET) ? \ @@ -94,13 +66,9 @@ ((((struct sockaddr *)(saddr))->sa_family == AF_INET) ? \ ((struct sockaddr_in *)(saddr))->sin_port : \ ((struct sockaddr_in6 *)(saddr))->sin6_port) -#else -#define _IN6ADDR(in6) "#error" -#define _SALENBYAF(family) sizeof(struct sockaddr_in) -#define _INALENBYAF(family) sizeof(struct in_addr) -#define _INADDRBYSA(saddr) ((caddr_t)&((struct sockaddr_in *)(saddr))->sin_addr) -#define _INPORTBYSA(saddr) (((struct sockaddr_in *)(saddr))->sin_port) -#endif /* defined(INET6) */ -#endif /* !defined(KERNEL) && !defined(_KERNEL) */ + +#ifdef SYSCTL_DECL +SYSCTL_DECL(_net_key); +#endif #endif /* _NETKEY_KEY_VAR_H_ */ diff --git a/sys/netkey/keysock.c b/sys/netkey/keysock.c new file mode 100644 index 0000000..b3c8652 --- /dev/null +++ b/sys/netkey/keysock.c @@ -0,0 +1,542 @@ +/* + * 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. + * + * $FreeBSD$ + */ + +/* KAME @(#)$Id: keysock.c,v 1.2 1999/08/16 19:30:36 shin Exp $ */ + +/* This code has derived from sys/net/rtsock.c on FreeBSD2.2.5 */ + +#include <opt_ipsec.h> + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/sysctl.h> +#include <sys/mbuf.h> +#include <sys/malloc.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/domain.h> +#include <sys/protosw.h> +#include <sys/errno.h> + +#include <machine/ipl.h> + +#include <net/raw_cb.h> +#include <net/route.h> + +#include <net/pfkeyv2.h> +#include <netkey/keydb.h> +#include <netkey/key.h> +#include <netkey/keysock.h> +#ifdef IPSEC_DEBUG +#include <netkey/key_debug.h> +#else +#define KEYDEBUG(lev,arg) +#endif + +#include <machine/stdarg.h> + +static MALLOC_DEFINE(M_SECA, "key mgmt", + "security associations, key management"); + +struct sockaddr key_dst = { 2, PF_KEY, }; +struct sockaddr key_src = { 2, PF_KEY, }; +struct sockproto key_proto = { PF_KEY, PF_KEY_V2 }; + +static int key_sendup0 __P((struct rawcb *, struct mbuf *, int)); + +#define KMALLOC(p, t, n) \ + ((p) = (t) malloc((unsigned long)(n), M_SECA, M_NOWAIT)) +#define KFREE(p) \ + free((caddr_t)(p), M_SECA); + +/* + * key_abort() + * derived from net/rtsock.c:rts_abort() + */ +static int +key_abort(struct socket *so) +{ + int s, error; + s = splnet(); + error = raw_usrreqs.pru_abort(so); + splx(s); + return error; +} + +/* + * key_attach() + * derived from net/rtsock.c:rts_attach() + */ +static int +key_attach(struct socket *so, int proto, struct proc *p) +{ + struct keycb *kp; + int s, error; + + if (sotorawcb(so) != 0) + return EISCONN; /* XXX panic? */ + MALLOC(kp, struct keycb *, sizeof *kp, M_PCB, M_WAITOK); /* XXX */ + if (kp == 0) + return ENOBUFS; + bzero(kp, sizeof *kp); + + /* + * The splnet() is necessary to block protocols from sending + * error notifications (like RTM_REDIRECT or RTM_LOSING) while + * this PCB is extant but incompletely initialized. + * Probably we should try to do more of this work beforehand and + * eliminate the spl. + */ + s = splnet(); + so->so_pcb = (caddr_t)kp; + error = raw_usrreqs.pru_attach(so, proto, p); + kp = (struct keycb *)sotorawcb(so); + if (error) { + free(kp, M_PCB); + so->so_pcb = (caddr_t) 0; + splx(s); + printf("key_usrreq: key_usrreq results %d\n", error); + return error; + } + + kp->kp_promisc = kp->kp_registered = 0; + + if (kp->kp_raw.rcb_proto.sp_protocol == PF_KEY) /* XXX: AF_KEY */ + key_cb.key_count++; + key_cb.any_count++; + kp->kp_raw.rcb_laddr = &key_src; + kp->kp_raw.rcb_faddr = &key_dst; + soisconnected(so); + so->so_options |= SO_USELOOPBACK; + + splx(s); + return 0; +} + +/* + * key_bind() + * derived from net/rtsock.c:rts_bind() + */ +static int +key_bind(struct socket *so, struct sockaddr *nam, struct proc *p) +{ + int s, error; + s = splnet(); + error = raw_usrreqs.pru_bind(so, nam, p); /* xxx just EINVAL */ + splx(s); + return error; +} + +/* + * key_connect() + * derived from net/rtsock.c:rts_connect() + */ +static int +key_connect(struct socket *so, struct sockaddr *nam, struct proc *p) +{ + int s, error; + s = splnet(); + error = raw_usrreqs.pru_connect(so, nam, p); /* XXX just EINVAL */ + splx(s); + return error; +} + +/* + * key_detach() + * derived from net/rtsock.c:rts_detach() + */ +static int +key_detach(struct socket *so) +{ + struct keycb *kp = (struct keycb *)sotorawcb(so); + int s, error; + + s = splnet(); + if (kp != 0) { + if (kp->kp_raw.rcb_proto.sp_protocol + == PF_KEY) /* XXX: AF_KEY */ + key_cb.key_count--; + key_cb.any_count--; + + key_freereg(so); + } + error = raw_usrreqs.pru_detach(so); + splx(s); + return error; +} + +/* + * key_disconnect() + * derived from net/rtsock.c:key_disconnect() + */ +static int +key_disconnect(struct socket *so) +{ + int s, error; + s = splnet(); + error = raw_usrreqs.pru_disconnect(so); + splx(s); + return error; +} + +/* + * key_peeraddr() + * derived from net/rtsock.c:rts_peeraddr() + */ +static int +key_peeraddr(struct socket *so, struct sockaddr **nam) +{ + int s, error; + s = splnet(); + error = raw_usrreqs.pru_peeraddr(so, nam); + splx(s); + return error; +} + +/* + * key_send() + * derived from net/rtsock.c:rts_send() + */ +static int +key_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, + struct mbuf *control, struct proc *p) +{ + int s, error; + s = splnet(); + error = raw_usrreqs.pru_send(so, flags, m, nam, control, p); + splx(s); + return error; +} + +/* + * key_shutdown() + * derived from net/rtsock.c:rts_shutdown() + */ +static int +key_shutdown(struct socket *so) +{ + int s, error; + s = splnet(); + error = raw_usrreqs.pru_shutdown(so); + splx(s); + return error; +} + +/* + * key_sockaddr() + * derived from net/rtsock.c:rts_sockaddr() + */ +static int +key_sockaddr(struct socket *so, struct sockaddr **nam) +{ + int s, error; + s = splnet(); + error = raw_usrreqs.pru_sockaddr(so, nam); + splx(s); + return error; +} + +struct pr_usrreqs key_usrreqs = { + key_abort, pru_accept_notsupp, key_attach, key_bind, + key_connect, + pru_connect2_notsupp, pru_control_notsupp, key_detach, + key_disconnect, pru_listen_notsupp, key_peeraddr, + pru_rcvd_notsupp, + pru_rcvoob_notsupp, key_send, pru_sense_null, key_shutdown, + key_sockaddr, sosend, soreceive, sopoll +}; + +/* + * key_output() + */ +int +key_output(struct mbuf *m, struct socket *so) +{ + struct sadb_msg *msg = NULL; + int len, error = 0; + int s; + int target; + + if (m == 0) + panic("key_output: NULL pointer was passed.\n"); + + if (m->m_len < sizeof(long) + && (m = m_pullup(m, 8)) == 0) { + printf("key_output: can't pullup mbuf\n"); + error = ENOBUFS; + goto end; + } + + if ((m->m_flags & M_PKTHDR) == 0) + panic("key_output: not M_PKTHDR ??"); + +#if defined(IPSEC_DEBUG) + KEYDEBUG(KEYDEBUG_KEY_DUMP, kdebug_mbuf(m)); +#endif /* defined(IPSEC_DEBUG) */ + + len = m->m_pkthdr.len; + if (len < sizeof(struct sadb_msg) + || len != PFKEY_UNUNIT64(mtod(m, struct sadb_msg *)->sadb_msg_len)) { + printf("key_output: Invalid message length.\n"); + error = EINVAL; + goto end; + } + + /* + * allocate memory for sadb_msg, and copy to sadb_msg from mbuf + * XXX: To be processed directly without a copy. + */ + KMALLOC(msg, struct sadb_msg *, len); + if (msg == 0) { + printf("key_output: No more memory.\n"); + error = ENOBUFS; + goto end; + /* or do panic ? */ + } + m_copydata(m, 0, len, (caddr_t)msg); + + /*XXX giant lock*/ + s = splnet(); + if ((len = key_parse(&msg, so, &target)) == 0) { + /* discard. i.e. no need to reply. */ + error = 0; + splx(s); + goto end; + } + + /* send up message to the socket */ + error = key_sendup(so, msg, len, target); + splx(s); + KFREE(msg); +end: + m_freem(m); + return (error); +} + +/* + * send message to the socket. + */ +static int +key_sendup0(rp, m, promisc) + struct rawcb *rp; + struct mbuf *m; + int promisc; +{ + if (promisc) { + struct sadb_msg *pmsg; + + M_PREPEND(m, sizeof(struct sadb_msg), M_NOWAIT); + if (m && m->m_len < sizeof(struct sadb_msg)) + m = m_pullup(m, sizeof(struct sadb_msg)); + if (!m) { + printf("key_sendup0: cannot pullup\n"); + m_freem(m); + return ENOBUFS; + } + m->m_pkthdr.len += sizeof(*pmsg); + + pmsg = mtod(m, struct sadb_msg *); + bzero(pmsg, sizeof(*pmsg)); + pmsg->sadb_msg_version = PF_KEY_V2; + pmsg->sadb_msg_type = SADB_X_PROMISC; + pmsg->sadb_msg_len = PFKEY_UNIT64(m->m_pkthdr.len); + /* pid and seq? */ + } + + if (!sbappendaddr(&rp->rcb_socket->so_rcv, + (struct sockaddr *)&key_src, m, NULL)) { + printf("key_sendup0: sbappendaddr failed\n"); + m_freem(m); + return ENOBUFS; + } + sorwakeup(rp->rcb_socket); + return 0; +} + +int +key_sendup(so, msg, len, target) + struct socket *so; + struct sadb_msg *msg; + u_int len; + int target; /*target of the resulting message*/ +{ + struct mbuf *m, *n, *mprev; + struct keycb *kp; + int sendup; + struct rawcb *rp; + int error; + int tlen; + + /* sanity check */ + if (so == 0 || msg == 0) + panic("key_sendup: NULL pointer was passed.\n"); + + KEYDEBUG(KEYDEBUG_KEY_DUMP, + printf("key_sendup: \n"); + kdebug_sadb(msg)); + + /* + * Get mbuf chain whenever possible (not clusters), + * to save socket buffer. We'll be generating many SADB_ACQUIRE + * messages to listening key sockets. If we simmply allocate clusters, + * sbappendaddr() will raise ENOBUFS due to too little sbspace(). + * sbspace() computes # of actual data bytes AND mbuf region. + * + * TODO: SADB_ACQUIRE filters should be implemented. + */ + tlen = len; + m = mprev = NULL; + while (tlen > 0) { + if (tlen == len) { + MGETHDR(n, M_DONTWAIT, MT_DATA); + n->m_len = MHLEN; + } else { + MGET(n, M_DONTWAIT, MT_DATA); + n->m_len = MLEN; + } + if (!n) + return ENOBUFS; + if (tlen > MCLBYTES) { /*XXX better threshold? */ + MCLGET(n, M_DONTWAIT); + if ((n->m_flags & M_EXT) == 0) { + m_free(n); + m_freem(m); + return ENOBUFS; + } + n->m_len = MCLBYTES; + } + + if (tlen < n->m_len) + n->m_len = tlen; + n->m_next = NULL; + if (m == NULL) + m = mprev = n; + else { + mprev->m_next = n; + mprev = n; + } + tlen -= n->m_len; + n = NULL; + } + m->m_pkthdr.len = len; + m->m_pkthdr.rcvif = NULL; + m_copyback(m, 0, len, (caddr_t)msg); + + LIST_FOREACH(rp, &rawcb_list, list) + { + if (rp->rcb_proto.sp_family != PF_KEY) + continue; + if (rp->rcb_proto.sp_protocol + && rp->rcb_proto.sp_protocol != PF_KEY_V2) { + continue; + } + + kp = (struct keycb *)rp; + + /* + * If you are in promiscuous mode, and when you get broadcasted + * reply, you'll get two PF_KEY messages. + * (based on pf_key@inner.net message on 14 Oct 1998) + */ + if (((struct keycb *)rp)->kp_promisc) { + if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) { + (void)key_sendup0(rp, n, 1); + n = NULL; + } + } + + /* the exact target will be processed later */ + if (sotorawcb(so) == rp) + continue; + + sendup = 0; + switch (target) { + case KEY_SENDUP_ONE: + /* the statement has no effect */ + if (sotorawcb(so) == rp) + sendup++; + break; + case KEY_SENDUP_ALL: + sendup++; + break; + case KEY_SENDUP_REGISTERED: + if (kp->kp_registered) + sendup++; + break; + } + + if (!sendup) + continue; + + if ((n = m_copy(m, 0, (int)M_COPYALL)) == NULL) { + printf("key_sendup: m_copy fail\n"); + m_freem(m); + return ENOBUFS; + } + + if ((error = key_sendup0(rp, n, 0)) != 0) { + m_freem(m); + return error; + } + + n = NULL; + } + + error = key_sendup0(sotorawcb(so), m, 0); + m = NULL; + return error; +} + +/* sysctl */ +SYSCTL_NODE(_net, PF_KEY, key, CTLFLAG_RW, 0, "Key Family"); + +/* + * Definitions of protocols supported in the KEY domain. + */ + +extern struct domain keydomain; + +struct protosw keysw[] = { +{ SOCK_RAW, &keydomain, PF_KEY_V2, PR_ATOMIC|PR_ADDR, + 0, key_output, raw_ctlinput, 0, + 0, + raw_init, 0, 0, 0, + &key_usrreqs +} +}; + +struct domain keydomain = + { PF_KEY, "key", key_init, 0, 0, + keysw, &keysw[sizeof(keysw)/sizeof(keysw[0])] }; + +DOMAIN_SET(key); diff --git a/sys/netkey/keysock.h b/sys/netkey/keysock.h index d71e5aa..2fb475f 100644 --- a/sys/netkey/keysock.h +++ b/sys/netkey/keysock.h @@ -41,7 +41,7 @@ struct keycb { int kp_registered; /* registered socket */ }; -extern int key_output __P((struct mbuf *, ...)); +extern int key_output __P((struct mbuf *, struct socket *)); extern int key_usrreq __P((struct socket *, int, struct mbuf *, struct mbuf *, struct mbuf *)); diff --git a/sys/sys/socket.h b/sys/sys/socket.h index de550ff..7111dc6 100644 --- a/sys/sys/socket.h +++ b/sys/sys/socket.h @@ -363,7 +363,7 @@ struct cmsgcred { /* given pointer to struct cmsghdr, return pointer to next cmsghdr */ #define CMSG_NXTHDR(mhdr, cmsg) \ (((caddr_t)(cmsg) + (cmsg)->cmsg_len + sizeof(struct cmsghdr) > \ - (mhdr)->msg_control + (mhdr)->msg_controllen) ? \ + (caddr_t)(mhdr)->msg_control + (mhdr)->msg_controllen) ? \ (struct cmsghdr *)NULL : \ (struct cmsghdr *)((caddr_t)(cmsg) + CMSG_ALIGN((cmsg)->cmsg_len))) diff --git a/usr.sbin/Makefile b/usr.sbin/Makefile index 0cbab49..00b1a1d 100644 --- a/usr.sbin/Makefile +++ b/usr.sbin/Makefile @@ -35,7 +35,6 @@ SUBDIR= IPXrouted \ kbdcontrol \ kbdmap \ kernbb \ - keyadmin \ keyserv \ kvm_mkdb \ lpr \ |