xform_tcp.c (302408) | xform_tcp.c (315514) |
---|---|
1/* $FreeBSD: stable/11/sys/netipsec/xform_tcp.c 302054 2016-06-21 13:48:49Z bz $ */ 2 | |
3/*- 4 * Copyright (c) 2003 Bruce M. Simpson <bms@spc.org> | 1/*- 2 * Copyright (c) 2003 Bruce M. Simpson <bms@spc.org> |
3 * Copyright (c) 2016 Andrey V. Elsukov <ae@FreeBSD.org> |
|
5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright --- 10 unchanged lines hidden (view full) --- 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30/* TCP MD5 Signature Option (RFC2385) */ | 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright --- 10 unchanged lines hidden (view full) --- 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29/* TCP MD5 Signature Option (RFC2385) */ |
30#include <sys/cdefs.h> 31__FBSDID("$FreeBSD: stable/11/sys/netipsec/xform_tcp.c 315514 2017-03-18 22:04:20Z ae $"); 32 |
|
31#include "opt_inet.h" 32#include "opt_inet6.h" | 33#include "opt_inet.h" 34#include "opt_inet6.h" |
35#include "opt_ipsec.h" |
|
33 34#include <sys/param.h> 35#include <sys/systm.h> 36#include <sys/mbuf.h> 37#include <sys/lock.h> | 36 37#include <sys/param.h> 38#include <sys/systm.h> 39#include <sys/mbuf.h> 40#include <sys/lock.h> |
41#include <sys/md5.h> 42#include <sys/rmlock.h> |
|
38#include <sys/socket.h> | 43#include <sys/socket.h> |
44#include <sys/sockopt.h> |
|
39#include <sys/kernel.h> | 45#include <sys/kernel.h> |
46#include <sys/module.h> |
|
40#include <sys/protosw.h> | 47#include <sys/protosw.h> |
41#include <sys/sysctl.h> | |
42 43#include <netinet/in.h> | 48 49#include <netinet/in.h> |
50#include <netinet/in_pcb.h> |
|
44#include <netinet/in_systm.h> 45#include <netinet/ip.h> 46#include <netinet/ip_var.h> 47#include <netinet/tcp.h> 48#include <netinet/tcp_var.h> 49 50#include <net/vnet.h> 51 52#include <netipsec/ipsec.h> | 51#include <netinet/in_systm.h> 52#include <netinet/ip.h> 53#include <netinet/ip_var.h> 54#include <netinet/tcp.h> 55#include <netinet/tcp_var.h> 56 57#include <net/vnet.h> 58 59#include <netipsec/ipsec.h> |
60#include <netipsec/ipsec_support.h> |
|
53#include <netipsec/xform.h> 54 55#ifdef INET6 56#include <netinet/ip6.h> 57#include <netipsec/ipsec6.h> 58#endif 59 60#include <netipsec/key.h> 61#include <netipsec/key_debug.h> 62 | 61#include <netipsec/xform.h> 62 63#ifdef INET6 64#include <netinet/ip6.h> 65#include <netipsec/ipsec6.h> 66#endif 67 68#include <netipsec/key.h> 69#include <netipsec/key_debug.h> 70 |
71#define TCP_SIGLEN 16 /* length of computed digest in bytes */ 72#define TCP_KEYLEN_MIN 1 /* minimum length of TCP-MD5 key */ 73#define TCP_KEYLEN_MAX 80 /* maximum length of TCP-MD5 key */ 74 75static int 76tcp_ipsec_pcbctl(struct inpcb *inp, struct sockopt *sopt) 77{ 78 struct tcpcb *tp; 79 int error, optval; 80 81 INP_WLOCK_ASSERT(inp); 82 if (sopt->sopt_name != TCP_MD5SIG) { 83 INP_WUNLOCK(inp); 84 return (ENOPROTOOPT); 85 } 86 87 tp = intotcpcb(inp); 88 if (sopt->sopt_dir == SOPT_GET) { 89 optval = (tp->t_flags & TF_SIGNATURE) ? 1 : 0; 90 INP_WUNLOCK(inp); 91 92 /* On success return with released INP_WLOCK */ 93 return (sooptcopyout(sopt, &optval, sizeof(optval))); 94 } 95 96 INP_WUNLOCK(inp); 97 98 error = sooptcopyin(sopt, &optval, sizeof(optval), sizeof(optval)); 99 if (error != 0) 100 return (error); 101 102 /* INP_WLOCK_RECHECK */ 103 INP_WLOCK(inp); 104 if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) { 105 INP_WUNLOCK(inp); 106 return (ECONNRESET); 107 } 108 if (optval > 0) 109 tp->t_flags |= TF_SIGNATURE; 110 else 111 tp->t_flags &= ~TF_SIGNATURE; 112 113 /* On success return with acquired INP_WLOCK */ 114 return (error); 115} 116 |
|
63/* | 117/* |
118 * Callback function invoked by m_apply() to digest TCP segment data 119 * contained within an mbuf chain. 120 */ 121static int 122tcp_signature_apply(void *fstate, void *data, u_int len) 123{ 124 125 MD5Update(fstate, (u_char *)data, len); 126 return (0); 127} 128 129#ifdef INET 130static int 131ip_pseudo_compute(struct mbuf *m, MD5_CTX *ctx) 132{ 133 struct ippseudo ipp; 134 struct ip *ip; 135 136 ip = mtod(m, struct ip *); 137 ipp.ippseudo_src.s_addr = ip->ip_src.s_addr; 138 ipp.ippseudo_dst.s_addr = ip->ip_dst.s_addr; 139 ipp.ippseudo_p = IPPROTO_TCP; 140 ipp.ippseudo_pad = 0; 141 ipp.ippseudo_len = htons(m->m_pkthdr.len - (ip->ip_hl << 2)); 142 MD5Update(ctx, (char *)&ipp, sizeof(ipp)); 143 return (ip->ip_hl << 2); 144} 145#endif 146 147#ifdef INET6 148static int 149ip6_pseudo_compute(struct mbuf *m, MD5_CTX *ctx) 150{ 151 struct ip6_pseudo { 152 struct in6_addr src, dst; 153 uint32_t len; 154 uint32_t nxt; 155 } ip6p __aligned(4); 156 struct ip6_hdr *ip6; 157 158 ip6 = mtod(m, struct ip6_hdr *); 159 ip6p.src = ip6->ip6_src; 160 ip6p.dst = ip6->ip6_dst; 161 ip6p.len = htonl(m->m_pkthdr.len - sizeof(*ip6)); /* XXX: ext headers */ 162 ip6p.nxt = htonl(IPPROTO_TCP); 163 MD5Update(ctx, (char *)&ip6p, sizeof(ip6p)); 164 return (sizeof(*ip6)); 165} 166#endif 167 168static int 169tcp_signature_compute(struct mbuf *m, struct tcphdr *th, 170 struct secasvar *sav, u_char *buf) 171{ 172 MD5_CTX ctx; 173 int len; 174 u_short csum; 175 176 MD5Init(&ctx); 177 /* Step 1: Update MD5 hash with IP(v6) pseudo-header. */ 178 switch (sav->sah->saidx.dst.sa.sa_family) { 179#ifdef INET 180 case AF_INET: 181 len = ip_pseudo_compute(m, &ctx); 182 break; 183#endif 184#ifdef INET6 185 case AF_INET6: 186 len = ip6_pseudo_compute(m, &ctx); 187 break; 188#endif 189 default: 190 return (EAFNOSUPPORT); 191 } 192 /* 193 * Step 2: Update MD5 hash with TCP header, excluding options. 194 * The TCP checksum must be set to zero. 195 */ 196 csum = th->th_sum; 197 th->th_sum = 0; 198 MD5Update(&ctx, (char *)th, sizeof(struct tcphdr)); 199 th->th_sum = csum; 200 /* 201 * Step 3: Update MD5 hash with TCP segment data. 202 * Use m_apply() to avoid an early m_pullup(). 203 */ 204 len += (th->th_off << 2); 205 if (m->m_pkthdr.len - len > 0) 206 m_apply(m, len, m->m_pkthdr.len - len, 207 tcp_signature_apply, &ctx); 208 /* 209 * Step 4: Update MD5 hash with shared secret. 210 */ 211 MD5Update(&ctx, sav->key_auth->key_data, _KEYLEN(sav->key_auth)); 212 MD5Final(buf, &ctx); 213 key_sa_recordxfer(sav, m); 214 return (0); 215} 216 217static void 218setsockaddrs(const struct mbuf *m, union sockaddr_union *src, 219 union sockaddr_union *dst) 220{ 221 struct ip *ip; 222 223 IPSEC_ASSERT(m->m_len >= sizeof(*ip), ("unexpected mbuf len")); 224 225 ip = mtod(m, struct ip *); 226 switch (ip->ip_v) { 227#ifdef INET 228 case IPVERSION: 229 ipsec4_setsockaddrs(m, src, dst); 230 break; 231#endif 232#ifdef INET6 233 case (IPV6_VERSION >> 4): 234 ipsec6_setsockaddrs(m, src, dst); 235 break; 236#endif 237 default: 238 bzero(src, sizeof(*src)); 239 bzero(dst, sizeof(*dst)); 240 } 241} 242 243/* 244 * Compute TCP-MD5 hash of an *INBOUND* TCP segment. 245 * Parameters: 246 * m pointer to head of mbuf chain 247 * th pointer to TCP header 248 * buf pointer to storage for computed MD5 digest 249 * 250 * Return 0 if successful, otherwise return -1. 251 */ 252static int 253tcp_ipsec_input(struct mbuf *m, struct tcphdr *th, u_char *buf) 254{ 255 char tmpdigest[TCP_SIGLEN]; 256 struct secasindex saidx; 257 struct secasvar *sav; 258 259 setsockaddrs(m, &saidx.src, &saidx.dst); 260 saidx.proto = IPPROTO_TCP; 261 saidx.mode = IPSEC_MODE_TCPMD5; 262 saidx.reqid = 0; 263 sav = key_allocsa_tcpmd5(&saidx); 264 if (sav == NULL) { 265 KMOD_TCPSTAT_INC(tcps_sig_err_buildsig); 266 return (EACCES); 267 } 268 /* 269 * tcp_input() operates with TCP header fields in host 270 * byte order. We expect them in network byte order. 271 */ 272 tcp_fields_to_net(th); 273 tcp_signature_compute(m, th, sav, tmpdigest); 274 tcp_fields_to_host(th); 275 key_freesav(&sav); 276 if (bcmp(buf, tmpdigest, TCP_SIGLEN) != 0) { 277 KMOD_TCPSTAT_INC(tcps_sig_rcvbadsig); 278 return (EACCES); 279 } 280 KMOD_TCPSTAT_INC(tcps_sig_rcvgoodsig); 281 return (0); 282} 283 284/* 285 * Compute TCP-MD5 hash of an *OUTBOUND* TCP segment. 286 * Parameters: 287 * m pointer to head of mbuf chain 288 * th pointer to TCP header 289 * buf pointer to storage for computed MD5 digest 290 * 291 * Return 0 if successful, otherwise return error code. 292 */ 293static int 294tcp_ipsec_output(struct mbuf *m, struct tcphdr *th, u_char *buf) 295{ 296 struct secasindex saidx; 297 struct secasvar *sav; 298 299 setsockaddrs(m, &saidx.src, &saidx.dst); 300 saidx.proto = IPPROTO_TCP; 301 saidx.mode = IPSEC_MODE_TCPMD5; 302 saidx.reqid = 0; 303 sav = key_allocsa_tcpmd5(&saidx); 304 if (sav == NULL) { 305 KMOD_TCPSTAT_INC(tcps_sig_err_buildsig); 306 return (EACCES); 307 } 308 tcp_signature_compute(m, th, sav, buf); 309 key_freesav(&sav); 310 return (0); 311} 312 313/* |
|
64 * Initialize a TCP-MD5 SA. Called when the SA is being set up. 65 * 66 * We don't need to set up the tdb prefixed fields, as we don't use the 67 * opencrypto code; we just perform a key length check. 68 * | 314 * Initialize a TCP-MD5 SA. Called when the SA is being set up. 315 * 316 * We don't need to set up the tdb prefixed fields, as we don't use the 317 * opencrypto code; we just perform a key length check. 318 * |
69 * XXX: Currently we only allow a single 'magic' SPI to be used. | 319 * XXX: Currently we have used single 'magic' SPI and need to still 320 * support this. |
70 * 71 * This allows per-host granularity without affecting the userland 72 * interface, which is a simple socket option toggle switch, 73 * TCP_SIGNATURE_ENABLE. 74 * 75 * To allow per-service granularity requires that we have a means 76 * of mapping port to SPI. The mandated way of doing this is to 77 * use SPD entries to specify packet flows which get the TCP-MD5 78 * treatment, however the code to do this is currently unstable 79 * and unsuitable for production use. 80 * 81 * Therefore we use this compromise in the meantime. 82 */ 83static int 84tcpsignature_init(struct secasvar *sav, struct xformsw *xsp) 85{ 86 int keylen; 87 | 321 * 322 * This allows per-host granularity without affecting the userland 323 * interface, which is a simple socket option toggle switch, 324 * TCP_SIGNATURE_ENABLE. 325 * 326 * To allow per-service granularity requires that we have a means 327 * of mapping port to SPI. The mandated way of doing this is to 328 * use SPD entries to specify packet flows which get the TCP-MD5 329 * treatment, however the code to do this is currently unstable 330 * and unsuitable for production use. 331 * 332 * Therefore we use this compromise in the meantime. 333 */ 334static int 335tcpsignature_init(struct secasvar *sav, struct xformsw *xsp) 336{ 337 int keylen; 338 |
88 if (sav->spi != htonl(TCP_SIG_SPI)) { 89 DPRINTF(("%s: SPI must be TCP_SIG_SPI (0x1000)\n", 90 __func__)); 91 return (EINVAL); 92 } | |
93 if (sav->alg_auth != SADB_X_AALG_TCP_MD5) { 94 DPRINTF(("%s: unsupported authentication algorithm %u\n", 95 __func__, sav->alg_auth)); 96 return (EINVAL); 97 } 98 if (sav->key_auth == NULL) { 99 DPRINTF(("%s: no authentication key present\n", __func__)); 100 return (EINVAL); 101 } 102 keylen = _KEYLEN(sav->key_auth); 103 if ((keylen < TCP_KEYLEN_MIN) || (keylen > TCP_KEYLEN_MAX)) { 104 DPRINTF(("%s: invalid key length %u\n", __func__, keylen)); 105 return (EINVAL); 106 } | 339 if (sav->alg_auth != SADB_X_AALG_TCP_MD5) { 340 DPRINTF(("%s: unsupported authentication algorithm %u\n", 341 __func__, sav->alg_auth)); 342 return (EINVAL); 343 } 344 if (sav->key_auth == NULL) { 345 DPRINTF(("%s: no authentication key present\n", __func__)); 346 return (EINVAL); 347 } 348 keylen = _KEYLEN(sav->key_auth); 349 if ((keylen < TCP_KEYLEN_MIN) || (keylen > TCP_KEYLEN_MAX)) { 350 DPRINTF(("%s: invalid key length %u\n", __func__, keylen)); 351 return (EINVAL); 352 } |
107 | 353 sav->tdb_xform = xsp; |
108 return (0); 109} 110 111/* | 354 return (0); 355} 356 357/* |
112 * Paranoia. 113 * | |
114 * Called when the SA is deleted. 115 */ 116static int 117tcpsignature_zeroize(struct secasvar *sav) 118{ 119 | 358 * Called when the SA is deleted. 359 */ 360static int 361tcpsignature_zeroize(struct secasvar *sav) 362{ 363 |
120 if (sav->key_auth) | 364 if (sav->key_auth != NULL) |
121 bzero(sav->key_auth->key_data, _KEYLEN(sav->key_auth)); | 365 bzero(sav->key_auth->key_data, _KEYLEN(sav->key_auth)); |
122 123 sav->tdb_cryptoid = 0; 124 sav->tdb_authalgxform = NULL; | |
125 sav->tdb_xform = NULL; | 366 sav->tdb_xform = NULL; |
126 | |
127 return (0); 128} 129 | 367 return (0); 368} 369 |
130/* 131 * Verify that an input packet passes authentication. 132 * Called from the ipsec layer. 133 * We do this from within tcp itself, so this routine is just a stub. 134 */ 135static int 136tcpsignature_input(struct mbuf *m, struct secasvar *sav, int skip, 137 int protoff) 138{ | 370static struct xformsw tcpsignature_xformsw = { 371 .xf_type = XF_TCPSIGNATURE, 372 .xf_name = "TCP-MD5", 373 .xf_init = tcpsignature_init, 374 .xf_zeroize = tcpsignature_zeroize, 375}; |
139 | 376 |
140 return (0); 141} | 377static const struct tcpmd5_methods tcpmd5_methods = { 378 .input = tcp_ipsec_input, 379 .output = tcp_ipsec_output, 380 .pcbctl = tcp_ipsec_pcbctl, 381}; |
142 | 382 |
143/* 144 * Prepend the authentication header. 145 * Called from the ipsec layer. 146 * We do this from within tcp itself, so this routine is just a stub. 147 */ | 383#ifndef KLD_MODULE 384/* TCP-MD5 support is build in the kernel */ 385static const struct tcpmd5_support tcpmd5_ipsec = { 386 .enabled = IPSEC_MODULE_ENABLED, 387 .methods = &tcpmd5_methods 388}; 389const struct tcpmd5_support * const tcp_ipsec_support = &tcpmd5_ipsec; 390#endif /* !KLD_MODULE */ 391 |
148static int | 392static int |
149tcpsignature_output(struct mbuf *m, struct ipsecrequest *isr, 150 struct mbuf **mp, int skip, int protoff) | 393tcpmd5_modevent(module_t mod, int type, void *data) |
151{ 152 | 394{ 395 |
153 return (EINVAL); | 396 switch (type) { 397 case MOD_LOAD: 398 xform_attach(&tcpsignature_xformsw); 399#ifdef KLD_MODULE 400 tcpmd5_support_enable(&tcpmd5_methods); 401#endif 402 break; 403 case MOD_UNLOAD: 404#ifdef KLD_MODULE 405 tcpmd5_support_disable(); 406#endif 407 xform_detach(&tcpsignature_xformsw); 408 break; 409 default: 410 return (EOPNOTSUPP); 411 } 412 return (0); |
154} 155 | 413} 414 |
156static struct xformsw tcpsignature_xformsw = { 157 XF_TCPSIGNATURE, XFT_AUTH, "TCPMD5", 158 tcpsignature_init, tcpsignature_zeroize, 159 tcpsignature_input, tcpsignature_output | 415static moduledata_t tcpmd5_mod = { 416 "tcpmd5", 417 tcpmd5_modevent, 418 0 |
160}; 161 | 419}; 420 |
162static void 163tcpsignature_attach(void) 164{ 165 166 xform_register(&tcpsignature_xformsw); 167} 168 169SYSINIT(tcpsignature_xform_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_MIDDLE, 170 tcpsignature_attach, NULL); | 421DECLARE_MODULE(tcpmd5, tcpmd5_mod, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY); 422MODULE_VERSION(tcpmd5, 1); 423#ifdef KLD_MODULE 424MODULE_DEPEND(tcpmd5, ipsec_support, 1, 1, 1); 425#endif |