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