xref: /openbsd/sbin/iked/ikev2_msg.c (revision 8fbd7fcb)
1*8fbd7fcbSdoug /*	$OpenBSD: ikev2_msg.c,v 1.36 2014/08/25 07:50:25 doug Exp $	*/
2fde46d6eSreyk 
3fde46d6eSreyk /*
4fcebd35dSreyk  * Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
5fde46d6eSreyk  *
6fde46d6eSreyk  * Permission to use, copy, modify, and distribute this software for any
7fde46d6eSreyk  * purpose with or without fee is hereby granted, provided that the above
8fde46d6eSreyk  * copyright notice and this permission notice appear in all copies.
9fde46d6eSreyk  *
10fde46d6eSreyk  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11fde46d6eSreyk  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12fde46d6eSreyk  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13fde46d6eSreyk  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14fde46d6eSreyk  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15fde46d6eSreyk  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16fde46d6eSreyk  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17fde46d6eSreyk  */
18fde46d6eSreyk 
19fde46d6eSreyk #include <sys/param.h>
20fde46d6eSreyk #include <sys/queue.h>
21fde46d6eSreyk #include <sys/socket.h>
22fde46d6eSreyk #include <sys/wait.h>
23fde46d6eSreyk #include <sys/uio.h>
24fde46d6eSreyk 
25fde46d6eSreyk #include <netinet/in.h>
26fde46d6eSreyk #include <netinet/ip_ipsp.h>
27fde46d6eSreyk #include <arpa/inet.h>
28fde46d6eSreyk 
29fde46d6eSreyk #include <stdlib.h>
30fde46d6eSreyk #include <stdio.h>
31fde46d6eSreyk #include <unistd.h>
32fde46d6eSreyk #include <string.h>
33fde46d6eSreyk #include <getopt.h>
34fde46d6eSreyk #include <signal.h>
35fde46d6eSreyk #include <errno.h>
36fde46d6eSreyk #include <err.h>
37fde46d6eSreyk #include <pwd.h>
38fde46d6eSreyk #include <event.h>
39fde46d6eSreyk 
40fde46d6eSreyk #include <openssl/sha.h>
41fde46d6eSreyk #include <openssl/evp.h>
42fde46d6eSreyk 
43fde46d6eSreyk #include "iked.h"
44fde46d6eSreyk #include "ikev2.h"
45fde46d6eSreyk #include "eap.h"
46fde46d6eSreyk #include "dh.h"
47fde46d6eSreyk 
48c45fd413Smikeb void	 ikev2_msg_response_timeout(struct iked *, void *);
49c45fd413Smikeb void	 ikev2_msg_retransmit_timeout(struct iked *, void *);
50c45fd413Smikeb 
51fde46d6eSreyk void
52fde46d6eSreyk ikev2_msg_cb(int fd, short event, void *arg)
53fde46d6eSreyk {
54fde46d6eSreyk 	struct iked_socket	*sock = arg;
55fde46d6eSreyk 	struct iked		*env = sock->sock_env;
56fde46d6eSreyk 	struct iked_message	 msg;
57fde46d6eSreyk 	struct ike_header	 hdr;
58fde46d6eSreyk 	u_int32_t		 natt = 0x00000000;
59fde46d6eSreyk 	u_int8_t		 buf[IKED_MSGBUF_MAX];
60fde46d6eSreyk 	ssize_t			 len;
61fde46d6eSreyk 	off_t			 off;
62fde46d6eSreyk 	struct iovec		 iov[2];
63fde46d6eSreyk 
64fde46d6eSreyk 	bzero(&msg, sizeof(msg));
65fde46d6eSreyk 	bzero(buf, sizeof(buf));
66fde46d6eSreyk 
67fde46d6eSreyk 	msg.msg_peerlen = sizeof(msg.msg_peer);
68fde46d6eSreyk 	msg.msg_locallen = sizeof(msg.msg_local);
6926d7dba1Sreyk 	msg.msg_parent = &msg;
70fde46d6eSreyk 	memcpy(&msg.msg_local, &sock->sock_addr, sizeof(sock->sock_addr));
71fde46d6eSreyk 
72fde46d6eSreyk 	if ((len = recvfromto(fd, buf, sizeof(buf), 0,
73fde46d6eSreyk 	    (struct sockaddr *)&msg.msg_peer, &msg.msg_peerlen,
74fde46d6eSreyk 	    (struct sockaddr *)&msg.msg_local, &msg.msg_locallen)) <
75fde46d6eSreyk 	    (ssize_t)sizeof(natt))
76fde46d6eSreyk 		return;
77fde46d6eSreyk 
7847d6a31cSmarkus 	if (socket_getport((struct sockaddr *)&msg.msg_local) ==
7947d6a31cSmarkus 	    IKED_NATT_PORT) {
80fde46d6eSreyk 		if (bcmp(&natt, buf, sizeof(natt)) != 0)
81fde46d6eSreyk 			return;
82fde46d6eSreyk 		msg.msg_natt = 1;
83fde46d6eSreyk 		off = sizeof(natt);
84fde46d6eSreyk 	} else
85fde46d6eSreyk 		off = 0;
86fde46d6eSreyk 
87fde46d6eSreyk 	if ((size_t)(len - off) <= sizeof(hdr))
88fde46d6eSreyk 		return;
89fde46d6eSreyk 	memcpy(&hdr, buf + off, sizeof(hdr));
90fde46d6eSreyk 
91fde46d6eSreyk 	if ((msg.msg_data = ibuf_new(buf + off, len - off)) == NULL)
92fde46d6eSreyk 		return;
93fde46d6eSreyk 
94fde46d6eSreyk 	if (hdr.ike_version == IKEV1_VERSION) {
95fde46d6eSreyk 		iov[0].iov_base = &msg;
96fde46d6eSreyk 		iov[0].iov_len = sizeof(msg);
97fde46d6eSreyk 		iov[1].iov_base = buf;
98fde46d6eSreyk 		iov[1].iov_len = len;
99fde46d6eSreyk 
100bf556abcSreyk 		proc_composev_imsg(&env->sc_ps, PROC_IKEV1, -1,
101bf556abcSreyk 		    IMSG_IKE_MESSAGE, -1, iov, 2);
102fde46d6eSreyk 		goto done;
103fde46d6eSreyk 	}
104fde46d6eSreyk 	TAILQ_INIT(&msg.msg_proposals);
105fde46d6eSreyk 
106fde46d6eSreyk 	msg.msg_fd = fd;
107fde46d6eSreyk 	ikev2_recv(env, &msg);
108fde46d6eSreyk 
109fde46d6eSreyk  done:
110763023d6Sreyk 	ikev2_msg_cleanup(env, &msg);
111fde46d6eSreyk }
112fde46d6eSreyk 
113fde46d6eSreyk struct ibuf *
114fde46d6eSreyk ikev2_msg_init(struct iked *env, struct iked_message *msg,
115fde46d6eSreyk     struct sockaddr_storage *peer, socklen_t peerlen,
116fde46d6eSreyk     struct sockaddr_storage *local, socklen_t locallen, int response)
117fde46d6eSreyk {
118fde46d6eSreyk 	bzero(msg, sizeof(*msg));
119fde46d6eSreyk 	memcpy(&msg->msg_peer, peer, peerlen);
120fde46d6eSreyk 	msg->msg_peerlen = peerlen;
121fde46d6eSreyk 	memcpy(&msg->msg_local, local, locallen);
122fde46d6eSreyk 	msg->msg_locallen = locallen;
123fde46d6eSreyk 	msg->msg_response = response ? 1 : 0;
124fde46d6eSreyk 	msg->msg_fd = -1;
125fde46d6eSreyk 	msg->msg_data = ibuf_static();
12626d7dba1Sreyk 	msg->msg_e = 0;
12726d7dba1Sreyk 	msg->msg_parent = msg;	/* has to be set */
128763023d6Sreyk 	TAILQ_INIT(&msg->msg_proposals);
129fde46d6eSreyk 
130fde46d6eSreyk 	return (msg->msg_data);
131fde46d6eSreyk }
132fde46d6eSreyk 
133c45fd413Smikeb struct iked_message *
134c45fd413Smikeb ikev2_msg_copy(struct iked *env, struct iked_message *msg)
135c45fd413Smikeb {
136c45fd413Smikeb 	struct iked_message		*m = NULL;
137c45fd413Smikeb 	struct ibuf			*buf;
138d39d09feSreyk 	size_t				 len;
13912c9fd31Sreyk 	void				*ptr;
140c45fd413Smikeb 
141d39d09feSreyk 	if (ibuf_size(msg->msg_data) < msg->msg_offset)
142d39d09feSreyk 		return (NULL);
143d39d09feSreyk 	len = ibuf_size(msg->msg_data) - msg->msg_offset;
144d39d09feSreyk 
145d39d09feSreyk 	if ((ptr = ibuf_seek(msg->msg_data, msg->msg_offset, len)) == NULL ||
14612c9fd31Sreyk 	    (m = malloc(sizeof(*m))) == NULL ||
147c45fd413Smikeb 	    (buf = ikev2_msg_init(env, m, &msg->msg_peer, msg->msg_peerlen,
148c45fd413Smikeb 	     &msg->msg_local, msg->msg_locallen, msg->msg_response)) == NULL ||
14912c9fd31Sreyk 	    ibuf_add(buf, ptr, len))
150c45fd413Smikeb 		return (NULL);
151c45fd413Smikeb 
152c45fd413Smikeb 	m->msg_fd = msg->msg_fd;
153c45fd413Smikeb 	m->msg_msgid = msg->msg_msgid;
154c45fd413Smikeb 	m->msg_offset = msg->msg_offset;
155c45fd413Smikeb 	m->msg_sa = msg->msg_sa;
156c45fd413Smikeb 
157c45fd413Smikeb 	return (m);
158c45fd413Smikeb }
159c45fd413Smikeb 
160763023d6Sreyk void
161763023d6Sreyk ikev2_msg_cleanup(struct iked *env, struct iked_message *msg)
162763023d6Sreyk {
16326d7dba1Sreyk 	if (msg == msg->msg_parent) {
16426d7dba1Sreyk 		ibuf_release(msg->msg_nonce);
16526d7dba1Sreyk 		ibuf_release(msg->msg_ke);
16626d7dba1Sreyk 		ibuf_release(msg->msg_auth.id_buf);
16726d7dba1Sreyk 		ibuf_release(msg->msg_id.id_buf);
16826d7dba1Sreyk 		ibuf_release(msg->msg_cert.id_buf);
16926d7dba1Sreyk 
17026d7dba1Sreyk 		config_free_proposals(&msg->msg_proposals, 0);
17126d7dba1Sreyk 	}
17226d7dba1Sreyk 
173763023d6Sreyk 	if (msg->msg_data != NULL) {
174763023d6Sreyk 		ibuf_release(msg->msg_data);
175763023d6Sreyk 		msg->msg_data = NULL;
176763023d6Sreyk 	}
177763023d6Sreyk }
178763023d6Sreyk 
179fde46d6eSreyk int
180fde46d6eSreyk ikev2_msg_valid_ike_sa(struct iked *env, struct ike_header *oldhdr,
181fde46d6eSreyk     struct iked_message *msg)
182fde46d6eSreyk {
183fde46d6eSreyk #if 0
184fde46d6eSreyk 	/* XXX Disabled, see comment below */
185fde46d6eSreyk 	struct iked_message		 resp;
186fde46d6eSreyk 	struct ike_header		*hdr;
187fde46d6eSreyk 	struct ikev2_payload		*pld;
188fde46d6eSreyk 	struct ikev2_notify		*n;
189fde46d6eSreyk 	struct ibuf			*buf;
190fde46d6eSreyk 	struct iked_sa			 sa;
191fde46d6eSreyk #endif
192fde46d6eSreyk 
1936e1880a3Smarkus 	if (msg->msg_sa != NULL && msg->msg_policy != NULL) {
1946e1880a3Smarkus 		/*
1956e1880a3Smarkus 		 * Only permit informational requests from initiator
1966e1880a3Smarkus 		 * on closing SAs (for DELETE).
1976e1880a3Smarkus 		 */
1986e1880a3Smarkus 		if (msg->msg_sa->sa_state == IKEV2_STATE_CLOSING) {
1996e1880a3Smarkus 			if (((oldhdr->ike_flags &
2006e1880a3Smarkus 			    (IKEV2_FLAG_INITIATOR|IKEV2_FLAG_RESPONSE)) ==
2016e1880a3Smarkus 			    IKEV2_FLAG_INITIATOR) &&
2026e1880a3Smarkus 			    (oldhdr->ike_exchange ==
2036e1880a3Smarkus 			    IKEV2_EXCHANGE_INFORMATIONAL))
204fde46d6eSreyk 				return (0);
2056e1880a3Smarkus 			return (-1);
2066e1880a3Smarkus 		}
2076e1880a3Smarkus 		return (0);
2086e1880a3Smarkus 	}
209fde46d6eSreyk 
210fde46d6eSreyk #if 0
211fde46d6eSreyk 	/*
212fde46d6eSreyk 	 * XXX Sending INVALID_IKE_SPIs notifications is disabled
213fde46d6eSreyk 	 * XXX because it is not mandatory and ignored by most
214fde46d6eSreyk 	 * XXX implementations.  We might want to enable it in
215fde46d6eSreyk 	 * XXX combination with a rate-limitation to avoid DoS situations.
216fde46d6eSreyk 	 */
217fde46d6eSreyk 
218fde46d6eSreyk 	/* Fail without error message */
219fde46d6eSreyk 	if (msg->msg_response || msg->msg_policy == NULL)
220fde46d6eSreyk 		return (-1);
221fde46d6eSreyk 
222fde46d6eSreyk 	/* Invalid IKE SA, return notification */
223fde46d6eSreyk 	if ((buf = ikev2_msg_init(env, &resp,
224fde46d6eSreyk 	    &msg->msg_peer, msg->msg_peerlen,
225fde46d6eSreyk 	    &msg->msg_local, msg->msg_locallen, 1)) == NULL)
226fde46d6eSreyk 		goto done;
227fde46d6eSreyk 
228d9c13a0aSmikeb 	resp.msg_fd = msg->msg_fd;
229d9c13a0aSmikeb 
230fde46d6eSreyk 	bzero(&sa, sizeof(sa));
231fde46d6eSreyk 	if ((oldhdr->ike_flags & IKEV2_FLAG_INITIATOR) == 0)
232fde46d6eSreyk 		sa.sa_hdr.sh_initiator = 1;
233fde46d6eSreyk 	sa.sa_hdr.sh_ispi = betoh64(oldhdr->ike_ispi);
234fde46d6eSreyk 	sa.sa_hdr.sh_rspi = betoh64(oldhdr->ike_rspi);
235fde46d6eSreyk 
236c45fd413Smikeb 	resp.msg_msgid = betoh32(oldhdr->ike_msgid);
237c45fd413Smikeb 
238fde46d6eSreyk 	/* IKE header */
239c45fd413Smikeb 	if ((hdr = ikev2_add_header(buf, &sa, resp.msg_msgid,
240fde46d6eSreyk 	    IKEV2_PAYLOAD_NOTIFY, IKEV2_EXCHANGE_INFORMATIONAL,
241fde46d6eSreyk 	    IKEV2_FLAG_RESPONSE)) == NULL)
242fde46d6eSreyk 		goto done;
243fde46d6eSreyk 
244fde46d6eSreyk 	/* SA payload */
245fde46d6eSreyk 	if ((pld = ikev2_add_payload(buf)) == NULL)
246fde46d6eSreyk 		goto done;
247fde46d6eSreyk 	if ((n = ibuf_advance(buf, sizeof(*n))) == NULL)
248fde46d6eSreyk 		goto done;
249fde46d6eSreyk 	n->n_protoid = IKEV2_SAPROTO_IKE;
250fde46d6eSreyk 	n->n_spisize = 0;
251fde46d6eSreyk 	n->n_type = htobe16(IKEV2_N_INVALID_IKE_SPI);
252fde46d6eSreyk 
253fde46d6eSreyk 	if (ikev2_next_payload(pld, sizeof(*n), IKEV2_PAYLOAD_NONE) == -1)
254fde46d6eSreyk 		goto done;
255fde46d6eSreyk 
256fde46d6eSreyk 	if (ikev2_set_header(hdr, ibuf_size(buf) - sizeof(*hdr)) == -1)
257fde46d6eSreyk 		goto done;
258fde46d6eSreyk 
259fde46d6eSreyk 	(void)ikev2_pld_parse(env, hdr, &resp, 0);
260d9c13a0aSmikeb 	(void)ikev2_msg_send(env, &resp);
261fde46d6eSreyk 
262fde46d6eSreyk  done:
263763023d6Sreyk 	ikev2_msg_cleanup(env, &resp);
264fde46d6eSreyk #endif
265fde46d6eSreyk 
266fde46d6eSreyk 	/* Always fail */
267fde46d6eSreyk 	return (-1);
268fde46d6eSreyk }
269fde46d6eSreyk 
270fde46d6eSreyk int
271d9c13a0aSmikeb ikev2_msg_send(struct iked *env, struct iked_message *msg)
272fde46d6eSreyk {
273c45fd413Smikeb 	struct iked_sa		*sa = msg->msg_sa;
274fde46d6eSreyk 	struct ibuf		*buf = msg->msg_data;
275fde46d6eSreyk 	u_int32_t		 natt = 0x00000000;
27612c9fd31Sreyk 	int			 isnatt = 0;
277670a137dSmikeb 	u_int8_t		 exchange, flags;
278fde46d6eSreyk 	struct ike_header	*hdr;
279c45fd413Smikeb 	struct iked_message	*m;
280fde46d6eSreyk 
281fde46d6eSreyk 	if (buf == NULL || (hdr = ibuf_seek(msg->msg_data,
282fde46d6eSreyk 	    msg->msg_offset, sizeof(*hdr))) == NULL)
283fde46d6eSreyk 		return (-1);
284fde46d6eSreyk 
28512c9fd31Sreyk 	isnatt = (msg->msg_natt || (msg->msg_sa && msg->msg_sa->sa_natt));
28612c9fd31Sreyk 
287670a137dSmikeb 	exchange = hdr->ike_exchange;
288670a137dSmikeb 	flags = hdr->ike_flags;
2897f7372eaSmarkus 	log_info("%s: %s %s from %s to %s msgid %u, %ld bytes%s", __func__,
290670a137dSmikeb 	    print_map(exchange, ikev2_exchange_map),
2917f7372eaSmarkus 	    (flags & IKEV2_FLAG_RESPONSE) ? "response" : "request",
29247d6a31cSmarkus 	    print_host((struct sockaddr *)&msg->msg_local, NULL, 0),
29347d6a31cSmarkus 	    print_host((struct sockaddr *)&msg->msg_peer, NULL, 0),
2947f7372eaSmarkus 	    betoh32(hdr->ike_msgid),
29512c9fd31Sreyk 	    ibuf_length(buf), isnatt ? ", NAT-T" : "");
296fde46d6eSreyk 
29712c9fd31Sreyk 	if (isnatt) {
298fde46d6eSreyk 		if (ibuf_prepend(buf, &natt, sizeof(natt)) == -1) {
299fde46d6eSreyk 			log_debug("%s: failed to set NAT-T", __func__);
300fde46d6eSreyk 			return (-1);
301fde46d6eSreyk 		}
302c45fd413Smikeb 		msg->msg_offset += sizeof(natt);
303fde46d6eSreyk 	}
304d9c13a0aSmikeb 
305d9c13a0aSmikeb 	if ((sendto(msg->msg_fd, ibuf_data(buf), ibuf_size(buf), 0,
306fde46d6eSreyk 	    (struct sockaddr *)&msg->msg_peer, msg->msg_peerlen)) == -1) {
307fde46d6eSreyk 		log_warn("%s: sendto", __func__);
308fde46d6eSreyk 		return (-1);
309fde46d6eSreyk 	}
310fde46d6eSreyk 
311c45fd413Smikeb 	if (!sa)
312c45fd413Smikeb 		return (0);
313c45fd413Smikeb 
314c45fd413Smikeb 	if ((m = ikev2_msg_copy(env, msg)) == NULL) {
315c45fd413Smikeb 		log_debug("%s: failed to copy a message", __func__);
316c45fd413Smikeb 		return (-1);
317c45fd413Smikeb 	}
318670a137dSmikeb 	m->msg_exchange = exchange;
319c45fd413Smikeb 
320670a137dSmikeb 	if (flags & IKEV2_FLAG_RESPONSE) {
321c45fd413Smikeb 		TAILQ_INSERT_TAIL(&sa->sa_responses, m, msg_entry);
322b3eeacebSmikeb 		timer_set(env, &m->msg_timer, ikev2_msg_response_timeout, m);
323b3eeacebSmikeb 		timer_add(env, &m->msg_timer, IKED_RESPONSE_TIMEOUT);
324c45fd413Smikeb 	} else {
325c45fd413Smikeb 		TAILQ_INSERT_TAIL(&sa->sa_requests, m, msg_entry);
326b3eeacebSmikeb 		timer_set(env, &m->msg_timer, ikev2_msg_retransmit_timeout, m);
327b3eeacebSmikeb 		timer_add(env, &m->msg_timer, IKED_RETRANSMIT_TIMEOUT);
328c45fd413Smikeb 	}
329c45fd413Smikeb 
330fde46d6eSreyk 	return (0);
331fde46d6eSreyk }
332fde46d6eSreyk 
333fde46d6eSreyk u_int32_t
334c45fd413Smikeb ikev2_msg_id(struct iked *env, struct iked_sa *sa)
335fde46d6eSreyk {
336c45fd413Smikeb 	u_int32_t		id = sa->sa_reqid;
337fde46d6eSreyk 
33810650a52Smikeb 	if (++sa->sa_reqid == UINT32_MAX) {
339fde46d6eSreyk 		/* XXX we should close and renegotiate the connection now */
340fde46d6eSreyk 		log_debug("%s: IKEv2 message sequence overflow", __func__);
341fde46d6eSreyk 	}
34210650a52Smikeb 	return (id);
343fde46d6eSreyk }
344fde46d6eSreyk 
345fde46d6eSreyk struct ibuf *
346fde46d6eSreyk ikev2_msg_encrypt(struct iked *env, struct iked_sa *sa, struct ibuf *src)
347fde46d6eSreyk {
348fde46d6eSreyk 	size_t			 len, ivlen, encrlen, integrlen, blocklen,
349fde46d6eSreyk 				    outlen;
350fde46d6eSreyk 	u_int8_t		*buf, pad = 0, *ptr;
35188d75aadSreyk 	struct ibuf		*encr, *dst = NULL, *out = NULL;
352fde46d6eSreyk 
353fde46d6eSreyk 	buf = ibuf_data(src);
354fde46d6eSreyk 	len = ibuf_size(src);
355fde46d6eSreyk 
356328746baSreyk 	log_debug("%s: decrypted length %zu", __func__, len);
357fde46d6eSreyk 	print_hex(buf, 0, len);
358fde46d6eSreyk 
359fde46d6eSreyk 	if (sa == NULL ||
360fde46d6eSreyk 	    sa->sa_encr == NULL ||
361fde46d6eSreyk 	    sa->sa_integr == NULL) {
362fde46d6eSreyk 		log_debug("%s: invalid SA", __func__);
363fde46d6eSreyk 		goto done;
364fde46d6eSreyk 	}
365fde46d6eSreyk 
36688d75aadSreyk 	if (sa->sa_hdr.sh_initiator)
367fde46d6eSreyk 		encr = sa->sa_key_iencr;
36888d75aadSreyk 	else
369fde46d6eSreyk 		encr = sa->sa_key_rencr;
370fde46d6eSreyk 
371fde46d6eSreyk 	blocklen = cipher_length(sa->sa_encr);
372fde46d6eSreyk 	ivlen = cipher_ivlength(sa->sa_encr);
373fde46d6eSreyk 	integrlen = hash_length(sa->sa_integr);
374fde46d6eSreyk 	encrlen = roundup(len + sizeof(pad), blocklen);
375fde46d6eSreyk 	pad = encrlen - (len + sizeof(pad));
376fde46d6eSreyk 
377fde46d6eSreyk 	/*
378fde46d6eSreyk 	 * Pad the payload and encrypt it
379fde46d6eSreyk 	 */
380fde46d6eSreyk 	if (pad) {
381fde46d6eSreyk 		if ((ptr = ibuf_advance(src, pad)) == NULL)
382fde46d6eSreyk 			goto done;
383fde46d6eSreyk 		arc4random_buf(ptr, pad);
384fde46d6eSreyk 	}
385fde46d6eSreyk 	if (ibuf_add(src, &pad, sizeof(pad)) != 0)
386fde46d6eSreyk 		goto done;
387fde46d6eSreyk 
388328746baSreyk 	log_debug("%s: padded length %zu", __func__, ibuf_size(src));
389fde46d6eSreyk 	print_hex(ibuf_data(src), 0, ibuf_size(src));
390fde46d6eSreyk 
391fde46d6eSreyk 	cipher_setkey(sa->sa_encr, encr->buf, ibuf_length(encr));
39288d75aadSreyk 	cipher_setiv(sa->sa_encr, NULL, 0);	/* XXX ivlen */
393fde46d6eSreyk 	cipher_init_encrypt(sa->sa_encr);
394fde46d6eSreyk 
395fde46d6eSreyk 	if ((dst = ibuf_dup(sa->sa_encr->encr_iv)) == NULL)
396fde46d6eSreyk 		goto done;
397fde46d6eSreyk 
398fde46d6eSreyk 	if ((out = ibuf_new(NULL,
399fde46d6eSreyk 	    cipher_outlength(sa->sa_encr, encrlen))) == NULL)
400fde46d6eSreyk 		goto done;
401fde46d6eSreyk 
402fde46d6eSreyk 	outlen = ibuf_size(out);
403fde46d6eSreyk 	cipher_update(sa->sa_encr,
404fde46d6eSreyk 	    ibuf_data(src), encrlen, ibuf_data(out), &outlen);
405fde46d6eSreyk 
406fde46d6eSreyk 	if (outlen && ibuf_add(dst, ibuf_data(out), outlen) != 0)
407fde46d6eSreyk 		goto done;
408fde46d6eSreyk 
409fde46d6eSreyk 	if ((ptr = ibuf_advance(dst, integrlen)) == NULL)
410fde46d6eSreyk 		goto done;
411*8fbd7fcbSdoug 	explicit_bzero(ptr, integrlen);
412fde46d6eSreyk 
413328746baSreyk 	log_debug("%s: length %zu, padding %d, output length %zu",
414fde46d6eSreyk 	    __func__, len + sizeof(pad), pad, ibuf_size(dst));
415fde46d6eSreyk 	print_hex(ibuf_data(dst), 0, ibuf_size(dst));
416fde46d6eSreyk 
417fde46d6eSreyk 	ibuf_release(src);
418fde46d6eSreyk 	ibuf_release(out);
419fde46d6eSreyk 	return (dst);
420fde46d6eSreyk  done:
421fde46d6eSreyk 	ibuf_release(src);
422fde46d6eSreyk 	ibuf_release(out);
423fde46d6eSreyk 	ibuf_release(dst);
424fde46d6eSreyk 	return (NULL);
425fde46d6eSreyk }
426fde46d6eSreyk 
427fde46d6eSreyk int
428fde46d6eSreyk ikev2_msg_integr(struct iked *env, struct iked_sa *sa, struct ibuf *src)
429fde46d6eSreyk {
430fde46d6eSreyk 	int			 ret = -1;
431fde46d6eSreyk 	size_t			 integrlen, tmplen;
43288d75aadSreyk 	struct ibuf		*integr, *tmp = NULL;
433fde46d6eSreyk 	u_int8_t		*ptr;
434fde46d6eSreyk 
435328746baSreyk 	log_debug("%s: message length %zu", __func__, ibuf_size(src));
436fde46d6eSreyk 	print_hex(ibuf_data(src), 0, ibuf_size(src));
437fde46d6eSreyk 
438fde46d6eSreyk 	if (sa == NULL ||
439fde46d6eSreyk 	    sa->sa_integr == NULL) {
440fde46d6eSreyk 		log_debug("%s: invalid SA", __func__);
441fde46d6eSreyk 		return (-1);
442fde46d6eSreyk 	}
443fde46d6eSreyk 
44488d75aadSreyk 	if (sa->sa_hdr.sh_initiator)
445fde46d6eSreyk 		integr = sa->sa_key_iauth;
44688d75aadSreyk 	else
447fde46d6eSreyk 		integr = sa->sa_key_rauth;
448fde46d6eSreyk 
449fde46d6eSreyk 	integrlen = hash_length(sa->sa_integr);
450fde46d6eSreyk 
451328746baSreyk 	log_debug("%s: integrity checksum length %zu", __func__,
452fde46d6eSreyk 	    integrlen);
453fde46d6eSreyk 
454fde46d6eSreyk 	/*
455fde46d6eSreyk 	 * Validate packet checksum
456fde46d6eSreyk 	 */
457fde46d6eSreyk 	if ((tmp = ibuf_new(NULL, hash_keylength(sa->sa_integr))) == NULL)
458fde46d6eSreyk 		goto done;
459fde46d6eSreyk 
460fde46d6eSreyk 	hash_setkey(sa->sa_integr, ibuf_data(integr), ibuf_size(integr));
461fde46d6eSreyk 	hash_init(sa->sa_integr);
462fde46d6eSreyk 	hash_update(sa->sa_integr, ibuf_data(src),
463fde46d6eSreyk 	    ibuf_size(src) - integrlen);
464fde46d6eSreyk 	hash_final(sa->sa_integr, ibuf_data(tmp), &tmplen);
465fde46d6eSreyk 
466fde46d6eSreyk 	if (tmplen != integrlen) {
467fde46d6eSreyk 		log_debug("%s: hash failure", __func__);
468fde46d6eSreyk 		goto done;
469fde46d6eSreyk 	}
470fde46d6eSreyk 
471fde46d6eSreyk 	if ((ptr = ibuf_seek(src,
472fde46d6eSreyk 	    ibuf_size(src) - integrlen, integrlen)) == NULL)
473fde46d6eSreyk 		goto done;
474fde46d6eSreyk 	memcpy(ptr, ibuf_data(tmp), tmplen);
475fde46d6eSreyk 
476fde46d6eSreyk 	print_hex(ibuf_data(tmp), 0, ibuf_size(tmp));
477fde46d6eSreyk 
478fde46d6eSreyk 	ret = 0;
479fde46d6eSreyk  done:
480fde46d6eSreyk 	ibuf_release(tmp);
481fde46d6eSreyk 
482fde46d6eSreyk 	return (ret);
483fde46d6eSreyk }
484fde46d6eSreyk 
485fde46d6eSreyk struct ibuf *
486fde46d6eSreyk ikev2_msg_decrypt(struct iked *env, struct iked_sa *sa,
487fde46d6eSreyk     struct ibuf *msg, struct ibuf *src)
488fde46d6eSreyk {
489e0696045Sreyk 	ssize_t			 ivlen, encrlen, integrlen, blocklen,
490fde46d6eSreyk 				    outlen, tmplen;
491e0696045Sreyk 	u_int8_t		 pad = 0, *ptr;
492fde46d6eSreyk 	struct ibuf		*integr, *encr, *tmp = NULL, *out = NULL;
493fde46d6eSreyk 	off_t			 ivoff, encroff, integroff;
494fde46d6eSreyk 
495fde46d6eSreyk 	if (sa == NULL ||
496fde46d6eSreyk 	    sa->sa_encr == NULL ||
497fde46d6eSreyk 	    sa->sa_integr == NULL) {
498fde46d6eSreyk 		log_debug("%s: invalid SA", __func__);
499fde46d6eSreyk 		print_hex(ibuf_data(src), 0, ibuf_size(src));
500fde46d6eSreyk 		goto done;
501fde46d6eSreyk 	}
502fde46d6eSreyk 
503fde46d6eSreyk 	if (!sa->sa_hdr.sh_initiator) {
504fde46d6eSreyk 		encr = sa->sa_key_iencr;
505fde46d6eSreyk 		integr = sa->sa_key_iauth;
506fde46d6eSreyk 	} else {
507fde46d6eSreyk 		encr = sa->sa_key_rencr;
508fde46d6eSreyk 		integr = sa->sa_key_rauth;
509fde46d6eSreyk 	}
510fde46d6eSreyk 
511fde46d6eSreyk 	blocklen = cipher_length(sa->sa_encr);
512fde46d6eSreyk 	ivlen = cipher_ivlength(sa->sa_encr);
513fde46d6eSreyk 	ivoff = 0;
514fde46d6eSreyk 	integrlen = hash_length(sa->sa_integr);
515fde46d6eSreyk 	integroff = ibuf_size(src) - integrlen;
516fde46d6eSreyk 	encroff = ivlen;
517fde46d6eSreyk 	encrlen = ibuf_size(src) - integrlen - ivlen;
518fde46d6eSreyk 
519e0696045Sreyk 	if (encrlen < 0 || integroff < 0) {
520e0696045Sreyk 		log_debug("%s: invalid integrity value", __func__);
521e0696045Sreyk 		goto done;
522e0696045Sreyk 	}
523e0696045Sreyk 
524328746baSreyk 	log_debug("%s: IV length %zd", __func__, ivlen);
525fde46d6eSreyk 	print_hex(ibuf_data(src), 0, ivlen);
526328746baSreyk 	log_debug("%s: encrypted payload length %zd", __func__, encrlen);
527fde46d6eSreyk 	print_hex(ibuf_data(src), encroff, encrlen);
528328746baSreyk 	log_debug("%s: integrity checksum length %zd", __func__, integrlen);
529fde46d6eSreyk 	print_hex(ibuf_data(src), integroff, integrlen);
530fde46d6eSreyk 
531fde46d6eSreyk 	/*
532fde46d6eSreyk 	 * Validate packet checksum
533fde46d6eSreyk 	 */
534fde46d6eSreyk 	if ((tmp = ibuf_new(NULL, ibuf_length(integr))) == NULL)
535fde46d6eSreyk 		goto done;
536fde46d6eSreyk 
537fde46d6eSreyk 	hash_setkey(sa->sa_integr, integr->buf, ibuf_length(integr));
538fde46d6eSreyk 	hash_init(sa->sa_integr);
539fde46d6eSreyk 	hash_update(sa->sa_integr, ibuf_data(msg),
540fde46d6eSreyk 	    ibuf_size(msg) - integrlen);
541fde46d6eSreyk 	hash_final(sa->sa_integr, tmp->buf, &tmplen);
542fde46d6eSreyk 
543fde46d6eSreyk 	if (memcmp(tmp->buf, ibuf_data(src) + integroff, integrlen) != 0) {
544fde46d6eSreyk 		log_debug("%s: integrity check failed", __func__);
545fde46d6eSreyk 		goto done;
546fde46d6eSreyk 	}
547fde46d6eSreyk 
548b0eeedd0Smikeb 	log_debug("%s: integrity check succeeded", __func__);
549fde46d6eSreyk 	print_hex(tmp->buf, 0, tmplen);
550fde46d6eSreyk 
551fde46d6eSreyk 	ibuf_release(tmp);
552fde46d6eSreyk 	tmp = NULL;
553fde46d6eSreyk 
554fde46d6eSreyk 	/*
555fde46d6eSreyk 	 * Decrypt the payload and strip any padding
556fde46d6eSreyk 	 */
557fde46d6eSreyk 	if ((encrlen % blocklen) != 0) {
558fde46d6eSreyk 		log_debug("%s: unaligned encrypted payload", __func__);
559fde46d6eSreyk 		goto done;
560fde46d6eSreyk 	}
561fde46d6eSreyk 
562fde46d6eSreyk 	cipher_setkey(sa->sa_encr, encr->buf, ibuf_length(encr));
563fde46d6eSreyk 	cipher_setiv(sa->sa_encr, ibuf_data(src) + ivoff, ivlen);
564fde46d6eSreyk 	cipher_init_decrypt(sa->sa_encr);
565fde46d6eSreyk 
566fde46d6eSreyk 	if ((out = ibuf_new(NULL, cipher_outlength(sa->sa_encr,
567fde46d6eSreyk 	    encrlen))) == NULL)
568fde46d6eSreyk 		goto done;
569fde46d6eSreyk 
570e0696045Sreyk 	if ((outlen = ibuf_length(out)) != 0) {
5713189733aSmikeb 		cipher_update(sa->sa_encr, ibuf_data(src) + encroff, encrlen,
5723189733aSmikeb 		    ibuf_data(out), &outlen);
5733189733aSmikeb 
574fde46d6eSreyk 		ptr = ibuf_seek(out, outlen - 1, 1);
575fde46d6eSreyk 		pad = *ptr;
576e0696045Sreyk 	}
577fde46d6eSreyk 
578328746baSreyk 	log_debug("%s: decrypted payload length %zd/%zd padding %d",
579fde46d6eSreyk 	    __func__, outlen, encrlen, pad);
580fde46d6eSreyk 	print_hex(ibuf_data(out), 0, ibuf_size(out));
581fde46d6eSreyk 
582fde46d6eSreyk 	if (ibuf_setsize(out, outlen) != 0)
583fde46d6eSreyk 		goto done;
584fde46d6eSreyk 
585fde46d6eSreyk 	ibuf_release(src);
586fde46d6eSreyk 	return (out);
587fde46d6eSreyk  done:
588fde46d6eSreyk 	ibuf_release(tmp);
589fde46d6eSreyk 	ibuf_release(out);
590fde46d6eSreyk 	ibuf_release(src);
591fde46d6eSreyk 	return (NULL);
592fde46d6eSreyk }
593fde46d6eSreyk 
594fde46d6eSreyk int
595c45fd413Smikeb ikev2_msg_send_encrypt(struct iked *env, struct iked_sa *sa, struct ibuf **ep,
596c45fd413Smikeb     u_int8_t exchange, u_int8_t firstpayload, int response)
597fde46d6eSreyk {
598fde46d6eSreyk 	struct iked_message		 resp;
599fde46d6eSreyk 	struct ike_header		*hdr;
600fde46d6eSreyk 	struct ikev2_payload		*pld;
601fde46d6eSreyk 	struct ibuf			*buf, *e = *ep;
602fde46d6eSreyk 	int				 ret = -1;
603fde46d6eSreyk 
604c45fd413Smikeb 	if ((buf = ikev2_msg_init(env, &resp, &sa->sa_peer.addr,
605c45fd413Smikeb 	    sa->sa_peer.addr.ss_len, &sa->sa_local.addr,
606c45fd413Smikeb 	    sa->sa_local.addr.ss_len, response)) == NULL)
607fde46d6eSreyk 		goto done;
608fde46d6eSreyk 
609c45fd413Smikeb 	resp.msg_msgid = response ? sa->sa_msgid : ikev2_msg_id(env, sa);
610c45fd413Smikeb 
611fde46d6eSreyk 	/* IKE header */
612c45fd413Smikeb 	if ((hdr = ikev2_add_header(buf, sa, resp.msg_msgid, IKEV2_PAYLOAD_SK,
613c45fd413Smikeb 	    exchange, response ? IKEV2_FLAG_RESPONSE : 0)) == NULL)
614fde46d6eSreyk 		goto done;
615fde46d6eSreyk 
616fde46d6eSreyk 	if ((pld = ikev2_add_payload(buf)) == NULL)
617fde46d6eSreyk 		goto done;
618fde46d6eSreyk 
619fde46d6eSreyk 	/* Encrypt message and add as an E payload */
620fde46d6eSreyk 	if ((e = ikev2_msg_encrypt(env, sa, e)) == NULL) {
621fde46d6eSreyk 		log_debug("%s: encryption failed", __func__);
622fde46d6eSreyk 		goto done;
623fde46d6eSreyk 	}
624fde46d6eSreyk 	if (ibuf_cat(buf, e) != 0)
625fde46d6eSreyk 		goto done;
626fde46d6eSreyk 	if (ikev2_next_payload(pld, ibuf_size(e), firstpayload) == -1)
627fde46d6eSreyk 		goto done;
628fde46d6eSreyk 
629fde46d6eSreyk 	if (ikev2_set_header(hdr, ibuf_size(buf) - sizeof(*hdr)) == -1)
630fde46d6eSreyk 		goto done;
631fde46d6eSreyk 
632fde46d6eSreyk 	/* Add integrity checksum (HMAC) */
633fde46d6eSreyk 	if (ikev2_msg_integr(env, sa, buf) != 0) {
634fde46d6eSreyk 		log_debug("%s: integrity checksum failed", __func__);
635fde46d6eSreyk 		goto done;
636fde46d6eSreyk 	}
637fde46d6eSreyk 
638fde46d6eSreyk 	resp.msg_data = buf;
639fde46d6eSreyk 	resp.msg_sa = sa;
640d9c13a0aSmikeb 	resp.msg_fd = sa->sa_fd;
641fde46d6eSreyk 	TAILQ_INIT(&resp.msg_proposals);
642fde46d6eSreyk 
643fde46d6eSreyk 	(void)ikev2_pld_parse(env, hdr, &resp, 0);
644fde46d6eSreyk 
645d9c13a0aSmikeb 	ret = ikev2_msg_send(env, &resp);
646fde46d6eSreyk 
647fde46d6eSreyk  done:
648fde46d6eSreyk 	/* e is cleaned up by the calling function */
649fde46d6eSreyk 	*ep = e;
650763023d6Sreyk 	ikev2_msg_cleanup(env, &resp);
651fde46d6eSreyk 
652fde46d6eSreyk 	return (ret);
653fde46d6eSreyk }
654fde46d6eSreyk 
655fde46d6eSreyk struct ibuf *
656fde46d6eSreyk ikev2_msg_auth(struct iked *env, struct iked_sa *sa, int response)
657fde46d6eSreyk {
658fde46d6eSreyk 	struct ibuf		*authmsg = NULL, *nonce, *prfkey, *buf;
659fde46d6eSreyk 	u_int8_t		*ptr;
660fde46d6eSreyk 	struct iked_id		*id;
661fde46d6eSreyk 	size_t			 tmplen;
662fde46d6eSreyk 
663fde46d6eSreyk 	/*
664fde46d6eSreyk 	 * Create the payload to be signed/MAC'ed for AUTH
665fde46d6eSreyk 	 */
666fde46d6eSreyk 
667fde46d6eSreyk 	if (!response) {
668fde46d6eSreyk 		if ((nonce = sa->sa_rnonce) == NULL ||
669fde46d6eSreyk 		    (sa->sa_iid.id_type == 0) ||
670fde46d6eSreyk 		    (prfkey = sa->sa_key_iprf) == NULL ||
671fde46d6eSreyk 		    (buf = sa->sa_1stmsg) == NULL)
672fde46d6eSreyk 			return (NULL);
673fde46d6eSreyk 		id = &sa->sa_iid;
674fde46d6eSreyk 	} else {
675fde46d6eSreyk 		if ((nonce = sa->sa_inonce) == NULL ||
676fde46d6eSreyk 		    (sa->sa_rid.id_type == 0) ||
677fde46d6eSreyk 		    (prfkey = sa->sa_key_rprf) == NULL ||
678fde46d6eSreyk 		    (buf = sa->sa_2ndmsg) == NULL)
679fde46d6eSreyk 			return (NULL);
680fde46d6eSreyk 		id = &sa->sa_rid;
681fde46d6eSreyk 	}
682fde46d6eSreyk 
683fde46d6eSreyk 	if ((authmsg = ibuf_dup(buf)) == NULL)
684fde46d6eSreyk 		return (NULL);
685fde46d6eSreyk 	if (ibuf_cat(authmsg, nonce) != 0)
686fde46d6eSreyk 		goto fail;
687fde46d6eSreyk 
688fde46d6eSreyk 	if ((hash_setkey(sa->sa_prf, ibuf_data(prfkey),
689fde46d6eSreyk 	    ibuf_size(prfkey))) == NULL)
690fde46d6eSreyk 		goto fail;
691fde46d6eSreyk 
692fde46d6eSreyk 	if ((ptr = ibuf_advance(authmsg,
693fde46d6eSreyk 	    hash_length(sa->sa_prf))) == NULL)
694fde46d6eSreyk 		goto fail;
695fde46d6eSreyk 
696fde46d6eSreyk 	hash_init(sa->sa_prf);
697fde46d6eSreyk 	hash_update(sa->sa_prf, ibuf_data(id->id_buf), ibuf_size(id->id_buf));
698fde46d6eSreyk 	hash_final(sa->sa_prf, ptr, &tmplen);
699fde46d6eSreyk 
700fde46d6eSreyk 	if (tmplen != hash_length(sa->sa_prf))
701fde46d6eSreyk 		goto fail;
702fde46d6eSreyk 
703328746baSreyk 	log_debug("%s: %s auth data length %zu",
704fde46d6eSreyk 	    __func__, response ? "responder" : "initiator",
705fde46d6eSreyk 	    ibuf_size(authmsg));
706fde46d6eSreyk 	print_hex(ibuf_data(authmsg), 0, ibuf_size(authmsg));
707fde46d6eSreyk 
708fde46d6eSreyk 	return (authmsg);
709fde46d6eSreyk 
710fde46d6eSreyk  fail:
711fde46d6eSreyk 	ibuf_release(authmsg);
712fde46d6eSreyk 	return (NULL);
713fde46d6eSreyk }
714fde46d6eSreyk 
715fde46d6eSreyk int
716fde46d6eSreyk ikev2_msg_authverify(struct iked *env, struct iked_sa *sa,
717fde46d6eSreyk     struct iked_auth *auth, u_int8_t *buf, size_t len, struct ibuf *authmsg)
718fde46d6eSreyk {
719fde46d6eSreyk 	u_int8_t			*key, *psk = NULL;
720fde46d6eSreyk 	ssize_t				 keylen;
721fde46d6eSreyk 	struct iked_id			*id;
722fde46d6eSreyk 	struct iked_dsa			*dsa = NULL;
723fde46d6eSreyk 	int				 ret = -1;
724fde46d6eSreyk 	u_int8_t			 keytype;
725fde46d6eSreyk 
726fde46d6eSreyk 	if (sa->sa_hdr.sh_initiator)
727fde46d6eSreyk 		id = &sa->sa_rcert;
728fde46d6eSreyk 	else
729fde46d6eSreyk 		id = &sa->sa_icert;
730fde46d6eSreyk 
731fde46d6eSreyk 	if ((dsa = dsa_verify_new(auth->auth_method, sa->sa_prf)) == NULL) {
732fde46d6eSreyk 		log_debug("%s: invalid auth method", __func__);
733fde46d6eSreyk 		return (-1);
734fde46d6eSreyk 	}
735fde46d6eSreyk 
736fde46d6eSreyk 	switch (auth->auth_method) {
737fde46d6eSreyk 	case IKEV2_AUTH_SHARED_KEY_MIC:
738fde46d6eSreyk 		if (!auth->auth_length) {
739fde46d6eSreyk 			log_debug("%s: no pre-shared key found", __func__);
740fde46d6eSreyk 			goto done;
741fde46d6eSreyk 		}
742fde46d6eSreyk 		if ((keylen = ikev2_psk(sa, auth->auth_data,
743fde46d6eSreyk 		    auth->auth_length, &psk)) == -1) {
744fde46d6eSreyk 			log_debug("%s: failed to get PSK", __func__);
745fde46d6eSreyk 			goto done;
746fde46d6eSreyk 		}
747fde46d6eSreyk 		key = psk;
748fde46d6eSreyk 		keytype = 0;
749fde46d6eSreyk 		break;
750fde46d6eSreyk 	default:
751202133c5Sreyk 		if (!id->id_type || !ibuf_length(id->id_buf)) {
752fde46d6eSreyk 			log_debug("%s: no cert found", __func__);
753fde46d6eSreyk 			goto done;
754fde46d6eSreyk 		}
755fde46d6eSreyk 		key = ibuf_data(id->id_buf);
756fde46d6eSreyk 		keylen = ibuf_size(id->id_buf);
757fde46d6eSreyk 		keytype = id->id_type;
758fde46d6eSreyk 		break;
759fde46d6eSreyk 	}
760fde46d6eSreyk 
761328746baSreyk 	log_debug("%s: method %s keylen %zd type %s", __func__,
762fde46d6eSreyk 	    print_map(auth->auth_method, ikev2_auth_map), keylen,
763fde46d6eSreyk 	    print_map(id->id_type, ikev2_cert_map));
764fde46d6eSreyk 
765fde46d6eSreyk 	if (dsa_setkey(dsa, key, keylen, keytype) == NULL ||
766fde46d6eSreyk 	    dsa_init(dsa) != 0 ||
767fde46d6eSreyk 	    dsa_update(dsa, ibuf_data(authmsg), ibuf_size(authmsg))) {
768fde46d6eSreyk 		log_debug("%s: failed to compute digital signature", __func__);
769fde46d6eSreyk 		goto done;
770fde46d6eSreyk 	}
771fde46d6eSreyk 
772fde46d6eSreyk 	if ((ret = dsa_verify_final(dsa, buf, len)) == 0) {
773fde46d6eSreyk 		log_debug("%s: authentication successful", __func__);
774fde46d6eSreyk 		sa_state(env, sa, IKEV2_STATE_AUTH_SUCCESS);
7754a986ab9Smarkus 		sa_stateflags(sa, IKED_REQ_AUTHVALID);
776fde46d6eSreyk 
777fde46d6eSreyk 		if (!sa->sa_policy->pol_auth.auth_eap &&
778fde46d6eSreyk 		    auth->auth_method == IKEV2_AUTH_SHARED_KEY_MIC)
779fde46d6eSreyk 			sa_state(env, sa, IKEV2_STATE_VALID);
780fde46d6eSreyk 	} else {
781fde46d6eSreyk 		log_debug("%s: authentication failed", __func__);
782fde46d6eSreyk 		sa_state(env, sa, IKEV2_STATE_AUTH_REQUEST);
783fde46d6eSreyk 	}
784fde46d6eSreyk 
785fde46d6eSreyk  done:
786fde46d6eSreyk 	if (psk != NULL)
787fde46d6eSreyk 		free(psk);
788fde46d6eSreyk 	dsa_free(dsa);
789fde46d6eSreyk 
790fde46d6eSreyk 	return (ret);
791fde46d6eSreyk }
792fde46d6eSreyk 
793fde46d6eSreyk int
794fde46d6eSreyk ikev2_msg_authsign(struct iked *env, struct iked_sa *sa,
795fde46d6eSreyk     struct iked_auth *auth, struct ibuf *authmsg)
796fde46d6eSreyk {
797fde46d6eSreyk 	u_int8_t			*key, *psk = NULL;
798fde46d6eSreyk 	ssize_t				 keylen;
799fde46d6eSreyk 	struct iked_hash		*prf = sa->sa_prf;
800fde46d6eSreyk 	struct iked_id			*id;
801fde46d6eSreyk 	struct iked_dsa			*dsa = NULL;
802fde46d6eSreyk 	struct ibuf			*buf;
803fde46d6eSreyk 	int				 ret = -1;
804fde46d6eSreyk 	u_int8_t			 keytype;
805fde46d6eSreyk 
806fde46d6eSreyk 	if (sa->sa_hdr.sh_initiator)
807fde46d6eSreyk 		id = &sa->sa_icert;
808fde46d6eSreyk 	else
809fde46d6eSreyk 		id = &sa->sa_rcert;
810fde46d6eSreyk 
811fde46d6eSreyk 	if ((dsa = dsa_sign_new(auth->auth_method, prf)) == NULL) {
812fde46d6eSreyk 		log_debug("%s: invalid auth method", __func__);
813fde46d6eSreyk 		return (-1);
814fde46d6eSreyk 	}
815fde46d6eSreyk 
816fde46d6eSreyk 	switch (auth->auth_method) {
817fde46d6eSreyk 	case IKEV2_AUTH_SHARED_KEY_MIC:
818fde46d6eSreyk 		if (!auth->auth_length) {
819fde46d6eSreyk 			log_debug("%s: no pre-shared key found", __func__);
820fde46d6eSreyk 			goto done;
821fde46d6eSreyk 		}
822fde46d6eSreyk 		if ((keylen = ikev2_psk(sa, auth->auth_data,
823fde46d6eSreyk 		    auth->auth_length, &psk)) == -1) {
824fde46d6eSreyk 			log_debug("%s: failed to get PSK", __func__);
825fde46d6eSreyk 			goto done;
826fde46d6eSreyk 		}
827fde46d6eSreyk 		key = psk;
828fde46d6eSreyk 		keytype = 0;
829fde46d6eSreyk 		break;
830fde46d6eSreyk 	default:
831fde46d6eSreyk 		if (id == NULL) {
832fde46d6eSreyk 			log_debug("%s: no cert found", __func__);
833fde46d6eSreyk 			goto done;
834fde46d6eSreyk 		}
835fde46d6eSreyk 		key = ibuf_data(id->id_buf);
836fde46d6eSreyk 		keylen = ibuf_size(id->id_buf);
837fde46d6eSreyk 		keytype = id->id_type;
838fde46d6eSreyk 		break;
839fde46d6eSreyk 	}
840fde46d6eSreyk 
841fde46d6eSreyk 	if (dsa_setkey(dsa, key, keylen, keytype) == NULL ||
842fde46d6eSreyk 	    dsa_init(dsa) != 0 ||
843fde46d6eSreyk 	    dsa_update(dsa, ibuf_data(authmsg), ibuf_size(authmsg))) {
844fde46d6eSreyk 		log_debug("%s: failed to compute digital signature", __func__);
845fde46d6eSreyk 		goto done;
846fde46d6eSreyk 	}
847fde46d6eSreyk 
848fde46d6eSreyk 	ibuf_release(sa->sa_localauth.id_buf);
849fde46d6eSreyk 	sa->sa_localauth.id_buf = NULL;
850fde46d6eSreyk 
851fde46d6eSreyk 	if ((buf = ibuf_new(NULL, dsa_length(dsa))) == NULL) {
852fde46d6eSreyk 		log_debug("%s: failed to get auth buffer", __func__);
853fde46d6eSreyk 		goto done;
854fde46d6eSreyk 	}
855fde46d6eSreyk 
856fde46d6eSreyk 	if ((ret = dsa_sign_final(dsa,
857fde46d6eSreyk 	    ibuf_data(buf), ibuf_size(buf))) == -1) {
858fde46d6eSreyk 		log_debug("%s: failed to create auth signature", __func__);
859fde46d6eSreyk 		ibuf_release(buf);
860fde46d6eSreyk 		goto done;
861fde46d6eSreyk 	}
862fde46d6eSreyk 
863fde46d6eSreyk 	sa->sa_localauth.id_type = auth->auth_method;
864fde46d6eSreyk 	sa->sa_localauth.id_buf = buf;
865fde46d6eSreyk 
866fde46d6eSreyk 	ret = 0;
867fde46d6eSreyk  done:
868fde46d6eSreyk 	if (psk != NULL)
869fde46d6eSreyk 		free(psk);
870fde46d6eSreyk 	dsa_free(dsa);
871fde46d6eSreyk 
872fde46d6eSreyk 	return (ret);
873fde46d6eSreyk }
874ae494144Sreyk 
875ae494144Sreyk int
876ae494144Sreyk ikev2_msg_frompeer(struct iked_message *msg)
877ae494144Sreyk {
878ae494144Sreyk 	struct iked_sa		*sa = msg->msg_sa;
879ae494144Sreyk 	struct ike_header	*hdr;
880ae494144Sreyk 
88126d7dba1Sreyk 	msg = msg->msg_parent;
8821b0d4946Sreyk 
883ae494144Sreyk 	if (sa == NULL ||
884ae494144Sreyk 	    (hdr = ibuf_seek(msg->msg_data, 0, sizeof(*hdr))) == NULL)
885ae494144Sreyk 		return (0);
886ae494144Sreyk 
887ae494144Sreyk 	if (!sa->sa_hdr.sh_initiator &&
888ae494144Sreyk 	    (hdr->ike_flags & IKEV2_FLAG_INITIATOR))
889ae494144Sreyk 		return (1);
890ae494144Sreyk 	else if (sa->sa_hdr.sh_initiator &&
891ae494144Sreyk 	    (hdr->ike_flags & IKEV2_FLAG_INITIATOR) == 0)
892ae494144Sreyk 		return (1);
893ae494144Sreyk 
894ae494144Sreyk 	return (0);
895ae494144Sreyk }
896ae494144Sreyk 
897ae494144Sreyk struct iked_socket *
89812c9fd31Sreyk ikev2_msg_getsocket(struct iked *env, int af, int natt)
899ae494144Sreyk {
900ae494144Sreyk 	switch (af) {
901ae494144Sreyk 	case AF_INET:
90212c9fd31Sreyk 		return (env->sc_sock4[natt ? 1 : 0]);
903ae494144Sreyk 	case AF_INET6:
90412c9fd31Sreyk 		return (env->sc_sock6[natt ? 1 : 0]);
905ae494144Sreyk 	}
906ae494144Sreyk 
907ae494144Sreyk 	log_debug("%s: af socket %d not available", __func__, af);
908ae494144Sreyk 	return (NULL);
909ae494144Sreyk }
910c45fd413Smikeb 
911c45fd413Smikeb void
912c45fd413Smikeb ikev2_msg_prevail(struct iked *env, struct iked_msgqueue *queue,
913c45fd413Smikeb     struct iked_message *msg)
914c45fd413Smikeb {
91504ab0f1dSmikeb 	struct iked_message	*m, *mtmp;
916c45fd413Smikeb 
91704ab0f1dSmikeb 	TAILQ_FOREACH_SAFE(m, queue, msg_entry, mtmp) {
918c45fd413Smikeb 		if (m->msg_msgid < msg->msg_msgid)
919c45fd413Smikeb 			ikev2_msg_dispose(env, queue, m);
920c45fd413Smikeb 	}
921c45fd413Smikeb }
922c45fd413Smikeb 
923c45fd413Smikeb void
924c45fd413Smikeb ikev2_msg_dispose(struct iked *env, struct iked_msgqueue *queue,
925c45fd413Smikeb     struct iked_message *msg)
926c45fd413Smikeb {
927c45fd413Smikeb 	TAILQ_REMOVE(queue, msg, msg_entry);
928b3eeacebSmikeb 	timer_del(env, &msg->msg_timer);
929c45fd413Smikeb 	ikev2_msg_cleanup(env, msg);
930c45fd413Smikeb 	free(msg);
931c45fd413Smikeb }
932c45fd413Smikeb 
933c45fd413Smikeb void
934c45fd413Smikeb ikev2_msg_flushqueue(struct iked *env, struct iked_msgqueue *queue)
935c45fd413Smikeb {
936c45fd413Smikeb 	struct iked_message	*m = NULL;
937c45fd413Smikeb 
938c45fd413Smikeb 	while ((m = TAILQ_FIRST(queue)) != NULL)
939c45fd413Smikeb 		ikev2_msg_dispose(env, queue, m);
940c45fd413Smikeb }
941c45fd413Smikeb 
942c45fd413Smikeb struct iked_message *
94356d51042Smikeb ikev2_msg_lookup(struct iked *env, struct iked_msgqueue *queue,
94456d51042Smikeb     struct iked_message *msg, struct ike_header *hdr)
945c45fd413Smikeb {
946c45fd413Smikeb 	struct iked_message	*m = NULL;
947c45fd413Smikeb 
948c45fd413Smikeb 	TAILQ_FOREACH(m, queue, msg_entry) {
94956d51042Smikeb 		if (m->msg_msgid == msg->msg_msgid &&
95056d51042Smikeb 		    m->msg_exchange == hdr->ike_exchange)
951c45fd413Smikeb 			break;
952c45fd413Smikeb 	}
953c45fd413Smikeb 
95456d51042Smikeb 	return (m);
955c45fd413Smikeb }
956c45fd413Smikeb 
957c45fd413Smikeb int
958c45fd413Smikeb ikev2_msg_retransmit_response(struct iked *env, struct iked_sa *sa,
959c45fd413Smikeb     struct iked_message *msg)
960c45fd413Smikeb {
961c45fd413Smikeb 	if ((sendto(msg->msg_fd, ibuf_data(msg->msg_data),
962c45fd413Smikeb 	    ibuf_size(msg->msg_data), 0, (struct sockaddr *)&msg->msg_peer,
963c45fd413Smikeb 	    msg->msg_peerlen)) == -1) {
964c45fd413Smikeb 		log_warn("%s: sendto", __func__);
965c45fd413Smikeb 		return (-1);
966c45fd413Smikeb 	}
967c45fd413Smikeb 
968b3eeacebSmikeb 	timer_add(env, &msg->msg_timer, IKED_RESPONSE_TIMEOUT);
969c45fd413Smikeb 	return (0);
970c45fd413Smikeb }
971c45fd413Smikeb 
972c45fd413Smikeb void
973c45fd413Smikeb ikev2_msg_response_timeout(struct iked *env, void *arg)
974c45fd413Smikeb {
975c45fd413Smikeb 	struct iked_message	*msg = arg;
976c45fd413Smikeb 	struct iked_sa		*sa = msg->msg_sa;
977c45fd413Smikeb 
978c45fd413Smikeb 	ikev2_msg_dispose(env, &sa->sa_responses, msg);
979c45fd413Smikeb }
980c45fd413Smikeb 
981c45fd413Smikeb void
982c45fd413Smikeb ikev2_msg_retransmit_timeout(struct iked *env, void *arg)
983c45fd413Smikeb {
984c45fd413Smikeb 	struct iked_message	*msg = arg;
985c45fd413Smikeb 	struct iked_sa		*sa = msg->msg_sa;
986c45fd413Smikeb 
9878d81c769Smikeb 	if (msg->msg_tries < IKED_RETRANSMIT_TRIES) {
988c45fd413Smikeb 		if ((sendto(msg->msg_fd, ibuf_data(msg->msg_data),
989c45fd413Smikeb 		    ibuf_size(msg->msg_data), 0,
9908d81c769Smikeb 		    (struct sockaddr *)&msg->msg_peer,
9918d81c769Smikeb 		    msg->msg_peerlen)) == -1) {
992c45fd413Smikeb 			log_warn("%s: sendto", __func__);
993c45fd413Smikeb 			sa_free(env, sa);
994c45fd413Smikeb 			return;
995c45fd413Smikeb 		}
996c45fd413Smikeb 		/* Exponential timeout */
997b3eeacebSmikeb 		timer_add(env, &msg->msg_timer,
998c45fd413Smikeb 		    IKED_RETRANSMIT_TIMEOUT * (2 << (msg->msg_tries++)));
9998d81c769Smikeb 	} else {
10007f7372eaSmarkus 		log_debug("%s: retransmit limit reached for msgid %u",
10017f7372eaSmarkus 		    __func__, msg->msg_msgid);
1002c45fd413Smikeb 		sa_free(env, sa);
1003c45fd413Smikeb 	}
10048d81c769Smikeb }
1005