Sophie

Sophie

distrib > Mageia > 6 > armv7hl > media > core-release-src > by-pkgid > 8e6f31fb43c5dc7e676a6f6234c70858 > files > 3

openswan-2.6.39-10.mga6.src.rpm

From b36d3109d05f1b069a0a712de7777cef6f6a48e4 Mon Sep 17 00:00:00 2001
From: Patrick Naubert <patrickn@xelerance.com>
Date: Tue, 18 Feb 2014 18:55:39 -0500
Subject: [PATCH] Fix for CVE-2014-2037

CVE-2014-2037 is a continuation of CVE-2013-6466.  We missed some
cases.  This patch was taken from RedHat's Openswan patch cluster.

Original authors of this patch are Paul Wouters and Hugh Redelmeier.
---
 include/constants.h           |   1 +
 include/ietf_constants.h      |   4 +-
 include/names_constant.h      |   3 +
 include/packet.h              |   2 +-
 lib/libopenswan/constants.c   |  25 ++---
 lib/libpluto/packet.c         |   9 +-
 programs/pluto/demux.h        |   5 +-
 programs/pluto/ikev1.c        |   7 +-
 programs/pluto/ikev2.c        | 234 ++++++++++++++++++++++++++----------------
 programs/pluto/ikev2.h        |   5 +-
 programs/pluto/ikev2_parent.c |  30 +-----
 11 files changed, 186 insertions(+), 139 deletions(-)

diff --git a/include/constants.h b/include/constants.h
index ac89852..ed27cf2 100644
--- a/include/constants.h
+++ b/include/constants.h
@@ -76,6 +76,7 @@
  */
 
 typedef unsigned long long lset_t;
+#define LELEM_ROOF  64  /* all elements must be less than this */
 #define LEMPTY 0ULL
 #define LELEM(opt) (1ULL << (opt))
 #define LRANGE(lwb, upb) LRANGES(LELEM(lwb), LELEM(upb))
diff --git a/include/ietf_constants.h b/include/ietf_constants.h
index a897d40..3a0e023 100644
--- a/include/ietf_constants.h
+++ b/include/ietf_constants.h
@@ -4,7 +4,7 @@
  * Copyright (C) 2012 Paul Wouters <pwouters@redhat.com>
  * Copyright (C) 2004 Michael Richardson <mcr@xelerance.com>
  * Copyright (C) 1997 Angelos D. Keromytis.
- * Copyright (C) 1998-2002  D. Hugh Redelmeier.
+ * Copyright (C) 1998-2002,2014  D. Hugh Redelmeier.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
@@ -388,6 +388,8 @@ enum next_payload_types {
 	ISAKMP_NEXT_NATOA_DRAFTS = 131   /* NAT-Traversal: NAT-OA (drafts) */
 };
 
+#define ISAKMP_v2PAYLOAD_TYPE_BASE     ISAKMP_NEXT_v2SA        /* lowest value of a v2 payload type */
+
 /* These values are to be used within the Type field of an Attribute (14) 
  *    ISAKMP payload.  */
 #define ISAKMP_CFG_REQUEST         1
diff --git a/include/names_constant.h b/include/names_constant.h
index 96515a2..e22e517 100644
--- a/include/names_constant.h
+++ b/include/names_constant.h
@@ -30,7 +30,10 @@
 extern enum_names version_names;
 extern enum_names doi_names;
 extern enum_names payload_names;
+extern enum_names payload_names_ikev2;
 extern const char *const payload_name[];
+extern const char *const payload_name_ikev2[];
+extern const char *const payload_name_ikev2_main[];
 extern enum_names attr_msg_type_names;
 extern enum_names modecfg_attr_names;
 extern enum_names xauth_type_names;
diff --git a/include/packet.h b/include/packet.h
index 4aa647a..c5c7d51 100644
--- a/include/packet.h
+++ b/include/packet.h
@@ -671,7 +671,7 @@ struct isakmp_nat_oa
  * That leaves only Identification payloads as a problem.
  * We make all these entries NULL
  */
-extern struct_desc *const payload_descs[ISAKMP_NEXT_ROOF];
+extern const struct_desc *payload_desc(unsigned p);
 
 /*
  * IKEv2 structures
diff --git a/lib/libopenswan/constants.c b/lib/libopenswan/constants.c
index 3bfb22b..932b205 100644
--- a/lib/libopenswan/constants.c
+++ b/lib/libopenswan/constants.c
@@ -146,7 +146,8 @@ enum_names connection_kind_names =
 	NULL
     };
 
-const char *const payload_names_ikev2[] = {
+/* dual-use: for enum_name and for bitnamesof */
+const char *const payload_name_ikev2_main[] = {
     "ISAKMP_NEXT_v2SA",            /* 33 */
     "ISAKMP_NEXT_v2KE",
     "ISAKMP_NEXT_v2IDi",
@@ -163,23 +164,23 @@ enum_names connection_kind_names =
     "ISAKMP_NEXT_v2E",
     "ISAKMP_NEXT_v2CP",
     "ISAKMP_NEXT_v2EAP",
-    NULL
+    NULL    /* termination for bitnamesof() */
 };
 
-const char *const payload_name_nat_d[] = {
-    "ISAKMP_NEXT_NAT-D",
-    "ISAKMP_NEXT_NAT-OA",
-    NULL
+static enum_names payload_names_ikev2_main =
+{ ISAKMP_NEXT_v2SA, ISAKMP_NEXT_v2EAP, payload_name_ikev2_main,
+  NULL };
+
+const char *const payload_name_ikev2[] = {
+    "ISAKMP_NEXT_v2NONE",            /* 33 */
 };
 
-static enum_names payload_names_nat_d =
-{ ISAKMP_NEXT_NATD_DRAFTS, ISAKMP_NEXT_NATOA_DRAFTS, payload_name_nat_d, NULL };
-static enum_names payload_names_ikev2_d =
-{ ISAKMP_NEXT_v2SA, ISAKMP_NEXT_v2EAP, payload_names_ikev2, &payload_names_nat_d };
+enum_names payload_names_ikev2 =
+{ ISAKMP_NEXT_NONE, ISAKMP_NEXT_NONE, payload_name_ikev2,
+  &payload_names_ikev2_main };
 
 enum_names payload_names =
-{ ISAKMP_NEXT_NONE, ISAKMP_NEXT_NATOA_RFC, payload_name, &payload_names_ikev2_d };
-
+{ ISAKMP_NEXT_NONE, ISAKMP_NEXT_NATOA_RFC, payload_name, &payload_names_ikev2_main };
 
 /* Exchange types (note: two discontinuous ranges) */
 
diff --git a/lib/libpluto/packet.c b/lib/libpluto/packet.c
index 1675507..ce312b9 100644
--- a/lib/libpluto/packet.c
+++ b/lib/libpluto/packet.c
@@ -1,6 +1,6 @@
 /* parsing packets: formats and tools
  * Copyright (C) 1997 Angelos D. Keromytis.
- * Copyright (C) 1998-2001  D. Hugh Redelmeier.
+ * Copyright (C) 1998-2001,2013-2014  D. Hugh Redelmeier.
  * Copyright (C) 2012 Avesh Agarwal <avagarwa@redhat.com>
  * Copyright (C) 2012 Paul Wouters <pwouters@redhat.com>
  *
@@ -1106,7 +1106,7 @@ struct_desc ikev2_e_desc = { "IKEv2 Encryption Payload",
  * That leaves only Identification payloads as a problem.
  * We make all these entries NULL
  */
-struct_desc *const payload_descs[ISAKMP_NEXT_ROOF] = {
+static struct_desc *const payload_descs[] = {
     NULL,				/* 0 ISAKMP_NEXT_NONE (No other payload following) */
     &isakmp_sa_desc,			/* 1 ISAKMP_NEXT_SA (Security Association) */
     NULL,				/* 2 ISAKMP_NEXT_P (Proposal) */
@@ -1146,6 +1146,11 @@ struct_desc *const payload_descs[ISAKMP_NEXT_ROOF] = {
     &ikev2_e_desc,                      /* 46 */
 };
 
+const struct_desc *payload_desc(unsigned p)
+{
+	return p < elemsof(payload_descs) ? payload_descs[p] : NULL;
+}
+
 void
 init_pbs(pb_stream *pbs, u_int8_t *start, size_t len, const char *name)
 {
diff --git a/programs/pluto/demux.h b/programs/pluto/demux.h
index 520577c..296395e 100644
--- a/programs/pluto/demux.h
+++ b/programs/pluto/demux.h
@@ -81,8 +81,9 @@ struct msg_digest {
 #   define PAYLIMIT 30
     struct payload_digest
 	digest[PAYLIMIT],
-	*digest_roof,
-	*chain[ISAKMP_NEXT_ROOF];
+	*digest_roof;
+	struct payload_digest
+		*chain[(unsigned)ISAKMP_NEXT_ROOF];
     struct isakmp_quirks quirks;
 };
 
diff --git a/programs/pluto/ikev1.c b/programs/pluto/ikev1.c
index 13ae193..cb0b370 100644
--- a/programs/pluto/ikev1.c
+++ b/programs/pluto/ikev1.c
@@ -1557,7 +1557,7 @@ void process_packet_tail(struct msg_digest **mdp)
 
 	while (np != ISAKMP_NEXT_NONE)
 	{
-	    struct_desc *sd = np < ISAKMP_NEXT_ROOF? payload_descs[np] : NULL;
+	    struct_desc *sd = payload_desc(np);
 
 	    if (pd == &md->digest[PAYLIMIT])
 	    {
@@ -1604,12 +1604,12 @@ void process_packet_tail(struct msg_digest **mdp)
 #ifdef NAT_TRAVERSAL
 		case ISAKMP_NEXT_NATD_DRAFTS:
 		    np = ISAKMP_NEXT_NATD_RFC;  /* NAT-D relocated */
-		    sd = payload_descs[np];
+		    sd = payload_desc(np);
 		    break;
 
 		case ISAKMP_NEXT_NATOA_DRAFTS:
 		    np = ISAKMP_NEXT_NATOA_RFC;  /* NAT-OA relocated */
-		    sd = payload_descs[np];
+		    sd = payload_desc(np);
 		    break;
 #endif
 		default:
@@ -1619,6 +1619,7 @@ void process_packet_tail(struct msg_digest **mdp)
 		    SEND_NOTIFICATION(INVALID_PAYLOAD_TYPE);
 		    return;
 		}
+	    passert(sd != NULL);
 	    }
 
 	    {
diff --git a/programs/pluto/ikev2.c b/programs/pluto/ikev2.c
index f88956a..b667df1 100644
--- a/programs/pluto/ikev2.c
+++ b/programs/pluto/ikev2.c
@@ -81,20 +81,18 @@ struct state_v2_microcode {
     enum state_kind state, next_state;
     enum isakmp_xchg_types recv_type;
     lset_t flags;
-    lset_t req_payloads;	/* required payloads (allows just one) */
-    lset_t opt_payloads;	/* optional payloads (any mumber) */
+    lset_t req_clear_payloads;  /* required unencrypted payloads (allows just one) for received packet */
+    lset_t opt_clear_payloads;  /* optional unencrypted payloads (none or one) for received packet */
+    lset_t req_enc_payloads;  /* required encrypted payloads (allows just one) for received packet */
+    lset_t opt_enc_payloads;  /* optional encrypted payloads (none or one) for received packet */
     enum event_type timeout_event;
     state_transition_fn *processor;
 };
 
 enum smf2_flags {
     SMF2_INITIATOR = LELEM(1),
-    SMF2_RESPONDER = 0,
-
-    SMF2_STATENEEDED=LELEM(2),
-    SMF2_NEWSTATE  = 0,
-
-    SMF2_REPLY     = LELEM(3),
+    SMF2_STATENEEDED = LELEM(2),
+    SMF2_REPLY = LELEM(3),
 };
 
 /*
@@ -133,18 +131,26 @@ enum smf2_flags {
  *
  */
 
-/* it is not clear how the flags will be used yet, if at all */
+#define PT(n) ISAKMP_NEXT_v2 ## n
+#define P(n) LELEM(PT(n) - ISAKMP_v2PAYLOAD_TYPE_BASE)
+static const lset_t everywhere_payloads = P(N) | P(V); /* can appear in any packet */
+static const lset_t repeatable_payloads = P(N) | P(D) | P(CP) | P(V);  /* if one can appear, many can appear */
 
-static const struct state_v2_microcode state_microcode_table[] = {
+/* microcode to parent first initiator state: not associated with an input packet */
+const struct state_v2_microcode ikev2_parent_firststate_microcode =
     { .state      = STATE_UNDEFINED,
       .next_state = STATE_PARENT_I1,
       .flags      = SMF2_INITIATOR,
       .processor  = NULL,
-    },
+};
 
+/* microcode for input packet processing */
+static const struct state_v2_microcode v2_state_microcode_table[] = {
     { .state      = STATE_PARENT_I1,
       .next_state = STATE_PARENT_I2,
       .flags = SMF2_INITIATOR|SMF2_STATENEEDED|SMF2_REPLY,
+      .req_clear_payloads = P(SA) | P(KE) | P(Nr),
+      .opt_clear_payloads = P(CERTREQ),
       .processor  = ikev2parent_inR1outI2,
       .recv_type  = ISAKMP_v2_SA_INIT,
     },
@@ -152,6 +158,9 @@ enum smf2_flags {
     { .state      = STATE_PARENT_I2,
       .next_state = STATE_PARENT_I3,
       .flags = SMF2_INITIATOR|SMF2_STATENEEDED,
+      .req_clear_payloads = P(E),
+      .req_enc_payloads = P(IDr) | P(AUTH) | P(SA) | P(TSi) | P(TSr),
+      .opt_enc_payloads = P(CERT),
       .processor  = ikev2parent_inR2,
       .recv_type  = ISAKMP_v2_AUTH,
       .timeout_event = EVENT_SA_REPLACE,
@@ -159,14 +168,18 @@ enum smf2_flags {
 
     { .state      = STATE_UNDEFINED,
       .next_state = STATE_PARENT_R1,
-      .flags = SMF2_RESPONDER|SMF2_NEWSTATE|SMF2_REPLY,
+      .flags =  /* not SMF2_INITIATOR, not SMF2_STATENEEDED */ SMF2_REPLY,
+      .req_clear_payloads = P(SA) | P(KE) | P(Ni),
       .processor  = ikev2parent_inI1outR1,
       .recv_type  = ISAKMP_v2_SA_INIT,
     },
 
     { .state      = STATE_PARENT_R1,
       .next_state = STATE_PARENT_R2,
-      .flags = SMF2_RESPONDER|SMF2_STATENEEDED|SMF2_REPLY,
+      .flags =  /* not SMF2_INITIATOR */ SMF2_STATENEEDED | SMF2_REPLY,
+      .req_clear_payloads = P(E),
+      .req_enc_payloads = P(IDi) | P(AUTH) | P(SA) | P(TSi) | P(TSr),
+      .opt_enc_payloads = P(CERT) | P(CERTREQ) | P(IDr),
       .processor  = ikev2parent_inI2outR2,
       .recv_type  = ISAKMP_v2_AUTH,
       .timeout_event = EVENT_SA_REPLACE,
@@ -176,6 +189,8 @@ enum smf2_flags {
     { .state      = STATE_PARENT_I2,
       .next_state = STATE_PARENT_I2,
       .flags      = SMF2_STATENEEDED,
+      .req_clear_payloads = P(E),
+      .opt_enc_payloads = P(N) | P(D) | P(CP),
       .processor  = process_informational_ikev2,
       .recv_type  = ISAKMP_v2_INFORMATIONAL,
     },
@@ -185,6 +200,8 @@ enum smf2_flags {
     { .state      = STATE_PARENT_R1,
       .next_state = STATE_PARENT_R1,
       .flags      = SMF2_STATENEEDED,
+      .req_clear_payloads = P(E),
+      .opt_enc_payloads = P(N) | P(D) | P(CP),
       .processor  = process_informational_ikev2,
       .recv_type  = ISAKMP_v2_INFORMATIONAL,
     },
@@ -193,6 +210,8 @@ enum smf2_flags {
     { .state      = STATE_PARENT_I3,
       .next_state = STATE_PARENT_I3,
       .flags      = SMF2_STATENEEDED,
+      .req_clear_payloads = P(E),
+      .opt_enc_payloads = P(N) | P(D) | P(CP),
       .processor  = process_informational_ikev2,
       .recv_type  = ISAKMP_v2_INFORMATIONAL,
     },
@@ -201,6 +220,8 @@ enum smf2_flags {
     { .state      = STATE_PARENT_R2,
       .next_state = STATE_PARENT_R2,
       .flags      = SMF2_STATENEEDED,
+      .req_clear_payloads = P(E),
+      .opt_enc_payloads = P(N) | P(D) | P(CP),
       .processor  = process_informational_ikev2,
       .recv_type  = ISAKMP_v2_INFORMATIONAL,
     },
@@ -209,6 +230,8 @@ enum smf2_flags {
     { .state      = STATE_IKESA_DEL,
       .next_state = STATE_IKESA_DEL,
       .flags      = SMF2_STATENEEDED,
+      .req_clear_payloads = P(E),
+      .opt_enc_payloads = P(N) | P(D) | P(CP),
       .processor  = process_informational_ikev2,
       .recv_type  = ISAKMP_v2_INFORMATIONAL,
     },
@@ -218,105 +241,143 @@ enum smf2_flags {
     { .state      = STATE_IKEv2_ROOF }
 };
 
-
-const struct state_v2_microcode *ikev2_parent_firststate()
-{
-    return &state_microcode_table[0];
-}
-
+#undef P
+#undef PT
 
 /*
  * split up an incoming message into payloads
  */
-stf_status
+static stf_status
 ikev2_process_payloads(struct msg_digest *md,
 			    pb_stream    *in_pbs,
-			    unsigned int from_state,
-			    unsigned int np)
+          unsigned int np,
+          lset_t req_payloads,
+          lset_t opt_payloads)
 {
     struct payload_digest *pd = md->digest_roof;
-    struct state *st = md->st;
-
-    /* lset_t needed = smc->req_payloads; */
-
-    /* zero out the digest descriptors -- might nuke [v2E] digest! */
+    lset_t seen = LEMPTY;
+    /* ??? zero out the digest descriptors -- might nuke ISAKMP_NEXT_v2E digest! */
 
     while (np != ISAKMP_NEXT_NONE)
     {
-	struct_desc *sd = np < ISAKMP_NEXT_ROOF? payload_descs[np] : NULL;
-	int thisp = np;
-	bool unknown_payload = FALSE;
+  struct_desc *sd = payload_desc(np);
 
 	memset(pd, 0, sizeof(*pd));
 
 	if (pd == &md->digest[PAYLIMIT])
 	{
 	    loglog(RC_LOG_SERIOUS, "more than %d payloads in message; ignored", PAYLIMIT);
-	    SEND_NOTIFICATION(PAYLOAD_MALFORMED);
-	    return STF_FAIL;
+      return STF_FAIL + v2N_INVALID_SYNTAX;
 	}
 
-	if (sd == NULL)
-	{
-	    unknown_payload = TRUE;
-	    sd = &ikev2_generic_desc;
+
+  memset(pd, 0, sizeof(*pd));     /* ??? is this needed? */
+
+
+  if (sd == NULL || np < ISAKMP_v2PAYLOAD_TYPE_BASE) {
+    /* This payload is unknown to us.
+     * RFCs 4306 and 5996 2.5 say that if the payload
+     * has the Critical Bit, we should be upset
+     * but if it does not, we should just ignore it.
+     */
+    if (!in_struct(&pd->payload, &ikev2_generic_desc, in_pbs, &pd->pbs)) {
+      loglog(RC_LOG_SERIOUS, "malformed payload in packet");
+      return STF_FAIL + v2N_INVALID_SYNTAX;
+    }
+    if (pd->payload.v2gen.isag_critical & ISAKMP_PAYLOAD_CRITICAL) {
+      /* It was critical.
+       * See RFC 5996 1.5 "Version Numbers and Forward Compatibility"
+       * ??? we are supposed to send the offending np byte back in the
+       * notify payload.
+       */
+      loglog(RC_LOG_SERIOUS,
+             "critical payload (%s) was not understood. Message dropped.",
+             enum_show(&payload_names_ikev2, np));
+      return STF_FAIL + v2N_UNSUPPORTED_CRITICAL_PAYLOAD;
+    }
+    loglog(RC_COMMENT, "non-critical payload ignored because it contains an unknown or"
+           " unexpected payload type (%s) at the outermost level",
+           enum_show(&payload_names_ikev2, np));
+    np = pd->payload.generic.isag_np;
+    continue;
 	}
 
-	/* why to process an unknown payload*/
-	/* critical bit in RFC 4306/5996 is just 1 bit not a byte*/
-	/* As per RFC other 7 bits are RESERVED and should be ignored*/
-	if(unknown_payload) {
-	    if(pd->payload.v2gen.isag_critical & ISAKMP_PAYLOAD_CRITICAL) {
-		/* it was critical */
-		loglog(RC_LOG_SERIOUS, "critical payload (%s) was not understood. Message dropped."
-		       , enum_show(&payload_names, thisp));
-		return STF_FATAL;
-	    }
-	    loglog(RC_COMMENT, "non-critical payload ignored because it contains an unknown or"
-		   " unexpected payload type (%s) at the outermost level"
-		   , enum_show(&payload_names, thisp));
+  passert(np - ISAKMP_v2PAYLOAD_TYPE_BASE < LELEM_ROOF);
+
+  {
+    lset_t s = LELEM(np - ISAKMP_v2PAYLOAD_TYPE_BASE);
+
+    if (s & seen & ~repeatable_payloads) {
+      /* improperly repeated payload */
+      loglog(RC_LOG_SERIOUS,
+             "payload (%s) unexpectedly repeated. Message dropped.",
+             enum_show(&payload_names_ikev2, np));
+      return STF_FAIL + v2N_INVALID_SYNTAX;
+    }
+    if ((s & (req_payloads | opt_payloads | everywhere_payloads)) == LEMPTY) {
+      /* unexpected payload */
+      loglog(RC_LOG_SERIOUS,
+             "payload (%s) unexpected. Message dropped.",
+             enum_show(&payload_names_ikev2, np));
+      return STF_FAIL + v2N_INVALID_SYNTAX;
+    }
+    seen |= s;
 	}
 
 	if (!in_struct(&pd->payload, sd, in_pbs, &pd->pbs))
 	{
-	    loglog(RC_LOG_SERIOUS, "malformed payload in packet");
-	    SEND_NOTIFICATION(PAYLOAD_MALFORMED);
-	    return STF_FAIL;
+      loglog(RC_LOG_SERIOUS, "malformed payload in packet");
+      return STF_FAIL + v2N_INVALID_SYNTAX;
 	}
 
 
 	DBG(DBG_PARSING
 	    , DBG_log("processing payload: %s (len=%u)\n"
-		      , enum_show(&payload_names, thisp)
+          , enum_show(&payload_names, np)
 		      , pd->payload.generic.isag_length));
 
 	/* place this payload at the end of the chain for this type */
 	{
 	    struct payload_digest **p;
 
-	    for (p = &md->chain[thisp]; *p != NULL; p = &(*p)->next)
+      for (p = &md->chain[np]; *p != NULL; p = &(*p)->next)
 		;
 	    *p = pd;
 	    pd->next = NULL;
 	}
 
-	np = pd->payload.generic.isag_np;
-
-	/* do payload-type specific things that need to be here. */
-	switch(thisp) {
+  switch(np) {
 	case ISAKMP_NEXT_v2E:
 	    np = ISAKMP_NEXT_NONE;
 	    break;
-	default:   /* nothing special */
+  default:
+      np = pd->payload.generic.isag_np;
 	    break;
 	}
 
 	pd++;
     }
+
+    if (req_payloads & ~seen) {
+   /* improperly repeated payload */
+   loglog(RC_LOG_SERIOUS,
+     "missing payload(s) (%s). Message dropped.",
+     bitnamesof(payload_name_ikev2_main, req_payloads & ~seen));
+   return STF_FAIL + v2N_INVALID_SYNTAX;
+     }
+
     md->digest_roof = pd;
     return STF_OK;
 }
 
+/* this stub is needed because struct state_v2_microcode is local to this file */
+stf_status ikev2_process_encrypted_payloads(struct msg_digest *md,
+            pb_stream   *in_pbs,
+            unsigned int np)
+{
+  return ikev2_process_payloads(md, in_pbs, np, md->svm->req_enc_payloads, md->svm->opt_enc_payloads);
+}
+
 /*
  * process an input packet, possibly generating a reply.
  *
@@ -468,7 +526,7 @@ const struct state_v2_microcode *ikev2_parent_firststate()
 	from_state = st->st_state;
     }
 
-    for(svm = state_microcode_table; svm->state != STATE_IKEv2_ROOF; svm++) {
+    for(svm = v2_state_microcode_table; svm->state != STATE_IKEv2_ROOF; svm++) {
 	if(svm->flags & SMF2_STATENEEDED) {
 	    if(st==NULL) continue;
 	}
@@ -502,10 +560,15 @@ const struct state_v2_microcode *ikev2_parent_firststate()
 	return;
     }
 
+    md->svm = svm;
+    md->from_state = from_state;
+    md->st = st;
+
     {
 	stf_status stf;
-	stf = ikev2_process_payloads(md, &md->message_pbs
-				     , from_state, md->hdr.isa_np);
+  stf = ikev2_process_payloads(md, &md->message_pbs,
+      md->hdr.isa_np,
+      svm->req_clear_payloads, svm->opt_clear_payloads);
 	if(stf != STF_OK) {
 	    complete_v2_state_transition(mdp, stf);
 	    return;
@@ -521,26 +583,7 @@ const struct state_v2_microcode *ikev2_parent_firststate()
 
     md->message_pbs.roof = md->message_pbs.cur;
 
-#if 0
-    /* check that all mandatory payloads appeared */
-    if (needed != 0)
-    {
-	loglog(RC_LOG_SERIOUS, "message for %s is missing payloads %s"
-	       , enum_show(&state_names, from_state)
-	       , bitnamesof(payload_name, needed));
-	SEND_NOTIFICATION(PAYLOAD_MALFORMED);
-	return;
-#endif
-
-    md->svm = svm;
-    md->from_state = from_state;
-    md->st  = st;
-
-    {
-	stf_status stf;
-	stf = (svm->processor)(md);
-	complete_v2_state_transition(mdp, stf);
-    }
+    complete_v2_state_transition(mdp, (svm->processor)(md));
 }
 
 bool
@@ -1077,10 +1120,25 @@ void complete_v2_state_transition(struct msg_digest **mdp
 v2_notification_t
 accept_v2_nonce(struct msg_digest *md, chunk_t *dest, const char *name)
 {
-    return accept_nonce(md, dest, name, ISAKMP_NEXT_v2Ni);
-}
+	pb_stream *nonce_pbs;
+	size_t len;
+
+	if(md->chain[ISAKMP_NEXT_v2Ni] == NULL) {
+		loglog(RC_LOG_SERIOUS, "missing nonce Ni");
+		return v2N_INVALID_SYNTAX;
+	}
 
+	nonce_pbs = &md->chain[ISAKMP_NEXT_v2Ni]->pbs;
+	len = pbs_left(nonce_pbs);
 
+	if (len < MINIMUM_NONCE_SIZE || MAXIMUM_NONCE_SIZE < len) {
+		loglog(RC_LOG_SERIOUS, "%s length not between %d and %d",
+			name, MINIMUM_NONCE_SIZE, MAXIMUM_NONCE_SIZE);
+		return v2N_INVALID_SYNTAX; /* ??? */
+	}
+	clonereplacechunk(*dest, nonce_pbs->cur, len, "nonce");
+	return NOTHING_WRONG;
+}
 
 /*
  * Local Variables:
diff --git a/programs/pluto/ikev2.h b/programs/pluto/ikev2.h
index 15ed6a4..355c3d5 100644
--- a/programs/pluto/ikev2.h
+++ b/programs/pluto/ikev2.h
@@ -40,7 +40,7 @@ extern void complete_v2_state_transition(struct msg_digest **mdp
 extern stf_status ikev2parent_inI2outR2(struct msg_digest *md);
 extern stf_status ikev2parent_inR2(struct msg_digest *md);
 
-extern const struct state_v2_microcode *ikev2_parent_firststate(void);
+extern const struct state_v2_microcode ikev2_parent_firststate_microcode;
 
 extern v2_notification_t accept_v2_nonce(struct msg_digest *md, chunk_t *dest
 				      , const char *name);
@@ -88,9 +88,8 @@ extern void send_v2_notification_from_state(struct state *st
 
 extern void send_v2_notification_from_md(struct msg_digest *md,u_int16_t type
    					 , chunk_t *data);
-extern stf_status ikev2_process_payloads(struct msg_digest *md,
+extern stf_status ikev2_process_encrypted_payloads(struct msg_digest *md,
 					 pb_stream   *in_pbs,
-					 unsigned int from_state,
 					 unsigned int np);
 
 extern bool ikev2_decode_peer_id(struct msg_digest *md
diff --git a/programs/pluto/ikev2_parent.c b/programs/pluto/ikev2_parent.c
index 1b22eda..475508b 100644
--- a/programs/pluto/ikev2_parent.c
+++ b/programs/pluto/ikev2_parent.c
@@ -216,7 +216,7 @@ static stf_status ikev2_parent_outI1_common(struct msg_digest *md
 
         ke->md = alloc_md();
         ke->md->from_state = STATE_IKEv2_BASE;
-        ke->md->svm = ikev2_parent_firststate();
+        ke->md->svm = &ikev2_parent_firststate_microcode;
         ke->md->st = st;
         set_suspended(st, ke->md);
 
@@ -928,7 +928,7 @@ stf_status ikev2parent_inR1outI2(struct msg_digest *md)
                                 st->st_dcookie);
                 DBG_log("next STATE_PARENT_I1 resend I1 with the dcookie"));
 
-            md->svm = ikev2_parent_firststate();
+            md->svm = &ikev2_parent_firststate_microcode;
 
             change_state(st, STATE_PARENT_I1);
             st->st_msgid_last_localreq = INVALID_MSGID;
@@ -947,23 +947,6 @@ stf_status ikev2parent_inR1outI2(struct msg_digest *md)
         }
 
     /*
-     * If we did not get a KE payload, we cannot continue. There * should be
-     * a Notify telling us why. We inform the user, but continue to try this
-     * connection via regular retransmit intervals.
-     */
-    if( md->chain[ISAKMP_NEXT_v2N]  && (md->chain[ISAKMP_NEXT_v2KE] == NULL))
-        {
-            const char *from_state_name = enum_name(&state_names, st->st_state);
-            const u_int16_t isan_type =  md->chain[ISAKMP_NEXT_v2N]->payload.v2n.isan_type;
-            openswan_log("%s: received %s"
-                         , from_state_name
-                         , enum_name(&ikev2_notify_names , isan_type));
-            return STF_FAIL + isan_type;
-        } else if( md->chain[ISAKMP_NEXT_v2N]) {
-        DBG(DBG_CONTROL,DBG_log("received a notify.."));
-    }
-
-    /*
      * the responder sent us back KE, Gr, Nr, and it's our time to calculate
      * the shared key values.
      */
@@ -1265,14 +1248,7 @@ stf_status ikev2_decrypt_msg(struct msg_digest *md
         init_pbs(&md->clr_pbs, encstart, enclen - (padlen+1), "cleartext");
     }
 
-    { stf_status ret;
-        ret = ikev2_process_payloads(md, &md->clr_pbs, st->st_state, np);
-        if(ret != STF_OK) {
-            return ret;
-        }
-    }
-
-    return STF_OK;
+    return ikev2_process_encrypted_payloads(md, &md->clr_pbs, np);
 }
 
 static stf_status ikev2_send_auth(struct connection *c
-- 
1.8.5.5