X-Git-Url: https://git.saurik.com/apple/ipsec.git/blobdiff_plain/52b7d2ce06d68d0a9160d16f6e7c08c21c149d0d..64c59980f82beb1accdfb0d8567e51b97b9c7857:/ipsec-tools/racoon/oakley.c?ds=sidebyside diff --git a/ipsec-tools/racoon/oakley.c b/ipsec-tools/racoon/oakley.c index 1d52885..d2dab6b 100644 --- a/ipsec-tools/racoon/oakley.c +++ b/ipsec-tools/racoon/oakley.c @@ -1,4 +1,6 @@ -/* $Id: oakley.c,v 1.17.2.5 2005/10/04 09:54:27 manubsd Exp $ */ +/* $NetBSD: oakley.c,v 1.9.6.2 2007/04/04 13:08:28 vanhu Exp $ */ + +/* Id: oakley.c,v 1.32 2006/05/26 12:19:46 manubsd Exp */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -36,13 +38,17 @@ #include /* XXX for subjectaltname */ #include /* XXX for subjectaltname */ -#include +#ifdef HAVE_OPENSSL #include +#include +#endif #include #include #include #include +#include +#include #if TIME_WITH_SYS_TIME # include @@ -54,6 +60,9 @@ # include # endif #endif +#ifdef ENABLE_HYBRID +#include +#endif #include "var.h" #include "misc.h" @@ -69,10 +78,7 @@ #include "isakmp_cfg.h" #endif #include "oakley.h" -#include "admin.h" -#include "privsep.h" #include "localconf.h" -#include "remoteconf.h" #include "policy.h" #include "handler.h" #include "ipsec_doi.h" @@ -81,43 +87,57 @@ #include "sainfo.h" #include "proposal.h" #include "crypto_openssl.h" -#ifdef __APPLE__ #include "crypto_cssm.h" +#if HAVE_OPENDIR #include "open_dir.h" #endif #include "dnssec.h" #include "sockmisc.h" #include "strnames.h" #include "gcmalloc.h" -#include "rsalist.h" -#ifdef __APPLE__ -#include -#endif - - -#ifdef HAVE_GSSAPI -#include "gssapi.h" +#include +#include "remoteconf.h" +#include "vpn_control.h" +#if TARGET_OS_EMBEDDED +#include +#include #endif +#include "vpn_control_var.h" +#include "ikev2_rfc.h" +#include "extern.h" #define OUTBOUND_SA 0 #define INBOUND_SA 1 -#ifdef __APPLE__ #define CERT_CHECKID_FROM_PEER 0 #define CERT_CHECKID_FROM_RMCONFIG 1 -#endif +#ifdef HAVE_OPENSSL #define INITDHVAL(a, s, d, t) \ do { \ - vchar_t buf; \ - buf.v = str2val((s), 16, &buf.l); \ - memset(&a, 0, sizeof(struct dhgroup)); \ - a.type = (t); \ - a.prime = vdup(&buf); \ - a.gen1 = 2; \ - a.gen2 = 0; \ - racoon_free(buf.v); \ +vchar_t buf; \ +buf.v = str2val((s), 16, &buf.l); \ +memset(&a, 0, sizeof(struct dhgroup)); \ +a.type = (t); \ +a.prime = vdup(&buf); \ +a.gen1 = 2; \ +a.gen2 = 0; \ +racoon_free(buf.v); \ } while(0); +#else /* HAVE_OPENSSL */ +#define INITDHVAL(a, s, d, t) \ +do { \ +vchar_t buf; \ +buf.v = str2val((s), 16, &buf.l); \ +memset(&a, 0, sizeof(struct dhgroup)); \ +a.desc = (d); \ +a.type = (t); \ +a.prime = vdup(&buf); \ +a.gen1 = 2; \ +a.gen2 = 0; \ +racoon_free(buf.v); \ +} while(0); +#endif /* HAVE_OPENSSL */ struct dhgroup dh_modp768; struct dhgroup dh_modp1024; @@ -129,24 +149,21 @@ struct dhgroup dh_modp6144; struct dhgroup dh_modp8192; -static int oakley_check_dh_pub __P((vchar_t *, vchar_t **)); -static int oakley_compute_keymat_x __P((struct ph2handle *, int, int)); -static int get_cert_fromlocal __P((struct ph1handle *, int)); -static int get_plainrsa_fromlocal __P((struct ph1handle *, int)); -#ifdef __APPLE__ -static int oakley_check_certid __P((struct ph1handle *iph1, int)); -static int oakley_check_certid_1 __P((struct ph1handle*, int, int, void*)); -#else -static int oakley_check_certid __P((struct ph1handle *iph1)); +static int oakley_check_dh_pub (vchar_t *, vchar_t **); +static int oakley_compute_keymat_x (phase2_handle_t *, int, int); +static int oakley_compute_ikev2_keymat_x (phase2_handle_t *); +static int get_cert_fromlocal (phase1_handle_t *, int); +static int oakley_check_certid (phase1_handle_t *iph1); +static int oakley_check_certid_1 (vchar_t *, int, int, void*, cert_status_t *certStatus); +static vchar_t * oakley_prf_plus (vchar_t *, vchar_t *, int, phase1_handle_t *iph1); +#ifdef HAVE_OPENSSL +static int check_typeofcertname (int, int); #endif -static int check_typeofcertname __P((int, int)); -static cert_t *save_certbuf __P((struct isakmp_gen *)); -static cert_t *save_certx509 __P((X509 *)); -static int oakley_padlen __P((int, int)); +static cert_t *save_certbuf (struct isakmp_gen *); +static int oakley_padlen (int, int); -#ifdef __APPLE__ -static int base64toCFData(vchar_t *, CFDataRef*); -#endif +static int base64toCFData (vchar_t *, CFDataRef*); +static cert_t *oakley_appendcert_to_certchain (cert_t *, cert_t *); int oakley_get_defaultlifetime() @@ -179,17 +196,12 @@ oakley_dhinit() } void -oakley_dhgrp_free(dhgrp) - struct dhgroup *dhgrp; +oakley_dhgrp_free(struct dhgroup *dhgrp) { - if (dhgrp->prime) - vfree(dhgrp->prime); - if (dhgrp->curve_a) - vfree(dhgrp->curve_a); - if (dhgrp->curve_b) - vfree(dhgrp->curve_b); - if (dhgrp->order) - vfree(dhgrp->order); + VPTRINIT(dhgrp->prime); + VPTRINIT(dhgrp->curve_a); + VPTRINIT(dhgrp->curve_b); + VPTRINIT(dhgrp->order); racoon_free(dhgrp); } @@ -200,8 +212,7 @@ oakley_dhgrp_free(dhgrp) * performed, prepending zero bits to the value if necessary. */ static int -oakley_check_dh_pub(prime, pub0) - vchar_t *prime, **pub0; +oakley_check_dh_pub(vchar_t *prime, vchar_t **pub0) { vchar_t *tmp; vchar_t *pub = *pub0; @@ -211,7 +222,7 @@ oakley_check_dh_pub(prime, pub0) if (prime->l < pub->l) { /* what should i do ? */ - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "invalid public information was generated.\n"); return -1; } @@ -219,7 +230,7 @@ oakley_check_dh_pub(prime, pub0) /* prime->l > pub->l */ tmp = vmalloc(prime->l); if (tmp == NULL) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "failed to get DH buffer.\n"); return -1; } @@ -236,16 +247,15 @@ oakley_check_dh_pub(prime, pub0) * IN: *dh, *pub, *priv, *pub_p * OUT: **gxy */ +#ifdef HAVE_OPENSSL int -oakley_dh_compute(dh, pub, priv, pub_p, gxy) - const struct dhgroup *dh; - vchar_t *pub, *priv, *pub_p, **gxy; +oakley_dh_compute(const struct dhgroup *dh, vchar_t *pub, vchar_t *priv, vchar_t *pub_p, vchar_t **gxy) { #ifdef ENABLE_STATS struct timeval start, end; #endif if ((*gxy = vmalloc(dh->prime->l)) == NULL) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "failed to get DH buffer.\n"); return -1; } @@ -256,44 +266,103 @@ oakley_dh_compute(dh, pub, priv, pub_p, gxy) switch (dh->type) { case OAKLEY_ATTR_GRP_TYPE_MODP: if (eay_dh_compute(dh->prime, dh->gen1, pub, priv, pub_p, gxy) < 0) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "failed to compute dh value.\n"); return -1; } break; case OAKLEY_ATTR_GRP_TYPE_ECP: case OAKLEY_ATTR_GRP_TYPE_EC2N: - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "dh type %d isn't supported.\n", dh->type); return -1; default: - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "invalid dh type %d.\n", dh->type); return -1; } #ifdef ENABLE_STATS gettimeofday(&end, NULL); - syslog(LOG_NOTICE, "%s(%s%d): %8.6f", __func__, + plog(ASL_LEVEL_NOTICE, "%s(%s%d): %8.6f", __func__, s_attr_isakmp_group(dh->type), dh->prime->l << 3, timedelta(&start, &end)); #endif - plog(LLV_DEBUG, LOCATION, NULL, "compute DH's shared.\n"); - plogdump(LLV_DEBUG, (*gxy)->v, (*gxy)->l); + plog(ASL_LEVEL_DEBUG, "compute DH's shared.\n"); + + return 0; +} +#else +int +oakley_dh_compute(const struct dhgroup *dh, vchar_t *pub_p, size_t publicKeySize, vchar_t **gxy, SecDHContext *dhC) +{ + + vchar_t *computed_key = NULL; + size_t computed_keylen; + size_t maxKeyLen; + +#ifdef ENABLE_STATS + struct timeval start, end; + gettimeofday(&start, NULL); +#endif + + plog(ASL_LEVEL_DEBUG, "compute DH result.\n"); + maxKeyLen = SecDHGetMaxKeyLength(*dhC); + computed_key = vmalloc(maxKeyLen); + if (computed_key == NULL) { + plog(ASL_LEVEL_ERR, "memory error.\n"); + goto fail; + } + computed_keylen = computed_key->l; + if (SecDHComputeKey(*dhC, (uint8_t*)pub_p->v + (maxKeyLen - publicKeySize), publicKeySize, + (uint8_t*)computed_key->v, &computed_keylen)) { + plog(ASL_LEVEL_ERR, "failed to compute dh value.\n"); + goto fail; + } + +#ifdef ENABLE_STATS + gettimeofday(&end, NULL); + plog(ASL_LEVEL_NOTICE, "%s(%s%d): %8.6f", __func__, + s_attr_isakmp_group(dh->type), dh->prime->l << 3, + timedelta(&start, &end)); +#endif + + *gxy = vmalloc(maxKeyLen); + if (*gxy == NULL) { + plog(ASL_LEVEL_ERR, "memory error.\n"); + goto fail; + } + memcpy((*gxy)->v + (maxKeyLen - computed_keylen), computed_key->v, computed_keylen); + plog(ASL_LEVEL_DEBUG, "compute DH's shared.\n"); + if (*dhC) { + SecDHDestroy(*dhC); + *dhC = NULL; + } + vfree(computed_key); return 0; + +fail: + if (*dhC) { + SecDHDestroy(*dhC); + *dhC = NULL; + } + vfree(*gxy); + vfree(computed_key); + return -1; } +#endif + /* * generate values of DH * IN: *dh * OUT: **pub, **priv */ +#ifdef HAVE_OPENSSL int -oakley_dh_generate(dh, pub, priv) - const struct dhgroup *dh; - vchar_t **pub, **priv; +oakley_dh_generate(const struct dhgroup *dh, vchar_t **pub, vchar_t **priv) { #ifdef ENABLE_STATS struct timeval start, end; @@ -302,7 +371,7 @@ oakley_dh_generate(dh, pub, priv) switch (dh->type) { case OAKLEY_ATTR_GRP_TYPE_MODP: if (eay_dh_generate(dh->prime, dh->gen1, dh->gen2, pub, priv) < 0) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "failed to compute dh value.\n"); return -1; } @@ -310,18 +379,18 @@ oakley_dh_generate(dh, pub, priv) case OAKLEY_ATTR_GRP_TYPE_ECP: case OAKLEY_ATTR_GRP_TYPE_EC2N: - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "dh type %d isn't supported.\n", dh->type); return -1; default: - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "invalid dh type %d.\n", dh->type); return -1; } #ifdef ENABLE_STATS gettimeofday(&end, NULL); - syslog(LOG_NOTICE, "%s(%s%d): %8.6f", __func__, + plog(ASL_LEVEL_NOTICE, "%s(%s%d): %8.6f", __func__, s_attr_isakmp_group(dh->type), dh->prime->l << 3, timedelta(&start, &end)); #endif @@ -329,21 +398,99 @@ oakley_dh_generate(dh, pub, priv) if (oakley_check_dh_pub(dh->prime, pub) != 0) return -1; - plog(LLV_DEBUG, LOCATION, NULL, "compute DH's private.\n"); - plogdump(LLV_DEBUG, (*priv)->v, (*priv)->l); - plog(LLV_DEBUG, LOCATION, NULL, "compute DH's public.\n"); - plogdump(LLV_DEBUG, (*pub)->v, (*pub)->l); + plog(ASL_LEVEL_DEBUG, "compute DH's private.\n"); + plog(ASL_LEVEL_DEBUG, "compute DH's public.\n"); return 0; } +#else +int +oakley_dh_generate(const struct dhgroup *dh, vchar_t **pub, size_t *publicKeySize, SecDHContext *dhC) +{ + vchar_t *public = NULL; + size_t maxKeyLen; + +#ifdef ENABLE_STATS + struct timeval start, end; + gettimeofday(&start, NULL); +#endif + + plog(ASL_LEVEL_DEBUG, "generate DH key pair.\n"); + *pub = NULL; + switch (dh->type) { + case OAKLEY_ATTR_GRP_TYPE_MODP: +#define SECDH_MODP_GENERATOR 2 + if (SecDHCreate(SECDH_MODP_GENERATOR, (uint8_t*)dh->prime->v, dh->prime->l, 0, NULL, 0, dhC)) { + plog(ASL_LEVEL_ERR, "failed to create dh context.\n"); + goto fail; + } + maxKeyLen = SecDHGetMaxKeyLength(*dhC); + public = vmalloc(maxKeyLen); + *publicKeySize = public->l; + if (public == NULL) { + plog(ASL_LEVEL_ERR, "memory error.\n"); + goto fail; + } + if (SecDHGenerateKeypair(*dhC, (uint8_t*)public->v, publicKeySize)) { + plog(ASL_LEVEL_ERR, "failed to generate dh key pair.\n"); + goto fail; + } + plog(ASL_LEVEL_DEBUG, "got DH key pair.\n"); + + *pub = vmalloc(maxKeyLen); + if (*pub == NULL) { + plog(ASL_LEVEL_ERR, "memory error.\n"); + goto fail; + } + /* copy and fill with leading zeros */ + memcpy((*pub)->v + (maxKeyLen - *publicKeySize), public->v, *publicKeySize); + break; + + case OAKLEY_ATTR_GRP_TYPE_ECP: + case OAKLEY_ATTR_GRP_TYPE_EC2N: + plog(ASL_LEVEL_ERR, + "dh type %d isn't supported.\n", dh->type); + goto fail; + default: + plog(ASL_LEVEL_ERR, + "invalid dh type %d.\n", dh->type); + goto fail; + } + +#ifdef ENABLE_STATS + gettimeofday(&end, NULL); + plog(ASL_LEVEL_NOTICE, "%s(%s%d): %8.6f", __func__, + s_attr_isakmp_group(dh->type), dh->prime->l << 3, + timedelta(&start, &end)); +#endif + + if (oakley_check_dh_pub(dh->prime, pub) != 0) { + plog(ASL_LEVEL_DEBUG, "failed DH public key size check.\n"); + goto fail; + } + + //plogdump(ASL_LEVEL_DEBUG, (*pub)->v, (*pub)->l, "compute DH's public.\n"); + + vfree(public); + return 0; + +fail: + if (*dhC) { + SecDHDestroy(*dhC); + *dhC = NULL; + } + vfree(*pub); + vfree(public); + return -1; + +} +#endif /* * copy pre-defined dhgroup values. */ int -oakley_setdhgroup(group, dhgrp) - int group; - struct dhgroup **dhgrp; +oakley_setdhgroup(int group, struct dhgroup **dhgrp) { struct dhgroup *g; @@ -351,21 +498,21 @@ oakley_setdhgroup(group, dhgrp) g = alg_oakley_dhdef_group(group); if (g == NULL) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "invalid DH parameter grp=%d.\n", group); return -1; } if (!g->type || !g->prime || !g->gen1) { /* unsuported */ - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "unsupported DH parameters grp=%d.\n", group); return -1; } *dhgrp = racoon_calloc(1, sizeof(struct dhgroup)); if (*dhgrp == NULL) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "failed to get DH buffer.\n"); return 0; } @@ -386,25 +533,28 @@ oakley_setdhgroup(group, dhgrp) * modify oakley_compute_keymat() accordingly. */ vchar_t * -oakley_prf(key, buf, iph1) - vchar_t *key, *buf; - struct ph1handle *iph1; +oakley_prf(vchar_t *key, vchar_t *buf, phase1_handle_t *iph1) { vchar_t *res = NULL; int type; if (iph1->approval == NULL) { - /* - * it's before negotiating hash algorithm. - * We use md5 as default. - */ - type = OAKLEY_ATTR_HASH_ALG_MD5; + if (iph1->version == ISAKMP_VERSION_NUMBER_IKEV1) { + /* + * it's before negotiating hash algorithm. + * We use md5 as default. + */ + type = OAKLEY_ATTR_HASH_ALG_MD5; + } else { + type = OAKLEY_ATTR_HASH_ALG_SHA; + } } else - type = iph1->approval->hashtype; - - res = alg_oakley_hmacdef_one(type, key, buf); + { + type = iph1->approval->hashtype; + } + res = alg_oakley_hmacdef_one(type, key, buf); if (res == NULL) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "invalid hmac algorithm %d.\n", type); return NULL; } @@ -416,25 +566,32 @@ oakley_prf(key, buf, iph1) * hash */ vchar_t * -oakley_hash(buf, iph1) - vchar_t *buf; - struct ph1handle *iph1; +oakley_hash(vchar_t *buf, phase1_handle_t *iph1) { vchar_t *res = NULL; int type; if (iph1->approval == NULL) { - /* - * it's before negotiating hash algorithm. - * We use md5 as default. - */ - type = OAKLEY_ATTR_HASH_ALG_MD5; - } else - type = iph1->approval->hashtype; + if (iph1->version == ISAKMP_VERSION_NUMBER_IKEV1) { + /* + * it's before negotiating hash algorithm. + * We use md5 as default. + */ + type = OAKLEY_ATTR_HASH_ALG_MD5; + } else { + type = OAKLEY_ATTR_HASH_ALG_SHA; + } + } else { + if (iph1->version == ISAKMP_VERSION_NUMBER_IKEV1) { + type = iph1->approval->hashtype; + } else { + type = OAKLEY_ATTR_HASH_ALG_SHA; + } + } res = alg_oakley_hashdef_one(type, buf); if (res == NULL) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "invalid hash algorithm %d.\n", type); return NULL; } @@ -447,16 +604,18 @@ oakley_hash(buf, iph1) * see seciton 5.5 Phase 2 - Quick Mode in isakmp-oakley-05. */ int -oakley_compute_keymat(iph2, side) - struct ph2handle *iph2; - int side; +oakley_compute_keymat(phase2_handle_t *iph2, int side) { int error = -1; /* compute sharing secret of DH when PFS */ if (iph2->approval->pfs_group && iph2->dhpub_p) { +#ifdef HAVE_OPENSSL if (oakley_dh_compute(iph2->pfsgrp, iph2->dhpub, - iph2->dhpriv, iph2->dhpub_p, &iph2->dhgxy) < 0) + iph2->dhpriv, iph2->dhpub_p, &iph2->dhgxy) < 0) +#else + if (oakley_dh_compute(iph2->pfsgrp, iph2->dhpub_p, iph2->publicKeySize, &iph2->dhgxy, &iph2->dhC) < 0) +#endif goto end; } @@ -465,7 +624,7 @@ oakley_compute_keymat(iph2, side) || oakley_compute_keymat_x(iph2, side, OUTBOUND_SA) < 0) goto end; - plog(LLV_DEBUG, LOCATION, NULL, "KEYMAT computed.\n"); + plog(ASL_LEVEL_DEBUG, "KEYMAT computed.\n"); error = 0; @@ -473,6 +632,7 @@ end: return error; } + /* * compute KEYMAT. * KEYMAT = prf(SKEYID_d, protocol | SPI | Ni_b | Nr_b). @@ -483,10 +643,7 @@ end: * so we do not implement RFC2409 Appendix B (DOORAK-MAC example). */ static int -oakley_compute_keymat_x(iph2, side, sa_dir) - struct ph2handle *iph2; - int side; - int sa_dir; +oakley_compute_keymat_x(phase2_handle_t *iph2, int side, int sa_dir) { vchar_t *buf = NULL, *res = NULL, *bp; char *p; @@ -507,7 +664,7 @@ oakley_compute_keymat_x(iph2, side, sa_dir) + iph2->nonce_p->l); buf = vmalloc(len); if (buf == NULL) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "failed to get keymat buffer.\n"); goto end; } @@ -537,8 +694,7 @@ oakley_compute_keymat_x(iph2, side, sa_dir) p += bp->l; /* compute IV */ - plog(LLV_DEBUG, LOCATION, NULL, "KEYMAT compute with\n"); - plogdump(LLV_DEBUG, buf->v, buf->l); + //plogdump(ASL_LEVEL_DEBUG, buf->v, buf->l, "KEYMAT compute with\n"); /* res = K1 */ res = oakley_prf(iph2->ph1->skeyid_d, buf, iph2->ph1); @@ -570,16 +726,16 @@ oakley_compute_keymat_x(iph2, side, sa_dir) default: break; } - plog(LLV_DEBUG, LOCATION, NULL, "encklen=%d authklen=%d\n", + plog(ASL_LEVEL_DEBUG, "encklen=%d authklen=%d\n", encklen, authklen); dupkeymat = (encklen + authklen) / 8 / res->l; dupkeymat += 2; /* safety mergin */ if (dupkeymat < 3) dupkeymat = 3; - plog(LLV_DEBUG, LOCATION, NULL, - "generating %zu bits of key (dupkeymat=%d)\n", - dupkeymat * 8 * res->l, dupkeymat); + //plog(ASL_LEVEL_DEBUG, + // "generating %zu bits of key (dupkeymat=%d)\n", + // dupkeymat * 8 * res->l, dupkeymat); if (0 < --dupkeymat) { vchar_t *prev = res; /* K(n-1) */ vchar_t *seed = NULL; /* seed for Kn */ @@ -595,13 +751,13 @@ oakley_compute_keymat_x(iph2, side, sa_dir) * K3 = prf(SKEYID_d, K2 | src) * Kn = prf(SKEYID_d, K(n-1) | src) */ - plog(LLV_DEBUG, LOCATION, NULL, - "generating K1...K%d for KEYMAT.\n", - dupkeymat + 1); + //plog(ASL_LEVEL_DEBUG, + // "generating K1...K%d for KEYMAT.\n", + // dupkeymat + 1); seed = vmalloc(prev->l + buf->l); if (seed == NULL) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "failed to get keymat buffer.\n"); if (prev && prev != res) vfree(prev); @@ -610,13 +766,14 @@ oakley_compute_keymat_x(iph2, side, sa_dir) while (dupkeymat--) { vchar_t *this = NULL; /* Kn */ + int update_prev; memcpy(seed->v, prev->v, prev->l); memcpy(seed->v + prev->l, buf->v, buf->l); this = oakley_prf(iph2->ph1->skeyid_d, seed, iph2->ph1); if (!this) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "oakley_prf memory overflow\n"); if (prev && prev != res) vfree(prev); @@ -625,10 +782,16 @@ oakley_compute_keymat_x(iph2, side, sa_dir) goto end; } + update_prev = (prev && prev == res) ? 1 : 0; + l = res->l; res = vrealloc(res, l + this->l); + + if (update_prev) + prev = res; + if (res == NULL) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "failed to get keymat buffer.\n"); if (prev && prev != res) vfree(prev); @@ -649,7 +812,7 @@ oakley_compute_keymat_x(iph2, side, sa_dir) vfree(seed); } - plogdump(LLV_DEBUG, res->v, res->l); + //plogdump(ASL_LEVEL_DEBUG, res->v, res->l, ""); if (sa_dir == INBOUND_SA) pr->keymat = res; @@ -682,69 +845,13 @@ end: return error; } -#if notyet -/* - * NOTE: Must terminate by NULL. - */ -vchar_t * -oakley_compute_hashx(struct ph1handle *iph1, ...) -{ - vchar_t *buf, *res; - vchar_t *s; - caddr_t p; - int len; - - va_list ap; - - /* get buffer length */ - va_start(ap, iph1); - len = 0; - while ((s = va_arg(ap, vchar_t *)) != NULL) { - len += s->l - } - va_end(ap); - - buf = vmalloc(len); - if (buf == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "failed to get hash buffer\n"); - return NULL; - } - - /* set buffer */ - va_start(ap, iph1); - p = buf->v; - while ((s = va_arg(ap, char *)) != NULL) { - memcpy(p, s->v, s->l); - p += s->l; - } - va_end(ap); - - plog(LLV_DEBUG, LOCATION, NULL, "HASH with: \n"); - plogdump(LLV_DEBUG, buf->v, buf->l); - - /* compute HASH */ - res = oakley_prf(iph1->skeyid_a, buf, iph1); - vfree(buf); - if (res == NULL) - return NULL; - - plog(LLV_DEBUG, LOCATION, NULL, "HASH computed:\n"); - plogdump(LLV_DEBUG, res->v, res->l); - - return res; -} -#endif /* * compute HASH(3) prf(SKEYID_a, 0 | M-ID | Ni_b | Nr_b) * see seciton 5.5 Phase 2 - Quick Mode in isakmp-oakley-05. */ vchar_t * -oakley_compute_hash3(iph1, msgid, body) - struct ph1handle *iph1; - u_int32_t msgid; - vchar_t *body; +oakley_compute_hash3(phase1_handle_t *iph1, u_int32_t msgid, vchar_t *body) { vchar_t *buf = 0, *res = 0; int len; @@ -754,7 +861,7 @@ oakley_compute_hash3(iph1, msgid, body) len = 1 + sizeof(u_int32_t) + body->l; buf = vmalloc(len); if (buf == NULL) { - plog(LLV_DEBUG, LOCATION, NULL, + plog(ASL_LEVEL_DEBUG, "failed to get hash buffer\n"); goto end; } @@ -765,9 +872,6 @@ oakley_compute_hash3(iph1, msgid, body) memcpy(buf->v + 1 + sizeof(u_int32_t), body->v, body->l); - plog(LLV_DEBUG, LOCATION, NULL, "HASH with: \n"); - plogdump(LLV_DEBUG, buf->v, buf->l); - /* compute HASH */ res = oakley_prf(iph1->skeyid_a, buf, iph1); if (res == NULL) @@ -775,8 +879,7 @@ oakley_compute_hash3(iph1, msgid, body) error = 0; - plog(LLV_DEBUG, LOCATION, NULL, "HASH computed:\n"); - plogdump(LLV_DEBUG, res->v, res->l); + //plogdump(ASL_LEVEL_DEBUG, res->v, res->l, "HASH computed:\n"); end: if (buf != NULL) @@ -795,10 +898,7 @@ end: * prf(SKEYID_a, M-ID | N/D) */ vchar_t * -oakley_compute_hash1(iph1, msgid, body) - struct ph1handle *iph1; - u_int32_t msgid; - vchar_t *body; +oakley_compute_hash1(phase1_handle_t *iph1, u_int32_t msgid, vchar_t *body) { vchar_t *buf = NULL, *res = NULL; char *p; @@ -809,7 +909,7 @@ oakley_compute_hash1(iph1, msgid, body) len = sizeof(u_int32_t) + body->l; buf = vmalloc(len); if (buf == NULL) { - plog(LLV_DEBUG, LOCATION, NULL, + plog(ASL_LEVEL_DEBUG, "failed to get hash buffer\n"); goto end; } @@ -821,9 +921,6 @@ oakley_compute_hash1(iph1, msgid, body) memcpy(p, body->v, body->l); - plog(LLV_DEBUG, LOCATION, NULL, "HASH with:\n"); - plogdump(LLV_DEBUG, buf->v, buf->l); - /* compute HASH */ res = oakley_prf(iph1->skeyid_a, buf, iph1); if (res == NULL) @@ -831,8 +928,7 @@ oakley_compute_hash1(iph1, msgid, body) error = 0; - plog(LLV_DEBUG, LOCATION, NULL, "HASH computed:\n"); - plogdump(LLV_DEBUG, res->v, res->l); + //plogdump(ASL_LEVEL_DEBUG, res->v, res->l, "HASH computed:\n"); end: if (buf != NULL) @@ -848,17 +944,12 @@ end: * for gssapi, also include all GSS tokens, and call gss_wrap on the result */ vchar_t * -oakley_ph1hash_common(iph1, sw) - struct ph1handle *iph1; - int sw; +oakley_ph1hash_common(phase1_handle_t *iph1, int sw) { vchar_t *buf = NULL, *res = NULL, *bp; char *p, *bp2; int len, bl; int error = -1; -#ifdef HAVE_GSSAPI - vchar_t *gsstokens = NULL; -#endif /* create buffer */ len = iph1->dhpub->l @@ -867,25 +958,9 @@ oakley_ph1hash_common(iph1, sw) + iph1->sa->l + (sw == GENERATE ? iph1->id->l : iph1->id_p->l); -#ifdef HAVE_GSSAPI - if (iph1->approval->authmethod == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB) { - if (iph1->gi_i != NULL && iph1->gi_r != NULL) { - bp = (sw == GENERATE ? iph1->gi_i : iph1->gi_r); - len += bp->l; - } - if (sw == GENERATE) - gssapi_get_itokens(iph1, &gsstokens); - else - gssapi_get_rtokens(iph1, &gsstokens); - if (gsstokens == NULL) - return NULL; - len += gsstokens->l; - } -#endif - buf = vmalloc(len); if (buf == NULL) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "failed to get hash buffer\n"); goto end; } @@ -928,21 +1003,6 @@ oakley_ph1hash_common(iph1, sw) memcpy(p, bp->v, bp->l); p += bp->l; -#ifdef HAVE_GSSAPI - if (iph1->approval->authmethod == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB) { - if (iph1->gi_i != NULL && iph1->gi_r != NULL) { - bp = (sw == GENERATE ? iph1->gi_i : iph1->gi_r); - memcpy(p, bp->v, bp->l); - p += bp->l; - } - memcpy(p, gsstokens->v, gsstokens->l); - p += gsstokens->l; - } -#endif - - plog(LLV_DEBUG, LOCATION, NULL, "HASH with:\n"); - plogdump(LLV_DEBUG, buf->v, buf->l); - /* compute HASH */ res = oakley_prf(iph1->skeyid, buf, iph1); if (res == NULL) @@ -950,16 +1010,9 @@ oakley_ph1hash_common(iph1, sw) error = 0; - plog(LLV_DEBUG, LOCATION, NULL, "HASH computed:\n"); - plogdump(LLV_DEBUG, res->v, res->l); - end: if (buf != NULL) vfree(buf); -#ifdef HAVE_GSSAPI - if (gsstokens != NULL) - vfree(gsstokens); -#endif return res; } @@ -971,9 +1024,7 @@ end: * HASH_I = prf(hash(Ni_b | Nr_b), g^xi | CKY-I | CKY-R | SAi_b | IDii_b) */ vchar_t * -oakley_ph1hash_base_i(iph1, sw) - struct ph1handle *iph1; - int sw; +oakley_ph1hash_base_i(phase1_handle_t *iph1, int sw) { vchar_t *buf = NULL, *res = NULL, *bp; vchar_t *hashkey = NULL; @@ -984,36 +1035,42 @@ oakley_ph1hash_base_i(iph1, sw) /* sanity check */ if (iph1->etype != ISAKMP_ETYPE_BASE) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "invalid etype for this hash function\n"); return NULL; } - switch (iph1->approval->authmethod) { + switch (AUTHMETHOD(iph1)) { case OAKLEY_ATTR_AUTH_METHOD_PSKEY: case OAKLEY_ATTR_AUTH_METHOD_RSAENC: case OAKLEY_ATTR_AUTH_METHOD_RSAREV: +#ifdef ENABLE_HYBRID + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAENC_I: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAENC_R: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAREV_I: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAREV_R: + case FICTIVE_AUTH_METHOD_XAUTH_PSKEY_I: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_R: +#endif if (iph1->skeyid == NULL) { - plog(LLV_ERROR, LOCATION, NULL, "no SKEYID found.\n"); + plog(ASL_LEVEL_ERR, "no SKEYID found.\n"); return NULL; } hashkey = iph1->skeyid; break; - case OAKLEY_ATTR_AUTH_METHOD_DSSSIG: case OAKLEY_ATTR_AUTH_METHOD_RSASIG: - case OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB: #ifdef ENABLE_HYBRID - case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_R: - case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_R: case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I: - case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I: + case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_R: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_I: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_R: #endif /* make hash for seed */ len = iph1->nonce->l + iph1->nonce_p->l; buf = vmalloc(len); if (buf == NULL) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "failed to get hash buffer\n"); goto end; } @@ -1037,7 +1094,7 @@ oakley_ph1hash_base_i(iph1, sw) break; default: - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "not supported authentication method %d\n", iph1->approval->authmethod); return NULL; @@ -1050,7 +1107,7 @@ oakley_ph1hash_base_i(iph1, sw) + (sw == GENERATE ? iph1->id->l : iph1->id_p->l); buf = vmalloc(len); if (buf == NULL) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "failed to get hash buffer\n"); goto end; } @@ -1072,8 +1129,7 @@ oakley_ph1hash_base_i(iph1, sw) memcpy(p, bp->v, bp->l); p += bp->l; - plog(LLV_DEBUG, LOCATION, NULL, "HASH_I with:\n"); - plogdump(LLV_DEBUG, buf->v, buf->l); + //plogdump(ASL_LEVEL_DEBUG, buf->v, buf->l, "HASH_I with:\n"); /* compute HASH */ res = oakley_prf(hashkey, buf, iph1); @@ -1082,8 +1138,7 @@ oakley_ph1hash_base_i(iph1, sw) error = 0; - plog(LLV_DEBUG, LOCATION, NULL, "HASH_I computed:\n"); - plogdump(LLV_DEBUG, res->v, res->l); + //plogdump(ASL_LEVEL_DEBUG, res->v, res->l, "HASH_I computed:\n"); end: if (hash != NULL) @@ -1099,9 +1154,7 @@ end: * HASH_R = prf(hash(Ni_b | Nr_b), g^xi | g^xr | CKY-I | CKY-R | SAi_b | IDii_b) */ vchar_t * -oakley_ph1hash_base_r(iph1, sw) - struct ph1handle *iph1; - int sw; +oakley_ph1hash_base_r(phase1_handle_t *iph1, int sw) { vchar_t *buf = NULL, *res = NULL, *bp; vchar_t *hash = NULL; @@ -1111,27 +1164,34 @@ oakley_ph1hash_base_r(iph1, sw) /* sanity check */ if (iph1->etype != ISAKMP_ETYPE_BASE) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "invalid etype for this hash function\n"); return NULL; } - if (iph1->approval->authmethod != OAKLEY_ATTR_AUTH_METHOD_DSSSIG + + switch(AUTHMETHOD(iph1)) { + case OAKLEY_ATTR_AUTH_METHOD_RSASIG: #ifdef ENABLE_HYBRID - && iph1->approval->authmethod != OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I - && iph1->approval->authmethod != OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I + case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I: + case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_R: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_I: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_R: + case FICTIVE_AUTH_METHOD_XAUTH_PSKEY_I: #endif - && iph1->approval->authmethod != OAKLEY_ATTR_AUTH_METHOD_RSASIG) { - plog(LLV_ERROR, LOCATION, NULL, + break; + default: + plog(ASL_LEVEL_ERR, "not supported authentication method %d\n", iph1->approval->authmethod); return NULL; + break; } /* make hash for seed */ len = iph1->nonce->l + iph1->nonce_p->l; buf = vmalloc(len); if (buf == NULL) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "failed to get hash buffer\n"); goto end; } @@ -1159,7 +1219,7 @@ oakley_ph1hash_base_r(iph1, sw) + (sw == GENERATE ? iph1->id_p->l : iph1->id->l); buf = vmalloc(len); if (buf == NULL) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "failed to get hash buffer\n"); goto end; } @@ -1186,8 +1246,7 @@ oakley_ph1hash_base_r(iph1, sw) memcpy(p, bp->v, bp->l); p += bp->l; - plog(LLV_DEBUG, LOCATION, NULL, "HASH with:\n"); - plogdump(LLV_DEBUG, buf->v, buf->l); + //plogdump(ASL_LEVEL_DEBUG, buf->v, buf->l, "HASH_R with:\n"); /* compute HASH */ res = oakley_prf(hash, buf, iph1); @@ -1196,8 +1255,7 @@ oakley_ph1hash_base_r(iph1, sw) error = 0; - plog(LLV_DEBUG, LOCATION, NULL, "HASH computed:\n"); - plogdump(LLV_DEBUG, res->v, res->l); + //plogdump(ASL_LEVEL_DEBUG, res->v, res->l, "HASH_R computed:\n"); end: if (buf != NULL) @@ -1207,6 +1265,37 @@ end: return res; } +#if HAVE_OPENDIR +static int +oakley_verify_userid(phase1_handle_t *iph1) +{ + cert_t *p; + vchar_t *user_id; + int user_id_found = 0; + + for (p = iph1->cert_p; p; p = p->chain) { + user_id = eay_get_x509_common_name(&p->cert); //%%%%%%%% fix this + if (user_id) { + user_id_found = 1; + // the following functions will check if user_id == 0 + if (open_dir_authorize_id(user_id, iph1->rmconf->open_dir_auth_group)) { + vfree(user_id); + return 0; + } + vfree(user_id); + } + } + if (user_id_found) { + plog(ASL_LEVEL_ERR, + "the peer is not authorized for access.\n"); + } else { + plog(ASL_LEVEL_ERR, + "the peer is not authorized for access - user ID not found.\n"); + } + return ISAKMP_NTYPE_AUTHENTICATION_FAILED; +} +#endif /* HAVE_OPENDIR */ + /* * compute each authentication method in phase 1. * OUT: @@ -1216,54 +1305,69 @@ end: * the value is notification type. */ int -oakley_validate_auth(iph1) - struct ph1handle *iph1; +oakley_validate_auth(phase1_handle_t *iph1) { vchar_t *my_hash = NULL; int result; -#ifdef HAVE_GSSAPI - vchar_t *gsshash = NULL; -#endif #ifdef ENABLE_STATS struct timeval start, end; #endif + SecKeyRef publicKeyRef = NULL; #ifdef ENABLE_STATS gettimeofday(&start, NULL); #endif - switch (iph1->approval->authmethod) { + + switch (AUTHMETHOD(iph1)) { case OAKLEY_ATTR_AUTH_METHOD_PSKEY: +#ifdef ENABLE_HYBRID + case FICTIVE_AUTH_METHOD_XAUTH_PSKEY_I: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_R: +#endif /* validate HASH */ { char *r_hash; if (iph1->id_p == NULL || iph1->pl_hash == NULL) { - plog(LLV_ERROR, LOCATION, iph1->remote, + plog(ASL_LEVEL_ERR, "few isakmp message received.\n"); return ISAKMP_NTYPE_PAYLOAD_MALFORMED; } - +#ifdef ENABLE_HYBRID + if (AUTHMETHOD(iph1) == FICTIVE_AUTH_METHOD_XAUTH_PSKEY_I && + ((iph1->mode_cfg->flags & ISAKMP_CFG_VENDORID_XAUTH) == 0)) + { + plog(ASL_LEVEL_ERR, "No SIG was passed, " + "hybrid auth is enabled, " + "but peer is no Xauth compliant\n"); + return ISAKMP_NTYPE_SITUATION_NOT_SUPPORTED; + break; + } +#endif r_hash = (caddr_t)(iph1->pl_hash + 1); - plog(LLV_DEBUG, LOCATION, NULL, "HASH received:"); - plogdump(LLV_DEBUG, r_hash, - ntohs(iph1->pl_hash->h.len) - sizeof(*iph1->pl_hash)); + //plogdump(ASL_LEVEL_DEBUG, r_hash, + // ntohs(iph1->pl_hash->h.len) - sizeof(*iph1->pl_hash), "HASH received:\n"); - switch (iph1->etype) { - case ISAKMP_ETYPE_IDENT: - case ISAKMP_ETYPE_AGG: - my_hash = oakley_ph1hash_common(iph1, VALIDATE); - break; - case ISAKMP_ETYPE_BASE: - if (iph1->side == INITIATOR) + if (iph1->version == ISAKMP_VERSION_NUMBER_IKEV1) { + switch (iph1->etype) { + case ISAKMP_ETYPE_IDENT: + case ISAKMP_ETYPE_AGG: my_hash = oakley_ph1hash_common(iph1, VALIDATE); - else - my_hash = oakley_ph1hash_base_i(iph1, VALIDATE); - break; - default: - plog(LLV_ERROR, LOCATION, NULL, - "invalid etype %d\n", iph1->etype); - return ISAKMP_NTYPE_INVALID_EXCHANGE_TYPE; + break; + case ISAKMP_ETYPE_BASE: + if (iph1->side == INITIATOR) + my_hash = oakley_ph1hash_common(iph1, VALIDATE); + else + my_hash = oakley_ph1hash_base_i(iph1, VALIDATE); + break; + default: + plog(ASL_LEVEL_ERR, + "invalid etype %d\n", iph1->etype); + return ISAKMP_NTYPE_INVALID_EXCHANGE_TYPE; + } + } else { + my_hash = oakley_ph1hash_common(iph1, VALIDATE); } if (my_hash == NULL) return ISAKMP_INTERNAL_ERROR; @@ -1272,18 +1376,18 @@ oakley_validate_auth(iph1) vfree(my_hash); if (result) { - plog(LLV_ERROR, LOCATION, NULL, "HASH mismatched\n"); + plog(ASL_LEVEL_ERR, "HASH mismatched\n"); return ISAKMP_NTYPE_INVALID_HASH_INFORMATION; } - plog(LLV_DEBUG, LOCATION, NULL, "HASH for PSK validated.\n"); + plog(ASL_LEVEL_DEBUG, "HASH for PSK validated.\n"); } break; - case OAKLEY_ATTR_AUTH_METHOD_DSSSIG: case OAKLEY_ATTR_AUTH_METHOD_RSASIG: #ifdef ENABLE_HYBRID - case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_R: - case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_R: + case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_I: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_R: #endif { int error = 0; @@ -1291,76 +1395,29 @@ oakley_validate_auth(iph1) /* validation */ if (iph1->id_p == NULL) { - plog(LLV_ERROR, LOCATION, iph1->remote, + plog(ASL_LEVEL_ERR, "no ID payload was passed.\n"); return ISAKMP_NTYPE_PAYLOAD_MALFORMED; } if (iph1->sig_p == NULL) { - plog(LLV_ERROR, LOCATION, iph1->remote, + plog(ASL_LEVEL_ERR, "no SIG payload was passed.\n"); return ISAKMP_NTYPE_PAYLOAD_MALFORMED; } - plog(LLV_DEBUG, LOCATION, NULL, "SIGN passed:\n"); - plogdump(LLV_DEBUG, iph1->sig_p->v, iph1->sig_p->l); + plog(ASL_LEVEL_DEBUG, "*** SIGN passed\n"); /* get peer's cert */ switch (iph1->rmconf->getcert_method) { case ISAKMP_GETCERT_PAYLOAD: if (iph1->cert_p == NULL) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "no peer's CERT payload found.\n"); return ISAKMP_INTERNAL_ERROR; } break; - case ISAKMP_GETCERT_LOCALFILE: - switch (iph1->rmconf->certtype) { - case ISAKMP_CERT_X509SIGN: - if (iph1->rmconf->peerscertfile == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "no peer's CERT file found.\n"); - return ISAKMP_INTERNAL_ERROR; - } - - /* don't use cached cert */ - if (iph1->cert_p != NULL) { - oakley_delcert(iph1->cert_p); - iph1->cert_p = NULL; - } - - error = get_cert_fromlocal(iph1, 0); - break; - - case ISAKMP_CERT_PLAINRSA: - error = get_plainrsa_fromlocal(iph1, 0); - break; - } - if (error) - return ISAKMP_INTERNAL_ERROR; - break; - case ISAKMP_GETCERT_DNS: - if (iph1->rmconf->peerscertfile != NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "why peer's CERT file is defined " - "though getcert method is dns ?\n"); - return ISAKMP_INTERNAL_ERROR; - } - - /* don't use cached cert */ - if (iph1->cert_p != NULL) { - oakley_delcert(iph1->cert_p); - iph1->cert_p = NULL; - } - - iph1->cert_p = dnssec_getcert(iph1->id_p); - if (iph1->cert_p == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "no CERT RR found.\n"); - return ISAKMP_INTERNAL_ERROR; - } - break; default: - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "invalid getcert_mothod: %d\n", iph1->rmconf->getcert_method); return ISAKMP_INTERNAL_ERROR; @@ -1368,53 +1425,25 @@ oakley_validate_auth(iph1) /* compare ID payload and certificate name */ if (iph1->rmconf->verify_cert && -#ifdef __APPLE__ - (error = oakley_check_certid(iph1, CERT_CHECKID_FROM_PEER)) != 0) -#else - (error = oakley_check_certid(iph1)) != 0) -#endif - return error; - -#ifdef __APPLE__ - - /* check configured peers identifier against cert IDs */ - /* allows checking of specified ID against multiple ids in the cert */ - /* such as multiple domain names */ - if (iph1->rmconf->cert_verification_option == VERIFICATION_OPTION_PEERS_IDENTIFIER && - (error = oakley_check_certid(iph1, CERT_CHECKID_FROM_RMCONFIG)) != 0) + (error = oakley_check_certid(iph1)) != 0) return error; +#if HAVE_OPENDIR /* check cert common name against Open Directory authentication group */ if (iph1->rmconf->cert_verification_option == VERIFICATION_OPTION_OPEN_DIR) { - - vchar_t *user_id = NULL; - - user_id = eay_get_x509_common_name(&iph1->cert_p->cert); - if (user_id) { - // the following functions will check if user_id == 0 - if (open_dir_authorize_id(user_id, iph1->rmconf->open_dir_auth_group) == 0) { - plog(LLV_ERROR, LOCATION, NULL, - "the peer is not authorized for access.\n"); - vfree(user_id); - return ISAKMP_NTYPE_AUTHENTICATION_FAILED; - } - vfree(user_id); - } else { - plog(LLV_ERROR, LOCATION, NULL, - "the peer is not authorized for access - user ID not found.\n"); - return ISAKMP_NTYPE_AUTHENTICATION_FAILED; + if (oakley_verify_userid(iph1)) { + return ISAKMP_NTYPE_AUTHENTICATION_FAILED; } } -#endif +#endif /* HAVE_OPENDIR */ /* verify certificate */ if (iph1->rmconf->verify_cert && iph1->rmconf->getcert_method == ISAKMP_GETCERT_PAYLOAD) { certtype = iph1->rmconf->certtype; #ifdef ENABLE_HYBRID - switch (iph1->approval->authmethod) { - case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_R: - case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_R: + switch (AUTHMETHOD(iph1)) { + case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I: certtype = iph1->cert_p->type; break; default: @@ -1423,61 +1452,78 @@ oakley_validate_auth(iph1) #endif switch (certtype) { case ISAKMP_CERT_X509SIGN: -#ifdef __APPLE__ - if (iph1->rmconf->cert_verification == VERIFICATION_MODULE_SEC_FRAMEWORK) - error = crypto_cssm_check_x509cert(&iph1->cert_p->cert); - else + { + /* use ID from remote configuration */ + /* check each ID in list */ + struct idspec *id_spec; + CFStringRef hostname = NULL; + char *peers_id; + struct genlist_entry *gpb = NULL; + + if (iph1->rmconf->cert_verification_option == VERIFICATION_OPTION_PEERS_IDENTIFIER) { + id_spec = genlist_next(iph1->rmconf->idvl_p, &gpb); /* expect only one id */ + if (id_spec->idtype == IDTYPE_ADDRESS) { + switch ((ALIGNED_CAST(struct sockaddr_storage *)(id_spec->id->v))->ss_family) { + case AF_INET: + peers_id = inet_ntoa((ALIGNED_CAST(struct sockaddr_in *)(id_spec->id->v))->sin_addr); + hostname = CFStringCreateWithCString(NULL, peers_id, kCFStringEncodingUTF8); + break; +#ifdef INET6 + case AF_INET6: + return ISAKMP_NTYPE_INVALID_ID_INFORMATION; /* not currently supported for embedded */ + break; #endif - { - char path[MAXPATHLEN]; - char *ca; - - if (iph1->rmconf->cacertfile != NULL) { - getpathname(path, sizeof(path), - LC_PATHTYPE_CERT, - iph1->rmconf->cacertfile); - ca = path; - } else { - ca = NULL; - } - - error = eay_check_x509cert(&iph1->cert_p->cert, - lcconf->pathinfo[LC_PATHTYPE_CERT], - ca, 0); + default: + plog(ASL_LEVEL_ERR, + "unknown address type for peers identifier.\n"); + return ISAKMP_NTYPE_AUTHENTICATION_FAILED; + break; + } + } else + hostname = CFStringCreateWithBytes(NULL, (u_int8_t *)id_spec->id->v, id_spec->id->l, kCFStringEncodingUTF8, FALSE); } - break; + error = crypto_cssm_check_x509cert(oakley_get_peer_cert_from_certchain(iph1), iph1->cert_p, hostname, &publicKeyRef); + if (hostname) + CFRelease(hostname); + } + break; default: - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "no supported certtype %d\n", certtype); return ISAKMP_INTERNAL_ERROR; } if (error != 0) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "the peer's certificate is not verified.\n"); return ISAKMP_NTYPE_INVALID_CERT_AUTHORITY; } } + plog(ASL_LEVEL_DEBUG, "CERT validated\n"); - plog(LLV_DEBUG, LOCATION, NULL, "CERT validated\n"); - - /* compute hash */ - switch (iph1->etype) { - case ISAKMP_ETYPE_IDENT: - case ISAKMP_ETYPE_AGG: - my_hash = oakley_ph1hash_common(iph1, VALIDATE); - break; - case ISAKMP_ETYPE_BASE: - if (iph1->side == INITIATOR) - my_hash = oakley_ph1hash_base_r(iph1, VALIDATE); - else - my_hash = oakley_ph1hash_base_i(iph1, VALIDATE); - break; - default: - plog(LLV_ERROR, LOCATION, NULL, - "invalid etype %d\n", iph1->etype); - return ISAKMP_NTYPE_INVALID_EXCHANGE_TYPE; + if (iph1->version == ISAKMP_VERSION_NUMBER_IKEV1) { + /* compute hash */ + switch (iph1->etype) { + case ISAKMP_ETYPE_IDENT: + case ISAKMP_ETYPE_AGG: + my_hash = oakley_ph1hash_common(iph1, VALIDATE); + break; + case ISAKMP_ETYPE_BASE: + if (iph1->side == INITIATOR) + my_hash = oakley_ph1hash_base_r(iph1, VALIDATE); + else + my_hash = oakley_ph1hash_base_i(iph1, VALIDATE); + break; + default: + plog(ASL_LEVEL_ERR, + "invalid etype %d\n", iph1->etype); + return ISAKMP_NTYPE_INVALID_EXCHANGE_TYPE; + } + } else { + vchar_t *octets = NULL; + octets = ikev2_ike_sa_auth_get_octets(iph1, (iph1->side == INITIATOR)? FALSE : TRUE); + my_hash = alg_oakley_hashdef_one(OAKLEY_ATTR_HASH_ALG_SHA, octets); } if (my_hash == NULL) return ISAKMP_INTERNAL_ERROR; @@ -1485,9 +1531,8 @@ oakley_validate_auth(iph1) certtype = iph1->rmconf->certtype; #ifdef ENABLE_HYBRID - switch (iph1->approval->authmethod) { - case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_R: - case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_R: + switch (AUTHMETHOD(iph1)) { + case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I: certtype = iph1->cert_p->type; break; default: @@ -1496,110 +1541,81 @@ oakley_validate_auth(iph1) #endif /* check signature */ switch (certtype) { - case ISAKMP_CERT_X509SIGN: - case ISAKMP_CERT_DNS: - error = eay_check_x509sign(my_hash, - iph1->sig_p, - &iph1->cert_p->cert); - break; - case ISAKMP_CERT_PLAINRSA: - iph1->rsa_p = rsa_try_check_rsasign(my_hash, - iph1->sig_p, iph1->rsa_candidates); - error = iph1->rsa_p ? 0 : -1; - - break; - default: - plog(LLV_ERROR, LOCATION, NULL, - "no supported certtype %d\n", - certtype); - vfree(my_hash); - return ISAKMP_INTERNAL_ERROR; + case ISAKMP_CERT_X509SIGN: + if (publicKeyRef == NULL) { + plog(ASL_LEVEL_ERR, "@@@@@@ publicKeyRef is NULL\n"); + } + if (iph1->version == ISAKMP_VERSION_NUMBER_IKEV1) { + error = crypto_cssm_verify_x509sign(publicKeyRef, my_hash, iph1->sig_p, FALSE); + } else { + error = crypto_cssm_verify_x509sign(publicKeyRef, my_hash, iph1->sig_p, TRUE); + } + if (error) { + plog(ASL_LEVEL_ERR, "error verifying signature %s\n", GetSecurityErrorString(error)); + } + + CFRelease(publicKeyRef); + break; + default: + plog(ASL_LEVEL_ERR, + "no supported certtype %d\n", + certtype); + vfree(my_hash); + return ISAKMP_INTERNAL_ERROR; } vfree(my_hash); if (error != 0) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "Invalid SIG.\n"); return ISAKMP_NTYPE_INVALID_SIGNATURE; } - plog(LLV_DEBUG, LOCATION, NULL, "SIG authenticated\n"); + plog(ASL_LEVEL_DEBUG, "SIG authenticated\n"); } break; #ifdef ENABLE_HYBRID - case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I: - case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I: + case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_R: { if ((iph1->mode_cfg->flags & ISAKMP_CFG_VENDORID_XAUTH) == 0) { - plog(LLV_ERROR, LOCATION, NULL, "No SIG was passed, " + plog(ASL_LEVEL_ERR, "No SIG was passed, " "hybrid auth is enabled, " "but peer is no Xauth compliant\n"); return ISAKMP_NTYPE_SITUATION_NOT_SUPPORTED; break; } - plog(LLV_INFO, LOCATION, NULL, "No SIG was passed, " + plog(ASL_LEVEL_INFO, "No SIG was passed, " "but hybrid auth is enabled\n"); return 0; break; } -#endif -#ifdef HAVE_GSSAPI - case OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB: - switch (iph1->etype) { - case ISAKMP_ETYPE_IDENT: - case ISAKMP_ETYPE_AGG: - my_hash = oakley_ph1hash_common(iph1, VALIDATE); - break; - default: - plog(LLV_ERROR, LOCATION, NULL, - "invalid etype %d\n", iph1->etype); - return ISAKMP_NTYPE_INVALID_EXCHANGE_TYPE; - } - - if (my_hash == NULL) { - if (gssapi_more_tokens(iph1)) - return ISAKMP_NTYPE_INVALID_EXCHANGE_TYPE; - else - return ISAKMP_NTYPE_INVALID_HASH_INFORMATION; - } - - gsshash = gssapi_unwraphash(iph1); - if (gsshash == NULL) { - vfree(my_hash); - return ISAKMP_NTYPE_INVALID_HASH_INFORMATION; - } - - result = memcmp(my_hash->v, gsshash->v, my_hash->l); - vfree(my_hash); - vfree(gsshash); - - if (result) { - plog(LLV_ERROR, LOCATION, NULL, "HASH mismatched\n"); - return ISAKMP_NTYPE_INVALID_HASH_INFORMATION; - } - plog(LLV_DEBUG, LOCATION, NULL, "hash compared OK\n"); - break; #endif case OAKLEY_ATTR_AUTH_METHOD_RSAENC: case OAKLEY_ATTR_AUTH_METHOD_RSAREV: +#ifdef ENABLE_HYBRID + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAENC_I: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAENC_R: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAREV_I: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAREV_R: +#endif if (iph1->id_p == NULL || iph1->pl_hash == NULL) { - plog(LLV_ERROR, LOCATION, iph1->remote, + plog(ASL_LEVEL_ERR, "few isakmp message received.\n"); return ISAKMP_NTYPE_PAYLOAD_MALFORMED; } - plog(LLV_ERROR, LOCATION, iph1->remote, + plog(ASL_LEVEL_ERR, "not supported authmethod type %s\n", s_oakley_attr_method(iph1->approval->authmethod)); return ISAKMP_INTERNAL_ERROR; default: - plog(LLV_ERROR, LOCATION, iph1->remote, + plog(ASL_LEVEL_ERR, "invalid authmethod %d why ?\n", iph1->approval->authmethod); return ISAKMP_INTERNAL_ERROR; } #ifdef ENABLE_STATS gettimeofday(&end, NULL); - syslog(LOG_NOTICE, "%s(%s): %8.6f", __func__, + plog(ASL_LEVEL_NOTICE, "%s(%s): %8.6f", __func__, s_oakley_attr_method(iph1->approval->authmethod), timedelta(&start, &end)); #endif @@ -1607,26 +1623,66 @@ oakley_validate_auth(iph1) return 0; } -/* get my certificate +int +oakley_find_status_in_certchain (cert_t *certchain, cert_status_t certStatus) +{ + cert_t *p; + + for (p = certchain; p; p = p->chain) { + if (p->status == certStatus) { + return 1; + } + } + return 0; +} + +static +int +oakley_vpncontrol_notify_ike_failed_if_mycert_invalid (phase1_handle_t *iph1, int notify_initiator) +{ +#if TARGET_OS_EMBEDDED + int premature = oakley_find_status_in_certchain(iph1->cert, CERT_STATUS_PREMATURE); + int expired = oakley_find_status_in_certchain(iph1->cert, CERT_STATUS_EXPIRED); + if (premature || expired) { + u_int32_t address; + u_int32_t fail_reason; + + if (iph1->remote->ss_family == AF_INET) + address = ((struct sockaddr_in *)(iph1->remote))->sin_addr.s_addr; + else + address = 0; + if (premature) { + fail_reason = VPNCTL_NTYPE_LOCAL_CERT_PREMATURE; + } else { + fail_reason = VPNCTL_NTYPE_LOCAL_CERT_EXPIRED; + } + vpncontrol_notify_ike_failed(fail_reason, notify_initiator, address, 0, NULL); + return -1; + } +#endif /* TARGET_OS_EMBEDDED */ + return 0; +} + +/* get my certificate * NOTE: include certificate type. */ int -oakley_getmycert(iph1) - struct ph1handle *iph1; +oakley_getmycert(phase1_handle_t *iph1) { + int err; + switch (iph1->rmconf->certtype) { case ISAKMP_CERT_X509SIGN: if (iph1->cert) return 0; - return get_cert_fromlocal(iph1, 1); - - case ISAKMP_CERT_PLAINRSA: - if (iph1->rsa) - return 0; - return get_plainrsa_fromlocal(iph1, 1); - + if ( !(err = get_cert_fromlocal(iph1, 1))){ + if (oakley_vpncontrol_notify_ike_failed_if_mycert_invalid(iph1, FROM_LOCAL)) { + return -1; + } + } + return err; default: - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "Unknown certtype #%d\n", iph1->rmconf->certtype); return -1; @@ -1641,67 +1697,43 @@ oakley_getmycert(iph1) * my == 0 peer's cert. */ static int -get_cert_fromlocal(iph1, my) - struct ph1handle *iph1; - int my; +get_cert_fromlocal(phase1_handle_t *iph1, int my) { - char path[MAXPATHLEN]; vchar_t *cert = NULL; cert_t **certpl; - char *certfile; int error = -1; + cert_status_t status = CERT_STATUS_OK; - if (my) { - certfile = iph1->rmconf->mycertfile; + if (my) certpl = &iph1->cert; - } else { - certfile = iph1->rmconf->peerscertfile; + else certpl = &iph1->cert_p; - } - -#ifdef __APPLE__ - if (!certfile && iph1->rmconf->identity_in_keychain == 0) { -#else - if (!certfile) { -#endif - plog(LLV_ERROR, LOCATION, NULL, "no CERT defined.\n"); + if (iph1->rmconf->identity_in_keychain == 0) { + plog(ASL_LEVEL_ERR, "no CERT defined.\n"); return 0; } switch (iph1->rmconf->certtype) { case ISAKMP_CERT_X509SIGN: -#ifdef __APPLE__ if (iph1->rmconf->identity_in_keychain) { CFDataRef dataRef; - if (base64toCFData(iph1->rmconf->keychainCertRef, &dataRef)) + if (iph1->rmconf->keychainCertRef == NULL || base64toCFData(iph1->rmconf->keychainCertRef, &dataRef)) goto end; - cert = crypto_cssm_get_x509cert(dataRef); + cert = crypto_cssm_get_x509cert(dataRef, &status); + plog(ASL_LEVEL_DEBUG, "done with chking cert status %d\n",status); CFRelease(dataRef); break; } // else fall thru -#endif - case ISAKMP_CERT_DNS: - /* make public file name */ - getpathname(path, sizeof(path), LC_PATHTYPE_CERT, certfile); - cert = eay_get_x509cert(path); - if (cert) { - char *p = NULL; - p = eay_get_x509text(cert); - plog(LLV_DEBUG, LOCATION, NULL, "%s", p ? p : "\n"); - racoon_free(p); - }; - break; - default: - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "not supported certtype %d\n", iph1->rmconf->certtype); goto end; } if (!cert) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "failed to get %s CERT.\n", my ? "my" : "peers"); goto end; @@ -1709,13 +1741,13 @@ get_cert_fromlocal(iph1, my) *certpl = oakley_newcert(); if (!*certpl) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "failed to get cert buffer.\n"); goto end; } (*certpl)->pl = vmalloc(cert->l + 1); if ((*certpl)->pl == NULL) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "failed to get cert buffer\n"); oakley_delcert(*certpl); *certpl = NULL; @@ -1724,12 +1756,12 @@ get_cert_fromlocal(iph1, my) memcpy((*certpl)->pl->v + 1, cert->v, cert->l); (*certpl)->pl->v[0] = iph1->rmconf->certtype; (*certpl)->type = iph1->rmconf->certtype; + (*certpl)->status = status; (*certpl)->cert.v = (*certpl)->pl->v + 1; (*certpl)->cert.l = (*certpl)->pl->l - 1; - plog(LLV_DEBUG, LOCATION, NULL, "created CERT payload:\n"); - plogdump(LLV_DEBUG, (*certpl)->pl->v, (*certpl)->pl->l); - + plog(ASL_LEVEL_DEBUG, "created CERT payload\n"); + error = 0; end: @@ -1739,108 +1771,39 @@ end: return error; } -static int -get_plainrsa_fromlocal(iph1, my) - struct ph1handle *iph1; - int my; -{ - char path[MAXPATHLEN]; - vchar_t *cert = NULL; - char *certfile; - int error = -1; - - iph1->rsa_candidates = rsa_lookup_keys(iph1, my); - if (!iph1->rsa_candidates || rsa_list_count(iph1->rsa_candidates) == 0) { - plog(LLV_ERROR, LOCATION, NULL, - "%s RSA key not found for %s\n", - my ? "Private" : "Public", - saddr2str_fromto("%s <-> %s", iph1->local, iph1->remote)); - goto end; - } - - if (my && rsa_list_count(iph1->rsa_candidates) > 1) { - plog(LLV_WARNING, LOCATION, NULL, - "More than one (=%lu) private PlainRSA key found for %s\n", - rsa_list_count(iph1->rsa_candidates), - saddr2str_fromto("%s <-> %s", iph1->local, iph1->remote)); - plog(LLV_WARNING, LOCATION, NULL, - "This may have unpredictable results, i.e. wrong key could be used!\n"); - plog(LLV_WARNING, LOCATION, NULL, - "Consider using only one single private key for all peers...\n"); - } - if (my) { - iph1->rsa = ((struct rsa_key *)genlist_next(iph1->rsa_candidates, NULL))->rsa; - genlist_free(iph1->rsa_candidates, NULL); - iph1->rsa_candidates = NULL; - } - - error = 0; - -end: - return error; -} /* get signature */ int -oakley_getsign(iph1) - struct ph1handle *iph1; +oakley_getsign(phase1_handle_t *iph1) { - char path[MAXPATHLEN]; vchar_t *privkey = NULL; int error = -1; switch (iph1->rmconf->certtype) { case ISAKMP_CERT_X509SIGN: -#ifdef __APPLE__ // cert in keychain - use cssm to sign if (iph1->rmconf->identity_in_keychain) { CFDataRef dataRef; - if (base64toCFData(iph1->rmconf->keychainCertRef, &dataRef)) + if (iph1->rmconf->keychainCertRef == NULL || base64toCFData(iph1->rmconf->keychainCertRef, &dataRef)) goto end; iph1->sig = crypto_cssm_getsign(dataRef, iph1->hash); CFRelease(dataRef); break; } // else fall thru -#endif - case ISAKMP_CERT_DNS: - if (iph1->rmconf->myprivfile == NULL) { - plog(LLV_ERROR, LOCATION, NULL, "no cert defined.\n"); - goto end; - } - - /* make private file name */ - getpathname(path, sizeof(path), - LC_PATHTYPE_CERT, - iph1->rmconf->myprivfile); - privkey = privsep_eay_get_pkcs1privkey(path); - if (privkey == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "failed to get private key.\n"); - goto end; - } - plog(LLV_DEBUG2, LOCATION, NULL, "private key:\n"); - plogdump(LLV_DEBUG2, privkey->v, privkey->l); - - iph1->sig = eay_get_x509sign(iph1->hash, privkey); - break; - case ISAKMP_CERT_PLAINRSA: - iph1->sig = eay_get_rsasign(iph1->hash, iph1->rsa); - break; default: - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "Unknown certtype #%d\n", iph1->rmconf->certtype); goto end; } if (iph1->sig == NULL) { - plog(LLV_ERROR, LOCATION, NULL, "failed to sign.\n"); + plog(ASL_LEVEL_ERR, "failed to sign.\n"); goto end; } - plog(LLV_DEBUG, LOCATION, NULL, "SIGN computed:\n"); - plogdump(LLV_DEBUG, iph1->sig->v, iph1->sig->l); + //plogdump(ASL_LEVEL_DEBUG, iph1->sig->v, iph1->sig->l, "SIGN computed:\n"); error = 0; @@ -1851,114 +1814,218 @@ end: return error; } -#ifdef __APPLE__ +void +oakley_verify_certid(phase1_handle_t *iph1) +{ + if (iph1->rmconf->verify_cert && + oakley_check_certid(iph1)){ + plog(ASL_LEVEL_DEBUG, + "Discarding CERT: does not match ID:\n"); + oakley_delcert(iph1->cert_p); + iph1->cert_p = NULL; + } +} + +static int +oakley_check_certid_in_certchain(cert_t *certchain, int idtype, int idlen, void *id) +{ + cert_t *p; + + for (p = certchain; p; p = p->chain) { + if (oakley_check_certid_1(&p->cert, idtype, idlen, id, &p->status) == 0) { + return 0; + } + } + return ISAKMP_NTYPE_INVALID_ID_INFORMATION; +} + +cert_t * +oakley_get_peer_cert_from_certchain(phase1_handle_t * iph1) +{ + cert_t *p; + struct ipsecdoi_id_b *id_b; + int idlen; + void *peers_id; + + if (!iph1->id_p || !iph1->cert_p) { + plog(ASL_LEVEL_ERR, "no ID nor CERT found.\n"); + return NULL; + } + if (!iph1->cert_p->chain) { + // no chain: simply return the only cert + return iph1->cert_p; + } + + id_b = ALIGNED_CAST(struct ipsecdoi_id_b *)iph1->id_p->v; + peers_id = id_b + 1; + idlen = iph1->id_p->l - sizeof(*id_b); + for (p = iph1->cert_p; p; p = p->chain) { + if (oakley_check_certid_1(&p->cert, id_b->type, idlen, peers_id, &p->status) == 0) { + return p; + } + } + return NULL; +} /* * compare certificate name and ID value. */ static int -oakley_check_certid(iph1, which_id) - struct ph1handle *iph1; - int which_id; +oakley_check_certid(phase1_handle_t *iph1) { struct ipsecdoi_id_b *id_b; int idlen; u_int8_t doi_type = 255; void *peers_id = NULL; - struct genlist_entry *gpb = NULL; - if (which_id == CERT_CHECKID_FROM_PEER) { - /* use ID from peer */ - if (iph1->id_p == NULL || iph1->cert_p == NULL) { - plog(LLV_ERROR, LOCATION, NULL, "no ID nor CERT found.\n"); - return ISAKMP_NTYPE_INVALID_ID_INFORMATION; - } - id_b = (struct ipsecdoi_id_b *)iph1->id_p->v; - doi_type = id_b->type; - peers_id = id_b + 1; - idlen = iph1->id_p->l - sizeof(*id_b); - - return oakley_check_certid_1(iph1, doi_type, idlen, peers_id); + /* use ID from peer */ + if (iph1->id_p == NULL || iph1->cert_p == NULL) { + plog(ASL_LEVEL_ERR, "no ID nor CERT found.\n"); + return ISAKMP_NTYPE_INVALID_ID_INFORMATION; + } + id_b = ALIGNED_CAST(struct ipsecdoi_id_b *)iph1->id_p->v; + doi_type = id_b->type; + peers_id = id_b + 1; + idlen = iph1->id_p->l - sizeof(*id_b); + + return oakley_check_certid_in_certchain(iph1->cert_p, doi_type, idlen, peers_id); - } else { - /* use ID from remote configuration */ - /* check each ID in list */ - struct idspec *id_spec; - - for (id_spec = genlist_next (iph1->rmconf->idvl_p, &gpb); id_spec; id_spec = genlist_next (0, &gpb)) { - - if (id_spec->idtype == IDTYPE_ADDRESS) { - switch (((struct sockaddr *)(id_spec->id->v))->sa_family) { - case AF_INET: - doi_type = IPSECDOI_ID_IPV4_ADDR; - idlen = sizeof(struct in_addr); - peers_id = &(((struct sockaddr_in *)(id_spec->id->v))->sin_addr.s_addr); - break; - #ifdef INET6 - case AF_INET6: - doi_type = IPSECDOI_ID_IPV6_ADDR; - idlen = sizeof(struct in6_addr); - peers_id = &(((struct sockaddr_in6 *)(id_spec->id->v))->sin6_addr.s6_addr); - break; - #endif - default: - plog(LLV_ERROR, LOCATION, NULL, - "unknown address type for peers identifier.\n"); - return ISAKMP_NTYPE_AUTHENTICATION_FAILED; - break; - } - - } else { - doi_type = idtype2doi(id_spec->idtype); - peers_id = id_spec->id->v; - idlen = id_spec->id->l; - } - if (oakley_check_certid_1(iph1, doi_type, idlen, peers_id) == 0) - return 0; - } - return ISAKMP_NTYPE_INVALID_ID_INFORMATION; - } } - + static int -oakley_check_certid_1(iph1, idtype, idlen, id) - struct ph1handle *iph1; - int idtype; - int idlen; - void *id; +oakley_check_certid_1(vchar_t *cert, int idtype, int idlen, void *id, cert_status_t *certStatus) { - vchar_t *name = NULL; - char *altname = NULL; - int type, len; - int error; + int len; + int error = 0; +#if !TARGET_OS_EMBEDDED + int type; + char *altname = NULL; +#endif + switch (idtype) { case IPSECDOI_ID_DER_ASN1_DN: - name = eay_get_x509asn1subjectname(&iph1->cert_p->cert); - if (!name) { - plog(LLV_ERROR, LOCATION, NULL, - "failed to get subjectName\n"); + { + CFDataRef subject; + SecCertificateRef certificate; + UInt8* namePtr; + + certificate = crypto_cssm_x509cert_CreateSecCertificateRef(cert); + if (certificate == NULL) { + plog(ASL_LEVEL_ERR, + "failed to get SecCertificateRef\n"); + if (certStatus && !*certStatus) { + *certStatus = CERT_STATUS_INVALID; + } return ISAKMP_NTYPE_INVALID_CERTIFICATE; - } - if (idlen != name->l) { - plog(LLV_ERROR, LOCATION, NULL, - "Invalid ID length in phase 1.\n"); - vfree(name); - return ISAKMP_NTYPE_INVALID_ID_INFORMATION; - } - error = memcmp(id, name->v, idlen); - vfree(name); - if (error != 0) { - plog(LLV_ERROR, LOCATION, NULL, - "ID mismatched with subjectName.\n"); - return ISAKMP_NTYPE_INVALID_ID_INFORMATION; - } - return 0; + } + subject = crypto_cssm_CopySubjectSequence(certificate); + if (subject == NULL) { + plog(ASL_LEVEL_ERR, "failed to get certificate subjectName\n"); + if (certStatus && !*certStatus) { + *certStatus = CERT_STATUS_INVALID_SUBJNAME; + } + error = ISAKMP_NTYPE_INVALID_CERTIFICATE; + } else { + len = CFDataGetLength(subject); + namePtr = (UInt8*)CFDataGetBytePtr(subject); + if (namePtr) { + if (idlen != len || memcmp(id, namePtr, idlen)) { + plog(ASL_LEVEL_ERR, "ID mismatched with certificate subjectName\n"); + error =ISAKMP_NTYPE_INVALID_ID_INFORMATION; + } + } else { + plog(ASL_LEVEL_ERR, "no certificate subjectName found\n"); + error = ISAKMP_NTYPE_INVALID_CERTIFICATE; + } + } + if (error) { + plog(ASL_LEVEL_ERR, + "ID mismatched with certificate subjectName\n"); + plogdump(ASL_LEVEL_ERR, namePtr, len, "subjectName (type %s):\n", + s_ipsecdoi_ident(idtype)); + plogdump(ASL_LEVEL_ERR, id, idlen, "ID:\n"); + if (certStatus && !*certStatus) { + *certStatus = CERT_STATUS_INVALID_SUBJNAME; + } + } + CFRelease(certificate); + CFRelease(subject); + return 0; + } + break; + case IPSECDOI_ID_IPV4_ADDR: case IPSECDOI_ID_IPV6_ADDR: { - +#if TARGET_OS_EMBEDDED + CFIndex pos, count; + SecCertificateRef certificate; + CFArrayRef addresses; +#define ADDRESS_BUF_SIZE 64 + + certificate = crypto_cssm_x509cert_CreateSecCertificateRef(cert); + if (certificate == NULL) { + plog(ASL_LEVEL_ERR, + "failed to get SecCertificateRef\n"); + if (certStatus && !*certStatus) { + *certStatus = CERT_STATUS_INVALID; + } + return ISAKMP_NTYPE_INVALID_CERTIFICATE; + } + addresses = SecCertificateCopyIPAddresses(certificate); + if (addresses == NULL) { + plog(ASL_LEVEL_ERR, "failed to get subjectName\n"); + if (certStatus && !*certStatus) { + *certStatus = CERT_STATUS_INVALID_SUBJALTNAME; + } + CFRelease(certificate); + return ISAKMP_NTYPE_INVALID_CERTIFICATE; + } + count = CFArrayGetCount(addresses); + for (pos = 0; pos < count; pos++) { + + CFStringRef address; + CFIndex addressLen; + char *addressBuf, numAddress[128]; + int result; + + address = CFArrayGetValueAtIndex(addresses, pos); + addressLen = CFStringGetLength(address); + if (addressLen == 0) + continue; + addressBuf = racoon_malloc(ADDRESS_BUF_SIZE); + if (addressBuf == NULL) { + plog(ASL_LEVEL_ERR, "out of memory\n"); + CFRelease(addresses); + CFRelease(certificate); + return -1; + } + if (CFStringGetCString(address, addressBuf, ADDRESS_BUF_SIZE, kCFStringEncodingUTF8) == TRUE) { + result = inet_pton(idtype == IPSECDOI_ID_IPV4_ADDR ? AF_INET : AF_INET6, addressBuf, numAddress); + racoon_free(addressBuf); + if (result == 0) + continue; // wrong type or invalid address + if (!memcmp(id, numAddress, idtype == IPSECDOI_ID_IPV4_ADDR ? 32 : 128) == 0) { // found a match ? + CFRelease(addresses); + CFRelease(certificate); + return 0; + } + } else + racoon_free(addressBuf); + } + plog(ASL_LEVEL_ERR, "ID mismatched with subjectAltName.\n"); + plog(ASL_LEVEL_ERR, + "subjectAltName (expected type %s):\n", s_ipsecdoi_ident(idtype)); + plogdump(ASL_LEVEL_ERR, id, idlen, "ID:\n"); + CFRelease(addresses); + CFRelease(certificate); + if (certStatus && !*certStatus) { + *certStatus = CERT_STATUS_INVALID_SUBJALTNAME; + } + return ISAKMP_NTYPE_INVALID_ID_INFORMATION; +#else /* * Openssl returns the IPAddress as an ASN1 octet string (binary format) * followed by a trailing NULL. 5 bytes for IPv4 and 17 bytes for IPv6 @@ -1968,22 +2035,30 @@ oakley_check_certid_1(iph1, idtype, idlen, id) int pos; - if (idtype == IPSECDOI_ID_IPV4_ADDR && idlen != sizeof(struct in_addr) - || idtype == IPSECDOI_ID_IPV6_ADDR && idlen != sizeof(struct in6_addr)) { - plog(LLV_ERROR, LOCATION, NULL, + if ((idtype == IPSECDOI_ID_IPV4_ADDR && idlen != sizeof(struct in_addr)) + || (idtype == IPSECDOI_ID_IPV6_ADDR && idlen != sizeof(struct in6_addr))) { + plog(ASL_LEVEL_ERR, "invalid address length passed.\n"); return ISAKMP_NTYPE_INVALID_ID_INFORMATION; } for (pos = 1; ; pos++) { - if (eay_get_x509subjectaltname(&iph1->cert_p->cert, &altname, &type, pos, &len) !=0) { - plog(LLV_ERROR, LOCATION, NULL, + if (eay_get_x509subjectaltname(cert, &altname, &type, pos, &len) !=0) { + plog(ASL_LEVEL_ERR, "failed to get subjectAltName\n"); + if (certStatus && !*certStatus) { + *certStatus = CERT_STATUS_INVALID_SUBJALTNAME; + } return ISAKMP_NTYPE_INVALID_CERTIFICATE; } /* it's the end condition of the loop. */ if (!altname) { + plog(ASL_LEVEL_ERR, + "invalid subjectAltName\n"); + if (certStatus && !*certStatus) { + *certStatus = CERT_STATUS_INVALID_SUBJALTNAME; + } return ISAKMP_NTYPE_INVALID_ID_INFORMATION; } @@ -2014,38 +2089,181 @@ oakley_check_certid_1(iph1, idtype, idlen, id) #endif else { /* invalid IP address length in certificate - bad or bogus certificate */ - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "invalid IP address in certificate.\n"); + plogdump(ASL_LEVEL_ERR, altname, len, "subjectAltName (expected type %s, got type %s):\n", + s_ipsecdoi_ident(idtype), + s_ipsecdoi_ident(type)); racoon_free(altname); altname = NULL; + if (certStatus && !*certStatus) { + *certStatus = CERT_STATUS_INVALID_SUBJALTNAME; + } return ISAKMP_NTYPE_INVALID_CERTIFICATE; } /* compare the addresses */ error = memcmp(id, altname, idlen); + if (error) + continue; racoon_free(altname); - if (error != 0) { - plog(LLV_ERROR, LOCATION, NULL, - "ID mismatched with subjectAltName.\n"); - return ISAKMP_NTYPE_INVALID_ID_INFORMATION; + return 0; + } + /* failed to find a match */ + plog(ASL_LEVEL_ERR, + "ID mismatched with subjectAltName.\n"); + plogdump(ASL_LEVEL_ERR, altname, len, "subjectAltName (expected type %s, got type %s):\n", + s_ipsecdoi_ident(idtype), + s_ipsecdoi_ident(type)); + plogdump(ASL_LEVEL_ERR, id, idlen, "ID:\n"); + racoon_free(altname); + if (certStatus && !*certStatus) + *certStatus = CERT_STATUS_INVALID_SUBJALTNAME; + return ISAKMP_NTYPE_INVALID_ID_INFORMATION; + +#endif /* TARGET_OS_EMBEDDED */ + } + +#if TARGET_OS_EMBEDDED + case IPSECDOI_ID_FQDN: + { + CFIndex pos, count; + SecCertificateRef certificate; + CFArrayRef names; + CFStringRef name, ID; + + certificate = crypto_cssm_x509cert_CreateSecCertificateRef(cert); + if (certificate == NULL) { + plog(ASL_LEVEL_ERR, + "failed to get SecCertificateRef\n"); + if (certStatus && !*certStatus) { + *certStatus = CERT_STATUS_INVALID; } + return ISAKMP_NTYPE_INVALID_CERTIFICATE; + } + names = SecCertificateCopyDNSNames(certificate); + if (names == NULL) { + plog(ASL_LEVEL_ERR, + "failed to get subjectName\n"); + if (certStatus && !*certStatus) { + *certStatus = CERT_STATUS_INVALID_SUBJALTNAME; + } + CFRelease(certificate); + return ISAKMP_NTYPE_INVALID_CERTIFICATE; + } + count = CFArrayGetCount(names); + ID = CFStringCreateWithBytes(kCFAllocatorDefault, id, idlen, kCFStringEncodingUTF8, FALSE); + if (ID== NULL) { + plog(ASL_LEVEL_ERR, "memory error\n"); + CFRelease(names); + CFRelease(certificate); return 0; } + for (pos = 0; pos < count; pos++) { + name = CFArrayGetValueAtIndex(names, pos); + if (CFStringCompare(name, ID, 0) == kCFCompareEqualTo) { + CFRelease(ID); + CFRelease(names); + CFRelease(certificate); + return 0; + } + } + plog(ASL_LEVEL_ERR, "ID mismatched with subjectAltName.\n"); + plog(ASL_LEVEL_ERR, + "subjectAltName (expected type %s):\n", s_ipsecdoi_ident(idtype)); + plogdump(ASL_LEVEL_ERR, id, idlen, "ID:\n"); + CFRelease(ID); + CFRelease(names); + CFRelease(certificate); + if (certStatus && !*certStatus) { + *certStatus = CERT_STATUS_INVALID_SUBJALTNAME; + } + return ISAKMP_NTYPE_INVALID_ID_INFORMATION; + } + + case IPSECDOI_ID_USER_FQDN: + { + CFIndex pos, count; + + SecCertificateRef certificate; + CFArrayRef names; + CFStringRef name, ID; + + certificate = crypto_cssm_x509cert_CreateSecCertificateRef(cert); + if (certificate == NULL) { + plog(ASL_LEVEL_ERR, + "failed to get SecCertificateRef\n"); + if (certStatus && !*certStatus) { + *certStatus = CERT_STATUS_INVALID; + } + return ISAKMP_NTYPE_INVALID_CERTIFICATE; + } + names = SecCertificateCopyRFC822Names(certificate); + if (names == NULL) { + plog(ASL_LEVEL_ERR, + "failed to get subjectName\n"); + if (certStatus && !*certStatus) { + *certStatus = CERT_STATUS_INVALID_SUBJALTNAME; + } + CFRelease(certificate); + return ISAKMP_NTYPE_INVALID_CERTIFICATE; + } + count = CFArrayGetCount(names); + ID = CFStringCreateWithBytes(kCFAllocatorDefault, id, idlen, kCFStringEncodingUTF8, FALSE); + if (ID == NULL) { + plog(ASL_LEVEL_ERR, + "memory error\n"); + if (certStatus && !*certStatus) { + *certStatus = CERT_STATUS_INVALID; + } + CFRelease(names); + CFRelease(certificate); + return ISAKMP_NTYPE_INVALID_CERTIFICATE; + } + for (pos = 0; pos < count; pos++) { + name = CFArrayGetValueAtIndex(names, pos); + if (CFStringCompare(name, ID, 0) == kCFCompareEqualTo) { + CFRelease(ID); + CFRelease(names); + CFRelease(certificate); + return 0; + } + } + plog(ASL_LEVEL_ERR, "ID mismatched with subjectAltName.\n"); + plog(ASL_LEVEL_ERR, + "subjectAltName (expected type %s):\n", s_ipsecdoi_ident(idtype)); + plogdump(ASL_LEVEL_ERR, id, idlen, "ID:\n"); + CFRelease(ID); + CFRelease(names); + CFRelease(certificate); + if (certStatus && !*certStatus) { + *certStatus = CERT_STATUS_INVALID_SUBJALTNAME; + } + return ISAKMP_NTYPE_INVALID_ID_INFORMATION; } +#else case IPSECDOI_ID_FQDN: case IPSECDOI_ID_USER_FQDN: { int pos; for (pos = 1; ; pos++) { - if (eay_get_x509subjectaltname(&iph1->cert_p->cert, &altname, &type, pos, &len) != 0) { - plog(LLV_ERROR, LOCATION, NULL, + if (eay_get_x509subjectaltname(cert, &altname, &type, pos, &len) != 0) { + plog(ASL_LEVEL_ERR, "failed to get subjectAltName\n"); + if (certStatus && !*certStatus) { + *certStatus = CERT_STATUS_INVALID_SUBJALTNAME; + } return ISAKMP_NTYPE_INVALID_CERTIFICATE; } /* it's the end condition of the loop. */ if (!altname) { + plog(ASL_LEVEL_ERR, + "invalid subjectAltName\n"); + if (certStatus && !*certStatus) { + *certStatus = CERT_STATUS_INVALID_SUBJALTNAME; + } return ISAKMP_NTYPE_INVALID_ID_INFORMATION; } @@ -2063,203 +2281,37 @@ oakley_check_certid_1(iph1, idtype, idlen, id) continue; } error = memcmp(id, altname, idlen); + if (error) + continue; racoon_free(altname); - if (error) { - plog(LLV_ERROR, LOCATION, NULL, "ID mismatched.\n"); - return ISAKMP_NTYPE_INVALID_ID_INFORMATION; - } return 0; } + plog(ASL_LEVEL_ERR, "ID mismatched with subjectAltName.\n"); + plog(ASL_LEVEL_ERR, + "subjectAltName (expected type %s, got type %s):\n", + s_ipsecdoi_ident(idtype), + s_ipsecdoi_ident(type)); + plogdump(ASL_LEVEL_ERR, altname, len, "subjectAltName (expected type %s, got type %s):\n", + s_ipsecdoi_ident(idtype), + s_ipsecdoi_ident(type)); + plogdump(ASL_LEVEL_ERR, id, idlen, "ID:\n"); + racoon_free(altname); + if (certStatus && !*certStatus) + *certStatus = CERT_STATUS_INVALID_SUBJALTNAME; + return ISAKMP_NTYPE_INVALID_ID_INFORMATION; } +#endif default: - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "Impropper ID type passed: %s.\n", s_ipsecdoi_ident(idtype)); return ISAKMP_NTYPE_INVALID_ID_INFORMATION; } /*NOTREACHED*/ } - -#else /* __APPLE__ */ - -/* - * compare certificate name and ID value. - */ -static int -oakley_check_certid(iph1) - struct ph1handle *iph1; -{ - struct ipsecdoi_id_b *id_b; - vchar_t *name = NULL; - char *altname = NULL; - int idlen, type; - int error; - - if (iph1->id_p == NULL || iph1->cert_p == NULL) { - plog(LLV_ERROR, LOCATION, NULL, "no ID nor CERT found.\n"); - return ISAKMP_NTYPE_INVALID_ID_INFORMATION; - } - - id_b = (struct ipsecdoi_id_b *)iph1->id_p->v; - idlen = iph1->id_p->l - sizeof(*id_b); - - switch (id_b->type) { - case IPSECDOI_ID_DER_ASN1_DN: - name = eay_get_x509asn1subjectname(&iph1->cert_p->cert); - if (!name) { - plog(LLV_ERROR, LOCATION, NULL, - "failed to get subjectName\n"); - return ISAKMP_NTYPE_INVALID_CERTIFICATE; - } - if (idlen != name->l) { - plog(LLV_ERROR, LOCATION, NULL, - "Invalid ID length in phase 1.\n"); - vfree(name); - return ISAKMP_NTYPE_INVALID_ID_INFORMATION; - } - error = memcmp(id_b + 1, name->v, idlen); - vfree(name); - if (error != 0) { - plog(LLV_ERROR, LOCATION, NULL, - "ID mismatched with subjectAltName.\n"); - return ISAKMP_NTYPE_INVALID_ID_INFORMATION; - } - return 0; - case IPSECDOI_ID_IPV4_ADDR: - case IPSECDOI_ID_IPV6_ADDR: - { - /* - * converting to binary from string because openssl return - * a string even if object is a binary. - * XXX fix it ! access by ASN.1 directly without. - */ - struct addrinfo hints, *res; - caddr_t a = NULL; - int pos; - - for (pos = 1; ; pos++) { - if (eay_get_x509subjectaltname(&iph1->cert_p->cert, - &altname, &type, pos) !=0) { - plog(LLV_ERROR, LOCATION, NULL, - "failed to get subjectAltName\n"); - return ISAKMP_NTYPE_INVALID_CERTIFICATE; - } - - /* it's the end condition of the loop. */ - if (!altname) { - plog(LLV_ERROR, LOCATION, NULL, - "no proper subjectAltName.\n"); - return ISAKMP_NTYPE_INVALID_CERTIFICATE; - } - - if (check_typeofcertname(id_b->type, type) == 0) - break; - - /* next name */ - racoon_free(altname); - altname = NULL; - } - memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_UNSPEC; - hints.ai_socktype = SOCK_RAW; - hints.ai_flags = AI_NUMERICHOST; - error = getaddrinfo(altname, NULL, &hints, &res); - if (error != 0) { - plog(LLV_ERROR, LOCATION, NULL, - "no proper subjectAltName.\n"); - racoon_free(altname); - return ISAKMP_NTYPE_INVALID_CERTIFICATE; - } - switch (res->ai_family) { - case AF_INET: - a = (caddr_t)&((struct sockaddr_in *)res->ai_addr)->sin_addr.s_addr; - break; -#ifdef INET6 - case AF_INET6: - a = (caddr_t)&((struct sockaddr_in6 *)res->ai_addr)->sin6_addr.s6_addr; - break; -#endif - default: - plog(LLV_ERROR, LOCATION, NULL, - "family not supported: %d.\n", res->ai_family); - racoon_free(altname); - freeaddrinfo(res); - return ISAKMP_NTYPE_INVALID_CERTIFICATE; - } - error = memcmp(id_b + 1, a, idlen); - freeaddrinfo(res); - vfree(name); - if (error != 0) { - plog(LLV_ERROR, LOCATION, NULL, - "ID mismatched with subjectAltName.\n"); - return ISAKMP_NTYPE_INVALID_ID_INFORMATION; - } - return 0; - } - case IPSECDOI_ID_FQDN: - case IPSECDOI_ID_USER_FQDN: - { - int pos; - - for (pos = 1; ; pos++) { - if (eay_get_x509subjectaltname(&iph1->cert_p->cert, - &altname, &type, pos) != 0){ - plog(LLV_ERROR, LOCATION, NULL, - "failed to get subjectAltName\n"); - return ISAKMP_NTYPE_INVALID_CERTIFICATE; - } - - /* it's the end condition of the loop. */ - if (!altname) { - plog(LLV_ERROR, LOCATION, NULL, - "no proper subjectAltName.\n"); - return ISAKMP_NTYPE_INVALID_CERTIFICATE; - } - - if (check_typeofcertname(id_b->type, type) == 0) - break; - - /* next name */ - racoon_free(altname); - altname = NULL; - } - if (idlen != strlen(altname)) { - plog(LLV_ERROR, LOCATION, NULL, - "Invalid ID length in phase 1.\n"); - racoon_free(altname); - return ISAKMP_NTYPE_INVALID_ID_INFORMATION; - } - if (check_typeofcertname(id_b->type, type) != 0) { - plog(LLV_ERROR, LOCATION, NULL, - "ID type mismatched. ID: %s CERT: %s.\n", - s_ipsecdoi_ident(id_b->type), - s_ipsecdoi_ident(type)); - racoon_free(altname); - return ISAKMP_NTYPE_INVALID_ID_INFORMATION; - } - error = memcmp(id_b + 1, altname, idlen); - if (error) { - plog(LLV_ERROR, LOCATION, NULL, "ID mismatched.\n"); - racoon_free(altname); - return ISAKMP_NTYPE_INVALID_ID_INFORMATION; - } - racoon_free(altname); - return 0; - } - default: - plog(LLV_ERROR, LOCATION, NULL, - "Impropper ID type passed: %s.\n", - s_ipsecdoi_ident(id_b->type)); - return ISAKMP_NTYPE_INVALID_ID_INFORMATION; - } - /*NOTREACHED*/ -} - -#endif /* __APPLE__ */ - +#ifdef HAVE_OPENSSL static int -check_typeofcertname(doi, genid) - int doi, genid; +check_typeofcertname(int doi, int genid) { switch (doi) { case IPSECDOI_ID_IPV4_ADDR: @@ -2287,196 +2339,55 @@ check_typeofcertname(doi, genid) } /*NOTREACHED*/ } +#endif /* * save certificate including certificate type. */ int -oakley_savecert(iph1, gen) - struct ph1handle *iph1; - struct isakmp_gen *gen; +oakley_savecert(phase1_handle_t *iph1, struct isakmp_gen *gen) { cert_t **c; u_int8_t type; - STACK_OF(X509) *certs=NULL; - PKCS7 *p7; - - type = *(u_int8_t *)(gen + 1) & 0xff; - - switch (type) { - case ISAKMP_CERT_DNS: - plog(LLV_WARNING, LOCATION, NULL, - "CERT payload is unnecessary in DNSSEC. " - "ignore this CERT payload.\n"); - return 0; - case ISAKMP_CERT_PKCS7: - case ISAKMP_CERT_PGP: - case ISAKMP_CERT_X509SIGN: - case ISAKMP_CERT_KERBEROS: - case ISAKMP_CERT_SPKI: - c = &iph1->cert_p; - break; - case ISAKMP_CERT_CRL: - c = &iph1->crl_p; - break; - case ISAKMP_CERT_X509KE: - case ISAKMP_CERT_X509ATTR: - case ISAKMP_CERT_ARL: - plog(LLV_ERROR, LOCATION, NULL, - "No supported such CERT type %d\n", type); - return -1; - default: - plog(LLV_ERROR, LOCATION, NULL, - "Invalid CERT type %d\n", type); - return -1; - } - - /* XXX choice the 1th cert, ignore after the cert. */ - /* XXX should be processed. */ - if (*c) { - plog(LLV_WARNING, LOCATION, NULL, - "ignore 2nd CERT payload.\n"); - return 0; - } - - if (type == ISAKMP_CERT_PKCS7) { - u_char *bp; - int i; - - /* Skip the header */ - bp = (u_char *)(gen + 1); - /* And the first byte is the certificate type, - * we know that already - */ - bp++; - p7 = d2i_PKCS7(NULL, (void *)&bp, - ntohs(gen->len) - sizeof(*gen) - 1); - - if (!p7) { - plog(LLV_ERROR, LOCATION, NULL, - "Failed to parse PKCS#7 CERT.\n"); - return -1; - } - - /* Copied this from the openssl pkcs7 application; - * there"s little by way of documentation for any of - * it. I can only presume it"s correct. - */ - - i = OBJ_obj2nid(p7->type); - switch (i) { - case NID_pkcs7_signed: - certs=p7->d.sign->cert; - break; - case NID_pkcs7_signedAndEnveloped: - certs=p7->d.signed_and_enveloped->cert; - break; - default: - break; - } - - if (!certs) { - plog(LLV_ERROR, LOCATION, NULL, - "CERT PKCS#7 bundle contains no certs.\n"); - PKCS7_free(p7); - return -1; - } - - for (i = 0; i < sk_X509_num(certs); i++) { - int len; - u_char *bp; - X509 *cert = sk_X509_value(certs,i); - - plog(LLV_DEBUG, LOCATION, NULL, - "Trying PKCS#7 cert %d.\n", i); - - /* We'll just try each cert in turn */ - *c = save_certx509(cert); - - if (!*c) { - plog(LLV_ERROR, LOCATION, NULL, - "Failed to get CERT buffer.\n"); - continue; - } - - /* Ignore cert if it doesn't match identity - * XXX If verify cert is disabled, we still just take - * the first certificate.... - */ - if(iph1->rmconf->verify_cert && - oakley_check_certid(iph1, CERT_CHECKID_FROM_PEER)) { - plog(LLV_DEBUG, LOCATION, NULL, - "Discarding CERT: does not match ID.\n"); - oakley_delcert((*c)); - *c = NULL; - continue; - } - - { - char *p = eay_get_x509text(&(*c)->cert); - plog(LLV_DEBUG, LOCATION, NULL, "CERT saved:\n"); - plogdump(LLV_DEBUG, (*c)->cert.v, (*c)->cert.l); - plog(LLV_DEBUG, LOCATION, NULL, "%s", - p ? p : "\n"); - racoon_free(p); - } - break; - } - PKCS7_free(p7); - - } else { - *c = save_certbuf(gen); - if (!*c) { - plog(LLV_ERROR, LOCATION, NULL, - "Failed to get CERT buffer.\n"); - return -1; - } + type = *(u_int8_t *)(gen + 1) & 0xff; - switch ((*c)->type) { - case ISAKMP_CERT_DNS: - plog(LLV_WARNING, LOCATION, NULL, - "CERT payload is unnecessary in DNSSEC. " - "ignore it.\n"); - return 0; - case ISAKMP_CERT_PGP: - case ISAKMP_CERT_X509SIGN: - case ISAKMP_CERT_KERBEROS: - case ISAKMP_CERT_SPKI: - /* Ignore cert if it doesn't match identity - * XXX If verify cert is disabled, we still just take - * the first certificate.... - */ - if(iph1->rmconf->verify_cert && - oakley_check_certid(iph1, CERT_CHECKID_FROM_PEER)){ - plog(LLV_DEBUG, LOCATION, NULL, - "Discarding CERT: does not match ID.\n"); - oakley_delcert((*c)); - *c = NULL; - return 0; - } + switch (type) { + case ISAKMP_CERT_X509SIGN: + c = &iph1->cert_p; + break; + default: + plog(ASL_LEVEL_ERR, + "Invalid CERT type %d\n", type); + return -1; + } - { - char *p = eay_get_x509text(&(*c)->cert); - plog(LLV_DEBUG, LOCATION, NULL, "CERT saved:\n"); - plogdump(LLV_DEBUG, (*c)->cert.v, (*c)->cert.l); - plog(LLV_DEBUG, LOCATION, NULL, "%s", p ? p : "\n"); - racoon_free(p); - } - break; - case ISAKMP_CERT_CRL: - plog(LLV_DEBUG, LOCATION, NULL, "CRL saved:\n"); - plogdump(LLV_DEBUG, (*c)->cert.v, (*c)->cert.l); - break; - case ISAKMP_CERT_X509KE: - case ISAKMP_CERT_X509ATTR: - case ISAKMP_CERT_ARL: - default: - /* XXX */ - oakley_delcert((*c)); - *c = NULL; - return 0; - } + if (*c) { + plog(ASL_LEVEL_WARNING, + "preexisting CERT payload... chaining.\n"); } + + cert_t *new; + new = save_certbuf(gen); + if (!new) { + plog(ASL_LEVEL_ERR, + "Failed to get CERT buffer.\n"); + return -1; + } + + switch (new->type) { + case ISAKMP_CERT_X509SIGN: + /* Ignore cert if it doesn't match identity + * XXX If verify cert is disabled, we still just take + * the first certificate.... + */ + *c = oakley_appendcert_to_certchain(*c, new); + plog(ASL_LEVEL_DEBUG, "CERT saved:\n"); + break; + default: + /* XXX */ + oakley_delcert(new); + return 0; + } return 0; } @@ -2485,69 +2396,61 @@ oakley_savecert(iph1, gen) * save certificate including certificate type. */ int -oakley_savecr(iph1, gen) - struct ph1handle *iph1; - struct isakmp_gen *gen; +oakley_savecr(phase1_handle_t *iph1, struct isakmp_gen *gen) { cert_t **c; u_int8_t type; + cert_t *new; type = *(u_int8_t *)(gen + 1) & 0xff; switch (type) { - case ISAKMP_CERT_DNS: - plog(LLV_WARNING, LOCATION, NULL, - "CERT payload is unnecessary in DNSSEC\n"); - /*FALLTHRU*/ - case ISAKMP_CERT_PKCS7: - case ISAKMP_CERT_PGP: case ISAKMP_CERT_X509SIGN: - case ISAKMP_CERT_KERBEROS: - case ISAKMP_CERT_SPKI: + if (iph1->cr_p) { + oakley_delcert(iph1->cr_p); + iph1->cr_p = NULL; + } c = &iph1->cr_p; break; - case ISAKMP_CERT_X509KE: - case ISAKMP_CERT_X509ATTR: - case ISAKMP_CERT_ARL: - plog(LLV_ERROR, LOCATION, NULL, - "No supported such CR type %d\n", type); - return -1; - case ISAKMP_CERT_CRL: default: - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "Invalid CR type %d\n", type); return -1; } - *c = save_certbuf(gen); - if (!*c) { - plog(LLV_ERROR, LOCATION, NULL, + new = save_certbuf(gen); + if (!new) { + plog(ASL_LEVEL_ERR, "Failed to get CR buffer.\n"); return -1; } - - plog(LLV_DEBUG, LOCATION, NULL, "CR saved:\n"); - plogdump(LLV_DEBUG, (*c)->cert.v, (*c)->cert.l); + *c = oakley_appendcert_to_certchain(*c, new); + plog(ASL_LEVEL_DEBUG, "CR saved\n"); return 0; } static cert_t * -save_certbuf(gen) - struct isakmp_gen *gen; +save_certbuf(struct isakmp_gen *gen) { cert_t *new; + if(ntohs(gen->len) <= sizeof(*gen)){ + plog(ASL_LEVEL_ERR, + "Len is too small !!.\n"); + return NULL; + } + new = oakley_newcert(); if (!new) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "Failed to get CERT buffer.\n"); return NULL; } new->pl = vmalloc(ntohs(gen->len) - sizeof(*gen)); if (new->pl == NULL) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "Failed to copy CERT from packet.\n"); oakley_delcert(new); new = NULL; @@ -2561,39 +2464,6 @@ save_certbuf(gen) return new; } -static cert_t * -save_certx509(cert) - X509 *cert; -{ - cert_t *new; - int len; - u_char *bp; - - new = oakley_newcert(); - if (!new) { - plog(LLV_ERROR, LOCATION, NULL, - "Failed to get CERT buffer.\n"); - return NULL; - } - - len = i2d_X509(cert, NULL); - new->pl = vmalloc(len); - if (new->pl == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "Failed to copy CERT from packet.\n"); - oakley_delcert(new); - new = NULL; - return NULL; - } - bp = (u_char *) new->pl->v; - len = i2d_X509(cert, &bp); - new->type = ISAKMP_CERT_X509SIGN; - new->cert.v = new->pl->v; - new->cert.l = new->pl->l; - - return new; -} - /* * get my CR. * NOTE: No Certificate Authority field is included to CR payload at the @@ -2602,23 +2472,27 @@ save_certx509(cert) * if there is no specific certificate authority requested. */ vchar_t * -oakley_getcr(iph1) - struct ph1handle *iph1; +oakley_getcr(phase1_handle_t *iph1) { vchar_t *buf; buf = vmalloc(1); if (buf == NULL) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "failed to get cr buffer\n"); return NULL; } - buf->v[0] = iph1->rmconf->certtype; - - plog(LLV_DEBUG, LOCATION, NULL, "create my CR: %s\n", + if(iph1->rmconf->certtype == ISAKMP_CERT_NONE) { + buf->v[0] = iph1->rmconf->cacerttype; + plog(ASL_LEVEL_DEBUG, "create my CR: NONE, using %s instead\n", + s_isakmp_certtype(iph1->rmconf->cacerttype)); + } else { + buf->v[0] = iph1->rmconf->certtype; + plog(ASL_LEVEL_DEBUG, "create my CR: %s\n", s_isakmp_certtype(iph1->rmconf->certtype)); - if (buf->l > 1) - plogdump(LLV_DEBUG, buf->v, buf->l); + } + //if (buf->l > 1) + // plogdump(ASL_LEVEL_DEBUG, buf->v, buf->l, ""); return buf; } @@ -2627,18 +2501,17 @@ oakley_getcr(iph1) * check peer's CR. */ int -oakley_checkcr(iph1) - struct ph1handle *iph1; +oakley_checkcr(phase1_handle_t *iph1) { if (iph1->cr_p == NULL) return 0; - plog(LLV_DEBUG, LOCATION, iph1->remote, + plog(ASL_LEVEL_DEBUG, "peer transmitted CR: %s\n", s_isakmp_certtype(iph1->cr_p->type)); if (iph1->cr_p->type != iph1->rmconf->certtype) { - plog(LLV_ERROR, LOCATION, iph1->remote, + plog(ASL_LEVEL_ERR, "such a cert type isn't supported: %d\n", (char)iph1->cr_p->type); return -1; @@ -2651,15 +2524,14 @@ oakley_checkcr(iph1) * check to need CR payload. */ int -oakley_needcr(type) - int type; +oakley_needcr(int type) { switch (type) { - case OAKLEY_ATTR_AUTH_METHOD_DSSSIG: case OAKLEY_ATTR_AUTH_METHOD_RSASIG: #ifdef ENABLE_HYBRID case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I: - case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_I: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_R: #endif return 1; default: @@ -2668,6 +2540,63 @@ oakley_needcr(type) /*NOTREACHED*/ } +vchar_t * +oakley_getpskall(phase1_handle_t *iph1) +{ + vchar_t *secret = NULL; + + if (iph1->rmconf->shared_secret) { + + switch (iph1->rmconf->secrettype) { + case SECRETTYPE_KEY: + /* in psk file - use KEY from remote configuration to locate it */ + secret = getpsk(iph1->rmconf->shared_secret->v, iph1->rmconf->shared_secret->l-1); + break; +#if HAVE_KEYCHAIN + case SECRETTYPE_KEYCHAIN: + /* in the system keychain */ + secret = getpskfromkeychain(iph1->rmconf->shared_secret->v, iph1->etype, iph1->rmconf->secrettype, NULL); + break; + case SECRETTYPE_KEYCHAIN_BY_ID: + /* in the system keychain - use peer id */ + secret = getpskfromkeychain(iph1->rmconf->shared_secret->v, iph1->etype, iph1->rmconf->secrettype, iph1->id_p); + break; +#endif // HAVE_KEYCHAIN + case SECRETTYPE_USE: + /* in the remote configuration */ + default: + /* rmconf->shared_secret is a string and contains a NULL character that must be removed */ + secret = vmalloc(iph1->rmconf->shared_secret->l - 1); + if (secret == NULL) { + plog(ASL_LEVEL_ERR, "memory error.\n"); + goto end; + } + memcpy(secret->v, iph1->rmconf->shared_secret->v, secret->l); + } + } else if (iph1->version == ISAKMP_VERSION_NUMBER_IKEV2 || + iph1->etype != ISAKMP_ETYPE_IDENT) { + secret = getpskbyname(iph1->id_p); + if (!secret) { + if (iph1->rmconf->verify_identifier) { + plog(ASL_LEVEL_ERR, "couldn't find pskey by peer's ID.\n"); + goto end; + } + } + } + if (!secret) { + plog(ASL_LEVEL_NOTICE, "try to get pskey by the peer's address.\n"); + secret = getpskbyaddr(iph1->remote); + if (!secret) { + plog(ASL_LEVEL_ERR, + "couldn't find the pskey by address %s.\n", + saddrwop2str((struct sockaddr *)iph1->remote)); + } + } + +end: + return secret; +} + /* * compute SKEYID * see seciton 5. Exchanges in RFC 2409 @@ -2676,188 +2605,231 @@ oakley_needcr(type) * enc: SKEYID = prf(H(Ni_b | Nr_b), CKY-I | CKY-R) */ int -oakley_skeyid(iph1) - struct ph1handle *iph1; +oakley_skeyid(phase1_handle_t *iph1) { - vchar_t *buf = NULL, *bp; + vchar_t *key = NULL; + vchar_t *buf = NULL; + vchar_t *bp; char *p; int len; int error = -1; - + + /* SKEYID */ - switch(iph1->approval->authmethod) { - case OAKLEY_ATTR_AUTH_METHOD_PSKEY: -#ifdef __APPLE__ - if (iph1->rmconf->shared_secret) { - - switch (iph1->rmconf->secrettype) { - case SECRETTYPE_KEY: - /* in psk file - use KEY from remote configuration to locate it */ - iph1->authstr = getpsk(iph1->rmconf->shared_secret->v, iph1->rmconf->shared_secret->l-1); - break; - case SECRETTYPE_KEYCHAIN: - /* in the system keychain */ - iph1->authstr = getpskfromkeychain(iph1->rmconf->shared_secret->v, iph1->etype, iph1->rmconf->secrettype, NULL); - break; - case SECRETTYPE_KEYCHAIN_BY_ID: - /* in the system keychain - use peer id */ - iph1->authstr = getpskfromkeychain(iph1->rmconf->shared_secret->v, iph1->etype, iph1->rmconf->secrettype, iph1->id_p); - break; - case SECRETTYPE_USE: - /* in the remote configuration */ - default: - iph1->authstr = vdup(iph1->rmconf->shared_secret); - } - - } - else + switch (AUTHMETHOD(iph1)) { + case OAKLEY_ATTR_AUTH_METHOD_PSKEY: +#ifdef ENABLE_HYBRID + case FICTIVE_AUTH_METHOD_XAUTH_PSKEY_I: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_R: #endif - if (iph1->etype != ISAKMP_ETYPE_IDENT) { - iph1->authstr = getpskbyname(iph1->id_p); - if (iph1->authstr == NULL) { - if (iph1->rmconf->verify_identifier) { - plog(LLV_ERROR, LOCATION, iph1->remote, - "couldn't find the pskey.\n"); - goto end; - } - plog(LLV_NOTIFY, LOCATION, iph1->remote, - "couldn't find the proper pskey, " - "try to get one by the peer's address.\n"); - } - } - if (iph1->authstr == NULL) { - /* - * If the exchange type is the main mode or if it's - * failed to get the psk by ID, racoon try to get - * the psk by remote IP address. - * It may be nonsense. - */ - iph1->authstr = getpskbyaddr(iph1->remote); - if (iph1->authstr == NULL) { - plog(LLV_ERROR, LOCATION, iph1->remote, - "couldn't find the pskey for %s.\n", - saddrwop2str(iph1->remote)); - goto end; - } - } - plog(LLV_DEBUG, LOCATION, NULL, "the psk found.\n"); - /* should be secret PSK */ - plog(LLV_DEBUG2, LOCATION, NULL, "psk: "); - plogdump(LLV_DEBUG2, iph1->authstr->v, iph1->authstr->l); - - len = iph1->nonce->l + iph1->nonce_p->l; - buf = vmalloc(len); - if (buf == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "failed to get skeyid buffer\n"); - goto end; - } - p = buf->v; - - bp = (iph1->side == INITIATOR ? iph1->nonce : iph1->nonce_p); - plog(LLV_DEBUG, LOCATION, NULL, "nonce 1: "); - plogdump(LLV_DEBUG, bp->v, bp->l); - memcpy(p, bp->v, bp->l); - p += bp->l; - - bp = (iph1->side == INITIATOR ? iph1->nonce_p : iph1->nonce); - plog(LLV_DEBUG, LOCATION, NULL, "nonce 2: "); - plogdump(LLV_DEBUG, bp->v, bp->l); - memcpy(p, bp->v, bp->l); - p += bp->l; - - iph1->skeyid = oakley_prf(iph1->authstr, buf, iph1); - if (iph1->skeyid == NULL) - goto end; - break; - - case OAKLEY_ATTR_AUTH_METHOD_DSSSIG: - case OAKLEY_ATTR_AUTH_METHOD_RSASIG: + key = oakley_getpskall(iph1); + if (key == NULL) { + plog(ASL_LEVEL_ERR, + "couldn't find the pskey for %s.\n", + saddrwop2str((struct sockaddr *)iph1->remote)); + goto end; + } + plog(ASL_LEVEL_DEBUG, "the psk found.\n"); + /* should be secret PSK */ + plogdump(ASL_LEVEL_DEBUG, key->v, key->l, "psk: "); + + len = iph1->nonce->l + iph1->nonce_p->l; + buf = vmalloc(len); + if (buf == NULL) { + plog(ASL_LEVEL_ERR, + "failed to get skeyid buffer\n"); + goto end; + } + p = buf->v; + + bp = (iph1->side == INITIATOR ? iph1->nonce : iph1->nonce_p); + //plogdump(ASL_LEVEL_DEBUG, bp->v, bp->l, "nonce 1: "); + memcpy(p, bp->v, bp->l); + p += bp->l; + + bp = (iph1->side == INITIATOR ? iph1->nonce_p : iph1->nonce); + //plogdump(ASL_LEVEL_DEBUG, bp->v, bp->l, "nonce 2: "); + memcpy(p, bp->v, bp->l); + p += bp->l; + + iph1->skeyid = oakley_prf(key, buf, iph1); + + if (iph1->skeyid == NULL) + goto end; + break; + + case OAKLEY_ATTR_AUTH_METHOD_RSASIG: #ifdef ENABLE_HYBRID - case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I: - case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I: - case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_R: - case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_R: + case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I: + case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_R: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_I: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_R: #endif -#ifdef HAVE_GSSAPI - case OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB: + len = iph1->nonce->l + iph1->nonce_p->l; + buf = vmalloc(len); + if (buf == NULL) { + plog(ASL_LEVEL_ERR, + "failed to get nonce buffer\n"); + goto end; + } + p = buf->v; + + bp = (iph1->side == INITIATOR ? iph1->nonce : iph1->nonce_p); + //plogdump(ASL_LEVEL_DEBUG, bp->v, bp->l, "nonce1: "); + memcpy(p, bp->v, bp->l); + p += bp->l; + + bp = (iph1->side == INITIATOR ? iph1->nonce_p : iph1->nonce); + //plogdump(ASL_LEVEL_DEBUG, bp->v, bp->l, "nonce2: "); + memcpy(p, bp->v, bp->l); + p += bp->l; + + iph1->skeyid = oakley_prf(buf, iph1->dhgxy, iph1); + if (iph1->skeyid == NULL) + goto end; + break; + case OAKLEY_ATTR_AUTH_METHOD_RSAENC: + case OAKLEY_ATTR_AUTH_METHOD_RSAREV: +#ifdef ENABLE_HYBRID + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAENC_I: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAENC_R: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAREV_I: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAREV_R: #endif - len = iph1->nonce->l + iph1->nonce_p->l; - buf = vmalloc(len); - if (buf == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "failed to get nonce buffer\n"); - goto end; - } - p = buf->v; - - bp = (iph1->side == INITIATOR ? iph1->nonce : iph1->nonce_p); - plog(LLV_DEBUG, LOCATION, NULL, "nonce1: "); - plogdump(LLV_DEBUG, bp->v, bp->l); - memcpy(p, bp->v, bp->l); - p += bp->l; + plog(ASL_LEVEL_WARNING, + "not supported authentication method %s\n", + s_oakley_attr_method(iph1->approval->authmethod)); + goto end; + default: + plog(ASL_LEVEL_ERR, + "invalid authentication method %d\n", + iph1->approval->authmethod); + goto end; + } + + //plogdump(ASL_LEVEL_DEBUG, iph1->skeyid->v, iph1->skeyid->l, "IKEv1 SKEYID computed:\n"); + + error = 0; + +end: + if (key != NULL) + vfree(key); + if (buf != NULL) + vfree(buf); + return error; +} - bp = (iph1->side == INITIATOR ? iph1->nonce_p : iph1->nonce); - plog(LLV_DEBUG, LOCATION, NULL, "nonce2: "); - plogdump(LLV_DEBUG, bp->v, bp->l); - memcpy(p, bp->v, bp->l); - p += bp->l; +static vchar_t * +oakley_prf_plus (vchar_t *key, vchar_t *buf, int result_len, phase1_handle_t *iph1) +{ + vchar_t *t = 0; + uint8_t byte_value; + vchar_t *result = 0; + uint8_t *p; + vchar_t *bp; + int bp_len; + uint8_t *tmp; + vchar_t *prf; + + /* + * (draft-17) + prf+ (K,S) = T1 | T2 | T3 | T4 | ... + + where: + T1 = prf (K, S | 0x01) + T2 = prf (K, T1 | S | 0x02) + T3 = prf (K, T2 | S | 0x03) + T4 = prf (K, T3 | S | 0x04) + */ - iph1->skeyid = oakley_prf(buf, iph1->dhgxy, iph1); - if (iph1->skeyid == NULL) - goto end; - break; - case OAKLEY_ATTR_AUTH_METHOD_RSAENC: - case OAKLEY_ATTR_AUTH_METHOD_RSAREV: - plog(LLV_WARNING, LOCATION, NULL, - "not supported authentication method %s\n", - s_oakley_attr_method(iph1->approval->authmethod)); - goto end; - default: - plog(LLV_ERROR, LOCATION, NULL, - "invalid authentication method %d\n", - iph1->approval->authmethod); - goto end; + if (!(result = vmalloc(result_len))) { + return NULL; } - plog(LLV_DEBUG, LOCATION, NULL, "SKEYID computed:\n"); - plogdump(LLV_DEBUG, iph1->skeyid->v, iph1->skeyid->l); + /* + * initial T0 = empty + */ + t = 0; + p = (uint8_t *)result->v; + for (byte_value = 1; result_len > 0; ++byte_value) { + /* + * prf_output = prf(K, Ti-1 | S | byte) + */ + bp_len = buf->l + sizeof(byte_value); + if (t) { + bp_len += t->l; + } + bp = vmalloc(bp_len); + if (!bp) { + return NULL; + } + tmp = (__typeof__(tmp))bp->v; + + if (t) { + memcpy(tmp, t->v, t->l); + tmp += t->l; + } + memcpy(tmp, buf->v, buf->l); + tmp += buf->l; + memcpy(tmp, &byte_value, sizeof(byte_value)); + tmp += sizeof(byte_value); - error = 0; + if (!(prf = oakley_prf(key, bp, iph1))) { + VPTRINIT(bp); + return (vchar_t *)-1; + } + VPTRINIT(bp); -end: - if (buf != NULL) - vfree(buf); - return error; + /* + * concat prf_output + */ + memcpy(p, prf->v, prf->l > (size_t)result_len ? (size_t)result_len : prf->l); + p += prf->l; + result_len -= prf->l; + + /* + * Ti = prf_output + */ + if (t) { + bzero(t->v, t->l); + vfree(t); + } + t = prf; + } + if (t) { + bzero(t->v, t->l); + vfree(t); + } + return result; } /* * compute SKEYID_[dae] - * see seciton 5. Exchanges in RFC 2409 - * SKEYID_d = prf(SKEYID, g^ir | CKY-I | CKY-R | 0) - * SKEYID_a = prf(SKEYID, SKEYID_d | g^ir | CKY-I | CKY-R | 1) - * SKEYID_e = prf(SKEYID, SKEYID_a | g^ir | CKY-I | CKY-R | 2) */ int -oakley_skeyid_dae(iph1) - struct ph1handle *iph1; +oakley_skeyid_dae(phase1_handle_t *iph1) { - vchar_t *buf = NULL; + vchar_t *buf = NULL, *bp = NULL; char *p; int len; int error = -1; if (iph1->skeyid == NULL) { - plog(LLV_ERROR, LOCATION, NULL, "no SKEYID found.\n"); + plog(ASL_LEVEL_ERR, "no SKEYID found.\n"); goto end; } - + /* + * see seciton 5. Exchanges in RFC 2409 + * SKEYID_d = prf(SKEYID, g^ir | CKY-I | CKY-R | 0) + * SKEYID_a = prf(SKEYID, SKEYID_d | g^ir | CKY-I | CKY-R | 1) + * SKEYID_e = prf(SKEYID, SKEYID_a | g^ir | CKY-I | CKY-R | 2) + */ /* SKEYID D */ /* SKEYID_d = prf(SKEYID, g^xy | CKY-I | CKY-R | 0) */ len = iph1->dhgxy->l + sizeof(cookie_t) * 2 + 1; buf = vmalloc(len); if (buf == NULL) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "failed to get skeyid buffer\n"); goto end; } @@ -2877,15 +2849,14 @@ oakley_skeyid_dae(iph1) vfree(buf); buf = NULL; - plog(LLV_DEBUG, LOCATION, NULL, "SKEYID_d computed:\n"); - plogdump(LLV_DEBUG, iph1->skeyid_d->v, iph1->skeyid->l); + //plogdump(ASL_LEVEL_DEBUG, iph1->skeyid_d->v, iph1->skeyid_d->l, "SKEYID_d computed:\n"); /* SKEYID A */ /* SKEYID_a = prf(SKEYID, SKEYID_d | g^xy | CKY-I | CKY-R | 1) */ len = iph1->skeyid_d->l + iph1->dhgxy->l + sizeof(cookie_t) * 2 + 1; buf = vmalloc(len); if (buf == NULL) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "failed to get skeyid buffer\n"); goto end; } @@ -2906,15 +2877,14 @@ oakley_skeyid_dae(iph1) vfree(buf); buf = NULL; - plog(LLV_DEBUG, LOCATION, NULL, "SKEYID_a computed:\n"); - plogdump(LLV_DEBUG, iph1->skeyid_a->v, iph1->skeyid_a->l); + //plogdump(ASL_LEVEL_DEBUG, iph1->skeyid_a->v, iph1->skeyid_a->l, "SKEYID_a computed:\n"); /* SKEYID E */ /* SKEYID_e = prf(SKEYID, SKEYID_a | g^xy | CKY-I | CKY-R | 2) */ len = iph1->skeyid_a->l + iph1->dhgxy->l + sizeof(cookie_t) * 2 + 1; buf = vmalloc(len); if (buf == NULL) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "failed to get skeyid buffer\n"); goto end; } @@ -2935,8 +2905,7 @@ oakley_skeyid_dae(iph1) vfree(buf); buf = NULL; - plog(LLV_DEBUG, LOCATION, NULL, "SKEYID_e computed:\n"); - plogdump(LLV_DEBUG, iph1->skeyid_e->v, iph1->skeyid_e->l); + //plogdump(ASL_LEVEL_DEBUG, iph1->skeyid_e->v, iph1->skeyid_e->l, "SKEYID_e computed:\n"); error = 0; @@ -2951,8 +2920,7 @@ end: * see Appendix B. */ int -oakley_compute_enckey(iph1) - struct ph1handle *iph1; +oakley_compute_enckey(phase1_handle_t *iph1) { u_int keylen, prflen; int error = -1; @@ -2961,7 +2929,7 @@ oakley_compute_enckey(iph1) keylen = alg_oakley_encdef_keylen(iph1->approval->enctype, iph1->approval->encklen); if (keylen == -1) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "invalid encryption algoritym %d, " "or invalid key length %d.\n", iph1->approval->enctype, @@ -2970,15 +2938,52 @@ oakley_compute_enckey(iph1) } iph1->key = vmalloc(keylen >> 3); if (iph1->key == NULL) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "failed to get key buffer\n"); goto end; } + if (iph1->version == ISAKMP_VERSION_NUMBER_IKEV2) { + iph1->key_p = vmalloc(keylen >> 3); + if (iph1->key_p == NULL) { + plog(ASL_LEVEL_ERR, + "failed to get key buffer\n"); + goto end; + } + + if (iph1->key->l <= iph1->skeyid_e->l) { + plog(ASL_LEVEL_DEBUG, + "%s setting key len %zd, val %d (len %zd)", __FUNCTION__, iph1->key->l, (int)iph1->skeyid_e->v[0], iph1->skeyid_e->l); + /* + * if length(Ka) <= length(SKEYID_e) + * Ka = first length(K) bit of SKEYID_e + */ + memcpy(iph1->key->v, iph1->skeyid_e->v, iph1->key->l); + } else { + plog(ASL_LEVEL_ERR, + "unexpected key length error (exp %zd, got %zd)", + iph1->key->l, iph1->skeyid_e->l); + goto end; + } + if (iph1->key_p->l <= iph1->skeyid_e_p->l) { + plog(ASL_LEVEL_DEBUG, + "%s setting peer key len %zd, val %d (len %zd)", __FUNCTION__, iph1->key_p->l, (int)iph1->skeyid_e_p->v[0], iph1->skeyid_e_p->l); + /* + * if length(Ka) <= length(SKEYID_e) + * Ka = first length(K) bit of SKEYID_e + */ + memcpy(iph1->key_p->v, iph1->skeyid_e_p->v, iph1->key_p->l); + } else { + plog(ASL_LEVEL_ERR, + "unexpected peer key length error (exp %zd, got %zd)", + iph1->key_p->l, iph1->skeyid_e_p->l); + goto end; + } + } /* set prf length */ prflen = alg_oakley_hashdef_hashlen(iph1->approval->hashtype); if (prflen == -1) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "invalid hash type %d.\n", iph1->approval->hashtype); goto end; } @@ -2996,6 +3001,12 @@ oakley_compute_enckey(iph1) int cplen; int subkey; + if (iph1->version == ISAKMP_VERSION_NUMBER_IKEV2) { + plog(ASL_LEVEL_ERR, + "invalid key len (got %zu, expected %zu.\n", iph1->key->l, iph1->skeyid_e->l); + goto end; + } + /* * otherwise, * Ka = K1 | K2 | K3 @@ -3004,13 +3015,13 @@ oakley_compute_enckey(iph1) * K2 = prf(SKEYID_e, K1) * K3 = prf(SKEYID_e, K2) */ - plog(LLV_DEBUG, LOCATION, NULL, + plog(ASL_LEVEL_DEBUG, "len(SKEYID_e) < len(Ka) (%zu < %zu), " "generating long key (Ka = K1 | K2 | ...)\n", iph1->skeyid_e->l, iph1->key->l); if ((buf = vmalloc(prflen >> 3)) == 0) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "failed to get key buffer\n"); goto end; } @@ -3029,11 +3040,11 @@ oakley_compute_enckey(iph1) vfree(buf); goto end; } - plog(LLV_DEBUG, LOCATION, NULL, + plog(ASL_LEVEL_DEBUG, "compute intermediate encryption key K%d\n", subkey); - plogdump(LLV_DEBUG, buf->v, buf->l); - plogdump(LLV_DEBUG, res->v, res->l); + //plogdump(ASL_LEVEL_DEBUG, buf->v, buf->l, ""); + //plogdump(ASL_LEVEL_DEBUG, res->v, res->l, ""); cplen = (res->l < ep - p) ? res->l : ep - p; memcpy(p, res->v, cplen); @@ -3041,7 +3052,7 @@ oakley_compute_enckey(iph1) buf->l = prflen >> 3; /* to cancel K1 speciality */ if (res->l != buf->l) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "internal error: res->l=%zu buf->l=%zu\n", res->l, buf->l); vfree(res); @@ -3061,24 +3072,8 @@ oakley_compute_enckey(iph1) * draft-ietf-ipsec-ike-01.txt Appendix B. * draft-ietf-ipsec-ciph-aes-cbc-00.txt Section 2.3. */ -#if 0 - /* weakkey check */ - if (iph1->approval->enctype > ARRAYLEN(oakley_encdef) - || oakley_encdef[iph1->approval->enctype].weakkey == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "encryption algoritym %d isn't supported.\n", - iph1->approval->enctype); - goto end; - } - if ((oakley_encdef[iph1->approval->enctype].weakkey)(iph1->key)) { - plog(LLV_ERROR, LOCATION, NULL, - "weakkey was generated.\n"); - goto end; - } -#endif - plog(LLV_DEBUG, LOCATION, NULL, "final encryption key computed:\n"); - plogdump(LLV_DEBUG, iph1->key->v, iph1->key->l); + //plogdump(ASL_LEVEL_DEBUG, iph1->key->v, iph1->key->l, "final encryption key computed:\n"); error = 0; @@ -3088,26 +3083,26 @@ end: /* allocated new buffer for CERT */ cert_t * -oakley_newcert() +oakley_newcert(void) { cert_t *new; new = racoon_calloc(1, sizeof(*new)); if (new == NULL) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "failed to get cert's buffer\n"); return NULL; } new->pl = NULL; + new->chain = NULL; return new; } /* delete buffer for CERT */ void -oakley_delcert(cert) - cert_t *cert; +oakley_delcert_1(cert_t *cert) { if (!cert) return; @@ -3116,14 +3111,47 @@ oakley_delcert(cert) racoon_free(cert); } +/* delete buffer for CERT */ +void +oakley_delcert(cert_t *cert) +{ + cert_t *p, *to_delete; + + if (!cert) + return; + + for (p = cert; p;) { + to_delete = p; + p = p->chain; + oakley_delcert_1(to_delete); + } +} + +/* delete buffer for CERT */ +static cert_t * +oakley_appendcert_to_certchain(cert_t *certchain, cert_t *new) +{ + cert_t *p; + + if (!certchain) + return new; + + for (p = certchain; p; p = p->chain) { + if (!p->chain) { + p->chain = new; + return certchain; + } + } + return NULL; +} + /* * compute IV and set to ph1handle * IV = hash(g^xi | g^xr) * see 4.1 Phase 1 state in draft-ietf-ipsec-ike. */ int -oakley_newiv(iph1) - struct ph1handle *iph1; +oakley_newiv(phase1_handle_t *iph1) { struct isakmp_ivm *newivm = NULL; vchar_t *buf = NULL, *bp; @@ -3134,8 +3162,8 @@ oakley_newiv(iph1) len = iph1->dhpub->l + iph1->dhpub_p->l; buf = vmalloc(len); if (buf == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "failed to get iv buffer\n"); + plog(ASL_LEVEL_ERR, + "Failed to get IV buffer\n"); return -1; } @@ -3152,8 +3180,8 @@ oakley_newiv(iph1) /* allocate IVm */ newivm = racoon_calloc(1, sizeof(struct isakmp_ivm)); if (newivm == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "failed to get iv buffer\n"); + plog(ASL_LEVEL_ERR, + "Failed to get IV buffer\n"); vfree(buf); return -1; } @@ -3169,8 +3197,8 @@ oakley_newiv(iph1) /* adjust length of iv */ newivm->iv->l = alg_oakley_encdef_blocklen(iph1->approval->enctype); if (newivm->iv->l == -1) { - plog(LLV_ERROR, LOCATION, NULL, - "invalid encryption algoriym %d.\n", + plog(ASL_LEVEL_ERR, + "Invalid encryption algorithm %d.\n", iph1->approval->enctype); vfree(buf); oakley_delivm(newivm); @@ -3179,7 +3207,7 @@ oakley_newiv(iph1) /* create buffer to save iv */ if ((newivm->ive = vdup(newivm->iv)) == NULL) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "vdup (%s)\n", strerror(errno)); vfree(buf); oakley_delivm(newivm); @@ -3188,8 +3216,10 @@ oakley_newiv(iph1) vfree(buf); - plog(LLV_DEBUG, LOCATION, NULL, "IV computed:\n"); - plogdump(LLV_DEBUG, newivm->iv->v, newivm->iv->l); + //plogdump(ASL_LEVEL_DEBUG, newivm->iv->v, newivm->iv->l, "IV computed:\n"); + + if (iph1->ivm != NULL) + oakley_delivm(iph1->ivm); iph1->ivm = newivm; @@ -3206,9 +3236,7 @@ oakley_newiv(iph1) * see 4.2 Phase 2 state in draft-ietf-ipsec-ike. */ struct isakmp_ivm * -oakley_newiv2(iph1, msgid) - struct ph1handle *iph1; - u_int32_t msgid; +oakley_newiv2(phase1_handle_t *iph1, u_int32_t msgid) { struct isakmp_ivm *newivm = NULL; vchar_t *buf = NULL; @@ -3220,8 +3248,8 @@ oakley_newiv2(iph1, msgid) len = iph1->ivm->iv->l + sizeof(msgid_t); buf = vmalloc(len); if (buf == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "failed to get iv buffer\n"); + plog(ASL_LEVEL_ERR, + "Failed to get IV buffer\n"); goto end; } @@ -3232,15 +3260,14 @@ oakley_newiv2(iph1, msgid) memcpy(p, &msgid, sizeof(msgid)); - plog(LLV_DEBUG, LOCATION, NULL, "compute IV for phase2\n"); - plog(LLV_DEBUG, LOCATION, NULL, "phase1 last IV:\n"); - plogdump(LLV_DEBUG, buf->v, buf->l); + plog(ASL_LEVEL_DEBUG, "Compute IV for Phase 2\n"); + //plogdump(ASL_LEVEL_DEBUG, buf->v, buf->l, "Phase 1 last IV:\n"); /* allocate IVm */ newivm = racoon_calloc(1, sizeof(struct isakmp_ivm)); if (newivm == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "failed to get iv buffer\n"); + plog(ASL_LEVEL_ERR, + "Failed to get IV buffer\n"); goto end; } @@ -3251,22 +3278,21 @@ oakley_newiv2(iph1, msgid) /* adjust length of iv */ newivm->iv->l = alg_oakley_encdef_blocklen(iph1->approval->enctype); if (newivm->iv->l == -1) { - plog(LLV_ERROR, LOCATION, NULL, - "invalid encryption algoriym %d.\n", + plog(ASL_LEVEL_ERR, + "Invalid encryption algorithm %d.\n", iph1->approval->enctype); goto end; } /* create buffer to save new iv */ if ((newivm->ive = vdup(newivm->iv)) == NULL) { - plog(LLV_ERROR, LOCATION, NULL, "vdup (%s)\n", strerror(errno)); + plog(ASL_LEVEL_ERR, "vdup (%s)\n", strerror(errno)); goto end; } error = 0; - plog(LLV_DEBUG, LOCATION, NULL, "phase2 IV computed:\n"); - plogdump(LLV_DEBUG, newivm->iv->v, newivm->iv->l); + //plogdump(ASL_LEVEL_DEBUG, newivm->iv->v, newivm->iv->l, "Phase 2 IV computed:\n"); end: if (error && newivm != NULL){ @@ -3278,9 +3304,66 @@ end: return newivm; } +/* + * Compute unpredictable IV for IKEv2. + */ +int +oakley_newiv_ikev2(phase1_handle_t * iph1) +{ + struct isakmp_ivm *newivm = NULL; + int iv_length; + + /* Get IV length */ + iv_length = alg_oakley_encdef_blocklen(iph1->approval->enctype); + if (iv_length == -1) { + plog(ASL_LEVEL_ERR, "Invalid encryption algorithm %d.\n", iph1->approval->enctype); + } + + /* Allocate IV Manager */ + newivm = racoon_calloc(1, sizeof(struct isakmp_ivm)); + if (newivm == NULL) { + plog(ASL_LEVEL_ERR, "Failed to allocate IV buffer.\n"); + return -1; + } + + /* Compute IV */ + /* There are two recommended methods for generating unpredictable IVs. The first method is to apply the forward cipher function, under the same key that is used for the encryption of the plaintext, to a nonce. The nonce must be a data block that is unique to each execution of the encryption operation. For example, the nonce may be a counter, as described in Appendix B, or a message number. The second method is to generate a random data block using a FIPS- approved random number generator. + [National Institute of Standards and Technology, U.S. + Department of Commerce, "Recommendation for Block Cipher + Modes of Operation", SP 800-38A, 2001.] + */ + /* Currently, we implement the second scheme, which uses a random block */ + newivm->iv = eay_set_random(iv_length); + if (newivm->iv == NULL) { + oakley_delivm(newivm); + return -1; + } + + /* Adjust length of IV */ + if (newivm->iv->l != iv_length) { + plog(ASL_LEVEL_WARNING, "IV length was adjusted.\n"); + newivm->iv->l = iv_length; + } + + /* Make copy of IV in IVe */ + if ((newivm->ive = vdup(newivm->iv)) == NULL) { + plog(ASL_LEVEL_ERR, "vdup (%s)\n", strerror(errno)); + oakley_delivm(newivm); + return -1; + } + + /* Delete old IV if there is one */ + if (iph1->ivm != NULL) + oakley_delivm(iph1->ivm); + + iph1->ivm = newivm; + + return 0; +} + + void -oakley_delivm(ivm) - struct isakmp_ivm *ivm; +oakley_delivm(struct isakmp_ivm *ivm) { if (ivm == NULL) return; @@ -3290,6 +3373,7 @@ oakley_delivm(ivm) if (ivm->ive != NULL) vfree(ivm->ive); racoon_free(ivm); + plog(ASL_LEVEL_DEBUG, "IV freed\n"); return; } @@ -3299,9 +3383,7 @@ oakley_delivm(ivm) * save new iv and old iv. */ vchar_t * -oakley_do_decrypt(iph1, msg, ivdp, ivep) - struct ph1handle *iph1; - vchar_t *msg, *ivdp, *ivep; +oakley_do_ikev1_decrypt(phase1_handle_t *iph1, vchar_t *msg, vchar_t *ivdp, vchar_t *ivep) { vchar_t *buf = NULL, *new = NULL; char *pl; @@ -3310,12 +3392,12 @@ oakley_do_decrypt(iph1, msg, ivdp, ivep) int blen; int error = -1; - plog(LLV_DEBUG, LOCATION, NULL, "begin decryption.\n"); + plog(ASL_LEVEL_DEBUG, "Begin decryption.\n"); blen = alg_oakley_encdef_blocklen(iph1->approval->enctype); if (blen == -1) { - plog(LLV_ERROR, LOCATION, NULL, - "invalid encryption algoriym %d.\n", + plog(ASL_LEVEL_ERR, + "Invalid encryption algorithm %d.\n", iph1->approval->enctype); goto end; } @@ -3324,9 +3406,7 @@ oakley_do_decrypt(iph1, msg, ivdp, ivep) memset(ivep->v, 0, ivep->l); memcpy(ivep->v, (caddr_t)&msg->v[msg->l - blen], blen); - plog(LLV_DEBUG, LOCATION, NULL, - "IV was saved for next processing:\n"); - plogdump(LLV_DEBUG, ivep->v, ivep->l); + plogdump(ASL_LEVEL_DEBUG, ivep->v, ivep->l, "IV was saved for next processing:\n"); pl = msg->v + sizeof(struct isakmp); @@ -3335,8 +3415,8 @@ oakley_do_decrypt(iph1, msg, ivdp, ivep) /* create buffer */ buf = vmalloc(len); if (buf == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "failed to get buffer to decrypt.\n"); + plog(ASL_LEVEL_ERR, + "Failed to get buffer to decrypt.\n"); goto end; } memcpy(buf->v, pl, len); @@ -3344,53 +3424,45 @@ oakley_do_decrypt(iph1, msg, ivdp, ivep) /* do decrypt */ new = alg_oakley_encdef_decrypt(iph1->approval->enctype, buf, iph1->key, ivdp); - if (new == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "decryption %d failed.\n", iph1->approval->enctype); + if (new == NULL || new->v == NULL || new->l == 0) { + plog(ASL_LEVEL_ERR, + "Decryption %d failed.\n", iph1->approval->enctype); goto end; } - plog(LLV_DEBUG, LOCATION, NULL, "with key:\n"); - plogdump(LLV_DEBUG, iph1->key->v, iph1->key->l); + //plogdump(ASL_LEVEL_DEBUG, iph1->key->v, iph1->key->l, "with key:\n"); vfree(buf); buf = NULL; if (new == NULL) goto end; - plog(LLV_DEBUG, LOCATION, NULL, "decrypted payload by IV:\n"); - plogdump(LLV_DEBUG, ivdp->v, ivdp->l); - - plog(LLV_DEBUG, LOCATION, NULL, - "decrypted payload, but not trimed.\n"); - plogdump(LLV_DEBUG, new->v, new->l); + plog(ASL_LEVEL_DEBUG, "decrypted payload by IV:\n"); /* get padding length */ if (lcconf->pad_excltail) padlen = new->v[new->l - 1] + 1; else padlen = new->v[new->l - 1]; - plog(LLV_DEBUG, LOCATION, NULL, "padding len=%u\n", padlen); + plog(ASL_LEVEL_DEBUG, "padding len=%u\n", padlen); /* trim padding */ if (lcconf->pad_strict) { if (padlen > new->l) { - plog(LLV_ERROR, LOCATION, NULL, - "invalid padding len=%u, buflen=%zu.\n", - padlen, new->l); - plogdump(LLV_ERROR, new->v, new->l); + plog(ASL_LEVEL_ERR, "invalid padding len=%u, buflen=%zu.\n", + padlen, new->l); goto end; } new->l -= padlen; - plog(LLV_DEBUG, LOCATION, NULL, "trimmed padding\n"); + plog(ASL_LEVEL_DEBUG, "trimmed padding\n"); } else { - plog(LLV_DEBUG, LOCATION, NULL, "skip to trim padding.\n"); + plog(ASL_LEVEL_DEBUG, "skip to trim padding.\n"); } /* create new buffer */ len = sizeof(struct isakmp) + new->l; buf = vmalloc(len); if (buf == NULL) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "failed to get buffer to decrypt.\n"); goto end; } @@ -3398,8 +3470,7 @@ oakley_do_decrypt(iph1, msg, ivdp, ivep) memcpy(buf->v + sizeof(struct isakmp), new->v, new->l); ((struct isakmp *)buf->v)->len = htonl(buf->l); - plog(LLV_DEBUG, LOCATION, NULL, "decrypted.\n"); - plogdump(LLV_DEBUG, buf->v, buf->l); + plog(ASL_LEVEL_DEBUG, "decrypted.\n"); #ifdef HAVE_PRINT_ISAKMP_C isakmp_printpacket(buf, iph1->remote, iph1->local, 1); @@ -3418,13 +3489,24 @@ end: return buf; } +/* + * decrypt packet. + */ +vchar_t * +oakley_do_decrypt(phase1_handle_t *iph1, vchar_t *msg, vchar_t *ivdp, vchar_t *ivep) +{ + if (iph1->version == ISAKMP_VERSION_NUMBER_IKEV1) { + return(oakley_do_ikev1_decrypt(iph1, msg, ivdp, ivep)); + } + plog(ASL_LEVEL_ERR, "Failed to decrypt invalid IKE version"); + return NULL; +} + /* * encrypt packet. */ vchar_t * -oakley_do_encrypt(iph1, msg, ivep, ivp) - struct ph1handle *iph1; - vchar_t *msg, *ivep, *ivp; +oakley_do_ikev1_encrypt(phase1_handle_t *iph1, vchar_t *msg, vchar_t *ivep, vchar_t *ivp) { vchar_t *buf = 0, *new = 0; char *pl; @@ -3433,13 +3515,13 @@ oakley_do_encrypt(iph1, msg, ivep, ivp) int blen; int error = -1; - plog(LLV_DEBUG, LOCATION, NULL, "begin encryption.\n"); + plog(ASL_LEVEL_DEBUG, "Begin encryption.\n"); /* set cbc block length */ blen = alg_oakley_encdef_blocklen(iph1->approval->enctype); if (blen == -1) { - plog(LLV_ERROR, LOCATION, NULL, - "invalid encryption algoriym %d.\n", + plog(ASL_LEVEL_ERR, + "Invalid encryption algorithm %d.\n", iph1->approval->enctype); goto end; } @@ -3449,13 +3531,13 @@ oakley_do_encrypt(iph1, msg, ivep, ivp) /* add padding */ padlen = oakley_padlen(len, blen); - plog(LLV_DEBUG, LOCATION, NULL, "pad length = %u\n", padlen); + plog(ASL_LEVEL_DEBUG, "pad length = %u\n", padlen); /* create buffer */ buf = vmalloc(len + padlen); if (buf == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "failed to get buffer to encrypt.\n"); + plog(ASL_LEVEL_ERR, + "Failed to get buffer to encrypt.\n"); goto end; } if (padlen) { @@ -3474,40 +3556,37 @@ oakley_do_encrypt(iph1, msg, ivep, ivp) else buf->v[len + padlen - 1] = padlen; - plogdump(LLV_DEBUG, buf->v, buf->l); + plogdump(ASL_LEVEL_DEBUG, buf->v, buf->l, "About to encrypt %d bytes", buf->l); /* do encrypt */ new = alg_oakley_encdef_encrypt(iph1->approval->enctype, buf, iph1->key, ivep); if (new == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "encryption %d failed.\n", iph1->approval->enctype); + plog(ASL_LEVEL_ERR, + "Encryption %d failed.\n", iph1->approval->enctype); goto end; } - plog(LLV_DEBUG, LOCATION, NULL, "with key:\n"); - plogdump(LLV_DEBUG, iph1->key->v, iph1->key->l); + //plogdump(ASL_LEVEL_DEBUG, iph1->key->v, iph1->key->l, "with key:\n"); vfree(buf); buf = NULL; if (new == NULL) goto end; - plog(LLV_DEBUG, LOCATION, NULL, "encrypted payload by IV:\n"); - plogdump(LLV_DEBUG, ivep->v, ivep->l); + //plogdump(ASL_LEVEL_DEBUG, ivep->v, ivep->l, "encrypted payload by IV:\n"); /* save IV for next */ memset(ivp->v, 0, ivp->l); memcpy(ivp->v, (caddr_t)&new->v[new->l - blen], blen); - plog(LLV_DEBUG, LOCATION, NULL, "save IV for next:\n"); - plogdump(LLV_DEBUG, ivp->v, ivp->l); + //plogdump(ASL_LEVEL_DEBUG, ivp->v, ivp->l, "save IV for next:\n"); /* create new buffer */ len = sizeof(struct isakmp) + new->l; buf = vmalloc(len); if (buf == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "failed to get buffer to encrypt.\n"); + plog(ASL_LEVEL_ERR, + "Failed to get buffer to encrypt.\n"); goto end; } memcpy(buf->v, msg->v, sizeof(struct isakmp)); @@ -3516,7 +3595,7 @@ oakley_do_encrypt(iph1, msg, ivep, ivp) error = 0; - plog(LLV_DEBUG, LOCATION, NULL, "encrypted.\n"); + plog(ASL_LEVEL_DEBUG, "Encrypted.\n"); end: if (error && buf != NULL) { @@ -3529,14 +3608,27 @@ end: return buf; } + +/* + * encrypt packet. + */ +vchar_t * +oakley_do_encrypt(phase1_handle_t *iph1, vchar_t *msg, vchar_t *ivep, vchar_t *ivp) +{ + if (iph1->version == ISAKMP_VERSION_NUMBER_IKEV1) { + return(oakley_do_ikev1_encrypt(iph1, msg, ivep, ivp)); + } + plog(ASL_LEVEL_ERR, "Failed to encrypt invalid IKE version"); + return NULL; +} + /* culculate padding length */ static int -oakley_padlen(len, base) - int len, base; +oakley_padlen(int len, int base) { int padlen; - padlen = base - len % base; + padlen = base - (len % base); if (lcconf->pad_randomlen) padlen += ((eay_random() % (lcconf->pad_maxsize + 1) + 1) * @@ -3545,7 +3637,6 @@ oakley_padlen(len, base) return padlen; } -#ifdef __APPLE__ /* ----------------------------------------------------------------------------- The base-64 encoding packs three 8-bit bytes into four 7-bit ASCII characters. If the number of bytes in the original data isn't divisable @@ -3586,7 +3677,7 @@ static int base64toCFData(vchar_t *textin, CFDataRef *dataRef) int numeq = 0; int acc = 0; int cntr = 0; - uint8_t *textcur = textin->v; + uint8_t *textcur = (__typeof__(textcur))textin->v; int len = textin->l; int i; @@ -3623,4 +3714,4 @@ static int base64toCFData(vchar_t *textin, CFDataRef *dataRef) return -1; } -#endif +