summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorshin <shin@FreeBSD.org>1999-12-22 19:13:38 +0000
committershin <shin@FreeBSD.org>1999-12-22 19:13:38 +0000
commit50ba589c666f7d356304339b9cfc7fc9d173ad8d (patch)
tree46d6ae7c9680a93ce1c3a13378cef283df9f6544
parente396740391e7e60805bda6799ac3397d1fc8c539 (diff)
downloadFreeBSD-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
-rw-r--r--sys/conf/NOTES4
-rw-r--r--sys/conf/files27
-rw-r--r--sys/conf/options4
-rw-r--r--sys/crypto/blowfish/bf_cbc.c150
-rw-r--r--sys/crypto/blowfish/bf_cbc_m.c341
-rw-r--r--sys/crypto/blowfish/bf_enc.c142
-rw-r--r--sys/crypto/blowfish/bf_locl.h217
-rw-r--r--sys/crypto/blowfish/bf_pi.h327
-rw-r--r--sys/crypto/blowfish/bf_skey.c122
-rw-r--r--sys/crypto/blowfish/blowfish.h124
-rw-r--r--sys/crypto/cast128/cast128.c873
-rw-r--r--sys/crypto/cast128/cast128.h62
-rw-r--r--sys/crypto/cast128/cast128_cbc.c219
-rw-r--r--sys/crypto/cast128/cast128_subkey.h91
-rw-r--r--sys/crypto/des/des.h280
-rw-r--r--sys/crypto/des/des_3cbc.c246
-rw-r--r--sys/crypto/des/des_cbc.c328
-rw-r--r--sys/crypto/des/des_ecb.c231
-rw-r--r--sys/crypto/des/des_locl.h347
-rw-r--r--sys/crypto/des/des_setkey.c238
-rw-r--r--sys/crypto/des/podd.h66
-rw-r--r--sys/crypto/des/sk.h195
-rw-r--r--sys/crypto/des/spr.h195
-rw-r--r--sys/crypto/hmac_md5.c98
-rw-r--r--sys/crypto/hmac_md5.h37
-rw-r--r--sys/crypto/md5.c307
-rw-r--r--sys/crypto/md5.h75
-rw-r--r--sys/crypto/rc5/rc5.c218
-rw-r--r--sys/crypto/rc5/rc5.h86
-rw-r--r--sys/crypto/rc5/rc5_cbc.c211
-rw-r--r--sys/crypto/sha1.c275
-rw-r--r--sys/crypto/sha1.h71
-rw-r--r--sys/i386/conf/LINT4
-rw-r--r--sys/i386/conf/NOTES4
-rw-r--r--sys/net/bridge.c3
-rw-r--r--sys/net/route.c3
-rw-r--r--sys/netinet/igmp.c7
-rw-r--r--sys/netinet/igmp_var.h2
-rw-r--r--sys/netinet/in.c253
-rw-r--r--sys/netinet/in.h2
-rw-r--r--sys/netinet/in_gif.c38
-rw-r--r--sys/netinet/in_gif.h2
-rw-r--r--sys/netinet/in_pcb.c1
-rw-r--r--sys/netinet/in_proto.c37
-rw-r--r--sys/netinet/ip.h4
-rw-r--r--sys/netinet/ip_divert.c21
-rw-r--r--sys/netinet/ip_dummynet.c10
-rw-r--r--sys/netinet/ip_dummynet.h3
-rw-r--r--sys/netinet/ip_ecn.c149
-rw-r--r--sys/netinet/ip_ecn.h44
-rw-r--r--sys/netinet/ip_icmp.c50
-rw-r--r--sys/netinet/ip_icmp.h2
-rw-r--r--sys/netinet/ip_input.c142
-rw-r--r--sys/netinet/ip_mroute.c27
-rw-r--r--sys/netinet/ip_output.c237
-rw-r--r--sys/netinet/ip_var.h11
-rw-r--r--sys/netinet/ipprotosw.h103
-rw-r--r--sys/netinet/raw_ip.c41
-rw-r--r--sys/netinet/tcp_input.c5
-rw-r--r--sys/netinet/tcp_reass.c5
-rw-r--r--sys/netinet/tcp_usrreq.c12
-rw-r--r--sys/netinet/tcp_var.h2
-rw-r--r--sys/netinet/udp_usrreq.c4
-rw-r--r--sys/netinet6/ah.h88
-rw-r--r--sys/netinet6/ah6.h49
-rw-r--r--sys/netinet6/ah_core.c1125
-rw-r--r--sys/netinet6/ah_input.c708
-rw-r--r--sys/netinet6/ah_output.c532
-rw-r--r--sys/netinet6/esp.h99
-rw-r--r--sys/netinet6/esp6.h45
-rw-r--r--sys/netinet6/esp_core.c1236
-rw-r--r--sys/netinet6/esp_input.c984
-rw-r--r--sys/netinet6/esp_output.c683
-rw-r--r--sys/netinet6/icmp6.c18
-rw-r--r--sys/netinet6/icmp6.h4
-rw-r--r--sys/netinet6/in6_gif.c23
-rw-r--r--sys/netinet6/in6_pcb.c12
-rw-r--r--sys/netinet6/in6_proto.c13
-rw-r--r--sys/netinet6/ip6.h8
-rw-r--r--sys/netinet6/ip6_ecn.h43
-rw-r--r--sys/netinet6/ip6_forward.c10
-rw-r--r--sys/netinet6/ip6_fw.h202
-rw-r--r--sys/netinet6/ip6_input.c5
-rw-r--r--sys/netinet6/ip6_output.c29
-rw-r--r--sys/netinet6/ip6_var.h3
-rw-r--r--sys/netinet6/ipsec.c3061
-rw-r--r--sys/netinet6/ipsec.h6
-rw-r--r--sys/netinet6/ipsec6.h4
-rw-r--r--sys/netinet6/mld6.c6
-rw-r--r--sys/netinet6/nd6_nbr.c5
-rw-r--r--sys/netinet6/raw_ip6.c23
-rw-r--r--sys/netinet6/udp6_usrreq.c22
-rw-r--r--sys/netkey/key.c7264
-rw-r--r--sys/netkey/key.h367
-rw-r--r--sys/netkey/key_debug.c1262
-rw-r--r--sys/netkey/key_debug.h240
-rw-r--r--sys/netkey/key_var.h40
-rw-r--r--sys/netkey/keysock.c542
-rw-r--r--sys/netkey/keysock.h2
-rw-r--r--sys/sys/socket.h2
-rw-r--r--usr.sbin/Makefile1
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, &regtree[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(&regtree[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, &regtree[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, &regtree[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(&regtree[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 \
OpenPOWER on IntegriCloud