diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..af4b6ff
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+SOURCES/ikev1_dsa.fax.bz2
+SOURCES/ikev1_psk.fax.bz2
+SOURCES/ikev2.fax.bz2
+SOURCES/libreswan-3.29.tar.gz
diff --git a/.libreswan.metadata b/.libreswan.metadata
new file mode 100644
index 0000000..01d8128
--- /dev/null
+++ b/.libreswan.metadata
@@ -0,0 +1,4 @@
+b35cd50b8bc0a08b9c07713bf19c72d53bfe66bb SOURCES/ikev1_dsa.fax.bz2
+861d97bf488f9e296cad8c43ab72f111a5b1a848 SOURCES/ikev1_psk.fax.bz2
+fcaf77f3deae3d8e99cdb3b1f8abea63167a0633 SOURCES/ikev2.fax.bz2
+492cd1cf18c06e47b2864a57a355a7f5393f80cc SOURCES/libreswan-3.29.tar.gz
diff --git a/SOURCES/libreswan-3.28-maintain-different-v1v2-split.patch b/SOURCES/libreswan-3.28-maintain-different-v1v2-split.patch
new file mode 100644
index 0000000..dd53f19
--- /dev/null
+++ b/SOURCES/libreswan-3.28-maintain-different-v1v2-split.patch
@@ -0,0 +1,68 @@
+diff -Naur libreswan-3.28-orig/lib/libipsecconf/confread.c libreswan-3.28/lib/libipsecconf/confread.c
+--- libreswan-3.28-orig/lib/libipsecconf/confread.c 2019-05-20 23:01:54.000000000 -0400
++++ libreswan-3.28/lib/libipsecconf/confread.c 2019-05-21 16:59:20.861415770 -0400
+@@ -1273,13 +1273,16 @@
+
+ switch (conn->options[KNCF_IKEv2]) {
+ case fo_never:
+- case fo_permit:
+ conn->policy |= POLICY_IKEV1_ALLOW;
+ /* clear any inherited default */
+ conn->policy &= ~POLICY_IKEV2_ALLOW;
+ break;
+-
++ case fo_permit:
++ starter_error_append(perrl, "ikev2=permit is no longer accepted. Use ikev2=insist or ikev2=no|never");
++ return TRUE;
+ case fo_propose:
++ starter_error_append(perrl, "ikev2=propose or ikev2=yes is no longer accepted. Use ikev2=insist or ikev2=no|never");
++ return TRUE;
+ case fo_insist:
+ conn->policy |= POLICY_IKEV2_ALLOW;
+ /* clear any inherited default */
+diff -Naur libreswan-3.28-orig/programs/configs/d.ipsec.conf/ikev2.xml libreswan-3.28/programs/configs/d.ipsec.conf/ikev2.xml
+--- libreswan-3.28-orig/programs/configs/d.ipsec.conf/ikev2.xml 2019-05-20 23:01:54.000000000 -0400
++++ libreswan-3.28/programs/configs/d.ipsec.conf/ikev2.xml 2019-05-21 16:54:07.584141191 -0400
+@@ -1,13 +1,15 @@
+
+ ikev2
+
+-Whether to use IKEv1 (RFC 4301) or IKEv2 (RFC 7296) settings to be used.
+-Currently the accepted values are no(the default),
+-signifying only IKEv1 is accepted, or yes,
++Wether to use IKEv1 (RFC 4301) or IKEv2 (RFC 7296) as the Internet Key Exchange (IKE) protcol.
++Currently the accepted values are no (or never)
++signifying only IKEv1 is accepted, or insist(the default),
+ signifying only IKEv2 is accepted. Previous versions allowed the keywords
+-propose or permit
+-that would allow either IKEv1 or IKEv2, but this is no longer supported. The
+-permit option is interpreted as no and the propose option is interpreted as yes.
++propose, yes or permit
++that would allow either IKEv1 or IKEv2, but this is no longer supported and both options
++now cause the connection to fail to load. WARNING: This behaviour differs from upstream
++libreswan, which only accepts yes or no where yes means
++the same as insist.
+
+
+
+diff -Naur libreswan-3.28-orig/programs/whack/whack.c libreswan-3.28/programs/whack/whack.c
+--- libreswan-3.28-orig/programs/whack/whack.c 2019-05-20 23:01:54.000000000 -0400
++++ libreswan-3.28/programs/whack/whack.c 2019-05-21 17:01:37.868865569 -0400
+@@ -741,7 +741,7 @@
+
+ PS("ikev1-allow", IKEV1_ALLOW),
+ PS("ikev2-allow", IKEV2_ALLOW),
+- PS("ikev2-propose", IKEV2_ALLOW), /* map onto allow */
++ /* not in RHEL8 PS("ikev2-propose", IKEV2_ALLOW),*/
+
+ PS("allow-narrowing", IKEV2_ALLOW_NARROWING),
+ #ifdef XAUTH_HAVE_PAM
+@@ -1683,7 +1683,7 @@
+
+ /* --ikev1-allow */
+ case CDP_SINGLETON + POLICY_IKEV1_ALLOW_IX:
+- /* --ikev2-allow (now also --ikev2-propose) */
++ /* --ikev2-allow */
+ case CDP_SINGLETON + POLICY_IKEV2_ALLOW_IX:
+
+ /* --allow-narrowing */
diff --git a/SOURCES/libreswan-3.29-CVE-2019-10155-testing.patch b/SOURCES/libreswan-3.29-CVE-2019-10155-testing.patch
new file mode 100644
index 0000000..0384489
--- /dev/null
+++ b/SOURCES/libreswan-3.29-CVE-2019-10155-testing.patch
@@ -0,0 +1,1830 @@
+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
++ * 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 -> */
+ };
+
++/*
++ * 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
+ * Copyright (C) 2019-2019 Paul Wouters
+@@ -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 | ) */
++ .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 | ) */
++ .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 .
++ *
++ * 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 .
++ *
++ * 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
++#include
++
++#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(¬ify_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
+
+@@ -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
diff --git a/SPECS/libreswan.spec b/SPECS/libreswan.spec
new file mode 100644
index 0000000..d98bb76
--- /dev/null
+++ b/SPECS/libreswan.spec
@@ -0,0 +1,444 @@
+%global _hardened_build 1
+# These are rpm macros and are 0 or 1
+%global with_efence 0
+%global with_development 0
+%global with_cavstests 1
+# Libreswan config options
+%global libreswan_config \\\
+ FINALLIBEXECDIR=%{_libexecdir}/ipsec \\\
+ FINALMANDIR=%{_mandir} \\\
+ FIPSPRODUCTCHECK=%{_sysconfdir}/system-fips \\\
+ INC_RCDEFAULT=%{_initrddir} \\\
+ INC_USRLOCAL=%{_prefix} \\\
+ INITSYSTEM=systemd \\\
+ NSS_HAS_IPSEC_PROFILE=true \\\
+ USE_DNSSEC=true \\\
+ USE_FIPSCHECK=true \\\
+ USE_LABELED_IPSEC=true \\\
+ USE_LDAP=true \\\
+ USE_LIBCAP_NG=true \\\
+ USE_LIBCURL=true \\\
+ USE_LINUX_AUDIT=true \\\
+ USE_NM=true \\\
+ USE_SECCOMP=true \\\
+ USE_XAUTHPAM=true \\\
+ USE_KLIPS=false \\\
+%{nil}
+
+#global prever rc1
+
+Name: libreswan
+Summary: IPsec implementation with IKEv1 and IKEv2 keying protocols
+# version is generated in the release script
+Version: 3.29
+Release: %{?prever:0.}1%{?prever:.%{prever}}%{?dist}
+License: GPLv2
+Url: https://libreswan.org/
+Source0: https://download.libreswan.org/%{?prever:with_development/}%{name}-%{version}%{?prever}.tar.gz
+%if 0%{with_cavstests}
+Source1: https://download.libreswan.org/cavs/ikev1_dsa.fax.bz2
+Source2: https://download.libreswan.org/cavs/ikev1_psk.fax.bz2
+Source3: https://download.libreswan.org/cavs/ikev2.fax.bz2
+%endif
+
+Patch1: libreswan-3.28-maintain-different-v1v2-split.patch
+Patch2: libreswan-3.29-CVE-2019-10155-testing.patch
+
+Group: System Environment/Daemons
+BuildRequires: bison flex pkgconfig
+BuildRequires: systemd systemd-units systemd-devel
+Requires(post): coreutils bash systemd
+Requires(preun): systemd
+Requires(postun): systemd
+
+BuildRequires: pkgconfig hostname
+# minimum version for support for rhbz#1651314
+BuildRequires: nss-tools nss-devel >= 3.39.0-1.4
+Requires: nss >= 3.39.0-1.4
+BuildRequires: nspr-devel
+BuildRequires: pam-devel
+BuildRequires: libevent-devel
+BuildRequires: unbound-devel >= 1.6.0-6 ldns-devel
+BuildRequires: libseccomp-devel
+BuildRequires: libselinux-devel
+BuildRequires: fipscheck-devel
+Requires: fipscheck%{_isa}
+Buildrequires: audit-libs-devel
+
+BuildRequires: libcap-ng-devel
+BuildRequires: openldap-devel curl-devel
+%if 0%{with_efence}
+BuildRequires: ElectricFence
+%endif
+BuildRequires: xmlto
+
+Requires: nss-tools, nss-softokn
+Requires: iproute >= 2.6.8
+Requires: unbound-libs >= 1.6.6
+
+%description
+Libreswan is a free implementation of IKE/IPsec for Linux. IPsec is
+the Internet Protocol Security and uses strong cryptography to provide
+both authentication and encryption services. These services allow you
+to build secure tunnels through untrusted networks. Everything passing
+through the untrusted net is encrypted by the ipsec gateway machine and
+decrypted by the gateway at the other end of the tunnel. The resulting
+tunnel is a virtual private network or VPN.
+
+This package contains the daemons and userland tools for setting up
+Libreswan.
+
+Libreswan also supports IKEv2 (RFC7296) and Secure Labeling
+
+Libreswan is based on Openswan-2.6.38 which in turn is based on FreeS/WAN-2.04
+
+%prep
+%setup -q -n libreswan-%{version}%{?prever}
+pathfix.py -i %{__python3} -pn programs/verify/verify.in programs/show/show.in \
+ testing/cert_verify/usage_test testing/pluto/ikev1-01-fuzzer/cve-2015-3204.py \
+ testing/pluto/ikev2-15-fuzzer/send_bad_packets.py testing/x509/dist_certs.py \
+ programs/_unbound-hook/_unbound-hook.in
+
+# replace unsupported KLIPS README
+echo "KLIPS is not supported with RHEL8" > README.KLIPS
+
+# linking to freebl is not needed
+sed -i "s/-lfreebl //" mk/config.mk
+
+# enable crypto-policies support
+sed -i "s:#[ ]*include \(.*\)\(/crypto-policies/back-ends/libreswan.config\)$:include \1\2:" programs/configs/ipsec.conf.in
+
+%patch1 -p1
+%patch2 -p1
+
+%build
+%if 0%{with_efence}
+%global efence "-lefence"
+%endif
+
+#796683: -fno-strict-aliasing
+make %{?_smp_mflags} \
+%if 0%{with_development}
+ USERCOMPILE="-g -DGCC_LINT %(echo %{optflags} | sed -e s/-O[0-9]*/ /) %{?efence} -fPIE -pie -fno-strict-aliasing -Wformat-nonliteral -Wformat-security" \
+%else
+ USERCOMPILE="-g -DGCC_LINT %{optflags} %{?efence} -fPIE -pie -fno-strict-aliasing -Wformat-nonliteral -Wformat-security" \
+%endif
+ USERLINK="-g -pie -Wl,-z,relro,-z,now %{?efence}" \
+ %{libreswan_config} \
+ programs
+FS=$(pwd)
+
+# Add generation of HMAC checksums of the final stripped binaries
+%define __spec_install_post \
+ %{?__debug_package:%{__debug_install_post}} \
+ %{__arch_install_post} \
+ %{__os_install_post} \
+ fipshmac -d %{buildroot}%{_libdir}/fipscheck %{buildroot}%{_libexecdir}/ipsec/pluto \
+%{nil}
+
+%install
+make \
+ DESTDIR=%{buildroot} \
+ %{libreswan_config} \
+ install
+FS=$(pwd)
+rm -rf %{buildroot}/usr/share/doc/libreswan
+
+install -d -m 0755 %{buildroot}%{_rundir}/pluto
+# used when setting --perpeerlog without --perpeerlogbase
+install -d -m 0700 %{buildroot}%{_localstatedir}/log/pluto/peer
+install -d %{buildroot}%{_sbindir}
+
+install -d %{buildroot}%{_sysconfdir}/sysctl.d
+install -m 0644 packaging/fedora/libreswan-sysctl.conf \
+ %{buildroot}%{_sysconfdir}/sysctl.d/50-libreswan.conf
+
+mkdir -p %{buildroot}%{_libdir}/fipscheck
+
+echo "include %{_sysconfdir}/ipsec.d/*.secrets" \
+ > %{buildroot}%{_sysconfdir}/ipsec.secrets
+rm -fr %{buildroot}%{_sysconfdir}/rc.d/rc*
+# remove testing binaries
+rm -fr %{buildroot}%{_libexecdir}/ipsec/*check
+
+%if 0%{with_cavstests}
+%check
+# There is an elaborate upstream testing infrastructure which we do not
+# run here - it takes hours and uses kvm
+# We only run the CAVS tests.
+cp %{SOURCE1} %{SOURCE2} %{SOURCE3} .
+bunzip2 *.fax.bz2
+
+: starting CAVS test for IKEv2
+%{buildroot}%{_libexecdir}/ipsec/cavp -v2 ikev2.fax | \
+ diff -u ikev2.fax - > /dev/null
+: starting CAVS test for IKEv1 RSASIG
+%{buildroot}%{_libexecdir}/ipsec/cavp -v1dsa ikev1_dsa.fax | \
+ diff -u ikev1_dsa.fax - > /dev/null
+: starting CAVS test for IKEv1 PSK
+%{buildroot}%{_libexecdir}/ipsec/cavp -v1psk ikev1_psk.fax | \
+ diff -u ikev1_psk.fax - > /dev/null
+: CAVS tests passed
+
+# Some of these tests will show ERROR for negative testing - it will exit on real errors
+%{buildroot}%{_libexecdir}/ipsec/algparse -tp || { echo prooposal test failed; exit 1; }
+%{buildroot}%{_libexecdir}/ipsec/algparse -ta || { echo algorithm test failed; exit 1; }
+: Algorithm parser tests passed
+
+# self test for pluto daemon - this also shows which algorithms it allows in FIPS mode
+tmpdir=$(mktemp -d /tmp/libreswan-XXXXX)
+certutil -N -d sql:$tmpdir --empty-password
+%{buildroot}%{_libexecdir}/ipsec/pluto --selftest --nssdir $tmpdir --rundir $tmpdir
+: pluto self-test passed - verify FIPS algorithms allowed is still compliant with NIST
+
+%endif
+
+%post
+%systemd_post ipsec.service
+
+%preun
+%systemd_preun ipsec.service
+
+%postun
+%systemd_postun_with_restart ipsec.service
+
+%files
+%doc CHANGES COPYING CREDITS README* LICENSE
+%doc docs/*.* docs/examples
+%attr(0644,root,root) %config(noreplace) %{_sysconfdir}/ipsec.conf
+%attr(0600,root,root) %config(noreplace) %{_sysconfdir}/ipsec.secrets
+%attr(0700,root,root) %dir %{_sysconfdir}/ipsec.d
+%attr(0700,root,root) %dir %{_sysconfdir}/ipsec.d/policies
+%attr(0644,root,root) %config(noreplace) %{_sysconfdir}/ipsec.d/policies/*
+%attr(0644,root,root) %config(noreplace) %{_sysconfdir}/sysctl.d/50-libreswan.conf
+%attr(0700,root,root) %dir %{_localstatedir}/log/pluto
+%attr(0700,root,root) %dir %{_localstatedir}/log/pluto/peer
+%attr(0755,root,root) %dir %{_rundir}/pluto
+%attr(0644,root,root) %{_tmpfilesdir}/libreswan.conf
+%attr(0644,root,root) %{_unitdir}/ipsec.service
+%attr(0644,root,root) %config(noreplace) %{_sysconfdir}/pam.d/pluto
+%{_sbindir}/ipsec
+%{_libexecdir}/ipsec
+%attr(0644,root,root) %doc %{_mandir}/*/*
+%{_libdir}/fipscheck/pluto.hmac
+
+%changelog
+* Mon Jun 10 2019 Paul Wouters - 3.29-1
+- Resolves: rhbz#1712555 libreswan rebase to 3.29
+
+* Tue May 28 2019 Paul Wouters - 3.28-2
+- Resolves: rhbz#1713734: barf: shell syntax error in barf diagnostic tool
+
+* Tue May 21 2019 Paul Wouters - 3.28-1
+- Resolves: rhbz#1712555 libreswan rebase to 3.28
+- Resolves: rhbz#1683706 Libreswan shows incorrect error messages
+- Resolves: rhbz#1706180 Remove last usage of old (unused) PF_KEY API
+- Resolves: rhbz#1677045 Opportunistic IPsec instances of /32 groups or auto=start that receive delete won't restart
+- Resolves: rhbz#1686990 IKEv1 traffic interruption when responder deletes SAs 60 seconds before EVENT_SA_REPLACE
+- Resolves: rhbz#1608353 /usr/sbin/ipsec part of the libreswan packages still invokes commands that were deprecated a decade ago
+- Resolves: rhbz#1699318 'ipsec show' has python3 invalid syntax
+- Resolves: rhbz#1679394 libreswan using NSS IPsec profiles regresses when critical flags are set causing validation failure
+
+* Thu Feb 21 2019 Paul Wouters - 3.27-9
+- Resolves: rhbz#1648776 limit connections to be ikev1only or ikev2only and make ikev2only the default [man page update]
+
+* Fri Feb 15 2019 Paul Wouters - 3.27-8
+- Resolves: rhbz#1664101 system wide crypto policies causing IKE_INIT packet fragmentation
+
+* Tue Feb 05 2019 Paul Wouters - 3.27-7
+- Resolves: rhbz#1671793 proessing ISAKMP_NEXT_D with additional payloads causes dangling pointer to deleted state
+
+* Fri Feb 01 2019 Paul Wouters - 3.27-6
+- Resolves: rhbz#1668342 SELinux prevents libreswan from using some outbound ports causing DNS resolution failures at connection at load time
+
+* Thu Jan 10 2019 Paul Wouters - 3.27-5
+- Resolves: rhbz#1664522 libreswan 3.25 in FIPS mode is incorrectly rejecting X.509 public keys that are >= 3072 bits
+
+* Mon Dec 10 2018 Paul Wouters - 3.27-4
+- Resolves: rhbz#1657846 libreswan no longer needs to provide openswan in rhel8
+- Resolves: rhbz#1643388 libreswan: Unable to verify certificate with non-empty Extended Key Usage which does not include serverAuth or clientAuth
+- Resolves: rhbz#1657854 remove userland support for deprecated KLIPS IPsec stack support
+
+* Sun Dec 09 2018 Paul Wouters - 3.27-3
+- Resolves: rhbz#1648776 limit connections to be ikev1only or ikev2only and make ikev2only the default
+
+* Thu Nov 08 2018 Paul Wouters - 3.27-2
+- Resolves: rhbz#1645137 Libreswan segfaults when it loads configuration file with more then 5 connections
+
+* Mon Oct 08 2018 Paul Wouters - 3.27-1
+- Resolves: rhbz#1566574 Rebase to libreswan 3.27
+
+* Mon Sep 17 2018 Paul Wouters - 3.26-1
+- Resolves: rhbz#1566574 Rebase to libreswan 3.26
+- Resolves: rhbz#1527037 libreswan IPSEC implementation: should follow the policies of system-wide crypto policy
+- Resolves: rhbz#1375779 [IKEv2 Conformance] Test IKEv2.EN.R.1.1.6.7: Sending INVALID_KE_PAYLOAD failed
+- Resolves: rhbz#1085758 [TAHI][IKEv2] IKEv2.EN.I.1.2.1.1: Can't observe CREATE_CHILD_SA request for rekey
+- Resolves: rhbz#1053048 [TAHI][IKEv2] IKEv2.EN.I.1.2.4.1-7: libreswan doesn't sent CREATE_CHILD_SA after IKE_SA Lifetime timeout
+
+* Mon Aug 13 2018 Paul Wouters - 3.25-4
+- Resolves: rhbz#1590823 libreswan: Use Python 3 in RHEL 8
+
+* Wed Aug 01 2018 Charalampos Stratakis - 3.25-3.1
+- Rebuild for platform-python
+
+* Mon Jul 09 2018 Paul Wouters - 3.25-3
+- Cleanup shebangs for python3
+- Use the same options via macro for make programs and make install
+- Remove old ifdefs
+- Sync up patches to new upstream version
+- Add Requires: for unbound-libs >= 1.6.6
+- Enable crypto-policies support
+- Make rundir world readable for easier permission granting for socket
+
+* Tue Jun 26 2018 Charalampos Stratakis - 3.23-2.2
+- Make python shebangs point to python3
+
+* Fri Jun 22 2018 Troy Dawson - 3.23-2.1
+- Fix python shebangs (#1580773)
+
+* Mon Feb 19 2018 Paul Wouters - 3.23-2
+- Support crypto-policies package
+- Pull in some patches from upstream and IANA registry updates
+- gcc7 format-truncate fixes and workarounds
+
+* Wed Feb 07 2018 Fedora Release Engineering - 3.23-1.1
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild
+
+* Thu Jan 25 2018 Paul Wouters - 3.23-1
+- Updated to 3.23 - support for MOBIKE, PPK, CMAC, nic offload and performance improvements
+
+* Sat Jan 20 2018 Björn Esser - 3.22-1.1
+- Rebuilt for switch to libxcrypt
+
+* Mon Oct 23 2017 Paul Wouters - 3.22-1
+- Updated to 3.22 - many bugfixes, and unbound ipsecmod support
+
+* Wed Aug 9 2017 Paul Wouters - 3.21-1
+- Updated to 3.21
+
+* Thu Aug 03 2017 Fedora Release Engineering - 3.20-1.2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild
+
+* Wed Jul 26 2017 Fedora Release Engineering - 3.20-1.1
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild
+
+* Tue Mar 14 2017 Paul Wouters - 3.20-1
+- Updated to 3.20
+
+* Fri Mar 03 2017 Paul Wouters - 3.20-0.1.dr4
+- Update to 3.20dr4 to test mozbz#1336487 export CERT_CompareAVA
+
+* Fri Feb 10 2017 Fedora Release Engineering - 3.19-1.1
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild
+
+* Fri Feb 03 2017 Paul Wouters - 3.19-2
+- Resolves: rhbz#1392191 libreswan: crash when OSX client connects
+- Improved uniqueid and session replacing support
+- Test Buffer warning fix on size_t
+- Re-introduce --configdir for backwards compatibility
+
+* Sun Jan 15 2017 Paul Wouters - 3.19-1
+- Updated to 3.19 (see download.libreswan.org/CHANGES)
+
+* Mon Dec 19 2016 Miro Hrončok - 3.18-1.1
+- Rebuild for Python 3.6
+
+* Fri Jul 29 2016 Paul Wouters - 3.18-1
+- Updated to 3.18 for CVE-2016-5391 rhbz#1361164 and VTI support
+- Remove support for /etc/sysconfig/pluto (use native systemd instead)
+
+* Thu May 05 2016 Paul Wouters - 3.17-2
+- Resolves: rhbz#1324956 prelink is gone, /etc/prelink.conf.d/* is no longer used
+
+* Thu Apr 07 2016 Paul Wouters - 3.17-1
+- Updated to 3.17 for CVE-2016-3071
+- Disable LIBCAP_NG as it prevents unbound-control from working properly
+- Temporarilly disable WERROR due to a few minor known issues
+
+* Thu Feb 04 2016 Fedora Release Engineering - 3.16-1.1
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild
+
+* Fri Dec 18 2015 Paul Wouters - 3.16-1
+- Updated to 3.16 (see https://download.libreswan.org/CHANGES)
+
+* Tue Aug 11 2015 Paul Wouters - 3.15-1
+- Updated to 3.15 (see http://download.libreswan.org/CHANGES)
+- Resolves: rhbz#CVE-2015-3240 IKE daemon restart when receiving a bad DH gx
+- NSS database creation moved from spec file to service file
+- Run CAVS tests on package build
+- Added BuildRequire systemd-units and xmlto
+- Bumped minimum required nss to 3.16.1
+- Install tmpfiles
+- Install sysctl file
+- Update doc files to include
+
+* Mon Jul 13 2015 Paul Wouters - 3.13-2
+- Resolves: rhbz#1238967 Switch libreswan to use python3
+
+* Wed Jun 17 2015 Fedora Release Engineering - 3.13-1.1
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild
+
+* Mon Jun 01 2015 Paul Wouters - 3.13-1
+- Updated to 3.13 for CVE-2015-3204
+
+* Fri Nov 07 2014 Paul Wouters - 3.12-1
+- Updated to 3.12 Various IKEv2 fixes
+
+* Wed Oct 22 2014 Paul Wouters - 3.11-1
+- Updated to 3.11 (many fixes, including startup fixes)
+- Resolves: rhbz#1144941 libreswan 3.10 upgrade breaks old ipsec.secrets configs
+- Resolves: rhbz#1147072 ikev1 aggr mode connection fails after libreswan upgrade
+- Resolves: rhbz#1144831 Libreswan appears to start with systemd before all the NICs are up and running
+
+* Tue Sep 09 2014 Paul Wouters - 3.10-3
+- Fix some coverity issues, auto=route on bootup and snprintf on 32bit machines
+
+* Mon Sep 01 2014 Paul Wouters - 3.10-1
+- Updated to 3.10, major bugfix release, new xauth status options
+
+* Sun Aug 17 2014 Fedora Release Engineering - 3.9-1.1
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild
+
+* Thu Jul 10 2014 Paul Wouters - 3.9-1
+- Updated to 3.9. IKEv2 enhancements, ESP/IKE algo enhancements
+- Mark libreswan-fips.conf as config file
+- attr modifier for man pages no longer needed
+- BUGS file no longer exists upstream
+
+* Sat Jun 07 2014 Fedora Release Engineering - 3.8-1.1
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild
+
+* Sat Jan 18 2014 Paul Wouters - 3.8-1
+- Updated to 3.8, fixes rhbz#CVE-2013-6467 (rhbz#1054102)
+
+* Wed Dec 11 2013 Paul Wouters - 3.7-1
+- Updated to 3.7, fixes CVE-2013-4564
+- Fixes creating a bogus NSS db on startup (rhbz#1005410)
+
+* Thu Oct 31 2013 Paul Wouters - 3.6-1
+- Updated to 3.6 (IKEv2, MODECFG, Cisco interop fixes)
+- Generate empty NSS db if none exists
+
+* Mon Aug 19 2013 Paul Wouters - 3.5-3
+- Add a Provides: for openswan-doc
+
+* Sat Aug 03 2013 Fedora Release Engineering - 3.5-1.1
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_20_Mass_Rebuild
+
+* Mon Jul 15 2013 Paul Wouters - 3.5-2
+- Added interop patch for (some?) Cisco VPN clients sending 16 zero
+ bytes of extraneous IKE data
+- Removed fipscheck_version
+
+* Sat Jul 13 2013 Paul Wouters - 3.5-1
+- Updated to 3.5
+
+* Thu Jun 06 2013 Paul Wouters - 3.4-1
+- Updated to 3.4, which only contains style changes to kernel coding style
+- IN MEMORIAM: June 3rd, 2013 Hugh Daniel
+
+* Mon May 13 2013 Paul Wouters - 3.3-1
+- Updated to 3.3, which resolves CVE-2013-2052
+
+* Sat Apr 13 2013 Paul Wouters - 3.2-1
+- Initial package for Fedora