| File: | src/sbin/iked/ikev2_msg.c |
| Warning: | line 1257, column 3 Use of memory after it is freed |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* $OpenBSD: ikev2_msg.c,v 1.100 2023/08/04 19:06:25 claudio Exp $ */ | |||
| 2 | ||||
| 3 | /* | |||
| 4 | * Copyright (c) 2019 Tobias Heider <tobias.heider@stusta.de> | |||
| 5 | * Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org> | |||
| 6 | * | |||
| 7 | * Permission to use, copy, modify, and distribute this software for any | |||
| 8 | * purpose with or without fee is hereby granted, provided that the above | |||
| 9 | * copyright notice and this permission notice appear in all copies. | |||
| 10 | * | |||
| 11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
| 12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
| 13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
| 14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
| 15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
| 16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
| 17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
| 18 | */ | |||
| 19 | ||||
| 20 | #include <sys/types.h> | |||
| 21 | #include <sys/queue.h> | |||
| 22 | #include <sys/socket.h> | |||
| 23 | #include <sys/uio.h> | |||
| 24 | ||||
| 25 | #include <netinet/in.h> | |||
| 26 | #include <arpa/inet.h> | |||
| 27 | ||||
| 28 | #include <stdlib.h> | |||
| 29 | #include <stdio.h> | |||
| 30 | #include <syslog.h> | |||
| 31 | #include <unistd.h> | |||
| 32 | #include <string.h> | |||
| 33 | #include <signal.h> | |||
| 34 | #include <endian.h> | |||
| 35 | #include <errno(*__errno()).h> | |||
| 36 | #include <err.h> | |||
| 37 | #include <event.h> | |||
| 38 | ||||
| 39 | #include <openssl/sha.h> | |||
| 40 | #include <openssl/evp.h> | |||
| 41 | ||||
| 42 | #include "iked.h" | |||
| 43 | #include "ikev2.h" | |||
| 44 | #include "eap.h" | |||
| 45 | #include "dh.h" | |||
| 46 | ||||
| 47 | void ikev1_recv(struct iked *, struct iked_message *); | |||
| 48 | void ikev2_msg_response_timeout(struct iked *, void *); | |||
| 49 | void ikev2_msg_retransmit_timeout(struct iked *, void *); | |||
| 50 | int ikev2_check_frag_oversize(struct iked_sa *, struct ibuf *); | |||
| 51 | int ikev2_send_encrypted_fragments(struct iked *, struct iked_sa *, | |||
| 52 | struct ibuf *, uint8_t, uint8_t, int); | |||
| 53 | int ikev2_msg_encrypt_prepare(struct iked_sa *, struct ikev2_payload *, | |||
| 54 | struct ibuf*, struct ibuf *, struct ike_header *, uint8_t, int); | |||
| 55 | ||||
| 56 | void | |||
| 57 | ikev2_msg_cb(int fd, short event, void *arg) | |||
| 58 | { | |||
| 59 | struct iked_socket *sock = arg; | |||
| 60 | struct iked *env = sock->sock_env; | |||
| 61 | struct iked_message msg; | |||
| 62 | struct ike_header hdr; | |||
| 63 | uint32_t natt = 0x00000000; | |||
| 64 | uint8_t buf[IKED_MSGBUF_MAX8192]; | |||
| 65 | ssize_t len; | |||
| 66 | off_t off; | |||
| 67 | ||||
| 68 | bzero(&msg, sizeof(msg)); | |||
| 69 | bzero(buf, sizeof(buf)); | |||
| 70 | ||||
| 71 | msg.msg_peerlen = sizeof(msg.msg_peer); | |||
| 72 | msg.msg_locallen = sizeof(msg.msg_local); | |||
| 73 | msg.msg_parent = &msg; | |||
| 74 | memcpy(&msg.msg_local, &sock->sock_addr, sizeof(sock->sock_addr)); | |||
| 75 | ||||
| 76 | if ((len = recvfromto(fd, buf, sizeof(buf), 0, | |||
| 77 | (struct sockaddr *)&msg.msg_peer, &msg.msg_peerlen, | |||
| 78 | (struct sockaddr *)&msg.msg_local, &msg.msg_locallen)) < | |||
| 79 | (ssize_t)sizeof(natt)) | |||
| 80 | return; | |||
| 81 | ||||
| 82 | if (socket_getport((struct sockaddr *)&msg.msg_local) == | |||
| 83 | env->sc_nattportsc_static.st_nattport) { | |||
| 84 | if (memcmp(&natt, buf, sizeof(natt)) != 0) | |||
| 85 | return; | |||
| 86 | msg.msg_natt = 1; | |||
| 87 | off = sizeof(natt); | |||
| 88 | } else | |||
| 89 | off = 0; | |||
| 90 | ||||
| 91 | if ((size_t)(len - off) <= sizeof(hdr)) | |||
| 92 | return; | |||
| 93 | memcpy(&hdr, buf + off, sizeof(hdr)); | |||
| 94 | ||||
| 95 | if ((msg.msg_data = ibuf_new(buf + off, len - off)) == NULL((void *)0)) | |||
| 96 | return; | |||
| 97 | ||||
| 98 | TAILQ_INIT(&msg.msg_proposals)do { (&msg.msg_proposals)->tqh_first = ((void *)0); (& msg.msg_proposals)->tqh_last = &(&msg.msg_proposals )->tqh_first; } while (0); | |||
| 99 | SIMPLEQ_INIT(&msg.msg_certreqs)do { (&msg.msg_certreqs)->sqh_first = ((void *)0); (& msg.msg_certreqs)->sqh_last = &(&msg.msg_certreqs) ->sqh_first; } while (0); | |||
| 100 | msg.msg_fd = fd; | |||
| 101 | ||||
| 102 | if (hdr.ike_version == IKEV1_VERSION0x10) | |||
| 103 | ikev1_recv(env, &msg); | |||
| 104 | else | |||
| 105 | ikev2_recv(env, &msg); | |||
| 106 | ||||
| 107 | ikev2_msg_cleanup(env, &msg); | |||
| 108 | } | |||
| 109 | ||||
| 110 | void | |||
| 111 | ikev1_recv(struct iked *env, struct iked_message *msg) | |||
| 112 | { | |||
| 113 | struct ike_header *hdr; | |||
| 114 | ||||
| 115 | if (ibuf_size(msg->msg_data) <= sizeof(*hdr)) { | |||
| 116 | log_debug("%s: short message", __func__); | |||
| 117 | return; | |||
| 118 | } | |||
| 119 | ||||
| 120 | hdr = (struct ike_header *)ibuf_data(msg->msg_data); | |||
| 121 | ||||
| 122 | log_debug("%s: header ispi %s rspi %s" | |||
| 123 | " nextpayload %u version 0x%02x exchange %u flags 0x%02x" | |||
| 124 | " msgid %u length %u", __func__, | |||
| 125 | print_spi(betoh64(hdr->ike_ispi)(__uint64_t)(__builtin_constant_p(hdr->ike_ispi) ? (__uint64_t )((((__uint64_t)(hdr->ike_ispi) & 0xff) << 56) | ((__uint64_t)(hdr->ike_ispi) & 0xff00ULL) << 40 | ((__uint64_t)(hdr->ike_ispi) & 0xff0000ULL) << 24 | ((__uint64_t)(hdr->ike_ispi) & 0xff000000ULL) << 8 | ((__uint64_t)(hdr->ike_ispi) & 0xff00000000ULL) >> 8 | ((__uint64_t)(hdr->ike_ispi) & 0xff0000000000ULL) >> 24 | ((__uint64_t)(hdr->ike_ispi) & 0xff000000000000ULL ) >> 40 | ((__uint64_t)(hdr->ike_ispi) & 0xff00000000000000ULL ) >> 56) : __swap64md(hdr->ike_ispi)), 8), | |||
| 126 | print_spi(betoh64(hdr->ike_rspi)(__uint64_t)(__builtin_constant_p(hdr->ike_rspi) ? (__uint64_t )((((__uint64_t)(hdr->ike_rspi) & 0xff) << 56) | ((__uint64_t)(hdr->ike_rspi) & 0xff00ULL) << 40 | ((__uint64_t)(hdr->ike_rspi) & 0xff0000ULL) << 24 | ((__uint64_t)(hdr->ike_rspi) & 0xff000000ULL) << 8 | ((__uint64_t)(hdr->ike_rspi) & 0xff00000000ULL) >> 8 | ((__uint64_t)(hdr->ike_rspi) & 0xff0000000000ULL) >> 24 | ((__uint64_t)(hdr->ike_rspi) & 0xff000000000000ULL ) >> 40 | ((__uint64_t)(hdr->ike_rspi) & 0xff00000000000000ULL ) >> 56) : __swap64md(hdr->ike_rspi)), 8), | |||
| 127 | hdr->ike_nextpayload, | |||
| 128 | hdr->ike_version, | |||
| 129 | hdr->ike_exchange, | |||
| 130 | hdr->ike_flags, | |||
| 131 | betoh32(hdr->ike_msgid)(__uint32_t)(__builtin_constant_p(hdr->ike_msgid) ? (__uint32_t )(((__uint32_t)(hdr->ike_msgid) & 0xff) << 24 | ( (__uint32_t)(hdr->ike_msgid) & 0xff00) << 8 | (( __uint32_t)(hdr->ike_msgid) & 0xff0000) >> 8 | ( (__uint32_t)(hdr->ike_msgid) & 0xff000000) >> 24 ) : __swap32md(hdr->ike_msgid)), | |||
| 132 | betoh32(hdr->ike_length)(__uint32_t)(__builtin_constant_p(hdr->ike_length) ? (__uint32_t )(((__uint32_t)(hdr->ike_length) & 0xff) << 24 | ((__uint32_t)(hdr->ike_length) & 0xff00) << 8 | ((__uint32_t)(hdr->ike_length) & 0xff0000) >> 8 | ((__uint32_t)(hdr->ike_length) & 0xff000000) >> 24) : __swap32md(hdr->ike_length))); | |||
| 133 | ||||
| 134 | log_debug("%s: IKEv1 not supported", __func__); | |||
| 135 | } | |||
| 136 | ||||
| 137 | struct ibuf * | |||
| 138 | ikev2_msg_init(struct iked *env, struct iked_message *msg, | |||
| 139 | struct sockaddr_storage *peer, socklen_t peerlen, | |||
| 140 | struct sockaddr_storage *local, socklen_t locallen, int response) | |||
| 141 | { | |||
| 142 | bzero(msg, sizeof(*msg)); | |||
| 143 | memcpy(&msg->msg_peer, peer, peerlen); | |||
| 144 | msg->msg_peerlen = peerlen; | |||
| 145 | memcpy(&msg->msg_local, local, locallen); | |||
| 146 | msg->msg_locallen = locallen; | |||
| 147 | msg->msg_response = response ? 1 : 0; | |||
| 148 | msg->msg_fd = -1; | |||
| 149 | msg->msg_data = ibuf_static(); | |||
| 150 | msg->msg_e = 0; | |||
| 151 | msg->msg_parent = msg; /* has to be set */ | |||
| 152 | TAILQ_INIT(&msg->msg_proposals)do { (&msg->msg_proposals)->tqh_first = ((void *)0) ; (&msg->msg_proposals)->tqh_last = &(&msg-> msg_proposals)->tqh_first; } while (0); | |||
| 153 | ||||
| 154 | return (msg->msg_data); | |||
| 155 | } | |||
| 156 | ||||
| 157 | struct iked_message * | |||
| 158 | ikev2_msg_copy(struct iked *env, struct iked_message *msg) | |||
| 159 | { | |||
| 160 | struct iked_message *m = NULL((void *)0); | |||
| 161 | struct ibuf *buf; | |||
| 162 | size_t len; | |||
| 163 | void *ptr; | |||
| 164 | ||||
| 165 | if (ibuf_size(msg->msg_data) < msg->msg_offset) | |||
| 166 | return (NULL((void *)0)); | |||
| 167 | len = ibuf_size(msg->msg_data) - msg->msg_offset; | |||
| 168 | ||||
| 169 | if ((m = malloc(sizeof(*m))) == NULL((void *)0)) | |||
| 170 | return (NULL((void *)0)); | |||
| 171 | ||||
| 172 | if ((ptr = ibuf_seek(msg->msg_data, msg->msg_offset, len)) == NULL((void *)0) || | |||
| 173 | (buf = ikev2_msg_init(env, m, &msg->msg_peer, msg->msg_peerlen, | |||
| 174 | &msg->msg_local, msg->msg_locallen, msg->msg_response)) == NULL((void *)0) || | |||
| 175 | ibuf_add(buf, ptr, len)) { | |||
| 176 | free(m); | |||
| 177 | return (NULL((void *)0)); | |||
| 178 | } | |||
| 179 | ||||
| 180 | m->msg_fd = msg->msg_fd; | |||
| 181 | m->msg_msgid = msg->msg_msgid; | |||
| 182 | m->msg_offset = msg->msg_offset; | |||
| 183 | m->msg_sa = msg->msg_sa; | |||
| 184 | ||||
| 185 | return (m); | |||
| 186 | } | |||
| 187 | ||||
| 188 | void | |||
| 189 | ikev2_msg_cleanup(struct iked *env, struct iked_message *msg) | |||
| 190 | { | |||
| 191 | struct iked_certreq *cr; | |||
| 192 | int i; | |||
| 193 | ||||
| 194 | if (msg == msg->msg_parent) { | |||
| 195 | ibuf_free(msg->msg_nonce); | |||
| 196 | ibuf_free(msg->msg_ke); | |||
| 197 | ibuf_free(msg->msg_auth.id_buf); | |||
| 198 | ibuf_free(msg->msg_peerid.id_buf); | |||
| 199 | ibuf_free(msg->msg_localid.id_buf); | |||
| 200 | ibuf_free(msg->msg_cert.id_buf); | |||
| 201 | for (i = 0; i < IKED_SCERT_MAX3; i++) | |||
| 202 | ibuf_free(msg->msg_scert[i].id_buf); | |||
| 203 | ibuf_free(msg->msg_cookie); | |||
| 204 | ibuf_free(msg->msg_cookie2); | |||
| 205 | ibuf_free(msg->msg_del_buf); | |||
| 206 | free(msg->msg_eap.eam_user); | |||
| 207 | free(msg->msg_cp_addr); | |||
| 208 | free(msg->msg_cp_addr6); | |||
| 209 | free(msg->msg_cp_dns); | |||
| 210 | ||||
| 211 | msg->msg_nonce = NULL((void *)0); | |||
| 212 | msg->msg_ke = NULL((void *)0); | |||
| 213 | msg->msg_auth.id_buf = NULL((void *)0); | |||
| 214 | msg->msg_peerid.id_buf = NULL((void *)0); | |||
| 215 | msg->msg_localid.id_buf = NULL((void *)0); | |||
| 216 | msg->msg_cert.id_buf = NULL((void *)0); | |||
| 217 | for (i = 0; i < IKED_SCERT_MAX3; i++) | |||
| 218 | msg->msg_scert[i].id_buf = NULL((void *)0); | |||
| 219 | msg->msg_cookie = NULL((void *)0); | |||
| 220 | msg->msg_cookie2 = NULL((void *)0); | |||
| 221 | msg->msg_del_buf = NULL((void *)0); | |||
| 222 | msg->msg_eap.eam_user = NULL((void *)0); | |||
| 223 | msg->msg_cp_addr = NULL((void *)0); | |||
| 224 | msg->msg_cp_addr6 = NULL((void *)0); | |||
| 225 | msg->msg_cp_dns = NULL((void *)0); | |||
| 226 | ||||
| 227 | config_free_proposals(&msg->msg_proposals, 0); | |||
| 228 | while ((cr = SIMPLEQ_FIRST(&msg->msg_certreqs)((&msg->msg_certreqs)->sqh_first))) { | |||
| 229 | ibuf_free(cr->cr_data); | |||
| 230 | SIMPLEQ_REMOVE_HEAD(&msg->msg_certreqs, cr_entry)do { if (((&msg->msg_certreqs)->sqh_first = (&msg ->msg_certreqs)->sqh_first->cr_entry.sqe_next) == (( void *)0)) (&msg->msg_certreqs)->sqh_last = &(& msg->msg_certreqs)->sqh_first; } while (0); | |||
| 231 | free(cr); | |||
| 232 | } | |||
| 233 | } | |||
| 234 | ||||
| 235 | if (msg->msg_data != NULL((void *)0)) { | |||
| 236 | ibuf_free(msg->msg_data); | |||
| 237 | msg->msg_data = NULL((void *)0); | |||
| 238 | } | |||
| 239 | } | |||
| 240 | ||||
| 241 | int | |||
| 242 | ikev2_msg_valid_ike_sa(struct iked *env, struct ike_header *oldhdr, | |||
| 243 | struct iked_message *msg) | |||
| 244 | { | |||
| 245 | if (msg->msg_sa != NULL((void *)0) && msg->msg_policy != NULL((void *)0)) { | |||
| 246 | if (msg->msg_sa->sa_state == IKEV2_STATE_CLOSED11) | |||
| 247 | return (-1); | |||
| 248 | /* | |||
| 249 | * Only permit informational requests from initiator | |||
| 250 | * on closing SAs (for DELETE). | |||
| 251 | */ | |||
| 252 | if (msg->msg_sa->sa_state == IKEV2_STATE_CLOSING10) { | |||
| 253 | if (((oldhdr->ike_flags & | |||
| 254 | (IKEV2_FLAG_INITIATOR0x08|IKEV2_FLAG_RESPONSE0x20)) == | |||
| 255 | IKEV2_FLAG_INITIATOR0x08) && | |||
| 256 | (oldhdr->ike_exchange == | |||
| 257 | IKEV2_EXCHANGE_INFORMATIONAL37)) | |||
| 258 | return (0); | |||
| 259 | return (-1); | |||
| 260 | } | |||
| 261 | return (0); | |||
| 262 | } | |||
| 263 | ||||
| 264 | /* Always fail */ | |||
| 265 | return (-1); | |||
| 266 | } | |||
| 267 | ||||
| 268 | int | |||
| 269 | ikev2_msg_send(struct iked *env, struct iked_message *msg) | |||
| 270 | { | |||
| 271 | struct iked_sa *sa = msg->msg_sa; | |||
| 272 | struct ibuf *buf = msg->msg_data; | |||
| 273 | uint32_t natt = 0x00000000; | |||
| 274 | int isnatt = 0; | |||
| 275 | uint8_t exchange, flags; | |||
| 276 | struct ike_header *hdr; | |||
| 277 | struct iked_message *m; | |||
| 278 | ||||
| 279 | if (buf == NULL((void *)0) || (hdr = ibuf_seek(msg->msg_data, | |||
| 280 | msg->msg_offset, sizeof(*hdr))) == NULL((void *)0)) | |||
| 281 | return (-1); | |||
| 282 | ||||
| 283 | isnatt = (msg->msg_natt || (sa && sa->sa_natt)); | |||
| 284 | ||||
| 285 | exchange = hdr->ike_exchange; | |||
| 286 | flags = hdr->ike_flags; | |||
| 287 | logit(exchange == IKEV2_EXCHANGE_INFORMATIONAL37 ? LOG_DEBUG7 : LOG_INFO6, | |||
| 288 | "%ssend %s %s %u peer %s local %s, %zu bytes%s", | |||
| 289 | SPI_IH(hdr)ikev2_ikesa_info((__uint64_t)(__builtin_constant_p((hdr)-> ike_ispi) ? (__uint64_t)((((__uint64_t)((hdr)->ike_ispi) & 0xff) << 56) | ((__uint64_t)((hdr)->ike_ispi) & 0xff00ULL) << 40 | ((__uint64_t)((hdr)->ike_ispi) & 0xff0000ULL) << 24 | ((__uint64_t)((hdr)->ike_ispi) & 0xff000000ULL) << 8 | ((__uint64_t)((hdr)->ike_ispi ) & 0xff00000000ULL) >> 8 | ((__uint64_t)((hdr)-> ike_ispi) & 0xff0000000000ULL) >> 24 | ((__uint64_t )((hdr)->ike_ispi) & 0xff000000000000ULL) >> 40 | ((__uint64_t)((hdr)->ike_ispi) & 0xff00000000000000ULL ) >> 56) : __swap64md((hdr)->ike_ispi)), ((void *)0) ), | |||
| 290 | print_map(exchange, ikev2_exchange_map), | |||
| 291 | (flags & IKEV2_FLAG_RESPONSE0x20) ? "res" : "req", | |||
| 292 | betoh32(hdr->ike_msgid)(__uint32_t)(__builtin_constant_p(hdr->ike_msgid) ? (__uint32_t )(((__uint32_t)(hdr->ike_msgid) & 0xff) << 24 | ( (__uint32_t)(hdr->ike_msgid) & 0xff00) << 8 | (( __uint32_t)(hdr->ike_msgid) & 0xff0000) >> 8 | ( (__uint32_t)(hdr->ike_msgid) & 0xff000000) >> 24 ) : __swap32md(hdr->ike_msgid)), | |||
| 293 | print_addr(&msg->msg_peer), | |||
| 294 | print_addr(&msg->msg_local), | |||
| 295 | ibuf_size(buf), isnatt ? ", NAT-T" : ""); | |||
| 296 | ||||
| 297 | if (isnatt) { | |||
| 298 | struct ibuf *new; | |||
| 299 | if ((new = ibuf_new(&natt, sizeof(natt))) == NULL((void *)0)) { | |||
| 300 | log_debug("%s: failed to set NAT-T", __func__); | |||
| 301 | return (-1); | |||
| 302 | } | |||
| 303 | if (ibuf_add_buf(new, buf) == -1) { | |||
| 304 | ibuf_free(new); | |||
| 305 | log_debug("%s: failed to set NAT-T", __func__); | |||
| 306 | return (-1); | |||
| 307 | } | |||
| 308 | ibuf_free(buf); | |||
| 309 | buf = msg->msg_data = new; | |||
| 310 | } | |||
| 311 | ||||
| 312 | if (sendtofrom(msg->msg_fd, ibuf_data(buf), ibuf_size(buf), 0, | |||
| 313 | (struct sockaddr *)&msg->msg_peer, msg->msg_peerlen, | |||
| 314 | (struct sockaddr *)&msg->msg_local, msg->msg_locallen) == -1) { | |||
| 315 | log_warn("%s: sendtofrom", __func__); | |||
| 316 | if (sa != NULL((void *)0) && errno(*__errno()) == EADDRNOTAVAIL49) { | |||
| 317 | sa_state(env, sa, IKEV2_STATE_CLOSING10); | |||
| 318 | timer_del(env, &sa->sa_timer); | |||
| 319 | timer_set(env, &sa->sa_timer, | |||
| 320 | ikev2_ike_sa_timeout, sa); | |||
| 321 | timer_add(env, &sa->sa_timer, | |||
| 322 | IKED_IKE_SA_DELETE_TIMEOUT120); | |||
| 323 | } | |||
| 324 | ikestat_inc(env, ikes_msg_send_failures)do { env->sc_stats.ikes_msg_send_failures += (1); } while( 0); | |||
| 325 | } else | |||
| 326 | ikestat_inc(env, ikes_msg_sent)do { env->sc_stats.ikes_msg_sent += (1); } while(0); | |||
| 327 | ||||
| 328 | if (sa == NULL((void *)0)) | |||
| 329 | return (0); | |||
| 330 | ||||
| 331 | if ((m = ikev2_msg_copy(env, msg)) == NULL((void *)0)) { | |||
| 332 | log_debug("%s: failed to copy a message", __func__); | |||
| 333 | return (-1); | |||
| 334 | } | |||
| 335 | m->msg_exchange = exchange; | |||
| 336 | ||||
| 337 | if (flags & IKEV2_FLAG_RESPONSE0x20) { | |||
| 338 | if (ikev2_msg_enqueue(env, &sa->sa_responses, m, | |||
| 339 | IKED_RESPONSE_TIMEOUT120) != 0) { | |||
| 340 | ikev2_msg_cleanup(env, m); | |||
| 341 | free(m); | |||
| 342 | return (-1); | |||
| 343 | } | |||
| 344 | } else { | |||
| 345 | if (ikev2_msg_enqueue(env, &sa->sa_requests, m, | |||
| 346 | IKED_RETRANSMIT_TIMEOUT2) != 0) { | |||
| 347 | ikev2_msg_cleanup(env, m); | |||
| 348 | free(m); | |||
| 349 | return (-1); | |||
| 350 | } | |||
| 351 | } | |||
| 352 | ||||
| 353 | return (0); | |||
| 354 | } | |||
| 355 | ||||
| 356 | uint32_t | |||
| 357 | ikev2_msg_id(struct iked *env, struct iked_sa *sa) | |||
| 358 | { | |||
| 359 | uint32_t id = sa->sa_reqid; | |||
| 360 | ||||
| 361 | if (++sa->sa_reqid == UINT32_MAX0xffffffffU) { | |||
| 362 | /* XXX we should close and renegotiate the connection now */ | |||
| 363 | log_debug("%s: IKEv2 message sequence overflow", __func__); | |||
| 364 | } | |||
| 365 | return (id); | |||
| 366 | } | |||
| 367 | ||||
| 368 | /* | |||
| 369 | * Calculate the final sizes of the IKEv2 header and the encrypted payload | |||
| 370 | * header. This must be done before encryption to make sure the correct | |||
| 371 | * headers are authenticated. | |||
| 372 | */ | |||
| 373 | int | |||
| 374 | ikev2_msg_encrypt_prepare(struct iked_sa *sa, struct ikev2_payload *pld, | |||
| 375 | struct ibuf *buf, struct ibuf *e, struct ike_header *hdr, | |||
| 376 | uint8_t firstpayload, int fragmentation) | |||
| 377 | { | |||
| 378 | size_t len, ivlen, encrlen, integrlen, blocklen, pldlen, outlen; | |||
| 379 | ||||
| 380 | if (sa == NULL((void *)0) || | |||
| 381 | sa->sa_encr == NULL((void *)0) || | |||
| 382 | sa->sa_integr == NULL((void *)0)) { | |||
| 383 | log_debug("%s: invalid SA", __func__); | |||
| 384 | return (-1); | |||
| 385 | } | |||
| 386 | ||||
| 387 | len = ibuf_size(e); | |||
| 388 | blocklen = cipher_length(sa->sa_encr); | |||
| 389 | integrlen = hash_length(sa->sa_integr); | |||
| 390 | ivlen = cipher_ivlength(sa->sa_encr); | |||
| 391 | encrlen = roundup(len + 1, blocklen)((((len + 1)+((blocklen)-1))/(blocklen))*(blocklen)); | |||
| 392 | outlen = cipher_outlength(sa->sa_encr, encrlen); | |||
| 393 | pldlen = ivlen + outlen + integrlen; | |||
| 394 | ||||
| 395 | if (ikev2_next_payload(pld, | |||
| 396 | pldlen + (fragmentation ? sizeof(struct ikev2_frag_payload) : 0), | |||
| 397 | firstpayload) == -1) | |||
| 398 | return (-1); | |||
| 399 | if (ikev2_set_header(hdr, ibuf_size(buf) + pldlen - sizeof(*hdr)) == -1) | |||
| 400 | return (-1); | |||
| 401 | ||||
| 402 | return (0); | |||
| 403 | } | |||
| 404 | ||||
| 405 | struct ibuf * | |||
| 406 | ikev2_msg_encrypt(struct iked *env, struct iked_sa *sa, struct ibuf *src, | |||
| 407 | struct ibuf *aad) | |||
| 408 | { | |||
| 409 | size_t len, encrlen, integrlen, blocklen, | |||
| 410 | outlen; | |||
| 411 | uint8_t *buf, pad = 0, *ptr; | |||
| 412 | struct ibuf *encr, *dst = NULL((void *)0), *out = NULL((void *)0); | |||
| 413 | ||||
| 414 | buf = ibuf_data(src); | |||
| 415 | len = ibuf_size(src); | |||
| 416 | ||||
| 417 | log_debug("%s: decrypted length %zu", __func__, len); | |||
| 418 | print_hex(buf, 0, len); | |||
| 419 | ||||
| 420 | if (sa == NULL((void *)0) || | |||
| 421 | sa->sa_encr == NULL((void *)0) || | |||
| 422 | sa->sa_integr == NULL((void *)0)) { | |||
| 423 | log_debug("%s: invalid SA", __func__); | |||
| 424 | goto done; | |||
| 425 | } | |||
| 426 | ||||
| 427 | if (sa->sa_hdr.sh_initiator) | |||
| 428 | encr = sa->sa_key_iencr; | |||
| 429 | else | |||
| 430 | encr = sa->sa_key_rencr; | |||
| 431 | ||||
| 432 | blocklen = cipher_length(sa->sa_encr); | |||
| 433 | integrlen = hash_length(sa->sa_integr); | |||
| 434 | encrlen = roundup(len + sizeof(pad), blocklen)((((len + sizeof(pad))+((blocklen)-1))/(blocklen))*(blocklen) ); | |||
| 435 | pad = encrlen - (len + sizeof(pad)); | |||
| 436 | ||||
| 437 | /* | |||
| 438 | * Pad the payload and encrypt it | |||
| 439 | */ | |||
| 440 | if (pad) { | |||
| 441 | if ((ptr = ibuf_reserve(src, pad)) == NULL((void *)0)) | |||
| 442 | goto done; | |||
| 443 | arc4random_buf(ptr, pad); | |||
| 444 | } | |||
| 445 | if (ibuf_add(src, &pad, sizeof(pad)) != 0) | |||
| 446 | goto done; | |||
| 447 | ||||
| 448 | log_debug("%s: padded length %zu", __func__, ibuf_size(src)); | |||
| 449 | print_hexbuf(src); | |||
| 450 | ||||
| 451 | cipher_setkey(sa->sa_encr, ibuf_data(encr), ibuf_size(encr)); | |||
| 452 | cipher_setiv(sa->sa_encr, NULL((void *)0), 0); /* XXX ivlen */ | |||
| 453 | if (cipher_init_encrypt(sa->sa_encr) == -1) { | |||
| 454 | log_info("%s: error initiating cipher.", __func__); | |||
| 455 | goto done; | |||
| 456 | } | |||
| 457 | ||||
| 458 | if ((dst = ibuf_dup(sa->sa_encr->encr_iv)) == NULL((void *)0)) | |||
| 459 | goto done; | |||
| 460 | ||||
| 461 | if ((out = ibuf_new(NULL((void *)0), | |||
| 462 | cipher_outlength(sa->sa_encr, encrlen))) == NULL((void *)0)) | |||
| 463 | goto done; | |||
| 464 | ||||
| 465 | outlen = ibuf_size(out); | |||
| 466 | ||||
| 467 | /* Add AAD for AEAD ciphers */ | |||
| 468 | if (sa->sa_integr->hash_isaead) | |||
| 469 | cipher_aad(sa->sa_encr, ibuf_data(aad), ibuf_size(aad), | |||
| 470 | &outlen); | |||
| 471 | ||||
| 472 | if (cipher_update(sa->sa_encr, ibuf_data(src), encrlen, | |||
| 473 | ibuf_data(out), &outlen) == -1) { | |||
| 474 | log_info("%s: error updating cipher.", __func__); | |||
| 475 | goto done; | |||
| 476 | } | |||
| 477 | ||||
| 478 | if (cipher_final(sa->sa_encr) == -1) { | |||
| 479 | log_info("%s: encryption failed.", __func__); | |||
| 480 | goto done; | |||
| 481 | } | |||
| 482 | ||||
| 483 | if (outlen && ibuf_add(dst, ibuf_data(out), outlen) != 0) | |||
| 484 | goto done; | |||
| 485 | ||||
| 486 | if ((ptr = ibuf_reserve(dst, integrlen)) == NULL((void *)0)) | |||
| 487 | goto done; | |||
| 488 | explicit_bzero(ptr, integrlen); | |||
| 489 | ||||
| 490 | log_debug("%s: length %zu, padding %d, output length %zu", | |||
| 491 | __func__, len + sizeof(pad), pad, ibuf_size(dst)); | |||
| 492 | print_hexbuf(dst); | |||
| 493 | ||||
| 494 | ibuf_free(src); | |||
| 495 | ibuf_free(out); | |||
| 496 | return (dst); | |||
| 497 | done: | |||
| 498 | ibuf_free(src); | |||
| 499 | ibuf_free(out); | |||
| 500 | ibuf_free(dst); | |||
| 501 | return (NULL((void *)0)); | |||
| 502 | } | |||
| 503 | ||||
| 504 | int | |||
| 505 | ikev2_msg_integr(struct iked *env, struct iked_sa *sa, struct ibuf *src) | |||
| 506 | { | |||
| 507 | int ret = -1; | |||
| 508 | size_t integrlen, tmplen; | |||
| 509 | struct ibuf *integr, *tmp = NULL((void *)0); | |||
| 510 | uint8_t *ptr; | |||
| 511 | ||||
| 512 | log_debug("%s: message length %zu", __func__, ibuf_size(src)); | |||
| 513 | print_hexbuf(src); | |||
| 514 | ||||
| 515 | if (sa == NULL((void *)0) || | |||
| 516 | sa->sa_encr == NULL((void *)0) || | |||
| 517 | sa->sa_integr == NULL((void *)0)) { | |||
| 518 | log_debug("%s: invalid SA", __func__); | |||
| 519 | return (-1); | |||
| 520 | } | |||
| 521 | ||||
| 522 | integrlen = hash_length(sa->sa_integr); | |||
| 523 | log_debug("%s: integrity checksum length %zu", __func__, | |||
| 524 | integrlen); | |||
| 525 | ||||
| 526 | /* | |||
| 527 | * Validate packet checksum | |||
| 528 | */ | |||
| 529 | if ((tmp = ibuf_new(NULL((void *)0), hash_keylength(sa->sa_integr))) == NULL((void *)0)) | |||
| 530 | goto done; | |||
| 531 | ||||
| 532 | if (!sa->sa_integr->hash_isaead) { | |||
| 533 | if (sa->sa_hdr.sh_initiator) | |||
| 534 | integr = sa->sa_key_iauth; | |||
| 535 | else | |||
| 536 | integr = sa->sa_key_rauth; | |||
| 537 | ||||
| 538 | hash_setkey(sa->sa_integr, ibuf_data(integr), | |||
| 539 | ibuf_size(integr)); | |||
| 540 | hash_init(sa->sa_integr); | |||
| 541 | hash_update(sa->sa_integr, ibuf_data(src), | |||
| 542 | ibuf_size(src) - integrlen); | |||
| 543 | hash_final(sa->sa_integr, ibuf_data(tmp), &tmplen); | |||
| 544 | ||||
| 545 | if (tmplen != integrlen) { | |||
| 546 | log_debug("%s: hash failure", __func__); | |||
| 547 | goto done; | |||
| 548 | } | |||
| 549 | } else { | |||
| 550 | /* Append AEAD tag */ | |||
| 551 | if (cipher_gettag(sa->sa_encr, ibuf_data(tmp), ibuf_size(tmp))) | |||
| 552 | goto done; | |||
| 553 | } | |||
| 554 | ||||
| 555 | if ((ptr = ibuf_seek(src, | |||
| 556 | ibuf_size(src) - integrlen, integrlen)) == NULL((void *)0)) | |||
| 557 | goto done; | |||
| 558 | memcpy(ptr, ibuf_data(tmp), integrlen); | |||
| 559 | ||||
| 560 | print_hexbuf(tmp); | |||
| 561 | ||||
| 562 | ret = 0; | |||
| 563 | done: | |||
| 564 | ibuf_free(tmp); | |||
| 565 | ||||
| 566 | return (ret); | |||
| 567 | } | |||
| 568 | ||||
| 569 | struct ibuf * | |||
| 570 | ikev2_msg_decrypt(struct iked *env, struct iked_sa *sa, | |||
| 571 | struct ibuf *msg, struct ibuf *src) | |||
| 572 | { | |||
| 573 | ssize_t ivlen, encrlen, integrlen, blocklen, | |||
| 574 | outlen, tmplen; | |||
| 575 | uint8_t pad = 0, *ptr, *integrdata; | |||
| 576 | struct ibuf *integr, *encr, *tmp = NULL((void *)0), *out = NULL((void *)0); | |||
| 577 | off_t ivoff, encroff, integroff; | |||
| 578 | ||||
| 579 | if (sa == NULL((void *)0) || | |||
| 580 | sa->sa_encr == NULL((void *)0) || | |||
| 581 | sa->sa_integr == NULL((void *)0)) { | |||
| 582 | log_debug("%s: invalid SA", __func__); | |||
| 583 | print_hexbuf(src); | |||
| 584 | goto done; | |||
| 585 | } | |||
| 586 | ||||
| 587 | if (!sa->sa_hdr.sh_initiator) { | |||
| 588 | encr = sa->sa_key_iencr; | |||
| 589 | integr = sa->sa_key_iauth; | |||
| 590 | } else { | |||
| 591 | encr = sa->sa_key_rencr; | |||
| 592 | integr = sa->sa_key_rauth; | |||
| 593 | } | |||
| 594 | ||||
| 595 | blocklen = cipher_length(sa->sa_encr); | |||
| 596 | ivlen = cipher_ivlength(sa->sa_encr); | |||
| 597 | ivoff = 0; | |||
| 598 | integrlen = hash_length(sa->sa_integr); | |||
| 599 | integroff = ibuf_size(src) - integrlen; | |||
| 600 | encroff = ivlen; | |||
| 601 | encrlen = ibuf_size(src) - integrlen - ivlen; | |||
| 602 | ||||
| 603 | if (encrlen < 0 || integroff < 0) { | |||
| 604 | log_debug("%s: invalid integrity value", __func__); | |||
| 605 | goto done; | |||
| 606 | } | |||
| 607 | ||||
| 608 | log_debug("%s: IV length %zd", __func__, ivlen); | |||
| 609 | print_hex(ibuf_data(src), 0, ivlen); | |||
| 610 | log_debug("%s: encrypted payload length %zd", __func__, encrlen); | |||
| 611 | print_hex(ibuf_data(src), encroff, encrlen); | |||
| 612 | log_debug("%s: integrity checksum length %zd", __func__, integrlen); | |||
| 613 | print_hex(ibuf_data(src), integroff, integrlen); | |||
| 614 | ||||
| 615 | /* | |||
| 616 | * Validate packet checksum | |||
| 617 | */ | |||
| 618 | if (!sa->sa_integr->hash_isaead) { | |||
| 619 | if ((tmp = ibuf_new(NULL((void *)0), hash_keylength(sa->sa_integr))) == NULL((void *)0)) | |||
| 620 | goto done; | |||
| 621 | ||||
| 622 | hash_setkey(sa->sa_integr, ibuf_data(integr), | |||
| 623 | ibuf_size(integr)); | |||
| 624 | hash_init(sa->sa_integr); | |||
| 625 | hash_update(sa->sa_integr, ibuf_data(msg), | |||
| 626 | ibuf_size(msg) - integrlen); | |||
| 627 | hash_final(sa->sa_integr, ibuf_data(tmp), &tmplen); | |||
| 628 | ||||
| 629 | integrdata = ibuf_seek(src, integroff, integrlen); | |||
| 630 | if (integrdata == NULL((void *)0)) | |||
| 631 | goto done; | |||
| 632 | if (memcmp(ibuf_data(tmp), integrdata, integrlen) != 0) { | |||
| 633 | log_debug("%s: integrity check failed", __func__); | |||
| 634 | goto done; | |||
| 635 | } | |||
| 636 | ||||
| 637 | log_debug("%s: integrity check succeeded", __func__); | |||
| 638 | print_hex(ibuf_data(tmp), 0, tmplen); | |||
| 639 | ||||
| 640 | ibuf_free(tmp); | |||
| 641 | tmp = NULL((void *)0); | |||
| 642 | } | |||
| 643 | ||||
| 644 | /* | |||
| 645 | * Decrypt the payload and strip any padding | |||
| 646 | */ | |||
| 647 | if ((encrlen % blocklen) != 0) { | |||
| 648 | log_debug("%s: unaligned encrypted payload", __func__); | |||
| 649 | goto done; | |||
| 650 | } | |||
| 651 | ||||
| 652 | cipher_setkey(sa->sa_encr, ibuf_data(encr), ibuf_size(encr)); | |||
| 653 | cipher_setiv(sa->sa_encr, ibuf_seek(src, ivoff, ivlen), ivlen); | |||
| 654 | if (cipher_init_decrypt(sa->sa_encr) == -1) { | |||
| 655 | log_info("%s: error initiating cipher.", __func__); | |||
| 656 | goto done; | |||
| 657 | } | |||
| 658 | ||||
| 659 | /* Set AEAD tag */ | |||
| 660 | if (sa->sa_integr->hash_isaead) { | |||
| 661 | integrdata = ibuf_seek(src, integroff, integrlen); | |||
| 662 | if (integrdata == NULL((void *)0)) | |||
| 663 | goto done; | |||
| 664 | if (cipher_settag(sa->sa_encr, integrdata, integrlen)) { | |||
| 665 | log_info("%s: failed to set tag.", __func__); | |||
| 666 | goto done; | |||
| 667 | } | |||
| 668 | } | |||
| 669 | ||||
| 670 | if ((out = ibuf_new(NULL((void *)0), cipher_outlength(sa->sa_encr, | |||
| 671 | encrlen))) == NULL((void *)0)) | |||
| 672 | goto done; | |||
| 673 | ||||
| 674 | /* | |||
| 675 | * Add additional authenticated data for AEAD ciphers | |||
| 676 | */ | |||
| 677 | if (sa->sa_integr->hash_isaead) { | |||
| 678 | log_debug("%s: AAD length %zu", __func__, | |||
| 679 | ibuf_size(msg) - ibuf_size(src)); | |||
| 680 | print_hex(ibuf_data(msg), 0, ibuf_size(msg) - ibuf_size(src)); | |||
| 681 | cipher_aad(sa->sa_encr, ibuf_data(msg), | |||
| 682 | ibuf_size(msg) - ibuf_size(src), &outlen); | |||
| 683 | } | |||
| 684 | ||||
| 685 | if ((outlen = ibuf_size(out)) != 0) { | |||
| 686 | if (cipher_update(sa->sa_encr, ibuf_seek(src, encroff, encrlen), | |||
| 687 | encrlen, ibuf_data(out), &outlen) == -1) { | |||
| 688 | log_info("%s: error updating cipher.", __func__); | |||
| 689 | goto done; | |||
| 690 | } | |||
| 691 | ||||
| 692 | ptr = ibuf_seek(out, outlen - 1, 1); | |||
| 693 | pad = *ptr; | |||
| 694 | } | |||
| 695 | ||||
| 696 | if (cipher_final(sa->sa_encr) == -1) { | |||
| 697 | log_info("%s: decryption failed.", __func__); | |||
| 698 | goto done; | |||
| 699 | } | |||
| 700 | ||||
| 701 | log_debug("%s: decrypted payload length %zd/%zd padding %d", | |||
| 702 | __func__, outlen, encrlen, pad); | |||
| 703 | print_hexbuf(out); | |||
| 704 | ||||
| 705 | /* Strip padding and padding length */ | |||
| 706 | if (ibuf_setsize(out, outlen - pad - 1) != 0) | |||
| 707 | goto done; | |||
| 708 | ||||
| 709 | ibuf_free(src); | |||
| 710 | return (out); | |||
| 711 | done: | |||
| 712 | ibuf_free(tmp); | |||
| 713 | ibuf_free(out); | |||
| 714 | ibuf_free(src); | |||
| 715 | return (NULL((void *)0)); | |||
| 716 | } | |||
| 717 | ||||
| 718 | int | |||
| 719 | ikev2_check_frag_oversize(struct iked_sa *sa, struct ibuf *buf) { | |||
| 720 | size_t len = ibuf_length(buf); | |||
| 721 | sa_family_t sa_fam; | |||
| 722 | size_t max; | |||
| 723 | size_t ivlen, integrlen, blocklen; | |||
| 724 | ||||
| 725 | if (sa == NULL((void *)0) || | |||
| 726 | sa->sa_encr == NULL((void *)0) || | |||
| 727 | sa->sa_integr == NULL((void *)0)) { | |||
| 728 | log_debug("%s: invalid SA", __func__); | |||
| 729 | return (-1); | |||
| 730 | } | |||
| 731 | ||||
| 732 | sa_fam = ((struct sockaddr *)&sa->sa_local.addr)->sa_family; | |||
| 733 | ||||
| 734 | max = sa_fam == AF_INET2 ? IKEV2_MAXLEN_IPV4_FRAG(576 - (20 + 8 + 28)) | |||
| 735 | : IKEV2_MAXLEN_IPV6_FRAG(1280 - (40 + 8 + 28)); | |||
| 736 | ||||
| 737 | blocklen = cipher_length(sa->sa_encr); | |||
| 738 | ivlen = cipher_ivlength(sa->sa_encr); | |||
| 739 | integrlen = hash_length(sa->sa_integr); | |||
| 740 | ||||
| 741 | /* Estimated maximum packet size (with 0 < padding < blocklen) */ | |||
| 742 | return ((len + ivlen + blocklen + integrlen) >= max) && sa->sa_frag; | |||
| 743 | } | |||
| 744 | ||||
| 745 | int | |||
| 746 | ikev2_msg_send_encrypt(struct iked *env, struct iked_sa *sa, struct ibuf **ep, | |||
| 747 | uint8_t exchange, uint8_t firstpayload, int response) | |||
| 748 | { | |||
| 749 | struct iked_message resp; | |||
| 750 | struct ike_header *hdr; | |||
| 751 | struct ikev2_payload *pld; | |||
| 752 | struct ibuf *buf, *e = *ep; | |||
| 753 | int ret = -1; | |||
| 754 | ||||
| 755 | /* Check if msg needs to be fragmented */ | |||
| 756 | if (ikev2_check_frag_oversize(sa, e)) { | |||
| 757 | return ikev2_send_encrypted_fragments(env, sa, e, exchange, | |||
| 758 | firstpayload, response); | |||
| 759 | } | |||
| 760 | ||||
| 761 | if ((buf = ikev2_msg_init(env, &resp, &sa->sa_peer.addr, | |||
| 762 | sa->sa_peer.addr.ss_len, &sa->sa_local.addr, | |||
| 763 | sa->sa_local.addr.ss_len, response)) == NULL((void *)0)) | |||
| 764 | goto done; | |||
| 765 | ||||
| 766 | resp.msg_msgid = response ? sa->sa_msgid_current : ikev2_msg_id(env, sa); | |||
| 767 | ||||
| 768 | /* IKE header */ | |||
| 769 | if ((hdr = ikev2_add_header(buf, sa, resp.msg_msgid, IKEV2_PAYLOAD_SK46, | |||
| 770 | exchange, response ? IKEV2_FLAG_RESPONSE0x20 : 0)) == NULL((void *)0)) | |||
| 771 | goto done; | |||
| 772 | ||||
| 773 | if ((pld = ikev2_add_payload(buf)) == NULL((void *)0)) | |||
| 774 | goto done; | |||
| 775 | ||||
| 776 | if (ikev2_msg_encrypt_prepare(sa, pld, buf, e, hdr, firstpayload, 0) == -1) | |||
| 777 | goto done; | |||
| 778 | ||||
| 779 | /* Encrypt message and add as an E payload */ | |||
| 780 | if ((e = ikev2_msg_encrypt(env, sa, e, buf)) == NULL((void *)0)) { | |||
| 781 | log_debug("%s: encryption failed", __func__); | |||
| 782 | goto done; | |||
| 783 | } | |||
| 784 | if (ibuf_add_buf(buf, e) != 0) | |||
| 785 | goto done; | |||
| 786 | ||||
| 787 | /* Add integrity checksum (HMAC) */ | |||
| 788 | if (ikev2_msg_integr(env, sa, buf) != 0) { | |||
| 789 | log_debug("%s: integrity checksum failed", __func__); | |||
| 790 | goto done; | |||
| 791 | } | |||
| 792 | ||||
| 793 | resp.msg_data = buf; | |||
| 794 | resp.msg_sa = sa; | |||
| 795 | resp.msg_fd = sa->sa_fd; | |||
| 796 | TAILQ_INIT(&resp.msg_proposals)do { (&resp.msg_proposals)->tqh_first = ((void *)0); ( &resp.msg_proposals)->tqh_last = &(&resp.msg_proposals )->tqh_first; } while (0); | |||
| 797 | ||||
| 798 | (void)ikev2_pld_parse(env, hdr, &resp, 0); | |||
| 799 | ||||
| 800 | ret = ikev2_msg_send(env, &resp); | |||
| 801 | ||||
| 802 | done: | |||
| 803 | /* e is cleaned up by the calling function */ | |||
| 804 | *ep = e; | |||
| 805 | ikev2_msg_cleanup(env, &resp); | |||
| 806 | ||||
| 807 | return (ret); | |||
| 808 | } | |||
| 809 | ||||
| 810 | int | |||
| 811 | ikev2_send_encrypted_fragments(struct iked *env, struct iked_sa *sa, | |||
| 812 | struct ibuf *in, uint8_t exchange, uint8_t firstpayload, int response) { | |||
| 813 | struct iked_message resp; | |||
| 814 | struct ibuf *buf, *e = NULL((void *)0); | |||
| 815 | struct ike_header *hdr; | |||
| 816 | struct ikev2_payload *pld; | |||
| 817 | struct ikev2_frag_payload *frag; | |||
| 818 | sa_family_t sa_fam; | |||
| 819 | size_t ivlen, integrlen, blocklen; | |||
| 820 | size_t max_len, left, offset=0; | |||
| 821 | size_t frag_num = 1, frag_total; | |||
| 822 | uint8_t *data; | |||
| 823 | uint32_t msgid; | |||
| 824 | int ret = -1; | |||
| 825 | ||||
| 826 | if (sa == NULL((void *)0) || | |||
| 827 | sa->sa_encr == NULL((void *)0) || | |||
| 828 | sa->sa_integr == NULL((void *)0)) { | |||
| 829 | log_debug("%s: invalid SA", __func__); | |||
| 830 | ikestat_inc(env, ikes_frag_send_failures)do { env->sc_stats.ikes_frag_send_failures += (1); } while (0); | |||
| 831 | return ret; | |||
| 832 | } | |||
| 833 | ||||
| 834 | sa_fam = ((struct sockaddr *)&sa->sa_local.addr)->sa_family; | |||
| 835 | ||||
| 836 | left = ibuf_length(in); | |||
| 837 | ||||
| 838 | /* Calculate max allowed size of a fragments payload */ | |||
| 839 | blocklen = cipher_length(sa->sa_encr); | |||
| 840 | ivlen = cipher_ivlength(sa->sa_encr); | |||
| 841 | integrlen = hash_length(sa->sa_integr); | |||
| 842 | max_len = (sa_fam == AF_INET2 ? IKEV2_MAXLEN_IPV4_FRAG(576 - (20 + 8 + 28)) | |||
| 843 | : IKEV2_MAXLEN_IPV6_FRAG(1280 - (40 + 8 + 28))) | |||
| 844 | - ivlen - blocklen - integrlen; | |||
| 845 | ||||
| 846 | /* Total number of fragments to send */ | |||
| 847 | frag_total = (left / max_len) + 1; | |||
| 848 | ||||
| 849 | msgid = response ? sa->sa_msgid_current : ikev2_msg_id(env, sa); | |||
| 850 | ||||
| 851 | while (frag_num <= frag_total) { | |||
| 852 | if ((buf = ikev2_msg_init(env, &resp, &sa->sa_peer.addr, | |||
| 853 | sa->sa_peer.addr.ss_len, &sa->sa_local.addr, | |||
| 854 | sa->sa_local.addr.ss_len, response)) == NULL((void *)0)) | |||
| 855 | goto done; | |||
| 856 | ||||
| 857 | resp.msg_msgid = msgid; | |||
| 858 | ||||
| 859 | /* IKE header */ | |||
| 860 | if ((hdr = ikev2_add_header(buf, sa, resp.msg_msgid, | |||
| 861 | IKEV2_PAYLOAD_SKF53, exchange, response ? IKEV2_FLAG_RESPONSE0x20 | |||
| 862 | : 0)) == NULL((void *)0)) | |||
| 863 | goto done; | |||
| 864 | ||||
| 865 | /* Payload header */ | |||
| 866 | if ((pld = ikev2_add_payload(buf)) == NULL((void *)0)) | |||
| 867 | goto done; | |||
| 868 | ||||
| 869 | /* Fragment header */ | |||
| 870 | if ((frag = ibuf_reserve(buf, sizeof(*frag))) == NULL((void *)0)) { | |||
| 871 | log_debug("%s: failed to add SKF fragment header", | |||
| 872 | __func__); | |||
| 873 | goto done; | |||
| 874 | } | |||
| 875 | frag->frag_num = htobe16(frag_num)(__uint16_t)(__builtin_constant_p(frag_num) ? (__uint16_t)((( __uint16_t)(frag_num) & 0xffU) << 8 | ((__uint16_t) (frag_num) & 0xff00U) >> 8) : __swap16md(frag_num)); | |||
| 876 | frag->frag_total = htobe16(frag_total)(__uint16_t)(__builtin_constant_p(frag_total) ? (__uint16_t)( ((__uint16_t)(frag_total) & 0xffU) << 8 | ((__uint16_t )(frag_total) & 0xff00U) >> 8) : __swap16md(frag_total )); | |||
| 877 | ||||
| 878 | /* Encrypt message and add as an E payload */ | |||
| 879 | data = ibuf_seek(in, offset, 0); | |||
| 880 | if ((e = ibuf_new(data, MINIMUM(left, max_len)(((left)<(max_len))?(left):(max_len)))) == NULL((void *)0)) { | |||
| 881 | goto done; | |||
| 882 | } | |||
| 883 | ||||
| 884 | if (ikev2_msg_encrypt_prepare(sa, pld, buf, e, hdr, | |||
| 885 | firstpayload, 1) == -1) | |||
| 886 | goto done; | |||
| 887 | ||||
| 888 | if ((e = ikev2_msg_encrypt(env, sa, e, buf)) == NULL((void *)0)) { | |||
| 889 | log_debug("%s: encryption failed", __func__); | |||
| 890 | goto done; | |||
| 891 | } | |||
| 892 | if (ibuf_add_buf(buf, e) != 0) | |||
| 893 | goto done; | |||
| 894 | ||||
| 895 | /* Add integrity checksum (HMAC) */ | |||
| 896 | if (ikev2_msg_integr(env, sa, buf) != 0) { | |||
| 897 | log_debug("%s: integrity checksum failed", __func__); | |||
| 898 | goto done; | |||
| 899 | } | |||
| 900 | ||||
| 901 | log_debug("%s: Fragment %zu of %zu has size of %zu bytes.", | |||
| 902 | __func__, frag_num, frag_total, | |||
| 903 | ibuf_size(buf) - sizeof(*hdr)); | |||
| 904 | print_hexbuf(buf); | |||
| 905 | ||||
| 906 | resp.msg_data = buf; | |||
| 907 | resp.msg_sa = sa; | |||
| 908 | resp.msg_fd = sa->sa_fd; | |||
| 909 | TAILQ_INIT(&resp.msg_proposals)do { (&resp.msg_proposals)->tqh_first = ((void *)0); ( &resp.msg_proposals)->tqh_last = &(&resp.msg_proposals )->tqh_first; } while (0); | |||
| 910 | ||||
| 911 | if (ikev2_msg_send(env, &resp) == -1) | |||
| 912 | goto done; | |||
| 913 | ||||
| 914 | ikestat_inc(env, ikes_frag_sent)do { env->sc_stats.ikes_frag_sent += (1); } while(0); | |||
| 915 | ||||
| 916 | offset += MINIMUM(left, max_len)(((left)<(max_len))?(left):(max_len)); | |||
| 917 | left -= MINIMUM(left, max_len)(((left)<(max_len))?(left):(max_len)); | |||
| 918 | frag_num++; | |||
| 919 | ||||
| 920 | /* MUST be zero after first fragment */ | |||
| 921 | firstpayload = 0; | |||
| 922 | ||||
| 923 | ikev2_msg_cleanup(env, &resp); | |||
| 924 | ibuf_free(e); | |||
| 925 | e = NULL((void *)0); | |||
| 926 | } | |||
| 927 | ||||
| 928 | return 0; | |||
| 929 | done: | |||
| 930 | ikev2_msg_cleanup(env, &resp); | |||
| 931 | ibuf_free(e); | |||
| 932 | ikestat_inc(env, ikes_frag_send_failures)do { env->sc_stats.ikes_frag_send_failures += (1); } while (0); | |||
| 933 | return ret; | |||
| 934 | } | |||
| 935 | ||||
| 936 | struct ibuf * | |||
| 937 | ikev2_msg_auth(struct iked *env, struct iked_sa *sa, int response) | |||
| 938 | { | |||
| 939 | struct ibuf *authmsg = NULL((void *)0), *nonce, *prfkey, *buf; | |||
| 940 | uint8_t *ptr; | |||
| 941 | struct iked_id *id; | |||
| 942 | size_t tmplen; | |||
| 943 | ||||
| 944 | /* | |||
| 945 | * Create the payload to be signed/MAC'ed for AUTH | |||
| 946 | */ | |||
| 947 | ||||
| 948 | if (!response) { | |||
| 949 | if ((nonce = sa->sa_rnoncesa_kex.kex_rnonce) == NULL((void *)0) || | |||
| 950 | (sa->sa_iid.id_type == 0) || | |||
| 951 | (prfkey = sa->sa_key_iprf) == NULL((void *)0) || | |||
| 952 | (buf = sa->sa_1stmsg) == NULL((void *)0)) | |||
| 953 | return (NULL((void *)0)); | |||
| 954 | id = &sa->sa_iid; | |||
| 955 | } else { | |||
| 956 | if ((nonce = sa->sa_inoncesa_kex.kex_inonce) == NULL((void *)0) || | |||
| 957 | (sa->sa_rid.id_type == 0) || | |||
| 958 | (prfkey = sa->sa_key_rprf) == NULL((void *)0) || | |||
| 959 | (buf = sa->sa_2ndmsg) == NULL((void *)0)) | |||
| 960 | return (NULL((void *)0)); | |||
| 961 | id = &sa->sa_rid; | |||
| 962 | } | |||
| 963 | ||||
| 964 | if ((authmsg = ibuf_dup(buf)) == NULL((void *)0)) | |||
| 965 | return (NULL((void *)0)); | |||
| 966 | if (ibuf_add_buf(authmsg, nonce) != 0) | |||
| 967 | goto fail; | |||
| 968 | ||||
| 969 | if ((hash_setkey(sa->sa_prf, ibuf_data(prfkey), | |||
| 970 | ibuf_size(prfkey))) == NULL((void *)0)) | |||
| 971 | goto fail; | |||
| 972 | ||||
| 973 | /* require non-truncating hash */ | |||
| 974 | if (hash_keylength(sa->sa_prf) != hash_length(sa->sa_prf)) | |||
| 975 | goto fail; | |||
| 976 | ||||
| 977 | if ((ptr = ibuf_reserve(authmsg, hash_keylength(sa->sa_prf))) == NULL((void *)0)) | |||
| 978 | goto fail; | |||
| 979 | ||||
| 980 | hash_init(sa->sa_prf); | |||
| 981 | hash_update(sa->sa_prf, ibuf_data(id->id_buf), ibuf_size(id->id_buf)); | |||
| 982 | hash_final(sa->sa_prf, ptr, &tmplen); | |||
| 983 | ||||
| 984 | if (tmplen != hash_length(sa->sa_prf)) | |||
| 985 | goto fail; | |||
| 986 | ||||
| 987 | log_debug("%s: %s auth data length %zu", | |||
| 988 | __func__, response ? "responder" : "initiator", | |||
| 989 | ibuf_size(authmsg)); | |||
| 990 | print_hexbuf(authmsg); | |||
| 991 | ||||
| 992 | return (authmsg); | |||
| 993 | ||||
| 994 | fail: | |||
| 995 | ibuf_free(authmsg); | |||
| 996 | return (NULL((void *)0)); | |||
| 997 | } | |||
| 998 | ||||
| 999 | int | |||
| 1000 | ikev2_msg_authverify(struct iked *env, struct iked_sa *sa, | |||
| 1001 | struct iked_auth *auth, uint8_t *buf, size_t len, struct ibuf *authmsg) | |||
| 1002 | { | |||
| 1003 | uint8_t *key, *psk = NULL((void *)0); | |||
| 1004 | ssize_t keylen; | |||
| 1005 | struct iked_id *id; | |||
| 1006 | struct iked_dsa *dsa = NULL((void *)0); | |||
| 1007 | int ret = -1; | |||
| 1008 | uint8_t keytype; | |||
| 1009 | ||||
| 1010 | if (sa->sa_hdr.sh_initiator) | |||
| 1011 | id = &sa->sa_rcert; | |||
| 1012 | else | |||
| 1013 | id = &sa->sa_icert; | |||
| 1014 | ||||
| 1015 | if ((dsa = dsa_verify_new(auth->auth_method, sa->sa_prf)) == NULL((void *)0)) { | |||
| 1016 | log_debug("%s: invalid auth method", __func__); | |||
| 1017 | return (-1); | |||
| 1018 | } | |||
| 1019 | ||||
| 1020 | switch (auth->auth_method) { | |||
| 1021 | case IKEV2_AUTH_SHARED_KEY_MIC2: | |||
| 1022 | if (!auth->auth_length) { | |||
| 1023 | log_debug("%s: no pre-shared key found", __func__); | |||
| 1024 | goto done; | |||
| 1025 | } | |||
| 1026 | if ((keylen = ikev2_psk(sa, auth->auth_data, | |||
| 1027 | auth->auth_length, &psk)) == -1) { | |||
| 1028 | log_debug("%s: failed to get PSK", __func__); | |||
| 1029 | goto done; | |||
| 1030 | } | |||
| 1031 | key = psk; | |||
| 1032 | keytype = 0; | |||
| 1033 | break; | |||
| 1034 | default: | |||
| 1035 | if (!id->id_type || !ibuf_length(id->id_buf)) { | |||
| 1036 | log_debug("%s: no cert found", __func__); | |||
| 1037 | goto done; | |||
| 1038 | } | |||
| 1039 | key = ibuf_data(id->id_buf); | |||
| 1040 | keylen = ibuf_size(id->id_buf); | |||
| 1041 | keytype = id->id_type; | |||
| 1042 | break; | |||
| 1043 | } | |||
| 1044 | ||||
| 1045 | log_debug("%s: method %s keylen %zd type %s", __func__, | |||
| 1046 | print_map(auth->auth_method, ikev2_auth_map), keylen, | |||
| 1047 | print_map(id->id_type, ikev2_cert_map)); | |||
| 1048 | ||||
| 1049 | if (dsa_setkey(dsa, key, keylen, keytype) == NULL((void *)0) || | |||
| 1050 | dsa_init(dsa, buf, len) != 0 || | |||
| 1051 | dsa_update(dsa, ibuf_data(authmsg), ibuf_size(authmsg))) { | |||
| 1052 | log_debug("%s: failed to compute digital signature", __func__); | |||
| 1053 | goto done; | |||
| 1054 | } | |||
| 1055 | ||||
| 1056 | if ((ret = dsa_verify_final(dsa, buf, len)) == 0) { | |||
| 1057 | log_debug("%s: authentication successful", __func__); | |||
| 1058 | sa_state(env, sa, IKEV2_STATE_AUTH_SUCCESS6); | |||
| 1059 | sa_stateflags(sa, IKED_REQ_AUTHVALID0x0010); | |||
| 1060 | } else { | |||
| 1061 | log_debug("%s: authentication failed", __func__); | |||
| 1062 | sa_state(env, sa, IKEV2_STATE_AUTH_REQUEST5); | |||
| 1063 | } | |||
| 1064 | ||||
| 1065 | done: | |||
| 1066 | free(psk); | |||
| 1067 | dsa_free(dsa); | |||
| 1068 | ||||
| 1069 | return (ret); | |||
| 1070 | } | |||
| 1071 | ||||
| 1072 | int | |||
| 1073 | ikev2_msg_authsign(struct iked *env, struct iked_sa *sa, | |||
| 1074 | struct iked_auth *auth, struct ibuf *authmsg) | |||
| 1075 | { | |||
| 1076 | uint8_t *key, *psk = NULL((void *)0); | |||
| 1077 | ssize_t keylen, siglen; | |||
| 1078 | struct iked_hash *prf = sa->sa_prf; | |||
| 1079 | struct iked_id *id; | |||
| 1080 | struct iked_dsa *dsa = NULL((void *)0); | |||
| 1081 | struct ibuf *buf; | |||
| 1082 | int ret = -1; | |||
| 1083 | uint8_t keytype; | |||
| 1084 | ||||
| 1085 | if (sa->sa_hdr.sh_initiator) | |||
| 1086 | id = &sa->sa_icert; | |||
| 1087 | else | |||
| 1088 | id = &sa->sa_rcert; | |||
| 1089 | ||||
| 1090 | if ((dsa = dsa_sign_new(auth->auth_method, prf)) == NULL((void *)0)) { | |||
| 1091 | log_debug("%s: invalid auth method", __func__); | |||
| 1092 | return (-1); | |||
| 1093 | } | |||
| 1094 | ||||
| 1095 | switch (auth->auth_method) { | |||
| 1096 | case IKEV2_AUTH_SHARED_KEY_MIC2: | |||
| 1097 | if (!auth->auth_length) { | |||
| 1098 | log_debug("%s: no pre-shared key found", __func__); | |||
| 1099 | goto done; | |||
| 1100 | } | |||
| 1101 | if ((keylen = ikev2_psk(sa, auth->auth_data, | |||
| 1102 | auth->auth_length, &psk)) == -1) { | |||
| 1103 | log_debug("%s: failed to get PSK", __func__); | |||
| 1104 | goto done; | |||
| 1105 | } | |||
| 1106 | key = psk; | |||
| 1107 | keytype = 0; | |||
| 1108 | break; | |||
| 1109 | default: | |||
| 1110 | if (id == NULL((void *)0)) { | |||
| 1111 | log_debug("%s: no cert found", __func__); | |||
| 1112 | goto done; | |||
| 1113 | } | |||
| 1114 | key = ibuf_data(id->id_buf); | |||
| 1115 | keylen = ibuf_size(id->id_buf); | |||
| 1116 | keytype = id->id_type; | |||
| 1117 | break; | |||
| 1118 | } | |||
| 1119 | ||||
| 1120 | if (dsa_setkey(dsa, key, keylen, keytype) == NULL((void *)0) || | |||
| 1121 | dsa_init(dsa, NULL((void *)0), 0) != 0 || | |||
| 1122 | dsa_update(dsa, ibuf_data(authmsg), ibuf_size(authmsg))) { | |||
| 1123 | log_debug("%s: failed to compute digital signature", __func__); | |||
| 1124 | goto done; | |||
| 1125 | } | |||
| 1126 | ||||
| 1127 | ibuf_free(sa->sa_localauth.id_buf); | |||
| 1128 | sa->sa_localauth.id_buf = NULL((void *)0); | |||
| 1129 | ||||
| 1130 | if ((buf = ibuf_new(NULL((void *)0), dsa_length(dsa))) == NULL((void *)0)) { | |||
| 1131 | log_debug("%s: failed to get auth buffer", __func__); | |||
| 1132 | goto done; | |||
| 1133 | } | |||
| 1134 | ||||
| 1135 | if ((siglen = dsa_sign_final(dsa, | |||
| 1136 | ibuf_data(buf), ibuf_size(buf))) < 0) { | |||
| 1137 | log_debug("%s: failed to create auth signature", __func__); | |||
| 1138 | ibuf_free(buf); | |||
| 1139 | goto done; | |||
| 1140 | } | |||
| 1141 | ||||
| 1142 | if (ibuf_setsize(buf, siglen) < 0) { | |||
| 1143 | log_debug("%s: failed to set auth signature size to %zd", | |||
| 1144 | __func__, siglen); | |||
| 1145 | ibuf_free(buf); | |||
| 1146 | goto done; | |||
| 1147 | } | |||
| 1148 | ||||
| 1149 | sa->sa_localauth.id_type = auth->auth_method; | |||
| 1150 | sa->sa_localauth.id_buf = buf; | |||
| 1151 | ||||
| 1152 | ret = 0; | |||
| 1153 | done: | |||
| 1154 | free(psk); | |||
| 1155 | dsa_free(dsa); | |||
| 1156 | ||||
| 1157 | return (ret); | |||
| 1158 | } | |||
| 1159 | ||||
| 1160 | int | |||
| 1161 | ikev2_msg_frompeer(struct iked_message *msg) | |||
| 1162 | { | |||
| 1163 | struct iked_sa *sa = msg->msg_sa; | |||
| 1164 | struct ike_header *hdr; | |||
| 1165 | ||||
| 1166 | msg = msg->msg_parent; | |||
| 1167 | ||||
| 1168 | if (sa == NULL((void *)0) || | |||
| 1169 | (hdr = ibuf_seek(msg->msg_data, 0, sizeof(*hdr))) == NULL((void *)0)) | |||
| 1170 | return (0); | |||
| 1171 | ||||
| 1172 | if (!sa->sa_hdr.sh_initiator && | |||
| 1173 | (hdr->ike_flags & IKEV2_FLAG_INITIATOR0x08)) | |||
| 1174 | return (1); | |||
| 1175 | else if (sa->sa_hdr.sh_initiator && | |||
| 1176 | (hdr->ike_flags & IKEV2_FLAG_INITIATOR0x08) == 0) | |||
| 1177 | return (1); | |||
| 1178 | ||||
| 1179 | return (0); | |||
| 1180 | } | |||
| 1181 | ||||
| 1182 | struct iked_socket * | |||
| 1183 | ikev2_msg_getsocket(struct iked *env, int af, int natt) | |||
| 1184 | { | |||
| 1185 | switch (af) { | |||
| 1186 | case AF_INET2: | |||
| 1187 | return (env->sc_sock4[natt ? 1 : 0]); | |||
| 1188 | case AF_INET624: | |||
| 1189 | return (env->sc_sock6[natt ? 1 : 0]); | |||
| 1190 | } | |||
| 1191 | ||||
| 1192 | log_debug("%s: af socket %d not available", __func__, af); | |||
| 1193 | return (NULL((void *)0)); | |||
| 1194 | } | |||
| 1195 | ||||
| 1196 | int | |||
| 1197 | ikev2_msg_enqueue(struct iked *env, struct iked_msgqueue *queue, | |||
| 1198 | struct iked_message *msg, int timeout) | |||
| 1199 | { | |||
| 1200 | struct iked_msg_retransmit *mr; | |||
| 1201 | ||||
| 1202 | if ((mr = ikev2_msg_lookup(env, queue, msg, msg->msg_exchange)) == | |||
| 1203 | NULL((void *)0)) { | |||
| 1204 | if ((mr = calloc(1, sizeof(*mr))) == NULL((void *)0)) | |||
| 1205 | return (-1); | |||
| 1206 | TAILQ_INIT(&mr->mrt_frags)do { (&mr->mrt_frags)->tqh_first = ((void *)0); (& mr->mrt_frags)->tqh_last = &(&mr->mrt_frags) ->tqh_first; } while (0); | |||
| 1207 | mr->mrt_tries = 0; | |||
| 1208 | ||||
| 1209 | timer_set(env, &mr->mrt_timer, msg->msg_response ? | |||
| 1210 | ikev2_msg_response_timeout : ikev2_msg_retransmit_timeout, | |||
| 1211 | mr); | |||
| 1212 | timer_add(env, &mr->mrt_timer, timeout); | |||
| 1213 | ||||
| 1214 | TAILQ_INSERT_TAIL(queue, mr, mrt_entry)do { (mr)->mrt_entry.tqe_next = ((void *)0); (mr)->mrt_entry .tqe_prev = (queue)->tqh_last; *(queue)->tqh_last = (mr ); (queue)->tqh_last = &(mr)->mrt_entry.tqe_next; } while (0); | |||
| 1215 | } | |||
| 1216 | ||||
| 1217 | TAILQ_INSERT_TAIL(&mr->mrt_frags, msg, msg_entry)do { (msg)->msg_entry.tqe_next = ((void *)0); (msg)->msg_entry .tqe_prev = (&mr->mrt_frags)->tqh_last; *(&mr-> mrt_frags)->tqh_last = (msg); (&mr->mrt_frags)-> tqh_last = &(msg)->msg_entry.tqe_next; } while (0); | |||
| 1218 | ||||
| 1219 | return 0; | |||
| 1220 | } | |||
| 1221 | ||||
| 1222 | void | |||
| 1223 | ikev2_msg_prevail(struct iked *env, struct iked_msgqueue *queue, | |||
| 1224 | struct iked_message *msg) | |||
| 1225 | { | |||
| 1226 | struct iked_msg_retransmit *mr, *mrtmp; | |||
| 1227 | ||||
| 1228 | TAILQ_FOREACH_SAFE(mr, queue, mrt_entry, mrtmp)for ((mr) = ((queue)->tqh_first); (mr) != ((void *)0) && ((mrtmp) = ((mr)->mrt_entry.tqe_next), 1); (mr) = (mrtmp) ) { | |||
| 1229 | if (TAILQ_FIRST(&mr->mrt_frags)((&mr->mrt_frags)->tqh_first)->msg_msgid < msg->msg_msgid) | |||
| 1230 | ikev2_msg_dispose(env, queue, mr); | |||
| 1231 | } | |||
| 1232 | } | |||
| 1233 | ||||
| 1234 | void | |||
| 1235 | ikev2_msg_dispose(struct iked *env, struct iked_msgqueue *queue, | |||
| 1236 | struct iked_msg_retransmit *mr) | |||
| 1237 | { | |||
| 1238 | struct iked_message *m; | |||
| 1239 | ||||
| 1240 | while ((m = TAILQ_FIRST(&mr->mrt_frags)((&mr->mrt_frags)->tqh_first)) != NULL((void *)0)) { | |||
| 1241 | TAILQ_REMOVE(&mr->mrt_frags, m, msg_entry)do { if (((m)->msg_entry.tqe_next) != ((void *)0)) (m)-> msg_entry.tqe_next->msg_entry.tqe_prev = (m)->msg_entry .tqe_prev; else (&mr->mrt_frags)->tqh_last = (m)-> msg_entry.tqe_prev; *(m)->msg_entry.tqe_prev = (m)->msg_entry .tqe_next; ; ; } while (0); | |||
| 1242 | ikev2_msg_cleanup(env, m); | |||
| 1243 | free(m); | |||
| 1244 | } | |||
| 1245 | ||||
| 1246 | timer_del(env, &mr->mrt_timer); | |||
| 1247 | TAILQ_REMOVE(queue, mr, mrt_entry)do { if (((mr)->mrt_entry.tqe_next) != ((void *)0)) (mr)-> mrt_entry.tqe_next->mrt_entry.tqe_prev = (mr)->mrt_entry .tqe_prev; else (queue)->tqh_last = (mr)->mrt_entry.tqe_prev ; *(mr)->mrt_entry.tqe_prev = (mr)->mrt_entry.tqe_next; ; ; } while (0); | |||
| 1248 | free(mr); | |||
| 1249 | } | |||
| 1250 | ||||
| 1251 | void | |||
| 1252 | ikev2_msg_flushqueue(struct iked *env, struct iked_msgqueue *queue) | |||
| 1253 | { | |||
| 1254 | struct iked_msg_retransmit *mr = NULL((void *)0); | |||
| 1255 | ||||
| 1256 | while ((mr = TAILQ_FIRST(queue)((queue)->tqh_first)) != NULL((void *)0)) | |||
| ||||
| 1257 | ikev2_msg_dispose(env, queue, mr); | |||
| ||||
| 1258 | } | |||
| 1259 | ||||
| 1260 | struct iked_msg_retransmit * | |||
| 1261 | ikev2_msg_lookup(struct iked *env, struct iked_msgqueue *queue, | |||
| 1262 | struct iked_message *msg, uint8_t exchange) | |||
| 1263 | { | |||
| 1264 | struct iked_msg_retransmit *mr = NULL((void *)0); | |||
| 1265 | ||||
| 1266 | TAILQ_FOREACH(mr, queue, mrt_entry)for((mr) = ((queue)->tqh_first); (mr) != ((void *)0); (mr) = ((mr)->mrt_entry.tqe_next)) { | |||
| 1267 | if (TAILQ_FIRST(&mr->mrt_frags)((&mr->mrt_frags)->tqh_first)->msg_msgid == | |||
| 1268 | msg->msg_msgid && | |||
| 1269 | TAILQ_FIRST(&mr->mrt_frags)((&mr->mrt_frags)->tqh_first)->msg_exchange == exchange) | |||
| 1270 | break; | |||
| 1271 | } | |||
| 1272 | ||||
| 1273 | return (mr); | |||
| 1274 | } | |||
| 1275 | ||||
| 1276 | int | |||
| 1277 | ikev2_msg_retransmit_response(struct iked *env, struct iked_sa *sa, | |||
| 1278 | struct iked_message *msg, uint8_t exchange) | |||
| 1279 | { | |||
| 1280 | struct iked_msg_retransmit *mr = NULL((void *)0); | |||
| 1281 | struct iked_message *m = NULL((void *)0); | |||
| 1282 | ||||
| 1283 | if ((mr = ikev2_msg_lookup(env, &sa->sa_responses, msg, exchange)) | |||
| 1284 | == NULL((void *)0)) | |||
| 1285 | return (-2); /* not found */ | |||
| 1286 | ||||
| 1287 | TAILQ_FOREACH(m, &mr->mrt_frags, msg_entry)for((m) = ((&mr->mrt_frags)->tqh_first); (m) != ((void *)0); (m) = ((m)->msg_entry.tqe_next)) { | |||
| 1288 | if (sendtofrom(m->msg_fd, ibuf_data(m->msg_data), | |||
| 1289 | ibuf_size(m->msg_data), 0, | |||
| 1290 | (struct sockaddr *)&m->msg_peer, m->msg_peerlen, | |||
| 1291 | (struct sockaddr *)&m->msg_local, m->msg_locallen) == -1) { | |||
| 1292 | log_warn("%s: sendtofrom", __func__); | |||
| 1293 | ikestat_inc(env, ikes_msg_send_failures)do { env->sc_stats.ikes_msg_send_failures += (1); } while( 0); | |||
| 1294 | return (-1); | |||
| 1295 | } | |||
| 1296 | log_info("%sretransmit %s res %u local %s peer %s", | |||
| 1297 | SPI_SA(sa, NULL)ikev2_ikesa_info((&(sa)->sa_hdr)->sh_ispi, ((((void *)0)))), | |||
| 1298 | print_map(exchange, ikev2_exchange_map), | |||
| 1299 | m->msg_msgid, | |||
| 1300 | print_addr(&m->msg_local), | |||
| 1301 | print_addr(&m->msg_peer)); | |||
| 1302 | } | |||
| 1303 | ||||
| 1304 | timer_add(env, &mr->mrt_timer, IKED_RESPONSE_TIMEOUT120); | |||
| 1305 | ikestat_inc(env, ikes_retransmit_response)do { env->sc_stats.ikes_retransmit_response += (1); } while (0); | |||
| 1306 | return (0); | |||
| 1307 | } | |||
| 1308 | ||||
| 1309 | void | |||
| 1310 | ikev2_msg_response_timeout(struct iked *env, void *arg) | |||
| 1311 | { | |||
| 1312 | struct iked_msg_retransmit *mr = arg; | |||
| 1313 | struct iked_sa *sa; | |||
| 1314 | ||||
| 1315 | sa = TAILQ_FIRST(&mr->mrt_frags)((&mr->mrt_frags)->tqh_first)->msg_sa; | |||
| 1316 | ikev2_msg_dispose(env, &sa->sa_responses, mr); | |||
| 1317 | } | |||
| 1318 | ||||
| 1319 | void | |||
| 1320 | ikev2_msg_retransmit_timeout(struct iked *env, void *arg) | |||
| 1321 | { | |||
| 1322 | struct iked_msg_retransmit *mr = arg; | |||
| 1323 | struct iked_message *msg = TAILQ_FIRST(&mr->mrt_frags)((&mr->mrt_frags)->tqh_first); | |||
| 1324 | struct iked_sa *sa = msg->msg_sa; | |||
| 1325 | ||||
| 1326 | if (mr->mrt_tries < IKED_RETRANSMIT_TRIES5) { | |||
| 1327 | TAILQ_FOREACH(msg, &mr->mrt_frags, msg_entry)for((msg) = ((&mr->mrt_frags)->tqh_first); (msg) != ((void *)0); (msg) = ((msg)->msg_entry.tqe_next)) { | |||
| 1328 | if (sendtofrom(msg->msg_fd, ibuf_data(msg->msg_data), | |||
| 1329 | ibuf_size(msg->msg_data), 0, | |||
| 1330 | (struct sockaddr *)&msg->msg_peer, msg->msg_peerlen, | |||
| 1331 | (struct sockaddr *)&msg->msg_local, | |||
| 1332 | msg->msg_locallen) == -1) { | |||
| 1333 | log_warn("%s: sendtofrom", __func__); | |||
| 1334 | ikev2_ike_sa_setreason(sa, "retransmit failed"); | |||
| 1335 | sa_free(env, sa); | |||
| 1336 | ikestat_inc(env, ikes_msg_send_failures)do { env->sc_stats.ikes_msg_send_failures += (1); } while( 0); | |||
| 1337 | return; | |||
| 1338 | } | |||
| 1339 | log_info("%sretransmit %d %s req %u peer %s " | |||
| 1340 | "local %s", SPI_SA(sa, NULL)ikev2_ikesa_info((&(sa)->sa_hdr)->sh_ispi, ((((void *)0)))), mr->mrt_tries + 1, | |||
| 1341 | print_map(msg->msg_exchange, ikev2_exchange_map), | |||
| 1342 | msg->msg_msgid, | |||
| 1343 | print_addr(&msg->msg_peer), | |||
| 1344 | print_addr(&msg->msg_local)); | |||
| 1345 | } | |||
| 1346 | /* Exponential timeout */ | |||
| 1347 | timer_add(env, &mr->mrt_timer, | |||
| 1348 | IKED_RETRANSMIT_TIMEOUT2 * (2 << (mr->mrt_tries++))); | |||
| 1349 | ikestat_inc(env, ikes_retransmit_request)do { env->sc_stats.ikes_retransmit_request += (1); } while (0); | |||
| 1350 | } else { | |||
| 1351 | log_debug("%s: retransmit limit reached for req %u", | |||
| 1352 | __func__, msg->msg_msgid); | |||
| 1353 | ikev2_ike_sa_setreason(sa, "retransmit limit reached"); | |||
| 1354 | ikestat_inc(env, ikes_retransmit_limit)do { env->sc_stats.ikes_retransmit_limit += (1); } while(0 ); | |||
| 1355 | sa_free(env, sa); | |||
| 1356 | } | |||
| 1357 | } |