Blame SOURCES/libreswan-3.29-CVE-2019-10155-testing.patch

d8e7ea
diff -Naur libreswan-3.29-orig/include/impair.h libreswan-3.29/include/impair.h
d8e7ea
--- libreswan-3.29-orig/include/impair.h	2019-06-10 10:22:04.000000000 -0400
d8e7ea
+++ libreswan-3.29/include/impair.h	2019-06-11 19:22:39.786283961 -0400
d8e7ea
@@ -1,6 +1,6 @@
d8e7ea
-/* impair operation
d8e7ea
+/* impair operation, for libreswan
d8e7ea
  *
d8e7ea
- * Copyright (C) 2019 Andrew Cagney <cagney@gnu.org>
d8e7ea
+ * Copyright (C) 2018-2019 Andrew Cagney
d8e7ea
  *
d8e7ea
  * This program is free software; you can redistribute it and/or modify it
d8e7ea
  * under the terms of the GNU General Public License as published by the
d8e7ea
@@ -22,9 +22,7 @@
d8e7ea
 #include "lswcdefs.h"
d8e7ea
 
d8e7ea
 /*
d8e7ea
- * How to impair something.  This is just the start ...
d8e7ea
- *
d8e7ea
- * Extra enums go here.
d8e7ea
+ * Meddle with the contents of a payload.
d8e7ea
  */
d8e7ea
 
d8e7ea
 enum send_impairment {
d8e7ea
@@ -35,6 +33,21 @@
d8e7ea
 	SEND_ROOF, /* >= ROOF -> <number> */
d8e7ea
 };
d8e7ea
 
d8e7ea
+/*
d8e7ea
+ * Meddle with a specific exchange.
d8e7ea
+ */
d8e7ea
+
d8e7ea
+enum exchange_impairment {
d8e7ea
+	NO_EXCHANGE = 0,
d8e7ea
+	NOTIFICATION_EXCHANGE,
d8e7ea
+	QUICK_EXCHANGE,
d8e7ea
+	XAUTH_EXCHANGE,
d8e7ea
+	DELETE_EXCHANGE,
d8e7ea
+};
d8e7ea
+
d8e7ea
+/*
d8e7ea
+ * add more here
d8e7ea
+ */
d8e7ea
 #if 0
d8e7ea
 enum xxx_impair ...;
d8e7ea
 #endif
d8e7ea
@@ -53,6 +66,10 @@
d8e7ea
 extern enum send_impairment impair_ike_key_length_attribute;
d8e7ea
 extern enum send_impairment impair_child_key_length_attribute;
d8e7ea
 
d8e7ea
+extern enum send_impairment impair_v1_hash_payload;
d8e7ea
+extern enum exchange_impairment impair_v1_hash_exchange;
d8e7ea
+extern bool impair_v1_hash_check;
d8e7ea
+
d8e7ea
 /*
d8e7ea
  * What whack sends across the wire for a impair.
d8e7ea
  */
d8e7ea
diff -Naur libreswan-3.29-orig/lib/libswan/impair.c libreswan-3.29/lib/libswan/impair.c
d8e7ea
--- libreswan-3.29-orig/lib/libswan/impair.c	2019-06-10 10:22:04.000000000 -0400
d8e7ea
+++ libreswan-3.29/lib/libswan/impair.c	2019-06-11 19:22:54.290445191 -0400
d8e7ea
@@ -1,5 +1,4 @@
d8e7ea
-/*
d8e7ea
- * impair constants, for libreswan
d8e7ea
+/* impair constants, for libreswan
d8e7ea
  *
d8e7ea
  * Copyright (C) 2017-2019 Andrew Cagney <cagney@gnu.org>
d8e7ea
  * Copyright (C) 2019-2019 Paul Wouters <pwouters@redhat.com>
d8e7ea
@@ -125,6 +124,19 @@
d8e7ea
 static const struct keywords send_impairment_keywords =
d8e7ea
 	DIRECT_KEYWORDS("send impaired content", send_impairment_value);
d8e7ea
 
d8e7ea
+static const struct keyword exchange_impairment_value[] = {
d8e7ea
+#define S(E, H) [E##_EXCHANGE] = { .name = "SEND_" #E, .sname = #E, .value = E##_EXCHANGE, .details = H, }
d8e7ea
+	S(NO, "do not modify exchanges"),
d8e7ea
+	S(QUICK, "modify IKEv1 QUICK exchanges"),
d8e7ea
+	S(XAUTH, "modify IKEv1 XAUTH exchanges"),
d8e7ea
+	S(NOTIFICATION, "modify notification (informational) exchanges"),
d8e7ea
+	S(DELETE, "modify delete exchanges"),
d8e7ea
+#undef S
d8e7ea
+};
d8e7ea
+
d8e7ea
+static const struct keywords exchange_impairment_keywords =
d8e7ea
+	DIRECT_KEYWORDS("impaire exchange content", exchange_impairment_value);
d8e7ea
+
d8e7ea
 struct impairment {
d8e7ea
 	const char *what;
d8e7ea
 	const char *help;
d8e7ea
@@ -182,6 +194,27 @@
d8e7ea
 		.how_keynum = &send_impairment_keywords,
d8e7ea
 		V(impair_child_key_length_attribute),
d8e7ea
 	},
d8e7ea
+
d8e7ea
+	/*
d8e7ea
+	 * IKEv1: hash payloads
d8e7ea
+	 */
d8e7ea
+	{
d8e7ea
+		.what = "v1-hash-check",
d8e7ea
+		.help = "disable check of incoming IKEv1 hash payload",
d8e7ea
+		V(impair_emitting),
d8e7ea
+	},
d8e7ea
+	{
d8e7ea
+		.what = "v1-hash-payload",
d8e7ea
+		.help = "corrupt the outgoing HASH payload",
d8e7ea
+		.how_keynum = &send_impairment_keywords,
d8e7ea
+		V(impair_v1_hash_payload),
d8e7ea
+	},
d8e7ea
+	{
d8e7ea
+		.what = "v1-hash-exchange",
d8e7ea
+		.help = "the outgoing exchange that should contain the corrupted HASH payload",
d8e7ea
+		.how_keynum = &exchange_impairment_keywords,
d8e7ea
+		V(impair_v1_hash_exchange),
d8e7ea
+	},
d8e7ea
 };
d8e7ea
 
d8e7ea
 static void help(const char *prefix, const struct impairment *cr)
d8e7ea
@@ -522,8 +555,9 @@
d8e7ea
 }
d8e7ea
 
d8e7ea
 /*
d8e7ea
- * declare these last so that all references are forced to use the
d8e7ea
- * declaration in the header.
d8e7ea
+ * XXX: define these at the end of the file so that all references are
d8e7ea
+ * forced to use the declaration in the header (help stop code
d8e7ea
+ * refering to the wrong variable?).
d8e7ea
  */
d8e7ea
 
d8e7ea
 bool impair_revival;
d8e7ea
@@ -531,3 +565,6 @@
d8e7ea
 enum send_impairment impair_ke_payload;
d8e7ea
 enum send_impairment impair_ike_key_length_attribute;
d8e7ea
 enum send_impairment impair_child_key_length_attribute;
d8e7ea
+bool impair_v1_hash_check;
d8e7ea
+enum send_impairment impair_v1_hash_payload;
d8e7ea
+enum exchange_impairment impair_v1_hash_exchange;
d8e7ea
diff -Naur libreswan-3.29-orig/programs/pluto/ikev1.c libreswan-3.29/programs/pluto/ikev1.c
d8e7ea
--- libreswan-3.29-orig/programs/pluto/ikev1.c	2019-06-10 10:22:04.000000000 -0400
d8e7ea
+++ libreswan-3.29/programs/pluto/ikev1.c	2019-06-11 19:27:44.516665524 -0400
d8e7ea
@@ -157,6 +157,7 @@
d8e7ea
 #include "ikev1_dpd.h"
d8e7ea
 #include "hostpair.h"
d8e7ea
 #include "ip_address.h"
d8e7ea
+#include "ikev1_hash.h"
d8e7ea
 
d8e7ea
 #ifdef HAVE_NM
d8e7ea
 #include "kernel.h"
d8e7ea
@@ -181,6 +182,8 @@
d8e7ea
 	lset_t opt_payloads;    /* optional payloads (any mumber) */
d8e7ea
 	enum event_type timeout_event;
d8e7ea
 	ikev1_state_transition_fn *processor;
d8e7ea
+	const char *message;
d8e7ea
+	enum v1_hash_type hash_type;
d8e7ea
 };
d8e7ea
 
d8e7ea
 /* State Microcode Flags, in several groups */
d8e7ea
@@ -255,6 +258,7 @@
d8e7ea
 static const struct state_v1_microcode v1_state_microcode_table[] = {
d8e7ea
 
d8e7ea
 #define P(n) LELEM(ISAKMP_NEXT_ ##n)
d8e7ea
+#define FM(F) .processor = F, .message = #F
d8e7ea
 
d8e7ea
 	/***** Phase 1 Main Mode *****/
d8e7ea
 
d8e7ea
@@ -266,7 +270,9 @@
d8e7ea
 	{ STATE_MAIN_R0, STATE_MAIN_R1,
d8e7ea
 	  SMF_ALL_AUTH | SMF_REPLY,
d8e7ea
 	  P(SA), P(VID) | P(CR),
d8e7ea
-	  EVENT_SO_DISCARD, main_inI1_outR1 },
d8e7ea
+	  EVENT_SO_DISCARD,
d8e7ea
+	  FM(main_inI1_outR1),
d8e7ea
+	  .hash_type = V1_HASH_NONE, },
d8e7ea
 
d8e7ea
 	/* STATE_MAIN_I1: R1 --> I2
d8e7ea
 	 * HDR, SA --> auth dependent
d8e7ea
@@ -281,7 +287,9 @@
d8e7ea
 	{ STATE_MAIN_I1, STATE_MAIN_I2,
d8e7ea
 	  SMF_ALL_AUTH | SMF_INITIATOR | SMF_REPLY,
d8e7ea
 	  P(SA), P(VID) | P(CR),
d8e7ea
-	  EVENT_RETRANSMIT, main_inR1_outI2 },
d8e7ea
+	  EVENT_RETRANSMIT,
d8e7ea
+	  FM(main_inR1_outI2),
d8e7ea
+	  .hash_type = V1_HASH_NONE, },
d8e7ea
 
d8e7ea
 	/* STATE_MAIN_R1: I2 --> R2
d8e7ea
 	 * SMF_PSK_AUTH, SMF_DS_AUTH: HDR, KE, Ni --> HDR, KE, Nr
d8e7ea
@@ -294,17 +302,23 @@
d8e7ea
 	{ STATE_MAIN_R1, STATE_MAIN_R2,
d8e7ea
 	  SMF_PSK_AUTH | SMF_DS_AUTH | SMF_REPLY | SMF_RETRANSMIT_ON_DUPLICATE,
d8e7ea
 	  P(KE) | P(NONCE), P(VID) | P(CR) | P(NATD_RFC),
d8e7ea
-	  EVENT_RETRANSMIT, main_inI2_outR2 },
d8e7ea
+	  EVENT_RETRANSMIT,
d8e7ea
+	  FM(main_inI2_outR2),
d8e7ea
+	  .hash_type = V1_HASH_NONE, },
d8e7ea
 
d8e7ea
 	{ STATE_MAIN_R1, STATE_UNDEFINED,
d8e7ea
 	  SMF_PKE_AUTH | SMF_REPLY | SMF_RETRANSMIT_ON_DUPLICATE,
d8e7ea
 	  P(KE) | P(ID) | P(NONCE), P(VID) | P(CR) | P(HASH),
d8e7ea
-	  EVENT_RETRANSMIT, unexpected /* ??? not yet implemented */ },
d8e7ea
+	  EVENT_RETRANSMIT,
d8e7ea
+	  FM(unexpected) /* ??? not yet implemented */,
d8e7ea
+	  .hash_type = V1_HASH_NONE, },
d8e7ea
 
d8e7ea
 	{ STATE_MAIN_R1, STATE_UNDEFINED,
d8e7ea
 	  SMF_RPKE_AUTH | SMF_REPLY | SMF_RETRANSMIT_ON_DUPLICATE,
d8e7ea
 	  P(NONCE) | P(KE) | P(ID), P(VID) | P(CR) | P(HASH) | P(CERT),
d8e7ea
-	  EVENT_RETRANSMIT, unexpected /* ??? not yet implemented */ },
d8e7ea
+	  EVENT_RETRANSMIT,
d8e7ea
+	  FM(unexpected) /* ??? not yet implemented */,
d8e7ea
+	  .hash_type = V1_HASH_NONE, },
d8e7ea
 
d8e7ea
 	/* for states from here on, output message must be encrypted */
d8e7ea
 
d8e7ea
@@ -319,17 +333,24 @@
d8e7ea
 	{ STATE_MAIN_I2, STATE_MAIN_I3,
d8e7ea
 	  SMF_PSK_AUTH | SMF_DS_AUTH | SMF_INITIATOR | SMF_OUTPUT_ENCRYPTED | SMF_REPLY,
d8e7ea
 	  P(KE) | P(NONCE), P(VID) | P(CR) | P(NATD_RFC),
d8e7ea
-	  EVENT_RETRANSMIT, main_inR2_outI3 },
d8e7ea
+	  EVENT_RETRANSMIT,
d8e7ea
+	  FM(main_inR2_outI3),
d8e7ea
+	  /* calls main_mode_hash() after DH */
d8e7ea
+	  .hash_type = V1_HASH_NONE, },
d8e7ea
 
d8e7ea
 	{ STATE_MAIN_I2, STATE_UNDEFINED,
d8e7ea
 	  SMF_PKE_AUTH | SMF_INITIATOR | SMF_OUTPUT_ENCRYPTED | SMF_REPLY,
d8e7ea
 	  P(KE) | P(ID) | P(NONCE), P(VID) | P(CR),
d8e7ea
-	  EVENT_RETRANSMIT, unexpected /* ??? not yet implemented */ },
d8e7ea
+	  EVENT_RETRANSMIT,
d8e7ea
+	  FM(unexpected) /* ??? not yet implemented */,
d8e7ea
+	  .hash_type = V1_HASH_NONE, },
d8e7ea
 
d8e7ea
 	{ STATE_MAIN_I2, STATE_UNDEFINED,
d8e7ea
 	  SMF_ALL_AUTH | SMF_INITIATOR | SMF_OUTPUT_ENCRYPTED | SMF_REPLY,
d8e7ea
 	  P(NONCE) | P(KE) | P(ID), P(VID) | P(CR),
d8e7ea
-	  EVENT_RETRANSMIT, unexpected /* ??? not yet implemented */ },
d8e7ea
+	  EVENT_RETRANSMIT,
d8e7ea
+	  FM(unexpected) /* ??? not yet implemented */,
d8e7ea
+	  .hash_type = V1_HASH_NONE, },
d8e7ea
 
d8e7ea
 	/* for states from here on, input message must be encrypted */
d8e7ea
 
d8e7ea
@@ -342,20 +363,34 @@
d8e7ea
 	  SMF_PSK_AUTH | SMF_FIRST_ENCRYPTED_INPUT | SMF_ENCRYPTED |
d8e7ea
 		SMF_REPLY | SMF_RELEASE_PENDING_P2,
d8e7ea
 	  P(ID) | P(HASH), P(VID) | P(CR),
d8e7ea
-	  EVENT_SA_REPLACE, main_inI3_outR3 },
d8e7ea
+	  EVENT_SA_REPLACE,
d8e7ea
+	  FM(main_inI3_outR3),
d8e7ea
+	  /* calls oakley_id_and_auth() which calls main_mode_hash() */
d8e7ea
+	  /* RFC 2409: 5. Exchanges & 5.2 Phase 1 Authenticated With Public Key Encryption
d8e7ea
+	     HASH_I = prf(SKEYID, g^xi | g^xr | CKY-I | CKY-R | SAi_b | IDii_b ) */
d8e7ea
+	  .hash_type = V1_HASH_NONE, },
d8e7ea
 
d8e7ea
 	{ STATE_MAIN_R2, STATE_MAIN_R3,
d8e7ea
 	  SMF_DS_AUTH | SMF_FIRST_ENCRYPTED_INPUT | SMF_ENCRYPTED |
d8e7ea
 		SMF_REPLY | SMF_RELEASE_PENDING_P2,
d8e7ea
 	  P(ID) | P(SIG), P(VID) | P(CR) | P(CERT),
d8e7ea
-	  EVENT_SA_REPLACE, main_inI3_outR3 },
d8e7ea
+	  EVENT_SA_REPLACE,
d8e7ea
+	  FM(main_inI3_outR3),
d8e7ea
+	  /* calls oakley_id_and_auth() which calls main_mode_hash() */
d8e7ea
+	  /* RFC 2409: 5. Exchanges & 5.1 IKE Phase 1 Authenticated With Signatures
d8e7ea
+	     HASH_I = prf(SKEYID, g^xi | g^xr | CKY-I | CKY-R | SAi_b | IDii_b )
d8e7ea
+	     SIG_I = SIGN(HASH_I) *",
d8e7ea
+	     SIG_I = SIGN(HASH_I) */
d8e7ea
+	  .hash_type = V1_HASH_NONE, },
d8e7ea
 
d8e7ea
 	{ STATE_MAIN_R2, STATE_UNDEFINED,
d8e7ea
 	  SMF_PKE_AUTH | SMF_RPKE_AUTH | SMF_FIRST_ENCRYPTED_INPUT |
d8e7ea
 		SMF_ENCRYPTED |
d8e7ea
 		SMF_REPLY | SMF_RELEASE_PENDING_P2,
d8e7ea
 	  P(HASH), P(VID) | P(CR),
d8e7ea
-	  EVENT_SA_REPLACE, unexpected /* ??? not yet implemented */ },
d8e7ea
+	  EVENT_SA_REPLACE,
d8e7ea
+	  FM(unexpected) /* ??? not yet implemented */,
d8e7ea
+	  .hash_type = V1_HASH_NONE, },
d8e7ea
 
d8e7ea
 	/* STATE_MAIN_I3: R3 --> done
d8e7ea
 	 * SMF_PSK_AUTH: HDR*, IDr1, HASH_R --> done
d8e7ea
@@ -367,31 +402,48 @@
d8e7ea
 	  SMF_PSK_AUTH | SMF_INITIATOR |
d8e7ea
 		SMF_FIRST_ENCRYPTED_INPUT | SMF_ENCRYPTED | SMF_RELEASE_PENDING_P2,
d8e7ea
 	  P(ID) | P(HASH), P(VID) | P(CR),
d8e7ea
-	  EVENT_SA_REPLACE, main_inR3 },
d8e7ea
+	  EVENT_SA_REPLACE,
d8e7ea
+	  FM(main_inR3),
d8e7ea
+	  /* calls oakley_id_and_auth() which calls main_mode_hash() */
d8e7ea
+	  /* RFC 2409: 5. Exchanges & 5.2 Phase 1 Authenticated With Public Key Encryption
d8e7ea
+	     HASH_R = prf(SKEYID, g^xr | g^xi | CKY-R | CKY-I | SAi_b | IDir_b ) */
d8e7ea
+	  .hash_type = V1_HASH_NONE, },
d8e7ea
 
d8e7ea
 	{ STATE_MAIN_I3, STATE_MAIN_I4,
d8e7ea
 	  SMF_DS_AUTH | SMF_INITIATOR |
d8e7ea
 		SMF_FIRST_ENCRYPTED_INPUT | SMF_ENCRYPTED | SMF_RELEASE_PENDING_P2,
d8e7ea
 	  P(ID) | P(SIG), P(VID) | P(CR) | P(CERT),
d8e7ea
-	  EVENT_SA_REPLACE, main_inR3 },
d8e7ea
+	  EVENT_SA_REPLACE,
d8e7ea
+	  FM(main_inR3),
d8e7ea
+	  /* calls oakley_id_and_auth() which calls main_mode_hash() */
d8e7ea
+	  /* RFC 2409: 5. Exchanges & 5.1 IKE Phase 1 Authenticated With Signatures
d8e7ea
+	     HASH_R = prf(SKEYID, g^xr | g^xi | CKY-R | CKY-I | SAi_b | IDir_b )
d8e7ea
+	     SIG_R = SIGN(HASH_R) */
d8e7ea
+	  .hash_type = V1_HASH_NONE, },
d8e7ea
 
d8e7ea
 	{ STATE_MAIN_I3, STATE_UNDEFINED,
d8e7ea
 	  SMF_PKE_AUTH | SMF_RPKE_AUTH | SMF_INITIATOR |
d8e7ea
 		SMF_FIRST_ENCRYPTED_INPUT | SMF_ENCRYPTED | SMF_RELEASE_PENDING_P2,
d8e7ea
 	  P(HASH), P(VID) | P(CR),
d8e7ea
-	  EVENT_SA_REPLACE, unexpected /* ??? not yet implemented */ },
d8e7ea
+	  EVENT_SA_REPLACE,
d8e7ea
+	  FM(unexpected) /* ??? not yet implemented */,
d8e7ea
+	  .hash_type = V1_HASH_NONE, },
d8e7ea
 
d8e7ea
 	/* STATE_MAIN_R3: can only get here due to packet loss */
d8e7ea
 	{ STATE_MAIN_R3, STATE_UNDEFINED,
d8e7ea
 	  SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_RETRANSMIT_ON_DUPLICATE,
d8e7ea
 	  LEMPTY, LEMPTY,
d8e7ea
-	  EVENT_NULL, unexpected },
d8e7ea
+	  EVENT_NULL,
d8e7ea
+	  FM(unexpected),
d8e7ea
+	  .hash_type = V1_HASH_NONE, },
d8e7ea
 
d8e7ea
 	/* STATE_MAIN_I4: can only get here due to packet loss */
d8e7ea
 	{ STATE_MAIN_I4, STATE_UNDEFINED,
d8e7ea
 	  SMF_ALL_AUTH | SMF_INITIATOR | SMF_ENCRYPTED,
d8e7ea
 	  LEMPTY, LEMPTY,
d8e7ea
-	  EVENT_NULL, unexpected },
d8e7ea
+	  EVENT_NULL,
d8e7ea
+	  FM(unexpected),
d8e7ea
+	  .hash_type = V1_HASH_NONE, },
d8e7ea
 
d8e7ea
 	/***** Phase 1 Aggressive Mode *****/
d8e7ea
 
d8e7ea
@@ -413,7 +465,10 @@
d8e7ea
 	{ STATE_AGGR_R0, STATE_AGGR_R1,
d8e7ea
 	  SMF_PSK_AUTH | SMF_DS_AUTH | SMF_REPLY,
d8e7ea
 	  P(SA) | P(KE) | P(NONCE) | P(ID), P(VID) | P(NATD_RFC),
d8e7ea
-	  EVENT_SO_DISCARD, aggr_inI1_outR1 },
d8e7ea
+	  EVENT_SO_DISCARD,
d8e7ea
+	  FM(aggr_inI1_outR1),
d8e7ea
+	  /* N/A */
d8e7ea
+	  .hash_type = V1_HASH_NONE, },
d8e7ea
 
d8e7ea
 	/* STATE_AGGR_I1:
d8e7ea
 	 * SMF_PSK_AUTH: HDR, SA, KE, Nr, IDir, HASH_R
d8e7ea
@@ -425,13 +480,24 @@
d8e7ea
 	  SMF_PSK_AUTH | SMF_INITIATOR | SMF_OUTPUT_ENCRYPTED | SMF_REPLY |
d8e7ea
 		SMF_RELEASE_PENDING_P2,
d8e7ea
 	  P(SA) | P(KE) | P(NONCE) | P(ID) | P(HASH), P(VID) | P(NATD_RFC),
d8e7ea
-	  EVENT_SA_REPLACE, aggr_inR1_outI2 },
d8e7ea
+	  EVENT_SA_REPLACE,
d8e7ea
+	  FM(aggr_inR1_outI2),
d8e7ea
+	  /* after DH calls oakley_id_and_auth() which calls main_mode_hash() */
d8e7ea
+	  /* RFC 2409: 5. Exchanges & 5.2 Phase 1 Authenticated With Public Key Encryption
d8e7ea
+	     HASH_R = prf(SKEYID, g^xr | g^xi | CKY-R | CKY-I | SAi_b | IDir_b ) */
d8e7ea
+	  .hash_type = V1_HASH_NONE, },
d8e7ea
 
d8e7ea
 	{ STATE_AGGR_I1, STATE_AGGR_I2,
d8e7ea
 	  SMF_DS_AUTH | SMF_INITIATOR | SMF_OUTPUT_ENCRYPTED | SMF_REPLY |
d8e7ea
 		SMF_RELEASE_PENDING_P2,
d8e7ea
 	  P(SA) | P(KE) | P(NONCE) | P(ID) | P(SIG), P(VID) | P(NATD_RFC),
d8e7ea
-	  EVENT_SA_REPLACE, aggr_inR1_outI2 },
d8e7ea
+	  EVENT_SA_REPLACE,
d8e7ea
+	  FM(aggr_inR1_outI2),
d8e7ea
+	  /* after DH calls oakley_id_and_auth() which calls main_mode_hash() */
d8e7ea
+	  /* RFC 2409: 5. Exchanges & 5.1 IKE Phase 1 Authenticated With Signatures
d8e7ea
+	     HASH_R = prf(SKEYID, g^xr | g^xi | CKY-R | CKY-I | SAi_b | IDir_b )
d8e7ea
+	     SIG_R = SIGN(HASH_R) */
d8e7ea
+	  .hash_type = V1_HASH_NONE, },
d8e7ea
 
d8e7ea
 	/* STATE_AGGR_R1:
d8e7ea
 	 * SMF_PSK_AUTH: HDR*, HASH_I --> done
d8e7ea
@@ -442,24 +508,39 @@
d8e7ea
 		SMF_OUTPUT_ENCRYPTED | SMF_RELEASE_PENDING_P2 |
d8e7ea
 		SMF_RETRANSMIT_ON_DUPLICATE,
d8e7ea
 	  P(HASH), P(VID) | P(NATD_RFC),
d8e7ea
-	  EVENT_SA_REPLACE, aggr_inI2 },
d8e7ea
+	  EVENT_SA_REPLACE,
d8e7ea
+	  FM(aggr_inI2),
d8e7ea
+	  /* calls oakley_id_and_auth() which calls main_mode_hash() */
d8e7ea
+	  /* RFC 2409: 5. Exchanges & 5.2 Phase 1 Authenticated With Public Key Encryption
d8e7ea
+	     HASH_I = prf(SKEYID, g^xi | g^xr | CKY-I | CKY-R | SAi_b | IDii_b ) */
d8e7ea
+	  .hash_type = V1_HASH_NONE, },
d8e7ea
 
d8e7ea
 	{ STATE_AGGR_R1, STATE_AGGR_R2,
d8e7ea
 	  SMF_DS_AUTH | SMF_FIRST_ENCRYPTED_INPUT |
d8e7ea
 		SMF_OUTPUT_ENCRYPTED | SMF_RELEASE_PENDING_P2 |
d8e7ea
 		SMF_RETRANSMIT_ON_DUPLICATE,
d8e7ea
 	  P(SIG), P(VID) | P(NATD_RFC),
d8e7ea
-	  EVENT_SA_REPLACE, aggr_inI2 },
d8e7ea
+	  EVENT_SA_REPLACE,
d8e7ea
+	  FM(aggr_inI2),
d8e7ea
+	  /* calls oakley_id_and_auth() which calls main_mode_hash() */
d8e7ea
+	  /* RFC 2409: 5. Exchanges & 5.1 IKE Phase 1 Authenticated With Signatures
d8e7ea
+	     HASH_I = prf(SKEYID, g^xi | g^xr | CKY-I | CKY-R | SAi_b | IDii_b )
d8e7ea
+	     SIG_I = SIGN(HASH_I) */
d8e7ea
+	  .hash_type = V1_HASH_NONE, },
d8e7ea
 
d8e7ea
 	/* STATE_AGGR_I2: can only get here due to packet loss */
d8e7ea
 	{ STATE_AGGR_I2, STATE_UNDEFINED,
d8e7ea
 	  SMF_ALL_AUTH | SMF_INITIATOR | SMF_RETRANSMIT_ON_DUPLICATE,
d8e7ea
-	  LEMPTY, LEMPTY, EVENT_NULL, unexpected },
d8e7ea
+	  LEMPTY, LEMPTY, EVENT_NULL,
d8e7ea
+	  FM(unexpected),
d8e7ea
+	  .hash_type = V1_HASH_NONE, },
d8e7ea
 
d8e7ea
 	/* STATE_AGGR_R2: can only get here due to packet loss */
d8e7ea
 	{ STATE_AGGR_R2, STATE_UNDEFINED,
d8e7ea
 	  SMF_ALL_AUTH,
d8e7ea
-	  LEMPTY, LEMPTY, EVENT_NULL, unexpected },
d8e7ea
+	  LEMPTY, LEMPTY, EVENT_NULL,
d8e7ea
+	  FM(unexpected),
d8e7ea
+	  .hash_type = V1_HASH_NONE, },
d8e7ea
 
d8e7ea
 	/***** Phase 2 Quick Mode *****/
d8e7ea
 
d8e7ea
@@ -478,7 +559,11 @@
d8e7ea
 	{ STATE_QUICK_R0, STATE_QUICK_R1,
d8e7ea
 	  SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_REPLY,
d8e7ea
 	  P(HASH) | P(SA) | P(NONCE), /* P(SA) | */ P(KE) | P(ID) | P(NATOA_RFC),
d8e7ea
-	  EVENT_RETRANSMIT, quick_inI1_outR1 },
d8e7ea
+	  EVENT_RETRANSMIT,
d8e7ea
+	  FM(quick_inI1_outR1),
d8e7ea
+	  /* RFC 2409: 5.5 Phase 2 - Quick Mode:
d8e7ea
+	     HASH(1) = prf(SKEYID_a, M-ID | <rest>) */
d8e7ea
+	  .hash_type = V1_HASH_1, },
d8e7ea
 
d8e7ea
 	/* STATE_QUICK_I1:
d8e7ea
 	 * HDR*, HASH(2), SA, Nr [, KE ] [, IDci, IDcr ] -->
d8e7ea
@@ -489,7 +574,11 @@
d8e7ea
 	{ STATE_QUICK_I1, STATE_QUICK_I2,
d8e7ea
 	  SMF_ALL_AUTH | SMF_INITIATOR | SMF_ENCRYPTED | SMF_REPLY,
d8e7ea
 	  P(HASH) | P(SA) | P(NONCE), /* P(SA) | */ P(KE) | P(ID) | P(NATOA_RFC),
d8e7ea
-	  EVENT_SA_REPLACE, quick_inR1_outI2 },
d8e7ea
+	  EVENT_SA_REPLACE,
d8e7ea
+	  FM(quick_inR1_outI2),
d8e7ea
+	  /* RFC 2409: 5.5 Phase 2 - Quick Mode:
d8e7ea
+	     HASH(2) = prf(SKEYID_a, M-ID | Ni_b | <rest>) */
d8e7ea
+	  .hash_type = V1_HASH_2, },
d8e7ea
 
d8e7ea
 	/* STATE_QUICK_R1: HDR*, HASH(3) --> done
d8e7ea
 	 * Installs outbound IPsec SAs, routing, etc.
d8e7ea
@@ -497,20 +586,28 @@
d8e7ea
 	{ STATE_QUICK_R1, STATE_QUICK_R2,
d8e7ea
 	  SMF_ALL_AUTH | SMF_ENCRYPTED,
d8e7ea
 	  P(HASH), LEMPTY,
d8e7ea
-	  EVENT_SA_REPLACE, quick_inI2 },
d8e7ea
+	  EVENT_SA_REPLACE,
d8e7ea
+	  FM(quick_inI2),
d8e7ea
+	  /* RFC 2409: 5.5 Phase 2 - Quick Mode:
d8e7ea
+	     HASH(3) = prf(SKEYID_a, 0 | M-ID | Ni_b | Nr_b) */
d8e7ea
+	  .hash_type = V1_HASH_3, },
d8e7ea
 
d8e7ea
 	/* STATE_QUICK_I2: can only happen due to lost packet */
d8e7ea
 	{ STATE_QUICK_I2, STATE_UNDEFINED,
d8e7ea
 	  SMF_ALL_AUTH | SMF_INITIATOR | SMF_ENCRYPTED |
d8e7ea
 		SMF_RETRANSMIT_ON_DUPLICATE,
d8e7ea
 	  LEMPTY, LEMPTY,
d8e7ea
-	  EVENT_NULL, unexpected },
d8e7ea
+	  EVENT_NULL,
d8e7ea
+	  FM(unexpected),
d8e7ea
+	  .hash_type = V1_HASH_NONE, },
d8e7ea
 
d8e7ea
 	/* STATE_QUICK_R2: can only happen due to lost packet */
d8e7ea
 	{ STATE_QUICK_R2, STATE_UNDEFINED,
d8e7ea
 	  SMF_ALL_AUTH | SMF_ENCRYPTED,
d8e7ea
 	  LEMPTY, LEMPTY,
d8e7ea
-	  EVENT_NULL, unexpected },
d8e7ea
+	  EVENT_NULL,
d8e7ea
+	  FM(unexpected),
d8e7ea
+	  .hash_type = V1_HASH_NONE, },
d8e7ea
 
d8e7ea
 	/***** informational messages *****/
d8e7ea
 
d8e7ea
@@ -522,7 +619,9 @@
d8e7ea
 	{ STATE_INFO, STATE_UNDEFINED,
d8e7ea
 	  SMF_ALL_AUTH,
d8e7ea
 	  LEMPTY, LEMPTY,
d8e7ea
-	  EVENT_NULL, informational },
d8e7ea
+	  EVENT_NULL,
d8e7ea
+	  FM(informational),
d8e7ea
+	  .hash_type = V1_HASH_NONE, },
d8e7ea
 
d8e7ea
 	/* Informational Exchange (RFC 2408 4.8):
d8e7ea
 	 * HDR* N/D
d8e7ea
@@ -531,29 +630,41 @@
d8e7ea
 	{ STATE_INFO_PROTECTED, STATE_UNDEFINED,
d8e7ea
 	  SMF_ALL_AUTH | SMF_ENCRYPTED,
d8e7ea
 	  P(HASH), LEMPTY,
d8e7ea
-	  EVENT_NULL, informational },
d8e7ea
+	  EVENT_NULL,
d8e7ea
+	  FM(informational),
d8e7ea
+	  /* RFC 2409: 5.7 ISAKMP Informational Exchanges:
d8e7ea
+	     HASH(1) = prf(SKEYID_a, M-ID | N/D) */
d8e7ea
+	  .hash_type = V1_HASH_1, },
d8e7ea
 
d8e7ea
 	{ STATE_XAUTH_R0, STATE_XAUTH_R1,
d8e7ea
 	  SMF_ALL_AUTH | SMF_ENCRYPTED,
d8e7ea
 	  P(MCFG_ATTR) | P(HASH), P(VID),
d8e7ea
-	  EVENT_NULL, xauth_inR0 }, /* Re-transmit may be done by previous state */
d8e7ea
+	  EVENT_NULL,
d8e7ea
+	  FM(xauth_inR0),
d8e7ea
+	  /* RFC ????: */
d8e7ea
+	  .hash_type = V1_HASH_1, }, /* Re-transmit may be done by previous state */
d8e7ea
 
d8e7ea
 	{ STATE_XAUTH_R1, STATE_MAIN_R3,
d8e7ea
 	  SMF_ALL_AUTH | SMF_ENCRYPTED,
d8e7ea
 	  P(MCFG_ATTR) | P(HASH), P(VID),
d8e7ea
-	  EVENT_SA_REPLACE, xauth_inR1 },
d8e7ea
+	  EVENT_SA_REPLACE,
d8e7ea
+	  FM(xauth_inR1),
d8e7ea
+	  /* RFC ????: */
d8e7ea
+	  .hash_type = V1_HASH_1, },
d8e7ea
 
d8e7ea
 #if 0
d8e7ea
 	/* for situation where there is XAUTH + ModeCFG */
d8e7ea
 	{ STATE_XAUTH_R2, STATE_XAUTH_R3,
d8e7ea
 	  SMF_ALL_AUTH | SMF_ENCRYPTED,
d8e7ea
 	  P(MCFG_ATTR) | P(HASH), P(VID),
d8e7ea
-	  EVENT_SA_REPLACE, xauth_inR2 },
d8e7ea
+	  EVENT_SA_REPLACE,
d8e7ea
+	  FM(xauth_inR2), },
d8e7ea
 
d8e7ea
 	{ STATE_XAUTH_R3, STATE_MAIN_R3,
d8e7ea
 	  SMF_ALL_AUTH | SMF_ENCRYPTED,
d8e7ea
 	  P(MCFG_ATTR) | P(HASH), P(VID),
d8e7ea
-	  EVENT_SA_REPLACE, xauth_inR3 },
d8e7ea
+	  EVENT_SA_REPLACE,
d8e7ea
+	  FM(xauth_inR3), },
d8e7ea
 #endif
d8e7ea
 
d8e7ea
 /* MODE_CFG_x:
d8e7ea
@@ -568,37 +679,57 @@
d8e7ea
 	{ STATE_MODE_CFG_R0, STATE_MODE_CFG_R1,
d8e7ea
 	  SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_REPLY,
d8e7ea
 	  P(MCFG_ATTR) | P(HASH), P(VID),
d8e7ea
-	  EVENT_SA_REPLACE, modecfg_inR0 },
d8e7ea
+	  EVENT_SA_REPLACE,
d8e7ea
+	  FM(modecfg_inR0),
d8e7ea
+	  /* RFC ????: */
d8e7ea
+	  .hash_type = V1_HASH_1, },
d8e7ea
 
d8e7ea
 	{ STATE_MODE_CFG_R1, STATE_MODE_CFG_R2,
d8e7ea
 	  SMF_ALL_AUTH | SMF_ENCRYPTED,
d8e7ea
 	  P(MCFG_ATTR) | P(HASH), P(VID),
d8e7ea
-	  EVENT_SA_REPLACE, modecfg_inR1 },
d8e7ea
+	  EVENT_SA_REPLACE,
d8e7ea
+	  FM(modecfg_inR1),
d8e7ea
+	  /* RFC ????: */
d8e7ea
+	  .hash_type = V1_HASH_1, },
d8e7ea
 
d8e7ea
 	{ STATE_MODE_CFG_R2, STATE_UNDEFINED,
d8e7ea
 	  SMF_ALL_AUTH | SMF_ENCRYPTED,
d8e7ea
 	  LEMPTY, LEMPTY,
d8e7ea
-	  EVENT_NULL, unexpected },
d8e7ea
+	  EVENT_NULL,
d8e7ea
+	  FM(unexpected),
d8e7ea
+	  .hash_type = V1_HASH_NONE, },
d8e7ea
 
d8e7ea
 	{ STATE_MODE_CFG_I1, STATE_MAIN_I4,
d8e7ea
 	  SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_RELEASE_PENDING_P2,
d8e7ea
 	  P(MCFG_ATTR) | P(HASH), P(VID),
d8e7ea
-	  EVENT_SA_REPLACE, modecfg_inR1 },
d8e7ea
+	  EVENT_SA_REPLACE,
d8e7ea
+	  FM(modecfg_inR1),
d8e7ea
+	  /* RFC ????: */
d8e7ea
+	  .hash_type = V1_HASH_1, },
d8e7ea
 
d8e7ea
 	{ STATE_XAUTH_I0, STATE_XAUTH_I1,
d8e7ea
 	  SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_REPLY | SMF_RELEASE_PENDING_P2,
d8e7ea
 	  P(MCFG_ATTR) | P(HASH), P(VID),
d8e7ea
-	  EVENT_RETRANSMIT, xauth_inI0 },
d8e7ea
+	  EVENT_RETRANSMIT,
d8e7ea
+	  FM(xauth_inI0),
d8e7ea
+	  /* RFC ????: */
d8e7ea
+	  .hash_type = V1_HASH_1, },
d8e7ea
 
d8e7ea
 	{ STATE_XAUTH_I1, STATE_MAIN_I4,
d8e7ea
 	  SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_REPLY | SMF_RELEASE_PENDING_P2,
d8e7ea
 	  P(MCFG_ATTR) | P(HASH), P(VID),
d8e7ea
-	  EVENT_RETRANSMIT, xauth_inI1 },
d8e7ea
+	  EVENT_RETRANSMIT,
d8e7ea
+	  FM(xauth_inI1),
d8e7ea
+	  /* RFC ????: */
d8e7ea
+	  .hash_type = V1_HASH_1, },
d8e7ea
 
d8e7ea
 	{ STATE_IKEv1_ROOF, STATE_IKEv1_ROOF,
d8e7ea
 	  LEMPTY,
d8e7ea
 	  LEMPTY, LEMPTY,
d8e7ea
-	  EVENT_NULL, NULL },
d8e7ea
+	  EVENT_NULL, NULL,
d8e7ea
+	  .hash_type = V1_HASH_NONE, },
d8e7ea
+
d8e7ea
+#undef FM
d8e7ea
 #undef P
d8e7ea
 };
d8e7ea
 
d8e7ea
@@ -748,6 +879,11 @@
d8e7ea
 		DBGF(DBG_TMI, "processing IKEv1 state transition %s -> %s",
d8e7ea
 		     from->fs_short_name, to->fs_short_name);
d8e7ea
 
d8e7ea
+		if (t->message == NULL) {
d8e7ea
+			PEXPECT_LOG("transition %s -> %s missing .message",
d8e7ea
+				from->fs_short_name, to->fs_short_name);
d8e7ea
+		}
d8e7ea
+
d8e7ea
 		/*
d8e7ea
 		 * Point .fs_v1_transitions at to the first entry in
d8e7ea
 		 * v1_state_microcode_table for that state.  All other
d8e7ea
@@ -786,10 +922,32 @@
d8e7ea
 		 * always true of a state?
d8e7ea
 		 */
d8e7ea
 		if ((t->flags & from->fs_flags) != from->fs_flags) {
d8e7ea
-			DBGF(DBG_BASE, "transition %s -> %s missing flags 0x%"PRIxLSET,
d8e7ea
-			     from->fs_short_name, to->fs_short_name, from->fs_flags);
d8e7ea
+			DBGF(DBG_BASE, "transition %s -> %s (%s) missing flags 0x%"PRIxLSET,
d8e7ea
+			     from->fs_short_name, to->fs_short_name,
d8e7ea
+			     t->message, from->fs_flags);
d8e7ea
 		}
d8e7ea
 		from->fs_flags |= t->flags & SMF_RETRANSMIT_ON_DUPLICATE;
d8e7ea
+
d8e7ea
+		if (!(t->flags & SMF_FIRST_ENCRYPTED_INPUT) &&
d8e7ea
+		    (t->flags & SMF_INPUT_ENCRYPTED) &&
d8e7ea
+		    t->processor != unexpected) {
d8e7ea
+			/*
d8e7ea
+			 * The first encrypted message carries
d8e7ea
+			 * authentication information so isn't
d8e7ea
+			 * applicable.  Other encrypted messages
d8e7ea
+			 * require integrity via the HASH payload.
d8e7ea
+			 */
d8e7ea
+			if (!(t->req_payloads & LELEM(ISAKMP_NEXT_HASH))) {
d8e7ea
+				PEXPECT_LOG("transition %s -> %s (%s) missing HASH payload",
d8e7ea
+					    from->fs_short_name, to->fs_short_name,
d8e7ea
+					    t->message);
d8e7ea
+			}
d8e7ea
+			if (t->hash_type == V1_HASH_NONE) {
d8e7ea
+				PEXPECT_LOG("transition %s -> %s (%s) missing HASH protection",
d8e7ea
+					    from->fs_short_name, to->fs_short_name,
d8e7ea
+					    t->message);
d8e7ea
+			}
d8e7ea
+		}
d8e7ea
 	}
d8e7ea
 
d8e7ea
 	/*
d8e7ea
@@ -2252,30 +2410,9 @@
d8e7ea
 		}
d8e7ea
 	}
d8e7ea
 
d8e7ea
-	if (md->hdr.isa_xchg == ISAKMP_XCHG_INFO &&
d8e7ea
-	    md->hdr.isa_np == ISAKMP_NEXT_HASH) {
d8e7ea
-		pb_stream *const hash_pbs = &(md)->chain[ISAKMP_NEXT_HASH]->pbs;
d8e7ea
-		u_char hash_val[MAX_DIGEST_LEN];
d8e7ea
-		size_t hash_len = quick_mode_hash12(hash_val, hash_pbs->roof,
d8e7ea
-						    md->message_pbs.roof,
d8e7ea
-						    st, &md->hdr.isa_msgid, FALSE);
d8e7ea
-		if (pbs_left(hash_pbs) != hash_len) {
d8e7ea
-			loglog(RC_LOG_SERIOUS,
d8e7ea
-			       "received 'informational' message HASH(1) data is the wrong length (received %zu bytes but expected %zu)",
d8e7ea
-			       pbs_left(hash_pbs), hash_len);
d8e7ea
-			return;
d8e7ea
-		}
d8e7ea
-		if (!memeq(hash_pbs->cur, hash_val, hash_len)) {
d8e7ea
-			if (DBGP(DBG_CRYPT)) {
d8e7ea
-				DBG_dump("received 'informational':",
d8e7ea
-					 hash_pbs->cur, pbs_left(hash_pbs));
d8e7ea
-			}
d8e7ea
-			loglog(RC_LOG_SERIOUS,
d8e7ea
-			       "received 'informational' message HASH(1) data does not match computed value");
d8e7ea
-			return;
d8e7ea
-		} else {
d8e7ea
-			dbg("received 'informational' message HASH(1) data ok");
d8e7ea
-		}
d8e7ea
+	if (!check_v1_HASH(smc->hash_type, smc->message, st, md)) {
d8e7ea
+		/*SEND_NOTIFICATION(INVALID_HASH_INFORMATION);*/
d8e7ea
+		return;
d8e7ea
 	}
d8e7ea
 
d8e7ea
 	/* more sanity checking: enforce most ordering constraints */
d8e7ea
diff -Naur libreswan-3.29-orig/programs/pluto/ikev1_hash.c libreswan-3.29/programs/pluto/ikev1_hash.c
d8e7ea
--- libreswan-3.29-orig/programs/pluto/ikev1_hash.c	1969-12-31 19:00:00.000000000 -0500
d8e7ea
+++ libreswan-3.29/programs/pluto/ikev1_hash.c	2019-06-11 19:24:00.543181473 -0400
d8e7ea
@@ -0,0 +1,158 @@
d8e7ea
+/* IKEv1 HASH payload wierdness, for Libreswan
d8e7ea
+ *
d8e7ea
+ * Copyright (C) 2019  Andrew Cagney
d8e7ea
+ *
d8e7ea
+ * This program is free software; you can redistribute it and/or modify it
d8e7ea
+ * under the terms of the GNU General Public License as published by the
d8e7ea
+ * Free Software Foundation; either version 2 of the License, or (at your
d8e7ea
+ * option) any later version.  See <https://www.gnu.org/licenses/gpl2.txt>.
d8e7ea
+ *
d8e7ea
+ * This program is distributed in the hope that it will be useful, but
d8e7ea
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
d8e7ea
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
d8e7ea
+ * for more details.
d8e7ea
+ *
d8e7ea
+ */
d8e7ea
+
d8e7ea
+#include "ikev1_hash.h"
d8e7ea
+
d8e7ea
+#include "state.h"
d8e7ea
+#include "crypt_prf.h"
d8e7ea
+#include "ike_alg.h"
d8e7ea
+#include "lswlog.h"
d8e7ea
+#include "demux.h"
d8e7ea
+#include "impair.h"
d8e7ea
+
d8e7ea
+bool emit_v1_HASH(enum v1_hash_type hash_type, const char *what,
d8e7ea
+		  enum exchange_impairment exchange,
d8e7ea
+		  struct state *st, struct v1_hash_fixup *fixup,
d8e7ea
+		  pb_stream *rbody)
d8e7ea
+{
d8e7ea
+	zero(fixup);
d8e7ea
+	fixup->what = what;
d8e7ea
+	fixup->hash_type = hash_type;
d8e7ea
+	fixup->impair = (impair_v1_hash_exchange == exchange
d8e7ea
+			 ? impair_v1_hash_payload : SEND_NORMAL);
d8e7ea
+	if (fixup->impair == SEND_OMIT) {
d8e7ea
+		libreswan_log("IMPAIR: omitting HASH payload for %s", what);
d8e7ea
+		return true;
d8e7ea
+	}
d8e7ea
+	pb_stream hash_pbs;
d8e7ea
+	if (!ikev1_out_generic(0, &isakmp_hash_desc, rbody, &hash_pbs)) {
d8e7ea
+		return false;
d8e7ea
+	}
d8e7ea
+	if (fixup->impair == SEND_EMPTY) {
d8e7ea
+		libreswan_log("IMPAIR: sending HASH payload with no data for %s", what);
d8e7ea
+	} else {
d8e7ea
+		/* reserve space for HASH data */
d8e7ea
+		fixup->hash_data = chunk(hash_pbs.cur, st->st_oakley.ta_prf->prf_output_size);
d8e7ea
+		if (!out_zero(fixup->hash_data.len, &hash_pbs, "HASH DATA"))
d8e7ea
+			return false;
d8e7ea
+	}
d8e7ea
+	close_output_pbs(&hash_pbs);
d8e7ea
+	/* save start of rest of message for later */
d8e7ea
+	fixup->body = rbody->cur;
d8e7ea
+	return true;
d8e7ea
+}
d8e7ea
+
d8e7ea
+void fixup_v1_HASH(struct state *st, const struct v1_hash_fixup *fixup,
d8e7ea
+		   msgid_t msgid, const uint8_t *roof)
d8e7ea
+{
d8e7ea
+	if (fixup->impair >= SEND_ROOF) {
d8e7ea
+		libreswan_log("IMPAIR: setting HASH payload bytes to %02x",
d8e7ea
+			      fixup->impair - SEND_ROOF);
d8e7ea
+		/* chunk_fill()? */
d8e7ea
+		memset(fixup->hash_data.ptr, fixup->impair - SEND_ROOF,
d8e7ea
+		       fixup->hash_data.len);
d8e7ea
+		return;
d8e7ea
+	} else if (fixup->impair != SEND_NORMAL) {
d8e7ea
+		/* already logged above? */
d8e7ea
+		return;
d8e7ea
+	}
d8e7ea
+	struct crypt_prf *hash =
d8e7ea
+		crypt_prf_init_symkey("HASH(1)", st->st_oakley.ta_prf,
d8e7ea
+				      "SKEYID_a", st->st_skeyid_a_nss);
d8e7ea
+	/* msgid */
d8e7ea
+	passert(sizeof(msgid_t) == sizeof(uint32_t));
d8e7ea
+	msgid_t raw_msgid = htonl(msgid);
d8e7ea
+	switch (fixup->hash_type) {
d8e7ea
+	case V1_HASH_1:
d8e7ea
+		/* HASH(1) = prf(SKEYID_a, M-ID | payload ) */
d8e7ea
+		crypt_prf_update_bytes(hash, "M-ID", &raw_msgid, sizeof(raw_msgid));
d8e7ea
+		crypt_prf_update_bytes(hash, "payload",
d8e7ea
+				       fixup->body, roof - fixup->body);
d8e7ea
+		break;
d8e7ea
+	case V1_HASH_2:
d8e7ea
+		/* HASH(2) = prf(SKEYID_a, M-ID | Ni_b | payload ) */
d8e7ea
+		crypt_prf_update_bytes(hash, "M-ID", &raw_msgid, sizeof(raw_msgid));
d8e7ea
+		crypt_prf_update_chunk(hash, "Ni_b", st->st_ni);
d8e7ea
+		crypt_prf_update_bytes(hash, "payload",
d8e7ea
+				       fixup->body, roof - fixup->body);
d8e7ea
+		break;
d8e7ea
+	case V1_HASH_3:
d8e7ea
+		/* HASH(3) = prf(SKEYID_a, 0 | M-ID | Ni_b | Nr_b) */
d8e7ea
+		crypt_prf_update_byte(hash, "0", 0);
d8e7ea
+		crypt_prf_update_bytes(hash, "M-ID", &raw_msgid, sizeof(raw_msgid));
d8e7ea
+		crypt_prf_update_chunk(hash, "Ni_b", st->st_ni);
d8e7ea
+		crypt_prf_update_chunk(hash, "Nr_b", st->st_nr);
d8e7ea
+		break;
d8e7ea
+	default:
d8e7ea
+		bad_case(fixup->hash_type);
d8e7ea
+	}
d8e7ea
+	/* stuff result into hash_data */
d8e7ea
+	passert(fixup->hash_data.len == st->st_oakley.ta_prf->prf_output_size);
d8e7ea
+	crypt_prf_final_bytes(&hash, fixup->hash_data.ptr, fixup->hash_data.len);
d8e7ea
+	if (DBGP(DBG_BASE)) {
d8e7ea
+		DBG_log("%s HASH(%u):", fixup->what, fixup->hash_type);
d8e7ea
+		DBG_dump_chunk(NULL, fixup->hash_data);
d8e7ea
+	}
d8e7ea
+}
d8e7ea
+
d8e7ea
+bool check_v1_HASH(enum v1_hash_type type, const char *what,
d8e7ea
+		   struct state *st, struct msg_digest *md)
d8e7ea
+{
d8e7ea
+	if (type == V1_HASH_NONE) {
d8e7ea
+		dbg("message '%s' HASH payload not checked early", what);
d8e7ea
+		return true;
d8e7ea
+	}
d8e7ea
+	if (impair_v1_hash_check) {
d8e7ea
+		libreswan_log("IMPAIR: skipping check of '%s' HASH payload", what);
d8e7ea
+		return true;
d8e7ea
+	}
d8e7ea
+	if (md->hdr.isa_np != ISAKMP_NEXT_HASH) {
d8e7ea
+		loglog(RC_LOG_SERIOUS, "received '%s' message is missing a HASH(%u) payload",
d8e7ea
+		       what, type);
d8e7ea
+		return false;
d8e7ea
+	}
d8e7ea
+	pb_stream *hash_pbs = &md->chain[ISAKMP_NEXT_HASH]->pbs;
d8e7ea
+	chunk_t received_hash = same_in_pbs_left_as_chunk(hash_pbs);
d8e7ea
+	if (received_hash.len != st->st_oakley.ta_prf->prf_output_size) {
d8e7ea
+		loglog(RC_LOG_SERIOUS,
d8e7ea
+		       "received '%s' message HASH(%u) data is the wrong length (received %zd bytes but expected %zd)",
d8e7ea
+		       what, type, received_hash.len, st->st_oakley.ta_prf->prf_output_size);
d8e7ea
+		return false;
d8e7ea
+	}
d8e7ea
+	/* compute the expected hash */
d8e7ea
+	uint8_t hash_val[MAX_DIGEST_LEN];
d8e7ea
+	passert(sizeof(hash_val) >= st->st_oakley.ta_prf->prf_output_size);
d8e7ea
+	struct v1_hash_fixup expected = {
d8e7ea
+		.hash_data = chunk(hash_val, st->st_oakley.ta_prf->prf_output_size),
d8e7ea
+		.body = received_hash.ptr + received_hash.len,
d8e7ea
+		.what = what,
d8e7ea
+		.hash_type = type,
d8e7ea
+	};
d8e7ea
+	fixup_v1_HASH(st, &expected, md->hdr.isa_msgid, md->message_pbs.roof);
d8e7ea
+	/* does it match? */
d8e7ea
+	if (!chunk_eq(received_hash, expected.hash_data)) {
d8e7ea
+		if (DBGP(DBG_BASE)) {
d8e7ea
+			DBG_log("received %s HASH_DATA:", what);
d8e7ea
+			DBG_dump_chunk(NULL, received_hash);
d8e7ea
+		}
d8e7ea
+		loglog(RC_LOG_SERIOUS,
d8e7ea
+		       "received '%s' message HASH(%u) data does not match computed value",
d8e7ea
+		       what, type);
d8e7ea
+		return false;
d8e7ea
+	}
d8e7ea
+	dbg("received '%s' message HASH(%u) data ok", what, type);
d8e7ea
+	return true;
d8e7ea
+}
d8e7ea
diff -Naur libreswan-3.29-orig/programs/pluto/ikev1_hash.h libreswan-3.29/programs/pluto/ikev1_hash.h
d8e7ea
--- libreswan-3.29-orig/programs/pluto/ikev1_hash.h	1969-12-31 19:00:00.000000000 -0500
d8e7ea
+++ libreswan-3.29/programs/pluto/ikev1_hash.h	2019-06-11 19:24:00.543181473 -0400
d8e7ea
@@ -0,0 +1,77 @@
d8e7ea
+/* IKEv1 HASH payload wierdness, for Libreswan
d8e7ea
+ *
d8e7ea
+ * Copyright (C) 2019  Andrew Cagney
d8e7ea
+ *
d8e7ea
+ * This program is free software; you can redistribute it and/or modify it
d8e7ea
+ * under the terms of the GNU General Public License as published by the
d8e7ea
+ * Free Software Foundation; either version 2 of the License, or (at your
d8e7ea
+ * option) any later version.  See <https://www.gnu.org/licenses/gpl2.txt>.
d8e7ea
+ *
d8e7ea
+ * This program is distributed in the hope that it will be useful, but
d8e7ea
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
d8e7ea
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
d8e7ea
+ * for more details.
d8e7ea
+ *
d8e7ea
+ */
d8e7ea
+
d8e7ea
+#ifndef IKEV1_HASH_H
d8e7ea
+#define IKEV1_HASH_H
d8e7ea
+
d8e7ea
+#include <stdint.h>
d8e7ea
+#include <stdbool.h>
d8e7ea
+
d8e7ea
+#include "chunk.h"
d8e7ea
+#include "defs.h"	/* for msgid_t */
d8e7ea
+#include "packet.h"	/* for pb_stream */
d8e7ea
+#include "impair.h"
d8e7ea
+
d8e7ea
+struct state;
d8e7ea
+struct msg_digest;
d8e7ea
+
d8e7ea
+/*
d8e7ea
+ * RFC 2409: 5.5 Phase 2 - Quick Mode
d8e7ea
+ *
d8e7ea
+ * HASH(1) = prf(SKEYID_a, M-ID | SA | Ni [ | KE ] [ | IDci | IDcr )
d8e7ea
+ * aka HASH(1) = prf(SKEYID_a, M-ID | payload )
d8e7ea
+ *
d8e7ea
+ * HASH(2) = prf(SKEYID_a, M-ID | Ni_b | SA | Nr [ | KE ] [ | IDci | IDcr )
d8e7ea
+ * aka HASH(2) = prf(SKEYID_a, M-ID | Ni_b | payload )
d8e7ea
+ *
d8e7ea
+ * HASH(3) = prf(SKEYID_a, 0 | M-ID | Ni_b | Nr_b)
d8e7ea
+ */
d8e7ea
+
d8e7ea
+enum v1_hash_type {
d8e7ea
+	V1_HASH_NONE,
d8e7ea
+	V1_HASH_1 = 1,
d8e7ea
+	V1_HASH_2 = 2,
d8e7ea
+	V1_HASH_3 = 3,
d8e7ea
+};
d8e7ea
+
d8e7ea
+/*
d8e7ea
+ * Emit (saving where it is) and fixup (a previously saved) v1 HASH
d8e7ea
+ * payload.
d8e7ea
+ */
d8e7ea
+
d8e7ea
+struct v1_hash_fixup {
d8e7ea
+	chunk_t hash_data;
d8e7ea
+	const uint8_t *body;
d8e7ea
+	msgid_t msgid;
d8e7ea
+	const char *what;
d8e7ea
+	enum send_impairment impair;
d8e7ea
+	enum v1_hash_type hash_type;
d8e7ea
+};
d8e7ea
+
d8e7ea
+bool emit_v1_HASH(enum v1_hash_type type, const char *what,
d8e7ea
+		  enum exchange_impairment exchange, struct state *st,
d8e7ea
+		  struct v1_hash_fixup *hash_fixup, pb_stream *out_pbs);
d8e7ea
+
d8e7ea
+void fixup_v1_HASH(struct state *st, const struct v1_hash_fixup *data,
d8e7ea
+		   msgid_t msgid, const uint8_t *roof);
d8e7ea
+
d8e7ea
+/*
d8e7ea
+ * Check the IKEv1 HASH payload.
d8e7ea
+ */
d8e7ea
+bool check_v1_HASH(enum v1_hash_type type, const char *what,
d8e7ea
+		   struct state *st, struct msg_digest *md);
d8e7ea
+
d8e7ea
+#endif
d8e7ea
diff -Naur libreswan-3.29-orig/programs/pluto/ikev1_main.c libreswan-3.29/programs/pluto/ikev1_main.c
d8e7ea
--- libreswan-3.29-orig/programs/pluto/ikev1_main.c	2019-06-10 10:22:04.000000000 -0400
d8e7ea
+++ libreswan-3.29/programs/pluto/ikev1_main.c	2019-06-11 19:23:55.362124010 -0400
d8e7ea
@@ -65,6 +65,7 @@
d8e7ea
 #include "fetch.h"
d8e7ea
 #include "asn1.h"
d8e7ea
 #include "pending.h"
d8e7ea
+#include "ikev1_hash.h"
d8e7ea
 
d8e7ea
 #include "crypto.h"
d8e7ea
 #include "secrets.h"
d8e7ea
@@ -1547,6 +1548,10 @@
d8e7ea
 				"received Hash Payload does not match computed value");
d8e7ea
 			/* XXX Could send notification back */
d8e7ea
 			r = STF_FAIL + INVALID_HASH_INFORMATION;
d8e7ea
+		} else {
d8e7ea
+			dbg("received '%s' message HASH_%s data ok",
d8e7ea
+			    aggrmode ? "Aggr" : "Main",
d8e7ea
+			    initiator ? "R" : "I" /*reverse*/);
d8e7ea
 		}
d8e7ea
 		break;
d8e7ea
 	}
d8e7ea
@@ -1555,6 +1560,11 @@
d8e7ea
 	{
d8e7ea
 		r = RSA_check_signature(st, hash_val, hash_len,
d8e7ea
 					&md->chain[ISAKMP_NEXT_SIG]->pbs, 0 /* for ikev2 only*/);
d8e7ea
+		if (r != STF_OK) {
d8e7ea
+			dbg("received '%s' message SIG_%s data did not match computed value",
d8e7ea
+			    aggrmode ? "Aggr" : "Main",
d8e7ea
+			    initiator ? "R" : "I" /*reverse*/);
d8e7ea
+		}
d8e7ea
 		break;
d8e7ea
 	}
d8e7ea
 	/* These are the only IKEv1 AUTH methods we support */
d8e7ea
@@ -1862,14 +1872,11 @@
d8e7ea
 }
d8e7ea
 
d8e7ea
 stf_status send_isakmp_notification(struct state *st,
d8e7ea
-				uint16_t type, const void *data,
d8e7ea
-				size_t len)
d8e7ea
+				    uint16_t type, const void *data,
d8e7ea
+				    size_t len)
d8e7ea
 {
d8e7ea
 	msgid_t msgid;
d8e7ea
 	pb_stream rbody;
d8e7ea
-	u_char
d8e7ea
-		*r_hashval, /* where in reply to jam hash value */
d8e7ea
-		*r_hash_start; /* start of what is to be hashed */
d8e7ea
 
d8e7ea
 	msgid = generate_msgid(st);
d8e7ea
 
d8e7ea
@@ -1879,7 +1886,6 @@
d8e7ea
 	/* HDR* */
d8e7ea
 	{
d8e7ea
 		struct isakmp_hdr hdr = {
d8e7ea
-			.isa_np = ISAKMP_NEXT_HASH,
d8e7ea
 			.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT |
d8e7ea
 				ISAKMP_MINOR_VERSION,
d8e7ea
 			.isa_xchg = ISAKMP_XCHG_INFO,
d8e7ea
@@ -1891,8 +1897,13 @@
d8e7ea
 		if (!out_struct(&hdr, &isakmp_hdr_desc, &reply_stream, &rbody))
d8e7ea
 			return STF_INTERNAL_ERROR;
d8e7ea
 	}
d8e7ea
-	/* HASH -- create and note space to be filled later */
d8e7ea
-	START_HASH_PAYLOAD(rbody, ISAKMP_NEXT_N);
d8e7ea
+
d8e7ea
+	struct v1_hash_fixup hash_fixup;
d8e7ea
+	if (!emit_v1_HASH(V1_HASH_1, "notification",
d8e7ea
+			  NOTIFICATION_EXCHANGE,
d8e7ea
+			  st, &hash_fixup, &rbody)) {
d8e7ea
+		return STF_INTERNAL_ERROR;
d8e7ea
+	}
d8e7ea
 
d8e7ea
 	/* NOTIFY */
d8e7ea
 	{
d8e7ea
@@ -1919,23 +1930,8 @@
d8e7ea
 		close_output_pbs(&notify_pbs);
d8e7ea
 	}
d8e7ea
 
d8e7ea
+	fixup_v1_HASH(st, &hash_fixup, msgid, rbody.cur);
d8e7ea
 
d8e7ea
-	{
d8e7ea
-		/* finish computing HASH */
d8e7ea
-		struct hmac_ctx ctx;
d8e7ea
-
d8e7ea
-		hmac_init(&ctx, st->st_oakley.ta_prf, st->st_skeyid_a_nss);
d8e7ea
-		passert(sizeof(msgid_t) == sizeof(uint32_t));
d8e7ea
-		msgid_t raw_msgid = htonl(msgid);
d8e7ea
-		hmac_update(&ctx, (const void *)&raw_msgid, sizeof(raw_msgid));
d8e7ea
-		hmac_update(&ctx, r_hash_start, rbody.cur - r_hash_start);
d8e7ea
-		hmac_final(r_hashval, &ctx;;
d8e7ea
-
d8e7ea
-		DBG(DBG_CRYPT, {
d8e7ea
-				DBG_log("HASH computed:");
d8e7ea
-				DBG_dump("", r_hashval, ctx.hmac_digest_len);
d8e7ea
-			});
d8e7ea
-	}
d8e7ea
 	/*
d8e7ea
 	 * save old IV (this prevents from copying a whole new state object
d8e7ea
 	 * for NOTIFICATION / DELETE messages we don't need to maintain a state
d8e7ea
@@ -1984,13 +1980,9 @@
d8e7ea
 	pb_stream pbs;
d8e7ea
 
d8e7ea
 	pb_stream r_hdr_pbs;
d8e7ea
-	u_char *r_hashval, *r_hash_start;
d8e7ea
 	static monotime_t last_malformed = MONOTIME_EPOCH;
d8e7ea
 	monotime_t n = mononow();
d8e7ea
 
d8e7ea
-	r_hashval = NULL;
d8e7ea
-	r_hash_start = NULL;
d8e7ea
-
d8e7ea
 	switch (type) {
d8e7ea
 	case PAYLOAD_MALFORMED:
d8e7ea
 		/* only send one per second. */
d8e7ea
@@ -2065,7 +2057,6 @@
d8e7ea
 		struct isakmp_hdr hdr = {
d8e7ea
 			.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT |
d8e7ea
 				ISAKMP_MINOR_VERSION,
d8e7ea
-			.isa_np = encst ? ISAKMP_NEXT_HASH : ISAKMP_NEXT_N,
d8e7ea
 			.isa_xchg = ISAKMP_XCHG_INFO,
d8e7ea
 			.isa_msgid = msgid,
d8e7ea
 			.isa_flags = encst ? ISAKMP_FLAGS_v1_ENCRYPTION : 0,
d8e7ea
@@ -2078,15 +2069,14 @@
d8e7ea
 	}
d8e7ea
 
d8e7ea
 	/* HASH -- value to be filled later */
d8e7ea
-	if (encst) {
d8e7ea
-		pb_stream hash_pbs;
d8e7ea
-		passert(ikev1_out_generic(ISAKMP_NEXT_N, &isakmp_hash_desc, &r_hdr_pbs,
d8e7ea
-					  &hash_pbs));
d8e7ea
-		r_hashval = hash_pbs.cur; /* remember where to plant value */
d8e7ea
-		passert(out_zero(encst->st_oakley.ta_prf->prf_output_size,
d8e7ea
-				 &hash_pbs, "HASH(1)"));
d8e7ea
-		close_output_pbs(&hash_pbs);
d8e7ea
-		r_hash_start = r_hdr_pbs.cur; /* hash from after HASH(1) */
d8e7ea
+	struct v1_hash_fixup hash_fixup;
d8e7ea
+	if (encst != NULL) {
d8e7ea
+		if (!emit_v1_HASH(V1_HASH_1, "send notification",
d8e7ea
+				  NOTIFICATION_EXCHANGE,
d8e7ea
+				  encst, &hash_fixup, &r_hdr_pbs)) {
d8e7ea
+			/* return STF_INTERNAL_ERROR; */
d8e7ea
+			return;
d8e7ea
+		}
d8e7ea
 	}
d8e7ea
 
d8e7ea
 	/* Notification Payload */
d8e7ea
@@ -2111,21 +2101,8 @@
d8e7ea
 	}
d8e7ea
 
d8e7ea
 	/* calculate hash value and patch into Hash Payload */
d8e7ea
-	if (encst) {
d8e7ea
-		struct hmac_ctx ctx;
d8e7ea
-
d8e7ea
-		hmac_init(&ctx, encst->st_oakley.ta_prf,
d8e7ea
-			  encst->st_skeyid_a_nss);
d8e7ea
-		passert(sizeof(msgid_t) == sizeof(uint32_t));
d8e7ea
-		msgid_t raw_msgid = htonl(msgid);
d8e7ea
-		hmac_update(&ctx, (const void *)&raw_msgid, sizeof(raw_msgid));
d8e7ea
-		hmac_update(&ctx, r_hash_start, r_hdr_pbs.cur - r_hash_start);
d8e7ea
-		hmac_final(r_hashval, &ctx;;
d8e7ea
-
d8e7ea
-		DBG(DBG_CRYPT, {
d8e7ea
-				DBG_log("HASH(1) computed:");
d8e7ea
-				DBG_dump("", r_hashval, ctx.hmac_digest_len);
d8e7ea
-			});
d8e7ea
+	if (encst != NULL) {
d8e7ea
+		fixup_v1_HASH(encst, &hash_fixup, msgid, r_hdr_pbs.cur);
d8e7ea
 	}
d8e7ea
 
d8e7ea
 	if (encst != NULL) {
d8e7ea
@@ -2242,9 +2219,6 @@
d8e7ea
 	struct state *p1st;
d8e7ea
 	ip_said said[EM_MAXRELSPIS];
d8e7ea
 	ip_said *ns = said;
d8e7ea
-	u_char
d8e7ea
-		*r_hashval, /* where in reply to jam hash value */
d8e7ea
-		*r_hash_start; /* start of what is to be hashed */
d8e7ea
 	bool isakmp_sa = FALSE;
d8e7ea
 
d8e7ea
 	/* If there are IPsec SA's related to this state struct... */
d8e7ea
@@ -2288,7 +2262,6 @@
d8e7ea
 		struct isakmp_hdr hdr = {
d8e7ea
 			.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT |
d8e7ea
 				ISAKMP_MINOR_VERSION,
d8e7ea
-			.isa_np = ISAKMP_NEXT_HASH,
d8e7ea
 			.isa_xchg = ISAKMP_XCHG_INFO,
d8e7ea
 			.isa_msgid = msgid,
d8e7ea
 			.isa_flags = ISAKMP_FLAGS_v1_ENCRYPTION,
d8e7ea
@@ -2300,16 +2273,10 @@
d8e7ea
 	}
d8e7ea
 
d8e7ea
 	/* HASH -- value to be filled later */
d8e7ea
-	{
d8e7ea
-		pb_stream hash_pbs;
d8e7ea
-
d8e7ea
-		passert(ikev1_out_generic(ISAKMP_NEXT_D, &isakmp_hash_desc, &r_hdr_pbs,
d8e7ea
-					  &hash_pbs));
d8e7ea
-		r_hashval = hash_pbs.cur; /* remember where to plant value */
d8e7ea
-		passert(out_zero(p1st->st_oakley.ta_prf->prf_output_size,
d8e7ea
-				 &hash_pbs, "HASH(1)"));
d8e7ea
-		close_output_pbs(&hash_pbs);
d8e7ea
-		r_hash_start = r_hdr_pbs.cur; /* hash from after HASH(1) */
d8e7ea
+	struct v1_hash_fixup hash_fixup;
d8e7ea
+	if (!emit_v1_HASH(V1_HASH_1, "send delete", DELETE_EXCHANGE,
d8e7ea
+			  p1st, &hash_fixup, &r_hdr_pbs)) {
d8e7ea
+		return /* STF_INTERNAL_ERROR */;
d8e7ea
 	}
d8e7ea
 
d8e7ea
 	/* Delete Payloads */
d8e7ea
@@ -2375,22 +2342,7 @@
d8e7ea
 	}
d8e7ea
 
d8e7ea
 	/* calculate hash value and patch into Hash Payload */
d8e7ea
-	{
d8e7ea
-		struct hmac_ctx ctx;
d8e7ea
-
d8e7ea
-		hmac_init(&ctx, p1st->st_oakley.ta_prf,
d8e7ea
-			  p1st->st_skeyid_a_nss);
d8e7ea
-		passert(sizeof(msgid_t) == sizeof(uint32_t));
d8e7ea
-		msgid_t raw_msgid = htonl(msgid);
d8e7ea
-		hmac_update(&ctx, (const void *)&raw_msgid, sizeof(raw_msgid));
d8e7ea
-		hmac_update(&ctx, r_hash_start, r_hdr_pbs.cur - r_hash_start);
d8e7ea
-		hmac_final(r_hashval, &ctx;;
d8e7ea
-
d8e7ea
-		DBG(DBG_CRYPT, {
d8e7ea
-				DBG_log("HASH(1) computed:");
d8e7ea
-				DBG_dump("", r_hashval, ctx.hmac_digest_len);
d8e7ea
-			});
d8e7ea
-	}
d8e7ea
+	fixup_v1_HASH(p1st, &hash_fixup, msgid, r_hdr_pbs.cur);
d8e7ea
 
d8e7ea
 	/*
d8e7ea
 	 * Do a dance to avoid needing a new state object.
d8e7ea
diff -Naur libreswan-3.29-orig/programs/pluto/ikev1_quick.c libreswan-3.29/programs/pluto/ikev1_quick.c
d8e7ea
--- libreswan-3.29-orig/programs/pluto/ikev1_quick.c	2019-06-10 10:22:04.000000000 -0400
d8e7ea
+++ libreswan-3.29/programs/pluto/ikev1_quick.c	2019-06-11 19:28:00.687844878 -0400
d8e7ea
@@ -81,6 +81,7 @@
d8e7ea
 #include "pluto_x509.h"
d8e7ea
 #include "ip_address.h"
d8e7ea
 #include "af_info.h"
d8e7ea
+#include "ikev1_hash.h"
d8e7ea
 
d8e7ea
 #include <blapit.h>
d8e7ea
 
d8e7ea
@@ -660,69 +661,6 @@
d8e7ea
 	return !bad_proposal;
d8e7ea
 }
d8e7ea
 
d8e7ea
-/* Compute HASH(1), HASH(2) of Quick Mode.
d8e7ea
- * HASH(1) is part of Quick I1 message.
d8e7ea
- * HASH(2) is part of Quick R1 message.
d8e7ea
- * Used by: quick_outI1, quick_inI1_outR1 (twice), quick_inR1_outI2
d8e7ea
- * (see RFC 2409 "IKE" 5.5, pg. 18 or draft-ietf-ipsec-ike-01.txt 6.2 pg 25)
d8e7ea
- */
d8e7ea
-size_t quick_mode_hash12(u_char *dest, const u_char *start,
d8e7ea
-			 const u_char *roof,
d8e7ea
-			 const struct state *st, const msgid_t *msgid,
d8e7ea
-			 bool hash2)
d8e7ea
-{
d8e7ea
-	struct hmac_ctx ctx;
d8e7ea
-
d8e7ea
-#if 0   /* if desperate to debug hashing */
d8e7ea
-#   define hmac_update(ctx, ptr, len) { \
d8e7ea
-		DBG_dump("hash input", (ptr), (len)); \
d8e7ea
-		(hmac_update)((ctx), (ptr), (len)); \
d8e7ea
-}
d8e7ea
-	DBG_dump("hash key", st->st_skeyid_a.ptr, st->st_skeyid_a.len);
d8e7ea
-#endif
d8e7ea
-	hmac_init(&ctx, st->st_oakley.ta_prf, st->st_skeyid_a_nss);
d8e7ea
-	passert(sizeof(msgid_t) == sizeof(uint32_t));
d8e7ea
-	msgid_t raw_msgid = htonl(*msgid);
d8e7ea
-	hmac_update(&ctx, (const void *)&raw_msgid, sizeof(raw_msgid));
d8e7ea
-	if (hash2)
d8e7ea
-		hmac_update_chunk(&ctx, st->st_ni); /* include Ni_b in the hash */
d8e7ea
-	hmac_update(&ctx, start, roof - start);
d8e7ea
-	hmac_final(dest, &ctx;;
d8e7ea
-
d8e7ea
-	DBG(DBG_CRYPT, {
d8e7ea
-			DBG_log("HASH(%d) computed:", hash2 + 1);
d8e7ea
-			DBG_dump("", dest, ctx.hmac_digest_len);
d8e7ea
-		});
d8e7ea
-	return ctx.hmac_digest_len;
d8e7ea
-
d8e7ea
-#   undef hmac_update
d8e7ea
-}
d8e7ea
-
d8e7ea
-/* Compute HASH(3) in Quick Mode (part of Quick I2 message).
d8e7ea
- * Used by: quick_inR1_outI2, quick_inI2
d8e7ea
- * See RFC2409 "The Internet Key Exchange (IKE)" 5.5.
d8e7ea
- * NOTE: this hash (unlike HASH(1) and HASH(2)) ONLY covers the
d8e7ea
- * Message ID and Nonces.  This is a mistake.
d8e7ea
- */
d8e7ea
-static size_t quick_mode_hash3(u_char *dest, struct state *st)
d8e7ea
-{
d8e7ea
-	struct hmac_ctx ctx;
d8e7ea
-
d8e7ea
-	hmac_init(&ctx, st->st_oakley.ta_prf, st->st_skeyid_a_nss);
d8e7ea
-	hmac_update(&ctx, (const u_char *)"\0", 1);
d8e7ea
-	passert(sizeof(msgid_t) == sizeof(uint32_t));
d8e7ea
-	msgid_t raw_msgid = htonl(st->st_msgid);
d8e7ea
-	hmac_update(&ctx, (const void*)&raw_msgid, sizeof(raw_msgid));
d8e7ea
-	hmac_update_chunk(&ctx, st->st_ni);
d8e7ea
-	hmac_update_chunk(&ctx, st->st_nr);
d8e7ea
-	hmac_final(dest, &ctx;;
d8e7ea
-	if (DBGP(DBG_CRYPT)) {
d8e7ea
-		DBG_dump("HASH(3) computed:", dest,
d8e7ea
-			 ctx.hmac_digest_len);
d8e7ea
-	}
d8e7ea
-	return ctx.hmac_digest_len;
d8e7ea
-}
d8e7ea
-
d8e7ea
 /* Compute Phase 2 IV.
d8e7ea
  * Uses Phase 1 IV from st_iv; puts result in st_new_iv.
d8e7ea
  */
d8e7ea
@@ -879,9 +817,6 @@
d8e7ea
 	struct state *isakmp_sa = state_with_serialno(st->st_clonedfrom);
d8e7ea
 	struct connection *c = st->st_connection;
d8e7ea
 	pb_stream rbody;
d8e7ea
-	u_char          /* set by START_HASH_PAYLOAD: */
d8e7ea
-		*r_hashval,     /* where in reply to jam hash value */
d8e7ea
-		*r_hash_start;  /* start of what is to be hashed */
d8e7ea
 	bool has_client = c->spd.this.has_client || c->spd.that.has_client ||
d8e7ea
 			  c->spd.this.protocol != 0 || c->spd.that.protocol != 0 ||
d8e7ea
 			  c->spd.this.port != 0 || c->spd.that.port != 0;
d8e7ea
@@ -915,7 +850,6 @@
d8e7ea
 		struct isakmp_hdr hdr = {
d8e7ea
 			.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT |
d8e7ea
 					  ISAKMP_MINOR_VERSION,
d8e7ea
-			.isa_np = ISAKMP_NEXT_HASH,
d8e7ea
 			.isa_xchg = ISAKMP_XCHG_QUICK,
d8e7ea
 			.isa_msgid = st->st_msgid,
d8e7ea
 			.isa_flags = ISAKMP_FLAGS_v1_ENCRYPTION,
d8e7ea
@@ -930,7 +864,11 @@
d8e7ea
 	}
d8e7ea
 
d8e7ea
 	/* HASH(1) -- create and note space to be filled later */
d8e7ea
-	START_HASH_PAYLOAD(rbody, ISAKMP_NEXT_SA);
d8e7ea
+	struct v1_hash_fixup hash_fixup;
d8e7ea
+	if (!emit_v1_HASH(V1_HASH_1, "outI1", QUICK_EXCHANGE,
d8e7ea
+			  st, &hash_fixup, &rbody)) {
d8e7ea
+		return STF_INTERNAL_ERROR;
d8e7ea
+	}
d8e7ea
 
d8e7ea
 	/* SA out */
d8e7ea
 
d8e7ea
@@ -1010,8 +948,7 @@
d8e7ea
 	}
d8e7ea
 
d8e7ea
 	/* finish computing  HASH(1), inserting it in output */
d8e7ea
-	(void) quick_mode_hash12(r_hashval, r_hash_start, rbody.cur,
d8e7ea
-				 st, &st->st_msgid, FALSE);
d8e7ea
+	fixup_v1_HASH(st, &hash_fixup, st->st_msgid, rbody.cur);
d8e7ea
 
d8e7ea
 	/* encrypt message, except for fixed part of header */
d8e7ea
 
d8e7ea
@@ -1098,13 +1035,6 @@
d8e7ea
 	struct payload_digest *const id_pd = md->chain[ISAKMP_NEXT_ID];
d8e7ea
 	struct verify_oppo_bundle b;
d8e7ea
 
d8e7ea
-	/* HASH(1) in */
d8e7ea
-	CHECK_QUICK_HASH(md,
d8e7ea
-			 quick_mode_hash12(hash_val, hash_pbs->roof,
d8e7ea
-					   md->message_pbs.roof,
d8e7ea
-					   p1st, &md->hdr.isa_msgid, FALSE),
d8e7ea
-			 "HASH(1)", "Quick I1");
d8e7ea
-
d8e7ea
 	/* [ IDci, IDcr ] in
d8e7ea
 	 * We do this now (probably out of physical order) because
d8e7ea
 	 * we wish to select the correct connection before we consult
d8e7ea
@@ -1577,9 +1507,6 @@
d8e7ea
 	struct state *st = md->st;
d8e7ea
 	struct payload_digest *const id_pd = md->chain[ISAKMP_NEXT_ID];
d8e7ea
 	struct payload_digest *const sapd = md->chain[ISAKMP_NEXT_SA];
d8e7ea
-	u_char          /* set by START_HASH_PAYLOAD: */
d8e7ea
-		*r_hashval,     /* where in reply to jam hash value */
d8e7ea
-		*r_hash_start;  /* from where to start hashing */
d8e7ea
 
d8e7ea
 	/* Start the output packet.
d8e7ea
 	 *
d8e7ea
@@ -1594,12 +1521,15 @@
d8e7ea
 
d8e7ea
 	/* HDR* out */
d8e7ea
 	pb_stream rbody;
d8e7ea
-	ikev1_init_out_pbs_echo_hdr(md, TRUE, ISAKMP_NEXT_HASH,
d8e7ea
+	ikev1_init_out_pbs_echo_hdr(md, TRUE, 0,
d8e7ea
 				    &reply_stream, reply_buffer, sizeof(reply_buffer),
d8e7ea
 				    &rbody);
d8e7ea
 
d8e7ea
-	/* HASH(2) out -- first pass */
d8e7ea
-	START_HASH_PAYLOAD(rbody, ISAKMP_NEXT_SA);
d8e7ea
+	struct v1_hash_fixup hash_fixup;
d8e7ea
+	if (!emit_v1_HASH(V1_HASH_2, "quick inR1 outI2",
d8e7ea
+			  QUICK_EXCHANGE, st, &hash_fixup, &rbody)) {
d8e7ea
+		return STF_INTERNAL_ERROR;
d8e7ea
+	}
d8e7ea
 
d8e7ea
 	passert(st->st_connection != NULL);
d8e7ea
 
d8e7ea
@@ -1720,8 +1650,7 @@
d8e7ea
 	}
d8e7ea
 
d8e7ea
 	/* Compute reply HASH(2) and insert in output */
d8e7ea
-	(void)quick_mode_hash12(r_hashval, r_hash_start, rbody.cur,
d8e7ea
-				st, &st->st_msgid, TRUE);
d8e7ea
+	fixup_v1_HASH(st, &hash_fixup, st->st_msgid, rbody.cur);
d8e7ea
 
d8e7ea
 	/* Derive new keying material */
d8e7ea
 	compute_keymats(st);
d8e7ea
@@ -1758,13 +1687,6 @@
d8e7ea
 
d8e7ea
 stf_status quick_inR1_outI2(struct state *st, struct msg_digest *md)
d8e7ea
 {
d8e7ea
-	/* HASH(2) in */
d8e7ea
-	CHECK_QUICK_HASH(md,
d8e7ea
-			 quick_mode_hash12(hash_val, hash_pbs->roof,
d8e7ea
-					   md->message_pbs.roof,
d8e7ea
-					   st, &st->st_msgid, TRUE),
d8e7ea
-			 "HASH(2)", "Quick R1");
d8e7ea
-
d8e7ea
 	/* SA in */
d8e7ea
 	{
d8e7ea
 		struct payload_digest *const sa_pd = md->chain[ISAKMP_NEXT_SA];
d8e7ea
@@ -1812,7 +1734,7 @@
d8e7ea
 	struct connection *c = st->st_connection;
d8e7ea
 
d8e7ea
 	pb_stream rbody;
d8e7ea
-	ikev1_init_out_pbs_echo_hdr(md, TRUE, ISAKMP_NEXT_HASH,
d8e7ea
+	ikev1_init_out_pbs_echo_hdr(md, TRUE, 0,
d8e7ea
 				    &reply_stream, reply_buffer, sizeof(reply_buffer),
d8e7ea
 				    &rbody);
d8e7ea
 
d8e7ea
@@ -1907,7 +1829,7 @@
d8e7ea
 
d8e7ea
 	/* HASH(3) out -- sometimes, we add more content */
d8e7ea
 	{
d8e7ea
-		u_char *r_hashval;	/* set by START_HASH_PAYLOAD */
d8e7ea
+		struct v1_hash_fixup hash_fixup;
d8e7ea
 
d8e7ea
 #ifdef IMPAIR_UNALIGNED_I2_MSG
d8e7ea
 		{
d8e7ea
@@ -1945,12 +1867,13 @@
d8e7ea
 			}
d8e7ea
 		}
d8e7ea
 #else
d8e7ea
-		START_HASH_PAYLOAD_NO_R_HASH_START(rbody,
d8e7ea
-						   ISAKMP_NEXT_NONE);
d8e7ea
+		if (!emit_v1_HASH(V1_HASH_3, "quick_inR1_outI2",
d8e7ea
+				  QUICK_EXCHANGE, st, &hash_fixup, &rbody)) {
d8e7ea
+			return STF_INTERNAL_ERROR;
d8e7ea
+		}
d8e7ea
 #endif
d8e7ea
 
d8e7ea
-
d8e7ea
-		(void)quick_mode_hash3(r_hashval, st);
d8e7ea
+		fixup_v1_HASH(st, &hash_fixup, st->st_msgid, NULL);
d8e7ea
 	}
d8e7ea
 
d8e7ea
 	/* Derive new keying material */
d8e7ea
@@ -1986,12 +1909,8 @@
d8e7ea
  * (see RFC 2409 "IKE" 5.5)
d8e7ea
  * Installs outbound IPsec SAs, routing, etc.
d8e7ea
  */
d8e7ea
-stf_status quick_inI2(struct state *st, struct msg_digest *md)
d8e7ea
+stf_status quick_inI2(struct state *st, struct msg_digest *md UNUSED)
d8e7ea
 {
d8e7ea
-	/* HASH(3) in */
d8e7ea
-	CHECK_QUICK_HASH(md, quick_mode_hash3(hash_val, st),
d8e7ea
-			 "HASH(3)", "Quick I2");
d8e7ea
-
d8e7ea
 	/* Tell the kernel to establish the outbound and routing part of the new SA
d8e7ea
 	 * (the previous state established inbound)
d8e7ea
 	 * (unless the commit bit is set -- which we don't support).
d8e7ea
diff -Naur libreswan-3.29-orig/programs/pluto/ikev1_xauth.c libreswan-3.29/programs/pluto/ikev1_xauth.c
d8e7ea
--- libreswan-3.29-orig/programs/pluto/ikev1_xauth.c	2019-06-10 10:22:04.000000000 -0400
d8e7ea
+++ libreswan-3.29/programs/pluto/ikev1_xauth.c	2019-06-11 19:28:00.688844889 -0400
d8e7ea
@@ -78,6 +78,8 @@
d8e7ea
 #include "send.h"		/* for send without recording */
d8e7ea
 #include "ikev1_send.h"
d8e7ea
 #include "af_info.h"
d8e7ea
+#include "ikev1_hash.h"
d8e7ea
+#include "impair.h"
d8e7ea
 
d8e7ea
 /* forward declarations */
d8e7ea
 static stf_status xauth_client_ackstatus(struct state *st,
d8e7ea
@@ -198,25 +200,19 @@
d8e7ea
  * @param st State structure
d8e7ea
  * @return size_t Length of the HASH
d8e7ea
  */
d8e7ea
-static size_t xauth_mode_cfg_hash(u_char *dest,
d8e7ea
-				  const u_char *start,
d8e7ea
-				  const u_char *roof,
d8e7ea
-				  const struct state *st)
d8e7ea
-{
d8e7ea
-	struct hmac_ctx ctx;
d8e7ea
-
d8e7ea
-	hmac_init(&ctx, st->st_oakley.ta_prf, st->st_skeyid_a_nss);
d8e7ea
-	passert(sizeof(msgid_t) == sizeof(uint32_t));
d8e7ea
-	msgid_t raw_msgid = htonl(st->st_msgid_phase15);
d8e7ea
-	hmac_update(&ctx, (const void *)&raw_msgid, sizeof(raw_msgid));
d8e7ea
-	hmac_update(&ctx, start, roof - start);
d8e7ea
-	hmac_final(dest, &ctx;;
d8e7ea
-
d8e7ea
-	DBG(DBG_CRYPT|DBG_XAUTH, {
d8e7ea
-		DBG_log("XAUTH: HASH computed:");
d8e7ea
-		DBG_dump("", dest, ctx.hmac_digest_len);
d8e7ea
-	});
d8e7ea
-	return ctx.hmac_digest_len;
d8e7ea
+
d8e7ea
+static bool emit_xauth_hash(const char *what, struct state *st,
d8e7ea
+			    struct v1_hash_fixup *hash_fixup, pb_stream *out)
d8e7ea
+{
d8e7ea
+	return emit_v1_HASH(V1_HASH_1, what, XAUTH_EXCHANGE,
d8e7ea
+			    st, hash_fixup, out);
d8e7ea
+}
d8e7ea
+
d8e7ea
+static void fixup_xauth_hash(struct state *st,
d8e7ea
+			     struct v1_hash_fixup *hash_fixup,
d8e7ea
+			     const uint8_t *roof)
d8e7ea
+{
d8e7ea
+	fixup_v1_HASH(st, hash_fixup, st->st_msgid_phase15, roof);
d8e7ea
 }
d8e7ea
 
d8e7ea
 /**
d8e7ea
@@ -383,23 +379,10 @@
d8e7ea
 			bool use_modecfg_addr_as_client_addr,
d8e7ea
 			uint16_t ap_id)
d8e7ea
 {
d8e7ea
-	unsigned char *r_hash_start, *r_hashval;
d8e7ea
-
d8e7ea
-	/* START_HASH_PAYLOAD(rbody, ISAKMP_NEXT_MCFG_ATTR); */
d8e7ea
-
d8e7ea
-	{
d8e7ea
-		pb_stream hash_pbs;
d8e7ea
-
d8e7ea
-		if (!ikev1_out_generic(ISAKMP_NEXT_MCFG_ATTR, &isakmp_hash_desc, rbody, &hash_pbs))
d8e7ea
-			return STF_INTERNAL_ERROR;
d8e7ea
-
d8e7ea
-		r_hashval = hash_pbs.cur; /* remember where to plant value */
d8e7ea
-		if (!out_zero(st->st_oakley.ta_prf->prf_output_size,
d8e7ea
-			      &hash_pbs, "HASH"))
d8e7ea
-			return STF_INTERNAL_ERROR;
d8e7ea
-
d8e7ea
-		close_output_pbs(&hash_pbs);
d8e7ea
-		r_hash_start = rbody->cur; /* hash from after HASH payload */
d8e7ea
+	struct v1_hash_fixup hash_fixup;
d8e7ea
+	if (!emit_xauth_hash("XAUTH: mode config response",
d8e7ea
+			     st, &hash_fixup, rbody)) {
d8e7ea
+		return STF_INTERNAL_ERROR;
d8e7ea
 	}
d8e7ea
 
d8e7ea
 	/* ATTR out */
d8e7ea
@@ -497,7 +480,7 @@
d8e7ea
 			return STF_INTERNAL_ERROR;
d8e7ea
 	}
d8e7ea
 
d8e7ea
-	xauth_mode_cfg_hash(r_hashval, r_hash_start, rbody->cur, st);
d8e7ea
+	fixup_xauth_hash(st, &hash_fixup, rbody->cur);
d8e7ea
 
d8e7ea
 	if (!ikev1_close_message(rbody, st) ||
d8e7ea
 	    !ikev1_encrypt_message(rbody, st))
d8e7ea
@@ -523,7 +506,6 @@
d8e7ea
 	/* HDR out */
d8e7ea
 	{
d8e7ea
 		struct isakmp_hdr hdr = {
d8e7ea
-			.isa_np = ISAKMP_NEXT_HASH,
d8e7ea
 			.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT |
d8e7ea
 				  ISAKMP_MINOR_VERSION,
d8e7ea
 			.isa_xchg = ISAKMP_XCHG_MODE_CFG,
d8e7ea
@@ -604,7 +586,6 @@
d8e7ea
 	pb_stream reply;
d8e7ea
 	pb_stream rbody;
d8e7ea
 	unsigned char buf[256];
d8e7ea
-	u_char *r_hash_start, *r_hashval;
d8e7ea
 	const enum state_kind p_state = st->st_state;
d8e7ea
 
d8e7ea
 	/* set up reply */
d8e7ea
@@ -620,7 +601,6 @@
d8e7ea
 	/* HDR out */
d8e7ea
 	{
d8e7ea
 		struct isakmp_hdr hdr = {
d8e7ea
-			.isa_np = ISAKMP_NEXT_HASH,
d8e7ea
 			.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT |
d8e7ea
 				  ISAKMP_MINOR_VERSION,
d8e7ea
 			.isa_xchg = ISAKMP_XCHG_MODE_CFG,
d8e7ea
@@ -638,7 +618,11 @@
d8e7ea
 			return STF_INTERNAL_ERROR;
d8e7ea
 	}
d8e7ea
 
d8e7ea
-	START_HASH_PAYLOAD(rbody, ISAKMP_NEXT_MCFG_ATTR);
d8e7ea
+	struct v1_hash_fixup hash_fixup;
d8e7ea
+	if (!emit_xauth_hash("XAUTH: send request",
d8e7ea
+			     st, &hash_fixup, &rbody)) {
d8e7ea
+		return STF_INTERNAL_ERROR;
d8e7ea
+	}
d8e7ea
 
d8e7ea
 	/* ATTR out */
d8e7ea
 	{
d8e7ea
@@ -668,7 +652,7 @@
d8e7ea
 			return STF_INTERNAL_ERROR;
d8e7ea
 	}
d8e7ea
 
d8e7ea
-	xauth_mode_cfg_hash(r_hashval, r_hash_start, rbody.cur, st);
d8e7ea
+	fixup_xauth_hash(st, &hash_fixup, rbody.cur);
d8e7ea
 
d8e7ea
 	if (!ikev1_close_message(&rbody, st))
d8e7ea
 			return STF_INTERNAL_ERROR;
d8e7ea
@@ -719,7 +703,6 @@
d8e7ea
 	pb_stream reply;
d8e7ea
 	pb_stream rbody;
d8e7ea
 	unsigned char buf[256];
d8e7ea
-	u_char *r_hash_start, *r_hashval;
d8e7ea
 
d8e7ea
 	/* set up reply */
d8e7ea
 	init_out_pbs(&reply, buf, sizeof(buf), "xauth_buf");
d8e7ea
@@ -733,7 +716,6 @@
d8e7ea
 	/* HDR out */
d8e7ea
 	{
d8e7ea
 		struct isakmp_hdr hdr = {
d8e7ea
-			.isa_np = ISAKMP_NEXT_HASH,
d8e7ea
 			.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT |
d8e7ea
 				  ISAKMP_MINOR_VERSION,
d8e7ea
 			.isa_xchg = ISAKMP_XCHG_MODE_CFG,
d8e7ea
@@ -752,7 +734,11 @@
d8e7ea
 			return STF_INTERNAL_ERROR;
d8e7ea
 	}
d8e7ea
 
d8e7ea
-	START_HASH_PAYLOAD(rbody, ISAKMP_NEXT_MCFG_ATTR);
d8e7ea
+	struct v1_hash_fixup hash_fixup;
d8e7ea
+	if (!emit_xauth_hash("XAUTH: mode config request",
d8e7ea
+			     st, &hash_fixup, &rbody)) {
d8e7ea
+		return STF_INTERNAL_ERROR;
d8e7ea
+	}
d8e7ea
 
d8e7ea
 	/* ATTR out */
d8e7ea
 	{
d8e7ea
@@ -785,7 +771,7 @@
d8e7ea
 			return STF_INTERNAL_ERROR;
d8e7ea
 	}
d8e7ea
 
d8e7ea
-	xauth_mode_cfg_hash(r_hashval, r_hash_start, rbody.cur, st);
d8e7ea
+	fixup_xauth_hash(st, &hash_fixup, rbody.cur);
d8e7ea
 
d8e7ea
 	if (!ikev1_close_message(&rbody, st))
d8e7ea
 		return STF_INTERNAL_ERROR;
d8e7ea
@@ -821,7 +807,6 @@
d8e7ea
 	pb_stream reply;
d8e7ea
 	pb_stream rbody;
d8e7ea
 	unsigned char buf[256];
d8e7ea
-	u_char *r_hash_start, *r_hashval;
d8e7ea
 
d8e7ea
 	/* set up reply */
d8e7ea
 	init_out_pbs(&reply, buf, sizeof(buf), "xauth_buf");
d8e7ea
@@ -832,7 +817,6 @@
d8e7ea
 	/* HDR out */
d8e7ea
 	{
d8e7ea
 		struct isakmp_hdr hdr = {
d8e7ea
-			.isa_np = ISAKMP_NEXT_HASH,
d8e7ea
 			.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT |
d8e7ea
 				  ISAKMP_MINOR_VERSION,
d8e7ea
 			.isa_xchg = ISAKMP_XCHG_MODE_CFG,
d8e7ea
@@ -850,7 +834,10 @@
d8e7ea
 			return STF_INTERNAL_ERROR;
d8e7ea
 	}
d8e7ea
 
d8e7ea
-	START_HASH_PAYLOAD(rbody, ISAKMP_NEXT_MCFG_ATTR);
d8e7ea
+	struct v1_hash_fixup hash_fixup;
d8e7ea
+	if (!emit_xauth_hash("XAUTH: status", st, &hash_fixup, &rbody)) {
d8e7ea
+		return STF_INTERNAL_ERROR;
d8e7ea
+	}
d8e7ea
 
d8e7ea
 	/* ATTR out */
d8e7ea
 	{
d8e7ea
@@ -873,7 +860,7 @@
d8e7ea
 			return STF_INTERNAL_ERROR;
d8e7ea
 	}
d8e7ea
 
d8e7ea
-	xauth_mode_cfg_hash(r_hashval, r_hash_start, rbody.cur, st);
d8e7ea
+	fixup_xauth_hash(st, &hash_fixup, rbody.cur);
d8e7ea
 
d8e7ea
 	if (!ikev1_close_message(&rbody, st))
d8e7ea
 		return STF_INTERNAL_ERROR;
d8e7ea
@@ -1280,12 +1267,6 @@
d8e7ea
 	bool gotname = FALSE,
d8e7ea
 		gotpassword = FALSE;
d8e7ea
 
d8e7ea
-	CHECK_QUICK_HASH(md,
d8e7ea
-			 xauth_mode_cfg_hash(hash_val, hash_pbs->roof,
d8e7ea
-					     md->message_pbs.roof,
d8e7ea
-					     st),
d8e7ea
-			 "XAUTH-HASH", "XAUTH R0");
d8e7ea
-
d8e7ea
 	setchunk(name, unknown, sizeof(unknown) - 1);	/* to make diagnostics easier */
d8e7ea
 
d8e7ea
 	/* XXX This needs checking with the proper RFC's - ISAKMP_CFG_ACK got added for Cisco interop */
d8e7ea
@@ -1469,11 +1450,6 @@
d8e7ea
 	DBG(DBG_CONTROLMORE, DBG_log("arrived in modecfg_inR0"));
d8e7ea
 
d8e7ea
 	st->st_msgid_phase15 = md->hdr.isa_msgid;
d8e7ea
-	CHECK_QUICK_HASH(md,
d8e7ea
-			 xauth_mode_cfg_hash(hash_val,
d8e7ea
-					     hash_pbs->roof,
d8e7ea
-					     md->message_pbs.roof, st),
d8e7ea
-			 "MODECFG-HASH", "MODE R0");
d8e7ea
 
d8e7ea
 	switch (ma->isama_type) {
d8e7ea
 	default:
d8e7ea
@@ -1559,12 +1535,6 @@
d8e7ea
 	DBG(DBG_CONTROL, DBG_log("modecfg_inI2"));
d8e7ea
 
d8e7ea
 	st->st_msgid_phase15 = md->hdr.isa_msgid;
d8e7ea
-	CHECK_QUICK_HASH(md,
d8e7ea
-			 xauth_mode_cfg_hash(hash_val,
d8e7ea
-					     hash_pbs->roof,
d8e7ea
-					     md->message_pbs.roof,
d8e7ea
-					     st),
d8e7ea
-			 "MODECFG-HASH", "MODE R1");
d8e7ea
 
d8e7ea
 	/* CHECK that SET has been received. */
d8e7ea
 
d8e7ea
@@ -1690,11 +1660,6 @@
d8e7ea
 	DBG(DBG_CONTROL, DBG_log("modecfg_inR1: received mode cfg reply"));
d8e7ea
 
d8e7ea
 	st->st_msgid_phase15 = md->hdr.isa_msgid;
d8e7ea
-	CHECK_QUICK_HASH(md,
d8e7ea
-			 xauth_mode_cfg_hash(hash_val, hash_pbs->roof,
d8e7ea
-					     md->message_pbs.roof,
d8e7ea
-					     st),
d8e7ea
-			 "MODECFG-HASH", "MODE R1");
d8e7ea
 
d8e7ea
 	switch (ma->isama_type) {
d8e7ea
 	default:
d8e7ea
@@ -1978,26 +1943,12 @@
d8e7ea
 			     pb_stream *rbody,
d8e7ea
 			     uint16_t ap_id)
d8e7ea
 {
d8e7ea
-	unsigned char *r_hash_start, *r_hashval;
d8e7ea
 	char xauth_username[MAX_XAUTH_USERNAME_LEN];
d8e7ea
 	struct connection *c = st->st_connection;
d8e7ea
 
d8e7ea
-	/* START_HASH_PAYLOAD(rbody, ISAKMP_NEXT_MCFG_ATTR); */
d8e7ea
-
d8e7ea
-	{
d8e7ea
-		pb_stream hash_pbs;
d8e7ea
-		int np = ISAKMP_NEXT_MCFG_ATTR;
d8e7ea
-
d8e7ea
-		if (!ikev1_out_generic(np, &isakmp_hash_desc, rbody, &hash_pbs))
d8e7ea
-			return STF_INTERNAL_ERROR;
d8e7ea
-
d8e7ea
-		r_hashval = hash_pbs.cur; /* remember where to plant value */
d8e7ea
-		if (!out_zero(st->st_oakley.ta_prf->prf_output_size,
d8e7ea
-			      &hash_pbs, "HASH"))
d8e7ea
-			return STF_INTERNAL_ERROR;
d8e7ea
-
d8e7ea
-		close_output_pbs(&hash_pbs);
d8e7ea
-		r_hash_start = (rbody)->cur; /* hash from after HASH payload */
d8e7ea
+	struct v1_hash_fixup hash_fixup;
d8e7ea
+	if (!emit_xauth_hash("XAUTH: client response", st, &hash_fixup, rbody)) {
d8e7ea
+		return STF_INTERNAL_ERROR;
d8e7ea
 	}
d8e7ea
 
d8e7ea
 	/* MCFG_ATTR out */
d8e7ea
@@ -2201,7 +2152,7 @@
d8e7ea
 	libreswan_log("XAUTH: Answering XAUTH challenge with user='%s'",
d8e7ea
 		      st->st_xauth_username);
d8e7ea
 
d8e7ea
-	xauth_mode_cfg_hash(r_hashval, r_hash_start, rbody->cur, st);
d8e7ea
+	fixup_xauth_hash(st, &hash_fixup, rbody->cur);
d8e7ea
 
d8e7ea
 	if (!ikev1_close_message(rbody, st) ||
d8e7ea
 	    !ikev1_encrypt_message(rbody, st))
d8e7ea
@@ -2252,10 +2203,6 @@
d8e7ea
 	}
d8e7ea
 
d8e7ea
 	st->st_msgid_phase15 = md->hdr.isa_msgid;
d8e7ea
-	CHECK_QUICK_HASH(md, xauth_mode_cfg_hash(hash_val,
d8e7ea
-						 hash_pbs->roof,
d8e7ea
-						 md->message_pbs.roof, st),
d8e7ea
-			 "MODECFG-HASH", "XAUTH I0");
d8e7ea
 
d8e7ea
 	switch (ma->isama_type) {
d8e7ea
 	default:
d8e7ea
@@ -2446,24 +2393,9 @@
d8e7ea
 					 pb_stream *rbody,
d8e7ea
 					 uint16_t ap_id)
d8e7ea
 {
d8e7ea
-	unsigned char *r_hash_start, *r_hashval;
d8e7ea
-
d8e7ea
-	/* START_HASH_PAYLOAD(rbody, ISAKMP_NEXT_MCFG_ATTR); */
d8e7ea
-
d8e7ea
-	{
d8e7ea
-		pb_stream hash_pbs;
d8e7ea
-		int np = ISAKMP_NEXT_MCFG_ATTR;
d8e7ea
-
d8e7ea
-		if (!ikev1_out_generic(np, &isakmp_hash_desc, rbody, &hash_pbs))
d8e7ea
-			return STF_INTERNAL_ERROR;
d8e7ea
-
d8e7ea
-		r_hashval = hash_pbs.cur; /* remember where to plant value */
d8e7ea
-		if (!out_zero(st->st_oakley.ta_prf->prf_output_size,
d8e7ea
-			      &hash_pbs, "HASH"))
d8e7ea
-			return STF_INTERNAL_ERROR;
d8e7ea
-
d8e7ea
-		close_output_pbs(&hash_pbs);
d8e7ea
-		r_hash_start = (rbody)->cur; /* hash from after HASH payload */
d8e7ea
+	struct v1_hash_fixup hash_fixup;
d8e7ea
+	if (!emit_xauth_hash("XAUTH: ack status", st, &hash_fixup, rbody)) {
d8e7ea
+		return STF_INTERNAL_ERROR;
d8e7ea
 	}
d8e7ea
 
d8e7ea
 	/* ATTR out */
d8e7ea
@@ -2486,7 +2418,7 @@
d8e7ea
 			return STF_INTERNAL_ERROR;
d8e7ea
 	}
d8e7ea
 
d8e7ea
-	xauth_mode_cfg_hash(r_hashval, r_hash_start, rbody->cur, st);
d8e7ea
+	fixup_xauth_hash(st, &hash_fixup, rbody->cur);
d8e7ea
 
d8e7ea
 	if (!ikev1_close_message(rbody, st) ||
d8e7ea
 	    !ikev1_encrypt_message(rbody, st))
d8e7ea
@@ -2525,11 +2457,6 @@
d8e7ea
 	DBG(DBG_CONTROLMORE, DBG_log("Continuing with xauth_inI1"));
d8e7ea
 
d8e7ea
 	st->st_msgid_phase15 = md->hdr.isa_msgid;
d8e7ea
-	CHECK_QUICK_HASH(md,
d8e7ea
-			 xauth_mode_cfg_hash(hash_val,
d8e7ea
-					     hash_pbs->roof,
d8e7ea
-					     md->message_pbs.roof, st),
d8e7ea
-			 "MODECFG-HASH", "XAUTH I1");
d8e7ea
 
d8e7ea
 	switch (ma->isama_type) {
d8e7ea
 	default:
d8e7ea
diff -Naur libreswan-3.29-orig/programs/pluto/ipsec_doi.h libreswan-3.29/programs/pluto/ipsec_doi.h
d8e7ea
--- libreswan-3.29-orig/programs/pluto/ipsec_doi.h	2019-06-10 10:22:04.000000000 -0400
d8e7ea
+++ libreswan-3.29/programs/pluto/ipsec_doi.h	2019-06-11 19:28:00.688844889 -0400
d8e7ea
@@ -65,67 +65,6 @@
d8e7ea
 		      const struct oakley_group_desc *gr,
d8e7ea
 		      struct payload_digest *ke_pd);
d8e7ea
 
d8e7ea
-/* START_HASH_PAYLOAD_NO_HASH_START
d8e7ea
- *
d8e7ea
- * Emit a to-be-filled-in hash payload, noting the field start (r_hashval)
d8e7ea
- * and the start of the part of the message to be hashed (r_hash_start).
d8e7ea
- * This macro is magic.
d8e7ea
- * - it can cause the caller to return
d8e7ea
- * - it references variables local to the caller (r_hashval, st)
d8e7ea
- */
d8e7ea
-#define START_HASH_PAYLOAD_NO_R_HASH_START(rbody, np) { \
d8e7ea
-		pb_stream hash_pbs; \
d8e7ea
-		if (!ikev1_out_generic(np, &isakmp_hash_desc, &(rbody), &hash_pbs)) \
d8e7ea
-			return STF_INTERNAL_ERROR; \
d8e7ea
-		r_hashval = hash_pbs.cur; /* remember where to plant value */ \
d8e7ea
-		if (!out_zero(st->st_oakley.ta_prf->prf_output_size, \
d8e7ea
-			      &hash_pbs, "HASH")) \
d8e7ea
-			return STF_INTERNAL_ERROR; \
d8e7ea
-		close_output_pbs(&hash_pbs); \
d8e7ea
-}
d8e7ea
-
d8e7ea
-/* START_HASH_PAYLOAD
d8e7ea
- *
d8e7ea
- * Emit a to-be-filled-in hash payload, noting the field start (r_hashval)
d8e7ea
- * and the start of the part of the message to be hashed (r_hash_start).
d8e7ea
- * This macro is magic.
d8e7ea
- * - it can cause the caller to return
d8e7ea
- * - it references variables local to the caller (r_hashval, r_hash_start, st)
d8e7ea
- */
d8e7ea
-#define START_HASH_PAYLOAD(rbody, np) { \
d8e7ea
-		START_HASH_PAYLOAD_NO_R_HASH_START(rbody, np); \
d8e7ea
-		r_hash_start = (rbody).cur; /* hash from after HASH payload */ \
d8e7ea
-}
d8e7ea
-
d8e7ea
-/* CHECK_QUICK_HASH
d8e7ea
- *
d8e7ea
- * This macro is magic -- it cannot be expressed as a function.
d8e7ea
- * - it causes the caller to return!
d8e7ea
- * - it declares local variables and expects the "do_hash" argument
d8e7ea
- *   expression to reference them (hash_val, hash_pbs)
d8e7ea
- */
d8e7ea
-#define CHECK_QUICK_HASH(md, do_hash, hash_name, msg_name) { \
d8e7ea
-		pb_stream *const hash_pbs = &(md)->chain[ISAKMP_NEXT_HASH]->pbs; \
d8e7ea
-		u_char hash_val[MAX_DIGEST_LEN];			\
d8e7ea
-		size_t hash_len = (do_hash);				\
d8e7ea
-		if (pbs_left(hash_pbs) != hash_len ||			\
d8e7ea
-		    !memeq(hash_pbs->cur, hash_val, hash_len)) {	\
d8e7ea
-			if (DBGP(DBG_CRYPT)) {				\
d8e7ea
-				DBG_dump("received " hash_name ":",	\
d8e7ea
-					 hash_pbs->cur, pbs_left(hash_pbs)); \
d8e7ea
-			}						\
d8e7ea
-			loglog(RC_LOG_SERIOUS,				\
d8e7ea
-			       "received " hash_name " does not match computed value in " msg_name); \
d8e7ea
-			/* XXX Could send notification back */		\
d8e7ea
-			return STF_FAIL + INVALID_HASH_INFORMATION;	\
d8e7ea
-		}							\
d8e7ea
-	}
d8e7ea
-
d8e7ea
-size_t quick_mode_hash12(u_char *dest, const u_char *start,
d8e7ea
-			 const u_char *roof,
d8e7ea
-			 const struct state *st, const msgid_t *msgid,
d8e7ea
-			 bool hash2);
d8e7ea
-
d8e7ea
 extern stf_status send_isakmp_notification(struct state *st,
d8e7ea
 					   uint16_t type, const void *data,
d8e7ea
 					   size_t len);
d8e7ea
diff -Naur libreswan-3.29-orig/programs/pluto/Makefile libreswan-3.29/programs/pluto/Makefile
d8e7ea
--- libreswan-3.29-orig/programs/pluto/Makefile	2019-06-10 10:22:04.000000000 -0400
d8e7ea
+++ libreswan-3.29/programs/pluto/Makefile	2019-06-11 19:23:19.841729230 -0400
d8e7ea
@@ -215,6 +215,7 @@
d8e7ea
 OBJS += ikev2_ipseckey.o
d8e7ea
 endif
d8e7ea
 OBJS += ikev1.o ikev1_main.o ikev1_quick.o ikev1_dpd.o ikev1_spdb_struct.o ikev1_msgid.o
d8e7ea
+OBJS += ikev1_hash.o
d8e7ea
 OBJS += ikev2.o ikev2_parent.o ikev2_child.o ikev2_spdb_struct.o
d8e7ea
 OBJS += ikev2_ecdsa.o ikev2_rsa.o ikev2_psk.o ikev2_ppk.o ikev2_crypto.o
d8e7ea
 OBJS += ikev2_redirect.o