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