]> git.saurik.com Git - apple/ipsec.git/blobdiff - ipsec-tools/racoon/oakley.c
ipsec-146.3.tar.gz
[apple/ipsec.git] / ipsec-tools / racoon / oakley.c
index 1d5288579d197622537eb25a856cda0a08db55ef..eefa0fb135cb5a78621b4964ed6bfaeec2f21a35 100644 (file)
@@ -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.
 #include <sys/socket.h>        /* XXX for subjectaltname */
 #include <netinet/in.h>        /* XXX for subjectaltname */
 
-#include <openssl/x509.h>
+#ifdef HAVE_OPENSSL
 #include <openssl/pkcs7.h>
+#include <openssl/x509.h>
+#endif
 
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 #include <errno.h>
+#include <arpa/inet.h>
+#include <TargetConditionals.h>
 
 #if TIME_WITH_SYS_TIME
 # include <sys/time.h>
@@ -54,6 +60,9 @@
 #  include <time.h>
 # endif
 #endif
+#ifdef ENABLE_HYBRID
+#include <resolv.h>
+#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"
 #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 <CoreFoundation/CFData.h>
 #endif
-
-
+#include <CoreFoundation/CoreFoundation.h>
+#include "remoteconf.h"
+#include "vpn_control.h"
+#if TARGET_OS_EMBEDDED
+#include <Security/SecCertificate.h>
+#include <Security/SecCertificatePriv.h>
+#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
+