diff options
author | cmetz <cmetz@cvs.openbsd.org> | 1999-07-06 20:17:54 +0000 |
---|---|---|
committer | cmetz <cmetz@cvs.openbsd.org> | 1999-07-06 20:17:54 +0000 |
commit | b572bd87e759146844b72e7a327306a471ae69c7 (patch) | |
tree | 3e21a6f1fca265ba2767f46b76bfd8d2182243b9 | |
parent | 1b325370253fe0a5d55ea7f66f9477a75800daaf (diff) |
Added support for TCP MD5 option (RFC 2385).
-rw-r--r-- | sys/conf/files | 10 | ||||
-rw-r--r-- | sys/net/pfkeyv2.c | 25 | ||||
-rw-r--r-- | sys/net/pfkeyv2.h | 23 | ||||
-rw-r--r-- | sys/netinet/ip.h | 15 | ||||
-rw-r--r-- | sys/netinet/ip_ipsp.c | 8 | ||||
-rw-r--r-- | sys/netinet/ip_ipsp.h | 13 | ||||
-rw-r--r-- | sys/netinet/tcp.h | 5 | ||||
-rw-r--r-- | sys/netinet/tcp_input.c | 166 | ||||
-rw-r--r-- | sys/netinet/tcp_output.c | 128 | ||||
-rw-r--r-- | sys/netinet/tcp_subr.c | 95 | ||||
-rw-r--r-- | sys/netinet/tcp_usrreq.c | 30 | ||||
-rw-r--r-- | sys/netinet/tcp_var.h | 13 |
12 files changed, 494 insertions, 37 deletions
diff --git a/sys/conf/files b/sys/conf/files index 5afdf8b393c..7b994ae2f62 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1,4 +1,4 @@ -# $OpenBSD: files,v 1.119 1999/07/01 23:10:39 deraadt Exp $ +# $OpenBSD: files,v 1.120 1999/07/06 20:17:52 cmetz Exp $ # $NetBSD: files,v 1.87 1996/05/19 17:17:50 jonathan Exp $ # @(#)files.newconf 7.5 (Berkeley) 5/10/93 @@ -455,7 +455,7 @@ file netinet/ip_state.c ipfilter file netinet/ip_proxy.c ipfilter file netinet/ip_auth.c ipfilter file netinet/ip_log.c ipfilter -file netinet/ip_ipsp.c inet & ipsec +file netinet/ip_ipsp.c inet & (ipsec | tcp_signature) file netinet/ip_ip4.c inet & (ipsec | mrouting) file netinet/ip_ah.c inet & ipsec file netinet/ip_esp.c inet & ipsec @@ -650,6 +650,6 @@ file netinet6/in6_proto.c inet6 file netinet6/ipv6_trans.c inet6 # ... PF_KEY -file net/pfkey.c key | ipsec -file net/pfkeyv2.c key | ipsec -file net/pfkeyv2_parsemessage.c key | ipsec +file net/pfkey.c key | ipsec | tcp_signature +file net/pfkeyv2.c key | ipsec | tcp_signature +file net/pfkeyv2_parsemessage.c key | ipsec | tcp_signature diff --git a/sys/net/pfkeyv2.c b/sys/net/pfkeyv2.c index f9aed42b41c..46b84dc1b5e 100644 --- a/sys/net/pfkeyv2.c +++ b/sys/net/pfkeyv2.c @@ -774,6 +774,12 @@ pfkeyv2_send(struct socket *socket, void *message, int len) sa.tdb_sproto = IPPROTO_IPIP; break; +#ifdef TCP_SIGNATURE + case SADB_X_SATYPE_TCPSIGNATURE: + sa.tdb_sproto = IPPROTO_TCP; + break; +#endif /* TCP_SIGNATURE */ + default: /* Nothing else supported */ rval = EOPNOTSUPP; goto ret; @@ -861,6 +867,13 @@ pfkeyv2_send(struct socket *socket, void *message, int len) newsa->tdb_sproto = IPPROTO_IPIP; alg = XF_IP4; break; + +#ifdef TCP_SIGNATURE + case SADB_X_SATYPE_TCPSIGNATURE: + newsa->tdb_sproto = IPPROTO_TCP; + alg = XF_TCPSIGNATURE; + break; +#endif /* TCP_SIGNATURE */ default: /* Nothing else supported */ rval = EOPNOTSUPP; @@ -988,6 +1001,13 @@ pfkeyv2_send(struct socket *socket, void *message, int len) alg = XF_IP4; break; +#ifdef TCP_SIGNATURE + case SADB_X_SATYPE_TCPSIGNATURE: + newsa->tdb_sproto = IPPROTO_TCP; + alg = XF_TCPSIGNATURE; + break; +#endif /* TCP_SIGNATURE */ + default: /* Nothing else supported */ rval = EOPNOTSUPP; goto splxret; @@ -1757,6 +1777,11 @@ pfkeyv2_expire(struct tdb *sa, u_int16_t type) case IPPROTO_IPIP: satype = SADB_X_SATYPE_IPIP; break; +#ifdef TCP_SIGNATURE + case IPPROTO_TCP: + satype = SADB_X_SATYPE_TCPSIGNATURE; + break; +#endif /* TCP_SIGNATURE */ default: rval = EOPNOTSUPP; goto ret; diff --git a/sys/net/pfkeyv2.h b/sys/net/pfkeyv2.h index 36f22763df6..1a7f52d0d5b 100644 --- a/sys/net/pfkeyv2.h +++ b/sys/net/pfkeyv2.h @@ -191,17 +191,18 @@ struct sadb_protocol { #define SADB_EXT_MAX 22 /* Fix pfkeyv2.c struct pfkeyv2_socket if SATYPE_MAX > 31 */ -#define SADB_SATYPE_UNSPEC 0 -#define SADB_SATYPE_AH 1 -#define SADB_SATYPE_ESP 2 -#define SADB_SATYPE_RSVP 3 -#define SADB_SATYPE_OSPFV2 4 -#define SADB_SATYPE_RIPV2 5 -#define SADB_SATYPE_MIP 6 -#define SADB_X_SATYPE_AH_OLD 7 -#define SADB_X_SATYPE_ESP_OLD 8 -#define SADB_X_SATYPE_IPIP 9 -#define SADB_SATYPE_MAX 9 +#define SADB_SATYPE_UNSPEC 0 +#define SADB_SATYPE_AH 1 +#define SADB_SATYPE_ESP 2 +#define SADB_SATYPE_RSVP 3 +#define SADB_SATYPE_OSPFV2 4 +#define SADB_SATYPE_RIPV2 5 +#define SADB_SATYPE_MIP 6 +#define SADB_X_SATYPE_AH_OLD 7 +#define SADB_X_SATYPE_ESP_OLD 8 +#define SADB_X_SATYPE_IPIP 9 +#define SADB_X_SATYPE_TCPSIGNATURE 10 +#define SADB_SATYPE_MAX 10 #define SADB_SASTATE_LARVAL 0 #define SADB_SASTATE_MATURE 1 diff --git a/sys/netinet/ip.h b/sys/netinet/ip.h index b3326f17066..524938bb9c7 100644 --- a/sys/netinet/ip.h +++ b/sys/netinet/ip.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ip.h,v 1.4 1997/02/24 14:06:36 niklas Exp $ */ +/* $OpenBSD: ip.h,v 1.5 1999/07/06 20:17:52 cmetz Exp $ */ /* $NetBSD: ip.h,v 1.9 1995/05/15 01:22:44 cgd Exp $ */ /* @@ -167,3 +167,16 @@ struct ip_timestamp { #define IPTTLDEC 1 /* subtracted when forwarding */ #define IP_MSS 576 /* default maximum segment size */ + +/* + * This is the real IPv4 psuedo 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 */ +}; diff --git a/sys/netinet/ip_ipsp.c b/sys/netinet/ip_ipsp.c index 17aee8d995a..749c747c347 100644 --- a/sys/netinet/ip_ipsp.c +++ b/sys/netinet/ip_ipsp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_ipsp.c,v 1.46 1999/06/07 07:20:38 angelos Exp $ */ +/* $OpenBSD: ip_ipsp.c,v 1.47 1999/07/06 20:17:52 cmetz Exp $ */ /* * The authors of this code are John Ioannidis (ji@tla.org), @@ -139,6 +139,12 @@ struct xformsw xformsw[] = { "Encryption + Authentication + Replay Protection", esp_new_attach, esp_new_init, esp_new_zeroize, esp_new_input, esp_new_output, }, +#ifdef TCP_SIGNATURE + { XF_TCPSIGNATURE, XFT_AUTH, "TCP MD5 Signature Option, RFC 2385", + tcp_signature_tdb_attach, tcp_signature_tdb_init, + tcp_signature_tdb_zeroize, tcp_signature_tdb_input, + tcp_signature_tdb_output, } +#endif /* TCP_SIGNATURE */ }; struct xformsw *xformswNXFORMSW = &xformsw[sizeof(xformsw)/sizeof(xformsw[0])]; diff --git a/sys/netinet/ip_ipsp.h b/sys/netinet/ip_ipsp.h index 02e861e3594..7c256a5767c 100644 --- a/sys/netinet/ip_ipsp.h +++ b/sys/netinet/ip_ipsp.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_ipsp.h,v 1.37 1999/06/30 17:23:59 deraadt Exp $ */ +/* $OpenBSD: ip_ipsp.h,v 1.38 1999/07/06 20:17:52 cmetz Exp $ */ /* * The authors of this code are John Ioannidis (ji@tla.org), @@ -356,6 +356,7 @@ struct xformsw #define XF_OLD_ESP 3 /* RFCs 1829 & 1851 */ #define XF_NEW_AH 4 /* AH HMAC 96bits */ #define XF_NEW_ESP 5 /* ESP + auth 96bits + replay counter */ +#define XF_TCPSIGNATURE 6 /* TCP MD5 Signature option, RFC 2358 */ /* xform attributes */ #define XFT_AUTH 0x0001 @@ -494,6 +495,16 @@ extern int esp_new_output(struct mbuf *, struct sockaddr_encap *, struct tdb *, struct mbuf **); extern struct mbuf *esp_new_input(struct mbuf *, struct tdb *); +/* XF_TCPSIGNATURE */ +extern int tcp_signature_tdb_attach __P((void)); +extern int tcp_signature_tdb_init __P((struct tdb *, struct xformsw *, + struct ipsecinit *)); +extern int tcp_signature_tdb_zeroize __P((struct tdb *)); +extern struct mbuf *tcp_signature_tdb_input __P((struct mbuf *, struct tdb *)); +extern int tcp_signature_tdb_output __P((struct mbuf *, + struct sockaddr_encap *, struct tdb *, + struct mbuf **)); + /* Padding */ extern caddr_t m_pad(struct mbuf *, int, int); diff --git a/sys/netinet/tcp.h b/sys/netinet/tcp.h index b32970f4f4a..0bd98882b2b 100644 --- a/sys/netinet/tcp.h +++ b/sys/netinet/tcp.h @@ -1,4 +1,4 @@ -/* $OpenBSD: tcp.h,v 1.7 1999/07/02 21:22:13 cmetz Exp $ */ +/* $OpenBSD: tcp.h,v 1.8 1999/07/06 20:17:52 cmetz Exp $ */ /* $NetBSD: tcp.h,v 1.8 1995/04/17 05:32:58 cgd Exp $ */ /* @@ -85,6 +85,8 @@ struct tcphdr { #define TCPOPT_TIMESTAMP 8 #define TCPOLEN_TIMESTAMP 10 #define TCPOLEN_TSTAMP_APPA (TCPOLEN_TIMESTAMP+2) /* appendix A */ +#define TCPOPT_SIGNATURE 19 +#define TCPOLEN_SIGNATURE 18 #define MAX_TCPOPTLEN 40 /* Absolute maximum TCP options len */ @@ -118,6 +120,7 @@ struct tcphdr { */ #define TCP_NODELAY 0x01 /* don't delay send to coalesce pkts */ #define TCP_MAXSEG 0x02 /* set maximum segment size */ +#define TCP_SIGNATURE_ENABLE 0x04 /* enable TCP MD5 signature option */ #define TCP_SACK_DISABLE 0x300 /* disable SACKs (if enabled by def.) */ #endif /* !_NETINET_TCP_H_ */ diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c index 4bc691e5928..9674066c544 100644 --- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tcp_input.c,v 1.39 1999/07/06 20:14:06 cmetz Exp $ */ +/* $OpenBSD: tcp_input.c,v 1.40 1999/07/06 20:17:52 cmetz Exp $ */ /* $NetBSD: tcp_input.c,v 1.23 1996/02/13 23:43:44 christos Exp $ */ /* @@ -758,9 +758,15 @@ findpcb: * Process options if not in LISTEN state, * else do it below (after getting remote address). */ - if (optp && tp->t_state != TCPS_LISTEN) - tcp_dooptions(tp, optp, optlen, th, - &ts_present, &ts_val, &ts_ecr); + if (tp->t_state != TCPS_LISTEN) +#ifdef TCP_SIGNATURE + if (optp || (tp->t_flags & TF_SIGNATURE)) +#else /* TCP_SIGNATURE */ + if (optp) +#endif /* TCP_SIGNATURE */ + if (tcp_dooptions(tp, optp, optlen, th, m, iphlen, + &ts_present, &ts_val, &ts_ecr)) + goto drop; #ifdef TCP_SACK if (!tp->sack_disable) { @@ -1068,7 +1074,7 @@ findpcb: case PF_INET6: { struct sockaddr_in6 *sin6; - struct laddr6; + struct in6_addr laddr6; /* * This is probably the place to set the tp->pf @@ -1113,9 +1119,19 @@ findpcb: goto drop; } - if (optp) - tcp_dooptions(tp, optp, optlen, th, - &ts_present, &ts_val, &ts_ecr); +#ifdef TCP_SIGNATURE + if (optp || (tp->t_flags & TF_SIGNATURE)) { +#else /* TCP_SIGNATURE */ + if (optp) { +#endif /* TCP_SIGNATURE */ + m->m_data -= iphlen + off; + m->m_len += iphlen + off; + if (tcp_dooptions(tp, optp, optlen, th, m, iphlen, + &ts_present, &ts_val, &ts_ecr)) + goto drop; + m->m_data += iphlen + off; + m->m_len -= iphlen + off; + } #ifdef TCP_SACK /* @@ -2137,17 +2153,22 @@ drop: #ifndef TUBA_INCLUDE } -void -tcp_dooptions(tp, cp, cnt, th, ts_present, ts_val, ts_ecr) +int +tcp_dooptions(tp, cp, cnt, th, m, iphlen, ts_present, ts_val, ts_ecr) struct tcpcb *tp; u_char *cp; int cnt; struct tcphdr *th; + struct mbuf *m; + int iphlen; int *ts_present; u_int32_t *ts_val, *ts_ecr; { u_int16_t mss = 0; int opt, optlen; +#ifdef TCP_SIGNATURE + caddr_t sigp = NULL; +#endif /* TCP_SIGNATURE */ for (; cnt > 0; cnt -= optlen, cp += optlen) { opt = cp[0]; @@ -2216,12 +2237,137 @@ tcp_dooptions(tp, cp, cnt, th, ts_present, ts_val, ts_ecr) continue; break; #endif +#ifdef TCP_SIGNATURE + case TCPOPT_SIGNATURE: + if (optlen != TCPOLEN_SIGNATURE) + continue; + + if (sigp && bcmp(sigp, cp + 2, 16)) + return -1; + + sigp = cp + 2; + break; +#endif /* TCP_SIGNATURE */ } } +#ifdef TCP_SIGNATURE + if ((sigp ? TF_SIGNATURE : 0) ^ (tp->t_flags & TF_SIGNATURE)) { + tcpstat.tcps_rcvbadsig++; + return -1; + } + + if (sigp) { + MD5_CTX ctx; + union sockaddr_union sa; + struct tdb *tdb; + char sig[16]; + + memset(&sa, 0, sizeof(union sockaddr_union)); + + switch (tp->pf) { + case 0: + case AF_INET: + sa.sa.sa_len = sizeof(struct sockaddr_in); + sa.sa.sa_family = AF_INET; + sa.sin.sin_addr = tp->t_inpcb->inp_laddr; + break; +#ifdef INET6 + case AF_INET6: + sa.sa.sa_len = sizeof(struct sockaddr_in6); + sa.sa.sa_family = AF_INET6; + sa.sin6.sin6_addr = tp->t_inpcb->inp_laddr6; + break; +#endif /* INET6 */ + } + + tdb = gettdb(0, &sa, IPPROTO_TCP); + if (tdb == NULL) { + printf("tdb miss\n"); + tcpstat.tcps_rcvbadsig++; + return -1; + } + + MD5Init(&ctx); + + switch(tp->pf) { + case 0: +#ifdef INET + case AF_INET: + { + struct ippseudo ippseudo; + + ippseudo.ippseudo_src = + tp->t_inpcb->inp_faddr; + ippseudo.ippseudo_dst = + tp->t_inpcb->inp_laddr; + ippseudo.ippseudo_pad = 0; + ippseudo.ippseudo_p = IPPROTO_TCP; + ippseudo.ippseudo_len = htons( + m->m_pkthdr.len - iphlen); + + MD5Update(&ctx, (char *)&ippseudo, + sizeof(struct ippseudo)); + } + break; +#endif /* INET */ +#ifdef INET6 + case AF_INET6: + { + static int printed = 0; + + if (!printed) { + printf("error: TCP MD5 support" + " for IPv6 not yet" + " implemented.\n"); + printed = 1; + } + } + break +#endif /* INET6 */ + } + + { + struct tcphdr tcphdr; + + tcphdr.th_sport = th->th_sport; + tcphdr.th_dport = th->th_dport; + tcphdr.th_seq = htonl(th->th_seq); + tcphdr.th_ack = htonl(th->th_ack); + tcphdr.th_off = th->th_off; + tcphdr.th_x2 = th->th_x2; + tcphdr.th_flags = th->th_flags; + tcphdr.th_win = htons(th->th_win); + tcphdr.th_sum = 0; + tcphdr.th_urp = htons(th->th_urp); + + MD5Update(&ctx, (char *)&tcphdr, + sizeof(struct tcphdr)); + } + + if (m_apply(m, iphlen + th->th_off * sizeof(uint32_t), + m->m_pkthdr.len - (iphlen + th->th_off * + sizeof(uint32_t)), tcp_signature_apply, + (caddr_t)&ctx)) + return (-1); + + MD5Update(&ctx, tdb->tdb_amxkey, tdb->tdb_amxkeylen); + MD5Final(sig, &ctx); + + if (bcmp(sig, sigp, 16)) { + tcpstat.tcps_rcvbadsig++; + return (-1); + } + + tcpstat.tcps_rcvgoodsig++; + }; +#endif /* TCP_SIGNATURE */ + /* Update t_maxopd and t_maxseg after all options are processed */ if (th->th_flags & TH_SYN) (void) tcp_mss(tp, mss); /* sets t_maxseg */ + + return (0); } #if defined(TCP_SACK) || defined(TCP_NEWRENO) diff --git a/sys/netinet/tcp_output.c b/sys/netinet/tcp_output.c index 8c6eecfb9c7..7f79d2067a7 100644 --- a/sys/netinet/tcp_output.c +++ b/sys/netinet/tcp_output.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tcp_output.c,v 1.20 1999/07/06 20:14:06 cmetz Exp $ */ +/* $OpenBSD: tcp_output.c,v 1.21 1999/07/06 20:17:53 cmetz Exp $ */ /* $NetBSD: tcp_output.c,v 1.16 1997/06/03 16:17:09 kml Exp $ */ /* @@ -83,6 +83,10 @@ didn't get a copy, you may request one from <license@ipv6.nrl.navy.mil>. #include <netinet6/tcpipv6.h> #endif /* INET6 */ +#ifdef TCP_SIGNATURE +#include <sys/md5k.h> +#endif /* TCP_SIGNATURE */ + #ifdef notyet extern struct mbuf *m_copypack(); #endif @@ -186,6 +190,14 @@ tcp_output(tp) #if defined(TCP_SACK) || defined(TCP_NEWRENO) int maxburst = TCP_MAXBURST; #endif +#ifdef TCP_SIGNATURE + unsigned int sigoff; +#endif /* TCP_SIGNATURE */ + +#if defined(TCP_SACK) && defined(TCP_SIGNATURE) && defined(DIAGNOSTIC) + if (!tp->sack_disable && (tp->t_flags & TF_SIGNATURE)) + return (EINVAL); +#endif /* defined(TCP_SACK) && defined(TCP_SIGNATURE) && defined(DIAGNOSTIC) */ /* * Determine length of data that should be transmitted, @@ -509,6 +521,33 @@ send: optlen += TCPOLEN_TSTAMP_APPA; } +#ifdef TCP_SIGNATURE + if (tp->t_flags & TF_SIGNATURE) { + u_int8_t *bp = (u_int8_t *)(opt + optlen); + + /* Send signature option */ + *(bp++) = TCPOPT_SIGNATURE; + *(bp++) = TCPOLEN_SIGNATURE; + sigoff = optlen + 2; + + { + unsigned int i; + + for (i = 0; i < 16; i++) + *(bp++) = 0; + } + + optlen += TCPOLEN_SIGNATURE; + + /* Pad options list to the next 32 bit boundary and + * terminate it. + */ + *bp++ = TCPOPT_NOP; + *bp++ = TCPOPT_EOL; + optlen += 2; + } +#endif /* TCP_SIGNATURE */ + #ifdef TCP_SACK /* * Send SACKs if necessary. This should be the last option processed. @@ -743,6 +782,93 @@ send: #endif /* INET6 */ } +#ifdef TCP_SIGNATURE + if (tp->t_flags & TF_SIGNATURE) { + MD5_CTX ctx; + union sockaddr_union sa; + struct tdb *tdb; + + memset(&sa, 0, sizeof(union sockaddr_union)); + +#if defined(INET) && defined(INET6) + switch(tp->pf) { +#else /* defined(INET) && defined(INET6) */ + switch (0) { +#endif /* defined(INET) && defined(INET6) */ + case 0: +#ifdef INET + case AF_INET: + sa.sa.sa_len = sizeof(struct sockaddr_in); + sa.sa.sa_family = AF_INET; + sa.sin.sin_addr = mtod(m, struct ip *)->ip_dst; + break; +#endif /* INET */ +#ifdef INET6 + case AF_INET6: + sa.sa.sa_len = sizeof(struct sockaddr_in6); + sa.sa.sa_family = AF_INET6; + sa.sin6.sin6_addr = mtod(m, struct ipv6 *)->ipv6_dst; + break; +#endif /* INET6 */ + } + + tdb = gettdb(0, &sa, IPPROTO_TCP); + if (tdb == NULL) + return (EPERM); + + MD5Init(&ctx); + +#if defined(INET) && defined(INET6) + switch(tp->pf) { +#else /* defined(INET) && defined(INET6) */ + switch (0) { +#endif /* defined(INET) && defined(INET6) */ + case 0: +#ifdef INET + case AF_INET: + { + struct ippseudo ippseudo; + struct ipovly *ipovly; + + ipovly = mtod(m, struct ipovly *); + + ippseudo.ippseudo_src = ipovly->ih_src; + ippseudo.ippseudo_dst = ipovly->ih_dst; + ippseudo.ippseudo_pad = 0; + ippseudo.ippseudo_p = IPPROTO_TCP; + ippseudo.ippseudo_len = ipovly->ih_len; + MD5Update(&ctx, (char *)&ippseudo, + sizeof(struct ippseudo)); + MD5Update(&ctx, mtod(m, caddr_t) + + sizeof(struct ip), + sizeof(struct tcphdr)); + } + break; +#endif /* INET */ +#ifdef INET6 + case AF_INET6: + { + static int printed = 0; + + if (!printed) { + printf("error: TCP MD5 support for " + "IPv6 not yet implemented.\n"); + printed = 1; + } + } + break; +#endif /* INET6 */ + } + + if (len && m_apply(m, hdrlen, len, tcp_signature_apply, + (caddr_t)&ctx)) + return (EINVAL); + + MD5Update(&ctx, tdb->tdb_amxkey, tdb->tdb_amxkeylen); + MD5Final(mtod(m, caddr_t) + hdrlen - optlen + sigoff, &ctx); + } +#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 5c733a877ad..b0f498d808c 100644 --- a/sys/netinet/tcp_subr.c +++ b/sys/netinet/tcp_subr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tcp_subr.c,v 1.17 1999/07/06 18:01:55 cmetz Exp $ */ +/* $OpenBSD: tcp_subr.c,v 1.18 1999/07/06 20:17:53 cmetz Exp $ */ /* $NetBSD: tcp_subr.c,v 1.22 1996/02/13 23:44:00 christos Exp $ */ /* @@ -81,6 +81,10 @@ didn't get a copy, you may request one from <license@ipv6.nrl.navy.mil>. #include <sys/domain.h> #endif /* INET6 */ +#ifdef TCP_SIGNATURE +#include <sys/md5k.h> +#endif /* TCP_SIGNATURE */ + /* patchable/settable parameters for tcp */ int tcp_mssdflt = TCP_MSS; int tcp_rttdflt = TCPTV_SRTTDFLT / PR_SLOWHZ; @@ -756,3 +760,92 @@ tcp_quench(inp, errno) if (tp) tp->snd_cwnd = tp->t_maxseg; } + +#ifdef TCP_SIGNATURE +int +tcp_signature_tdb_attach() +{ + return (0); +} + +int +tcp_signature_tdb_init(tdbp, xsp, ii) + struct tdb *tdbp; + struct xformsw *xsp; + struct ipsecinit *ii; +{ + char *c; +#define isdigit(c) (((c) >= '0') && ((c) <= '9')) +#define isalpha(c) ( (((c) >= 'A') && ((c) <= 'Z')) || \ + (((c) >= 'a') && ((c) <= 'z')) ) + + if ((ii->ii_authkeylen < 1) || (ii->ii_authkeylen > 80)) + return (EINVAL); + + c = (char *)ii->ii_authkey; + + while (c < (char *)ii->ii_authkey + ii->ii_authkeylen - 1) { + if (isdigit(*c)) { + if (*(c + 1) == ' ') + return (EINVAL); + } else { + if (!isalpha(*c)) + return (EINVAL); + } + + c++; + } + + if (!isdigit(*c) && !isalpha(*c)) + return (EINVAL); + + tdbp->tdb_amxkey = malloc(ii->ii_authkeylen, M_XDATA, M_DONTWAIT); + if (tdbp->tdb_amxkey == NULL) + return (ENOMEM); + bcopy(ii->ii_authkey, tdbp->tdb_amxkey, ii->ii_authkeylen); + tdbp->tdb_amxkeylen = ii->ii_authkeylen; + + return (0); +} + +int +tcp_signature_tdb_zeroize(tdbp) + struct tdb *tdbp; +{ + if (tdbp->tdb_amxkey) { + bzero(tdbp->tdb_amxkey, tdbp->tdb_amxkeylen); + free(tdbp->tdb_amxkey, M_XDATA); + tdbp->tdb_amxkey = NULL; + } + + return (0); +} + +struct mbuf * +tcp_signature_tdb_input(m, tdbp) + struct mbuf *m; + struct tdb *tdbp; +{ + return (0); +} + +int +tcp_signature_tdb_output(m, gw, tdbp, mp) + struct mbuf *m; + struct sockaddr_encap *gw; + struct tdb *tdbp; + struct mbuf **mp; +{ + return (EINVAL); +} + +int +tcp_signature_apply(fstate, data, len) + caddr_t fstate; + caddr_t data; + unsigned int len; +{ + MD5Update((MD5_CTX *)fstate, (char *)data, len); + return 0; +} +#endif /* TCP_SIGNATURE */ diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c index de6ee75474f..d9ca963cc58 100644 --- a/sys/netinet/tcp_usrreq.c +++ b/sys/netinet/tcp_usrreq.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tcp_usrreq.c,v 1.34 1999/07/02 20:39:08 cmetz Exp $ */ +/* $OpenBSD: tcp_usrreq.c,v 1.35 1999/07/06 20:17:53 cmetz Exp $ */ /* $NetBSD: tcp_usrreq.c,v 1.20 1996/02/13 23:44:16 christos Exp $ */ /* @@ -555,13 +555,39 @@ tcp_ctloutput(op, so, level, optname, mp) break; } + if (tp->t_flags & TF_SIGNATURE) { + error = EPERM; + break; + } + if (*mtod(m, int *)) tp->sack_disable = 1; else tp->sack_disable = 0; break; #endif - default: +#ifdef TCP_SIGNATURE + case TCP_SIGNATURE_ENABLE: + if (m == NULL || m->m_len < sizeof (int)) { + error = EINVAL; + break; + } + + if (TCPS_HAVEESTABLISHED(tp->t_state)) { + error = EPERM; + break; + } + + if (*mtod(m, int *)) { + tp->t_flags |= TF_SIGNATURE; +#ifdef TCP_SACK + tp->sack_disable = 1; +#endif /* TCP_SACK */ + } else + tp->t_flags &= ~TF_SIGNATURE; + break; +#endif /* TCP_SIGNATURE */ + default: error = ENOPROTOOPT; break; } diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h index 3dfc0277860..7b583c5fae5 100644 --- a/sys/netinet/tcp_var.h +++ b/sys/netinet/tcp_var.h @@ -1,4 +1,4 @@ -/* $OpenBSD: tcp_var.h,v 1.20 1999/07/02 21:22:14 cmetz Exp $ */ +/* $OpenBSD: tcp_var.h,v 1.21 1999/07/06 20:17:53 cmetz Exp $ */ /* $NetBSD: tcp_var.h,v 1.17 1996/02/13 23:44:24 christos Exp $ */ /* @@ -76,6 +76,7 @@ struct tcpcb { #define TF_REQ_TSTMP 0x0080 /* have/will request timestamps */ #define TF_RCVD_TSTMP 0x0100 /* a timestamp was received in SYN */ #define TF_SACK_PERMIT 0x0200 /* other side said I could SACK */ +#define TF_SIGNATURE 0x0400 /* require TCP MD5 signature */ struct mbuf *t_template; /* skeletal packet for transmit */ struct inpcb *t_inpcb; /* back pointer to internet pcb */ @@ -267,6 +268,9 @@ struct tcpstat { u_int32_t tcps_pcbhashmiss; /* input packets missing pcb hash */ u_int32_t tcps_noport; /* no socket on port */ u_int32_t tcps_badsyn; /* SYN packet with src==dst rcv'ed */ + + u_int32_t tcps_rcvbadsig; /* rcvd bad/missing TCP signatures */ + u_int64_t tcps_rcvgoodsig; /* rcvd good TCP signatures */ }; /* @@ -326,8 +330,8 @@ struct tcpcb * tcp_disconnect __P((struct tcpcb *)); struct tcpcb * tcp_drop __P((struct tcpcb *, int)); -void tcp_dooptions __P((struct tcpcb *, - u_char *, int, struct tcphdr *, int *, u_int32_t *, u_int32_t *)); +int tcp_dooptions __P((struct tcpcb *, u_char *, int, struct tcphdr *, + struct mbuf *, int, int *, u_int32_t *, u_int32_t *)); void tcp_drain __P((void)); void tcp_fasttimo __P((void)); void tcp_init __P((void)); @@ -373,5 +377,8 @@ void tcp_print_holes __P((struct tcpcb *tp)); int tcp_newreno __P((struct tcpcb *, struct tcphdr *)); u_long tcp_seq_subtract __P((u_long, u_long )); #endif /* TCP_NEWRENO || TCP_SACK */ +#ifdef TCP_SIGNATURE +int tcp_signature_apply __P((caddr_t, caddr_t, unsigned int)); +#endif /* TCP_SIGNATURE */ #endif /* _KERNEL */ |