From b19929283b69fe2facf3900846620a3b688de8df Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Mon, 6 Sep 2010 11:01:49 -0700 Subject: [PATCH] kernel - Port TCP-MD5 (RFC 2385) implementation. I have imported FreeBSD commits r125680, r125681 and r183001 into the DragonFlyBSD code, it works well for both IPv4 and IPv6 BGP sessions. This adds TCP_SIGNATURE to 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 Submitted-by: David =?iso-8859-1?Q?B=C9RARD?= Ported-from: FreeBSD --- 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 | 164 +++++++++++++++++++++++++++++++++++++++++++++ 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 +++++ 13 files changed, 336 insertions(+), 2 deletions(-) diff --git a/sys/conf/options b/sys/conf/options index 46644b6ef4..34248909a2 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 10a7a68ad7..fe244b7f76 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 06b8686f21..e6d557425a 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 29cbae68ea..d59e840dc1 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 7c48b70dc2..7caa5761f6 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 9bcc360d50..c978d86930 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 97c5ed78fe..6268cba8d0 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,9 @@ tcp_output(struct tcpcb *tp) long len, recvwin, sendwin; int nsacked = 0; int off, flags, error; +#ifdef TCP_SIGNATURE + int sigoff = 0; +#endif struct mbuf *m; struct ip *ip = NULL; struct ipovly *ipov = NULL; @@ -599,6 +603,28 @@ send: tp->reportblk.rblk_start != tp->reportblk.rblk_end)) tcp_sack_fill_report(tp, opt, &optlen); +#ifdef TCP_SIGNATURE + 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 +844,12 @@ send: tp->snd_up = tp->snd_una; /* drag it along */ } +#ifdef TCP_SIGNATURE + if (tp->t_flags & TF_SIGNATURE) + tcpsignature_compute(m, 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 ab3327e3df..f64b97cb09 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 +#include #ifdef INET6 #include #endif @@ -1979,3 +1981,165 @@ 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 TCP 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. + * + * 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 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; +#ifdef INET6 + struct ip6_hdr *ip6; + struct in6_addr in6; + uint32_t plen; + uint16_t nhdr; +#endif /* INET6 */ + 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 *); +#ifdef INET6 + ip6 = NULL; /* Make the compiler happy. */ +#endif /* INET6 */ + /* + * Look up an SADB entry which matches the address found in + * the segment. + */ + switch (IP_VHL_V(ip->ip_vhl)) { + case IPVERSION: + sav = key_allocsa(AF_INET, (caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst, + IPPROTO_TCP, htonl(TCP_SIG_SPI)); + break; +#ifdef INET6 + case (IPV6_VERSION >> 4): + ip6 = mtod(m, struct ip6_hdr *); + sav = key_allocsa(AF_INET6, (caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst, + IPPROTO_TCP, htonl(TCP_SIG_SPI)); + break; +#endif /* INET6 */ + default: + return (EINVAL); + /* NOTREACHED */ + break; + } + if (sav == NULL) { + kprintf("%s: SADB lookup failed\n", __func__); + return (EINVAL); + } + MD5Init(&ctx); + + /* + * 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. + */ + switch (IP_VHL_V(ip->ip_vhl)) { + case IPVERSION: + ipovly = (struct ipovly *)ip; + 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)); + th = (struct tcphdr *)((u_char *)ip + sizeof(struct ip)); + doff = sizeof(struct ip) + sizeof(struct tcphdr) + optlen; + break; +#ifdef INET6 + /* + * RFC 2385, 2.0 Proposal + * For IPv6, the pseudo-header is as described in RFC 2460, namely the + * 128-bit source IPv6 address, 128-bit destination IPv6 address, zero- + * extended next header value (to form 32 bits), and 32-bit segment + * length. + * Note: Upper-Layer Packet Length comes before Next Header. + */ + case (IPV6_VERSION >> 4): + in6 = ip6->ip6_src; + in6_clearscope(&in6); + MD5Update(&ctx, (char *)&in6, sizeof(struct in6_addr)); + in6 = ip6->ip6_dst; + in6_clearscope(&in6); + MD5Update(&ctx, (char *)&in6, sizeof(struct in6_addr)); + plen = htonl(len + sizeof(struct tcphdr) + optlen); + MD5Update(&ctx, (char *)&plen, sizeof(uint32_t)); + nhdr = 0; + MD5Update(&ctx, (char *)&nhdr, sizeof(uint8_t)); + MD5Update(&ctx, (char *)&nhdr, sizeof(uint8_t)); + MD5Update(&ctx, (char *)&nhdr, sizeof(uint8_t)); + nhdr = IPPROTO_TCP; + MD5Update(&ctx, (char *)&nhdr, sizeof(uint8_t)); + th = (struct tcphdr *)((u_char *)ip6 + sizeof(struct ip6_hdr)); + doff = sizeof(struct ip6_hdr) + sizeof(struct tcphdr) + optlen; + break; +#endif /* INET6 */ + default: + return (EINVAL); + /* NOTREACHED */ + break; + } + /* + * 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 9aa6eb5be8..bc5fc02946 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, 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 785d25ac1e..b3a456fdb7 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 248394eb32..5b10d87255 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 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 248118c064..7c2ed8ecbc 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 c56e3be010..a00d8dfc73 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: -- 2.11.4.GIT