[PATCH 1/2] Import of RFC 2385 (TCP-MD5) digest support from FreeBSD
BERARD David
contact at davidberard.fr
Fri Sep 3 11:53:16 PDT 2010
This can be enabled by compiling a kernel with options TCP_SIGNATURE
and IPSEC.
For the uninitiated, this is a TCP option which provides for a means of
authenticating TCP sessions which came into being before IPSEC. It is
still relevant today, however, as it is used by many commercial router
vendors, particularly with BGP, and as such has become a requirement for
interconnect at many major Internet points of presence.
Tested with a Cisco 2611XM running IOS 12.3(24), and Quagga 0.99.17
---
lib/libipsec/ipsec_dump_policy.c | 3 +
lib/libipsec/pfkey.c | 15 +++++-
lib/libipsec/pfkey_dump.c | 3 +
lib/libipsec/policy_token.l | 1 +
share/man/man4/tcp.4 | 31 +++++++++++
sys/conf/options | 1 +
sys/config/LINT | 8 +++
sys/netinet/ip.h | 12 ++++
sys/netinet/ip_output.c | 1 +
sys/netinet/tcp.h | 3 +
sys/netinet/tcp_input.c | 17 ++++++-
sys/netinet/tcp_output.c | 32 +++++++++++
sys/netinet/tcp_subr.c | 108 ++++++++++++++++++++++++++++++++++++++
sys/netinet/tcp_syncache.c | 42 +++++++++++++++
sys/netinet/tcp_usrreq.c | 14 +++++
sys/netinet/tcp_var.h | 25 ++++++++-
sys/netinet6/ipsec.h | 2 +
sys/netproto/key/key.c | 17 ++++++
usr.sbin/setkey/parse.y | 14 ++++-
usr.sbin/setkey/setkey.8 | 7 +++
usr.sbin/setkey/token.l | 2 +
21 files changed, 352 insertions(+), 6 deletions(-)
diff --git a/lib/libipsec/ipsec_dump_policy.c b/lib/libipsec/ipsec_dump_policy.c
index 0d1460c..05a7b44 100644
--- a/lib/libipsec/ipsec_dump_policy.c
+++ b/lib/libipsec/ipsec_dump_policy.c
@@ -191,6 +191,9 @@ ipsec_dump_ipsecrequest(char *buf, size_t len,
case IPPROTO_IPCOMP:
proto = "ipcomp";
break;
+ case IPPROTO_TCP:
+ proto = "tcp";
+ break;
default:
__ipsec_errcode = EIPSEC_INVAL_PROTO;
return NULL;
diff --git a/lib/libipsec/pfkey.c b/lib/libipsec/pfkey.c
index 75b1cb1..ee881bc 100644
--- a/lib/libipsec/pfkey.c
+++ b/lib/libipsec/pfkey.c
@@ -79,12 +79,13 @@ static caddr_t pfkey_setsadbxsa2 (caddr_t, caddr_t, u_int32_t, u_int32_t);
/*
* make and search supported algorithm structure.
*/
-static struct sadb_supported *ipsec_supported[] = { NULL, NULL, NULL, };
+static struct sadb_supported *ipsec_supported[] = { NULL, NULL, NULL, NULL};
static int supported_map[] = {
SADB_SATYPE_AH,
SADB_SATYPE_ESP,
SADB_X_SATYPE_IPCOMP,
+ SADB_X_SATYPE_TCPSIGNATURE,
};
static int
@@ -1166,6 +1167,16 @@ pfkey_send_x1(so, type, satype, mode, src, dst, spi, reqid, wsize,
return -1;
}
break;
+ case SADB_X_SATYPE_TCPSIGNATURE:
+ if (e_type != SADB_EALG_NONE) {
+ __ipsec_errcode = EIPSEC_INVAL_ALGS;
+ return -1;
+ }
+ if (a_type != SADB_X_AALG_TCP_MD5) {
+ __ipsec_errcode = EIPSEC_INVAL_ALGS;
+ return -1;
+ }
+ break;
default:
__ipsec_errcode = EIPSEC_INVAL_SATYPE;
return -1;
@@ -1376,6 +1387,7 @@ pfkey_send_x3(so, type, satype)
case SADB_SATYPE_AH:
case SADB_SATYPE_ESP:
case SADB_X_SATYPE_IPCOMP:
+ case SADB_X_SATYPE_TCPSIGNATURE:
break;
default:
__ipsec_errcode = EIPSEC_INVAL_SATYPE;
@@ -1835,6 +1847,7 @@ pfkey_check(mhp)
case SADB_SATYPE_ESP:
case SADB_SATYPE_AH:
case SADB_X_SATYPE_IPCOMP:
+ case SADB_X_SATYPE_TCPSIGNATURE:
switch (msg->sadb_msg_type) {
case SADB_X_SPDADD:
case SADB_X_SPDDELETE:
diff --git a/lib/libipsec/pfkey_dump.c b/lib/libipsec/pfkey_dump.c
index ba4d2bb..2b4901c 100644
--- a/lib/libipsec/pfkey_dump.c
+++ b/lib/libipsec/pfkey_dump.c
@@ -124,6 +124,8 @@ static char *str_satype[] = {
"ripv2",
"mip",
"ipcomp",
+ "policy",
+ "tcp",
};
static char *str_mode[] = {
@@ -162,6 +164,7 @@ static struct val2str str_alg_auth[] = {
{ SADB_X_AALG_MD5, "md5", },
{ SADB_X_AALG_SHA, "sha", },
{ SADB_X_AALG_NULL, "null", },
+ { SADB_X_AALG_TCP_MD5, "tcp-md5", },
#ifdef SADB_X_AALG_SHA2_256
{ SADB_X_AALG_SHA2_256, "hmac-sha2-256", },
#endif
diff --git a/lib/libipsec/policy_token.l b/lib/libipsec/policy_token.l
index f51607d..77ff00b 100644
--- a/lib/libipsec/policy_token.l
+++ b/lib/libipsec/policy_token.l
@@ -104,6 +104,7 @@ entrust { yylval.num = IPSEC_POLICY_ENTRUST; return(ACTION); }
esp { yylval.num = IPPROTO_ESP; return(PROTOCOL); }
ah { yylval.num = IPPROTO_AH; return(PROTOCOL); }
ipcomp { yylval.num = IPPROTO_IPCOMP; return(PROTOCOL); }
+tcp { yylval.num = IPPROTO_TCP; return(PROTOCOL); }
transport { yylval.num = IPSEC_MODE_TRANSPORT; return(MODE); }
tunnel { yylval.num = IPSEC_MODE_TUNNEL; return(MODE); }
diff --git a/share/man/man4/tcp.4 b/share/man/man4/tcp.4
index 1c14006..f9b5862 100644
--- a/share/man/man4/tcp.4
+++ b/share/man/man4/tcp.4
@@ -156,6 +156,31 @@ option is set to a non-zero value,
.Tn TCP
will delay sending any data at all until either the socket is closed,
or the internal send buffer is filled.
+.It Dv TCP_SIGNATURE_ENABLE
+This option enables the use of MD5 digests (also known as TCP-MD5)
+on writes to the specified socket.
+In the current release, only outgoing traffic is digested;
+digests on incoming traffic are not verified.
+The current default behavior for the system is to respond to a system
+advertising this option with TCP-MD5; this may change.
+.Pp
+One common use for this in a DragonFlyBSD router deployment is to enable
+based routers to interwork with Cisco equipment at peering points.
+Support for this feature conforms to RFC 2385.
+Only IPv4 (AF_INET) sessions are supported.
+.Pp
+In order for this option to function correctly, it is necessary for the
+administrator to add a tcp-md5 key entry to the system's security
+associations database (SADB) using the
+.Xr setkey 8
+utility.
+This entry must have an SPI of 0x1000 and can therefore only be specified
+on a per-host basis at this time.
+.Pp
+If an SADB entry cannot be found for the destination, the outgoing traffic
+will have an invalid digest option prepended, and the following error message
+will be visible on the system console:
+.Em "tcpsignature_compute: SADB lookup failed for %d.%d.%d.%d" .
.El
.Pp
The option level for the
@@ -381,6 +406,7 @@ address.
.Xr blackhole 4 ,
.Xr inet 4 ,
.Xr intro 4 ,
+.Xr setkey 8,
.Xr ip 4
.Rs
.%A V. Jacobson
@@ -389,6 +415,11 @@ address.
.%T "TCP Extensions for High Performance"
.%O RFC 1323
.Re
+.Rs
+.%A "A. Heffernan"
+.%T "Protection of BGP Sessions via the TCP MD5 Signature Option"
+.%O "RFC 2385"
+.Re
.Sh HISTORY
The
.Nm
diff --git a/sys/conf/options b/sys/conf/options
index 46644b6..3424890 100644
--- a/sys/conf/options
+++ b/sys/conf/options
@@ -316,6 +316,7 @@ PPP_DEFLATE opt_ppp.h
PPP_FILTER opt_ppp.h
SLIP_IFF_OPTS opt_slip.h
TCPDEBUG
+TCP_SIGNATURE opt_inet.h
TCP_DROP_SYNFIN opt_tcp_input.h
XBONEHACK
diff --git a/sys/config/LINT b/sys/config/LINT
index 2149f0f..0675084 100644
--- a/sys/config/LINT
+++ b/sys/config/LINT
@@ -653,6 +653,14 @@ options MBUF_STRESS_TEST
options ACCEPT_FILTER_DATA
options ACCEPT_FILTER_HTTP
+# TCP_SIGNATURE adds support for RFC 2385 (TCP-MD5) digests. These are
+# carried in TCP option 19. This option is commonly used to protect
+# TCP sessions (e.g. BGP) where IPSEC is not available nor desirable.
+# This is enabled on a per-socket basis using the TCP_MD5SIG socket option.
+# This requires the use of 'device crypto', 'options IPSEC'
+# or 'device cryptodev'.
+options TCP_SIGNATURE #include support for RFC 2385
+
#
# TCP_DROP_SYNFIN adds support for ignoring TCP packets with SYN+FIN. This
# prevents nmap et al. from identifying the TCP/IP stack, but breaks support
diff --git a/sys/netinet/ip.h b/sys/netinet/ip.h
index 06b8686..e6d5574 100644
--- a/sys/netinet/ip.h
+++ b/sys/netinet/ip.h
@@ -211,4 +211,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 29cbae6..d59e840 100644
--- a/sys/netinet/ip_output.c
+++ b/sys/netinet/ip_output.c
@@ -570,6 +570,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 7c48b70..7caa576 100644
--- a/sys/netinet/tcp.h
+++ b/sys/netinet/tcp.h
@@ -110,6 +110,8 @@ struct tcphdr {
#define TCPOPT_CC 11 /* CC options: RFC-1644 */
#define TCPOPT_CCNEW 12
#define TCPOPT_CCECHO 13
+#define TCPOPT_SIGNATURE 19 /* Keyed MD5: RFC 2385 */
+#define TCPOLEN_SIGNATURE 18
/*
* Default maximum segment size for TCP.
@@ -160,5 +162,6 @@ 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
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c
index 9bcc360..c978d86 100644
--- a/sys/netinet/tcp_input.c
+++ b/sys/netinet/tcp_input.c
@@ -69,6 +69,7 @@
*/
#include "opt_ipfw.h" /* for ipfw_fwd */
+#include "opt_inet.h"
#include "opt_inet6.h"
#include "opt_ipsec.h"
#include "opt_tcpdebug.h"
@@ -520,7 +521,8 @@ tcp_input(struct mbuf *m, ...)
struct inpcb *inp = NULL;
u_char *optp = NULL;
int optlen = 0;
- int len, tlen, off;
+ int tlen, off;
+ int len = 0;
int drop_hdrlen;
struct tcpcb *tp = NULL;
int thflags;
@@ -2701,6 +2703,19 @@ tcp_dooptions(struct tcpopt *to, u_char *cp, int cnt, boolean_t is_syn)
r->rblk_end = ntohl(r->rblk_end);
}
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 97c5ed7..dd8292b 100644
--- a/sys/netinet/tcp_output.c
+++ b/sys/netinet/tcp_output.c
@@ -68,6 +68,7 @@
* $DragonFly: src/sys/netinet/tcp_output.c,v 1.34 2007/04/22 01:13:14 dillon Exp $
*/
+#include "opt_inet.h"
#include "opt_inet6.h"
#include "opt_ipsec.h"
#include "opt_tcpdebug.h"
@@ -151,6 +152,7 @@ tcp_output(struct tcpcb *tp)
long len, recvwin, sendwin;
int nsacked = 0;
int off, flags, error;
+ int sigoff = 0;
struct mbuf *m;
struct ip *ip = NULL;
struct ipovly *ipov = NULL;
@@ -599,6 +601,29 @@ send:
tp->reportblk.rblk_start != tp->reportblk.rblk_end))
tcp_sack_fill_report(tp, opt, &optlen);
+#ifdef TCP_SIGNATURE
+ if (!isipv6)
+ 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 */
KASSERT(optlen <= TCP_MAXOLEN, ("too many TCP options"));
hdrlen += optlen;
@@ -818,6 +843,13 @@ send:
tp->snd_up = tp->snd_una; /* drag it along */
}
+#ifdef TCP_SIGNATURE
+ if (!isipv6)
+ 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_subr.c b/sys/netinet/tcp_subr.c
index ab3327e..fafda1e 100644
--- a/sys/netinet/tcp_subr.c
+++ b/sys/netinet/tcp_subr.c
@@ -69,6 +69,7 @@
*/
#include "opt_compat.h"
+#include "opt_inet.h"
#include "opt_inet6.h"
#include "opt_ipsec.h"
#include "opt_tcpdebug.h"
@@ -126,6 +127,7 @@
#ifdef IPSEC
#include <netinet6/ipsec.h>
+#include <netproto/key/key.h>
#ifdef INET6
#include <netinet6/ipsec6.h>
#endif
@@ -1979,3 +1981,109 @@ tcp_xmit_bandwidth_limit(struct tcpcb *tp, tcp_seq ack_seq)
bwnd = tp->t_maxseg * 2;
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 */
+{
+ 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 *);
+ /*
+ * Look up an SADB entry which matches the address found in
+ * the segment.
+ */
+ sav = key_allocsa(AF_INET, (caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst,
+ IPPROTO_TCP, htonl(TCP_SIG_SPI));
+ if (sav == NULL) {
+ kprintf("%s: SADB lookup failed\n", __func__);
+ 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 9aa6eb5..ce53940 100644
--- a/sys/netinet/tcp_syncache.c
+++ b/sys/netinet/tcp_syncache.c
@@ -72,6 +72,7 @@
* $DragonFly: src/sys/netinet/tcp_syncache.c,v 1.35 2008/11/22 11:03:35 sephe Exp $
*/
+#include "opt_inet.h"
#include "opt_inet6.h"
#include "opt_ipsec.h"
@@ -848,6 +849,12 @@ syncache_socket(struct syncache *sc, struct socket *lso, struct mbuf *m)
if (sc->sc_flags & SCF_SACK_PERMITTED)
tp->t_flags |= TF_SACK_PERMITTED;
+#ifdef TCP_SIGNATURE
+ if (sc->sc_flags & SCF_SIGNATURE)
+ tp->t_flags |= TF_SIGNATURE;
+#endif /* TCP_SIGNATURE */
+
+
tcp_mss(tp, sc->sc_peer_mss);
/*
@@ -1081,6 +1088,17 @@ syncache_add(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th,
sc->sc_flags |= SCF_SACK_PERMITTED;
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 */
if (syncache_respond(sc, m) == 0) {
syncache_insert(sc, sch);
@@ -1137,6 +1155,10 @@ syncache_respond(struct syncache *sc, struct mbuf *m)
((sc->sc_flags & SCF_TIMESTAMP) ? TCPOLEN_TSTAMP_APPA : 0) +
((sc->sc_flags & SCF_SACK_PERMITTED) ?
TCPOLEN_SACK_PERMITTED_ALIGNED : 0);
+#ifdef TCP_SIGNATURE
+ optlen += ((sc->sc_flags & SCF_SIGNATURE) ?
+ (TCPOLEN_SIGNATURE + 2) : 0);
+#endif /* TCP_SIGNATURE */
}
tlen = hlen + sizeof(struct tcphdr) + optlen;
@@ -1237,6 +1259,26 @@ syncache_respond(struct syncache *sc, struct mbuf *m)
optp += TCPOLEN_TSTAMP_APPA;
}
+#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 */
+
if (sc->sc_flags & SCF_SACK_PERMITTED) {
*((u_int32_t *)optp) = htonl(TCPOPT_SACK_PERMITTED_ALIGNED);
optp += TCPOLEN_SACK_PERMITTED_ALIGNED;
diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c
index 785d25a..b3a456f 100644
--- a/sys/netinet/tcp_usrreq.c
+++ b/sys/netinet/tcp_usrreq.c
@@ -69,6 +69,7 @@
*/
#include "opt_ipsec.h"
+#include "opt_inet.h"
#include "opt_inet6.h"
#include "opt_tcpdebug.h"
@@ -1252,6 +1253,14 @@ tcp_ctloutput(struct socket *so, struct sockopt *sopt)
if (error)
break;
switch (sopt->sopt_name) {
+#ifdef TCP_SIGNATURE
+ case TCP_SIGNATURE_ENABLE:
+ if (optval > 0)
+ tp->t_flags |= TF_SIGNATURE;
+ else
+ tp->t_flags &= ~TF_SIGNATURE;
+ break;
+#endif /* TCP_SIGNATURE */
case TCP_NODELAY:
case TCP_NOOPT:
switch (sopt->sopt_name) {
@@ -1309,6 +1318,11 @@ tcp_ctloutput(struct socket *so, struct sockopt *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 248394e..3549565 100644
--- a/sys/netinet/tcp_var.h
+++ b/sys/netinet/tcp_var.h
@@ -160,7 +160,7 @@ struct tcpcb {
#define TF_NEEDFIN 0x00000800 /* send FIN (implicit state) */
#define TF_NOPUSH 0x00001000 /* don't push */
#define TF_SYNCACHE 0x00002000 /* syncache present */
-/* 0x00001000 - 0x00008000 were used for T/TCP */
+#define TF_SIGNATURE 0x00004000 /* require MD5 digests (RFC2385) */
#define TF_MORETOCOME 0x00010000 /* More data to be appended to sock */
#define TF_LQ_OVERFLOW 0x00020000 /* listen queue overflow */
#define TF_LASTIDLE 0x00040000 /* connection was previously idle */
@@ -274,6 +274,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 */
+
/*
* TCP statistics.
*/
@@ -402,6 +417,8 @@ struct tcpopt {
#define TOF_SCALE 0x0020
#define TOF_SACK_PERMITTED 0x0040
#define TOF_SACK 0x0080
+#define TOF_SIGNATURE 0x0100 /* signature option present */
+#define TOF_SIGLEN 0x0200 /* sigature length valid (RFC2385) */
u_int32_t to_tsval;
u_int32_t to_tsecr;
u_int16_t to_mss;
@@ -432,6 +449,7 @@ struct syncache {
#define SCF_TIMESTAMP 0x04 /* negotiated timestamps */
#define SCF_UNREACH 0x10 /* icmp unreachable received */
#define SCF_SACK_PERMITTED 0x20 /* saw SACK permitted option */
+#define SCF_SIGNATURE 0x40 /* send MD5 digests */
#define SCF_MARKER 0x80 /* not a real entry */
TAILQ_ENTRY(syncache) sc_hash;
TAILQ_ENTRY(syncache) sc_timerq;
@@ -627,6 +645,11 @@ void syncache_chkrst(struct in_conninfo *, struct tcphdr *);
void syncache_badack(struct in_conninfo *);
void syncache_destroy(struct tcpcb *tp);
+#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;
diff --git a/sys/netinet6/ipsec.h b/sys/netinet6/ipsec.h
index 248118c..7c2ed8e 100644
--- a/sys/netinet6/ipsec.h
+++ b/sys/netinet6/ipsec.h
@@ -140,6 +140,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.
@@ -163,6 +164,7 @@ struct secspacq {
#define IPSEC_POLICY_IPSEC 2 /* do 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/netproto/key/key.c b/sys/netproto/key/key.c
index c56e3be..a00d8df 100644
--- a/sys/netproto/key/key.c
+++ b/sys/netproto/key/key.c
@@ -2945,6 +2945,7 @@ key_setsaval(struct secasvar *sav, struct mbuf *m,
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;
@@ -3000,6 +3001,7 @@ key_setsaval(struct secasvar *sav, struct mbuf *m,
sav->key_enc = NULL; /*just in case*/
break;
case SADB_SATYPE_AH:
+ case SADB_X_SATYPE_TCPSIGNATURE:
default:
error = EINVAL;
break;
@@ -3034,6 +3036,7 @@ key_setsaval(struct secasvar *sav, struct mbuf *m,
break;
case SADB_SATYPE_AH:
case SADB_X_SATYPE_IPCOMP:
+ case SADB_X_SATYPE_TCPSIGNATURE:
break;
default:
ipseclog((LOG_DEBUG, "key_setsaval: invalid SA type.\n"));
@@ -3213,6 +3216,15 @@ key_mature(struct secasvar *sav)
checkmask = 4;
mustmask = 4;
break;
+ case IPPROTO_TCP:
+ if (sav->alg_auth != SADB_X_AALG_TCP_MD5) {
+ ipseclog((LOG_DEBUG, "key_mature: "
+ "protocol and algorithm mismated.\n"));
+ return(EINVAL);
+ }
+ checkmask = 0;
+ mustmask = 0;
+ break;
default:
ipseclog((LOG_DEBUG, "key_mature: Invalid satype.\n"));
return EPROTONOSUPPORT;
@@ -4407,6 +4419,8 @@ key_satype2proto(u_int8_t satype)
return IPPROTO_ESP;
case SADB_X_SATYPE_IPCOMP:
return IPPROTO_IPCOMP;
+ case SADB_X_SATYPE_TCPSIGNATURE:
+ return IPPROTO_TCP;
break;
default:
return 0;
@@ -4429,6 +4443,8 @@ key_proto2satype(u_int16_t proto)
return SADB_SATYPE_ESP;
case IPPROTO_IPCOMP:
return SADB_X_SATYPE_IPCOMP;
+ case IPPROTO_TCP:
+ return SADB_X_SATYPE_TCPSIGNATURE;
break;
default:
return 0;
@@ -6757,6 +6773,7 @@ key_parse(struct mbuf *m, struct socket *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:
diff --git a/usr.sbin/setkey/parse.y b/usr.sbin/setkey/parse.y
index f2c1149..5609f37 100644
--- a/usr.sbin/setkey/parse.y
+++ b/usr.sbin/setkey/parse.y
@@ -102,7 +102,7 @@ extern void yyerror(const char *);
%token EOT
%token ADD GET DELETE DELETEALL FLUSH DUMP
%token ADDRESS PREFIX PORT PORTANY
-%token UP_PROTO PR_ESP PR_AH PR_IPCOMP
+%token UP_PROTO PR_ESP PR_AH PR_IPCOMP PR_TCP
%token F_PROTOCOL F_AUTH F_ENC F_REPLAY F_COMP F_RAWCPI
%token F_MODE MODE F_REQID
%token F_EXT EXTENSION NOCYCLICSEQ
@@ -114,7 +114,7 @@ extern void yyerror(const char *);
%token F_POLICY PL_REQUESTS
%type <num> PORT PREFIX EXTENSION MODE
-%type <num> UP_PROTO PR_ESP PR_AH PR_IPCOMP
+%type <num> UP_PROTO PR_ESP PR_AH PR_IPCOMP PR_TCP
%type <num> ALG_AUTH ALG_ENC ALG_ENC_DESDERIV ALG_ENC_DES32IV ALG_COMP
%type <num> DECSTRING
%type <val> ADDRESS PL_REQUESTS
@@ -230,6 +230,10 @@ protocol_spec
{
p_satype = SADB_X_SATYPE_IPCOMP;
}
+ | PR_TCP
+ {
+ p_satype = SADB_X_SATYPE_TCPSIGNATURE;
+ }
;
spi
@@ -349,7 +353,11 @@ auth_key
p_key_auth_len = $1.len;
p_key_auth = pp_key;
- if (ipsec_check_keylen(SADB_EXT_SUPPORTED_AUTH,
+ if (p_alg_auth == SADB_X_AALG_TCP_MD5) {
+ if ((p_key_auth_len < 1) || (p_key_auth_len >
+ 80))
+ return -1;
+ } else if (ipsec_check_keylen(SADB_EXT_SUPPORTED_AUTH,
p_alg_auth,
PFKEY_UNUNIT64(p_key_auth_len)) < 0) {
yyerror(ipsec_strerror());
diff --git a/usr.sbin/setkey/setkey.8 b/usr.sbin/setkey/setkey.8
index 84d575d..b72db79 100644
--- a/usr.sbin/setkey/setkey.8
+++ b/usr.sbin/setkey/setkey.8
@@ -220,6 +220,8 @@ AH based on rfc2402
AH based on rfc1826
.It Li ipcomp
IPCOMP
+.It Li tcp
+TCP-MD5 based on rfc2385
.El
.\"
.Pp
@@ -230,6 +232,8 @@ You cannot use the set of SPI values in the range 0 through 255.
(with
.Li 0x
attached).
+TCP-MD5 associations must use 0x1000 and therefore only have per-host
+granularity at this time.
.\"
.Pp
.It Ar extensions
@@ -547,6 +551,7 @@ hmac-sha2-384 384 ah: 96bit ICV (no document)
384 ah-old: 128bit ICV (no document)
hmac-sha2-512 512 ah: 96bit ICV (no document)
512 ah-old: 128bit ICV (no document)
+tcp-md5 8 to 640 tcp: rfc2385
.Ed
.Pp
Followings are the list of encryption algorithms that can be used as
@@ -602,6 +607,8 @@ dump esp ;
spdadd 10.0.11.41/32[21] 10.0.11.33/32[any] any
-P out ipsec esp/tunnel/192.168.0.1-192.168.1.2/require ;
+add 10.1.10.34 10.1.10.36 tcp 0x1000 -A tcp-md5 "TCP-MD5 BGP secret" ;
+
.Ed
.\"
.Sh DIAGNOSTICS
diff --git a/usr.sbin/setkey/token.l b/usr.sbin/setkey/token.l
index a0f7865..afb8300 100644
--- a/usr.sbin/setkey/token.l
+++ b/usr.sbin/setkey/token.l
@@ -163,6 +163,7 @@ esp { PREPROC; yylval.num = 0; return(PR_ESP); }
ah-old { PREPROC; yylval.num = 1; return(PR_AH); }
esp-old { PREPROC; yylval.num = 1; return(PR_ESP); }
ipcomp { PREPROC; yylval.num = 0; return(PR_IPCOMP); }
+tcp { PREPROC; yylval.num = 0; return(PR_TCP); }
/* authentication alogorithm */
{hyphen}A { PREPROC; return(F_AUTH); }
@@ -173,6 +174,7 @@ keyed-sha1 { PREPROC; yylval.num = SADB_X_AALG_SHA; return(ALG_AUTH); }
hmac-sha2-256 { PREPROC; yylval.num = SADB_X_AALG_SHA2_256; return(ALG_AUTH); }
hmac-sha2-384 { PREPROC; yylval.num = SADB_X_AALG_SHA2_384; return(ALG_AUTH); }
hmac-sha2-512 { PREPROC; yylval.num = SADB_X_AALG_SHA2_512; return(ALG_AUTH); }
+tcp-md5 { PREPROC; yylval.num = SADB_X_AALG_TCP_MD5; return(ALG_AUTH); }
null { PREPROC; yylval.num = SADB_X_AALG_NULL; return(ALG_AUTH); }
/* encryption alogorithm */
--
1.6.6.2
--XsQoSWH+UP9D9v3l
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="0002-Implement-IPv6-support-for-TCP-MD5-Signature-Option-.patch"
More information about the Submit
mailing list