summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/conf/files18
-rw-r--r--sys/net/encap.c231
-rw-r--r--sys/net/encap.h140
-rw-r--r--sys/net/if.c4
-rw-r--r--sys/net/if_enc.c16
-rw-r--r--sys/netinet/ip_ah.c62
-rw-r--r--sys/netinet/ip_ah.h168
-rw-r--r--sys/netinet/ip_ah_new.c894
-rw-r--r--sys/netinet/ip_ah_old.c778
-rw-r--r--sys/netinet/ip_esp.c57
-rw-r--r--sys/netinet/ip_esp.h172
-rw-r--r--sys/netinet/ip_esp_new.c767
-rw-r--r--sys/netinet/ip_esp_old.c809
-rw-r--r--sys/netinet/ip_ip4.c72
-rw-r--r--sys/netinet/ip_ipsp.c241
-rw-r--r--sys/netinet/ip_ipsp.h154
-rw-r--r--sys/netinet/ip_output.c53
-rw-r--r--sys/netinet/ip_sha1.h7
-rw-r--r--sys/sys/mbuf.h7
19 files changed, 4050 insertions, 600 deletions
diff --git a/sys/conf/files b/sys/conf/files
index 183594bd74d..a7f2311c02a 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -1,4 +1,4 @@
-# $OpenBSD: files,v 1.59 1997/06/20 19:44:47 provos Exp $
+# $OpenBSD: files,v 1.60 1997/07/11 23:37:50 provos Exp $
# $NetBSD: files,v 1.87 1996/05/19 17:17:50 jonathan Exp $
# @(#)files.newconf 7.5 (Berkeley) 5/10/93
@@ -299,22 +299,18 @@ file netinet/fil.c ipfilter
file netinet/ip_nat.c ipfilter
file netinet/ip_frag.c ipfilter
file netinet/ip_state.c ipfilter
-file netinet/ip_ah.c inet & ipsec
-file netinet/ip_esp.c inet & ipsec
-file netinet/ip_espdes.c inet & ipsec
-file netinet/ip_esp3des.c inet & ipsec
-file netinet/ip_espdesmd5.c inet & ipsec
file netinet/ip_ipsp.c inet & ipsec
-file netinet/ip_ahmd5.c inet & ipsec
-file netinet/ip_ahsha1.c inet & ipsec
file netinet/ip_ip4.c inet & ipsec
-file netinet/ip_ahhmacmd5.c inet & ipsec
-file netinet/ip_ahhmacsha1.c inet & ipsec
+file netinet/ip_ah.c inet & ipsec
+file netinet/ip_esp.c inet & ipsec
+file netinet/ip_esp_old.c inet & ipsec
+file netinet/ip_esp_new.c inet & ipsec
+file netinet/ip_ah_old.c inet & ipsec
+file netinet/ip_ah_new.c inet & ipsec
file netinet/ip_sha1.c inet & ipsec
file netinet/libdeslite/ecb_enc.c inet & ipsec
file netinet/libdeslite/set_key.c inet & ipsec
file netinet/libdeslite/ecb3_enc.c inet & ipsec
-file netinet/ip_esp3desmd5.c inet & ipsec
file netiso/clnp_debug.c iso
file netiso/clnp_er.c iso
file netiso/clnp_frag.c iso
diff --git a/sys/net/encap.c b/sys/net/encap.c
index 11c44a79561..9e0845f098b 100644
--- a/sys/net/encap.c
+++ b/sys/net/encap.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: encap.c,v 1.7 1997/07/02 06:58:40 provos Exp $ */
+/* $OpenBSD: encap.c,v 1.8 1997/07/11 23:37:51 provos Exp $ */
/*
* The author of this code is John Ioannidis, ji@tla.org,
@@ -32,6 +32,8 @@
#include <sys/domain.h>
#include <sys/protosw.h>
#include <sys/ioctl.h>
+#include <vm/vm.h>
+#include <sys/sysctl.h>
#include <net/if.h>
#include <net/route.h>
@@ -46,14 +48,13 @@
#include <netinet/ip_ipsp.h>
#include <netinet/ip_ip4.h>
-extern struct ifnet loif;
-
-extern int ipspkernfs_dirty;
+#include <sys/syslog.h>
void encap_init(void);
int encap_output __P((struct mbuf *, ...));
int encap_usrreq(struct socket *, int, struct mbuf *, struct mbuf *,
struct mbuf *);
+int encap_sysctl(int *, u_int, void *, size_t *, void *, size_t);
extern int tdb_init(struct tdb *, struct mbuf *);
@@ -68,15 +69,38 @@ struct protosw encapsw[] = {
raw_input, encap_output, raw_ctlinput, 0,
encap_usrreq,
encap_init, 0, 0, 0,
+ encap_sysctl
},
};
struct domain encapdomain =
{ AF_ENCAP, "encapsulation", 0, 0, 0,
- encapsw, &encapsw[sizeof(encapsw)/sizeof(encapsw[0])], 0,
+ encapsw, &encapsw[sizeof(encapsw) / sizeof(encapsw[0])], 0,
rn_inithead, 16, sizeof(struct sockaddr_encap)};
+/*
+ * Sysctl for encap variables
+ */
+int
+encap_sysctl(int *name, u_int namelen, void *oldp, size_t *oldplenp,
+ void *newp, size_t newlen)
+{
+ /* All sysctl names at this level are terminal */
+ if (namelen != 1)
+ return ENOTDIR;
+
+ switch (name[0])
+ {
+ case IPSECCTL_ENCDEBUG:
+ return (sysctl_int(oldp, oldplenp, newp, newlen, &encdebug));
+
+ default:
+ return ENOPROTOOPT;
+ }
+ /* Not reached */
+}
+
void
encap_init()
{
@@ -84,7 +108,7 @@ encap_init()
for (xsp = xformsw; xsp < xformswNXFORMSW; xsp++)
{
- printf("encap_init: attaching <%s>\n", xsp->xf_name);
+ log(LOG_INFO, "encap_init(): attaching <%s>\n", xsp->xf_name);
(*(xsp->xf_attach))();
}
}
@@ -101,7 +125,10 @@ encap_usrreq(register struct socket *so, int req, struct mbuf *m,
if (req == PRU_ATTACH)
{
MALLOC(rp, struct rawcb *, sizeof(*rp), M_PCB, M_WAITOK);
- if ((so->so_pcb = (caddr_t)rp))
+ if (rp == (struct rawcb *) NULL)
+ return ENOBUFS;
+
+ if ((so->so_pcb = (caddr_t) rp))
bzero(so->so_pcb, sizeof(*rp));
}
@@ -114,7 +141,7 @@ encap_usrreq(register struct socket *so, int req, struct mbuf *m,
if (error)
{
- free((caddr_t)rp, M_PCB);
+ free((caddr_t) rp, M_PCB);
splx(s);
return error;
}
@@ -136,14 +163,16 @@ va_dcl
#endif
{
#define SENDERR(e) do { error = e; goto flush;} while (0)
+ struct sockaddr_encap encapdst, encapgw, encapnetmask;
int len, emlen, error = 0;
struct encap_msghdr *emp;
struct tdb *tdbp, *tdbp2;
caddr_t buffer = 0;
struct socket *so;
+ struct flow *flow;
u_int32_t spi;
va_list ap;
-
+
va_start(ap, m);
so = va_arg(ap, struct socket *);
va_end(ap);
@@ -153,7 +182,7 @@ va_dcl
return ENOBUFS;
if ((m->m_flags & M_PKTHDR) == 0)
- panic("encap_output");
+ panic("encap_output()");
len = m->m_pkthdr.len;
@@ -191,28 +220,24 @@ va_dcl
(emp->em_odst.s_addr != 0))
SENDERR(EINVAL);
- tdbp = gettdb(emp->em_spi, emp->em_dst);
+ tdbp = gettdb(emp->em_spi, emp->em_dst, emp->em_sproto);
if (tdbp == NULL)
{
- MALLOC(tdbp, struct tdb *, sizeof (*tdbp), M_TDB, M_WAITOK);
+ MALLOC(tdbp, struct tdb *, sizeof(*tdbp), M_TDB, M_WAITOK);
if (tdbp == NULL)
SENDERR(ENOBUFS);
- bzero((caddr_t)tdbp, sizeof(*tdbp));
+ bzero((caddr_t) tdbp, sizeof(*tdbp));
tdbp->tdb_spi = emp->em_spi;
tdbp->tdb_dst = emp->em_dst;
-
+ tdbp->tdb_sproto = emp->em_sproto;
puttdb(tdbp);
}
else
if (tdbp->tdb_xform)
(*tdbp->tdb_xform->xf_zeroize)(tdbp);
- tdbp->tdb_proto = emp->em_proto;
- tdbp->tdb_sport = emp->em_sport;
- tdbp->tdb_dport = emp->em_dport;
-
tdbp->tdb_src = emp->em_src;
/* Check if this is an encapsulating SPI */
@@ -308,15 +333,13 @@ va_dcl
if (error)
SENDERR(EINVAL);
- ipspkernfs_dirty = 1;
-
break;
case EMT_DELSPI:
if (emlen != EMT_DELSPI_FLEN)
SENDERR(EINVAL);
- tdbp = gettdb(emp->em_gen_spi, emp->em_gen_dst);
+ tdbp = gettdb(emp->em_gen_spi, emp->em_gen_dst, emp->em_gen_sproto);
if (tdbp == NULL)
SENDERR(ENOENT);
@@ -330,7 +353,7 @@ va_dcl
if (emlen != EMT_DELSPICHAIN_FLEN)
SENDERR(EINVAL);
- tdbp = gettdb(emp->em_gen_spi, emp->em_gen_dst);
+ tdbp = gettdb(emp->em_gen_spi, emp->em_gen_dst, emp->em_gen_sproto);
if (tdbp == NULL)
SENDERR(ENOENT);
@@ -344,26 +367,28 @@ va_dcl
if (emlen != EMT_GRPSPIS_FLEN)
SENDERR(EINVAL);
- tdbp = gettdb(emp->em_rel_spi, emp->em_rel_dst);
+ tdbp = gettdb(emp->em_rel_spi, emp->em_rel_dst, emp->em_rel_sproto);
if (tdbp == NULL)
SENDERR(ENOENT);
- tdbp2 = gettdb(emp->em_rel_spi2, emp->em_rel_dst2);
+ tdbp2 = gettdb(emp->em_rel_spi2, emp->em_rel_dst2,
+ emp->em_rel_sproto2);
if (tdbp2 == NULL)
SENDERR(ENOENT);
tdbp->tdb_onext = tdbp2;
tdbp2->tdb_inext = tdbp;
- ipspkernfs_dirty = 1;
error = 0;
+
break;
case EMT_RESERVESPI:
if (emlen != EMT_RESERVESPI_FLEN)
SENDERR(EINVAL);
- spi = reserve_spi(emp->em_gen_spi, emp->em_gen_dst, &error);
+ spi = reserve_spi(emp->em_gen_spi, emp->em_gen_dst,
+ emp->em_gen_sproto, &error);
if (spi == 0)
SENDERR(error);
@@ -384,40 +409,174 @@ va_dcl
break;
- case EMT_ENABLESPI:
- if (emlen != EMT_ENABLESPI_FLEN)
+ case EMT_VALIDATE:
+ if (emlen != EMT_VALIDATE_FLEN)
SENDERR(EINVAL);
- tdbp = gettdb(emp->em_gen_spi, emp->em_gen_dst);
+ tdbp = gettdb(emp->em_gen_spi, emp->em_gen_dst, emp->em_gen_sproto);
if (tdbp == NULL)
SENDERR(ENOENT);
/* Clear the INVALID flag */
tdbp->tdb_flags &= (~TDBF_INVALID);
- /* XXX Install a routing entry */
-
error = 0;
break;
- case EMT_DISABLESPI:
- if (emlen != EMT_DISABLESPI_FLEN)
+ case EMT_INVALIDATE:
+ if (emlen != EMT_INVALIDATE_FLEN)
SENDERR(EINVAL);
- tdbp = gettdb(emp->em_gen_spi, emp->em_gen_dst);
+ tdbp = gettdb(emp->em_gen_spi, emp->em_gen_dst, emp->em_gen_sproto);
if (tdbp == NULL)
SENDERR(ENOENT);
/* Set the INVALID flag */
tdbp->tdb_flags |= TDBF_INVALID;
- /* XXX Delete a routing entry, if on exists */
-
error = 0;
break;
+ case EMT_ENABLESPI:
+ if (emlen != EMT_ENABLESPI_FLEN)
+ SENDERR(EINVAL);
+
+ tdbp = gettdb(emp->em_ena_spi, emp->em_ena_dst, emp->em_ena_sproto);
+ if (tdbp == NULL)
+ SENDERR(ENOENT);
+
+ flow = find_flow(emp->em_ena_isrc, emp->em_ena_ismask,
+ emp->em_ena_idst, emp->em_ena_idmask,
+ emp->em_ena_protocol, emp->em_ena_sport,
+ emp->em_ena_dport, tdbp);
+ if (flow != (struct flow *) NULL)
+ SENDERR(EEXIST);
+
+ flow = get_flow();
+ if (flow == (struct flow *) NULL)
+ SENDERR(ENOBUFS);
+
+ flow->flow_src.s_addr = emp->em_ena_isrc.s_addr;
+ flow->flow_dst.s_addr = emp->em_ena_idst.s_addr;
+ flow->flow_srcmask.s_addr = emp->em_ena_ismask.s_addr;
+ flow->flow_dstmask.s_addr = emp->em_ena_idmask.s_addr;
+ flow->flow_proto = emp->em_ena_protocol;
+ flow->flow_sport = emp->em_ena_sport;
+ flow->flow_dport = emp->em_ena_dport;
+
+ put_flow(flow, tdbp);
+
+ /* Setup the encap fields */
+ encapdst.sen_len = SENT_IP4_LEN;
+ encapdst.sen_family = AF_ENCAP;
+ encapdst.sen_type = SENT_IP4;
+ encapdst.sen_ip_src.s_addr = flow->flow_src.s_addr;
+ encapdst.sen_ip_dst.s_addr = flow->flow_dst.s_addr;
+ encapdst.sen_proto = flow->flow_proto;
+ encapdst.sen_sport = flow->flow_sport;
+ encapdst.sen_dport = flow->flow_dport;
+
+ encapgw.sen_len = SENT_IPSP_LEN;
+ encapgw.sen_family = AF_ENCAP;
+ encapgw.sen_type = SENT_IPSP;
+ encapgw.sen_ipsp_dst.s_addr = tdbp->tdb_dst.s_addr;
+ encapgw.sen_ipsp_spi = tdbp->tdb_spi;
+
+ encapnetmask.sen_len = SENT_IP4_LEN;
+ encapnetmask.sen_family = AF_ENCAP;
+ encapnetmask.sen_type = SENT_IP4;
+ encapnetmask.sen_ip_src.s_addr = flow->flow_srcmask.s_addr;
+ encapnetmask.sen_ip_dst.s_addr = flow->flow_dstmask.s_addr;
+
+ if (flow->flow_proto)
+ {
+ encapnetmask.sen_proto = 0xff;
+
+ if (flow->flow_sport)
+ encapnetmask.sen_sport = 0xffff;
+
+ if (flow->flow_dport)
+ encapnetmask.sen_dport = 0xffff;
+ }
+
+ /* Add the entry in the routing table */
+ error = rtrequest(RTM_ADD, (struct sockaddr *) &encapdst,
+ (struct sockaddr *) &encapgw,
+ (struct sockaddr *) &encapnetmask,
+ RTF_UP | RTF_GATEWAY | RTF_STATIC,
+ (struct rtentry **) 0);
+
+ if (error)
+ {
+ delete_flow(flow, tdbp);
+ SENDERR(error);
+ }
+
+ error = 0;
+
+ break;
+
+ case EMT_DISABLESPI:
+ if (emlen != EMT_DISABLESPI_FLEN)
+ SENDERR(EINVAL);
+
+ tdbp = gettdb(emp->em_gen_spi, emp->em_gen_dst, emp->em_gen_sproto);
+ if (tdbp == NULL)
+ SENDERR(ENOENT);
+
+ flow = find_flow(emp->em_ena_isrc, emp->em_ena_ismask,
+ emp->em_ena_idst, emp->em_ena_idmask,
+ emp->em_ena_protocol, emp->em_ena_sport,
+ emp->em_ena_dport, tdbp);
+ if (flow == (struct flow *) NULL)
+ SENDERR(ENOENT);
+
+ /* Setup the encap fields */
+ encapdst.sen_len = SENT_IP4_LEN;
+ encapdst.sen_family = AF_ENCAP;
+ encapdst.sen_type = SENT_IP4;
+ encapdst.sen_ip_src.s_addr = flow->flow_src.s_addr;
+ encapdst.sen_ip_dst.s_addr = flow->flow_dst.s_addr;
+ encapdst.sen_proto = flow->flow_proto;
+ encapdst.sen_sport = flow->flow_sport;
+ encapdst.sen_dport = flow->flow_dport;
+
+ encapgw.sen_len = SENT_IPSP_LEN;
+ encapgw.sen_family = AF_ENCAP;
+ encapgw.sen_type = SENT_IPSP;
+ encapgw.sen_ipsp_dst.s_addr = tdbp->tdb_dst.s_addr;
+ encapgw.sen_ipsp_spi = tdbp->tdb_spi;
+
+ encapnetmask.sen_len = SENT_IP4_LEN;
+ encapnetmask.sen_family = AF_ENCAP;
+ encapnetmask.sen_type = SENT_IP4;
+ encapnetmask.sen_ip_src.s_addr = flow->flow_srcmask.s_addr;
+ encapnetmask.sen_ip_dst.s_addr = flow->flow_dstmask.s_addr;
+
+ if (flow->flow_proto)
+ {
+ encapnetmask.sen_proto = 0xff;
+
+ if (flow->flow_sport)
+ encapnetmask.sen_sport = 0xffff;
+
+ if (flow->flow_dport)
+ encapnetmask.sen_dport = 0xffff;
+ }
+
+ /* Add the entry in the routing table */
+ error = rtrequest(RTM_DELETE, (struct sockaddr *) &encapdst,
+ (struct sockaddr *) &encapgw,
+ (struct sockaddr *) &encapnetmask,
+ RTF_UP | RTF_GATEWAY | RTF_STATIC,
+ (struct rtentry **) 0);
+
+ delete_flow(flow, tdbp);
+
+ break;
+
case EMT_NOTIFY:
if (emlen <= EMT_NOTIFY_FLEN)
SENDERR(EINVAL);
diff --git a/sys/net/encap.h b/sys/net/encap.h
index e02c13aca07..81b4c40cad9 100644
--- a/sys/net/encap.h
+++ b/sys/net/encap.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: encap.h,v 1.6 1997/07/02 06:58:40 provos Exp $ */
+/* $OpenBSD: encap.h,v 1.7 1997/07/11 23:37:52 provos Exp $ */
/*
* The author of this code is John Ioannidis, ji@tla.org,
@@ -69,7 +69,8 @@ struct sockaddr_encap
{
struct in_addr Dst;
u_int32_t Spi;
- u_int8_t Filler[8];
+ u_int8_t Sproto;
+ u_int8_t Filler[7];
} Sipsp;
} Sen;
};
@@ -85,6 +86,7 @@ struct sockaddr_encap
#define sen_dport Sen.Sip4.Dport
#define sen_ipsp_dst Sen.Sipsp.Dst
#define sen_ipsp_spi Sen.Sipsp.Spi
+#define sen_ipsp_sproto Sen.Sipsp.Sproto
/*
* The "type" is really part of the address as far as the routing
@@ -136,12 +138,11 @@ struct encap_msghdr
int32_t Alg; /* Algorithm to use */
struct in_addr Dst; /* Destination address */
struct in_addr Src; /* This is used to set our source
- * address when doing tunneling and
- * the outgoing packet does not
- * have a source address (is zero) */
- struct in_addr oSrc; /* Source... */
- struct in_addr oDst; /* ...and destination in outter IP
- * header, if we're doing IP-in-IP */
+ * address when the outgoing packet
+ * does not have a source address
+ * (is zero). */
+ struct in_addr oSrc; /* Outter header source address */
+ struct in_addr oDst; /* Same, for destination address */
u_int64_t Relative_Hard; /* Expire relative to creation */
u_int64_t Relative_Soft;
u_int64_t First_Use_Hard; /* Expire relative to first use */
@@ -159,24 +160,24 @@ struct encap_msghdr
* the system default TTL will be used.
* If set to anything else, then the
* ttl used will be TTL % 256 */
- u_int16_t Sport; /* Source port, if applicable */
- u_int16_t Dport; /* Destination port, if applicable */
- u_int8_t Proto; /* Protocol, if applicable */
- u_int8_t foo[3]; /* Alignment */
+ u_int8_t Sproto; /* ESP or AH */
+ u_int8_t Foo[3]; /* Alignment */
u_int8_t Dat[1]; /* Data */
} Xfm;
/*
* For expiration notifications, the kernel fills in
- * Notification_Type, Spi and Dst. No direct response is expected.
+ * Notification_Type, Spi, Dst and Sproto.
+ * No direct response is expected.
*
* For SA Requests, the kernel fills in
- * Notification_Type, MsgID, Spi, Seclevel, Dst (and optionally
+ * Notification_Type, MsgID, Seclevel, Dst, SAType, (and optionally
* Protocol, Src, Sport, Dport and UserID).
*
* The response should have the same values in all the fields
* and:
- * Spi/Spi2/Spi3 will hold the SPIs for the three seclevels
+ * Spi will hold the SPI for the three seclevels
+ * Sproto will hold the IPsec protocol used (AH/ESP)
* UserID can optionally hold the peer's UserID (if applicable)
*/
struct /* kernel->userland notifications */
@@ -184,60 +185,93 @@ struct encap_msghdr
u_int32_t Notification_Type;
u_int32_t MsgID; /* Request ID */
u_int32_t Spi;
- u_int32_t Spi2;
- u_int32_t Spi3;
- u_int8_t Seclevel[3]; /* see netinet/in_pcb.h */
- u_int8_t Protocol; /* Transport mode for which protocol */
+ u_int32_t SAType; /* What do we want for this SA */
struct in_addr Dst; /* Peer */
struct in_addr Src; /* Might have our local address */
u_int16_t Sport; /* Source port */
u_int16_t Dport; /* Destination port */
+ u_int8_t Protocol; /* Transport protocol */
+ u_int8_t Sproto; /* IPsec protocol */
+ u_int8_t Foo[2]; /* Alignment */
u_int8_t UserID[1]; /* Might be used to indicate user */
} Notify;
/* Link two SPIs */
struct
{
- u_int32_t emr_spi; /* SPI */
- u_int32_t emr_spi2;
- struct in_addr emr_dst; /* Dest */
- struct in_addr emr_dst2;
+ u_int32_t Spi; /* SPI */
+ u_int32_t Spi2;
+ struct in_addr Dst; /* Dest */
+ struct in_addr Dst2;
+ u_int8_t Sproto; /* IPsec protocol */
+ u_int8_t Sproto2;
+ u_int16_t Foo;
} Rel;
- /* For general use */
+ /* Enable/disable an SA for a session */
+ struct
+ {
+ u_int32_t Spi;
+ struct in_addr Dst;
+ struct in_addr iSrc; /* Source... */
+ struct in_addr iDst; /* ...and destination in inner IP */
+ struct in_addr iSmask; /* Source netmask */
+ struct in_addr iDmask; /* Destination netmask */
+ u_int16_t Sport; /* Source port, if applicable */
+ u_int16_t Dport; /* Destination port, if applicable */
+ u_int8_t Protocol; /* Transport mode for which protocol */
+ u_int8_t Sproto; /* IPsec protocol */
+ u_int8_t Foo[2]; /* Alignment */
+ } Ena;
+
+ /* For general use: (in)validate, delete (chain), reserve */
struct
{
- u_int32_t emg_spi;
- struct in_addr emg_dst;
+ u_int32_t Spi;
+ struct in_addr Dst;
+ u_int8_t Sproto;
+ u_int8_t Foo[3];
} Gen;
} Eu;
};
-#define NOTIFY_SOFT_EXPIRE 0 /* Soft expiration of SA */
-#define NOTIFY_HARD_EXPIRE 1 /* Hard expiration of SA */
-#define NOTIFY_REQUEST_SA 2 /* Establish an SA */
+#define ENCAP_MSG_FIXED_LEN (2 * sizeof(u_int32_t))
+
+#define NOTIFY_SOFT_EXPIRE 0 /* Soft expiration of SA */
+#define NOTIFY_HARD_EXPIRE 1 /* Hard expiration of SA */
+#define NOTIFY_REQUEST_SA 2 /* Establish an SA */
+
+#define em_ena_spi Eu.Ena.Spi
+#define em_ena_dst Eu.Ena.Dst
+#define em_ena_isrc Eu.Ena.iSrc
+#define em_ena_idst Eu.Ena.iDst
+#define em_ena_ismask Eu.Ena.iSmask
+#define em_ena_idmask Eu.Ena.iDmask
+#define em_ena_sport Eu.Ena.Sport
+#define em_ena_dport Eu.Ena.Dport
+#define em_ena_protocol Eu.Ena.Protocol
+#define em_ena_sproto Eu.Ena.Sproto
-#define em_gen_spi Eu.Gen.emg_spi
-#define em_gen_dst Eu.Gen.emg_dst
+#define em_gen_spi Eu.Gen.Spi
+#define em_gen_dst Eu.Gen.Dst
+#define em_gen_sproto Eu.Gen.Sproto
#define em_not_type Eu.Notify.Notification_Type
#define em_not_spi Eu.Notify.Spi
-#define em_not_spi2 Eu.Notify.Spi2
-#define em_not_spi3 Eu.Notify.Spi3
#define em_not_dst Eu.Notify.Dst
-#define em_not_seclevel Eu.Notify.Seclevel
+#define em_not_satype Eu.Notify.SAType
#define em_not_userid Eu.Notify.UserID
#define em_not_msgid Eu.Notify.MsgID
#define em_not_sport Eu.Notify.Sport
#define em_not_dport Eu.Notify.Dport
#define em_not_protocol Eu.Notify.Protocol
+#define em_not_sproto Eu.Notify.Sproto
#define em_spi Eu.Xfm.Spi
#define em_dst Eu.Xfm.Dst
#define em_src Eu.Xfm.Src
-#define em_osrc Eu.Xfm.oSrc
-#define em_odst Eu.Xfm.oDst
-#define em_if Eu.Xfm.If
+#define em_osrc Eu.Xfm.oSrc
+#define em_odst Eu.Xfm.oDst
#define em_alg Eu.Xfm.Alg
#define em_dat Eu.Xfm.Dat
#define em_relative_hard Eu.Xfm.Relative_Hard
@@ -251,34 +285,38 @@ struct encap_msghdr
#define em_packets_hard Eu.Xfm.Packets_Hard
#define em_packets_soft Eu.Xfm.Packets_Soft
#define em_ttl Eu.Xfm.TTL
-#define em_proto Eu.Xfm.Proto
-#define em_sport Eu.Xfm.Sport
-#define em_dport Eu.Xfm.Dport
+#define em_sproto Eu.Xfm.Sproto
-#define em_rel_spi Eu.Rel.emr_spi
-#define em_rel_spi2 Eu.Rel.emr_spi2
-#define em_rel_dst Eu.Rel.emr_dst
-#define em_rel_dst2 Eu.Rel.emr_dst2
+#define em_rel_spi Eu.Rel.Spi
+#define em_rel_spi2 Eu.Rel.Spi2
+#define em_rel_dst Eu.Rel.Dst
+#define em_rel_dst2 Eu.Rel.Dst2
+#define em_rel_sproto Eu.Rel.Sproto
+#define em_rel_sproto2 Eu.Rel.Sproto2
#define EMT_SETSPI 1 /* Set SPI properties */
-#define EMT_GRPSPIS 2 /* Group SPIs (output order) */
+#define EMT_GRPSPIS 2 /* Group SPIs */
#define EMT_DELSPI 3 /* delete an SPI */
#define EMT_DELSPICHAIN 4 /* delete an SPI chain starting from */
#define EMT_RESERVESPI 5 /* Give us an SPI */
#define EMT_ENABLESPI 6 /* Enable an SA */
#define EMT_DISABLESPI 7 /* Disable an SA */
#define EMT_NOTIFY 8 /* kernel->userland key mgmt not. */
+#define EMT_VALIDATE 9 /* Make an SPI valid for use */
+#define EMT_INVALIDATE 10 /* Make an SPI invalid for use */
/* Total packet lengths */
-#define EMT_SETSPI_FLEN 124
-#define EMT_GRPSPIS_FLEN 24
-#define EMT_GENLEN 16
+#define EMT_SETSPI_FLEN 120
+#define EMT_GRPSPIS_FLEN 28
+#define EMT_GENLEN 20
#define EMT_DELSPI_FLEN EMT_GENLEN
#define EMT_DELSPICHAIN_FLEN EMT_GENLEN
-#define EMT_ENABLESPI_FLEN EMT_GENLEN
-#define EMT_DISABLESPI_FLEN EMT_GENLEN
#define EMT_RESERVESPI_FLEN EMT_GENLEN
-#define EMT_NOTIFY_FLEN 44
+#define EMT_VALIDATE_FLEN EMT_GENLEN
+#define EMT_INVALIDATE_FLEN EMT_GENLEN
+#define EMT_NOTIFY_FLEN 40
+#define EMT_ENABLESPI_FLEN 40
+#define EMT_DISABLESPI_FLEN EMT_ENABLESPI_FLEN
#ifdef _KERNEL
extern struct ifaddr *encap_findgwifa(struct sockaddr *);
diff --git a/sys/net/if.c b/sys/net/if.c
index 6e680460266..e69d74c8f7d 100644
--- a/sys/net/if.c
+++ b/sys/net/if.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if.c,v 1.12 1996/08/03 17:50:35 deraadt Exp $ */
+/* $OpenBSD: if.c,v 1.13 1997/07/11 23:37:52 provos Exp $ */
/* $NetBSD: if.c,v 1.35 1996/05/07 05:26:04 thorpej Exp $ */
/*
@@ -229,7 +229,7 @@ ifa_ifwithnet(addr)
for (ifa = ifp->if_addrlist.tqh_first; ifa != 0; ifa = ifa->ifa_list.tqe_next) {
register char *cp, *cp2, *cp3;
- if (ifa->ifa_addr->sa_family != af ||
+ if (!ifa->ifa_addr || ifa->ifa_addr->sa_family != af ||
ifa->ifa_netmask == 0)
next: continue;
cp = addr_data;
diff --git a/sys/net/if_enc.c b/sys/net/if_enc.c
index 0f0cff17d8c..de2544fd9b8 100644
--- a/sys/net/if_enc.c
+++ b/sys/net/if_enc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_enc.c,v 1.4 1997/07/01 22:12:39 provos Exp $ */
+/* $OpenBSD: if_enc.c,v 1.5 1997/07/11 23:37:53 provos Exp $ */
/*
* The author of this code is John Ioannidis, ji@tla.org,
@@ -66,7 +66,7 @@ struct ifnet enc_softc;
void encattach __P((int));
int encoutput __P((struct ifnet *, struct mbuf *, struct sockaddr *,
- struct rtentry *));
+ struct rtentry *));
int encioctl __P((struct ifnet *, u_long, caddr_t));
void encrtrequest __P((int, struct rtentry *, struct sockaddr *));
@@ -98,10 +98,10 @@ encattach(int nenc)
#endif
/* Just a bogus entry */
- ifa = (struct ifaddr *)malloc(sizeof(struct ifaddr) +
- sizeof(struct sockaddr), M_IFADDR, M_WAITOK);
+ ifa = (struct ifaddr *) malloc(sizeof(struct ifaddr) +
+ sizeof(struct sockaddr), M_IFADDR, M_WAITOK);
bzero(ifa, sizeof(struct ifaddr) + sizeof(struct sockaddr));
- ifa->ifa_addr = ifa->ifa_dstaddr = (struct sockaddr *)(ifa + 1);
+ ifa->ifa_addr = ifa->ifa_dstaddr = (struct sockaddr *) (ifa + 1);
ifa->ifa_ifp = &enc_softc;
TAILQ_INSERT_HEAD(&(enc_softc.if_addrlist), ifa, ifa_list);
}
@@ -120,7 +120,7 @@ register struct rtentry *rt;
int s, isr;
if ((m->m_flags & M_PKTHDR) == 0)
- panic("encoutput no HDR");
+ panic("encoutput(): no HDR");
ifp->if_lastchange = time;
@@ -139,7 +139,7 @@ register struct rtentry *rt;
m0.m_next = m;
m0.m_len = 4;
- m0.m_data = (char *)&af;
+ m0.m_data = (char *) &af;
bpf_mtap(ifp->if_bpf, &m0);
}
@@ -239,7 +239,7 @@ caddr_t data;
*/
ifp->if_flags |= IFF_UP;
- ifa = (struct ifaddr *)data;
+ ifa = (struct ifaddr *) data;
break;
diff --git a/sys/netinet/ip_ah.c b/sys/netinet/ip_ah.c
index 1e5cdddc26b..a003c5ab71f 100644
--- a/sys/netinet/ip_ah.c
+++ b/sys/netinet/ip_ah.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_ah.c,v 1.7 1997/07/01 22:12:41 provos Exp $ */
+/* $OpenBSD: ip_ah.c,v 1.8 1997/07/11 23:37:54 provos Exp $ */
/*
* The author of this code is John Ioannidis, ji@tla.org,
@@ -59,6 +59,8 @@
#include <netinet/ip_ipsp.h>
#include <netinet/ip_ah.h>
+#include <sys/syslog.h>
+
void ah_input __P((struct mbuf *, int));
/*
@@ -68,42 +70,35 @@ void ah_input __P((struct mbuf *, int));
void
ah_input(register struct mbuf *m, int iphlen)
{
- struct ip *ipo;
- struct ah *ahp;
- struct tdb *tdbp;
struct ifqueue *ifq = NULL;
+ struct ip *ipo, ipn;
+ struct ah_old *ahp, ahn;
+ struct tdb *tdbp;
int s;
ahstat.ahs_input++;
-#if 0 /* We need them to verify the packet */
- /*
- * Strip IP options, if any.
- */
-
- if (iphlen > sizeof (struct ip))
- {
- ip_stripoptions(m, (struct mbuf *)0);
- iphlen = sizeof (struct ip);
- }
-#endif
-
/*
* Make sure that at least the fixed part of the AH header is
* in the first mbuf.
*/
ipo = mtod(m, struct ip *);
- if (m->m_len < iphlen + AH_FLENGTH)
+ if (m->m_len < iphlen + AH_OLD_FLENGTH)
{
- if ((m = m_pullup(m, iphlen + AH_FLENGTH)) == 0)
+ if ((m = m_pullup(m, iphlen + AH_OLD_FLENGTH)) == 0)
{
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ah_input(): (possibly too short) packet from %x to %x dropped\n", ipo->ip_src, ipo->ip_dst);
+#endif /* ENCDEBUG */
ahstat.ahs_hdrops++;
return;
}
ipo = mtod(m, struct ip *);
}
- ahp = (struct ah *)((caddr_t)ipo + iphlen);
+
+ ahp = (struct ah_old *) ((caddr_t) ipo + iphlen);
/*
* Find tunnel control block and (indirectly) call the appropriate
@@ -111,13 +106,10 @@ ah_input(register struct mbuf *m, int iphlen)
* IP packet ready to go through input processing.
*/
- tdbp = gettdb(ahp->ah_spi, ipo->ip_dst);
+ tdbp = gettdb(ahp->ah_spi, ipo->ip_dst, IPPROTO_AH);
if (tdbp == NULL)
{
-#ifdef ENCDEBUG
- if (encdebug)
- printf("ah_input: no tdb for spi=%x\n", ahp->ah_spi);
-#endif ENCDEBUG
+ log(LOG_ERR, "ah_input(): could not find SA for AH packet from %x to %x, spi %08x", ipo->ip_src, ipo->ip_dst, ahp->ah_spi);
m_freem(m);
ahstat.ahs_notdb++;
return;
@@ -125,10 +117,9 @@ ah_input(register struct mbuf *m, int iphlen)
if (tdbp->tdb_flags & TDBF_INVALID)
{
-#ifdef ENCDEBUG
- if (encdebug)
- printf("ah_input: spi=%x is no longer/yet valid\n", ahp->ah_spi);
-#endif /* ENCDEBUG */
+ log(LOG_ALERT,
+ "ah_input(): attempted to use invalid AH SA %08x, packet %x->%x",
+ ahp->ah_spi, ipo->ip_src, ipo->ip_dst);
m_freem(m);
ahstat.ahs_invalid++;
return;
@@ -136,10 +127,7 @@ ah_input(register struct mbuf *m, int iphlen)
if (tdbp->tdb_xform == NULL)
{
-#ifdef ENCDEBUG
- if (encdebug)
- printf("ah_input: no xform for spi=%x\n", ahp->ah_spi);
-#endif ENCDEBUG
+ log(LOG_ALERT, "ah_input(): attempted to use uninitialized AH SA %08x, packet from %x to %x", ahp->ah_spi, ipo->ip_src, ipo->ip_dst);
m_freem(m);
ahstat.ahs_noxform++;
return;
@@ -151,10 +139,13 @@ ah_input(register struct mbuf *m, int iphlen)
if (tdbp->tdb_first_use == 0)
tdbp->tdb_first_use = time.tv_sec;
+ ipn = *ipo;
+ ahn = *ahp;
+
m = (*(tdbp->tdb_xform->xf_input))(m, tdbp);
-
if (m == NULL)
{
+ log(LOG_ALERT, "ah_input(): authentication failed for AH packet from %x to %x, spi %08x", ipn.ip_src, ipn.ip_dst, ahn.ah_spi);
ahstat.ahs_badkcr++;
return;
}
@@ -173,8 +164,13 @@ ah_input(register struct mbuf *m, int iphlen)
m_freem(m);
ahstat.ahs_qfull++;
splx(s);
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ah_input(): dropped packet because of full IP queue\n");
+#endif /* ENCDEBUG */
return;
}
+
IF_ENQUEUE(ifq, m);
schednetisr(NETISR_IP);
splx(s);
diff --git a/sys/netinet/ip_ah.h b/sys/netinet/ip_ah.h
index da9840e14e7..4781fbd6eaa 100644
--- a/sys/netinet/ip_ah.h
+++ b/sys/netinet/ip_ah.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_ah.h,v 1.7 1997/06/25 07:53:21 provos Exp $ */
+/* $OpenBSD: ip_ah.h,v 1.8 1997/07/11 23:37:54 provos Exp $ */
/*
* The author of this code is John Ioannidis, ji@tla.org,
@@ -31,16 +31,22 @@
#include <sys/md5k.h>
#include <netinet/ip_sha1.h>
-struct ah
+struct ah_old
{
u_int8_t ah_nh; /* Next header (protocol) */
u_int8_t ah_hl; /* AH length, in 32-bit words */
u_int16_t ah_rv; /* reserved, must be 0 */
u_int32_t ah_spi; /* Security Parameters Index */
- u_int8_t ah_data[1]; /* More, really*/
+ u_int8_t ah_data[1]; /* More, really */
};
-#define AH_FLENGTH 8 /* size of fixed part */
+#define AH_OLD_FLENGTH 8 /* size of fixed part */
+
+/* Authenticator lengths */
+#define AH_MD5_ALEN 16
+#define AH_SHA1_ALEN 20
+
+#define AH_ALEN_MAX AH_SHA1_ALEN /* Keep this updated */
struct ahstat
{
@@ -58,131 +64,93 @@ struct ahstat
u_int32_t ahs_invalid; /* Trying to use an invalid TDB */
};
-#define AHHMACMD5_KMAX 64 /* max 512 bits key */
-#define AHHMACMD5_AMAX 64 /* up to 512 bits of authenticator */
-#define AHHMACMD5_RPLS 2 /* 64 bits of replay counter */
-
-#define HMACMD5_HASHLEN 16
-#define HMACMD5_RPLENGTH 8
-
-#define HMACMD5_IPAD_VAL 0x36
-#define HMACMD5_OPAD_VAL 0x5C
-
-#define AHHMACMD5_KMAX 64 /* max 512 bits key */
-#define AHHMACMD5_AMAX 64 /* up to 512 bits of authenticator */
-#define AHHMACMD5_RPLS 2 /* 64 bits of replay counter */
+#define AH_HMAC_HASHLEN 12 /* 96 bits of authenticator */
+#define AH_HMAC_RPLENGTH 4 /* 32 bits of replay counter */
+#define AH_HMAC_INITIAL_RPL 1 /* Replay counter initial value */
-#define HMACMD5_HASHLEN 16
-#define HMACMD5_RPLENGTH 8
+#define HMAC_IPAD_VAL 0x36
+#define HMAC_OPAD_VAL 0x5C
+#define HMAC_BLOCK_LEN 64
-#define HMACMD5_IPAD_VAL 0x36
-#define HMACMD5_OPAD_VAL 0x5C
-
-struct ahhmacmd5
+struct ah_new
{
u_int8_t ah_nh; /* Next header (protocol) */
u_int8_t ah_hl; /* AH length, in 32-bit words */
u_int16_t ah_rv; /* reserved, must be 0 */
u_int32_t ah_spi; /* Security Parameters Index */
- u_int64_t ah_rpl; /* Replay prevention */
- u_int8_t ah_data[AHHMACMD5_AMAX];/* Authenticator */
+ u_int32_t ah_rpl; /* Replay prevention */
+ u_int8_t ah_data[AH_HMAC_HASHLEN];/* Authenticator */
};
-struct ahhmacmd5_xencap
-{
- u_int16_t amx_alen;
- u_int16_t amx_rpl;
- int32_t amx_wnd;
- u_int8_t amx_key[AHHMACMD5_KMAX];
-};
+#define AH_NEW_FLENGTH (sizeof(struct ah_new))
-struct ahhmacmd5_xdata
+struct ah_new_xencap
{
- u_int32_t amx_alen; /* authenticator length */
+ u_int32_t amx_hash_algorithm;
int32_t amx_wnd;
- u_int64_t amx_rpl; /* Replay counter */
- u_int64_t amx_bitmap;
- MD5_CTX amx_ictx; /* Internal key+padding */
- MD5_CTX amx_octx; /* External key+padding */
+ u_int32_t amx_keylen;
+ u_int8_t amx_key[1];
};
-#define AHHMACSHA1_KMAX 64 /* max 512 bits key */
-#define AHHMACSHA1_AMAX 64 /* up to 512 bits of authenticator */
-#define AHHMACSHA1_RPLS 2 /* 64 bits of replay counter */
+#define AH_NEW_XENCAP_LEN (3 * sizeof(u_int32_t))
-#define HMACSHA1_HASHLEN 20
-#define HMACSHA1_RPLENGTH 8
-
-#define HMACSHA1_IPAD_VAL 0x36
-#define HMACSHA1_OPAD_VAL 0x5C
-
-struct ahhmacsha1
-{
- u_int8_t ah_nh; /* Next header (protocol) */
- u_int8_t ah_hl; /* AH length, in 32-bit words */
- u_int16_t ah_rv; /* reserved, must be 0 */
- u_int32_t ah_spi; /* Security Parameters Index */
- u_int64_t ah_rpl; /* Replay prevention */
- u_int8_t ah_data[AHHMACSHA1_AMAX];/* Authenticator */
-};
-
-struct ahhmacsha1_xencap
+struct ah_new_xdata
{
- u_int32_t amx_alen;
+ u_int32_t amx_hash_algorithm;
int32_t amx_wnd;
- u_int8_t amx_key[AHHMACSHA1_KMAX];
+ u_int32_t amx_rpl; /* Replay counter */
+ u_int32_t amx_bitmap;
+ union
+ {
+ struct
+ {
+ MD5_CTX amx_ictx; /* Internal key+padding */
+ MD5_CTX amx_octx; /* External key+padding */
+ } MD5stuff;
+
+ struct
+ {
+ SHA1_CTX amx_ictx;
+ SHA1_CTX amx_octx;
+ } SHA1stuff;
+ } Hashes;
};
-struct ahhmacsha1_xdata
-{
- u_int32_t amx_alen; /* authenticator length */
- int32_t amx_wnd;
- u_int64_t amx_rpl; /* Replay counter */
- u_int64_t amx_bitmap;
- SHA1_CTX amx_ictx; /* Internal key+padding */
- SHA1_CTX amx_octx; /* External key+padding */
-};
-
-#define AHMD5_KMAX 32 /* max 256 bits key */
-#define AHMD5_AMAX 64 /* up to 512 bits of authenticator */
-#define AHSHA1_KMAX 32
-#define AHSHA1_AMAX 64
-
-struct ahmd5
-{
- u_int8_t ah_nh; /* Next header (protocol) */
- u_int8_t ah_hl; /* AH length, in 32-bit words */
- u_int16_t ah_rv; /* reserved, must be 0 */
- u_int32_t ah_spi; /* Security Parameters Index */
- u_int8_t ah_data[AHMD5_AMAX]; /* */
-};
-
-struct ahsha1
-{
- u_int8_t ah_nh; /* Next header (protocol) */
- u_int8_t ah_hl; /* AH length, in 32-bit words */
- u_int16_t ah_rv; /* reserved, must be 0 */
- u_int32_t ah_spi; /* Security Parameters Index */
- u_int8_t ah_data[AHSHA1_AMAX]; /* */
-};
+#define amx_md5_ictx Hashes.MD5stuff.amx_ictx
+#define amx_md5_octx Hashes.MD5stuff.amx_octx
+#define amx_sha1_ictx Hashes.SHA1stuff.amx_ictx
+#define amx_sha1_octx Hashes.SHA1stuff.amx_octx
#define AHMD5_ALEN 16 /* Size of MD5 digest */
#define AHSHA1_ALEN 20 /* Size of SHA-1 digest */
-struct ahmd5_xdata
+struct ah_old_xdata
{
- u_int16_t amx_klen; /* Key material length */
- u_int16_t amx_alen; /* authenticator length */
- u_int8_t amx_key[AHMD5_KMAX]; /* Key material */
+ u_int32_t amx_hash_algorithm;
+ u_int32_t amx_keylen; /* Key material length */
+ union
+ {
+ MD5_CTX amx_MD5_ctx;
+ SHA1_CTX amx_SHA1_ctx;
+ } Hashes;
+ u_int8_t amx_key[1]; /* Key material */
};
-struct ahsha1_xdata
+#define amx_md5_ctx Hashes.amx_MD5_ctx
+#define amx_sha1_ctx Hashes.amx_SHA1_ctx
+
+struct ah_old_xencap
{
- u_int16_t amx_klen; /* Key material length */
- u_int16_t amx_alen; /* authenticator length */
- u_int8_t amx_key[AHSHA1_KMAX]; /* Key material */
+ u_int32_t amx_hash_algorithm;
+ u_int32_t amx_keylen;
+ u_int8_t amx_key[1];
};
+#define AH_OLD_XENCAP_LEN (2 * sizeof(u_int32_t))
+
+#define AH_HMAC_IPAD_VAL 0x36
+#define AH_HMAC_OPAD_VAL 0x5C
+
#ifdef _KERNEL
struct ahstat ahstat;
#endif
diff --git a/sys/netinet/ip_ah_new.c b/sys/netinet/ip_ah_new.c
new file mode 100644
index 00000000000..e5aabc7a04f
--- /dev/null
+++ b/sys/netinet/ip_ah_new.c
@@ -0,0 +1,894 @@
+/* $OpenBSD: ip_ah_new.c,v 1.1 1997/07/11 23:37:55 provos Exp $ */
+
+/*
+ * The author of this code is John Ioannidis, ji@tla.org,
+ * (except when noted otherwise).
+ *
+ * This code was written for BSD/OS in Athens, Greece, in November 1995.
+ *
+ * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
+ * by Angelos D. Keromytis, kermit@forthnet.gr.
+ *
+ * Copyright (C) 1995, 1996, 1997 by John Ioannidis and Angelos D. Keromytis.
+ *
+ * Permission to use, copy, and modify this software without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, NEITHER AUTHOR MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+/*
+ * Based on RFC 2085.
+ */
+
+#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/socketvar.h>
+
+#include <machine/cpu.h>
+#include <machine/endian.h>
+
+#include <net/if.h>
+#include <net/route.h>
+#include <net/netisr.h>
+#include <net/raw_cb.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/in_pcb.h>
+#include <netinet/in_var.h>
+#include <netinet/ip_var.h>
+#include <netinet/ip_icmp.h>
+
+#include <net/encap.h>
+
+#include <netinet/ip_ipsp.h>
+#include <netinet/ip_ah.h>
+#include <sys/syslog.h>
+
+/*
+ * ah_new_attach() is called from the transformation initialization code.
+ * It just returns.
+ */
+
+int
+ah_new_attach()
+{
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ah_new_attach(): setting up\n");
+#endif /* ENCDEBUG */
+ return 0;
+}
+
+/*
+ * ah_new_init() is called when an SPI is being set up. It interprets the
+ * encap_msghdr present in m, and sets up the transformation data.
+ */
+
+int
+ah_new_init(struct tdb *tdbp, struct xformsw *xsp, struct mbuf *m)
+{
+ struct ah_new_xdata *xd;
+ struct ah_new_xencap txd;
+ struct encap_msghdr *em;
+ caddr_t buffer = NULL;
+ int blocklen, i;
+
+ if (m->m_len < ENCAP_MSG_FIXED_LEN)
+ {
+ if ((m = m_pullup(m, ENCAP_MSG_FIXED_LEN)) == NULL)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ah_new_init(): m_pullup failed\n");
+#endif /* ENCDEBUG */
+ return ENOBUFS;
+ }
+ }
+
+ em = mtod(m, struct encap_msghdr *);
+ if (em->em_msglen - EMT_SETSPI_FLEN <= AH_NEW_XENCAP_LEN)
+ {
+ log(LOG_WARNING, "ah_new_init() initialization failed");
+ return EINVAL;
+ }
+
+ /* Just copy the standard fields */
+ m_copydata(m, EMT_SETSPI_FLEN, AH_NEW_XENCAP_LEN, (caddr_t) &txd);
+
+ /* Check whether the hash algorithm is supposed */
+ switch (txd.amx_hash_algorithm)
+ {
+ case ALG_AUTH_MD5:
+ case ALG_AUTH_SHA1:
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ah_new_init(): initalized TDB with hash algorithm %d\n",
+ txd.amx_hash_algorithm);
+#endif /* ENCDEBUG */
+ blocklen = HMAC_BLOCK_LEN;
+ break;
+
+ default:
+ log(LOG_WARNING, "ah_new_init(): unsupported authentication algorithm %d specified", txd.amx_hash_algorithm);
+ return EINVAL;
+ }
+
+ if (txd.amx_keylen + EMT_SETSPI_FLEN + AH_NEW_XENCAP_LEN != em->em_msglen)
+ {
+ log(LOG_WARNING, "ah_new_init(): message length (%d) doesn't match",
+ em->em_msglen);
+ return EINVAL;
+ }
+
+ MALLOC(tdbp->tdb_xdata, caddr_t, sizeof(struct ah_new_xdata),
+ M_XDATA, M_WAITOK);
+ if (tdbp->tdb_xdata == NULL)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ah_new_init(): MALLOC failed\n");
+#endif /* ENCDEBUG */
+ return ENOBUFS;
+ }
+
+ MALLOC(buffer, caddr_t,
+ (txd.amx_keylen < blocklen ? blocklen : txd.amx_keylen),
+ M_TEMP, M_WAITOK);
+ if (buffer == NULL)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ah_new_init(): MALLOC failed\n");
+#endif /* ENCDEBUG */
+ free(tdbp->tdb_xdata, M_XDATA);
+ return ENOBUFS;
+ }
+
+ bzero(buffer, (txd.amx_keylen < blocklen ? blocklen : txd.amx_keylen));
+ bzero(tdbp->tdb_xdata, sizeof(struct ah_new_xdata));
+ xd = (struct ah_new_xdata *) tdbp->tdb_xdata;
+
+ /* Copy the key to the buffer */
+ m_copydata(m, EMT_SETSPI_FLEN + AH_NEW_XENCAP_LEN, txd.amx_keylen, buffer);
+
+ /* Shorten the key if necessary */
+ if (txd.amx_keylen > blocklen)
+ {
+ switch (txd.amx_hash_algorithm)
+ {
+ case ALG_AUTH_MD5:
+ MD5Init(&(xd->amx_md5_ictx));
+ MD5Update(&(xd->amx_md5_ictx), buffer, txd.amx_keylen);
+ bzero(buffer,
+ (txd.amx_keylen < blocklen ? blocklen : txd.amx_keylen));
+ MD5Final(buffer, &(xd->amx_md5_ictx));
+ break;
+
+ case ALG_AUTH_SHA1:
+ SHA1Init(&(xd->amx_sha1_ictx));
+ SHA1Update(&(xd->amx_sha1_ictx), buffer, txd.amx_keylen);
+ bzero(buffer,
+ (txd.amx_keylen < blocklen ? blocklen : txd.amx_keylen));
+ SHA1Final(buffer, &(xd->amx_sha1_ictx));
+ break;
+ }
+ }
+
+ /* Pointer to the transform */
+ tdbp->tdb_xform = xsp;
+
+ xd->amx_hash_algorithm = txd.amx_hash_algorithm;
+ xd->amx_rpl = AH_HMAC_INITIAL_RPL;
+ xd->amx_wnd = txd.amx_wnd;
+ xd->amx_bitmap = 0;
+
+ /* Precompute the I and O pads of the HMAC */
+ for (i = 0; i < blocklen; i++)
+ buffer[i] ^= HMAC_IPAD_VAL;
+
+ switch (xd->amx_hash_algorithm)
+ {
+ case ALG_AUTH_MD5:
+ MD5Init(&(xd->amx_md5_ictx));
+ MD5Update(&(xd->amx_md5_ictx), buffer, blocklen);
+ break;
+
+ case ALG_AUTH_SHA1:
+ SHA1Init(&(xd->amx_sha1_ictx));
+ SHA1Update(&(xd->amx_sha1_ictx), buffer, blocklen);
+ break;
+ }
+
+ for (i = 0; i < blocklen; i++)
+ buffer[i] ^= (HMAC_IPAD_VAL ^ HMAC_IPAD_VAL);
+
+ switch (xd->amx_hash_algorithm)
+ {
+ case ALG_AUTH_MD5:
+ MD5Init(&(xd->amx_md5_octx));
+ MD5Update(&(xd->amx_md5_octx), buffer, blocklen);
+ break;
+
+ case ALG_AUTH_SHA1:
+ SHA1Init(&(xd->amx_sha1_octx));
+ SHA1Update(&(xd->amx_sha1_octx), buffer, blocklen);
+ break;
+ }
+
+ bzero(buffer, blocklen); /* paranoid */
+ free(buffer, M_TEMP);
+
+ bzero(ipseczeroes, IPSEC_ZEROES_SIZE); /* paranoid */
+
+ return 0;
+}
+
+/* Free memory */
+int
+ah_new_zeroize(struct tdb *tdbp)
+{
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ah_new_zeroize(): freeing memory\n");
+#endif /* ENCDEBUG */
+ FREE(tdbp->tdb_xdata, M_XDATA);
+ return 0;
+}
+
+/*
+ * ah_new_input() gets called to verify that an input packet
+ * passes authentication.
+ */
+
+struct mbuf *
+ah_new_input(struct mbuf *m, struct tdb *tdb)
+{
+ struct ah_new_xdata *xd;
+ struct ip *ip, ipo;
+ struct ah_new *aho, *ah;
+ struct ifnet *rcvif;
+ int ohlen, len, count, off, errc;
+ u_int32_t btsx;
+ struct mbuf *m0;
+ MD5_CTX md5ctx;
+ SHA1_CTX sha1ctx;
+ u_int8_t optval;
+ u_char buffer[40];
+
+ aho = (struct ah_new *) buffer;
+
+ xd = (struct ah_new_xdata *) tdb->tdb_xdata;
+
+ switch (xd->amx_hash_algorithm)
+ {
+ case ALG_AUTH_MD5:
+ case ALG_AUTH_SHA1:
+ break;
+
+ default:
+ log(LOG_ALERT,
+ "ah_new_input(): unsupported algorithm %d in SA %x/%08x",
+ xd->amx_hash_algorithm, tdb->tdb_dst, tdb->tdb_spi);
+ m_freem(m);
+ return NULL;
+ }
+
+ ohlen = sizeof(struct ip) + AH_NEW_FLENGTH;
+
+ rcvif = m->m_pkthdr.rcvif;
+ if (rcvif == NULL)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ah_new_input(): receive interface is NULL!!!\n");
+#endif /* ENCDEBUG */
+ rcvif = &enc_softc;
+ }
+
+ if (m->m_len < ohlen)
+ {
+ if ((m = m_pullup(m, ohlen)) == NULL)
+ {
+ ahstat.ahs_hdrops++;
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ah_new_input(): (possibly too short) packet dropped\n");
+#endif /* ENCDEBUG */
+ return NULL;
+ }
+ }
+
+ ip = mtod(m, struct ip *);
+
+ /* Adjust, if options are present */
+ if ((ip->ip_hl << 2) > sizeof(struct ip))
+ {
+ if ((m = m_pullup(m, ohlen - sizeof (struct ip) +
+ (ip->ip_hl << 2))) == NULL)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ah_new_input(): m_pullup() failed\n");
+#endif /* ENCDEBUG */
+ ahstat.ahs_hdrops++;
+ return NULL;
+ }
+
+ ip = mtod(m, struct ip *);
+ ah = (struct ah_new *) ((u_int8_t *) ip + (ip->ip_hl << 2));
+ ohlen += ((ip->ip_hl << 2) - sizeof(struct ip));
+ }
+ else
+ ah = (struct ah_new *) (ip + 1);
+
+ if (ah->ah_hl * sizeof(u_int32_t) != AH_HMAC_HASHLEN)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ah_new_input(): bad authenticator length for packet from %x to %x, spi %08x\n", ip->ip_src, ip->ip_dst, ah->ah_spi);
+#endif /* ENCDEBUG */
+ ahstat.ahs_badauthl++;
+ m_freem(m);
+ return NULL;
+ }
+
+ /* Replay window checking */
+ if (xd->amx_wnd >= 0)
+ {
+ btsx = ntohl(ah->ah_rpl);
+ if ((errc = checkreplaywindow32(btsx, 0, &(xd->amx_rpl), xd->amx_wnd,
+ &(xd->amx_bitmap))) != 0)
+ {
+ switch(errc)
+ {
+ case 1:
+ log(LOG_ERR, "ah_new_input(): replay counter wrapped for packets from %x to %x, spi %08x\n", ip->ip_src, ip->ip_dst, ah->ah_spi);
+ ahstat.ahs_wrap++;
+ break;
+
+ case 2:
+ case 3:
+ log(LOG_WARNING, "ahhmachmd5_input(): duplicate packet received, %x->%x spi %08x", ip->ip_src, ip->ip_dst, ah->ah_spi);
+ ahstat.ahs_replay++;
+ break;
+ }
+
+ m_freem(m);
+ return NULL;
+ }
+ }
+
+ ipo = *ip;
+ ipo.ip_tos = 0;
+ ipo.ip_len += (ip->ip_hl << 2); /* adjusted in ip_intr() */
+ HTONS(ipo.ip_len);
+ HTONS(ipo.ip_id);
+ ipo.ip_off = htons(ipo.ip_off & IP_DF); /* XXX -- and the C bit? */
+ ipo.ip_ttl = 0;
+ ipo.ip_sum = 0;
+
+ switch (xd->amx_hash_algorithm)
+ {
+ case ALG_AUTH_MD5:
+ md5ctx = xd->amx_md5_ictx;
+ MD5Update(&md5ctx, (unsigned char *) &ipo, sizeof(struct ip));
+ break;
+
+ case ALG_AUTH_SHA1:
+ sha1ctx = xd->amx_sha1_ictx;
+ SHA1Update(&sha1ctx, (unsigned char *) &ipo, sizeof(struct ip));
+ break;
+ }
+
+ /* Options */
+ if ((ip->ip_hl << 2 > sizeof(struct ip)))
+ for (off = sizeof(struct ip); off < (ip->ip_hl << 2);)
+ {
+ optval = ((u_int8_t *) ip)[off];
+ switch (optval)
+ {
+ case IPOPT_EOL:
+ switch (xd->amx_hash_algorithm)
+ {
+ case ALG_AUTH_MD5:
+ MD5Update(&md5ctx, ipseczeroes, 1);
+ break;
+
+ case ALG_AUTH_SHA1:
+ SHA1Update(&sha1ctx, ipseczeroes, 1);
+ break;
+ }
+
+ off = ip->ip_hl << 2;
+ break;
+
+ case IPOPT_NOP:
+ switch (xd->amx_hash_algorithm)
+ {
+ case ALG_AUTH_MD5:
+ MD5Update(&md5ctx, ipseczeroes, 1);
+ break;
+
+ case ALG_AUTH_SHA1:
+ SHA1Update(&sha1ctx, ipseczeroes, 1);
+ break;
+ }
+
+ off++;
+ break;
+
+ case IPOPT_SECURITY:
+ case 133:
+ case 134:
+ optval = ((u_int8_t *) ip)[off + 1];
+
+ switch (xd->amx_hash_algorithm)
+ {
+ case ALG_AUTH_MD5:
+ MD5Update(&md5ctx, (u_int8_t *) ip + off, optval);
+ break;
+
+ case ALG_AUTH_SHA1:
+ SHA1Update(&sha1ctx, (u_int8_t *) ip + off, optval);
+ break;
+ }
+
+ off += optval;
+ break;
+
+ default:
+ optval = ((u_int8_t *) ip)[off + 1];
+
+ switch (xd->amx_hash_algorithm)
+ {
+ case ALG_AUTH_MD5:
+ MD5Update(&md5ctx, ipseczeroes, optval);
+ break;
+
+ case ALG_AUTH_SHA1:
+ SHA1Update(&sha1ctx, ipseczeroes, optval);
+ break;
+ }
+
+ off += optval;
+ break;
+ }
+ }
+
+ switch (xd->amx_hash_algorithm)
+ {
+ case ALG_AUTH_MD5:
+ MD5Update(&md5ctx, (unsigned char *) ah, AH_NEW_FLENGTH -
+ AH_HMAC_HASHLEN);
+ MD5Update(&md5ctx, ipseczeroes, AH_HMAC_HASHLEN);
+ break;
+
+ case ALG_AUTH_SHA1:
+ SHA1Update(&sha1ctx, (unsigned char *) ah, AH_NEW_FLENGTH -
+ AH_HMAC_HASHLEN);
+ SHA1Update(&sha1ctx, ipseczeroes, AH_HMAC_HASHLEN);
+ break;
+ }
+
+
+ /*
+ * Code shamelessly stolen from m_copydata
+ */
+ off = ohlen;
+ len = m->m_pkthdr.len - off;
+ m0 = m;
+
+ while (off > 0)
+ {
+ if (m0 == 0)
+ panic("ah_new_input(): m_copydata (off)");
+
+ if (off < m0->m_len)
+ break;
+
+ off -= m0->m_len;
+ m0 = m0->m_next;
+ }
+
+ while (len > 0)
+ {
+ if (m0 == 0)
+ panic("ah_new_input(): m_copydata (copy)");
+
+ count = min(m0->m_len - off, len);
+
+ switch (xd->amx_hash_algorithm)
+ {
+ case ALG_AUTH_MD5:
+ MD5Update(&md5ctx, mtod(m0, unsigned char *) + off, count);
+ break;
+
+ case ALG_AUTH_SHA1:
+ SHA1Update(&sha1ctx, mtod(m0, unsigned char *) + off, count);
+ break;
+ }
+
+ len -= count;
+ off = 0;
+ m0 = m0->m_next;
+ }
+
+ switch (xd->amx_hash_algorithm)
+ {
+ case ALG_AUTH_MD5:
+ MD5Final((unsigned char *) (aho->ah_data), &md5ctx);
+ md5ctx = xd->amx_md5_octx;
+ MD5Update(&md5ctx, (unsigned char *) (aho->ah_data),
+ AH_HMAC_HASHLEN);
+ MD5Final((unsigned char *) (aho->ah_data), &md5ctx);
+ break;
+
+ case ALG_AUTH_SHA1:
+ SHA1Final((unsigned char *) (aho->ah_data), &sha1ctx);
+ sha1ctx = xd->amx_sha1_octx;
+ SHA1Update(&sha1ctx, (unsigned char *) (aho->ah_data),
+ AH_HMAC_HASHLEN);
+ SHA1Final((unsigned char *) (aho->ah_data), &sha1ctx);
+ break;
+ }
+
+
+ if (bcmp(aho->ah_data, ah->ah_data, AH_HMAC_HASHLEN))
+ {
+ log(LOG_ALERT,
+ "ah_new_input(): authentication failed for packet from %x to %x, spi %08x", ip->ip_src, ip->ip_dst, ah->ah_spi);
+ ahstat.ahs_badauth++;
+ m_freem(m);
+ return NULL;
+ }
+
+ ipo = *ip;
+ ipo.ip_p = ah->ah_nh;
+
+ /* Save options */
+ m_copydata(m, sizeof(struct ip), (ip->ip_hl << 2) - sizeof(struct ip),
+ (caddr_t) buffer);
+
+ m->m_len -= AH_NEW_FLENGTH;
+ m->m_data += AH_NEW_FLENGTH;
+ m->m_pkthdr.len -= AH_NEW_FLENGTH;
+ m->m_pkthdr.rcvif = rcvif; /* this should not be necessary */
+
+ ip = mtod(m, struct ip *);
+ *ip = ipo;
+ ip->ip_len = htons(ip->ip_len - AH_NEW_FLENGTH + (ip->ip_hl << 2));
+ HTONS(ip->ip_id);
+ HTONS(ip->ip_off);
+ ip->ip_sum = 0;
+
+ /* Copy the options back */
+ m_copyback(m, sizeof(struct ip), (ip->ip_hl << 2) - sizeof(struct ip),
+ (caddr_t) buffer);
+
+ ip->ip_sum = in_cksum(m, (ip->ip_hl << 2));
+
+ /* Update the counters */
+ tdb->tdb_cur_packets++;
+ tdb->tdb_cur_bytes += ntohs(ip->ip_len) - (ip->ip_hl << 2);
+
+ return m;
+}
+
+int
+ah_new_output(struct mbuf *m, struct sockaddr_encap *gw, struct tdb *tdb,
+ struct mbuf **mp)
+{
+ struct ah_new_xdata *xd;
+ struct ip *ip, ipo;
+ struct ah_new aho, *ah;
+ register int len, off, count;
+ register struct mbuf *m0;
+ MD5_CTX md5ctx;
+ SHA1_CTX sha1ctx;
+ int ilen, ohlen;
+ u_int8_t optval;
+ u_char buffer[AH_ALEN_MAX], opts[40];
+
+ ahstat.ahs_output++;
+ m = m_pullup(m, sizeof(struct ip));
+ if (m == NULL)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ah_new_output(): m_pullup() failed, SA %x/%08x\n",
+ tdb->tdb_dst, tdb->tdb_spi);
+#endif /* ENCDEBUG */
+ return ENOBUFS;
+ }
+
+ ip = mtod(m, struct ip *);
+
+ xd = (struct ah_new_xdata *) tdb->tdb_xdata;
+
+ if ((ip->ip_hl << 2) > sizeof(struct ip))
+ {
+ if ((m = m_pullup(m, ip->ip_hl << 2)) == NULL)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ah_new_output(): m_pullup() failed, SA &x/%08x\n",
+ tdb->tdb_dst, tdb->tdb_spi);
+#endif /* ENCDEBUG */
+ ahstat.ahs_hdrops++;
+ return NULL;
+ }
+
+ ip = mtod(m, struct ip *);
+ }
+
+ /* Save options */
+ m_copydata(m, sizeof(struct ip), (ip->ip_hl << 2) - sizeof(struct ip),
+ (caddr_t) opts);
+
+ switch (xd->amx_hash_algorithm)
+ {
+ case ALG_AUTH_MD5:
+ case ALG_AUTH_SHA1:
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ah_new_output(): using hash algorithm %d\n",
+ xd->amx_hash_algorithm);
+#endif /* ENCDEBUG */
+ break;
+
+ default:
+ log(LOG_ALERT,
+ "ah_new_output(): unsupported algorithm %d in SA %x/%08x",
+ xd->amx_hash_algorithm, tdb->tdb_dst, tdb->tdb_spi);
+ m_freem(m);
+ return NULL;
+ }
+
+ ilen = ntohs(ip->ip_len);
+
+ ohlen = AH_NEW_FLENGTH;
+
+ ipo.ip_v = IPVERSION;
+ ipo.ip_hl = ip->ip_hl;
+ ipo.ip_tos = 0;
+ ipo.ip_len = htons(ohlen + ilen);
+ ipo.ip_id = ip->ip_id;
+ ipo.ip_off = htons(ntohs(ip->ip_off) & IP_DF);
+ ipo.ip_ttl = 0;
+ ipo.ip_p = IPPROTO_AH;
+ ipo.ip_sum = 0;
+ ipo.ip_src = ip->ip_src;
+ ipo.ip_dst = ip->ip_dst;
+
+ bzero(&aho, sizeof(struct ah_new));
+
+ aho.ah_nh = ip->ip_p;
+ aho.ah_hl = (AH_HMAC_HASHLEN >> 2);
+ aho.ah_rv = 0;
+ aho.ah_spi = tdb->tdb_spi;
+
+ if (xd->amx_rpl == 0)
+ {
+ log(LOG_ALERT, "ah_new_output(): SA %x/%0x8 should have expired",
+ tdb->tdb_dst, tdb->tdb_spi);
+ m_freem(m);
+ ahstat.ahs_wrap++;
+ return NULL;
+ }
+
+ aho.ah_rpl = htonl(xd->amx_rpl++);
+
+ switch (xd->amx_hash_algorithm)
+ {
+ case ALG_AUTH_MD5:
+ md5ctx = xd->amx_md5_ictx;
+ MD5Update(&md5ctx, (unsigned char *) &ipo, sizeof(struct ip));
+ break;
+
+ case ALG_AUTH_SHA1:
+ sha1ctx = xd->amx_sha1_ictx;
+ SHA1Update(&sha1ctx, (unsigned char *) &ipo, sizeof(struct ip));
+ break;
+ }
+
+ /* Options */
+ if ((ip->ip_hl << 2) > sizeof(struct ip))
+ for (off = sizeof(struct ip); off < (ip->ip_hl << 2);)
+ {
+ optval = ((u_int8_t *) ip)[off];
+ switch (optval)
+ {
+ case IPOPT_EOL:
+ switch (xd->amx_hash_algorithm)
+ {
+ case ALG_AUTH_MD5:
+ MD5Update(&md5ctx, ipseczeroes, 1);
+ break;
+
+ case ALG_AUTH_SHA1:
+ SHA1Update(&sha1ctx, ipseczeroes, 1);
+ break;
+ }
+
+ off = ip->ip_hl << 2;
+ break;
+
+ case IPOPT_NOP:
+ switch (xd->amx_hash_algorithm)
+ {
+ case ALG_AUTH_MD5:
+ MD5Update(&md5ctx, ipseczeroes, 1);
+ break;
+
+ case ALG_AUTH_SHA1:
+ SHA1Update(&sha1ctx, ipseczeroes, 1);
+ break;
+ }
+
+ off++;
+ break;
+
+ case IPOPT_SECURITY:
+ case 133:
+ case 134:
+ optval = ((u_int8_t *) ip)[off + 1];
+
+ switch (xd->amx_hash_algorithm)
+ {
+ case ALG_AUTH_MD5:
+ MD5Update(&md5ctx, (u_int8_t *) ip + off, optval);
+ break;
+
+ case ALG_AUTH_SHA1:
+ SHA1Update(&sha1ctx, (u_int8_t *) ip + off, optval);
+ break;
+ }
+
+ off += optval;
+ break;
+
+ default:
+ optval = ((u_int8_t *) ip)[off + 1];
+
+ switch (xd->amx_hash_algorithm)
+ {
+ case ALG_AUTH_MD5:
+ MD5Update(&md5ctx, ipseczeroes, optval);
+ break;
+
+ case ALG_AUTH_SHA1:
+ SHA1Update(&sha1ctx, ipseczeroes, optval);
+ break;
+ }
+
+ off += optval;
+ break;
+ }
+ }
+
+ switch (xd->amx_hash_algorithm)
+ {
+ case ALG_AUTH_MD5:
+ MD5Update(&md5ctx, (unsigned char *) &aho, AH_NEW_FLENGTH);
+ break;
+
+ case ALG_AUTH_SHA1:
+ SHA1Update(&sha1ctx, (unsigned char *) &aho, AH_NEW_FLENGTH);
+ break;
+ }
+
+ off = ip->ip_hl << 2;
+
+ /*
+ * Code shamelessly stolen from m_copydata
+ */
+ len = m->m_pkthdr.len - off;
+
+ m0 = m;
+
+ while (len > 0)
+ {
+ if (m0 == 0)
+ panic("ah_new_output(): m_copydata");
+ count = min(m0->m_len - off, len);
+
+ switch (xd->amx_hash_algorithm)
+ {
+ case ALG_AUTH_MD5:
+ MD5Update(&md5ctx, mtod(m0, unsigned char *) + off, count);
+ break;
+
+ case ALG_AUTH_SHA1:
+ SHA1Update(&sha1ctx, mtod(m0, unsigned char *) + off, count);
+ break;
+ }
+
+ len -= count;
+ off = 0;
+ m0 = m0->m_next;
+ }
+
+ ipo.ip_tos = ip->ip_tos;
+ ipo.ip_id = ip->ip_id;
+ ipo.ip_off = ip->ip_off;
+ ipo.ip_ttl = ip->ip_ttl;
+/* ipo.ip_len = ntohs(ipo.ip_len); */
+
+ M_PREPEND(m, ohlen, M_DONTWAIT);
+ if (m == NULL)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ah_new_output(): M_PREPEND() failed for packet from %x to %x, spi %08x\n", ipo.ip_src, ipo.ip_dst, tdb->tdb_spi);
+#endif /* ENCDEBUG */
+ return ENOBUFS;
+ }
+
+ m = m_pullup(m, ohlen + (ipo.ip_hl << 2));
+ if (m == NULL)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ah_new_output(): m_pullup() failed for packet from %x to %x, spi %08x\n", ipo.ip_src, ipo.ip_dst, tdb->tdb_spi);
+#endif /* ENCDEBUG */
+ return ENOBUFS;
+ }
+
+ ip = mtod(m, struct ip *);
+ ah = (struct ah_new *) ((u_int8_t *) ip + (ipo.ip_hl << 2));
+ *ip = ipo;
+ ah->ah_nh = aho.ah_nh;
+ ah->ah_hl = aho.ah_hl;
+ ah->ah_rv = aho.ah_rv;
+ ah->ah_spi = aho.ah_spi;
+ ah->ah_rpl = aho.ah_rpl;
+
+ switch (xd->amx_hash_algorithm)
+ {
+ case ALG_AUTH_MD5:
+ MD5Final(buffer, &md5ctx);
+ md5ctx = xd->amx_md5_octx;
+ MD5Update(&md5ctx, buffer, AH_MD5_ALEN);
+ MD5Final(buffer, &md5ctx);
+ break;
+
+ case ALG_AUTH_SHA1:
+ SHA1Final(buffer, &sha1ctx);
+ sha1ctx = xd->amx_sha1_octx;
+ SHA1Update(&sha1ctx, buffer, AH_SHA1_ALEN);
+ SHA1Final(buffer, &sha1ctx);
+ break;
+ }
+
+ /* Restore the options */
+ m_copyback(m, sizeof(struct ip), (ip->ip_hl << 2) - sizeof(struct ip),
+ (caddr_t) opts);
+
+ /* Copy the authenticator */
+ bcopy(buffer, ah->ah_data, AH_HMAC_HASHLEN);
+
+ *mp = m;
+
+ /* Update the counters */
+ tdb->tdb_cur_packets++;
+ tdb->tdb_cur_bytes += ip->ip_len - (ip->ip_hl << 2) - AH_NEW_FLENGTH;
+
+ return 0;
+}
diff --git a/sys/netinet/ip_ah_old.c b/sys/netinet/ip_ah_old.c
new file mode 100644
index 00000000000..0cf653c62b1
--- /dev/null
+++ b/sys/netinet/ip_ah_old.c
@@ -0,0 +1,778 @@
+
+/*
+ * The author of this code is John Ioannidis, ji@tla.org,
+ * (except when noted otherwise).
+ *
+ * This code was written for BSD/OS in Athens, Greece, in November 1995.
+ *
+ * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
+ * by Angelos D. Keromytis, kermit@forthnet.gr.
+ *
+ * Copyright (C) 1995, 1996, 1997 by John Ioannidis and Angelos D. Keromytis.
+ *
+ * Permission to use, copy, and modify this software without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, NEITHER AUTHOR MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+/*
+ * Authentication Header Processing
+ * Per RFCs 1828/1852 (Metzger & Simpson)
+ */
+
+#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 <machine/cpu.h>
+
+#include <net/if.h>
+#include <net/route.h>
+#include <net/netisr.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/in_pcb.h>
+#include <netinet/in_var.h>
+#include <netinet/ip_var.h>
+#include <netinet/ip_icmp.h>
+
+#include <sys/socketvar.h>
+#include <net/raw_cb.h>
+#include <net/encap.h>
+
+#include <netinet/ip_ipsp.h>
+#include <netinet/ip_ah.h>
+#include <sys/syslog.h>
+
+/*
+ * ah_old_attach() is called from the transformation initialization code.
+ */
+
+int
+ah_old_attach()
+{
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ah_old_attach(): setting up\n");
+#endif /* ENCDEBUG */
+ return 0;
+}
+
+/*
+ * ah_old_init() is called when an SPI is being set up. It interprets the
+ * encap_msghdr present in m, and sets up the transformation data.
+ */
+
+int
+ah_old_init(struct tdb *tdbp, struct xformsw *xsp, struct mbuf *m)
+{
+ struct ah_old_xencap xenc;
+ struct ah_old_xdata *xd;
+ struct encap_msghdr *em;
+
+ if (m->m_len < ENCAP_MSG_FIXED_LEN)
+ {
+ if ((m = m_pullup(m, ENCAP_MSG_FIXED_LEN)) == NULL)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ah_old_init(): m_pullup failed\n");
+#endif /* ENCDEBUG */
+ return ENOBUFS;
+ }
+ }
+
+ em = mtod(m, struct encap_msghdr *);
+ if (em->em_msglen - EMT_SETSPI_FLEN <= AH_OLD_XENCAP_LEN)
+ {
+ log(LOG_WARNING, "ah_old_init(): initialization failed");
+ return EINVAL;
+ }
+
+ /* Just copy the standard fields */
+ m_copydata(m, EMT_SETSPI_FLEN, AH_OLD_XENCAP_LEN, (caddr_t) &xenc);
+
+ /* Check whether the hash algorithm is supported */
+ switch (xenc.amx_hash_algorithm)
+ {
+ case ALG_AUTH_MD5:
+ case ALG_AUTH_SHA1:
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ah_old_init(): initialized TDB with hash algorithm %d\n",
+ xenc.amx_hash_algorithm);
+#endif /* ENCDEBUG */
+ break;
+
+ default:
+ log(LOG_WARNING, "ah_old_init(): unsupported authentication algorithm %d specified", xenc.amx_hash_algorithm);
+ m_freem(m);
+ return EINVAL;
+ }
+
+ if (xenc.amx_keylen + EMT_SETSPI_FLEN + AH_OLD_XENCAP_LEN != em->em_msglen)
+ {
+ log(LOG_WARNING, "ah_old_init(): message length (%d) doesn't match",
+ em->em_msglen);
+ return EINVAL;
+ }
+
+ MALLOC(tdbp->tdb_xdata, caddr_t, sizeof(struct ah_old_xdata) +
+ xenc.amx_keylen, M_XDATA, M_WAITOK);
+ if (tdbp->tdb_xdata == NULL)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ah_old_init(): MALLOC() failed\n");
+#endif /* ENCDEBUG */
+ return ENOBUFS;
+ }
+
+ bzero(tdbp->tdb_xdata, sizeof(struct ah_old_xdata) + xenc.amx_keylen);
+ xd = (struct ah_old_xdata *) tdbp->tdb_xdata;
+
+ /* Pointer to the transform */
+ tdbp->tdb_xform = xsp;
+
+ xd->amx_keylen = xenc.amx_keylen;
+ xd->amx_hash_algorithm = xenc.amx_hash_algorithm;
+
+ /* Copy the key material */
+ m_copydata(m, EMT_SETSPI_FLEN + AH_OLD_XENCAP_LEN, xd->amx_keylen,
+ (caddr_t) xd->amx_key);
+
+ /* Save us some time in processing */
+ switch (xd->amx_hash_algorithm)
+ {
+ case ALG_AUTH_MD5:
+ MD5Init(&(xd->amx_md5_ctx));
+ MD5Update(&(xd->amx_md5_ctx), xd->amx_key, xd->amx_keylen);
+ MD5Final(NULL, &(xd->amx_md5_ctx));
+ break;
+
+ case ALG_AUTH_SHA1:
+ SHA1Init(&(xd->amx_sha1_ctx));
+ SHA1Update(&(xd->amx_sha1_ctx), xd->amx_key, xd->amx_keylen);
+ SHA1Final(NULL, &(xd->amx_sha1_ctx));
+ break;
+ }
+
+ bzero(ipseczeroes, IPSEC_ZEROES_SIZE); /* paranoid */
+
+ return 0;
+}
+
+/*
+ * Free memory
+ */
+
+int
+ah_old_zeroize(struct tdb *tdbp)
+{
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ah_old_zeroize(): freeing memory\n");
+#endif /* ENCDEBUG */
+ FREE(tdbp->tdb_xdata, M_XDATA);
+ return 0;
+}
+
+/*
+ * ah_old_input() gets called to verify that an input packet
+ * passes authentication.
+ */
+
+struct mbuf *
+ah_old_input(struct mbuf *m, struct tdb *tdb)
+{
+ struct ah_old_xdata *xd;
+ struct ip *ip, ipo;
+ struct ah_old *ah, *aho;
+ struct ifnet *rcvif;
+ int ohlen, len, count, off, alen;
+ struct mbuf *m0;
+ MD5_CTX md5ctx;
+ SHA1_CTX sha1ctx;
+ u_int8_t optval;
+ u_char buffer[40];
+
+ aho = (struct ah_old *) buffer;
+
+ xd = (struct ah_old_xdata *) tdb->tdb_xdata;
+
+ switch (xd->amx_hash_algorithm)
+ {
+ case ALG_AUTH_MD5:
+ alen = AH_MD5_ALEN;
+ break;
+
+ case ALG_AUTH_SHA1:
+ alen = AH_SHA1_ALEN;
+ break;
+
+ default:
+ log(LOG_ALERT,
+ "ah_old_input(): unsupported algorithm %d in SA %x/%08x",
+ xd->amx_hash_algorithm, tdb->tdb_dst, tdb->tdb_spi);
+ m_freem(m);
+ return NULL;
+ }
+
+ ohlen = sizeof(struct ip) + AH_OLD_FLENGTH + alen;
+
+ rcvif = m->m_pkthdr.rcvif;
+ if (rcvif == NULL)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ah_old_input(): receive interface is NULL!\n");
+#endif /* ENCDEBUG */
+ rcvif = &enc_softc;
+ }
+
+ if (m->m_len < ohlen)
+ {
+ if ((m = m_pullup(m, ohlen)) == NULL)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ah_old_input(): m_pullup() failed\n");
+#endif /* ENCDEBUG */
+ ahstat.ahs_hdrops++;
+ return NULL;
+ }
+ }
+
+ ip = mtod(m, struct ip *);
+
+ if ((ip->ip_hl << 2) > sizeof(struct ip))
+ {
+ if ((m = m_pullup(m, ohlen - sizeof (struct ip) +
+ (ip->ip_hl << 2))) == NULL)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ah_old_input(): m_pullup() failed\n");
+#endif /* ENCDEBUG */
+ ahstat.ahs_hdrops++;
+ return NULL;
+ }
+
+ ip = mtod(m, struct ip *);
+ ah = (struct ah_old *)((u_int8_t *) ip + (ip->ip_hl << 2));
+ ohlen += ((ip->ip_hl << 2) - sizeof(struct ip));
+ }
+ else
+ ah = (struct ah_old *) (ip + 1);
+
+ ipo = *ip;
+ ipo.ip_tos = 0;
+ ipo.ip_len += (ip->ip_hl << 2); /* adjusted in ip_intr() */
+ HTONS(ipo.ip_len);
+ HTONS(ipo.ip_id);
+ ipo.ip_off = htons(ipo.ip_off & IP_DF); /* XXX -- and the C bit? */
+ ipo.ip_ttl = 0;
+ ipo.ip_sum = 0;
+
+ switch (xd->amx_hash_algorithm)
+ {
+ case ALG_AUTH_MD5:
+ md5ctx = xd->amx_md5_ctx;
+ MD5Update(&md5ctx, (unsigned char *) &ipo, sizeof(struct ip));
+ break;
+
+ case ALG_AUTH_SHA1:
+ sha1ctx = xd->amx_sha1_ctx;
+ SHA1Update(&sha1ctx, (unsigned char *) &ipo, sizeof(struct ip));
+ break;
+ }
+
+ /* Options */
+ if ((ip->ip_hl << 2) > sizeof(struct ip))
+ for (off = sizeof(struct ip); off < (ip->ip_hl << 2);)
+ {
+ optval = ((u_int8_t *) ip)[off];
+ switch (optval)
+ {
+ case IPOPT_EOL:
+ switch (xd->amx_hash_algorithm)
+ {
+ case ALG_AUTH_MD5:
+ MD5Update(&md5ctx, ipseczeroes, 1);
+ break;
+
+ case ALG_AUTH_SHA1:
+ SHA1Update(&sha1ctx, ipseczeroes, 1);
+ break;
+ }
+
+ off = ip->ip_hl << 2;
+ break;
+
+ case IPOPT_NOP:
+ switch (xd->amx_hash_algorithm)
+ {
+ case ALG_AUTH_MD5:
+ MD5Update(&md5ctx, ipseczeroes, 1);
+ break;
+
+ case ALG_AUTH_SHA1:
+ SHA1Update(&sha1ctx, ipseczeroes, 1);
+ break;
+ }
+
+ off++;
+ break;
+
+ case IPOPT_SECURITY:
+ case 133:
+ case 134:
+ optval = ((u_int8_t *) ip)[off + 1];
+
+ switch (xd->amx_hash_algorithm)
+ {
+ case ALG_AUTH_MD5:
+ MD5Update(&md5ctx, (u_int8_t *) ip + off, optval);
+ break;
+
+ case ALG_AUTH_SHA1:
+ SHA1Update(&sha1ctx, (u_int8_t *) ip + off, optval);
+ break;
+ }
+
+ off += optval;
+ break;
+
+ default:
+ optval = ((u_int8_t *) ip)[off + 1];
+
+ switch (xd->amx_hash_algorithm)
+ {
+ case ALG_AUTH_MD5:
+ MD5Update(&md5ctx, ipseczeroes, optval);
+ break;
+
+ case ALG_AUTH_SHA1:
+ SHA1Update(&sha1ctx, ipseczeroes, optval);
+ break;
+ }
+
+ off += optval;
+ break;
+ }
+ }
+
+
+ switch (xd->amx_hash_algorithm)
+ {
+ case ALG_AUTH_MD5:
+ MD5Update(&md5ctx, (unsigned char *) ah, AH_OLD_FLENGTH);
+ MD5Update(&md5ctx, ipseczeroes, AH_MD5_ALEN);
+ break;
+
+ case ALG_AUTH_SHA1:
+ SHA1Update(&sha1ctx, (unsigned char *) ah, AH_OLD_FLENGTH);
+ SHA1Update(&sha1ctx, ipseczeroes, AH_SHA1_ALEN);
+ break;
+ }
+
+ /*
+ * Code shamelessly stolen from m_copydata
+ */
+ off = ohlen;
+ len = m->m_pkthdr.len - off;
+ m0 = m;
+
+ while (off > 0)
+ {
+ if (m0 == 0)
+ panic("ah_old_input(): m_copydata (off)");
+
+ if (off < m0->m_len)
+ break;
+
+ off -= m0->m_len;
+ m0 = m0->m_next;
+ }
+
+ while (len > 0)
+ {
+ if (m0 == 0)
+ panic("ah_old_input(): m_copydata (copy)");
+
+ count = min(m0->m_len - off, len);
+
+ switch (xd->amx_hash_algorithm)
+ {
+ case ALG_AUTH_MD5:
+ MD5Update(&md5ctx, mtod(m0, unsigned char *) + off, count);
+ break;
+
+ case ALG_AUTH_SHA1:
+ SHA1Update(&sha1ctx, mtod(m0, unsigned char *) + off, count);
+ }
+
+ len -= count;
+ off = 0;
+ m0 = m0->m_next;
+ }
+
+ switch (xd->amx_hash_algorithm)
+ {
+ case ALG_AUTH_MD5:
+ MD5Update(&md5ctx, (unsigned char *) xd->amx_key, xd->amx_keylen);
+ MD5Final((unsigned char *) (aho->ah_data), &md5ctx);
+ break;
+
+ case ALG_AUTH_SHA1:
+ SHA1Update(&sha1ctx, (unsigned char *) xd->amx_key, xd->amx_keylen);
+ SHA1Final((unsigned char *) (aho->ah_data), &sha1ctx);
+ break;
+ }
+
+ if (bcmp(aho->ah_data, ah->ah_data, alen))
+ {
+ log(LOG_ALERT, "ah_old_input(): authentication failed for packet from %x to %x, spi %08x", ipo.ip_src, ipo.ip_dst, tdb->tdb_spi);
+ ahstat.ahs_badauth++;
+ m_freem(m);
+ return NULL;
+ }
+
+ ipo = *ip;
+ ipo.ip_p = ah->ah_nh;
+
+ /* Save options */
+ m_copydata(m, sizeof(struct ip), (ip->ip_hl << 2) - sizeof(struct ip),
+ (caddr_t) buffer);
+
+ m->m_len -= (AH_OLD_FLENGTH + alen);
+ m->m_data += (AH_OLD_FLENGTH + alen);
+ m->m_pkthdr.len -= (AH_OLD_FLENGTH + alen);
+ m->m_pkthdr.rcvif = rcvif; /* this should not be necessary */
+
+ ip = mtod(m, struct ip *);
+ *ip = ipo;
+ ip->ip_len = htons(ip->ip_len - AH_OLD_FLENGTH - alen + (ip->ip_hl << 2));
+ HTONS(ip->ip_id);
+ HTONS(ip->ip_off);
+ ip->ip_sum = 0;
+
+ /* Copy the options back */
+ m_copyback(m, sizeof(struct ip), (ip->ip_hl << 2) - sizeof(struct ip),
+ (caddr_t) buffer);
+
+ ip->ip_sum = in_cksum(m, (ip->ip_hl << 2));
+
+ /* Update the counters */
+ tdb->tdb_cur_packets++;
+ tdb->tdb_cur_bytes += ntohs(ip->ip_len) - (ip->ip_hl << 2);
+
+ return m;
+}
+
+int
+ah_old_output(struct mbuf *m, struct sockaddr_encap *gw, struct tdb *tdb,
+ struct mbuf **mp)
+{
+ struct ah_old_xdata *xd;
+ struct ip *ip, ipo;
+ struct ah_old *ah, aho;
+ register int len, off, count;
+ register struct mbuf *m0;
+ MD5_CTX md5ctx;
+ SHA1_CTX sha1ctx;
+ int ilen, ohlen, alen;
+ u_int8_t optval;
+ u_char opts[40];
+
+ ahstat.ahs_output++;
+ m = m_pullup(m, sizeof(struct ip));
+ if (m == NULL)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ah_old_output(): m_pullup() failed, SA %x/%08x\n",
+ tdb->tdb_dst, tdb->tdb_spi);
+#endif /* ENCDEBUG */
+ return ENOBUFS;
+ }
+
+ ip = mtod(m, struct ip *);
+
+ xd = (struct ah_old_xdata *) tdb->tdb_xdata;
+
+ if ((ip->ip_hl << 2) > sizeof(struct ip))
+ {
+ if ((m = m_pullup(m, ip->ip_hl << 2)) == NULL)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ah_old_output(): m_pullup() failed, SA &x/%08x\n",
+ tdb->tdb_dst, tdb->tdb_spi);
+#endif /* ENCDEBUG */
+ ahstat.ahs_hdrops++;
+ return NULL;
+ }
+
+ ip = mtod(m, struct ip *);
+ }
+
+ switch (xd->amx_hash_algorithm)
+ {
+ case ALG_AUTH_MD5:
+ alen = AH_MD5_ALEN;
+ break;
+
+ case ALG_AUTH_SHA1:
+ alen = AH_SHA1_ALEN;
+ break;
+
+ default:
+ log(LOG_ALERT,
+ "ah_old_output(): unsupported algorithm %d in SA %x/%08x",
+ xd->amx_hash_algorithm, tdb->tdb_dst, tdb->tdb_spi);
+ m_freem(m);
+ return NULL;
+ }
+
+ /* Save the options */
+ m_copydata(m, sizeof(struct ip), (ip->ip_hl << 2) - sizeof(struct ip),
+ (caddr_t) opts);
+
+ ilen = ntohs(ip->ip_len);
+
+ ohlen = AH_OLD_FLENGTH + alen;
+
+ ipo.ip_v = IPVERSION;
+ ipo.ip_hl = ip->ip_hl;
+ ipo.ip_tos = 0;
+ ipo.ip_len = htons(ohlen + ilen);
+ ipo.ip_id = ip->ip_id;
+ ipo.ip_off = htons(ntohs(ip->ip_off) & IP_DF);
+ ipo.ip_ttl = 0;
+ ipo.ip_p = IPPROTO_AH;
+ ipo.ip_sum = 0;
+ ipo.ip_src = ip->ip_src;
+ ipo.ip_dst = ip->ip_dst;
+
+ aho.ah_nh = ip->ip_p;
+ aho.ah_hl = alen >> 2;
+ aho.ah_rv = 0;
+ aho.ah_spi = tdb->tdb_spi;
+
+ switch (xd->amx_hash_algorithm)
+ {
+ case ALG_AUTH_MD5:
+ md5ctx = xd->amx_md5_ctx;
+ MD5Update(&md5ctx, (unsigned char *) &ipo, sizeof(struct ip));
+ break;
+
+ case ALG_AUTH_SHA1:
+ sha1ctx = xd->amx_sha1_ctx;
+ SHA1Update(&sha1ctx, (unsigned char *) &ipo, sizeof(struct ip));
+ break;
+ }
+
+ /* Options */
+ if ((ip->ip_hl << 2) > sizeof(struct ip))
+ for (off = sizeof(struct ip); off < (ip->ip_hl << 2);)
+ {
+ optval = ((u_int8_t *) ip)[off];
+ switch (optval)
+ {
+ case IPOPT_EOL:
+ switch (xd->amx_hash_algorithm)
+ {
+ case ALG_AUTH_MD5:
+ MD5Update(&md5ctx, ipseczeroes, 1);
+ break;
+
+ case ALG_AUTH_SHA1:
+ SHA1Update(&sha1ctx, ipseczeroes, 1);
+ break;
+ }
+
+ off = ip->ip_hl << 2;
+ break;
+
+ case IPOPT_NOP:
+ switch (xd->amx_hash_algorithm)
+ {
+ case ALG_AUTH_MD5:
+ MD5Update(&md5ctx, ipseczeroes, 1);
+ break;
+
+ case ALG_AUTH_SHA1:
+ SHA1Update(&sha1ctx, ipseczeroes, 1);
+ break;
+ }
+
+ off++;
+ break;
+
+ case IPOPT_SECURITY:
+ case 133:
+ case 134:
+ optval = ((u_int8_t *) ip)[off + 1];
+
+ switch (xd->amx_hash_algorithm)
+ {
+ case ALG_AUTH_MD5:
+ MD5Update(&md5ctx, (u_int8_t *) ip + off, optval);
+ break;
+
+ case ALG_AUTH_SHA1:
+ SHA1Update(&sha1ctx, (u_int8_t *) ip + off, optval);
+ break;
+ }
+
+ off += optval;
+ break;
+
+ default:
+ optval = ((u_int8_t *) ip)[off + 1];
+
+ switch (xd->amx_hash_algorithm)
+ {
+ case ALG_AUTH_MD5:
+ MD5Update(&md5ctx, ipseczeroes, optval);
+ break;
+
+ case ALG_AUTH_SHA1:
+ SHA1Update(&sha1ctx, ipseczeroes, optval);
+ break;
+ }
+
+ off += optval;
+ break;
+ }
+ }
+
+ switch (xd->amx_hash_algorithm)
+ {
+ case ALG_AUTH_MD5:
+ MD5Update(&md5ctx, (unsigned char *) &aho, AH_OLD_FLENGTH);
+ MD5Update(&md5ctx, ipseczeroes, alen);
+ break;
+
+ case ALG_AUTH_SHA1:
+ SHA1Update(&sha1ctx, (unsigned char *) &aho, AH_OLD_FLENGTH);
+ SHA1Update(&sha1ctx, ipseczeroes, alen);
+ break;
+ }
+
+ /* Skip the IP header and any options */
+ off = ip->ip_hl << 2;
+
+ /*
+ * Code shamelessly stolen from m_copydata
+ */
+ len = m->m_pkthdr.len - off;
+
+ m0 = m;
+
+ while (len > 0)
+ {
+ if (m0 == 0)
+ panic("ah_old_output(): m_copydata()");
+ count = min(m0->m_len - off, len);
+
+ switch (xd->amx_hash_algorithm)
+ {
+ case ALG_AUTH_MD5:
+ MD5Update(&md5ctx, mtod(m0, unsigned char *) + off, count);
+ break;
+
+ case ALG_AUTH_SHA1:
+ SHA1Update(&sha1ctx, mtod(m0, unsigned char *) + off, count);
+ break;
+ }
+
+ len -= count;
+ off = 0;
+ m0 = m0->m_next;
+ }
+
+ switch (xd->amx_hash_algorithm)
+ {
+ case ALG_AUTH_MD5:
+ MD5Update(&md5ctx, (unsigned char *) xd->amx_key, xd->amx_keylen);
+ break;
+
+ case ALG_AUTH_SHA1:
+ SHA1Update(&sha1ctx, (unsigned char *) xd->amx_key, xd->amx_keylen);
+ break;
+ }
+
+ ipo.ip_tos = ip->ip_tos;
+ ipo.ip_id = ip->ip_id;
+ ipo.ip_off = ip->ip_off;
+ ipo.ip_ttl = ip->ip_ttl;
+/* ipo.ip_len = ntohs(ipo.ip_len); */
+
+ M_PREPEND(m, ohlen, M_DONTWAIT);
+ if (m == NULL)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ah_old_output(): M_PREPEND() failed for packet from %x to %x, spi %08x\n", ipo.ip_src, ipo.ip_dst, tdb->tdb_spi);
+#endif /* ENCDEBUG */
+ return ENOBUFS;
+ }
+
+ m = m_pullup(m, ohlen + (ipo.ip_hl << 2));
+ if (m == NULL)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ah_old_output(): m_pullup() failed for packet from %x to %x, spi %08x\n", ipo.ip_src, ipo.ip_dst, tdb->tdb_spi);
+#endif /* ENCDEBUG */
+ return ENOBUFS;
+ }
+
+ ip = mtod(m, struct ip *);
+ ah = (struct ah_old *) ((u_int8_t *) ip + (ipo.ip_hl << 2));
+ *ip = ipo;
+ ah->ah_nh = aho.ah_nh;
+ ah->ah_hl = aho.ah_hl;
+ ah->ah_rv = aho.ah_rv;
+ ah->ah_spi = aho.ah_spi;
+
+ /* Restore the options */
+ m_copyback(m, sizeof(struct ip), (ip->ip_hl << 2) - sizeof(struct ip),
+ (caddr_t) opts);
+
+ switch (xd->amx_hash_algorithm)
+ {
+ case ALG_AUTH_MD5:
+ MD5Final(ah->ah_data, &md5ctx);
+ break;
+
+ case ALG_AUTH_SHA1:
+ SHA1Final(ah->ah_data, &sha1ctx);
+ break;
+ }
+
+ *mp = m;
+
+ /* Update the counters */
+ tdb->tdb_cur_packets++;
+ tdb->tdb_cur_bytes += ip->ip_len - (ip->ip_hl << 2) - AH_OLD_FLENGTH - alen;
+
+ return 0;
+}
diff --git a/sys/netinet/ip_esp.c b/sys/netinet/ip_esp.c
index fc3f12bd412..064e49e5999 100644
--- a/sys/netinet/ip_esp.c
+++ b/sys/netinet/ip_esp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_esp.c,v 1.7 1997/07/01 22:12:45 provos Exp $ */
+/* $OpenBSD: ip_esp.c,v 1.8 1997/07/11 23:37:56 provos Exp $ */
/*
* The author of this code is John Ioannidis, ji@tla.org,
@@ -58,6 +58,7 @@
#include <netinet/ip_icmp.h>
#include <netinet/ip_ipsp.h>
#include <netinet/ip_esp.h>
+#include <sys/syslog.h>
void esp_input __P((struct mbuf *, int));
@@ -68,39 +69,35 @@ void esp_input __P((struct mbuf *, int));
void
esp_input(register struct mbuf *m, int iphlen)
{
- struct ip *ipo;
struct ifqueue *ifq = NULL;
- int s;
- u_int32_t spi;
+ struct ip *ipo, ipn;
struct tdb *tdbp;
+ u_int32_t spi;
+ int s;
espstat.esps_input++;
/*
- * Strip IP options, if any.
- */
-
- if (iphlen > sizeof (struct ip))
- {
- ip_stripoptions(m, (struct mbuf *)0);
- iphlen = sizeof (struct ip);
- }
-
- /*
* Make sure that at least the SPI is in the same mbuf
*/
ipo = mtod(m, struct ip *);
- if (m->m_len < iphlen + ESP_FLENGTH)
+ if (m->m_len < iphlen + sizeof(u_int32_t))
{
- if ((m = m_pullup(m, iphlen + ESP_FLENGTH)) == 0)
+ if ((m = m_pullup(m, iphlen + sizeof(u_int32_t))) == 0)
{
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("esp_input(): (possibly too short) packet from %x to %x dropped\n", ipo->ip_src, ipo->ip_dst);
+#endif /* ENCDEBUG */
espstat.esps_hdrops++;
return;
}
+
ipo = mtod(m, struct ip *);
}
- spi = *((u_int32_t *)((caddr_t)ipo + iphlen));
+
+ spi = *((u_int32_t *) ((caddr_t) ipo + iphlen));
/*
* Find tunnel control block and (indirectly) call the appropriate
@@ -108,13 +105,10 @@ esp_input(register struct mbuf *m, int iphlen)
* IP packet ready to go through input processing.
*/
- tdbp = gettdb(spi, ipo->ip_dst);
+ tdbp = gettdb(spi, ipo->ip_dst, IPPROTO_ESP);
if (tdbp == NULL)
{
-#ifdef ENCDEBUG
- if (encdebug)
- printf("esp_input: no tdb for spi=%x\n", spi);
-#endif ENCDEBUG
+ log(LOG_ERR, "esp_input(): could not find SA for ESP packet from %x to %x, spi %08x", ipo->ip_src, ipo->ip_dst, spi);
m_freem(m);
espstat.esps_notdb++;
return;
@@ -122,10 +116,9 @@ esp_input(register struct mbuf *m, int iphlen)
if (tdbp->tdb_flags & TDBF_INVALID)
{
-#ifdef ENCDEBUG
- if (encdebug);
- printf("esp_input: spi=%x is not longer/yet valid\n", spi);
-#endif
+ log(LOG_ALERT,
+ "esp_input(): attempted to use invalid ESP SA %08x, packet %x->%x",
+ spi, ipo->ip_src, ipo->ip_dst);
m_freem(m);
espstat.esps_invalid++;
return;
@@ -133,10 +126,7 @@ esp_input(register struct mbuf *m, int iphlen)
if (tdbp->tdb_xform == NULL)
{
-#ifdef ENCDEBUG
- if (encdebug)
- printf("esp_input: no xform for spi=%x\n", spi);
-#endif ENCDEBUG
+ log(LOG_ALERT, "esp_input(): attempted to use uninitialized ESP SA %08x, packet from %x to %x", spi, ipo->ip_src, ipo->ip_dst);
m_freem(m);
espstat.esps_noxform++;
return;
@@ -148,11 +138,13 @@ esp_input(register struct mbuf *m, int iphlen)
if (tdbp->tdb_first_use == 0)
tdbp->tdb_first_use = time.tv_sec;
+ ipn = *ipo;
m = (*(tdbp->tdb_xform->xf_input))(m, tdbp);
if (m == NULL)
{
+ log(LOG_ALERT, "esp_input(): processing failed for ESP packet from %x to %x, spi %08x", ipn.ip_src, ipn.ip_dst, spi);
espstat.esps_badkcr++;
return;
}
@@ -171,8 +163,13 @@ esp_input(register struct mbuf *m, int iphlen)
m_freem(m);
espstat.esps_qfull++;
splx(s);
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("esp_input(): dropped packet because of full IP queue\n");
+#endif /* ENCDEBUG */
return;
}
+
IF_ENQUEUE(ifq, m);
schednetisr(NETISR_IP);
splx(s);
diff --git a/sys/netinet/ip_esp.h b/sys/netinet/ip_esp.h
index e7798ff8d04..02122fa2fe7 100644
--- a/sys/netinet/ip_esp.h
+++ b/sys/netinet/ip_esp.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_esp.h,v 1.7 1997/06/25 07:53:24 provos Exp $ */
+/* $OpenBSD: ip_esp.h,v 1.8 1997/07/11 23:37:56 provos Exp $ */
/*
* The author of this code is John Ioannidis, ji@tla.org,
@@ -32,39 +32,24 @@
#include <sys/md5k.h>
#endif
-#define ESPDESMD5_KEYSZ 64
-#define ESPDESMD5_IVS 8
-#define ESPDESMD5_ALEN 16
-#define ESPDESMD5_IPAD_VAL 0x36
-#define ESPDESMD5_OPAD_VAL 0x5C
-#define ESPDESMD5_DESBLK 8
-#define ESPDESMD5_RPLENGTH 4
-#define ESPDESMD5_DPADI 0x5C
-#define ESPDESMD5_DPADR 0x3A
-#define ESPDESMD5_IPADI 0xAC
-#define ESPDESMD5_IPADR 0x55
-#define ESPDESMD5_HPADI 0x53
-#define ESPDESMD5_HPADR 0x3C
-#define ESPDESMD5_RPADI 0x35
-#define ESPDESMD5_RPADR 0xCC
-
-#define ESP3DESMD5_KEYSZ 64
-#define ESP3DESMD5_IVS 8
-#define ESP3DESMD5_ALEN 16
-#define ESP3DESMD5_IPAD_VAL 0x36
-#define ESP3DESMD5_OPAD_VAL 0x5C
-#define ESP3DESMD5_DESBLK 8
-#define ESP3DESMD5_RPLENGTH 4
-#define ESP3DESMD5_DPADI 0x5C
-#define ESP3DESMD5_DPADR 0x3A
-#define ESP3DESMD5_IPADI 0xAC
-#define ESP3DESMD5_IPADR 0x55
-#define ESP3DESMD5_HPADI 0x53
-#define ESP3DESMD5_HPADR 0x3C
-#define ESP3DESMD5_RPADI 0x35
-#define ESP3DESMD5_RPADR 0xCC
-
-struct esp
+#include <netinet/ip_sha1.h>
+
+/* IV lengths */
+#define ESP_DES_IVS 8
+#define ESP_3DES_IVS 8
+
+#define ESP_MAX_IVS ESP_3DES_IVS
+
+/* Block sizes -- it is assumed that they're powers of 2 */
+#define ESP_DES_BLKS 8
+#define ESP_3DES_BLKS 8
+
+/* Various defines for the "new" ESP */
+#define ESP_NEW_ALEN 12 /* 96bits authenticator */
+#define ESP_NEW_IPAD_VAL 0x36
+#define ESP_NEW_OPAD_VAL 0x5C
+
+struct esp_old
{
u_int32_t esp_spi; /* Security Parameters Index */
u_int8_t esp_iv[8]; /* iv[4] may actually be data! */
@@ -86,33 +71,13 @@ struct espstat
u_int32_t esps_invalid; /* Trying to use an invalid TDB */
};
-struct espdes_xdata
-{
- int32_t edx_ivlen; /* 4 or 8 */
- union
- {
- u_int8_t Iv[8]; /* that's enough space */
- u_int32_t Ivl; /* make sure this is 4 bytes */
- u_int64_t Ivq; /* make sure this is 8 bytes! */
- }Iu;
-#define edx_iv Iu.Iv
-#define edx_ivl Iu.Ivl
-#define edx_ivq Iu.Ivq
- union
- {
- u_int8_t Rk[8];
- u_int32_t Eks[16][2];
- }Xu;
-#define edx_rk Xu.Rk
-#define edx_eks Xu.Eks
-};
-
-struct esp3des_xdata
+struct esp_old_xdata
{
- int32_t edx_ivlen; /* 4 or 8 */
+ u_int32_t edx_enc_algorithm;
+ int32_t edx_ivlen; /* 4 or 8 */
union
{
- u_int8_t Iv[8]; /* that's enough space */
+ u_int8_t Iv[ESP_3DES_IVS]; /* that's enough space */
u_int32_t Ivl; /* make sure this is 4 bytes */
u_int64_t Ivq; /* make sure this is 8 bytes! */
}Iu;
@@ -128,61 +93,43 @@ struct esp3des_xdata
#define edx_eks Xu.Eks
};
-struct esp3desmd5_xencap
+struct esp_old_xencap
{
- int8_t edx_ivlen; /* 0 or 8 */
- int8_t edx_initiator; /* 1 if setting an I key */
- u_int16_t edx_keylen;
- u_int32_t edx_wnd;
- u_int8_t edx_ivv[ESP3DESMD5_IVS];
- u_int8_t edx_key[ESP3DESMD5_KEYSZ];
+ u_int32_t edx_enc_algorithm;
+ u_int32_t edx_ivlen;
+ u_int32_t edx_keylen;
+ u_int8_t edx_data[1]; /* IV + key material */
};
-struct espdesmd5_xencap
+#define ESP_OLD_XENCAP_LEN (3 * sizeof(u_int32_t))
+
+struct esp_new_xencap
{
- int8_t edx_ivlen; /* 0 or 8 */
- int8_t edx_initiator; /* 1 if setting an I key */
- u_int16_t edx_keylen;
+ u_int32_t edx_enc_algorithm;
+ u_int32_t edx_hash_algorithm;
+ int32_t edx_ivlen; /* 0 or 8 */
+ u_int32_t edx_keylen;
u_int32_t edx_wnd;
- u_int8_t edx_ivv[ESPDESMD5_IVS];
- u_int8_t edx_key[ESPDESMD5_KEYSZ];
+ u_int32_t edx_flags;
+ u_int8_t edx_data[1]; /* IV + key material */
};
-#define ESPDESMD5_ULENGTH 8+ESPDESMD5_IVS+ESPDESMD5_KEYSZ
-#define ESP3DESMD5_ULENGTH 8+ESP3DESMD5_IVS+ESP3DESMD5_KEYSZ
+#define ESP_NEW_XENCAP_LEN (6 * sizeof(u_int32_t))
-struct espdesmd5_xdata
+#define ESP_NEW_FLAG_AUTH 0x00000001 /* Doing authentication too */
+struct esp_new_xdata
{
- int32_t edx_ivlen; /* 0 or 8 */
- u_int32_t edx_rpl; /* Replay counter */
- u_int32_t edx_wnd; /* Replay window */
+ u_int32_t edx_enc_algorithm;
+ u_int32_t edx_hash_algorithm;
+ int32_t edx_ivlen; /* 0 or 8 */
+ u_int32_t edx_rpl; /* Replay counter */
+ u_int32_t edx_wnd; /* Replay window */
u_int32_t edx_bitmap;
+ u_int32_t edx_flags;
u_int32_t edx_initial; /* initial replay value */
union
{
- u_int8_t Iv[8]; /* that's enough space */
- u_int32_t Ivl; /* make sure this is 4 bytes */
- u_int64_t Ivq; /* make sure this is 8 bytes! */
- }Iu;
- union
- {
- u_int8_t Rk[8];
- u_int32_t Eks[16][2];
- }Xu;
- MD5_CTX edx_ictx;
- MD5_CTX edx_octx;
-};
-
-struct esp3desmd5_xdata
-{
- int32_t edx_ivlen; /* 0 or 4 or 8 */
- u_int32_t edx_rpl; /* Replay counter */
- u_int32_t edx_wnd; /* Replay window */
- u_int32_t edx_bitmap;
- u_int32_t edx_initial;
- union
- {
- u_int8_t Iv[8]; /* that's enough space */
+ u_int8_t Iv[ESP_MAX_IVS]; /* that's enough space */
u_int32_t Ivl; /* make sure this is 4 bytes */
u_int64_t Ivq; /* make sure this is 8 bytes! */
}Iu;
@@ -191,15 +138,28 @@ struct esp3desmd5_xdata
u_int8_t Rk[3][8];
u_int32_t Eks[3][16][2];
}Xu;
- MD5_CTX edx_ictx;
- MD5_CTX edx_octx;
+ union
+ {
+ struct
+ {
+ MD5_CTX edx_ictx;
+ MD5_CTX edx_octx;
+ } MD5stuff;
+ struct
+ {
+ SHA1_CTX edx_ictx;
+ SHA1_CTX edx_octx;
+ } SHA1stuff;
+ } Hashes;
};
-#define ESP_FLENGTH 12
-#define ESP_ULENGTH 20 /* coming from user mode */
+#define edx_md5_ictx Hashes.MD5stuff.edx_ictx
+#define edx_md5_octx Hashes.MD5stuff.edx_octx
+#define edx_sha1_ictx Hashes.SHA1stuff.edx_ictx
+#define edx_sha1_octx Hashes.SHA1stuff.edx_octx
-#ifdef _KERNEL
+#define ESP_OLD_FLENGTH 12
+#ifdef _KERNEL
struct espstat espstat;
-
#endif
diff --git a/sys/netinet/ip_esp_new.c b/sys/netinet/ip_esp_new.c
new file mode 100644
index 00000000000..5c09292ae0b
--- /dev/null
+++ b/sys/netinet/ip_esp_new.c
@@ -0,0 +1,767 @@
+/* $OpenBSD: ip_esp_new.c,v 1.1 1997/07/11 23:37:57 provos Exp $ */
+
+/*
+ * The author of this code is John Ioannidis, ji@tla.org,
+ * (except when noted otherwise).
+ *
+ * This code was written for BSD/OS in Athens, Greece, in November 1995.
+ *
+ * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
+ * by Angelos D. Keromytis, kermit@forthnet.gr.
+ *
+ * Copyright (C) 1995, 1996, 1997 by John Ioannidis and Angelos D. Keromytis.
+ *
+ * Permission to use, copy, and modify this software without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, NEITHER AUTHOR MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+/*
+ * Based on draft-ietf-ipsec-esp-des-md5-03.txt.
+ */
+
+#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 <machine/cpu.h>
+
+#include <net/if.h>
+#include <net/route.h>
+#include <net/netisr.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/in_pcb.h>
+#include <netinet/in_var.h>
+#include <netinet/ip_var.h>
+
+#include <sys/socketvar.h>
+#include <net/raw_cb.h>
+#include <net/encap.h>
+
+#include <netinet/ip_icmp.h>
+#include <netinet/ip_ipsp.h>
+#include <netinet/ip_esp.h>
+#include <sys/syslog.h>
+
+extern void des_ecb3_encrypt(caddr_t, caddr_t, caddr_t, caddr_t, caddr_t, int);
+extern void des_ecb_encrypt(caddr_t, caddr_t, caddr_t, int);
+extern void des_set_key(caddr_t, caddr_t);
+
+int
+esp_new_attach()
+{
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ah_new_attach(): setting up\n");
+#endif /* ENCDEBUG */
+ return 0;
+}
+
+/*
+ * esp_new_init() is called when an SPI is being set up. It interprets the
+ * encap_msghdr present in m, and sets up the transformation data, in
+ * this case, the encryption and decryption key schedules
+ */
+
+int
+esp_new_init(struct tdb *tdbp, struct xformsw *xsp, struct mbuf *m)
+{
+#if 0
+ struct esp_new_xdata *xd;
+ struct esp_new_xencap txd;
+ struct encap_msghdr *em;
+ caddr_t buffer = NULL;
+
+ if (m->m_len < ENCAP_MSG_FIXED_LEN)
+ {
+ if ((m = m_pullup(m, ENCAP_MSG_FIXED_LEN)) == NULL)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("esp_new_init(): m_pullup failed\n");
+#endif /* ENCDEBUG */
+ return ENOBUFS;
+ }
+ }
+
+ em = mtod(m, struct encap_msghdr *);
+ if (em->em_msglen - EMT_SETSPI <= ESP_NEW_XENCAP_LEN)
+ {
+ log(LOG_WARNING, "esp_new_init(): initialization failed");
+ return EINVAL;
+ }
+
+ /* Just copy the standard fields */
+ m_copydata(m, EMT_SETSPI_FLEN, ESP_NEW_XENCAP_LEN, (caddr_t) &txd);
+
+ /* Check wether the encryption algorithm is supported */
+ switch (txd.edx_enc_algorithm)
+ {
+ case ALG_ENC_DES:
+ case ALG_ENC_3DES:
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("esp_new_init(): initialized TDB with enc algorithm %d\n",
+ txd.edx_enc_algorithm);
+#endif /* ENCDEBUG */
+ break;
+
+ default:
+ log(LOG_WARNING, "esp_new_init(): unsupported encryption algorithm %d specified", txd.edx_enc_algorithm);
+ return EINVAL;
+ }
+
+ /* Check whether the encryption algorithm is supported */
+ if (txd.edx_flags & ESP_NEW_FLAG_AUTH)
+ switch (txd.edx_hash_algorithm)
+ {
+ case ALG_AUTH_MD5:
+ case ALG_AUTH_SHA1:
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("esp_new_init(): initialized TDB with hash algorithm %d\n", txd.edx_enc_algorithm);
+#endif /* ENCDEBUG */
+ break;
+
+ default:
+ log(LOG_WARNING, "esp_old_init(): unsupported encryption algorithm %d specified", txd.edx_enc_algorithm);
+ return EINVAL;
+ }
+
+ if (txd.edx_ivlen + txd.edx_keylen + EMT_SETSPI_FLEN + ESP_NEW_XENCAP_LEN
+ != em->em_msglen)
+ {
+ log(LOG_WARNING, "esp_new_init(): message length (%d) doesn't match",
+ em->em_msglen);
+ return EINVAL;
+ }
+
+ /* XXX Check the IV lengths */
+
+ MALLOC(tdbp->tdb_xdata, caddr_t, sizeof(struct esp_new_xdata),
+ M_XDATA, M_WAITOK);
+ if (tdbp->tdb_xdata == NULL)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("esp_new_init(): MALLOC() failed\n");
+#endif /* ENCDEBUG */
+ return ENOBUFS;
+ }
+
+ /* Or larger ? XXX */
+ MALLOC(buffer, caddr_t, txd.edx_keylen, M_TEMP, M_WAITOK);
+ if (buffer == NULL)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("esp_new_init(): MALLOC() failed\n");
+#endif /* ENCDEBUG */
+ free(tdbp->tdb_xdata, M_XDATA);
+ return ENOBUFS;
+ }
+
+ bzero(buffer, txd.edx_keylen);
+ bzero(tdbp->tdb_xdata, sizeof(struct esp_new_xdata));
+ xd = (struct esp_new_xdata *) tdbp->tdb_xdata;
+
+ /* Pointer to the transform */
+ tdbp->tdb_xform = xsp;
+
+#if 0
+ xd->edx_ivlen = txd.edx_ivlen;
+ xd->edx_wnd = txd.edx_wnd;
+
+ /* Fix the IV */
+ if (txd.edx_ivlen)
+ bcopy(txd.edx_ivv, xd->edx_iv, ESPDESMD5_IVS);
+ else
+ {
+ for (len = 0; len < ESPDESMD5_KEYSZ; len++)
+ buf[len] = txd.edx_initiator ? ESPDESMD5_IPADI :
+ ESPDESMD5_IPADR;
+
+ MD5Init(&ctx);
+ MD5Update(&ctx, buf, ESPDESMD5_KEYSZ);
+ MD5Update(&ctx, txd.edx_key, txd.edx_keylen);
+ MD5Final(buf, &ctx);
+ bcopy(buf, xd->edx_iv, ESPDESMD5_IVS);
+ }
+
+ /* DES key */
+
+ MD5Init(&ctx);
+ for (len = 0; len < ESPDESMD5_KEYSZ; len++)
+ buf[len] = txd.edx_initiator ? ESPDESMD5_DPADI : ESPDESMD5_DPADR;
+
+ MD5Update(&ctx, buf, ESPDESMD5_KEYSZ);
+ MD5Update(&ctx, txd.edx_key, txd.edx_keylen);
+ MD5Final(buf, &ctx);
+ des_set_key((caddr_t)buf, (caddr_t)(xd->edx_eks));
+
+ /* HMAC contexts */
+
+ MD5Init(&ctx);
+ for (len = 0; len < ESPDESMD5_KEYSZ; len++)
+ buf[len] = txd.edx_initiator ? ESPDESMD5_HPADI : ESPDESMD5_HPADR;
+
+ MD5Update(&ctx, buf, ESPDESMD5_KEYSZ);
+ MD5Update(&ctx, txd.edx_key, txd.edx_keylen);
+ MD5Final(buf, &ctx);
+
+ bzero(buf + ESPDESMD5_ALEN, ESPDESMD5_KEYSZ - ESPDESMD5_ALEN);
+
+ for (len = 0; len < ESPDESMD5_KEYSZ; len++)
+ buf[len] ^= ESPDESMD5_IPAD_VAL;
+
+ MD5Init(&ctx);
+ MD5Update(&ctx, buf, ESPDESMD5_KEYSZ);
+ xd->edx_ictx = ctx;
+
+ for (len = 0; len < ESPDESMD5_KEYSZ; len++)
+ buf[len] ^= (ESPDESMD5_IPAD_VAL ^ ESPDESMD5_OPAD_VAL);
+
+ MD5Init(&ctx);
+ MD5Update(&ctx, buf, ESPDESMD5_KEYSZ);
+ xd->edx_octx = ctx;
+
+ /* Replay counter */
+
+ for (len = 0; len < ESPDESMD5_KEYSZ; len++)
+ buf[len] = txd.edx_initiator ? ESPDESMD5_RPADI :
+ ESPDESMD5_RPADR;
+
+ MD5Init(&ctx);
+ MD5Update(&ctx, buf, ESPDESMD5_KEYSZ);
+ MD5Update(&ctx, txd.edx_key, txd.edx_keylen);
+ MD5Final(buf, &ctx);
+ bcopy(buf, (unsigned char *)&(xd->edx_rpl), ESPDESMD5_RPLENGTH);
+ xd->edx_initial = xd->edx_rpl - 1;
+
+ bzero(&ctx, sizeof(MD5_CTX));
+
+ bzero(buffer, txd.edx_keylen); /* fix XXX */
+ free(buffer, M_TEMP);
+#endif
+
+ bzero(ipseczeroes, IPSEC_ZEROES_SIZE); /* paranoid */
+#endif
+ return 0;
+}
+
+int
+esp_new_zeroize(struct tdb *tdbp)
+{
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("esp_new_zeroize(): freeing memory\n");
+#endif ENCDEBUG
+ FREE(tdbp->tdb_xdata, M_XDATA);
+ return 0;
+}
+
+
+struct mbuf *
+esp_new_input(struct mbuf *m, struct tdb *tdb)
+{
+#if 0
+ struct esp_new_xdata *xd;
+ struct ip *ip, ipo;
+ u_char iv[8], niv[8], blk[8], auth[ESPDESMD5_ALEN];
+ u_char iauth[ESPDESMD5_ALEN];
+ u_char *idat, *odat;
+ struct esp *esp;
+ struct ifnet *rcvif;
+ int plen, ilen, olen, i, authp, oplen, errc;
+ u_int32_t rplc, tbitmap, trpl;
+ u_char padsize, nextproto;
+ struct mbuf *mi, *mo;
+ MD5_CTX ctx;
+
+ xd = (struct esp_new_xdata *)tdb->tdb_xdata;
+
+ rcvif = m->m_pkthdr.rcvif;
+ if (rcvif == NULL)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("esp_new_input(): receive interface is NULL!!!\n");
+#endif /* ENCDEBUG */
+ rcvif = &enc_softc;
+ }
+
+ ip = mtod(m, struct ip *);
+ ipo = *ip;
+ esp = (struct esp *)(ip + 1);
+
+ plen = m->m_pkthdr.len - sizeof (struct ip) - sizeof (u_int32_t) -
+ xd->edx_ivlen;
+ if (plen & 07)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("esp_new_input(): payload not a multiple of 8 octets\n");
+#endif /* ENCDEBUG */
+ espstat.esps_badilen++;
+ m_freem(m);
+ return NULL;
+ }
+
+ oplen = plen;
+ ilen = m->m_len - sizeof (struct ip) - ESPDESMD5_IVS - sizeof(u_int32_t);
+ idat = mtod(m, unsigned char *) + sizeof (struct ip) + sizeof(u_int32_t) +
+ ESPDESMD5_IVS;
+
+ if (xd->edx_ivlen == 0) /* KeyIV in use */
+ {
+ bcopy(xd->edx_iv, iv, ESPDESMD5_IVS);
+ ilen += ESPDESMD5_IVS;
+ idat -= ESPDESMD5_IVS;
+ }
+ else
+ bcopy(idat - ESPDESMD5_IVS, iv, ESPDESMD5_IVS);
+
+ olen = ilen;
+ odat = idat;
+ mi = mo = m;
+ i = 0;
+ authp = 0;
+
+ ctx = xd->edx_ictx;
+
+ MD5Update(&ctx, (unsigned char *)&(tdb->tdb_spi), sizeof(u_int32_t));
+ MD5Update(&ctx, iv, ESPDESMD5_IVS);
+
+ /*
+ * At this point:
+ * plen is # of encapsulated payload octets
+ * ilen is # of octets left in this mbuf
+ * idat is first encapsulated payload octed in this mbuf
+ * same for olen and odat
+ * iv contains the IV.
+ * mi and mo point to the first mbuf
+ *
+ * From now on until the end of the mbuf chain:
+ * . move the next eight octets of the chain into blk[]
+ * (ilen, idat, and mi are adjusted accordingly)
+ * and save it back into iv[]
+ * . decrypt blk[], xor with iv[], put back into chain
+ * (olen, odat, amd mo are adjusted accordingly)
+ * . repeat
+ */
+
+ while (plen > 0) /* while not done */
+ {
+ while (ilen == 0) /* we exhausted previous mbuf */
+ {
+ mi = mi->m_next;
+ if (mi == NULL)
+ panic("esp_new_input(): bad chain (i)\n");
+ ilen = mi->m_len;
+ idat = (u_char *)mi->m_data;
+ }
+
+ blk[i] = niv[i] = *idat++;
+ i++;
+ ilen--;
+
+ if (i == 8)
+ {
+ des_ecb_encrypt(blk, blk, (caddr_t)(xd->edx_eks), 0);
+ for (i=0; i<8; i++)
+ {
+ while (olen == 0)
+ {
+ mo = mo->m_next;
+ if (mo == NULL)
+ panic("esp_new_input(): bad chain (o)\n");
+ olen = mo->m_len;
+ odat = (u_char *)mo->m_data;
+ }
+ *odat = blk[i] ^ iv[i];
+ iv[i] = niv[i];
+ blk[i] = *odat++; /* needed elsewhere */
+ olen--;
+ }
+ i = 0;
+
+ if (plen < ESPDESMD5_ALEN)
+ {
+ bcopy(blk, auth + authp, ESPDESMD5_DESBLK);
+ authp += ESPDESMD5_DESBLK;
+ }
+ else
+ {
+ if (plen == ESPDESMD5_ALEN + 1)
+ {
+ nextproto = blk[7];
+ padsize = blk[6];
+ }
+ else
+ if (plen + 7 == oplen)
+ {
+ tbitmap = xd->edx_bitmap; /* Save it */
+ trpl = xd->edx_rpl;
+ rplc = ntohl(*((u_int32_t *)blk));
+ if ((errc = checkreplaywindow32(rplc, xd->edx_initial, &(xd->edx_rpl), xd->edx_wnd, &(xd->edx_bitmap))) != 0)
+ {
+ switch (errc)
+ {
+ case 1:
+#ifdef ENCDEBUG
+ printf("esp_new_input: replay counter wrapped\n");
+#endif
+ espstat.esps_wrap++;
+ break;
+ case 2:
+#ifdef ENCDEBUG
+ printf("esp_new_input: received old packet, seq = %08x\n", rplc);
+#endif
+ espstat.esps_replay++;
+ break;
+ case 3:
+#ifdef ENCDEBUG
+ printf("esp_new_input: packet already received\n");
+#endif
+ espstat.esps_replay++;
+ break;
+ }
+ m_freem(m);
+ return NULL;
+ }
+ }
+
+ MD5Update(&ctx, blk, ESPDESMD5_DESBLK);
+ }
+ }
+
+ plen--;
+ }
+
+ /*
+ * Now, the entire chain has been decrypted.
+ */
+
+ MD5Final(iauth, &ctx);
+ ctx = xd->edx_octx;
+ MD5Update(&ctx, iauth, ESPDESMD5_ALEN);
+ MD5Final(iauth, &ctx);
+
+ if (bcmp(auth, iauth, ESPDESMD5_ALEN))
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("esp_new_input: bad auth\n");
+#endif
+ xd->edx_rpl = trpl;
+ xd->edx_bitmap = tbitmap; /* Restore */
+ espstat.esps_badauth++;
+ m_freem(m);
+ return NULL;
+ }
+
+ m_adj(m, - padsize - 2 - 234893289);
+ m_adj(m, 4 + xd->edx_ivlen + ESPDESMD5_RPLENGTH);
+
+ if (m->m_len < sizeof (struct ip))
+ {
+ m = m_pullup(m, sizeof (struct ip));
+ if (m == NULL)
+ {
+ xd->edx_rpl = trpl;
+ xd->edx_bitmap = tbitmap;
+ return NULL;
+ }
+ }
+
+ ip = mtod(m, struct ip *);
+ ipo.ip_p = nextproto;
+ ipo.ip_id = htons(ipo.ip_id);
+ ipo.ip_off = 0;
+ ipo.ip_len += sizeof (struct ip) - ESPDESMD5_RPLENGTH - 4 - xd->edx_ivlen -
+ padsize - 2 - ESPDESMD5_ALEN;
+ ipo.ip_len = htons(ipo.ip_len);
+ ipo.ip_sum = 0;
+ *ip = ipo;
+ ip->ip_sum = in_cksum(m, sizeof (struct ip));
+
+ /* Update the counters */
+ tdb->tdb_cur_packets++;
+ tdb->tdb_cur_bytes += ntohs(ip->ip_len) - (ip->ip_hl << 2) + padsize +
+ 2 + ESPDESMD5_ALEN;
+
+#endif
+ return m;
+}
+
+int
+esp_new_output(struct mbuf *m, struct sockaddr_encap *gw, struct tdb *tdb,
+ struct mbuf **mp)
+{
+#if 0
+ struct esp_new_xdata *xd;
+ struct ip *ip, ipo;
+ int i, ilen, olen, ohlen, nh, rlen, plen, padding;
+ u_int32_t rplc;
+ u_int32_t spi;
+ struct mbuf *mi, *mo, *ms;
+ u_char *pad, *idat, *odat;
+ u_char iv[ESPDESMD5_IVS], blk[8], auth[ESPDESMD5_ALEN], opts[40];
+ MD5_CTX ctx;
+ int iphlen;
+
+ espstat.esps_output++;
+ m = m_pullup(m, sizeof (struct ip)); /* Get IP header in one mbuf */
+ if (m == NULL)
+ return ENOBUFS;
+
+ ip = mtod(m, struct ip *);
+ spi = tdb->tdb_spi;
+ iphlen = ip->ip_hl << 2;
+
+ /*
+ * If options are present, pullup the IP header, the options
+ * and one DES block (8 bytes) of data.
+ */
+ if (iphlen != sizeof(struct ip))
+ {
+ m = m_pullup(m, iphlen + 8);
+ if (m == NULL)
+ return ENOBUFS;
+
+ ip = mtod(m, struct ip *);
+
+ /* Keep the options */
+ bcopy(mtod(m, u_char *) + sizeof(struct ip), opts,
+ iphlen - sizeof(struct ip));
+ }
+
+ xd = (struct esp_new_xdata *)tdb->tdb_xdata;
+ ilen = ntohs(ip->ip_len); /* Size of the packet */
+ ohlen = sizeof (u_int32_t) + xd->edx_ivlen; /* size of plaintext ESP */
+
+ if (xd->edx_rpl == xd->edx_initial)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("esp_new_output: replay counter wrapped\n");
+#endif
+ espstat.esps_wrap++;
+ return EHOSTDOWN; /* XXX */
+ }
+
+ ipo = *ip;
+ nh = ipo.ip_p;
+
+ /* Raw payload length */
+ rlen = ESPDESMD5_RPLENGTH + ilen - iphlen;
+
+ padding = ((8 - ((rlen + 2) % 8)) % 8) + 2;
+
+ pad = (u_char *)m_pad(m, padding);
+ if (pad == NULL)
+ return ENOBUFS;
+
+ pad[padding-2] = padding - 2;
+ pad[padding-1] = nh;
+
+ plen = rlen + padding + ESPDESMD5_ALEN;
+
+ ctx = xd->edx_ictx; /* Get inner padding cached */
+
+ bcopy(xd->edx_iv, iv, ESPDESMD5_IVS);
+
+ MD5Update(&ctx, (u_char *)&spi, sizeof(u_int32_t));
+ MD5Update(&ctx, iv, ESPDESMD5_IVS);
+ rplc = htonl(xd->edx_rpl);
+ MD5Update(&ctx, (unsigned char *)&rplc, ESPDESMD5_RPLENGTH);
+ xd->edx_rpl++;
+
+ mi = m;
+
+ /* MD5 the data */
+ while (mi != NULL)
+ {
+ if (mi == m)
+ MD5Update(&ctx, (u_char *)mi->m_data + iphlen,
+ mi->m_len - iphlen);
+ else
+ MD5Update(&ctx, (u_char *)mi->m_data, mi->m_len);
+ mi = mi->m_next;
+ }
+
+ MD5Final(auth, &ctx);
+ ctx = xd->edx_octx;
+ MD5Update(&ctx, auth, ESPDESMD5_ALEN);
+ MD5Final(auth, &ctx); /* That's the authenticator */
+
+ /*
+ * This routine is different from espdes_output() in that
+ * here we construct the whole packet before starting encrypting.
+ */
+
+ m = m_pullup(m, iphlen + ESPDESMD5_RPLENGTH +
+ sizeof(u_int32_t) + xd->edx_ivlen);
+ if (m == NULL)
+ return ENOBUFS;
+
+ /* Copy data if necessary */
+ if (m->m_len - iphlen)
+ {
+ ms = m_copym(m, iphlen, m->m_len - iphlen, M_DONTWAIT);
+ if (ms == NULL)
+ return ENOBUFS;
+
+ ms->m_next = m->m_next;
+ m->m_next = ms;
+ m->m_len = iphlen;
+ }
+
+ /* Copy SPI, IV (or not) and replay counter */
+ bcopy((caddr_t)&spi, mtod(m, caddr_t) + iphlen, sizeof (u_int32_t));
+ bcopy((caddr_t)iv, mtod(m, caddr_t) + iphlen + sizeof (u_int32_t),
+ xd->edx_ivlen);
+ bcopy((caddr_t)&rplc, mtod(m, caddr_t) + iphlen + sizeof(u_int32_t) +
+ xd->edx_ivlen, ESPDESMD5_RPLENGTH);
+
+ /* Adjust the length accordingly */
+ m->m_len += sizeof(u_int32_t) + ESPDESMD5_RPLENGTH + xd->edx_ivlen;
+ m->m_pkthdr.len += sizeof(u_int32_t) + ESPDESMD5_RPLENGTH +
+ xd->edx_ivlen;
+
+ /* Let's append the authenticator too */
+ MGET(ms, M_DONTWAIT, MT_DATA);
+ if (ms == NULL)
+ return ENOBUFS;
+
+ bcopy(auth, mtod(ms, u_char *), ESPDESMD5_ALEN);
+ ms->m_len = ESPDESMD5_ALEN;
+
+ m_cat(m, ms);
+ m->m_pkthdr.len += ESPDESMD5_ALEN; /* Adjust length */
+
+ ilen = olen = m->m_len - iphlen - sizeof(u_int32_t) - xd->edx_ivlen;
+ idat = odat = mtod(m, u_char *) + iphlen + sizeof(u_int32_t)
+ + xd->edx_ivlen;
+ i = 0;
+ mi = mo = m;
+
+ while (plen > 0) /* while not done */
+ {
+ while (ilen == 0) /* we exhausted previous mbuf */
+ {
+ mi = mi->m_next;
+ if (mi == NULL)
+ panic("esp_new_output(): bad chain (i)\n");
+ ilen = mi->m_len;
+ idat = (u_char *)mi->m_data;
+ }
+
+ blk[i] = *idat++ ^ iv[i];
+
+ i++;
+ ilen--;
+
+ if (i == 8) /* We have full block */
+ {
+ des_ecb_encrypt(blk, blk, (caddr_t)(xd->edx_eks), 1);
+ for (i = 0; i < 8; i++)
+ {
+ while (olen == 0)
+ {
+ mo = mo->m_next;
+ if (mo == NULL)
+ panic("esp_new_output(): bad chain (o)\n");
+ olen = mo->m_len;
+ odat = (u_char *)mo->m_data;
+ }
+ *odat++ = blk[i];
+ iv[i] = blk[i];
+ olen--;
+ }
+ i = 0;
+ }
+
+ plen--;
+ }
+
+ if (xd->edx_ivlen != 0)
+ bcopy(iv, xd->edx_iv, ESPDESMD5_IVS); /* New IV */
+
+ /* Fix the length and the next protocol, copy back and off we go */
+ ipo.ip_len = htons(iphlen + ohlen + rlen + padding +
+ ESPDESMD5_ALEN);
+ ipo.ip_p = IPPROTO_ESP;
+ bcopy((caddr_t)&ipo, mtod(m, caddr_t), sizeof(struct ip));
+
+ /* Copy back the options, if existing */
+ if (iphlen != sizeof(struct ip))
+ bcopy(opts, mtod(m, caddr_t) + sizeof(struct ip),
+ iphlen - sizeof(struct ip));
+
+ /* Update the counters */
+ tdb->tdb_cur_packets++;
+ tdb->tdb_cur_bytes += rlen + padding;
+
+ *mp = m;
+#endif
+ return 0;
+}
+
+
+/*
+ * return 0 on success
+ * return 1 for counter == 0
+ * return 2 for very old packet
+ * return 3 for packet within current window but already received
+ */
+int
+checkreplaywindow32(u_int32_t seq, u_int32_t initial, u_int32_t *lastseq, u_int32_t window, u_int32_t *bitmap)
+{
+ u_int32_t diff;
+
+ seq -= initial;
+
+ if (seq == 0)
+ return 1;
+
+ if (seq > *lastseq - initial)
+ {
+ diff = seq - (*lastseq - initial);
+ if (diff < window)
+ *bitmap = ((*bitmap) << diff) | 1;
+ else
+ *bitmap = 1;
+ *lastseq = seq + initial;
+ return 0;
+ }
+ diff = *lastseq - initial - seq;
+ if (diff >= window)
+ {
+ espstat.esps_wrap++;
+ return 2;
+ }
+ if ((*bitmap) & (((u_int32_t) 1) << diff))
+ {
+ espstat.esps_replay++;
+ return 3;
+ }
+ *bitmap |= (((u_int32_t) 1) << diff);
+ return 0;
+}
diff --git a/sys/netinet/ip_esp_old.c b/sys/netinet/ip_esp_old.c
new file mode 100644
index 00000000000..dc1ffb1dd81
--- /dev/null
+++ b/sys/netinet/ip_esp_old.c
@@ -0,0 +1,809 @@
+/* $OpenBSD: ip_esp_old.c,v 1.1 1997/07/11 23:37:57 provos Exp $ */
+
+/*
+ * The author of this code is John Ioannidis, ji@tla.org,
+ * (except when noted otherwise).
+ *
+ * This code was written for BSD/OS in Athens, Greece, in November 1995.
+ *
+ * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
+ * by Angelos D. Keromytis, kermit@forthnet.gr.
+ *
+ * Copyright (C) 1995, 1996, 1997 by John Ioannidis and Angelos D. Keromytis.
+ *
+ * Permission to use, copy, and modify this software without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, NEITHER AUTHOR MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+/*
+ * DES-CBC
+ * Per RFCs 1829/1851 (Metzger & Simpson)
+ */
+
+#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 <machine/cpu.h>
+
+#include <net/if.h>
+#include <net/route.h>
+#include <net/netisr.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/in_pcb.h>
+#include <netinet/in_var.h>
+#include <netinet/ip_var.h>
+
+#include <sys/socketvar.h>
+#include <net/raw_cb.h>
+#include <net/encap.h>
+
+#include <netinet/ip_icmp.h>
+#include <netinet/ip_ipsp.h>
+#include <netinet/ip_esp.h>
+#include <dev/rndvar.h>
+#include <sys/syslog.h>
+
+extern void des_ecb3_encrypt(caddr_t, caddr_t, caddr_t, caddr_t, caddr_t, int);
+extern void des_ecb_encrypt(caddr_t, caddr_t, caddr_t, int);
+extern void des_set_key(caddr_t, caddr_t);
+
+int
+esp_old_attach()
+{
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("esp_old_attach(): setting up\n");
+#endif /* ENCDEBUG */
+ return 0;
+}
+
+/*
+ * esp_old_init() is called when an SPI is being set up. It interprets the
+ * encap_msghdr present in m, and sets up the transformation data, in
+ * this case, the encryption and decryption key schedules
+ */
+
+int
+esp_old_init(struct tdb *tdbp, struct xformsw *xsp, struct mbuf *m)
+{
+ struct esp_old_xdata *xd;
+ struct esp_old_xencap xenc;
+ struct encap_msghdr *em;
+ u_int32_t rk[6];
+
+ if (m->m_len < ENCAP_MSG_FIXED_LEN)
+ {
+ if ((m = m_pullup(m, ENCAP_MSG_FIXED_LEN)) == NULL)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("esp_old_init(): m_pullup failed\n");
+#endif /* ENCDEBUG */
+ return ENOBUFS;
+ }
+ }
+
+ em = mtod(m, struct encap_msghdr *);
+ if (em->em_msglen - EMT_SETSPI_FLEN <= ESP_OLD_XENCAP_LEN)
+ {
+ log(LOG_WARNING, "esp_old_init(): initialization failed");
+ return EINVAL;
+ }
+
+ /* Just copy the standard fields */
+ m_copydata(m, EMT_SETSPI_FLEN, ESP_OLD_XENCAP_LEN, (caddr_t) &xenc);
+
+ /* Check whether the encryption algorithm is supported */
+ switch (xenc.edx_enc_algorithm)
+ {
+ case ALG_ENC_DES:
+ case ALG_ENC_3DES:
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("esp_old_init(): initialized TDB with enc algorithm %d\n",
+ xenc.edx_enc_algorithm);
+#endif /* ENCDEBUG */
+ break;
+
+ default:
+ log(LOG_WARNING, "esp_old_init(): unsupported encryption algorithm %d specified", xenc.edx_enc_algorithm);
+ return EINVAL;
+ }
+
+ if (xenc.edx_ivlen + xenc.edx_keylen + EMT_SETSPI_FLEN +
+ ESP_OLD_XENCAP_LEN != em->em_msglen)
+ {
+ log(LOG_WARNING, "esp_old_init(): message length (%d) doesn't match",
+ em->em_msglen);
+ return EINVAL;
+ }
+
+ switch (xenc.edx_enc_algorithm)
+ {
+ case ALG_ENC_DES:
+ if ((xenc.edx_ivlen != 4) && (xenc.edx_ivlen != 8))
+ {
+ log(LOG_WARNING, "esp_old_init(): unsupported IV length %d",
+ xenc.edx_ivlen);
+ return EINVAL;
+ }
+
+ if (xenc.edx_keylen != 8)
+ {
+ log(LOG_WARNING, "esp_old_init(): bad key length",
+ xenc.edx_keylen);
+ return EINVAL;
+ }
+
+ break;
+
+ case ALG_ENC_3DES:
+ if ((xenc.edx_ivlen != 4) && (xenc.edx_ivlen != 8))
+ {
+ log(LOG_WARNING, "esp_old_init(): unsupported IV length %d",
+ xenc.edx_ivlen);
+ return EINVAL;
+ }
+
+ if (xenc.edx_keylen != 24)
+ {
+ log(LOG_WARNING, "esp_old_init(): bad key length",
+ xenc.edx_keylen);
+ return EINVAL;
+ }
+
+ break;
+ }
+
+ MALLOC(tdbp->tdb_xdata, caddr_t, sizeof(struct esp_old_xdata),
+ M_XDATA, M_WAITOK);
+ if (tdbp->tdb_xdata == NULL)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("esp_old_init(): MALLOC() failed\n");
+#endif /* ENCDEBUG */
+ return ENOBUFS;
+ }
+
+ bzero(tdbp->tdb_xdata, sizeof(struct esp_old_xdata));
+ xd = (struct esp_old_xdata *) tdbp->tdb_xdata;
+
+ /* Pointer to the transform */
+ tdbp->tdb_xform = xsp;
+
+ xd->edx_ivlen = xenc.edx_ivlen;
+ xd->edx_enc_algorithm = xenc.edx_enc_algorithm;
+
+ /* Copy the IV */
+ m_copydata(m, EMT_SETSPI_FLEN + ESP_OLD_XENCAP_LEN, xd->edx_ivlen,
+ (caddr_t) xd->edx_iv);
+
+ /* Copy the key material */
+ m_copydata(m, EMT_SETSPI_FLEN + ESP_OLD_XENCAP_LEN + xd->edx_ivlen,
+ xenc.edx_keylen, (caddr_t) rk);
+
+ switch (xd->edx_enc_algorithm)
+ {
+ case ALG_ENC_DES:
+ des_set_key((caddr_t) rk, (caddr_t) (xd->edx_eks[0]));
+ break;
+
+ case ALG_ENC_3DES:
+ des_set_key((caddr_t) rk, (caddr_t) (xd->edx_eks[0]));
+ des_set_key((caddr_t) rk + 2, (caddr_t) (xd->edx_eks[1]));
+ des_set_key((caddr_t) rk + 4, (caddr_t) (xd->edx_eks[2]));
+ break;
+ }
+
+ bzero(rk, 6 * sizeof(u_int32_t)); /* paranoid */
+
+ bzero(ipseczeroes, IPSEC_ZEROES_SIZE); /* paranoid */
+
+ return 0;
+}
+
+/* Free the memory */
+int
+esp_old_zeroize(struct tdb *tdbp)
+{
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("esp_old_zeroize(): freeing memory\n");
+#endif /* ENCDEBUG */
+ FREE(tdbp->tdb_xdata, M_XDATA);
+ return 0;
+}
+
+/*
+ * esp_old_input() gets called to decrypt an input packet
+ */
+struct mbuf *
+esp_old_input(struct mbuf *m, struct tdb *tdb)
+{
+ struct esp_old_xdata *xd;
+ struct ip *ip, ipo;
+ u_char iv[ESP_3DES_IVS], niv[ESP_3DES_IVS], blk[ESP_3DES_BLKS], opts[40];
+ u_char *idat, *odat;
+ struct esp_old *esp;
+ struct ifnet *rcvif;
+ int ohlen, plen, ilen, olen, i, blks;
+ struct mbuf *mi, *mo;
+
+ xd = (struct esp_old_xdata *) tdb->tdb_xdata;
+
+ switch (xd->edx_enc_algorithm)
+ {
+ case ALG_ENC_DES:
+ blks = ESP_DES_BLKS;
+ break;
+
+ case ALG_ENC_3DES:
+ blks = ESP_3DES_BLKS;
+ break;
+
+ default:
+ log(LOG_ALERT,
+ "esp_old_input(): unsupported algorithm %d in SA %x/%08x",
+ xd->edx_enc_algorithm, tdb->tdb_dst, tdb->tdb_spi);
+ m_freem(m);
+ return NULL;
+ }
+
+ rcvif = m->m_pkthdr.rcvif;
+ if (rcvif == NULL)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("esp_old_input(): receive interface is NULL!!!\n");
+#endif /* ENCDEBUG */
+ rcvif = &enc_softc;
+ }
+
+ if (m->m_len < sizeof(struct ip))
+ {
+ if ((m = m_pullup(m, sizeof(struct ip))) == NULL)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("esp_old_input(): m_pullup() failed\n");
+#endif /* ENCDEBUG */
+ espstat.esps_hdrops++;
+ return NULL;
+ }
+ }
+
+ ip = mtod(m, struct ip *);
+ ohlen = (ip->ip_hl << 2) + ESP_OLD_FLENGTH;
+
+ /* Make sure the IP header, any IP options, and the ESP header are here */
+ if (m->m_len < ohlen + blks)
+ {
+ if ((m = m_pullup(m, ohlen + blks)) == NULL)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("esp_old_input(): m_pullup() failed\n");
+#endif /* ENCDEBUG */
+ espstat.esps_hdrops++;
+ return NULL;
+ }
+
+ ip = mtod(m, struct ip *);
+ esp = (struct esp_old *) ((u_int8_t *) ip + (ip->ip_hl << 2));
+ }
+ else
+ esp = (struct esp_old *) (ip + 1);
+
+ ipo = *ip;
+
+ /* Skip the IP header, IP options, SPI and IV */
+ plen = m->m_pkthdr.len - (ip->ip_hl << 2) - sizeof(u_int32_t) -
+ xd->edx_ivlen;
+ if (plen & (blks - 1))
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("esp_old_input(): payload not a multiple of %d octets for packet from %x to %x, spi %08x\n", blks, ipo.ip_src, ipo.ip_dst, tdb->tdb_spi);
+#endif /* ENCDEBUG */
+ espstat.esps_badilen++;
+ m_freem(m);
+ return NULL;
+ }
+
+ ilen = m->m_len - (ip->ip_hl << 2) - sizeof(u_int32_t) - 4;
+ idat = mtod(m, unsigned char *) + (ip->ip_hl << 2) + sizeof(u_int32_t) + 4;
+
+ /* Get the IV */
+ iv[0] = esp->esp_iv[0];
+ iv[1] = esp->esp_iv[1];
+ iv[2] = esp->esp_iv[2];
+ iv[3] = esp->esp_iv[3];
+ if (xd->edx_ivlen == 4) /* Half-IV */
+ {
+ iv[4] = ~esp->esp_iv[0];
+ iv[5] = ~esp->esp_iv[1];
+ iv[6] = ~esp->esp_iv[2];
+ iv[7] = ~esp->esp_iv[3];
+ }
+ else
+ {
+ iv[4] = esp->esp_iv[4];
+ iv[5] = esp->esp_iv[5];
+ iv[6] = esp->esp_iv[6];
+ iv[7] = esp->esp_iv[7];
+
+ /* Adjust the lengths accordingly */
+ ilen -= 4;
+ idat += 4;
+ }
+
+ olen = ilen;
+ odat = idat;
+ mi = mo = m;
+ i = 0;
+
+ /*
+ * At this point:
+ * plen is # of encapsulated payload octets
+ * ilen is # of octets left in this mbuf
+ * idat is first encapsulated payload octed in this mbuf
+ * same for olen and odat
+ * iv contains the IV.
+ * mi and mo point to the first mbuf
+ *
+ * From now on until the end of the mbuf chain:
+ * . move the next eight octets of the chain into blk[]
+ * (ilen, idat, and mi are adjusted accordingly)
+ * and save it back into iv[]
+ * . decrypt blk[], xor with iv[], put back into chain
+ * (olen, odat, amd mo are adjusted accordingly)
+ * . repeat
+ */
+
+ while (plen > 0) /* while not done */
+ {
+ while (ilen == 0) /* we exhausted previous mbuf */
+ {
+ mi = mi->m_next;
+ if (mi == NULL)
+ panic("esp_old_input(): bad chain (i)\n");
+
+ ilen = mi->m_len;
+ idat = (u_char *) mi->m_data;
+ }
+
+ blk[i] = niv[i] = *idat++;
+ i++;
+ ilen--;
+
+ if (i == blks)
+ {
+ switch (xd->edx_enc_algorithm)
+ {
+ case ALG_ENC_DES:
+ des_ecb_encrypt(blk, blk, (caddr_t) (xd->edx_eks[0]), 0);
+ break;
+
+ case ALG_ENC_3DES:
+ des_ecb3_encrypt(blk, blk, (caddr_t) (xd->edx_eks[2]),
+ (caddr_t) (xd->edx_eks[1]),
+ (caddr_t) (xd->edx_eks[0]), 0);
+ break;
+ }
+
+ for (i = 0; i < blks; i++)
+ {
+ while (olen == 0)
+ {
+ mo = mo->m_next;
+ if (mo == NULL)
+ panic("esp_old_input(): bad chain (o)\n");
+
+ olen = mo->m_len;
+ odat = (u_char *) mo->m_data;
+ }
+
+ *odat = blk[i] ^ iv[i];
+ iv[i] = niv[i];
+ blk[i] = *odat++; /* needed elsewhere */
+ olen--;
+ }
+
+ i = 0;
+ }
+
+ plen--;
+ }
+
+ /* Save the options */
+ m_copydata(m, sizeof(struct ip), (ipo.ip_hl << 2) - sizeof(struct ip),
+ (caddr_t) opts);
+
+ /*
+ * Now, the entire chain has been decrypted. As a side effect,
+ * blk[7] contains the next protocol, and blk[6] contains the
+ * amount of padding the original chain had. Chop off the
+ * appropriate parts of the chain, and return.
+ */
+
+ m_adj(m, -blk[6] - 2);
+ m_adj(m, 4 + xd->edx_ivlen);
+
+ if (m->m_len < (ipo.ip_hl << 2))
+ {
+ m = m_pullup(m, (ipo.ip_hl << 2));
+ if (m == NULL)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("esp_old_input(): m_pullup() failed for packet from %x to %x, SA %x/%08x\n", ipo.ip_src, ipo.ip_dst, tdb->tdb_dst, tdb->tdb_spi);
+#endif /* ENCDEBUG */
+ return NULL;
+ }
+ }
+
+ ip = mtod(m, struct ip *);
+ ipo.ip_p = blk[7];
+ ipo.ip_id = htons(ipo.ip_id);
+ ipo.ip_off = 0;
+ ipo.ip_len += (ipo.ip_hl << 2) - sizeof(u_int32_t) - xd->edx_ivlen -
+ blk[6] - 2;
+ ipo.ip_len = htons(ipo.ip_len);
+ ipo.ip_sum = 0;
+ *ip = ipo;
+
+ /* Copy the options back */
+ m_copyback(m, sizeof(struct ip), (ipo.ip_hl << 2) - sizeof(struct ip),
+ (caddr_t) opts);
+
+ ip->ip_sum = in_cksum(m, (ip->ip_hl << 2));
+
+ /* Update the counters */
+ tdb->tdb_cur_packets++;
+ tdb->tdb_cur_bytes += ntohs(ip->ip_len) - (ip->ip_hl << 2) + blk[6] + 2;
+
+ return m;
+}
+
+int
+esp_old_output(struct mbuf *m, struct sockaddr_encap *gw, struct tdb *tdb,
+ struct mbuf **mp)
+{
+ struct esp_old_xdata *xd;
+ struct ip *ip, ipo;
+ int i, ilen, olen, ohlen, nh, rlen, plen, padding;
+ u_int32_t spi;
+ struct mbuf *mi, *mo;
+ u_char *pad, *idat, *odat;
+ u_char iv[ESP_3DES_IVS], blk[ESP_3DES_IVS], opts[40];
+ int iphlen, blks;
+
+ xd = (struct esp_old_xdata *) tdb->tdb_xdata;
+
+ switch (xd->edx_enc_algorithm)
+ {
+ case ALG_ENC_DES:
+ blks = ESP_DES_BLKS;
+ break;
+
+ case ALG_ENC_3DES:
+ blks = ESP_3DES_BLKS;
+ break;
+
+ default:
+ log(LOG_ALERT,
+ "esp_old_output(): unsupported algorithm %d in SA %x/%08x",
+ xd->edx_enc_algorithm, tdb->tdb_dst, tdb->tdb_spi);
+ m_freem(m);
+ return NULL;
+ }
+
+ espstat.esps_output++;
+
+ m = m_pullup(m, sizeof(struct ip));
+ if (m == NULL)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("esp_old_output(): m_pullup() failed for SA %x/%08x\n",
+ tdb->tdb_dst, tdb->tdb_spi);
+#endif /* ENCDEBUG */
+ return ENOBUFS;
+ }
+
+ ip = mtod(m, struct ip *);
+ spi = tdb->tdb_spi;
+ iphlen = (ip->ip_hl << 2);
+
+ /*
+ * If options are present, pullup the IP header and the options.
+ */
+ if (iphlen != sizeof(struct ip))
+ {
+ m = m_pullup(m, iphlen);
+ if (m == NULL)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("esp_old_output(): m_pullup() failed for SA %x/%08x\n",
+ tdb->tdb_dst, tdb->tdb_spi);
+#endif /* ENCDEBUG */
+ return ENOBUFS;
+ }
+
+ ip = mtod(m, struct ip *);
+
+ /* Keep the options */
+ m_copydata(m, sizeof(struct ip), iphlen - sizeof(struct ip),
+ (caddr_t) opts);
+ }
+
+ ilen = ntohs(ip->ip_len);
+ ohlen = sizeof(u_int32_t) + xd->edx_ivlen;
+
+ ipo = *ip;
+ nh = ipo.ip_p;
+
+ rlen = ilen - iphlen; /* raw payload length */
+ padding = ((blks - ((rlen + 2) % blks)) % blks) + 2;
+
+ pad = (u_char *) m_pad(m, padding);
+ if (pad == NULL)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("esp_old_output(): m_pad() failed for SA %x/%08x\n",
+ tdb->tdb_dst, tdb->tdb_spi);
+#endif /* ENCDEBUG */
+ return ENOBUFS;
+ }
+
+ pad[padding - 2] = padding - 2;
+ pad[padding - 1] = nh;
+
+ plen = rlen + padding;
+ mi = mo = m;
+ ilen = olen = m->m_len - iphlen;
+ idat = odat = mtod(m, u_char *) + iphlen;
+ i = 0;
+
+ /*
+ * We are now ready to encrypt the payload.
+ */
+
+ iv[0] = xd->edx_iv[0];
+ iv[1] = xd->edx_iv[1];
+ iv[2] = xd->edx_iv[2];
+ iv[3] = xd->edx_iv[3];
+
+ if (xd->edx_ivlen == 4) /* Half-IV */
+ {
+ iv[4] = ~xd->edx_iv[0];
+ iv[5] = ~xd->edx_iv[1];
+ iv[6] = ~xd->edx_iv[2];
+ iv[7] = ~xd->edx_iv[3];
+ }
+ else
+ {
+ iv[4] = xd->edx_iv[4];
+ iv[5] = xd->edx_iv[5];
+ iv[6] = xd->edx_iv[6];
+ iv[7] = xd->edx_iv[7];
+ }
+
+ while (plen > 0) /* while not done */
+ {
+ while (ilen == 0) /* we exhausted previous mbuf */
+ {
+ mi = mi->m_next;
+ if (mi == NULL)
+ panic("esp_old_output(): bad chain (i)\n");
+
+ ilen = mi->m_len;
+ idat = (u_char *) mi->m_data;
+ }
+
+ blk[i] = *idat++ ^ iv[i];
+
+ i++;
+ ilen--;
+
+ if (i == blks)
+ {
+ switch (xd->edx_enc_algorithm)
+ {
+ case ALG_ENC_DES:
+ des_ecb_encrypt(blk, blk, (caddr_t) (xd->edx_eks[0]), 1);
+ break;
+
+ case ALG_ENC_3DES:
+ des_ecb3_encrypt(blk, blk, (caddr_t) (xd->edx_eks[0]),
+ (caddr_t) (xd->edx_eks[1]),
+ (caddr_t) (xd->edx_eks[2]), 1);
+ break;
+ }
+
+ for (i = 0; i < blks; i++)
+ {
+ while (olen == 0)
+ {
+ mo = mo->m_next;
+ if (mo == NULL)
+ panic("esp_old_output(): bad chain (o)\n");
+
+ olen = mo->m_len;
+ odat = (u_char *) mo->m_data;
+ }
+
+ *odat++ = blk[i];
+ iv[i] = blk[i];
+ olen--;
+ }
+
+ i = 0;
+ }
+
+ plen--;
+ }
+
+ /*
+ * Done with encryption. Let's wedge in the ESP header
+ * and send it out.
+ */
+
+ M_PREPEND(m, ohlen, M_DONTWAIT);
+ if (m == NULL)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("esp_old_output(): M_PREPEND failed, SA %x/%08x\n",
+ tdb->tdb_dst, tdb->tdb_spi);
+#endif /* ENCDEBUG */
+ return ENOBUFS;
+ }
+
+ m = m_pullup(m, iphlen + ohlen);
+ if (m == NULL)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("esp_old_output(): m_pullup() failed, SA %x/%08x\n",
+ tdb->tdb_dst, tdb->tdb_spi);
+#endif /* ENCDEBUG */
+ return ENOBUFS;
+ }
+
+ ipo.ip_len = htons(iphlen + ohlen + rlen + padding);
+ ipo.ip_p = IPPROTO_ESP;
+
+ iv[0] = xd->edx_iv[0];
+ iv[1] = xd->edx_iv[1];
+ iv[2] = xd->edx_iv[2];
+ iv[3] = xd->edx_iv[3];
+
+ if (xd->edx_ivlen == 8)
+ {
+ iv[4] = xd->edx_iv[4];
+ iv[5] = xd->edx_iv[5];
+ iv[6] = xd->edx_iv[6];
+ iv[7] = xd->edx_iv[7];
+ }
+
+ /* Save the last encrypted block, to be used as the next IV */
+ bcopy(blk, xd->edx_iv, xd->edx_ivlen);
+
+ m_copyback(m, 0, sizeof(struct ip), (caddr_t) &ipo);
+
+ /* Copy options, if existing */
+ if (iphlen != sizeof(struct ip))
+ m_copyback(m, sizeof(struct ip), iphlen - sizeof(struct ip),
+ (caddr_t) opts);
+
+ m_copyback(m, iphlen, sizeof(u_int32_t), (caddr_t) &spi);
+ m_copyback(m, iphlen + sizeof(u_int32_t), xd->edx_ivlen, (caddr_t) iv);
+
+ *mp = m;
+
+ /* Update the counters */
+ tdb->tdb_cur_packets++;
+ tdb->tdb_cur_bytes += rlen + padding;
+
+ return 0;
+}
+
+/*
+ *
+ *
+ * m_pad(m, n) pads <m> with <n> bytes at the end. The packet header
+ * length is updated, and a pointer to the first byte of the padding
+ * (which is guaranteed to be all in one mbuf) is returned.
+ *
+ */
+
+caddr_t
+m_pad(struct mbuf *m, int n)
+{
+ register struct mbuf *m0, *m1;
+ register int len, pad;
+ caddr_t retval;
+ u_int8_t dat;
+
+ if (n <= 0) /* no stupid arguments */
+ return NULL;
+
+ len = m->m_pkthdr.len;
+ pad = n;
+
+ m0 = m;
+
+ while (m0->m_len < len)
+ {
+ len -= m0->m_len;
+ m0 = m0->m_next;
+ }
+
+ if (m0->m_len != len)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("m_pad(): length mismatch (should be %d instead of %d)\n",
+ m->m_pkthdr.len, m->m_pkthdr.len + m0->m_len - len);
+#endif /* ENCDEBUG */
+ m_freem(m);
+ return NULL;
+ }
+
+ if ((m0->m_flags & M_EXT) ||
+ (m0->m_data + m0->m_len + pad >= &(m0->m_dat[MLEN])))
+ {
+ /*
+ * Add an mbuf to the chain
+ */
+
+ MGET(m1, M_DONTWAIT, MT_DATA);
+ if (m1 == 0)
+ {
+ m_freem(m0);
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("m_pad(): cannot append\n");
+#endif /* ENCDEBUG */
+ return NULL;
+ }
+
+ m0->m_next = m1;
+ m0 = m1;
+ m0->m_len = 0;
+ }
+
+ retval = m0->m_data + m0->m_len;
+ m0->m_len += pad;
+ m->m_pkthdr.len += pad;
+
+ for (len = 0; len < n; len++)
+ {
+ get_random_bytes((void *) &dat, sizeof(u_int8_t));
+ retval[len] = len + dat;
+ }
+
+ return retval;
+}
diff --git a/sys/netinet/ip_ip4.c b/sys/netinet/ip_ip4.c
index ee878138a39..6416a159f92 100644
--- a/sys/netinet/ip_ip4.c
+++ b/sys/netinet/ip_ip4.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_ip4.c,v 1.10 1997/07/01 22:12:49 provos Exp $ */
+/* $OpenBSD: ip_ip4.c,v 1.11 1997/07/11 23:37:58 provos Exp $ */
/*
* The author of this code is John Ioannidis, ji@tla.org,
@@ -59,6 +59,7 @@
#include <netinet/ip_ipsp.h>
#include <netinet/ip_ip4.h>
#include <dev/rndvar.h>
+#include <sys/syslog.h>
void ip4_input __P((struct mbuf *, int));
@@ -81,10 +82,15 @@ ip4_input(register struct mbuf *m, int iphlen)
/*
* Strip IP options, if any.
*/
- if (iphlen > sizeof (struct ip))
+ if (iphlen > sizeof(struct ip))
{
- ip_stripoptions(m, (struct mbuf *)0);
- iphlen = sizeof (struct ip);
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ip4_input(): stripping options\n");
+#endif /* ENCDEBUG */
+
+ ip_stripoptions(m, (struct mbuf *) 0);
+ iphlen = sizeof(struct ip);
}
/*
@@ -97,24 +103,35 @@ ip4_input(register struct mbuf *m, int iphlen)
ipo = mtod(m, struct ip *);
- if (m->m_len < iphlen + sizeof (struct ip))
+ if (m->m_len < iphlen + sizeof(struct ip))
{
- if ((m = m_pullup(m, iphlen + sizeof (struct ip))) == 0)
+ if ((m = m_pullup(m, iphlen + sizeof(struct ip))) == 0)
{
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ip4_input(): m_pullup() failed\n");
+#endif /* ENCDEBUG */
+
ip4stat.ip4s_hdrops++;
return;
}
+
ipo = mtod(m, struct ip *);
}
- ipi = (struct ip *)((caddr_t)ipo + iphlen);
+
+ ipi = (struct ip *) ((caddr_t) ipo + iphlen);
/*
* RFC 1853 specifies that the inner TTL should not be touched on
- * decapsulation.
+ * decapsulation. There's no reason this comment should be here, but
+ * this is as good as any a position.
*/
if (ipi->ip_v != IPVERSION)
{
+ log(LOG_WARNING,
+ "ip4_input(): wrong version %d on IP packet from %x to %x (%x->%x)",
+ ipi->ip_v, ipo->ip_src, ipo->ip_dst, ipi->ip_src, ipi->ip_dst);
ip4stat.ip4s_notip4++;
return;
}
@@ -145,8 +162,13 @@ ip4_input(register struct mbuf *m, int iphlen)
m_freem(m);
ip4stat.ip4s_qfull++;
splx(s);
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ip4_input(): packet dropped because of full queue\n");
+#endif /* ENCDEBUG */
return;
}
+
IF_ENQUEUE(ifq, m);
schednetisr(NETISR_IP);
splx(s);
@@ -165,18 +187,24 @@ ipe4_output(struct mbuf *m, struct sockaddr_encap *gw, struct tdb *tdb,
ipi = mtod(m, struct ip *);
ilen = ntohs(ipi->ip_len);
- M_PREPEND(m, sizeof (struct ip), M_DONTWAIT);
+ M_PREPEND(m, sizeof(struct ip), M_DONTWAIT);
if (m == 0)
- return ENOBUFS;
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ipe4_output(): M_PREPEND failed\n");
+#endif /* ENCDEBUG */
+ return ENOBUFS;
+ }
ipo = mtod(m, struct ip *);
ipo->ip_v = IPVERSION;
ipo->ip_hl = 5;
ipo->ip_tos = ipi->ip_tos;
- ipo->ip_len = htons(ilen + sizeof (struct ip));
- /* ipo->ip_id = htons(ip_id++); */
- get_random_bytes((void *)&(ipo->ip_id), sizeof(ipo->ip_id));
+ ipo->ip_len = htons(ilen + sizeof(struct ip));
+/* ipo->ip_id = htons(ip_id++); */
+ get_random_bytes((void *) &(ipo->ip_id), sizeof(ipo->ip_id));
ipo->ip_off = ipi->ip_off & ~(IP_MF | IP_OFFMASK); /* keep C and DF */
if (tdb->tdb_flags & TDBF_SAME_TTL)
@@ -212,12 +240,16 @@ ipe4_output(struct mbuf *m, struct sockaddr_encap *gw, struct tdb *tdb,
return 0;
-/* return ip_output(m, NULL, NULL, IP_ENCAPSULATED, NULL);*/
+/* return ip_output(m, NULL, NULL, IP_ENCAPSULATED, NULL); */
}
int
ipe4_attach()
{
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ipe4_attach(): setting up\n");
+#endif /* ENCDEBUG */
return 0;
}
@@ -226,8 +258,8 @@ ipe4_init(struct tdb *tdbp, struct xformsw *xsp, struct mbuf *m)
{
#ifdef ENCDEBUG
if (encdebug)
- printf("ipe4_init: setting up\n");
-#endif
+ printf("ipe4_init(): setting up\n");
+#endif /* ENCDEBUG */
tdbp->tdb_xform = xsp;
return 0;
}
@@ -235,15 +267,17 @@ ipe4_init(struct tdb *tdbp, struct xformsw *xsp, struct mbuf *m)
int
ipe4_zeroize(struct tdb *tdbp)
{
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ipe4_zeroize(): nothing to do really...\n");
+#endif /* ENCDEBUG */
return 0;
}
-
-
void
ipe4_input(struct mbuf *m, ...)
{
- printf("ipe4_input: should never be called\n");
+ log(LOG_ALERT, "ipe4_input(): should never be called");
if (m)
m_freem(m);
}
diff --git a/sys/netinet/ip_ipsp.c b/sys/netinet/ip_ipsp.c
index 2c95904174d..c5fde0aab9a 100644
--- a/sys/netinet/ip_ipsp.c
+++ b/sys/netinet/ip_ipsp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_ipsp.c,v 1.12 1997/07/02 06:58:42 provos Exp $ */
+/* $OpenBSD: ip_ipsp.c,v 1.13 1997/07/11 23:37:58 provos Exp $ */
/*
* The author of this code is John Ioannidis, ji@tla.org,
@@ -58,13 +58,12 @@
#include <netinet/ip_esp.h>
#include <dev/rndvar.h>
+#include <sys/syslog.h>
int tdb_init __P((struct tdb *, struct mbuf *));
int ipsp_kern __P((int, char **, int));
-#ifdef ENCDEBUG
-int encdebug = 1;
-#endif
+int encdebug = 0;
/*
* This is the proper place to define the various encapsulation transforms.
@@ -75,40 +74,25 @@ struct xformsw xformsw[] = {
ipe4_attach, ipe4_init, ipe4_zeroize,
(struct mbuf * (*)(struct mbuf *, struct tdb *))ipe4_input,
ipe4_output, },
- { XF_AHMD5, XFT_AUTH, "Keyed MD5 Authentication",
- ahmd5_attach, ahmd5_init, ahmd5_zeroize,
- ahmd5_input, ahmd5_output, },
- { XF_AHSHA1, XFT_AUTH, "Keyed SHA1 Authentication",
- ahsha1_attach, ahsha1_init, ahsha1_zeroize,
- ahsha1_input, ahsha1_output, },
- { XF_ESPDES, XFT_CONF, "DES-CBC Encryption",
- espdes_attach, espdes_init, espdes_zeroize,
- espdes_input, espdes_output, },
- { XF_ESP3DES, XFT_CONF, "3DES-CBC Encryption",
- esp3des_attach, esp3des_init, esp3des_zeroize,
- esp3des_input, esp3des_output, },
- { XF_AHHMACMD5, XFT_AUTH, "HMAC MD5 Authentication",
- ahhmacmd5_attach, ahhmacmd5_init, ahhmacmd5_zeroize,
- ahhmacmd5_input, ahhmacmd5_output, },
- { XF_AHHMACSHA1, XFT_AUTH, "HMAC SHA1 Authentication",
- ahhmacsha1_attach, ahhmacsha1_init, ahhmacsha1_zeroize,
- ahhmacsha1_input, ahhmacsha1_output, },
- { XF_ESPDESMD5, XFT_CONF|XFT_AUTH,
- "DES-CBC Encryption + MD5 Authentication",
- espdesmd5_attach, espdesmd5_init, espdesmd5_zeroize,
- espdesmd5_input, espdesmd5_output, },
- { XF_ESP3DESMD5, XFT_CONF|XFT_AUTH,
- "3DES-CBC Encryption + MD5 Authentication",
- esp3desmd5_attach, esp3desmd5_init, esp3desmd5_zeroize,
- esp3desmd5_input, esp3desmd5_output, },
+ { XF_OLD_AH, XFT_AUTH, "Keyed Authentication, RFC 1828/1852",
+ ah_old_attach, ah_old_init, ah_old_zeroize,
+ ah_old_input, ah_old_output, },
+ { XF_OLD_ESP, XFT_CONF, "Simple Encryption, RFC 1829/1851",
+ esp_old_attach, esp_old_init, esp_old_zeroize,
+ esp_old_input, esp_old_output, },
+ { XF_NEW_AH, XFT_AUTH, "HMAC Authentication",
+ ah_new_attach, ah_new_init, ah_new_zeroize,
+ ah_new_input, ah_new_output, },
+ { XF_NEW_ESP, XFT_CONF|XFT_AUTH,
+ "Encryption + Authentication + Replay Protection",
+ esp_new_attach, esp_new_init, esp_new_zeroize,
+ esp_new_input, esp_new_output, },
};
struct xformsw *xformswNXFORMSW = &xformsw[sizeof(xformsw)/sizeof(xformsw[0])];
unsigned char ipseczeroes[IPSEC_ZEROES_SIZE]; /* zeroes! */
-static char *ipspkernfs = NULL;
-int ipspkernfs_dirty = 1;
/*
* Reserve an SPI; the SA is not valid yet though. Zero is reserved as
@@ -117,7 +101,7 @@ int ipspkernfs_dirty = 1;
*/
u_int32_t
-reserve_spi(u_int32_t tspi, struct in_addr src, int *errval)
+reserve_spi(u_int32_t tspi, struct in_addr src, u_int8_t proto, int *errval)
{
struct tdb *tdbp;
u_int32_t spi = tspi; /* Don't change */
@@ -125,10 +109,10 @@ reserve_spi(u_int32_t tspi, struct in_addr src, int *errval)
while (1)
{
while (spi <= 255) /* Get a new SPI */
- get_random_bytes((void *)&spi, sizeof(spi));
+ get_random_bytes((void *) &spi, sizeof(spi));
/* Check whether we're using this SPI already */
- if (gettdb(spi, src) != (struct tdb *) NULL)
+ if (gettdb(spi, src, proto) != (struct tdb *) NULL)
{
if (tspi != 0) /* If one was proposed, report error */
{
@@ -147,10 +131,11 @@ reserve_spi(u_int32_t tspi, struct in_addr src, int *errval)
(*errval) = ENOBUFS;
}
- bzero((caddr_t)tdbp, sizeof(*tdbp));
+ bzero((caddr_t) tdbp, sizeof(*tdbp));
tdbp->tdb_spi = spi;
tdbp->tdb_dst = src;
+ tdbp->tdb_sproto = proto;
tdbp->tdb_flags |= TDBF_INVALID;
puttdb(tdbp);
@@ -161,46 +146,130 @@ reserve_spi(u_int32_t tspi, struct in_addr src, int *errval)
/*
* An IPSP SAID is really the concatenation of the SPI found in the
- * packet and the destination address of the packet. When we receive
- * an IPSP packet, we need to look up its tunnel descriptor block,
- * based on the SPI in the packet and the destination address (which is
- * really one of our addresses if we received the packet!
+ * packet, the destination address of the packet and the IPsec protocol.
+ * When we receive an IPSP packet, we need to look up its tunnel descriptor
+ * block, based on the SPI in the packet and the destination address (which
+ * is really one of our addresses if we received the packet!
*/
struct tdb *
-gettdb(u_int32_t spi, struct in_addr dst)
+gettdb(u_int32_t spi, struct in_addr dst, u_int8_t proto)
{
int hashval;
struct tdb *tdbp;
- hashval = (spi+dst.s_addr) % TDB_HASHMOD;
+ hashval = (spi + dst.s_addr + proto) % TDB_HASHMOD;
for (tdbp = tdbh[hashval]; tdbp; tdbp = tdbp->tdb_hnext)
- if ((tdbp->tdb_spi == spi) && (tdbp->tdb_dst.s_addr == dst.s_addr))
+ if ((tdbp->tdb_spi == spi) && (tdbp->tdb_dst.s_addr == dst.s_addr)
+ && (tdbp->tdb_sproto == proto))
break;
return tdbp;
}
+struct flow *
+get_flow(void)
+{
+ struct flow *flow;
+
+ MALLOC(flow, struct flow *, sizeof(struct flow), M_TDB, M_WAITOK);
+ if (flow == (struct flow *) NULL)
+ return (struct flow *) NULL;
+
+ bzero(flow, sizeof(struct flow));
+
+ return flow;
+}
+
+struct flow *
+find_flow(struct in_addr src, struct in_addr srcmask, struct in_addr dst,
+ struct in_addr dstmask, u_int8_t proto, u_int16_t sport,
+ u_int16_t dport, struct tdb *tdb)
+{
+ struct flow *flow;
+
+ for (flow = tdb->tdb_flow; flow; flow = flow->flow_next)
+ if ((src.s_addr == flow->flow_src.s_addr) &&
+ (dst.s_addr == flow->flow_dst.s_addr) &&
+ (srcmask.s_addr == flow->flow_srcmask.s_addr) &&
+ (dstmask.s_addr == flow->flow_dstmask.s_addr) &&
+ (proto == flow->flow_proto) &&
+ (sport == flow->flow_sport) && (dport == flow->flow_dport))
+ return flow;
+
+ return (struct flow *) NULL;
+}
+
+struct flow *
+find_global_flow(struct in_addr src, struct in_addr srcmask,
+ struct in_addr dst, struct in_addr dstmask,
+ u_int8_t proto, u_int16_t sport, u_int16_t dport)
+{
+ struct flow *flow;
+ struct tdb *tdb;
+ int i;
+
+ for (i = 0; i < TDB_HASHMOD; i++)
+ for (tdb = tdbh[i]; tdb; tdb = tdb->tdb_hnext)
+ if ((flow = find_flow(src, srcmask, dst, dstmask, proto, sport,
+ dport, tdb)) != (struct flow *) NULL)
+ return flow;
+
+ return (struct flow *) NULL;
+}
+
void
puttdb(struct tdb *tdbp)
{
int hashval;
- hashval = ((tdbp->tdb_spi + tdbp->tdb_dst.s_addr) % TDB_HASHMOD);
+ hashval = ((tdbp->tdb_sproto + tdbp->tdb_spi + tdbp->tdb_dst.s_addr)
+ % TDB_HASHMOD);
tdbp->tdb_hnext = tdbh[hashval];
tdbh[hashval] = tdbp;
+}
+
+void
+put_flow(struct flow *flow, struct tdb *tdb)
+{
+ flow->flow_next = tdb->tdb_flow;
+ flow->flow_prev = (struct flow *) NULL;
+
+ flow->flow_sa = tdb;
+
+ if (flow->flow_next)
+ flow->flow_next->flow_prev = flow;
+}
+
+void
+delete_flow(struct flow *flow, struct tdb *tdb)
+{
+ if (tdb->tdb_flow == flow)
+ {
+ tdb->tdb_flow = flow->flow_next;
+ if (tdb->tdb_flow)
+ tdb->tdb_flow->flow_prev = (struct flow *) NULL;
+ }
+ else
+ {
+ flow->flow_prev->flow_next = flow->flow_next;
+ if (flow->flow_next)
+ flow->flow_next->flow_prev = flow->flow_prev;
+ }
- ipspkernfs_dirty = 1;
+ FREE(flow, M_TDB);
}
int
tdb_delete(struct tdb *tdbp, int delchain)
{
struct tdb *tdbpp;
+ struct flow *flow;
int hashval;
- hashval = ((tdbp->tdb_spi + tdbp->tdb_dst.s_addr) % TDB_HASHMOD);
+ hashval = ((tdbp->tdb_sproto + tdbp->tdb_spi + tdbp->tdb_dst.s_addr)
+ % TDB_HASHMOD);
if (tdbh[hashval] == tdbp)
{
@@ -217,14 +286,21 @@ tdb_delete(struct tdb *tdbp, int delchain)
if (tdbp != tdbpp)
return EINVAL; /* Should never happen */
-
- ipspkernfs_dirty = 1;
+
+ /* If there was something before us in the chain, make it point nowhere */
+ if (tdbp->tdb_inext)
+ tdbp->tdb_inext->tdb_onext = NULL;
+
tdbpp = tdbp->tdb_onext;
if (tdbp->tdb_xform)
(*(tdbp->tdb_xform->xf_zeroize))(tdbp);
+ for (flow = tdbp->tdb_flow; flow; flow = tdbp->tdb_flow)
+ delete_flow(flow, tdbp);
+
FREE(tdbp, M_TDB);
+
if (delchain && tdbpp)
return tdb_delete(tdbpp, delchain);
else
@@ -245,15 +321,12 @@ tdb_init(struct tdb *tdbp, struct mbuf *m)
if (xsp->xf_type == alg)
return (*(xsp->xf_init))(tdbp, xsp, m);
-#ifdef ENCDEBUG
- if (encdebug)
- printf("tdbinit: no alg %d for spi %x, addr %x\n", alg, tdbp->tdb_spi,
- ntohl(tdbp->tdb_dst.s_addr));
-#endif
+ log(LOG_ERR, "tdb_init(): no alg %d for spi %08x, addr %x, proto %d", alg,
+ tdbp->tdb_spi, tdbp->tdb_dst.s_addr, tdbp->tdb_sproto);
/* Record establishment time */
tdbp->tdb_established = time.tv_sec;
-
+
m_freem(m);
return EINVAL;
}
@@ -264,63 +337,5 @@ tdb_init(struct tdb *tdbp, struct mbuf *m)
int
ipsp_kern(int off, char **bufp, int len)
{
- struct tdb *tdbp;
- int i, k;
- char *b;
-
- if (off != 0)
- return 0;
-
- if ((!ipspkernfs_dirty) && (ipspkernfs))
- {
- *bufp = ipspkernfs;
- return strlen(ipspkernfs);
- }
- else
- ipspkernfs_dirty = 0;
-
- if (ipspkernfs)
- {
- FREE(ipspkernfs, M_XDATA);
- ipspkernfs = NULL;
- }
-
- for (i = 0, k = 0; i < TDB_HASHMOD; i++)
- for (tdbp = tdbh[i]; tdbp != (struct tdb *) NULL; tdbp = tdbp->tdb_hnext)
- {
- /* Being paranoid to avoid buffer overflows */
-
- if (tdbp->tdb_xform)
- k += 126 + strlen(tdbp->tdb_xform->xf_name);
- else
- k += 60;
- }
-
- if (k == 0)
- return 0;
-
- MALLOC(ipspkernfs, char *, k + 1, M_XDATA, M_DONTWAIT);
- if (!ipspkernfs)
- return 0;
-
- for (i = 0, k = 0; i < TDB_HASHMOD; i++)
- for (tdbp = tdbh[i]; tdbp != (struct tdb *) NULL; tdbp = tdbp->tdb_hnext)
- {
- b = (char *)&(tdbp->tdb_dst.s_addr);
- if (!tdbp->tdb_xform)
- k += sprintf(ipspkernfs + k, "SPI=%x, destination=%d.%d.%d.%d\n",
- tdbp->tdb_spi, ((int)b[0] & 0xff), ((int)b[1] & 0xff), ((int)b[2] & 0xff), ((int)b[3] & 0xff));
- else
- k += sprintf(ipspkernfs + k,
- "SPI=%x, destination=%d.%d.%d.%d\n algorithm=%d (%s)\n next SPI=%x, previous SPI=%x\n",
- ntohl(tdbp->tdb_spi), ((int)b[0] & 0xff), ((int)b[1] & 0xff),
- ((int)b[2] & 0xff), ((int)b[3] & 0xff),
- tdbp->tdb_xform->xf_type, tdbp->tdb_xform->xf_name,
- (tdbp->tdb_onext ? ntohl(tdbp->tdb_onext->tdb_spi) : 0),
- (tdbp->tdb_inext ? ntohl(tdbp->tdb_inext->tdb_spi) : 0));
- }
-
- ipspkernfs[k] = '\0';
- *bufp = ipspkernfs;
- return strlen(ipspkernfs);
+ return 0;
}
diff --git a/sys/netinet/ip_ipsp.h b/sys/netinet/ip_ipsp.h
index e78c964f2f4..56cbb2b2701 100644
--- a/sys/netinet/ip_ipsp.h
+++ b/sys/netinet/ip_ipsp.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_ipsp.h,v 1.10 1997/07/02 06:58:43 provos Exp $ */
+/* $OpenBSD: ip_ipsp.h,v 1.11 1997/07/11 23:37:59 provos Exp $ */
/*
* The author of this code is John Ioannidis, ji@tla.org,
@@ -27,6 +27,21 @@
* IPSP global definitions.
*/
+struct flow
+{
+ struct flow *flow_next; /* Next in flow chain */
+ struct flow *flow_prev; /* Previous in flow chain */
+ struct tdb *flow_sa; /* Pointer to the SA */
+ struct in_addr flow_src; /* Source address */
+ struct in_addr flow_srcmask; /* Source netmask */
+ struct in_addr flow_dst; /* Destination address */
+ struct in_addr flow_dstmask; /* Destination netmask */
+ u_int16_t flow_sport; /* Source port, if applicable */
+ u_int16_t flow_dport; /* Destination port, if applicable */
+ u_int8_t flow_proto; /* Transport protocol, if applicable */
+ u_int8_t foo[3]; /* Alignment */
+};
+
struct tdb /* tunnel descriptor block */
{
struct tdb *tdb_hnext; /* next in hash chain */
@@ -73,12 +88,10 @@ struct tdb /* tunnel descriptor block */
* of outter IP header if we're doing
* tunneling */
caddr_t tdb_xdata; /* transformation data (opaque) */
- u_int16_t tdb_sport; /* Source port, if applicable */
- u_int16_t tdb_dport; /* Destination port, if applicable */
-
+ struct flow *tdb_flow; /* Which flows use this SA */
u_int8_t tdb_ttl; /* TTL used in tunneling */
- u_int8_t tdb_proto; /* Protocol carried */
- u_int16_t tdb_foo; /* alignment */
+ u_int8_t tdb_sproto; /* IPsec protocol */
+ u_int8_t tdb_foo[2]; /* Alignment */
};
#define TDB_HASHMOD 257
@@ -96,16 +109,18 @@ struct xformsw
};
#define XF_IP4 1 /* IP inside IP */
-#define XF_AHMD5 2 /* AH MD5 */
-#define XF_AHSHA1 3 /* AH SHA */
-#define XF_ESPDES 4 /* ESP DES-CBC */
-#define XF_ESP3DES 5 /* ESP DES3-CBC */
-#define XF_AHHMACMD5 6 /* AH-HMAC-MD5 with opt replay prot */
-#define XF_AHHMACSHA1 7 /* AH-HMAC-SHA1 with opt replay prot */
-#define XF_ESPDESMD5 8 /* ESP DES-CBC + MD5 */
-#define XF_ESP3DESMD5 9 /* ESP 3DES-CBC + MD5 */
-#define XF_NEWESP 10 /* The new ESP transforms */
-#define XF_NEWAH 11 /* The new AH transforms */
+#define XF_OLD_AH 2 /* RFCs 1828 & 1852 */
+#define XF_OLD_ESP 3 /* RFCs 1829 & 1851 */
+#define XF_NEW_AH 4 /* AH HMAC 96bits */
+#define XF_NEW_ESP 5 /* ESP + auth 96bits + replay counter */
+
+/* Supported key hash algorithms */
+#define ALG_AUTH_MD5 1
+#define ALG_AUTH_SHA1 2
+
+/* Supported encryption algorithms */
+#define ALG_ENC_DES 1
+#define ALG_ENC_3DES 2
#define XFT_AUTH 0x0001
#define XFT_CONF 0x0100
@@ -136,55 +151,84 @@ htonq(u_int64_t q)
extern unsigned char ipseczeroes[];
+/*
+ * Names for IPsec sysctl objects
+ */
+#define IPSECCTL_ENCDEBUG 1 /* turn debugging on/off */
+#define IPSECCTL_MAXID 2
+
+#define IPSECCTL_NAMES {\
+ { 0, 0 }, \
+ { "encdebug", CTLTYPE_INT }, \
+}
+
#ifdef _KERNEL
-#undef ENCDEBUG
extern int encdebug;
struct tdb *tdbh[TDB_HASHMOD];
extern struct xformsw xformsw[], *xformswNXFORMSW;
-extern u_int32_t reserve_spi(u_int32_t, struct in_addr, int *);
-extern struct tdb *gettdb(u_int32_t, struct in_addr);
+/* TDB management routines */
+extern u_int32_t reserve_spi(u_int32_t, struct in_addr, u_int8_t, int *);
+extern struct tdb *gettdb(u_int32_t, struct in_addr, u_int8_t);
extern void puttdb(struct tdb *);
extern int tdb_delete(struct tdb *, int);
-extern int ipe4_attach(void), ipe4_init(struct tdb *, struct xformsw *, struct mbuf *), ipe4_zeroize(struct tdb *);
-extern int ipe4_output(struct mbuf *, struct sockaddr_encap *, struct tdb *, struct mbuf **);
+/* Flow management routines */
+extern struct flow *get_flow(void);
+extern void put_flow(struct flow *, struct tdb *);
+extern void delete_flow(struct flow *, struct tdb *);
+extern struct flow *find_flow(struct in_addr, struct in_addr, struct in_addr,
+ struct in_addr, u_int8_t, u_int16_t, u_int16_t,
+ struct tdb *);
+extern struct flow *find_global_flow(struct in_addr, struct in_addr,
+ struct in_addr, struct in_addr, u_int8_t,
+ u_int16_t, u_int16_t);
+
+/* XF_IP4 */
+extern int ipe4_attach(void);
+extern int ipe4_init(struct tdb *, struct xformsw *, struct mbuf *);
+extern int ipe4_zeroize(struct tdb *);
+extern int ipe4_output(struct mbuf *, struct sockaddr_encap *, struct tdb *,
+ struct mbuf **);
extern void ipe4_input __P((struct mbuf *, ...));
-extern int ahmd5_attach(void), ahmd5_init(struct tdb *, struct xformsw *, struct mbuf *), ahmd5_zeroize(struct tdb *);
-extern int ahmd5_output(struct mbuf *, struct sockaddr_encap *, struct tdb *, struct mbuf **);
-extern struct mbuf *ahmd5_input(struct mbuf *, struct tdb *);
-
-extern int ahsha1_attach(void), ahsha1_init(struct tdb *, struct xformsw *, struct mbuf *), ahsha1_zeroize(struct tdb *);
-extern int ahsha1_output(struct mbuf *, struct sockaddr_encap *, struct tdb *, struct mbuf **);
-extern struct mbuf *ahsha1_input(struct mbuf *, struct tdb *);
-
-extern int ahhmacmd5_attach(void), ahhmacmd5_init(struct tdb *, struct xformsw *, struct mbuf *), ahhmacmd5_zeroize(struct tdb *);
-extern int ahhmacmd5_output(struct mbuf *, struct sockaddr_encap *, struct tdb *, struct mbuf **);
-extern struct mbuf *ahhmacmd5_input(struct mbuf *, struct tdb *);
-
-extern int ahhmacsha1_attach(void), ahhmacsha1_init(struct tdb *, struct xformsw *, struct mbuf *), ahhmacsha1_zeroize(struct tdb *);
-extern int ahhmacsha1_output(struct mbuf *, struct sockaddr_encap *, struct tdb *, struct mbuf **);
-extern struct mbuf *ahhmacsha1_input(struct mbuf *, struct tdb *);
-
-extern int espdes_attach(void), espdes_init(struct tdb *, struct xformsw *, struct mbuf *), espdes_zeroize(struct tdb *);
-extern int espdes_output(struct mbuf *, struct sockaddr_encap *, struct tdb *, struct mbuf **);
-extern struct mbuf *espdes_input(struct mbuf *, struct tdb *);
-
-extern int esp3des_attach(void), esp3des_init(struct tdb *, struct xformsw *, struct mbuf *), esp3des_zeroize(struct tdb *);
-extern int esp3des_output(struct mbuf *, struct sockaddr_encap *, struct tdb *, struct mbuf **);
-extern struct mbuf *esp3des_input(struct mbuf *, struct tdb *);
-
-extern int espdesmd5_attach(void), espdesmd5_init(struct tdb *, struct xformsw *, struct mbuf *), espdesmd5_zeroize(struct tdb *);
-extern int espdesmd5_output(struct mbuf *, struct sockaddr_encap *, struct tdb *, struct mbuf **);
-extern struct mbuf *espdesmd5_input(struct mbuf *, struct tdb *);
-
-extern int esp3desmd5_attach(void), esp3desmd5_init(struct tdb *, struct xformsw *, struct mbuf *), esp3desmd5_zeroize(struct tdb *);
-extern int esp3desmd5_output(struct mbuf *, struct sockaddr_encap *, struct tdb *, struct mbuf **);
-extern struct mbuf *esp3desmd5_input(struct mbuf *, struct tdb *);
-
+/* XF_OLD_AH */
+extern int ah_old_attach(void);
+extern int ah_old_init(struct tdb *, struct xformsw *, struct mbuf *);
+extern int ah_old_zeroize(struct tdb *);
+extern int ah_old_output(struct mbuf *, struct sockaddr_encap *, struct tdb *,
+ struct mbuf **);
+extern struct mbuf *ah_old_input(struct mbuf *, struct tdb *);
+
+/* XF_NEW_AH */
+extern int ah_new_attach(void);
+extern int ah_new_init(struct tdb *, struct xformsw *, struct mbuf *);
+extern int ah_new_zeroize(struct tdb *);
+extern int ah_new_output(struct mbuf *, struct sockaddr_encap *, struct tdb *,
+ struct mbuf **);
+extern struct mbuf *ah_new_input(struct mbuf *, struct tdb *);
+
+/* XF_OLD_ESP */
+extern int esp_old_attach(void);
+extern int esp_old_init(struct tdb *, struct xformsw *, struct mbuf *);
+extern int esp_old_zeroize(struct tdb *);
+extern int esp_old_output(struct mbuf *, struct sockaddr_encap *, struct tdb *,
+ struct mbuf **);
+extern struct mbuf *esp_old_input(struct mbuf *, struct tdb *);
+
+/* XF_NEW_ESP */
+extern int esp_new_attach(void);
+extern int esp_new_init(struct tdb *, struct xformsw *, struct mbuf *);
+extern int esp_new_zeroize(struct tdb *);
+extern int esp_new_output(struct mbuf *, struct sockaddr_encap *, struct tdb *,
+ struct mbuf **);
+extern struct mbuf *esp_new_input(struct mbuf *, struct tdb *);
+
+/* Padding */
extern caddr_t m_pad(struct mbuf *, int);
-extern int checkreplaywindow32(u_int32_t, u_int32_t, u_int32_t *, u_int32_t, u_int32_t *);
-extern int checkreplaywindow64(u_int64_t, u_int64_t *, u_int64_t, u_int64_t *);
+
+/* Replay window */
+extern int checkreplaywindow32(u_int32_t, u_int32_t, u_int32_t *, u_int32_t,
+ u_int32_t *);
#endif
diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c
index a282dd5eedb..5b722029c1e 100644
--- a/sys/netinet/ip_output.c
+++ b/sys/netinet/ip_output.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_output.c,v 1.15 1997/07/01 22:12:53 provos Exp $ */
+/* $OpenBSD: ip_output.c,v 1.16 1997/07/11 23:37:59 provos Exp $ */
/* $NetBSD: ip_output.c,v 1.28 1996/02/13 23:43:07 christos Exp $ */
/*
@@ -67,6 +67,7 @@
#include <netinet/ip_ipsp.h>
#include <netinet/udp.h>
#include <netinet/tcp.h>
+#include <sys/syslog.h>
#endif
static struct mbuf *ip_insertoptions __P((struct mbuf *, struct mbuf *, int *));
@@ -153,8 +154,8 @@ ip_output(m0, va_alist)
struct sockaddr_encap *dst, *gw;
struct tdb *tdb;
- bzero((caddr_t)re, sizeof (*re));
- dst = (struct sockaddr_encap *)&re->re_dst;
+ bzero((caddr_t) re, sizeof(*re));
+ dst = (struct sockaddr_encap *) &re->re_dst;
dst->sen_family = AF_ENCAP;
dst->sen_len = SENT_IP4_LEN;
dst->sen_type = SENT_IP4;
@@ -174,24 +175,27 @@ ip_output(m0, va_alist)
dst->sen_sport = ntohs(udp->uh_sport);
dst->sen_dport = ntohs(udp->uh_dport);
break;
+
case IPPROTO_TCP:
tcp = (struct tcphdr *) (mtod(m, u_char *) + hlen);
dst->sen_sport = ntohs(tcp->th_sport);
dst->sen_dport = ntohs(tcp->th_dport);
break;
+
default:
dst->sen_sport = 0;
dst->sen_dport = 0;
}
- rtalloc((struct route *)re);
+
+ rtalloc((struct route *) re);
if (re->re_rt == NULL)
goto no_encap;
- gw = (struct sockaddr_encap *)(re->re_rt->rt_gateway);
+ gw = (struct sockaddr_encap *) (re->re_rt->rt_gateway);
if (gw == NULL || gw->sen_type != SENT_IPSP) {
#ifdef ENCDEBUG
if (encdebug)
- printf("ip_output: no gw or gw data not IPSP\n");
+ printf("ip_output(): no gw or gw data not IPSP\n");
#endif /* ENCDEBUG */
m_freem(m);
RTFREE(re->re_rt);
@@ -210,45 +214,27 @@ ip_output(m0, va_alist)
* to the appropriate transformation.
*/
- tdb = (struct tdb *) gettdb(gw->sen_ipsp_spi, gw->sen_ipsp_dst);
+ tdb = (struct tdb *) gettdb(gw->sen_ipsp_spi, gw->sen_ipsp_dst,
+ gw->sen_ipsp_sproto);
/* Fix the ip_src field if necessary */
if ((ip->ip_src.s_addr == INADDR_ANY) && tdb)
ip->ip_src = tdb->tdb_src;
- /*
- * If we're doing IP-in-IP first, let the options be.
- * Otherwise, get rid of them.
- * XXX This means we don't send packets with IP options
- * XXX unless they're encapsulated (and, presumably,
- * XXX subsequently authenticated).
- */
- if (tdb && tdb->tdb_xform)
- if ((tdb->tdb_xform->xf_type != XF_IP4) ||
- (tdb->tdb_flags & TDBF_TUNNELING))
- if (hlen > sizeof (struct ip)) { /* XXX IPOPT */
- ip_stripoptions(m, (struct mbuf *)0);
- hlen = sizeof (struct ip);
- }
-
/* Now fix the checksum */
ip->ip_sum = in_cksum(m, hlen);
#ifdef ENCDEBUG
if (encdebug)
- printf("ip_output: tdb=0x%x, tdb->tdb_xform=0x%x, tdb->tdb_xform->xf_output=%x\n", tdb, tdb->tdb_xform, tdb->tdb_xform->xf_output);
+ printf("ip_output(): tdb=%08x, tdb->tdb_xform=0x%x, tdb->tdb_xform->xf_output=%x, sproto=%x\n", tdb, tdb->tdb_xform, tdb->tdb_xform->xf_output, tdb->tdb_sproto);
#endif /* ENCDEBUG */
while (tdb && tdb->tdb_xform) {
m0 = NULL;
/* Check if the SPI is invalid */
- if (tdb->tdb_flags & TDBF_INVALID)
- {
-#ifdef ENCDEBUG
- if (encdebug)
- printf("ip_output: attempt to use invalid SPI %08x", tdb->tdb_spi);
-#endif /* ENCDEBUG */
+ if (tdb->tdb_flags & TDBF_INVALID) {
+ log(LOG_ALERT, "ip_output(): attempt to use invalid SA %x/%08x/%x", tdb->tdb_dst, tdb->tdb_spi, tdb->tdb_sproto);
m_freem(m);
RTFREE(re->re_rt);
return ENXIO;
@@ -258,7 +244,7 @@ ip_output(m0, va_alist)
if (tdb->tdb_flags & TDBF_TUNNELING) {
#ifdef ENCDEBUG
if (encdebug)
- printf("ip_output: doing tunneling\n");
+ printf("ip_output(): tunneling\n");
#endif /* ENCDEBUG */
/* Register first use */
@@ -277,8 +263,8 @@ ip_output(m0, va_alist)
#ifdef ENCDEBUG
if (encdebug)
- printf("ip_output: calling %s\n",
- tdb->tdb_xform->xf_name);
+ printf("ip_output(): calling %s\n",
+ tdb->tdb_xform->xf_name);
#endif /* ENCDEBUG */
/* Register first use */
@@ -308,7 +294,8 @@ ip_output(m0, va_alist)
NTOHS(ip->ip_len);
NTOHS(ip->ip_off);
- return ip_output(m, NULL, NULL, IP_ENCAPSULATED | IP_RAWOUTPUT, NULL);
+ return ip_output(m, NULL, NULL, IP_ENCAPSULATED | IP_RAWOUTPUT,
+ NULL);
no_encap:
/* This is for possible future use, don't move or delete */
diff --git a/sys/netinet/ip_sha1.h b/sys/netinet/ip_sha1.h
index 64615eb0e3a..186a774f9a2 100644
--- a/sys/netinet/ip_sha1.h
+++ b/sys/netinet/ip_sha1.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_sha1.h,v 1.3 1997/06/21 00:09:20 deraadt Exp $ */
+/* $OpenBSD: ip_sha1.h,v 1.4 1997/07/11 23:38:00 provos Exp $ */
/*
SHA-1 in C
@@ -6,6 +6,9 @@ By Steve Reid <steve@edmweb.com>
100% Public Domain
*/
+#ifndef _SHA1_H_
+#define _SHA1_H_
+
typedef struct {
u_int32_t state[5];
u_int32_t count[2];
@@ -16,3 +19,5 @@ void SHA1Transform(u_int32_t state[5], unsigned char buffer[64]);
void SHA1Init(SHA1_CTX* context);
void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int len);
void SHA1Final(unsigned char digest[20], SHA1_CTX* context);
+
+#endif /* _SHA1_H_ */
diff --git a/sys/sys/mbuf.h b/sys/sys/mbuf.h
index 92c66064bcd..224e8d3c6a7 100644
--- a/sys/sys/mbuf.h
+++ b/sys/sys/mbuf.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: mbuf.h,v 1.4 1997/06/08 18:17:14 deraadt Exp $ */
+/* $OpenBSD: mbuf.h,v 1.5 1997/07/11 23:37:50 provos Exp $ */
/* $NetBSD: mbuf.h,v 1.19 1996/02/09 18:25:14 christos Exp $ */
/*
@@ -123,9 +123,12 @@ struct mbuf {
/* mbuf pkthdr flags, also in m_flags */
#define M_BCAST 0x0100 /* send/received as link-level broadcast */
#define M_MCAST 0x0200 /* send/received as link-level multicast */
+#define M_CONF 0x0400 /* packet was encrypted (ESP-transport) */
+#define M_AUTH 0x0800 /* packet was authenticated (AH) */
+#define M_CTUN 0x1000 /* packet was encrypted (ESP-tunnel) */
/* flags copied when copying m_pkthdr */
-#define M_COPYFLAGS (M_PKTHDR|M_EOR|M_BCAST|M_MCAST)
+#define M_COPYFLAGS (M_PKTHDR|M_EOR|M_BCAST|M_MCAST|M_CONF|M_AUTH|M_CTUN)
/* mbuf types */
#define MT_FREE 0 /* should be on free list */