1c398230bSWarner Losh /*- 2*fe267a55SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 3*fe267a55SPedro F. Giffuni * 455d2c71bSBruce M Simpson * Copyright (c) 2003 Bruce M. Simpson <bms@spc.org> 5fcf59617SAndrey V. Elsukov * Copyright (c) 2016 Andrey V. Elsukov <ae@FreeBSD.org> 655d2c71bSBruce M Simpson * 755d2c71bSBruce M Simpson * Redistribution and use in source and binary forms, with or without 855d2c71bSBruce M Simpson * modification, are permitted provided that the following conditions 955d2c71bSBruce M Simpson * are met: 1055d2c71bSBruce M Simpson * 1155d2c71bSBruce M Simpson * 1. Redistributions of source code must retain the above copyright 1255d2c71bSBruce M Simpson * notice, this list of conditions and the following disclaimer. 1355d2c71bSBruce M Simpson * 2. Redistributions in binary form must reproduce the above copyright 1455d2c71bSBruce M Simpson * notice, this list of conditions and the following disclaimer in the 1555d2c71bSBruce M Simpson * documentation and/or other materials provided with the distribution. 1655d2c71bSBruce M Simpson * 3. The name of the author may not be used to endorse or promote products 1755d2c71bSBruce M Simpson * derived from this software without specific prior written permission. 1855d2c71bSBruce M Simpson * 1955d2c71bSBruce M Simpson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 2055d2c71bSBruce M Simpson * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2155d2c71bSBruce M Simpson * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2255d2c71bSBruce M Simpson * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2355d2c71bSBruce M Simpson * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2455d2c71bSBruce M Simpson * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2555d2c71bSBruce M Simpson * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2655d2c71bSBruce M Simpson * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2755d2c71bSBruce M Simpson * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2855d2c71bSBruce M Simpson * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2955d2c71bSBruce M Simpson */ 3055d2c71bSBruce M Simpson 3155d2c71bSBruce M Simpson /* TCP MD5 Signature Option (RFC2385) */ 32fcf59617SAndrey V. Elsukov #include <sys/cdefs.h> 33fcf59617SAndrey V. Elsukov __FBSDID("$FreeBSD$"); 34fcf59617SAndrey V. Elsukov 3555d2c71bSBruce M Simpson #include "opt_inet.h" 3655d2c71bSBruce M Simpson #include "opt_inet6.h" 37fcf59617SAndrey V. Elsukov #include "opt_ipsec.h" 3855d2c71bSBruce M Simpson 3955d2c71bSBruce M Simpson #include <sys/param.h> 4055d2c71bSBruce M Simpson #include <sys/systm.h> 4155d2c71bSBruce M Simpson #include <sys/mbuf.h> 4255d2c71bSBruce M Simpson #include <sys/lock.h> 43fcf59617SAndrey V. Elsukov #include <sys/md5.h> 44fcf59617SAndrey V. Elsukov #include <sys/rmlock.h> 4555d2c71bSBruce M Simpson #include <sys/socket.h> 46fcf59617SAndrey V. Elsukov #include <sys/sockopt.h> 4755d2c71bSBruce M Simpson #include <sys/kernel.h> 48fcf59617SAndrey V. Elsukov #include <sys/module.h> 4955d2c71bSBruce M Simpson #include <sys/protosw.h> 5055d2c71bSBruce M Simpson 5155d2c71bSBruce M Simpson #include <netinet/in.h> 52fcf59617SAndrey V. Elsukov #include <netinet/in_pcb.h> 5355d2c71bSBruce M Simpson #include <netinet/in_systm.h> 5455d2c71bSBruce M Simpson #include <netinet/ip.h> 5555d2c71bSBruce M Simpson #include <netinet/ip_var.h> 5655d2c71bSBruce M Simpson #include <netinet/tcp.h> 5755d2c71bSBruce M Simpson #include <netinet/tcp_var.h> 5855d2c71bSBruce M Simpson 59eddfbb76SRobert Watson #include <net/vnet.h> 60eddfbb76SRobert Watson 6155d2c71bSBruce M Simpson #include <netipsec/ipsec.h> 62fcf59617SAndrey V. Elsukov #include <netipsec/ipsec_support.h> 6355d2c71bSBruce M Simpson #include <netipsec/xform.h> 6455d2c71bSBruce M Simpson 6555d2c71bSBruce M Simpson #ifdef INET6 6655d2c71bSBruce M Simpson #include <netinet/ip6.h> 6755d2c71bSBruce M Simpson #include <netipsec/ipsec6.h> 6855d2c71bSBruce M Simpson #endif 6955d2c71bSBruce M Simpson 7055d2c71bSBruce M Simpson #include <netipsec/key.h> 7155d2c71bSBruce M Simpson #include <netipsec/key_debug.h> 7255d2c71bSBruce M Simpson 73fcf59617SAndrey V. Elsukov #define TCP_SIGLEN 16 /* length of computed digest in bytes */ 74fcf59617SAndrey V. Elsukov #define TCP_KEYLEN_MIN 1 /* minimum length of TCP-MD5 key */ 75fcf59617SAndrey V. Elsukov #define TCP_KEYLEN_MAX 80 /* maximum length of TCP-MD5 key */ 76fcf59617SAndrey V. Elsukov 77fcf59617SAndrey V. Elsukov static int 78fcf59617SAndrey V. Elsukov tcp_ipsec_pcbctl(struct inpcb *inp, struct sockopt *sopt) 79fcf59617SAndrey V. Elsukov { 80fcf59617SAndrey V. Elsukov struct tcpcb *tp; 81fcf59617SAndrey V. Elsukov int error, optval; 82fcf59617SAndrey V. Elsukov 83fcf59617SAndrey V. Elsukov INP_WLOCK_ASSERT(inp); 84fcf59617SAndrey V. Elsukov if (sopt->sopt_name != TCP_MD5SIG) { 85fcf59617SAndrey V. Elsukov INP_WUNLOCK(inp); 86fcf59617SAndrey V. Elsukov return (ENOPROTOOPT); 87fcf59617SAndrey V. Elsukov } 88fcf59617SAndrey V. Elsukov 89fcf59617SAndrey V. Elsukov tp = intotcpcb(inp); 90fcf59617SAndrey V. Elsukov if (sopt->sopt_dir == SOPT_GET) { 91fcf59617SAndrey V. Elsukov optval = (tp->t_flags & TF_SIGNATURE) ? 1 : 0; 92fcf59617SAndrey V. Elsukov INP_WUNLOCK(inp); 93fcf59617SAndrey V. Elsukov 94fcf59617SAndrey V. Elsukov /* On success return with released INP_WLOCK */ 95fcf59617SAndrey V. Elsukov return (sooptcopyout(sopt, &optval, sizeof(optval))); 96fcf59617SAndrey V. Elsukov } 97fcf59617SAndrey V. Elsukov 98fcf59617SAndrey V. Elsukov INP_WUNLOCK(inp); 99fcf59617SAndrey V. Elsukov 100fcf59617SAndrey V. Elsukov error = sooptcopyin(sopt, &optval, sizeof(optval), sizeof(optval)); 101fcf59617SAndrey V. Elsukov if (error != 0) 102fcf59617SAndrey V. Elsukov return (error); 103fcf59617SAndrey V. Elsukov 104fcf59617SAndrey V. Elsukov /* INP_WLOCK_RECHECK */ 105fcf59617SAndrey V. Elsukov INP_WLOCK(inp); 106fcf59617SAndrey V. Elsukov if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) { 107fcf59617SAndrey V. Elsukov INP_WUNLOCK(inp); 108fcf59617SAndrey V. Elsukov return (ECONNRESET); 109fcf59617SAndrey V. Elsukov } 110fcf59617SAndrey V. Elsukov if (optval > 0) 111fcf59617SAndrey V. Elsukov tp->t_flags |= TF_SIGNATURE; 112fcf59617SAndrey V. Elsukov else 113fcf59617SAndrey V. Elsukov tp->t_flags &= ~TF_SIGNATURE; 114fcf59617SAndrey V. Elsukov 115fcf59617SAndrey V. Elsukov /* On success return with acquired INP_WLOCK */ 116fcf59617SAndrey V. Elsukov return (error); 117fcf59617SAndrey V. Elsukov } 118fcf59617SAndrey V. Elsukov 119fcf59617SAndrey V. Elsukov /* 120fcf59617SAndrey V. Elsukov * Callback function invoked by m_apply() to digest TCP segment data 121fcf59617SAndrey V. Elsukov * contained within an mbuf chain. 122fcf59617SAndrey V. Elsukov */ 123fcf59617SAndrey V. Elsukov static int 124fcf59617SAndrey V. Elsukov tcp_signature_apply(void *fstate, void *data, u_int len) 125fcf59617SAndrey V. Elsukov { 126fcf59617SAndrey V. Elsukov 127fcf59617SAndrey V. Elsukov MD5Update(fstate, (u_char *)data, len); 128fcf59617SAndrey V. Elsukov return (0); 129fcf59617SAndrey V. Elsukov } 130fcf59617SAndrey V. Elsukov 131fcf59617SAndrey V. Elsukov #ifdef INET 132fcf59617SAndrey V. Elsukov static int 133fcf59617SAndrey V. Elsukov ip_pseudo_compute(struct mbuf *m, MD5_CTX *ctx) 134fcf59617SAndrey V. Elsukov { 135fcf59617SAndrey V. Elsukov struct ippseudo ipp; 136fcf59617SAndrey V. Elsukov struct ip *ip; 137fcf59617SAndrey V. Elsukov 138fcf59617SAndrey V. Elsukov ip = mtod(m, struct ip *); 139fcf59617SAndrey V. Elsukov ipp.ippseudo_src.s_addr = ip->ip_src.s_addr; 140fcf59617SAndrey V. Elsukov ipp.ippseudo_dst.s_addr = ip->ip_dst.s_addr; 141fcf59617SAndrey V. Elsukov ipp.ippseudo_p = IPPROTO_TCP; 142fcf59617SAndrey V. Elsukov ipp.ippseudo_pad = 0; 143fcf59617SAndrey V. Elsukov ipp.ippseudo_len = htons(m->m_pkthdr.len - (ip->ip_hl << 2)); 144fcf59617SAndrey V. Elsukov MD5Update(ctx, (char *)&ipp, sizeof(ipp)); 145fcf59617SAndrey V. Elsukov return (ip->ip_hl << 2); 146fcf59617SAndrey V. Elsukov } 147fcf59617SAndrey V. Elsukov #endif 148fcf59617SAndrey V. Elsukov 149fcf59617SAndrey V. Elsukov #ifdef INET6 150fcf59617SAndrey V. Elsukov static int 151fcf59617SAndrey V. Elsukov ip6_pseudo_compute(struct mbuf *m, MD5_CTX *ctx) 152fcf59617SAndrey V. Elsukov { 153fcf59617SAndrey V. Elsukov struct ip6_pseudo { 154fcf59617SAndrey V. Elsukov struct in6_addr src, dst; 155fcf59617SAndrey V. Elsukov uint32_t len; 156fcf59617SAndrey V. Elsukov uint32_t nxt; 157fcf59617SAndrey V. Elsukov } ip6p __aligned(4); 158fcf59617SAndrey V. Elsukov struct ip6_hdr *ip6; 159fcf59617SAndrey V. Elsukov 160fcf59617SAndrey V. Elsukov ip6 = mtod(m, struct ip6_hdr *); 161fcf59617SAndrey V. Elsukov ip6p.src = ip6->ip6_src; 162fcf59617SAndrey V. Elsukov ip6p.dst = ip6->ip6_dst; 163fcf59617SAndrey V. Elsukov ip6p.len = htonl(m->m_pkthdr.len - sizeof(*ip6)); /* XXX: ext headers */ 164fcf59617SAndrey V. Elsukov ip6p.nxt = htonl(IPPROTO_TCP); 165fcf59617SAndrey V. Elsukov MD5Update(ctx, (char *)&ip6p, sizeof(ip6p)); 166fcf59617SAndrey V. Elsukov return (sizeof(*ip6)); 167fcf59617SAndrey V. Elsukov } 168fcf59617SAndrey V. Elsukov #endif 169fcf59617SAndrey V. Elsukov 170fcf59617SAndrey V. Elsukov static int 171fcf59617SAndrey V. Elsukov tcp_signature_compute(struct mbuf *m, struct tcphdr *th, 172fcf59617SAndrey V. Elsukov struct secasvar *sav, u_char *buf) 173fcf59617SAndrey V. Elsukov { 174fcf59617SAndrey V. Elsukov MD5_CTX ctx; 175fcf59617SAndrey V. Elsukov int len; 176fcf59617SAndrey V. Elsukov u_short csum; 177fcf59617SAndrey V. Elsukov 178fcf59617SAndrey V. Elsukov MD5Init(&ctx); 179fcf59617SAndrey V. Elsukov /* Step 1: Update MD5 hash with IP(v6) pseudo-header. */ 180fcf59617SAndrey V. Elsukov switch (sav->sah->saidx.dst.sa.sa_family) { 181fcf59617SAndrey V. Elsukov #ifdef INET 182fcf59617SAndrey V. Elsukov case AF_INET: 183fcf59617SAndrey V. Elsukov len = ip_pseudo_compute(m, &ctx); 184fcf59617SAndrey V. Elsukov break; 185fcf59617SAndrey V. Elsukov #endif 186fcf59617SAndrey V. Elsukov #ifdef INET6 187fcf59617SAndrey V. Elsukov case AF_INET6: 188fcf59617SAndrey V. Elsukov len = ip6_pseudo_compute(m, &ctx); 189fcf59617SAndrey V. Elsukov break; 190fcf59617SAndrey V. Elsukov #endif 191fcf59617SAndrey V. Elsukov default: 192fcf59617SAndrey V. Elsukov return (EAFNOSUPPORT); 193fcf59617SAndrey V. Elsukov } 194fcf59617SAndrey V. Elsukov /* 195fcf59617SAndrey V. Elsukov * Step 2: Update MD5 hash with TCP header, excluding options. 196fcf59617SAndrey V. Elsukov * The TCP checksum must be set to zero. 197fcf59617SAndrey V. Elsukov */ 198fcf59617SAndrey V. Elsukov csum = th->th_sum; 199fcf59617SAndrey V. Elsukov th->th_sum = 0; 200fcf59617SAndrey V. Elsukov MD5Update(&ctx, (char *)th, sizeof(struct tcphdr)); 201fcf59617SAndrey V. Elsukov th->th_sum = csum; 202fcf59617SAndrey V. Elsukov /* 203fcf59617SAndrey V. Elsukov * Step 3: Update MD5 hash with TCP segment data. 204fcf59617SAndrey V. Elsukov * Use m_apply() to avoid an early m_pullup(). 205fcf59617SAndrey V. Elsukov */ 206fcf59617SAndrey V. Elsukov len += (th->th_off << 2); 207fcf59617SAndrey V. Elsukov if (m->m_pkthdr.len - len > 0) 208fcf59617SAndrey V. Elsukov m_apply(m, len, m->m_pkthdr.len - len, 209fcf59617SAndrey V. Elsukov tcp_signature_apply, &ctx); 210fcf59617SAndrey V. Elsukov /* 211fcf59617SAndrey V. Elsukov * Step 4: Update MD5 hash with shared secret. 212fcf59617SAndrey V. Elsukov */ 213fcf59617SAndrey V. Elsukov MD5Update(&ctx, sav->key_auth->key_data, _KEYLEN(sav->key_auth)); 214fcf59617SAndrey V. Elsukov MD5Final(buf, &ctx); 215fcf59617SAndrey V. Elsukov key_sa_recordxfer(sav, m); 216fcf59617SAndrey V. Elsukov return (0); 217fcf59617SAndrey V. Elsukov } 218fcf59617SAndrey V. Elsukov 219fcf59617SAndrey V. Elsukov static void 220fcf59617SAndrey V. Elsukov setsockaddrs(const struct mbuf *m, union sockaddr_union *src, 221fcf59617SAndrey V. Elsukov union sockaddr_union *dst) 222fcf59617SAndrey V. Elsukov { 223fcf59617SAndrey V. Elsukov struct ip *ip; 224fcf59617SAndrey V. Elsukov 225fcf59617SAndrey V. Elsukov IPSEC_ASSERT(m->m_len >= sizeof(*ip), ("unexpected mbuf len")); 226fcf59617SAndrey V. Elsukov 227fcf59617SAndrey V. Elsukov ip = mtod(m, struct ip *); 228fcf59617SAndrey V. Elsukov switch (ip->ip_v) { 229fcf59617SAndrey V. Elsukov #ifdef INET 230fcf59617SAndrey V. Elsukov case IPVERSION: 231fcf59617SAndrey V. Elsukov ipsec4_setsockaddrs(m, src, dst); 232fcf59617SAndrey V. Elsukov break; 233fcf59617SAndrey V. Elsukov #endif 234fcf59617SAndrey V. Elsukov #ifdef INET6 235fcf59617SAndrey V. Elsukov case (IPV6_VERSION >> 4): 236fcf59617SAndrey V. Elsukov ipsec6_setsockaddrs(m, src, dst); 237fcf59617SAndrey V. Elsukov break; 238fcf59617SAndrey V. Elsukov #endif 239fcf59617SAndrey V. Elsukov default: 240fcf59617SAndrey V. Elsukov bzero(src, sizeof(*src)); 241fcf59617SAndrey V. Elsukov bzero(dst, sizeof(*dst)); 242fcf59617SAndrey V. Elsukov } 243fcf59617SAndrey V. Elsukov } 244fcf59617SAndrey V. Elsukov 245fcf59617SAndrey V. Elsukov /* 246fcf59617SAndrey V. Elsukov * Compute TCP-MD5 hash of an *INBOUND* TCP segment. 247fcf59617SAndrey V. Elsukov * Parameters: 248fcf59617SAndrey V. Elsukov * m pointer to head of mbuf chain 249fcf59617SAndrey V. Elsukov * th pointer to TCP header 250fcf59617SAndrey V. Elsukov * buf pointer to storage for computed MD5 digest 251fcf59617SAndrey V. Elsukov * 252fcf59617SAndrey V. Elsukov * Return 0 if successful, otherwise return -1. 253fcf59617SAndrey V. Elsukov */ 254fcf59617SAndrey V. Elsukov static int 255fcf59617SAndrey V. Elsukov tcp_ipsec_input(struct mbuf *m, struct tcphdr *th, u_char *buf) 256fcf59617SAndrey V. Elsukov { 257fcf59617SAndrey V. Elsukov char tmpdigest[TCP_SIGLEN]; 258fcf59617SAndrey V. Elsukov struct secasindex saidx; 259fcf59617SAndrey V. Elsukov struct secasvar *sav; 260fcf59617SAndrey V. Elsukov 261fcf59617SAndrey V. Elsukov setsockaddrs(m, &saidx.src, &saidx.dst); 262fcf59617SAndrey V. Elsukov saidx.proto = IPPROTO_TCP; 263fcf59617SAndrey V. Elsukov saidx.mode = IPSEC_MODE_TCPMD5; 264fcf59617SAndrey V. Elsukov saidx.reqid = 0; 265fcf59617SAndrey V. Elsukov sav = key_allocsa_tcpmd5(&saidx); 266fcf59617SAndrey V. Elsukov if (sav == NULL) { 267fcf59617SAndrey V. Elsukov KMOD_TCPSTAT_INC(tcps_sig_err_buildsig); 268fcf59617SAndrey V. Elsukov return (EACCES); 269fcf59617SAndrey V. Elsukov } 270fcf59617SAndrey V. Elsukov /* 271fcf59617SAndrey V. Elsukov * tcp_input() operates with TCP header fields in host 272fcf59617SAndrey V. Elsukov * byte order. We expect them in network byte order. 273fcf59617SAndrey V. Elsukov */ 274fcf59617SAndrey V. Elsukov tcp_fields_to_net(th); 275fcf59617SAndrey V. Elsukov tcp_signature_compute(m, th, sav, tmpdigest); 276fcf59617SAndrey V. Elsukov tcp_fields_to_host(th); 277fcf59617SAndrey V. Elsukov key_freesav(&sav); 278fcf59617SAndrey V. Elsukov if (bcmp(buf, tmpdigest, TCP_SIGLEN) != 0) { 279fcf59617SAndrey V. Elsukov KMOD_TCPSTAT_INC(tcps_sig_rcvbadsig); 280fcf59617SAndrey V. Elsukov return (EACCES); 281fcf59617SAndrey V. Elsukov } 282fcf59617SAndrey V. Elsukov KMOD_TCPSTAT_INC(tcps_sig_rcvgoodsig); 283fcf59617SAndrey V. Elsukov return (0); 284fcf59617SAndrey V. Elsukov } 285fcf59617SAndrey V. Elsukov 286fcf59617SAndrey V. Elsukov /* 287fcf59617SAndrey V. Elsukov * Compute TCP-MD5 hash of an *OUTBOUND* TCP segment. 288fcf59617SAndrey V. Elsukov * Parameters: 289fcf59617SAndrey V. Elsukov * m pointer to head of mbuf chain 290fcf59617SAndrey V. Elsukov * th pointer to TCP header 291fcf59617SAndrey V. Elsukov * buf pointer to storage for computed MD5 digest 292fcf59617SAndrey V. Elsukov * 293fcf59617SAndrey V. Elsukov * Return 0 if successful, otherwise return error code. 294fcf59617SAndrey V. Elsukov */ 295fcf59617SAndrey V. Elsukov static int 296fcf59617SAndrey V. Elsukov tcp_ipsec_output(struct mbuf *m, struct tcphdr *th, u_char *buf) 297fcf59617SAndrey V. Elsukov { 298fcf59617SAndrey V. Elsukov struct secasindex saidx; 299fcf59617SAndrey V. Elsukov struct secasvar *sav; 300fcf59617SAndrey V. Elsukov 301fcf59617SAndrey V. Elsukov setsockaddrs(m, &saidx.src, &saidx.dst); 302fcf59617SAndrey V. Elsukov saidx.proto = IPPROTO_TCP; 303fcf59617SAndrey V. Elsukov saidx.mode = IPSEC_MODE_TCPMD5; 304fcf59617SAndrey V. Elsukov saidx.reqid = 0; 305fcf59617SAndrey V. Elsukov sav = key_allocsa_tcpmd5(&saidx); 306fcf59617SAndrey V. Elsukov if (sav == NULL) { 307fcf59617SAndrey V. Elsukov KMOD_TCPSTAT_INC(tcps_sig_err_buildsig); 308fcf59617SAndrey V. Elsukov return (EACCES); 309fcf59617SAndrey V. Elsukov } 310fcf59617SAndrey V. Elsukov tcp_signature_compute(m, th, sav, buf); 311fcf59617SAndrey V. Elsukov key_freesav(&sav); 312fcf59617SAndrey V. Elsukov return (0); 313fcf59617SAndrey V. Elsukov } 314fcf59617SAndrey V. Elsukov 31555d2c71bSBruce M Simpson /* 31655d2c71bSBruce M Simpson * Initialize a TCP-MD5 SA. Called when the SA is being set up. 31755d2c71bSBruce M Simpson * 31855d2c71bSBruce M Simpson * We don't need to set up the tdb prefixed fields, as we don't use the 31955d2c71bSBruce M Simpson * opencrypto code; we just perform a key length check. 32055d2c71bSBruce M Simpson * 321fcf59617SAndrey V. Elsukov * XXX: Currently we have used single 'magic' SPI and need to still 322fcf59617SAndrey V. Elsukov * support this. 32355d2c71bSBruce M Simpson * 32455d2c71bSBruce M Simpson * This allows per-host granularity without affecting the userland 32555d2c71bSBruce M Simpson * interface, which is a simple socket option toggle switch, 32655d2c71bSBruce M Simpson * TCP_SIGNATURE_ENABLE. 32755d2c71bSBruce M Simpson * 32855d2c71bSBruce M Simpson * To allow per-service granularity requires that we have a means 32955d2c71bSBruce M Simpson * of mapping port to SPI. The mandated way of doing this is to 33055d2c71bSBruce M Simpson * use SPD entries to specify packet flows which get the TCP-MD5 33155d2c71bSBruce M Simpson * treatment, however the code to do this is currently unstable 33255d2c71bSBruce M Simpson * and unsuitable for production use. 33355d2c71bSBruce M Simpson * 33455d2c71bSBruce M Simpson * Therefore we use this compromise in the meantime. 33555d2c71bSBruce M Simpson */ 33655d2c71bSBruce M Simpson static int 33755d2c71bSBruce M Simpson tcpsignature_init(struct secasvar *sav, struct xformsw *xsp) 33855d2c71bSBruce M Simpson { 33955d2c71bSBruce M Simpson int keylen; 34055d2c71bSBruce M Simpson 34155d2c71bSBruce M Simpson if (sav->alg_auth != SADB_X_AALG_TCP_MD5) { 34255d2c71bSBruce M Simpson DPRINTF(("%s: unsupported authentication algorithm %u\n", 34355d2c71bSBruce M Simpson __func__, sav->alg_auth)); 34455d2c71bSBruce M Simpson return (EINVAL); 34555d2c71bSBruce M Simpson } 34655d2c71bSBruce M Simpson if (sav->key_auth == NULL) { 34755d2c71bSBruce M Simpson DPRINTF(("%s: no authentication key present\n", __func__)); 34855d2c71bSBruce M Simpson return (EINVAL); 34955d2c71bSBruce M Simpson } 35055d2c71bSBruce M Simpson keylen = _KEYLEN(sav->key_auth); 35155d2c71bSBruce M Simpson if ((keylen < TCP_KEYLEN_MIN) || (keylen > TCP_KEYLEN_MAX)) { 35255d2c71bSBruce M Simpson DPRINTF(("%s: invalid key length %u\n", __func__, keylen)); 35355d2c71bSBruce M Simpson return (EINVAL); 35455d2c71bSBruce M Simpson } 355fcf59617SAndrey V. Elsukov sav->tdb_xform = xsp; 35655d2c71bSBruce M Simpson return (0); 35755d2c71bSBruce M Simpson } 35855d2c71bSBruce M Simpson 35955d2c71bSBruce M Simpson /* 36055d2c71bSBruce M Simpson * Called when the SA is deleted. 36155d2c71bSBruce M Simpson */ 36255d2c71bSBruce M Simpson static int 36355d2c71bSBruce M Simpson tcpsignature_zeroize(struct secasvar *sav) 36455d2c71bSBruce M Simpson { 36555d2c71bSBruce M Simpson 366fcf59617SAndrey V. Elsukov if (sav->key_auth != NULL) 367a0196c3cSGeorge V. Neville-Neil bzero(sav->key_auth->key_data, _KEYLEN(sav->key_auth)); 36855d2c71bSBruce M Simpson sav->tdb_xform = NULL; 36955d2c71bSBruce M Simpson return (0); 37055d2c71bSBruce M Simpson } 37155d2c71bSBruce M Simpson 37255d2c71bSBruce M Simpson static struct xformsw tcpsignature_xformsw = { 373fcf59617SAndrey V. Elsukov .xf_type = XF_TCPSIGNATURE, 374fcf59617SAndrey V. Elsukov .xf_name = "TCP-MD5", 375fcf59617SAndrey V. Elsukov .xf_init = tcpsignature_init, 376fcf59617SAndrey V. Elsukov .xf_zeroize = tcpsignature_zeroize, 37755d2c71bSBruce M Simpson }; 37855d2c71bSBruce M Simpson 379fcf59617SAndrey V. Elsukov static const struct tcpmd5_methods tcpmd5_methods = { 380fcf59617SAndrey V. Elsukov .input = tcp_ipsec_input, 381fcf59617SAndrey V. Elsukov .output = tcp_ipsec_output, 382fcf59617SAndrey V. Elsukov .pcbctl = tcp_ipsec_pcbctl, 383fcf59617SAndrey V. Elsukov }; 384fcf59617SAndrey V. Elsukov 385fcf59617SAndrey V. Elsukov #ifndef KLD_MODULE 386fcf59617SAndrey V. Elsukov /* TCP-MD5 support is build in the kernel */ 387fcf59617SAndrey V. Elsukov static const struct tcpmd5_support tcpmd5_ipsec = { 388fcf59617SAndrey V. Elsukov .enabled = IPSEC_MODULE_ENABLED, 389fcf59617SAndrey V. Elsukov .methods = &tcpmd5_methods 390fcf59617SAndrey V. Elsukov }; 391fcf59617SAndrey V. Elsukov const struct tcpmd5_support * const tcp_ipsec_support = &tcpmd5_ipsec; 392fcf59617SAndrey V. Elsukov #endif /* !KLD_MODULE */ 393fcf59617SAndrey V. Elsukov 394fcf59617SAndrey V. Elsukov static int 395fcf59617SAndrey V. Elsukov tcpmd5_modevent(module_t mod, int type, void *data) 39655d2c71bSBruce M Simpson { 39755d2c71bSBruce M Simpson 398fcf59617SAndrey V. Elsukov switch (type) { 399fcf59617SAndrey V. Elsukov case MOD_LOAD: 400fcf59617SAndrey V. Elsukov xform_attach(&tcpsignature_xformsw); 401fcf59617SAndrey V. Elsukov #ifdef KLD_MODULE 402fcf59617SAndrey V. Elsukov tcpmd5_support_enable(&tcpmd5_methods); 403fcf59617SAndrey V. Elsukov #endif 404fcf59617SAndrey V. Elsukov break; 405fcf59617SAndrey V. Elsukov case MOD_UNLOAD: 406fcf59617SAndrey V. Elsukov #ifdef KLD_MODULE 407fcf59617SAndrey V. Elsukov tcpmd5_support_disable(); 408fcf59617SAndrey V. Elsukov #endif 409fcf59617SAndrey V. Elsukov xform_detach(&tcpsignature_xformsw); 410fcf59617SAndrey V. Elsukov break; 411fcf59617SAndrey V. Elsukov default: 412fcf59617SAndrey V. Elsukov return (EOPNOTSUPP); 413fcf59617SAndrey V. Elsukov } 414fcf59617SAndrey V. Elsukov return (0); 41555d2c71bSBruce M Simpson } 41655d2c71bSBruce M Simpson 417fcf59617SAndrey V. Elsukov static moduledata_t tcpmd5_mod = { 418fcf59617SAndrey V. Elsukov "tcpmd5", 419fcf59617SAndrey V. Elsukov tcpmd5_modevent, 420fcf59617SAndrey V. Elsukov 0 421fcf59617SAndrey V. Elsukov }; 422fcf59617SAndrey V. Elsukov 423fcf59617SAndrey V. Elsukov DECLARE_MODULE(tcpmd5, tcpmd5_mod, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY); 424fcf59617SAndrey V. Elsukov MODULE_VERSION(tcpmd5, 1); 425fcf59617SAndrey V. Elsukov #ifdef KLD_MODULE 426fcf59617SAndrey V. Elsukov MODULE_DEPEND(tcpmd5, ipsec_support, 1, 1, 1); 427fcf59617SAndrey V. Elsukov #endif 428