X-Git-Url: https://git.saurik.com/apple/ipsec.git/blobdiff_plain/52b7d2ce06d68d0a9160d16f6e7c08c21c149d0d..869d26af2154b0619928167c83079c8c0bf7163d:/ipsec-tools/racoon/oakley.c?ds=sidebyside diff --git a/ipsec-tools/racoon/oakley.c b/ipsec-tools/racoon/oakley.c index 1d52885..eefa0fb 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" @@ -72,7 +81,6 @@ #include "admin.h" #include "privsep.h" #include "localconf.h" -#include "remoteconf.h" #include "policy.h" #include "handler.h" #include "ipsec_doi.h" @@ -81,43 +89,61 @@ #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" +#ifdef HAVE_OPENSSL #include "rsalist.h" -#ifdef __APPLE__ -#include #endif - - +#include +#include "remoteconf.h" +#include "vpn_control.h" +#if TARGET_OS_EMBEDDED +#include +#include +#endif #ifdef HAVE_GSSAPI #include "gssapi.h" #endif +#include "vpn_control_var.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; @@ -132,21 +158,32 @@ 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)); +#ifdef HAVE_OPENSSL 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)); #endif +static int oakley_check_certid __P((struct ph1handle *iph1, int)); +static int oakley_check_certid_1 __P((vchar_t *, int, int, void*, cert_status_t *certStatus)); static int check_typeofcertname __P((int, int)); static cert_t *save_certbuf __P((struct isakmp_gen *)); +#ifdef HAVE_OPENSSL static cert_t *save_certx509 __P((X509 *)); +#endif static int oakley_padlen __P((int, int)); -#ifdef __APPLE__ static int base64toCFData(vchar_t *, CFDataRef*); +static cert_t *oakley_appendcert_to_certchain(cert_t *, cert_t *); + +static void oakley_cert_prettyprint (vchar_t *cert) +{ + char *p = NULL; +#ifdef HAVE_OPENSSL + p = eay_get_x509text(cert); +#else + /* add new cert dump code here */ #endif + plog(LLV_DEBUG, LOCATION, NULL, "%s", p ? p : "\n"); + racoon_free(p); +} int oakley_get_defaultlifetime() @@ -236,10 +273,9 @@ 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; @@ -284,12 +320,69 @@ oakley_dh_compute(dh, pub, priv, pub_p, gxy) 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(LLV_DEBUG, LOCATION, NULL, "compute DH result.\n"); + + maxKeyLen = SecDHGetMaxKeyLength(dhC); + computed_key = vmalloc(maxKeyLen); + if (computed_key == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "memory error.\n"); + goto fail; + } + computed_keylen = computed_key->l; + if (SecDHComputeKey(dhC, pub_p->v + (maxKeyLen - publicKeySize), publicKeySize, + computed_key->v, &computed_keylen)) { + plog(LLV_ERROR, LOCATION, NULL, "failed to compute dh value.\n"); + goto fail; + } + +#ifdef ENABLE_STATS + gettimeofday(&end, NULL); + syslog(LOG_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(LLV_ERROR, LOCATION, NULL, "memory error.\n"); + goto fail; + } + memcpy((*gxy)->v + (maxKeyLen - computed_keylen), computed_key->v, computed_keylen); + plog(LLV_DEBUG, LOCATION, NULL, "compute DH's shared.\n"); + plogdump(LLV_DEBUG, (*gxy)->v, (*gxy)->l); + SecDHDestroy(dhC); + vfree(computed_key); + return 0; + +fail: + SecDHDestroy(dhC); + 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; @@ -336,6 +429,90 @@ oakley_dh_generate(dh, pub, priv) 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(LLV_DEBUG, LOCATION, NULL, "generate DH key pair.\n"); + *pub = NULL; + switch (dh->type) { + case OAKLEY_ATTR_GRP_TYPE_MODP: + if (dh->desc != OAKLEY_ATTR_GRP_DESC_MODP1024 && dh->desc != OAKLEY_ATTR_GRP_DESC_MODP1536) { + plog(LLV_ERROR, LOCATION, NULL, "Invalid dh group.\n"); + goto fail; + } + if (SecDHCreate(dh->desc, dh->prime->v, dh->prime->l, 0, NULL, 0, dhC)) { + plog(LLV_ERROR, LOCATION, NULL, "failed to create dh context.\n"); + goto fail; + } + maxKeyLen = SecDHGetMaxKeyLength(*dhC); + public = vmalloc(maxKeyLen); + *publicKeySize = public->l; + if (public == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "memory error.\n"); + goto fail; + } + if (SecDHGenerateKeypair(*dhC, public->v, publicKeySize)) { + plog(LLV_ERROR, LOCATION, NULL, "failed to generate dh key pair.\n"); + goto fail; + } + plog(LLV_DEBUG, LOCATION, NULL, "got DH key pair.\n"); + + *pub = vmalloc(maxKeyLen); + if (*pub == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "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(LLV_ERROR, LOCATION, NULL, + "dh type %d isn't supported.\n", dh->type); + goto fail; + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid dh type %d.\n", dh->type); + goto fail; + } + +#ifdef ENABLE_STATS + gettimeofday(&end, NULL); + syslog(LOG_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(LLV_DEBUG, LOCATION, NULL, "failed DH public key size check.\n"); + goto fail; + } + + plog(LLV_DEBUG, LOCATION, NULL, "compute DH's private.\n"); + plog(LLV_DEBUG, LOCATION, NULL, "compute DH's public.\n"); + plogdump(LLV_DEBUG, (*pub)->v, (*pub)->l); + + vfree(public); + return 0; + +fail: + SecDHDestroy(*dhC); + vfree(*pub); + vfree(public); + return -1; + +} +#endif /* * copy pre-defined dhgroup values. @@ -455,8 +632,12 @@ oakley_compute_keymat(iph2, side) /* 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; } @@ -610,6 +791,7 @@ 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); @@ -625,8 +807,14 @@ 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, "failed to get keymat buffer.\n"); @@ -868,7 +1056,7 @@ oakley_ph1hash_common(iph1, sw) + (sw == GENERATE ? iph1->id->l : iph1->id_p->l); #ifdef HAVE_GSSAPI - if (iph1->approval->authmethod == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB) { + if (AUTHMETHOD(iph1) == 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; @@ -929,7 +1117,7 @@ oakley_ph1hash_common(iph1, sw) p += bp->l; #ifdef HAVE_GSSAPI - if (iph1->approval->authmethod == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB) { + if (AUTHMETHOD(iph1) == 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); @@ -950,7 +1138,8 @@ oakley_ph1hash_common(iph1, sw) error = 0; - plog(LLV_DEBUG, LOCATION, NULL, "HASH computed:\n"); + plog(LLV_DEBUG, LOCATION, NULL, "HASH (%s) computed:\n", + iph1->side == INITIATOR ? "init" : "resp"); plogdump(LLV_DEBUG, res->v, res->l); end: @@ -989,10 +1178,18 @@ oakley_ph1hash_base_i(iph1, sw) 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"); return NULL; @@ -1002,12 +1199,18 @@ oakley_ph1hash_base_i(iph1, sw) case OAKLEY_ATTR_AUTH_METHOD_DSSSIG: case OAKLEY_ATTR_AUTH_METHOD_RSASIG: +#ifdef HAVE_GSSAPI case OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB: +#endif #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_RSA_R: case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I: + case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_R: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_I: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_R: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_I: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_R: #endif /* make hash for seed */ len = iph1->nonce->l + iph1->nonce_p->l; @@ -1115,16 +1318,28 @@ oakley_ph1hash_base_r(iph1, sw) "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_DSSSIG: + 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_HYBRID_DSS_I: + case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_R: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_I: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_R: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_I: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_R: + case FICTIVE_AUTH_METHOD_XAUTH_PSKEY_I: #endif - && iph1->approval->authmethod != OAKLEY_ATTR_AUTH_METHOD_RSASIG) { + break; + default: plog(LLV_ERROR, LOCATION, NULL, "not supported authentication method %d\n", iph1->approval->authmethod); return NULL; + break; } /* make hash for seed */ @@ -1186,7 +1401,7 @@ oakley_ph1hash_base_r(iph1, sw) memcpy(p, bp->v, bp->l); p += bp->l; - plog(LLV_DEBUG, LOCATION, NULL, "HASH with:\n"); + plog(LLV_DEBUG, LOCATION, NULL, "HASH_R with:\n"); plogdump(LLV_DEBUG, buf->v, buf->l); /* compute HASH */ @@ -1196,7 +1411,7 @@ oakley_ph1hash_base_r(iph1, sw) error = 0; - plog(LLV_DEBUG, LOCATION, NULL, "HASH computed:\n"); + plog(LLV_DEBUG, LOCATION, NULL, "HASH_R computed:\n"); plogdump(LLV_DEBUG, res->v, res->l); end: @@ -1207,6 +1422,81 @@ end: return res; } +#if HAVE_OPENDIR +static int +oakley_verify_userid(iph1) + struct ph1handle *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); + 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(LLV_ERROR, LOCATION, NULL, + "the peer is not authorized for access.\n"); + } else { + plog(LLV_ERROR, LOCATION, NULL, + "the peer is not authorized for access - user ID not found.\n"); + } + return ISAKMP_NTYPE_AUTHENTICATION_FAILED; +} +#endif /* HAVE_OPENDIR */ + +#ifdef HAVE_OPENSSL +static int +oakley_verify_x509sign(certchain, my_hash, my_sig) + cert_t *certchain; + vchar_t *my_hash; + vchar_t *my_sig; +{ + cert_t *p; + int result = -1; + + for (p = certchain; p; p = p->chain) { + if ((result = eay_check_x509sign(my_hash, + my_sig, + &p->cert)) == 0) { + break; + } + } + return result; +} +#endif +#ifdef HAVE_OPENSSL +static int +oakley_check_x509cert(certchain, capath, cafile, local) + cert_t *certchain; + char *capath; + char *cafile; + int local; +{ + cert_t *p; + int result = 0; + + for (p = certchain; p; p = p->chain) { + if ((result = eay_check_x509cert(&p->cert, + capath, + cafile, + local))) { + break; + } + } + return result; +} +#endif /* HAVE_OPENSSL */ + /* * compute each authentication method in phase 1. * OUT: @@ -1227,12 +1517,20 @@ oakley_validate_auth(iph1) #ifdef ENABLE_STATS struct timeval start, end; #endif +#if TARGET_OS_EMBEDDED + SecKeyRef publicKeyRef; +#endif #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; @@ -1242,10 +1540,20 @@ oakley_validate_auth(iph1) "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(LLV_ERROR, LOCATION, NULL, "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:"); + plog(LLV_DEBUG, LOCATION, NULL, "HASH received:\n"); plogdump(LLV_DEBUG, r_hash, ntohs(iph1->pl_hash->h.len) - sizeof(*iph1->pl_hash)); @@ -1282,8 +1590,12 @@ oakley_validate_auth(iph1) 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_HYBRID_DSS_I: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_I: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_R: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_I: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_R: #endif { int error = 0; @@ -1313,6 +1625,7 @@ oakley_validate_auth(iph1) return ISAKMP_INTERNAL_ERROR; } break; +#ifdef HAVE_OPENSSL case ISAKMP_GETCERT_LOCALFILE: switch (iph1->rmconf->certtype) { case ISAKMP_CERT_X509SIGN: @@ -1338,6 +1651,7 @@ oakley_validate_auth(iph1) if (error) return ISAKMP_INTERNAL_ERROR; break; +#endif case ISAKMP_GETCERT_DNS: if (iph1->rmconf->peerscertfile != NULL) { plog(LLV_ERROR, LOCATION, NULL, @@ -1368,53 +1682,35 @@ 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 !TARGET_OS_EMBEDDED if (iph1->rmconf->cert_verification_option == VERIFICATION_OPTION_PEERS_IDENTIFIER && (error = oakley_check_certid(iph1, CERT_CHECKID_FROM_RMCONFIG)) != 0) return error; +#endif +#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: + case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I: certtype = iph1->cert_p->type; break; default: @@ -1423,11 +1719,49 @@ oakley_validate_auth(iph1) #endif switch (certtype) { case ISAKMP_CERT_X509SIGN: -#ifdef __APPLE__ + +#if TARGET_OS_EMBEDDED + { + /* 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 (((struct sockaddr *)(id_spec->id->v))->sa_family) { + case AF_INET: + peers_id = inet_ntoa(((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 + default: + plog(LLV_ERROR, LOCATION, NULL, + "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); + } + error = crypto_cssm_check_x509cert(oakley_get_peer_cert_from_certchain(iph1), iph1->cert_p, hostname, &publicKeyRef); + if (hostname) + CFRelease(hostname); + } + +#else /* TARGET_OS_EMBEDDED */ if (iph1->rmconf->cert_verification == VERIFICATION_MODULE_SEC_FRAMEWORK) - error = crypto_cssm_check_x509cert(&iph1->cert_p->cert); + error = crypto_cssm_check_x509cert(oakley_get_peer_cert_from_certchain(iph1), + iph1->cert_p, + NULL); else -#endif { char path[MAXPATHLEN]; char *ca; @@ -1441,10 +1775,11 @@ oakley_validate_auth(iph1) ca = NULL; } - error = eay_check_x509cert(&iph1->cert_p->cert, - lcconf->pathinfo[LC_PATHTYPE_CERT], - ca, 0); + error = oakley_check_x509cert(iph1->cert_p, + lcconf->pathinfo[LC_PATHTYPE_CERT], + ca, 0); } +#endif /* TARGET_OS_EMBEDDED */ break; default: @@ -1459,7 +1794,6 @@ oakley_validate_auth(iph1) } } - plog(LLV_DEBUG, LOCATION, NULL, "CERT validated\n"); /* compute hash */ @@ -1485,9 +1819,9 @@ 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: + case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I: certtype = iph1->cert_p->type; break; default: @@ -1498,16 +1832,24 @@ oakley_validate_auth(iph1) switch (certtype) { case ISAKMP_CERT_X509SIGN: case ISAKMP_CERT_DNS: - error = eay_check_x509sign(my_hash, - iph1->sig_p, - &iph1->cert_p->cert); +#if TARGET_OS_EMBEDDED + error = crypto_cssm_verify_x509sign(publicKeyRef, my_hash, iph1->sig_p); + if (error) + plog(LLV_ERROR, LOCATION, NULL, "error verifying signature %s\n", GetSecurityErrorString(error)); + + CFRelease(publicKeyRef); +#else + error = oakley_verify_x509sign(iph1->cert_p, my_hash, iph1->sig_p); +#endif break; +#ifdef HAVE_OPENSSL 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; +#endif default: plog(LLV_ERROR, LOCATION, NULL, "no supported certtype %d\n", @@ -1526,8 +1868,8 @@ oakley_validate_auth(iph1) } 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: + case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_R: { if ((iph1->mode_cfg->flags & ISAKMP_CFG_VENDORID_XAUTH) == 0) { plog(LLV_ERROR, LOCATION, NULL, "No SIG was passed, " @@ -1545,6 +1887,11 @@ oakley_validate_auth(iph1) #endif #ifdef HAVE_GSSAPI case OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB: + /* check if we're not into XAUTH_PSKEY_I instead */ +#ifdef ENABLE_HYBRID + if (iph1->rmconf->xauth) + break; +#endif switch (iph1->etype) { case ISAKMP_ETYPE_IDENT: case ISAKMP_ETYPE_AGG: @@ -1582,6 +1929,12 @@ oakley_validate_auth(iph1) #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, "few isakmp message received.\n"); @@ -1607,6 +1960,47 @@ oakley_validate_auth(iph1) return 0; } +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 (struct ph1handle *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->sa_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. */ @@ -1614,17 +2008,25 @@ int oakley_getmycert(iph1) struct ph1handle *iph1; { + int err; + u_int32_t address; + switch (iph1->rmconf->certtype) { case ISAKMP_CERT_X509SIGN: if (iph1->cert) return 0; - return get_cert_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; +#ifdef HAVE_OPENSSL case ISAKMP_CERT_PLAINRSA: if (iph1->rsa) return 0; return get_plainrsa_fromlocal(iph1, 1); - +#endif default: plog(LLV_ERROR, LOCATION, NULL, "Unknown certtype #%d\n", @@ -1650,6 +2052,7 @@ get_cert_fromlocal(iph1, my) cert_t **certpl; char *certfile; int error = -1; + cert_status_t status = CERT_STATUS_OK; if (my) { certfile = iph1->rmconf->mycertfile; @@ -1658,41 +2061,33 @@ get_cert_fromlocal(iph1, my) certfile = iph1->rmconf->peerscertfile; 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"); 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(LLV_DEBUG, LOCATION, NULL, "done with chking cert status %d\n",status); CFRelease(dataRef); break; } // else fall thru -#endif +#ifdef HAVE_OPENSSL 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); + oakley_cert_prettyprint(cert); }; break; - +#endif default: plog(LLV_ERROR, LOCATION, NULL, "not supported certtype %d\n", @@ -1724,12 +2119,14 @@ 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); - + oakley_cert_prettyprint(cert); + error = 0; end: @@ -1739,6 +2136,7 @@ end: return error; } +#ifdef HAVE_OPENSSL static int get_plainrsa_fromlocal(iph1, my) struct ph1handle *iph1; @@ -1750,28 +2148,39 @@ get_plainrsa_fromlocal(iph1, my) int error = -1; iph1->rsa_candidates = rsa_lookup_keys(iph1, my); - if (!iph1->rsa_candidates || rsa_list_count(iph1->rsa_candidates) == 0) { + 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)); + 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", + "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)); + 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"); + "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"); + "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; + iph1->rsa = ((struct rsa_key *) + genlist_next(iph1->rsa_candidates, NULL))->rsa; + genlist_free(iph1->rsa_candidates, NULL); iph1->rsa_candidates = NULL; + + if (iph1->rsa == NULL) + goto end; } error = 0; @@ -1779,6 +2188,7 @@ get_plainrsa_fromlocal(iph1, my) end: return error; } +#endif /* get signature */ int @@ -1791,18 +2201,17 @@ oakley_getsign(iph1) 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 +#ifdef HAVE_OPENSSL case ISAKMP_CERT_DNS: if (iph1->rmconf->myprivfile == NULL) { plog(LLV_ERROR, LOCATION, NULL, "no cert defined.\n"); @@ -1827,6 +2236,7 @@ oakley_getsign(iph1) case ISAKMP_CERT_PLAINRSA: iph1->sig = eay_get_rsasign(iph1->hash, iph1->rsa); break; +#endif default: plog(LLV_ERROR, LOCATION, NULL, "Unknown certtype #%d\n", @@ -1851,26 +2261,83 @@ end: return error; } -#ifdef __APPLE__ +void +oakley_verify_certid(iph1) +struct ph1handle *iph1; +{ + 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(iph1->cert_p); + iph1->cert_p = NULL; + } +} -/* - * compare certificate name and ID value. - */ static int -oakley_check_certid(iph1, which_id) - struct ph1handle *iph1; - int which_id; -{ - struct ipsecdoi_id_b *id_b; +oakley_check_certid_in_certchain(certchain, idtype, idlen, id) + cert_t *certchain; + int idtype; int idlen; - u_int8_t doi_type = 255; - void *peers_id = NULL; - struct genlist_entry *gpb = NULL; + void *id; +{ + cert_t *p; - 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"); + 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(iph1) + struct ph1handle * iph1; +{ + cert_t *p; + struct ipsecdoi_id_b *id_b; + int idlen; + void *peers_id; + + if (!iph1->id_p || !iph1->cert_p) { + plog(LLV_ERROR, LOCATION, NULL, "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 = (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; +{ + 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; @@ -1878,7 +2345,7 @@ oakley_check_certid(iph1, which_id) peers_id = id_b + 1; idlen = iph1->id_p->l - sizeof(*id_b); - return oakley_check_certid_1(iph1, doi_type, idlen, peers_id); + return oakley_check_certid_in_certchain(iph1->cert_p, doi_type, idlen, peers_id); } else { /* use ID from remote configuration */ @@ -1913,19 +2380,20 @@ oakley_check_certid(iph1, which_id) peers_id = id_spec->id->v; idlen = id_spec->id->l; } - if (oakley_check_certid_1(iph1, doi_type, idlen, peers_id) == 0) + if (oakley_check_certid_in_certchain(iph1->cert_p, doi_type, idlen, peers_id) == 0) return 0; } - return ISAKMP_NTYPE_INVALID_ID_INFORMATION; + return ISAKMP_NTYPE_INVALID_ID_INFORMATION; } } static int -oakley_check_certid_1(iph1, idtype, idlen, id) - struct ph1handle *iph1; +oakley_check_certid_1(cert, idtype, idlen, id, certStatus) + vchar_t *cert; int idtype; int idlen; void *id; + cert_status_t *certStatus; { vchar_t *name = NULL; @@ -1935,30 +2403,167 @@ oakley_check_certid_1(iph1, idtype, idlen, id) switch (idtype) { case IPSECDOI_ID_DER_ASN1_DN: - name = eay_get_x509asn1subjectname(&iph1->cert_p->cert); +#if TARGET_OS_EMBEDDED + { + SecCertificateRef certificate; + CFDataRef subject; + UInt8* namePtr; + + certificate = crypto_cssm_x509cert_get_SecCertificateRef(cert); + if (certificate == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "failed to get SecCertificateRef\n"); + if (certStatus && !*certStatus) { + *certStatus = CERT_STATUS_INVALID; + } + return ISAKMP_NTYPE_INVALID_CERTIFICATE; + } + subject = SecCertificateCopySubjectSequence(certificate); + if (subject == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "failed to get subjectName\n"); + if (certStatus && !*certStatus) { + *certStatus = CERT_STATUS_INVALID_SUBJNAME; + } + CFRelease(certificate); + return ISAKMP_NTYPE_INVALID_CERTIFICATE; + } + len = CFDataGetLength(subject); + namePtr = CFDataGetBytePtr(subject); + if (idlen != len) { + plog(LLV_ERROR, LOCATION, NULL, "Invalid ID length in phase 1.\n"); + if (certStatus && !*certStatus) { + *certStatus = CERT_STATUS_INVALID_SUBJNAME; + } + CFRelease(subject); + CFRelease(certificate); + return ISAKMP_NTYPE_INVALID_ID_INFORMATION; + } + error = memcmp(id, namePtr, idlen); + if (error != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "ID mismatched with subjectName.\n"); + plog(LLV_ERROR, LOCATION, NULL, + "subjectName (type %s):\n", + s_ipsecdoi_ident(idtype)); + plogdump(LLV_ERROR, namePtr, len); + plog(LLV_ERROR, LOCATION, NULL, + "ID:\n"); + plogdump(LLV_ERROR, id, idlen); + if (certStatus && !*certStatus) { + *certStatus = CERT_STATUS_INVALID_SUBJNAME; + } + CFRelease(certificate); + CFRelease(subject); + return ISAKMP_NTYPE_INVALID_ID_INFORMATION; + } + } +#else + name = eay_get_x509asn1subjectname(cert); if (!name) { plog(LLV_ERROR, LOCATION, NULL, "failed to get subjectName\n"); + if (certStatus && !*certStatus) { + *certStatus = CERT_STATUS_INVALID_SUBJNAME; + } return ISAKMP_NTYPE_INVALID_CERTIFICATE; } if (idlen != name->l) { plog(LLV_ERROR, LOCATION, NULL, "Invalid ID length in phase 1.\n"); vfree(name); + if (certStatus && !*certStatus) { + *certStatus = CERT_STATUS_INVALID_SUBJNAME; + } 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"); + plog(LLV_ERROR, LOCATION, NULL, + "subjectName (type %s):\n", + s_ipsecdoi_ident(idtype)); + plogdump(LLV_ERROR, name->v, name->l); + plog(LLV_ERROR, LOCATION, NULL, + "ID:\n"); + plogdump(LLV_ERROR, id, idlen); + vfree(name); + if (certStatus && !*certStatus) { + *certStatus = CERT_STATUS_INVALID_SUBJNAME; + } return ISAKMP_NTYPE_INVALID_ID_INFORMATION; } + vfree(name); +#endif return 0; + case IPSECDOI_ID_IPV4_ADDR: case IPSECDOI_ID_IPV6_ADDR: { - +#if TARGET_OS_EMBEDDED + CFIndex pos, count; + SecCertificateRef certificate; + CFArrayRef addresses; + + certificate = crypto_cssm_x509cert_get_SecCertificateRef(cert); + if (certificate == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get SecCertificateRef\n"); + if (certStatus && !*certStatus) { + *certStatus = CERT_STATUS_INVALID; + } + return ISAKMP_NTYPE_INVALID_CERTIFICATE; + } + addresses = SecCertificateCopyIPAddresses(certificate); + if (addresses == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "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(addressLen + 1); + if (addressBuf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "out of memory\n"); + return -1; + } + if (CFStringGetCString(address, addressBuf, addressLen + 1, 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(LLV_ERROR, LOCATION, NULL, "ID mismatched with subjectAltName.\n"); + plog(LLV_ERROR, LOCATION, NULL, + "subjectAltName (expected type %s):\n", s_ipsecdoi_ident(idtype)); + plog(LLV_ERROR, LOCATION, NULL, "ID:\n"); + plogdump(LLV_ERROR, id, idlen); + 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 @@ -1976,14 +2581,22 @@ oakley_check_certid_1(iph1, idtype, idlen, id) } for (pos = 1; ; pos++) { - if (eay_get_x509subjectaltname(&iph1->cert_p->cert, &altname, &type, pos, &len) !=0) { + if (eay_get_x509subjectaltname(cert, &altname, &type, pos, &len) !=0) { plog(LLV_ERROR, LOCATION, NULL, "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(LLV_ERROR, LOCATION, NULL, + "invalid subjectAltName\n"); + if (certStatus && !*certStatus) { + *certStatus = CERT_STATUS_INVALID_SUBJALTNAME; + } return ISAKMP_NTYPE_INVALID_ID_INFORMATION; } @@ -2016,247 +2629,233 @@ oakley_check_certid_1(iph1, idtype, idlen, id) /* invalid IP address length in certificate - bad or bogus certificate */ plog(LLV_ERROR, LOCATION, NULL, "invalid IP address in certificate.\n"); + plog(LLV_ERROR, LOCATION, NULL, + "subjectAltName (expected type %s, got type %s):\n", + s_ipsecdoi_ident(idtype), + s_ipsecdoi_ident(type)); + plogdump(LLV_ERROR, altname, len); 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); - racoon_free(altname); - 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, &len) != 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) { - return ISAKMP_NTYPE_INVALID_ID_INFORMATION; - } - - if (check_typeofcertname(idtype, type) != 0) { - /* wrong general type - skip this one */ - racoon_free(altname); - altname = NULL; - continue; - } - - if (idlen != strlen(altname)) { - /* wrong length - skip this one */ - racoon_free(altname); - altname = NULL; + if (error) continue; - } - error = memcmp(id, altname, idlen); racoon_free(altname); - if (error) { - plog(LLV_ERROR, LOCATION, NULL, "ID mismatched.\n"); - return ISAKMP_NTYPE_INVALID_ID_INFORMATION; - } return 0; - } - } - default: + } + /* failed to find a match */ plog(LLV_ERROR, LOCATION, NULL, - "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"); + "ID mismatched with subjectAltName.\n"); + plog(LLV_ERROR, LOCATION, NULL, + "subjectAltName (expected type %s, got type %s):\n", + s_ipsecdoi_ident(idtype), + s_ipsecdoi_ident(type)); + plogdump(LLV_ERROR, altname, len); + plog(LLV_ERROR, LOCATION, NULL, + "ID:\n"); + plogdump(LLV_ERROR, id, idlen); + racoon_free(altname); + if (certStatus && !*certStatus) + *certStatus = CERT_STATUS_INVALID_SUBJALTNAME; return ISAKMP_NTYPE_INVALID_ID_INFORMATION; + +#endif /* TARGET_OS_EMBEDDED */ } - 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) { +#if TARGET_OS_EMBEDDED + case IPSECDOI_ID_FQDN: + { + CFIndex pos, count; + SecCertificateRef certificate; + CFArrayRef names; + CFStringRef name, ID; + + certificate = crypto_cssm_x509cert_get_SecCertificateRef(cert); + if (certificate == NULL) { plog(LLV_ERROR, LOCATION, NULL, - "failed to get subjectName\n"); + "failed to get SecCertificateRef\n"); + if (certStatus && !*certStatus) { + *certStatus = CERT_STATUS_INVALID; + } return ISAKMP_NTYPE_INVALID_CERTIFICATE; } - if (idlen != name->l) { + names = SecCertificateCopyDNSNames(certificate); + if (names == NULL) { plog(LLV_ERROR, LOCATION, NULL, - "Invalid ID length in phase 1.\n"); - vfree(name); - return ISAKMP_NTYPE_INVALID_ID_INFORMATION; + "failed to get subjectName\n"); + if (certStatus && !*certStatus) { + *certStatus = CERT_STATUS_INVALID_SUBJALTNAME; + } + CFRelease(certificate); + return ISAKMP_NTYPE_INVALID_CERTIFICATE; } - 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; + count = CFArrayGetCount(names); + ID = CFStringCreateWithCString(NULL, id, kCFStringEncodingUTF8); + if (ID== NULL) { + plog(LLV_ERROR, LOCATION, NULL, "memory error\n"); + CFRelease(names); + CFRelease(certificate); + } - 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; + for (pos = 0; pos < count; pos++) { + name = CFArrayGetValueAtIndex(names, pos); + if (CFStringCompare(name, ID, 0) == kCFCompareEqualTo) { + CFRelease(ID); + CFRelease(names); + CFRelease(certificate); + return 0; } - - 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, "ID mismatched with subjectAltName.\n"); + plog(LLV_ERROR, LOCATION, NULL, + "subjectAltName (expected type %s):\n", s_ipsecdoi_ident(idtype)); + plog(LLV_ERROR, LOCATION, NULL, "ID:\n"); + plogdump(LLV_ERROR, id, idlen); + 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_get_SecCertificateRef(cert); + if (certificate == NULL) { plog(LLV_ERROR, LOCATION, NULL, - "no proper subjectAltName.\n"); - racoon_free(altname); + "failed to get SecCertificateRef\n"); + if (certStatus && !*certStatus) { + *certStatus = CERT_STATUS_INVALID; + } 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: + names = SecCertificateCopyRFC822Names(certificate); + if (names == NULL) { plog(LLV_ERROR, LOCATION, NULL, - "family not supported: %d.\n", res->ai_family); - racoon_free(altname); - freeaddrinfo(res); + "failed to get subjectName\n"); + if (certStatus && !*certStatus) { + *certStatus = CERT_STATUS_INVALID_SUBJALTNAME; + } + CFRelease(certificate); return ISAKMP_NTYPE_INVALID_CERTIFICATE; } - error = memcmp(id_b + 1, a, idlen); - freeaddrinfo(res); - vfree(name); - if (error != 0) { + count = CFArrayGetCount(names); + ID = CFStringCreateWithCString(NULL, id, kCFStringEncodingUTF8); + if (ID == NULL) { plog(LLV_ERROR, LOCATION, NULL, - "ID mismatched with subjectAltName.\n"); - return ISAKMP_NTYPE_INVALID_ID_INFORMATION; + "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; + } } - return 0; + plog(LLV_ERROR, LOCATION, NULL, "ID mismatched with subjectAltName.\n"); + plog(LLV_ERROR, LOCATION, NULL, + "subjectAltName (expected type %s):\n", s_ipsecdoi_ident(idtype)); + plog(LLV_ERROR, LOCATION, NULL, "ID:\n"); + plogdump(LLV_ERROR, id, idlen); + 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) != 0){ + if (eay_get_x509subjectaltname(cert, &altname, &type, pos, &len) != 0) { plog(LLV_ERROR, LOCATION, NULL, "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(LLV_ERROR, LOCATION, NULL, - "no proper subjectAltName.\n"); - return ISAKMP_NTYPE_INVALID_CERTIFICATE; + "invalid subjectAltName\n"); + if (certStatus && !*certStatus) { + *certStatus = CERT_STATUS_INVALID_SUBJALTNAME; + } + return ISAKMP_NTYPE_INVALID_ID_INFORMATION; } - if (check_typeofcertname(id_b->type, type) == 0) - break; + if (check_typeofcertname(idtype, type) != 0) { + /* wrong general type - skip this one */ + racoon_free(altname); + altname = NULL; + continue; + } - /* 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"); + if (idlen != strlen(altname)) { + /* wrong length - skip this one */ + racoon_free(altname); + altname = NULL; + continue; + } + error = memcmp(id, altname, idlen); + if (error) + continue; racoon_free(altname); - return ISAKMP_NTYPE_INVALID_ID_INFORMATION; + return 0; } + plog(LLV_ERROR, LOCATION, NULL, "ID mismatched with subjectAltName.\n"); + plog(LLV_ERROR, LOCATION, NULL, + "subjectAltName (expected type %s, got type %s):\n", + s_ipsecdoi_ident(idtype), + s_ipsecdoi_ident(type)); + plogdump(LLV_ERROR, altname, len); + plog(LLV_ERROR, LOCATION, NULL, + "ID:\n"); + plogdump(LLV_ERROR, id, idlen); racoon_free(altname); - return 0; + if (certStatus && !*certStatus) + *certStatus = CERT_STATUS_INVALID_SUBJALTNAME; + return ISAKMP_NTYPE_INVALID_ID_INFORMATION; } +#endif default: plog(LLV_ERROR, LOCATION, NULL, "Impropper ID type passed: %s.\n", - s_ipsecdoi_ident(id_b->type)); + s_ipsecdoi_ident(idtype)); return ISAKMP_NTYPE_INVALID_ID_INFORMATION; - } + } /*NOTREACHED*/ } - -#endif /* __APPLE__ */ - +#ifdef HAVE_OPENSSL static int check_typeofcertname(doi, genid) int doi, genid; @@ -2287,6 +2886,7 @@ check_typeofcertname(doi, genid) } /*NOTREACHED*/ } +#endif /* * save certificate including certificate type. @@ -2298,9 +2898,10 @@ oakley_savecert(iph1, gen) { cert_t **c; u_int8_t type; +#ifdef HAVE_OPENSSL STACK_OF(X509) *certs=NULL; PKCS7 *p7; - +#endif type = *(u_int8_t *)(gen + 1) & 0xff; switch (type) { @@ -2331,14 +2932,11 @@ oakley_savecert(iph1, gen) 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; + "preexisting CERT payload... chaining.\n"); } - +#ifdef HAVE_OPENSSL if (type == ISAKMP_CERT_PKCS7) { u_char *bp; int i; @@ -2385,54 +2983,38 @@ oakley_savecert(iph1, gen) for (i = 0; i < sk_X509_num(certs); i++) { int len; u_char *bp; + cert_t *new; 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) { + new = save_certx509(cert); + if (!new) { 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; + *c = oakley_appendcert_to_certchain(*c, new); + plog(LLV_DEBUG, LOCATION, NULL, "CERT saved:\n"); + plogdump(LLV_DEBUG, new->cert.v, new->cert.l); + oakley_cert_prettyprint(&new->cert); } PKCS7_free(p7); - } else { - *c = save_certbuf(gen); - if (!*c) { + } else +#endif + { + cert_t *new; + new = save_certbuf(gen); + if (!new) { plog(LLV_ERROR, LOCATION, NULL, "Failed to get CERT buffer.\n"); return -1; } - switch ((*c)->type) { + switch (new->type) { case ISAKMP_CERT_DNS: plog(LLV_WARNING, LOCATION, NULL, "CERT payload is unnecessary in DNSSEC. " @@ -2446,34 +3028,23 @@ oakley_savecert(iph1, gen) * 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; - } - - { - 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); - } + *c = oakley_appendcert_to_certchain(*c, new); + plog(LLV_DEBUG, LOCATION, NULL, "CERT saved:\n"); + plogdump(LLV_DEBUG, new->cert.v, new->cert.l); + oakley_cert_prettyprint(&new->cert); break; case ISAKMP_CERT_CRL: + *c = oakley_appendcert_to_certchain(*c, new); plog(LLV_DEBUG, LOCATION, NULL, "CRL saved:\n"); - plogdump(LLV_DEBUG, (*c)->cert.v, (*c)->cert.l); + plogdump(LLV_DEBUG, new->cert.v, new->cert.l); + oakley_cert_prettyprint(&new->cert); break; case ISAKMP_CERT_X509KE: case ISAKMP_CERT_X509ATTR: case ISAKMP_CERT_ARL: default: /* XXX */ - oakley_delcert((*c)); - *c = NULL; + oakley_delcert(new); return 0; } } @@ -2491,6 +3062,7 @@ oakley_savecr(iph1, gen) { cert_t **c; u_int8_t type; + cert_t *new; type = *(u_int8_t *)(gen + 1) & 0xff; @@ -2504,6 +3076,10 @@ oakley_savecr(iph1, gen) 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: @@ -2519,15 +3095,15 @@ oakley_savecr(iph1, gen) return -1; } - *c = save_certbuf(gen); - if (!*c) { + new = save_certbuf(gen); + if (!new) { plog(LLV_ERROR, LOCATION, NULL, "Failed to get CR buffer.\n"); return -1; } - + *c = oakley_appendcert_to_certchain(*c, new); plog(LLV_DEBUG, LOCATION, NULL, "CR saved:\n"); - plogdump(LLV_DEBUG, (*c)->cert.v, (*c)->cert.l); + plogdump(LLV_DEBUG, new->cert.v, new->cert.l); return 0; } @@ -2538,6 +3114,12 @@ save_certbuf(gen) { cert_t *new; + if(ntohs(gen->len) <= sizeof(*gen)){ + plog(LLV_ERROR, LOCATION, NULL, + "Len is too small !!.\n"); + return NULL; + } + new = oakley_newcert(); if (!new) { plog(LLV_ERROR, LOCATION, NULL, @@ -2561,6 +3143,7 @@ save_certbuf(gen) return new; } +#ifdef HAVE_OPENSSL static cert_t * save_certx509(cert) X509 *cert; @@ -2593,6 +3176,7 @@ save_certx509(cert) return new; } +#endif /* * get my CR. @@ -2613,10 +3197,15 @@ oakley_getcr(iph1) "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(LLV_DEBUG, LOCATION, NULL, "create my CR: NONE, using %s instead\n", + s_isakmp_certtype(iph1->rmconf->cacerttype)); + } else { + buf->v[0] = iph1->rmconf->certtype; + plog(LLV_DEBUG, LOCATION, NULL, "create my CR: %s\n", s_isakmp_certtype(iph1->rmconf->certtype)); + } if (buf->l > 1) plogdump(LLV_DEBUG, buf->v, buf->l); @@ -2660,6 +3249,10 @@ oakley_needcr(type) #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: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_I: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_R: #endif return 1; default: @@ -2685,9 +3278,12 @@ oakley_skeyid(iph1) int error = -1; /* SKEYID */ - switch(iph1->approval->authmethod) { + switch (AUTHMETHOD(iph1)) { case OAKLEY_ATTR_AUTH_METHOD_PSKEY: -#ifdef __APPLE__ +#ifdef ENABLE_HYBRID + case FICTIVE_AUTH_METHOD_XAUTH_PSKEY_I: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_R: +#endif if (iph1->rmconf->shared_secret) { switch (iph1->rmconf->secrettype) { @@ -2695,6 +3291,7 @@ oakley_skeyid(iph1) /* 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; +#if HAVE_KEYCHAIN case SECRETTYPE_KEYCHAIN: /* in the system keychain */ iph1->authstr = getpskfromkeychain(iph1->rmconf->shared_secret->v, iph1->etype, iph1->rmconf->secrettype, NULL); @@ -2703,15 +3300,20 @@ oakley_skeyid(iph1) /* in the system keychain - use peer id */ iph1->authstr = 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: - iph1->authstr = vdup(iph1->rmconf->shared_secret); + /* rmconf->shared_secret is a string and contains a NULL character that must be removed */ + iph1->authstr = vmalloc(iph1->rmconf->shared_secret->l - 1); + if (iph1->authstr == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "memory error.\n"); + break; + } + memcpy(iph1->authstr->v, iph1->rmconf->shared_secret->v, iph1->authstr->l); } - } else -#endif if (iph1->etype != ISAKMP_ETYPE_IDENT) { iph1->authstr = getpskbyname(iph1->id_p); if (iph1->authstr == NULL) { @@ -2778,6 +3380,10 @@ oakley_skeyid(iph1) 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_XAUTH_RSASIG_I: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_R: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_I: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_R: #endif #ifdef HAVE_GSSAPI case OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB: @@ -2809,6 +3415,12 @@ oakley_skeyid(iph1) 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 plog(LLV_WARNING, LOCATION, NULL, "not supported authentication method %s\n", s_oakley_attr_method(iph1->approval->authmethod)); @@ -2878,7 +3490,7 @@ oakley_skeyid_dae(iph1) buf = NULL; plog(LLV_DEBUG, LOCATION, NULL, "SKEYID_d computed:\n"); - plogdump(LLV_DEBUG, iph1->skeyid_d->v, iph1->skeyid->l); + plogdump(LLV_DEBUG, iph1->skeyid_d->v, iph1->skeyid_d->l); /* SKEYID A */ /* SKEYID_a = prf(SKEYID, SKEYID_d | g^xy | CKY-I | CKY-R | 1) */ @@ -3100,13 +3712,14 @@ oakley_newcert() } new->pl = NULL; + new->chain = NULL; return new; } /* delete buffer for CERT */ void -oakley_delcert(cert) +oakley_delcert_1(cert) cert_t *cert; { if (!cert) @@ -3116,6 +3729,43 @@ oakley_delcert(cert) racoon_free(cert); } +/* delete buffer for CERT */ +void +oakley_delcert(cert) + 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(certchain, new) + 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) @@ -3191,6 +3841,9 @@ oakley_newiv(iph1) plog(LLV_DEBUG, LOCATION, NULL, "IV computed:\n"); plogdump(LLV_DEBUG, newivm->iv->v, newivm->iv->l); + if (iph1->ivm != NULL) + oakley_delivm(iph1->ivm); + iph1->ivm = newivm; return 0; @@ -3290,6 +3943,7 @@ oakley_delivm(ivm) if (ivm->ive != NULL) vfree(ivm->ive); racoon_free(ivm); + plog(LLV_DEBUG, LOCATION, NULL, "IV freed\n"); return; } @@ -3344,7 +3998,7 @@ oakley_do_decrypt(iph1, msg, ivdp, ivep) /* do decrypt */ new = alg_oakley_encdef_decrypt(iph1->approval->enctype, buf, iph1->key, ivdp); - if (new == NULL) { + if (new == NULL || new->v == NULL || new->l == 0) { plog(LLV_ERROR, LOCATION, NULL, "decryption %d failed.\n", iph1->approval->enctype); goto end; @@ -3545,7 +4199,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 @@ -3623,4 +4276,4 @@ static int base64toCFData(vchar_t *textin, CFDataRef *dataRef) return -1; } -#endif +