summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/conf/files1
-rw-r--r--sys/conf/options1
-rw-r--r--sys/net/pfkeyv2.h6
-rw-r--r--sys/netinet/ip.h12
-rw-r--r--sys/netinet/ip_output.c1
-rw-r--r--sys/netinet/tcp.h3
-rw-r--r--sys/netinet/tcp_input.c17
-rw-r--r--sys/netinet/tcp_output.c37
-rw-r--r--sys/netinet/tcp_reass.c17
-rw-r--r--sys/netinet/tcp_subr.c114
-rw-r--r--sys/netinet/tcp_syncache.c40
-rw-r--r--sys/netinet/tcp_timewait.c114
-rw-r--r--sys/netinet/tcp_usrreq.c19
-rw-r--r--sys/netinet/tcp_var.h25
-rw-r--r--sys/netinet6/ipsec.h2
-rw-r--r--sys/netipsec/ipsec.h1
-rw-r--r--sys/netipsec/key.c18
17 files changed, 424 insertions, 4 deletions
diff --git a/sys/conf/files b/sys/conf/files
index 233ae14..88a23b5 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -1506,6 +1506,7 @@ netipsec/xform_ah.c optional fast_ipsec
netipsec/xform_esp.c optional fast_ipsec
netipsec/xform_ipcomp.c optional fast_ipsec
netipsec/xform_ipip.c optional fast_ipsec
+netipsec/xform_tcp.c optional fast_ipsec tcp_signature
netipx/ipx.c optional ipx
netipx/ipx_cksum.c optional ipx
netipx/ipx_input.c optional ipx
diff --git a/sys/conf/options b/sys/conf/options
index 3b36f81..d9c37d6 100644
--- a/sys/conf/options
+++ b/sys/conf/options
@@ -360,6 +360,7 @@ PPP_FILTER opt_ppp.h
RANDOM_IP_ID
SLIP_IFF_OPTS opt_slip.h
TCPDEBUG
+TCP_SIGNATURE opt_inet.h
TCP_DROP_SYNFIN opt_tcp_input.h
XBONEHACK
MBUF_STRESS_TEST opt_mbuf_stress_test.h
diff --git a/sys/net/pfkeyv2.h b/sys/net/pfkeyv2.h
index 4a3fc84..a164f3b 100644
--- a/sys/net/pfkeyv2.h
+++ b/sys/net/pfkeyv2.h
@@ -286,7 +286,8 @@ struct sadb_x_ipsecrequest {
#define SADB_SATYPE_MIP 8
#define SADB_X_SATYPE_IPCOMP 9
/*#define SADB_X_SATYPE_POLICY 10 obsolete, do not reuse */
-#define SADB_SATYPE_MAX 11
+#define SADB_X_SATYPE_TCPSIGNATURE 11
+#define SADB_SATYPE_MAX 12
#define SADB_SASTATE_LARVAL 0
#define SADB_SASTATE_MATURE 1
@@ -300,7 +301,7 @@ struct sadb_x_ipsecrequest {
#define SADB_AALG_NONE 0
#define SADB_AALG_MD5HMAC 2
#define SADB_AALG_SHA1HMAC 3
-#define SADB_AALG_MAX 251
+#define SADB_AALG_MAX 252
/* private allocations - based on RFC2407/IANA assignment */
#define SADB_X_AALG_SHA2_256 5
#define SADB_X_AALG_SHA2_384 6
@@ -311,6 +312,7 @@ struct sadb_x_ipsecrequest {
#define SADB_X_AALG_MD5 249 /* Keyed MD5 */
#define SADB_X_AALG_SHA 250 /* Keyed SHA */
#define SADB_X_AALG_NULL 251 /* null authentication */
+#define SADB_X_AALG_TCP_MD5 252 /* Keyed TCP-MD5 (RFC2385) */
/* RFC2367 numbers - meets RFC2407 */
#define SADB_EALG_NONE 0
diff --git a/sys/netinet/ip.h b/sys/netinet/ip.h
index 025ad08..aca0432 100644
--- a/sys/netinet/ip.h
+++ b/sys/netinet/ip.h
@@ -193,4 +193,16 @@ struct ip_timestamp {
#define IP_MSS 576 /* default maximum segment size */
+/*
+ * This is the real IPv4 pseudo header, used for computing the TCP and UDP
+ * checksums. For the Internet checksum, struct ipovly can be used instead.
+ * For stronger checksums, the real thing must be used.
+ */
+struct ippseudo {
+ struct in_addr ippseudo_src; /* source internet address */
+ struct in_addr ippseudo_dst; /* destination internet address */
+ u_int8_t ippseudo_pad; /* pad, must be zero */
+ u_int8_t ippseudo_p; /* protocol */
+ u_int16_t ippseudo_len; /* protocol length */
+} __packed;
#endif
diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c
index a872c00..e567936 100644
--- a/sys/netinet/ip_output.c
+++ b/sys/netinet/ip_output.c
@@ -499,6 +499,7 @@ sendit:
case IPSEC_POLICY_BYPASS:
case IPSEC_POLICY_NONE:
+ case IPSEC_POLICY_TCP:
/* no need to do IPsec. */
goto skip_ipsec;
diff --git a/sys/netinet/tcp.h b/sys/netinet/tcp.h
index d958aaf..1df59b6 100644
--- a/sys/netinet/tcp.h
+++ b/sys/netinet/tcp.h
@@ -102,6 +102,8 @@ struct tcphdr {
#define TCPOLEN_CC_APPA (TCPOLEN_CC+2)
#define TCPOPT_CC_HDR(ccopt) \
(TCPOPT_NOP<<24|TCPOPT_NOP<<16|(ccopt)<<8|TCPOLEN_CC)
+#define TCPOPT_SIGNATURE 19 /* Keyed MD5: RFC 2385 */
+#define TCPOLEN_SIGNATURE 18
/*
* Default maximum segment size for TCP.
@@ -156,6 +158,7 @@ struct tcphdr {
#define TCP_MAXSEG 0x02 /* set maximum segment size */
#define TCP_NOPUSH 0x04 /* don't push last block of write */
#define TCP_NOOPT 0x08 /* don't use TCP options */
+#define TCP_SIGNATURE_ENABLE 0x10 /* use MD5 digests (RFC2385) */
#endif
#endif /* !_NETINET_TCP_H_ */
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c
index 2b7f99a..6562368 100644
--- a/sys/netinet/tcp_input.c
+++ b/sys/netinet/tcp_input.c
@@ -35,6 +35,7 @@
*/
#include "opt_ipfw.h" /* for ipfw_fwd */
+#include "opt_inet.h"
#include "opt_inet6.h"
#include "opt_ipsec.h"
#include "opt_mac.h"
@@ -349,7 +350,8 @@ tcp_input(m, off0)
register struct inpcb *inp = NULL;
u_char *optp = NULL;
int optlen = 0;
- int len, tlen, off;
+ int len = 0;
+ int tlen, off;
int drop_hdrlen;
register struct tcpcb *tp = 0;
register int thflags;
@@ -2524,6 +2526,19 @@ tcp_dooptions(to, cp, cnt, is_syn)
(char *)&to->to_ccecho, sizeof(to->to_ccecho));
to->to_ccecho = ntohl(to->to_ccecho);
break;
+#ifdef TCP_SIGNATURE
+ /*
+ * XXX In order to reply to a host which has set the
+ * TCP_SIGNATURE option in its initial SYN, we have to
+ * record the fact that the option was observed here
+ * for the syncache code to perform the correct response.
+ */
+ case TCPOPT_SIGNATURE:
+ if (optlen != TCPOLEN_SIGNATURE)
+ continue;
+ to->to_flags |= (TOF_SIGNATURE | TOF_SIGLEN);
+ break;
+#endif /* TCP_SIGNATURE */
default:
continue;
}
diff --git a/sys/netinet/tcp_output.c b/sys/netinet/tcp_output.c
index f30d6c3..c868033 100644
--- a/sys/netinet/tcp_output.c
+++ b/sys/netinet/tcp_output.c
@@ -34,6 +34,7 @@
* $FreeBSD$
*/
+#include "opt_inet.h"
#include "opt_inet6.h"
#include "opt_ipsec.h"
#include "opt_mac.h"
@@ -115,6 +116,7 @@ tcp_output(struct tcpcb *tp)
struct socket *so = tp->t_inpcb->inp_socket;
long len, recwin, sendwin;
int off, flags, error;
+ int sigoff = 0;
struct mbuf *m;
struct ip *ip = NULL;
struct ipovly *ipov = NULL;
@@ -537,6 +539,32 @@ send:
}
}
+#ifdef TCP_SIGNATURE
+#ifdef INET6
+ if (!isipv6)
+#endif
+ if (tp->t_flags & TF_SIGNATURE) {
+ int i;
+ u_char *bp;
+ /*
+ * Initialize TCP-MD5 option (RFC2385)
+ */
+ bp = (u_char *)opt + optlen;
+ *bp++ = TCPOPT_SIGNATURE;
+ *bp++ = TCPOLEN_SIGNATURE;
+ sigoff = optlen + 2;
+ for (i = 0; i < TCP_SIGLEN; i++)
+ *bp++ = 0;
+ optlen += TCPOLEN_SIGNATURE;
+ /*
+ * Terminate options list and maintain 32-bit alignment.
+ */
+ *bp++ = TCPOPT_NOP;
+ *bp++ = TCPOPT_EOL;
+ optlen += 2;
+ }
+#endif /* TCP_SIGNATURE */
+
hdrlen += optlen;
#ifdef INET6
@@ -754,6 +782,15 @@ send:
*/
tp->snd_up = tp->snd_una; /* drag it along */
+#ifdef TCP_SIGNATURE
+#ifdef INET6
+ if (!isipv6)
+#endif
+ if (tp->t_flags & TF_SIGNATURE)
+ tcpsignature_compute(m, sizeof(struct ip), len, optlen,
+ (u_char *)(th + 1) + sigoff, IPSEC_DIR_OUTBOUND);
+#endif /* TCP_SIGNATURE */
+
/*
* Put TCP length in extended header, and then
* checksum extended header and data.
diff --git a/sys/netinet/tcp_reass.c b/sys/netinet/tcp_reass.c
index 2b7f99a..6562368 100644
--- a/sys/netinet/tcp_reass.c
+++ b/sys/netinet/tcp_reass.c
@@ -35,6 +35,7 @@
*/
#include "opt_ipfw.h" /* for ipfw_fwd */
+#include "opt_inet.h"
#include "opt_inet6.h"
#include "opt_ipsec.h"
#include "opt_mac.h"
@@ -349,7 +350,8 @@ tcp_input(m, off0)
register struct inpcb *inp = NULL;
u_char *optp = NULL;
int optlen = 0;
- int len, tlen, off;
+ int len = 0;
+ int tlen, off;
int drop_hdrlen;
register struct tcpcb *tp = 0;
register int thflags;
@@ -2524,6 +2526,19 @@ tcp_dooptions(to, cp, cnt, is_syn)
(char *)&to->to_ccecho, sizeof(to->to_ccecho));
to->to_ccecho = ntohl(to->to_ccecho);
break;
+#ifdef TCP_SIGNATURE
+ /*
+ * XXX In order to reply to a host which has set the
+ * TCP_SIGNATURE option in its initial SYN, we have to
+ * record the fact that the option was observed here
+ * for the syncache code to perform the correct response.
+ */
+ case TCPOPT_SIGNATURE:
+ if (optlen != TCPOLEN_SIGNATURE)
+ continue;
+ to->to_flags |= (TOF_SIGNATURE | TOF_SIGLEN);
+ break;
+#endif /* TCP_SIGNATURE */
default:
continue;
}
diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c
index 4b56295..689d0cd 100644
--- a/sys/netinet/tcp_subr.c
+++ b/sys/netinet/tcp_subr.c
@@ -35,6 +35,7 @@
*/
#include "opt_compat.h"
+#include "opt_inet.h"
#include "opt_inet6.h"
#include "opt_ipsec.h"
#include "opt_mac.h"
@@ -101,9 +102,11 @@
#ifdef FAST_IPSEC
#include <netipsec/ipsec.h>
+#include <netipsec/xform.h>
#ifdef INET6
#include <netipsec/ipsec6.h>
#endif
+#include <netipsec/key.h>
#define IPSEC
#endif /*FAST_IPSEC*/
@@ -1917,3 +1920,114 @@ tcp_xmit_bandwidth_limit(struct tcpcb *tp, tcp_seq ack_seq)
tp->snd_bwnd = bwnd;
}
+#ifdef TCP_SIGNATURE
+/*
+ * Compute TCP-MD5 hash of a TCPv4 segment. (RFC2385)
+ *
+ * We do this over ip, tcphdr, segment data, and the key in the SADB.
+ * When called from tcp_input(), we can be sure that th_sum has been
+ * zeroed out and verified already.
+ *
+ * This function is for IPv4 use only. Calling this function with an
+ * IPv6 packet in the mbuf chain will yield undefined results.
+ *
+ * Return 0 if successful, otherwise return -1.
+ *
+ * XXX The key is retrieved from the system's PF_KEY SADB, by keying a
+ * search with the destination IP address, and a 'magic SPI' to be
+ * determined by the application. This is hardcoded elsewhere to 1179
+ * right now. Another branch of this code exists which uses the SPD to
+ * specify per-application flows but it is unstable.
+ */
+int
+tcpsignature_compute(
+ struct mbuf *m, /* mbuf chain */
+ int off0, /* offset to TCP header */
+ int len, /* length of TCP data */
+ int optlen, /* length of TCP options */
+ u_char *buf, /* storage for MD5 digest */
+ u_int direction) /* direction of flow */
+{
+ union sockaddr_union dst;
+ struct ippseudo ippseudo;
+ MD5_CTX ctx;
+ int doff;
+ struct ip *ip;
+ struct ipovly *ipovly;
+ struct secasvar *sav;
+ struct tcphdr *th;
+ u_short savecsum;
+
+ KASSERT(m != NULL, ("passed NULL mbuf. Game over."));
+ KASSERT(buf != NULL, ("passed NULL storage pointer for MD5 signature"));
+ /*
+ * Extract the destination from the IP header in the mbuf.
+ */
+ ip = mtod(m, struct ip *);
+ bzero(&dst, sizeof(union sockaddr_union));
+ dst.sa.sa_len = sizeof(struct sockaddr_in);
+ dst.sa.sa_family = AF_INET;
+ dst.sin.sin_addr = (direction == IPSEC_DIR_INBOUND) ?
+ ip->ip_src : ip->ip_dst;
+ /*
+ * Look up an SADB entry which matches the address found in
+ * the segment.
+ */
+ sav = KEY_ALLOCSA(&dst, IPPROTO_TCP, htonl(TCP_SIG_SPI));
+ if (sav == NULL) {
+ printf("%s: SADB lookup failed for %s\n", __func__,
+ inet_ntoa(dst.sin.sin_addr));
+ return (EINVAL);
+ }
+ MD5Init(&ctx);
+
+ ipovly = (struct ipovly *)ip;
+ th = (struct tcphdr *)((u_char *)ip + off0);
+ doff = off0 + sizeof(struct tcphdr) + optlen;
+ /*
+ * Step 1: Update MD5 hash with IP pseudo-header.
+ *
+ * XXX The ippseudo header MUST be digested in network byte order,
+ * or else we'll fail the regression test. Assume all fields we've
+ * been doing arithmetic on have been in host byte order.
+ * XXX One cannot depend on ipovly->ih_len here. When called from
+ * tcp_output(), the underlying ip_len member has not yet been set.
+ */
+ ippseudo.ippseudo_src = ipovly->ih_src;
+ ippseudo.ippseudo_dst = ipovly->ih_dst;
+ ippseudo.ippseudo_pad = 0;
+ ippseudo.ippseudo_p = IPPROTO_TCP;
+ ippseudo.ippseudo_len = htons(len + sizeof(struct tcphdr) + optlen);
+ MD5Update(&ctx, (char *)&ippseudo, sizeof(struct ippseudo));
+ /*
+ * Step 2: Update MD5 hash with TCP header, excluding options.
+ * The TCP checksum must be set to zero.
+ */
+ savecsum = th->th_sum;
+ th->th_sum = 0;
+ MD5Update(&ctx, (char *)th, sizeof(struct tcphdr));
+ th->th_sum = savecsum;
+ /*
+ * Step 3: Update MD5 hash with TCP segment data.
+ * Use m_apply() to avoid an early m_pullup().
+ */
+ if (len > 0)
+ m_apply(m, doff, len, tcpsignature_apply, &ctx);
+ /*
+ * Step 4: Update MD5 hash with shared secret.
+ */
+ MD5Update(&ctx, _KEYBUF(sav->key_auth), _KEYLEN(sav->key_auth));
+ MD5Final(buf, &ctx);
+ key_sa_recordxfer(sav, m);
+ KEY_FREESAV(&sav);
+ return (0);
+}
+
+int
+tcpsignature_apply(void *fstate, void *data, unsigned int len)
+{
+
+ MD5Update((MD5_CTX *)fstate, (unsigned char *)data, len);
+ return (0);
+}
+#endif /* TCP_SIGNATURE */
diff --git a/sys/netinet/tcp_syncache.c b/sys/netinet/tcp_syncache.c
index 9343bf4..14eb315 100644
--- a/sys/netinet/tcp_syncache.c
+++ b/sys/netinet/tcp_syncache.c
@@ -34,6 +34,7 @@
* $FreeBSD$
*/
+#include "opt_inet.h"
#include "opt_inet6.h"
#include "opt_ipsec.h"
#include "opt_mac.h"
@@ -695,6 +696,10 @@ syncache_socket(sc, lso, m)
tp->cc_send = sc->sc_cc_send;
tp->cc_recv = sc->sc_cc_recv;
}
+#ifdef TCP_SIGNATURE
+ if (sc->sc_flags & SCF_SIGNATURE)
+ tp->t_flags |= TF_SIGNATURE;
+#endif /* TCP_SIGNATURE */
/*
* Set up MSS and get cached values from tcp_hostcache.
@@ -970,6 +975,17 @@ syncache_add(inc, to, th, sop, m)
}
if (tp->t_flags & TF_NOOPT)
sc->sc_flags = SCF_NOOPT;
+#ifdef TCP_SIGNATURE
+ /*
+ * If listening socket requested TCP digests, and received SYN
+ * contains the option, flag this in the syncache so that
+ * syncache_respond() will do the right thing with the SYN+ACK.
+ * XXX Currently we always record the option by default and will
+ * attempt to use it in syncache_respond().
+ */
+ if (to->to_flags & TOF_SIGNATURE)
+ sc->sc_flags = SCF_SIGNATURE;
+#endif /* TCP_SIGNATURE */
/*
* XXX
@@ -1083,6 +1099,10 @@ syncache_respond(sc, m)
((sc->sc_flags & SCF_WINSCALE) ? 4 : 0) +
((sc->sc_flags & SCF_TIMESTAMP) ? TCPOLEN_TSTAMP_APPA : 0) +
((sc->sc_flags & SCF_CC) ? TCPOLEN_CC_APPA * 2 : 0);
+#ifdef TCP_SIGNATURE
+ optlen += ((sc->sc_flags & SCF_SIGNATURE) ?
+ (TCPOLEN_SIGNATURE + 2) : 0);
+#endif /* TCP_SIGNATURE */
}
tlen = hlen + sizeof(struct tcphdr) + optlen;
@@ -1200,6 +1220,26 @@ syncache_respond(sc, m)
*lp = htonl(sc->sc_cc_recv);
optp += TCPOLEN_CC_APPA * 2;
}
+
+#ifdef TCP_SIGNATURE
+ /*
+ * Handle TCP-MD5 passive opener response.
+ */
+ if (sc->sc_flags & SCF_SIGNATURE) {
+ u_int8_t *bp = optp;
+ int i;
+
+ *bp++ = TCPOPT_SIGNATURE;
+ *bp++ = TCPOLEN_SIGNATURE;
+ for (i = 0; i < TCP_SIGLEN; i++)
+ *bp++ = 0;
+ tcpsignature_compute(m, sizeof(struct ip), 0, optlen,
+ optp + 2, IPSEC_DIR_OUTBOUND);
+ *bp++ = TCPOPT_NOP;
+ *bp++ = TCPOPT_EOL;
+ optp += TCPOLEN_SIGNATURE + 2;
+ }
+#endif /* TCP_SIGNATURE */
}
#ifdef INET6
diff --git a/sys/netinet/tcp_timewait.c b/sys/netinet/tcp_timewait.c
index 4b56295..689d0cd 100644
--- a/sys/netinet/tcp_timewait.c
+++ b/sys/netinet/tcp_timewait.c
@@ -35,6 +35,7 @@
*/
#include "opt_compat.h"
+#include "opt_inet.h"
#include "opt_inet6.h"
#include "opt_ipsec.h"
#include "opt_mac.h"
@@ -101,9 +102,11 @@
#ifdef FAST_IPSEC
#include <netipsec/ipsec.h>
+#include <netipsec/xform.h>
#ifdef INET6
#include <netipsec/ipsec6.h>
#endif
+#include <netipsec/key.h>
#define IPSEC
#endif /*FAST_IPSEC*/
@@ -1917,3 +1920,114 @@ tcp_xmit_bandwidth_limit(struct tcpcb *tp, tcp_seq ack_seq)
tp->snd_bwnd = bwnd;
}
+#ifdef TCP_SIGNATURE
+/*
+ * Compute TCP-MD5 hash of a TCPv4 segment. (RFC2385)
+ *
+ * We do this over ip, tcphdr, segment data, and the key in the SADB.
+ * When called from tcp_input(), we can be sure that th_sum has been
+ * zeroed out and verified already.
+ *
+ * This function is for IPv4 use only. Calling this function with an
+ * IPv6 packet in the mbuf chain will yield undefined results.
+ *
+ * Return 0 if successful, otherwise return -1.
+ *
+ * XXX The key is retrieved from the system's PF_KEY SADB, by keying a
+ * search with the destination IP address, and a 'magic SPI' to be
+ * determined by the application. This is hardcoded elsewhere to 1179
+ * right now. Another branch of this code exists which uses the SPD to
+ * specify per-application flows but it is unstable.
+ */
+int
+tcpsignature_compute(
+ struct mbuf *m, /* mbuf chain */
+ int off0, /* offset to TCP header */
+ int len, /* length of TCP data */
+ int optlen, /* length of TCP options */
+ u_char *buf, /* storage for MD5 digest */
+ u_int direction) /* direction of flow */
+{
+ union sockaddr_union dst;
+ struct ippseudo ippseudo;
+ MD5_CTX ctx;
+ int doff;
+ struct ip *ip;
+ struct ipovly *ipovly;
+ struct secasvar *sav;
+ struct tcphdr *th;
+ u_short savecsum;
+
+ KASSERT(m != NULL, ("passed NULL mbuf. Game over."));
+ KASSERT(buf != NULL, ("passed NULL storage pointer for MD5 signature"));
+ /*
+ * Extract the destination from the IP header in the mbuf.
+ */
+ ip = mtod(m, struct ip *);
+ bzero(&dst, sizeof(union sockaddr_union));
+ dst.sa.sa_len = sizeof(struct sockaddr_in);
+ dst.sa.sa_family = AF_INET;
+ dst.sin.sin_addr = (direction == IPSEC_DIR_INBOUND) ?
+ ip->ip_src : ip->ip_dst;
+ /*
+ * Look up an SADB entry which matches the address found in
+ * the segment.
+ */
+ sav = KEY_ALLOCSA(&dst, IPPROTO_TCP, htonl(TCP_SIG_SPI));
+ if (sav == NULL) {
+ printf("%s: SADB lookup failed for %s\n", __func__,
+ inet_ntoa(dst.sin.sin_addr));
+ return (EINVAL);
+ }
+ MD5Init(&ctx);
+
+ ipovly = (struct ipovly *)ip;
+ th = (struct tcphdr *)((u_char *)ip + off0);
+ doff = off0 + sizeof(struct tcphdr) + optlen;
+ /*
+ * Step 1: Update MD5 hash with IP pseudo-header.
+ *
+ * XXX The ippseudo header MUST be digested in network byte order,
+ * or else we'll fail the regression test. Assume all fields we've
+ * been doing arithmetic on have been in host byte order.
+ * XXX One cannot depend on ipovly->ih_len here. When called from
+ * tcp_output(), the underlying ip_len member has not yet been set.
+ */
+ ippseudo.ippseudo_src = ipovly->ih_src;
+ ippseudo.ippseudo_dst = ipovly->ih_dst;
+ ippseudo.ippseudo_pad = 0;
+ ippseudo.ippseudo_p = IPPROTO_TCP;
+ ippseudo.ippseudo_len = htons(len + sizeof(struct tcphdr) + optlen);
+ MD5Update(&ctx, (char *)&ippseudo, sizeof(struct ippseudo));
+ /*
+ * Step 2: Update MD5 hash with TCP header, excluding options.
+ * The TCP checksum must be set to zero.
+ */
+ savecsum = th->th_sum;
+ th->th_sum = 0;
+ MD5Update(&ctx, (char *)th, sizeof(struct tcphdr));
+ th->th_sum = savecsum;
+ /*
+ * Step 3: Update MD5 hash with TCP segment data.
+ * Use m_apply() to avoid an early m_pullup().
+ */
+ if (len > 0)
+ m_apply(m, doff, len, tcpsignature_apply, &ctx);
+ /*
+ * Step 4: Update MD5 hash with shared secret.
+ */
+ MD5Update(&ctx, _KEYBUF(sav->key_auth), _KEYLEN(sav->key_auth));
+ MD5Final(buf, &ctx);
+ key_sa_recordxfer(sav, m);
+ KEY_FREESAV(&sav);
+ return (0);
+}
+
+int
+tcpsignature_apply(void *fstate, void *data, unsigned int len)
+{
+
+ MD5Update((MD5_CTX *)fstate, (unsigned char *)data, len);
+ return (0);
+}
+#endif /* TCP_SIGNATURE */
diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c
index 212ccd2..6d4e540 100644
--- a/sys/netinet/tcp_usrreq.c
+++ b/sys/netinet/tcp_usrreq.c
@@ -35,6 +35,7 @@
*/
#include "opt_ipsec.h"
+#include "opt_inet.h"
#include "opt_inet6.h"
#include "opt_tcpdebug.h"
@@ -1065,6 +1066,19 @@ tcp_ctloutput(so, sopt)
switch (sopt->sopt_dir) {
case SOPT_SET:
switch (sopt->sopt_name) {
+#ifdef TCP_SIGNATURE
+ case TCP_SIGNATURE_ENABLE:
+ error = sooptcopyin(sopt, &optval, sizeof optval,
+ sizeof optval);
+ if (error)
+ break;
+
+ if (optval > 0)
+ tp->t_flags |= TF_SIGNATURE;
+ else
+ tp->t_flags &= ~TF_SIGNATURE;
+ break;
+#endif /* TCP_SIGNATURE */
case TCP_NODELAY:
case TCP_NOOPT:
error = sooptcopyin(sopt, &optval, sizeof optval,
@@ -1125,6 +1139,11 @@ tcp_ctloutput(so, sopt)
case SOPT_GET:
switch (sopt->sopt_name) {
+#ifdef TCP_SIGNATURE
+ case TCP_SIGNATURE_ENABLE:
+ optval = (tp->t_flags & TF_SIGNATURE) ? 1 : 0;
+ break;
+#endif /* TCP_SIGNATURE */
case TCP_NODELAY:
optval = tp->t_flags & TF_NODELAY;
break;
diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h
index 33353b4..0390f1e 100644
--- a/sys/netinet/tcp_var.h
+++ b/sys/netinet/tcp_var.h
@@ -105,6 +105,7 @@ struct tcpcb {
#define TF_RXWIN0SENT 0x080000 /* sent a receiver win 0 in response */
#define TF_FASTRECOVERY 0x100000 /* in NewReno Fast Recovery */
#define TF_WASFRECOVERY 0x200000 /* was in NewReno Fast Recovery */
+#define TF_SIGNATURE 0x400000 /* require MD5 digests (RFC2385) */
int t_force; /* 1 if forcing out a byte */
tcp_seq snd_una; /* send unacknowledged */
@@ -189,6 +190,21 @@ struct tcpcb {
#define ENTER_FASTRECOVERY(tp) tp->t_flags |= TF_FASTRECOVERY
#define EXIT_FASTRECOVERY(tp) tp->t_flags &= ~TF_FASTRECOVERY
+#ifdef TCP_SIGNATURE
+/*
+ * Defines which are needed by the xform_tcp module and tcp_[in|out]put
+ * for SADB verification and lookup.
+ */
+#define TCP_SIGLEN 16 /* length of computed digest in bytes */
+#define TCP_KEYLEN_MIN 1 /* minimum length of TCP-MD5 key */
+#define TCP_KEYLEN_MAX 80 /* maximum length of TCP-MD5 key */
+/*
+ * Only a single SA per host may be specified at this time. An SPI is
+ * needed in order for the KEY_ALLOCSA() lookup to work.
+ */
+#define TCP_SIG_SPI 0x1000
+#endif /* TCP_SIGNATURE */
+
/*
* Structure to hold TCP options that are only used during segment
* processing (in tcp_input), but not held in the tcpcb.
@@ -203,6 +219,8 @@ struct tcpopt {
#define TOF_CCECHO 0x0008
#define TOF_MSS 0x0010
#define TOF_SCALE 0x0020
+#define TOF_SIGNATURE 0x0040 /* signature option present */
+#define TOF_SIGLEN 0x0080 /* sigature length valid (RFC2385) */
u_int32_t to_tsval;
u_int32_t to_tsecr;
tcp_cc to_cc; /* holds CC or CCnew */
@@ -234,6 +252,7 @@ struct syncache {
#define SCF_TIMESTAMP 0x04 /* negotiated timestamps */
#define SCF_CC 0x08 /* negotiated CC */
#define SCF_UNREACH 0x10 /* icmp unreachable received */
+#define SCF_SIGNATURE 0x20 /* send MD5 digests */
TAILQ_ENTRY(syncache) sc_hash;
TAILQ_ENTRY(syncache) sc_timerq;
};
@@ -549,6 +568,12 @@ void tcp_hc_updatetao(struct in_conninfo *, int, tcp_cc, u_short);
#define TCP_HC_TAO_CCSENT 0x2
#define TCP_HC_TAO_MSSOPT 0x3
+#ifdef TCP_SIGNATURE
+int tcpsignature_apply(void *fstate, void *data, unsigned int len);
+int tcpsignature_compute(struct mbuf *m, int off0, int len, int tcpoptlen,
+ u_char *buf, u_int direction);
+#endif /* TCP_SIGNATURE */
+
extern struct pr_usrreqs tcp_usrreqs;
extern u_long tcp_sendspace;
extern u_long tcp_recvspace;
diff --git a/sys/netinet6/ipsec.h b/sys/netinet6/ipsec.h
index d74a066..4739ddc 100644
--- a/sys/netinet6/ipsec.h
+++ b/sys/netinet6/ipsec.h
@@ -163,6 +163,7 @@ struct ipsecaux {
#define IPSEC_MODE_ANY 0 /* i.e. wildcard. */
#define IPSEC_MODE_TRANSPORT 1
#define IPSEC_MODE_TUNNEL 2
+#define IPSEC_MODE_TCPMD5 3 /* TCP MD5 mode */
/*
* Direction of security policy.
@@ -186,6 +187,7 @@ struct ipsecaux {
#define IPSEC_POLICY_IPSEC 2 /* pass to IPsec */
#define IPSEC_POLICY_ENTRUST 3 /* consulting SPD if present. */
#define IPSEC_POLICY_BYPASS 4 /* only for privileged socket. */
+#define IPSEC_POLICY_TCP 5 /* TCP MD5 policy */
/* Security protocol level */
#define IPSEC_LEVEL_DEFAULT 0 /* reference to system default */
diff --git a/sys/netipsec/ipsec.h b/sys/netipsec/ipsec.h
index c381afd..b15a919 100644
--- a/sys/netipsec/ipsec.h
+++ b/sys/netipsec/ipsec.h
@@ -161,6 +161,7 @@ struct secspacq {
#define IPSEC_MODE_ANY 0 /* i.e. wildcard. */
#define IPSEC_MODE_TRANSPORT 1
#define IPSEC_MODE_TUNNEL 2
+#define IPSEC_MODE_TCPMD5 3 /* TCP MD5 mode */
/*
* Direction of security policy.
diff --git a/sys/netipsec/key.c b/sys/netipsec/key.c
index 7a49007..ad41950 100644
--- a/sys/netipsec/key.c
+++ b/sys/netipsec/key.c
@@ -3003,6 +3003,7 @@ key_setsaval(sav, m, mhp)
switch (mhp->msg->sadb_msg_satype) {
case SADB_SATYPE_AH:
case SADB_SATYPE_ESP:
+ case SADB_X_SATYPE_TCPSIGNATURE:
if (len == PFKEY_ALIGN8(sizeof(struct sadb_key)) &&
sav->alg_auth != SADB_X_AALG_NULL)
error = EINVAL;
@@ -3060,6 +3061,7 @@ key_setsaval(sav, m, mhp)
sav->key_enc = NULL; /*just in case*/
break;
case SADB_SATYPE_AH:
+ case SADB_X_SATYPE_TCPSIGNATURE:
default:
error = EINVAL;
break;
@@ -3084,6 +3086,9 @@ key_setsaval(sav, m, mhp)
case SADB_X_SATYPE_IPCOMP:
error = xform_init(sav, XF_IPCOMP);
break;
+ case SADB_X_SATYPE_TCPSIGNATURE:
+ error = xform_init(sav, XF_TCPSIGNATURE);
+ break;
}
if (error) {
ipseclog((LOG_DEBUG, "%s: unable to initialize SA type %u.\n",
@@ -3216,6 +3221,14 @@ key_mature(struct secasvar *sav)
}
error = xform_init(sav, XF_IPCOMP);
break;
+ case IPPROTO_TCP:
+ if (sav->alg_enc != SADB_EALG_NONE) {
+ ipseclog((LOG_DEBUG, "%s: protocol and algorithm "
+ "mismated.\n", __func__));
+ return(EINVAL);
+ }
+ error = xform_init(sav, XF_TCPSIGNATURE);
+ break;
default:
ipseclog((LOG_DEBUG, "%s: Invalid satype.\n", __func__));
error = EPROTONOSUPPORT;
@@ -4251,6 +4264,8 @@ key_satype2proto(satype)
return IPPROTO_ESP;
case SADB_X_SATYPE_IPCOMP:
return IPPROTO_IPCOMP;
+ case SADB_X_SATYPE_TCPSIGNATURE:
+ return IPPROTO_TCP;
default:
return 0;
}
@@ -4273,6 +4288,8 @@ key_proto2satype(proto)
return SADB_SATYPE_ESP;
case IPPROTO_IPCOMP:
return SADB_X_SATYPE_IPCOMP;
+ case IPPROTO_TCP:
+ return SADB_X_SATYPE_TCPSIGNATURE;
default:
return 0;
}
@@ -6674,6 +6691,7 @@ key_parse(m, so)
case SADB_SATYPE_AH:
case SADB_SATYPE_ESP:
case SADB_X_SATYPE_IPCOMP:
+ case SADB_X_SATYPE_TCPSIGNATURE:
switch (msg->sadb_msg_type) {
case SADB_X_SPDADD:
case SADB_X_SPDDELETE:
OpenPOWER on IntegriCloud