1c398230bSWarner Losh /*- 2fe267a55SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 3fe267a55SPedro 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> 58*0fb0711dSMichael Tuexen #include <netinet/udp.h> 5955d2c71bSBruce M Simpson 60eddfbb76SRobert Watson #include <net/vnet.h> 61eddfbb76SRobert Watson 6255d2c71bSBruce M Simpson #include <netipsec/ipsec.h> 63fcf59617SAndrey V. Elsukov #include <netipsec/ipsec_support.h> 6455d2c71bSBruce M Simpson #include <netipsec/xform.h> 6555d2c71bSBruce M Simpson 6655d2c71bSBruce M Simpson #ifdef INET6 6755d2c71bSBruce M Simpson #include <netinet/ip6.h> 6855d2c71bSBruce M Simpson #include <netipsec/ipsec6.h> 6955d2c71bSBruce M Simpson #endif 7055d2c71bSBruce M Simpson 7155d2c71bSBruce M Simpson #include <netipsec/key.h> 7255d2c71bSBruce M Simpson #include <netipsec/key_debug.h> 7355d2c71bSBruce M Simpson 74fcf59617SAndrey V. Elsukov #define TCP_SIGLEN 16 /* length of computed digest in bytes */ 75fcf59617SAndrey V. Elsukov #define TCP_KEYLEN_MIN 1 /* minimum length of TCP-MD5 key */ 76fcf59617SAndrey V. Elsukov #define TCP_KEYLEN_MAX 80 /* maximum length of TCP-MD5 key */ 77fcf59617SAndrey V. Elsukov 78fcf59617SAndrey V. Elsukov static int 79fcf59617SAndrey V. Elsukov tcp_ipsec_pcbctl(struct inpcb *inp, struct sockopt *sopt) 80fcf59617SAndrey V. Elsukov { 81fcf59617SAndrey V. Elsukov struct tcpcb *tp; 82fcf59617SAndrey V. Elsukov int error, optval; 83fcf59617SAndrey V. Elsukov 84fcf59617SAndrey V. Elsukov if (sopt->sopt_name != TCP_MD5SIG) { 85fcf59617SAndrey V. Elsukov return (ENOPROTOOPT); 86fcf59617SAndrey V. Elsukov } 87fcf59617SAndrey V. Elsukov 88fcf59617SAndrey V. Elsukov if (sopt->sopt_dir == SOPT_GET) { 89968ac175SSean Bruno INP_RLOCK(inp); 9053af6903SGleb Smirnoff if (inp->inp_flags & INP_DROPPED) { 91968ac175SSean Bruno INP_RUNLOCK(inp); 92968ac175SSean Bruno return (ECONNRESET); 93968ac175SSean Bruno } 94968ac175SSean Bruno tp = intotcpcb(inp); 95fcf59617SAndrey V. Elsukov optval = (tp->t_flags & TF_SIGNATURE) ? 1 : 0; 96968ac175SSean Bruno INP_RUNLOCK(inp); 97fcf59617SAndrey V. Elsukov 98fcf59617SAndrey V. Elsukov /* On success return with released INP_WLOCK */ 99fcf59617SAndrey V. Elsukov return (sooptcopyout(sopt, &optval, sizeof(optval))); 100fcf59617SAndrey V. Elsukov } 101fcf59617SAndrey V. Elsukov 102fcf59617SAndrey V. Elsukov error = sooptcopyin(sopt, &optval, sizeof(optval), sizeof(optval)); 103fcf59617SAndrey V. Elsukov if (error != 0) 104fcf59617SAndrey V. Elsukov return (error); 105fcf59617SAndrey V. Elsukov 106fcf59617SAndrey V. Elsukov /* INP_WLOCK_RECHECK */ 107fcf59617SAndrey V. Elsukov INP_WLOCK(inp); 10853af6903SGleb Smirnoff if (inp->inp_flags & INP_DROPPED) { 109fcf59617SAndrey V. Elsukov INP_WUNLOCK(inp); 110fcf59617SAndrey V. Elsukov return (ECONNRESET); 111fcf59617SAndrey V. Elsukov } 112968ac175SSean Bruno tp = intotcpcb(inp); 113fcf59617SAndrey V. Elsukov if (optval > 0) 114fcf59617SAndrey V. Elsukov tp->t_flags |= TF_SIGNATURE; 115fcf59617SAndrey V. Elsukov else 116fcf59617SAndrey V. Elsukov tp->t_flags &= ~TF_SIGNATURE; 117fcf59617SAndrey V. Elsukov 118968ac175SSean Bruno INP_WUNLOCK(inp); 119fcf59617SAndrey V. Elsukov return (error); 120fcf59617SAndrey V. Elsukov } 121fcf59617SAndrey V. Elsukov 122fcf59617SAndrey V. Elsukov /* 123fcf59617SAndrey V. Elsukov * Callback function invoked by m_apply() to digest TCP segment data 124fcf59617SAndrey V. Elsukov * contained within an mbuf chain. 125fcf59617SAndrey V. Elsukov */ 126fcf59617SAndrey V. Elsukov static int 127fcf59617SAndrey V. Elsukov tcp_signature_apply(void *fstate, void *data, u_int len) 128fcf59617SAndrey V. Elsukov { 129fcf59617SAndrey V. Elsukov 130fcf59617SAndrey V. Elsukov MD5Update(fstate, (u_char *)data, len); 131fcf59617SAndrey V. Elsukov return (0); 132fcf59617SAndrey V. Elsukov } 133fcf59617SAndrey V. Elsukov 134fcf59617SAndrey V. Elsukov #ifdef INET 135fcf59617SAndrey V. Elsukov static int 136fcf59617SAndrey V. Elsukov ip_pseudo_compute(struct mbuf *m, MD5_CTX *ctx) 137fcf59617SAndrey V. Elsukov { 138fcf59617SAndrey V. Elsukov struct ippseudo ipp; 139fcf59617SAndrey V. Elsukov struct ip *ip; 140*0fb0711dSMichael Tuexen int hdr_len; 141fcf59617SAndrey V. Elsukov 142fcf59617SAndrey V. Elsukov ip = mtod(m, struct ip *); 143fcf59617SAndrey V. Elsukov ipp.ippseudo_src.s_addr = ip->ip_src.s_addr; 144fcf59617SAndrey V. Elsukov ipp.ippseudo_dst.s_addr = ip->ip_dst.s_addr; 145fcf59617SAndrey V. Elsukov ipp.ippseudo_p = IPPROTO_TCP; 146fcf59617SAndrey V. Elsukov ipp.ippseudo_pad = 0; 147*0fb0711dSMichael Tuexen hdr_len = ip->ip_hl << 2; 148*0fb0711dSMichael Tuexen if (ip->ip_p == IPPROTO_UDP) 149*0fb0711dSMichael Tuexen /* TCP over UDP */ 150*0fb0711dSMichael Tuexen hdr_len += sizeof(struct udphdr); 151*0fb0711dSMichael Tuexen ipp.ippseudo_len = htons(m->m_pkthdr.len - hdr_len); 152fcf59617SAndrey V. Elsukov MD5Update(ctx, (char *)&ipp, sizeof(ipp)); 153*0fb0711dSMichael Tuexen return (hdr_len); 154fcf59617SAndrey V. Elsukov } 155fcf59617SAndrey V. Elsukov #endif 156fcf59617SAndrey V. Elsukov 157fcf59617SAndrey V. Elsukov #ifdef INET6 158fcf59617SAndrey V. Elsukov static int 159fcf59617SAndrey V. Elsukov ip6_pseudo_compute(struct mbuf *m, MD5_CTX *ctx) 160fcf59617SAndrey V. Elsukov { 161fcf59617SAndrey V. Elsukov struct ip6_pseudo { 162fcf59617SAndrey V. Elsukov struct in6_addr src, dst; 163fcf59617SAndrey V. Elsukov uint32_t len; 164fcf59617SAndrey V. Elsukov uint32_t nxt; 165fcf59617SAndrey V. Elsukov } ip6p __aligned(4); 166fcf59617SAndrey V. Elsukov struct ip6_hdr *ip6; 167*0fb0711dSMichael Tuexen int hdr_len; 168fcf59617SAndrey V. Elsukov 169fcf59617SAndrey V. Elsukov ip6 = mtod(m, struct ip6_hdr *); 170fcf59617SAndrey V. Elsukov ip6p.src = ip6->ip6_src; 171fcf59617SAndrey V. Elsukov ip6p.dst = ip6->ip6_dst; 172*0fb0711dSMichael Tuexen hdr_len = sizeof(struct ip6_hdr); 173*0fb0711dSMichael Tuexen if (ip6->ip6_nxt == IPPROTO_UDP) 174*0fb0711dSMichael Tuexen /* TCP over UDP */ 175*0fb0711dSMichael Tuexen hdr_len += sizeof(struct udphdr); 176*0fb0711dSMichael Tuexen /* XXX: ext headers */ 177*0fb0711dSMichael Tuexen ip6p.len = htonl(m->m_pkthdr.len - hdr_len); 178fcf59617SAndrey V. Elsukov ip6p.nxt = htonl(IPPROTO_TCP); 179fcf59617SAndrey V. Elsukov MD5Update(ctx, (char *)&ip6p, sizeof(ip6p)); 180*0fb0711dSMichael Tuexen return (hdr_len); 181fcf59617SAndrey V. Elsukov } 182fcf59617SAndrey V. Elsukov #endif 183fcf59617SAndrey V. Elsukov 184fcf59617SAndrey V. Elsukov static int 185fcf59617SAndrey V. Elsukov tcp_signature_compute(struct mbuf *m, struct tcphdr *th, 186fcf59617SAndrey V. Elsukov struct secasvar *sav, u_char *buf) 187fcf59617SAndrey V. Elsukov { 188fcf59617SAndrey V. Elsukov MD5_CTX ctx; 189fcf59617SAndrey V. Elsukov int len; 190fcf59617SAndrey V. Elsukov u_short csum; 191fcf59617SAndrey V. Elsukov 192fcf59617SAndrey V. Elsukov MD5Init(&ctx); 193fcf59617SAndrey V. Elsukov /* Step 1: Update MD5 hash with IP(v6) pseudo-header. */ 194fcf59617SAndrey V. Elsukov switch (sav->sah->saidx.dst.sa.sa_family) { 195fcf59617SAndrey V. Elsukov #ifdef INET 196fcf59617SAndrey V. Elsukov case AF_INET: 197fcf59617SAndrey V. Elsukov len = ip_pseudo_compute(m, &ctx); 198fcf59617SAndrey V. Elsukov break; 199fcf59617SAndrey V. Elsukov #endif 200fcf59617SAndrey V. Elsukov #ifdef INET6 201fcf59617SAndrey V. Elsukov case AF_INET6: 202fcf59617SAndrey V. Elsukov len = ip6_pseudo_compute(m, &ctx); 203fcf59617SAndrey V. Elsukov break; 204fcf59617SAndrey V. Elsukov #endif 205fcf59617SAndrey V. Elsukov default: 206fcf59617SAndrey V. Elsukov return (EAFNOSUPPORT); 207fcf59617SAndrey V. Elsukov } 208fcf59617SAndrey V. Elsukov /* 209fcf59617SAndrey V. Elsukov * Step 2: Update MD5 hash with TCP header, excluding options. 210fcf59617SAndrey V. Elsukov * The TCP checksum must be set to zero. 211fcf59617SAndrey V. Elsukov */ 212fcf59617SAndrey V. Elsukov csum = th->th_sum; 213fcf59617SAndrey V. Elsukov th->th_sum = 0; 214fcf59617SAndrey V. Elsukov MD5Update(&ctx, (char *)th, sizeof(struct tcphdr)); 215fcf59617SAndrey V. Elsukov th->th_sum = csum; 216fcf59617SAndrey V. Elsukov /* 217fcf59617SAndrey V. Elsukov * Step 3: Update MD5 hash with TCP segment data. 218fcf59617SAndrey V. Elsukov * Use m_apply() to avoid an early m_pullup(). 219fcf59617SAndrey V. Elsukov */ 220fcf59617SAndrey V. Elsukov len += (th->th_off << 2); 221fcf59617SAndrey V. Elsukov if (m->m_pkthdr.len - len > 0) 222fcf59617SAndrey V. Elsukov m_apply(m, len, m->m_pkthdr.len - len, 223fcf59617SAndrey V. Elsukov tcp_signature_apply, &ctx); 224fcf59617SAndrey V. Elsukov /* 225fcf59617SAndrey V. Elsukov * Step 4: Update MD5 hash with shared secret. 226fcf59617SAndrey V. Elsukov */ 227fcf59617SAndrey V. Elsukov MD5Update(&ctx, sav->key_auth->key_data, _KEYLEN(sav->key_auth)); 228fcf59617SAndrey V. Elsukov MD5Final(buf, &ctx); 229fcf59617SAndrey V. Elsukov key_sa_recordxfer(sav, m); 230fcf59617SAndrey V. Elsukov return (0); 231fcf59617SAndrey V. Elsukov } 232fcf59617SAndrey V. Elsukov 233fcf59617SAndrey V. Elsukov static void 234fcf59617SAndrey V. Elsukov setsockaddrs(const struct mbuf *m, union sockaddr_union *src, 235fcf59617SAndrey V. Elsukov union sockaddr_union *dst) 236fcf59617SAndrey V. Elsukov { 237fcf59617SAndrey V. Elsukov struct ip *ip; 238fcf59617SAndrey V. Elsukov 239fcf59617SAndrey V. Elsukov IPSEC_ASSERT(m->m_len >= sizeof(*ip), ("unexpected mbuf len")); 240fcf59617SAndrey V. Elsukov 241fcf59617SAndrey V. Elsukov ip = mtod(m, struct ip *); 242fcf59617SAndrey V. Elsukov switch (ip->ip_v) { 243fcf59617SAndrey V. Elsukov #ifdef INET 244fcf59617SAndrey V. Elsukov case IPVERSION: 245fcf59617SAndrey V. Elsukov ipsec4_setsockaddrs(m, src, dst); 246fcf59617SAndrey V. Elsukov break; 247fcf59617SAndrey V. Elsukov #endif 248fcf59617SAndrey V. Elsukov #ifdef INET6 249fcf59617SAndrey V. Elsukov case (IPV6_VERSION >> 4): 250fcf59617SAndrey V. Elsukov ipsec6_setsockaddrs(m, src, dst); 251fcf59617SAndrey V. Elsukov break; 252fcf59617SAndrey V. Elsukov #endif 253fcf59617SAndrey V. Elsukov default: 254fcf59617SAndrey V. Elsukov bzero(src, sizeof(*src)); 255fcf59617SAndrey V. Elsukov bzero(dst, sizeof(*dst)); 256fcf59617SAndrey V. Elsukov } 257fcf59617SAndrey V. Elsukov } 258fcf59617SAndrey V. Elsukov 259fcf59617SAndrey V. Elsukov /* 260fcf59617SAndrey V. Elsukov * Compute TCP-MD5 hash of an *INBOUND* TCP segment. 261fcf59617SAndrey V. Elsukov * Parameters: 262fcf59617SAndrey V. Elsukov * m pointer to head of mbuf chain 263fcf59617SAndrey V. Elsukov * th pointer to TCP header 264fcf59617SAndrey V. Elsukov * buf pointer to storage for computed MD5 digest 265fcf59617SAndrey V. Elsukov * 26691d38811SRobert Wing * Return 0 if successful, otherwise return error code. 267fcf59617SAndrey V. Elsukov */ 268fcf59617SAndrey V. Elsukov static int 269fcf59617SAndrey V. Elsukov tcp_ipsec_input(struct mbuf *m, struct tcphdr *th, u_char *buf) 270fcf59617SAndrey V. Elsukov { 271fcf59617SAndrey V. Elsukov char tmpdigest[TCP_SIGLEN]; 272fcf59617SAndrey V. Elsukov struct secasindex saidx; 273fcf59617SAndrey V. Elsukov struct secasvar *sav; 274fcf59617SAndrey V. Elsukov 275fcf59617SAndrey V. Elsukov setsockaddrs(m, &saidx.src, &saidx.dst); 276fcf59617SAndrey V. Elsukov saidx.proto = IPPROTO_TCP; 277fcf59617SAndrey V. Elsukov saidx.mode = IPSEC_MODE_TCPMD5; 278fcf59617SAndrey V. Elsukov saidx.reqid = 0; 279fcf59617SAndrey V. Elsukov sav = key_allocsa_tcpmd5(&saidx); 280fcf59617SAndrey V. Elsukov if (sav == NULL) { 281fcf59617SAndrey V. Elsukov KMOD_TCPSTAT_INC(tcps_sig_err_buildsig); 28291d38811SRobert Wing return (ENOENT); 283fcf59617SAndrey V. Elsukov } 284eb18708eSRobert Wing if (buf == NULL) { 285eb18708eSRobert Wing key_freesav(&sav); 286eb18708eSRobert Wing KMOD_TCPSTAT_INC(tcps_sig_err_nosigopt); 287eb18708eSRobert Wing return (EACCES); 288eb18708eSRobert Wing } 289fcf59617SAndrey V. Elsukov /* 290fcf59617SAndrey V. Elsukov * tcp_input() operates with TCP header fields in host 291fcf59617SAndrey V. Elsukov * byte order. We expect them in network byte order. 292fcf59617SAndrey V. Elsukov */ 293fcf59617SAndrey V. Elsukov tcp_fields_to_net(th); 294fcf59617SAndrey V. Elsukov tcp_signature_compute(m, th, sav, tmpdigest); 295fcf59617SAndrey V. Elsukov tcp_fields_to_host(th); 296fcf59617SAndrey V. Elsukov key_freesav(&sav); 297fcf59617SAndrey V. Elsukov if (bcmp(buf, tmpdigest, TCP_SIGLEN) != 0) { 298fcf59617SAndrey V. Elsukov KMOD_TCPSTAT_INC(tcps_sig_rcvbadsig); 299fcf59617SAndrey V. Elsukov return (EACCES); 300fcf59617SAndrey V. Elsukov } 301fcf59617SAndrey V. Elsukov KMOD_TCPSTAT_INC(tcps_sig_rcvgoodsig); 302fcf59617SAndrey V. Elsukov return (0); 303fcf59617SAndrey V. Elsukov } 304fcf59617SAndrey V. Elsukov 305fcf59617SAndrey V. Elsukov /* 306fcf59617SAndrey V. Elsukov * Compute TCP-MD5 hash of an *OUTBOUND* TCP segment. 307fcf59617SAndrey V. Elsukov * Parameters: 308fcf59617SAndrey V. Elsukov * m pointer to head of mbuf chain 309fcf59617SAndrey V. Elsukov * th pointer to TCP header 310fcf59617SAndrey V. Elsukov * buf pointer to storage for computed MD5 digest 311fcf59617SAndrey V. Elsukov * 312fcf59617SAndrey V. Elsukov * Return 0 if successful, otherwise return error code. 313fcf59617SAndrey V. Elsukov */ 314fcf59617SAndrey V. Elsukov static int 315fcf59617SAndrey V. Elsukov tcp_ipsec_output(struct mbuf *m, struct tcphdr *th, u_char *buf) 316fcf59617SAndrey V. Elsukov { 317fcf59617SAndrey V. Elsukov struct secasindex saidx; 318fcf59617SAndrey V. Elsukov struct secasvar *sav; 319fcf59617SAndrey V. Elsukov 320fcf59617SAndrey V. Elsukov setsockaddrs(m, &saidx.src, &saidx.dst); 321fcf59617SAndrey V. Elsukov saidx.proto = IPPROTO_TCP; 322fcf59617SAndrey V. Elsukov saidx.mode = IPSEC_MODE_TCPMD5; 323fcf59617SAndrey V. Elsukov saidx.reqid = 0; 324fcf59617SAndrey V. Elsukov sav = key_allocsa_tcpmd5(&saidx); 325fcf59617SAndrey V. Elsukov if (sav == NULL) { 326fcf59617SAndrey V. Elsukov KMOD_TCPSTAT_INC(tcps_sig_err_buildsig); 32791d38811SRobert Wing return (ENOENT); 328fcf59617SAndrey V. Elsukov } 329fcf59617SAndrey V. Elsukov tcp_signature_compute(m, th, sav, buf); 330fcf59617SAndrey V. Elsukov key_freesav(&sav); 331fcf59617SAndrey V. Elsukov return (0); 332fcf59617SAndrey V. Elsukov } 333fcf59617SAndrey V. Elsukov 33455d2c71bSBruce M Simpson /* 33555d2c71bSBruce M Simpson * Initialize a TCP-MD5 SA. Called when the SA is being set up. 33655d2c71bSBruce M Simpson * 33755d2c71bSBruce M Simpson * We don't need to set up the tdb prefixed fields, as we don't use the 33855d2c71bSBruce M Simpson * opencrypto code; we just perform a key length check. 33955d2c71bSBruce M Simpson * 340fcf59617SAndrey V. Elsukov * XXX: Currently we have used single 'magic' SPI and need to still 341fcf59617SAndrey V. Elsukov * support this. 34255d2c71bSBruce M Simpson * 34355d2c71bSBruce M Simpson * This allows per-host granularity without affecting the userland 34455d2c71bSBruce M Simpson * interface, which is a simple socket option toggle switch, 34555d2c71bSBruce M Simpson * TCP_SIGNATURE_ENABLE. 34655d2c71bSBruce M Simpson * 34755d2c71bSBruce M Simpson * To allow per-service granularity requires that we have a means 34855d2c71bSBruce M Simpson * of mapping port to SPI. The mandated way of doing this is to 34955d2c71bSBruce M Simpson * use SPD entries to specify packet flows which get the TCP-MD5 35055d2c71bSBruce M Simpson * treatment, however the code to do this is currently unstable 35155d2c71bSBruce M Simpson * and unsuitable for production use. 35255d2c71bSBruce M Simpson * 35355d2c71bSBruce M Simpson * Therefore we use this compromise in the meantime. 35455d2c71bSBruce M Simpson */ 35555d2c71bSBruce M Simpson static int 35655d2c71bSBruce M Simpson tcpsignature_init(struct secasvar *sav, struct xformsw *xsp) 35755d2c71bSBruce M Simpson { 35855d2c71bSBruce M Simpson int keylen; 35955d2c71bSBruce M Simpson 36055d2c71bSBruce M Simpson if (sav->alg_auth != SADB_X_AALG_TCP_MD5) { 36155d2c71bSBruce M Simpson DPRINTF(("%s: unsupported authentication algorithm %u\n", 36255d2c71bSBruce M Simpson __func__, sav->alg_auth)); 36355d2c71bSBruce M Simpson return (EINVAL); 36455d2c71bSBruce M Simpson } 36555d2c71bSBruce M Simpson if (sav->key_auth == NULL) { 36655d2c71bSBruce M Simpson DPRINTF(("%s: no authentication key present\n", __func__)); 36755d2c71bSBruce M Simpson return (EINVAL); 36855d2c71bSBruce M Simpson } 36955d2c71bSBruce M Simpson keylen = _KEYLEN(sav->key_auth); 37055d2c71bSBruce M Simpson if ((keylen < TCP_KEYLEN_MIN) || (keylen > TCP_KEYLEN_MAX)) { 37155d2c71bSBruce M Simpson DPRINTF(("%s: invalid key length %u\n", __func__, keylen)); 37255d2c71bSBruce M Simpson return (EINVAL); 37355d2c71bSBruce M Simpson } 374fcf59617SAndrey V. Elsukov sav->tdb_xform = xsp; 37555d2c71bSBruce M Simpson return (0); 37655d2c71bSBruce M Simpson } 37755d2c71bSBruce M Simpson 37855d2c71bSBruce M Simpson /* 37955d2c71bSBruce M Simpson * Called when the SA is deleted. 38055d2c71bSBruce M Simpson */ 381dae61c9dSJohn Baldwin static void 382dae61c9dSJohn Baldwin tcpsignature_cleanup(struct secasvar *sav) 38355d2c71bSBruce M Simpson { 38455d2c71bSBruce M Simpson } 38555d2c71bSBruce M Simpson 38655d2c71bSBruce M Simpson static struct xformsw tcpsignature_xformsw = { 387fcf59617SAndrey V. Elsukov .xf_type = XF_TCPSIGNATURE, 388fcf59617SAndrey V. Elsukov .xf_name = "TCP-MD5", 389fcf59617SAndrey V. Elsukov .xf_init = tcpsignature_init, 390dae61c9dSJohn Baldwin .xf_cleanup = tcpsignature_cleanup, 39155d2c71bSBruce M Simpson }; 39255d2c71bSBruce M Simpson 393fcf59617SAndrey V. Elsukov static const struct tcpmd5_methods tcpmd5_methods = { 394fcf59617SAndrey V. Elsukov .input = tcp_ipsec_input, 395fcf59617SAndrey V. Elsukov .output = tcp_ipsec_output, 396fcf59617SAndrey V. Elsukov .pcbctl = tcp_ipsec_pcbctl, 397fcf59617SAndrey V. Elsukov }; 398fcf59617SAndrey V. Elsukov 399fcf59617SAndrey V. Elsukov #ifndef KLD_MODULE 400fcf59617SAndrey V. Elsukov /* TCP-MD5 support is build in the kernel */ 401fcf59617SAndrey V. Elsukov static const struct tcpmd5_support tcpmd5_ipsec = { 402fcf59617SAndrey V. Elsukov .enabled = IPSEC_MODULE_ENABLED, 403fcf59617SAndrey V. Elsukov .methods = &tcpmd5_methods 404fcf59617SAndrey V. Elsukov }; 405fcf59617SAndrey V. Elsukov const struct tcpmd5_support * const tcp_ipsec_support = &tcpmd5_ipsec; 406fcf59617SAndrey V. Elsukov #endif /* !KLD_MODULE */ 407fcf59617SAndrey V. Elsukov 408fcf59617SAndrey V. Elsukov static int 409fcf59617SAndrey V. Elsukov tcpmd5_modevent(module_t mod, int type, void *data) 41055d2c71bSBruce M Simpson { 41155d2c71bSBruce M Simpson 412fcf59617SAndrey V. Elsukov switch (type) { 413fcf59617SAndrey V. Elsukov case MOD_LOAD: 414fcf59617SAndrey V. Elsukov xform_attach(&tcpsignature_xformsw); 415fcf59617SAndrey V. Elsukov #ifdef KLD_MODULE 416fcf59617SAndrey V. Elsukov tcpmd5_support_enable(&tcpmd5_methods); 417fcf59617SAndrey V. Elsukov #endif 418fcf59617SAndrey V. Elsukov break; 419fcf59617SAndrey V. Elsukov case MOD_UNLOAD: 420fcf59617SAndrey V. Elsukov #ifdef KLD_MODULE 421fcf59617SAndrey V. Elsukov tcpmd5_support_disable(); 422fcf59617SAndrey V. Elsukov #endif 423fcf59617SAndrey V. Elsukov xform_detach(&tcpsignature_xformsw); 424fcf59617SAndrey V. Elsukov break; 425fcf59617SAndrey V. Elsukov default: 426fcf59617SAndrey V. Elsukov return (EOPNOTSUPP); 427fcf59617SAndrey V. Elsukov } 428fcf59617SAndrey V. Elsukov return (0); 42955d2c71bSBruce M Simpson } 43055d2c71bSBruce M Simpson 431fcf59617SAndrey V. Elsukov static moduledata_t tcpmd5_mod = { 432fcf59617SAndrey V. Elsukov "tcpmd5", 433fcf59617SAndrey V. Elsukov tcpmd5_modevent, 434fcf59617SAndrey V. Elsukov 0 435fcf59617SAndrey V. Elsukov }; 436fcf59617SAndrey V. Elsukov 437fcf59617SAndrey V. Elsukov DECLARE_MODULE(tcpmd5, tcpmd5_mod, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY); 438fcf59617SAndrey V. Elsukov MODULE_VERSION(tcpmd5, 1); 439fcf59617SAndrey V. Elsukov #ifdef KLD_MODULE 440fcf59617SAndrey V. Elsukov MODULE_DEPEND(tcpmd5, ipsec_support, 1, 1, 1); 441fcf59617SAndrey V. Elsukov #endif 442