1*d8ea035bSderaadt /* $OpenBSD: ikev2_msg.c,v 1.83 2021/11/29 06:43:42 deraadt Exp $ */ 2fde46d6eSreyk 3fde46d6eSreyk /* 465c540d0Spatrick * Copyright (c) 2019 Tobias Heider <tobias.heider@stusta.de> 5fcebd35dSreyk * Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org> 6fde46d6eSreyk * 7fde46d6eSreyk * Permission to use, copy, modify, and distribute this software for any 8fde46d6eSreyk * purpose with or without fee is hereby granted, provided that the above 9fde46d6eSreyk * copyright notice and this permission notice appear in all copies. 10fde46d6eSreyk * 11fde46d6eSreyk * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12fde46d6eSreyk * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13fde46d6eSreyk * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14fde46d6eSreyk * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15fde46d6eSreyk * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16fde46d6eSreyk * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17fde46d6eSreyk * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18fde46d6eSreyk */ 19fde46d6eSreyk 20*d8ea035bSderaadt #include <sys/types.h> 21fde46d6eSreyk #include <sys/queue.h> 22fde46d6eSreyk #include <sys/socket.h> 23fde46d6eSreyk #include <sys/uio.h> 24fde46d6eSreyk 25fde46d6eSreyk #include <netinet/in.h> 26fde46d6eSreyk #include <arpa/inet.h> 27fde46d6eSreyk 28fde46d6eSreyk #include <stdlib.h> 29fde46d6eSreyk #include <stdio.h> 3053684dccStobhe #include <syslog.h> 31fde46d6eSreyk #include <unistd.h> 32fde46d6eSreyk #include <string.h> 33fde46d6eSreyk #include <signal.h> 34fde46d6eSreyk #include <errno.h> 35fde46d6eSreyk #include <err.h> 36fde46d6eSreyk #include <event.h> 37fde46d6eSreyk 38fde46d6eSreyk #include <openssl/sha.h> 39fde46d6eSreyk #include <openssl/evp.h> 40fde46d6eSreyk 41fde46d6eSreyk #include "iked.h" 42fde46d6eSreyk #include "ikev2.h" 43fde46d6eSreyk #include "eap.h" 44fde46d6eSreyk #include "dh.h" 45fde46d6eSreyk 4605256619Sreyk void ikev1_recv(struct iked *, struct iked_message *); 47c45fd413Smikeb void ikev2_msg_response_timeout(struct iked *, void *); 48c45fd413Smikeb void ikev2_msg_retransmit_timeout(struct iked *, void *); 49d56261e5Stobhe int ikev2_check_frag_oversize(struct iked_sa *, struct ibuf *); 50d56261e5Stobhe int ikev2_send_encrypted_fragments(struct iked *, struct iked_sa *, 51d56261e5Stobhe struct ibuf *, uint8_t, uint8_t, int); 5215863c3aStobhe int ikev2_msg_encrypt_prepare(struct iked_sa *, struct ikev2_payload *, 5315863c3aStobhe struct ibuf*, struct ibuf *, struct ike_header *, uint8_t, int); 54c45fd413Smikeb 55fde46d6eSreyk void 56fde46d6eSreyk ikev2_msg_cb(int fd, short event, void *arg) 57fde46d6eSreyk { 58fde46d6eSreyk struct iked_socket *sock = arg; 59fde46d6eSreyk struct iked *env = sock->sock_env; 60fde46d6eSreyk struct iked_message msg; 61fde46d6eSreyk struct ike_header hdr; 62d09d3a7dSreyk uint32_t natt = 0x00000000; 63d09d3a7dSreyk uint8_t buf[IKED_MSGBUF_MAX]; 64fde46d6eSreyk ssize_t len; 65fde46d6eSreyk off_t off; 66fde46d6eSreyk 67fde46d6eSreyk bzero(&msg, sizeof(msg)); 68fde46d6eSreyk bzero(buf, sizeof(buf)); 69fde46d6eSreyk 70fde46d6eSreyk msg.msg_peerlen = sizeof(msg.msg_peer); 71fde46d6eSreyk msg.msg_locallen = sizeof(msg.msg_local); 7226d7dba1Sreyk msg.msg_parent = &msg; 73fde46d6eSreyk memcpy(&msg.msg_local, &sock->sock_addr, sizeof(sock->sock_addr)); 74fde46d6eSreyk 75fde46d6eSreyk if ((len = recvfromto(fd, buf, sizeof(buf), 0, 76fde46d6eSreyk (struct sockaddr *)&msg.msg_peer, &msg.msg_peerlen, 77fde46d6eSreyk (struct sockaddr *)&msg.msg_local, &msg.msg_locallen)) < 78fde46d6eSreyk (ssize_t)sizeof(natt)) 79fde46d6eSreyk return; 80fde46d6eSreyk 8147d6a31cSmarkus if (socket_getport((struct sockaddr *)&msg.msg_local) == 8259c69d76Stobhe env->sc_nattport) { 8334d94968Stedu if (memcmp(&natt, buf, sizeof(natt)) != 0) 84fde46d6eSreyk return; 85fde46d6eSreyk msg.msg_natt = 1; 86fde46d6eSreyk off = sizeof(natt); 87fde46d6eSreyk } else 88fde46d6eSreyk off = 0; 89fde46d6eSreyk 90fde46d6eSreyk if ((size_t)(len - off) <= sizeof(hdr)) 91fde46d6eSreyk return; 92fde46d6eSreyk memcpy(&hdr, buf + off, sizeof(hdr)); 93fde46d6eSreyk 94fde46d6eSreyk if ((msg.msg_data = ibuf_new(buf + off, len - off)) == NULL) 95fde46d6eSreyk return; 96fde46d6eSreyk 97fde46d6eSreyk TAILQ_INIT(&msg.msg_proposals); 983e395450Stobhe SIMPLEQ_INIT(&msg.msg_certreqs); 99fde46d6eSreyk msg.msg_fd = fd; 10005256619Sreyk 10105256619Sreyk if (hdr.ike_version == IKEV1_VERSION) 10205256619Sreyk ikev1_recv(env, &msg); 10305256619Sreyk else 104fde46d6eSreyk ikev2_recv(env, &msg); 105fde46d6eSreyk 106763023d6Sreyk ikev2_msg_cleanup(env, &msg); 107fde46d6eSreyk } 108fde46d6eSreyk 10905256619Sreyk void 11005256619Sreyk ikev1_recv(struct iked *env, struct iked_message *msg) 11105256619Sreyk { 11205256619Sreyk struct ike_header *hdr; 11305256619Sreyk 11405256619Sreyk if (ibuf_size(msg->msg_data) <= sizeof(*hdr)) { 11505256619Sreyk log_debug("%s: short message", __func__); 11605256619Sreyk return; 11705256619Sreyk } 11805256619Sreyk 11905256619Sreyk hdr = (struct ike_header *)ibuf_data(msg->msg_data); 12005256619Sreyk 12105256619Sreyk log_debug("%s: header ispi %s rspi %s" 12205256619Sreyk " nextpayload %u version 0x%02x exchange %u flags 0x%02x" 12305256619Sreyk " msgid %u length %u", __func__, 12405256619Sreyk print_spi(betoh64(hdr->ike_ispi), 8), 12505256619Sreyk print_spi(betoh64(hdr->ike_rspi), 8), 12605256619Sreyk hdr->ike_nextpayload, 12705256619Sreyk hdr->ike_version, 12805256619Sreyk hdr->ike_exchange, 12905256619Sreyk hdr->ike_flags, 13005256619Sreyk betoh32(hdr->ike_msgid), 13105256619Sreyk betoh32(hdr->ike_length)); 13205256619Sreyk 13305256619Sreyk log_debug("%s: IKEv1 not supported", __func__); 13405256619Sreyk } 13505256619Sreyk 136fde46d6eSreyk struct ibuf * 137fde46d6eSreyk ikev2_msg_init(struct iked *env, struct iked_message *msg, 138fde46d6eSreyk struct sockaddr_storage *peer, socklen_t peerlen, 139fde46d6eSreyk struct sockaddr_storage *local, socklen_t locallen, int response) 140fde46d6eSreyk { 141fde46d6eSreyk bzero(msg, sizeof(*msg)); 142fde46d6eSreyk memcpy(&msg->msg_peer, peer, peerlen); 143fde46d6eSreyk msg->msg_peerlen = peerlen; 144fde46d6eSreyk memcpy(&msg->msg_local, local, locallen); 145fde46d6eSreyk msg->msg_locallen = locallen; 146fde46d6eSreyk msg->msg_response = response ? 1 : 0; 147fde46d6eSreyk msg->msg_fd = -1; 148fde46d6eSreyk msg->msg_data = ibuf_static(); 14926d7dba1Sreyk msg->msg_e = 0; 15026d7dba1Sreyk msg->msg_parent = msg; /* has to be set */ 151763023d6Sreyk TAILQ_INIT(&msg->msg_proposals); 152fde46d6eSreyk 153fde46d6eSreyk return (msg->msg_data); 154fde46d6eSreyk } 155fde46d6eSreyk 156c45fd413Smikeb struct iked_message * 157c45fd413Smikeb ikev2_msg_copy(struct iked *env, struct iked_message *msg) 158c45fd413Smikeb { 159c45fd413Smikeb struct iked_message *m = NULL; 160c45fd413Smikeb struct ibuf *buf; 161d39d09feSreyk size_t len; 16212c9fd31Sreyk void *ptr; 163c45fd413Smikeb 164d39d09feSreyk if (ibuf_size(msg->msg_data) < msg->msg_offset) 165d39d09feSreyk return (NULL); 166d39d09feSreyk len = ibuf_size(msg->msg_data) - msg->msg_offset; 167d39d09feSreyk 1688f4d0788Stobhe if ((m = malloc(sizeof(*m))) == NULL) 1698f4d0788Stobhe return (NULL); 1708f4d0788Stobhe 171d39d09feSreyk if ((ptr = ibuf_seek(msg->msg_data, msg->msg_offset, len)) == NULL || 172c45fd413Smikeb (buf = ikev2_msg_init(env, m, &msg->msg_peer, msg->msg_peerlen, 173c45fd413Smikeb &msg->msg_local, msg->msg_locallen, msg->msg_response)) == NULL || 1748f4d0788Stobhe ibuf_add(buf, ptr, len)) { 1758f4d0788Stobhe free(m); 176c45fd413Smikeb return (NULL); 1778f4d0788Stobhe } 178c45fd413Smikeb 179c45fd413Smikeb m->msg_fd = msg->msg_fd; 180c45fd413Smikeb m->msg_msgid = msg->msg_msgid; 181c45fd413Smikeb m->msg_offset = msg->msg_offset; 182c45fd413Smikeb m->msg_sa = msg->msg_sa; 183c45fd413Smikeb 184c45fd413Smikeb return (m); 185c45fd413Smikeb } 186c45fd413Smikeb 187763023d6Sreyk void 188763023d6Sreyk ikev2_msg_cleanup(struct iked *env, struct iked_message *msg) 189763023d6Sreyk { 190eb2389caStobhe struct iked_certreq *cr; 191eb2389caStobhe 19226d7dba1Sreyk if (msg == msg->msg_parent) { 19326d7dba1Sreyk ibuf_release(msg->msg_nonce); 19426d7dba1Sreyk ibuf_release(msg->msg_ke); 19526d7dba1Sreyk ibuf_release(msg->msg_auth.id_buf); 1969ce164edStobhe ibuf_release(msg->msg_peerid.id_buf); 197e3f5cf2eSpatrick ibuf_release(msg->msg_localid.id_buf); 19826d7dba1Sreyk ibuf_release(msg->msg_cert.id_buf); 199d4bcf9ebSreyk ibuf_release(msg->msg_cookie); 200c0b327e6Spatrick ibuf_release(msg->msg_cookie2); 201da56c325Stobhe ibuf_release(msg->msg_del_buf); 20225b39a47Stobhe free(msg->msg_eap.eam_user); 20352b3354cStobhe free(msg->msg_cp_addr); 20452b3354cStobhe free(msg->msg_cp_addr6); 2059ef39cf4Stobhe free(msg->msg_cp_dns); 20626d7dba1Sreyk 2073642bd88Smikeb msg->msg_nonce = NULL; 2083642bd88Smikeb msg->msg_ke = NULL; 2093642bd88Smikeb msg->msg_auth.id_buf = NULL; 2109ce164edStobhe msg->msg_peerid.id_buf = NULL; 211e3f5cf2eSpatrick msg->msg_localid.id_buf = NULL; 2123642bd88Smikeb msg->msg_cert.id_buf = NULL; 213d4bcf9ebSreyk msg->msg_cookie = NULL; 214c0b327e6Spatrick msg->msg_cookie2 = NULL; 215da56c325Stobhe msg->msg_del_buf = NULL; 21625b39a47Stobhe msg->msg_eap.eam_user = NULL; 21752b3354cStobhe msg->msg_cp_addr = NULL; 21852b3354cStobhe msg->msg_cp_addr6 = NULL; 2199ef39cf4Stobhe msg->msg_cp_dns = NULL; 220d4bcf9ebSreyk 22126d7dba1Sreyk config_free_proposals(&msg->msg_proposals, 0); 2223e395450Stobhe while ((cr = SIMPLEQ_FIRST(&msg->msg_certreqs))) { 223eb2389caStobhe ibuf_release(cr->cr_data); 2243e395450Stobhe SIMPLEQ_REMOVE_HEAD(&msg->msg_certreqs, cr_entry); 225eb2389caStobhe free(cr); 226eb2389caStobhe } 22726d7dba1Sreyk } 22826d7dba1Sreyk 229763023d6Sreyk if (msg->msg_data != NULL) { 230763023d6Sreyk ibuf_release(msg->msg_data); 231763023d6Sreyk msg->msg_data = NULL; 232763023d6Sreyk } 233763023d6Sreyk } 234763023d6Sreyk 235fde46d6eSreyk int 236fde46d6eSreyk ikev2_msg_valid_ike_sa(struct iked *env, struct ike_header *oldhdr, 237fde46d6eSreyk struct iked_message *msg) 238fde46d6eSreyk { 2396e1880a3Smarkus if (msg->msg_sa != NULL && msg->msg_policy != NULL) { 24069aac1baSmikeb if (msg->msg_sa->sa_state == IKEV2_STATE_CLOSED) 24169aac1baSmikeb return (-1); 2426e1880a3Smarkus /* 2436e1880a3Smarkus * Only permit informational requests from initiator 2446e1880a3Smarkus * on closing SAs (for DELETE). 2456e1880a3Smarkus */ 2466e1880a3Smarkus if (msg->msg_sa->sa_state == IKEV2_STATE_CLOSING) { 2476e1880a3Smarkus if (((oldhdr->ike_flags & 2486e1880a3Smarkus (IKEV2_FLAG_INITIATOR|IKEV2_FLAG_RESPONSE)) == 2496e1880a3Smarkus IKEV2_FLAG_INITIATOR) && 2506e1880a3Smarkus (oldhdr->ike_exchange == 2516e1880a3Smarkus IKEV2_EXCHANGE_INFORMATIONAL)) 252fde46d6eSreyk return (0); 2536e1880a3Smarkus return (-1); 2546e1880a3Smarkus } 2556e1880a3Smarkus return (0); 2566e1880a3Smarkus } 257fde46d6eSreyk 258fde46d6eSreyk /* Always fail */ 259fde46d6eSreyk return (-1); 260fde46d6eSreyk } 261fde46d6eSreyk 262fde46d6eSreyk int 263d9c13a0aSmikeb ikev2_msg_send(struct iked *env, struct iked_message *msg) 264fde46d6eSreyk { 265c45fd413Smikeb struct iked_sa *sa = msg->msg_sa; 266fde46d6eSreyk struct ibuf *buf = msg->msg_data; 267d09d3a7dSreyk uint32_t natt = 0x00000000; 26812c9fd31Sreyk int isnatt = 0; 269d09d3a7dSreyk uint8_t exchange, flags; 270fde46d6eSreyk struct ike_header *hdr; 271c45fd413Smikeb struct iked_message *m; 272fde46d6eSreyk 273fde46d6eSreyk if (buf == NULL || (hdr = ibuf_seek(msg->msg_data, 274fde46d6eSreyk msg->msg_offset, sizeof(*hdr))) == NULL) 275fde46d6eSreyk return (-1); 276fde46d6eSreyk 2770804246aStobhe isnatt = (msg->msg_natt || (sa && sa->sa_natt)); 27812c9fd31Sreyk 279670a137dSmikeb exchange = hdr->ike_exchange; 280670a137dSmikeb flags = hdr->ike_flags; 28153684dccStobhe logit(exchange == IKEV2_EXCHANGE_INFORMATIONAL ? LOG_DEBUG : LOG_INFO, 28253684dccStobhe "%ssend %s %s %u peer %s local %s, %ld bytes%s", 283ecea226bStobhe SPI_IH(hdr), 284670a137dSmikeb print_map(exchange, ikev2_exchange_map), 285ecea226bStobhe (flags & IKEV2_FLAG_RESPONSE) ? "res" : "req", 2867f7372eaSmarkus betoh32(hdr->ike_msgid), 287ecea226bStobhe print_host((struct sockaddr *)&msg->msg_peer, NULL, 0), 288ecea226bStobhe print_host((struct sockaddr *)&msg->msg_local, NULL, 0), 28912c9fd31Sreyk ibuf_length(buf), isnatt ? ", NAT-T" : ""); 290fde46d6eSreyk 29112c9fd31Sreyk if (isnatt) { 292fde46d6eSreyk if (ibuf_prepend(buf, &natt, sizeof(natt)) == -1) { 293fde46d6eSreyk log_debug("%s: failed to set NAT-T", __func__); 294fde46d6eSreyk return (-1); 295fde46d6eSreyk } 296fde46d6eSreyk } 297d9c13a0aSmikeb 2985ec2ede8Svgross if (sendtofrom(msg->msg_fd, ibuf_data(buf), ibuf_size(buf), 0, 2995ec2ede8Svgross (struct sockaddr *)&msg->msg_peer, msg->msg_peerlen, 3005ec2ede8Svgross (struct sockaddr *)&msg->msg_local, msg->msg_locallen) == -1) { 3010804246aStobhe log_warn("%s: sendtofrom", __func__); 3020804246aStobhe if (sa != NULL && errno == EADDRNOTAVAIL) { 3030804246aStobhe sa_state(env, sa, IKEV2_STATE_CLOSING); 3040804246aStobhe timer_del(env, &sa->sa_timer); 3050804246aStobhe timer_set(env, &sa->sa_timer, 3060804246aStobhe ikev2_ike_sa_timeout, sa); 3070804246aStobhe timer_add(env, &sa->sa_timer, 308a6fc7f59Shenning IKED_IKE_SA_DELETE_TIMEOUT); 309a6fc7f59Shenning } 310fde46d6eSreyk } 311fde46d6eSreyk 3120804246aStobhe if (sa == NULL) 313c45fd413Smikeb return (0); 314c45fd413Smikeb 315c45fd413Smikeb if ((m = ikev2_msg_copy(env, msg)) == NULL) { 316c45fd413Smikeb log_debug("%s: failed to copy a message", __func__); 317c45fd413Smikeb return (-1); 318c45fd413Smikeb } 319670a137dSmikeb m->msg_exchange = exchange; 320c45fd413Smikeb 321670a137dSmikeb if (flags & IKEV2_FLAG_RESPONSE) { 322c45fd413Smikeb TAILQ_INSERT_TAIL(&sa->sa_responses, m, msg_entry); 323b3eeacebSmikeb timer_set(env, &m->msg_timer, ikev2_msg_response_timeout, m); 324b3eeacebSmikeb timer_add(env, &m->msg_timer, IKED_RESPONSE_TIMEOUT); 325c45fd413Smikeb } else { 326c45fd413Smikeb TAILQ_INSERT_TAIL(&sa->sa_requests, m, msg_entry); 327b3eeacebSmikeb timer_set(env, &m->msg_timer, ikev2_msg_retransmit_timeout, m); 328b3eeacebSmikeb timer_add(env, &m->msg_timer, IKED_RETRANSMIT_TIMEOUT); 329c45fd413Smikeb } 330c45fd413Smikeb 331fde46d6eSreyk return (0); 332fde46d6eSreyk } 333fde46d6eSreyk 334d09d3a7dSreyk uint32_t 335c45fd413Smikeb ikev2_msg_id(struct iked *env, struct iked_sa *sa) 336fde46d6eSreyk { 337d09d3a7dSreyk uint32_t id = sa->sa_reqid; 338fde46d6eSreyk 33910650a52Smikeb if (++sa->sa_reqid == UINT32_MAX) { 340fde46d6eSreyk /* XXX we should close and renegotiate the connection now */ 341fde46d6eSreyk log_debug("%s: IKEv2 message sequence overflow", __func__); 342fde46d6eSreyk } 34310650a52Smikeb return (id); 344fde46d6eSreyk } 345fde46d6eSreyk 34615863c3aStobhe /* 34715863c3aStobhe * Calculate the final sizes of the IKEv2 header and the encrypted payload 34815863c3aStobhe * header. This must be done before encryption to make sure the correct 34915863c3aStobhe * headers are authenticated. 35015863c3aStobhe */ 35115863c3aStobhe int 35215863c3aStobhe ikev2_msg_encrypt_prepare(struct iked_sa *sa, struct ikev2_payload *pld, 35315863c3aStobhe struct ibuf *buf, struct ibuf *e, struct ike_header *hdr, 35415863c3aStobhe uint8_t firstpayload, int fragmentation) 35515863c3aStobhe { 35615863c3aStobhe size_t len, ivlen, encrlen, integrlen, blocklen, pldlen, outlen; 35715863c3aStobhe 35815863c3aStobhe if (sa == NULL || 35915863c3aStobhe sa->sa_encr == NULL || 36015863c3aStobhe sa->sa_integr == NULL) { 36115863c3aStobhe log_debug("%s: invalid SA", __func__); 36215863c3aStobhe return (-1); 36315863c3aStobhe } 36415863c3aStobhe 36515863c3aStobhe len = ibuf_size(e); 36615863c3aStobhe blocklen = cipher_length(sa->sa_encr); 36715863c3aStobhe integrlen = hash_length(sa->sa_integr); 36815863c3aStobhe ivlen = cipher_ivlength(sa->sa_encr); 36915863c3aStobhe encrlen = roundup(len + 1, blocklen); 37015863c3aStobhe outlen = cipher_outlength(sa->sa_encr, encrlen); 37115863c3aStobhe pldlen = ivlen + outlen + integrlen; 37215863c3aStobhe 37315863c3aStobhe if (ikev2_next_payload(pld, 37415863c3aStobhe pldlen + (fragmentation ? sizeof(struct ikev2_frag_payload) : 0), 37515863c3aStobhe firstpayload) == -1) 37615863c3aStobhe return (-1); 37715863c3aStobhe if (ikev2_set_header(hdr, ibuf_size(buf) + pldlen - sizeof(*hdr)) == -1) 37815863c3aStobhe return (-1); 37915863c3aStobhe 38015863c3aStobhe return (0); 38115863c3aStobhe } 38215863c3aStobhe 383fde46d6eSreyk struct ibuf * 38415863c3aStobhe ikev2_msg_encrypt(struct iked *env, struct iked_sa *sa, struct ibuf *src, 38515863c3aStobhe struct ibuf *aad) 386fde46d6eSreyk { 3879ebe96b0Stobhe size_t len, encrlen, integrlen, blocklen, 388fde46d6eSreyk outlen; 389d09d3a7dSreyk uint8_t *buf, pad = 0, *ptr; 39088d75aadSreyk struct ibuf *encr, *dst = NULL, *out = NULL; 391fde46d6eSreyk 392fde46d6eSreyk buf = ibuf_data(src); 393fde46d6eSreyk len = ibuf_size(src); 394fde46d6eSreyk 395328746baSreyk log_debug("%s: decrypted length %zu", __func__, len); 396fde46d6eSreyk print_hex(buf, 0, len); 397fde46d6eSreyk 398fde46d6eSreyk if (sa == NULL || 399fde46d6eSreyk sa->sa_encr == NULL || 400fde46d6eSreyk sa->sa_integr == NULL) { 401fde46d6eSreyk log_debug("%s: invalid SA", __func__); 402fde46d6eSreyk goto done; 403fde46d6eSreyk } 404fde46d6eSreyk 40588d75aadSreyk if (sa->sa_hdr.sh_initiator) 406fde46d6eSreyk encr = sa->sa_key_iencr; 40788d75aadSreyk else 408fde46d6eSreyk encr = sa->sa_key_rencr; 409fde46d6eSreyk 410fde46d6eSreyk blocklen = cipher_length(sa->sa_encr); 411fde46d6eSreyk integrlen = hash_length(sa->sa_integr); 412fde46d6eSreyk encrlen = roundup(len + sizeof(pad), blocklen); 413fde46d6eSreyk pad = encrlen - (len + sizeof(pad)); 414fde46d6eSreyk 415fde46d6eSreyk /* 416fde46d6eSreyk * Pad the payload and encrypt it 417fde46d6eSreyk */ 418fde46d6eSreyk if (pad) { 419fde46d6eSreyk if ((ptr = ibuf_advance(src, pad)) == NULL) 420fde46d6eSreyk goto done; 421fde46d6eSreyk arc4random_buf(ptr, pad); 422fde46d6eSreyk } 423fde46d6eSreyk if (ibuf_add(src, &pad, sizeof(pad)) != 0) 424fde46d6eSreyk goto done; 425fde46d6eSreyk 426328746baSreyk log_debug("%s: padded length %zu", __func__, ibuf_size(src)); 427fde46d6eSreyk print_hex(ibuf_data(src), 0, ibuf_size(src)); 428fde46d6eSreyk 429fde46d6eSreyk cipher_setkey(sa->sa_encr, encr->buf, ibuf_length(encr)); 43088d75aadSreyk cipher_setiv(sa->sa_encr, NULL, 0); /* XXX ivlen */ 43181b8fecaStobhe if (cipher_init_encrypt(sa->sa_encr) == -1) { 43281b8fecaStobhe log_info("%s: error initiating cipher.", __func__); 43381b8fecaStobhe goto done; 43481b8fecaStobhe } 435fde46d6eSreyk 436fde46d6eSreyk if ((dst = ibuf_dup(sa->sa_encr->encr_iv)) == NULL) 437fde46d6eSreyk goto done; 438fde46d6eSreyk 439fde46d6eSreyk if ((out = ibuf_new(NULL, 440fde46d6eSreyk cipher_outlength(sa->sa_encr, encrlen))) == NULL) 441fde46d6eSreyk goto done; 442fde46d6eSreyk 443fde46d6eSreyk outlen = ibuf_size(out); 44415863c3aStobhe 44515863c3aStobhe /* Add AAD for AEAD ciphers */ 44615863c3aStobhe if (sa->sa_integr->hash_isaead) 44715863c3aStobhe cipher_aad(sa->sa_encr, ibuf_data(aad), 44815863c3aStobhe ibuf_length(aad), &outlen); 44915863c3aStobhe 45081b8fecaStobhe if (cipher_update(sa->sa_encr, ibuf_data(src), encrlen, 45181b8fecaStobhe ibuf_data(out), &outlen) == -1) { 45281b8fecaStobhe log_info("%s: error updating cipher.", __func__); 45381b8fecaStobhe goto done; 45481b8fecaStobhe } 455fde46d6eSreyk 45615863c3aStobhe if (cipher_final(sa->sa_encr) == -1) { 45715863c3aStobhe log_info("%s: encryption failed.", __func__); 45815863c3aStobhe goto done; 45915863c3aStobhe } 46015863c3aStobhe 461fde46d6eSreyk if (outlen && ibuf_add(dst, ibuf_data(out), outlen) != 0) 462fde46d6eSreyk goto done; 463fde46d6eSreyk 464fde46d6eSreyk if ((ptr = ibuf_advance(dst, integrlen)) == NULL) 465fde46d6eSreyk goto done; 4668fbd7fcbSdoug explicit_bzero(ptr, integrlen); 467fde46d6eSreyk 468328746baSreyk log_debug("%s: length %zu, padding %d, output length %zu", 469fde46d6eSreyk __func__, len + sizeof(pad), pad, ibuf_size(dst)); 470fde46d6eSreyk print_hex(ibuf_data(dst), 0, ibuf_size(dst)); 471fde46d6eSreyk 472fde46d6eSreyk ibuf_release(src); 473fde46d6eSreyk ibuf_release(out); 474fde46d6eSreyk return (dst); 475fde46d6eSreyk done: 476fde46d6eSreyk ibuf_release(src); 477fde46d6eSreyk ibuf_release(out); 478fde46d6eSreyk ibuf_release(dst); 479fde46d6eSreyk return (NULL); 480fde46d6eSreyk } 481fde46d6eSreyk 482fde46d6eSreyk int 483fde46d6eSreyk ikev2_msg_integr(struct iked *env, struct iked_sa *sa, struct ibuf *src) 484fde46d6eSreyk { 485fde46d6eSreyk int ret = -1; 486fde46d6eSreyk size_t integrlen, tmplen; 48788d75aadSreyk struct ibuf *integr, *tmp = NULL; 488d09d3a7dSreyk uint8_t *ptr; 489fde46d6eSreyk 490328746baSreyk log_debug("%s: message length %zu", __func__, ibuf_size(src)); 491fde46d6eSreyk print_hex(ibuf_data(src), 0, ibuf_size(src)); 492fde46d6eSreyk 493fde46d6eSreyk if (sa == NULL || 49415863c3aStobhe sa->sa_encr == NULL || 495fde46d6eSreyk sa->sa_integr == NULL) { 496fde46d6eSreyk log_debug("%s: invalid SA", __func__); 497fde46d6eSreyk return (-1); 498fde46d6eSreyk } 499fde46d6eSreyk 500fde46d6eSreyk integrlen = hash_length(sa->sa_integr); 501328746baSreyk log_debug("%s: integrity checksum length %zu", __func__, 502fde46d6eSreyk integrlen); 503fde46d6eSreyk 504fde46d6eSreyk /* 505fde46d6eSreyk * Validate packet checksum 506fde46d6eSreyk */ 507fde46d6eSreyk if ((tmp = ibuf_new(NULL, hash_keylength(sa->sa_integr))) == NULL) 508fde46d6eSreyk goto done; 509fde46d6eSreyk 51015863c3aStobhe if (!sa->sa_integr->hash_isaead) { 51115863c3aStobhe if (sa->sa_hdr.sh_initiator) 51215863c3aStobhe integr = sa->sa_key_iauth; 51315863c3aStobhe else 51415863c3aStobhe integr = sa->sa_key_rauth; 51515863c3aStobhe 51615863c3aStobhe hash_setkey(sa->sa_integr, ibuf_data(integr), 51715863c3aStobhe ibuf_size(integr)); 518fde46d6eSreyk hash_init(sa->sa_integr); 519fde46d6eSreyk hash_update(sa->sa_integr, ibuf_data(src), 520fde46d6eSreyk ibuf_size(src) - integrlen); 521fde46d6eSreyk hash_final(sa->sa_integr, ibuf_data(tmp), &tmplen); 522fde46d6eSreyk 523fde46d6eSreyk if (tmplen != integrlen) { 524fde46d6eSreyk log_debug("%s: hash failure", __func__); 525fde46d6eSreyk goto done; 526fde46d6eSreyk } 52715863c3aStobhe } else { 52815863c3aStobhe /* Append AEAD tag */ 52915863c3aStobhe if (cipher_gettag(sa->sa_encr, ibuf_data(tmp), ibuf_size(tmp))) 53015863c3aStobhe goto done; 53115863c3aStobhe } 532fde46d6eSreyk 533fde46d6eSreyk if ((ptr = ibuf_seek(src, 534fde46d6eSreyk ibuf_size(src) - integrlen, integrlen)) == NULL) 535fde46d6eSreyk goto done; 53615863c3aStobhe memcpy(ptr, ibuf_data(tmp), integrlen); 537fde46d6eSreyk 538fde46d6eSreyk print_hex(ibuf_data(tmp), 0, ibuf_size(tmp)); 539fde46d6eSreyk 540fde46d6eSreyk ret = 0; 541fde46d6eSreyk done: 542fde46d6eSreyk ibuf_release(tmp); 543fde46d6eSreyk 544fde46d6eSreyk return (ret); 545fde46d6eSreyk } 546fde46d6eSreyk 547fde46d6eSreyk struct ibuf * 548fde46d6eSreyk ikev2_msg_decrypt(struct iked *env, struct iked_sa *sa, 549fde46d6eSreyk struct ibuf *msg, struct ibuf *src) 550fde46d6eSreyk { 551e0696045Sreyk ssize_t ivlen, encrlen, integrlen, blocklen, 552fde46d6eSreyk outlen, tmplen; 55315863c3aStobhe uint8_t pad = 0, *ptr, *integrdata; 554fde46d6eSreyk struct ibuf *integr, *encr, *tmp = NULL, *out = NULL; 555fde46d6eSreyk off_t ivoff, encroff, integroff; 556fde46d6eSreyk 557fde46d6eSreyk if (sa == NULL || 558fde46d6eSreyk sa->sa_encr == NULL || 559fde46d6eSreyk sa->sa_integr == NULL) { 560fde46d6eSreyk log_debug("%s: invalid SA", __func__); 561fde46d6eSreyk print_hex(ibuf_data(src), 0, ibuf_size(src)); 562fde46d6eSreyk goto done; 563fde46d6eSreyk } 564fde46d6eSreyk 565fde46d6eSreyk if (!sa->sa_hdr.sh_initiator) { 566fde46d6eSreyk encr = sa->sa_key_iencr; 567fde46d6eSreyk integr = sa->sa_key_iauth; 568fde46d6eSreyk } else { 569fde46d6eSreyk encr = sa->sa_key_rencr; 570fde46d6eSreyk integr = sa->sa_key_rauth; 571fde46d6eSreyk } 572fde46d6eSreyk 573fde46d6eSreyk blocklen = cipher_length(sa->sa_encr); 574fde46d6eSreyk ivlen = cipher_ivlength(sa->sa_encr); 575fde46d6eSreyk ivoff = 0; 576fde46d6eSreyk integrlen = hash_length(sa->sa_integr); 577fde46d6eSreyk integroff = ibuf_size(src) - integrlen; 578fde46d6eSreyk encroff = ivlen; 579fde46d6eSreyk encrlen = ibuf_size(src) - integrlen - ivlen; 580fde46d6eSreyk 581e0696045Sreyk if (encrlen < 0 || integroff < 0) { 582e0696045Sreyk log_debug("%s: invalid integrity value", __func__); 583e0696045Sreyk goto done; 584e0696045Sreyk } 585e0696045Sreyk 586328746baSreyk log_debug("%s: IV length %zd", __func__, ivlen); 587fde46d6eSreyk print_hex(ibuf_data(src), 0, ivlen); 588328746baSreyk log_debug("%s: encrypted payload length %zd", __func__, encrlen); 589fde46d6eSreyk print_hex(ibuf_data(src), encroff, encrlen); 590328746baSreyk log_debug("%s: integrity checksum length %zd", __func__, integrlen); 591fde46d6eSreyk print_hex(ibuf_data(src), integroff, integrlen); 592fde46d6eSreyk 593fde46d6eSreyk /* 594fde46d6eSreyk * Validate packet checksum 595fde46d6eSreyk */ 59615863c3aStobhe if (!sa->sa_integr->hash_isaead) { 597d0e3d0abStobhe if ((tmp = ibuf_new(NULL, hash_keylength(sa->sa_integr))) == NULL) 598fde46d6eSreyk goto done; 599fde46d6eSreyk 600fde46d6eSreyk hash_setkey(sa->sa_integr, integr->buf, ibuf_length(integr)); 601fde46d6eSreyk hash_init(sa->sa_integr); 602fde46d6eSreyk hash_update(sa->sa_integr, ibuf_data(msg), 603fde46d6eSreyk ibuf_size(msg) - integrlen); 604fde46d6eSreyk hash_final(sa->sa_integr, tmp->buf, &tmplen); 605fde46d6eSreyk 60615863c3aStobhe integrdata = ibuf_seek(src, integroff, integrlen); 60715863c3aStobhe if (integrdata == NULL) 60815863c3aStobhe goto done; 60915863c3aStobhe if (memcmp(tmp->buf, integrdata, integrlen) != 0) { 610fde46d6eSreyk log_debug("%s: integrity check failed", __func__); 611fde46d6eSreyk goto done; 612fde46d6eSreyk } 613fde46d6eSreyk 614b0eeedd0Smikeb log_debug("%s: integrity check succeeded", __func__); 615fde46d6eSreyk print_hex(tmp->buf, 0, tmplen); 616fde46d6eSreyk 617fde46d6eSreyk ibuf_release(tmp); 618fde46d6eSreyk tmp = NULL; 61915863c3aStobhe } 620fde46d6eSreyk 621fde46d6eSreyk /* 622fde46d6eSreyk * Decrypt the payload and strip any padding 623fde46d6eSreyk */ 624fde46d6eSreyk if ((encrlen % blocklen) != 0) { 625fde46d6eSreyk log_debug("%s: unaligned encrypted payload", __func__); 626fde46d6eSreyk goto done; 627fde46d6eSreyk } 628fde46d6eSreyk 629fde46d6eSreyk cipher_setkey(sa->sa_encr, encr->buf, ibuf_length(encr)); 630fde46d6eSreyk cipher_setiv(sa->sa_encr, ibuf_data(src) + ivoff, ivlen); 63181b8fecaStobhe if (cipher_init_decrypt(sa->sa_encr) == -1) { 63281b8fecaStobhe log_info("%s: error initiating cipher.", __func__); 63381b8fecaStobhe goto done; 63481b8fecaStobhe } 635fde46d6eSreyk 63615863c3aStobhe /* Set AEAD tag */ 63715863c3aStobhe if (sa->sa_integr->hash_isaead) { 63815863c3aStobhe integrdata = ibuf_seek(src, integroff, integrlen); 63915863c3aStobhe if (integrdata == NULL) 64015863c3aStobhe goto done; 64115863c3aStobhe if (cipher_settag(sa->sa_encr, integrdata, integrlen)) { 64215863c3aStobhe log_info("%s: failed to set tag.", __func__); 64315863c3aStobhe goto done; 64415863c3aStobhe } 64515863c3aStobhe } 64615863c3aStobhe 647fde46d6eSreyk if ((out = ibuf_new(NULL, cipher_outlength(sa->sa_encr, 648fde46d6eSreyk encrlen))) == NULL) 649fde46d6eSreyk goto done; 650fde46d6eSreyk 65115863c3aStobhe /* 65215863c3aStobhe * Add additional authenticated data for AEAD ciphers 65315863c3aStobhe */ 65415863c3aStobhe if (sa->sa_integr->hash_isaead) { 65515863c3aStobhe log_debug("%s: AAD length %zu", __func__, ibuf_length(msg) - ibuf_length(src)); 65615863c3aStobhe print_hex(ibuf_data(msg), 0, ibuf_length(msg) - ibuf_length(src)); 65715863c3aStobhe cipher_aad(sa->sa_encr, ibuf_data(msg), 65815863c3aStobhe ibuf_length(msg) - ibuf_length(src), &outlen); 65915863c3aStobhe } 66015863c3aStobhe 661e0696045Sreyk if ((outlen = ibuf_length(out)) != 0) { 66281b8fecaStobhe if (cipher_update(sa->sa_encr, ibuf_data(src) + encroff, 66381b8fecaStobhe encrlen, ibuf_data(out), &outlen) == -1) { 66481b8fecaStobhe log_info("%s: error updating cipher.", __func__); 66581b8fecaStobhe goto done; 66681b8fecaStobhe } 6673189733aSmikeb 668fde46d6eSreyk ptr = ibuf_seek(out, outlen - 1, 1); 669fde46d6eSreyk pad = *ptr; 670e0696045Sreyk } 671fde46d6eSreyk 67215863c3aStobhe if (cipher_final(sa->sa_encr) == -1) { 67315863c3aStobhe log_info("%s: decryption failed.", __func__); 67415863c3aStobhe goto done; 67515863c3aStobhe } 67615863c3aStobhe 677328746baSreyk log_debug("%s: decrypted payload length %zd/%zd padding %d", 678fde46d6eSreyk __func__, outlen, encrlen, pad); 679fde46d6eSreyk print_hex(ibuf_data(out), 0, ibuf_size(out)); 680fde46d6eSreyk 68165c540d0Spatrick /* Strip padding and padding length */ 68265c540d0Spatrick if (ibuf_setsize(out, outlen - pad - 1) != 0) 683fde46d6eSreyk goto done; 684fde46d6eSreyk 685fde46d6eSreyk ibuf_release(src); 686fde46d6eSreyk return (out); 687fde46d6eSreyk done: 688fde46d6eSreyk ibuf_release(tmp); 689fde46d6eSreyk ibuf_release(out); 690fde46d6eSreyk ibuf_release(src); 691fde46d6eSreyk return (NULL); 692fde46d6eSreyk } 693fde46d6eSreyk 694fde46d6eSreyk int 69565c540d0Spatrick ikev2_check_frag_oversize(struct iked_sa *sa, struct ibuf *buf) { 69665c540d0Spatrick size_t len = ibuf_length(buf); 69765c540d0Spatrick sa_family_t sa_fam; 69865c540d0Spatrick size_t max; 69965c540d0Spatrick size_t ivlen, integrlen, blocklen; 70065c540d0Spatrick 70115863c3aStobhe if (sa == NULL || 70215863c3aStobhe sa->sa_encr == NULL || 70315863c3aStobhe sa->sa_integr == NULL) { 70415863c3aStobhe log_debug("%s: invalid SA", __func__); 70515863c3aStobhe return (-1); 70615863c3aStobhe } 70715863c3aStobhe 70865c540d0Spatrick sa_fam = ((struct sockaddr *)&sa->sa_local.addr)->sa_family; 70965c540d0Spatrick 71065c540d0Spatrick max = sa_fam == AF_INET ? IKEV2_MAXLEN_IPV4_FRAG 71165c540d0Spatrick : IKEV2_MAXLEN_IPV6_FRAG; 71265c540d0Spatrick 71365c540d0Spatrick blocklen = cipher_length(sa->sa_encr); 71465c540d0Spatrick ivlen = cipher_ivlength(sa->sa_encr); 71565c540d0Spatrick integrlen = hash_length(sa->sa_integr); 71665c540d0Spatrick 71765c540d0Spatrick /* Estimated maximum packet size (with 0 < padding < blocklen) */ 71865c540d0Spatrick return ((len + ivlen + blocklen + integrlen) >= max) && sa->sa_frag; 71965c540d0Spatrick } 72065c540d0Spatrick 72165c540d0Spatrick int 722c45fd413Smikeb ikev2_msg_send_encrypt(struct iked *env, struct iked_sa *sa, struct ibuf **ep, 723d09d3a7dSreyk uint8_t exchange, uint8_t firstpayload, int response) 724fde46d6eSreyk { 725fde46d6eSreyk struct iked_message resp; 726fde46d6eSreyk struct ike_header *hdr; 727fde46d6eSreyk struct ikev2_payload *pld; 728fde46d6eSreyk struct ibuf *buf, *e = *ep; 729fde46d6eSreyk int ret = -1; 730fde46d6eSreyk 73165c540d0Spatrick /* Check if msg needs to be fragmented */ 73265c540d0Spatrick if (ikev2_check_frag_oversize(sa, e)) { 73365c540d0Spatrick return ikev2_send_encrypted_fragments(env, sa, e, exchange, 73465c540d0Spatrick firstpayload, response); 73565c540d0Spatrick } 73665c540d0Spatrick 737c45fd413Smikeb if ((buf = ikev2_msg_init(env, &resp, &sa->sa_peer.addr, 738c45fd413Smikeb sa->sa_peer.addr.ss_len, &sa->sa_local.addr, 739c45fd413Smikeb sa->sa_local.addr.ss_len, response)) == NULL) 740fde46d6eSreyk goto done; 741fde46d6eSreyk 74230904802Spatrick resp.msg_msgid = response ? sa->sa_msgid_current : ikev2_msg_id(env, sa); 743c45fd413Smikeb 744fde46d6eSreyk /* IKE header */ 745c45fd413Smikeb if ((hdr = ikev2_add_header(buf, sa, resp.msg_msgid, IKEV2_PAYLOAD_SK, 746c45fd413Smikeb exchange, response ? IKEV2_FLAG_RESPONSE : 0)) == NULL) 747fde46d6eSreyk goto done; 748fde46d6eSreyk 749fde46d6eSreyk if ((pld = ikev2_add_payload(buf)) == NULL) 750fde46d6eSreyk goto done; 751fde46d6eSreyk 75215863c3aStobhe if (ikev2_msg_encrypt_prepare(sa, pld, buf, e, hdr, firstpayload, 0) == -1) 75315863c3aStobhe goto done; 75415863c3aStobhe 755fde46d6eSreyk /* Encrypt message and add as an E payload */ 75615863c3aStobhe if ((e = ikev2_msg_encrypt(env, sa, e, buf)) == NULL) { 757fde46d6eSreyk log_debug("%s: encryption failed", __func__); 758fde46d6eSreyk goto done; 759fde46d6eSreyk } 760fde46d6eSreyk if (ibuf_cat(buf, e) != 0) 761fde46d6eSreyk goto done; 762fde46d6eSreyk 763fde46d6eSreyk /* Add integrity checksum (HMAC) */ 764fde46d6eSreyk if (ikev2_msg_integr(env, sa, buf) != 0) { 765fde46d6eSreyk log_debug("%s: integrity checksum failed", __func__); 766fde46d6eSreyk goto done; 767fde46d6eSreyk } 768fde46d6eSreyk 769fde46d6eSreyk resp.msg_data = buf; 770fde46d6eSreyk resp.msg_sa = sa; 771d9c13a0aSmikeb resp.msg_fd = sa->sa_fd; 772fde46d6eSreyk TAILQ_INIT(&resp.msg_proposals); 773fde46d6eSreyk 774fde46d6eSreyk (void)ikev2_pld_parse(env, hdr, &resp, 0); 775fde46d6eSreyk 776d9c13a0aSmikeb ret = ikev2_msg_send(env, &resp); 777fde46d6eSreyk 778fde46d6eSreyk done: 779fde46d6eSreyk /* e is cleaned up by the calling function */ 780fde46d6eSreyk *ep = e; 781763023d6Sreyk ikev2_msg_cleanup(env, &resp); 782fde46d6eSreyk 783fde46d6eSreyk return (ret); 784fde46d6eSreyk } 785fde46d6eSreyk 78665c540d0Spatrick int 78765c540d0Spatrick ikev2_send_encrypted_fragments(struct iked *env, struct iked_sa *sa, 78865c540d0Spatrick struct ibuf *in, uint8_t exchange, uint8_t firstpayload, int response) { 78965c540d0Spatrick struct iked_message resp; 7904387480dStobhe struct ibuf *buf, *e = NULL; 79165c540d0Spatrick struct ike_header *hdr; 79265c540d0Spatrick struct ikev2_payload *pld; 79365c540d0Spatrick struct ikev2_frag_payload *frag; 79465c540d0Spatrick sa_family_t sa_fam; 79565c540d0Spatrick size_t ivlen, integrlen, blocklen; 796ab8e3451Sderaadt size_t max_len, left, offset=0; 79765c540d0Spatrick size_t frag_num = 1, frag_total; 79865c540d0Spatrick uint8_t *data; 79965c540d0Spatrick uint32_t msgid; 80065c540d0Spatrick int ret = -1; 80165c540d0Spatrick 80215863c3aStobhe if (sa == NULL || 80315863c3aStobhe sa->sa_encr == NULL || 80415863c3aStobhe sa->sa_integr == NULL) { 80515863c3aStobhe log_debug("%s: invalid SA", __func__); 80615863c3aStobhe goto done; 80715863c3aStobhe } 80815863c3aStobhe 80965c540d0Spatrick sa_fam = ((struct sockaddr *)&sa->sa_local.addr)->sa_family; 81065c540d0Spatrick 81165c540d0Spatrick left = ibuf_length(in); 81265c540d0Spatrick 81365c540d0Spatrick /* Calculate max allowed size of a fragments payload */ 81465c540d0Spatrick blocklen = cipher_length(sa->sa_encr); 81565c540d0Spatrick ivlen = cipher_ivlength(sa->sa_encr); 81665c540d0Spatrick integrlen = hash_length(sa->sa_integr); 81765c540d0Spatrick max_len = (sa_fam == AF_INET ? IKEV2_MAXLEN_IPV4_FRAG 81865c540d0Spatrick : IKEV2_MAXLEN_IPV6_FRAG) 81965c540d0Spatrick - ivlen - blocklen - integrlen; 82065c540d0Spatrick 82165c540d0Spatrick /* Total number of fragments to send */ 82265c540d0Spatrick frag_total = (left / max_len) + 1; 82365c540d0Spatrick 82465c540d0Spatrick msgid = response ? sa->sa_msgid_current : ikev2_msg_id(env, sa); 82565c540d0Spatrick 82665c540d0Spatrick while (frag_num <= frag_total) { 82765c540d0Spatrick if ((buf = ikev2_msg_init(env, &resp, &sa->sa_peer.addr, 82865c540d0Spatrick sa->sa_peer.addr.ss_len, &sa->sa_local.addr, 82965c540d0Spatrick sa->sa_local.addr.ss_len, response)) == NULL) 83065c540d0Spatrick goto done; 83165c540d0Spatrick 83265c540d0Spatrick resp.msg_msgid = msgid; 83365c540d0Spatrick 83465c540d0Spatrick /* IKE header */ 83565c540d0Spatrick if ((hdr = ikev2_add_header(buf, sa, resp.msg_msgid, 83665c540d0Spatrick IKEV2_PAYLOAD_SKF, exchange, response ? IKEV2_FLAG_RESPONSE 83765c540d0Spatrick : 0)) == NULL) 83865c540d0Spatrick goto done; 83965c540d0Spatrick 84065c540d0Spatrick /* Payload header */ 84165c540d0Spatrick if ((pld = ikev2_add_payload(buf)) == NULL) 84265c540d0Spatrick goto done; 84365c540d0Spatrick 84465c540d0Spatrick /* Fragment header */ 84565c540d0Spatrick if ((frag = ibuf_advance(buf, sizeof(*frag))) == NULL) { 84665c540d0Spatrick log_debug("%s: failed to add SKF fragment header", 84765c540d0Spatrick __func__); 84865c540d0Spatrick goto done; 84965c540d0Spatrick } 85065c540d0Spatrick frag->frag_num = htobe16(frag_num); 85165c540d0Spatrick frag->frag_total = htobe16(frag_total); 85265c540d0Spatrick 85365c540d0Spatrick /* Encrypt message and add as an E payload */ 85465c540d0Spatrick data = ibuf_seek(in, offset, 0); 855*d8ea035bSderaadt if ((e = ibuf_new(data, MINIMUM(left, max_len))) == NULL) { 85665c540d0Spatrick goto done; 85765c540d0Spatrick } 85815863c3aStobhe 85915863c3aStobhe if (ikev2_msg_encrypt_prepare(sa, pld, buf, e, hdr, 86015863c3aStobhe firstpayload, 1) == -1) 86115863c3aStobhe goto done; 86215863c3aStobhe 86315863c3aStobhe if ((e = ikev2_msg_encrypt(env, sa, e, buf)) == NULL) { 86465c540d0Spatrick log_debug("%s: encryption failed", __func__); 86565c540d0Spatrick goto done; 86665c540d0Spatrick } 86765c540d0Spatrick if (ibuf_cat(buf, e) != 0) 86865c540d0Spatrick goto done; 86965c540d0Spatrick 87065c540d0Spatrick /* Add integrity checksum (HMAC) */ 87165c540d0Spatrick if (ikev2_msg_integr(env, sa, buf) != 0) { 87265c540d0Spatrick log_debug("%s: integrity checksum failed", __func__); 87365c540d0Spatrick goto done; 87465c540d0Spatrick } 87565c540d0Spatrick 87665c540d0Spatrick log_debug("%s: Fragment %zu of %zu has size of %zu bytes.", 87765c540d0Spatrick __func__, frag_num, frag_total, 87865c540d0Spatrick ibuf_size(buf) - sizeof(*hdr)); 87965c540d0Spatrick print_hex(ibuf_data(buf), 0, ibuf_size(buf)); 88065c540d0Spatrick 88165c540d0Spatrick resp.msg_data = buf; 88265c540d0Spatrick resp.msg_sa = sa; 88365c540d0Spatrick resp.msg_fd = sa->sa_fd; 88465c540d0Spatrick TAILQ_INIT(&resp.msg_proposals); 88565c540d0Spatrick 88665c540d0Spatrick if (ikev2_msg_send(env, &resp) == -1) 88765c540d0Spatrick goto done; 88865c540d0Spatrick 889*d8ea035bSderaadt offset += MINIMUM(left, max_len); 890*d8ea035bSderaadt left -= MINIMUM(left, max_len); 89165c540d0Spatrick frag_num++; 89265c540d0Spatrick 89365c540d0Spatrick /* MUST be zero after first fragment */ 89465c540d0Spatrick firstpayload = 0; 89565c540d0Spatrick 89665c540d0Spatrick ikev2_msg_cleanup(env, &resp); 89765c540d0Spatrick ibuf_release(e); 89865c540d0Spatrick e = NULL; 89965c540d0Spatrick } 90065c540d0Spatrick 90165c540d0Spatrick return 0; 90265c540d0Spatrick done: 90365c540d0Spatrick ikev2_msg_cleanup(env, &resp); 90465c540d0Spatrick ibuf_release(e); 90565c540d0Spatrick return ret; 90665c540d0Spatrick } 90765c540d0Spatrick 908fde46d6eSreyk struct ibuf * 909fde46d6eSreyk ikev2_msg_auth(struct iked *env, struct iked_sa *sa, int response) 910fde46d6eSreyk { 911fde46d6eSreyk struct ibuf *authmsg = NULL, *nonce, *prfkey, *buf; 912d09d3a7dSreyk uint8_t *ptr; 913fde46d6eSreyk struct iked_id *id; 914fde46d6eSreyk size_t tmplen; 915fde46d6eSreyk 916fde46d6eSreyk /* 917fde46d6eSreyk * Create the payload to be signed/MAC'ed for AUTH 918fde46d6eSreyk */ 919fde46d6eSreyk 920fde46d6eSreyk if (!response) { 921fde46d6eSreyk if ((nonce = sa->sa_rnonce) == NULL || 922fde46d6eSreyk (sa->sa_iid.id_type == 0) || 923fde46d6eSreyk (prfkey = sa->sa_key_iprf) == NULL || 924fde46d6eSreyk (buf = sa->sa_1stmsg) == NULL) 925fde46d6eSreyk return (NULL); 926fde46d6eSreyk id = &sa->sa_iid; 927fde46d6eSreyk } else { 928fde46d6eSreyk if ((nonce = sa->sa_inonce) == NULL || 929fde46d6eSreyk (sa->sa_rid.id_type == 0) || 930fde46d6eSreyk (prfkey = sa->sa_key_rprf) == NULL || 931fde46d6eSreyk (buf = sa->sa_2ndmsg) == NULL) 932fde46d6eSreyk return (NULL); 933fde46d6eSreyk id = &sa->sa_rid; 934fde46d6eSreyk } 935fde46d6eSreyk 936fde46d6eSreyk if ((authmsg = ibuf_dup(buf)) == NULL) 937fde46d6eSreyk return (NULL); 938fde46d6eSreyk if (ibuf_cat(authmsg, nonce) != 0) 939fde46d6eSreyk goto fail; 940fde46d6eSreyk 941fde46d6eSreyk if ((hash_setkey(sa->sa_prf, ibuf_data(prfkey), 942fde46d6eSreyk ibuf_size(prfkey))) == NULL) 943fde46d6eSreyk goto fail; 944fde46d6eSreyk 945d0e3d0abStobhe /* require non-truncating hash */ 946d0e3d0abStobhe if (hash_keylength(sa->sa_prf) != hash_length(sa->sa_prf)) 947d0e3d0abStobhe goto fail; 948d0e3d0abStobhe 949d0e3d0abStobhe if ((ptr = ibuf_advance(authmsg, hash_keylength(sa->sa_prf))) == NULL) 950fde46d6eSreyk goto fail; 951fde46d6eSreyk 952fde46d6eSreyk hash_init(sa->sa_prf); 953fde46d6eSreyk hash_update(sa->sa_prf, ibuf_data(id->id_buf), ibuf_size(id->id_buf)); 954fde46d6eSreyk hash_final(sa->sa_prf, ptr, &tmplen); 955fde46d6eSreyk 956fde46d6eSreyk if (tmplen != hash_length(sa->sa_prf)) 957fde46d6eSreyk goto fail; 958fde46d6eSreyk 959328746baSreyk log_debug("%s: %s auth data length %zu", 960fde46d6eSreyk __func__, response ? "responder" : "initiator", 961fde46d6eSreyk ibuf_size(authmsg)); 962fde46d6eSreyk print_hex(ibuf_data(authmsg), 0, ibuf_size(authmsg)); 963fde46d6eSreyk 964fde46d6eSreyk return (authmsg); 965fde46d6eSreyk 966fde46d6eSreyk fail: 967fde46d6eSreyk ibuf_release(authmsg); 968fde46d6eSreyk return (NULL); 969fde46d6eSreyk } 970fde46d6eSreyk 971fde46d6eSreyk int 972fde46d6eSreyk ikev2_msg_authverify(struct iked *env, struct iked_sa *sa, 973d09d3a7dSreyk struct iked_auth *auth, uint8_t *buf, size_t len, struct ibuf *authmsg) 974fde46d6eSreyk { 975d09d3a7dSreyk uint8_t *key, *psk = NULL; 976fde46d6eSreyk ssize_t keylen; 977fde46d6eSreyk struct iked_id *id; 978fde46d6eSreyk struct iked_dsa *dsa = NULL; 979fde46d6eSreyk int ret = -1; 980d09d3a7dSreyk uint8_t keytype; 981fde46d6eSreyk 982fde46d6eSreyk if (sa->sa_hdr.sh_initiator) 983fde46d6eSreyk id = &sa->sa_rcert; 984fde46d6eSreyk else 985fde46d6eSreyk id = &sa->sa_icert; 986fde46d6eSreyk 987fde46d6eSreyk if ((dsa = dsa_verify_new(auth->auth_method, sa->sa_prf)) == NULL) { 988fde46d6eSreyk log_debug("%s: invalid auth method", __func__); 989fde46d6eSreyk return (-1); 990fde46d6eSreyk } 991fde46d6eSreyk 992fde46d6eSreyk switch (auth->auth_method) { 993fde46d6eSreyk case IKEV2_AUTH_SHARED_KEY_MIC: 994fde46d6eSreyk if (!auth->auth_length) { 995fde46d6eSreyk log_debug("%s: no pre-shared key found", __func__); 996fde46d6eSreyk goto done; 997fde46d6eSreyk } 998fde46d6eSreyk if ((keylen = ikev2_psk(sa, auth->auth_data, 999fde46d6eSreyk auth->auth_length, &psk)) == -1) { 1000fde46d6eSreyk log_debug("%s: failed to get PSK", __func__); 1001fde46d6eSreyk goto done; 1002fde46d6eSreyk } 1003fde46d6eSreyk key = psk; 1004fde46d6eSreyk keytype = 0; 1005fde46d6eSreyk break; 1006fde46d6eSreyk default: 1007202133c5Sreyk if (!id->id_type || !ibuf_length(id->id_buf)) { 1008fde46d6eSreyk log_debug("%s: no cert found", __func__); 1009fde46d6eSreyk goto done; 1010fde46d6eSreyk } 1011fde46d6eSreyk key = ibuf_data(id->id_buf); 1012fde46d6eSreyk keylen = ibuf_size(id->id_buf); 1013fde46d6eSreyk keytype = id->id_type; 1014fde46d6eSreyk break; 1015fde46d6eSreyk } 1016fde46d6eSreyk 1017328746baSreyk log_debug("%s: method %s keylen %zd type %s", __func__, 1018fde46d6eSreyk print_map(auth->auth_method, ikev2_auth_map), keylen, 1019fde46d6eSreyk print_map(id->id_type, ikev2_cert_map)); 1020fde46d6eSreyk 1021fde46d6eSreyk if (dsa_setkey(dsa, key, keylen, keytype) == NULL || 102248b975e3Smarkus dsa_init(dsa, buf, len) != 0 || 1023fde46d6eSreyk dsa_update(dsa, ibuf_data(authmsg), ibuf_size(authmsg))) { 1024fde46d6eSreyk log_debug("%s: failed to compute digital signature", __func__); 1025fde46d6eSreyk goto done; 1026fde46d6eSreyk } 1027fde46d6eSreyk 1028fde46d6eSreyk if ((ret = dsa_verify_final(dsa, buf, len)) == 0) { 1029fde46d6eSreyk log_debug("%s: authentication successful", __func__); 1030fde46d6eSreyk sa_state(env, sa, IKEV2_STATE_AUTH_SUCCESS); 10314a986ab9Smarkus sa_stateflags(sa, IKED_REQ_AUTHVALID); 1032fde46d6eSreyk } else { 1033fde46d6eSreyk log_debug("%s: authentication failed", __func__); 1034fde46d6eSreyk sa_state(env, sa, IKEV2_STATE_AUTH_REQUEST); 1035fde46d6eSreyk } 1036fde46d6eSreyk 1037fde46d6eSreyk done: 1038fde46d6eSreyk free(psk); 1039fde46d6eSreyk dsa_free(dsa); 1040fde46d6eSreyk 1041fde46d6eSreyk return (ret); 1042fde46d6eSreyk } 1043fde46d6eSreyk 1044fde46d6eSreyk int 1045fde46d6eSreyk ikev2_msg_authsign(struct iked *env, struct iked_sa *sa, 1046fde46d6eSreyk struct iked_auth *auth, struct ibuf *authmsg) 1047fde46d6eSreyk { 1048d09d3a7dSreyk uint8_t *key, *psk = NULL; 10495e4d3a37Sreyk ssize_t keylen, siglen; 1050fde46d6eSreyk struct iked_hash *prf = sa->sa_prf; 1051fde46d6eSreyk struct iked_id *id; 1052fde46d6eSreyk struct iked_dsa *dsa = NULL; 1053fde46d6eSreyk struct ibuf *buf; 1054fde46d6eSreyk int ret = -1; 1055d09d3a7dSreyk uint8_t keytype; 1056fde46d6eSreyk 1057fde46d6eSreyk if (sa->sa_hdr.sh_initiator) 1058fde46d6eSreyk id = &sa->sa_icert; 1059fde46d6eSreyk else 1060fde46d6eSreyk id = &sa->sa_rcert; 1061fde46d6eSreyk 1062fde46d6eSreyk if ((dsa = dsa_sign_new(auth->auth_method, prf)) == NULL) { 1063fde46d6eSreyk log_debug("%s: invalid auth method", __func__); 1064fde46d6eSreyk return (-1); 1065fde46d6eSreyk } 1066fde46d6eSreyk 1067fde46d6eSreyk switch (auth->auth_method) { 1068fde46d6eSreyk case IKEV2_AUTH_SHARED_KEY_MIC: 1069fde46d6eSreyk if (!auth->auth_length) { 1070fde46d6eSreyk log_debug("%s: no pre-shared key found", __func__); 1071fde46d6eSreyk goto done; 1072fde46d6eSreyk } 1073fde46d6eSreyk if ((keylen = ikev2_psk(sa, auth->auth_data, 1074fde46d6eSreyk auth->auth_length, &psk)) == -1) { 1075fde46d6eSreyk log_debug("%s: failed to get PSK", __func__); 1076fde46d6eSreyk goto done; 1077fde46d6eSreyk } 1078fde46d6eSreyk key = psk; 1079fde46d6eSreyk keytype = 0; 1080fde46d6eSreyk break; 1081fde46d6eSreyk default: 1082fde46d6eSreyk if (id == NULL) { 1083fde46d6eSreyk log_debug("%s: no cert found", __func__); 1084fde46d6eSreyk goto done; 1085fde46d6eSreyk } 1086fde46d6eSreyk key = ibuf_data(id->id_buf); 1087fde46d6eSreyk keylen = ibuf_size(id->id_buf); 1088fde46d6eSreyk keytype = id->id_type; 1089fde46d6eSreyk break; 1090fde46d6eSreyk } 1091fde46d6eSreyk 1092fde46d6eSreyk if (dsa_setkey(dsa, key, keylen, keytype) == NULL || 109348b975e3Smarkus dsa_init(dsa, NULL, 0) != 0 || 1094fde46d6eSreyk dsa_update(dsa, ibuf_data(authmsg), ibuf_size(authmsg))) { 1095fde46d6eSreyk log_debug("%s: failed to compute digital signature", __func__); 1096fde46d6eSreyk goto done; 1097fde46d6eSreyk } 1098fde46d6eSreyk 1099fde46d6eSreyk ibuf_release(sa->sa_localauth.id_buf); 1100fde46d6eSreyk sa->sa_localauth.id_buf = NULL; 1101fde46d6eSreyk 1102fde46d6eSreyk if ((buf = ibuf_new(NULL, dsa_length(dsa))) == NULL) { 1103fde46d6eSreyk log_debug("%s: failed to get auth buffer", __func__); 1104fde46d6eSreyk goto done; 1105fde46d6eSreyk } 1106fde46d6eSreyk 11075e4d3a37Sreyk if ((siglen = dsa_sign_final(dsa, 11085e4d3a37Sreyk ibuf_data(buf), ibuf_size(buf))) < 0) { 1109fde46d6eSreyk log_debug("%s: failed to create auth signature", __func__); 1110fde46d6eSreyk ibuf_release(buf); 1111fde46d6eSreyk goto done; 1112fde46d6eSreyk } 1113fde46d6eSreyk 11145e4d3a37Sreyk if (ibuf_setsize(buf, siglen) < 0) { 11155e4d3a37Sreyk log_debug("%s: failed to set auth signature size to %zd", 11165e4d3a37Sreyk __func__, siglen); 11175e4d3a37Sreyk ibuf_release(buf); 11185e4d3a37Sreyk goto done; 11195e4d3a37Sreyk } 11205e4d3a37Sreyk 1121fde46d6eSreyk sa->sa_localauth.id_type = auth->auth_method; 1122fde46d6eSreyk sa->sa_localauth.id_buf = buf; 1123fde46d6eSreyk 1124fde46d6eSreyk ret = 0; 1125fde46d6eSreyk done: 1126fde46d6eSreyk free(psk); 1127fde46d6eSreyk dsa_free(dsa); 1128fde46d6eSreyk 1129fde46d6eSreyk return (ret); 1130fde46d6eSreyk } 1131ae494144Sreyk 1132ae494144Sreyk int 1133ae494144Sreyk ikev2_msg_frompeer(struct iked_message *msg) 1134ae494144Sreyk { 1135ae494144Sreyk struct iked_sa *sa = msg->msg_sa; 1136ae494144Sreyk struct ike_header *hdr; 1137ae494144Sreyk 113826d7dba1Sreyk msg = msg->msg_parent; 11391b0d4946Sreyk 1140ae494144Sreyk if (sa == NULL || 1141ae494144Sreyk (hdr = ibuf_seek(msg->msg_data, 0, sizeof(*hdr))) == NULL) 1142ae494144Sreyk return (0); 1143ae494144Sreyk 1144ae494144Sreyk if (!sa->sa_hdr.sh_initiator && 1145ae494144Sreyk (hdr->ike_flags & IKEV2_FLAG_INITIATOR)) 1146ae494144Sreyk return (1); 1147ae494144Sreyk else if (sa->sa_hdr.sh_initiator && 1148ae494144Sreyk (hdr->ike_flags & IKEV2_FLAG_INITIATOR) == 0) 1149ae494144Sreyk return (1); 1150ae494144Sreyk 1151ae494144Sreyk return (0); 1152ae494144Sreyk } 1153ae494144Sreyk 1154ae494144Sreyk struct iked_socket * 115512c9fd31Sreyk ikev2_msg_getsocket(struct iked *env, int af, int natt) 1156ae494144Sreyk { 1157ae494144Sreyk switch (af) { 1158ae494144Sreyk case AF_INET: 115912c9fd31Sreyk return (env->sc_sock4[natt ? 1 : 0]); 1160ae494144Sreyk case AF_INET6: 116112c9fd31Sreyk return (env->sc_sock6[natt ? 1 : 0]); 1162ae494144Sreyk } 1163ae494144Sreyk 1164ae494144Sreyk log_debug("%s: af socket %d not available", __func__, af); 1165ae494144Sreyk return (NULL); 1166ae494144Sreyk } 1167c45fd413Smikeb 1168c45fd413Smikeb void 1169c45fd413Smikeb ikev2_msg_prevail(struct iked *env, struct iked_msgqueue *queue, 1170c45fd413Smikeb struct iked_message *msg) 1171c45fd413Smikeb { 117204ab0f1dSmikeb struct iked_message *m, *mtmp; 1173c45fd413Smikeb 117404ab0f1dSmikeb TAILQ_FOREACH_SAFE(m, queue, msg_entry, mtmp) { 1175c45fd413Smikeb if (m->msg_msgid < msg->msg_msgid) 1176c45fd413Smikeb ikev2_msg_dispose(env, queue, m); 1177c45fd413Smikeb } 1178c45fd413Smikeb } 1179c45fd413Smikeb 1180c45fd413Smikeb void 1181c45fd413Smikeb ikev2_msg_dispose(struct iked *env, struct iked_msgqueue *queue, 1182c45fd413Smikeb struct iked_message *msg) 1183c45fd413Smikeb { 1184c45fd413Smikeb TAILQ_REMOVE(queue, msg, msg_entry); 1185b3eeacebSmikeb timer_del(env, &msg->msg_timer); 1186c45fd413Smikeb ikev2_msg_cleanup(env, msg); 1187c45fd413Smikeb free(msg); 1188c45fd413Smikeb } 1189c45fd413Smikeb 1190c45fd413Smikeb void 1191c45fd413Smikeb ikev2_msg_flushqueue(struct iked *env, struct iked_msgqueue *queue) 1192c45fd413Smikeb { 1193c45fd413Smikeb struct iked_message *m = NULL; 1194c45fd413Smikeb 1195c45fd413Smikeb while ((m = TAILQ_FIRST(queue)) != NULL) 1196c45fd413Smikeb ikev2_msg_dispose(env, queue, m); 1197c45fd413Smikeb } 1198c45fd413Smikeb 1199c45fd413Smikeb struct iked_message * 120056d51042Smikeb ikev2_msg_lookup(struct iked *env, struct iked_msgqueue *queue, 120156d51042Smikeb struct iked_message *msg, struct ike_header *hdr) 1202c45fd413Smikeb { 1203c45fd413Smikeb struct iked_message *m = NULL; 1204c45fd413Smikeb 1205c45fd413Smikeb TAILQ_FOREACH(m, queue, msg_entry) { 120656d51042Smikeb if (m->msg_msgid == msg->msg_msgid && 120756d51042Smikeb m->msg_exchange == hdr->ike_exchange) 1208c45fd413Smikeb break; 1209c45fd413Smikeb } 1210c45fd413Smikeb 121156d51042Smikeb return (m); 1212c45fd413Smikeb } 1213c45fd413Smikeb 121462cdfd0dStobhe void 121562cdfd0dStobhe ikev2_msg_lookup_dispose_all(struct iked *env, struct iked_msgqueue *queue, 121662cdfd0dStobhe struct iked_message *msg, struct ike_header *hdr) 121762cdfd0dStobhe { 121862cdfd0dStobhe struct iked_message *m = NULL, *tmp = NULL; 121962cdfd0dStobhe 122062cdfd0dStobhe TAILQ_FOREACH_SAFE(m, queue, msg_entry, tmp) { 122162cdfd0dStobhe if (m->msg_msgid == msg->msg_msgid && 122262cdfd0dStobhe m->msg_exchange == hdr->ike_exchange) { 122362cdfd0dStobhe TAILQ_REMOVE(queue, m, msg_entry); 122462cdfd0dStobhe timer_del(env, &m->msg_timer); 122562cdfd0dStobhe ikev2_msg_cleanup(env, m); 122662cdfd0dStobhe free(m); 122762cdfd0dStobhe } 122862cdfd0dStobhe } 122962cdfd0dStobhe } 123062cdfd0dStobhe 123162cdfd0dStobhe int 123262cdfd0dStobhe ikev2_msg_lookup_retransmit_all(struct iked *env, struct iked_msgqueue *queue, 123362cdfd0dStobhe struct iked_message *msg, struct ike_header *hdr, struct iked_sa *sa) 123462cdfd0dStobhe { 123562cdfd0dStobhe struct iked_message *m = NULL, *tmp = NULL; 123662cdfd0dStobhe int count = 0; 123762cdfd0dStobhe 123862cdfd0dStobhe TAILQ_FOREACH_SAFE(m, queue, msg_entry, tmp) { 123962cdfd0dStobhe if (m->msg_msgid == msg->msg_msgid && 124062cdfd0dStobhe m->msg_exchange == hdr->ike_exchange) { 124162cdfd0dStobhe if (ikev2_msg_retransmit_response(env, sa, m)) 124262cdfd0dStobhe return -1; 124362cdfd0dStobhe count++; 124462cdfd0dStobhe } 124562cdfd0dStobhe } 124662cdfd0dStobhe return count; 124762cdfd0dStobhe } 124862cdfd0dStobhe 1249c45fd413Smikeb int 1250c45fd413Smikeb ikev2_msg_retransmit_response(struct iked *env, struct iked_sa *sa, 1251c45fd413Smikeb struct iked_message *msg) 1252c45fd413Smikeb { 12535ec2ede8Svgross if (sendtofrom(msg->msg_fd, ibuf_data(msg->msg_data), 12545ec2ede8Svgross ibuf_size(msg->msg_data), 0, 12555ec2ede8Svgross (struct sockaddr *)&msg->msg_peer, msg->msg_peerlen, 12565ec2ede8Svgross (struct sockaddr *)&msg->msg_local, msg->msg_locallen) == -1) { 12575ec2ede8Svgross log_warn("%s: sendtofrom", __func__); 1258c45fd413Smikeb return (-1); 1259c45fd413Smikeb } 1260f3610affStobhe log_info("%sretransmit %s res %u local %s peer %s", 1261f3610affStobhe SPI_SA(sa, NULL), 1262f3610affStobhe print_map(msg->msg_exchange, ikev2_exchange_map), 1263f3610affStobhe msg->msg_msgid, 1264f3610affStobhe print_host((struct sockaddr *)&msg->msg_local, NULL, 0), 1265f3610affStobhe print_host((struct sockaddr *)&msg->msg_peer, NULL, 0)); 1266c45fd413Smikeb 1267b3eeacebSmikeb timer_add(env, &msg->msg_timer, IKED_RESPONSE_TIMEOUT); 1268c45fd413Smikeb return (0); 1269c45fd413Smikeb } 1270c45fd413Smikeb 1271c45fd413Smikeb void 1272c45fd413Smikeb ikev2_msg_response_timeout(struct iked *env, void *arg) 1273c45fd413Smikeb { 1274c45fd413Smikeb struct iked_message *msg = arg; 1275c45fd413Smikeb struct iked_sa *sa = msg->msg_sa; 1276c45fd413Smikeb 1277c45fd413Smikeb ikev2_msg_dispose(env, &sa->sa_responses, msg); 1278c45fd413Smikeb } 1279c45fd413Smikeb 1280c45fd413Smikeb void 1281c45fd413Smikeb ikev2_msg_retransmit_timeout(struct iked *env, void *arg) 1282c45fd413Smikeb { 1283c45fd413Smikeb struct iked_message *msg = arg; 1284c45fd413Smikeb struct iked_sa *sa = msg->msg_sa; 1285c45fd413Smikeb 12868d81c769Smikeb if (msg->msg_tries < IKED_RETRANSMIT_TRIES) { 12875ec2ede8Svgross if (sendtofrom(msg->msg_fd, ibuf_data(msg->msg_data), 1288c45fd413Smikeb ibuf_size(msg->msg_data), 0, 12895ec2ede8Svgross (struct sockaddr *)&msg->msg_peer, msg->msg_peerlen, 12905ec2ede8Svgross (struct sockaddr *)&msg->msg_local, 12915ec2ede8Svgross msg->msg_locallen) == -1) { 12925ec2ede8Svgross log_warn("%s: sendtofrom", __func__); 129384a9a21bStobhe ikev2_ike_sa_setreason(sa, "retransmit failed"); 1294c45fd413Smikeb sa_free(env, sa); 1295c45fd413Smikeb return; 1296c45fd413Smikeb } 1297c45fd413Smikeb /* Exponential timeout */ 1298b3eeacebSmikeb timer_add(env, &msg->msg_timer, 1299c45fd413Smikeb IKED_RETRANSMIT_TIMEOUT * (2 << (msg->msg_tries++))); 1300f3610affStobhe log_info("%sretransmit %d %s req %u peer %s local %s", 1301f3610affStobhe SPI_SA(sa, NULL), 1302f3610affStobhe msg->msg_tries, 1303f3610affStobhe print_map(msg->msg_exchange, ikev2_exchange_map), 1304f3610affStobhe msg->msg_msgid, 1305f3610affStobhe print_host((struct sockaddr *)&msg->msg_peer, NULL, 0), 1306f3610affStobhe print_host((struct sockaddr *)&msg->msg_local, NULL, 0)); 13078d81c769Smikeb } else { 1308f3610affStobhe log_debug("%s: retransmit limit reached for req %u", 13097f7372eaSmarkus __func__, msg->msg_msgid); 131084a9a21bStobhe ikev2_ike_sa_setreason(sa, "retransmit limit reached"); 1311c45fd413Smikeb sa_free(env, sa); 1312c45fd413Smikeb } 13138d81c769Smikeb } 1314