diff options
Diffstat (limited to 'src/racoon/isakmp_quick.c')
-rw-r--r-- | src/racoon/isakmp_quick.c | 2189 |
1 files changed, 0 insertions, 2189 deletions
diff --git a/src/racoon/isakmp_quick.c b/src/racoon/isakmp_quick.c deleted file mode 100644 index 963438d..0000000 --- a/src/racoon/isakmp_quick.c +++ /dev/null @@ -1,2189 +0,0 @@ -/* $NetBSD: isakmp_quick.c,v 1.11.4.1 2007/08/01 11:52:21 vanhu Exp $ */ - -/* Id: isakmp_quick.c,v 1.29 2006/08/22 18:17:17 manubsd Exp */ - -/* - * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "config.h" - -#include <sys/types.h> -#include <sys/param.h> -#include <sys/socket.h> - -#include <netinet/in.h> - -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <errno.h> -#if TIME_WITH_SYS_TIME -# include <sys/time.h> -# include <time.h> -#else -# if HAVE_SYS_TIME_H -# include <sys/time.h> -# else -# include <time.h> -# endif -#endif -#ifdef ENABLE_HYBRID -#include <resolv.h> -#endif - -#include PATH_IPSEC_H - -#include "var.h" -#include "vmbuf.h" -#include "schedule.h" -#include "misc.h" -#include "plog.h" -#include "debug.h" - -#include "localconf.h" -#include "remoteconf.h" -#include "handler.h" -#include "policy.h" -#include "proposal.h" -#include "isakmp_var.h" -#include "isakmp.h" -#include "isakmp_inf.h" -#include "isakmp_quick.h" -#include "oakley.h" -#include "ipsec_doi.h" -#include "crypto_openssl.h" -#include "pfkey.h" -#include "policy.h" -#include "algorithm.h" -#include "sockmisc.h" -#include "proposal.h" -#include "sainfo.h" -#include "admin.h" -#include "strnames.h" - -/* quick mode */ -static vchar_t *quick_ir1mx __P((struct ph2handle *, vchar_t *, vchar_t *)); -static int get_sainfo_r __P((struct ph2handle *)); -static int get_proposal_r __P((struct ph2handle *)); - -/* %%% - * Quick Mode - */ -/* - * begin Quick Mode as initiator. send pfkey getspi message to kernel. - */ -int -quick_i1prep(iph2, msg) - struct ph2handle *iph2; - vchar_t *msg; /* must be null pointer */ -{ - int error = ISAKMP_INTERNAL_ERROR; - - /* validity check */ - if (iph2->status != PHASE2ST_STATUS2) { - plog(LLV_ERROR, LOCATION, NULL, - "status mismatched %d.\n", iph2->status); - goto end; - } - - iph2->msgid = isakmp_newmsgid2(iph2->ph1); - iph2->ivm = oakley_newiv2(iph2->ph1, iph2->msgid); - if (iph2->ivm == NULL) - return 0; - - iph2->status = PHASE2ST_GETSPISENT; - - /* don't anything if local test mode. */ - if (f_local) { - error = 0; - goto end; - } - - /* send getspi message */ - if (pk_sendgetspi(iph2) < 0) - goto end; - - plog(LLV_DEBUG, LOCATION, NULL, "pfkey getspi sent.\n"); - - iph2->sce = sched_new(lcconf->wait_ph2complete, - pfkey_timeover_stub, iph2); - - error = 0; - -end: - return error; -} - -/* - * send to responder - * HDR*, HASH(1), SA, Ni [, KE ] [, IDi2, IDr2 ] - */ -int -quick_i1send(iph2, msg) - struct ph2handle *iph2; - vchar_t *msg; /* must be null pointer */ -{ - vchar_t *body = NULL; - vchar_t *hash = NULL; - struct isakmp_gen *gen; - char *p; - int tlen; - int error = ISAKMP_INTERNAL_ERROR; - int pfsgroup, idci, idcr; - int np; - struct ipsecdoi_id_b *id, *id_p; - - /* validity check */ - if (msg != NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "msg has to be NULL in this function.\n"); - goto end; - } - if (iph2->status != PHASE2ST_GETSPIDONE) { - plog(LLV_ERROR, LOCATION, NULL, - "status mismatched %d.\n", iph2->status); - goto end; - } - - /* create SA payload for my proposal */ - if (ipsecdoi_setph2proposal(iph2) < 0) - goto end; - - /* generate NONCE value */ - iph2->nonce = eay_set_random(iph2->ph1->rmconf->nonce_size); - if (iph2->nonce == NULL) - goto end; - - /* - * DH value calculation is kicked out into cfparse.y. - * because pfs group can not be negotiated, it's only to be checked - * acceptable. - */ - /* generate KE value if need */ - pfsgroup = iph2->proposal->pfs_group; - if (pfsgroup) { - /* DH group settting if PFS is required. */ - if (oakley_setdhgroup(pfsgroup, &iph2->pfsgrp) < 0) { - plog(LLV_ERROR, LOCATION, NULL, - "failed to set DH value.\n"); - goto end; - } - if (oakley_dh_generate(iph2->pfsgrp, - &iph2->dhpub, &iph2->dhpriv) < 0) { - goto end; - } - } - - /* generate ID value */ - if (ipsecdoi_setid2(iph2) < 0) { - plog(LLV_ERROR, LOCATION, NULL, - "failed to get ID.\n"); - goto end; - } - plog(LLV_DEBUG, LOCATION, NULL, "IDci:\n"); - plogdump(LLV_DEBUG, iph2->id->v, iph2->id->l); - plog(LLV_DEBUG, LOCATION, NULL, "IDcr:\n"); - plogdump(LLV_DEBUG, iph2->id_p->v, iph2->id_p->l); - - /* - * we do not attach IDci nor IDcr, under the following condition: - * - all proposals are transport mode - * - no MIP6 or proxy - * - id payload suggests to encrypt all the traffic (no specific - * protocol type) - */ - id = (struct ipsecdoi_id_b *)iph2->id->v; - id_p = (struct ipsecdoi_id_b *)iph2->id_p->v; - if (id->proto_id == 0 - && id_p->proto_id == 0 - && iph2->ph1->rmconf->support_proxy == 0 - && ipsecdoi_transportmode(iph2->proposal)) { - idci = idcr = 0; - } else - idci = idcr = 1; - - /* create SA;NONCE payload, and KE if need, and IDii, IDir. */ - tlen = + sizeof(*gen) + iph2->sa->l - + sizeof(*gen) + iph2->nonce->l; - if (pfsgroup) - tlen += (sizeof(*gen) + iph2->dhpub->l); - if (idci) - tlen += sizeof(*gen) + iph2->id->l; - if (idcr) - tlen += sizeof(*gen) + iph2->id_p->l; - - body = vmalloc(tlen); - if (body == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "failed to get buffer to send.\n"); - goto end; - } - - p = body->v; - - /* add SA payload */ - p = set_isakmp_payload(p, iph2->sa, ISAKMP_NPTYPE_NONCE); - - /* add NONCE payload */ - if (pfsgroup) - np = ISAKMP_NPTYPE_KE; - else if (idci || idcr) - np = ISAKMP_NPTYPE_ID; - else - np = ISAKMP_NPTYPE_NONE; - p = set_isakmp_payload(p, iph2->nonce, np); - - /* add KE payload if need. */ - np = (idci || idcr) ? ISAKMP_NPTYPE_ID : ISAKMP_NPTYPE_NONE; - if (pfsgroup) - p = set_isakmp_payload(p, iph2->dhpub, np); - - /* IDci */ - np = (idcr) ? ISAKMP_NPTYPE_ID : ISAKMP_NPTYPE_NONE; - if (idci) - p = set_isakmp_payload(p, iph2->id, np); - - /* IDcr */ - if (idcr) - p = set_isakmp_payload(p, iph2->id_p, ISAKMP_NPTYPE_NONE); - - /* generate HASH(1) */ - hash = oakley_compute_hash1(iph2->ph1, iph2->msgid, body); - if (hash == NULL) - goto end; - - /* send isakmp payload */ - iph2->sendbuf = quick_ir1mx(iph2, body, hash); - if (iph2->sendbuf == NULL) - goto end; - - /* send the packet, add to the schedule to resend */ - iph2->retry_counter = iph2->ph1->rmconf->retry_counter; - if (isakmp_ph2resend(iph2) == -1) - goto end; - - /* change status of isakmp status entry */ - iph2->status = PHASE2ST_MSG1SENT; - - error = 0; - -end: - if (body != NULL) - vfree(body); - if (hash != NULL) - vfree(hash); - - return error; -} - -/* - * receive from responder - * HDR*, HASH(2), SA, Nr [, KE ] [, IDi2, IDr2 ] - */ -int -quick_i2recv(iph2, msg0) - struct ph2handle *iph2; - vchar_t *msg0; -{ - vchar_t *msg = NULL; - vchar_t *hbuf = NULL; /* for hash computing. */ - vchar_t *pbuf = NULL; /* for payload parsing */ - struct isakmp_parse_t *pa; - struct isakmp *isakmp = (struct isakmp *)msg0->v; - struct isakmp_pl_hash *hash = NULL; - int f_id; - char *p; - int tlen; - int error = ISAKMP_INTERNAL_ERROR; - - /* validity check */ - if (iph2->status != PHASE2ST_MSG1SENT) { - plog(LLV_ERROR, LOCATION, NULL, - "status mismatched %d.\n", iph2->status); - goto end; - } - - /* decrypt packet */ - if (!ISSET(((struct isakmp *)msg0->v)->flags, ISAKMP_FLAG_E)) { - plog(LLV_ERROR, LOCATION, iph2->ph1->remote, - "Packet wasn't encrypted.\n"); - goto end; - } - msg = oakley_do_decrypt(iph2->ph1, msg0, iph2->ivm->iv, iph2->ivm->ive); - if (msg == NULL) - goto end; - - /* create buffer for validating HASH(2) */ - /* - * ordering rule: - * 1. the first one must be HASH - * 2. the second one must be SA (added in isakmp-oakley-05!) - * 3. two IDs must be considered as IDci, then IDcr - */ - pbuf = isakmp_parse(msg); - if (pbuf == NULL) - goto end; - pa = (struct isakmp_parse_t *)pbuf->v; - - /* HASH payload is fixed postion */ - if (pa->type != ISAKMP_NPTYPE_HASH) { - plog(LLV_ERROR, LOCATION, iph2->ph1->remote, - "received invalid next payload type %d, " - "expecting %d.\n", - pa->type, ISAKMP_NPTYPE_HASH); - goto end; - } - hash = (struct isakmp_pl_hash *)pa->ptr; - pa++; - - /* - * this restriction was introduced in isakmp-oakley-05. - * we do not check this for backward compatibility. - * TODO: command line/config file option to enable/disable this code - */ - /* HASH payload is fixed postion */ - if (pa->type != ISAKMP_NPTYPE_SA) { - plog(LLV_WARNING, LOCATION, iph2->ph1->remote, - "received invalid next payload type %d, " - "expecting %d.\n", - pa->type, ISAKMP_NPTYPE_HASH); - } - - /* allocate buffer for computing HASH(2) */ - tlen = iph2->nonce->l - + ntohl(isakmp->len) - sizeof(*isakmp); - hbuf = vmalloc(tlen); - if (hbuf == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "failed to get hash buffer.\n"); - goto end; - } - p = hbuf->v + iph2->nonce->l; /* retain the space for Ni_b */ - - /* - * parse the payloads. - * copy non-HASH payloads into hbuf, so that we can validate HASH. - */ - iph2->sa_ret = NULL; - f_id = 0; /* flag to use checking ID */ - tlen = 0; /* count payload length except of HASH payload. */ - for (; pa->type; pa++) { - - /* copy to buffer for HASH */ - /* Don't modify the payload */ - memcpy(p, pa->ptr, pa->len); - - switch (pa->type) { - case ISAKMP_NPTYPE_SA: - if (iph2->sa_ret != NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "Ignored, multiple SA " - "isn't supported.\n"); - break; - } - if (isakmp_p2ph(&iph2->sa_ret, pa->ptr) < 0) - goto end; - break; - - case ISAKMP_NPTYPE_NONCE: - if (isakmp_p2ph(&iph2->nonce_p, pa->ptr) < 0) - goto end; - break; - - case ISAKMP_NPTYPE_KE: - if (isakmp_p2ph(&iph2->dhpub_p, pa->ptr) < 0) - goto end; - break; - - case ISAKMP_NPTYPE_ID: - { - vchar_t *vp; - - /* check ID value */ - if (f_id == 0) { - /* for IDci */ - f_id = 1; - vp = iph2->id; - } else { - /* for IDcr */ - vp = iph2->id_p; - } - -#ifndef ANDROID_PATCHED - if (memcmp(vp->v, (caddr_t)pa->ptr + sizeof(struct isakmp_gen), vp->l)) { - - plog(LLV_ERROR, LOCATION, NULL, - "mismatched ID was returned.\n"); - error = ISAKMP_NTYPE_ATTRIBUTES_NOT_SUPPORTED; - goto end; - } -#endif - } - break; - - case ISAKMP_NPTYPE_N: - isakmp_check_notify(pa->ptr, iph2->ph1); - break; - -#ifdef ENABLE_NATT - case ISAKMP_NPTYPE_NATOA_DRAFT: - case ISAKMP_NPTYPE_NATOA_RFC: - /* Ignore original source/destination messages */ - break; -#endif - - default: - /* don't send information, see ident_r1recv() */ - plog(LLV_ERROR, LOCATION, iph2->ph1->remote, - "ignore the packet, " - "received unexpecting payload type %d.\n", - pa->type); - goto end; - } - - p += pa->len; - - /* compute true length of payload. */ - tlen += pa->len; - } - - /* payload existency check */ - if (hash == NULL || iph2->sa_ret == NULL || iph2->nonce_p == NULL) { - plog(LLV_ERROR, LOCATION, iph2->ph1->remote, - "few isakmp message received.\n"); - goto end; - } - - /* Fixed buffer for calculating HASH */ - memcpy(hbuf->v, iph2->nonce->v, iph2->nonce->l); - plog(LLV_DEBUG, LOCATION, NULL, - "HASH allocated:hbuf->l=%zu actual:tlen=%zu\n", - hbuf->l, tlen + iph2->nonce->l); - /* adjust buffer length for HASH */ - hbuf->l = iph2->nonce->l + tlen; - - /* validate HASH(2) */ - { - char *r_hash; - vchar_t *my_hash = NULL; - int result; - - r_hash = (char *)hash + sizeof(*hash); - - plog(LLV_DEBUG, LOCATION, NULL, "HASH(2) received:"); - plogdump(LLV_DEBUG, r_hash, ntohs(hash->h.len) - sizeof(*hash)); - - my_hash = oakley_compute_hash1(iph2->ph1, iph2->msgid, hbuf); - if (my_hash == NULL) - goto end; - - result = memcmp(my_hash->v, r_hash, my_hash->l); - vfree(my_hash); - - if (result) { - plog(LLV_DEBUG, LOCATION, iph2->ph1->remote, - "HASH(2) mismatch.\n"); - error = ISAKMP_NTYPE_INVALID_HASH_INFORMATION; - goto end; - } - } - - /* validity check SA payload sent from responder */ - if (ipsecdoi_checkph2proposal(iph2) < 0) { - error = ISAKMP_NTYPE_NO_PROPOSAL_CHOSEN; - goto end; - } - - /* change status of isakmp status entry */ - iph2->status = PHASE2ST_STATUS6; - - error = 0; - -end: - if (hbuf) - vfree(hbuf); - if (pbuf) - vfree(pbuf); - if (msg) - vfree(msg); - - if (error) { - VPTRINIT(iph2->sa_ret); - VPTRINIT(iph2->nonce_p); - VPTRINIT(iph2->dhpub_p); - VPTRINIT(iph2->id); - VPTRINIT(iph2->id_p); - } - - return error; -} - -/* - * send to responder - * HDR*, HASH(3) - */ -int -quick_i2send(iph2, msg0) - struct ph2handle *iph2; - vchar_t *msg0; -{ - vchar_t *msg = NULL; - vchar_t *buf = NULL; - vchar_t *hash = NULL; - char *p = NULL; - int tlen; - int error = ISAKMP_INTERNAL_ERROR; - - /* validity check */ - if (iph2->status != PHASE2ST_STATUS6) { - plog(LLV_ERROR, LOCATION, NULL, - "status mismatched %d.\n", iph2->status); - goto end; - } - - /* generate HASH(3) */ - { - vchar_t *tmp = NULL; - - plog(LLV_DEBUG, LOCATION, NULL, "HASH(3) generate\n"); - - tmp = vmalloc(iph2->nonce->l + iph2->nonce_p->l); - if (tmp == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "failed to get hash buffer.\n"); - goto end; - } - memcpy(tmp->v, iph2->nonce->v, iph2->nonce->l); - memcpy(tmp->v + iph2->nonce->l, iph2->nonce_p->v, iph2->nonce_p->l); - - hash = oakley_compute_hash3(iph2->ph1, iph2->msgid, tmp); - vfree(tmp); - - if (hash == NULL) - goto end; - } - - /* create buffer for isakmp payload */ - tlen = sizeof(struct isakmp) - + sizeof(struct isakmp_gen) + hash->l; - buf = vmalloc(tlen); - if (buf == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "failed to get buffer to send.\n"); - goto end; - } - - /* create isakmp header */ - p = set_isakmp_header2(buf, iph2, ISAKMP_NPTYPE_HASH); - if (p == NULL) - goto end; - - /* add HASH(3) payload */ - p = set_isakmp_payload(p, hash, ISAKMP_NPTYPE_NONE); - -#ifdef HAVE_PRINT_ISAKMP_C - isakmp_printpacket(buf, iph2->ph1->local, iph2->ph1->remote, 1); -#endif - - /* encoding */ - iph2->sendbuf = oakley_do_encrypt(iph2->ph1, buf, iph2->ivm->ive, iph2->ivm->iv); - if (iph2->sendbuf == NULL) - goto end; - - /* if there is commit bit, need resending */ - if (ISSET(iph2->flags, ISAKMP_FLAG_C)) { - /* send the packet, add to the schedule to resend */ - iph2->retry_counter = iph2->ph1->rmconf->retry_counter; - if (isakmp_ph2resend(iph2) == -1) - goto end; - } else { - /* send the packet */ - if (isakmp_send(iph2->ph1, iph2->sendbuf) < 0) - goto end; - } - - /* the sending message is added to the received-list. */ - if (add_recvdpkt(iph2->ph1->remote, iph2->ph1->local, - iph2->sendbuf, msg0) == -1) { - plog(LLV_ERROR , LOCATION, NULL, - "failed to add a response packet to the tree.\n"); - goto end; - } - - /* compute both of KEYMATs */ - if (oakley_compute_keymat(iph2, INITIATOR) < 0) - goto end; - - iph2->status = PHASE2ST_ADDSA; - - /* don't anything if local test mode. */ - if (f_local) { - error = 0; - goto end; - } - - /* if there is commit bit don't set up SA now. */ - if (ISSET(iph2->flags, ISAKMP_FLAG_C)) { - iph2->status = PHASE2ST_COMMIT; - error = 0; - goto end; - } - - /* Do UPDATE for initiator */ - plog(LLV_DEBUG, LOCATION, NULL, "call pk_sendupdate\n"); - if (pk_sendupdate(iph2) < 0) { - plog(LLV_ERROR, LOCATION, NULL, "pfkey update failed.\n"); - goto end; - } - plog(LLV_DEBUG, LOCATION, NULL, "pfkey update sent.\n"); - - /* Do ADD for responder */ - if (pk_sendadd(iph2) < 0) { - plog(LLV_ERROR, LOCATION, NULL, "pfkey add failed.\n"); - goto end; - } - plog(LLV_DEBUG, LOCATION, NULL, "pfkey add sent.\n"); - - error = 0; - -end: - if (buf != NULL) - vfree(buf); - if (msg != NULL) - vfree(msg); - if (hash != NULL) - vfree(hash); - - return error; -} - -/* - * receive from responder - * HDR#*, HASH(4), notify - */ -int -quick_i3recv(iph2, msg0) - struct ph2handle *iph2; - vchar_t *msg0; -{ - vchar_t *msg = NULL; - vchar_t *pbuf = NULL; /* for payload parsing */ - struct isakmp_parse_t *pa; - struct isakmp_pl_hash *hash = NULL; - vchar_t *notify = NULL; - int error = ISAKMP_INTERNAL_ERROR; - - /* validity check */ - if (iph2->status != PHASE2ST_COMMIT) { - plog(LLV_ERROR, LOCATION, NULL, - "status mismatched %d.\n", iph2->status); - goto end; - } - - /* decrypt packet */ - if (!ISSET(((struct isakmp *)msg0->v)->flags, ISAKMP_FLAG_E)) { - plog(LLV_ERROR, LOCATION, iph2->ph1->remote, - "Packet wasn't encrypted.\n"); - goto end; - } - msg = oakley_do_decrypt(iph2->ph1, msg0, iph2->ivm->iv, iph2->ivm->ive); - if (msg == NULL) - goto end; - - /* validate the type of next payload */ - pbuf = isakmp_parse(msg); - if (pbuf == NULL) - goto end; - - for (pa = (struct isakmp_parse_t *)pbuf->v; - pa->type != ISAKMP_NPTYPE_NONE; - pa++) { - - switch (pa->type) { - case ISAKMP_NPTYPE_HASH: - hash = (struct isakmp_pl_hash *)pa->ptr; - break; - case ISAKMP_NPTYPE_N: - if (notify != NULL) { - plog(LLV_WARNING, LOCATION, NULL, - "Ignoring multiples notifications\n"); - break; - } - isakmp_check_notify(pa->ptr, iph2->ph1); - notify = vmalloc(pa->len); - if (notify == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "failed to get notify buffer.\n"); - goto end; - } - memcpy(notify->v, pa->ptr, notify->l); - break; - default: - /* don't send information, see ident_r1recv() */ - plog(LLV_ERROR, LOCATION, iph2->ph1->remote, - "ignore the packet, " - "received unexpecting payload type %d.\n", - pa->type); - goto end; - } - } - - /* payload existency check */ - if (hash == NULL) { - plog(LLV_ERROR, LOCATION, iph2->ph1->remote, - "few isakmp message received.\n"); - goto end; - } - - /* validate HASH(4) */ - { - char *r_hash; - vchar_t *my_hash = NULL; - vchar_t *tmp = NULL; - int result; - - r_hash = (char *)hash + sizeof(*hash); - - plog(LLV_DEBUG, LOCATION, NULL, "HASH(4) validate:"); - plogdump(LLV_DEBUG, r_hash, ntohs(hash->h.len) - sizeof(*hash)); - - my_hash = oakley_compute_hash1(iph2->ph1, iph2->msgid, notify); - vfree(tmp); - if (my_hash == NULL) - goto end; - - result = memcmp(my_hash->v, r_hash, my_hash->l); - vfree(my_hash); - - if (result) { - plog(LLV_DEBUG, LOCATION, iph2->ph1->remote, - "HASH(4) mismatch.\n"); - error = ISAKMP_NTYPE_INVALID_HASH_INFORMATION; - goto end; - } - } - - iph2->status = PHASE2ST_ADDSA; - iph2->flags ^= ISAKMP_FLAG_C; /* reset bit */ - - /* don't anything if local test mode. */ - if (f_local) { - error = 0; - goto end; - } - - /* Do UPDATE for initiator */ - plog(LLV_DEBUG, LOCATION, NULL, "call pk_sendupdate\n"); - if (pk_sendupdate(iph2) < 0) { - plog(LLV_ERROR, LOCATION, NULL, "pfkey update failed.\n"); - goto end; - } - plog(LLV_DEBUG, LOCATION, NULL, "pfkey update sent.\n"); - - /* Do ADD for responder */ - if (pk_sendadd(iph2) < 0) { - plog(LLV_ERROR, LOCATION, NULL, "pfkey add failed.\n"); - goto end; - } - plog(LLV_DEBUG, LOCATION, NULL, "pfkey add sent.\n"); - - error = 0; - -end: - if (msg != NULL) - vfree(msg); - if (pbuf != NULL) - vfree(pbuf); - if (notify != NULL) - vfree(notify); - - return error; -} - -/* - * receive from initiator - * HDR*, HASH(1), SA, Ni [, KE ] [, IDi2, IDr2 ] - */ -int -quick_r1recv(iph2, msg0) - struct ph2handle *iph2; - vchar_t *msg0; -{ - vchar_t *msg = NULL; - vchar_t *hbuf = NULL; /* for hash computing. */ - vchar_t *pbuf = NULL; /* for payload parsing */ - struct isakmp_parse_t *pa; - struct isakmp *isakmp = (struct isakmp *)msg0->v; - struct isakmp_pl_hash *hash = NULL; - char *p; - int tlen; - int f_id_order; /* for ID payload detection */ - int error = ISAKMP_INTERNAL_ERROR; - - /* validity check */ - if (iph2->status != PHASE2ST_START) { - plog(LLV_ERROR, LOCATION, NULL, - "status mismatched %d.\n", iph2->status); - goto end; - } - - /* decrypting */ - if (!ISSET(((struct isakmp *)msg0->v)->flags, ISAKMP_FLAG_E)) { - plog(LLV_ERROR, LOCATION, iph2->ph1->remote, - "Packet wasn't encrypted.\n"); - error = ISAKMP_NTYPE_PAYLOAD_MALFORMED; - goto end; - } - /* decrypt packet */ - msg = oakley_do_decrypt(iph2->ph1, msg0, iph2->ivm->iv, iph2->ivm->ive); - if (msg == NULL) - goto end; - - /* create buffer for using to validate HASH(1) */ - /* - * ordering rule: - * 1. the first one must be HASH - * 2. the second one must be SA (added in isakmp-oakley-05!) - * 3. two IDs must be considered as IDci, then IDcr - */ - pbuf = isakmp_parse(msg); - if (pbuf == NULL) - goto end; - pa = (struct isakmp_parse_t *)pbuf->v; - - /* HASH payload is fixed postion */ - if (pa->type != ISAKMP_NPTYPE_HASH) { - plog(LLV_ERROR, LOCATION, iph2->ph1->remote, - "received invalid next payload type %d, " - "expecting %d.\n", - pa->type, ISAKMP_NPTYPE_HASH); - error = ISAKMP_NTYPE_BAD_PROPOSAL_SYNTAX; - goto end; - } - hash = (struct isakmp_pl_hash *)pa->ptr; - pa++; - - /* - * this restriction was introduced in isakmp-oakley-05. - * we do not check this for backward compatibility. - * TODO: command line/config file option to enable/disable this code - */ - /* HASH payload is fixed postion */ - if (pa->type != ISAKMP_NPTYPE_SA) { - plog(LLV_WARNING, LOCATION, iph2->ph1->remote, - "received invalid next payload type %d, " - "expecting %d.\n", - pa->type, ISAKMP_NPTYPE_SA); - error = ISAKMP_NTYPE_BAD_PROPOSAL_SYNTAX; - } - - /* allocate buffer for computing HASH(1) */ - tlen = ntohl(isakmp->len) - sizeof(*isakmp); - hbuf = vmalloc(tlen); - if (hbuf == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "failed to get hash buffer.\n"); - goto end; - } - p = hbuf->v; - - /* - * parse the payloads. - * copy non-HASH payloads into hbuf, so that we can validate HASH. - */ - iph2->sa = NULL; /* we don't support multi SAs. */ - iph2->nonce_p = NULL; - iph2->dhpub_p = NULL; - iph2->id_p = NULL; - iph2->id = NULL; - tlen = 0; /* count payload length except of HASH payload. */ - - /* - * IDi2 MUST be immediatelly followed by IDr2. We allowed the - * illegal case, but logged. First ID payload is to be IDi2. - * And next ID payload is to be IDr2. - */ - f_id_order = 0; - - for (; pa->type; pa++) { - - /* copy to buffer for HASH */ - /* Don't modify the payload */ - memcpy(p, pa->ptr, pa->len); - - if (pa->type != ISAKMP_NPTYPE_ID) - f_id_order = 0; - - switch (pa->type) { - case ISAKMP_NPTYPE_SA: - if (iph2->sa != NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "Multi SAs isn't supported.\n"); - goto end; - } - if (isakmp_p2ph(&iph2->sa, pa->ptr) < 0) - goto end; - break; - - case ISAKMP_NPTYPE_NONCE: - if (isakmp_p2ph(&iph2->nonce_p, pa->ptr) < 0) - goto end; - break; - - case ISAKMP_NPTYPE_KE: - if (isakmp_p2ph(&iph2->dhpub_p, pa->ptr) < 0) - goto end; - break; - - case ISAKMP_NPTYPE_ID: - if (iph2->id_p == NULL) { - /* for IDci */ - f_id_order++; - - if (isakmp_p2ph(&iph2->id_p, pa->ptr) < 0) - goto end; - - } else if (iph2->id == NULL) { - /* for IDcr */ - if (f_id_order == 0) { - plog(LLV_ERROR, LOCATION, NULL, - "IDr2 payload is not " - "immediatelly followed " - "by IDi2. We allowed.\n"); - /* XXX we allowed in this case. */ - } - - if (isakmp_p2ph(&iph2->id, pa->ptr) < 0) - goto end; - } else { - plog(LLV_ERROR, LOCATION, NULL, - "received too many ID payloads.\n"); - plogdump(LLV_ERROR, iph2->id->v, iph2->id->l); - error = ISAKMP_NTYPE_INVALID_ID_INFORMATION; - goto end; - } - break; - - case ISAKMP_NPTYPE_N: - isakmp_check_notify(pa->ptr, iph2->ph1); - break; - -#ifdef ENABLE_NATT - case ISAKMP_NPTYPE_NATOA_DRAFT: - case ISAKMP_NPTYPE_NATOA_RFC: - /* Ignore original source/destination messages */ - break; -#endif - - default: - plog(LLV_ERROR, LOCATION, iph2->ph1->remote, - "ignore the packet, " - "received unexpecting payload type %d.\n", - pa->type); - error = ISAKMP_NTYPE_PAYLOAD_MALFORMED; - goto end; - } - - p += pa->len; - - /* compute true length of payload. */ - tlen += pa->len; - } - - /* payload existency check */ - if (hash == NULL || iph2->sa == NULL || iph2->nonce_p == NULL) { - plog(LLV_ERROR, LOCATION, iph2->ph1->remote, - "few isakmp message received.\n"); - error = ISAKMP_NTYPE_PAYLOAD_MALFORMED; - goto end; - } - - if (iph2->id_p) { - plog(LLV_DEBUG, LOCATION, NULL, "received IDci2:"); - plogdump(LLV_DEBUG, iph2->id_p->v, iph2->id_p->l); - } - if (iph2->id) { - plog(LLV_DEBUG, LOCATION, NULL, "received IDcr2:"); - plogdump(LLV_DEBUG, iph2->id->v, iph2->id->l); - } - - /* adjust buffer length for HASH */ - hbuf->l = tlen; - - /* validate HASH(1) */ - { - char *r_hash; - vchar_t *my_hash = NULL; - int result; - - r_hash = (caddr_t)hash + sizeof(*hash); - - plog(LLV_DEBUG, LOCATION, NULL, "HASH(1) validate:"); - plogdump(LLV_DEBUG, r_hash, ntohs(hash->h.len) - sizeof(*hash)); - - my_hash = oakley_compute_hash1(iph2->ph1, iph2->msgid, hbuf); - if (my_hash == NULL) - goto end; - - result = memcmp(my_hash->v, r_hash, my_hash->l); - vfree(my_hash); - - if (result) { - plog(LLV_DEBUG, LOCATION, iph2->ph1->remote, - "HASH(1) mismatch.\n"); - error = ISAKMP_NTYPE_INVALID_HASH_INFORMATION; - goto end; - } - } - - /* get sainfo */ - error = get_sainfo_r(iph2); - if (error) { - plog(LLV_ERROR, LOCATION, NULL, - "failed to get sainfo.\n"); - goto end; - } - - - /* check the existence of ID payload and create responder's proposal */ - error = get_proposal_r(iph2); - switch (error) { - case -2: - /* generate a policy template from peer's proposal */ - if (set_proposal_from_proposal(iph2)) { - plog(LLV_ERROR, LOCATION, NULL, - "failed to generate a proposal template " - "from client's proposal.\n"); - return ISAKMP_INTERNAL_ERROR; - } - /*FALLTHROUGH*/ - case 0: - /* select single proposal or reject it. */ - if (ipsecdoi_selectph2proposal(iph2) < 0) { - error = ISAKMP_NTYPE_NO_PROPOSAL_CHOSEN; - goto end; - } - break; - default: - plog(LLV_ERROR, LOCATION, NULL, - "failed to get proposal for responder.\n"); - goto end; - } - - /* check KE and attribute of PFS */ - if (iph2->dhpub_p != NULL && iph2->approval->pfs_group == 0) { - plog(LLV_ERROR, LOCATION, NULL, - "no PFS is specified, but peer sends KE.\n"); - error = ISAKMP_NTYPE_NO_PROPOSAL_CHOSEN; - goto end; - } - if (iph2->dhpub_p == NULL && iph2->approval->pfs_group != 0) { - plog(LLV_ERROR, LOCATION, NULL, - "PFS is specified, but peer doesn't sends KE.\n"); - error = ISAKMP_NTYPE_NO_PROPOSAL_CHOSEN; - goto end; - } - - /* - * save the packet from the initiator in order to resend the - * responder's first packet against this packet. - */ - iph2->msg1 = vdup(msg0); - - /* change status of isakmp status entry */ - iph2->status = PHASE2ST_STATUS2; - - error = 0; - -end: - if (hbuf) - vfree(hbuf); - if (msg) - vfree(msg); - if (pbuf) - vfree(pbuf); - - if (error) { - VPTRINIT(iph2->sa); - VPTRINIT(iph2->nonce_p); - VPTRINIT(iph2->dhpub_p); - VPTRINIT(iph2->id); - VPTRINIT(iph2->id_p); - } - - return error; -} - -/* - * call pfkey_getspi. - */ -int -quick_r1prep(iph2, msg) - struct ph2handle *iph2; - vchar_t *msg; -{ - int error = ISAKMP_INTERNAL_ERROR; - - /* validity check */ - if (iph2->status != PHASE2ST_STATUS2) { - plog(LLV_ERROR, LOCATION, NULL, - "status mismatched %d.\n", iph2->status); - goto end; - } - - iph2->status = PHASE2ST_GETSPISENT; - - /* send getspi message */ - if (pk_sendgetspi(iph2) < 0) - goto end; - - plog(LLV_DEBUG, LOCATION, NULL, "pfkey getspi sent.\n"); - - iph2->sce = sched_new(lcconf->wait_ph2complete, - pfkey_timeover_stub, iph2); - - error = 0; - -end: - return error; -} - -/* - * send to initiator - * HDR*, HASH(2), SA, Nr [, KE ] [, IDi2, IDr2 ] - */ -int -quick_r2send(iph2, msg) - struct ph2handle *iph2; - vchar_t *msg; -{ - vchar_t *body = NULL; - vchar_t *hash = NULL; - struct isakmp_gen *gen; - char *p; - int tlen; - int error = ISAKMP_INTERNAL_ERROR; - int pfsgroup; - u_int8_t *np_p = NULL; - - /* validity check */ - if (msg != NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "msg has to be NULL in this function.\n"); - goto end; - } - if (iph2->status != PHASE2ST_GETSPIDONE) { - plog(LLV_ERROR, LOCATION, NULL, - "status mismatched %d.\n", iph2->status); - goto end; - } - - /* update responders SPI */ - if (ipsecdoi_updatespi(iph2) < 0) { - plog(LLV_ERROR, LOCATION, NULL, "failed to update spi.\n"); - goto end; - } - - /* generate NONCE value */ - iph2->nonce = eay_set_random(iph2->ph1->rmconf->nonce_size); - if (iph2->nonce == NULL) - goto end; - - /* generate KE value if need */ - pfsgroup = iph2->approval->pfs_group; - if (iph2->dhpub_p != NULL && pfsgroup != 0) { - /* DH group settting if PFS is required. */ - if (oakley_setdhgroup(pfsgroup, &iph2->pfsgrp) < 0) { - plog(LLV_ERROR, LOCATION, NULL, - "failed to set DH value.\n"); - goto end; - } - /* generate DH public value */ - if (oakley_dh_generate(iph2->pfsgrp, - &iph2->dhpub, &iph2->dhpriv) < 0) { - goto end; - } - } - - /* create SA;NONCE payload, and KE and ID if need */ - tlen = sizeof(*gen) + iph2->sa_ret->l - + sizeof(*gen) + iph2->nonce->l; - if (iph2->dhpub_p != NULL && pfsgroup != 0) - tlen += (sizeof(*gen) + iph2->dhpub->l); - if (iph2->id_p != NULL) - tlen += (sizeof(*gen) + iph2->id_p->l - + sizeof(*gen) + iph2->id->l); - - body = vmalloc(tlen); - if (body == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "failed to get buffer to send.\n"); - goto end; - } - p = body->v; - - /* make SA payload */ - p = set_isakmp_payload(body->v, iph2->sa_ret, ISAKMP_NPTYPE_NONCE); - - /* add NONCE payload */ - np_p = &((struct isakmp_gen *)p)->np; /* XXX */ - p = set_isakmp_payload(p, iph2->nonce, - (iph2->dhpub_p != NULL && pfsgroup != 0) - ? ISAKMP_NPTYPE_KE - : (iph2->id_p != NULL - ? ISAKMP_NPTYPE_ID - : ISAKMP_NPTYPE_NONE)); - - /* add KE payload if need. */ - if (iph2->dhpub_p != NULL && pfsgroup != 0) { - np_p = &((struct isakmp_gen *)p)->np; /* XXX */ - p = set_isakmp_payload(p, iph2->dhpub, - (iph2->id_p == NULL) - ? ISAKMP_NPTYPE_NONE - : ISAKMP_NPTYPE_ID); - } - - /* add ID payloads received. */ - if (iph2->id_p != NULL) { - /* IDci */ - p = set_isakmp_payload(p, iph2->id_p, ISAKMP_NPTYPE_ID); - /* IDcr */ - np_p = &((struct isakmp_gen *)p)->np; /* XXX */ - p = set_isakmp_payload(p, iph2->id, ISAKMP_NPTYPE_NONE); - } - - /* add a RESPONDER-LIFETIME notify payload if needed */ - { - vchar_t *data = NULL; - struct saprop *pp = iph2->approval; - struct saproto *pr; - - if (pp->claim & IPSECDOI_ATTR_SA_LD_TYPE_SEC) { - u_int32_t v = htonl((u_int32_t)pp->lifetime); - data = isakmp_add_attr_l(data, IPSECDOI_ATTR_SA_LD_TYPE, - IPSECDOI_ATTR_SA_LD_TYPE_SEC); - if (!data) - goto end; - data = isakmp_add_attr_v(data, IPSECDOI_ATTR_SA_LD, - (caddr_t)&v, sizeof(v)); - if (!data) - goto end; - } - if (pp->claim & IPSECDOI_ATTR_SA_LD_TYPE_KB) { - u_int32_t v = htonl((u_int32_t)pp->lifebyte); - data = isakmp_add_attr_l(data, IPSECDOI_ATTR_SA_LD_TYPE, - IPSECDOI_ATTR_SA_LD_TYPE_KB); - if (!data) - goto end; - data = isakmp_add_attr_v(data, IPSECDOI_ATTR_SA_LD, - (caddr_t)&v, sizeof(v)); - if (!data) - goto end; - } - - /* - * XXX Is there only single RESPONDER-LIFETIME payload in a IKE message - * in the case of SA bundle ? - */ - if (data) { - for (pr = pp->head; pr; pr = pr->next) { - body = isakmp_add_pl_n(body, &np_p, - ISAKMP_NTYPE_RESPONDER_LIFETIME, pr, data); - if (!body) { - vfree(data); - return error; /* XXX */ - } - } - vfree(data); - } - } - - /* generate HASH(2) */ - { - vchar_t *tmp; - - tmp = vmalloc(iph2->nonce_p->l + body->l); - if (tmp == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "failed to get hash buffer.\n"); - goto end; - } - memcpy(tmp->v, iph2->nonce_p->v, iph2->nonce_p->l); - memcpy(tmp->v + iph2->nonce_p->l, body->v, body->l); - - hash = oakley_compute_hash1(iph2->ph1, iph2->msgid, tmp); - vfree(tmp); - - if (hash == NULL) - goto end; - } - - /* send isakmp payload */ - iph2->sendbuf = quick_ir1mx(iph2, body, hash); - if (iph2->sendbuf == NULL) - goto end; - - /* send the packet, add to the schedule to resend */ - iph2->retry_counter = iph2->ph1->rmconf->retry_counter; - if (isakmp_ph2resend(iph2) == -1) - goto end; - - /* the sending message is added to the received-list. */ - if (add_recvdpkt(iph2->ph1->remote, iph2->ph1->local, iph2->sendbuf, iph2->msg1) == -1) { - plog(LLV_ERROR , LOCATION, NULL, - "failed to add a response packet to the tree.\n"); - goto end; - } - - /* change status of isakmp status entry */ - iph2->status = PHASE2ST_MSG1SENT; - - error = 0; - -end: - if (body != NULL) - vfree(body); - if (hash != NULL) - vfree(hash); - - return error; -} - -/* - * receive from initiator - * HDR*, HASH(3) - */ -int -quick_r3recv(iph2, msg0) - struct ph2handle *iph2; - vchar_t *msg0; -{ - vchar_t *msg = NULL; - vchar_t *pbuf = NULL; /* for payload parsing */ - struct isakmp_parse_t *pa; - struct isakmp_pl_hash *hash = NULL; - int error = ISAKMP_INTERNAL_ERROR; - - /* validity check */ - if (iph2->status != PHASE2ST_MSG1SENT) { - plog(LLV_ERROR, LOCATION, NULL, - "status mismatched %d.\n", iph2->status); - goto end; - } - - /* decrypt packet */ - if (!ISSET(((struct isakmp *)msg0->v)->flags, ISAKMP_FLAG_E)) { - plog(LLV_ERROR, LOCATION, iph2->ph1->remote, - "Packet wasn't encrypted.\n"); - goto end; - } - msg = oakley_do_decrypt(iph2->ph1, msg0, iph2->ivm->iv, iph2->ivm->ive); - if (msg == NULL) - goto end; - - /* validate the type of next payload */ - pbuf = isakmp_parse(msg); - if (pbuf == NULL) - goto end; - - for (pa = (struct isakmp_parse_t *)pbuf->v; - pa->type != ISAKMP_NPTYPE_NONE; - pa++) { - - switch (pa->type) { - case ISAKMP_NPTYPE_HASH: - hash = (struct isakmp_pl_hash *)pa->ptr; - break; - case ISAKMP_NPTYPE_N: - isakmp_check_notify(pa->ptr, iph2->ph1); - break; - default: - /* don't send information, see ident_r1recv() */ - plog(LLV_ERROR, LOCATION, iph2->ph1->remote, - "ignore the packet, " - "received unexpecting payload type %d.\n", - pa->type); - goto end; - } - } - - /* payload existency check */ - if (hash == NULL) { - plog(LLV_ERROR, LOCATION, iph2->ph1->remote, - "few isakmp message received.\n"); - goto end; - } - - /* validate HASH(3) */ - /* HASH(3) = prf(SKEYID_a, 0 | M-ID | Ni_b | Nr_b) */ - { - char *r_hash; - vchar_t *my_hash = NULL; - vchar_t *tmp = NULL; - int result; - - r_hash = (char *)hash + sizeof(*hash); - - plog(LLV_DEBUG, LOCATION, NULL, "HASH(3) validate:"); - plogdump(LLV_DEBUG, r_hash, ntohs(hash->h.len) - sizeof(*hash)); - - tmp = vmalloc(iph2->nonce_p->l + iph2->nonce->l); - if (tmp == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "failed to get hash buffer.\n"); - goto end; - } - memcpy(tmp->v, iph2->nonce_p->v, iph2->nonce_p->l); - memcpy(tmp->v + iph2->nonce_p->l, iph2->nonce->v, iph2->nonce->l); - - my_hash = oakley_compute_hash3(iph2->ph1, iph2->msgid, tmp); - vfree(tmp); - if (my_hash == NULL) - goto end; - - result = memcmp(my_hash->v, r_hash, my_hash->l); - vfree(my_hash); - - if (result) { - plog(LLV_ERROR, LOCATION, iph2->ph1->remote, - "HASH(3) mismatch.\n"); - error = ISAKMP_NTYPE_INVALID_HASH_INFORMATION; - goto end; - } - } - - /* if there is commit bit, don't set up SA now. */ - if (ISSET(iph2->flags, ISAKMP_FLAG_C)) { - iph2->status = PHASE2ST_COMMIT; - } else - iph2->status = PHASE2ST_STATUS6; - - error = 0; - -end: - if (pbuf != NULL) - vfree(pbuf); - if (msg != NULL) - vfree(msg); - - return error; -} - -/* - * send to initiator - * HDR#*, HASH(4), notify - */ -int -quick_r3send(iph2, msg0) - struct ph2handle *iph2; - vchar_t *msg0; -{ - vchar_t *buf = NULL; - vchar_t *myhash = NULL; - struct isakmp_pl_n *n; - vchar_t *notify = NULL; - char *p; - int tlen; - int error = ISAKMP_INTERNAL_ERROR; - - /* validity check */ - if (iph2->status != PHASE2ST_COMMIT) { - plog(LLV_ERROR, LOCATION, NULL, - "status mismatched %d.\n", iph2->status); - goto end; - } - - /* generate HASH(4) */ - /* XXX What can I do in the case of multiple different SA */ - plog(LLV_DEBUG, LOCATION, NULL, "HASH(4) generate\n"); - - /* XXX What should I do if there are multiple SAs ? */ - tlen = sizeof(struct isakmp_pl_n) + iph2->approval->head->spisize; - notify = vmalloc(tlen); - if (notify == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "failed to get notify buffer.\n"); - goto end; - } - n = (struct isakmp_pl_n *)notify->v; - n->h.np = ISAKMP_NPTYPE_NONE; - n->h.len = htons(tlen); - n->doi = htonl(IPSEC_DOI); - n->proto_id = iph2->approval->head->proto_id; - n->spi_size = sizeof(iph2->approval->head->spisize); - n->type = htons(ISAKMP_NTYPE_CONNECTED); - memcpy(n + 1, &iph2->approval->head->spi, iph2->approval->head->spisize); - - myhash = oakley_compute_hash1(iph2->ph1, iph2->msgid, notify); - if (myhash == NULL) - goto end; - - /* create buffer for isakmp payload */ - tlen = sizeof(struct isakmp) - + sizeof(struct isakmp_gen) + myhash->l - + notify->l; - buf = vmalloc(tlen); - if (buf == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "failed to get buffer to send.\n"); - goto end; - } - - /* create isakmp header */ - p = set_isakmp_header2(buf, iph2, ISAKMP_NPTYPE_HASH); - if (p == NULL) - goto end; - - /* add HASH(4) payload */ - p = set_isakmp_payload(p, myhash, ISAKMP_NPTYPE_N); - - /* add notify payload */ - memcpy(p, notify->v, notify->l); - -#ifdef HAVE_PRINT_ISAKMP_C - isakmp_printpacket(buf, iph2->ph1->local, iph2->ph1->remote, 1); -#endif - - /* encoding */ - iph2->sendbuf = oakley_do_encrypt(iph2->ph1, buf, iph2->ivm->ive, iph2->ivm->iv); - if (iph2->sendbuf == NULL) - goto end; - - /* send the packet */ - if (isakmp_send(iph2->ph1, iph2->sendbuf) < 0) - goto end; - - /* the sending message is added to the received-list. */ - if (add_recvdpkt(iph2->ph1->remote, iph2->ph1->local, iph2->sendbuf, msg0) == -1) { - plog(LLV_ERROR , LOCATION, NULL, - "failed to add a response packet to the tree.\n"); - goto end; - } - - iph2->status = PHASE2ST_COMMIT; - - error = 0; - -end: - if (buf != NULL) - vfree(buf); - if (myhash != NULL) - vfree(myhash); - if (notify != NULL) - vfree(notify); - - return error; -} - -int -tunnel_mode_prop(p) - struct saprop *p; -{ - struct saproto *pr; - - for (pr = p->head; pr; pr = pr->next) - if (pr->encmode == IPSECDOI_ATTR_ENC_MODE_TUNNEL) - return 1; - return 0; -} - -/* - * set SA to kernel. - */ -int -quick_r3prep(iph2, msg0) - struct ph2handle *iph2; - vchar_t *msg0; -{ - int error = ISAKMP_INTERNAL_ERROR; - - /* validity check */ - if (iph2->status != PHASE2ST_STATUS6) { - plog(LLV_ERROR, LOCATION, NULL, - "status mismatched %d.\n", iph2->status); - goto end; - } - - /* compute both of KEYMATs */ - if (oakley_compute_keymat(iph2, RESPONDER) < 0) - goto end; - - iph2->status = PHASE2ST_ADDSA; - iph2->flags ^= ISAKMP_FLAG_C; /* reset bit */ - - /* don't anything if local test mode. */ - if (f_local) { - error = 0; - goto end; - } - - /* Do UPDATE as responder */ - plog(LLV_DEBUG, LOCATION, NULL, "call pk_sendupdate\n"); - if (pk_sendupdate(iph2) < 0) { - plog(LLV_ERROR, LOCATION, NULL, "pfkey update failed.\n"); - goto end; - } - plog(LLV_DEBUG, LOCATION, NULL, "pfkey update sent.\n"); - - /* Do ADD for responder */ - if (pk_sendadd(iph2) < 0) { - plog(LLV_ERROR, LOCATION, NULL, "pfkey add failed.\n"); - goto end; - } - plog(LLV_DEBUG, LOCATION, NULL, "pfkey add sent.\n"); - - /* - * set policies into SPD if the policy is generated - * from peer's policy. - */ - if (iph2->spidx_gen) { - - struct policyindex *spidx; - struct sockaddr_storage addr; - u_int8_t pref; - struct sockaddr *src = iph2->src; - struct sockaddr *dst = iph2->dst; - - /* make inbound policy */ - iph2->src = dst; - iph2->dst = src; - if (pk_sendspdupdate2(iph2) < 0) { - plog(LLV_ERROR, LOCATION, NULL, - "pfkey spdupdate2(inbound) failed.\n"); - goto end; - } - plog(LLV_DEBUG, LOCATION, NULL, - "pfkey spdupdate2(inbound) sent.\n"); - - spidx = (struct policyindex *)iph2->spidx_gen; -#ifdef HAVE_POLICY_FWD - /* make forward policy if required */ - if (tunnel_mode_prop(iph2->approval)) { - spidx->dir = IPSEC_DIR_FWD; - if (pk_sendspdupdate2(iph2) < 0) { - plog(LLV_ERROR, LOCATION, NULL, - "pfkey spdupdate2(forward) failed.\n"); - goto end; - } - plog(LLV_DEBUG, LOCATION, NULL, - "pfkey spdupdate2(forward) sent.\n"); - } -#endif - - /* make outbound policy */ - iph2->src = src; - iph2->dst = dst; - spidx->dir = IPSEC_DIR_OUTBOUND; - addr = spidx->src; - spidx->src = spidx->dst; - spidx->dst = addr; - pref = spidx->prefs; - spidx->prefs = spidx->prefd; - spidx->prefd = pref; - - if (pk_sendspdupdate2(iph2) < 0) { - plog(LLV_ERROR, LOCATION, NULL, - "pfkey spdupdate2(outbound) failed.\n"); - goto end; - } - plog(LLV_DEBUG, LOCATION, NULL, - "pfkey spdupdate2(outbound) sent.\n"); - - /* spidx_gen is unnecessary any more */ - delsp_bothdir((struct policyindex *)iph2->spidx_gen); - racoon_free(iph2->spidx_gen); - iph2->spidx_gen = NULL; - iph2->generated_spidx=1; - } - - error = 0; - -end: - return error; -} - -/* - * create HASH, body (SA, NONCE) payload with isakmp header. - */ -static vchar_t * -quick_ir1mx(iph2, body, hash) - struct ph2handle *iph2; - vchar_t *body, *hash; -{ - struct isakmp *isakmp; - vchar_t *buf = NULL, *new = NULL; - char *p; - int tlen; - struct isakmp_gen *gen; - int error = ISAKMP_INTERNAL_ERROR; - - /* create buffer for isakmp payload */ - tlen = sizeof(*isakmp) - + sizeof(*gen) + hash->l - + body->l; - buf = vmalloc(tlen); - if (buf == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "failed to get buffer to send.\n"); - goto end; - } - - /* re-set encryption flag, for serurity. */ - iph2->flags |= ISAKMP_FLAG_E; - - /* set isakmp header */ - p = set_isakmp_header2(buf, iph2, ISAKMP_NPTYPE_HASH); - if (p == NULL) - goto end; - - /* add HASH payload */ - /* XXX is next type always SA ? */ - p = set_isakmp_payload(p, hash, ISAKMP_NPTYPE_SA); - - /* add body payload */ - memcpy(p, body->v, body->l); - -#ifdef HAVE_PRINT_ISAKMP_C - isakmp_printpacket(buf, iph2->ph1->local, iph2->ph1->remote, 1); -#endif - - /* encoding */ - new = oakley_do_encrypt(iph2->ph1, buf, iph2->ivm->ive, iph2->ivm->iv); - - if (new == NULL) - goto end; - - vfree(buf); - - buf = new; - - error = 0; - -end: - if (error && buf != NULL) { - vfree(buf); - buf = NULL; - } - - return buf; -} - -/* - * get remote's sainfo. - * NOTE: this function is for responder. - */ -static int -get_sainfo_r(iph2) - struct ph2handle *iph2; -{ - vchar_t *idsrc = NULL, *iddst = NULL; - int prefixlen; - int error = ISAKMP_INTERNAL_ERROR; - int remoteid = 0; - - if (iph2->id == NULL) { - switch (iph2->src->sa_family) { - case AF_INET: - prefixlen = sizeof(struct in_addr) << 3; - break; - case AF_INET6: - prefixlen = sizeof(struct in6_addr) << 3; - break; - default: - plog(LLV_ERROR, LOCATION, NULL, - "invalid family: %d\n", iph2->src->sa_family); - goto end; - } - idsrc = ipsecdoi_sockaddr2id(iph2->src, prefixlen, - IPSEC_ULPROTO_ANY); - } else { - idsrc = vdup(iph2->id); - } - if (idsrc == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "failed to set ID for source.\n"); - goto end; - } - - if (iph2->id_p == NULL) { - switch (iph2->dst->sa_family) { - case AF_INET: - prefixlen = sizeof(struct in_addr) << 3; - break; - case AF_INET6: - prefixlen = sizeof(struct in6_addr) << 3; - break; - default: - plog(LLV_ERROR, LOCATION, NULL, - "invalid family: %d\n", iph2->dst->sa_family); - goto end; - } - iddst = ipsecdoi_sockaddr2id(iph2->dst, prefixlen, - IPSEC_ULPROTO_ANY); - } else { - iddst = vdup(iph2->id_p); - } - if (iddst == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "failed to set ID for destination.\n"); - goto end; - } - - { - struct remoteconf *conf; - conf = getrmconf(iph2->dst); - if (conf != NULL) - remoteid=conf->ph1id; - else{ - plog(LLV_DEBUG, LOCATION, NULL, "Warning: no valid rmconf !\n"); - remoteid=0; - } - - } - - iph2->sainfo = getsainfo(idsrc, iddst, iph2->ph1->id_p, remoteid); - if (iph2->sainfo == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "failed to get sainfo.\n"); - goto end; - } - -#ifdef ENABLE_HYBRID - /* xauth group inclusion check */ - if (iph2->sainfo->group != NULL) - if(group_check(iph2->ph1,&iph2->sainfo->group->v,1)) - goto end; -#endif - - plog(LLV_DEBUG, LOCATION, NULL, - "selected sainfo: %s\n", sainfo2str(iph2->sainfo)); - - error = 0; -end: - if (idsrc) - vfree(idsrc); - if (iddst) - vfree(iddst); - - return error; -} - -/* - * Copy both IP addresses in ID payloads into [src,dst]_id if both ID types - * are IP address and same address family. - * Then get remote's policy from SPD copied from kernel. - * If the type of ID payload is address or subnet type, then the index is - * made from the payload. If there is no ID payload, or the type of ID - * payload is NOT address type, then the index is made from the address - * pair of phase 1. - * NOTE: This function is only for responder. - */ -static int -get_proposal_r(iph2) - struct ph2handle *iph2; -{ - struct policyindex spidx; - struct secpolicy *sp_in, *sp_out; - int idi2type = 0; /* switch whether copy IDs into id[src,dst]. */ - int error = ISAKMP_INTERNAL_ERROR; - - /* check the existence of ID payload */ - if ((iph2->id_p != NULL && iph2->id == NULL) - || (iph2->id_p == NULL && iph2->id != NULL)) { - plog(LLV_ERROR, LOCATION, NULL, - "Both IDs wasn't found in payload.\n"); - return ISAKMP_NTYPE_INVALID_ID_INFORMATION; - } - - /* make sure if id[src,dst] is null. */ - if (iph2->src_id || iph2->dst_id) { - plog(LLV_ERROR, LOCATION, NULL, - "Why do ID[src,dst] exist already.\n"); - return ISAKMP_INTERNAL_ERROR; - } - - memset(&spidx, 0, sizeof(spidx)); - -#define _XIDT(d) ((struct ipsecdoi_id_b *)(d)->v)->type - - /* make a spidx; a key to search SPD */ - spidx.dir = IPSEC_DIR_INBOUND; - spidx.ul_proto = 0; - - /* - * make destination address in spidx from either ID payload - * or phase 1 address into a address in spidx. - */ - if (iph2->id != NULL - && (_XIDT(iph2->id) == IPSECDOI_ID_IPV4_ADDR - || _XIDT(iph2->id) == IPSECDOI_ID_IPV6_ADDR - || _XIDT(iph2->id) == IPSECDOI_ID_IPV4_ADDR_SUBNET - || _XIDT(iph2->id) == IPSECDOI_ID_IPV6_ADDR_SUBNET)) { - /* get a destination address of a policy */ - error = ipsecdoi_id2sockaddr(iph2->id, - (struct sockaddr *)&spidx.dst, - &spidx.prefd, &spidx.ul_proto); - if (error) - return error; - -#ifdef INET6 - /* - * get scopeid from the SA address. - * note that the phase 1 source address is used as - * a destination address to search for a inbound policy entry - * because rcoon is responder. - */ - if (_XIDT(iph2->id) == IPSECDOI_ID_IPV6_ADDR) { - error = setscopeid((struct sockaddr *)&spidx.dst, - iph2->src); - if (error) - return error; - } -#endif - - if (_XIDT(iph2->id) == IPSECDOI_ID_IPV4_ADDR - || _XIDT(iph2->id) == IPSECDOI_ID_IPV6_ADDR) - idi2type = _XIDT(iph2->id); - - } else { - - plog(LLV_DEBUG, LOCATION, NULL, - "get a destination address of SP index " - "from phase1 address " - "due to no ID payloads found " - "OR because ID type is not address.\n"); - - /* - * copy the SOURCE address of IKE into the DESTINATION address - * of the key to search the SPD because the direction of policy - * is inbound. - */ - memcpy(&spidx.dst, iph2->src, sysdep_sa_len(iph2->src)); - switch (spidx.dst.ss_family) { - case AF_INET: - spidx.prefd = sizeof(struct in_addr) << 3; - break; -#ifdef INET6 - case AF_INET6: - spidx.prefd = sizeof(struct in6_addr) << 3; - break; -#endif - default: - spidx.prefd = 0; - break; - } - } - - /* make source address in spidx */ - if (iph2->id_p != NULL - && (_XIDT(iph2->id_p) == IPSECDOI_ID_IPV4_ADDR - || _XIDT(iph2->id_p) == IPSECDOI_ID_IPV6_ADDR - || _XIDT(iph2->id_p) == IPSECDOI_ID_IPV4_ADDR_SUBNET - || _XIDT(iph2->id_p) == IPSECDOI_ID_IPV6_ADDR_SUBNET)) { - /* get a source address of inbound SA */ - error = ipsecdoi_id2sockaddr(iph2->id_p, - (struct sockaddr *)&spidx.src, - &spidx.prefs, &spidx.ul_proto); - if (error) - return error; - -#ifdef INET6 - /* - * get scopeid from the SA address. - * for more detail, see above of this function. - */ - if (_XIDT(iph2->id_p) == IPSECDOI_ID_IPV6_ADDR) { - error = setscopeid((struct sockaddr *)&spidx.src, - iph2->dst); - if (error) - return error; - } -#endif - - /* make id[src,dst] if both ID types are IP address and same */ - if (_XIDT(iph2->id_p) == idi2type - && spidx.dst.ss_family == spidx.src.ss_family) { - iph2->src_id = dupsaddr((struct sockaddr *)&spidx.dst); - if (iph2->src_id == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "buffer allocation failed.\n"); - return ISAKMP_INTERNAL_ERROR; - } - iph2->dst_id = dupsaddr((struct sockaddr *)&spidx.src); - if (iph2->dst_id == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "buffer allocation failed.\n"); - return ISAKMP_INTERNAL_ERROR; - } - } - - } else { - plog(LLV_DEBUG, LOCATION, NULL, - "get a source address of SP index " - "from phase1 address " - "due to no ID payloads found " - "OR because ID type is not address.\n"); - - /* see above comment. */ - memcpy(&spidx.src, iph2->dst, sysdep_sa_len(iph2->dst)); - switch (spidx.src.ss_family) { - case AF_INET: - spidx.prefs = sizeof(struct in_addr) << 3; - break; -#ifdef INET6 - case AF_INET6: - spidx.prefs = sizeof(struct in6_addr) << 3; - break; -#endif - default: - spidx.prefs = 0; - break; - } - } - -#undef _XIDT - - plog(LLV_DEBUG, LOCATION, NULL, - "get a src address from ID payload " - "%s prefixlen=%u ul_proto=%u\n", - saddr2str((struct sockaddr *)&spidx.src), - spidx.prefs, spidx.ul_proto); - plog(LLV_DEBUG, LOCATION, NULL, - "get dst address from ID payload " - "%s prefixlen=%u ul_proto=%u\n", - saddr2str((struct sockaddr *)&spidx.dst), - spidx.prefd, spidx.ul_proto); - - /* - * convert the ul_proto if it is 0 - * because 0 in ID payload means a wild card. - */ - if (spidx.ul_proto == 0) - spidx.ul_proto = IPSEC_ULPROTO_ANY; - -#ifdef HAVE_SECCTX - /* - * Need to use security context in spidx to ensure the correct - * policy is selected. The only way to get the security context - * is to look into the proposal sent by peer ahead of time. - */ - if (get_security_context(iph2->sa, &spidx)) { - plog(LLV_ERROR, LOCATION, NULL, - "error occurred trying to get security context.\n"); - return ISAKMP_INTERNAL_ERROR; - } -#endif /* HAVE_SECCTX */ - - /* get inbound policy */ - sp_in = getsp_r(&spidx); - if (sp_in == NULL) { - if (iph2->ph1->rmconf->gen_policy) { - plog(LLV_INFO, LOCATION, NULL, - "no policy found, " - "try to generate the policy : %s\n", - spidx2str(&spidx)); - iph2->spidx_gen = racoon_malloc(sizeof(spidx)); - if (!iph2->spidx_gen) { - plog(LLV_ERROR, LOCATION, NULL, - "buffer allocation failed.\n"); - return ISAKMP_INTERNAL_ERROR; - } - memcpy(iph2->spidx_gen, &spidx, sizeof(spidx)); - return -2; /* special value */ - } - plog(LLV_ERROR, LOCATION, NULL, - "no policy found: %s\n", spidx2str(&spidx)); - return ISAKMP_INTERNAL_ERROR; - } - /* Refresh existing generated policies - */ - if (iph2->ph1->rmconf->gen_policy) { - plog(LLV_INFO, LOCATION, NULL, - "Update the generated policy : %s\n", - spidx2str(&spidx)); - iph2->spidx_gen = racoon_malloc(sizeof(spidx)); - if (!iph2->spidx_gen) { - plog(LLV_ERROR, LOCATION, NULL, - "buffer allocation failed.\n"); - return ISAKMP_INTERNAL_ERROR; - } - memcpy(iph2->spidx_gen, &spidx, sizeof(spidx)); - } - - /* get outbound policy */ - { - struct sockaddr_storage addr; - u_int8_t pref; - - spidx.dir = IPSEC_DIR_OUTBOUND; - addr = spidx.src; - spidx.src = spidx.dst; - spidx.dst = addr; - pref = spidx.prefs; - spidx.prefs = spidx.prefd; - spidx.prefd = pref; - - sp_out = getsp_r(&spidx); - if (!sp_out) { - plog(LLV_WARNING, LOCATION, NULL, - "no outbound policy found: %s\n", - spidx2str(&spidx)); - } - } - - plog(LLV_DEBUG, LOCATION, NULL, - "suitable SP found:%s\n", spidx2str(&spidx)); - - /* - * In the responder side, the inbound policy should be using IPsec. - * outbound policy is not checked currently. - */ - if (sp_in->policy != IPSEC_POLICY_IPSEC) { - plog(LLV_ERROR, LOCATION, NULL, - "policy found, but no IPsec required: %s\n", - spidx2str(&spidx)); - return ISAKMP_INTERNAL_ERROR; - } - - /* set new proposal derived from a policy into the iph2->proposal. */ - if (set_proposal_from_policy(iph2, sp_in, sp_out) < 0) { - plog(LLV_ERROR, LOCATION, NULL, - "failed to create saprop.\n"); - return ISAKMP_INTERNAL_ERROR; - } - -#ifdef HAVE_SECCTX - if (spidx.sec_ctx.ctx_str) { - set_secctx_in_proposal(iph2, spidx); - } -#endif /* HAVE_SECCTX */ - - return 0; -} - |