Blame SOURCES/libreswan-3.8-create_child_stub.patch

1b7fd5
diff -Naur libreswan-3.8-orig/include/ietf_constants.h libreswan-3.8/include/ietf_constants.h
dbd905
--- libreswan-3.8-orig/include/ietf_constants.h	2014-01-16 02:46:24.000000000 -0500
dbd905
+++ libreswan-3.8/include/ietf_constants.h	2014-04-10 15:55:22.303340560 -0400
1b7fd5
@@ -607,7 +607,7 @@
1b7fd5
 	/* IKEv2 things */
1b7fd5
 	ISAKMP_v2_SA_INIT = 34,
1b7fd5
 	ISAKMP_v2_AUTH = 35,
1b7fd5
-	ISAKMP_v2_CHILD_SA = 36,
1b7fd5
+	ISAKMP_v2_CREATE_CHILD_SA = 36,
1b7fd5
 	ISAKMP_v2_INFORMATIONAL = 37,
1b7fd5
 	ISAKMP_v2_IKE_SESSION_RESUME = 38, /* RFC 5723 */
1b7fd5
 
1b7fd5
diff -Naur libreswan-3.8-orig/include/pluto_constants.h libreswan-3.8/include/pluto_constants.h
dbd905
--- libreswan-3.8-orig/include/pluto_constants.h	2014-01-16 02:46:24.000000000 -0500
dbd905
+++ libreswan-3.8/include/pluto_constants.h	2014-04-10 15:55:22.303340560 -0400
1b7fd5
@@ -424,6 +424,11 @@
1b7fd5
 
1b7fd5
 #define IS_PARENT_SA_ESTABLISHED(s) ((s) == STATE_PARENT_I2 || (s) == \
1b7fd5
 				     STATE_PARENT_R1 || (s) == STATE_IKESA_DEL)
1b7fd5
+
1b7fd5
+#define IS_V2_INITIATOR(s) ((s) == STATE_PARENT_I1 || \
1b7fd5
+                            (s) == STATE_PARENT_I2 || \
1b7fd5
+                            (s) == STATE_PARENT_I3)
1b7fd5
+
1b7fd5
 /*
1b7fd5
  * Issue here is that our child sa appears as a STATE_PARENT_I3/STATE_PARENT_R2 state which it should not
1b7fd5
  * So we fall back to checking if it is cloned, and therefor really a child
1b7fd5
diff -Naur libreswan-3.8-orig/lib/libswan/constants.c libreswan-3.8/lib/libswan/constants.c
dbd905
--- libreswan-3.8-orig/lib/libswan/constants.c	2014-01-16 02:46:24.000000000 -0500
dbd905
+++ libreswan-3.8/lib/libswan/constants.c	2014-04-10 15:55:22.303340560 -0400
1b7fd5
@@ -269,7 +269,7 @@
1b7fd5
 static const char *const exchange_name_ikev2[] = {
1b7fd5
 	"ISAKMP_v2_SA_INIT",
1b7fd5
 	"ISAKMP_v2_AUTH",
1b7fd5
-	"ISAKMP_v2_CHILD_SA",
1b7fd5
+	"ISAKMP_v2_CREATE_CHILD_SA",
1b7fd5
 	"ISAKMP_v2_INFORMATIONAL",
1b7fd5
 	"ISAKMP_v2_IKE_SESSION_RESUME",
1b7fd5
 };
1b7fd5
diff -Naur libreswan-3.8-orig/programs/pluto/ikev2.c libreswan-3.8/programs/pluto/ikev2.c
dbd905
--- libreswan-3.8-orig/programs/pluto/ikev2.c	2014-01-16 02:46:24.000000000 -0500
dbd905
+++ libreswan-3.8/programs/pluto/ikev2.c	2014-04-10 15:55:37.668690909 -0400
1b7fd5
@@ -150,6 +150,31 @@
1b7fd5
  *                                          TSi, TSr}
1b7fd5
  * [Child SA established]
1b7fd5
  *
1b7fd5
+ *
1b7fd5
+ * CREATE_CHILD_SA Exchanges:
1b7fd5
+ *
1b7fd5
+ * New Child SA
1b7fd5
+ *
1b7fd5
+ * HDR, SK {SA, Ni, [KEi],
1b7fd5
+ *            TSi, TSr}  -->
1b7fd5
+ *
1b7fd5
+ *                              <--  HDR, SK {SA, Nr, [KEr],
1b7fd5
+ *                                       TSi, TSr}
1b7fd5
+ *
1b7fd5
+ * Rekey Child SA
1b7fd5
+ *
1b7fd5
+ * HDR, SK {N(REKEY_SA), SA, Ni, [KEi],
1b7fd5
+ *     TSi, TSr}   -->
1b7fd5
+ *
1b7fd5
+ *                    <--  HDR, SK {SA, Nr, [KEr],
1b7fd5
+ *                             TSi, TSr}
1b7fd5
+ *
1b7fd5
+ * Rekey IKE SA (yes, IKE SA can be rekeyed using CREATE_CHILD_SA)
1b7fd5
+ *
1b7fd5
+ * HDR, SK {SA, Ni, KEi} -->
1b7fd5
+ *
1b7fd5
+ *                            <--  HDR, SK {SA, Nr, KEr}
1b7fd5
+ *
1b7fd5
  */
1b7fd5
 
1b7fd5
 /* Short forms for building payload type sets */
1b7fd5
@@ -287,6 +312,36 @@
1b7fd5
 	  .processor  = process_informational_ikev2,
1b7fd5
 	  .recv_type  = ISAKMP_v2_INFORMATIONAL, },
1b7fd5
 
1b7fd5
+	/*
1b7fd5
+	 * There are three different CREATE_CHILD_SA's invocations,
1b7fd5
+	 * this is the combined write up (not in RFC). See above for
1b7fd5
+	 * individual cases from RFC
1b7fd5
+	 *
1b7fd5
+	 * HDR, SK {SA, Ni, [KEi], [N(REKEY_SA)], [TSi, TSr]} -->
1b7fd5
+	 *                <-- HDR, SK {N}
1b7fd5
+	 *                <-- HDR, SK {SA, Nr, [KEr], [TSi, TSr]}
1b7fd5
+	 */
1b7fd5
+
1b7fd5
+	/* Create Child SA Exchange*/
1b7fd5
+	{ .state      = STATE_PARENT_I3,
1b7fd5
+	  .next_state = STATE_PARENT_I3,
1b7fd5
+	  .flags = SMF2_STATENEEDED | SMF2_REPLY,
1b7fd5
+	  .req_clear_payloads = P(E),
1b7fd5
+	  .req_enc_payloads = P(SA) | P(Ni),
1b7fd5
+	  .opt_enc_payloads = P(KE) | P(N) | P(TSi) | P(TSr),
1b7fd5
+	  .processor  = ikev2_in_create_child_sa,
1b7fd5
+	  .recv_type  = ISAKMP_v2_CREATE_CHILD_SA, },
1b7fd5
+
1b7fd5
+	/* Create Child SA Exchange*/
1b7fd5
+	{ .state      = STATE_PARENT_R2,
1b7fd5
+	  .next_state = STATE_PARENT_R2,
1b7fd5
+	  .flags = SMF2_STATENEEDED | SMF2_REPLY,
1b7fd5
+	  .req_clear_payloads = P(E),
1b7fd5
+	  .req_enc_payloads = P(SA) | P(Ni),
1b7fd5
+	  .opt_enc_payloads = P(KE) | P(N) | P(TSi) | P(TSr),
1b7fd5
+	  .processor  = ikev2_in_create_child_sa,
1b7fd5
+	  .recv_type  = ISAKMP_v2_CREATE_CHILD_SA, },
1b7fd5
+
1b7fd5
 	/* Informational Exchange*/
1b7fd5
 	{ .state      = STATE_PARENT_R2,
1b7fd5
 	  .next_state = STATE_PARENT_R2,
dbd905
@@ -607,7 +662,11 @@
dbd905
 			continue;
dbd905
 
dbd905
 		/* ??? not sure that this is necessary, but it ought to be correct */
dbd905
-		if ( ((svm->flags&SMF2_INITIATOR) != 0) != ((md->hdr.isa_flags & ISAKMP_FLAGS_R) != 0) )
dbd905
+		/* This check cannot apply for an informational exchange since one
dbd905
+		 * can be initiated by the initial responder.
dbd905
+		 */
dbd905
+		if (ix != ISAKMP_v2_INFORMATIONAL &&
dbd905
+			(((svm->flags&SMF2_INITIATOR) != 0) != ((md->hdr.isa_flags & ISAKMP_FLAGS_R) != 0)))
dbd905
 			continue;
dbd905
 
dbd905
 		/* must be the right state */
dbd905
@@ -832,6 +891,10 @@
dbd905
 
dbd905
 	case RESPONDER:
dbd905
 		pst->st_msgid_lastrecv = md->msgid_received;
dbd905
+		/* the responder requires msgid_nextuse if it ever needs to
dbd905
+		 * initiate an informational exchange
dbd905
+		 */
dbd905
+		pst->st_msgid_nextuse = md->msgid_received + 1;
dbd905
 		break;
dbd905
 	}
dbd905
 }
1b7fd5
diff -Naur libreswan-3.8-orig/programs/pluto/ikev2.h libreswan-3.8/programs/pluto/ikev2.h
dbd905
--- libreswan-3.8-orig/programs/pluto/ikev2.h	2014-01-16 02:46:24.000000000 -0500
dbd905
+++ libreswan-3.8/programs/pluto/ikev2.h	2014-04-10 15:55:22.304340582 -0400
1b7fd5
@@ -35,6 +35,8 @@
1b7fd5
 extern stf_status ikev2_send_informational(struct state *st);
1b7fd5
 
1b7fd5
 extern stf_status process_informational_ikev2(struct msg_digest *md);
1b7fd5
+extern stf_status ikev2_in_create_child_sa(struct msg_digest *md);
1b7fd5
+
1b7fd5
 extern stf_status ikev2parent_inI1outR1(struct msg_digest *md);
1b7fd5
 extern stf_status ikev2parent_inR1(struct msg_digest *md);
1b7fd5
 extern stf_status ikev2parent_inR1outI2(struct msg_digest *md);
1b7fd5
diff -Naur libreswan-3.8-orig/programs/pluto/ikev2_parent.c libreswan-3.8/programs/pluto/ikev2_parent.c
dbd905
--- libreswan-3.8-orig/programs/pluto/ikev2_parent.c	2014-01-16 02:46:24.000000000 -0500
dbd905
+++ libreswan-3.8/programs/pluto/ikev2_parent.c	2014-04-10 15:55:37.668690909 -0400
dbd905
@@ -2722,8 +2722,125 @@
1b7fd5
 	delete_state(pst);
1b7fd5
 }
1b7fd5
 
1b7fd5
+static stf_status ikev2_in_create_child_sa_refuse(struct msg_digest *md)
1b7fd5
+{
1b7fd5
+	struct state *st = md->st;
1b7fd5
+	struct state *pst = st;
1b7fd5
+	{
1b7fd5
+		unsigned char *authstart;
1b7fd5
+		unsigned char *encstart;
1b7fd5
+		unsigned char *iv;
1b7fd5
+		int ivsize;
1b7fd5
+		struct ikev2_generic e;
1b7fd5
+		pb_stream e_pbs, e_pbs_cipher;
1b7fd5
+		pb_stream request;
1b7fd5
+
1b7fd5
+		zero(&reply_buffer);
1b7fd5
+		init_pbs(&request, reply_buffer, sizeof(reply_buffer),
1b7fd5
+			 "create child SA exchange request response");
1b7fd5
+		authstart = request.cur;
1b7fd5
+
1b7fd5
+		/* HDR out */
1b7fd5
+		{
1b7fd5
+			struct isakmp_hdr r_hdr;
1b7fd5
+			zero(&r_hdr);
1b7fd5
+			r_hdr.isa_version = build_ike_version();
1b7fd5
+			memcpy(r_hdr.isa_rcookie, pst->st_rcookie,
1b7fd5
+			       COOKIE_SIZE);
1b7fd5
+			memcpy(r_hdr.isa_icookie, pst->st_icookie,
1b7fd5
+			       COOKIE_SIZE);
1b7fd5
+			r_hdr.isa_xchg = ISAKMP_v2_CREATE_CHILD_SA;
1b7fd5
+			r_hdr.isa_np = ISAKMP_NEXT_v2E;
1b7fd5
+			r_hdr.isa_flags |= ISAKMP_FLAGS_R;
1b7fd5
+			r_hdr.isa_msgid = htonl(pst->st_msgid_nextuse);
1b7fd5
+
1b7fd5
+			/* encryption role based on original state not md state */
1b7fd5
+			if (IS_V2_INITIATOR(pst->st_state))
1b7fd5
+				md->role = INITIATOR;
1b7fd5
+			else
1b7fd5
+				md->role = RESPONDER;
1b7fd5
+
1b7fd5
+			if (!out_struct(&r_hdr, &isakmp_hdr_desc,
1b7fd5
+					&request, &md->rbody)) {
1b7fd5
+				libreswan_log("error initializing hdr for "
1b7fd5
+						"CREATE_CHILD_SA  message");
1b7fd5
+				return STF_FATAL;
1b7fd5
+			}
1b7fd5
+		} /* HDR done*/
1b7fd5
+
1b7fd5
+		/* insert an Encryption payload header */
1b7fd5
+		e.isag_np = ISAKMP_NEXT_v2N;
1b7fd5
+		e.isag_critical = ISAKMP_PAYLOAD_NONCRITICAL;
1b7fd5
+		if (!out_struct(&e, &ikev2_e_desc, &md->rbody, &e_pbs))
1b7fd5
+			return STF_FATAL;
1b7fd5
+
1b7fd5
+		/* IV */
1b7fd5
+		iv = e_pbs.cur;
1b7fd5
+		ivsize = pst->st_oakley.encrypter->iv_size;
1b7fd5
+		if (!out_zero(ivsize, &e_pbs, "iv"))
1b7fd5
+			return STF_FATAL;
1b7fd5
+
1b7fd5
+		get_rnd_bytes(iv, ivsize);
1b7fd5
+
1b7fd5
+		/* note where cleartext starts */
1b7fd5
+		init_pbs(&e_pbs_cipher, e_pbs.cur, e_pbs.roof - e_pbs.cur,
1b7fd5
+			 "cleartext");
1b7fd5
+		e_pbs_cipher.container = &e_pbs;
1b7fd5
+		e_pbs_cipher.desc = NULL;
1b7fd5
+		e_pbs_cipher.cur = e_pbs.cur;
1b7fd5
+		encstart = e_pbs_cipher.cur;
1b7fd5
+
1b7fd5
+		chunk_t child_spi;
1b7fd5
+		memset(&child_spi, 0, sizeof(child_spi));
1b7fd5
+
1b7fd5
+		ship_v2N(ISAKMP_NEXT_v2NONE,
1b7fd5
+				ISAKMP_PAYLOAD_NONCRITICAL,
1b7fd5
+				PROTO_ISAKMP,
1b7fd5
+				&child_spi,
1b7fd5
+				v2N_NO_ADDITIONAL_SAS, NULL,
1b7fd5
+				&e_pbs_cipher);
1b7fd5
+
1b7fd5
+		ikev2_padup_pre_encrypt(md, &e_pbs_cipher);
1b7fd5
+		close_output_pbs(&e_pbs_cipher);
1b7fd5
+
1b7fd5
+		{
1b7fd5
+			stf_status ret;
1b7fd5
+			unsigned char *authloc = ikev2_authloc(md, &e_pbs);
1b7fd5
+
1b7fd5
+			if (!authloc)
1b7fd5
+				return STF_FATAL;
1b7fd5
+
1b7fd5
+			close_output_pbs(&e_pbs);
1b7fd5
+			close_output_pbs(&md->rbody);
1b7fd5
+			close_output_pbs(&request);
1b7fd5
+
1b7fd5
+			ret = ikev2_encrypt_msg(md, md->role,
1b7fd5
+						authstart,
1b7fd5
+						iv, encstart, authloc,
1b7fd5
+						&e_pbs, &e_pbs_cipher);
1b7fd5
+			if (ret != STF_OK)
1b7fd5
+				return ret;
1b7fd5
+		}
1b7fd5
+
1b7fd5
+		/* keep it for a retransmit if necessary */
1b7fd5
+		freeanychunk(pst->st_tpacket);
1b7fd5
+		clonetochunk(pst->st_tpacket, request.start,
1b7fd5
+			     pbs_offset(&request),
1b7fd5
+			     "reply packet for CREATE_CHILD_SA exchange");
1b7fd5
+		send_ike_msg(pst, __FUNCTION__);
1b7fd5
+	}
1b7fd5
+
1b7fd5
+	return STF_OK;
1b7fd5
+}
1b7fd5
+
1b7fd5
+stf_status ikev2_in_create_child_sa(struct msg_digest *md) 
1b7fd5
+{
1b7fd5
+	return ikev2_in_create_child_sa_refuse(md);
1b7fd5
+}
1b7fd5
+
1b7fd5
 stf_status process_informational_ikev2(struct msg_digest *md)
1b7fd5
 {
dbd905
+	enum phase1_role prole;
1b7fd5
 	/* verify that there is in fact an encrypted payload */
dbd905
 	if (md->chain[ISAKMP_NEXT_v2E] == NULL) {
dbd905
 		libreswan_log(
dbd905
@@ -2734,15 +2851,23 @@
dbd905
 	/* decrypt things. */
dbd905
 	{
dbd905
 		stf_status ret;
dbd905
+		struct state *ost = md->st;
dbd905
 
dbd905
-		if (md->hdr.isa_flags & ISAKMP_FLAGS_I) {
dbd905
+		/*
dbd905
+		 * Since an informational exchange can be started by the original responder,
dbd905
+		 * things such as encryption, decryption should be done based on the original
dbd905
+		 * role and not the md->role
dbd905
+		 */
dbd905
+		if (IS_V2_INITIATOR(ost->st_state)) {
dbd905
+			prole = INITIATOR;
dbd905
 			DBG(DBG_CONTROLMORE,
dbd905
-			    DBG_log("received informational exchange request from INITIATOR"));
dbd905
-			ret = ikev2_decrypt_msg(md, RESPONDER);
dbd905
+			    DBG_log("received informational exchange request from the original responder"));
dbd905
+			ret = ikev2_decrypt_msg(md, INITIATOR);
dbd905
 		} else {
dbd905
+			prole = RESPONDER;
dbd905
 			DBG(DBG_CONTROLMORE,
dbd905
-			    DBG_log("received informational exchange request from RESPONDER"));
dbd905
-			ret = ikev2_decrypt_msg(md, INITIATOR);
dbd905
+			    DBG_log("received informational exchange request from the original initiator"));
dbd905
+			ret = ikev2_decrypt_msg(md, RESPONDER);
dbd905
 		}
dbd905
 
dbd905
 		if (ret != STF_OK)
dbd905
@@ -2791,10 +2916,6 @@
dbd905
 				r_hdr.isa_np = ISAKMP_NEXT_v2E;
dbd905
 				r_hdr.isa_msgid = htonl(md->msgid_received);
dbd905
 
dbd905
-				/*set initiator bit if we are initiator*/
dbd905
-				if (md->role == INITIATOR)
dbd905
-					r_hdr.isa_flags |= ISAKMP_FLAGS_I;
dbd905
-
dbd905
 				r_hdr.isa_flags  |=  ISAKMP_FLAGS_R;
dbd905
 
dbd905
 				if (!out_struct(&r_hdr, &isakmp_hdr_desc,
dbd905
@@ -3016,7 +3137,7 @@
dbd905
 				close_output_pbs(&md->rbody);
dbd905
 				close_output_pbs(&reply_stream);
dbd905
 
dbd905
-				ret = ikev2_encrypt_msg(md, md->role,
dbd905
+				ret = ikev2_encrypt_msg(md, prole,
dbd905
 							authstart,
dbd905
 							iv, encstart, authloc,
dbd905
 							&e_pbs, &e_pbs_cipher);
dbd905
@@ -3158,7 +3279,7 @@
dbd905
 
dbd905
 stf_status ikev2_send_informational(struct state *st)
dbd905
 {
dbd905
-	struct state *pst = NULL;
dbd905
+	struct state *pst = st;
dbd905
 
dbd905
 	if (IS_CHILD_SA(st)) {
dbd905
 		pst = state_with_serialno(st->st_clonedfrom);
dbd905
@@ -3169,8 +3290,6 @@
dbd905
 			    DBG_log("INFORMATIONAL exchange can not be sent"));
dbd905
 			return STF_IGNORE;
dbd905
 		}
dbd905
-	} else {
dbd905
-		pst = st;
dbd905
 	}
dbd905
 
dbd905
 	{
dbd905
@@ -3180,7 +3299,6 @@
dbd905
 		int ivsize;
dbd905
 		struct msg_digest md;
dbd905
 		struct ikev2_generic e;
dbd905
-		enum phase1_role role;
dbd905
 		pb_stream e_pbs, e_pbs_cipher;
dbd905
 		pb_stream rbody;
dbd905
 		pb_stream request;
dbd905
@@ -3204,18 +3322,14 @@
dbd905
 			       COOKIE_SIZE);
dbd905
 			r_hdr.isa_xchg = ISAKMP_v2_INFORMATIONAL;
dbd905
 			r_hdr.isa_np = ISAKMP_NEXT_v2E;
dbd905
+			r_hdr.isa_flags |= ISAKMP_FLAGS_I;
dbd905
+			r_hdr.isa_msgid = htonl(pst->st_msgid_nextuse);
dbd905
 
dbd905
-			if (pst->st_state == STATE_PARENT_I2 ||
dbd905
-			    pst->st_state == STATE_PARENT_I3) {
dbd905
-				r_hdr.isa_flags |= ISAKMP_FLAGS_I;
dbd905
-				role = INITIATOR;
dbd905
-				r_hdr.isa_msgid = htonl(pst->st_msgid_nextuse);
dbd905
-			} else {
dbd905
-				role = RESPONDER;
dbd905
-				r_hdr.isa_msgid = htonl(
dbd905
-					pst->st_msgid_lastrecv + 1);
dbd905
-			}
dbd905
-
dbd905
+			/* encryption role based on original state not md state */
dbd905
+			if (IS_V2_INITIATOR(pst->st_state))
dbd905
+				md.role = INITIATOR;
dbd905
+			else
dbd905
+				md.role = RESPONDER;
dbd905
 			if (!out_struct(&r_hdr, &isakmp_hdr_desc,
dbd905
 					&request, &rbody)) {
dbd905
 				libreswan_log(
dbd905
@@ -3261,7 +3375,7 @@
dbd905
 			close_output_pbs(&rbody);
dbd905
 			close_output_pbs(&request);
dbd905
 
dbd905
-			ret = ikev2_encrypt_msg(&md, role,
dbd905
+			ret = ikev2_encrypt_msg(&md, md.role,
dbd905
 						authstart,
dbd905
 						iv, encstart, authloc,
dbd905
 						&e_pbs, &e_pbs_cipher);
dbd905
@@ -3276,7 +3390,6 @@
dbd905
 			     "reply packet for informational exchange");
dbd905
 		pst->st_pend_liveness = TRUE; /* we should only do this when dpd/liveness is active? */
dbd905
 		send_ike_msg(pst, __FUNCTION__);
dbd905
-		ikev2_update_counters(&md);
dbd905
 	}
dbd905
 
dbd905
 	return STF_OK;