1*10650a52Smikeb /* $OpenBSD: ikev2_msg.c,v 1.14 2012/05/24 14:41:36 mikeb Exp $ */ 2fde46d6eSreyk /* $vantronix: ikev2.c,v 1.101 2010/06/03 07:57:33 reyk Exp $ */ 3fde46d6eSreyk 4fde46d6eSreyk /* 5fde46d6eSreyk * Copyright (c) 2010 Reyk Floeter <reyk@vantronix.net> 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 20fde46d6eSreyk #include <sys/param.h> 21fde46d6eSreyk #include <sys/types.h> 22fde46d6eSreyk #include <sys/queue.h> 23fde46d6eSreyk #include <sys/socket.h> 24fde46d6eSreyk #include <sys/wait.h> 25fde46d6eSreyk #include <sys/uio.h> 26fde46d6eSreyk 27fde46d6eSreyk #include <netinet/in.h> 28fde46d6eSreyk #include <netinet/ip_ipsp.h> 29fde46d6eSreyk #include <arpa/inet.h> 30fde46d6eSreyk 31fde46d6eSreyk #include <stdlib.h> 32fde46d6eSreyk #include <stdio.h> 33fde46d6eSreyk #include <unistd.h> 34fde46d6eSreyk #include <string.h> 35fde46d6eSreyk #include <getopt.h> 36fde46d6eSreyk #include <signal.h> 37fde46d6eSreyk #include <errno.h> 38fde46d6eSreyk #include <err.h> 39fde46d6eSreyk #include <pwd.h> 40fde46d6eSreyk #include <event.h> 41fde46d6eSreyk 42fde46d6eSreyk #include <openssl/sha.h> 43fde46d6eSreyk #include <openssl/evp.h> 44fde46d6eSreyk 45fde46d6eSreyk #include "iked.h" 46fde46d6eSreyk #include "ikev2.h" 47fde46d6eSreyk #include "eap.h" 48fde46d6eSreyk #include "dh.h" 49fde46d6eSreyk 50fde46d6eSreyk void 51fde46d6eSreyk ikev2_msg_cb(int fd, short event, void *arg) 52fde46d6eSreyk { 53fde46d6eSreyk struct iked_socket *sock = arg; 54fde46d6eSreyk struct iked *env = sock->sock_env; 55fde46d6eSreyk struct iked_message msg; 56fde46d6eSreyk struct ike_header hdr; 57fde46d6eSreyk u_int32_t natt = 0x00000000; 58fde46d6eSreyk u_int8_t buf[IKED_MSGBUF_MAX]; 59fde46d6eSreyk ssize_t len; 60fde46d6eSreyk off_t off; 61fde46d6eSreyk struct iovec iov[2]; 62fde46d6eSreyk 63fde46d6eSreyk bzero(&msg, sizeof(msg)); 64fde46d6eSreyk bzero(buf, sizeof(buf)); 65fde46d6eSreyk 66fde46d6eSreyk msg.msg_peerlen = sizeof(msg.msg_peer); 67fde46d6eSreyk msg.msg_locallen = sizeof(msg.msg_local); 6826d7dba1Sreyk msg.msg_parent = &msg; 69fde46d6eSreyk memcpy(&msg.msg_local, &sock->sock_addr, sizeof(sock->sock_addr)); 70fde46d6eSreyk 71fde46d6eSreyk if ((len = recvfromto(fd, buf, sizeof(buf), 0, 72fde46d6eSreyk (struct sockaddr *)&msg.msg_peer, &msg.msg_peerlen, 73fde46d6eSreyk (struct sockaddr *)&msg.msg_local, &msg.msg_locallen)) < 74fde46d6eSreyk (ssize_t)sizeof(natt)) 75fde46d6eSreyk return; 76fde46d6eSreyk 77fde46d6eSreyk if (socket_getport(&msg.msg_local) == IKED_NATT_PORT) { 78fde46d6eSreyk if (bcmp(&natt, buf, sizeof(natt)) != 0) 79fde46d6eSreyk return; 80fde46d6eSreyk msg.msg_natt = 1; 81fde46d6eSreyk off = sizeof(natt); 82fde46d6eSreyk } else 83fde46d6eSreyk off = 0; 84fde46d6eSreyk 85fde46d6eSreyk if ((size_t)(len - off) <= sizeof(hdr)) 86fde46d6eSreyk return; 87fde46d6eSreyk memcpy(&hdr, buf + off, sizeof(hdr)); 88fde46d6eSreyk 89fde46d6eSreyk if ((msg.msg_data = ibuf_new(buf + off, len - off)) == NULL) 90fde46d6eSreyk return; 91fde46d6eSreyk 92fde46d6eSreyk if (hdr.ike_version == IKEV1_VERSION) { 93fde46d6eSreyk iov[0].iov_base = &msg; 94fde46d6eSreyk iov[0].iov_len = sizeof(msg); 95fde46d6eSreyk iov[1].iov_base = buf; 96fde46d6eSreyk iov[1].iov_len = len; 97fde46d6eSreyk 98fc7fd3e3Sreyk proc_composev_imsg(env, PROC_IKEV1, IMSG_IKE_MESSAGE, -1, 99fde46d6eSreyk iov, 2); 100fde46d6eSreyk goto done; 101fde46d6eSreyk } 102fde46d6eSreyk TAILQ_INIT(&msg.msg_proposals); 103fde46d6eSreyk 104fde46d6eSreyk msg.msg_fd = fd; 105fde46d6eSreyk ikev2_recv(env, &msg); 106fde46d6eSreyk 107fde46d6eSreyk done: 108763023d6Sreyk ikev2_msg_cleanup(env, &msg); 109fde46d6eSreyk } 110fde46d6eSreyk 111fde46d6eSreyk struct ibuf * 112fde46d6eSreyk ikev2_msg_init(struct iked *env, struct iked_message *msg, 113fde46d6eSreyk struct sockaddr_storage *peer, socklen_t peerlen, 114fde46d6eSreyk struct sockaddr_storage *local, socklen_t locallen, int response) 115fde46d6eSreyk { 116fde46d6eSreyk bzero(msg, sizeof(*msg)); 117fde46d6eSreyk memcpy(&msg->msg_peer, peer, peerlen); 118fde46d6eSreyk msg->msg_peerlen = peerlen; 119fde46d6eSreyk memcpy(&msg->msg_local, local, locallen); 120fde46d6eSreyk msg->msg_locallen = locallen; 121fde46d6eSreyk msg->msg_response = response ? 1 : 0; 122fde46d6eSreyk msg->msg_fd = -1; 123fde46d6eSreyk msg->msg_data = ibuf_static(); 12426d7dba1Sreyk msg->msg_e = 0; 12526d7dba1Sreyk msg->msg_parent = msg; /* has to be set */ 126763023d6Sreyk TAILQ_INIT(&msg->msg_proposals); 127fde46d6eSreyk 128fde46d6eSreyk return (msg->msg_data); 129fde46d6eSreyk } 130fde46d6eSreyk 131763023d6Sreyk void 132763023d6Sreyk ikev2_msg_cleanup(struct iked *env, struct iked_message *msg) 133763023d6Sreyk { 13426d7dba1Sreyk if (msg == msg->msg_parent) { 13526d7dba1Sreyk ibuf_release(msg->msg_nonce); 13626d7dba1Sreyk ibuf_release(msg->msg_ke); 13726d7dba1Sreyk ibuf_release(msg->msg_auth.id_buf); 13826d7dba1Sreyk ibuf_release(msg->msg_id.id_buf); 13926d7dba1Sreyk ibuf_release(msg->msg_cert.id_buf); 14026d7dba1Sreyk 14126d7dba1Sreyk config_free_proposals(&msg->msg_proposals, 0); 14226d7dba1Sreyk } 14326d7dba1Sreyk 144763023d6Sreyk if (msg->msg_data != NULL) { 145763023d6Sreyk ibuf_release(msg->msg_data); 146763023d6Sreyk msg->msg_data = NULL; 147763023d6Sreyk } 148763023d6Sreyk } 149763023d6Sreyk 150fde46d6eSreyk int 151fde46d6eSreyk ikev2_msg_valid_ike_sa(struct iked *env, struct ike_header *oldhdr, 152fde46d6eSreyk struct iked_message *msg) 153fde46d6eSreyk { 154fde46d6eSreyk #if 0 155fde46d6eSreyk /* XXX Disabled, see comment below */ 156fde46d6eSreyk struct iked_message resp; 157fde46d6eSreyk struct ike_header *hdr; 158fde46d6eSreyk struct ikev2_payload *pld; 159fde46d6eSreyk struct ikev2_notify *n; 160fde46d6eSreyk struct ibuf *buf; 161fde46d6eSreyk struct iked_sa sa; 162fde46d6eSreyk #endif 163fde46d6eSreyk 164fde46d6eSreyk if (msg->msg_sa != NULL && msg->msg_policy != NULL) 165fde46d6eSreyk return (0); 166fde46d6eSreyk 167fde46d6eSreyk #if 0 168fde46d6eSreyk /* 169fde46d6eSreyk * XXX Sending INVALID_IKE_SPIs notifications is disabled 170fde46d6eSreyk * XXX because it is not mandatory and ignored by most 171fde46d6eSreyk * XXX implementations. We might want to enable it in 172fde46d6eSreyk * XXX combination with a rate-limitation to avoid DoS situations. 173fde46d6eSreyk */ 174fde46d6eSreyk 175fde46d6eSreyk /* Fail without error message */ 176fde46d6eSreyk if (msg->msg_response || msg->msg_policy == NULL) 177fde46d6eSreyk return (-1); 178fde46d6eSreyk 179fde46d6eSreyk /* Invalid IKE SA, return notification */ 180fde46d6eSreyk if ((buf = ikev2_msg_init(env, &resp, 181fde46d6eSreyk &msg->msg_peer, msg->msg_peerlen, 182fde46d6eSreyk &msg->msg_local, msg->msg_locallen, 1)) == NULL) 183fde46d6eSreyk goto done; 184fde46d6eSreyk 185fde46d6eSreyk bzero(&sa, sizeof(sa)); 186fde46d6eSreyk if ((oldhdr->ike_flags & IKEV2_FLAG_INITIATOR) == 0) 187fde46d6eSreyk sa.sa_hdr.sh_initiator = 1; 188fde46d6eSreyk sa.sa_hdr.sh_ispi = betoh64(oldhdr->ike_ispi); 189fde46d6eSreyk sa.sa_hdr.sh_rspi = betoh64(oldhdr->ike_rspi); 190fde46d6eSreyk 191fde46d6eSreyk /* IKE header */ 192fde46d6eSreyk if ((hdr = ikev2_add_header(buf, &sa, betoh32(oldhdr->ike_msgid), 193fde46d6eSreyk IKEV2_PAYLOAD_NOTIFY, IKEV2_EXCHANGE_INFORMATIONAL, 194fde46d6eSreyk IKEV2_FLAG_RESPONSE)) == NULL) 195fde46d6eSreyk goto done; 196fde46d6eSreyk 197fde46d6eSreyk /* SA payload */ 198fde46d6eSreyk if ((pld = ikev2_add_payload(buf)) == NULL) 199fde46d6eSreyk goto done; 200fde46d6eSreyk if ((n = ibuf_advance(buf, sizeof(*n))) == NULL) 201fde46d6eSreyk goto done; 202fde46d6eSreyk n->n_protoid = IKEV2_SAPROTO_IKE; 203fde46d6eSreyk n->n_spisize = 0; 204fde46d6eSreyk n->n_type = htobe16(IKEV2_N_INVALID_IKE_SPI); 205fde46d6eSreyk 206fde46d6eSreyk if (ikev2_next_payload(pld, sizeof(*n), IKEV2_PAYLOAD_NONE) == -1) 207fde46d6eSreyk goto done; 208fde46d6eSreyk 209fde46d6eSreyk if (ikev2_set_header(hdr, ibuf_size(buf) - sizeof(*hdr)) == -1) 210fde46d6eSreyk goto done; 211fde46d6eSreyk 212fde46d6eSreyk (void)ikev2_pld_parse(env, hdr, &resp, 0); 213fde46d6eSreyk (void)ikev2_msg_send(env, msg->msg_fd, &resp); 214fde46d6eSreyk 215fde46d6eSreyk done: 216763023d6Sreyk ikev2_msg_cleanup(env, &resp); 217fde46d6eSreyk #endif 218fde46d6eSreyk 219fde46d6eSreyk /* Always fail */ 220fde46d6eSreyk return (-1); 221fde46d6eSreyk } 222fde46d6eSreyk 223fde46d6eSreyk int 224fde46d6eSreyk ikev2_msg_send(struct iked *env, int fd, struct iked_message *msg) 225fde46d6eSreyk { 226fde46d6eSreyk struct ibuf *buf = msg->msg_data; 227fde46d6eSreyk u_int32_t natt = 0x00000000; 228fde46d6eSreyk struct ike_header *hdr; 229fde46d6eSreyk 230fde46d6eSreyk if (buf == NULL || (hdr = ibuf_seek(msg->msg_data, 231fde46d6eSreyk msg->msg_offset, sizeof(*hdr))) == NULL) 232fde46d6eSreyk return (-1); 233fde46d6eSreyk 234d4614e98Sreyk log_info("%s: %s from %s to %s, %ld bytes", __func__, 235fde46d6eSreyk print_map(hdr->ike_exchange, ikev2_exchange_map), 236d4614e98Sreyk print_host(&msg->msg_local, NULL, 0), 237fde46d6eSreyk print_host(&msg->msg_peer, NULL, 0), 238d4614e98Sreyk ibuf_length(buf)); 239fde46d6eSreyk 240fde46d6eSreyk if (msg->msg_natt || (msg->msg_sa && msg->msg_sa->sa_natt)) { 241fde46d6eSreyk if (ibuf_prepend(buf, &natt, sizeof(natt)) == -1) { 242fde46d6eSreyk log_debug("%s: failed to set NAT-T", __func__); 243fde46d6eSreyk return (-1); 244fde46d6eSreyk } 245fde46d6eSreyk } 246fde46d6eSreyk if ((sendto(fd, ibuf_data(buf), ibuf_size(buf), 0, 247fde46d6eSreyk (struct sockaddr *)&msg->msg_peer, msg->msg_peerlen)) == -1) { 248fde46d6eSreyk log_warn("%s: sendto", __func__); 249fde46d6eSreyk return (-1); 250fde46d6eSreyk } 251fde46d6eSreyk 252fde46d6eSreyk return (0); 253fde46d6eSreyk } 254fde46d6eSreyk 255fde46d6eSreyk u_int32_t 256fde46d6eSreyk ikev2_msg_id(struct iked *env, struct iked_sa *sa, int response) 257fde46d6eSreyk { 258*10650a52Smikeb u_int32_t id; 259fde46d6eSreyk 260*10650a52Smikeb if (response) 261*10650a52Smikeb return (sa->sa_msgid); 262*10650a52Smikeb 263*10650a52Smikeb id = sa->sa_reqid; 264*10650a52Smikeb if (++sa->sa_reqid == UINT32_MAX) { 265fde46d6eSreyk /* XXX we should close and renegotiate the connection now */ 266fde46d6eSreyk log_debug("%s: IKEv2 message sequence overflow", __func__); 267fde46d6eSreyk } 268*10650a52Smikeb return (id); 269fde46d6eSreyk } 270fde46d6eSreyk 271fde46d6eSreyk struct ibuf * 272fde46d6eSreyk ikev2_msg_encrypt(struct iked *env, struct iked_sa *sa, struct ibuf *src) 273fde46d6eSreyk { 274fde46d6eSreyk size_t len, ivlen, encrlen, integrlen, blocklen, 275fde46d6eSreyk outlen; 276fde46d6eSreyk u_int8_t *buf, pad = 0, *ptr; 277fde46d6eSreyk struct ibuf *integr, *encr, *dst = NULL, *out = NULL; 278fde46d6eSreyk 279fde46d6eSreyk buf = ibuf_data(src); 280fde46d6eSreyk len = ibuf_size(src); 281fde46d6eSreyk 282fde46d6eSreyk log_debug("%s: decrypted length %d", __func__, len); 283fde46d6eSreyk print_hex(buf, 0, len); 284fde46d6eSreyk 285fde46d6eSreyk if (sa == NULL || 286fde46d6eSreyk sa->sa_encr == NULL || 287fde46d6eSreyk sa->sa_integr == NULL) { 288fde46d6eSreyk log_debug("%s: invalid SA", __func__); 289fde46d6eSreyk goto done; 290fde46d6eSreyk } 291fde46d6eSreyk 292fde46d6eSreyk if (sa->sa_hdr.sh_initiator) { 293fde46d6eSreyk encr = sa->sa_key_iencr; 294fde46d6eSreyk integr = sa->sa_key_iauth; 295fde46d6eSreyk } else { 296fde46d6eSreyk encr = sa->sa_key_rencr; 297fde46d6eSreyk integr = sa->sa_key_rauth; 298fde46d6eSreyk } 299fde46d6eSreyk 300fde46d6eSreyk blocklen = cipher_length(sa->sa_encr); 301fde46d6eSreyk ivlen = cipher_ivlength(sa->sa_encr); 302fde46d6eSreyk integrlen = hash_length(sa->sa_integr); 303fde46d6eSreyk encrlen = roundup(len + sizeof(pad), blocklen); 304fde46d6eSreyk pad = encrlen - (len + sizeof(pad)); 305fde46d6eSreyk 306fde46d6eSreyk /* 307fde46d6eSreyk * Pad the payload and encrypt it 308fde46d6eSreyk */ 309fde46d6eSreyk if (pad) { 310fde46d6eSreyk if ((ptr = ibuf_advance(src, pad)) == NULL) 311fde46d6eSreyk goto done; 312fde46d6eSreyk arc4random_buf(ptr, pad); 313fde46d6eSreyk } 314fde46d6eSreyk if (ibuf_add(src, &pad, sizeof(pad)) != 0) 315fde46d6eSreyk goto done; 316fde46d6eSreyk 317fde46d6eSreyk log_debug("%s: padded length %d", __func__, ibuf_size(src)); 318fde46d6eSreyk print_hex(ibuf_data(src), 0, ibuf_size(src)); 319fde46d6eSreyk 320fde46d6eSreyk cipher_setkey(sa->sa_encr, encr->buf, ibuf_length(encr)); 321fde46d6eSreyk cipher_setiv(sa->sa_encr, NULL, 0); /* new IV */ 322fde46d6eSreyk cipher_init_encrypt(sa->sa_encr); 323fde46d6eSreyk 324fde46d6eSreyk if ((dst = ibuf_dup(sa->sa_encr->encr_iv)) == NULL) 325fde46d6eSreyk goto done; 326fde46d6eSreyk 327fde46d6eSreyk if ((out = ibuf_new(NULL, 328fde46d6eSreyk cipher_outlength(sa->sa_encr, encrlen))) == NULL) 329fde46d6eSreyk goto done; 330fde46d6eSreyk 331fde46d6eSreyk outlen = ibuf_size(out); 332fde46d6eSreyk cipher_update(sa->sa_encr, 333fde46d6eSreyk ibuf_data(src), encrlen, ibuf_data(out), &outlen); 334fde46d6eSreyk 335fde46d6eSreyk if (outlen && ibuf_add(dst, ibuf_data(out), outlen) != 0) 336fde46d6eSreyk goto done; 337fde46d6eSreyk 338fde46d6eSreyk if ((ptr = ibuf_advance(dst, integrlen)) == NULL) 339fde46d6eSreyk goto done; 340fde46d6eSreyk bzero(ptr, integrlen); 341fde46d6eSreyk 342fde46d6eSreyk log_debug("%s: length %d, padding %d, output length %d", 343fde46d6eSreyk __func__, len + sizeof(pad), pad, ibuf_size(dst)); 344fde46d6eSreyk print_hex(ibuf_data(dst), 0, ibuf_size(dst)); 345fde46d6eSreyk 346fde46d6eSreyk ibuf_release(src); 347fde46d6eSreyk ibuf_release(out); 348fde46d6eSreyk return (dst); 349fde46d6eSreyk done: 350fde46d6eSreyk ibuf_release(src); 351fde46d6eSreyk ibuf_release(out); 352fde46d6eSreyk ibuf_release(dst); 353fde46d6eSreyk return (NULL); 354fde46d6eSreyk } 355fde46d6eSreyk 356fde46d6eSreyk int 357fde46d6eSreyk ikev2_msg_integr(struct iked *env, struct iked_sa *sa, struct ibuf *src) 358fde46d6eSreyk { 359fde46d6eSreyk int ret = -1; 360fde46d6eSreyk size_t integrlen, tmplen; 361fde46d6eSreyk struct ibuf *integr, *prf, *tmp = NULL; 362fde46d6eSreyk u_int8_t *ptr; 363fde46d6eSreyk 364fde46d6eSreyk log_debug("%s: message length %d", __func__, ibuf_size(src)); 365fde46d6eSreyk print_hex(ibuf_data(src), 0, ibuf_size(src)); 366fde46d6eSreyk 367fde46d6eSreyk if (sa == NULL || 368fde46d6eSreyk sa->sa_integr == NULL) { 369fde46d6eSreyk log_debug("%s: invalid SA", __func__); 370fde46d6eSreyk return (-1); 371fde46d6eSreyk } 372fde46d6eSreyk 373fde46d6eSreyk if (sa->sa_hdr.sh_initiator) { 374fde46d6eSreyk integr = sa->sa_key_iauth; 375fde46d6eSreyk prf = sa->sa_key_iprf; 376fde46d6eSreyk } else { 377fde46d6eSreyk integr = sa->sa_key_rauth; 378fde46d6eSreyk prf = sa->sa_key_rprf; 379fde46d6eSreyk } 380fde46d6eSreyk 381fde46d6eSreyk integrlen = hash_length(sa->sa_integr); 382fde46d6eSreyk 383fde46d6eSreyk log_debug("%s: integrity checksum length %d", __func__, 384fde46d6eSreyk integrlen); 385fde46d6eSreyk 386fde46d6eSreyk /* 387fde46d6eSreyk * Validate packet checksum 388fde46d6eSreyk */ 389fde46d6eSreyk if ((tmp = ibuf_new(NULL, hash_keylength(sa->sa_integr))) == NULL) 390fde46d6eSreyk goto done; 391fde46d6eSreyk 392fde46d6eSreyk hash_setkey(sa->sa_integr, ibuf_data(integr), ibuf_size(integr)); 393fde46d6eSreyk hash_init(sa->sa_integr); 394fde46d6eSreyk hash_update(sa->sa_integr, ibuf_data(src), 395fde46d6eSreyk ibuf_size(src) - integrlen); 396fde46d6eSreyk hash_final(sa->sa_integr, ibuf_data(tmp), &tmplen); 397fde46d6eSreyk 398fde46d6eSreyk if (tmplen != integrlen) { 399fde46d6eSreyk log_debug("%s: hash failure", __func__); 400fde46d6eSreyk goto done; 401fde46d6eSreyk } 402fde46d6eSreyk 403fde46d6eSreyk if ((ptr = ibuf_seek(src, 404fde46d6eSreyk ibuf_size(src) - integrlen, integrlen)) == NULL) 405fde46d6eSreyk goto done; 406fde46d6eSreyk memcpy(ptr, ibuf_data(tmp), tmplen); 407fde46d6eSreyk 408fde46d6eSreyk print_hex(ibuf_data(tmp), 0, ibuf_size(tmp)); 409fde46d6eSreyk 410fde46d6eSreyk ret = 0; 411fde46d6eSreyk done: 412fde46d6eSreyk ibuf_release(tmp); 413fde46d6eSreyk 414fde46d6eSreyk return (ret); 415fde46d6eSreyk } 416fde46d6eSreyk 417fde46d6eSreyk struct ibuf * 418fde46d6eSreyk ikev2_msg_decrypt(struct iked *env, struct iked_sa *sa, 419fde46d6eSreyk struct ibuf *msg, struct ibuf *src) 420fde46d6eSreyk { 421e0696045Sreyk ssize_t ivlen, encrlen, integrlen, blocklen, 422fde46d6eSreyk outlen, tmplen; 423e0696045Sreyk u_int8_t pad = 0, *ptr; 424fde46d6eSreyk struct ibuf *integr, *encr, *tmp = NULL, *out = NULL; 425fde46d6eSreyk off_t ivoff, encroff, integroff; 426fde46d6eSreyk 427fde46d6eSreyk if (sa == NULL || 428fde46d6eSreyk sa->sa_encr == NULL || 429fde46d6eSreyk sa->sa_integr == NULL) { 430fde46d6eSreyk log_debug("%s: invalid SA", __func__); 431fde46d6eSreyk print_hex(ibuf_data(src), 0, ibuf_size(src)); 432fde46d6eSreyk goto done; 433fde46d6eSreyk } 434fde46d6eSreyk 435fde46d6eSreyk if (!sa->sa_hdr.sh_initiator) { 436fde46d6eSreyk encr = sa->sa_key_iencr; 437fde46d6eSreyk integr = sa->sa_key_iauth; 438fde46d6eSreyk } else { 439fde46d6eSreyk encr = sa->sa_key_rencr; 440fde46d6eSreyk integr = sa->sa_key_rauth; 441fde46d6eSreyk } 442fde46d6eSreyk 443fde46d6eSreyk blocklen = cipher_length(sa->sa_encr); 444fde46d6eSreyk ivlen = cipher_ivlength(sa->sa_encr); 445fde46d6eSreyk ivoff = 0; 446fde46d6eSreyk integrlen = hash_length(sa->sa_integr); 447fde46d6eSreyk integroff = ibuf_size(src) - integrlen; 448fde46d6eSreyk encroff = ivlen; 449fde46d6eSreyk encrlen = ibuf_size(src) - integrlen - ivlen; 450fde46d6eSreyk 451e0696045Sreyk if (encrlen < 0 || integroff < 0) { 452e0696045Sreyk log_debug("%s: invalid integrity value", __func__); 453e0696045Sreyk goto done; 454e0696045Sreyk } 455e0696045Sreyk 456fde46d6eSreyk log_debug("%s: IV length %d", __func__, ivlen); 457fde46d6eSreyk print_hex(ibuf_data(src), 0, ivlen); 458fde46d6eSreyk log_debug("%s: encrypted payload length %d", __func__, encrlen); 459fde46d6eSreyk print_hex(ibuf_data(src), encroff, encrlen); 460fde46d6eSreyk log_debug("%s: integrity checksum length %d", __func__, integrlen); 461fde46d6eSreyk print_hex(ibuf_data(src), integroff, integrlen); 462fde46d6eSreyk 463fde46d6eSreyk /* 464fde46d6eSreyk * Validate packet checksum 465fde46d6eSreyk */ 466fde46d6eSreyk if ((tmp = ibuf_new(NULL, ibuf_length(integr))) == NULL) 467fde46d6eSreyk goto done; 468fde46d6eSreyk 469fde46d6eSreyk hash_setkey(sa->sa_integr, integr->buf, ibuf_length(integr)); 470fde46d6eSreyk hash_init(sa->sa_integr); 471fde46d6eSreyk hash_update(sa->sa_integr, ibuf_data(msg), 472fde46d6eSreyk ibuf_size(msg) - integrlen); 473fde46d6eSreyk hash_final(sa->sa_integr, tmp->buf, &tmplen); 474fde46d6eSreyk 475fde46d6eSreyk if (memcmp(tmp->buf, ibuf_data(src) + integroff, integrlen) != 0) { 476fde46d6eSreyk log_debug("%s: integrity check failed", __func__); 477fde46d6eSreyk goto done; 478fde46d6eSreyk } 479fde46d6eSreyk 480b0eeedd0Smikeb log_debug("%s: integrity check succeeded", __func__); 481fde46d6eSreyk print_hex(tmp->buf, 0, tmplen); 482fde46d6eSreyk 483fde46d6eSreyk ibuf_release(tmp); 484fde46d6eSreyk tmp = NULL; 485fde46d6eSreyk 486fde46d6eSreyk /* 487fde46d6eSreyk * Decrypt the payload and strip any padding 488fde46d6eSreyk */ 489fde46d6eSreyk if ((encrlen % blocklen) != 0) { 490fde46d6eSreyk log_debug("%s: unaligned encrypted payload", __func__); 491fde46d6eSreyk goto done; 492fde46d6eSreyk } 493fde46d6eSreyk 494fde46d6eSreyk cipher_setkey(sa->sa_encr, encr->buf, ibuf_length(encr)); 495fde46d6eSreyk cipher_setiv(sa->sa_encr, ibuf_data(src) + ivoff, ivlen); 496fde46d6eSreyk cipher_init_decrypt(sa->sa_encr); 497fde46d6eSreyk 498fde46d6eSreyk if ((out = ibuf_new(NULL, cipher_outlength(sa->sa_encr, 499fde46d6eSreyk encrlen))) == NULL) 500fde46d6eSreyk goto done; 501fde46d6eSreyk 502e0696045Sreyk if ((outlen = ibuf_length(out)) != 0) { 5033189733aSmikeb cipher_update(sa->sa_encr, ibuf_data(src) + encroff, encrlen, 5043189733aSmikeb ibuf_data(out), &outlen); 5053189733aSmikeb 506fde46d6eSreyk ptr = ibuf_seek(out, outlen - 1, 1); 507fde46d6eSreyk pad = *ptr; 508e0696045Sreyk } 509fde46d6eSreyk 510fde46d6eSreyk log_debug("%s: decrypted payload length %d/%d padding %d", 511fde46d6eSreyk __func__, outlen, encrlen, pad); 512fde46d6eSreyk print_hex(ibuf_data(out), 0, ibuf_size(out)); 513fde46d6eSreyk 514fde46d6eSreyk if (ibuf_setsize(out, outlen) != 0) 515fde46d6eSreyk goto done; 516fde46d6eSreyk 517fde46d6eSreyk ibuf_release(src); 518fde46d6eSreyk return (out); 519fde46d6eSreyk done: 520fde46d6eSreyk ibuf_release(tmp); 521fde46d6eSreyk ibuf_release(out); 522fde46d6eSreyk ibuf_release(src); 523fde46d6eSreyk return (NULL); 524fde46d6eSreyk } 525fde46d6eSreyk 526fde46d6eSreyk int 527fde46d6eSreyk ikev2_msg_send_encrypt(struct iked *env, struct iked_sa *sa, 528fde46d6eSreyk struct ibuf **ep, u_int8_t exchange, u_int8_t firstpayload, int response) 529fde46d6eSreyk { 530fde46d6eSreyk struct iked_message resp; 531fde46d6eSreyk struct ike_header *hdr; 532fde46d6eSreyk struct ikev2_payload *pld; 533fde46d6eSreyk struct ibuf *buf, *e = *ep; 534fde46d6eSreyk int ret = -1; 535fde46d6eSreyk 536fde46d6eSreyk if ((buf = ikev2_msg_init(env, &resp, 537fde46d6eSreyk &sa->sa_peer.addr, sa->sa_peer.addr.ss_len, 538fde46d6eSreyk &sa->sa_local.addr, sa->sa_local.addr.ss_len, 1)) == NULL) 539fde46d6eSreyk goto done; 540fde46d6eSreyk 541fde46d6eSreyk /* IKE header */ 542fde46d6eSreyk if ((hdr = ikev2_add_header(buf, sa, 543fde46d6eSreyk ikev2_msg_id(env, sa, response), 544f9b88c7aSmikeb IKEV2_PAYLOAD_SK, exchange, 545fde46d6eSreyk response ? IKEV2_FLAG_RESPONSE : 0)) == NULL) 546fde46d6eSreyk goto done; 547fde46d6eSreyk 548fde46d6eSreyk if ((pld = ikev2_add_payload(buf)) == NULL) 549fde46d6eSreyk goto done; 550fde46d6eSreyk 551fde46d6eSreyk /* Encrypt message and add as an E payload */ 552fde46d6eSreyk if ((e = ikev2_msg_encrypt(env, sa, e)) == NULL) { 553fde46d6eSreyk log_debug("%s: encryption failed", __func__); 554fde46d6eSreyk goto done; 555fde46d6eSreyk } 556fde46d6eSreyk if (ibuf_cat(buf, e) != 0) 557fde46d6eSreyk goto done; 558fde46d6eSreyk if (ikev2_next_payload(pld, ibuf_size(e), firstpayload) == -1) 559fde46d6eSreyk goto done; 560fde46d6eSreyk 561fde46d6eSreyk if (ikev2_set_header(hdr, ibuf_size(buf) - sizeof(*hdr)) == -1) 562fde46d6eSreyk goto done; 563fde46d6eSreyk 564fde46d6eSreyk /* Add integrity checksum (HMAC) */ 565fde46d6eSreyk if (ikev2_msg_integr(env, sa, buf) != 0) { 566fde46d6eSreyk log_debug("%s: integrity checksum failed", __func__); 567fde46d6eSreyk goto done; 568fde46d6eSreyk } 569fde46d6eSreyk 570fde46d6eSreyk resp.msg_data = buf; 571fde46d6eSreyk resp.msg_sa = sa; 572fde46d6eSreyk TAILQ_INIT(&resp.msg_proposals); 573fde46d6eSreyk 574fde46d6eSreyk (void)ikev2_pld_parse(env, hdr, &resp, 0); 575fde46d6eSreyk 576fde46d6eSreyk ret = ikev2_msg_send(env, sa->sa_fd, &resp); 577fde46d6eSreyk 578fde46d6eSreyk done: 579fde46d6eSreyk /* e is cleaned up by the calling function */ 580fde46d6eSreyk *ep = e; 581763023d6Sreyk ikev2_msg_cleanup(env, &resp); 582fde46d6eSreyk 583fde46d6eSreyk return (ret); 584fde46d6eSreyk } 585fde46d6eSreyk 586fde46d6eSreyk struct ibuf * 587fde46d6eSreyk ikev2_msg_auth(struct iked *env, struct iked_sa *sa, int response) 588fde46d6eSreyk { 589fde46d6eSreyk struct ibuf *authmsg = NULL, *nonce, *prfkey, *buf; 590fde46d6eSreyk u_int8_t *ptr; 591fde46d6eSreyk struct iked_id *id; 592fde46d6eSreyk size_t tmplen; 593fde46d6eSreyk 594fde46d6eSreyk /* 595fde46d6eSreyk * Create the payload to be signed/MAC'ed for AUTH 596fde46d6eSreyk */ 597fde46d6eSreyk 598fde46d6eSreyk if (!response) { 599fde46d6eSreyk if ((nonce = sa->sa_rnonce) == NULL || 600fde46d6eSreyk (sa->sa_iid.id_type == 0) || 601fde46d6eSreyk (prfkey = sa->sa_key_iprf) == NULL || 602fde46d6eSreyk (buf = sa->sa_1stmsg) == NULL) 603fde46d6eSreyk return (NULL); 604fde46d6eSreyk id = &sa->sa_iid; 605fde46d6eSreyk } else { 606fde46d6eSreyk if ((nonce = sa->sa_inonce) == NULL || 607fde46d6eSreyk (sa->sa_rid.id_type == 0) || 608fde46d6eSreyk (prfkey = sa->sa_key_rprf) == NULL || 609fde46d6eSreyk (buf = sa->sa_2ndmsg) == NULL) 610fde46d6eSreyk return (NULL); 611fde46d6eSreyk id = &sa->sa_rid; 612fde46d6eSreyk } 613fde46d6eSreyk 614fde46d6eSreyk if ((authmsg = ibuf_dup(buf)) == NULL) 615fde46d6eSreyk return (NULL); 616fde46d6eSreyk if (ibuf_cat(authmsg, nonce) != 0) 617fde46d6eSreyk goto fail; 618fde46d6eSreyk 619fde46d6eSreyk if ((hash_setkey(sa->sa_prf, ibuf_data(prfkey), 620fde46d6eSreyk ibuf_size(prfkey))) == NULL) 621fde46d6eSreyk goto fail; 622fde46d6eSreyk 623fde46d6eSreyk if ((ptr = ibuf_advance(authmsg, 624fde46d6eSreyk hash_length(sa->sa_prf))) == NULL) 625fde46d6eSreyk goto fail; 626fde46d6eSreyk 627fde46d6eSreyk hash_init(sa->sa_prf); 628fde46d6eSreyk hash_update(sa->sa_prf, ibuf_data(id->id_buf), ibuf_size(id->id_buf)); 629fde46d6eSreyk hash_final(sa->sa_prf, ptr, &tmplen); 630fde46d6eSreyk 631fde46d6eSreyk if (tmplen != hash_length(sa->sa_prf)) 632fde46d6eSreyk goto fail; 633fde46d6eSreyk 634fde46d6eSreyk log_debug("%s: %s auth data length %d", 635fde46d6eSreyk __func__, response ? "responder" : "initiator", 636fde46d6eSreyk ibuf_size(authmsg)); 637fde46d6eSreyk print_hex(ibuf_data(authmsg), 0, ibuf_size(authmsg)); 638fde46d6eSreyk 639fde46d6eSreyk return (authmsg); 640fde46d6eSreyk 641fde46d6eSreyk fail: 642fde46d6eSreyk ibuf_release(authmsg); 643fde46d6eSreyk return (NULL); 644fde46d6eSreyk } 645fde46d6eSreyk 646fde46d6eSreyk int 647fde46d6eSreyk ikev2_msg_authverify(struct iked *env, struct iked_sa *sa, 648fde46d6eSreyk struct iked_auth *auth, u_int8_t *buf, size_t len, struct ibuf *authmsg) 649fde46d6eSreyk { 650fde46d6eSreyk u_int8_t *key, *psk = NULL; 651fde46d6eSreyk ssize_t keylen; 652fde46d6eSreyk struct iked_id *id; 653fde46d6eSreyk struct iked_dsa *dsa = NULL; 654fde46d6eSreyk int ret = -1; 655fde46d6eSreyk u_int8_t keytype; 656fde46d6eSreyk 657fde46d6eSreyk if (sa->sa_hdr.sh_initiator) 658fde46d6eSreyk id = &sa->sa_rcert; 659fde46d6eSreyk else 660fde46d6eSreyk id = &sa->sa_icert; 661fde46d6eSreyk 662fde46d6eSreyk if ((dsa = dsa_verify_new(auth->auth_method, sa->sa_prf)) == NULL) { 663fde46d6eSreyk log_debug("%s: invalid auth method", __func__); 664fde46d6eSreyk return (-1); 665fde46d6eSreyk } 666fde46d6eSreyk 667fde46d6eSreyk switch (auth->auth_method) { 668fde46d6eSreyk case IKEV2_AUTH_SHARED_KEY_MIC: 669fde46d6eSreyk if (!auth->auth_length) { 670fde46d6eSreyk log_debug("%s: no pre-shared key found", __func__); 671fde46d6eSreyk goto done; 672fde46d6eSreyk } 673fde46d6eSreyk if ((keylen = ikev2_psk(sa, auth->auth_data, 674fde46d6eSreyk auth->auth_length, &psk)) == -1) { 675fde46d6eSreyk log_debug("%s: failed to get PSK", __func__); 676fde46d6eSreyk goto done; 677fde46d6eSreyk } 678fde46d6eSreyk key = psk; 679fde46d6eSreyk keytype = 0; 680fde46d6eSreyk break; 681fde46d6eSreyk default: 682202133c5Sreyk if (!id->id_type || !ibuf_length(id->id_buf)) { 683fde46d6eSreyk log_debug("%s: no cert found", __func__); 684fde46d6eSreyk goto done; 685fde46d6eSreyk } 686fde46d6eSreyk key = ibuf_data(id->id_buf); 687fde46d6eSreyk keylen = ibuf_size(id->id_buf); 688fde46d6eSreyk keytype = id->id_type; 689fde46d6eSreyk break; 690fde46d6eSreyk } 691fde46d6eSreyk 692fde46d6eSreyk log_debug("%s: method %s keylen %d type %s", __func__, 693fde46d6eSreyk print_map(auth->auth_method, ikev2_auth_map), keylen, 694fde46d6eSreyk print_map(id->id_type, ikev2_cert_map)); 695fde46d6eSreyk 696fde46d6eSreyk if (dsa_setkey(dsa, key, keylen, keytype) == NULL || 697fde46d6eSreyk dsa_init(dsa) != 0 || 698fde46d6eSreyk dsa_update(dsa, ibuf_data(authmsg), ibuf_size(authmsg))) { 699fde46d6eSreyk log_debug("%s: failed to compute digital signature", __func__); 700fde46d6eSreyk goto done; 701fde46d6eSreyk } 702fde46d6eSreyk 703fde46d6eSreyk if ((ret = dsa_verify_final(dsa, buf, len)) == 0) { 704fde46d6eSreyk log_debug("%s: authentication successful", __func__); 705fde46d6eSreyk sa_state(env, sa, IKEV2_STATE_AUTH_SUCCESS); 706fde46d6eSreyk 707fde46d6eSreyk if (!sa->sa_policy->pol_auth.auth_eap && 708fde46d6eSreyk auth->auth_method == IKEV2_AUTH_SHARED_KEY_MIC) 709fde46d6eSreyk sa_state(env, sa, IKEV2_STATE_VALID); 710fde46d6eSreyk } else { 711fde46d6eSreyk log_debug("%s: authentication failed", __func__); 712fde46d6eSreyk sa_state(env, sa, IKEV2_STATE_AUTH_REQUEST); 713fde46d6eSreyk } 714fde46d6eSreyk 715fde46d6eSreyk done: 716fde46d6eSreyk if (psk != NULL) 717fde46d6eSreyk free(psk); 718fde46d6eSreyk dsa_free(dsa); 719fde46d6eSreyk 720fde46d6eSreyk return (ret); 721fde46d6eSreyk } 722fde46d6eSreyk 723fde46d6eSreyk int 724fde46d6eSreyk ikev2_msg_authsign(struct iked *env, struct iked_sa *sa, 725fde46d6eSreyk struct iked_auth *auth, struct ibuf *authmsg) 726fde46d6eSreyk { 727fde46d6eSreyk u_int8_t *key, *psk = NULL; 728fde46d6eSreyk ssize_t keylen; 729fde46d6eSreyk struct iked_hash *prf = sa->sa_prf; 730fde46d6eSreyk struct iked_id *id; 731fde46d6eSreyk struct iked_dsa *dsa = NULL; 732fde46d6eSreyk struct ibuf *buf; 733fde46d6eSreyk int ret = -1; 734fde46d6eSreyk u_int8_t keytype; 735fde46d6eSreyk 736fde46d6eSreyk if (sa->sa_hdr.sh_initiator) 737fde46d6eSreyk id = &sa->sa_icert; 738fde46d6eSreyk else 739fde46d6eSreyk id = &sa->sa_rcert; 740fde46d6eSreyk 741fde46d6eSreyk if ((dsa = dsa_sign_new(auth->auth_method, prf)) == NULL) { 742fde46d6eSreyk log_debug("%s: invalid auth method", __func__); 743fde46d6eSreyk return (-1); 744fde46d6eSreyk } 745fde46d6eSreyk 746fde46d6eSreyk switch (auth->auth_method) { 747fde46d6eSreyk case IKEV2_AUTH_SHARED_KEY_MIC: 748fde46d6eSreyk if (!auth->auth_length) { 749fde46d6eSreyk log_debug("%s: no pre-shared key found", __func__); 750fde46d6eSreyk goto done; 751fde46d6eSreyk } 752fde46d6eSreyk if ((keylen = ikev2_psk(sa, auth->auth_data, 753fde46d6eSreyk auth->auth_length, &psk)) == -1) { 754fde46d6eSreyk log_debug("%s: failed to get PSK", __func__); 755fde46d6eSreyk goto done; 756fde46d6eSreyk } 757fde46d6eSreyk key = psk; 758fde46d6eSreyk keytype = 0; 759fde46d6eSreyk break; 760fde46d6eSreyk default: 761fde46d6eSreyk if (id == NULL) { 762fde46d6eSreyk log_debug("%s: no cert found", __func__); 763fde46d6eSreyk goto done; 764fde46d6eSreyk } 765fde46d6eSreyk key = ibuf_data(id->id_buf); 766fde46d6eSreyk keylen = ibuf_size(id->id_buf); 767fde46d6eSreyk keytype = id->id_type; 768fde46d6eSreyk break; 769fde46d6eSreyk } 770fde46d6eSreyk 771fde46d6eSreyk if (dsa_setkey(dsa, key, keylen, keytype) == NULL || 772fde46d6eSreyk dsa_init(dsa) != 0 || 773fde46d6eSreyk dsa_update(dsa, ibuf_data(authmsg), ibuf_size(authmsg))) { 774fde46d6eSreyk log_debug("%s: failed to compute digital signature", __func__); 775fde46d6eSreyk goto done; 776fde46d6eSreyk } 777fde46d6eSreyk 778fde46d6eSreyk ibuf_release(sa->sa_localauth.id_buf); 779fde46d6eSreyk sa->sa_localauth.id_buf = NULL; 780fde46d6eSreyk 781fde46d6eSreyk if ((buf = ibuf_new(NULL, dsa_length(dsa))) == NULL) { 782fde46d6eSreyk log_debug("%s: failed to get auth buffer", __func__); 783fde46d6eSreyk goto done; 784fde46d6eSreyk } 785fde46d6eSreyk 786fde46d6eSreyk if ((ret = dsa_sign_final(dsa, 787fde46d6eSreyk ibuf_data(buf), ibuf_size(buf))) == -1) { 788fde46d6eSreyk log_debug("%s: failed to create auth signature", __func__); 789fde46d6eSreyk ibuf_release(buf); 790fde46d6eSreyk goto done; 791fde46d6eSreyk } 792fde46d6eSreyk 793fde46d6eSreyk sa->sa_localauth.id_type = auth->auth_method; 794fde46d6eSreyk sa->sa_localauth.id_buf = buf; 795fde46d6eSreyk 796fde46d6eSreyk ret = 0; 797fde46d6eSreyk done: 798fde46d6eSreyk if (psk != NULL) 799fde46d6eSreyk free(psk); 800fde46d6eSreyk dsa_free(dsa); 801fde46d6eSreyk 802fde46d6eSreyk return (ret); 803fde46d6eSreyk } 804ae494144Sreyk 805ae494144Sreyk int 806ae494144Sreyk ikev2_msg_frompeer(struct iked_message *msg) 807ae494144Sreyk { 808ae494144Sreyk struct iked_sa *sa = msg->msg_sa; 809ae494144Sreyk struct ike_header *hdr; 810ae494144Sreyk 81126d7dba1Sreyk msg = msg->msg_parent; 8121b0d4946Sreyk 813ae494144Sreyk if (sa == NULL || 814ae494144Sreyk (hdr = ibuf_seek(msg->msg_data, 0, sizeof(*hdr))) == NULL) 815ae494144Sreyk return (0); 816ae494144Sreyk 817ae494144Sreyk if (!sa->sa_hdr.sh_initiator && 818ae494144Sreyk (hdr->ike_flags & IKEV2_FLAG_INITIATOR)) 819ae494144Sreyk return (1); 820ae494144Sreyk else if (sa->sa_hdr.sh_initiator && 821ae494144Sreyk (hdr->ike_flags & IKEV2_FLAG_INITIATOR) == 0) 822ae494144Sreyk return (1); 823ae494144Sreyk 824ae494144Sreyk return (0); 825ae494144Sreyk } 826ae494144Sreyk 827ae494144Sreyk struct iked_socket * 828ae494144Sreyk ikev2_msg_getsocket(struct iked *env, int af) 829ae494144Sreyk { 830ae494144Sreyk switch (af) { 831ae494144Sreyk case AF_INET: 832ae494144Sreyk return (env->sc_sock4); 833ae494144Sreyk case AF_INET6: 834ae494144Sreyk return (env->sc_sock6); 835ae494144Sreyk } 836ae494144Sreyk 837ae494144Sreyk log_debug("%s: af socket %d not available", __func__, af); 838ae494144Sreyk return (NULL); 839ae494144Sreyk } 840