kernel - Port TCP-MD5 (RFC 2385) implementation.
authorMatthew Dillon <dillon@apollo.backplane.com>
Mon, 6 Sep 2010 18:01:49 +0000 (11:01 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Mon, 6 Sep 2010 18:01:49 +0000 (11:01 -0700)
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?= <david@nfrance.com>
Ported-from: FreeBSD

13 files changed:
sys/conf/options
sys/config/LINT
sys/netinet/ip.h
sys/netinet/ip_output.c
sys/netinet/tcp.h
sys/netinet/tcp_input.c
sys/netinet/tcp_output.c
sys/netinet/tcp_subr.c
sys/netinet/tcp_syncache.c
sys/netinet/tcp_usrreq.c
sys/netinet/tcp_var.h
sys/netinet6/ipsec.h
sys/netproto/key/key.c

index 46644b6..3424890 100644 (file)
@@ -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
index 10a7a68..fe244b7 100644 (file)
@@ -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
index 06b8686..e6d5574 100644 (file)
@@ -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
index 29cbae6..d59e840 100644 (file)
@@ -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;
 
index 7c48b70..7caa576 100644 (file)
@@ -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
index 9bcc360..c978d86 100644 (file)
@@ -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;
                }
index 97c5ed7..6268cba 100644 (file)
@@ -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.
index ab3327e..f64b97c 100644 (file)
@@ -69,6 +69,7 @@
  */
 
 #include "opt_compat.h"
+#include "opt_inet.h"
 #include "opt_inet6.h"
 #include "opt_ipsec.h"
 #include "opt_tcpdebug.h"
 
 #ifdef IPSEC
 #include <netinet6/ipsec.h>
+#include <netproto/key/key.h>
 #ifdef INET6
 #include <netinet6/ipsec6.h>
 #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 */
index 9aa6eb5..bc5fc02 100644 (file)
@@ -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;
index 785d25a..b3a456f 100644 (file)
@@ -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;
index 248394e..5b10d87 100644 (file)
@@ -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;
index 248118c..7c2ed8e 100644 (file)
@@ -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 */
index c56e3be..a00d8df 100644 (file)
@@ -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: