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