xref: /freebsd/sys/netipsec/xform_tcp.c (revision dae61c9d09a79fc93c9486c212a586512339e6a0)
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>
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 	if (sopt->sopt_name != TCP_MD5SIG) {
84fcf59617SAndrey V. Elsukov 		return (ENOPROTOOPT);
85fcf59617SAndrey V. Elsukov 	}
86fcf59617SAndrey V. Elsukov 
87fcf59617SAndrey V. Elsukov 	if (sopt->sopt_dir == SOPT_GET) {
88968ac175SSean Bruno 		INP_RLOCK(inp);
89968ac175SSean Bruno 		if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) {
90968ac175SSean Bruno 			INP_RUNLOCK(inp);
91968ac175SSean Bruno 			return (ECONNRESET);
92968ac175SSean Bruno 		}
93968ac175SSean Bruno 		tp = intotcpcb(inp);
94fcf59617SAndrey V. Elsukov 		optval = (tp->t_flags & TF_SIGNATURE) ? 1 : 0;
95968ac175SSean Bruno 		INP_RUNLOCK(inp);
96fcf59617SAndrey V. Elsukov 
97fcf59617SAndrey V. Elsukov 		/* On success return with released INP_WLOCK */
98fcf59617SAndrey V. Elsukov 		return (sooptcopyout(sopt, &optval, sizeof(optval)));
99fcf59617SAndrey V. Elsukov 	}
100fcf59617SAndrey V. Elsukov 
101fcf59617SAndrey V. Elsukov 	error = sooptcopyin(sopt, &optval, sizeof(optval), sizeof(optval));
102fcf59617SAndrey V. Elsukov 	if (error != 0)
103fcf59617SAndrey V. Elsukov 		return (error);
104fcf59617SAndrey V. Elsukov 
105fcf59617SAndrey V. Elsukov 	/* INP_WLOCK_RECHECK */
106fcf59617SAndrey V. Elsukov 	INP_WLOCK(inp);
107fcf59617SAndrey V. Elsukov 	if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) {
108fcf59617SAndrey V. Elsukov 		INP_WUNLOCK(inp);
109fcf59617SAndrey V. Elsukov 		return (ECONNRESET);
110fcf59617SAndrey V. Elsukov 	}
111968ac175SSean Bruno 	tp = intotcpcb(inp);
112fcf59617SAndrey V. Elsukov 	if (optval > 0)
113fcf59617SAndrey V. Elsukov 		tp->t_flags |= TF_SIGNATURE;
114fcf59617SAndrey V. Elsukov 	else
115fcf59617SAndrey V. Elsukov 		tp->t_flags &= ~TF_SIGNATURE;
116fcf59617SAndrey V. Elsukov 
117968ac175SSean Bruno 	INP_WUNLOCK(inp);
118fcf59617SAndrey V. Elsukov 	return (error);
119fcf59617SAndrey V. Elsukov }
120fcf59617SAndrey V. Elsukov 
121fcf59617SAndrey V. Elsukov /*
122fcf59617SAndrey V. Elsukov  * Callback function invoked by m_apply() to digest TCP segment data
123fcf59617SAndrey V. Elsukov  * contained within an mbuf chain.
124fcf59617SAndrey V. Elsukov  */
125fcf59617SAndrey V. Elsukov static int
126fcf59617SAndrey V. Elsukov tcp_signature_apply(void *fstate, void *data, u_int len)
127fcf59617SAndrey V. Elsukov {
128fcf59617SAndrey V. Elsukov 
129fcf59617SAndrey V. Elsukov 	MD5Update(fstate, (u_char *)data, len);
130fcf59617SAndrey V. Elsukov 	return (0);
131fcf59617SAndrey V. Elsukov }
132fcf59617SAndrey V. Elsukov 
133fcf59617SAndrey V. Elsukov #ifdef INET
134fcf59617SAndrey V. Elsukov static int
135fcf59617SAndrey V. Elsukov ip_pseudo_compute(struct mbuf *m, MD5_CTX *ctx)
136fcf59617SAndrey V. Elsukov {
137fcf59617SAndrey V. Elsukov 	struct ippseudo ipp;
138fcf59617SAndrey V. Elsukov 	struct ip *ip;
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;
145fcf59617SAndrey V. Elsukov 	ipp.ippseudo_len = htons(m->m_pkthdr.len - (ip->ip_hl << 2));
146fcf59617SAndrey V. Elsukov 	MD5Update(ctx, (char *)&ipp, sizeof(ipp));
147fcf59617SAndrey V. Elsukov 	return (ip->ip_hl << 2);
148fcf59617SAndrey V. Elsukov }
149fcf59617SAndrey V. Elsukov #endif
150fcf59617SAndrey V. Elsukov 
151fcf59617SAndrey V. Elsukov #ifdef INET6
152fcf59617SAndrey V. Elsukov static int
153fcf59617SAndrey V. Elsukov ip6_pseudo_compute(struct mbuf *m, MD5_CTX *ctx)
154fcf59617SAndrey V. Elsukov {
155fcf59617SAndrey V. Elsukov 	struct ip6_pseudo {
156fcf59617SAndrey V. Elsukov 		struct in6_addr src, dst;
157fcf59617SAndrey V. Elsukov 		uint32_t len;
158fcf59617SAndrey V. Elsukov 		uint32_t nxt;
159fcf59617SAndrey V. Elsukov 	} ip6p __aligned(4);
160fcf59617SAndrey V. Elsukov 	struct ip6_hdr *ip6;
161fcf59617SAndrey V. Elsukov 
162fcf59617SAndrey V. Elsukov 	ip6 = mtod(m, struct ip6_hdr *);
163fcf59617SAndrey V. Elsukov 	ip6p.src = ip6->ip6_src;
164fcf59617SAndrey V. Elsukov 	ip6p.dst = ip6->ip6_dst;
165fcf59617SAndrey V. Elsukov 	ip6p.len = htonl(m->m_pkthdr.len - sizeof(*ip6)); /* XXX: ext headers */
166fcf59617SAndrey V. Elsukov 	ip6p.nxt = htonl(IPPROTO_TCP);
167fcf59617SAndrey V. Elsukov 	MD5Update(ctx, (char *)&ip6p, sizeof(ip6p));
168fcf59617SAndrey V. Elsukov 	return (sizeof(*ip6));
169fcf59617SAndrey V. Elsukov }
170fcf59617SAndrey V. Elsukov #endif
171fcf59617SAndrey V. Elsukov 
172fcf59617SAndrey V. Elsukov static int
173fcf59617SAndrey V. Elsukov tcp_signature_compute(struct mbuf *m, struct tcphdr *th,
174fcf59617SAndrey V. Elsukov     struct secasvar *sav, u_char *buf)
175fcf59617SAndrey V. Elsukov {
176fcf59617SAndrey V. Elsukov 	MD5_CTX ctx;
177fcf59617SAndrey V. Elsukov 	int len;
178fcf59617SAndrey V. Elsukov 	u_short csum;
179fcf59617SAndrey V. Elsukov 
180fcf59617SAndrey V. Elsukov 	MD5Init(&ctx);
181fcf59617SAndrey V. Elsukov 	 /* Step 1: Update MD5 hash with IP(v6) pseudo-header. */
182fcf59617SAndrey V. Elsukov 	switch (sav->sah->saidx.dst.sa.sa_family) {
183fcf59617SAndrey V. Elsukov #ifdef INET
184fcf59617SAndrey V. Elsukov 	case AF_INET:
185fcf59617SAndrey V. Elsukov 		len = ip_pseudo_compute(m, &ctx);
186fcf59617SAndrey V. Elsukov 		break;
187fcf59617SAndrey V. Elsukov #endif
188fcf59617SAndrey V. Elsukov #ifdef INET6
189fcf59617SAndrey V. Elsukov 	case AF_INET6:
190fcf59617SAndrey V. Elsukov 		len = ip6_pseudo_compute(m, &ctx);
191fcf59617SAndrey V. Elsukov 		break;
192fcf59617SAndrey V. Elsukov #endif
193fcf59617SAndrey V. Elsukov 	default:
194fcf59617SAndrey V. Elsukov 		return (EAFNOSUPPORT);
195fcf59617SAndrey V. Elsukov 	}
196fcf59617SAndrey V. Elsukov 	/*
197fcf59617SAndrey V. Elsukov 	 * Step 2: Update MD5 hash with TCP header, excluding options.
198fcf59617SAndrey V. Elsukov 	 * The TCP checksum must be set to zero.
199fcf59617SAndrey V. Elsukov 	 */
200fcf59617SAndrey V. Elsukov 	csum = th->th_sum;
201fcf59617SAndrey V. Elsukov 	th->th_sum = 0;
202fcf59617SAndrey V. Elsukov 	MD5Update(&ctx, (char *)th, sizeof(struct tcphdr));
203fcf59617SAndrey V. Elsukov 	th->th_sum = csum;
204fcf59617SAndrey V. Elsukov 	/*
205fcf59617SAndrey V. Elsukov 	 * Step 3: Update MD5 hash with TCP segment data.
206fcf59617SAndrey V. Elsukov 	 * Use m_apply() to avoid an early m_pullup().
207fcf59617SAndrey V. Elsukov 	 */
208fcf59617SAndrey V. Elsukov 	len += (th->th_off << 2);
209fcf59617SAndrey V. Elsukov 	if (m->m_pkthdr.len - len > 0)
210fcf59617SAndrey V. Elsukov 		m_apply(m, len, m->m_pkthdr.len - len,
211fcf59617SAndrey V. Elsukov 		    tcp_signature_apply, &ctx);
212fcf59617SAndrey V. Elsukov 	/*
213fcf59617SAndrey V. Elsukov 	 * Step 4: Update MD5 hash with shared secret.
214fcf59617SAndrey V. Elsukov 	 */
215fcf59617SAndrey V. Elsukov 	MD5Update(&ctx, sav->key_auth->key_data, _KEYLEN(sav->key_auth));
216fcf59617SAndrey V. Elsukov 	MD5Final(buf, &ctx);
217fcf59617SAndrey V. Elsukov 	key_sa_recordxfer(sav, m);
218fcf59617SAndrey V. Elsukov 	return (0);
219fcf59617SAndrey V. Elsukov }
220fcf59617SAndrey V. Elsukov 
221fcf59617SAndrey V. Elsukov static void
222fcf59617SAndrey V. Elsukov setsockaddrs(const struct mbuf *m, union sockaddr_union *src,
223fcf59617SAndrey V. Elsukov     union sockaddr_union *dst)
224fcf59617SAndrey V. Elsukov {
225fcf59617SAndrey V. Elsukov 	struct ip *ip;
226fcf59617SAndrey V. Elsukov 
227fcf59617SAndrey V. Elsukov 	IPSEC_ASSERT(m->m_len >= sizeof(*ip), ("unexpected mbuf len"));
228fcf59617SAndrey V. Elsukov 
229fcf59617SAndrey V. Elsukov 	ip = mtod(m, struct ip *);
230fcf59617SAndrey V. Elsukov 	switch (ip->ip_v) {
231fcf59617SAndrey V. Elsukov #ifdef INET
232fcf59617SAndrey V. Elsukov 	case IPVERSION:
233fcf59617SAndrey V. Elsukov 		ipsec4_setsockaddrs(m, src, dst);
234fcf59617SAndrey V. Elsukov 		break;
235fcf59617SAndrey V. Elsukov #endif
236fcf59617SAndrey V. Elsukov #ifdef INET6
237fcf59617SAndrey V. Elsukov 	case (IPV6_VERSION >> 4):
238fcf59617SAndrey V. Elsukov 		ipsec6_setsockaddrs(m, src, dst);
239fcf59617SAndrey V. Elsukov 		break;
240fcf59617SAndrey V. Elsukov #endif
241fcf59617SAndrey V. Elsukov 	default:
242fcf59617SAndrey V. Elsukov 		bzero(src, sizeof(*src));
243fcf59617SAndrey V. Elsukov 		bzero(dst, sizeof(*dst));
244fcf59617SAndrey V. Elsukov 	}
245fcf59617SAndrey V. Elsukov }
246fcf59617SAndrey V. Elsukov 
247fcf59617SAndrey V. Elsukov /*
248fcf59617SAndrey V. Elsukov  * Compute TCP-MD5 hash of an *INBOUND* TCP segment.
249fcf59617SAndrey V. Elsukov  * Parameters:
250fcf59617SAndrey V. Elsukov  * m		pointer to head of mbuf chain
251fcf59617SAndrey V. Elsukov  * th		pointer to TCP header
252fcf59617SAndrey V. Elsukov  * buf		pointer to storage for computed MD5 digest
253fcf59617SAndrey V. Elsukov  *
254fcf59617SAndrey V. Elsukov  * Return 0 if successful, otherwise return -1.
255fcf59617SAndrey V. Elsukov  */
256fcf59617SAndrey V. Elsukov static int
257fcf59617SAndrey V. Elsukov tcp_ipsec_input(struct mbuf *m, struct tcphdr *th, u_char *buf)
258fcf59617SAndrey V. Elsukov {
259fcf59617SAndrey V. Elsukov 	char tmpdigest[TCP_SIGLEN];
260fcf59617SAndrey V. Elsukov 	struct secasindex saidx;
261fcf59617SAndrey V. Elsukov 	struct secasvar *sav;
262fcf59617SAndrey V. Elsukov 
263fcf59617SAndrey V. Elsukov 	setsockaddrs(m, &saidx.src, &saidx.dst);
264fcf59617SAndrey V. Elsukov 	saidx.proto = IPPROTO_TCP;
265fcf59617SAndrey V. Elsukov 	saidx.mode = IPSEC_MODE_TCPMD5;
266fcf59617SAndrey V. Elsukov 	saidx.reqid = 0;
267fcf59617SAndrey V. Elsukov 	sav = key_allocsa_tcpmd5(&saidx);
268fcf59617SAndrey V. Elsukov 	if (sav == NULL) {
269fcf59617SAndrey V. Elsukov 		KMOD_TCPSTAT_INC(tcps_sig_err_buildsig);
270fcf59617SAndrey V. Elsukov 		return (EACCES);
271fcf59617SAndrey V. Elsukov 	}
272fcf59617SAndrey V. Elsukov 	/*
273fcf59617SAndrey V. Elsukov 	 * tcp_input() operates with TCP header fields in host
274fcf59617SAndrey V. Elsukov 	 * byte order. We expect them in network byte order.
275fcf59617SAndrey V. Elsukov 	 */
276fcf59617SAndrey V. Elsukov 	tcp_fields_to_net(th);
277fcf59617SAndrey V. Elsukov 	tcp_signature_compute(m, th, sav, tmpdigest);
278fcf59617SAndrey V. Elsukov 	tcp_fields_to_host(th);
279fcf59617SAndrey V. Elsukov 	key_freesav(&sav);
280fcf59617SAndrey V. Elsukov 	if (bcmp(buf, tmpdigest, TCP_SIGLEN) != 0) {
281fcf59617SAndrey V. Elsukov 		KMOD_TCPSTAT_INC(tcps_sig_rcvbadsig);
282fcf59617SAndrey V. Elsukov 		return (EACCES);
283fcf59617SAndrey V. Elsukov 	}
284fcf59617SAndrey V. Elsukov 	KMOD_TCPSTAT_INC(tcps_sig_rcvgoodsig);
285fcf59617SAndrey V. Elsukov 	return (0);
286fcf59617SAndrey V. Elsukov }
287fcf59617SAndrey V. Elsukov 
288fcf59617SAndrey V. Elsukov /*
289fcf59617SAndrey V. Elsukov  * Compute TCP-MD5 hash of an *OUTBOUND* TCP segment.
290fcf59617SAndrey V. Elsukov  * Parameters:
291fcf59617SAndrey V. Elsukov  * m		pointer to head of mbuf chain
292fcf59617SAndrey V. Elsukov  * th		pointer to TCP header
293fcf59617SAndrey V. Elsukov  * buf		pointer to storage for computed MD5 digest
294fcf59617SAndrey V. Elsukov  *
295fcf59617SAndrey V. Elsukov  * Return 0 if successful, otherwise return error code.
296fcf59617SAndrey V. Elsukov  */
297fcf59617SAndrey V. Elsukov static int
298fcf59617SAndrey V. Elsukov tcp_ipsec_output(struct mbuf *m, struct tcphdr *th, u_char *buf)
299fcf59617SAndrey V. Elsukov {
300fcf59617SAndrey V. Elsukov 	struct secasindex saidx;
301fcf59617SAndrey V. Elsukov 	struct secasvar *sav;
302fcf59617SAndrey V. Elsukov 
303fcf59617SAndrey V. Elsukov 	setsockaddrs(m, &saidx.src, &saidx.dst);
304fcf59617SAndrey V. Elsukov 	saidx.proto = IPPROTO_TCP;
305fcf59617SAndrey V. Elsukov 	saidx.mode = IPSEC_MODE_TCPMD5;
306fcf59617SAndrey V. Elsukov 	saidx.reqid = 0;
307fcf59617SAndrey V. Elsukov 	sav = key_allocsa_tcpmd5(&saidx);
308fcf59617SAndrey V. Elsukov 	if (sav == NULL) {
309fcf59617SAndrey V. Elsukov 		KMOD_TCPSTAT_INC(tcps_sig_err_buildsig);
310fcf59617SAndrey V. Elsukov 		return (EACCES);
311fcf59617SAndrey V. Elsukov 	}
312fcf59617SAndrey V. Elsukov 	tcp_signature_compute(m, th, sav, buf);
313fcf59617SAndrey V. Elsukov 	key_freesav(&sav);
314fcf59617SAndrey V. Elsukov 	return (0);
315fcf59617SAndrey V. Elsukov }
316fcf59617SAndrey V. Elsukov 
31755d2c71bSBruce M Simpson /*
31855d2c71bSBruce M Simpson  * Initialize a TCP-MD5 SA. Called when the SA is being set up.
31955d2c71bSBruce M Simpson  *
32055d2c71bSBruce M Simpson  * We don't need to set up the tdb prefixed fields, as we don't use the
32155d2c71bSBruce M Simpson  * opencrypto code; we just perform a key length check.
32255d2c71bSBruce M Simpson  *
323fcf59617SAndrey V. Elsukov  * XXX: Currently we have used single 'magic' SPI and need to still
324fcf59617SAndrey V. Elsukov  * support this.
32555d2c71bSBruce M Simpson  *
32655d2c71bSBruce M Simpson  * This allows per-host granularity without affecting the userland
32755d2c71bSBruce M Simpson  * interface, which is a simple socket option toggle switch,
32855d2c71bSBruce M Simpson  * TCP_SIGNATURE_ENABLE.
32955d2c71bSBruce M Simpson  *
33055d2c71bSBruce M Simpson  * To allow per-service granularity requires that we have a means
33155d2c71bSBruce M Simpson  * of mapping port to SPI. The mandated way of doing this is to
33255d2c71bSBruce M Simpson  * use SPD entries to specify packet flows which get the TCP-MD5
33355d2c71bSBruce M Simpson  * treatment, however the code to do this is currently unstable
33455d2c71bSBruce M Simpson  * and unsuitable for production use.
33555d2c71bSBruce M Simpson  *
33655d2c71bSBruce M Simpson  * Therefore we use this compromise in the meantime.
33755d2c71bSBruce M Simpson  */
33855d2c71bSBruce M Simpson static int
33955d2c71bSBruce M Simpson tcpsignature_init(struct secasvar *sav, struct xformsw *xsp)
34055d2c71bSBruce M Simpson {
34155d2c71bSBruce M Simpson 	int keylen;
34255d2c71bSBruce M Simpson 
34355d2c71bSBruce M Simpson 	if (sav->alg_auth != SADB_X_AALG_TCP_MD5) {
34455d2c71bSBruce M Simpson 		DPRINTF(("%s: unsupported authentication algorithm %u\n",
34555d2c71bSBruce M Simpson 		    __func__, sav->alg_auth));
34655d2c71bSBruce M Simpson 		return (EINVAL);
34755d2c71bSBruce M Simpson 	}
34855d2c71bSBruce M Simpson 	if (sav->key_auth == NULL) {
34955d2c71bSBruce M Simpson 		DPRINTF(("%s: no authentication key present\n", __func__));
35055d2c71bSBruce M Simpson 		return (EINVAL);
35155d2c71bSBruce M Simpson 	}
35255d2c71bSBruce M Simpson 	keylen = _KEYLEN(sav->key_auth);
35355d2c71bSBruce M Simpson 	if ((keylen < TCP_KEYLEN_MIN) || (keylen > TCP_KEYLEN_MAX)) {
35455d2c71bSBruce M Simpson 		DPRINTF(("%s: invalid key length %u\n", __func__, keylen));
35555d2c71bSBruce M Simpson 		return (EINVAL);
35655d2c71bSBruce M Simpson 	}
357fcf59617SAndrey V. Elsukov 	sav->tdb_xform = xsp;
35855d2c71bSBruce M Simpson 	return (0);
35955d2c71bSBruce M Simpson }
36055d2c71bSBruce M Simpson 
36155d2c71bSBruce M Simpson /*
36255d2c71bSBruce M Simpson  * Called when the SA is deleted.
36355d2c71bSBruce M Simpson  */
364*dae61c9dSJohn Baldwin static void
365*dae61c9dSJohn Baldwin tcpsignature_cleanup(struct secasvar *sav)
36655d2c71bSBruce M Simpson {
36755d2c71bSBruce M Simpson }
36855d2c71bSBruce M Simpson 
36955d2c71bSBruce M Simpson static struct xformsw tcpsignature_xformsw = {
370fcf59617SAndrey V. Elsukov 	.xf_type =	XF_TCPSIGNATURE,
371fcf59617SAndrey V. Elsukov 	.xf_name =	"TCP-MD5",
372fcf59617SAndrey V. Elsukov 	.xf_init =	tcpsignature_init,
373*dae61c9dSJohn Baldwin 	.xf_cleanup =	tcpsignature_cleanup,
37455d2c71bSBruce M Simpson };
37555d2c71bSBruce M Simpson 
376fcf59617SAndrey V. Elsukov static const struct tcpmd5_methods tcpmd5_methods = {
377fcf59617SAndrey V. Elsukov 	.input = tcp_ipsec_input,
378fcf59617SAndrey V. Elsukov 	.output = tcp_ipsec_output,
379fcf59617SAndrey V. Elsukov 	.pcbctl = tcp_ipsec_pcbctl,
380fcf59617SAndrey V. Elsukov };
381fcf59617SAndrey V. Elsukov 
382fcf59617SAndrey V. Elsukov #ifndef KLD_MODULE
383fcf59617SAndrey V. Elsukov /* TCP-MD5 support is build in the kernel */
384fcf59617SAndrey V. Elsukov static const struct tcpmd5_support tcpmd5_ipsec = {
385fcf59617SAndrey V. Elsukov 	.enabled = IPSEC_MODULE_ENABLED,
386fcf59617SAndrey V. Elsukov 	.methods = &tcpmd5_methods
387fcf59617SAndrey V. Elsukov };
388fcf59617SAndrey V. Elsukov const struct tcpmd5_support * const tcp_ipsec_support = &tcpmd5_ipsec;
389fcf59617SAndrey V. Elsukov #endif /* !KLD_MODULE */
390fcf59617SAndrey V. Elsukov 
391fcf59617SAndrey V. Elsukov static int
392fcf59617SAndrey V. Elsukov tcpmd5_modevent(module_t mod, int type, void *data)
39355d2c71bSBruce M Simpson {
39455d2c71bSBruce M Simpson 
395fcf59617SAndrey V. Elsukov 	switch (type) {
396fcf59617SAndrey V. Elsukov 	case MOD_LOAD:
397fcf59617SAndrey V. Elsukov 		xform_attach(&tcpsignature_xformsw);
398fcf59617SAndrey V. Elsukov #ifdef KLD_MODULE
399fcf59617SAndrey V. Elsukov 		tcpmd5_support_enable(&tcpmd5_methods);
400fcf59617SAndrey V. Elsukov #endif
401fcf59617SAndrey V. Elsukov 		break;
402fcf59617SAndrey V. Elsukov 	case MOD_UNLOAD:
403fcf59617SAndrey V. Elsukov #ifdef KLD_MODULE
404fcf59617SAndrey V. Elsukov 		tcpmd5_support_disable();
405fcf59617SAndrey V. Elsukov #endif
406fcf59617SAndrey V. Elsukov 		xform_detach(&tcpsignature_xformsw);
407fcf59617SAndrey V. Elsukov 		break;
408fcf59617SAndrey V. Elsukov 	default:
409fcf59617SAndrey V. Elsukov 		return (EOPNOTSUPP);
410fcf59617SAndrey V. Elsukov 	}
411fcf59617SAndrey V. Elsukov 	return (0);
41255d2c71bSBruce M Simpson }
41355d2c71bSBruce M Simpson 
414fcf59617SAndrey V. Elsukov static moduledata_t tcpmd5_mod = {
415fcf59617SAndrey V. Elsukov 	"tcpmd5",
416fcf59617SAndrey V. Elsukov 	tcpmd5_modevent,
417fcf59617SAndrey V. Elsukov 	0
418fcf59617SAndrey V. Elsukov };
419fcf59617SAndrey V. Elsukov 
420fcf59617SAndrey V. Elsukov DECLARE_MODULE(tcpmd5, tcpmd5_mod, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY);
421fcf59617SAndrey V. Elsukov MODULE_VERSION(tcpmd5, 1);
422fcf59617SAndrey V. Elsukov #ifdef KLD_MODULE
423fcf59617SAndrey V. Elsukov MODULE_DEPEND(tcpmd5, ipsec_support, 1, 1, 1);
424fcf59617SAndrey V. Elsukov #endif
425