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