CVE-2013-7294: Improper Input Validation (CWE-20)
value: The ikev2parent_inI1outR1 function in pluto/ikev2_parent.c in libreswan before 3.7 allows remote attackers to cause a denial of service (restart) via an IKEv2 I1 notification without a KE payload.
CWE description: The product receives input or data, but it does
        not validate or incorrectly validates that the input has the
        properties that are required to process the data safely and
        correctly.
Published: 2014-01-16T05:05Z
Repository: https://github.com/libreswan/libreswan
Language: C
Files changed: programs/pluto/ikev2_parent.c
Commit date: 2013-11-26 19:46:49 -0500
Commit message: SECURITY: Properly handle IKEv2 I1 notification packet without KE payload

Diff: diff --git a/programs/pluto/ikev2_parent.c b/programs/pluto/ikev2_parent.c
index 72526ba03..ce67cc3c0 100644
--- a/programs/pluto/ikev2_parent.c
+++ b/programs/pluto/ikev2_parent.c
@@ -304,12 +304,10 @@ static void ikev2_parent_outI1_continue(struct pluto_crypto_req_cont *pcrc,
 		if (ke->md)
 			release_md(ke->md);
 	}
 	reset_cur_state();
 	reset_globals();
-
-	passert(GLOBALS_ARE_RESET());
 }
 
 /*
  * unpack the calculate KE value, store it in state.
  * used by IKEv2: parent, child (PFS)
@@ -727,22 +725,35 @@ stf_status ikev2parent_inI1outR1(struct msg_digest *md)
 	 * that might permit this group.  If we think we are being DOS'ed
 	 * then we should demand a cookie.
 	 */
 	{
 		struct ikev2_ke *ke;
+		char fromname[ADDRTOT_BUF];
+		addrtot(&md->sender, 0, fromname, ADDRTOT_BUF);
+
+		if (!md->chain[ISAKMP_NEXT_v2KE]) {
+			/* is this a notify? If so, log it */
+			if(md->chain[ISAKMP_NEXT_v2N]) {
+				libreswan_log("Received Notify(%d): %s",
+					md->chain[ISAKMP_NEXT_v2N]->payload.v2n.isan_type,
+					enum_name(&ikev2_notify_names,
+						md->chain[ISAKMP_NEXT_v2N]->payload.v2n.isan_type));
+			}
+			libreswan_log(
+				"rejecting I1 from %s:%u, no KE payload present",
+				fromname, md->sender_port);
+			return STF_FAIL + v2N_INVALID_KE_PAYLOAD;
+		}
 		ke = &md->chain[ISAKMP_NEXT_v2KE]->payload.v2ke;
 
 		st->st_oakley.group = lookup_group(ke->isak_group);
 		if (st->st_oakley.group == NULL) {
-			char fromname[ADDRTOT_BUF];
-
-			addrtot(&md->sender, 0, fromname, ADDRTOT_BUF);
 			libreswan_log(
 				"rejecting I1 from %s:%u, invalid DH group=%u",
 				fromname, md->sender_port,
 				ke->isak_group);
-			return v2N_INVALID_KE_PAYLOAD;
+			return STF_FAIL + v2N_INVALID_KE_PAYLOAD;
 		}
 	}
 
 	/* now. we need to go calculate the nonce, and the KE */
 	{
@@ -817,12 +828,10 @@ static void ikev2_parent_inI1outR1_continue(struct pluto_crypto_req_cont *pcrc,
 		complete_v2_state_transition(&ke->md, e);
 		if (ke->md)
 			release_md(ke->md);
 	}
 	reset_globals();
-
-	passert(GLOBALS_ARE_RESET());
 }
 
 static stf_status ikev2_parent_inI1outR1_tail(
 	struct pluto_crypto_req_cont *pcrc,
 	struct pluto_crypto_req *r)
@@ -1143,12 +1152,10 @@ static void ikev2_parent_inR1outI2_continue(struct pluto_crypto_req_cont *pcrc,
 		complete_v2_state_transition(&dh->md, e);
 		if (dh->md)
 			release_md(dh->md);
 	}
 	reset_globals();
-
-	passert(GLOBALS_ARE_RESET());
 }
 
 static void ikev2_padup_pre_encrypt(struct msg_digest *md,
 				    pb_stream *e_pbs_cipher)
 {
@@ -1712,11 +1719,11 @@ stf_status ikev2parent_inI2outR2(struct msg_digest *md)
 		    "ikev2 parent inI2outR2: calculating g^{xy} in order to decrypt I2"));
 
 	/* verify that there is in fact an encrypted payload */
 	if (!md->chain[ISAKMP_NEXT_v2E]) {
 		libreswan_log("R2 state should receive an encrypted payload");
-		reset_globals();
+		reset_globals(); /* XXX suspicious - why was this deemed neccessary? */
 		return STF_FATAL;
 	}
 
 	/* now. we need to go calculate the g^xy */
 	{
@@ -1792,12 +1799,10 @@ static void ikev2_parent_inI2outR2_continue(struct pluto_crypto_req_cont *pcrc,
 		complete_v2_state_transition(&dh->md, e);
 		if (dh->md)
 			release_md(dh->md);
 	}
 	reset_globals();
-
-	passert(GLOBALS_ARE_RESET());
 }
 
 static stf_status ikev2_parent_inI2outR2_tail(
 	struct pluto_crypto_req_cont *pcrc,
 	struct pluto_crypto_req *r)

Vulnerable code: 
	passert(GLOBALS_ARE_RESET());
			char fromname[ADDRTOT_BUF];

			addrtot(&md->sender, 0, fromname, ADDRTOT_BUF);
			return v2N_INVALID_KE_PAYLOAD;

	passert(GLOBALS_ARE_RESET());

	passert(GLOBALS_ARE_RESET());
		reset_globals();

	passert(GLOBALS_ARE_RESET());
Fixed code: 		char fromname[ADDRTOT_BUF];
		addrtot(&md->sender, 0, fromname, ADDRTOT_BUF);

		if (!md->chain[ISAKMP_NEXT_v2KE]) {
			/* is this a notify? If so, log it */
			if(md->chain[ISAKMP_NEXT_v2N]) {
				libreswan_log("Received Notify(%d): %s",
					md->chain[ISAKMP_NEXT_v2N]->payload.v2n.isan_type,
					enum_name(&ikev2_notify_names,
						md->chain[ISAKMP_NEXT_v2N]->payload.v2n.isan_type));
			}
			libreswan_log(
				"rejecting I1 from %s:%u, no KE payload present",
				fromname, md->sender_port);
			return STF_FAIL + v2N_INVALID_KE_PAYLOAD;
		}
			return STF_FAIL + v2N_INVALID_KE_PAYLOAD;
		reset_globals(); /* XXX suspicious - why was this deemed neccessary? */