#include <sys/types.h>
#include <sys/param.h>
#include <sys/socket.h>
+#include <arpa/inet.h>
#include <netinet/in.h>
#ifdef ENABLE_NATT
#include "nattraversal.h"
#endif
-#include "ikev2_rfc.h"
#ifdef ENABLE_HYBRID
static int switch_authmethod(int);
static vchar_t *get_ph1approval (phase1_handle_t *, struct prop_pair **);
void print_ph1mismatched (struct prop_pair *, struct isakmpsa *);
-static int t2isakmpsa (struct isakmp_pl_t *, struct isakmpsa *);
static int cmp_aproppair_i (struct prop_pair *, struct prop_pair *);
static struct prop_pair *get_ph2approval (phase2_handle_t *,
struct prop_pair **);
check_trns_ipcomp, /* IPSECDOI_PROTO_IPCOMP */
};
-static int check_attr_isakmp (struct isakmp_pl_t *);
static int check_attr_ah (struct isakmp_pl_t *);
static int check_attr_esp (struct isakmp_pl_t *);
-static int check_attr_ipsec (int, struct isakmp_pl_t *);
-static int check_attr_ipcomp (struct isakmp_pl_t *);
static int (*check_attributes[]) (struct isakmp_pl_t *) = {
0,
check_attr_isakmp, /* IPSECDOI_PROTO_ISAKMP */
tsap->encklen == s->encklen &&
tsap->version == s->version) {
switch(check_level) {
- case PROP_CHECK_IKEV2:
case PROP_CHECK_OBEY:
goto found;
break;
/*
* get ISAKMP data attributes
*/
-static int
+int
t2isakmpsa(trns, sa)
struct isakmp_pl_t *trns;
struct isakmpsa *sa;
goto err;
while (tlen > 0) {
+ if (tlen < sizeof(struct isakmp_data)) {
+ plog(ASL_LEVEL_ERR,
+ "t2isakmpsa invalid length of isakmp data, expected %zu actual %d\n",
+ sizeof(struct isakmp_data), tlen);
+ goto err;
+ }
type = ntohs(d->type) & ~ISAKMP_GEN_MASK;
flag = ntohs(d->type) & ISAKMP_GEN_MASK;
p = (u_char *)&d->lorv;
} else { /*TLV*/
len = ntohs(d->lorv);
- if (len > tlen) {
- plog(ASL_LEVEL_ERR,
- "invalid ISAKMP-SA attr, attr-len %d, overall-len %d\n",
- len, tlen);
+ if ((len + sizeof(struct isakmp_data)) > tlen) {
+ plog(ASL_LEVEL_ERR,
+ "invalid ISAKMP-SA attr(%d), attr-len %d, overall-len %lu\n",
+ type, len, (tlen - sizeof(struct isakmp_data)));
return -1;
}
p = (u_char *)(d + 1);
sa->dhgrp->gen1 = 0;
if (len > 4)
return -1;
+
+ if ((len + sizeof(struct isakmp_data)) > tlen) {
+ plog(ASL_LEVEL_ERR,
+ "invalid ISAKMP-SA attr - OAKLEY_ATTR_GRP_GEN_ONE, attr-len %d, overall-len %lu\n",
+ len, (tlen - sizeof(struct isakmp_data)));
+ return -1;
+ }
+
memcpy(&sa->dhgrp->gen1, d + 1, len);
sa->dhgrp->gen1 = ntohl(sa->dhgrp->gen1);
}
sa->dhgrp->gen2 = 0;
if (len > 4)
return -1;
+
+ if ((len + sizeof(struct isakmp_data)) > tlen) {
+ plog(ASL_LEVEL_ERR,
+ "invalid ISAKMP-SA attr - OAKLEY_ATTR_GRP_GEN_TWO, attr-len %d, overall-len %lu\n",
+ len, (tlen - sizeof(struct isakmp_data)));
+ return -1;
+ }
+
memcpy(&sa->dhgrp->gen2, d + 1, len);
sa->dhgrp->gen2 = ntohl(sa->dhgrp->gen2);
}
d = (struct isakmp_data *)((char *)d + sizeof(*d));
} else {
tlen -= (sizeof(*d) + ntohs(d->lorv));
+ if (tlen < 0) {
+ plog(ASL_LEVEL_ERR,
+ "t2isakmpsa: packet too short - attr length %u for type %d\n",
+ ntohs(d->lorv), type);
+ return -1;
+ }
+
d = (struct isakmp_data *)((char *)d + sizeof(*d) + ntohs(d->lorv));
}
}
}
/* no proposal matching */
err:
- flushsaprop(pr0);
+ if (pr0 != NULL) {
+ flushsaprop(pr0);
+ pr0 = NULL;
+ }
return NULL;
found:
- flushsaprop(pr0);
+ if (pr0 != NULL) {
+ flushsaprop(pr0);
+ pr0 = NULL;
+ }
plog(ASL_LEVEL_DEBUG, "matched\n");
iph2->approval = pr;
goto bad;
}
+ if (pa->len < sizeof(struct isakmp_pl_p)) {
+ plog(ASL_LEVEL_ERR,
+ "get_proppair invalid length of proposal, expected %lu actual %d\n",
+ sizeof(struct isakmp_pl_p), pa->len);
+ vfree(pbuf);
+ goto bad;
+ }
+
prop = (struct isakmp_pl_p *)pa->ptr;
proplen = pa->len;
if (check_spi_size(prop->proto_id, prop->spi_size) < 0)
continue;
+ if (pa->len < (sizeof(struct isakmp_pl_p) + prop->spi_size)) {
+ plog(ASL_LEVEL_ERR,
+ "get_proppair invalid length of proposal spi size, expected %u actual %zu\n",
+ prop->spi_size, (pa->len - sizeof(struct isakmp_pl_p)));
+ vfree(pbuf);
+ goto bad;
+ }
+
/* get transform */
if (get_transform(prop, pair, &num_p) < 0) {
vfree(pbuf);
break;
}
+ if (pa->len < sizeof(struct isakmp_pl_t)) {
+ plog(ASL_LEVEL_ERR,
+ "get_transform invalid length of transform, expected %lu actual %d\n",
+ sizeof(struct isakmp_pl_t), pa->len);
+ break;
+ }
+
trns = (struct isakmp_pl_t *)pa->ptr;
trnslen = pa->len;
/*
* check data attributes in IKE.
*/
-static int
+int
check_attr_isakmp(trns)
struct isakmp_pl_t *trns;
{
d = (struct isakmp_data *)((caddr_t)trns + sizeof(struct isakmp_pl_t));
while (tlen > 0) {
+ if (tlen < sizeof(struct isakmp_data)) {
+ plog(ASL_LEVEL_ERR,
+ "check_attr_isakmp invalid length of isakmp data, expected %zu actual %d\n",
+ sizeof(struct isakmp_data), tlen);
+ return -1;
+ }
+
type = ntohs(d->type) & ~ISAKMP_GEN_MASK;
flag = ntohs(d->type) & ISAKMP_GEN_MASK;
lorv = ntohs(d->lorv);
tlen -= (sizeof(*d) + lorv);
d = (struct isakmp_data *)((char *)d
+ sizeof(*d) + lorv);
+ if (tlen < 0) {
+ plog(ASL_LEVEL_ERR,
+ "check_attr_isakmp: packet too short - attr length %u for type %d\n",
+ lorv, type);
+ return -1;
+ }
}
}
return check_attr_ipsec(IPSECDOI_PROTO_IPSEC_ESP, trns);
}
-static int
+int
check_attr_ipsec(proto_id, trns)
int proto_id;
struct isakmp_pl_t *trns;
memset(attrseen, 0, sizeof(attrseen));
while (tlen > 0) {
+ if (tlen < sizeof(struct isakmp_data)) {
+ plog(ASL_LEVEL_ERR,
+ "check_attr_ipsec invalid length of isakmp data, expected %zu actual %d\n",
+ sizeof(struct isakmp_data), tlen);
+ return -1;
+ }
+
type = ntohs(d->type) & ~ISAKMP_GEN_MASK;
flag = ntohs(d->type) & ISAKMP_GEN_MASK;
lorv = ntohs(d->lorv);
tlen -= (sizeof(*d) + lorv);
d = (struct isakmp_data *)((caddr_t)d
+ sizeof(*d) + lorv);
+ if (tlen < 0) {
+ plog(ASL_LEVEL_ERR,
+ "check_attr_ipsec: packet too short - attr length %u for type %d\n",
+ lorv, type);
+ return -1;
+ }
}
}
return 0;
}
-static int
+int
check_attr_ipcomp(trns)
struct isakmp_pl_t *trns;
{
memset(attrseen, 0, sizeof(attrseen));
while (tlen > 0) {
+ if (tlen < sizeof(struct isakmp_data)) {
+ plog(ASL_LEVEL_ERR,
+ "check_attr_ipcomp: invalid length of isakmp data, expected %zu actual %d\n",
+ sizeof(struct isakmp_data), tlen);
+ return -1;
+ }
+
type = ntohs(d->type) & ~ISAKMP_GEN_MASK;
flag = ntohs(d->type) & ISAKMP_GEN_MASK;
lorv = ntohs(d->lorv);
tlen -= (sizeof(*d) + lorv);
d = (struct isakmp_data *)((caddr_t)d
+ sizeof(*d) + lorv);
+ if (tlen < 0) {
+ plog(ASL_LEVEL_ERR,
+ "check_attr_ipcomp: packet too short - attr length %u for type %d\n",
+ lorv, type);
+ return -1;
+ }
}
}
(ALIGNED_CAST(struct ipsecdoi_sa_b *)mysa->v)->sit = htonl(props->rmconf->sittype);
(void)setph1prop(iph1, mysa->v + sizeof(struct ipsecdoi_sa_b));
- } else {
- (void)setph1prop(iph1, mysa->v);
}
return mysa;
caddr_t buf)
{
struct isakmpsa *props = iph1->rmconf->proposal;
- unsigned int version = iph1->version;
struct isakmp_pl_p *prop = NULL;
struct isakmpsa *s = NULL;
u_int8_t *np_t; /* pointer next trns type in previous header */
int trns_num;
caddr_t p = buf;
- u_int16_t tmplen;
int spi_size = 0;
- cookie_t *my_cookie = (iph1->side == INITIATOR) ? &iph1->index.i_ck : &iph1->index.r_ck;
-
proplen = sizeof(*prop) + spi_size;
if (buf) {
return p;
}
-
/*
* create phase2 proposal from policy configuration.
* NOT INCLUDING isakmp general header of SA payload.
for (a = proposal; a; a = a->next) {
for (b = a->head; b; b = b->next) {
if (b->proto_id == IPSECDOI_PROTO_IPCOMP) {
- // %%%%% todo - IKEv2 uses ipcomp notification
// skip this - not specified in the SA
// Need to set this in iph2 ???
continue;
}
// IKEv1 sends encode mode in SA - uses diferent codes when NATT being used
- // IKEv2 does not send encode mode in SA
#ifdef ENABLE_NATT
if (iph2->ph1->natt_flags & NAT_DETECTED) {
- plog (ASL_LEVEL_INFO, "NAT detected -> UDP encapsulation\n");
+ plog (ASL_LEVEL_NOTICE, "NAT detected -> UDP encapsulation\n");
b->udp_encap = 1;
if (iph2->version == ISAKMP_VERSION_NUMBER_IKEV1) {
int udp_diff = iph2->ph1->natt_options->mode_udp_diff;
vchar_t *ret = NULL;
struct ipsecdoi_id_b id_b;
vchar_t *ident = NULL;
+ struct sockaddr_in v4_address;
struct sockaddr_storage *ipid = NULL;
/* init */
if (ipid == NULL)
ipid = iph1->local;
+ {
+ if (ipid->ss_family == AF_INET6 &&
+ iph1->nat64_prefix.length) {
+ memset(&v4_address, 0, sizeof(v4_address));
+ v4_address.sin_len = sizeof(struct sockaddr_in);
+ v4_address.sin_family = AF_INET;
+ v4_address.sin_port = ((struct sockaddr_in6 *)ipid)->sin6_port;
+ v4_address.sin_addr.s_addr = 0;
+
+ ipid = ALIGNED_CAST(struct sockaddr_storage *)&v4_address;
+ }
+ }
+
/* use IP address */
switch (ipid->ss_family) {
case AF_INET:
return -1;
}
- iph2->id = ipsecdoi_sockaddr2id(&sp->spidx.src,
- sp->spidx.prefs, sp->spidx.ul_proto);
+ struct sockaddr_in local_v4_address;
+ struct sockaddr_storage *srcaddr = &sp->spidx.src;
+ u_int8_t prefs = sp->spidx.prefs;
+ if (sp->spidx.dst.ss_family == AF_INET6 &&
+ iph2->nat64_prefix.length) {
+ memset(&local_v4_address, 0, sizeof(local_v4_address));
+ local_v4_address.sin_len = sizeof(struct sockaddr_in);
+ local_v4_address.sin_family = AF_INET;
+ local_v4_address.sin_port = ((struct sockaddr_in6 *)&sp->spidx.src)->sin6_port;
+ // Setting a fixed IPv4 address to avoid FATAL-ID issue with 0.0.0.0 IPv4 address
+ inet_pton(AF_INET, "192.168.2.2", &local_v4_address.sin_addr);
+ srcaddr = ALIGNED_CAST(struct sockaddr_storage *)&local_v4_address;
+ prefs = 32;
+ }
+ iph2->id = ipsecdoi_sockaddr2id(srcaddr,
+ prefs, sp->spidx.ul_proto);
if (iph2->id == NULL) {
plog(ASL_LEVEL_ERR,
"failed to get ID for %s\n",
s_ipsecdoi_ident((ALIGNED_CAST(struct ipsecdoi_id_b *)iph2->id->v)->type));
/* remote side */
- iph2->id_p = ipsecdoi_sockaddr2id(&sp->spidx.dst,
- sp->spidx.prefd, sp->spidx.ul_proto);
+ struct sockaddr_in v4_address;
+ struct sockaddr_storage *dstaddr = &sp->spidx.dst;
+ u_int8_t prefd = sp->spidx.prefd;
+ if (sp->spidx.dst.ss_family == AF_INET6 &&
+ iph2->nat64_prefix.length) {
+ memset(&v4_address, 0, sizeof(v4_address));
+ v4_address.sin_len = sizeof(struct sockaddr_in);
+ v4_address.sin_family = AF_INET;
+ v4_address.sin_port = ((struct sockaddr_in6 *)&sp->spidx.dst)->sin6_port;
+ nw_nat64_extract_v4(&iph2->nat64_prefix, &((struct sockaddr_in6 *)&sp->spidx.dst)->sin6_addr, &v4_address.sin_addr);
+
+ dstaddr = ALIGNED_CAST(struct sockaddr_storage *)&v4_address;
+ prefd = 32;
+ }
+ iph2->id_p = ipsecdoi_sockaddr2id(dstaddr,
+ prefd, sp->spidx.ul_proto);
if (iph2->id_p == NULL) {
plog(ASL_LEVEL_ERR,
"failed to get ID for %s\n",
VPTRINIT(iph2->id);
return -1;
}
- plogdump(ASL_LEVEL_DEBUG, iph2->id->v, iph2->id->l, "use remote ID type %s\n",
+ plogdump(ASL_LEVEL_DEBUG, iph2->id_p->v, iph2->id_p->l, "use remote ID type %s\n",
s_ipsecdoi_ident((ALIGNED_CAST(struct ipsecdoi_id_b *)iph2->id_p->v)->type));
return 0;
if (prefixlen == (sizeof(struct in_addr) << 3)) {
type = IPSECDOI_ID_IPV4_ADDR;
len2 = 0;
- } else {
+ } else if (prefixlen < (sizeof(struct in_addr) << 3)) {
type = IPSECDOI_ID_IPV4_ADDR_SUBNET;
len2 = sizeof(struct in_addr);
+ } else {
+ plog(ASL_LEVEL_ERR,
+ "invalid prefix length: %d.\n", prefixlen);
+ return NULL;
}
sa = (caddr_t)&((struct sockaddr_in *)(saddr))->sin_addr;
port = ((struct sockaddr_in *)(saddr))->sin_port;
if (prefixlen == (sizeof(struct in6_addr) << 3)) {
type = IPSECDOI_ID_IPV6_ADDR;
len2 = 0;
- } else {
+ } else if (prefixlen < (sizeof(struct in6_addr) << 3)) {
type = IPSECDOI_ID_IPV6_ADDR_SUBNET;
len2 = sizeof(struct in6_addr);
+ } else {
+ plog(ASL_LEVEL_ERR,
+ "invalid prefix length: %d.\n", prefixlen);
+ return NULL;
}
sa = (caddr_t)&((struct sockaddr_in6 *)(saddr))->sin6_addr;
port = ((struct sockaddr_in6 *)(saddr))->sin6_port;
tr->authtype = IPSECDOI_ATTR_AUTH_NONE;
while (tlen > 0) {
+ if (tlen < sizeof(struct isakmp_data)) {
+ plog(ASL_LEVEL_ERR,
+ "ipsecdoi_t2satrns invalid length of isakmp data, expected %zu actual %d\n",
+ sizeof(struct isakmp_data), tlen);
+ return -1;
+ }
type = ntohs(d->type) & ~ISAKMP_GEN_MASK;
flag = ntohs(d->type) & ISAKMP_GEN_MASK;
memcpy(ld_buf->v, &d->lorv, sizeof(d->lorv));
} else {
int len = ntohs(d->lorv);
+ if ((len + sizeof(struct isakmp_data)) > tlen) {
+ plog(ASL_LEVEL_ERR,
+ "invalid IPsec attr(%d), attr-len %d, overall-len %lu\n",
+ type, len, (tlen - sizeof(struct isakmp_data)));
+ return -1;
+ }
/* i.e. ISAKMP_GEN_TLV */
ld_buf = vmalloc(len);
if (ld_buf == NULL) {
} else {
tlen -= (sizeof(*d) + ntohs(d->lorv));
d = (struct isakmp_data *)((caddr_t)d + sizeof(*d) + ntohs(d->lorv));
+ if (tlen < 0) {
+ plog(ASL_LEVEL_ERR,
+ "ipsecdoi_t2satrns: packet too short - attr length %u for type %d\n",
+ ntohs(d->lorv), type);
+ goto end;
+ }
}
}