diff --git a/.gitignore b/.gitignore
index 26f0a97..af4b6ff 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,4 @@
SOURCES/ikev1_dsa.fax.bz2
SOURCES/ikev1_psk.fax.bz2
SOURCES/ikev2.fax.bz2
-SOURCES/libreswan-3.27.tar.gz
+SOURCES/libreswan-3.29.tar.gz
diff --git a/.libreswan.metadata b/.libreswan.metadata
index b2b4b4e..01d8128 100644
--- a/.libreswan.metadata
+++ b/.libreswan.metadata
@@ -1,4 +1,4 @@
b35cd50b8bc0a08b9c07713bf19c72d53bfe66bb SOURCES/ikev1_dsa.fax.bz2
861d97bf488f9e296cad8c43ab72f111a5b1a848 SOURCES/ikev1_psk.fax.bz2
fcaf77f3deae3d8e99cdb3b1f8abea63167a0633 SOURCES/ikev2.fax.bz2
-c2e4b418ea286168bb022620a6af6a70cecffd14 SOURCES/libreswan-3.27.tar.gz
+492cd1cf18c06e47b2864a57a355a7f5393f80cc SOURCES/libreswan-3.29.tar.gz
diff --git a/SOURCES/libreswan-3.25-1664521-fips-keysize.patch b/SOURCES/libreswan-3.25-1664521-fips-keysize.patch
deleted file mode 100644
index e382f8c..0000000
--- a/SOURCES/libreswan-3.25-1664521-fips-keysize.patch
+++ /dev/null
@@ -1,35 +0,0 @@
-diff --git a/programs/pluto/connections.c b/programs/pluto/connections.c
-index 45e5bee1f..db1ac5303 100644
---- a/programs/pluto/connections.c
-+++ b/programs/pluto/connections.c
-@@ -846,9 +846,10 @@ static void load_end_nss_certificate(const char *which, CERTCertificate *cert,
- if (libreswan_fipsmode()) {
- SECKEYPublicKey *pk = CERT_ExtractPublicKey(cert);
- passert(pk != NULL);
-- if (pk->u.rsa.modulus.len < FIPS_MIN_RSA_KEY_SIZE) {
-+ if (pk->u.rsa.modulus.len * BITS_PER_BYTE < FIPS_MIN_RSA_KEY_SIZE) {
- whack_log(RC_FATAL,
-- "FIPS: Rejecting cert with key size under %d",
-+ "FIPS: Rejecting cert with key size %d which is under %d",
-+ pk->u.rsa.modulus.len * BITS_PER_BYTE,
- FIPS_MIN_RSA_KEY_SIZE);
- SECKEY_DestroyPublicKey(pk);
- return;
-diff --git a/programs/pluto/nss_cert_verify.c b/programs/pluto/nss_cert_verify.c
-index b4de167bb..9b031354b 100644
---- a/programs/pluto/nss_cert_verify.c
-+++ b/programs/pluto/nss_cert_verify.c
-@@ -460,9 +460,10 @@ static bool import_der_cert(CERTCertDBHandle *handle,
- if (libreswan_fipsmode()) {
- SECKEYPublicKey *pk = CERT_ExtractPublicKey(cert);
- passert(pk != NULL);
-- if (pk->u.rsa.modulus.len < FIPS_MIN_RSA_KEY_SIZE) {
-- libreswan_log("FIPS: Rejecting cert with key size under %d",
-- FIPS_MIN_RSA_KEY_SIZE);
-+ if ((pk->u.rsa.modulus.len * BITS_PER_BYTE) < FIPS_MIN_RSA_KEY_SIZE) {
-+ libreswan_log("FIPS: Rejecting peer cert with key size %d under %d",
-+ pk->u.rsa.modulus.len * BITS_PER_BYTE,
-+ FIPS_MIN_RSA_KEY_SIZE);
- SECKEY_DestroyPublicKey(pk);
- /*
- * XXX: Since the certificate isn't added to
diff --git a/SOURCES/libreswan-3.25-1724200-halfopen-shunt.patch b/SOURCES/libreswan-3.25-1724200-halfopen-shunt.patch
new file mode 100644
index 0000000..839b7c3
--- /dev/null
+++ b/SOURCES/libreswan-3.25-1724200-halfopen-shunt.patch
@@ -0,0 +1,13 @@
+diff -Naur libreswan-3.25-orig/programs/pluto/state.c libreswan-3.25/programs/pluto/state.c
+--- libreswan-3.25-orig/programs/pluto/state.c 2019-07-03 15:52:47.246474906 -0400
++++ libreswan-3.25/programs/pluto/state.c 2019-07-03 15:54:37.671850020 -0400
+@@ -1101,7 +1101,8 @@
+ #endif
+
+ /* If we are failed OE initiator, make shunt bare */
+- if (IS_IKE_SA(st) && (c->policy & POLICY_OPPORTUNISTIC) &&
++ if (IS_IKE_SA(st) && c->newest_isakmp_sa == st->st_serialno &&
++ (c->policy & POLICY_OPPORTUNISTIC) &&
+ (st->st_state == STATE_PARENT_I1 || st->st_state == STATE_PARENT_I2)) {
+ ipsec_spi_t failure_shunt = shunt_policy_spi(c, FALSE /* failure_shunt */);
+ ipsec_spi_t nego_shunt = shunt_policy_spi(c, TRUE /* negotiation shunt */);
diff --git a/SOURCES/libreswan-3.25-EKU-1639404.patch b/SOURCES/libreswan-3.25-EKU-1639404.patch
deleted file mode 100644
index 7249f6c..0000000
--- a/SOURCES/libreswan-3.25-EKU-1639404.patch
+++ /dev/null
@@ -1,108 +0,0 @@
-diff --git a/lib/libswan/Makefile b/lib/libswan/Makefile
-index 510148ad1..0f5c26228 100644
---- a/lib/libswan/Makefile
-+++ b/lib/libswan/Makefile
-@@ -200,10 +200,6 @@ CFLAGS+=-I${LIBRESWANSRCDIR}/include ${PORTINCLUDE}
- CFLAGS+=$(USERLAND_CFLAGS)
- CFLAGS+=${CROSSFLAGS}
-
--ifeq ($(NSS_REQ_AVA_COPY),true)
--CFLAGS+=-DNSS_REQ_AVA_COPY
--endif
--
- OBJS += $(abs_builddir)/version.o
-
- include $(top_srcdir)/mk/library.mk
-diff --git a/mk/config.mk b/mk/config.mk
-index 3f2bd55c1..fcdabd1fb 100644
---- a/mk/config.mk
-+++ b/mk/config.mk
-@@ -242,6 +242,17 @@ NSPR_LDFLAGS ?= -lnspr4
- # Use nss copy for CERT_CompareAVA
- # See https://bugzilla.mozilla.org/show_bug.cgi?id=1336487
- NSS_REQ_AVA_COPY?=true
-+ifeq ($(NSS_REQ_AVA_COPY),true)
-+NSSFLAGS+=-DNSS_REQ_AVA_COPY
-+endif
-+
-+# Use nss IPsec profile for X509 validation. This is less restrictive
-+# ok EKU's. This is not yet in upstream nss.
-+# See https://bugzilla.mozilla.org/show_bug.cgi?id=1252891
-+NSS_HAS_IPSEC_PROFILE?=false
-+ifeq ($(NSS_HAS_IPSEC_PROFILE),true)
-+NSSFLAGS+=-DNSS_IPSEC_PROFILE
-+endif
-
- # Use a local copy of xfrm.h. This can be needed on older systems
- # that do not ship linux/xfrm.h, or when the shipped version is too
-diff --git a/programs/pluto/nss_cert_verify.c b/programs/pluto/nss_cert_verify.c
-index 95c637f53..7d458ac2a 100644
---- a/programs/pluto/nss_cert_verify.c
-+++ b/programs/pluto/nss_cert_verify.c
-@@ -299,6 +299,28 @@ static int vfy_chain_pkix(CERTCertificate **chain, int chain_len,
- cvout[1].value.pointer.chain = NULL;
- cvout[2].type = cert_po_end;
-
-+ int fin;
-+
-+#ifdef NSS_IPSEC_PROFILE
-+ SECStatus rv = CERT_PKIXVerifyCert(end_cert, certificateUsageIPsec,
-+ cvin, cvout, NULL);
-+ if (rv != SECSuccess || cur_log->count > 0) {
-+ if (cur_log->count > 0 && cur_log->head != NULL) {
-+ fin = nss_err_to_revfail(cur_log->head);
-+ } else {
-+ /*
-+ * An rv != SECSuccess without CERTVerifyLog
-+ * results should not * happen, but catch it anyway
-+ */
-+ loglog(RC_LOG_SERIOUS, "X509: unspecified NSS verification failure");
-+ fin = VERIFY_RET_FAIL;
-+ }
-+ } else {
-+ DBG(DBG_X509, DBG_log("certificate is valid"));
-+ *end_out = end_cert;
-+ fin = VERIFY_RET_OK;
-+ }
-+#else
- /* kludge alert!!
- * verification may be performed twice: once with the
- * 'client' usage and once with 'server', which is an NSS
-@@ -307,12 +329,10 @@ static int vfy_chain_pkix(CERTCertificate **chain, int chain_len,
- * KU/EKU combinations
- */
-
-- int fin;
- SECCertificateUsage usage;
-
- for (usage = certificateUsageSSLClient; ; usage = certificateUsageSSLServer) {
- SECStatus rv = CERT_PKIXVerifyCert(end_cert, usage, cvin, cvout, NULL);
--
- if (rv != SECSuccess || cur_log->count > 0) {
- if (cur_log->count > 0 && cur_log->head != NULL) {
- if (usage == certificateUsageSSLClient &&
-@@ -346,6 +366,7 @@ static int vfy_chain_pkix(CERTCertificate **chain, int chain_len,
- }
- break;
- }
-+#endif
- pexpect(fin != 0);
-
- CERT_DestroyCertList(trustcl);
-diff --git a/programs/pluto/plutomain.c b/programs/pluto/plutomain.c
-index 50582822d..007d73f45 100644
---- a/programs/pluto/plutomain.c
-+++ b/programs/pluto/plutomain.c
-@@ -180,6 +180,12 @@ static const char compile_time_interop_options[] = ""
- " BROKEN_POPEN"
- #endif
- " NSS"
-+#ifdef NSS_REQ_AVA_COPY
-+ " (AVA copy)"
-+#endif
-+#ifdef NSS_IPSEC_PROFILE
-+ " (IPsec profile)"
-+#endif
- #ifdef USE_DNSSEC
- " DNSSEC"
- #endif
diff --git a/SOURCES/libreswan-3.27-1645137-addconn.patch b/SOURCES/libreswan-3.27-1645137-addconn.patch
deleted file mode 100644
index b8be440..0000000
--- a/SOURCES/libreswan-3.27-1645137-addconn.patch
+++ /dev/null
@@ -1,12 +0,0 @@
-diff -Naur libreswan-3.28/lib/libipsecconf/confread.c libreswan-3.28-orig/lib/libipsecconf/confread.c
---- libreswan-3.28/lib/libipsecconf/confread.c 2018-11-08 01:28:24.869885136 -0500
-+++ libreswan-3.28-orig/lib/libipsecconf/confread.c 2018-11-04 21:24:36.000000000 -0500
-@@ -827,7 +827,7 @@
- break;
- }
- }
-- pfreeany((*the_strings)[field]);
-+
-
- if (kw->string == NULL) {
- starter_error_append(perrl, "Invalid %s value",
diff --git a/SOURCES/libreswan-3.27-1648776-v1v2split.patch b/SOURCES/libreswan-3.27-1648776-v1v2split.patch
deleted file mode 100644
index c19a3e5..0000000
--- a/SOURCES/libreswan-3.27-1648776-v1v2split.patch
+++ /dev/null
@@ -1,145 +0,0 @@
-diff -Naur libreswan-3.27-orig/lib/libipsecconf/confread.c libreswan-3.27/lib/libipsecconf/confread.c
---- libreswan-3.27-orig/lib/libipsecconf/confread.c 2018-12-09 12:45:14.559217654 -0500
-+++ libreswan-3.27/lib/libipsecconf/confread.c 2018-12-09 13:05:01.641609352 -0500
-@@ -148,7 +148,7 @@
- cfg->conn_default.policy =
- POLICY_TUNNEL |
- POLICY_ENCRYPT | POLICY_PFS |
-- POLICY_IKEV1_ALLOW | POLICY_IKEV2_ALLOW | /* ikev2=permit */
-+ POLICY_IKEV2_ALLOW | POLICY_IKEV2_PROPOSE | /* ikev2=insist */
- POLICY_SAREF_TRACK | /* sareftrack=yes */
- POLICY_IKE_FRAG_ALLOW | /* ike_frag=yes */
- POLICY_ESN_NO; /* esn=no */
-@@ -1257,16 +1257,15 @@
- break;
-
- case fo_permit:
-- /* this is the default for now */
-- pv2 = POLICY_IKEV1_ALLOW | POLICY_IKEV2_ALLOW;
-- break;
-+ starter_error_append(perrl, "ikev2=permit is no longer accepted. Use ikev2=yes or ikev2=no");
-+ return TRUE;
-
- case fo_propose:
-- pv2 = POLICY_IKEV1_ALLOW | POLICY_IKEV2_ALLOW | POLICY_IKEV2_PROPOSE;
-- break;
-+ starter_error_append(perrl, "ikev2=propose is no longer accepted. Use ikev2=yes or ikev2=no");
-+ return TRUE;
-
- case fo_insist:
-- pv2 = POLICY_IKEV2_ALLOW | POLICY_IKEV2_PROPOSE;
-+ pv2 = POLICY_IKEV2_ALLOW | POLICY_IKEV2_PROPOSE;
- break;
- }
- conn->policy = (conn->policy & ~POLICY_IKEV2_MASK) | pv2;
-diff -Naur libreswan-3.27-orig/lib/libipsecconf/keywords.c libreswan-3.27/lib/libipsecconf/keywords.c
---- libreswan-3.27-orig/lib/libipsecconf/keywords.c 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/lib/libipsecconf/keywords.c 2018-12-09 13:02:15.541619284 -0500
-@@ -74,7 +74,7 @@
- static const struct keyword_enum_values kw_keyexchange_list = VALUES_INITIALIZER(kw_keyexchange_values);
-
- /*
-- * Values for Four-State options, such as ikev2
-+ * Values for Four-State options, such as ppk
- */
- static const struct keyword_enum_value kw_fourvalued_values[] = {
- { "never", fo_never },
-diff -Naur libreswan-3.27-orig/programs/configs/d.ipsec.conf/ikev2.xml libreswan-3.27/programs/configs/d.ipsec.conf/ikev2.xml
---- libreswan-3.27-orig/programs/configs/d.ipsec.conf/ikev2.xml 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/programs/configs/d.ipsec.conf/ikev2.xml 2018-12-09 13:02:15.541619284 -0500
-@@ -1,25 +1,13 @@
-
- ikev2
-
--IKEv2 (RFC 7296) settings to be used. Currently the accepted
--values are permit(the default),
--signifying IKEv2 will be accepted if received, but IKEv1 will be used
--when initiating; never or no signifying no IKEv2 negotiation should be
--transmitted or accepted; propose or
--yes signifying that we permit IKEv1
--and IKEv2, and use IKEv2 as the default to initiate; and insistsignifying we only accept and receive IKEv2 -
--IKEv1 negotiations will be rejected.
--
--If the ikev2= setting is set to permit
--or propose, Libreswan will try and detect a
--"bid down" attack from IKEv2 to IKEv1. Since there is no standard for
--transmitting the IKEv2 capability with IKEv1, Libreswan uses a special
--Vendor ID "CAN-IKEv2". If a fall back from IKEv2 to IKEv1 was detected,
--and the IKEv1 negotiation contains Vendor ID "CAN-IKEv2", Libreswan will
--immediately attempt and IKEv2 rekey and refuse to use the IKEv1 connection.
--With an ikev2= setting of insist, no IKEv1
--negotiation is allowed, and no bid down attack is possible.
-+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, 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.
-+
-
-
-diff -Naur libreswan-3.27-orig/programs/whack/whack.c libreswan-3.27/programs/whack/whack.c
---- libreswan-3.27-orig/programs/whack/whack.c 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/programs/whack/whack.c 2018-12-09 13:06:01.825333781 -0500
-@@ -108,7 +108,7 @@
- " [--mtu ] \\\n"
- " [--priority ] [--reqid ] \\\n"
- " [--tfc ] [--send-no-esp-tfc] \\\n"
-- " [--ikev1-allow | --ikev2-allow | --ikev2-propose] \\\n"
-+ " [--ikev1-allow | --ikev2-allow ] \\\n"
- " [--allow-narrowing] [--sareftrack] [--sarefconntrack] \\\n"
- " [--ikefrag-allow | --ikefrag-force] [--no-ikepad] \\\n"
- " [--esn ] [--no-esn] [--decap-dscp] [--nopmtudisc] [--mobike] \\\n"
-@@ -711,7 +711,6 @@
-
- PS("ikev1-allow", IKEV1_ALLOW),
- PS("ikev2-allow", IKEV2_ALLOW),
-- PS("ikev2-propose", IKEV2_PROPOSE),
-
- PS("allow-narrowing", IKEV2_ALLOW_NARROWING),
- #ifdef XAUTH_HAVE_PAM
-@@ -1627,8 +1626,6 @@
- case CDP_SINGLETON + POLICY_IKEV1_ALLOW_IX:
- /* --ikev2-allow */
- case CDP_SINGLETON + POLICY_IKEV2_ALLOW_IX:
-- /* --ikev2-propose */
-- case CDP_SINGLETON + POLICY_IKEV2_PROPOSE_IX:
-
- /* --allow-narrowing */
- case CDP_SINGLETON + POLICY_IKEV2_ALLOW_NARROWING_IX:
-@@ -2191,6 +2188,15 @@
- break;
- }
-
-+ /* fixup old to new style IKEv1/IKEv2 settings */
-+ if (msg.policy & POLICY_IKEV2_ALLOW) {
-+ /* IKEv2 now always has ALLOW+PROPOSE */
-+ msg.policy |= POLICY_IKEV2_PROPOSE;
-+ }
-+ if (msg.policy & POLICY_IKEV2_ALLOW &&
-+ msg.policy & POLICY_IKEV1_ALLOW) {
-+ diag("connection cannot be both ikev1 and ikev2");
-+ }
-
- if (oppo_dport != 0)
- setportof(htons(oppo_dport), &msg.oppo_peer_client);
-@@ -2267,11 +2273,12 @@
- diag("must specify connection authentication, eg --rsasig, --psk or --auth-null for non-shunt connection");
-
- /*
-- * If neither v1 nor v2, default to v1
-- * (backward compatibility)
-+ * If neither v1 nor v2, default to v2
- */
-- if (!(msg.policy & POLICY_IKEV2_MASK))
-- msg.policy |= POLICY_IKEV1_ALLOW;
-+ if (!(msg.policy & POLICY_IKEV2_MASK)) {
-+ msg.policy |= POLICY_IKEV2_ALLOW;
-+ msg.policy |= POLICY_IKEV2_PROPOSE;
-+ }
-
- /*
- * ??? this test can never fail:
diff --git a/SOURCES/libreswan-3.27-1671793-delete.patch b/SOURCES/libreswan-3.27-1671793-delete.patch
deleted file mode 100644
index 3ef2cd8..0000000
--- a/SOURCES/libreswan-3.27-1671793-delete.patch
+++ /dev/null
@@ -1,90 +0,0 @@
-diff -Naur libreswan-3.27-orig/include/pluto_constants.h libreswan-3.27/include/pluto_constants.h
---- libreswan-3.27-orig/include/pluto_constants.h 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/include/pluto_constants.h 2019-02-05 16:53:07.442895489 -0500
-@@ -421,6 +421,8 @@
-
- IMPAIR_SEND_PKCS7_THINGIE_IX,
-
-+ IMPAIR_IKEv1_DEL_WITH_NOTIFY_IX,
-+
- IMPAIR_roof_IX /* first unassigned IMPAIR */
- };
-
-@@ -463,6 +465,7 @@
- #define IMPAIR_REPLAY_DUPLICATES LELEM(IMPAIR_REPLAY_DUPLICATES_IX)
- #define IMPAIR_REPLAY_FORWARD LELEM(IMPAIR_REPLAY_FORWARD_IX)
- #define IMPAIR_REPLAY_BACKWARD LELEM(IMPAIR_REPLAY_BACKWARD_IX)
-+#define IMPAIR_IKEv1_DEL_WITH_NOTIFY LELEM(IMPAIR_IKEv1_DEL_WITH_NOTIFY_IX)
-
- #define IMPAIR_REPLAY_ENCRYPTED LELEM(IMPAIR_REPLAY_ENCRYPTED_IX)
- #define IMPAIR_CORRUPT_ENCRYPTED LELEM(IMPAIR_CORRUPT_ENCRYPTED_IX)
-@@ -478,6 +481,8 @@
-
- #define IMPAIR_SEND_PKCS7_THINGIE LELEM(IMPAIR_SEND_PKCS7_THINGIE_IX)
-
-+#define IMPAIR_IKEv1_DEL_WITH_NOTIFY LELEM(IMPAIR_IKEv1_DEL_WITH_NOTIFY_IX)
-+
- /* State of exchanges
- *
- * The name of the state describes the last message sent, not the
-diff -Naur libreswan-3.27-orig/lib/libswan/impair.c libreswan-3.27/lib/libswan/impair.c
---- libreswan-3.27-orig/lib/libswan/impair.c 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/lib/libswan/impair.c 2019-02-05 16:51:07.522924972 -0500
-@@ -87,6 +87,7 @@
- S(IMPAIR_SUPPRESS_RETRANSMITS, "impair-suppress-retransmits", "causes pluto to never send retransmits (wait the full timeout)"),
- S(IMPAIR_TIMEOUT_ON_RETRANSMIT, "impair-timeout-on-retransmit", "causes pluto to 'retry' (switch protocol) on the first retransmit"),
- S(IMPAIR_UNKNOWN_PAYLOAD_CRITICAL, "impair-unknown-payload-critical", "mark the unknown payload as critical"),
-+ S(IMPAIR_IKEv1_DEL_WITH_NOTIFY, "impair-ikev1-del-with-notify", "causes pluto to send IKE Delete with additional bogus Notify payload"),
-
- #undef S
- };
-diff -Naur libreswan-3.27-orig/programs/pluto/ikev1_main.c libreswan-3.27/programs/pluto/ikev1_main.c
---- libreswan-3.27-orig/programs/pluto/ikev1_main.c 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/programs/pluto/ikev1_main.c 2019-02-05 16:48:16.241538787 -0500
-@@ -2347,12 +2347,36 @@
- .isad_protoid = ns->proto,
- .isad_nospi = 1,
- };
-+
-+ if (DBGP(IMPAIR_IKEv1_DEL_WITH_NOTIFY))
-+ isad.isad_np = ISAKMP_NEXT_N; /* Notify */
-+
- passert(out_struct(&isad, &isakmp_delete_desc, &r_hdr_pbs,
- &del_pbs));
- passert(out_raw(&ns->spi, sizeof(ipsec_spi_t),
- &del_pbs,
- "delete payload"));
- close_output_pbs(&del_pbs);
-+
-+ if (DBGP(IMPAIR_IKEv1_DEL_WITH_NOTIFY)) {
-+ pb_stream cruft_pbs;
-+
-+ libreswan_log("IMPAIR: adding bogus Notify payload after IKE Delete payload");
-+ struct isakmp_notification isan = {
-+ .isan_np = ISAKMP_NEXT_NONE,
-+ .isan_doi = ISAKMP_DOI_IPSEC,
-+ .isan_protoid = PROTO_ISAKMP,
-+ .isan_spisize = COOKIE_SIZE * 2,
-+ .isan_type = INVALID_PAYLOAD_TYPE,
-+ };
-+
-+ passert(out_struct(&isan, &isakmp_notification_desc, &r_hdr_pbs,
-+ &cruft_pbs));
-+ passert(out_raw(&ns->spi, sizeof(ipsec_spi_t), &cruft_pbs,
-+ "notify payload"));
-+ close_output_pbs(&cruft_pbs);
-+ }
-+
- }
- }
-
-@@ -2599,7 +2623,9 @@
- rc->policy &= ~POLICY_UP;
- if (!shared_phase1_connection(rc)) {
- flush_pending_by_connection(rc);
-+ /* This also deletes the IKE SA, clear pointer */
- delete_states_by_connection(rc, FALSE);
-+ md->st = NULL;
- }
- reset_cur_connection();
- }
diff --git a/SOURCES/libreswan-3.27-outgoing-ports-1668342.patch b/SOURCES/libreswan-3.27-outgoing-ports-1668342.patch
deleted file mode 100644
index 2af73f5..0000000
--- a/SOURCES/libreswan-3.27-outgoing-ports-1668342.patch
+++ /dev/null
@@ -1,29 +0,0 @@
-diff -up libreswan-3.27/lib/libswan/unbound.c.orig libreswan-3.27/lib/libswan/unbound.c
---- libreswan-3.27/lib/libswan/unbound.c.orig 2019-01-24 16:28:27.191695613 +0100
-+++ libreswan-3.27/lib/libswan/unbound.c 2019-02-01 12:16:36.029309870 +0100
-@@ -95,6 +95,25 @@ static void unbound_ctx_config(bool do_d
- DBG(DBG_DNS, DBG_log("/etc/resolv.conf usage activated"));
- }
-
-+ /* Set a limit on outgoing ports, some ports are prohibited by SELinux policy */
-+ errno = 0;
-+ ugh = ub_ctx_set_option(dns_ctx, "outgoing-port-avoid:", "0-65535");
-+ if (ugh != 0) {
-+ loglog(RC_LOG_SERIOUS, "error setting outgoing-port-avoid: %s: %s",
-+ ub_strerror(ugh), strerror(errno));
-+ } else {
-+ DBG(DBG_DNS, DBG_log("outgoing-port-avoid set 0-65535"));
-+ }
-+
-+ errno = 0;
-+ ugh = ub_ctx_set_option(dns_ctx, "outgoing-port-permit:", "32768-60999");
-+ if (ugh != 0) {
-+ loglog(RC_LOG_SERIOUS, "error setting outgoing-port-permit: %s: %s",
-+ ub_strerror(ugh), strerror(errno));
-+ } else {
-+ DBG(DBG_DNS, DBG_log("outgoing-port-permit set 32768-60999"));
-+ }
-+
- if (!do_dnssec) {
- /* No DNSSEC - nothing more to configure */
- DBG(DBG_DNS, DBG_log("dnssec validation disabled by configuration"));
diff --git a/SOURCES/libreswan-3.27-parser.patch b/SOURCES/libreswan-3.27-parser.patch
deleted file mode 100644
index ea98c90..0000000
--- a/SOURCES/libreswan-3.27-parser.patch
+++ /dev/null
@@ -1,7144 +0,0 @@
-diff -Naur libreswan-3.27-orig/include/alg_byname.h libreswan-3.27/include/alg_byname.h
---- libreswan-3.27-orig/include/alg_byname.h 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/include/alg_byname.h 2019-02-15 16:32:28.971835267 -0500
-@@ -30,26 +30,26 @@
- * messages better align with the input files.
- */
-
--bool alg_byname_ok(const struct proposal_parser *parser,
-+bool alg_byname_ok(struct proposal_parser *parser,
- const struct ike_alg *alg, shunk_t print_name);
-
- /*
- * Helper functions to implement most of the lookup.
- */
-
--const struct ike_alg *encrypt_alg_byname(const struct proposal_parser *parser,
-+const struct ike_alg *encrypt_alg_byname(struct proposal_parser *parser,
- shunk_t name, size_t key_bit_length,
- shunk_t print_name);
-
--const struct ike_alg *prf_alg_byname(const struct proposal_parser *parser,
-+const struct ike_alg *prf_alg_byname(struct proposal_parser *parser,
- shunk_t name, size_t key_bit_length,
- shunk_t print_name);
-
--const struct ike_alg *integ_alg_byname(const struct proposal_parser *parser,
-+const struct ike_alg *integ_alg_byname(struct proposal_parser *parser,
- shunk_t name, size_t key_bit_length,
- shunk_t print_name);
-
--const struct ike_alg *dh_alg_byname(const struct proposal_parser *parser,
-+const struct ike_alg *dh_alg_byname(struct proposal_parser *parser,
- shunk_t name, size_t key_bit_length,
- shunk_t print_name);
-
-diff -Naur libreswan-3.27-orig/include/alg_info.h libreswan-3.27/include/alg_info.h
---- libreswan-3.27-orig/include/alg_info.h 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/include/alg_info.h 1969-12-31 19:00:00.000000000 -0500
-@@ -1,245 +0,0 @@
--/* Algorithm info parsing and creation functions
-- *
-- * Author: JuanJo Ciarlante
-- * Copyright (C) 2007 Michael Richardson
-- * Copyright (C) 2012-2013 Paul Wouters
-- * Copyright (C) 2013 D. Hugh Redelmeier
-- * Copyright (C) 2013 Paul Wouters
-- * Copyright (C) 2015-2017 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 ALG_INFO_H
--#define ALG_INFO_H
--
--#include "lswcdefs.h"
--#include "constants.h"
--#include "ike_alg.h"
--#include "shunk.h"
--
--struct alg_info;
--struct proposal_protocol;
--struct proposal_info;
--struct proposal_policy;
--struct proposal_parser;
--
--typedef const struct ike_alg *(alg_byname_fn)(const struct proposal_parser *parser,
-- shunk_t name, size_t key_bit_length,
-- shunk_t print_name);
--
--/*
-- * Parameters to tune the parser.
-- */
--
--struct proposal_policy {
-- bool ikev1;
-- bool ikev2;
-- bool pfs; /* For CHILD SA, use DH from IKE SA */
-- /*
-- * According to current policy, is the algorithm ok
-- * (supported)? If it isn't return FALSE.
-- *
-- * For instance, an IKE algorithm requires in-process support;
-- * while an ESP/AH algorithm requires kernel support.
-- */
-- bool (*alg_is_ok)(const struct ike_alg *alg);
-- /*
-- * Print a warning. Signature needs to match libreswan_log.
-- */
-- int (*warning)(const char *fmt, ...) PRINTF_LIKE(1);
--};
--
--/*
-- * Defaults to fill in.
-- */
--
--struct proposal_defaults {
-- const struct ike_alg **dh;
-- const struct ike_alg **prf;
-- const struct ike_alg **integ;
-- const struct ike_alg **encrypt;
--};
--
--/*
-- * Parameters to set the parser's basic behaviour - ESP/AH/IKE.
-- */
--
--struct proposal_protocol {
-- const char *name;
-- enum ike_alg_key ikev1_alg_id;
--
-- /*
-- * Lists of defaults.
-- */
-- const struct proposal_defaults *ikev1_defaults;
-- const struct proposal_defaults *ikev2_defaults;
--
-- /*
-- * Is the proposal OK?
-- *
-- * This is the final check, if this succeeds then the proposal
-- * is added.
-- */
-- bool (*proposal_ok)(const struct proposal_parser *parser,
-- const struct proposal_info *proposal);
--
-- /*
-- * XXX: Is the proto-id needed? Parser should be protocol
-- * agnostic.
-- */
-- unsigned protoid;
--
-- /*
-- * This lookup functions must set err and return null if NAME
-- * isn't valid.
-- */
-- alg_byname_fn *encrypt_alg_byname;
-- alg_byname_fn *prf_alg_byname;
-- alg_byname_fn *integ_alg_byname;
-- alg_byname_fn *dh_alg_byname;
--};
--
--/*
-- * Everything combined.
-- */
--struct proposal_parser {
-- const struct proposal_protocol *protocol;
-- const struct proposal_param *param;
-- const struct proposal_policy *policy;
-- char *err_buf;
-- size_t err_buf_len;
--};
--
--/*
-- * A proposal as decoded by the parser.
-- */
--
--struct proposal_info {
-- /*
-- * The encryption algorithm and key length.
-- *
-- * Because struct encrypt_desc still specifies multiple key
-- * lengths, ENCKEYLEN is still required.
-- */
-- const struct encrypt_desc *encrypt;
-- size_t enckeylen; /* keylength for ESP transform (bits) */
-- /*
-- * The integrity and PRF algorithms.
-- */
-- const struct prf_desc *prf;
-- const struct integ_desc *integ;
-- /*
-- * PFS/DH negotiation.
-- */
-- const struct oakley_group_desc *dh;
-- /*
-- * Which protocol is this proposal intended for?
-- */
-- const struct proposal_protocol *protocol;
--};
--
--/* common prefix of struct alg_info_esp and struct alg_info_ike */
--struct alg_info {
-- int alg_info_cnt;
-- int ref_cnt;
-- struct proposal_info proposals[128];
--};
--
--struct alg_info_esp {
-- struct alg_info ai; /* common prefix */
--};
--
--struct alg_info_ike {
-- struct alg_info ai; /* common prefix */
--};
--
--extern void alg_info_free(struct alg_info *alg_info);
--extern void alg_info_addref(struct alg_info *alg_info);
--extern void alg_info_delref(struct alg_info *alg_info);
--
--extern struct alg_info_ike *alg_info_ike_create_from_str(const struct proposal_policy *policy,
-- const char *alg_str,
-- char *err_buf, size_t err_buf_len);
--
--extern struct alg_info_esp *alg_info_esp_create_from_str(const struct proposal_policy *policy,
-- const char *alg_str,
-- char *err_buf, size_t err_buf_len);
--
--extern struct alg_info_esp *alg_info_ah_create_from_str(const struct proposal_policy *policy,
-- const char *alg_str,
-- char *err_buf, size_t err_buf_len);
--
--size_t lswlog_proposal_info(struct lswlog *log, const struct proposal_info *proposal);
--size_t lswlog_alg_info(struct lswlog *log, const struct alg_info *alg_info);
--
--/*
-- * Iterate through the elements of an ESP or IKE table.
-- *
-- * Use __typeof__ instead of const to get around ALG_INFO some times
-- * being const and sometimes not.
-- *
-- * XXX: yes, they are the same!
-- */
--
--#define FOR_EACH_PROPOSAL_INFO(ALG_INFO, PROPOSAL_INFO) \
-- for (__typeof__((ALG_INFO)->proposals[0]) *(PROPOSAL_INFO) = (ALG_INFO)->proposals; \
-- (PROPOSAL_INFO) < (ALG_INFO)->proposals + (ALG_INFO)->alg_info_cnt; \
-- (PROPOSAL_INFO)++)
--
--#define FOR_EACH_ESP_INFO(ALG_INFO, ESP_INFO) \
-- FOR_EACH_PROPOSAL_INFO(&((ALG_INFO)->ai), ESP_INFO)
--
--#define FOR_EACH_IKE_INFO(ALG_INFO, IKE_INFO) \
-- FOR_EACH_PROPOSAL_INFO(&((ALG_INFO)->ai), IKE_INFO)
--
--/*
-- * Error indicated by err_buf[0] != '\0'.
-- *
-- * POLICY should be used to guard algorithm supported checks. For
-- * instance: if POLICY=IKEV1, then IKEv1 support is required (IKEv2 is
-- * don't care); and if POLICY=IKEV1|IKEV2, then both IKEv1 and IKEv2
-- * support is required.
-- *
-- * Parsing with POLICY=IKEV1, but then proposing the result using
-- * IKEv2 is a program error. The IKEv2 should complain loudly and,
-- * we hope, not crash.
-- *
-- * Parsing with POLICY='0' is allowed. It will accept the algorithms
-- * unconditionally (spi.c seems to need this).
-- */
--
--struct proposal_parser proposal_parser(const struct proposal_policy *policy,
-- const struct proposal_protocol *protocol,
-- char *err_buf, size_t err_buf_len);
--
--bool alg_info_parse_str(const struct proposal_parser *parser,
-- struct alg_info *alg_info,
-- shunk_t alg_str);
--
--/*
-- * Check that encrypt==AEAD and/or integ==none don't contradict.
-- */
--bool proposal_aead_none_ok(const struct proposal_parser *parser,
-- const struct proposal_info *proposal);
--
--bool alg_info_pfs_vs_dh_check(const struct proposal_parser *parser,
-- struct alg_info_esp *aie);
--
--#if 0
--/* return true if it really is an error (when impaired return false) */
--bool proposal_error(const struct proposal_parser *parser,
-- const char *message, ...) PRINTF_LIKE(2);
--#endif
--
--bool impair_proposal_errors(const struct proposal_parser *parser);
--
--#endif /* ALG_INFO_H */
-diff -Naur libreswan-3.27-orig/include/ike_alg.h libreswan-3.27/include/ike_alg.h
---- libreswan-3.27-orig/include/ike_alg.h 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/include/ike_alg.h 2019-02-15 16:32:28.972835277 -0500
-@@ -252,7 +252,7 @@
- * Easier to just require that this contain everything then
- * poke around in multiple places.
- */
-- const char *names[5];
-+ const char *names[6];
- /*
- * See above.
- *
-diff -Naur libreswan-3.27-orig/include/lswlog.h libreswan-3.27/include/lswlog.h
---- libreswan-3.27-orig/include/lswlog.h 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/include/lswlog.h 2019-02-15 16:32:28.973835286 -0500
-@@ -577,7 +577,7 @@
- #define PEXPECT_LOG(FMT, ...) \
- libreswan_pexpect_log(__func__, \
- PASSERT_BASENAME, __LINE__, \
-- FMT, __VA_ARGS__)
-+ FMT,##__VA_ARGS__)
-
-
- /*
-diff -Naur libreswan-3.27-orig/include/names_constant.h libreswan-3.27/include/names_constant.h
---- libreswan-3.27-orig/include/names_constant.h 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/include/names_constant.h 2019-02-15 16:32:28.973835286 -0500
-@@ -41,6 +41,8 @@
- extern enum_names auth_alg_names;
- extern enum_names oakley_lifetime_names;
-
-+extern enum_names ike_version_names;
-+extern enum_names ike_version_liveness_names;
- extern enum_names version_names;
- extern enum_names doi_names;
- extern enum_names ikev1_payload_names;
-diff -Naur libreswan-3.27-orig/include/pluto_constants.h libreswan-3.27/include/pluto_constants.h
---- libreswan-3.27-orig/include/pluto_constants.h 2019-02-15 16:31:43.034408076 -0500
-+++ libreswan-3.27/include/pluto_constants.h 2019-02-15 16:32:28.974835295 -0500
-@@ -28,6 +28,12 @@
- # define DEFAULT_DNSSEC_ROOTKEY_FILE ""
- # endif
-
-+enum ike_version {
-+ IKEv1 = 1,
-+ IKEv2 = 2,
-+#define IKE_VERSION_ROOF 3
-+};
-+
- /*
- * IETF has no recommendations
- * FIPS SP800-77 sayas IKE max is 24h, IPsec max is 8h
-diff -Naur libreswan-3.27-orig/include/proposals.h libreswan-3.27/include/proposals.h
---- libreswan-3.27-orig/include/proposals.h 1969-12-31 19:00:00.000000000 -0500
-+++ libreswan-3.27/include/proposals.h 2019-02-15 16:32:28.975835304 -0500
-@@ -0,0 +1,264 @@
-+/* Proposals, for libreswan
-+ *
-+ * Author: JuanJo Ciarlante
-+ * Copyright (C) 2007 Michael Richardson
-+ * Copyright (C) 2012-2013 Paul Wouters
-+ * Copyright (C) 2013 D. Hugh Redelmeier
-+ * Copyright (C) 2013 Paul Wouters
-+ * Copyright (C) 2015-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 PROPOSALS_H
-+#define PROPOSALS_H
-+
-+#include "lswcdefs.h"
-+#include "constants.h"
-+#include "ike_alg.h"
-+#include "shunk.h"
-+
-+struct alg_info;
-+struct proposal_protocol;
-+struct proposal;
-+struct proposals;
-+struct proposal_policy;
-+struct proposal_parser;
-+
-+/*
-+ * XXX: needs to be merged with IKE_ALG_TYPE.
-+ */
-+enum proposal_algorithm {
-+ PROPOSAL_encrypt,
-+ PROPOSAL_prf,
-+ PROPOSAL_integ,
-+ PROPOSAL_dh,
-+ PROPOSAL_ALGORITHM_ROOF,
-+};
-+
-+/*
-+ * Everything combined.
-+ */
-+struct proposal_parser {
-+ const struct proposal_protocol *protocol;
-+ const struct proposal_param *param;
-+ const struct proposal_policy *policy;
-+ /* need to eliminate hardwired size */
-+ char error[200];
-+};
-+
-+/*
-+ * Parameters to tune the parser.
-+ */
-+
-+struct proposal_policy {
-+ enum ike_version version;
-+ unsigned parser_version;
-+ bool pfs; /* For CHILD SA, use DH from IKE SA */
-+ bool check_pfs_vs_dh;
-+ /*
-+ * According to current policy, is the algorithm ok
-+ * (supported)? If it isn't return FALSE.
-+ *
-+ * For instance, an IKE algorithm requires in-process support;
-+ * while an ESP/AH algorithm requires kernel support.
-+ */
-+ bool (*alg_is_ok)(const struct ike_alg *alg);
-+ /*
-+ * Print a warning. Signature needs to match libreswan_log.
-+ */
-+ int (*warning)(const char *fmt, ...) PRINTF_LIKE(1);
-+};
-+
-+/*
-+ * Defaults the parser uses to fill things in.
-+ */
-+
-+struct proposal_defaults {
-+ const struct ike_alg **dh;
-+ const struct ike_alg **prf;
-+ const struct ike_alg **integ;
-+ const struct ike_alg **encrypt;
-+};
-+
-+/*
-+ * The protocol - ESP/AH/IKE - the parser is processing.
-+ */
-+
-+typedef const struct ike_alg *(alg_byname_fn)(struct proposal_parser *parser,
-+ shunk_t name, size_t key_bit_length,
-+ shunk_t print_name);
-+
-+struct proposal_protocol {
-+ const char *name;
-+ enum ike_alg_key ikev1_alg_id;
-+
-+ /*
-+ * Lists of defaults for each IKE version.
-+ */
-+ const struct proposal_defaults *defaults[IKE_VERSION_ROOF];
-+
-+ /*
-+ * Is the proposal OK?
-+ *
-+ * This is the final check, if this succeeds then the proposal
-+ * is added.
-+ */
-+ bool (*proposal_ok)(struct proposal_parser *parser,
-+ const struct proposal *proposal);
-+
-+ /*
-+ * XXX: Is the proto-id needed? Parser should be protocol
-+ * agnostic.
-+ */
-+ unsigned protoid;
-+
-+ /*
-+ * This lookup functions must set err and return null if NAME
-+ * isn't valid.
-+ */
-+ alg_byname_fn *encrypt_alg_byname;
-+ alg_byname_fn *prf_alg_byname;
-+ alg_byname_fn *integ_alg_byname;
-+ alg_byname_fn *dh_alg_byname;
-+};
-+
-+/*
-+ * A proposal as decoded by the parser.
-+ */
-+
-+struct algorithm {
-+ const struct ike_alg *desc;
-+ /*
-+ * Because struct encrypt_desc still specifies multiple key
-+ * lengths, ENCKEYLEN is still required.
-+ */
-+ int enckeylen; /* only one! */
-+ struct algorithm *next;
-+};
-+
-+/* return counts of encrypt=aead and integ=none */
-+bool proposal_encrypt_aead(const struct proposal *proposal);
-+bool proposal_encrypt_norm(const struct proposal *proposal);
-+bool proposal_integ_none(const struct proposal *proposal);
-+
-+unsigned nr_proposals(struct proposals *proposals);
-+
-+extern void proposals_addref(struct proposals **proposals);
-+extern void proposals_delref(struct proposals **proposals);
-+
-+extern struct proposal *alloc_proposal(struct proposal_parser *parser);
-+extern void free_proposal(struct proposal **proposal);
-+
-+void free_algorithms(struct proposal *proposal, enum proposal_algorithm algorithm);
-+void append_proposal(struct proposals *proposals, struct proposal **proposal);
-+void append_algorithm(struct proposal_parser *parser,
-+ struct proposal *proposal, enum proposal_algorithm algorithm,
-+ const struct ike_alg *alg, int enckeylen);
-+
-+struct proposal_parser *alloc_proposal_parser(const struct proposal_policy *policy,
-+ const struct proposal_protocol *protocol);
-+void free_proposal_parser(struct proposal_parser **parser);
-+struct proposal_parser *ike_proposal_parser(const struct proposal_policy *policy);
-+struct proposal_parser *esp_proposal_parser(const struct proposal_policy *policy);
-+struct proposal_parser *ah_proposal_parser(const struct proposal_policy *policy);
-+
-+/*
-+ * XXX: useful?
-+ */
-+struct ike_proposals {
-+ struct proposals *p;
-+};
-+
-+struct child_proposals {
-+ struct proposals *p;
-+};
-+
-+void fmt_proposal(struct lswlog *log,
-+ const struct proposal *proposal);
-+void fmt_proposals(struct lswlog *log, const struct proposals *proposals);
-+
-+/*
-+ * Iterate through all the proposals and the proposal's algorithms.
-+ *
-+ * Use __typeof__ instead of const to get around ALG_INFO some times
-+ * being const and sometimes not.
-+ */
-+
-+struct proposal *next_proposal(const struct proposals *proposals,
-+ struct proposal *last_proposal);
-+
-+#define FOR_EACH_PROPOSAL(PROPOSALS, PROPOSAL) \
-+ for (struct proposal *PROPOSAL = next_proposal(PROPOSALS, NULL); \
-+ PROPOSAL != NULL; \
-+ PROPOSAL = next_proposal(PROPOSALS, PROPOSAL))
-+
-+struct algorithm *next_algorithm(const struct proposal *proposal,
-+ enum proposal_algorithm algorithm,
-+ struct algorithm *last);
-+
-+#define FOR_EACH_ALGORITHM(PROPOSAL, TYPE, ALGORITHM) \
-+ for (struct algorithm *ALGORITHM = next_algorithm(PROPOSAL, PROPOSAL_##TYPE, NULL); \
-+ ALGORITHM != NULL; ALGORITHM = next_algorithm(PROPOSAL, PROPOSAL_##TYPE, ALGORITHM))
-+
-+/*
-+ * Error indicated by err_buf[0] != '\0'.
-+ *
-+ * POLICY should be used to guard algorithm supported checks. For
-+ * instance: if POLICY=IKEV1, then IKEv1 support is required (IKEv2 is
-+ * don't care); and if POLICY=IKEV1|IKEV2, then both IKEv1 and IKEv2
-+ * support is required.
-+ *
-+ * Parsing with POLICY=IKEV1, but then proposing the result using
-+ * IKEv2 is a program error. The IKEv2 should complain loudly and,
-+ * we hope, not crash.
-+ *
-+ * Parsing with POLICY='0' is allowed. It will accept the algorithms
-+ * unconditionally (spi.c seems to need this).
-+ */
-+
-+struct proposals *proposals_from_str(struct proposal_parser *parser,
-+ const char *str);
-+
-+bool v1_proposals_parse_str(struct proposal_parser *parser,
-+ struct proposals *proposals,
-+ shunk_t alg_str);
-+bool v2_proposals_parse_str(struct proposal_parser *parser,
-+ struct proposals *proposals,
-+ shunk_t alg_str);
-+
-+/*
-+ * Check that encrypt==AEAD and/or integ==none don't contradict.
-+ */
-+bool proposal_aead_none_ok(struct proposal_parser *parser,
-+ const struct proposal *proposal);
-+
-+void proposal_error(struct proposal_parser *parser,
-+ const char *message, ...) PRINTF_LIKE(2);
-+
-+bool impair_proposal_errors(struct proposal_parser *parser);
-+
-+/*
-+ * Convert a generic proposal back into something the IKEv1 code can
-+ * digest.
-+ */
-+struct v1_proposal {
-+ int enckeylen;
-+ const struct encrypt_desc *encrypt;
-+ const struct prf_desc *prf;
-+ const struct integ_desc *integ;
-+ const struct oakley_group_desc *dh;
-+ const struct proposal_protocol *protocol;
-+};
-+
-+struct v1_proposal v1_proposal(const struct proposal *proposal);
-+
-+#endif /* PROPOSALS_H */
-diff -Naur libreswan-3.27-orig/include/shunk.h libreswan-3.27/include/shunk.h
---- libreswan-3.27-orig/include/shunk.h 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/include/shunk.h 2019-02-15 16:32:28.975835304 -0500
-@@ -1,7 +1,6 @@
--/*
-- * string fragments, for libreswan
-+/* constant string (octet) fragments, for libreswan
- *
-- * Copyright (C) 2018 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
-@@ -21,8 +20,15 @@
- #include /* size_t */
-
- /*
-- * shunk_t is a rip of of chunk_t, but with a character pointer. It
-- * is intended for string slicing.
-+ * Think of shunk_t and shunk_t as opposite solutions to the same
-+ * problem - carving up streams of octets:
-+ *
-+ * shunk_t's buffer is constant making it good for manipulating static
-+ * constant data (such as "a string"), chunk_t's is not.
-+ *
-+ * shunk_t's buffer is of type 'char' (which may or may not be signed)
-+ * making it easier to manipulate strings, chunk_t's is uint8_t making
-+ * it easier to manipulate raw bytes.
- */
-
- struct shunk {
-@@ -32,21 +38,49 @@
-
- typedef struct shunk shunk_t;
-
--extern const shunk_t empty_shunk;
-+/*
-+ * Just like for strings, an empty or zero length shunk such as
-+ * {.ptr="",.len = 0} should not be confused with the NULL shunk
-+ * (i.e., {.ptr=NULL,.len=0}).
-+ *
-+ * Use 'null_shunk' in initialisers. The only exception is static
-+ * initializers - which will get a compiler error - and NULL_SHUNK can
-+ * be used.
-+ */
-+
-+#define NULL_SHUNK { .ptr = NULL, .len = 0, }
-+extern const shunk_t null_shunk;
-
- shunk_t shunk1(const char *ptr); /* strlen() implied */
- shunk_t shunk2(const char *ptr, int len);
-
- /*
-- * shunk version of strsep() (which is like strtok())
-+ * A shunk version of strsep() (which is like strtok()) - split INPUT
-+ * in two using a character from the DELIM set.
-+ *
-+ * If INPUT contains a character from the DELIM set, return the
-+ * characters before the DELIM character as the next TOKEN, and set
-+ * INPUT to the sub-string following the DELIM character.
-+ *
-+ * If INPUT contains no character from the DELIM set, return INPUT as
-+ * the next TOKEN (possibly empty), and set INPUT to the null_shunk.
-+ *
-+ * If INPUT is the null_shunk, return the null_shunk as the next
-+ * TOKEN, string remains unchanged (still the null_shunk).
-+ *
-+ * One way to implement a simple parser is to use TOKEN.ptr==NULL as
-+ * an end-of-input indicator:
- *
-- * Split SHUNK in two using the DELIM set. Return a shunk of the
-- * characters up to but not including DELIM (or the entire string if
-- * DELIM isn't found. Update SHUNK to be one past DELIM.
-+ * shunk_t token = shunk_strsep(&input, ",");
-+ * while (token.ptr != NULL) {
-+ * ... process token ...
-+ * token = shunk_strsep(&input, ",");
-+ * }
- *
-- * XXX: should this return the DELIM?
-+ * XXX: Provided INPUT.ptr is non-NULL, INPUT.ptr[-1] is the DELIM
-+ * character; should this be made an explict parameter.
- */
--shunk_t shunk_strsep(shunk_t *shunk, const char *delim);
-+shunk_t shunk_strsep(shunk_t *input, const char *delim);
-
- /*
- * shunk version of string compare functions (or at least libreswan's
-diff -Naur libreswan-3.27-orig/lib/libswan/ah_info.c libreswan-3.27/lib/libswan/ah_info.c
---- libreswan-3.27-orig/lib/libswan/ah_info.c 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/lib/libswan/ah_info.c 2019-02-15 16:50:12.776728076 -0500
-@@ -22,50 +22,71 @@
-
- #include "lswalloc.h"
- #include "lswlog.h"
--#include "alg_info.h"
-+#include "proposals.h"
- #include "alg_byname.h"
- #include "lswfips.h"
-
- #include "ike_alg.h"
- #include "ike_alg_integ.h"
-
--static bool ah_proposal_ok(const struct proposal_parser *parser,
-- const struct proposal_info *proposal)
-+static bool ah_proposal_ok(struct proposal_parser *parser,
-+ const struct proposal *proposal)
- {
-- impaired_passert(PROPOSAL_PARSER, proposal->encrypt == NULL);
-- impaired_passert(PROPOSAL_PARSER, proposal->prf == NULL);
-- impaired_passert(PROPOSAL_PARSER, proposal->integ != NULL);
-+ impaired_passert(PROPOSAL_PARSER,
-+ next_algorithm(proposal, PROPOSAL_encrypt, NULL) == NULL);
-+ impaired_passert(PROPOSAL_PARSER,
-+ next_algorithm(proposal, PROPOSAL_prf, NULL) == NULL);
-+ impaired_passert(PROPOSAL_PARSER,
-+ next_algorithm(proposal, PROPOSAL_integ, NULL) != NULL);
-
- /* ah=null is invalid */
-- if (!IMPAIR(ALLOW_NULL_NONE) &&
-- proposal->integ == &ike_alg_integ_none) {
-- snprintf(parser->err_buf, parser->err_buf_len,
-- "AH cannot have 'none' as the integrity algorithm");
-- if (!impair_proposal_errors(parser)) {
-- return false;
-+ if (!IMPAIR(ALLOW_NULL_NONE)) {
-+ FOR_EACH_ALGORITHM(proposal, integ, alg) {
-+ /* passerts */
-+ const struct integ_desc *integ = integ_desc(alg->desc);
-+ if (integ == &ike_alg_integ_none) {
-+ proposal_error(parser, "AH cannot have 'none' as the integrity algorithm");
-+ if (!impair_proposal_errors(parser)) {
-+ return false;
-+ }
-+ }
- }
- }
-
- return true;
- }
-
--static const struct ike_alg *default_ah_integ[] = {
-+static const struct ike_alg *default_v1_ah_integ[] = {
- #ifdef USE_SHA1
- &ike_alg_integ_sha1.common,
- #endif
- NULL,
- };
-
--const struct proposal_defaults ah_defaults = {
-- .integ = default_ah_integ,
-+static const struct ike_alg *default_v2_ah_integ[] = {
-+#ifdef USE_SHA2
-+ &ike_alg_integ_sha2_512.common,
-+ &ike_alg_integ_sha2_256.common,
-+#endif
-+ NULL,
-+};
-+
-+const struct proposal_defaults v1_ah_defaults = {
-+ .integ = default_v1_ah_integ,
-+};
-+
-+const struct proposal_defaults v2_ah_defaults = {
-+ .integ = default_v2_ah_integ,
- };
-
- const struct proposal_protocol ah_proposal_protocol = {
- .name = "AH",
- .ikev1_alg_id = IKEv1_ESP_ID,
- .protoid = PROTO_IPSEC_AH,
-- .ikev1_defaults = &ah_defaults,
-- .ikev2_defaults = &ah_defaults,
-+ .defaults = {
-+ [IKEv1] = &v1_ah_defaults,
-+ [IKEv2] = &v2_ah_defaults,
-+ },
- .proposal_ok = ah_proposal_ok,
- .integ_alg_byname = integ_alg_byname,
- .dh_alg_byname = dh_alg_byname,
-@@ -77,7 +98,7 @@
- * parser configuration - encryption isn't allowed.
- *
- * ??? the only difference between
-- * alg_info_ah_create_from_str and alg_info_esp_create_from_str
-+ * ah_proposals_create_from_str and alg_info_esp_create_from_str
- * is in the second argument to proposal_parser.
- *
- * XXX: On the other hand, since "struct ike_info" and "struct
-@@ -87,33 +108,7 @@
-
- /* This function is tested in testing/algparse/algparse.c */
-
--struct alg_info_esp *alg_info_ah_create_from_str(const struct proposal_policy *policy,
-- const char *alg_str,
-- char *err_buf, size_t err_buf_len)
-+struct proposal_parser *ah_proposal_parser(const struct proposal_policy *policy)
- {
-- shunk_t string = shunk1(alg_str);
-- const struct proposal_parser parser = proposal_parser(policy,
-- &ah_proposal_protocol,
-- err_buf, err_buf_len);
--
-- /*
-- * alg_info storage should be sized dynamically
-- * but this may require two passes to know
-- * transform count in advance.
-- */
-- struct alg_info_esp *alg_info_ah = alloc_thing(struct alg_info_esp, "alg_info_ah");
--
-- if (!alg_info_parse_str(&parser, &alg_info_ah->ai, string)) {
-- passert(err_buf[0] != '\0');
-- alg_info_free(&alg_info_ah->ai);
-- return NULL;
-- }
--
-- if (!alg_info_pfs_vs_dh_check(&parser, alg_info_ah)) {
-- passert(err_buf[0] != '\0');
-- alg_info_free(&alg_info_ah->ai);
-- return NULL;
-- }
--
-- return alg_info_ah;
-+ return alloc_proposal_parser(policy, &ah_proposal_protocol);
- }
-diff -Naur libreswan-3.27-orig/lib/libswan/alg_byname.c libreswan-3.27/lib/libswan/alg_byname.c
---- libreswan-3.27-orig/lib/libswan/alg_byname.c 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/lib/libswan/alg_byname.c 2019-02-15 16:32:28.976835314 -0500
-@@ -17,11 +17,11 @@
- #include
-
- #include "lswlog.h"
--#include "alg_info.h"
-+#include "proposals.h"
- #include "alg_byname.h"
- #include "ike_alg.h"
-
--bool alg_byname_ok(const struct proposal_parser *parser,
-+bool alg_byname_ok(struct proposal_parser *parser,
- const struct ike_alg *alg, shunk_t print_name)
- {
- const struct proposal_protocol *protocol = parser->protocol;
-@@ -30,19 +30,27 @@
- * If the connection is IKEv1|IKEv2 then this code will
- * exclude anything not supported by both protocols.
- */
-- if (policy->ikev1 && alg->id[protocol->ikev1_alg_id] < 0) {
-- snprintf(parser->err_buf, parser->err_buf_len,
-- "%s %s algorithm '"PRI_SHUNK"' is not supported by IKEv1",
-- protocol->name, ike_alg_type_name(alg->algo_type),
-- PRI_shunk(print_name));
-- return false;
-- }
-- if (policy->ikev2 && alg->id[IKEv2_ALG_ID] < 0) {
-- snprintf(parser->err_buf, parser->err_buf_len,
-- "%s %s algorithm '"PRI_SHUNK"' is not supported by IKEv2",
-- protocol->name, ike_alg_type_name(alg->algo_type),
-- PRI_shunk(print_name));
-- return false;
-+ switch (policy->version) {
-+ case IKEv1:
-+ /* IKEv1 has different IDs for ESP/IKE/AH */
-+ if (alg->id[protocol->ikev1_alg_id] < 0) {
-+ proposal_error(parser, "%s %s algorithm '"PRI_SHUNK"' is not supported by IKEv1",
-+ protocol->name, ike_alg_type_name(alg->algo_type),
-+ PRI_shunk(print_name));
-+ return false;
-+ }
-+ break;
-+ case IKEv2:
-+ if (alg->id[IKEv2_ALG_ID] < 0) {
-+ proposal_error(parser, "%s %s algorithm '"PRI_SHUNK"' is not supported by IKEv2",
-+ protocol->name, ike_alg_type_name(alg->algo_type),
-+ PRI_shunk(print_name));
-+ return false;
-+ }
-+ break;
-+ default:
-+ /* ignore */
-+ break;
- }
- /*
- * According to parser policy, is the algorithm "implemented"?
-@@ -54,10 +62,9 @@
- */
- passert(policy->alg_is_ok != NULL);
- if (!policy->alg_is_ok(alg)) {
-- snprintf(parser->err_buf, parser->err_buf_len,
-- "%s %s algorithm '"PRI_SHUNK"' is not supported",
-- protocol->name, ike_alg_type_name(alg->algo_type),
-- PRI_shunk(print_name));
-+ proposal_error(parser, "%s %s algorithm '"PRI_SHUNK"' is not supported",
-+ protocol->name, ike_alg_type_name(alg->algo_type),
-+ PRI_shunk(print_name));
- return false;
- }
- /*
-@@ -69,16 +76,15 @@
- * Since it likely involves a lookup, it is left until last.
- */
- if (!ike_alg_is_valid(alg)) {
-- snprintf(parser->err_buf, parser->err_buf_len,
-- "%s %s algorithm '"PRI_SHUNK"' is not valid",
-- protocol->name, ike_alg_type_name(alg->algo_type),
-- PRI_shunk(print_name));
-+ proposal_error(parser, "%s %s algorithm '"PRI_SHUNK"' is not valid",
-+ protocol->name, ike_alg_type_name(alg->algo_type),
-+ PRI_shunk(print_name));
- return false;
- }
- return true;
- }
-
--static const struct ike_alg *alg_byname(const struct proposal_parser *parser,
-+static const struct ike_alg *alg_byname(struct proposal_parser *parser,
- const struct ike_alg_type *type,
- shunk_t name, shunk_t print_name)
- {
-@@ -91,15 +97,14 @@
- */
- if (ike_alg_enum_match(type, protocol->ikev1_alg_id, name) >= 0 ||
- ike_alg_enum_match(type, IKEv2_ALG_ID, name) >= 0) {
-- snprintf(parser->err_buf, parser->err_buf_len,
-- "%s %s algorithm '"PRI_SHUNK"' is not supported",
-- protocol->name, ike_alg_type_name(type),
-- PRI_shunk(print_name));
-+ proposal_error(parser, "%s %s algorithm '"PRI_SHUNK"' is not supported",
-+ protocol->name, ike_alg_type_name(type),
-+ PRI_shunk(print_name));
-+
- } else {
-- snprintf(parser->err_buf, parser->err_buf_len,
-- "%s %s algorithm '"PRI_SHUNK"' is not recognized",
-- protocol->name, ike_alg_type_name(type),
-- PRI_shunk(print_name));
-+ proposal_error(parser, "%s %s algorithm '"PRI_SHUNK"' is not recognized",
-+ protocol->name, ike_alg_type_name(type),
-+ PRI_shunk(print_name));
- }
- return NULL;
- }
-@@ -108,14 +113,14 @@
- * Does it pass muster?
- */
- if (!alg_byname_ok(parser, alg, print_name)) {
-- passert(parser->err_buf[0] != '\0');
-+ passert(parser->error[0] != '\0');
- return NULL;
- }
-
- return alg;
- }
-
--const struct ike_alg *encrypt_alg_byname(const struct proposal_parser *parser,
-+const struct ike_alg *encrypt_alg_byname(struct proposal_parser *parser,
- shunk_t name, size_t key_bit_length,
- shunk_t print_name)
- {
-@@ -127,10 +132,9 @@
- const struct encrypt_desc *encrypt = encrypt_desc(alg);
- if (!IMPAIR(SEND_KEY_SIZE_CHECK) && key_bit_length > 0) {
- if (encrypt->keylen_omitted) {
-- snprintf(parser->err_buf, parser->err_buf_len,
-- "%s does not take variable key lengths",
-- enum_short_name(&ikev2_trans_type_encr_names,
-- encrypt->common.id[IKEv2_ALG_ID]));
-+ proposal_error(parser, "%s does not take variable key lengths",
-+ enum_short_name(&ikev2_trans_type_encr_names,
-+ encrypt->common.id[IKEv2_ALG_ID]));
- if (!impair_proposal_errors(parser)) {
- return NULL;
- }
-@@ -141,8 +145,7 @@
- * should instead generate a real list from
- * encrypt.
- */
-- snprintf(parser->err_buf, parser->err_buf_len,
-- "wrong encryption key length - key size must be 128 (default), 192 or 256");
-+ proposal_error(parser, "wrong encryption key length - key size must be 128 (default), 192 or 256");
- if (!impair_proposal_errors(parser)) {
- return NULL;
- }
-@@ -151,21 +154,21 @@
- return alg;
- }
-
--const struct ike_alg *prf_alg_byname(const struct proposal_parser *parser,
-+const struct ike_alg *prf_alg_byname(struct proposal_parser *parser,
- shunk_t name, size_t key_bit_length UNUSED,
- shunk_t print_name)
- {
- return alg_byname(parser, IKE_ALG_PRF, name, print_name);
- }
-
--const struct ike_alg *integ_alg_byname(const struct proposal_parser *parser,
-+const struct ike_alg *integ_alg_byname(struct proposal_parser *parser,
- shunk_t name, size_t key_bit_length UNUSED,
- shunk_t print_name)
- {
- return alg_byname(parser, IKE_ALG_INTEG, name, print_name);
- }
-
--const struct ike_alg *dh_alg_byname(const struct proposal_parser *parser,
-+const struct ike_alg *dh_alg_byname(struct proposal_parser *parser,
- shunk_t name, size_t key_bit_length UNUSED,
- shunk_t print_name)
- {
-diff -Naur libreswan-3.27-orig/lib/libswan/alg_info.c libreswan-3.27/lib/libswan/alg_info.c
---- libreswan-3.27-orig/lib/libswan/alg_info.c 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/lib/libswan/alg_info.c 1969-12-31 19:00:00.000000000 -0500
-@@ -1,884 +0,0 @@
--/*
-- * Algorithm info parsing and creation functions
-- * Author: JuanJo Ciarlante
-- *
-- * Copyright (C) 2012 Paul Wouters
-- * Copyright (C) 2015-2018 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
--#include
--#include
--
--#include "lswlog.h"
--#include "lswalloc.h"
--#include "constants.h"
--#include "alg_info.h"
--#include "ike_alg.h"
--#include "ike_alg_integ.h"
--#include "ike_alg_dh.h"
--#include "alg_byname.h"
--
--/*
-- * Add the proposal defaults for the specific algorithm.
-- */
--
--typedef struct proposal_info merge_alg_default_t(struct proposal_info proposal,
-- const struct ike_alg *default_alg);
--
--static struct proposal_info merge_dh_default(struct proposal_info proposal,
-- const struct ike_alg *default_alg)
--{
-- proposal.dh = oakley_group_desc(default_alg);
-- return proposal;
--}
--
--static struct proposal_info merge_encrypt_default(struct proposal_info proposal,
-- const struct ike_alg *default_alg)
--{
-- proposal.encrypt = encrypt_desc(default_alg);
-- return proposal;
--}
--
--static struct proposal_info merge_prf_default(struct proposal_info proposal,
-- const struct ike_alg *default_alg)
--{
-- proposal.prf = prf_desc(default_alg);
-- return proposal;
--}
--
--static struct proposal_info merge_integ_default(struct proposal_info proposal,
-- const struct ike_alg *default_alg)
--{
-- proposal.integ = integ_desc(default_alg);
-- return proposal;
--}
--
--static bool add_proposal_defaults(const struct proposal_parser *parser,
-- const struct proposal_defaults *defaults,
-- struct alg_info *alg_info,
-- const struct proposal_info *proposal);
--
--static bool add_alg_defaults(const struct proposal_parser *parser,
-- const struct proposal_defaults *defaults,
-- struct alg_info *alg_info,
-- const struct proposal_info *proposal,
-- const struct ike_alg_type *type,
-- const struct ike_alg **default_algs,
-- merge_alg_default_t *merge_alg_default)
--{
-- /*
-- * Use VALID_ALG to add the valid algorithms into VALID_ALGS.
-- */
-- for (const struct ike_alg **default_alg = default_algs;
-- *default_alg; default_alg++) {
-- const struct ike_alg *alg = *default_alg;
-- if (!alg_byname_ok(parser, alg,
-- shunk1(alg->name))) {
-- DBG(DBG_PROPOSAL_PARSER,
-- DBG_log("skipping default %s",
-- parser->err_buf));
-- parser->err_buf[0] = '\0';
-- continue;
-- }
-- /* add it */
-- DBG(DBG_PROPOSAL_PARSER,
-- DBG_log("adding default %s %s",
-- ike_alg_type_name(type),
-- alg->name));
-- struct proposal_info merged_proposal = merge_alg_default(*proposal,
-- *default_alg);
-- if (!add_proposal_defaults(parser, defaults,
-- alg_info, &merged_proposal)) {
-- passert(parser->err_buf[0] != '\0');
-- return false;
-- }
-- }
-- return true;
--}
--
--/*
-- * Validate the proposal and, suppressing duplicates, add it to the
-- * proposal list.
-- */
--
--static bool add_proposal(const struct proposal_parser *parser,
-- struct alg_info *alg_info,
-- const struct proposal_info *proposal)
--{
-- /* duplicate? */
-- FOR_EACH_PROPOSAL_INFO(alg_info, existing_proposal) {
-- /*
-- * key length 0 is like a wild-card (it actually means
-- * propose default and strongest key lengths) so if
-- * either is zero just treat it as a match.
-- */
-- if (existing_proposal->encrypt == proposal->encrypt &&
-- existing_proposal->prf == proposal->prf &&
-- existing_proposal->integ == proposal->integ &&
-- existing_proposal->dh == proposal->dh &&
-- (existing_proposal->enckeylen == proposal->enckeylen ||
-- existing_proposal->enckeylen == 0 ||
-- proposal->enckeylen == 0)) {
-- if (IMPAIR(PROPOSAL_PARSER)) {
-- libreswan_log("IMPAIR: including duplicate %s proposal encrypt=%s enckeylen=%zu prf=%s integ=%s dh=%s",
-- proposal->protocol->name,
-- proposal->encrypt != NULL ? proposal->encrypt->common.name : "n/a",
-- proposal->enckeylen,
-- proposal->prf != NULL ? proposal->prf->common.name : "n/a",
-- proposal->integ != NULL ? proposal->integ->common.name : "n/a",
-- proposal->dh != NULL ? proposal->dh->common.name : "n/a");
-- } else {
-- DBG(DBG_CRYPT,
-- DBG_log("discarding duplicate %s proposal encrypt=%s enckeylen=%zu prf=%s integ=%s dh=%s",
-- proposal->protocol->name,
-- proposal->encrypt != NULL ? proposal->encrypt->common.name : "n/a",
-- proposal->enckeylen,
-- proposal->prf != NULL ? proposal->prf->common.name : "n/a",
-- proposal->integ != NULL ? proposal->integ->common.name : "n/a",
-- proposal->dh != NULL ? proposal->dh->common.name : "n/a"));
-- return true;
-- }
-- }
-- }
--
-- /* Overflow? */
-- if ((unsigned)alg_info->alg_info_cnt >= elemsof(alg_info->proposals)) {
-- snprintf(parser->err_buf, parser->err_buf_len,
-- "more than %zu %s algorithms specified",
-- elemsof(alg_info->proposals),
-- proposal->protocol->name);
-- /* drop it like a rock */
-- return false;
-- }
--
-- /* back end? */
-- if (!proposal->protocol->proposal_ok(parser, proposal)) {
-- return false;
-- }
--
-- alg_info->proposals[alg_info->alg_info_cnt++] = *proposal;
-- return true;
--}
--
--/*
-- * For all the algorithms, when an algorithm is missing (NULL), and
-- * there are defaults, add them.
-- */
--
--static bool add_proposal_defaults(const struct proposal_parser *parser,
-- const struct proposal_defaults *defaults,
-- struct alg_info *alg_info,
-- const struct proposal_info *proposal)
--{
-- /*
-- * Note that the order in which things are recursively added -
-- * MODP, ENCR, PRF/HASH - affects test results. It determines
-- * things like the order of proposals.
-- */
-- if (proposal->dh == NULL &&
-- defaults != NULL && defaults->dh != NULL) {
-- return add_alg_defaults(parser, defaults,
-- alg_info, proposal,
-- &ike_alg_dh, defaults->dh,
-- merge_dh_default);
-- } else if (proposal->encrypt == NULL &&
-- defaults != NULL && defaults->encrypt != NULL) {
-- return add_alg_defaults(parser, defaults,
-- alg_info, proposal,
-- &ike_alg_encrypt, defaults->encrypt,
-- merge_encrypt_default);
-- } else if (proposal->prf == NULL &&
-- defaults != NULL && defaults->prf != NULL) {
-- return add_alg_defaults(parser, defaults,
-- alg_info, proposal,
-- &ike_alg_prf, defaults->prf,
-- merge_prf_default);
-- } else if (proposal->integ == NULL &&
-- proposal->encrypt != NULL &&
-- encrypt_desc_is_aead(proposal->encrypt)) {
-- /*
-- * Since AEAD, integrity is always 'none'.
-- */
-- struct proposal_info merged_proposal = *proposal;
-- merged_proposal.integ = &ike_alg_integ_none;
-- return add_proposal_defaults(parser, defaults,
-- alg_info, &merged_proposal);
-- } else if (proposal->integ == NULL &&
-- defaults != NULL && defaults->integ != NULL) {
-- return add_alg_defaults(parser, defaults,
-- alg_info, proposal,
-- &ike_alg_integ, defaults->integ,
-- merge_integ_default);
-- } else if (proposal->integ == NULL &&
-- proposal->prf != NULL &&
-- proposal->encrypt != NULL &&
-- !encrypt_desc_is_aead(proposal->encrypt)) {
-- /*
-- * Since non-AEAD, use an integrity algorithm that is
-- * implemented using the PRF.
-- */
-- struct proposal_info merged_proposal = *proposal;
-- for (const struct integ_desc **algp = next_integ_desc(NULL);
-- algp != NULL; algp = next_integ_desc(algp)) {
-- const struct integ_desc *alg = *algp;
-- if (alg->prf == proposal->prf) {
-- merged_proposal.integ = alg;
-- break;
-- }
-- }
-- if (merged_proposal.integ == NULL) {
-- snprintf(parser->err_buf, parser->err_buf_len,
-- "%s integrity derived from PRF '%s' is not supported",
-- proposal->protocol->name,
-- proposal->prf->common.name);
-- return false;
-- }
-- return add_proposal_defaults(parser, defaults,
-- alg_info, &merged_proposal);
-- } else {
-- return add_proposal(parser, alg_info, proposal);
-- }
--}
--
--static bool merge_default_proposals(const struct proposal_parser *parser,
-- struct alg_info *alg_info,
-- const struct proposal_info *proposal)
--{
-- /*
-- * If there's a hint of IKEv1 being enabled then prefer its
-- * larger set of defaults.
-- *
-- * This should increase the odds of both ends interoperating.
-- *
-- * For instance, the IKEv2 defaults were preferred and one end
-- * has ikev2=never then, in aggressive mode, things don't
-- * work.
-- */
-- const struct proposal_defaults *defaults = (parser->policy->ikev1
-- ? proposal->protocol->ikev1_defaults
-- : proposal->protocol->ikev2_defaults);
-- return add_proposal_defaults(parser, defaults,
-- alg_info, proposal);
--}
--
--static const struct ike_alg *lookup_byname(const struct proposal_parser *parser,
-- alg_byname_fn *alg_byname,
-- shunk_t name,
-- size_t key_bit_length,
-- shunk_t print_name,
-- const char *what)
--{
-- if (name.len > 0) {
-- if (alg_byname != NULL) {
-- const struct ike_alg *alg = alg_byname(parser, name, key_bit_length,
-- print_name);
-- if (alg == NULL) {
-- DBG(DBG_PROPOSAL_PARSER,
-- DBG_log("%s_byname('"PRI_SHUNK"') failed: %s",
-- what, PRI_shunk(name),
-- parser->err_buf));
-- passert(parser->err_buf[0] != '\0');
-- return NULL;
-- }
-- DBG(DBG_PROPOSAL_PARSER,
-- DBG_log("%s_byname('"PRI_SHUNK"') returned '%s'",
-- what, PRI_shunk(name), alg->name));
-- return alg;
-- } else {
-- DBG(DBG_PROPOSAL_PARSER,
-- DBG_log("ignoring %s '"PRI_SHUNK"'",
-- what, PRI_shunk(name)));
-- return NULL;
-- }
-- }
-- return NULL;
--}
--
--static int parse_eklen(char *err_buf, size_t err_buf_len,
-- shunk_t buf)
--{
-- /* convert - if present */
-- char *end = NULL;
-- long eklen = strtol(buf.ptr, &end, 10);
-- if (buf.ptr + buf.len != end) {
-- snprintf(err_buf, err_buf_len,
-- "encryption key length '"PRI_SHUNK"' contains a non-numeric character",
-- PRI_shunk(buf));
-- return 0;
-- }
-- if (eklen >= INT_MAX) {
-- snprintf(err_buf, err_buf_len,
-- "encryption key length '"PRI_SHUNK"' WAY too big",
-- PRI_shunk(buf));
-- return 0;
-- }
-- if (eklen == 0) {
-- snprintf(err_buf, err_buf_len,
-- "encryption key length is zero");
-- return 0;
-- }
-- return eklen;
--}
--
--/*
-- * Try to parse any of -, _,
-- * , or . Strings like aes_gcm_16 and
-- * aes_gcm_16_256 end up in alg[0], while strings like aes_gcm_16-256
-- * end up in alg[0]-alg[1].
-- */
--
--struct token {
-- char sep;
-- shunk_t alg;
--};
--
--static bool parse_encrypt(const struct proposal_parser *parser,
-- struct token **tokens,
-- struct proposal_info *proposal)
--{
-- shunk_t ealg = (*tokens)[0].alg;
-- shunk_t eklen = (*tokens)[1].alg;
-- if (eklen.len > 0 && isdigit(eklen.ptr[0])) {
-- /* assume - */
-- int enckeylen = parse_eklen(parser->err_buf,
-- parser->err_buf_len,
-- eklen);
-- if (enckeylen <= 0) {
-- passert(parser->err_buf[0] != '\0');
-- return false;
-- }
-- /* print - */
-- shunk_t print_name = shunk2(ealg.ptr, eklen.ptr + eklen.len - ealg.ptr);
-- proposal->enckeylen = enckeylen;
-- proposal->encrypt =
-- encrypt_desc(lookup_byname(parser,
-- encrypt_alg_byname,
-- ealg, proposal->enckeylen,
-- print_name, "encryption"));
-- /* Was - rejected? */
-- if (parser->err_buf[0] != '\0') {
-- return false;
-- }
-- *tokens += 2; /* consume both tokens */
-- return true;
-- }
-- /* try */
-- shunk_t print_name = ealg;
-- proposal->encrypt =
-- encrypt_desc(lookup_byname(parser,
-- encrypt_alg_byname,
-- ealg, proposal->enckeylen,
-- print_name, "encryption"));
-- if (parser->err_buf[0] != '\0') {
-- /*
-- * Could it be or _? Work
-- * backwards skipping any digits.
-- */
-- shunk_t end = shunk2(ealg.ptr + ealg.len, 0);
-- while (end.ptr > ealg.ptr && isdigit(end.ptr[-1])) {
-- end.ptr--;
-- end.len++;
-- }
-- if (end.len == 0) {
-- /*
-- * no trailing and was rejected
-- */
-- passert(parser->err_buf[0] != '\0');
-- return false;
-- }
-- /* try to convert */
-- int enckeylen = parse_eklen(parser->err_buf, parser->err_buf_len, end);
-- if (enckeylen <= 0) {
-- passert(parser->err_buf[0] != '\0');
-- return false;
-- }
-- proposal->enckeylen = enckeylen;
-- /*
-- * trim from ; and then trim any
-- * trailing '_'
-- */
-- ealg.len = end.ptr - ealg.ptr;
-- if (end.ptr > ealg.ptr && end.ptr[-1] == '_') {
-- ealg.len -= 1;
-- }
-- /* try again */
-- parser->err_buf[0] = '\0';
-- proposal->encrypt =
-- encrypt_desc(lookup_byname(parser,
-- encrypt_alg_byname,
-- ealg, proposal->enckeylen,
-- print_name, "encryption"));
-- if (parser->err_buf[0] != '\0') {
-- return false;
-- }
-- }
-- *tokens += 1; /* consume one token */
-- return true;
--}
--
--static bool parser_alg_info_add(const struct proposal_parser *parser,
-- struct token *tokens, struct proposal_info proposal,
-- struct alg_info *alg_info)
--{
-- LSWDBGP(DBG_PROPOSAL_PARSER, buf) {
-- lswlogs(buf, "algs:");
-- for (struct token *token = tokens; token->alg.ptr != NULL; token++) {
-- lswlogf(buf, " algs[%tu] = '"PRI_SHUNK"'",
-- token - tokens, PRI_shunk(token->alg));
-- }
-- }
--
-- bool lookup_encrypt = parser->protocol->encrypt_alg_byname != NULL;
-- if (!lookup_encrypt && IMPAIR(PROPOSAL_PARSER)) {
-- /* Force lookup, will discard any error. */
-- lookup_encrypt = true;
-- }
-- if (lookup_encrypt && tokens->alg.ptr != NULL && tokens->sep != ';') {
-- if (!parse_encrypt(parser, &tokens, &proposal)) {
-- if (IMPAIR(PROPOSAL_PARSER)) {
-- /* ignore the lookup and stumble on */
-- parser->err_buf[0] = '\0';
-- } else {
-- passert(parser->err_buf[0] != '\0');
-- return false;
-- }
-- }
-- }
--
-- bool lookup_prf = parser->protocol->prf_alg_byname != NULL;
-- if (!lookup_prf && IMPAIR(PROPOSAL_PARSER)) {
-- /*
-- * Force PRF lookup when the folloing token looks like
-- * an INTEG algorithm (i.e., its lookup succeeds).
-- * Otherwise something like ah=sha1 gets parsed as
-- * ah=[encr]-sha1-[integ]-[dh].
-- */
-- shunk_t prf = tokens[0].alg;
-- shunk_t integ = tokens[1].alg;
-- if (prf.ptr != NULL && integ.ptr != NULL) {
-- lookup_prf = (lookup_byname(parser, integ_alg_byname,
-- integ, 0, integ, "integrity")
-- != NULL);
-- parser->err_buf[0] = '\0';
-- }
-- }
-- if (lookup_prf && tokens->alg.ptr != NULL && tokens->sep != ';') {
-- shunk_t prf = tokens[0].alg;
-- proposal.prf = prf_desc(lookup_byname(parser,
-- prf_alg_byname,
-- prf, 0, prf, "PRF"));
-- if (parser->err_buf[0] != '\0') {
-- return false;
-- }
-- tokens += 1; /* consume one arg */
-- }
--
-- bool lookup_integ = parser->protocol->integ_alg_byname != NULL;
-- if (!lookup_integ && IMPAIR(PROPOSAL_PARSER)) {
-- /* force things */
-- lookup_integ = true;
-- }
-- if (lookup_integ && tokens->alg.ptr != NULL && tokens->sep != ';') {
-- shunk_t integ = tokens[0].alg;
-- proposal.integ = integ_desc(lookup_byname(parser,
-- integ_alg_byname,
-- integ, 0, integ, "integrity"));
-- if (parser->err_buf[0] != '\0') {
-- if (tokens[1].alg.ptr != NULL) {
-- /*
-- * This alg should have been
-- * integrity, since the next would be
-- * DH; error applies.
-- */
-- passert(parser->err_buf[0] != '\0');
-- return false;
-- }
-- if (tokens[1].alg.ptr == NULL &&
-- parser->protocol->prf_alg_byname == NULL) {
-- /*
-- * Only one arg, integrity is prefered
-- * to DH (and no PRF); error applies.
-- */
-- passert(parser->err_buf[0] != '\0');
-- return false;
-- }
-- /* let DH try */
-- parser->err_buf[0] = '\0';
-- } else {
-- tokens += 1; /* consume one arg */
-- }
-- }
--
-- bool lookup_dh = parser->protocol->dh_alg_byname || IMPAIR(PROPOSAL_PARSER);
-- if (lookup_dh && tokens->alg.ptr != NULL) {
-- shunk_t dh = tokens[0].alg;
-- proposal.dh = oakley_group_desc(lookup_byname(parser,
-- dh_alg_byname,
-- dh, 0,
-- dh, "DH"));
-- if (parser->err_buf[0] != '\0') {
-- return false;
-- }
-- tokens += 1; /* consume one arg */
-- }
--
-- if (tokens->alg.ptr != NULL) {
-- snprintf(parser->err_buf, parser->err_buf_len,
-- "'"PRI_SHUNK"' unexpected",
-- PRI_shunk(tokens[0].alg));
-- return false;
-- }
--
-- if (IMPAIR(PROPOSAL_PARSER)) {
-- return add_proposal(parser, alg_info, &proposal);
-- } else {
-- return merge_default_proposals(parser, alg_info, &proposal);
-- }
--}
--
--
--bool alg_info_parse_str(const struct proposal_parser *parser,
-- struct alg_info *alg_info,
-- shunk_t alg_str)
--{
-- DBG(DBG_PROPOSAL_PARSER,
-- DBG_log("parsing '"PRI_SHUNK"' for %s",
-- PRI_shunk(alg_str), parser->protocol->name));
--
-- /* use default if no string */
-- if (alg_str.ptr == NULL) {
-- const struct proposal_info proposal = {
-- .protocol = parser->protocol,
-- };
-- return merge_default_proposals(parser, alg_info, &proposal);
-- }
--
-- if (alg_str.len == 0) {
-- /* XXX: hack to keep testsuite happy */
-- snprintf(parser->err_buf, parser->err_buf_len,
-- "String ended with invalid char, just after \"\"");
-- return false;
-- }
--
-- shunk_t prop_ptr = alg_str;
-- do {
-- /* find the next proposal */
-- shunk_t prop = shunk_strsep(&prop_ptr, ",");
-- /* parse it */
-- struct token tokens[8];
-- zero(&tokens);
-- struct token *token = tokens;
-- char last_sep = '\0';
-- shunk_t alg_ptr = prop;
-- do {
-- if (token + 1 >= tokens+elemsof(tokens)) {
-- /* space for NULL? */
-- snprintf(parser->err_buf, parser->err_buf_len,
-- "proposal too long");
-- return false;
-- }
-- /* find the next alg */
-- shunk_t alg = shunk_strsep(&alg_ptr, "-;,");
-- *token++ = (struct token) {
-- .alg = alg,
-- .sep = last_sep,
-- };
-- last_sep = alg.ptr[alg.len]; /* save separator */
-- } while (alg_ptr.len > 0);
-- struct proposal_info proposal = {
-- .protocol = parser->protocol,
-- };
-- if (!parser_alg_info_add(parser, tokens, proposal,
-- alg_info)) {
-- passert(parser->err_buf[0] != '\0');
-- return false;
-- }
-- } while (prop_ptr.len > 0);
-- return true;
--}
--
--struct proposal_parser proposal_parser(const struct proposal_policy *policy,
-- const struct proposal_protocol *protocol,
-- char *err_buf, size_t err_buf_len)
--{
-- const struct proposal_parser parser = {
-- .policy = policy,
-- .protocol = protocol,
-- .err_buf = err_buf,
-- .err_buf_len = err_buf_len,
-- };
-- err_buf[0] = '\0';
-- return parser;
--}
--
--bool proposal_aead_none_ok(const struct proposal_parser *parser,
-- const struct proposal_info *proposal)
--{
-- if (IMPAIR(ALLOW_NULL_NONE)) {
-- return true;
-- }
--
-- if (proposal->encrypt != NULL &&
-- encrypt_desc_is_aead(proposal->encrypt) &&
-- proposal->integ != NULL &&
-- proposal->integ != &ike_alg_integ_none) {
-- /*
-- * For instance, esp=aes_gcm-sha1" is invalid.
-- */
-- snprintf(parser->err_buf, parser->err_buf_len,
-- "AEAD %s encryption algorithm '%s' must have 'none' as the integrity algorithm",
-- proposal->protocol->name,
-- proposal->encrypt->common.name);
-- return false;
-- }
--
-- if (proposal->encrypt != NULL &&
-- !encrypt_desc_is_aead(proposal->encrypt) &&
-- proposal->integ != NULL &&
-- proposal->integ == &ike_alg_integ_none) {
-- /*
-- * For instance, esp=aes_cbc-none" is invalid.
-- */
-- snprintf(parser->err_buf, parser->err_buf_len,
-- "non-AEAD %s encryption algorithm '%s' cannot have 'none' as the integrity algorithm",
-- proposal->protocol->name,
-- proposal->encrypt->common.name);
-- return false;
-- }
--
-- return true;
--}
--
--/*
-- * alg_info struct can be shared by several connections instances,
-- * handle free() with ref_cnts.
-- *
-- * Use alg_info_free() if the value returned by *_parse_str() is found
-- * to be (semantically) bogus.
-- */
--
--void alg_info_free(struct alg_info *alg_info)
--{
-- passert(alg_info);
-- passert(alg_info->ref_cnt == 0);
-- pfree(alg_info);
--}
--
--void alg_info_addref(struct alg_info *alg_info)
--{
-- alg_info->ref_cnt++;
--}
--
--void alg_info_delref(struct alg_info *alg_info)
--{
-- passert(alg_info->ref_cnt != 0);
-- alg_info->ref_cnt--;
-- if (alg_info->ref_cnt == 0)
-- alg_info_free(alg_info);
--}
--
--size_t lswlog_proposal_info(struct lswlog *log,
-- const struct proposal_info *proposal)
--{
-- size_t size = 0;
-- const char *sep = "";
--
-- if (proposal->encrypt != NULL) {
-- size += lswlogs(log, sep); sep = "-";
-- size += lswlogs(log, proposal->encrypt->common.fqn);
-- if (proposal->enckeylen != 0) {
-- size += lswlogf(log, "_%zd", proposal->enckeylen);
-- }
-- } else if (IMPAIR(PROPOSAL_PARSER)) {
-- size += lswlogs(log, sep); sep = "-";
-- size += lswlogs(log, "[ENCRYPT]");
-- }
--
-- if (proposal->prf != NULL) {
-- size += lswlogs(log, sep); sep = "-";
-- size += lswlogs(log, proposal->prf->common.fqn);
-- } else if (IMPAIR(PROPOSAL_PARSER)) {
-- size += lswlogs(log, sep); sep = "-";
-- size += lswlogs(log, "[PRF]");
-- }
--
-- if (proposal->integ != NULL && proposal->prf == NULL) {
-- size += lswlogs(log, sep); sep = "-";
-- size += lswlogs(log, proposal->integ->common.fqn);
-- } else if (!(proposal->integ == &ike_alg_integ_none &&
-- encrypt_desc_is_aead(proposal->encrypt)) &&
-- proposal->integ != NULL && proposal->integ->prf != proposal->prf) {
-- size += lswlogs(log, sep); sep = "-";
-- size += lswlogs(log, proposal->integ->common.fqn);
-- } else if (IMPAIR(PROPOSAL_PARSER)) {
-- size += lswlogs(log, sep); sep = "-";
-- if (proposal->integ != NULL) {
-- size += lswlogs(log, proposal->integ->common.fqn);
-- } else {
-- size += lswlogs(log, "[INTEG]");
-- }
-- }
--
-- if (proposal->dh != NULL) {
-- size += lswlogs(log, sep); sep = "-"; /* sep not subsequently used */
-- size += lswlogs(log, proposal->dh->common.fqn);
-- } else if (IMPAIR(PROPOSAL_PARSER)) {
-- size += lswlogs(log, sep); sep = "-"; /* sep not subsequently used */
-- size += lswlogs(log, "[DH]");
-- }
--
-- return size;
--}
--
--size_t lswlog_alg_info(struct lswlog *log, const struct alg_info *alg_info)
--{
-- size_t size = 0;
-- const char *sep = "";
-- FOR_EACH_PROPOSAL_INFO(alg_info, proposal) {
-- size += lswlogs(log, sep);
-- size += lswlog_proposal_info(log, proposal);
-- sep = ", ";
-- }
-- return size;
--}
--
--/*
-- * When PFS=no ignore any DH algorithms, and when PFS=yes reject
-- * mixing implict and explicit DH.
-- */
--bool alg_info_pfs_vs_dh_check(const struct proposal_parser *parser,
-- struct alg_info_esp *aie)
--{
-- if (aie->ai.alg_info_cnt <= 0) {
-- /* let caller deal with no proposals. */
-- return true;
-- }
--
-- /* scrape the proposals for dh algorithms */
-- struct proposal_info *first_null = NULL;
-- struct proposal_info *first_dh = NULL;
-- struct proposal_info *second_dh = NULL;
-- struct proposal_info *first_none = NULL;
-- FOR_EACH_ESP_INFO(aie, alg) {
-- if (alg->dh == NULL) {
-- if (first_null == NULL) {
-- first_null = alg;
-- }
-- } else if (alg->dh == &ike_alg_dh_none) {
-- if (first_none == NULL) {
-- first_none = alg;
-- }
-- } else if (first_dh == NULL) {
-- first_dh = alg;
-- } else if (second_dh == NULL && first_dh->dh != alg->dh) {
-- second_dh = alg;
-- }
-- }
--
-- if (first_dh == NULL && first_none == NULL) {
-- /* no DH is always ok */
-- return true;
-- }
--
-- /*
-- * Try to generate very specific errors first. For instance,
-- * given PFS=no esp=aes,aes;dh21, an error stating that dh21
-- * is not valid because of PFS is more helpful than an error
-- * saying that all or no proposals need PFS.
-- */
--
-- /*
-- * Since PFS=NO overrides any DH, don't silently ignore it.
-- * Check this early so that a conflict with PFS=no code gets
-- * reported before anything else.
-- */
-- if (!parser->policy->pfs && (first_dh != NULL || first_none != NULL)) {
-- FOR_EACH_ESP_INFO(aie, alg) {
-- if (alg->dh == &ike_alg_dh_none) {
-- parser->policy->warning("ignoring redundant %s DH algorithm NONE as PFS policy is disabled",
-- parser->protocol->name);
-- } else if (alg->dh != NULL) {
-- parser->policy->warning("ignoring %s DH algorithm %s as PFS policy is disabled",
-- parser->protocol->name,
-- alg->dh->common.fqn);
-- }
-- alg->dh = NULL;
-- }
-- return true;
-- }
--
-- /*
-- * Since at least one proposal included DH, all proposals
-- * should. A proposal without DH is an error.
-- *
-- * (The converse, no proposals including DH was handled right
-- * at the start).
-- */
-- if (first_null != NULL) {
-- /* DH was specified */
-- snprintf(parser->err_buf, parser->err_buf_len,
-- "either all or no %s proposals should specify DH",
-- parser->protocol->name);
-- if (!impair_proposal_errors(parser)) {
-- return false;
-- }
-- }
--
-- /*
-- * IKEv1 only allows one DH algorithm.
-- */
-- if (parser->policy->ikev1) {
-- if (first_dh != NULL && second_dh != NULL) {
-- snprintf(parser->err_buf, parser->err_buf_len,
-- "more than one IKEv1 %s DH algorithm (%s, %s) is not allowed in quick mode",
-- parser->protocol->name,
-- first_dh->dh->common.fqn,
-- second_dh->dh->common.fqn);
-- if (!impair_proposal_errors(parser)) {
-- return false;
-- }
-- }
-- }
--
-- /*
-- * IKEv2, only implements one DH algorithm.
-- */
-- if (parser->policy->ikev2) {
-- if (first_dh != NULL && second_dh != NULL) {
-- snprintf(parser->err_buf, parser->err_buf_len,
-- "more than one IKEv2 %s DH algorithm (%s, %s) requires unimplemented CHILD_SA INVALID_KE",
-- parser->protocol->name,
-- first_dh->dh->common.fqn,
-- second_dh->dh->common.fqn);
-- if (!impair_proposal_errors(parser)) {
-- return false;
-- }
-- }
-- }
--
-- return true;
--}
--
--bool impair_proposal_errors(const struct proposal_parser *parser)
--{
-- pexpect(parser->err_buf[0] != '\0');
-- if (IMPAIR(PROPOSAL_PARSER)) {
-- libreswan_log("IMPAIR: ignoring proposal error: %s",
-- parser->err_buf);
-- parser->err_buf[0] = '\0';
-- return true;
-- } else {
-- return false;
-- }
--}
-diff -Naur libreswan-3.27-orig/lib/libswan/esp_info.c libreswan-3.27/lib/libswan/esp_info.c
---- libreswan-3.27-orig/lib/libswan/esp_info.c 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/lib/libswan/esp_info.c 2019-02-15 16:50:12.776728076 -0500
-@@ -22,7 +22,7 @@
-
- #include "lswalloc.h"
- #include "lswlog.h"
--#include "alg_info.h"
-+#include "proposals.h"
- #include "alg_byname.h"
- #include "lswfips.h"
-
-@@ -33,8 +33,8 @@
- /*
- * Add ESP alg info _with_ logic (policy):
- */
--static bool esp_proposal_ok(const struct proposal_parser *parser,
-- const struct proposal_info *proposal)
-+static bool esp_proposal_ok(struct proposal_parser *parser,
-+ const struct proposal *proposal)
- {
- if (!proposal_aead_none_ok(parser, proposal)) {
- if (!impair_proposal_errors(parser)) {
-@@ -42,12 +42,19 @@
- }
- }
-
-- impaired_passert(PROPOSAL_PARSER, proposal->encrypt != NULL);
-- impaired_passert(PROPOSAL_PARSER, proposal->prf == NULL);
-- impaired_passert(PROPOSAL_PARSER, proposal->integ != NULL);
-+ impaired_passert(PROPOSAL_PARSER,
-+ next_algorithm(proposal, PROPOSAL_encrypt, NULL) != NULL);
-+ impaired_passert(PROPOSAL_PARSER,
-+ next_algorithm(proposal, PROPOSAL_prf, NULL) == NULL);
-+ impaired_passert(PROPOSAL_PARSER,
-+ next_algorithm(proposal, PROPOSAL_integ, NULL) != NULL);
- return true;
- }
-
-+/*
-+ * since esp= must have an encryption algorithm this is normally
-+ * ignored.
-+ */
- static const struct ike_alg *default_esp_encrypt[] = {
- #ifdef USE_AES
- &ike_alg_encrypt_aes_cbc.common,
-@@ -55,24 +62,39 @@
- NULL,
- };
-
--static const struct ike_alg *default_esp_integ[] = {
-+static const struct ike_alg *default_v1_esp_integ[] = {
- #ifdef USE_SHA1
- &ike_alg_integ_sha1.common,
- #endif
- NULL,
- };
-
--static const struct proposal_defaults esp_defaults = {
-+static const struct ike_alg *default_v2_esp_integ[] = {
-+#ifdef USE_SHA2
-+ &ike_alg_integ_sha2_512.common,
-+ &ike_alg_integ_sha2_256.common,
-+#endif
-+ NULL,
-+};
-+
-+static const struct proposal_defaults v1_esp_defaults = {
- .encrypt = default_esp_encrypt,
-- .integ = default_esp_integ,
-+ .integ = default_v1_esp_integ,
-+};
-+
-+static const struct proposal_defaults v2_esp_defaults = {
-+ .encrypt = default_esp_encrypt,
-+ .integ = default_v2_esp_integ,
- };
-
- static const struct proposal_protocol esp_proposal_protocol = {
- .name = "ESP",
- .ikev1_alg_id = IKEv1_ESP_ID,
- .protoid = PROTO_IPSEC_ESP,
-- .ikev1_defaults = &esp_defaults,
-- .ikev2_defaults = &esp_defaults,
-+ .defaults = {
-+ [IKEv1] = &v1_esp_defaults,
-+ [IKEv2] = &v2_esp_defaults,
-+ },
- .proposal_ok = esp_proposal_ok,
- .encrypt_alg_byname = encrypt_alg_byname,
- .integ_alg_byname = integ_alg_byname,
-@@ -81,7 +103,7 @@
-
- /*
- * ??? the only difference between
-- * alg_info_ah_create_from_str and alg_info_esp_create_from_str
-+ * alg_info_ah_create_from_str and esp_proposals_create_from_str
- * is in the second argument to proposal_parser.
- *
- * XXX: On the other hand, since "struct ike_info" and "struct
-@@ -91,33 +113,7 @@
-
- /* This function is tested in testing/algparse/algparse.c */
-
--struct alg_info_esp *alg_info_esp_create_from_str(const struct proposal_policy *policy,
-- const char *alg_str,
-- char *err_buf, size_t err_buf_len)
-+struct proposal_parser *esp_proposal_parser(const struct proposal_policy *policy)
- {
-- shunk_t string = shunk1(alg_str);
-- const struct proposal_parser parser = proposal_parser(policy,
-- &esp_proposal_protocol,
-- err_buf, err_buf_len);
--
-- /*
-- * alg_info storage should be sized dynamically
-- * but this may require two passes to know
-- * transform count in advance.
-- */
-- struct alg_info_esp *alg_info_esp = alloc_thing(struct alg_info_esp,
-- "alg_info_esp");
-- if (!alg_info_parse_str(&parser, &alg_info_esp->ai, string)) {
-- passert(err_buf[0] != '\0');
-- alg_info_free(&alg_info_esp->ai);
-- return NULL;
-- }
--
-- if (!alg_info_pfs_vs_dh_check(&parser, alg_info_esp)) {
-- passert(err_buf[0] != '\0');
-- alg_info_free(&alg_info_esp->ai);
-- return NULL;
-- }
--
-- return alg_info_esp;
-+ return alloc_proposal_parser(policy, &esp_proposal_protocol);
- }
-diff -Naur libreswan-3.27-orig/lib/libswan/ike_alg.c libreswan-3.27/lib/libswan/ike_alg.c
---- libreswan-3.27-orig/lib/libswan/ike_alg.c 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/lib/libswan/ike_alg.c 2019-02-15 16:32:28.978835332 -0500
-@@ -37,7 +37,7 @@
- #include "ike_alg.h"
- #include "ike_alg_integ.h"
- #include "ike_alg_encrypt.h"
--#include "alg_info.h"
-+#include "proposals.h"
- #include "ike_alg_prf.h"
- #include "ike_alg_prf_hmac_ops.h"
- #include "ike_alg_prf_nss_ops.h"
-@@ -589,7 +589,7 @@
- static bool integ_desc_is_ike(const struct ike_alg *alg)
- {
- const struct integ_desc *integ = integ_desc(alg);
-- return integ->prf != NULL;
-+ return integ->prf != NULL || integ == &ike_alg_integ_none;
- }
-
- static struct algorithm_table integ_algorithms = ALGORITHM_TABLE(integ_descriptors);
-diff -Naur libreswan-3.27-orig/lib/libswan/ike_alg_dh.c libreswan-3.27/lib/libswan/ike_alg_dh.c
---- libreswan-3.27-orig/lib/libswan/ike_alg_dh.c 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/lib/libswan/ike_alg_dh.c 2019-02-15 16:32:28.979835342 -0500
-@@ -186,7 +186,7 @@
- .algo_type = IKE_ALG_DH,
- .name = "DH19",
- .fqn = "DH19",
-- .names = { "dh19", "ecp_256", },
-+ .names = { "dh19", "ecp_256", "ecp256" },
- .id = {
- [IKEv1_OAKLEY_ID] = OAKLEY_GROUP_ECP_256,
- [IKEv1_ESP_ID] = -1,
-@@ -205,7 +205,7 @@
- .algo_type = IKE_ALG_DH,
- .name = "DH20",
- .fqn = "DH20",
-- .names = { "dh20", "ecp_384", },
-+ .names = { "dh20", "ecp_384", "ecp384" },
- .id = {
- [IKEv1_OAKLEY_ID] = OAKLEY_GROUP_ECP_384,
- [IKEv1_ESP_ID] = -1,
-@@ -224,7 +224,7 @@
- .algo_type = IKE_ALG_DH,
- .name = "DH21",
- .fqn = "DH21",
-- .names = { "dh21", "ecp_521", },
-+ .names = { "dh21", "ecp_521", "ecp521" },
- .id = {
- [IKEv1_OAKLEY_ID] = OAKLEY_GROUP_ECP_521,
- [IKEv1_ESP_ID] = -1,
-diff -Naur libreswan-3.27-orig/lib/libswan/ike_alg_sha2.c libreswan-3.27/lib/libswan/ike_alg_sha2.c
---- libreswan-3.27-orig/lib/libswan/ike_alg_sha2.c 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/lib/libswan/ike_alg_sha2.c 2019-02-15 16:32:28.979835342 -0500
-@@ -79,7 +79,7 @@
- .common = {
- .name = "sha2_256",
- .fqn = "HMAC_SHA2_256_128",
-- .names = { "sha2", "sha256", "sha2_256", "hmac_sha2_256", "hmac_sha2_256_128", },
-+ .names = { "sha2", "sha256", "sha2_256", "sha2_256_128", "hmac_sha2_256", "hmac_sha2_256_128", },
- .algo_type = IKE_ALG_INTEG,
- .id = {
- [IKEv1_OAKLEY_ID] = OAKLEY_SHA2_256,
-@@ -206,7 +206,7 @@
- .common = {
- .name = "sha2_384",
- .fqn = "HMAC_SHA2_384_192",
-- .names = { "sha384", "sha2_384", "hmac_sha2_384", "hmac_sha2_384_192", },
-+ .names = { "sha384", "sha2_384", "sha2_384_192", "hmac_sha2_384", "hmac_sha2_384_192", },
- .algo_type = IKE_ALG_INTEG,
- .id = {
- [IKEv1_OAKLEY_ID] = OAKLEY_SHA2_384,
-@@ -308,7 +308,7 @@
- .common = {
- .name = "sha2_512",
- .fqn = "HMAC_SHA2_512_256",
-- .names = { "sha512", "sha2_512", "hmac_sha2_512", "hmac_sha2_512_256", },
-+ .names = { "sha512", "sha2_512", "sha2_512_256", "hmac_sha2_512", "hmac_sha2_512_256", },
- .algo_type = IKE_ALG_INTEG,
- .id = {
- [IKEv1_OAKLEY_ID] = OAKLEY_SHA2_512,
-diff -Naur libreswan-3.27-orig/lib/libswan/ike_info.c libreswan-3.27/lib/libswan/ike_info.c
---- libreswan-3.27-orig/lib/libswan/ike_info.c 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/lib/libswan/ike_info.c 2019-02-15 16:50:12.777728085 -0500
-@@ -27,10 +27,10 @@
- #include "ike_alg_integ.h"
- #include "ike_alg_prf.h"
- #include "ike_alg_dh.h"
--#include "alg_info.h"
-+#include "proposals.h"
-
--static bool ike_proposal_ok(const struct proposal_parser *parser,
-- const struct proposal_info *proposal)
-+static bool ike_proposal_ok(struct proposal_parser *parser,
-+ const struct proposal *proposal)
- {
- if (!proposal_aead_none_ok(parser, proposal)) {
- if (!impair_proposal_errors(parser)) {
-@@ -42,27 +42,42 @@
- * Check that the ALG_INFO spec is implemented.
- */
-
-- impaired_passert(PROPOSAL_PARSER, proposal->encrypt != NULL);
-- passert(proposal->encrypt == NULL || ike_alg_is_ike(&(proposal->encrypt->common)));
-- passert(IMPAIR(PROPOSAL_PARSER) || proposal->enckeylen == 0 ||
-- encrypt_has_key_bit_length(proposal->encrypt,
-- proposal->enckeylen));
--
-- impaired_passert(PROPOSAL_PARSER, proposal->prf != NULL);
-- passert(proposal->prf == NULL || ike_alg_is_ike(&(proposal->prf->common)));
--
-- impaired_passert(PROPOSAL_PARSER, proposal->integ != NULL);
-- passert(proposal->integ == &ike_alg_integ_none ||
-- proposal->integ == NULL ||
-- ike_alg_is_ike(&proposal->integ->common));
--
-- impaired_passert(PROPOSAL_PARSER, proposal->dh != NULL);
-- passert(proposal->dh == NULL || ike_alg_is_ike(&(proposal->dh->common)));
-- if (proposal->dh == &ike_alg_dh_none) {
-- snprintf(parser->err_buf, parser->err_buf_len,
-- "IKE DH algorithm 'none' not permitted");
-- if (!impair_proposal_errors(parser)) {
-- return false;
-+ impaired_passert(PROPOSAL_PARSER,
-+ next_algorithm(proposal, PROPOSAL_encrypt, NULL) != NULL);
-+ FOR_EACH_ALGORITHM(proposal, encrypt, alg) {
-+ const struct encrypt_desc *encrypt = encrypt_desc(alg->desc);
-+ passert(ike_alg_is_ike(&encrypt->common));
-+ passert(IMPAIR(PROPOSAL_PARSER) ||
-+ alg->enckeylen == 0 ||
-+ encrypt_has_key_bit_length(encrypt,
-+ alg->enckeylen));
-+ }
-+
-+ impaired_passert(PROPOSAL_PARSER,
-+ next_algorithm(proposal, PROPOSAL_prf, NULL) != NULL);
-+ FOR_EACH_ALGORITHM(proposal, prf, alg) {
-+ const struct prf_desc *prf = prf_desc(alg->desc);
-+ passert(ike_alg_is_ike(&prf->common));
-+ }
-+
-+ impaired_passert(PROPOSAL_PARSER,
-+ next_algorithm(proposal, PROPOSAL_integ, NULL) != NULL);
-+ FOR_EACH_ALGORITHM(proposal, integ, alg) {
-+ const struct integ_desc *integ = integ_desc(alg->desc);
-+ passert(integ == &ike_alg_integ_none ||
-+ ike_alg_is_ike(&integ->common));
-+ }
-+
-+ impaired_passert(PROPOSAL_PARSER,
-+ next_algorithm(proposal, PROPOSAL_dh, NULL) != NULL);
-+ FOR_EACH_ALGORITHM(proposal, dh, alg) {
-+ const struct oakley_group_desc *dh = dh_desc(alg->desc);
-+ passert(ike_alg_is_ike(&dh->common));
-+ if (dh == &ike_alg_dh_none) {
-+ proposal_error(parser, "IKE DH algorithm 'none' not permitted");
-+ if (!impair_proposal_errors(parser)) {
-+ return false;
-+ }
- }
- }
-
-@@ -84,9 +99,20 @@
- };
- static const struct ike_alg *default_ikev2_groups[] = {
- &oakley_group_modp2048.common,
-+ &oakley_group_modp3072.common,
-+ &oakley_group_modp4096.common,
-+ &oakley_group_modp8192.common,
-+ &oakley_group_dh19.common,
-+ &oakley_group_dh20.common,
-+ &oakley_group_dh21.common,
-+ &oakley_group_dh31.common,
- NULL,
- };
-
-+/*
-+ * since ike= must have an encryption algorithm this is normally
-+ * ignored.
-+ */
- static const struct ike_alg *default_ike_ealgs[] = {
- #ifdef USE_AES
- &ike_alg_encrypt_aes_cbc.common,
-@@ -97,7 +123,7 @@
- NULL,
- };
-
--static const struct ike_alg *default_ike_aalgs[] = {
-+static const struct ike_alg *default_v1_ike_prfs[] = {
- #ifdef USE_SHA2
- &ike_alg_prf_sha2_256.common,
- &ike_alg_prf_sha2_512.common,
-@@ -108,24 +134,34 @@
- NULL,
- };
-
-+static const struct ike_alg *default_v2_ike_prfs[] = {
-+#ifdef USE_SHA2
-+ &ike_alg_prf_sha2_512.common,
-+ &ike_alg_prf_sha2_256.common,
-+#endif
-+ NULL,
-+};
-+
- const struct proposal_defaults ikev1_ike_defaults = {
- .dh = default_ikev1_groups,
- .encrypt = default_ike_ealgs,
-- .prf = default_ike_aalgs,
-+ .prf = default_v1_ike_prfs,
- };
-
- const struct proposal_defaults ikev2_ike_defaults = {
- .dh = default_ikev2_groups,
- .encrypt = default_ike_ealgs,
-- .prf = default_ike_aalgs,
-+ .prf = default_v2_ike_prfs,
- };
-
- const struct proposal_protocol ike_proposal_protocol = {
- .name = "IKE",
- .ikev1_alg_id = IKEv1_OAKLEY_ID,
- .protoid = PROTO_ISAKMP,
-- .ikev1_defaults = &ikev1_ike_defaults,
-- .ikev2_defaults = &ikev2_ike_defaults,
-+ .defaults = {
-+ [IKEv1] = &ikev1_ike_defaults,
-+ [IKEv2] = &ikev2_ike_defaults,
-+ },
- .proposal_ok = ike_proposal_ok,
- .encrypt_alg_byname = encrypt_alg_byname,
- .prf_alg_byname = prf_alg_byname,
-@@ -133,25 +169,7 @@
- .dh_alg_byname = dh_alg_byname,
- };
-
--struct alg_info_ike *alg_info_ike_create_from_str(const struct proposal_policy *policy,
-- const char *alg_str,
-- char *err_buf, size_t err_buf_len)
-+struct proposal_parser *ike_proposal_parser(const struct proposal_policy *policy)
- {
-- /*
-- * alg_info storage should be sized dynamically
-- * but this may require two passes to know
-- * transform count in advance.
-- */
-- struct alg_info_ike *alg_info_ike = alloc_thing(struct alg_info_ike, "alg_info_ike");
-- const struct proposal_parser parser = proposal_parser(policy,
-- &ike_proposal_protocol,
-- err_buf, err_buf_len);
--
-- if (!alg_info_parse_str(&parser, &alg_info_ike->ai, shunk1(alg_str))) {
-- passert(err_buf[0] != '\0');
-- alg_info_free(&alg_info_ike->ai);
-- return NULL;
-- }
--
-- return alg_info_ike;
-+ return alloc_proposal_parser(policy, &ike_proposal_protocol);
- }
-diff -Naur libreswan-3.27-orig/lib/libswan/Makefile libreswan-3.27/lib/libswan/Makefile
---- libreswan-3.27-orig/lib/libswan/Makefile 2019-02-15 16:31:43.029408030 -0500
-+++ libreswan-3.27/lib/libswan/Makefile 2019-02-15 16:32:28.981835360 -0500
-@@ -74,7 +74,12 @@
- OBJS += satot.o
- OBJS += ultot.o
-
--OBJS += alg_info.o esp_info.o ike_info.o ah_info.o
-+OBJS += proposals.o
-+OBJS += v1_proposals.o
-+OBJS += v2_proposals.o
-+OBJS += esp_info.o
-+OBJS += ah_info.o
-+OBJS += ike_info.o
-
- OBJS += ckaid.o
-
-diff -Naur libreswan-3.27-orig/lib/libswan/proposals.c libreswan-3.27/lib/libswan/proposals.c
---- libreswan-3.27-orig/lib/libswan/proposals.c 1969-12-31 19:00:00.000000000 -0500
-+++ libreswan-3.27/lib/libswan/proposals.c 2019-02-15 16:46:01.378390204 -0500
-@@ -0,0 +1,573 @@
-+/*
-+ * Algorithm info parsing and creation functions
-+ * Author: JuanJo Ciarlante
-+ *
-+ * Copyright (C) 2012 Paul Wouters
-+ * Copyright (C) 2015-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
-+#include
-+#include
-+
-+#include "lswlog.h"
-+#include "lswalloc.h"
-+#include "constants.h"
-+#include "proposals.h"
-+#include "ike_alg.h"
-+#include "ike_alg_integ.h"
-+#include "ike_alg_dh.h"
-+#include "alg_byname.h"
-+
-+struct proposal {
-+ /*
-+ * The algorithm entries.
-+ */
-+ struct algorithm *algorithms[PROPOSAL_ALGORITHM_ROOF];
-+ /*
-+ * Which protocol is this proposal intended for?
-+ */
-+ const struct proposal_protocol *protocol;
-+ struct proposal *next;
-+};
-+
-+struct proposals {
-+ int ref_cnt;
-+ struct proposal *proposals;
-+};
-+
-+struct proposal_parser *alloc_proposal_parser(const struct proposal_policy *policy,
-+ const struct proposal_protocol *protocol)
-+{
-+ struct proposal_parser *parser = alloc_thing(struct proposal_parser, "parser");
-+ parser->policy = policy;
-+ parser->protocol = protocol;
-+ parser->error[0] = '\0';
-+ return parser;
-+}
-+
-+void free_proposal_parser(struct proposal_parser **parser)
-+{
-+ pfree(*parser);
-+ *parser = NULL;
-+}
-+
-+bool proposal_encrypt_aead(const struct proposal *proposal)
-+{
-+ if (proposal->algorithms[PROPOSAL_encrypt] == NULL) {
-+ return false;
-+ }
-+ FOR_EACH_ALGORITHM(proposal, encrypt, alg) {
-+ const struct encrypt_desc *encrypt = encrypt_desc(alg->desc);
-+ if (!encrypt_desc_is_aead(encrypt)) {
-+ return false;
-+ }
-+ }
-+ return true;
-+}
-+
-+bool proposal_encrypt_norm(const struct proposal *proposal)
-+{
-+ if (proposal->algorithms[PROPOSAL_encrypt] == NULL) {
-+ return false;
-+ }
-+ FOR_EACH_ALGORITHM(proposal, encrypt, alg) {
-+ const struct encrypt_desc *encrypt = encrypt_desc(alg->desc);
-+ if (encrypt_desc_is_aead(encrypt)) {
-+ return false;
-+ }
-+ }
-+ return true;
-+}
-+
-+bool proposal_integ_none(const struct proposal *proposal)
-+{
-+ /* interpret NULL as NONE */
-+ FOR_EACH_ALGORITHM(proposal, integ, alg) {
-+ const struct integ_desc *integ = integ_desc(alg->desc);
-+ if (integ != &ike_alg_integ_none) {
-+ return false;
-+ }
-+ }
-+ return true;
-+}
-+
-+bool proposal_aead_none_ok(struct proposal_parser *parser,
-+ const struct proposal *proposal)
-+{
-+ if (IMPAIR(ALLOW_NULL_NONE)) {
-+ return true;
-+ }
-+
-+ if (proposal->algorithms[PROPOSAL_encrypt] == NULL) {
-+ return true;
-+ }
-+
-+ /* are any and all encrypt algorithms AEAD? */
-+ bool aead = proposal_encrypt_aead(proposal);
-+ bool norm = proposal_encrypt_norm(proposal);
-+
-+ if (!aead && !norm) {
-+ proposal_error(parser, "AEAD and non-AEAD %s encryption algorithm can not be combined",
-+ proposal->protocol->name);
-+ return false;
-+ }
-+
-+ /* are any and all integ algorithms NONE? */
-+ bool none = proposal_integ_none(proposal);
-+
-+ if (aead && !none) {
-+ const struct ike_alg *encrypt = proposal->algorithms[PROPOSAL_encrypt]->desc;
-+ /*
-+ * At least one of the integrity algorithms wasn't
-+ * NONE. For instance, esp=aes_gcm-sha1" is invalid.
-+ */
-+ proposal_error(parser, "AEAD %s encryption algorithm '%s' must have 'none' as the integrity algorithm",
-+ proposal->protocol->name,
-+ encrypt->name);
-+ return false;
-+ }
-+
-+ if (norm && none) {
-+ const struct ike_alg *encrypt = proposal->algorithms[PROPOSAL_encrypt]->desc;
-+ /*
-+ * Not AEAD and either there was no integrity
-+ * algorithm (implying NONE) or at least one integrity
-+ * algorithm was NONE. For instance,
-+ * esp=aes_cbc-none" is invalid.
-+ */
-+ proposal_error(parser, "non-AEAD %s encryption algorithm '%s' cannot have 'none' as the integrity algorithm",
-+ proposal->protocol->name,
-+ encrypt->name);
-+ return false;
-+ }
-+
-+ return true;
-+}
-+
-+
-+/*
-+ * proposals struct can be shared by several connections instances,
-+ * handle free() with ref_cnts.
-+ */
-+
-+void proposals_addref(struct proposals **proposals)
-+{
-+ if ((*proposals) != NULL) {
-+ (*proposals)->ref_cnt++;
-+ }
-+}
-+
-+void proposals_delref(struct proposals **proposals)
-+{
-+ if ((*proposals) != NULL) {
-+ if ((*proposals)->ref_cnt == 0) {
-+ free_proposal(&(*proposals)->proposals);
-+ pfree((*proposals));
-+ } else {
-+ (*proposals)->ref_cnt--;
-+ }
-+ *proposals = NULL;
-+ }
-+}
-+struct proposal *next_proposal(const struct proposals *proposals,
-+ struct proposal *last)
-+{
-+ if (last == NULL) {
-+ return proposals->proposals;
-+ } else {
-+ return last->next;
-+ }
-+}
-+
-+unsigned nr_proposals(struct proposals *proposals)
-+{
-+ unsigned nr = 0;
-+ FOR_EACH_PROPOSAL(proposals, proposal) {
-+ nr++;
-+ }
-+ return nr;
-+}
-+
-+void append_proposal(struct proposals *proposals, struct proposal **proposal)
-+{
-+ struct proposal **end = &proposals->proposals;
-+ /* check for duplicates */
-+ while ((*end) != NULL) {
-+ bool same = true;
-+ for (enum proposal_algorithm pa = 0;
-+ same && pa < PROPOSAL_ALGORITHM_ROOF; pa++) {
-+ struct algorithm *old = (*end)->algorithms[pa];
-+ struct algorithm *new = (*proposal)->algorithms[pa];
-+ while (same) {
-+ if (new == NULL && old == NULL) {
-+ break;
-+ }
-+ if (new == NULL || old == NULL) {
-+ same = false;
-+ break;
-+ }
-+ if (new->desc != old->desc) {
-+ same = false;
-+ break;
-+ }
-+ /*
-+ * If list already contains encryption
-+ * with ENCKEYLEN=0 then new is a
-+ * duplicate as 0 generates all keys.
-+ * Ignore reverse vis aes128,aes.
-+ */
-+ if (old->desc->algo_type == IKE_ALG_ENCRYPT &&
-+ (old->enckeylen != 0 &&
-+ new->enckeylen != old->enckeylen)) {
-+ same = false;
-+ break;
-+ }
-+ new = new->next;
-+ old = old->next;
-+ }
-+ }
-+ if (same) {
-+ /* parser->policy->warning("discarding duplicate proposal"); */
-+ free_proposal(proposal);
-+ return;
-+ }
-+ end = &(*end)->next;
-+ }
-+ *end = *proposal;
-+ *proposal = NULL;
-+}
-+
-+struct v1_proposal v1_proposal(const struct proposal *proposal)
-+{
-+ struct v1_proposal v1 = {
-+ .protocol = proposal->protocol,
-+#define D(ALG) .ALG = proposal->algorithms[PROPOSAL_##ALG] != NULL ? ALG##_desc(proposal->algorithms[PROPOSAL_##ALG]->desc) : NULL
-+ D(encrypt),
-+ D(prf),
-+ D(integ),
-+ D(dh),
-+#undef D
-+ };
-+ v1.enckeylen = proposal->algorithms[PROPOSAL_encrypt] != NULL ? proposal->algorithms[PROPOSAL_encrypt]->enckeylen : 0;
-+
-+ return v1;
-+}
-+
-+struct algorithm *next_algorithm(const struct proposal *proposal,
-+ enum proposal_algorithm algorithm,
-+ struct algorithm *last)
-+{
-+ if (last == NULL) {
-+ /*
-+ * Hack, there should there a way to index algorithm
-+ * types; however the old enum proved very dangerous.
-+ */
-+ passert(algorithm < elemsof(proposal->algorithms));
-+ return proposal->algorithms[algorithm];
-+ } else {
-+ return last->next;
-+ }
-+}
-+
-+void free_algorithms(struct proposal *proposal,
-+ enum proposal_algorithm algorithm)
-+{
-+ passert(algorithm < elemsof(proposal->algorithms));
-+ struct algorithm *alg = proposal->algorithms[algorithm];
-+ while (alg != NULL) {
-+ struct algorithm *del = alg;
-+ alg = alg->next;
-+ pfree(del);
-+ }
-+ proposal->algorithms[algorithm] = NULL;
-+}
-+
-+struct proposal *alloc_proposal(struct proposal_parser *parser)
-+{
-+ struct proposal *proposal = alloc_thing(struct proposal, "proposal");
-+ proposal->protocol = parser->protocol;
-+ return proposal;
-+}
-+
-+void free_proposal(struct proposal **proposals)
-+{
-+ struct proposal *proposal = *proposals;
-+ while (proposal != NULL) {
-+ struct proposal *del = proposal;
-+ proposal = proposal->next;
-+ for (enum proposal_algorithm algorithm = 0;
-+ algorithm < PROPOSAL_ALGORITHM_ROOF;
-+ algorithm++) {
-+ free_algorithms(del, algorithm);
-+ }
-+ pfree(del);
-+ }
-+ *proposals = NULL;
-+}
-+
-+void append_algorithm(struct proposal_parser *parser,
-+ struct proposal *proposal,
-+ enum proposal_algorithm algorithm,
-+ const struct ike_alg *alg,
-+ int enckeylen)
-+{
-+ passert(algorithm < elemsof(proposal->algorithms));
-+ struct algorithm **end = &proposal->algorithms[algorithm];
-+ /* find end, and check for duplicates */
-+ while ((*end) != NULL) {
-+ /*
-+ * enckeylen=0 acts as a wildcard
-+ */
-+ if (alg == (*end)->desc &&
-+ (alg->algo_type != IKE_ALG_ENCRYPT ||
-+ ((*end)->enckeylen == 0 ||
-+ enckeylen == (*end)->enckeylen))) {
-+ parser->policy->warning("discarding duplicate algorithm '%s'",
-+ alg->name);
-+ return;
-+ }
-+ end = &(*end)->next;
-+ }
-+ struct algorithm new_algorithm = {
-+ .desc = alg,
-+ .enckeylen = enckeylen,
-+ };
-+ *end = clone_thing(new_algorithm, "alg");
-+}
-+
-+void fmt_proposal(struct lswlog *log,
-+ const struct proposal *proposal)
-+{
-+ const char *ps = "";
-+
-+ const char *as = "";
-+
-+ as = ps;
-+ FOR_EACH_ALGORITHM(proposal, encrypt, alg) {
-+ const struct encrypt_desc *encrypt = encrypt_desc(alg->desc);
-+ lswlogs(log, as); ps = "-"; as = "+";
-+ lswlogs(log, encrypt->common.fqn);
-+ if (alg->enckeylen != 0) {
-+ lswlogf(log, "_%d", alg->enckeylen);
-+ }
-+ }
-+
-+ as = ps;
-+ FOR_EACH_ALGORITHM(proposal, prf, alg) {
-+ const struct prf_desc *prf = prf_desc(alg->desc);
-+ lswlogs(log, as); ps = "-"; as = "+";
-+ lswlogs(log, prf->common.fqn);
-+ }
-+
-+ as = ps;
-+ if ((proposal->algorithms[PROPOSAL_prf] == NULL &&
-+ proposal->algorithms[PROPOSAL_integ] != NULL) ||
-+ (IMPAIR(PROPOSAL_PARSER) &&
-+ proposal->algorithms[PROPOSAL_integ] != NULL)) {
-+ FOR_EACH_ALGORITHM(proposal, integ, alg) {
-+ const struct integ_desc *integ = integ_desc(alg->desc);
-+ lswlogs(log, as); ps = "-"; as = "+";
-+ lswlogs(log, integ->common.fqn);
-+ }
-+ }
-+
-+ as = ps;
-+ FOR_EACH_ALGORITHM(proposal, dh, alg) {
-+ const struct oakley_group_desc *dh = dh_desc(alg->desc);
-+ lswlogs(log, as); ps = "-"; as = "+";
-+ lswlogs(log, dh->common.fqn);
-+ }
-+}
-+
-+void fmt_proposals(struct lswlog *log, const struct proposals *proposals)
-+{
-+ const char *sep = "";
-+ FOR_EACH_PROPOSAL(proposals, proposal) {
-+ lswlogs(log, sep);
-+ fmt_proposal(log, proposal);
-+ sep = ", ";
-+ }
-+}
-+
-+/*
-+ * When PFS=no ignore any DH algorithms, and when PFS=yes reject
-+ * mixing implict and explicit DH.
-+ */
-+static bool proposals_pfs_vs_dh_check(struct proposal_parser *parser,
-+ struct proposals *proposals)
-+{
-+ /* scrape the proposals for dh algorithms */
-+ const struct proposal *first_null = NULL;
-+ const struct proposal *first_none = NULL;
-+ const struct ike_alg *first_dh = NULL;
-+ const struct ike_alg *second_dh = NULL;
-+ FOR_EACH_PROPOSAL(proposals, proposal) {
-+ if (proposal->algorithms[PROPOSAL_dh] == NULL) {
-+ if (first_null == NULL) {
-+ first_null = proposal;
-+ }
-+ } else if (proposal->algorithms[PROPOSAL_dh]->desc == &ike_alg_dh_none.common) {
-+ if (first_none == NULL) {
-+ first_none = proposal;
-+ }
-+ } else if (first_dh == NULL) {
-+ first_dh = proposal->algorithms[PROPOSAL_dh]->desc;
-+ } else if (second_dh == NULL &&
-+ first_dh != proposal->algorithms[PROPOSAL_dh]->desc) {
-+ second_dh = proposal->algorithms[PROPOSAL_dh]->desc;
-+ }
-+ }
-+
-+ if (first_dh == NULL && first_none == NULL) {
-+ /* no DH is always ok */
-+ return true;
-+ }
-+
-+ /*
-+ * Try to generate very specific errors first. For instance,
-+ * given PFS=no esp=aes,aes;dh21, an error stating that dh21
-+ * is not valid because of PFS is more helpful than an error
-+ * saying that all or no proposals need PFS.
-+ */
-+
-+ /*
-+ * Since PFS=NO overrides any DH, don't silently ignore it.
-+ * Check this early so that a conflict with PFS=no code gets
-+ * reported before anything else.
-+ */
-+ if (!parser->policy->pfs && (first_dh != NULL || first_none != NULL)) {
-+ FOR_EACH_PROPOSAL(proposals, proposal) {
-+ const struct ike_alg *dh = NULL;
-+ if (proposal->algorithms[PROPOSAL_dh] != NULL) {
-+ dh = proposal->algorithms[PROPOSAL_dh]->desc;
-+ }
-+ if (dh == &ike_alg_dh_none.common) {
-+ parser->policy->warning("ignoring redundant %s DH algorithm NONE as PFS policy is disabled",
-+ parser->protocol->name);
-+ } else if (dh != NULL) {
-+ parser->policy->warning("ignoring %s DH algorithm %s as PFS policy is disabled",
-+ parser->protocol->name,
-+ dh->fqn);
-+ }
-+ free_algorithms(proposal, PROPOSAL_dh);
-+ }
-+ return true;
-+ }
-+
-+ /*
-+ * Since at least one proposal included DH, all proposals
-+ * should. A proposal without DH is an error.
-+ *
-+ * (The converse, no proposals including DH was handled right
-+ * at the start).
-+ */
-+ if (first_null != NULL) {
-+ /* DH was specified */
-+ proposal_error(parser, "either all or no %s proposals should specify DH",
-+ parser->protocol->name);
-+ if (!impair_proposal_errors(parser)) {
-+ return false;
-+ }
-+ }
-+
-+ switch (parser->policy->version) {
-+
-+ case IKEv1:
-+ /*
-+ * IKEv1 only allows one DH algorithm.
-+ */
-+ if (first_dh != NULL && second_dh != NULL) {
-+ proposal_error(parser, "more than one IKEv1 %s DH algorithm (%s, %s) is not allowed in quick mode",
-+ parser->protocol->name,
-+ first_dh->fqn,
-+ second_dh->fqn);
-+ if (!impair_proposal_errors(parser)) {
-+ return false;
-+ }
-+ }
-+ break;
-+
-+ case IKEv2:
-+ /*
-+ * IKEv2, only implements one DH algorithm.
-+ */
-+ if (first_dh != NULL && second_dh != NULL) {
-+ proposal_error(parser, "more than one IKEv2 %s DH algorithm (%s, %s) requires unimplemented CHILD_SA INVALID_KE",
-+ parser->protocol->name,
-+ first_dh->fqn,
-+ second_dh->fqn);
-+ if (!impair_proposal_errors(parser)) {
-+ return false;
-+ }
-+ }
-+ break;
-+
-+ default:
-+ /* ignore */
-+ break;
-+ }
-+
-+ return true;
-+}
-+
-+void proposal_error(struct proposal_parser *parser, const char *fmt, ...)
-+{
-+ va_list ap;
-+ va_start(ap, fmt);
-+ vsnprintf(parser->error, sizeof(parser->error), fmt, ap);
-+ va_end(ap);
-+}
-+
-+bool impair_proposal_errors(struct proposal_parser *parser)
-+{
-+ pexpect(parser->error[0] != '\0');
-+ if (IMPAIR(PROPOSAL_PARSER)) {
-+ libreswan_log("IMPAIR: ignoring proposal error: %s",
-+ parser->error);
-+ parser->error[0] = '\0';
-+ return true;
-+ } else {
-+ return false;
-+ }
-+}
-+
-+struct proposals *proposals_from_str(struct proposal_parser *parser,
-+ const char *str)
-+{
-+ struct proposals *proposals = alloc_thing(struct proposals, "proposals");
-+ unsigned parser_version = parser->policy->parser_version;
-+ if (parser_version == 0) {
-+ parser_version = parser->policy->version;
-+ }
-+ bool ok;
-+ switch (parser_version) {
-+ case 2: ok = v2_proposals_parse_str(parser, proposals, shunk1(str)); break;
-+ default: ok = v1_proposals_parse_str(parser, proposals, shunk1(str)); break;
-+ }
-+ if (!ok) {
-+ proposals_delref(&proposals);
-+ return NULL;
-+ }
-+ if (proposals->proposals == NULL) {
-+ proposals_delref(&proposals);
-+ return NULL;
-+ }
-+ if (parser->policy->check_pfs_vs_dh &&
-+ !proposals_pfs_vs_dh_check(parser, proposals)) {
-+ pexpect(parser->error[0] != '\0');
-+ proposals_delref(&proposals);
-+ return NULL;
-+ }
-+ return proposals;
-+}
-diff -Naur libreswan-3.27-orig/lib/libswan/shunk.c libreswan-3.27/lib/libswan/shunk.c
---- libreswan-3.27-orig/lib/libswan/shunk.c 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/lib/libswan/shunk.c 2019-02-15 16:32:28.982835370 -0500
-@@ -1,6 +1,6 @@
--/* string fragments, for libreswan
-+/* Constant string (octet) fragments, for libreswan
- *
-- * Copyright (C) 2018 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
-@@ -20,12 +20,17 @@
-
- #include "shunk.h"
-
--const shunk_t empty_shunk;
-+/*
-+ * Don't mistake a NULL_SHUNK for an empty shunk - just like for
-+ * strings they are different.
-+ */
-+
-+const shunk_t null_shunk = NULL_SHUNK;
-
- shunk_t shunk1(const char *ptr)
- {
- if (ptr == NULL) {
-- return empty_shunk;
-+ return null_shunk;
- } else {
- return shunk2(ptr, strlen(ptr));
- }
-@@ -34,28 +39,37 @@
- shunk_t shunk2(const char *ptr, int len)
- {
- /*
-- * Since a zero length string and a NULL string pointer are
-- * considered to be different, don't convert the former into
-- * an empty_chunk.
-+ * Since a zero length string is not the same as a NULL
-+ * string, don't try to be smart and convert the former into
-+ * the latter.
- */
- return (shunk_t) { .ptr = ptr, .len = len, };
- }
-
--shunk_t shunk_strsep(shunk_t *shunk, const char *delim)
-+shunk_t shunk_strsep(shunk_t *input, const char *delim)
- {
-- shunk_t token = shunk2(shunk->ptr, 0);
-- while (shunk->len > 0) {
-- if (strchr(delim, *shunk->ptr) != NULL) {
-+ /*
-+ * If INPUT is NULL, the loop is skipped and NULL is
-+ * returned.
-+ */
-+ shunk_t token = shunk2(input->ptr, 0);
-+ while (input->len > 0) {
-+ if (strchr(delim, *input->ptr) != NULL) {
- /* discard delim */
-- shunk->ptr++;
-- shunk->len--;
-+ input->ptr++;
-+ input->len--;
- return token;
- }
- /* advance, transfering the char */
- token.len++;
-- shunk->ptr++;
-- shunk->len--;
-+ input->ptr++;
-+ input->len--;
- }
-+ /*
-+ * Flag this as the last token by setting INPUT to NULL; next
-+ * call will return the NULL shunk.
-+ */
-+ *input = null_shunk;
- return token;
- }
-
-diff -Naur libreswan-3.27-orig/lib/libswan/v1_proposals.c libreswan-3.27/lib/libswan/v1_proposals.c
---- libreswan-3.27-orig/lib/libswan/v1_proposals.c 1969-12-31 19:00:00.000000000 -0500
-+++ libreswan-3.27/lib/libswan/v1_proposals.c 2019-02-15 16:47:22.485144451 -0500
-@@ -0,0 +1,578 @@
-+/* V1 algorithm proposal parsing, for libreswan
-+ *
-+ * Copyright (C) 2012 Paul Wouters
-+ * Copyright (C) 2015-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
-+#include
-+#include
-+
-+#include "lswlog.h"
-+#include "lswalloc.h"
-+#include "constants.h"
-+#include "proposals.h"
-+#include "ike_alg.h"
-+#include "ike_alg_integ.h"
-+#include "ike_alg_dh.h"
-+#include "alg_byname.h"
-+
-+/*
-+ * Add the proposal defaults for the specific algorithm.
-+ */
-+
-+typedef struct v1_proposal merge_alg_default_t(struct v1_proposal proposal,
-+ const struct ike_alg *default_alg);
-+
-+static struct v1_proposal merge_dh_default(struct v1_proposal proposal,
-+ const struct ike_alg *default_alg)
-+{
-+ proposal.dh = oakley_group_desc(default_alg);
-+ return proposal;
-+}
-+
-+static struct v1_proposal merge_encrypt_default(struct v1_proposal proposal,
-+ const struct ike_alg *default_alg)
-+{
-+ proposal.encrypt = encrypt_desc(default_alg);
-+ return proposal;
-+}
-+
-+static struct v1_proposal merge_prf_default(struct v1_proposal proposal,
-+ const struct ike_alg *default_alg)
-+{
-+ proposal.prf = prf_desc(default_alg);
-+ return proposal;
-+}
-+
-+static struct v1_proposal merge_integ_default(struct v1_proposal proposal,
-+ const struct ike_alg *default_alg)
-+{
-+ proposal.integ = integ_desc(default_alg);
-+ return proposal;
-+}
-+
-+static bool add_proposal_defaults(struct proposal_parser *parser,
-+ const struct proposal_defaults *defaults,
-+ struct proposals *proposals,
-+ const struct v1_proposal *proposal);
-+
-+static bool add_alg_defaults(struct proposal_parser *parser,
-+ const struct proposal_defaults *defaults,
-+ struct proposals *proposals,
-+ const struct v1_proposal *proposal,
-+ const struct ike_alg_type *type,
-+ const struct ike_alg **default_algs,
-+ merge_alg_default_t *merge_alg_default)
-+{
-+ /*
-+ * Use VALID_ALG to add the valid algorithms into VALID_ALGS.
-+ */
-+ for (const struct ike_alg **default_alg = default_algs;
-+ *default_alg; default_alg++) {
-+ const struct ike_alg *alg = *default_alg;
-+ if (!alg_byname_ok(parser, alg,
-+ shunk1(alg->name))) {
-+ DBG(DBG_PROPOSAL_PARSER,
-+ DBG_log("skipping default %s",
-+ parser->error));
-+ parser->error[0] = '\0';
-+ continue;
-+ }
-+ /* add it */
-+ DBG(DBG_PROPOSAL_PARSER,
-+ DBG_log("adding default %s %s",
-+ ike_alg_type_name(type),
-+ alg->name));
-+ struct v1_proposal merged_proposal = merge_alg_default(*proposal,
-+ *default_alg);
-+ if (!add_proposal_defaults(parser, defaults,
-+ proposals, &merged_proposal)) {
-+ passert(parser->error[0] != '\0');
-+ return false;
-+ }
-+ }
-+ return true;
-+}
-+
-+/*
-+ * Validate the proposal and, suppressing duplicates, add it to the
-+ * proposal list.
-+ */
-+
-+static bool add_proposal(struct proposal_parser *parser,
-+ struct proposals *proposals,
-+ const struct v1_proposal *proposal)
-+{
-+ struct proposal *new = alloc_proposal(parser);
-+ if (proposal->encrypt != NULL) {
-+ append_algorithm(parser, new, PROPOSAL_encrypt,
-+ &proposal->encrypt->common,
-+ proposal->enckeylen);
-+ }
-+#define A(NAME) \
-+ if (proposal->NAME != NULL) { \
-+ append_algorithm(parser, new, PROPOSAL_##NAME, \
-+ &proposal->NAME->common, 0); \
-+ }
-+ A(prf);
-+ A(integ);
-+ A(dh);
-+#undef A
-+ /* back end? */
-+ if (!proposal->protocol->proposal_ok(parser, new)) {
-+ free_proposal(&new);
-+ return false;
-+ }
-+ append_proposal(proposals, &new);
-+ return true;
-+}
-+
-+/*
-+ * For all the algorithms, when an algorithm is missing (NULL), and
-+ * there are defaults, add them.
-+ */
-+
-+static bool add_proposal_defaults(struct proposal_parser *parser,
-+ const struct proposal_defaults *defaults,
-+ struct proposals *proposals,
-+ const struct v1_proposal *proposal)
-+{
-+ /*
-+ * Note that the order in which things are recursively added -
-+ * MODP, ENCR, PRF/HASH - affects test results. It determines
-+ * things like the order of proposals.
-+ */
-+ if (proposal->dh == NULL &&
-+ defaults != NULL && defaults->dh != NULL) {
-+ return add_alg_defaults(parser, defaults,
-+ proposals, proposal,
-+ &ike_alg_dh, defaults->dh,
-+ merge_dh_default);
-+ } else if (proposal->encrypt == NULL &&
-+ defaults != NULL && defaults->encrypt != NULL) {
-+ return add_alg_defaults(parser, defaults,
-+ proposals, proposal,
-+ &ike_alg_encrypt, defaults->encrypt,
-+ merge_encrypt_default);
-+ } else if (proposal->prf == NULL &&
-+ defaults != NULL && defaults->prf != NULL) {
-+ return add_alg_defaults(parser, defaults,
-+ proposals, proposal,
-+ &ike_alg_prf, defaults->prf,
-+ merge_prf_default);
-+ } else if (proposal->integ == NULL &&
-+ proposal->encrypt != NULL &&
-+ encrypt_desc_is_aead(proposal->encrypt)) {
-+ /*
-+ * Since AEAD, integrity is always 'none'.
-+ */
-+ struct v1_proposal merged_proposal = *proposal;
-+ merged_proposal.integ = &ike_alg_integ_none;
-+ return add_proposal_defaults(parser, defaults,
-+ proposals, &merged_proposal);
-+ } else if (proposal->integ == NULL &&
-+ defaults != NULL && defaults->integ != NULL) {
-+ return add_alg_defaults(parser, defaults,
-+ proposals, proposal,
-+ &ike_alg_integ, defaults->integ,
-+ merge_integ_default);
-+ } else if (proposal->integ == NULL &&
-+ proposal->prf != NULL &&
-+ proposal->encrypt != NULL &&
-+ !encrypt_desc_is_aead(proposal->encrypt)) {
-+ /*
-+ * Since non-AEAD, use an integrity algorithm that is
-+ * implemented using the PRF.
-+ */
-+ struct v1_proposal merged_proposal = *proposal;
-+ for (const struct integ_desc **algp = next_integ_desc(NULL);
-+ algp != NULL; algp = next_integ_desc(algp)) {
-+ const struct integ_desc *alg = *algp;
-+ if (alg->prf == proposal->prf) {
-+ merged_proposal.integ = alg;
-+ break;
-+ }
-+ }
-+ if (merged_proposal.integ == NULL) {
-+ proposal_error(parser, "%s integrity derived from PRF '%s' is not supported",
-+ proposal->protocol->name,
-+ proposal->prf->common.name);
-+ return false;
-+ }
-+ return add_proposal_defaults(parser, defaults,
-+ proposals, &merged_proposal);
-+ } else {
-+ return add_proposal(parser, proposals, proposal);
-+ }
-+}
-+
-+static bool merge_default_proposals(struct proposal_parser *parser,
-+ struct proposals *proposals,
-+ const struct v1_proposal *proposal)
-+{
-+ /*
-+ * If there's a hint of IKEv1 being enabled then prefer its
-+ * larger set of defaults.
-+ *
-+ * This should increase the odds of both ends interoperating.
-+ *
-+ * For instance, the IKEv2 defaults were preferred and one end
-+ * has ikev2=never then, in aggressive mode, things don't
-+ * work.
-+ */
-+ passert(parser->policy->version < elemsof(proposal->protocol->defaults));
-+ const struct proposal_defaults *defaults =
-+ proposal->protocol->defaults[parser->policy->version];
-+ return add_proposal_defaults(parser, defaults,
-+ proposals, proposal);
-+}
-+
-+static const struct ike_alg *lookup_byname(struct proposal_parser *parser,
-+ alg_byname_fn *alg_byname,
-+ shunk_t name,
-+ size_t key_bit_length,
-+ shunk_t print_name,
-+ const char *what)
-+{
-+ if (name.len > 0) {
-+ if (alg_byname != NULL) {
-+ const struct ike_alg *alg = alg_byname(parser, name, key_bit_length,
-+ print_name);
-+ if (alg == NULL) {
-+ DBG(DBG_PROPOSAL_PARSER,
-+ DBG_log("%s_byname('"PRI_SHUNK"') failed: %s",
-+ what, PRI_shunk(name),
-+ parser->error));
-+ passert(parser->error[0] != '\0');
-+ return NULL;
-+ }
-+ DBG(DBG_PROPOSAL_PARSER,
-+ DBG_log("%s_byname('"PRI_SHUNK"') returned '%s'",
-+ what, PRI_shunk(name), alg->name));
-+ return alg;
-+ } else {
-+ DBG(DBG_PROPOSAL_PARSER,
-+ DBG_log("ignoring %s '"PRI_SHUNK"'",
-+ what, PRI_shunk(name)));
-+ return NULL;
-+ }
-+ }
-+ return NULL;
-+}
-+
-+static int parse_eklen(struct proposal_parser *parser, shunk_t buf)
-+{
-+ /* convert - if present */
-+ char *end = NULL;
-+ long eklen = strtol(buf.ptr, &end, 10);
-+ if (buf.ptr + buf.len != end) {
-+ proposal_error(parser, "encryption key length '"PRI_SHUNK"' contains a non-numeric character",
-+ PRI_shunk(buf));
-+ return 0;
-+ }
-+ if (eklen >= INT_MAX) {
-+ proposal_error(parser, "encryption key length '"PRI_SHUNK"' WAY too big",
-+ PRI_shunk(buf));
-+ return 0;
-+ }
-+ if (eklen == 0) {
-+ proposal_error(parser, "encryption key length is zero");
-+ return 0;
-+ }
-+ return eklen;
-+}
-+
-+/*
-+ * Try to parse any of -, _,
-+ * , or . Strings like aes_gcm_16 and
-+ * aes_gcm_16_256 end up in alg[0], while strings like aes_gcm_16-256
-+ * end up in alg[0]-alg[1].
-+ */
-+
-+struct token {
-+ char sep;
-+ shunk_t alg;
-+};
-+
-+static bool parse_encrypt(struct proposal_parser *parser,
-+ struct token **tokens,
-+ struct v1_proposal *proposal)
-+{
-+ shunk_t ealg = (*tokens)[0].alg;
-+ shunk_t eklen = (*tokens)[1].alg;
-+ if (eklen.len > 0 && isdigit(eklen.ptr[0])) {
-+ /* assume - */
-+ int enckeylen = parse_eklen(parser, eklen);
-+ if (enckeylen <= 0) {
-+ passert(parser->error[0] != '\0');
-+ return false;
-+ }
-+ /* print - */
-+ shunk_t print_name = shunk2(ealg.ptr, eklen.ptr + eklen.len - ealg.ptr);
-+ proposal->enckeylen = enckeylen;
-+ proposal->encrypt =
-+ encrypt_desc(lookup_byname(parser,
-+ encrypt_alg_byname,
-+ ealg, proposal->enckeylen,
-+ print_name, "encryption"));
-+ /* Was - rejected? */
-+ if (parser->error[0] != '\0') {
-+ return false;
-+ }
-+ *tokens += 2; /* consume both tokens */
-+ return true;
-+ }
-+ /* try */
-+ shunk_t print_name = ealg;
-+ proposal->encrypt =
-+ encrypt_desc(lookup_byname(parser,
-+ encrypt_alg_byname,
-+ ealg, proposal->enckeylen,
-+ print_name, "encryption"));
-+ if (parser->error[0] != '\0') {
-+ /*
-+ * Could it be or _? Work
-+ * backwards skipping any digits.
-+ */
-+ shunk_t end = shunk2(ealg.ptr + ealg.len, 0);
-+ while (end.ptr > ealg.ptr && isdigit(end.ptr[-1])) {
-+ end.ptr--;
-+ end.len++;
-+ }
-+ if (end.len == 0) {
-+ /*
-+ * no trailing and was rejected
-+ */
-+ passert(parser->error[0] != '\0');
-+ return false;
-+ }
-+ /* try to convert */
-+ int enckeylen = parse_eklen(parser, end);
-+ if (enckeylen <= 0) {
-+ passert(parser->error[0] != '\0');
-+ return false;
-+ }
-+ proposal->enckeylen = enckeylen;
-+ /*
-+ * trim from ; and then trim any
-+ * trailing '_'
-+ */
-+ ealg.len = end.ptr - ealg.ptr;
-+ if (end.ptr > ealg.ptr && end.ptr[-1] == '_') {
-+ ealg.len -= 1;
-+ }
-+ /* try again */
-+ parser->error[0] = '\0';
-+ proposal->encrypt =
-+ encrypt_desc(lookup_byname(parser,
-+ encrypt_alg_byname,
-+ ealg, proposal->enckeylen,
-+ print_name, "encryption"));
-+ if (parser->error[0] != '\0') {
-+ return false;
-+ }
-+ }
-+ *tokens += 1; /* consume one token */
-+ return true;
-+}
-+
-+static bool parser_proposals_add(struct proposal_parser *parser,
-+ struct token *tokens, struct v1_proposal proposal,
-+ struct proposals *proposals)
-+{
-+ LSWDBGP(DBG_PROPOSAL_PARSER, buf) {
-+ lswlogs(buf, "algs:");
-+ for (struct token *token = tokens; token->alg.ptr != NULL; token++) {
-+ lswlogf(buf, " algs[%tu] = '"PRI_SHUNK"'",
-+ token - tokens, PRI_shunk(token->alg));
-+ }
-+ }
-+
-+ bool lookup_encrypt = parser->protocol->encrypt_alg_byname != NULL;
-+ if (!lookup_encrypt && IMPAIR(PROPOSAL_PARSER)) {
-+ /* Force lookup, will discard any error. */
-+ lookup_encrypt = true;
-+ }
-+ if (lookup_encrypt && tokens->alg.ptr != NULL && tokens->sep != ';') {
-+ if (!parse_encrypt(parser, &tokens, &proposal)) {
-+ if (IMPAIR(PROPOSAL_PARSER)) {
-+ /* ignore the lookup and stumble on */
-+ parser->error[0] = '\0';
-+ } else {
-+ passert(parser->error[0] != '\0');
-+ return false;
-+ }
-+ }
-+ }
-+
-+ bool lookup_prf = parser->protocol->prf_alg_byname != NULL;
-+ if (!lookup_prf && IMPAIR(PROPOSAL_PARSER)) {
-+ /*
-+ * When impaired, only force PRF lookup when the the
-+ * token after this one is a valid INTEG algorithm.
-+ * Otherwise something like ah=sha1 gets parsed as
-+ * ah=[encr]-sha1-[integ]-[dh] instead of
-+ * ah=[encr]-[prf]-sha1-[dh].
-+ */
-+ shunk_t prf = tokens[0].alg;
-+ shunk_t integ = tokens[1].alg;
-+ if (prf.ptr != NULL && integ.ptr != NULL) {
-+ lookup_prf = (lookup_byname(parser, integ_alg_byname,
-+ integ, 0, integ, "integrity")
-+ != NULL);
-+ parser->error[0] = '\0';
-+ }
-+ }
-+ if (lookup_prf && tokens->alg.ptr != NULL && tokens->sep != ';') {
-+ shunk_t prf = tokens[0].alg;
-+ proposal.prf = prf_desc(lookup_byname(parser,
-+ prf_alg_byname,
-+ prf, 0, prf, "PRF"));
-+ if (parser->error[0] != '\0') {
-+ return false;
-+ }
-+ tokens += 1; /* consume one arg */
-+ }
-+
-+ /*
-+ * By default, don't allow IKE's [...]---[....].
-+ * Instead fill in integrity using the above PRF.
-+ *
-+ * XXX: The parser and output isn't consistent in that for ESP
-+ * it parses - but for IKE it parses
-+ * -. This seems to lead to confusion when
-+ * printing proposals - ike=aes_gcm-sha1 gets mis-read as as
-+ * using sha1 as integrity. ike-aes_gcm-none-sha1 would
-+ * clarify this but that makes for a fun parse.
-+ */
-+ bool lookup_integ = (parser->protocol->prf_alg_byname == NULL &&
-+ parser->protocol->integ_alg_byname != NULL);
-+ if (!lookup_integ && IMPAIR(PROPOSAL_PARSER)) {
-+ /* force things */
-+ lookup_integ = true;
-+ }
-+ if (lookup_integ && tokens->alg.ptr != NULL && tokens->sep != ';') {
-+ shunk_t integ = tokens[0].alg;
-+ proposal.integ = integ_desc(lookup_byname(parser,
-+ integ_alg_byname,
-+ integ, 0, integ, "integrity"));
-+ if (parser->error[0] != '\0') {
-+ if (tokens[1].alg.ptr != NULL) {
-+ /*
-+ * This alg should have been
-+ * integrity, since the next would be
-+ * DH; error applies.
-+ */
-+ passert(parser->error[0] != '\0');
-+ return false;
-+ }
-+ if (tokens[1].alg.ptr == NULL &&
-+ parser->protocol->prf_alg_byname == NULL) {
-+ /*
-+ * Only one arg, integrity is prefered
-+ * to DH (and no PRF); error applies.
-+ */
-+ passert(parser->error[0] != '\0');
-+ return false;
-+ }
-+ /* let DH try */
-+ parser->error[0] = '\0';
-+ } else {
-+ tokens += 1; /* consume one arg */
-+ }
-+ }
-+
-+ bool lookup_dh = parser->protocol->dh_alg_byname || IMPAIR(PROPOSAL_PARSER);
-+ if (lookup_dh && tokens->alg.ptr != NULL) {
-+ shunk_t dh = tokens[0].alg;
-+ proposal.dh = oakley_group_desc(lookup_byname(parser,
-+ dh_alg_byname,
-+ dh, 0,
-+ dh, "DH"));
-+ if (parser->error[0] != '\0') {
-+ return false;
-+ }
-+ tokens += 1; /* consume one arg */
-+ }
-+
-+ if (tokens->alg.ptr != NULL) {
-+ proposal_error(parser, "'"PRI_SHUNK"' unexpected",
-+ PRI_shunk(tokens[0].alg));
-+ return false;
-+ }
-+
-+ if (IMPAIR(PROPOSAL_PARSER)) {
-+ return add_proposal(parser, proposals, &proposal);
-+ } else {
-+ return merge_default_proposals(parser, proposals, &proposal);
-+ }
-+}
-+
-+bool v1_proposals_parse_str(struct proposal_parser *parser,
-+ struct proposals *proposals,
-+ shunk_t alg_str)
-+{
-+ DBG(DBG_PROPOSAL_PARSER,
-+ DBG_log("parsing '"PRI_SHUNK"' for %s",
-+ PRI_shunk(alg_str), parser->protocol->name));
-+
-+ /* use default if no string */
-+ if (alg_str.ptr == NULL) {
-+ const struct v1_proposal proposal = {
-+ .protocol = parser->protocol,
-+ };
-+ return merge_default_proposals(parser, proposals, &proposal);
-+ }
-+
-+ if (alg_str.len == 0) {
-+ /* XXX: hack to keep testsuite happy */
-+ proposal_error(parser, "String ended with invalid char, just after \"\"");
-+ return false;
-+ }
-+
-+ shunk_t prop_ptr = alg_str;
-+ do {
-+ /* find the next proposal */
-+ shunk_t prop = shunk_strsep(&prop_ptr, ",");
-+ /* parse it */
-+ struct token tokens[8];
-+ zero(&tokens);
-+ struct token *token = tokens;
-+ char last_sep = '\0';
-+ shunk_t alg_ptr = prop;
-+ do {
-+ if (token + 1 >= tokens+elemsof(tokens)) {
-+ /* space for NULL? */
-+ proposal_error(parser, "proposal too long");
-+ return false;
-+ }
-+ /* find the next alg */
-+ shunk_t alg = shunk_strsep(&alg_ptr, "-;,");
-+ *token++ = (struct token) {
-+ .alg = alg,
-+ .sep = last_sep,
-+ };
-+ last_sep = alg.ptr[alg.len]; /* save separator */
-+ } while (alg_ptr.len > 0);
-+ struct v1_proposal proposal = {
-+ .protocol = parser->protocol,
-+ };
-+ if (!parser_proposals_add(parser, tokens, proposal,
-+ proposals)) {
-+ passert(parser->error[0] != '\0');
-+ return false;
-+ }
-+ } while (prop_ptr.len > 0);
-+ return true;
-+}
-diff -Naur libreswan-3.27-orig/lib/libswan/v2_proposals.c libreswan-3.27/lib/libswan/v2_proposals.c
---- libreswan-3.27-orig/lib/libswan/v2_proposals.c 1969-12-31 19:00:00.000000000 -0500
-+++ libreswan-3.27/lib/libswan/v2_proposals.c 2019-02-15 16:49:23.278267768 -0500
-@@ -0,0 +1,398 @@
-+/* V2 algorithm proposal parsing, 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
-+#include
-+#include
-+
-+#include "lswlog.h"
-+#include "lswalloc.h"
-+#include "constants.h"
-+#include "proposals.h"
-+#include "ike_alg.h"
-+#include "ike_alg_integ.h"
-+#include "ike_alg_dh.h"
-+#include "alg_byname.h"
-+
-+/*
-+ * For all the algorithms, when an algorithm is missing (NULL), and
-+ * there are defaults, add them.
-+ */
-+
-+static void merge_algorithms(struct proposal_parser *parser,
-+ struct proposal *proposal,
-+ enum proposal_algorithm algorithm,
-+ const struct ike_alg **defaults)
-+{
-+ if (defaults == NULL) {
-+ return;
-+ }
-+ if (next_algorithm(proposal, algorithm, NULL) != NULL) {
-+ return;
-+ }
-+ for (const struct ike_alg **alg = defaults; (*alg) != NULL; alg++) {
-+ append_algorithm(parser, proposal, algorithm, *alg, 0);
-+ }
-+}
-+
-+static bool merge_defaults(struct proposal_parser *parser,
-+ struct proposal *proposal)
-+{
-+ pexpect(parser->policy->version < elemsof(parser->protocol->defaults));
-+ const struct proposal_defaults *defaults =
-+ parser->protocol->defaults[parser->policy->version];
-+ merge_algorithms(parser, proposal, PROPOSAL_encrypt, defaults->encrypt);
-+ merge_algorithms(parser, proposal, PROPOSAL_prf, defaults->prf);
-+ if (next_algorithm(proposal, PROPOSAL_integ, NULL) == NULL) {
-+ if (proposal_encrypt_aead(proposal)) {
-+ /*
-+ * Since AEAD, integrity is always 'none'.
-+ */
-+ append_algorithm(parser, proposal, PROPOSAL_integ,
-+ &ike_alg_integ_none.common, 0);
-+ } else if (defaults->integ != NULL) {
-+ /*
-+ * Merge in the defaults.
-+ */
-+ merge_algorithms(parser, proposal, PROPOSAL_integ,
-+ defaults->integ);
-+ } else if (next_algorithm(proposal, PROPOSAL_prf, NULL) != NULL &&
-+ proposal_encrypt_norm(proposal)) {
-+ /*
-+ * Since non-AEAD, use integrity algorithms
-+ * that are implemented using the PRFs.
-+ */
-+ FOR_EACH_ALGORITHM(proposal, prf, prf) {
-+ const struct integ_desc *integ = NULL;
-+ for (const struct integ_desc **integp = next_integ_desc(NULL);
-+ integp != NULL; integp = next_integ_desc(integp)) {
-+ if ((*integp)->prf != NULL &&
-+ &(*integp)->prf->common == prf->desc) {
-+ integ = *integp;
-+ break;
-+ }
-+ }
-+ if (integ == NULL) {
-+ proposal_error(parser, "%s integrity derived from PRF '%s' is not supported",
-+ parser->protocol->name,
-+ prf->desc->name);
-+ return false;
-+ }
-+ append_algorithm(parser, proposal, PROPOSAL_integ,
-+ &integ->common, 0);
-+ }
-+ }
-+ }
-+ merge_algorithms(parser, proposal, PROPOSAL_dh, defaults->dh);
-+ return true;
-+}
-+
-+static bool parse_alg(struct proposal_parser *parser,
-+ struct proposal *proposal,
-+ enum proposal_algorithm algorithm,
-+ alg_byname_fn *alg_byname,
-+ shunk_t token, int enckeylen, shunk_t print,
-+ const char *what)
-+{
-+ if (alg_byname == NULL) {
-+ /* n/a */
-+ return false;
-+ }
-+ if (token.len == 0) {
-+ /* will error at end */
-+ return false;
-+ }
-+ const struct ike_alg *alg = alg_byname(parser, token, enckeylen, print);
-+ if (alg == NULL) {
-+ if (DBGP(DBG_PROPOSAL_PARSER)) {
-+ DBG_log("%s_byname('"PRI_SHUNK"') failed: %s",
-+ what, PRI_shunk(token),
-+ parser->error);
-+ }
-+ pexpect(parser->error[0] != '\0');
-+ return false;
-+ }
-+ DBGF(DBG_PROPOSAL_PARSER, "adding %s algorithm %s[_%d]",
-+ what, alg->name, enckeylen);
-+ append_algorithm(parser, proposal, algorithm, alg, enckeylen);
-+ return true;
-+}
-+
-+/*
-+ * tokenize into
-+ */
-+
-+struct token {
-+ char delim;
-+ shunk_t alg;
-+ shunk_t input;
-+};
-+
-+static void next(struct token *token)
-+{
-+ if (token->delim == '\0') {
-+ /* first call, set delim to something bogus */
-+ token->delim = ' ';
-+ } else {
-+ token->delim = token->input.ptr != NULL ? token->input.ptr[-1] : ' ';
-+ }
-+ token->alg = shunk_strsep(&token->input, "-;+");
-+ if (DBGP(DBG_PROPOSAL_PARSER)) {
-+ if (token->alg.ptr == NULL) {
-+ DBG_log("delim: n/a alg: end-of-input");
-+ } else {
-+ DBG_log("delim: '%c' alg: '"PRI_SHUNK"'",
-+ token->delim, PRI_shunk(token->alg));
-+ }
-+ }
-+}
-+
-+/*
-+ * Try to parse any of -, _,
-+ * , or using some look-ahead.
-+ */
-+
-+static int parse_eklen(struct proposal_parser *parser, shunk_t buf)
-+{
-+ /* convert - if present */
-+ char *end = NULL;
-+ long eklen = strtol(buf.ptr, &end, 10);
-+ if (buf.ptr + buf.len != end) {
-+ proposal_error(parser, "encryption key length '"PRI_SHUNK"' contains a non-numeric character",
-+ PRI_shunk(buf));
-+ return 0;
-+ }
-+ if (eklen >= INT_MAX) {
-+ proposal_error(parser, "encryption key length '"PRI_SHUNK"' WAY too big",
-+ PRI_shunk(buf));
-+ return 0;
-+ }
-+ if (eklen == 0) {
-+ proposal_error(parser, "encryption key length is zero");
-+ return 0;
-+ }
-+ return eklen;
-+}
-+
-+static bool parse_encrypt(struct proposal_parser *parser,
-+ struct proposal *proposal, struct token *token)
-+{
-+ alg_byname_fn *alg_byname = parser->protocol->encrypt_alg_byname;
-+ if (alg_byname == NULL) {
-+ return false;
-+ }
-+ if (token->alg.len == 0) {
-+ return false;
-+ }
-+ shunk_t ealg = token->alg;
-+ /* try - using look-ahead? */
-+ struct token lookahead = *token;
-+ next(&lookahead);
-+ if (lookahead.delim == '-' &&
-+ lookahead.alg.len > 0 &&
-+ isdigit(lookahead.alg.ptr[0])) {
-+ shunk_t eklen = lookahead.alg;
-+ /* assume - */
-+ int enckeylen = parse_eklen(parser, eklen);
-+ if (enckeylen <= 0) {
-+ pexpect(parser->error[0] != '\0');
-+ return false;
-+ }
-+ /* print "-" in errors */
-+ shunk_t print_name = shunk2(ealg.ptr, eklen.ptr + eklen.len - ealg.ptr);
-+ if (!parse_alg(parser, proposal, PROPOSAL_encrypt, alg_byname,
-+ ealg, enckeylen, print_name, "encrypt")) {
-+ return false;
-+ }
-+ *token = lookahead;
-+ return true;
-+ }
-+ /* try (no key len) */
-+ shunk_t print_name = token->alg;
-+ if (!parse_alg(parser, proposal, PROPOSAL_encrypt, alg_byname,
-+ ealg, 0, print_name, "encrypt")) {
-+ /*
-+ * Could it be or _? Work
-+ * backwards skipping any digits.
-+ */
-+ shunk_t end = shunk2(ealg.ptr + ealg.len, 0);
-+ while (end.ptr > ealg.ptr && isdigit(end.ptr[-1])) {
-+ end.ptr--;
-+ end.len++;
-+ }
-+ if (end.len == 0) {
-+ /*
-+ * no trailing and was rejected
-+ */
-+ pexpect(parser->error[0] != '\0');
-+ return false;
-+ }
-+ /* try to convert */
-+ int enckeylen = parse_eklen(parser, end);
-+ if (enckeylen <= 0) {
-+ pexpect(parser->error[0] != '\0');
-+ return false;
-+ }
-+ /*
-+ * trim from ; and then trim any
-+ * trailing '_'
-+ */
-+ ealg.len = end.ptr - ealg.ptr;
-+ if (end.ptr > ealg.ptr && end.ptr[-1] == '_') {
-+ ealg.len -= 1;
-+ }
-+ /* try again */
-+ if (!parse_alg(parser, proposal, PROPOSAL_encrypt, alg_byname,
-+ ealg, enckeylen, print_name, "encrypt")) {
-+ return false;
-+ }
-+ }
-+ return true;
-+}
-+
-+static bool parse_proposal(struct proposal_parser *parser,
-+ struct proposals *proposals UNUSED, shunk_t input)
-+{
-+ if (DBGP(DBG_PROPOSAL_PARSER)) {
-+ DBG_log("proposal: '"PRI_SHUNK"'", PRI_shunk(input));
-+ }
-+
-+ char error[sizeof(parser->error)] = "";
-+ struct proposal *proposal = alloc_proposal(parser);
-+
-+ struct token token = {
-+ .input = input,
-+ };
-+ next(&token);
-+ /*
-+ * Encryption is not optional.
-+ */
-+ bool lookup_encrypt = parser->protocol->encrypt_alg_byname != NULL;
-+ if (lookup_encrypt) {
-+ if (!parse_encrypt(parser, proposal, &token)) {
-+ free_proposal(&proposal);
-+ return false;
-+ }
-+ error[0] = parser->error[0] = '\0';
-+ next(&token);
-+ while (token.delim == '+' &&
-+ parse_encrypt(parser, proposal, &token)) {
-+ error[0] = parser->error[0] = '\0';
-+ next(&token);
-+ }
-+ }
-+#define PARSE_ALG(STOP, ALG) \
-+ if (error[0] == '\0' && parser->error[0] != '\0') { \
-+ strcpy(error, parser->error); \
-+ DBGF(DBG_PROPOSAL_PARSER, "saved first error: %s", error); \
-+ } \
-+ if (token.delim != STOP && \
-+ parse_alg(parser, proposal, PROPOSAL_##ALG, \
-+ parser->protocol->ALG##_alg_byname, \
-+ token.alg, 0, token.alg, #ALG)) { \
-+ error[0] = parser->error[0] = '\0'; \
-+ next(&token); \
-+ while (token.delim == '+' && \
-+ parse_alg(parser, proposal, PROPOSAL_##ALG, \
-+ parser->protocol->ALG##_alg_byname, \
-+ token.alg, 0, token.alg, #ALG)) { \
-+ error[0] = parser->error[0] = '\0'; \
-+ next(&token); \
-+ } \
-+ }
-+ PARSE_ALG(';', prf);
-+ /*
-+ * By default, don't allow ike=...---... but do
-+ * allow esp=...-. In the case of IKE, when integrity
-+ * is required, it is filled in using the PRF.
-+ *
-+ * XXX: The parser and output isn't consistent in that for ESP
-+ * it parses - but for IKE it parses
-+ * -. This seems to lead to confusion when
-+ * printing proposals - ike=aes_gcm-sha1 gets mis-read as as
-+ * using sha1 as integrity. ike-aes_gcm-none-sha1 would
-+ * clarify this but that makes for a fun parse.
-+ */
-+ if (parser->protocol->prf_alg_byname == NULL ||
-+ IMPAIR(PROPOSAL_PARSER)) {
-+ PARSE_ALG(';', integ);
-+ }
-+ PARSE_ALG('\0', dh);
-+ if (error[0] != '\0') {
-+ DBGF(DBG_PROPOSAL_PARSER, "return first error: %s", error);
-+ free_proposal(&proposal);
-+ strcpy(parser->error, error);
-+ return false;
-+ }
-+ if (parser->error[0] != '\0') {
-+ DBGF(DBG_PROPOSAL_PARSER, "return last error: %s", parser->error);
-+ free_proposal(&proposal);
-+ return false;
-+ }
-+ if (token.alg.ptr != NULL) {
-+ proposal_error(parser, "'"PRI_SHUNK"' unexpected",
-+ PRI_shunk(token.alg));
-+ free_proposal(&proposal);
-+ return false;
-+ }
-+ if (!IMPAIR(PROPOSAL_PARSER) &&
-+ !merge_defaults(parser, proposal)) {
-+ free_proposal(&proposal);
-+ return false;
-+ }
-+ /* back end? */
-+ if (!parser->protocol->proposal_ok(parser, proposal)) {
-+ free_proposal(&proposal);
-+ return false;
-+ }
-+ append_proposal(proposals, &proposal);
-+ return true;
-+}
-+
-+bool v2_proposals_parse_str(struct proposal_parser *parser,
-+ struct proposals *proposals,
-+ shunk_t input)
-+{
-+ DBG(DBG_PROPOSAL_PARSER,
-+ DBG_log("parsing '"PRI_SHUNK"' for %s",
-+ PRI_shunk(input), parser->protocol->name));
-+
-+ /* use default if no string */
-+ if (input.ptr == NULL) {
-+ struct proposal *proposal = alloc_proposal(parser);
-+ if (!merge_defaults(parser, proposal)) {
-+ free_proposal(&proposal);
-+ return false;
-+ }
-+ append_proposal(proposals, &proposal);
-+ return true;
-+ }
-+
-+ if (input.len == 0) {
-+ /* XXX: hack to keep testsuite happy */
-+ proposal_error(parser, "String ended with invalid char, just after \"\"");
-+ return false;
-+ }
-+
-+ do {
-+ /* find the next proposal */
-+ shunk_t proposal = shunk_strsep(&input, ",");
-+ if (!parse_proposal(parser, proposals, proposal)) {
-+ pexpect(parser->error[0] != '\0');
-+ return false;
-+ }
-+ } while (input.len > 0);
-+ return true;
-+}
-diff -Naur libreswan-3.27-orig/programs/algparse/algparse.c libreswan-3.27/programs/algparse/algparse.c
---- libreswan-3.27-orig/programs/algparse/algparse.c 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/programs/algparse/algparse.c 2019-02-15 16:49:23.278267768 -0500
-@@ -9,15 +9,15 @@
- #include "lswconf.h"
-
- #include "ike_alg.h"
--#include "alg_info.h"
-+#include "proposals.h"
-
- static bool test_proposals = false;
- static bool test_algs = false;
- static bool verbose = false;
- static bool debug = false;
- static bool impair = false;
--static bool ikev1 = false;
--static bool ikev2 = false;
-+static enum ike_version ike_version = IKEv2;
-+static unsigned parser_version = 0;
- static bool fips = false;
- static bool pfs = false;
- static int failures = 0;
-@@ -25,23 +25,23 @@
- enum status { PASSED = 0, FAILED = 1, ERROR = 126, };
- enum expect { FAIL = false, PASS = true, COUNT, };
-
--#define CHECK(TYPE,PARSE,OK) { \
-+#define CHECK(CHECK,PARSE,OK) { \
- struct proposal_policy policy = { \
-- .ikev1 = ikev1, \
-- .ikev2 = ikev2, \
-+ .version = ike_version, \
-+ .parser_version = parser_version, \
- .alg_is_ok = OK, \
- .pfs = pfs, \
- .warning = warning, \
-+ .check_pfs_vs_dh = CHECK, \
- }; \
- printf("algparse "); \
- if (fips) { \
- printf("-fips "); \
- } \
-- if (ikev1) { \
-- printf("-v1 "); \
-- } \
-- if (ikev2) { \
-- printf("-v2 "); \
-+ switch (ike_version) { \
-+ case IKEv1: printf("-v1 "); break; \
-+ case IKEv2: printf("-v2 "); break; \
-+ default: break; \
- } \
- if (pfs) { \
- printf("-pfs "); \
-@@ -52,21 +52,19 @@
- printf("'%s=%s'\n", #PARSE, algstr); \
- } \
- fflush(NULL); \
-- char err_buf[512] = ""; /* ??? big enough? */ \
-- struct alg_info_##TYPE *e = \
-- alg_info_##PARSE##_create_from_str(&policy, \
-- algstr, \
-- err_buf, \
-- sizeof(err_buf)); \
-- if (e != NULL) { \
-- passert(err_buf[0] == '\0'); \
-- FOR_EACH_PROPOSAL_INFO(&e->ai, proposal) { \
-+ struct proposal_parser *parser = \
-+ PARSE##_proposal_parser(&policy); \
-+ struct proposals *proposals = \
-+ proposals_from_str(parser, algstr); \
-+ if (proposals != NULL) { \
-+ pexpect(parser->error[0] == '\0'); \
-+ FOR_EACH_PROPOSAL(proposals, proposal) { \
- LSWLOG_FILE(stdout, log) { \
- lswlogf(log, "\t"); \
-- lswlog_proposal_info(log, proposal); \
-+ fmt_proposal(log, proposal); \
- } \
- } \
-- alg_info_free(&e->ai); \
-+ proposals_delref(&proposals); \
- if (expected == FAIL) { \
- failures++; \
- fprintf(stderr, \
-@@ -76,8 +74,8 @@
- algstr == NULL ? "" : algstr); \
- } \
- } else { \
-- passert(err_buf[0]); \
-- printf("\tERROR: %s\n", err_buf); \
-+ pexpect(parser->error[0]); \
-+ printf("\tERROR: %s\n", parser->error); \
- if (expected == PASS) { \
- failures++; \
- fprintf(stderr, \
-@@ -89,6 +87,7 @@
- failures++; \
- } \
- } \
-+ free_proposal_parser(&parser); \
- fflush(NULL); \
- }
-
-@@ -122,17 +121,17 @@
-
- static void esp(enum expect expected, const char *algstr)
- {
-- CHECK(esp, esp, kernel_alg_is_ok);
-+ CHECK(true, esp, kernel_alg_is_ok);
- }
-
- static void ah(enum expect expected, const char *algstr)
- {
-- CHECK(esp, ah, kernel_alg_is_ok);
-+ CHECK(true, ah, kernel_alg_is_ok);
- }
-
- static void ike(enum expect expected, const char *algstr)
- {
-- CHECK(ike, ike, ike_alg_is_ike);
-+ CHECK(false, ike, ike_alg_is_ike);
- }
-
- typedef void (protocol_t)(enum expect expected, const char *);
-@@ -203,8 +202,8 @@
- esp(!fips, "3des-sha1;modp1024");
- esp(!fips, "3des-sha1;modp1536");
- esp(true, "3des-sha1;modp2048");
-- esp(!ikev1, "3des-sha1;dh21");
-- esp(!ikev1, "3des-sha1;ecp_521");
-+ esp(ike_version == IKEv2, "3des-sha1;dh21");
-+ esp(ike_version == IKEv2, "3des-sha1;ecp_521");
- esp(false, "3des-sha1;dh23");
- esp(false, "3des-sha1;dh24");
- esp(true, "3des-sha1");
-@@ -218,7 +217,7 @@
- esp(true, "aes-sha384");
- esp(true, "aes-sha512");
- esp(true, "aes128-sha1");
-- esp(true, "aes128-aes_xcbc");
-+ esp(!fips, "aes128-aes_xcbc");
- esp(true, "aes192-sha1");
- esp(true, "aes256-sha1");
- esp(true, "aes256-sha");
-@@ -300,18 +299,18 @@
- esp(!fips, "twofish");
-
- esp(!fips, "camellia_cbc_256-hmac_sha2_512_256;modp8192"); /* long */
-- esp(!fips, "null_auth_aes_gmac_256-null;modp8192"); /* long */
-+ esp(true, "null_auth_aes_gmac_256-null;modp8192"); /* long */
- esp(true, "3des-sha1;modp8192"); /* allow ';' when unambigious */
- esp(true, "3des-sha1-modp8192"); /* allow '-' when unambigious */
- esp(!pfs, "aes-sha1,3des-sha1;modp8192");
- esp(true, "aes-sha1-modp8192,3des-sha1-modp8192"); /* silly */
- esp(true, "aes-sha1-modp8192,aes-sha1-modp8192,aes-sha1-modp8192"); /* suppress duplicates */
-
-- esp(!ikev1, "aes;none");
-- esp(!ikev1 && !pfs, "aes;none,aes");
-- esp(!ikev1, "aes;none,aes;modp2048");
-- esp(!ikev1, "aes-sha1-none");
-- esp(!ikev1, "aes-sha1;none");
-+ esp(ike_version == IKEv2, "aes;none");
-+ esp(ike_version == IKEv2 && !pfs, "aes;none,aes");
-+ esp(ike_version == IKEv2, "aes;none,aes;modp2048");
-+ esp(ike_version == IKEv2, "aes-sha1-none");
-+ esp(ike_version == IKEv2, "aes-sha1;none");
-
- /*
- * should this be supported - for now man page says not
-@@ -374,9 +373,9 @@
- ah(true, "sha2_256");
- ah(true, "sha2_384");
- ah(true, "sha2_512");
-- ah(true, "aes_xcbc");
-- ah(!ikev1, "sha2-none");
-- ah(!ikev1, "sha2;none");
-+ ah(!fips, "aes_xcbc");
-+ ah(ike_version == IKEv2, "sha2-none");
-+ ah(ike_version == IKEv2, "sha2;none");
- ah(true, "sha1-modp8192,sha1-modp8192,sha1-modp8192"); /* suppress duplicates */
- ah(impair, "aes-sha1");
- ah(false, "vanityhash1");
-@@ -400,12 +399,15 @@
- ike(true, "3des;dh21");
- ike(true, "3des-sha1;dh21");
- ike(true, "3des-sha1-ecp_521");
-- ike(!ikev1, "aes_gcm");
-+ ike(ike_version == IKEv2, "aes_gcm");
- ike(true, "aes-sha1-modp8192,aes-sha1-modp8192,aes-sha1-modp8192"); /* suppress duplicates */
- ike(false, "aes;none");
- ike(false, "id2"); /* should be rejected; idXXX removed */
- ike(false, "3des-id2"); /* should be rejected; idXXX removed */
- ike(false, "aes_ccm"); /* ESP/AH only */
-+ ike(impair, "aes_gcm-sha1-none-modp2048");
-+ ike(impair, "aes_gcm+aes_gcm-sha1-none-modp2048");
-+ ike(false, "aes+aes_gcm"); /* mixing AEAD and NORM encryption */
- }
-
- static void usage(void)
-@@ -432,9 +434,8 @@
- "\n"
- "Additional options:\n"
- "\n"
-- " -v1 | -ikev1: require IKEv1 support\n"
-- " -v2 | -ikev2: require IKEv2 support\n"
-- " default: require either IKEv1 or IKEv2 support\n"
-+ " -v2 | -ikev2: configure for IKEv2 (default)\n"
-+ " -v1 | -ikev1: configure for IKEv1\n"
- " -pfs | -pfs=yes | -pfs=no: specify PFS (perfect forward privicy)\n"
- " default: no\n"
- " -fips | -fips=yes | -fips=no: force NSS's FIPS mode\n"
-@@ -446,6 +447,8 @@
- " -v --verbose: be more verbose\n"
- " -d --debug: enable debug logging\n"
- " -i --impair: disable all algorithm parser checks\n"
-+ " -p1: simple parser\n"
-+ " -p2: complex parser\n"
- "\n"
- "Examples:\n"
- "\n"
-@@ -483,10 +486,14 @@
- test_proposals = true;
- } else if (streq(arg, "ta")) {
- test_algs = true;
-+ } else if (streq(arg, "p1")) {
-+ parser_version = 1;
-+ } else if (streq(arg, "p2")) {
-+ parser_version = 2;
- } else if (streq(arg, "v1") || streq(arg, "ikev1")) {
-- ikev1 = true;
-+ ike_version = IKEv1;
- } else if (streq(arg, "v2") || streq(arg, "ikev2")) {
-- ikev2 = true;
-+ ike_version = IKEv2;
- } else if (streq(arg, "pfs") || streq(arg, "pfs=yes") || streq(arg, "pfs=on")) {
- pfs = true;
- } else if (streq(arg, "pfs=no") || streq(arg, "pfs=off")) {
-diff -Naur libreswan-3.27-orig/programs/pluto/connections.c libreswan-3.27/programs/pluto/connections.c
---- libreswan-3.27-orig/programs/pluto/connections.c 2019-02-15 16:31:43.031408048 -0500
-+++ libreswan-3.27/programs/pluto/connections.c 2019-02-15 16:32:28.986835407 -0500
-@@ -69,7 +69,7 @@
- #include "peerlog.h"
- #include "keys.h"
- #include "whack.h"
--#include "alg_info.h"
-+#include "proposals.h"
- #include "spdb.h"
- #include "ike_alg.h"
- #include "kernel_alg.h"
-@@ -352,17 +352,13 @@
- sr = next_sr;
- }
-
-- if (c->alg_info_ike != NULL) {
-- alg_info_delref(&c->alg_info_ike->ai);
-- c->alg_info_ike = NULL;
-- }
-- free_ikev2_proposals(&c->ike_proposals);
-+ proposals_delref(&c->ike_proposals.p);
-+ proposals_delref(&c->child_proposals.p);
-
-- if (c->alg_info_esp != NULL) {
-- alg_info_delref(&c->alg_info_esp->ai);
-- c->alg_info_esp = NULL;
-- }
-- free_ikev2_proposals(&c->esp_or_ah_proposals);
-+ free_ikev2_proposals(&c->v2_ike_proposals);
-+ free_ikev2_proposals(&c->v2_ike_auth_child_proposals);
-+ free_ikev2_proposals(&c->v2_create_child_proposals);
-+ c->v2_create_child_proposals_default_dh = NULL; /* static pointer */
-
- pfree(c);
- }
-@@ -807,11 +803,8 @@
- }
-
- /* increment references to algo's, if any */
-- if (c->alg_info_ike != NULL)
-- alg_info_addref(&c->alg_info_ike->ai);
--
-- if (c->alg_info_esp != NULL)
-- alg_info_addref(&c->alg_info_esp->ai);
-+ proposals_addref(&c->ike_proposals.p);
-+ proposals_addref(&c->child_proposals.p);
-
- if (c->pool != NULL)
- reference_addresspool(c);
-@@ -1496,8 +1489,6 @@
- c->connalias = wm->connalias;
- c->dnshostname = wm->dnshostname;
- c->policy = wm->policy;
-- c->alg_info_ike = NULL;
-- c->alg_info_esp = NULL;
- c->sighash_policy = wm->sighash_policy;
-
- if (NEVER_NEGOTIATE(c->policy)) {
-@@ -1556,49 +1547,35 @@
- /* IKE cipher suites */
-
- if (!LIN(POLICY_AUTH_NEVER, wm->policy) && wm->ike != NULL) {
-- char err_buf[256] = ""; /* ??? big enough? */
-
- const struct proposal_policy proposal_policy = {
-- .ikev1 = LIN(POLICY_IKEV1_ALLOW, wm->policy),
-- /*
-- * logic needs to match pick_initiator()
-- *
-- * XXX: Once pluto is changed to IKEv1 XOR
-- * IKEv2 it should be possible to move this
-- * magic into pluto proper and instead pass a
-- * simple boolean.
-- */
-- .ikev2 = LIN(POLICY_IKEV2_PROPOSE | POLICY_IKEV2_ALLOW, wm->policy),
-+ /* * logic needs to match pick_initiator() */
-+ .version = LIN(POLICY_IKEV2_ALLOW, wm->policy) ? IKEv2 : IKEv1,
- .alg_is_ok = ike_alg_is_ike,
- .pfs = LIN(POLICY_PFS, wm->policy),
-+ .check_pfs_vs_dh = false,
- .warning = libreswan_log,
- };
-
-- c->alg_info_ike = alg_info_ike_create_from_str(&proposal_policy, wm->ike,
-- err_buf, sizeof(err_buf));
-+ struct proposal_parser *parser = ike_proposal_parser(&proposal_policy);
-+ c->ike_proposals.p = proposals_from_str(parser, wm->ike);
-
-- if (c->alg_info_ike == NULL) {
-- pexpect(err_buf[0]); /* something */
-+ if (c->ike_proposals.p == NULL) {
-+ pexpect(parser->error[0]); /* something */
- loglog(RC_FATAL, "Failed to add connection \"%s\": ike string error: %s",
-- wm->name, err_buf);
-+ wm->name, parser->error);
-+ free_proposal_parser(&parser);
- pfree(c);
- return;
- }
-+ free_proposal_parser(&parser);
-
-- /* from here on, error returns should alg_info_free(&c->alg_info_ike->ai); */
-+ /* from here on, error returns should alg_info_free(&c->ike_proposals->ai); */
-
- LSWDBGP(DBG_CRYPT | DBG_CONTROL, buf) {
- lswlogs(buf, "ike (phase1) algorithm values: ");
-- lswlog_alg_info(buf, &c->alg_info_ike->ai);
-+ fmt_proposals(buf, c->ike_proposals.p);
- };
-- if (c->alg_info_ike->ai.alg_info_cnt == 0) {
-- loglog(RC_FATAL,
-- "Failed to add connection \"%s\": got 0 transforms for ike=\"%s\"",
-- wm->name, wm->ike);
-- alg_info_free(&c->alg_info_ike->ai);
-- pfree(c);
-- return;
-- }
- }
-
- /* ESP or AH cipher suites (but not both) */
-@@ -1607,10 +1584,7 @@
- DBG(DBG_CONTROL,
- DBG_log("from whack: got --esp=%s", wm->esp));
-
-- char err_buf[256] = ""; /* ??? big enough? */
--
- const struct proposal_policy proposal_policy = {
-- .ikev1 = LIN(POLICY_IKEV1_ALLOW, wm->policy),
- /*
- * logic needs to match pick_initiator()
- *
-@@ -1619,11 +1593,16 @@
- * magic into pluto proper and instead pass a
- * simple boolean.
- */
-- .ikev2 = LIN(POLICY_IKEV2_PROPOSE | POLICY_IKEV2_ALLOW, wm->policy),
-+ .version = LIN(POLICY_IKEV2_ALLOW, wm->policy) ? IKEv2 : IKEv1,
- .alg_is_ok = kernel_alg_is_ok,
- .pfs = LIN(POLICY_PFS, wm->policy),
-+ .check_pfs_vs_dh = true,
- .warning = libreswan_log,
- };
-+ struct proposal_parser *(*fn)(const struct proposal_policy *policy) =
-+ (c->policy & POLICY_ENCRYPT ? esp_proposal_parser :
-+ ah_proposal_parser);
-+ struct proposal_parser *parser = fn(&proposal_policy);
-
- /*
- * We checked above that exactly one of
-@@ -1632,42 +1611,22 @@
- * function is called (and those functions are
- * almost identical).
- */
-- c->alg_info_esp =
-- /* function: */
-- (c->policy & POLICY_ENCRYPT ?
-- alg_info_esp_create_from_str :
-- alg_info_ah_create_from_str)
-- /* arguments: */
-- (&proposal_policy,
-- wm->esp, err_buf, sizeof(err_buf));
--
-- if (c->alg_info_esp == NULL) {
-+ c->child_proposals.p = proposals_from_str(parser, wm->esp);
-+ if (c->child_proposals.p == NULL) {
- loglog(RC_FATAL,
- "Failed to add connection \"%s\", esp=\"%s\" is invalid: %s",
-- wm->name, wm->esp, err_buf);
-- if (c->alg_info_ike != NULL)
-- alg_info_free(&c->alg_info_ike->ai);
-+ wm->name, wm->esp, parser->error);
-+ free_proposal_parser(&parser);
- pfree(c);
- return;
- }
-+ free_proposal_parser(&parser);
-
-- /* from here on, error returns should alg_info_free(&c->alg_info_esp->ai); */
--
-- if (c->alg_info_esp->ai.alg_info_cnt == 0) {
-- loglog(RC_FATAL,
-- "Failed to add connection \"%s\", esp=\"%s\" contained 0 valid transforms",
-- wm->name, wm->esp);
-- if (c->alg_info_ike != NULL)
-- alg_info_free(&c->alg_info_ike->ai);
-- if (c->alg_info_esp != NULL) \
-- alg_info_free(&c->alg_info_esp->ai);
-- pfree(c);
-- return;
-- }
-+ /* from here on, error returns should alg_info_free(&c->child_proposals->ai); */
-
- LSWDBGP(DBG_CONTROL, buf) {
- lswlogs(buf, "ESP/AH string values: ");
-- lswlog_alg_info(buf, &c->alg_info_esp->ai);
-+ fmt_proposals(buf, c->child_proposals.p);
- };
- }
-
-diff -Naur libreswan-3.27-orig/programs/pluto/connections.h libreswan-3.27/programs/pluto/connections.h
---- libreswan-3.27-orig/programs/pluto/connections.h 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/programs/pluto/connections.h 2019-02-15 16:32:28.986835407 -0500
-@@ -29,6 +29,7 @@
- #define CONNECTIONS_H
-
- #include "fd.h"
-+#include "proposals.h"
-
- /* There are two kinds of connections:
- * - ISAKMP connections, between hosts (for IKE communication)
-@@ -318,8 +319,8 @@
- /* if multiple policies, next one to apply */
- struct connection *policy_next;
-
-- struct alg_info_esp *alg_info_esp; /* ??? OK for AH too? */
-- struct alg_info_ike *alg_info_ike;
-+ struct ike_proposals ike_proposals;
-+ struct child_proposals child_proposals;
-
- /*
- * The ALG_INFO converted to IKEv2 format.
-@@ -327,9 +328,23 @@
- * Since they are allocated on-demand so there's no need to
- * worry about copying them when a connection object gets
- * cloned.
-+ *
-+ * For a child SA, two different proposals are used:
-+ *
-+ * - during the IKE_AUTH exchange a proposal stripped of any
-+ * DH (it uses keying material from the IKE SA's SKSEED).
-+ *
-+ * - during a CREATE_CHILD_SA exchange, a mash up of the
-+ * proposal and the IKE SA's DH algorithm. Since the IKE
-+ * SA's DH can change, it too is saved so a rebuild can be
-+ * triggered.
-+ *
-+ * XXX: has to be a better way?
- */
-- struct ikev2_proposals *ike_proposals;
-- struct ikev2_proposals *esp_or_ah_proposals;
-+ struct ikev2_proposals *v2_ike_proposals;
-+ struct ikev2_proposals *v2_ike_auth_child_proposals;
-+ struct ikev2_proposals *v2_create_child_proposals;
-+ const struct oakley_group_desc *v2_create_child_proposals_default_dh;
-
- /* host_pair linkage */
- struct host_pair *host_pair;
-diff -Naur libreswan-3.27-orig/programs/pluto/crypto.c libreswan-3.27/programs/pluto/crypto.c
---- libreswan-3.27-orig/programs/pluto/crypto.c 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/programs/pluto/crypto.c 2019-02-15 16:32:28.987835416 -0500
-@@ -33,11 +33,12 @@
- #include "state.h"
- #include "log.h"
- #include "crypto.h"
--#include "alg_info.h"
-+#include "proposals.h"
- #include "ike_alg.h"
- #include "test_buffer.h"
- #include "connections.h"
-
-+#include "ike_alg_integ.h"
- #include "kernel_alg.h"
-
- /*
-@@ -47,7 +48,7 @@
- */
- void ike_alg_show_connection(const struct connection *c, const char *instance)
- {
-- if (c->alg_info_ike != NULL) {
-+ if (c->ike_proposals.p != NULL) {
- /*
- * List the algorithms as found in alg_info_ike and as
- * will be fed into the proposal code.
-@@ -79,30 +80,46 @@
- LSWLOG_WHACK(RC_COMMENT, buf) {
- lswlogf(buf, "\"%s\"%s: IKE algorithms: ",
- c->name, instance);
-- lswlog_alg_info(buf, &c->alg_info_ike->ai);
-+ fmt_proposals(buf, c->ike_proposals.p);
- }
- }
-
- const struct state *st = state_with_serialno(c->newest_isakmp_sa);
-
- if (st != NULL) {
-- /*
-- * Convert the crypt-suite into 'struct proposal_info'
-- * so that the parser's print-alg code can be used.
-- */
-- const struct proposal_info p = {
-- .encrypt = st->st_oakley.ta_encrypt,
-- .enckeylen = st->st_oakley.enckeylen,
-- .prf = st->st_oakley.ta_prf,
-- .integ = st->st_oakley.ta_integ,
-- .dh = st->st_oakley.ta_dh,
-- };
-- const char *v = st->st_ikev2 ? "IKEv2" : "IKE";
- LSWLOG_WHACK(RC_COMMENT, buf) {
- lswlogf(buf,
- "\"%s\"%s: %s algorithm newest: ",
-- c->name, instance, v);
-- lswlog_proposal_info(buf, &p);
-+ c->name, instance,
-+ "IKE");
-+ const struct trans_attrs *ta = &st->st_oakley;
-+ const char *sep = "";
-+ if (ta->ta_encrypt != NULL) {
-+ lswlogs(buf, sep); sep = "-";
-+ lswlogs(buf, ta->ta_encrypt->common.fqn);
-+ if (ta->enckeylen != 0) {
-+ lswlogf(buf, "_%d", ta->enckeylen);
-+ }
-+ }
-+ if (ta->ta_prf != NULL) {
-+ lswlogs(buf, sep); sep = "-";
-+ lswlogs(buf, ta->ta_prf->common.fqn);
-+ }
-+ /* XXX: should just print everything */
-+ if (ta->ta_integ != NULL) {
-+ if ((ta->ta_prf == NULL) ||
-+ (encrypt_desc_is_aead(ta->ta_encrypt) &&
-+ ta->ta_integ != &ike_alg_integ_none) ||
-+ (!encrypt_desc_is_aead(ta->ta_encrypt) &&
-+ ta->ta_integ->prf != ta->ta_prf)) {
-+ lswlogs(buf, sep); sep = "-";
-+ lswlogs(buf, ta->ta_integ->common.fqn);
-+ }
-+ }
-+ if (ta->ta_dh != NULL) {
-+ lswlogs(buf, sep); sep = "-";
-+ lswlogs(buf, ta->ta_dh->common.fqn);
-+ }
- }
- }
- }
-diff -Naur libreswan-3.27-orig/programs/pluto/db_ops.c libreswan-3.27/programs/pluto/db_ops.c
---- libreswan-3.27-orig/programs/pluto/db_ops.c 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/programs/pluto/db_ops.c 2019-02-15 16:32:28.987835416 -0500
-@@ -62,6 +62,7 @@
- #include "defs.h"
- #include "state.h"
- #include "packet.h"
-+#include "proposals.h"
- #include "spdb.h"
- #include "db_ops.h"
- #include "log.h"
-diff -Naur libreswan-3.27-orig/programs/pluto/hmac.c libreswan-3.27/programs/pluto/hmac.c
---- libreswan-3.27-orig/programs/pluto/hmac.c 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/programs/pluto/hmac.c 2019-02-15 16:32:28.988835425 -0500
-@@ -27,7 +27,7 @@
- #include "constants.h"
- #include "defs.h"
- #include "crypto.h"
--#include "alg_info.h"
-+#include "proposals.h"
- #include "ike_alg.h"
-
- #include
-diff -Naur libreswan-3.27-orig/programs/pluto/hostpair.c libreswan-3.27/programs/pluto/hostpair.c
---- libreswan-3.27-orig/programs/pluto/hostpair.c 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/programs/pluto/hostpair.c 2019-02-15 16:32:28.988835425 -0500
-@@ -57,7 +57,7 @@
- #include "log.h"
- #include "keys.h"
- #include "whack.h"
--#include "alg_info.h"
-+#include "proposals.h"
- #include "spdb.h"
- #include "ike_alg.h"
- #include "kernel_alg.h"
-diff -Naur libreswan-3.27-orig/programs/pluto/ikev1_aggr.c libreswan-3.27/programs/pluto/ikev1_aggr.c
---- libreswan-3.27-orig/programs/pluto/ikev1_aggr.c 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/programs/pluto/ikev1_aggr.c 2019-02-15 16:32:28.989835435 -0500
-@@ -24,7 +24,7 @@
-
- #include "constants.h" /* for dup_any()!?! ... */
- #include "lswlog.h"
--#include "alg_info.h"
-+#include "proposals.h"
-
- #include "defs.h"
- #include "state.h"
-diff -Naur libreswan-3.27-orig/programs/pluto/ikev1.h libreswan-3.27/programs/pluto/ikev1.h
---- libreswan-3.27-orig/programs/pluto/ikev1.h 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/programs/pluto/ikev1.h 2019-02-15 16:32:28.989835435 -0500
-@@ -6,11 +6,14 @@
- #include "packet.h" /* for pb_stream */
- #include "fd.h"
-
-+struct child_proposals;
-+struct ike_proposals;
-+
- /* ikev1.c */
-
- extern void init_ikev1(void);
-
--const struct oakley_group_desc *ikev1_quick_pfs(struct alg_info_esp *aie);
-+const struct oakley_group_desc *ikev1_quick_pfs(const struct child_proposals proposals);
-
- void ikev1_init_out_pbs_echo_hdr(struct msg_digest *md, bool enc, uint8_t np,
- pb_stream *output_stream, uint8_t *output_buffer,
-diff -Naur libreswan-3.27-orig/programs/pluto/ikev1_quick.c libreswan-3.27/programs/pluto/ikev1_quick.c
---- libreswan-3.27-orig/programs/pluto/ikev1_quick.c 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/programs/pluto/ikev1_quick.c 2019-02-15 16:32:28.990835444 -0500
-@@ -79,20 +79,22 @@
- #include "virtual.h" /* needs connections.h */
- #include "ikev1_dpd.h"
- #include "pluto_x509.h"
--#include "alg_info.h"
-+#include "proposals.h"
- #include "ip_address.h"
-
- #include
-
--const struct oakley_group_desc *ikev1_quick_pfs(struct alg_info_esp *aie)
-+const struct oakley_group_desc *ikev1_quick_pfs(const struct child_proposals proposals)
- {
-- if (aie == NULL) {
-+ if (proposals.p == NULL) {
- return NULL;
- }
-- if (aie->ai.alg_info_cnt == 0) {
-+ struct proposal *proposal = next_proposal(proposals.p, NULL);
-+ struct algorithm *dh = next_algorithm(proposal, PROPOSAL_dh, NULL);
-+ if (dh == NULL) {
- return NULL;
- }
-- return aie->ai.proposals[0].dh;
-+ return dh_desc(dh->desc);
- }
-
- /* accept_PFS_KE
-@@ -816,7 +818,7 @@
- * use that group.
- * if not, fallback to old use-same-as-P1 behaviour
- */
-- st->st_pfs_group = ikev1_quick_pfs(c->alg_info_esp);
-+ st->st_pfs_group = ikev1_quick_pfs(c->child_proposals);
- /* otherwise, use the same group as during Phase 1:
- * since no negotiation is possible, we pick one that is
- * very likely supported.
-@@ -832,8 +834,8 @@
- }
- lswlogf(buf, " {using isakmp#%lu msgid:%08" PRIx32 " proposal=",
- isakmp_sa->st_serialno, st->st_msgid);
-- if (st->st_connection->alg_info_esp != NULL) {
-- lswlog_alg_info(buf, &st->st_connection->alg_info_esp->ai);
-+ if (st->st_connection->child_proposals.p != NULL) {
-+ fmt_proposals(buf, st->st_connection->child_proposals.p);
- } else {
- lswlogf(buf, "defaults");
- }
-diff -Naur libreswan-3.27-orig/programs/pluto/ikev1_spdb_struct.c libreswan-3.27/programs/pluto/ikev1_spdb_struct.c
---- libreswan-3.27-orig/programs/pluto/ikev1_spdb_struct.c 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/programs/pluto/ikev1_spdb_struct.c 2019-02-15 16:32:28.991835453 -0500
-@@ -47,7 +47,7 @@
- #include "crypto.h"
-
- #include "ikev1.h"
--#include "alg_info.h"
-+#include "proposals.h"
- #include "kernel_alg.h"
- #include "ike_alg.h"
- #include "ike_alg_encrypt.h"
-@@ -305,17 +305,18 @@
- return false;
- }
-
-- if (c->alg_info_esp== NULL) {
-+ if (c->child_proposals.p == NULL) {
- DBGF(DBG_CONTROL, "ESP IPsec Transform verified unconditionally; no alg_info to check against");
- return true;
- }
-
-- FOR_EACH_ESP_INFO(c->alg_info_esp, esp_info) {
-- if (esp_info->encrypt == ta->ta_encrypt &&
-- (esp_info->enckeylen == 0 ||
-- ta->enckeylen == 0 ||
-- esp_info->enckeylen == ta->enckeylen) &&
-- esp_info->integ == ta->ta_integ) {
-+ FOR_EACH_PROPOSAL(c->child_proposals.p, proposal) {
-+ struct v1_proposal algs = v1_proposal(proposal);
-+ if (algs.encrypt == ta->ta_encrypt &&
-+ (algs.enckeylen == 0 ||
-+ ta->enckeylen == 0 ||
-+ algs.enckeylen == ta->enckeylen) &&
-+ algs.integ == ta->ta_integ) {
- DBG(DBG_CONTROL,
- DBG_log("ESP IPsec Transform verified; matches alg_info entry"));
- return true;
-@@ -351,14 +352,15 @@
- ta->ta_dh->common.fqn);
- return false;
- }
-- if (c->alg_info_esp == NULL) {
-+ if (c->child_proposals.p == NULL) {
- DBG(DBG_CONTROL,
- DBG_log("AH IPsec Transform verified unconditionally; no alg_info to check against"));
- return true;
- }
-
-- FOR_EACH_ESP_INFO(c->alg_info_esp, esp_info) { /* really AH */
-- if (esp_info->integ == ta->ta_integ) {
-+ FOR_EACH_PROPOSAL(c->child_proposals.p, proposal) { /* really AH */
-+ struct v1_proposal algs = v1_proposal(proposal);
-+ if (algs.integ == ta->ta_integ) {
- DBG(DBG_CONTROL,
- DBG_log("ESP IPsec Transform verified; matches alg_info entry"));
- return true;
-@@ -401,12 +403,12 @@
- * Aggr-Mode - Max transforms == 2 - Multiple
- * transforms, 1 DH group
- */
-- revised_sadb = oakley_alg_makedb(st->st_connection->alg_info_ike,
-+ revised_sadb = oakley_alg_makedb(st->st_connection->ike_proposals,
- auth_method,
- aggressive_mode);
- } else {
- revised_sadb = kernel_alg_makedb(st->st_connection->policy,
-- st->st_connection->alg_info_esp,
-+ st->st_connection->child_proposals,
- TRUE);
-
- /* add IPcomp proposal if policy asks for it */
-@@ -984,7 +986,7 @@
- }
-
- static bool ikev1_verify_ike(const struct trans_attrs *ta,
-- struct alg_info_ike *alg_info_ike)
-+ struct ike_proposals ike_proposals)
- {
- if (ta->ta_encrypt == NULL) {
- loglog(RC_LOG_SERIOUS,
-@@ -1005,7 +1007,7 @@
- loglog(RC_LOG_SERIOUS, "OAKLEY proposal refused: missing DH");
- return false;
- }
-- if (alg_info_ike == NULL) {
-+ if (ike_proposals.p == NULL) {
- DBG(DBG_CONTROL,
- DBG_log("OAKLEY proposal verified unconditionally; no alg_info to check against"));
- return true;
-@@ -1016,14 +1018,14 @@
- * if specified in "esp" string
- */
- bool ealg_insecure = (ta->enckeylen < 128);
--
-- FOR_EACH_IKE_INFO(alg_info_ike, ike_info) {
-- if (ike_info->encrypt == ta->ta_encrypt &&
-- (ike_info->enckeylen == 0 ||
-+ FOR_EACH_PROPOSAL(ike_proposals.p, proposal) {
-+ struct v1_proposal algs = v1_proposal(proposal);
-+ if (algs.encrypt == ta->ta_encrypt &&
-+ (algs.enckeylen == 0 ||
- ta->enckeylen == 0 ||
-- ike_info->enckeylen == ta->enckeylen) &&
-- ike_info->prf == ta->ta_prf &&
-- ike_info->dh == ta->ta_dh) {
-+ algs.enckeylen == ta->enckeylen) &&
-+ algs.prf == ta->ta_prf &&
-+ algs.dh == ta->ta_dh) {
- if (ealg_insecure) {
- loglog(RC_LOG_SERIOUS,
- "You should NOT use insecure/broken IKE algorithms (%s)!",
-@@ -1522,7 +1524,7 @@
- }
- /*
- * check if this keylen is compatible
-- * with specified alg_info_ike.
-+ * with specified ike_proposals.
- */
- if (!encrypt_has_key_bit_length(ta.ta_encrypt, val)) {
- ugh = "peer proposed key_len not valid for encrypt algo setup specified";
-@@ -1584,9 +1586,9 @@
- }
-
- /*
-- * ML: at last check for allowed transforms in alg_info_ike
-+ * ML: at last check for allowed transforms in ike_proposals
- */
-- if (!ikev1_verify_ike(&ta, c->alg_info_ike)) {
-+ if (!ikev1_verify_ike(&ta, c->ike_proposals)) {
- /*
- * already logged; UGH acts as a skip
- * rest of checks flag
-@@ -1715,7 +1717,7 @@
- const struct connection *c = st->st_connection;
-
- /*
-- * Construct the proposals by combining ALG_INFO_IKE with the
-+ * Construct the proposals by combining IKE_PROPOSALS with the
- * AUTH (proof of identity) extracted from the aggressive mode
- * SADB. As if by magic, attrs[2] is always the
- * authentication method.
-@@ -1733,7 +1735,7 @@
- * Max transforms == 2 - Multiple transforms, 1 DH
- * group
- */
-- revised_sadb = oakley_alg_makedb(c->alg_info_ike,
-+ revised_sadb = oakley_alg_makedb(c->ike_proposals,
- auth_method, TRUE);
- }
-
-diff -Naur libreswan-3.27-orig/programs/pluto/ikev2.c libreswan-3.27/programs/pluto/ikev2.c
---- libreswan-3.27-orig/programs/pluto/ikev2.c 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/programs/pluto/ikev2.c 2019-02-15 16:32:28.993835472 -0500
-@@ -68,7 +68,7 @@
- #include "vendor.h"
- #include "ip_address.h"
- #include "ikev2_send.h"
--#include "alg_info.h" /* for ike_info / esp_info */
-+#include "proposals.h" /* for ike_info / esp_info */
-
- #include "ietf_constants.h"
-
-diff -Naur libreswan-3.27-orig/programs/pluto/ikev2_crypto.c libreswan-3.27/programs/pluto/ikev2_crypto.c
---- libreswan-3.27-orig/programs/pluto/ikev2_crypto.c 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/programs/pluto/ikev2_crypto.c 2019-02-15 16:32:28.993835472 -0500
-@@ -52,7 +52,7 @@
- #include "ikev2.h"
- #include "ikev2_prf.h"
- #include "ike_alg.h"
--#include "alg_info.h"
-+#include "proposals.h"
- #include "kernel_alg.h"
- #include "crypt_symkey.h"
- #include "ikev2_prf.h"
-diff -Naur libreswan-3.27-orig/programs/pluto/ikev2.h libreswan-3.27/programs/pluto/ikev2.h
---- libreswan-3.27-orig/programs/pluto/ikev2.h 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/programs/pluto/ikev2.h 2019-02-15 16:32:28.994835481 -0500
-@@ -97,11 +97,27 @@
- void free_ikev2_proposal(struct ikev2_proposal **proposal);
- void free_ikev2_proposals(struct ikev2_proposals **proposals);
-
--void ikev2_need_ike_proposals(struct connection *c, const char *why);
-+/*
-+ * On-demand, generate proposals for either the IKE SA or the CHILD
-+ * SA.
-+ *
-+ * For CHILD SAs, two different proposal suites are used: during the
-+ * IKE_AUTH exchange a stripped down proposal that excludes DH; and
-+ * during the CREATE_CHILD_SA exchange DH a mashed up proposal that
-+ * can include the IKE SA's latest DH.
-+ *
-+ * This is done on-demand as, only at the point where the IKE or CHILD
-+ * SA is being instantiated, is it clear what proposals are needed.
-+ * For instance, when a CHILD SA shares an existing IKE SA, the CHILD
-+ * won't need IKE proposals but will need the IKE SA's DH.
-+ *
-+ * XXX: Should the CREATE CHILD SA proposals be stored in the state?
-+ */
-
--void ikev2_need_esp_or_ah_proposals(struct connection *c,
-- const char *why,
-- const struct oakley_group_desc *default_dh);
-+struct ikev2_proposals *get_v2_ike_proposals(struct connection *c, const char *why);
-+struct ikev2_proposals *get_v2_ike_auth_child_proposals(struct connection *c, const char *why);
-+struct ikev2_proposals *get_v2_create_child_proposals(struct connection *c, const char *why,
-+ const struct oakley_group_desc *default_dh);
-
- bool ikev2_emit_sa_proposal(pb_stream *pbs,
- const struct ikev2_proposal *proposal,
-diff -Naur libreswan-3.27-orig/programs/pluto/ikev2_parent.c libreswan-3.27/programs/pluto/ikev2_parent.c
---- libreswan-3.27-orig/programs/pluto/ikev2_parent.c 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/programs/pluto/ikev2_parent.c 2019-02-15 16:32:28.996835500 -0500
-@@ -67,7 +67,7 @@
- #include "pending.h"
- #include "kernel.h"
- #include "nat_traversal.h"
--#include "alg_info.h" /* for ike_info / esp_info */
-+#include "proposals.h" /* for ike_info / esp_info */
- #include "key.h" /* for SECKEY_DestroyPublicKey */
- #include "vendor.h"
- #include "crypt_hash.h"
-@@ -848,8 +848,9 @@
- * Initialize st->st_oakley, including the group number.
- * Grab the DH group from the first configured proposal and build KE.
- */
-- ikev2_need_ike_proposals(c, "IKE SA initiator selecting KE");
-- st->st_oakley.ta_dh = ikev2_proposals_first_dh(c->ike_proposals);
-+ struct ikev2_proposals *ike_proposals =
-+ get_v2_ike_proposals(c, "IKE SA initiator selecting KE");
-+ st->st_oakley.ta_dh = ikev2_proposals_first_dh(ike_proposals);
- if (st->st_oakley.ta_dh == NULL) {
- libreswan_log("proposals do not contain a valid DH");
- delete_state(st); /* pops state? */
-@@ -991,7 +992,8 @@
- }
- /* SA out */
- {
-- ikev2_need_ike_proposals(c, "IKE SA initiator emitting local proposals");
-+ struct ikev2_proposals *ike_proposals =
-+ get_v2_ike_proposals(c, "IKE SA initiator emitting local proposals");
- /*
- * Since this is an initial IKE exchange, the SPI is
- * emitted as is part of the packet header and not the
-@@ -999,7 +1001,7 @@
- */
- u_char *sa_start = rbody.cur;
- bool ret = ikev2_emit_sa_proposals(&rbody,
-- c->ike_proposals,
-+ ike_proposals,
- (chunk_t*)NULL);
- if (!ret) {
- libreswan_log("outsa fail");
-@@ -1328,7 +1330,8 @@
- }
-
- /* Get the proposals ready. */
-- ikev2_need_ike_proposals(c, "IKE SA responder matching remote proposals");
-+ struct ikev2_proposals *ike_proposals =
-+ get_v2_ike_proposals(c, "IKE SA responder matching remote proposals");
-
- /*
- * Select the proposal.
-@@ -1342,7 +1345,7 @@
- /*expect_accepted*/ FALSE,
- LIN(POLICY_OPPORTUNISTIC, c->policy),
- &accepted_ike_proposal,
-- c->ike_proposals);
-+ ike_proposals);
- if (ret != STF_OK)
- return ret;
-
-@@ -1812,9 +1815,10 @@
- pstats(invalidke_recv_s, sg.sg_group);
- pstats(invalidke_recv_u, st->st_oakley.ta_dh->group);
-
-- ikev2_need_ike_proposals(c, "IKE SA initiator validating remote's suggested KE");
-+ struct ikev2_proposals *ike_proposals =
-+ get_v2_ike_proposals(c, "IKE SA initiator validating remote's suggested KE");
-
-- if (ikev2_proposals_include_modp(c->ike_proposals, sg.sg_group)) {
-+ if (ikev2_proposals_include_modp(ike_proposals, sg.sg_group)) {
- DBG(DBG_CONTROLMORE, DBG_log("Suggested modp group is acceptable"));
- /*
- * Since there must be a group object
-@@ -2081,7 +2085,9 @@
- /* SA body in and out */
- struct payload_digest *const sa_pd =
- md->chain[ISAKMP_NEXT_v2SA];
-- ikev2_need_ike_proposals(c, "IKE SA initiator accepting remote proposal");
-+ struct ikev2_proposals *ike_proposals =
-+ get_v2_ike_proposals(c, "IKE SA initiator accepting remote proposal");
-+
-
- stf_status ret = ikev2_process_sa_payload("IKE initiator (accepting)",
- &sa_pd->pbs,
-@@ -2090,7 +2096,7 @@
- /*expect_accepted*/ TRUE,
- LIN(POLICY_OPPORTUNISTIC, c->policy),
- &st->st_accepted_ike_proposal,
-- c->ike_proposals);
-+ ike_proposals);
- if (ret != STF_OK) {
- DBG(DBG_CONTROLMORE, DBG_log("ikev2_parse_parent_sa_body() failed in ikev2_parent_inR1outI2()"));
- return ret;
-@@ -3564,17 +3570,13 @@
- sizeof(proto_info->our_spi));
-
- /*
-- * UNSET_GROUP means strip DH from the proposal. A
-- * CHILD_SA established during an AUTH exchange does
-+ * A CHILD_SA established during an AUTH exchange does
- * not propose DH - the IKE SA's SKEYSEED is always
- * used.
- */
-- free_ikev2_proposals(&cc->esp_or_ah_proposals);
-- ikev2_need_esp_or_ah_proposals(cc,
-- "IKE SA initiator emitting ESP/AH proposals",
-- &unset_group);
--
-- if (!ikev2_emit_sa_proposals(&e_pbs_cipher, cc->esp_or_ah_proposals,
-+ struct ikev2_proposals *child_proposals =
-+ get_v2_ike_auth_child_proposals(cc, "IKE SA initiator emitting ESP/AH proposals");
-+ if (!ikev2_emit_sa_proposals(&e_pbs_cipher, child_proposals,
- &local_spi))
- return STF_INTERNAL_ERROR;
-
-@@ -4374,31 +4376,25 @@
- stf_status ret;
-
- char *what;
-- const struct oakley_group_desc *default_dh;
-+ struct ikev2_proposals *child_proposals;
- if (isa_xchg == ISAKMP_v2_CREATE_CHILD_SA) {
- if (st->st_state == STATE_V2_CREATE_I) {
- what = "ESP/AH initiator accepting remote proposal";
- } else {
- what = "ESP/AH responder matching remote proposals";
- }
-- default_dh = (c->policy & POLICY_PFS) != LEMPTY
-+ const struct oakley_group_desc *default_dh = (c->policy & POLICY_PFS) != LEMPTY
- ? ike->sa.st_oakley.ta_dh
- : &ike_alg_dh_none;
-+ child_proposals = get_v2_create_child_proposals(c, what, default_dh);
- } else if (expect_accepted) {
-- what = "IKE SA initiator accepting remote ESP/AH proposal";
-- default_dh = &unset_group; /* no DH */
-+ what = "IKE_AUTH initiator accepting remote ESP/AH proposal";
-+ child_proposals = get_v2_ike_auth_child_proposals(c, what);
- } else {
-- what = "IKE SA responder matching remote ESP/AH proposals";
-- default_dh = &unset_group; /* no DH */
-- }
--
-- if (!expect_accepted) {
-- /* preparing to initiate or parse a request flush old ones */
-- free_ikev2_proposals(&c->esp_or_ah_proposals);
-+ what = "IKE_AUTH responder matching remote ESP/AH proposals";
-+ child_proposals = get_v2_ike_auth_child_proposals(c, what);
- }
-
-- ikev2_need_esp_or_ah_proposals(c, what, default_dh);
--
- ret = ikev2_process_sa_payload(what,
- &sa_pd->pbs,
- /*expect_ike*/ FALSE,
-@@ -4406,7 +4402,7 @@
- expect_accepted,
- LIN(POLICY_OPPORTUNISTIC, c->policy),
- &st->st_accepted_esp_or_ah_proposal,
-- c->esp_or_ah_proposals);
-+ child_proposals);
-
- if (ret != STF_OK) {
- LSWLOG_RC(RC_LOG_SERIOUS, buf) {
-@@ -5217,8 +5213,8 @@
- chunk_t local_spi;
- setchunk(local_spi, (uint8_t*)&proto_info->our_spi,
- sizeof(proto_info->our_spi));
--
-- if (!ikev2_emit_sa_proposals(outpbs, cc->esp_or_ah_proposals,
-+ passert(cc->v2_create_child_proposals != NULL);
-+ if (!ikev2_emit_sa_proposals(outpbs, cc->v2_create_child_proposals,
- &local_spi))
- return STF_INTERNAL_ERROR;
-
-@@ -5312,12 +5308,11 @@
- sizeof(st->st_icookie));
- local_nonce = st->st_ni;
-
-- /* ??? why do we need to free the previous proposals? */
-- free_ikev2_proposals(&c->ike_proposals);
-- ikev2_need_ike_proposals(c, "IKE SA initiating rekey");
-+ struct ikev2_proposals *ike_proposals =
-+ get_v2_ike_proposals(c, "IKE SA initiating rekey");
-
- /* send v2 IKE SAs*/
-- if (!ikev2_emit_sa_proposals(outpbs, c->ike_proposals, &local_spi)) {
-+ if (!ikev2_emit_sa_proposals(outpbs, ike_proposals, &local_spi)) {
- libreswan_log("outsa fail");
- DBG(DBG_CONTROL, DBG_log("problem emitting connection ike proposals in CREATE_CHILD_SA"));
- return STF_INTERNAL_ERROR;
-@@ -5379,7 +5374,8 @@
- struct payload_digest *const sa_pd = md->chain[ISAKMP_NEXT_v2SA];
-
- /* Get the proposals ready. */
-- ikev2_need_ike_proposals(c, "IKE SA accept response to rekey");
-+ struct ikev2_proposals *ike_proposals =
-+ get_v2_ike_proposals(c, "IKE SA accept response to rekey");
-
- stf_status ret = ikev2_process_sa_payload("IKE initiator (accepting)",
- &sa_pd->pbs,
-@@ -5388,7 +5384,7 @@
- /*expect_accepted*/ TRUE,
- LIN(POLICY_OPPORTUNISTIC, c->policy),
- &st->st_accepted_ike_proposal,
-- c->ike_proposals);
-+ ike_proposals);
- if (ret != STF_OK) {
- DBG(DBG_CONTROLMORE, DBG_log("failed to accept IKE SA, REKEY, response, in process_ike_rekey_sa_pl_response"));
- return ret;
-@@ -5424,7 +5420,8 @@
- struct payload_digest *const sa_pd = md->chain[ISAKMP_NEXT_v2SA];
-
- /* Get the proposals ready. */
-- ikev2_need_ike_proposals(c, "IKE SA responding to rekey");
-+ struct ikev2_proposals *ike_proposals =
-+ get_v2_ike_proposals(c, "IKE SA responding to rekey");
-
- struct ikev2_proposal *accepted_ike_proposal = NULL;
- stf_status ret = ikev2_process_sa_payload("IKE Rekey responder child",
-@@ -5434,7 +5431,7 @@
- /*expect_accepted*/ FALSE,
- LIN(POLICY_OPPORTUNISTIC, c->policy),
- &accepted_ike_proposal,
-- c->ike_proposals);
-+ ike_proposals);
- if (ret != STF_OK)
- return ret;
-
-@@ -6677,21 +6674,17 @@
- if (sa_type == IPSEC_SA) {
- const struct state *rst = state_with_serialno(p->replacing);
-
-- /*
-- * Because the proposal generated during AUTH won't contain DH,
-- * always force the proposal to be re-generated here. Not the
-- * most efficient, fix probably means moving the proposals to
-- * the state object.
-- */
-- free_ikev2_proposals(&c->esp_or_ah_proposals);
- const struct oakley_group_desc *default_dh =
- c->policy & POLICY_PFS ? ike->sa.st_oakley.ta_dh : NULL;
-
-- ikev2_need_esp_or_ah_proposals(c,
-- "ESP/AH initiator emitting proposals",
-- default_dh);
-+ struct ikev2_proposals *child_proposals =
-+ get_v2_create_child_proposals(c,
-+ "ESP/AH initiator emitting proposals",
-+ default_dh);
-+ /* see ikev2_child_add_ipsec_payloads */
-+ passert(c->v2_create_child_proposals != NULL);
-
-- st->st_pfs_group = ikev2_proposals_first_dh(c->esp_or_ah_proposals);
-+ st->st_pfs_group = ikev2_proposals_first_dh(child_proposals);
-
- DBG(DBG_CONTROLMORE, {
- const char *pfsgroupname = st->st_pfs_group == NULL ?
-diff -Naur libreswan-3.27-orig/programs/pluto/ikev2_spdb_struct.c libreswan-3.27/programs/pluto/ikev2_spdb_struct.c
---- libreswan-3.27-orig/programs/pluto/ikev2_spdb_struct.c 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/programs/pluto/ikev2_spdb_struct.c 2019-02-15 16:32:28.998835518 -0500
-@@ -51,7 +51,7 @@
-
- #include "crypto.h"
-
--#include "alg_info.h"
-+#include "proposals.h"
- #include "kernel_alg.h"
- #include "ike_alg.h"
- #include "ike_alg_integ.h"
-@@ -264,7 +264,7 @@
- *
- * PROPNUM is an int.
- */
--#define FOR_EACH_PROPOSAL(PROPNUM, PROPOSAL, PROPOSALS) \
-+#define FOR_EACH_V2_PROPOSAL(PROPNUM, PROPOSAL, PROPOSALS) \
- for ((PROPNUM) = 1, \
- (PROPOSAL) = &(PROPOSALS)->proposal[(PROPNUM)]; \
- (PROPNUM) < (PROPOSALS)->roof; \
-@@ -276,7 +276,7 @@
- *
- * PROPNUM, BASE, BOUND are all ints.
- */
--#define FOR_EACH_PROPOSAL_IN_RANGE(PROPNUM, PROPOSAL, PROPOSALS, BASE, BOUND) \
-+#define FOR_EACH_V2_PROPOSAL_IN_RANGE(PROPNUM, PROPOSAL, PROPOSALS, BASE, BOUND) \
- for ((PROPNUM) = ((BASE) > 0 ? (BASE) : 1), \
- (PROPOSAL) = &(PROPOSALS)->proposal[(PROPNUM)]; \
- (PROPNUM) < (BOUND) && (PROPNUM) < (PROPOSALS)->roof; \
-@@ -395,7 +395,7 @@
- const char *proposal_sep = "";
- int propnum;
- const struct ikev2_proposal *proposal;
-- FOR_EACH_PROPOSAL(propnum, proposal, proposals) {
-+ FOR_EACH_V2_PROPOSAL(propnum, proposal, proposals) {
- lswlogs(buf, proposal_sep);
- proposal_sep = " ";
- print_proposal(buf, propnum, proposal);
-@@ -443,8 +443,8 @@
- {
- int local_propnum;
- const struct ikev2_proposal *local_proposal;
-- FOR_EACH_PROPOSAL_IN_RANGE(local_propnum, local_proposal, local_proposals,
-- local_propnum_base, local_propnum_bound) {
-+ FOR_EACH_V2_PROPOSAL_IN_RANGE(local_propnum, local_proposal, local_proposals,
-+ local_propnum_base, local_propnum_bound) {
- struct ikev2_proposal_match *matching_local_proposal = &matching_local_proposals[local_propnum];
- /* clear matched */
- matching_local_proposal->matched_transform_types = LEMPTY;
-@@ -579,8 +579,8 @@
- */
- int local_propnum;
- struct ikev2_proposal *local_proposal;
-- FOR_EACH_PROPOSAL_IN_RANGE(local_propnum, local_proposal, local_proposals,
-- local_propnum_base, local_propnum_bound) {
-+ FOR_EACH_V2_PROPOSAL_IN_RANGE(local_propnum, local_proposal, local_proposals,
-+ local_propnum_base, local_propnum_bound) {
- if (local_proposal->protoid == remote_protoid) {
- /*
- * Search the proposal for transforms of this
-@@ -680,8 +680,8 @@
-
- int local_propnum;
- struct ikev2_proposal *local_proposal;
-- FOR_EACH_PROPOSAL_IN_RANGE(local_propnum, local_proposal, local_proposals,
-- local_propnum_base, local_propnum_bound) {
-+ FOR_EACH_V2_PROPOSAL_IN_RANGE(local_propnum, local_proposal, local_proposals,
-+ local_propnum_base, local_propnum_bound) {
- struct ikev2_proposal_match *matching_local_proposal = &matching_local_proposals[local_propnum];
- LSWDBGP(DBG_CONTROLMORE, log) {
- lswlogf(log, "comparing remote proposal %u containing ",
-@@ -834,7 +834,7 @@
- {
- int local_propnum;
- struct ikev2_proposal *local_proposal;
-- FOR_EACH_PROPOSAL(local_propnum, local_proposal, local_proposals) {
-+ FOR_EACH_V2_PROPOSAL(local_propnum, local_proposal, local_proposals) {
- struct ikev2_proposal_match *matching_local_proposal = &matching_local_proposals[local_propnum];
- enum ikev2_trans_type type;
- struct ikev2_transforms *local_transforms;
-@@ -1156,7 +1156,7 @@
- *
- * Must be freed by this function.
- */
-- stf_status status;
-+ stf_status status = STF_FAIL; /* initialized just to silence gcc -Og */
- LSWBUF(remote_print_buf) {
- int matching_local_propnum = ikev2_process_proposals(sa_payload,
- expect_ike, expect_spi,
-@@ -1448,7 +1448,7 @@
-
- int propnum;
- const struct ikev2_proposal *proposal;
-- FOR_EACH_PROPOSAL(propnum, proposal, proposals) {
-+ FOR_EACH_V2_PROPOSAL(propnum, proposal, proposals) {
- if (!emit_proposal(&sa_pbs, proposal, propnum, local_spi,
- (propnum < proposals->roof - 1
- ? v2_PROPOSAL_NON_LAST
-@@ -1804,9 +1804,9 @@
- return TRUE;
- }
-
--static struct ikev2_proposal *ikev2_proposal_from_proposal_info(const struct proposal_info *info,
-+static struct ikev2_proposal *ikev2_proposal_from_proposal_info(const struct proposal *proposal,
- enum ikev2_sec_proto_id protoid,
-- struct ikev2_proposals *proposals,
-+ struct ikev2_proposals *v2_proposals,
- const struct oakley_group_desc *default_dh)
- {
- /*
-@@ -1814,19 +1814,19 @@
- * contain partially constructed stuff from an earlier
- * iteration).
- */
-- struct ikev2_proposal *proposal = &proposals->proposal[proposals->roof];
-- *proposal = (struct ikev2_proposal) {
-+ struct ikev2_proposal *v2_proposal = &v2_proposals->proposal[v2_proposals->roof];
-+ *v2_proposal = (struct ikev2_proposal) {
- .protoid = protoid,
-- .propnum = proposals->roof,
-+ .propnum = v2_proposals->roof,
- };
-
- /*
- * Encryption.
- */
-- const struct encrypt_desc *encrypt = info->encrypt;
-- if (encrypt != NULL) {
-- if (!append_encrypt_transform(proposal, encrypt,
-- info->enckeylen)) {
-+ FOR_EACH_ALGORITHM(proposal, encrypt, alg) {
-+ const struct encrypt_desc *encrypt = encrypt_desc(alg->desc);
-+ if (!append_encrypt_transform(v2_proposal, encrypt,
-+ alg->enckeylen)) {
- return NULL;
- }
- }
-@@ -1834,22 +1834,22 @@
- /*
- * PRF.
- */
-- const struct prf_desc *prf = info->prf;
-- if (prf != NULL) {
-- append_transform(proposal, IKEv2_TRANS_TYPE_PRF,
-+ FOR_EACH_ALGORITHM(proposal, prf, alg) {
-+ const struct prf_desc *prf = prf_desc(alg->desc);
-+ append_transform(v2_proposal, IKEv2_TRANS_TYPE_PRF,
- prf->common.id[IKEv2_ALG_ID], 0);
- }
-
- /*
- * Integrity.
- */
-- const struct integ_desc *integ = info->integ;
-- if (integ != NULL) {
-+ FOR_EACH_ALGORITHM(proposal, integ, alg) {
-+ const struct integ_desc *integ = integ_desc(alg->desc);
- /*
- * While INTEG=NONE is included in the proposal it
- * omitted when emitted.
- */
-- append_transform(proposal, IKEv2_TRANS_TYPE_INTEG,
-+ append_transform(v2_proposal, IKEv2_TRANS_TYPE_INTEG,
- integ->common.id[IKEv2_ALG_ID], 0);
- }
-
-@@ -1860,20 +1860,25 @@
- * happens during the AUTH exchange). Otherwise use either
- * the proposed or default DH.
- */
-- const struct oakley_group_desc *dh =
-- default_dh == &unset_group ? &ike_alg_dh_none
-- : info->dh != NULL ? info->dh
-- : default_dh;
-- if (dh != NULL) {
-- /*
-- * WHILE DH=NONE is included in the proposal it is
-- * omitted when emitted.
-- */
-- append_transform(proposal, IKEv2_TRANS_TYPE_DH,
-- dh->common.id[IKEv2_ALG_ID], 0);
-+ if (default_dh == &unset_group) {
-+ append_transform(v2_proposal, IKEv2_TRANS_TYPE_DH,
-+ ike_alg_dh_none.common.id[IKEv2_ALG_ID], 0);
-+ } else if (next_algorithm(proposal, PROPOSAL_dh, NULL) != NULL) {
-+ FOR_EACH_ALGORITHM(proposal, dh, alg) {
-+ const struct oakley_group_desc *dh = dh_desc(alg->desc);
-+ /*
-+ * WHILE DH=NONE is included in the proposal it is
-+ * omitted when emitted.
-+ */
-+ append_transform(v2_proposal, IKEv2_TRANS_TYPE_DH,
-+ dh->common.id[IKEv2_ALG_ID], 0);
-+ }
-+ } else if (default_dh != NULL) {
-+ append_transform(v2_proposal, IKEv2_TRANS_TYPE_DH,
-+ default_dh->common.id[IKEv2_ALG_ID], 0);
- }
-
-- return proposal;
-+ return v2_proposal;
- }
-
- /*
-@@ -1993,67 +1998,73 @@
- };
-
- /*
-- * Ensure c->ike_proposals is filled in. If not, build it.
-- *
-- * ??? if c->ike_proposals was set for v1 we won't change it.
-+ * On-demand compute and return the IKE proposals for the connection.
- *
-- * WARNING: alg_info_ike is IKEv1
-+ * If the default alg_info_ike includes unknown algorithms those get
-+ * dropped, which can lead to no proposals.
- *
-- * If alg_info_ike includes unknown algorithms those get dropped,
-- * which can lead to no proposals.
-- * c->ike_proposals will not be NULL (see passert).
-+ * Never returns NULL (see passert).
- */
-
--void ikev2_need_ike_proposals(struct connection *c, const char *why) {
-- if (c->ike_proposals != NULL) {
-- DBGF(DBG_CONTROL, "already constructed local IKE proposals for connection %s (%s)",
-- c->name, why);
-- return;
-+struct ikev2_proposals *get_v2_ike_proposals(struct connection *c, const char *why)
-+{
-+ if (c->v2_ike_proposals != NULL) {
-+ LSWDBGP(DBG_CONTROL, buf) {
-+ lswlogf(buf, "using existing local IKE proposals for connection %s (%s): ",
-+ c->name, why);
-+ print_proposals(buf, c->v2_ike_proposals);
-+ }
-+ return c->v2_ike_proposals;
- }
-
- const char *notes;
-- if (c->alg_info_ike == NULL) {
-+ if (c->ike_proposals.p == NULL) {
- DBGF(DBG_CONTROL, "selecting default constructed local IKE proposals for connection %s (%s)",
- c->name, why);
-- c->ike_proposals = &default_ikev2_ike_proposals;
-+ c->v2_ike_proposals = &default_ikev2_ike_proposals;
- notes = " (default)";
- } else {
- DBGF(DBG_CONTROL, "constructing local IKE proposals for %s (%s)",
- c->name, why);
-- struct ikev2_proposals *proposals = alloc_thing(struct ikev2_proposals, "proposals");
-- int proposals_roof = c->alg_info_ike->ai.alg_info_cnt + 1;
-- proposals->proposal = alloc_things(struct ikev2_proposal, proposals_roof, "propsal");
-- proposals->on_heap = TRUE;
-- proposals->roof = 1;
-+ struct ikev2_proposals *v2_proposals = alloc_thing(struct ikev2_proposals,
-+ "proposals");
-+ /* +1 as proposal[0] is empty */
-+ int v2_proposals_roof = nr_proposals(c->ike_proposals.p) + 1;
-+ v2_proposals->proposal = alloc_things(struct ikev2_proposal,
-+ v2_proposals_roof, "propsal");
-+ v2_proposals->on_heap = TRUE;
-+ v2_proposals->roof = 1;
-
-- FOR_EACH_IKE_INFO(c->alg_info_ike, ike_info) {
-+ FOR_EACH_PROPOSAL(c->ike_proposals.p, ike_info) {
- LSWDBGP(DBG_CONTROL, buf) {
- lswlogs(buf, "converting ike_info ");
-- lswlog_proposal_info(buf, ike_info);
-+ fmt_proposal(buf, ike_info);
- lswlogs(buf, " to ikev2 ...");
- }
-
-- passert(proposals->roof < proposals_roof);
-- struct ikev2_proposal *proposal =
-- ikev2_proposal_from_proposal_info(ike_info, IKEv2_SEC_PROTO_IKE,
-- proposals, NULL);
-- if (proposal != NULL) {
-+ passert(v2_proposals->roof < v2_proposals_roof);
-+ struct ikev2_proposal *v2_proposal =
-+ ikev2_proposal_from_proposal_info(ike_info,
-+ IKEv2_SEC_PROTO_IKE,
-+ v2_proposals, NULL);
-+ if (v2_proposal != NULL) {
- DBG(DBG_CONTROL,
-- DBG_log_ikev2_proposal("... ", proposal));
-- proposals->roof++;
-+ DBG_log_ikev2_proposal("... ", v2_proposal));
-+ v2_proposals->roof++;
- }
- }
-- c->ike_proposals = proposals;
-+ c->v2_ike_proposals = v2_proposals;
- notes = "";
- }
-
-- LSWLOG(buf) {
-+ LSWLOG_CONNECTION(c, buf) {
- lswlogf(buf, "constructed local IKE proposals for %s (%s): ",
- c->name, why);
-- print_proposals(buf, c->ike_proposals);
-+ print_proposals(buf, c->v2_ike_proposals);
- lswlogs(buf, notes);
- }
-- passert(c->ike_proposals != NULL);
-+ passert(c->v2_ike_proposals != NULL);
-+ return c->v2_ike_proposals;
- }
-
- static struct ikev2_proposal default_ikev2_esp_proposal_missing_esn[] = {
-@@ -2143,19 +2154,23 @@
- }
- }
-
--void ikev2_need_esp_or_ah_proposals(struct connection *c,
-- const char *why,
-- const struct oakley_group_desc *default_dh)
-+static struct ikev2_proposals *get_v2_child_proposals(struct ikev2_proposals **child_proposals,
-+ struct connection *c,
-+ const char *why,
-+ const struct oakley_group_desc *default_dh)
- {
-- if (c->esp_or_ah_proposals != NULL) {
-- DBGF(DBG_CONTROL, "already constructed local ESP/AH proposals for %s (%s)",
-- c->name, why);
-- return;
-+ if (*child_proposals != NULL) {
-+ LSWDBGP(DBG_CONTROL, buf) {
-+ lswlogf(buf, "using existing local ESP/AH proposals for %s (%s): ",
-+ c->name, why);
-+ print_proposals(buf, *child_proposals);
-+ }
-+ return *child_proposals;
- }
-
- const char *notes;
-- if (c->alg_info_esp == NULL) {
-- DBGF(DBG_CONTROL, "selecting default construvted local ESP/AH proposals for %s (%s)",
-+ if (c->child_proposals.p == NULL) {
-+ DBGF(DBG_CONTROL, "selecting default local ESP/AH proposals for %s (%s)",
- c->name, why);
- lset_t esp_ah = c->policy & (POLICY_ENCRYPT | POLICY_AUTHENTICATE);
- struct ikev2_proposals *default_proposals_missing_esn;
-@@ -2186,38 +2201,38 @@
- /*
- * Clone the default proposal and add the missing ESN.
- */
-- struct ikev2_proposals *proposals = alloc_thing(struct ikev2_proposals,
-- "cloned ESP/AH proposals");
-- proposals->on_heap = TRUE;
-- proposals->roof = default_proposals_missing_esn->roof;
-+ struct ikev2_proposals *v2_proposals = alloc_thing(struct ikev2_proposals,
-+ "cloned ESP/AH proposals");
-+ v2_proposals->on_heap = TRUE;
-+ v2_proposals->roof = default_proposals_missing_esn->roof;
- if (add_empty_msdh_duplicates) {
- /* add space for duplicates, minus the empty first proposal */
-- proposals->roof += default_proposals_missing_esn->roof - 1;
-+ v2_proposals->roof += default_proposals_missing_esn->roof - 1;
- }
-- proposals->proposal = alloc_things(struct ikev2_proposal, proposals->roof,
-- "ESP/AH proposals");
-- memcpy(proposals->proposal, default_proposals_missing_esn->proposal,
-- sizeof(proposals->proposal[0]) * default_proposals_missing_esn->roof);
-+ v2_proposals->proposal = alloc_things(struct ikev2_proposal, v2_proposals->roof,
-+ "ESP/AH proposals");
-+ memcpy(v2_proposals->proposal, default_proposals_missing_esn->proposal,
-+ sizeof(v2_proposals->proposal[0]) * default_proposals_missing_esn->roof);
- if (add_empty_msdh_duplicates) {
- /*
- * Append duplicates but discarding
- * proposal[0] which is filler.
- */
-- memcpy(proposals->proposal + default_proposals_missing_esn->roof,
-+ memcpy(v2_proposals->proposal + default_proposals_missing_esn->roof,
- default_proposals_missing_esn->proposal + 1, /* skip "0" */
-- sizeof(proposals->proposal[0]) * (default_proposals_missing_esn->roof - 1));
-+ sizeof(v2_proposals->proposal[0]) * (default_proposals_missing_esn->roof - 1));
- }
-
- int propnum;
-- struct ikev2_proposal *proposal;
-- FOR_EACH_PROPOSAL(propnum, proposal, proposals) {
-- add_esn_transforms(proposal, c->policy);
-+ struct ikev2_proposal *v2_proposal;
-+ FOR_EACH_V2_PROPOSAL(propnum, v2_proposal, v2_proposals) {
-+ add_esn_transforms(v2_proposal, c->policy);
- }
- if (default_dh != NULL && default_dh != &unset_group) {
- DBGF(DBG_CONTROL, "adding dh %s to default proposals",
- default_dh->common.name);
-- FOR_EACH_PROPOSAL(propnum, proposal, proposals) {
-- append_transform(proposal,
-+ FOR_EACH_V2_PROPOSAL(propnum, v2_proposal, v2_proposals) {
-+ append_transform(v2_proposal,
- IKEv2_TRANS_TYPE_DH,
- default_dh->group, 0);
- if (propnum >= default_proposals_missing_esn->roof)
-@@ -2225,7 +2240,7 @@
- break;
- }
- }
-- c->esp_or_ah_proposals = proposals;
-+ *child_proposals = v2_proposals;
- notes = " (default)";
- } else {
- LSWDBGP(DBG_CONTROL, buf) {
-@@ -2250,17 +2265,18 @@
- bool add_empty_msdh_duplicates = (c->policy & POLICY_MSDH_DOWNGRADE) &&
- default_dh != &unset_group;
-
-- struct ikev2_proposals *proposals = alloc_thing(struct ikev2_proposals,
-- "ESP/AH proposals");
-- int proposals_roof = c->alg_info_esp->ai.alg_info_cnt + 1;
-+ struct ikev2_proposals *v2_proposals = alloc_thing(struct ikev2_proposals,
-+ "ESP/AH proposals");
-+ /* proposal[0] is empty so +1 */
-+ int v2_proposals_roof = nr_proposals(c->child_proposals.p) + 1;
- if (add_empty_msdh_duplicates) {
-- /* make space for everything duplicated */
-- proposals_roof += c->alg_info_esp->ai.alg_info_cnt;
-+ /* make space for everything duplicated; note +1 above */
-+ v2_proposals_roof = v2_proposals_roof * 2 - 1;
- }
-- proposals->proposal = alloc_things(struct ikev2_proposal, proposals_roof,
-- "ESP/AH proposal");
-- proposals->on_heap = TRUE;
-- proposals->roof = 1;
-+ v2_proposals->proposal = alloc_things(struct ikev2_proposal, v2_proposals_roof,
-+ "ESP/AH proposal");
-+ v2_proposals->on_heap = TRUE;
-+ v2_proposals->roof = 1;
-
- enum ikev2_sec_proto_id protoid;
- switch (c->policy & (POLICY_ENCRYPT | POLICY_AUTHENTICATE)) {
-@@ -2275,10 +2291,10 @@
- }
-
- for (int dup = 0; dup < (add_empty_msdh_duplicates ? 2 : 1); dup++) {
-- FOR_EACH_ESP_INFO(c->alg_info_esp, esp_info) {
-+ FOR_EACH_PROPOSAL(c->child_proposals.p, esp_info) {
- LSWDBGP(DBG_CONTROL, log) {
- lswlogf(log, "converting proposal ");
-- lswlog_proposal_info(log, esp_info);
-+ fmt_proposal(log, esp_info);
- lswlogf(log, " to ikev2 ...");
- }
-
-@@ -2286,37 +2302,94 @@
- * Get the next proposal with the
- * basics filled in.
- */
-- passert(proposals->roof < proposals_roof);
-- if (dup && default_dh == NULL && esp_info->dh == NULL) {
-+ passert(v2_proposals->roof < v2_proposals_roof);
-+ if (dup && default_dh == NULL &&
-+ next_algorithm(esp_info, PROPOSAL_dh, NULL) == NULL) {
- /*
- * First pass didn't include DH.
- */
- continue;
- }
-- struct ikev2_proposal *proposal =
-- ikev2_proposal_from_proposal_info(esp_info, protoid,
-- proposals,
-+ struct ikev2_proposal *v2_proposal =
-+ ikev2_proposal_from_proposal_info(esp_info,
-+ protoid,
-+ v2_proposals,
- dup ? &unset_group : default_dh);
-- if (proposal != NULL) {
-- add_esn_transforms(proposal, c->policy);
-+ if (v2_proposal != NULL) {
-+ add_esn_transforms(v2_proposal, c->policy);
- DBG(DBG_CONTROL,
-- DBG_log_ikev2_proposal("... ", proposal));
-- proposals->roof++;
-+ DBG_log_ikev2_proposal("... ", v2_proposal));
-+ v2_proposals->roof++;
- }
- }
- }
-
-- c->esp_or_ah_proposals = proposals;
-+ *child_proposals = v2_proposals;
- notes = "";
- }
-
-- LSWLOG(buf) {
-+ LSWLOG_CONNECTION(c, buf) {
- lswlogf(buf, "constructed local ESP/AH proposals for %s (%s): ",
- c->name, why);
-- print_proposals(buf, c->esp_or_ah_proposals);
-+ print_proposals(buf, *child_proposals);
- lswlogs(buf, notes);
- }
-- passert(c->esp_or_ah_proposals != NULL);
-+ passert(*child_proposals != NULL);
-+ return *child_proposals;
-+}
-+
-+/*
-+ * If needed, generate the proposals for a CHILD SA being created
-+ * during the IKE_AUTH exchange.
-+ *
-+ * Since a CHILD_SA established during an IKE_AUTH exchange does not
-+ * propose DH (keying material is taken from the IKE SA's SKEYSEED),
-+ * DH is stripped from the proposals.
-+ *
-+ * Since only things that affect this proposal suite are the
-+ * connection's .policy bits and the contents .child_proposals, and
-+ * modifiying those triggers the creation of a new connection (true?),
-+ * the connection can be cached.
-+ */
-+
-+struct ikev2_proposals *get_v2_ike_auth_child_proposals(struct connection *c, const char *why)
-+{
-+ /* UNSET_GROUP means strip DH from the proposal. */
-+ return get_v2_child_proposals(&c->v2_ike_auth_child_proposals, c,
-+ why, &unset_group);
-+}
-+
-+/*
-+ * If needed, generate the proposals for a CHILD SA being created (or
-+ * re-keyed) during a CREATE_CHILD_SA exchange.
-+ *
-+ * If the proposals do not include DH, and PFS is enabled, then the
-+ * DEFAULT_DH (DH used by the IKE SA) is added to all proposals.
-+ *
-+ * XXX:
-+ *
-+ * This means that the CHILD SA's proposal suite will change depending
-+ * on what DH is negotiated by the IKE SA! Hence the need to save the
-+ * DEFAULT_DH and check for change. It should probably be storing the
-+ * proposal in the state.
-+ *
-+ * Horrible.
-+ */
-+struct ikev2_proposals *get_v2_create_child_proposals(struct connection *c, const char *why,
-+ const struct oakley_group_desc *default_dh)
-+{
-+ if (c->v2_create_child_proposals_default_dh != default_dh) {
-+ const char *old_fqn = (c->v2_create_child_proposals_default_dh != NULL
-+ ? c->v2_create_child_proposals_default_dh->common.fqn
-+ : "no-PFS");
-+ const char *new_fqn = default_dh != NULL ? default_dh->common.fqn : "no-PFS";
-+ DBGF(DBG_CONTROL, "create child proposal's DH changed from %s to %s, flushing",
-+ old_fqn, new_fqn);
-+ free_ikev2_proposals(&c->v2_create_child_proposals);
-+ c->v2_create_child_proposals_default_dh = default_dh;
-+ }
-+ return get_v2_child_proposals(&c->v2_create_child_proposals, c, why,
-+ c->v2_create_child_proposals_default_dh);
- }
-
- struct ipsec_proto_info *ikev2_child_sa_proto_info(struct state *st, lset_t policy)
-@@ -2358,7 +2431,7 @@
- {
- int propnum;
- const struct ikev2_proposal *proposal;
-- FOR_EACH_PROPOSAL(propnum, proposal, proposals) {
-+ FOR_EACH_V2_PROPOSAL(propnum, proposal, proposals) {
- const struct ikev2_transforms *transforms = &proposal->transforms[IKEv2_TRANS_TYPE_DH];
- int t;
- for (t = 0; t < transforms->transform[t].valid; t++) {
-@@ -2393,7 +2466,7 @@
- {
- int propnum;
- const struct ikev2_proposal *proposal;
-- FOR_EACH_PROPOSAL(propnum, proposal, proposals) {
-+ FOR_EACH_V2_PROPOSAL(propnum, proposal, proposals) {
- const struct ikev2_transforms *transforms = &proposal->transforms[IKEv2_TRANS_TYPE_DH];
- const struct ikev2_transform *transform;
- FOR_EACH_TRANSFORM(transform, transforms) {
-diff -Naur libreswan-3.27-orig/programs/pluto/initiate.c libreswan-3.27/programs/pluto/initiate.c
---- libreswan-3.27-orig/programs/pluto/initiate.c 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/programs/pluto/initiate.c 2019-02-15 16:32:28.999835528 -0500
-@@ -63,7 +63,7 @@
- #include "log.h"
- #include "keys.h"
- #include "whack.h"
--#include "alg_info.h"
-+#include "proposals.h"
- #include "spdb.h"
- #include "ike_alg.h"
- #include "kernel_alg.h"
-@@ -287,15 +287,12 @@
- /* We will only request an IPsec SA if policy isn't empty
- * (ignoring Main Mode items).
- * This is a fudge, but not yet important.
-- * If we are to proceed asynchronously, whackfd will be NULL_FD.
- */
-
- if (c->policy & (POLICY_ENCRYPT | POLICY_AUTHENTICATE)) {
-- struct alg_info_esp *alg = c->alg_info_esp;
-- struct db_sa *phase2_sa = kernel_alg_makedb(
-- c->policy, alg, TRUE);
--
-- if (alg != NULL && phase2_sa == NULL) {
-+ struct db_sa *phase2_sa =
-+ kernel_alg_makedb(c->policy, c->child_proposals, TRUE);
-+ if (c->child_proposals.p != NULL && phase2_sa == NULL) {
- whack_log(RC_LOG_SERIOUS,
- "cannot initiate: no acceptable kernel algorithms loaded");
- reset_cur_connection();
-diff -Naur libreswan-3.27-orig/programs/pluto/kernel_bsdkame.c libreswan-3.27/programs/pluto/kernel_bsdkame.c
---- libreswan-3.27-orig/programs/pluto/kernel_bsdkame.c 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/programs/pluto/kernel_bsdkame.c 2019-02-15 16:32:28.999835528 -0500
-@@ -47,7 +47,6 @@
- #include "whack.h" /* for RC_LOG_SERIOUS */
- #include "packet.h" /* for pb_stream in nat_traversal.h */
- #include "nat_traversal.h"
--#include "alg_info.h"
- #include "kernel_alg.h"
- #include "kernel_sadb.h"
-
-diff -Naur libreswan-3.27-orig/programs/pluto/kernel.c libreswan-3.27/programs/pluto/kernel.c
---- libreswan-3.27-orig/programs/pluto/kernel.c 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/programs/pluto/kernel.c 2019-02-15 16:32:29.000835537 -0500
-@@ -1176,7 +1176,6 @@
- }
- }
-
--#include "alg_info.h"
- #include "kernel_alg.h"
-
- void set_text_said(char *text_said, const ip_address *dst,
-diff -Naur libreswan-3.27-orig/programs/pluto/kernel_klips.c libreswan-3.27/programs/pluto/kernel_klips.c
---- libreswan-3.27-orig/programs/pluto/kernel_klips.c 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/programs/pluto/kernel_klips.c 2019-02-15 16:32:29.000835537 -0500
-@@ -48,7 +48,6 @@
- #include "nat_traversal.h"
- #include "server.h"
-
--#include "alg_info.h"
- #include "kernel_alg.h"
- #include "ip_address.h"
-
-diff -Naur libreswan-3.27-orig/programs/pluto/kernel_mast.c libreswan-3.27/programs/pluto/kernel_mast.c
---- libreswan-3.27-orig/programs/pluto/kernel_mast.c 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/programs/pluto/kernel_mast.c 2019-02-15 16:32:29.001835546 -0500
-@@ -48,7 +48,6 @@
- #include "nat_traversal.h"
- #include "server.h"
-
--#include "alg_info.h"
- #include "kernel_alg.h"
-
- static int next_free_mast_device = -1;
-diff -Naur libreswan-3.27-orig/programs/pluto/kernel_pfkey.c libreswan-3.27/programs/pluto/kernel_pfkey.c
---- libreswan-3.27-orig/programs/pluto/kernel_pfkey.c 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/programs/pluto/kernel_pfkey.c 2019-02-15 16:32:29.001835546 -0500
-@@ -63,7 +63,6 @@
- #include "nat_traversal.h"
-
- #include "lsw_select.h"
--#include "alg_info.h"
- #include "kernel_alg.h"
- #include "ip_address.h"
-
-diff -Naur libreswan-3.27-orig/programs/pluto/plutoalg.c libreswan-3.27/programs/pluto/plutoalg.c
---- libreswan-3.27-orig/programs/pluto/plutoalg.c 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/programs/pluto/plutoalg.c 2019-02-15 16:32:29.002835556 -0500
-@@ -34,7 +34,7 @@
- #include "connections.h"
- #include "state.h"
- #include "kernel_alg.h"
--#include "alg_info.h"
-+#include "proposals.h"
- #include "ike_alg.h"
- #include "ike_alg_integ.h"
- #include "ike_alg_encrypt.h"
-@@ -47,15 +47,16 @@
- #include "ikev1.h" /* for ikev1_quick_dh() */
-
- static bool kernel_alg_db_add(struct db_context *db_ctx,
-- const struct proposal_info *esp_info,
-+ const struct proposal *proposal,
- lset_t policy, bool logit)
- {
- int ealg_i = SADB_EALG_NONE;
-
-+ struct v1_proposal algs = v1_proposal(proposal);
- if (policy & POLICY_ENCRYPT) {
-- ealg_i = esp_info->encrypt->common.id[IKEv1_ESP_ID];
-+ ealg_i = algs.encrypt->common.id[IKEv1_ESP_ID];
- /* already checked by the parser? */
-- if (!kernel_alg_encrypt_ok(esp_info->encrypt)) {
-+ if (!kernel_alg_encrypt_ok(algs.encrypt)) {
- if (logit) {
- loglog(RC_LOG_SERIOUS,
- "requested kernel enc ealg_id=%d not present",
-@@ -68,10 +69,10 @@
- }
- }
-
-- int aalg_i = esp_info->integ->integ_ikev1_ah_transform;
-+ int aalg_i = algs.integ->integ_ikev1_ah_transform;
-
- /* already checked by the parser? */
-- if (!kernel_alg_integ_ok(esp_info->integ)) {
-+ if (!kernel_alg_integ_ok(algs.integ)) {
- DBG_log("kernel_alg_db_add() kernel auth aalg_id=%d not present",
- aalg_i);
- return FALSE;
-@@ -82,32 +83,32 @@
- db_trans_add(db_ctx, ealg_i);
-
- /* add ESP auth attr (if present) */
-- if (esp_info->integ != &ike_alg_integ_none) {
-+ if (algs.integ != &ike_alg_integ_none) {
- db_attr_add_values(db_ctx,
- AUTH_ALGORITHM,
-- esp_info->integ->common.id[IKEv1_ESP_ID]);
-+ algs.integ->common.id[IKEv1_ESP_ID]);
- }
-
- /* add keylength if specified in esp= string */
-- if (esp_info->enckeylen != 0) {
-- db_attr_add_values(db_ctx,
-- KEY_LENGTH,
-- esp_info->enckeylen);
-+ if (algs.enckeylen != 0) {
-+ db_attr_add_values(db_ctx,
-+ KEY_LENGTH,
-+ algs.enckeylen);
- } else {
- /* no key length - if required add default here and add another max entry */
-- int def_ks = (esp_info->encrypt->keylen_omitted ? 0
-- : esp_info->encrypt->keydeflen);
-+ int def_ks = (algs.encrypt->keylen_omitted ? 0
-+ : algs.encrypt->keydeflen);
-
- if (def_ks != 0) {
- db_attr_add_values(db_ctx, KEY_LENGTH, def_ks);
- /* add this trans again with max key size */
-- int max_ks = encrypt_max_key_bit_length(esp_info->encrypt);
-+ int max_ks = encrypt_max_key_bit_length(algs.encrypt);
- if (def_ks != max_ks) {
- db_trans_add(db_ctx, ealg_i);
-- if (esp_info->integ != &ike_alg_integ_none) {
-+ if (algs.integ != &ike_alg_integ_none) {
- db_attr_add_values(db_ctx,
- AUTH_ALGORITHM,
-- esp_info->integ->common.id[IKEv1_ESP_ID]);
-+ algs.integ->common.id[IKEv1_ESP_ID]);
- }
- db_attr_add_values(db_ctx,
- KEY_LENGTH,
-@@ -120,8 +121,8 @@
- db_trans_add(db_ctx, aalg_i);
-
- /* add ESP auth attr */
-- db_attr_add_values(db_ctx,
-- AUTH_ALGORITHM, esp_info->integ->common.id[IKEv1_ESP_ID]);
-+ db_attr_add_values(db_ctx, AUTH_ALGORITHM,
-+ algs.integ->common.id[IKEv1_ESP_ID]);
- }
-
- return TRUE;
-@@ -135,7 +136,7 @@
- * for now this function does free() previous returned
- * malloced pointer (this quirk allows easier spdb.c change)
- */
--static struct db_context *kernel_alg_db_new(struct alg_info_esp *alg_info,
-+static struct db_context *kernel_alg_db_new(struct child_proposals proposals,
- lset_t policy, bool logit)
- {
- unsigned int trans_cnt = 0;
-@@ -157,25 +158,24 @@
-
- /*
- * Loop: for each element (struct esp_info) of
-- * alg_info, if kernel support is present then
-+ * proposals, if kernel support is present then
- * build the transform (and attrs)
- *
-- * if NULL alg_info, propose everything ...
-+ * if NULL proposals, propose everything ...
- */
-
- bool success = TRUE;
-- if (alg_info != NULL) {
-- FOR_EACH_ESP_INFO(alg_info, proposal) {
-+ if (proposals.p != NULL) {
-+ FOR_EACH_PROPOSAL(proposals.p, proposal) {
- LSWDBGP(DBG_CONTROL | DBG_EMITTING, buf) {
- lswlogs(buf, "adding proposal: ");
-- lswlog_proposal_info(buf, proposal);
-+ fmt_proposal(buf, proposal);
- }
-- if (!kernel_alg_db_add(ctx_new, proposal,
-- policy, logit))
-+ if (!kernel_alg_db_add(ctx_new, proposal, policy, logit))
- success = FALSE; /* ??? should we break? */
- }
- } else {
-- PEXPECT_LOG("%s", "alg_info should be non-NULL");
-+ PEXPECT_LOG("%s", "proposals should be non-NULL");
- }
-
- if (!success) {
-@@ -268,7 +268,7 @@
- * If this is NULL and PFS is required then callers fall back to using
- * the parent's DH algorithm.
- */
-- const struct oakley_group_desc *dh = ikev1_quick_pfs(c->alg_info_esp);
-+ const struct oakley_group_desc *dh = ikev1_quick_pfs(c->child_proposals);
- if (dh != NULL) {
- pfsbuf = dh->common.fqn;
- } else {
-@@ -278,7 +278,7 @@
- pfsbuf = "";
- }
-
-- if (c->alg_info_esp != NULL) {
-+ if (c->child_proposals.p != NULL) {
- LSWLOG_WHACK(RC_COMMENT, buf) {
- /*
- * If DH (PFS) was specified in the esp= or
-@@ -299,7 +299,7 @@
- */
- lswlogf(buf, "\"%s\"%s: %s algorithms: ",
- c->name, instance, satype);
-- lswlog_alg_info(buf, &c->alg_info_esp->ai);
-+ fmt_proposals(buf, c->child_proposals.p);
- }
- }
-
-@@ -326,10 +326,11 @@
- }
- }
-
--struct db_sa *kernel_alg_makedb(lset_t policy, struct alg_info_esp *ei,
-+struct db_sa *kernel_alg_makedb(lset_t policy,
-+ struct child_proposals proposals,
- bool logit)
- {
-- if (ei == NULL) {
-+ if (proposals.p == NULL) {
- struct db_sa *sadb;
- lset_t pm = POLICY_ENCRYPT | POLICY_AUTHENTICATE;
-
-@@ -344,7 +345,7 @@
- return sadb;
- }
-
-- struct db_context *dbnew = kernel_alg_db_new(ei, policy, logit);
-+ struct db_context *dbnew = kernel_alg_db_new(proposals, policy, logit);
-
- if (dbnew == NULL) {
- libreswan_log("failed to translate esp_info to proposal, returning empty");
-diff -Naur libreswan-3.27-orig/programs/pluto/spdb.c libreswan-3.27/programs/pluto/spdb.c
---- libreswan-3.27-orig/programs/pluto/spdb.c 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/programs/pluto/spdb.c 2019-02-15 16:32:29.002835556 -0500
-@@ -51,7 +51,6 @@
-
- #include "crypto.h"
-
--#include "alg_info.h"
- #include "kernel_alg.h"
- #include "ike_alg.h"
- #include "db_ops.h"
-diff -Naur libreswan-3.27-orig/programs/pluto/spdb.h libreswan-3.27/programs/pluto/spdb.h
---- libreswan-3.27-orig/programs/pluto/spdb.h 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/programs/pluto/spdb.h 2019-02-15 16:32:29.002835556 -0500
-@@ -171,12 +171,12 @@
- struct alg_info_ike;
- struct alg_info_esp;
-
--extern struct db_sa *oakley_alg_makedb(struct alg_info_ike *ai,
-+extern struct db_sa *oakley_alg_makedb(const struct ike_proposals proposals,
- enum ikev1_auth_method auth_method,
- bool single_dh);
-
- extern struct db_sa *kernel_alg_makedb(lset_t policy,
-- struct alg_info_esp *ei,
-+ const struct child_proposals proposals,
- bool logit);
-
- #endif /* _SPDB_H_ */
-diff -Naur libreswan-3.27-orig/programs/pluto/spdb_struct.c libreswan-3.27/programs/pluto/spdb_struct.c
---- libreswan-3.27-orig/programs/pluto/spdb_struct.c 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/programs/pluto/spdb_struct.c 2019-02-15 16:32:29.003835565 -0500
-@@ -45,7 +45,6 @@
-
- #include "crypto.h"
-
--#include "alg_info.h"
- #include "kernel_alg.h"
- #include "ike_alg.h"
- #include "db_ops.h"
-@@ -82,30 +81,31 @@
- * one DH group.
- */
-
--static struct db_sa *oakley_alg_mergedb(struct alg_info_ike *ai,
-+static struct db_sa *oakley_alg_mergedb(struct ike_proposals ike_proposals,
- enum ikev1_auth_method auth_method,
- bool single_dh);
-
--static struct alg_info_ike *ikev1_default_ike_info(void)
-+static struct ike_proposals ikev1_default_ike_info(void)
- {
- static const struct proposal_policy policy = {
-- .ikev1 = TRUE,
-+ .version = IKEv1,
-+ .check_pfs_vs_dh = false,
- .alg_is_ok = ike_alg_is_ike,
- .warning = libreswan_log,
- };
-
-- char err[100];
-- struct alg_info_ike *defaults =
-- alg_info_ike_create_from_str(&policy, NULL,
-- err, sizeof(err));
-- if (defaults == NULL) {
-- PEXPECT_LOG("Invalid IKEv1 default algorithms: %s", err);
-+ struct proposal_parser *parser = ike_proposal_parser(&policy);
-+ struct ike_proposals defaults = { .p = proposals_from_str(parser, NULL), };
-+ if (defaults.p == NULL) {
-+ PEXPECT_LOG("Invalid IKEv1 default algorithms: %s",
-+ parser->error);
- }
-
-+ free_proposal_parser(&parser);
- return defaults;
- }
-
--struct db_sa *oakley_alg_makedb(struct alg_info_ike *ai,
-+struct db_sa *oakley_alg_makedb(const struct ike_proposals ike_proposals,
- enum ikev1_auth_method auth_method,
- bool single_dh)
- {
-@@ -114,26 +114,25 @@
- * standard defaults.
- */
-
-- if (ai == NULL) {
-+ if (ike_proposals.p == NULL) {
- DBG(DBG_CONTROL, DBG_log(
- "no specific IKE algorithms specified - using defaults"));
-- struct alg_info_ike *default_info
-- = ikev1_default_ike_info();
-+ struct ike_proposals default_info = ikev1_default_ike_info();
- struct db_sa *new_db = oakley_alg_mergedb(default_info,
- auth_method,
- single_dh);
-- pfree(default_info);
-+ proposals_delref(&default_info.p);
- return new_db;
- } else {
-- return oakley_alg_mergedb(ai, auth_method, single_dh);
-+ return oakley_alg_mergedb(ike_proposals, auth_method, single_dh);
- }
- }
-
--struct db_sa *oakley_alg_mergedb(struct alg_info_ike *ai,
-+struct db_sa *oakley_alg_mergedb(struct ike_proposals ike_proposals,
- enum ikev1_auth_method auth_method,
- bool single_dh)
- {
-- passert(ai != NULL);
-+ passert(ike_proposals.p != NULL);
-
- struct db_sa *gsp = NULL;
-
-@@ -150,26 +149,28 @@
- * when creating each item, we will use the first transform
- * from the base item as the template.
- */
-- FOR_EACH_IKE_INFO(ai, ike_info) {
-+ FOR_EACH_PROPOSAL(ike_proposals.p, proposal) {
- struct db_sa *emp_sp;
-
-- passert(ike_info->encrypt);
-- passert(ike_info->prf);
-- passert(ike_info->dh);
--
-- unsigned ealg = ike_info->encrypt->common.ikev1_oakley_id;
-- unsigned halg = ike_info->prf->common.ikev1_oakley_id;
-- unsigned modp = ike_info->dh->group;
-- unsigned eklen = ike_info->enckeylen;
-+ struct v1_proposal algs = v1_proposal(proposal);
-+
-+ passert(algs.encrypt != NULL);
-+ passert(algs.prf != NULL);
-+ passert(algs.dh != NULL);
-+
-+ unsigned ealg = algs.encrypt->common.ikev1_oakley_id;
-+ unsigned halg = algs.prf->common.ikev1_oakley_id;
-+ unsigned modp = algs.dh->group;
-+ unsigned eklen = algs.enckeylen;
-
- DBG(DBG_CONTROL,
- DBG_log("oakley_alg_makedb() processing ealg=%s=%u halg=%s=%u modp=%s=%u eklen=%u",
-- ike_info->encrypt->common.name, ealg,
-- ike_info->prf->common.name, halg,
-- ike_info->dh->common.name, modp,
-+ algs.encrypt->common.name, ealg,
-+ algs.prf->common.name, halg,
-+ algs.dh->common.name, modp,
- eklen));
-
-- const struct encrypt_desc *enc_desc = ike_info->encrypt;
-+ const struct encrypt_desc *enc_desc = algs.encrypt;
- if (eklen != 0 && !encrypt_has_key_bit_length(enc_desc, eklen)) {
- PEXPECT_LOG("IKEv1 proposal with ENCRYPT%s (specified) keylen:%d, not valid, should have been dropped",
- enc_desc->common.name,
-@@ -251,7 +252,7 @@
- * a different DH group, we try to deal with this.
- */
- if (single_dh && transcnt > 0 &&
-- ike_info->dh->group != last_modp) {
-+ algs.dh->group != last_modp) {
- if (
- #ifdef USE_DH2
- last_modp == OAKLEY_GROUP_MODP1024 ||
-@@ -269,13 +270,13 @@
- }
-
- loglog(RC_LOG_SERIOUS,
-- "transform (%s,%s,%s keylen %zd) ignored.",
-+ "transform (%s,%s,%s keylen %d) ignored.",
- enum_name(&oakley_enc_names,
-- ike_info->encrypt->common.ikev1_oakley_id),
-+ algs.encrypt->common.ikev1_oakley_id),
- enum_name(&oakley_hash_names,
-- ike_info->prf->common.ikev1_oakley_id),
-- ike_info->dh->common.name,
-- ike_info->enckeylen);
-+ algs.prf->common.ikev1_oakley_id),
-+ algs.dh->common.name,
-+ algs.enckeylen);
- free_sa(&emp_sp);
- } else {
- /*
-@@ -303,9 +304,9 @@
- * Exclude 3des et.al. which do not include
- * default key lengths in the proposal.
- */
-- if (ike_info->enckeylen == 0 &&
-- !ike_info->encrypt->keylen_omitted) {
-- const struct encrypt_desc *enc_desc = ike_info->encrypt;
-+ if (algs.enckeylen == 0 &&
-+ !algs.encrypt->keylen_omitted) {
-+ const struct encrypt_desc *enc_desc = algs.encrypt;
- int def_ks = enc_desc->keydeflen;
- passert(def_ks); /* ike=null not supported */
- int max_ks = encrypt_max_key_bit_length(enc_desc);
-@@ -375,7 +376,7 @@
- emp_sp = NULL;
- }
- }
-- last_modp = ike_info->dh->group;
-+ last_modp = algs.dh->group;
- }
-
- transcnt++;
-diff -Naur libreswan-3.27-orig/programs/pluto/terminate.c libreswan-3.27/programs/pluto/terminate.c
---- libreswan-3.27-orig/programs/pluto/terminate.c 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/programs/pluto/terminate.c 2019-02-15 16:32:29.003835565 -0500
-@@ -53,7 +53,6 @@
- #include "log.h"
- #include "keys.h"
- #include "whack.h"
--#include "alg_info.h"
- #include "spdb.h"
- #include "ike_alg.h"
- #include "kernel_alg.h"
-diff -Naur libreswan-3.27-orig/programs/spi/spi.c libreswan-3.27/programs/spi/spi.c
---- libreswan-3.27-orig/programs/spi/spi.c 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/programs/spi/spi.c 2019-02-15 16:32:29.003835565 -0500
-@@ -61,7 +61,6 @@
-
- #include "lswlog.h"
- #include "lswtool.h"
--#include "alg_info.h"
- #include "kernel_alg.h"
- #include "kernel_sadb.h"
- #include "pfkey_help.h"
-diff -Naur libreswan-3.27-orig/testing/pluto/algparse-01/algparse.v1.pfs.txt libreswan-3.27/testing/pluto/algparse-01/algparse.v1.pfs.txt
---- libreswan-3.27-orig/testing/pluto/algparse-01/algparse.v1.pfs.txt 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/testing/pluto/algparse-01/algparse.v1.pfs.txt 2019-02-15 16:46:01.379390213 -0500
-@@ -386,3 +386,9 @@
- ERROR: IKE PRF algorithm 'id2' is not recognized
- algparse -v1 -pfs 'ike=aes_ccm'
- ERROR: IKE encryption algorithm 'aes_ccm' is not supported by IKEv1
-+algparse -v1 -pfs 'ike=aes_gcm-sha1-none-modp2048'
-+ ERROR: IKE encryption algorithm 'aes_gcm' is not supported by IKEv1
-+algparse -v1 -pfs 'ike=aes_gcm+aes_gcm-sha1-none-modp2048'
-+ ERROR: IKE encryption algorithm 'aes_gcm+aes_gcm' is not recognized
-+algparse -v1 -pfs 'ike=aes+aes_gcm'
-+ ERROR: IKE encryption algorithm 'aes+aes_gcm' is not recognized
-diff -Naur libreswan-3.27-orig/testing/pluto/algparse-01/algparse.v1.txt libreswan-3.27/testing/pluto/algparse-01/algparse.v1.txt
---- libreswan-3.27-orig/testing/pluto/algparse-01/algparse.v1.txt 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/testing/pluto/algparse-01/algparse.v1.txt 2019-02-15 16:46:01.379390213 -0500
-@@ -418,3 +418,9 @@
- ERROR: IKE PRF algorithm 'id2' is not recognized
- algparse -v1 'ike=aes_ccm'
- ERROR: IKE encryption algorithm 'aes_ccm' is not supported by IKEv1
-+algparse -v1 'ike=aes_gcm-sha1-none-modp2048'
-+ ERROR: IKE encryption algorithm 'aes_gcm' is not supported by IKEv1
-+algparse -v1 'ike=aes_gcm+aes_gcm-sha1-none-modp2048'
-+ ERROR: IKE encryption algorithm 'aes_gcm+aes_gcm' is not recognized
-+algparse -v1 'ike=aes+aes_gcm'
-+ ERROR: IKE encryption algorithm 'aes+aes_gcm' is not recognized
-diff -Naur libreswan-3.27-orig/testing/pluto/algparse-01/algparse.v2.pfs.txt libreswan-3.27/testing/pluto/algparse-01/algparse.v2.pfs.txt
---- libreswan-3.27-orig/testing/pluto/algparse-01/algparse.v2.pfs.txt 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/testing/pluto/algparse-01/algparse.v2.pfs.txt 2019-02-15 16:50:12.777728085 -0500
-@@ -1,11 +1,11 @@
- algparse -v2 -pfs 'esp'
-- AES_CBC-HMAC_SHA1_96
-+ AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -v2 -pfs 'esp='
- ERROR: String ended with invalid char, just after ""
- algparse -v2 -pfs 'esp=aes'
-- AES_CBC-HMAC_SHA1_96
-+ AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -v2 -pfs 'esp=aes;modp2048'
-- AES_CBC-HMAC_SHA1_96-MODP2048
-+ AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128-MODP2048
- algparse -v2 -pfs 'esp=aes-sha1'
- AES_CBC-HMAC_SHA1_96
- algparse -v2 -pfs 'esp=aes-sha1'
-@@ -13,7 +13,7 @@
- algparse -v2 -pfs 'esp=aes-sha1-modp2048'
- AES_CBC-HMAC_SHA1_96-MODP2048
- algparse -v2 -pfs 'esp=aes-128'
-- AES_CBC_128-HMAC_SHA1_96
-+ AES_CBC_128-HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -v2 -pfs 'esp=aes-128-sha1'
- AES_CBC_128-HMAC_SHA1_96
- algparse -v2 -pfs 'esp=aes-128-sha1'
-@@ -41,7 +41,7 @@
- algparse -v2 -pfs 'esp=null-sha1'
- NULL-HMAC_SHA1_96
- algparse -v2 -pfs 'esp=aes_cbc'
-- AES_CBC-HMAC_SHA1_96
-+ AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -v2 -pfs 'esp=aes-sha'
- AES_CBC-HMAC_SHA1_96
- algparse -v2 -pfs 'esp=aes-sha1'
-@@ -73,13 +73,13 @@
- algparse -v2 -pfs 'esp=aes256-sha2_512'
- AES_CBC_256-HMAC_SHA2_512_256
- algparse -v2 -pfs 'esp=camellia'
-- CAMELLIA_CBC-HMAC_SHA1_96
-+ CAMELLIA_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -v2 -pfs 'esp=camellia128'
-- CAMELLIA_CBC_128-HMAC_SHA1_96
-+ CAMELLIA_CBC_128-HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -v2 -pfs 'esp=camellia192'
-- CAMELLIA_CBC_192-HMAC_SHA1_96
-+ CAMELLIA_CBC_192-HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -v2 -pfs 'esp=camellia256'
-- CAMELLIA_CBC_256-HMAC_SHA1_96
-+ CAMELLIA_CBC_256-HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -v2 -pfs 'esp=aes_ccm'
- AES_CCM_16-NONE
- algparse -v2 -pfs 'esp=aes_ccm_a-128-null'
-@@ -181,19 +181,19 @@
- algparse -v2 -pfs 'esp=aes_gcm_16_256-null'
- AES_GCM_16_256-NONE
- algparse -v2 -pfs 'esp=aes_ctr'
-- AES_CTR-HMAC_SHA1_96
-+ AES_CTR-HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -v2 -pfs 'esp=aesctr'
-- AES_CTR-HMAC_SHA1_96
-+ AES_CTR-HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -v2 -pfs 'esp=aes_ctr128'
-- AES_CTR_128-HMAC_SHA1_96
-+ AES_CTR_128-HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -v2 -pfs 'esp=aes_ctr192'
-- AES_CTR_192-HMAC_SHA1_96
-+ AES_CTR_192-HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -v2 -pfs 'esp=aes_ctr256'
-- AES_CTR_256-HMAC_SHA1_96
-+ AES_CTR_256-HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -v2 -pfs 'esp=serpent'
-- SERPENT_CBC-HMAC_SHA1_96
-+ SERPENT_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -v2 -pfs 'esp=twofish'
-- TWOFISH_CBC-HMAC_SHA1_96
-+ TWOFISH_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -v2 -pfs 'esp=camellia_cbc_256-hmac_sha2_512_256;modp8192'
- CAMELLIA_CBC_256-HMAC_SHA2_512_256-MODP8192
- algparse -v2 -pfs 'esp=null_auth_aes_gmac_256-null;modp8192'
-@@ -210,12 +210,12 @@
- algparse -v2 -pfs 'esp=aes-sha1-modp8192,aes-sha1-modp8192,aes-sha1-modp8192'
- AES_CBC-HMAC_SHA1_96-MODP8192
- algparse -v2 -pfs 'esp=aes;none'
-- AES_CBC-HMAC_SHA1_96-NONE
-+ AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128-NONE
- algparse -v2 -pfs 'esp=aes;none,aes'
- ERROR: either all or no ESP proposals should specify DH
- algparse -v2 -pfs 'esp=aes;none,aes;modp2048'
-- AES_CBC-HMAC_SHA1_96-NONE
-- AES_CBC-HMAC_SHA1_96-MODP2048
-+ AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128-NONE
-+ AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128-MODP2048
- algparse -v2 -pfs 'esp=aes-sha1-none'
- AES_CBC-HMAC_SHA1_96-NONE
- algparse -v2 -pfs 'esp=aes-sha1;none'
-@@ -293,7 +293,7 @@
- algparse -v2 -pfs 'esp=3des-sha1-modp8192,3des-sha2-modp2048'
- ERROR: more than one IKEv2 ESP DH algorithm (MODP8192, MODP2048) requires unimplemented CHILD_SA INVALID_KE
- algparse -v2 -pfs 'ah'
-- HMAC_SHA1_96
-+ HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -v2 -pfs 'ah='
- ERROR: String ended with invalid char, just after ""
- algparse -v2 -pfs 'ah=md5'
-@@ -345,32 +345,23 @@
- algparse -v2 -pfs 'ah=ripemd'
- ERROR: AH integrity algorithm 'ripemd' is not recognized
- algparse -v2 -pfs 'ike'
-- AES_CBC-HMAC_SHA2_256-MODP2048
-- AES_CBC-HMAC_SHA2_512-MODP2048
-- AES_CBC-HMAC_SHA1-MODP2048
-- 3DES_CBC-HMAC_SHA2_256-MODP2048
-- 3DES_CBC-HMAC_SHA2_512-MODP2048
-- 3DES_CBC-HMAC_SHA1-MODP2048
-+ AES_CBC+3DES_CBC-HMAC_SHA2_512+HMAC_SHA2_256-MODP2048+MODP3072+MODP4096+MODP8192+DH19+DH20+DH21+DH31
- algparse -v2 -pfs 'ike='
- ERROR: String ended with invalid char, just after ""
- algparse -v2 -pfs 'ike=3des-sha1'
-- 3DES_CBC-HMAC_SHA1-MODP2048
-+ 3DES_CBC-HMAC_SHA1-MODP2048+MODP3072+MODP4096+MODP8192+DH19+DH20+DH21+DH31
- algparse -v2 -pfs 'ike=3des-sha1'
-- 3DES_CBC-HMAC_SHA1-MODP2048
-+ 3DES_CBC-HMAC_SHA1-MODP2048+MODP3072+MODP4096+MODP8192+DH19+DH20+DH21+DH31
- algparse -v2 -pfs 'ike=3des-sha1;modp1536'
- 3DES_CBC-HMAC_SHA1-MODP1536
- algparse -v2 -pfs 'ike=3des;dh21'
-- 3DES_CBC-HMAC_SHA2_256-DH21
-- 3DES_CBC-HMAC_SHA2_512-DH21
-- 3DES_CBC-HMAC_SHA1-DH21
-+ 3DES_CBC-HMAC_SHA2_512+HMAC_SHA2_256-DH21
- algparse -v2 -pfs 'ike=3des-sha1;dh21'
- 3DES_CBC-HMAC_SHA1-DH21
- algparse -v2 -pfs 'ike=3des-sha1-ecp_521'
- 3DES_CBC-HMAC_SHA1-DH21
- algparse -v2 -pfs 'ike=aes_gcm'
-- AES_GCM_16-HMAC_SHA2_256-MODP2048
-- AES_GCM_16-HMAC_SHA2_512-MODP2048
-- AES_GCM_16-HMAC_SHA1-MODP2048
-+ AES_GCM_16-HMAC_SHA2_512+HMAC_SHA2_256-MODP2048+MODP3072+MODP4096+MODP8192+DH19+DH20+DH21+DH31
- algparse -v2 -pfs 'ike=aes-sha1-modp8192,aes-sha1-modp8192,aes-sha1-modp8192'
- AES_CBC-HMAC_SHA1-MODP8192
- algparse -v2 -pfs 'ike=aes;none'
-@@ -381,3 +372,10 @@
- ERROR: IKE PRF algorithm 'id2' is not recognized
- algparse -v2 -pfs 'ike=aes_ccm'
- ERROR: IKE encryption algorithm 'aes_ccm' is not supported
-+algparse -v2 -pfs 'ike=aes_gcm-sha1-none-modp2048'
-+ ERROR: 'modp2048' unexpected
-+algparse -v2 -pfs 'ike=aes_gcm+aes_gcm-sha1-none-modp2048'
-+ WARNING: discarding duplicate algorithm 'aes_gcm_16'
-+ ERROR: 'modp2048' unexpected
-+algparse -v2 -pfs 'ike=aes+aes_gcm'
-+ ERROR: AEAD and non-AEAD IKE encryption algorithm can not be combined
-diff -Naur libreswan-3.27-orig/testing/pluto/algparse-01/algparse.v2.txt libreswan-3.27/testing/pluto/algparse-01/algparse.v2.txt
---- libreswan-3.27-orig/testing/pluto/algparse-01/algparse.v2.txt 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/testing/pluto/algparse-01/algparse.v2.txt 2019-02-15 16:50:12.778728094 -0500
-@@ -1,12 +1,12 @@
- algparse -v2 'esp'
-- AES_CBC-HMAC_SHA1_96
-+ AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -v2 'esp='
- ERROR: String ended with invalid char, just after ""
- algparse -v2 'esp=aes'
-- AES_CBC-HMAC_SHA1_96
-+ AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -v2 'esp=aes;modp2048'
- WARNING: ignoring ESP DH algorithm MODP2048 as PFS policy is disabled
-- AES_CBC-HMAC_SHA1_96
-+ AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -v2 'esp=aes-sha1'
- AES_CBC-HMAC_SHA1_96
- algparse -v2 'esp=aes-sha1'
-@@ -15,7 +15,7 @@
- WARNING: ignoring ESP DH algorithm MODP2048 as PFS policy is disabled
- AES_CBC-HMAC_SHA1_96
- algparse -v2 'esp=aes-128'
-- AES_CBC_128-HMAC_SHA1_96
-+ AES_CBC_128-HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -v2 'esp=aes-128-sha1'
- AES_CBC_128-HMAC_SHA1_96
- algparse -v2 'esp=aes-128-sha1'
-@@ -49,7 +49,7 @@
- algparse -v2 'esp=null-sha1'
- NULL-HMAC_SHA1_96
- algparse -v2 'esp=aes_cbc'
-- AES_CBC-HMAC_SHA1_96
-+ AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -v2 'esp=aes-sha'
- AES_CBC-HMAC_SHA1_96
- algparse -v2 'esp=aes-sha1'
-@@ -81,13 +81,13 @@
- algparse -v2 'esp=aes256-sha2_512'
- AES_CBC_256-HMAC_SHA2_512_256
- algparse -v2 'esp=camellia'
-- CAMELLIA_CBC-HMAC_SHA1_96
-+ CAMELLIA_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -v2 'esp=camellia128'
-- CAMELLIA_CBC_128-HMAC_SHA1_96
-+ CAMELLIA_CBC_128-HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -v2 'esp=camellia192'
-- CAMELLIA_CBC_192-HMAC_SHA1_96
-+ CAMELLIA_CBC_192-HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -v2 'esp=camellia256'
-- CAMELLIA_CBC_256-HMAC_SHA1_96
-+ CAMELLIA_CBC_256-HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -v2 'esp=aes_ccm'
- AES_CCM_16-NONE
- algparse -v2 'esp=aes_ccm_a-128-null'
-@@ -189,19 +189,19 @@
- algparse -v2 'esp=aes_gcm_16_256-null'
- AES_GCM_16_256-NONE
- algparse -v2 'esp=aes_ctr'
-- AES_CTR-HMAC_SHA1_96
-+ AES_CTR-HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -v2 'esp=aesctr'
-- AES_CTR-HMAC_SHA1_96
-+ AES_CTR-HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -v2 'esp=aes_ctr128'
-- AES_CTR_128-HMAC_SHA1_96
-+ AES_CTR_128-HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -v2 'esp=aes_ctr192'
-- AES_CTR_192-HMAC_SHA1_96
-+ AES_CTR_192-HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -v2 'esp=aes_ctr256'
-- AES_CTR_256-HMAC_SHA1_96
-+ AES_CTR_256-HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -v2 'esp=serpent'
-- SERPENT_CBC-HMAC_SHA1_96
-+ SERPENT_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -v2 'esp=twofish'
-- TWOFISH_CBC-HMAC_SHA1_96
-+ TWOFISH_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -v2 'esp=camellia_cbc_256-hmac_sha2_512_256;modp8192'
- WARNING: ignoring ESP DH algorithm MODP8192 as PFS policy is disabled
- CAMELLIA_CBC_256-HMAC_SHA2_512_256
-@@ -228,16 +228,16 @@
- AES_CBC-HMAC_SHA1_96
- algparse -v2 'esp=aes;none'
- WARNING: ignoring redundant ESP DH algorithm NONE as PFS policy is disabled
-- AES_CBC-HMAC_SHA1_96
-+ AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -v2 'esp=aes;none,aes'
- WARNING: ignoring redundant ESP DH algorithm NONE as PFS policy is disabled
-- AES_CBC-HMAC_SHA1_96
-- AES_CBC-HMAC_SHA1_96
-+ AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128
-+ AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -v2 'esp=aes;none,aes;modp2048'
- WARNING: ignoring redundant ESP DH algorithm NONE as PFS policy is disabled
- WARNING: ignoring ESP DH algorithm MODP2048 as PFS policy is disabled
-- AES_CBC-HMAC_SHA1_96
-- AES_CBC-HMAC_SHA1_96
-+ AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128
-+ AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -v2 'esp=aes-sha1-none'
- WARNING: ignoring redundant ESP DH algorithm NONE as PFS policy is disabled
- AES_CBC-HMAC_SHA1_96
-@@ -332,7 +332,7 @@
- 3DES_CBC-HMAC_SHA1_96
- 3DES_CBC-HMAC_SHA2_256_128
- algparse -v2 'ah'
-- HMAC_SHA1_96
-+ HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -v2 'ah='
- ERROR: String ended with invalid char, just after ""
- algparse -v2 'ah=md5'
-@@ -388,32 +388,23 @@
- algparse -v2 'ah=ripemd'
- ERROR: AH integrity algorithm 'ripemd' is not recognized
- algparse -v2 'ike'
-- AES_CBC-HMAC_SHA2_256-MODP2048
-- AES_CBC-HMAC_SHA2_512-MODP2048
-- AES_CBC-HMAC_SHA1-MODP2048
-- 3DES_CBC-HMAC_SHA2_256-MODP2048
-- 3DES_CBC-HMAC_SHA2_512-MODP2048
-- 3DES_CBC-HMAC_SHA1-MODP2048
-+ AES_CBC+3DES_CBC-HMAC_SHA2_512+HMAC_SHA2_256-MODP2048+MODP3072+MODP4096+MODP8192+DH19+DH20+DH21+DH31
- algparse -v2 'ike='
- ERROR: String ended with invalid char, just after ""
- algparse -v2 'ike=3des-sha1'
-- 3DES_CBC-HMAC_SHA1-MODP2048
-+ 3DES_CBC-HMAC_SHA1-MODP2048+MODP3072+MODP4096+MODP8192+DH19+DH20+DH21+DH31
- algparse -v2 'ike=3des-sha1'
-- 3DES_CBC-HMAC_SHA1-MODP2048
-+ 3DES_CBC-HMAC_SHA1-MODP2048+MODP3072+MODP4096+MODP8192+DH19+DH20+DH21+DH31
- algparse -v2 'ike=3des-sha1;modp1536'
- 3DES_CBC-HMAC_SHA1-MODP1536
- algparse -v2 'ike=3des;dh21'
-- 3DES_CBC-HMAC_SHA2_256-DH21
-- 3DES_CBC-HMAC_SHA2_512-DH21
-- 3DES_CBC-HMAC_SHA1-DH21
-+ 3DES_CBC-HMAC_SHA2_512+HMAC_SHA2_256-DH21
- algparse -v2 'ike=3des-sha1;dh21'
- 3DES_CBC-HMAC_SHA1-DH21
- algparse -v2 'ike=3des-sha1-ecp_521'
- 3DES_CBC-HMAC_SHA1-DH21
- algparse -v2 'ike=aes_gcm'
-- AES_GCM_16-HMAC_SHA2_256-MODP2048
-- AES_GCM_16-HMAC_SHA2_512-MODP2048
-- AES_GCM_16-HMAC_SHA1-MODP2048
-+ AES_GCM_16-HMAC_SHA2_512+HMAC_SHA2_256-MODP2048+MODP3072+MODP4096+MODP8192+DH19+DH20+DH21+DH31
- algparse -v2 'ike=aes-sha1-modp8192,aes-sha1-modp8192,aes-sha1-modp8192'
- AES_CBC-HMAC_SHA1-MODP8192
- algparse -v2 'ike=aes;none'
-@@ -424,3 +415,10 @@
- ERROR: IKE PRF algorithm 'id2' is not recognized
- algparse -v2 'ike=aes_ccm'
- ERROR: IKE encryption algorithm 'aes_ccm' is not supported
-+algparse -v2 'ike=aes_gcm-sha1-none-modp2048'
-+ ERROR: 'modp2048' unexpected
-+algparse -v2 'ike=aes_gcm+aes_gcm-sha1-none-modp2048'
-+ WARNING: discarding duplicate algorithm 'aes_gcm_16'
-+ ERROR: 'modp2048' unexpected
-+algparse -v2 'ike=aes+aes_gcm'
-+ ERROR: AEAD and non-AEAD IKE encryption algorithm can not be combined
-diff -Naur libreswan-3.27-orig/testing/pluto/algparse-01/algparse.v.txt libreswan-3.27/testing/pluto/algparse-01/algparse.v.txt
---- libreswan-3.27-orig/testing/pluto/algparse-01/algparse.v.txt 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/testing/pluto/algparse-01/algparse.v.txt 2019-02-15 16:32:29.004835574 -0500
-@@ -13,7 +13,7 @@
- algparse: SERPENT_CBC IKEv1: IKE ESP IKEv2: IKE ESP {256,192,*128} serpent
- algparse: TWOFISH_CBC IKEv1: IKE ESP IKEv2: IKE ESP {256,192,*128} twofish
- algparse: TWOFISH_SSH IKEv1: IKE IKEv2: IKE ESP {256,192,*128} twofish_cbc_ssh
--algparse: NULL_AUTH_AES_GMAC IKEv1: ESP IKEv2: ESP {256,192,*128} aes_gmac
-+algparse: NULL_AUTH_AES_GMAC IKEv1: ESP IKEv2: ESP FIPS {256,192,*128} aes_gmac
- algparse: NULL IKEv1: ESP IKEv2: ESP []
- algparse: CHACHA20_POLY1305 IKEv1: IKEv2: IKE ESP [*256] chacha20poly1305
- algparse: Hash algorithms:
-@@ -28,17 +28,17 @@
- algparse: HMAC_SHA2_256 IKEv1: IKE IKEv2: IKE FIPS sha2, sha256, sha2_256
- algparse: HMAC_SHA2_384 IKEv1: IKE IKEv2: IKE FIPS sha384, sha2_384
- algparse: HMAC_SHA2_512 IKEv1: IKE IKEv2: IKE FIPS sha512, sha2_512
--algparse: AES_XCBC IKEv1: IKEv2: IKE FIPS aes128_xcbc
-+algparse: AES_XCBC IKEv1: IKEv2: IKE aes128_xcbc
- algparse: Integrity algorithms:
- algparse: HMAC_MD5_96 IKEv1: IKE ESP AH IKEv2: IKE ESP AH md5, hmac_md5
- algparse: HMAC_SHA1_96 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS sha, sha1, sha1_96, hmac_sha1
--algparse: HMAC_SHA2_512_256 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS sha512, sha2_512, hmac_sha2_512
--algparse: HMAC_SHA2_384_192 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS sha384, sha2_384, hmac_sha2_384
--algparse: HMAC_SHA2_256_128 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS sha2, sha256, sha2_256, hmac_sha2_256
-+algparse: HMAC_SHA2_512_256 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS sha512, sha2_512, sha2_512_256, hmac_sha2_512
-+algparse: HMAC_SHA2_384_192 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS sha384, sha2_384, sha2_384_192, hmac_sha2_384
-+algparse: HMAC_SHA2_256_128 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS sha2, sha256, sha2_256, sha2_256_128, hmac_sha2_256
- algparse: HMAC_SHA2_256_TRUNCBUG IKEv1: ESP AH IKEv2: AH
--algparse: AES_XCBC_96 IKEv1: ESP AH IKEv2: IKE ESP AH FIPS aes_xcbc, aes128_xcbc, aes128_xcbc_96
-+algparse: AES_XCBC_96 IKEv1: ESP AH IKEv2: IKE ESP AH aes_xcbc, aes128_xcbc, aes128_xcbc_96
- algparse: AES_CMAC_96 IKEv1: ESP AH IKEv2: ESP AH FIPS aes_cmac
--algparse: NONE IKEv1: ESP IKEv2: ESP FIPS null
-+algparse: NONE IKEv1: ESP IKEv2: IKE ESP FIPS null
- algparse: DH algorithms:
- algparse: NONE IKEv1: IKEv2: IKE ESP AH FIPS null, dh0
- algparse: MODP1024 IKEv1: IKE ESP AH IKEv2: IKE ESP AH dh2
-@@ -48,8 +48,8 @@
- algparse: MODP4096 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS dh16
- algparse: MODP6144 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS dh17
- algparse: MODP8192 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS dh18
--algparse: DH19 IKEv1: IKE IKEv2: IKE ESP AH FIPS ecp_256
--algparse: DH20 IKEv1: IKE IKEv2: IKE ESP AH FIPS ecp_384
--algparse: DH21 IKEv1: IKE IKEv2: IKE ESP AH FIPS ecp_521
-+algparse: DH19 IKEv1: IKE IKEv2: IKE ESP AH FIPS ecp_256, ecp256
-+algparse: DH20 IKEv1: IKE IKEv2: IKE ESP AH FIPS ecp_384, ecp384
-+algparse: DH21 IKEv1: IKE IKEv2: IKE ESP AH FIPS ecp_521, ecp521
- algparse: DH31 IKEv1: IKE IKEv2: IKE ESP AH curve25519
- algparse: leak detective found no leaks
-diff -Naur libreswan-3.27-orig/testing/pluto/algparse-01/west.conf libreswan-3.27/testing/pluto/algparse-01/west.conf
---- libreswan-3.27-orig/testing/pluto/algparse-01/west.conf 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/testing/pluto/algparse-01/west.conf 2019-02-15 16:32:29.004835574 -0500
-@@ -10,4 +10,7 @@
- protostack=netkey
- plutodebug=all
-
-+conn %default
-+ ikev2=no
-+
- include /testing/baseconfigs/all/etc/ipsec.d/ipsec.conf.common
-diff -Naur libreswan-3.27-orig/testing/pluto/algparse-01/west.console.txt libreswan-3.27/testing/pluto/algparse-01/west.console.txt
---- libreswan-3.27-orig/testing/pluto/algparse-01/west.console.txt 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/testing/pluto/algparse-01/west.console.txt 2019-02-15 16:32:29.005835584 -0500
-@@ -5,8 +5,6 @@
- ../bin/algparse.sh PATH/libexec/ipsec/algparse algparse*.txt
- PATH/libexec/ipsec/algparse -v1 -pfs -t # algparse.v1.pfs.txt
- PATH/libexec/ipsec/algparse -v1 -t # algparse.v1.txt
--PATH/libexec/ipsec/algparse -v1 -v2 -pfs -t # algparse.v1.v2.pfs.txt
--PATH/libexec/ipsec/algparse -v1 -v2 -t # algparse.v1.v2.txt
- PATH/libexec/ipsec/algparse -v2 -pfs -t # algparse.v2.pfs.txt
- PATH/libexec/ipsec/algparse -v2 -t # algparse.v2.txt
- PATH/libexec/ipsec/algparse -v # algparse.v.txt
-@@ -48,7 +46,7 @@
- SERPENT_CBC IKEv1: IKE ESP IKEv2: IKE ESP {256,192,*128} serpent
- TWOFISH_CBC IKEv1: IKE ESP IKEv2: IKE ESP {256,192,*128} twofish
- TWOFISH_SSH IKEv1: IKE IKEv2: IKE ESP {256,192,*128} twofish_cbc_ssh
-- NULL_AUTH_AES_GMAC IKEv1: ESP IKEv2: ESP {256,192,*128} aes_gmac
-+ NULL_AUTH_AES_GMAC IKEv1: ESP IKEv2: ESP FIPS {256,192,*128} aes_gmac
- NULL IKEv1: ESP IKEv2: ESP []
- CHACHA20_POLY1305 IKEv1: IKEv2: IKE ESP [*256] chacha20poly1305
- Hash algorithms:
-@@ -63,7 +61,7 @@
- HMAC_SHA2_256 IKEv1: IKE IKEv2: IKE FIPS sha2, sha256, sha2_256
- HMAC_SHA2_384 IKEv1: IKE IKEv2: IKE FIPS sha384, sha2_384
- HMAC_SHA2_512 IKEv1: IKE IKEv2: IKE FIPS sha512, sha2_512
-- AES_XCBC IKEv1: IKEv2: IKE FIPS aes128_xcbc
-+ AES_XCBC IKEv1: IKEv2: IKE aes128_xcbc
- Integrity algorithms:
- HMAC_MD5_96 IKEv1: IKE ESP AH IKEv2: IKE ESP AH md5, hmac_md5
- HMAC_SHA1_96 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS sha, sha1, sha1_96, hmac_sha1
-@@ -71,7 +69,7 @@
- HMAC_SHA2_384_192 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS sha384, sha2_384, hmac_sha2_384
- HMAC_SHA2_256_128 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS sha2, sha256, sha2_256, hmac_sha2_256
- HMAC_SHA2_256_TRUNCBUG IKEv1: ESP AH IKEv2: AH
-- AES_XCBC_96 IKEv1: ESP AH IKEv2: IKE ESP AH FIPS aes_xcbc, aes128_xcbc, aes128_xcbc_96
-+ AES_XCBC_96 IKEv1: ESP AH IKEv2: IKE ESP AH aes_xcbc, aes128_xcbc, aes128_xcbc_96
- AES_CMAC_96 IKEv1: ESP AH IKEv2: ESP AH FIPS aes_cmac
- NONE IKEv1: ESP IKEv2: ESP FIPS null
- DH algorithms:
-diff -Naur libreswan-3.27-orig/testing/pluto/algparse-02-fips/algparse.v1.pfs.txt libreswan-3.27/testing/pluto/algparse-02-fips/algparse.v1.pfs.txt
---- libreswan-3.27-orig/testing/pluto/algparse-02-fips/algparse.v1.pfs.txt 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/testing/pluto/algparse-02-fips/algparse.v1.pfs.txt 2019-02-15 16:46:01.380390223 -0500
-@@ -57,7 +57,7 @@
- algparse -fips -v1 -pfs 'esp=aes128-sha1'
- AES_CBC_128-HMAC_SHA1_96
- algparse -fips -v1 -pfs 'esp=aes128-aes_xcbc'
-- AES_CBC_128-AES_XCBC_96
-+ ERROR: ESP integrity algorithm 'aes_xcbc' is not supported
- algparse -fips -v1 -pfs 'esp=aes192-sha1'
- AES_CBC_192-HMAC_SHA1_96
- algparse -fips -v1 -pfs 'esp=aes256-sha1'
-@@ -197,7 +197,7 @@
- algparse -fips -v1 -pfs 'esp=camellia_cbc_256-hmac_sha2_512_256;modp8192'
- ERROR: ESP encryption algorithm 'camellia_cbc_256' is not supported
- algparse -fips -v1 -pfs 'esp=null_auth_aes_gmac_256-null;modp8192'
-- ERROR: ESP encryption algorithm 'null_auth_aes_gmac_256' is not supported
-+ NULL_AUTH_AES_GMAC_256-NONE-MODP8192
- algparse -fips -v1 -pfs 'esp=3des-sha1;modp8192'
- 3DES_CBC-HMAC_SHA1_96-MODP8192
- algparse -fips -v1 -pfs 'esp=3des-sha1-modp8192'
-@@ -318,7 +318,7 @@
- algparse -fips -v1 -pfs 'ah=sha2_512'
- HMAC_SHA2_512_256
- algparse -fips -v1 -pfs 'ah=aes_xcbc'
-- AES_XCBC_96
-+ ERROR: AH integrity algorithm 'aes_xcbc' is not supported
- algparse -fips -v1 -pfs 'ah=sha2-none'
- ERROR: AH DH algorithm 'none' is not supported by IKEv1
- algparse -fips -v1 -pfs 'ah=sha2;none'
-@@ -378,3 +378,9 @@
- ERROR: IKE PRF algorithm 'id2' is not recognized
- algparse -fips -v1 -pfs 'ike=aes_ccm'
- ERROR: IKE encryption algorithm 'aes_ccm' is not supported by IKEv1
-+algparse -fips -v1 -pfs 'ike=aes_gcm-sha1-none-modp2048'
-+ ERROR: IKE encryption algorithm 'aes_gcm' is not supported by IKEv1
-+algparse -fips -v1 -pfs 'ike=aes_gcm+aes_gcm-sha1-none-modp2048'
-+ ERROR: IKE encryption algorithm 'aes_gcm+aes_gcm' is not recognized
-+algparse -fips -v1 -pfs 'ike=aes+aes_gcm'
-+ ERROR: IKE encryption algorithm 'aes+aes_gcm' is not recognized
-diff -Naur libreswan-3.27-orig/testing/pluto/algparse-02-fips/algparse.v1.txt libreswan-3.27/testing/pluto/algparse-02-fips/algparse.v1.txt
---- libreswan-3.27-orig/testing/pluto/algparse-02-fips/algparse.v1.txt 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/testing/pluto/algparse-02-fips/algparse.v1.txt 2019-02-15 16:46:01.380390223 -0500
-@@ -61,7 +61,7 @@
- algparse -fips -v1 'esp=aes128-sha1'
- AES_CBC_128-HMAC_SHA1_96
- algparse -fips -v1 'esp=aes128-aes_xcbc'
-- AES_CBC_128-AES_XCBC_96
-+ ERROR: ESP integrity algorithm 'aes_xcbc' is not supported
- algparse -fips -v1 'esp=aes192-sha1'
- AES_CBC_192-HMAC_SHA1_96
- algparse -fips -v1 'esp=aes256-sha1'
-@@ -201,7 +201,8 @@
- algparse -fips -v1 'esp=camellia_cbc_256-hmac_sha2_512_256;modp8192'
- ERROR: ESP encryption algorithm 'camellia_cbc_256' is not supported
- algparse -fips -v1 'esp=null_auth_aes_gmac_256-null;modp8192'
-- ERROR: ESP encryption algorithm 'null_auth_aes_gmac_256' is not supported
-+ WARNING: ignoring ESP DH algorithm MODP8192 as PFS policy is disabled
-+ NULL_AUTH_AES_GMAC_256-NONE
- algparse -fips -v1 'esp=3des-sha1;modp8192'
- WARNING: ignoring ESP DH algorithm MODP8192 as PFS policy is disabled
- 3DES_CBC-HMAC_SHA1_96
-@@ -345,7 +346,7 @@
- algparse -fips -v1 'ah=sha2_512'
- HMAC_SHA2_512_256
- algparse -fips -v1 'ah=aes_xcbc'
-- AES_XCBC_96
-+ ERROR: AH integrity algorithm 'aes_xcbc' is not supported
- algparse -fips -v1 'ah=sha2-none'
- ERROR: AH DH algorithm 'none' is not supported by IKEv1
- algparse -fips -v1 'ah=sha2;none'
-@@ -406,3 +407,9 @@
- ERROR: IKE PRF algorithm 'id2' is not recognized
- algparse -fips -v1 'ike=aes_ccm'
- ERROR: IKE encryption algorithm 'aes_ccm' is not supported by IKEv1
-+algparse -fips -v1 'ike=aes_gcm-sha1-none-modp2048'
-+ ERROR: IKE encryption algorithm 'aes_gcm' is not supported by IKEv1
-+algparse -fips -v1 'ike=aes_gcm+aes_gcm-sha1-none-modp2048'
-+ ERROR: IKE encryption algorithm 'aes_gcm+aes_gcm' is not recognized
-+algparse -fips -v1 'ike=aes+aes_gcm'
-+ ERROR: IKE encryption algorithm 'aes+aes_gcm' is not recognized
-diff -Naur libreswan-3.27-orig/testing/pluto/algparse-02-fips/algparse.v2.pfs.txt libreswan-3.27/testing/pluto/algparse-02-fips/algparse.v2.pfs.txt
---- libreswan-3.27-orig/testing/pluto/algparse-02-fips/algparse.v2.pfs.txt 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/testing/pluto/algparse-02-fips/algparse.v2.pfs.txt 2019-02-15 16:50:12.778728094 -0500
-@@ -1,11 +1,11 @@
- algparse -fips -v2 -pfs 'esp'
-- AES_CBC-HMAC_SHA1_96
-+ AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -fips -v2 -pfs 'esp='
- ERROR: String ended with invalid char, just after ""
- algparse -fips -v2 -pfs 'esp=aes'
-- AES_CBC-HMAC_SHA1_96
-+ AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -fips -v2 -pfs 'esp=aes;modp2048'
-- AES_CBC-HMAC_SHA1_96-MODP2048
-+ AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128-MODP2048
- algparse -fips -v2 -pfs 'esp=aes-sha1'
- AES_CBC-HMAC_SHA1_96
- algparse -fips -v2 -pfs 'esp=aes-sha1'
-@@ -13,7 +13,7 @@
- algparse -fips -v2 -pfs 'esp=aes-sha1-modp2048'
- AES_CBC-HMAC_SHA1_96-MODP2048
- algparse -fips -v2 -pfs 'esp=aes-128'
-- AES_CBC_128-HMAC_SHA1_96
-+ AES_CBC_128-HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -fips -v2 -pfs 'esp=aes-128-sha1'
- AES_CBC_128-HMAC_SHA1_96
- algparse -fips -v2 -pfs 'esp=aes-128-sha1'
-@@ -41,7 +41,7 @@
- algparse -fips -v2 -pfs 'esp=null-sha1'
- ERROR: ESP encryption algorithm 'null' is not supported
- algparse -fips -v2 -pfs 'esp=aes_cbc'
-- AES_CBC-HMAC_SHA1_96
-+ AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -fips -v2 -pfs 'esp=aes-sha'
- AES_CBC-HMAC_SHA1_96
- algparse -fips -v2 -pfs 'esp=aes-sha1'
-@@ -57,7 +57,7 @@
- algparse -fips -v2 -pfs 'esp=aes128-sha1'
- AES_CBC_128-HMAC_SHA1_96
- algparse -fips -v2 -pfs 'esp=aes128-aes_xcbc'
-- AES_CBC_128-AES_XCBC_96
-+ ERROR: ESP integrity algorithm 'aes_xcbc' is not supported
- algparse -fips -v2 -pfs 'esp=aes192-sha1'
- AES_CBC_192-HMAC_SHA1_96
- algparse -fips -v2 -pfs 'esp=aes256-sha1'
-@@ -181,15 +181,15 @@
- algparse -fips -v2 -pfs 'esp=aes_gcm_16_256-null'
- AES_GCM_16_256-NONE
- algparse -fips -v2 -pfs 'esp=aes_ctr'
-- AES_CTR-HMAC_SHA1_96
-+ AES_CTR-HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -fips -v2 -pfs 'esp=aesctr'
-- AES_CTR-HMAC_SHA1_96
-+ AES_CTR-HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -fips -v2 -pfs 'esp=aes_ctr128'
-- AES_CTR_128-HMAC_SHA1_96
-+ AES_CTR_128-HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -fips -v2 -pfs 'esp=aes_ctr192'
-- AES_CTR_192-HMAC_SHA1_96
-+ AES_CTR_192-HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -fips -v2 -pfs 'esp=aes_ctr256'
-- AES_CTR_256-HMAC_SHA1_96
-+ AES_CTR_256-HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -fips -v2 -pfs 'esp=serpent'
- ERROR: ESP encryption algorithm 'serpent' is not supported
- algparse -fips -v2 -pfs 'esp=twofish'
-@@ -197,7 +197,7 @@
- algparse -fips -v2 -pfs 'esp=camellia_cbc_256-hmac_sha2_512_256;modp8192'
- ERROR: ESP encryption algorithm 'camellia_cbc_256' is not supported
- algparse -fips -v2 -pfs 'esp=null_auth_aes_gmac_256-null;modp8192'
-- ERROR: ESP encryption algorithm 'null_auth_aes_gmac_256' is not supported
-+ NULL_AUTH_AES_GMAC_256-NONE-MODP8192
- algparse -fips -v2 -pfs 'esp=3des-sha1;modp8192'
- 3DES_CBC-HMAC_SHA1_96-MODP8192
- algparse -fips -v2 -pfs 'esp=3des-sha1-modp8192'
-@@ -210,12 +210,12 @@
- algparse -fips -v2 -pfs 'esp=aes-sha1-modp8192,aes-sha1-modp8192,aes-sha1-modp8192'
- AES_CBC-HMAC_SHA1_96-MODP8192
- algparse -fips -v2 -pfs 'esp=aes;none'
-- AES_CBC-HMAC_SHA1_96-NONE
-+ AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128-NONE
- algparse -fips -v2 -pfs 'esp=aes;none,aes'
- ERROR: either all or no ESP proposals should specify DH
- algparse -fips -v2 -pfs 'esp=aes;none,aes;modp2048'
-- AES_CBC-HMAC_SHA1_96-NONE
-- AES_CBC-HMAC_SHA1_96-MODP2048
-+ AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128-NONE
-+ AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128-MODP2048
- algparse -fips -v2 -pfs 'esp=aes-sha1-none'
- AES_CBC-HMAC_SHA1_96-NONE
- algparse -fips -v2 -pfs 'esp=aes-sha1;none'
-@@ -293,7 +293,7 @@
- algparse -fips -v2 -pfs 'esp=3des-sha1-modp8192,3des-sha2-modp2048'
- ERROR: more than one IKEv2 ESP DH algorithm (MODP8192, MODP2048) requires unimplemented CHILD_SA INVALID_KE
- algparse -fips -v2 -pfs 'ah'
-- HMAC_SHA1_96
-+ HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -fips -v2 -pfs 'ah='
- ERROR: String ended with invalid char, just after ""
- algparse -fips -v2 -pfs 'ah=md5'
-@@ -319,7 +319,7 @@
- algparse -fips -v2 -pfs 'ah=sha2_512'
- HMAC_SHA2_512_256
- algparse -fips -v2 -pfs 'ah=aes_xcbc'
-- AES_XCBC_96
-+ ERROR: AH integrity algorithm 'aes_xcbc' is not supported
- algparse -fips -v2 -pfs 'ah=sha2-none'
- HMAC_SHA2_256_128-NONE
- algparse -fips -v2 -pfs 'ah=sha2;none'
-@@ -345,32 +345,23 @@
- algparse -fips -v2 -pfs 'ah=ripemd'
- ERROR: AH integrity algorithm 'ripemd' is not recognized
- algparse -fips -v2 -pfs 'ike'
-- AES_CBC-HMAC_SHA2_256-MODP2048
-- AES_CBC-HMAC_SHA2_512-MODP2048
-- AES_CBC-HMAC_SHA1-MODP2048
-- 3DES_CBC-HMAC_SHA2_256-MODP2048
-- 3DES_CBC-HMAC_SHA2_512-MODP2048
-- 3DES_CBC-HMAC_SHA1-MODP2048
-+ AES_CBC+3DES_CBC-HMAC_SHA2_512+HMAC_SHA2_256-MODP2048+MODP3072+MODP4096+MODP8192+DH19+DH20+DH21+DH31
- algparse -fips -v2 -pfs 'ike='
- ERROR: String ended with invalid char, just after ""
- algparse -fips -v2 -pfs 'ike=3des-sha1'
-- 3DES_CBC-HMAC_SHA1-MODP2048
-+ 3DES_CBC-HMAC_SHA1-MODP2048+MODP3072+MODP4096+MODP8192+DH19+DH20+DH21+DH31
- algparse -fips -v2 -pfs 'ike=3des-sha1'
-- 3DES_CBC-HMAC_SHA1-MODP2048
-+ 3DES_CBC-HMAC_SHA1-MODP2048+MODP3072+MODP4096+MODP8192+DH19+DH20+DH21+DH31
- algparse -fips -v2 -pfs 'ike=3des-sha1;modp1536'
- ERROR: IKE DH algorithm 'modp1536' is not supported
- algparse -fips -v2 -pfs 'ike=3des;dh21'
-- 3DES_CBC-HMAC_SHA2_256-DH21
-- 3DES_CBC-HMAC_SHA2_512-DH21
-- 3DES_CBC-HMAC_SHA1-DH21
-+ 3DES_CBC-HMAC_SHA2_512+HMAC_SHA2_256-DH21
- algparse -fips -v2 -pfs 'ike=3des-sha1;dh21'
- 3DES_CBC-HMAC_SHA1-DH21
- algparse -fips -v2 -pfs 'ike=3des-sha1-ecp_521'
- 3DES_CBC-HMAC_SHA1-DH21
- algparse -fips -v2 -pfs 'ike=aes_gcm'
-- AES_GCM_16-HMAC_SHA2_256-MODP2048
-- AES_GCM_16-HMAC_SHA2_512-MODP2048
-- AES_GCM_16-HMAC_SHA1-MODP2048
-+ AES_GCM_16-HMAC_SHA2_512+HMAC_SHA2_256-MODP2048+MODP3072+MODP4096+MODP8192+DH19+DH20+DH21+DH31
- algparse -fips -v2 -pfs 'ike=aes-sha1-modp8192,aes-sha1-modp8192,aes-sha1-modp8192'
- AES_CBC-HMAC_SHA1-MODP8192
- algparse -fips -v2 -pfs 'ike=aes;none'
-@@ -381,3 +372,10 @@
- ERROR: IKE PRF algorithm 'id2' is not recognized
- algparse -fips -v2 -pfs 'ike=aes_ccm'
- ERROR: IKE encryption algorithm 'aes_ccm' is not supported
-+algparse -fips -v2 -pfs 'ike=aes_gcm-sha1-none-modp2048'
-+ ERROR: 'modp2048' unexpected
-+algparse -fips -v2 -pfs 'ike=aes_gcm+aes_gcm-sha1-none-modp2048'
-+ WARNING: discarding duplicate algorithm 'aes_gcm_16'
-+ ERROR: 'modp2048' unexpected
-+algparse -fips -v2 -pfs 'ike=aes+aes_gcm'
-+ ERROR: AEAD and non-AEAD IKE encryption algorithm can not be combined
-diff -Naur libreswan-3.27-orig/testing/pluto/algparse-02-fips/algparse.v2.txt libreswan-3.27/testing/pluto/algparse-02-fips/algparse.v2.txt
---- libreswan-3.27-orig/testing/pluto/algparse-02-fips/algparse.v2.txt 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/testing/pluto/algparse-02-fips/algparse.v2.txt 2019-02-15 16:50:12.778728094 -0500
-@@ -1,12 +1,12 @@
- algparse -fips -v2 'esp'
-- AES_CBC-HMAC_SHA1_96
-+ AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -fips -v2 'esp='
- ERROR: String ended with invalid char, just after ""
- algparse -fips -v2 'esp=aes'
-- AES_CBC-HMAC_SHA1_96
-+ AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -fips -v2 'esp=aes;modp2048'
- WARNING: ignoring ESP DH algorithm MODP2048 as PFS policy is disabled
-- AES_CBC-HMAC_SHA1_96
-+ AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -fips -v2 'esp=aes-sha1'
- AES_CBC-HMAC_SHA1_96
- algparse -fips -v2 'esp=aes-sha1'
-@@ -15,7 +15,7 @@
- WARNING: ignoring ESP DH algorithm MODP2048 as PFS policy is disabled
- AES_CBC-HMAC_SHA1_96
- algparse -fips -v2 'esp=aes-128'
-- AES_CBC_128-HMAC_SHA1_96
-+ AES_CBC_128-HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -fips -v2 'esp=aes-128-sha1'
- AES_CBC_128-HMAC_SHA1_96
- algparse -fips -v2 'esp=aes-128-sha1'
-@@ -47,7 +47,7 @@
- algparse -fips -v2 'esp=null-sha1'
- ERROR: ESP encryption algorithm 'null' is not supported
- algparse -fips -v2 'esp=aes_cbc'
-- AES_CBC-HMAC_SHA1_96
-+ AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -fips -v2 'esp=aes-sha'
- AES_CBC-HMAC_SHA1_96
- algparse -fips -v2 'esp=aes-sha1'
-@@ -63,7 +63,7 @@
- algparse -fips -v2 'esp=aes128-sha1'
- AES_CBC_128-HMAC_SHA1_96
- algparse -fips -v2 'esp=aes128-aes_xcbc'
-- AES_CBC_128-AES_XCBC_96
-+ ERROR: ESP integrity algorithm 'aes_xcbc' is not supported
- algparse -fips -v2 'esp=aes192-sha1'
- AES_CBC_192-HMAC_SHA1_96
- algparse -fips -v2 'esp=aes256-sha1'
-@@ -187,15 +187,15 @@
- algparse -fips -v2 'esp=aes_gcm_16_256-null'
- AES_GCM_16_256-NONE
- algparse -fips -v2 'esp=aes_ctr'
-- AES_CTR-HMAC_SHA1_96
-+ AES_CTR-HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -fips -v2 'esp=aesctr'
-- AES_CTR-HMAC_SHA1_96
-+ AES_CTR-HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -fips -v2 'esp=aes_ctr128'
-- AES_CTR_128-HMAC_SHA1_96
-+ AES_CTR_128-HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -fips -v2 'esp=aes_ctr192'
-- AES_CTR_192-HMAC_SHA1_96
-+ AES_CTR_192-HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -fips -v2 'esp=aes_ctr256'
-- AES_CTR_256-HMAC_SHA1_96
-+ AES_CTR_256-HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -fips -v2 'esp=serpent'
- ERROR: ESP encryption algorithm 'serpent' is not supported
- algparse -fips -v2 'esp=twofish'
-@@ -203,7 +203,8 @@
- algparse -fips -v2 'esp=camellia_cbc_256-hmac_sha2_512_256;modp8192'
- ERROR: ESP encryption algorithm 'camellia_cbc_256' is not supported
- algparse -fips -v2 'esp=null_auth_aes_gmac_256-null;modp8192'
-- ERROR: ESP encryption algorithm 'null_auth_aes_gmac_256' is not supported
-+ WARNING: ignoring ESP DH algorithm MODP8192 as PFS policy is disabled
-+ NULL_AUTH_AES_GMAC_256-NONE
- algparse -fips -v2 'esp=3des-sha1;modp8192'
- WARNING: ignoring ESP DH algorithm MODP8192 as PFS policy is disabled
- 3DES_CBC-HMAC_SHA1_96
-@@ -224,16 +225,16 @@
- AES_CBC-HMAC_SHA1_96
- algparse -fips -v2 'esp=aes;none'
- WARNING: ignoring redundant ESP DH algorithm NONE as PFS policy is disabled
-- AES_CBC-HMAC_SHA1_96
-+ AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -fips -v2 'esp=aes;none,aes'
- WARNING: ignoring redundant ESP DH algorithm NONE as PFS policy is disabled
-- AES_CBC-HMAC_SHA1_96
-- AES_CBC-HMAC_SHA1_96
-+ AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128
-+ AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -fips -v2 'esp=aes;none,aes;modp2048'
- WARNING: ignoring redundant ESP DH algorithm NONE as PFS policy is disabled
- WARNING: ignoring ESP DH algorithm MODP2048 as PFS policy is disabled
-- AES_CBC-HMAC_SHA1_96
-- AES_CBC-HMAC_SHA1_96
-+ AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128
-+ AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -fips -v2 'esp=aes-sha1-none'
- WARNING: ignoring redundant ESP DH algorithm NONE as PFS policy is disabled
- AES_CBC-HMAC_SHA1_96
-@@ -328,7 +329,7 @@
- 3DES_CBC-HMAC_SHA1_96
- 3DES_CBC-HMAC_SHA2_256_128
- algparse -fips -v2 'ah'
-- HMAC_SHA1_96
-+ HMAC_SHA2_512_256+HMAC_SHA2_256_128
- algparse -fips -v2 'ah='
- ERROR: String ended with invalid char, just after ""
- algparse -fips -v2 'ah=md5'
-@@ -355,7 +356,7 @@
- algparse -fips -v2 'ah=sha2_512'
- HMAC_SHA2_512_256
- algparse -fips -v2 'ah=aes_xcbc'
-- AES_XCBC_96
-+ ERROR: AH integrity algorithm 'aes_xcbc' is not supported
- algparse -fips -v2 'ah=sha2-none'
- WARNING: ignoring redundant AH DH algorithm NONE as PFS policy is disabled
- HMAC_SHA2_256_128
-@@ -384,32 +385,23 @@
- algparse -fips -v2 'ah=ripemd'
- ERROR: AH integrity algorithm 'ripemd' is not recognized
- algparse -fips -v2 'ike'
-- AES_CBC-HMAC_SHA2_256-MODP2048
-- AES_CBC-HMAC_SHA2_512-MODP2048
-- AES_CBC-HMAC_SHA1-MODP2048
-- 3DES_CBC-HMAC_SHA2_256-MODP2048
-- 3DES_CBC-HMAC_SHA2_512-MODP2048
-- 3DES_CBC-HMAC_SHA1-MODP2048
-+ AES_CBC+3DES_CBC-HMAC_SHA2_512+HMAC_SHA2_256-MODP2048+MODP3072+MODP4096+MODP8192+DH19+DH20+DH21+DH31
- algparse -fips -v2 'ike='
- ERROR: String ended with invalid char, just after ""
- algparse -fips -v2 'ike=3des-sha1'
-- 3DES_CBC-HMAC_SHA1-MODP2048
-+ 3DES_CBC-HMAC_SHA1-MODP2048+MODP3072+MODP4096+MODP8192+DH19+DH20+DH21+DH31
- algparse -fips -v2 'ike=3des-sha1'
-- 3DES_CBC-HMAC_SHA1-MODP2048
-+ 3DES_CBC-HMAC_SHA1-MODP2048+MODP3072+MODP4096+MODP8192+DH19+DH20+DH21+DH31
- algparse -fips -v2 'ike=3des-sha1;modp1536'
- ERROR: IKE DH algorithm 'modp1536' is not supported
- algparse -fips -v2 'ike=3des;dh21'
-- 3DES_CBC-HMAC_SHA2_256-DH21
-- 3DES_CBC-HMAC_SHA2_512-DH21
-- 3DES_CBC-HMAC_SHA1-DH21
-+ 3DES_CBC-HMAC_SHA2_512+HMAC_SHA2_256-DH21
- algparse -fips -v2 'ike=3des-sha1;dh21'
- 3DES_CBC-HMAC_SHA1-DH21
- algparse -fips -v2 'ike=3des-sha1-ecp_521'
- 3DES_CBC-HMAC_SHA1-DH21
- algparse -fips -v2 'ike=aes_gcm'
-- AES_GCM_16-HMAC_SHA2_256-MODP2048
-- AES_GCM_16-HMAC_SHA2_512-MODP2048
-- AES_GCM_16-HMAC_SHA1-MODP2048
-+ AES_GCM_16-HMAC_SHA2_512+HMAC_SHA2_256-MODP2048+MODP3072+MODP4096+MODP8192+DH19+DH20+DH21+DH31
- algparse -fips -v2 'ike=aes-sha1-modp8192,aes-sha1-modp8192,aes-sha1-modp8192'
- AES_CBC-HMAC_SHA1-MODP8192
- algparse -fips -v2 'ike=aes;none'
-@@ -420,3 +412,10 @@
- ERROR: IKE PRF algorithm 'id2' is not recognized
- algparse -fips -v2 'ike=aes_ccm'
- ERROR: IKE encryption algorithm 'aes_ccm' is not supported
-+algparse -fips -v2 'ike=aes_gcm-sha1-none-modp2048'
-+ ERROR: 'modp2048' unexpected
-+algparse -fips -v2 'ike=aes_gcm+aes_gcm-sha1-none-modp2048'
-+ WARNING: discarding duplicate algorithm 'aes_gcm_16'
-+ ERROR: 'modp2048' unexpected
-+algparse -fips -v2 'ike=aes+aes_gcm'
-+ ERROR: AEAD and non-AEAD IKE encryption algorithm can not be combined
-diff -Naur libreswan-3.27-orig/testing/pluto/algparse-02-fips/algparse.v.txt libreswan-3.27/testing/pluto/algparse-02-fips/algparse.v.txt
---- libreswan-3.27-orig/testing/pluto/algparse-02-fips/algparse.v.txt 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/testing/pluto/algparse-02-fips/algparse.v.txt 2019-02-15 16:32:29.006835593 -0500
-@@ -3,13 +3,14 @@
- algparse: Encryption algorithm SERPENT_CBC disabled; not FIPS compliant
- algparse: Encryption algorithm TWOFISH_CBC disabled; not FIPS compliant
- algparse: Encryption algorithm TWOFISH_SSH disabled; not FIPS compliant
--algparse: Encryption algorithm NULL_AUTH_AES_GMAC disabled; not FIPS compliant
- algparse: Encryption algorithm NULL disabled; not FIPS compliant
- algparse: Encryption algorithm CHACHA20_POLY1305 disabled; not FIPS compliant
- algparse: Hash algorithm MD5 disabled; not FIPS compliant
- algparse: PRF algorithm HMAC_MD5 disabled; not FIPS compliant
-+algparse: PRF algorithm AES_XCBC disabled; not FIPS compliant
- algparse: Integrity algorithm HMAC_MD5_96 disabled; not FIPS compliant
- algparse: Integrity algorithm HMAC_SHA2_256_TRUNCBUG disabled; not FIPS compliant
-+algparse: Integrity algorithm AES_XCBC_96 disabled; not FIPS compliant
- algparse: DH algorithm MODP1024 disabled; not FIPS compliant
- algparse: DH algorithm MODP1536 disabled; not FIPS compliant
- algparse: DH algorithm DH31 disabled; not FIPS compliant
-@@ -23,6 +24,7 @@
- algparse: AES_GCM_8 IKEv1: ESP IKEv2: IKE ESP FIPS {256,192,*128} aes_gcm_a
- algparse: AES_CTR IKEv1: IKE ESP IKEv2: IKE ESP FIPS {256,192,*128} aesctr
- algparse: AES_CBC IKEv1: IKE ESP IKEv2: IKE ESP FIPS {256,192,*128} aes
-+algparse: NULL_AUTH_AES_GMAC IKEv1: ESP IKEv2: ESP FIPS {256,192,*128} aes_gmac
- algparse: FIPS Hash algorithms:
- algparse: SHA1 IKEv1: IKE IKEv2: FIPS sha
- algparse: SHA2_256 IKEv1: IKE IKEv2: FIPS sha2, sha256
-@@ -33,15 +35,13 @@
- algparse: HMAC_SHA2_256 IKEv1: IKE IKEv2: IKE FIPS sha2, sha256, sha2_256
- algparse: HMAC_SHA2_384 IKEv1: IKE IKEv2: IKE FIPS sha384, sha2_384
- algparse: HMAC_SHA2_512 IKEv1: IKE IKEv2: IKE FIPS sha512, sha2_512
--algparse: AES_XCBC IKEv1: IKEv2: IKE FIPS aes128_xcbc
- algparse: FIPS Integrity algorithms:
- algparse: HMAC_SHA1_96 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS sha, sha1, sha1_96, hmac_sha1
--algparse: HMAC_SHA2_512_256 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS sha512, sha2_512, hmac_sha2_512
--algparse: HMAC_SHA2_384_192 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS sha384, sha2_384, hmac_sha2_384
--algparse: HMAC_SHA2_256_128 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS sha2, sha256, sha2_256, hmac_sha2_256
--algparse: AES_XCBC_96 IKEv1: ESP AH IKEv2: IKE ESP AH FIPS aes_xcbc, aes128_xcbc, aes128_xcbc_96
-+algparse: HMAC_SHA2_512_256 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS sha512, sha2_512, sha2_512_256, hmac_sha2_512
-+algparse: HMAC_SHA2_384_192 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS sha384, sha2_384, sha2_384_192, hmac_sha2_384
-+algparse: HMAC_SHA2_256_128 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS sha2, sha256, sha2_256, sha2_256_128, hmac_sha2_256
- algparse: AES_CMAC_96 IKEv1: ESP AH IKEv2: ESP AH FIPS aes_cmac
--algparse: NONE IKEv1: ESP IKEv2: ESP FIPS null
-+algparse: NONE IKEv1: ESP IKEv2: IKE ESP FIPS null
- algparse: FIPS DH algorithms:
- algparse: NONE IKEv1: IKEv2: IKE ESP AH FIPS null, dh0
- algparse: MODP2048 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS dh14
-@@ -49,7 +49,7 @@
- algparse: MODP4096 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS dh16
- algparse: MODP6144 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS dh17
- algparse: MODP8192 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS dh18
--algparse: DH19 IKEv1: IKE IKEv2: IKE ESP AH FIPS ecp_256
--algparse: DH20 IKEv1: IKE IKEv2: IKE ESP AH FIPS ecp_384
--algparse: DH21 IKEv1: IKE IKEv2: IKE ESP AH FIPS ecp_521
-+algparse: DH19 IKEv1: IKE IKEv2: IKE ESP AH FIPS ecp_256, ecp256
-+algparse: DH20 IKEv1: IKE IKEv2: IKE ESP AH FIPS ecp_384, ecp384
-+algparse: DH21 IKEv1: IKE IKEv2: IKE ESP AH FIPS ecp_521, ecp521
- algparse: leak detective found no leaks
-diff -Naur libreswan-3.27-orig/testing/pluto/algparse-02-fips/west.conf libreswan-3.27/testing/pluto/algparse-02-fips/west.conf
---- libreswan-3.27-orig/testing/pluto/algparse-02-fips/west.conf 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/testing/pluto/algparse-02-fips/west.conf 2019-02-15 16:32:29.006835593 -0500
-@@ -10,4 +10,7 @@
- protostack=netkey
- plutodebug=all
-
-+conn %default
-+ ikev2=no
-+
- include /testing/baseconfigs/all/etc/ipsec.d/ipsec.conf.common
-diff -Naur libreswan-3.27-orig/testing/pluto/algparse-02-fips/west.console.txt libreswan-3.27/testing/pluto/algparse-02-fips/west.console.txt
---- libreswan-3.27-orig/testing/pluto/algparse-02-fips/west.console.txt 2018-10-07 22:52:09.000000000 -0400
-+++ libreswan-3.27/testing/pluto/algparse-02-fips/west.console.txt 2019-02-15 16:32:29.006835593 -0500
-@@ -7,8 +7,6 @@
- ../bin/algparse.sh PATH/libexec/ipsec/algparse algparse*.txt
- PATH/libexec/ipsec/algparse -v1 -pfs -t # algparse.v1.pfs.txt
- PATH/libexec/ipsec/algparse -v1 -t # algparse.v1.txt
--PATH/libexec/ipsec/algparse -v1 -v2 -pfs -t # algparse.v1.v2.pfs.txt
--PATH/libexec/ipsec/algparse -v1 -v2 -t # algparse.v1.v2.txt
- PATH/libexec/ipsec/algparse -v2 -pfs -t # algparse.v2.pfs.txt
- PATH/libexec/ipsec/algparse -v2 -t # algparse.v2.txt
- PATH/libexec/ipsec/algparse -v # algparse.v.txt
-@@ -50,6 +48,7 @@
- AES_GCM_8 IKEv1: ESP IKEv2: IKE ESP FIPS {256,192,*128} aes_gcm_a
- AES_CTR IKEv1: IKE ESP IKEv2: IKE ESP FIPS {256,192,*128} aesctr
- AES_CBC IKEv1: IKE ESP IKEv2: IKE ESP FIPS {256,192,*128} aes
-+ NULL_AUTH_AES_GMAC IKEv1: ESP IKEv2: ESP FIPS {256,192,*128} aes_gmac
- FIPS Hash algorithms:
- SHA1 IKEv1: IKE IKEv2: FIPS sha
- SHA2_256 IKEv1: IKE IKEv2: FIPS sha2, sha256
-@@ -60,13 +59,11 @@
- HMAC_SHA2_256 IKEv1: IKE IKEv2: IKE FIPS sha2, sha256, sha2_256
- HMAC_SHA2_384 IKEv1: IKE IKEv2: IKE FIPS sha384, sha2_384
- HMAC_SHA2_512 IKEv1: IKE IKEv2: IKE FIPS sha512, sha2_512
-- AES_XCBC IKEv1: IKEv2: IKE FIPS aes128_xcbc
- FIPS Integrity algorithms:
- HMAC_SHA1_96 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS sha, sha1, sha1_96, hmac_sha1
- HMAC_SHA2_512_256 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS sha512, sha2_512, hmac_sha2_512
- HMAC_SHA2_384_192 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS sha384, sha2_384, hmac_sha2_384
- HMAC_SHA2_256_128 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS sha2, sha256, sha2_256, hmac_sha2_256
-- AES_XCBC_96 IKEv1: ESP AH IKEv2: IKE ESP AH FIPS aes_xcbc, aes128_xcbc, aes128_xcbc_96
- AES_CMAC_96 IKEv1: ESP AH IKEv2: ESP AH FIPS aes_cmac
- NONE IKEv1: ESP IKEv2: ESP FIPS null
- FIPS DH algorithms:
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-1699318-show.patch b/SOURCES/libreswan-3.29-1699318-show.patch
new file mode 100644
index 0000000..dff8604
--- /dev/null
+++ b/SOURCES/libreswan-3.29-1699318-show.patch
@@ -0,0 +1,38 @@
+diff -Naur libreswan-3.29-orig/programs/show/show.in libreswan-3.29/programs/show/show.in
+--- libreswan-3.29-orig/programs/show/show.in 2019-07-31 20:03:51.794714920 -0400
++++ libreswan-3.29/programs/show/show.in 2019-07-31 20:02:38.792224647 -0400
+@@ -1,7 +1,7 @@
+ #!/usr/bin/python
+
+ import sys
+-import commands
++import subprocess
+ import argparse
+ try:
+ import ipaddress
+@@ -42,14 +42,14 @@
+ source = args.source
+ else:
+ getsrccmd = "ip -o ro get %s" % dest
+- status, output = commands.getstatusoutput(getsrccmd)
++ output = subprocess.getoutput([getsrccmd])
+ try:
+ source = output.split("src")[1].strip().split(" ")[0]
+ except Exception:
+ sys.exit("failed to find source ip for destination %s" % dest)
+
+ if args.debug:
+- print "Need to find matching IPsec policy for %s/32 <=> %s/32" % (source, dest)
++ print("Need to find matching IPsec policy for %s/32 <=> %s/32" % (source, dest))
+
+ if dest:
+ if "/" in source:
+@@ -65,7 +65,7 @@
+ sys.exit(1)
+
+ ipxfrmcmd = 'ip -o xfrm pol | grep -v socket | grep "dir out"'
+- status, output = commands.getstatusoutput(ipxfrmcmd)
++ output = subprocess.getoutput([ipxfrmcmd])
+ polsrc = ""
+ poldst = ""
+ for line in output.split("\n"):
diff --git a/SOURCES/libreswan-3.29-1714331-nss-kdf.patch b/SOURCES/libreswan-3.29-1714331-nss-kdf.patch
new file mode 100644
index 0000000..16b8a5a
--- /dev/null
+++ b/SOURCES/libreswan-3.29-1714331-nss-kdf.patch
@@ -0,0 +1,770 @@
+diff -Naur libreswan-3.29-orig/lib/libswan/ike_alg_aes.c libreswan-3.29/lib/libswan/ike_alg_aes.c
+--- libreswan-3.29-orig/lib/libswan/ike_alg_aes.c 2019-06-10 10:22:04.000000000 -0400
++++ libreswan-3.29/lib/libswan/ike_alg_aes.c 2019-08-11 13:31:13.849294693 -0400
+@@ -23,14 +23,21 @@
+
+ #include "constants.h" /* for BYTES_FOR_BITS() */
+ #include "ietf_constants.h"
++
+ #include "ike_alg.h"
++#include "ike_alg_encrypt.h"
++#include "ike_alg_integ.h"
++#include "ike_alg_prf.h"
++
+ #include "ike_alg_encrypt_nss_cbc_ops.h"
+ #include "ike_alg_encrypt_nss_ctr_ops.h"
+ #include "ike_alg_encrypt_nss_gcm_ops.h"
++#ifdef CKM_AES_XCBC_MAC
++#include "ike_alg_prf_nss_ops.h"
++#else
+ #include "ike_alg_prf_nss_xcbc_ops.h"
+-#include "ike_alg_encrypt.h"
+-#include "ike_alg_integ.h"
+-#include "ike_alg_prf.h"
++#endif
++
+ #include "sadb.h"
+
+ const struct encrypt_desc ike_alg_encrypt_aes_cbc = {
+@@ -313,6 +320,7 @@
+ .encrypt_kernel_audit_name = "AES_CCM_C",
+ };
+
++#ifdef USE_PRF_AES_XCBC
+ const struct prf_desc ike_alg_prf_aes_xcbc = {
+ .common = {
+ .name = "aes_xcbc",
+@@ -326,14 +334,23 @@
+ },
+ .fips = false,
+ },
++#ifdef CKM_AES_XCBC_MAC
++ .nss = {
++ .mechanism = CKM_AES_XCBC_MAC,
++ },
++ .prf_ops = &ike_alg_prf_nss_ops,
++#else
++ /* XXX: NSS encryption algorithm used by custom XCBC */
+ .nss = {
+ .mechanism = CKM_AES_ECB,
+ },
++ .prf_ops = &ike_alg_prf_nss_xcbc_ops,
++#endif
+ .prf_key_size = BYTES_FOR_BITS(128),
+ .prf_output_size = BYTES_FOR_BITS(128),
+- .prf_ops = &ike_alg_prf_nss_xcbc_ops,
+ .prf_ike_audit_name = "aes_xcbc",
+ };
++#endif
+
+ const struct integ_desc ike_alg_integ_aes_xcbc = {
+ .common = {
+@@ -351,7 +368,7 @@
+ .integ_keymat_size = AES_XCBC_DIGEST_SIZE,
+ .integ_output_size = AES_XCBC_DIGEST_SIZE_TRUNC, /* XXX 96 */
+ .integ_ikev1_ah_transform = AH_AES_XCBC_MAC,
+-#ifdef USE_XCBC
++#ifdef USE_PRF_AES_XCBC
+ .prf = &ike_alg_prf_aes_xcbc,
+ #endif
+ #ifdef SADB_X_AALG_AES_XCBC_MAC
+diff -Naur libreswan-3.29-orig/lib/libswan/ike_alg.c libreswan-3.29/lib/libswan/ike_alg.c
+--- libreswan-3.29-orig/lib/libswan/ike_alg.c 2019-06-10 10:22:04.000000000 -0400
++++ libreswan-3.29/lib/libswan/ike_alg.c 2019-08-11 13:31:13.850294706 -0400
+@@ -478,7 +478,7 @@
+ &ike_alg_prf_sha2_384,
+ &ike_alg_prf_sha2_512,
+ #endif
+-#ifdef USE_XCBC
++#ifdef USE_PRF_AES_XCBC
+ &ike_alg_prf_aes_xcbc,
+ #endif
+ };
+diff -Naur libreswan-3.29-orig/lib/libswan/ike_alg_md5.c libreswan-3.29/lib/libswan/ike_alg_md5.c
+--- libreswan-3.29-orig/lib/libswan/ike_alg_md5.c 2019-06-10 10:22:04.000000000 -0400
++++ libreswan-3.29/lib/libswan/ike_alg_md5.c 2019-08-11 13:31:13.851294720 -0400
+@@ -26,7 +26,7 @@
+ #include "ike_alg_hash.h"
+ #include "ike_alg_prf.h"
+ #include "ike_alg_hash_nss_ops.h"
+-#include "ike_alg_prf_hmac_ops.h"
++#include "ike_alg_prf_nss_ops.h"
+ #include "sadb.h"
+
+ const struct hash_desc ike_alg_hash_md5 = {
+@@ -63,10 +63,13 @@
+ [IKEv2_ALG_ID] = IKEv2_PRF_HMAC_MD5,
+ },
+ },
++ .nss = {
++ .mechanism = CKM_MD5_HMAC,
++ },
+ .prf_key_size = MD5_DIGEST_SIZE,
+ .prf_output_size = MD5_DIGEST_SIZE,
+ .hasher = &ike_alg_hash_md5,
+- .prf_ops = &ike_alg_prf_hmac_ops,
++ .prf_ops = &ike_alg_prf_nss_ops,
+ .prf_ike_audit_name = "md5",
+ };
+
+diff -Naur libreswan-3.29-orig/mk/config.mk libreswan-3.29/mk/config.mk
+--- libreswan-3.29-orig/mk/config.mk 2019-08-11 13:30:45.756906229 -0400
++++ libreswan-3.29/mk/config.mk 2019-08-11 13:31:13.852294734 -0400
+@@ -239,6 +239,18 @@
+ NSS_UTIL_LDFLAGS ?= -lnssutil3
+ NSPR_LDFLAGS ?= -lnspr4
+
++# Use the NSS Key Derivation Function (KDF) instead of using the NSS
++# secure hash functions to build our own PRF. With this enabled,
++# libreswan itself no longer needs to be FIPS validated.
++# Requires NSS >= 3.44
++USE_NSS_PRF?=false
++ifeq ($(USE_NSS_PRF),true)
++NSSFLAGS+=-DUSE_NSS_PRF
++USE_NSS_AVA_COPY=false
++endif
++
++#
++#
+ # Use local copy of nss function CERT_CompareAVA
+ # See https://bugzilla.mozilla.org/show_bug.cgi?id=1336487
+ # This work-around is needed with nss versions before 3.30.
+diff -Naur libreswan-3.29-orig/mk/userland-cflags.mk libreswan-3.29/mk/userland-cflags.mk
+--- libreswan-3.29-orig/mk/userland-cflags.mk 2019-06-10 10:22:04.000000000 -0400
++++ libreswan-3.29/mk/userland-cflags.mk 2019-08-11 13:31:13.853294748 -0400
+@@ -269,9 +269,10 @@
+ LIBTWOFISH= ${OBJDIRTOP}/lib/libcrypto/libtwofish/libtwofish.a
+ endif
+
+-USE_XCBC ?= true
+-ifeq ($(USE_XCBC),true)
+-USERLAND_CFLAGS += -DUSE_XCBC
++# Requires NSS >= 3.44 or backport
++USE_PRF_AES_XCBC ?= true
++ifeq ($(USE_PRF_AES_XCBC),true)
++USERLAND_CFLAGS += -DUSE_PRF_AES_XCBC
+ endif
+
+ #
+diff -Naur libreswan-3.29-orig/programs/pluto/crypt_symkey.c libreswan-3.29/programs/pluto/crypt_symkey.c
+--- libreswan-3.29-orig/programs/pluto/crypt_symkey.c 2019-06-10 10:22:04.000000000 -0400
++++ libreswan-3.29/programs/pluto/crypt_symkey.c 2019-08-11 13:31:13.854294762 -0400
+@@ -15,7 +15,6 @@
+ * for more details.
+ */
+
+-#include "libreswan.h"
+ #include "lswalloc.h"
+ #include "lswlog.h"
+ #include "ike_alg.h"
+@@ -23,6 +22,7 @@
+ #include "crypto.h"
+ #include "lswfips.h"
+ #include "lswnss.h"
++#include "crypt_prf.h" /* hack */
+
+ #define SPACES " "
+
+@@ -590,9 +590,51 @@
+
+ PK11SymKey *prf_key_from_symkey_bytes(const char *name,
+ const struct prf_desc *prf,
+- size_t symkey_start_byte, size_t sizeof_symkey,
++ size_t symkey_start_byte, size_t symkey_size,
+ PK11SymKey *source_key)
+ {
++#ifdef CKM_AES_XCBC_MAC
++ if (prf->nss.mechanism == CKM_AES_XCBC_MAC &&
++ symkey_size != prf->prf_key_size) {
++ PK11SymKey *tmp = symkey_from_symkey("tmp", source_key,
++ CKM_VENDOR_DEFINED, /*flags*/0,
++ symkey_start_byte, symkey_size);
++ /*
++ * code lifted from ike_alg_prf_nss_xcbc_ops.c
++ */
++ size_t dkey_sz = sizeof_symkey(tmp);
++ if (dkey_sz < prf->prf_key_size) {
++ DBGF(DBG_CRYPT, "XCBC: Key %zd<%zd too small, padding with zeros",
++ dkey_sz, prf->prf_key_size);
++ /*
++ * right pad with zeros
++ */
++ chunk_t zeros = alloc_chunk(prf->prf_key_size - dkey_sz, "zeros");
++ append_symkey_chunk(&tmp, zeros);
++ freeanychunk(zeros);
++ } else {
++ pexpect(dkey_sz > prf->prf_key_size);
++ DBGF(DBG_CRYPT, "XCBC: Key %zd>%zd too big, rehashing to size",
++ dkey_sz, prf->prf_key_size);
++ /*
++ * put the key through the mac with a zero
++ * key; recursive
++ */
++ chunk_t zeros = alloc_chunk(prf->prf_key_size, "zeros");
++ PK11SymKey *zero_key = prf_key_from_bytes("zeros", prf, zeros.ptr, zeros.len);
++ freeanychunk(zeros);
++ struct crypt_prf *xmac = crypt_prf_init_symkey("xmac", prf, "zero", zero_key);
++ crypt_prf_update_symkey(xmac, "tmp", tmp);
++ PK11SymKey *tmp2 = crypt_prf_final_symkey(&xmac);
++ release_symkey(name, "tmp2", &tmp);
++ tmp = tmp2;
++ }
++ PK11SymKey *key = symkey_from_symkey(name, tmp, CKM_AES_XCBC_MAC, CKF_SIGN,
++ 0, prf->prf_key_size);
++ release_symkey(name, "tmp", &tmp);
++ return key;
++ }
++#endif
+ /*
+ * NSS expects a key's mechanism to match the NSS algorithm
+ * the key is intended for. If this is wrong then the
+@@ -614,7 +656,7 @@
+ mechanism = prf->nss.mechanism;
+ }
+ return symkey_from_symkey(name, source_key, mechanism, flags,
+- symkey_start_byte, sizeof_symkey);
++ symkey_start_byte, symkey_size);
+ }
+
+ /*
+@@ -656,9 +698,13 @@
+ PK11SymKey *key_from_symkey_bytes(PK11SymKey *source_key,
+ size_t next_byte, size_t sizeof_key)
+ {
+- return symkey_from_symkey("result", source_key,
+- CKM_EXTRACT_KEY_FROM_KEY,
+- 0, next_byte, sizeof_key);
++ if (sizeof_key == 0) {
++ return NULL;
++ } else {
++ return symkey_from_symkey("result", source_key,
++ CKM_EXTRACT_KEY_FROM_KEY,
++ 0, next_byte, sizeof_key);
++ }
+ }
+
+ /*
+diff -Naur libreswan-3.29-orig/programs/pluto/ikev1_prf.c libreswan-3.29/programs/pluto/ikev1_prf.c
+--- libreswan-3.29-orig/programs/pluto/ikev1_prf.c 2019-06-10 10:22:04.000000000 -0400
++++ libreswan-3.29/programs/pluto/ikev1_prf.c 2019-08-11 13:31:13.855294776 -0400
+@@ -17,8 +17,11 @@
+ * for more details.
+ */
+
++#include "lswlog.h" /* for LSWLOG_PEXPECT() */
++
+ #include "ikev1_prf.h"
+
++#include "ike_alg.h"
+ #include "crypt_prf.h"
+ #include "crypt_symkey.h"
+
+@@ -32,6 +35,25 @@
+ const chunk_t Nr,
+ /*const*/ PK11SymKey *dh_secret /* NSS doesn't do const */)
+ {
++#ifdef USE_NSS_PRF
++ CK_NSS_IKE_PRF_DERIVE_PARAMS ike_prf_params = {
++ .prfMechanism = prf_desc->nss.mechanism,
++ .bDataAsKey = CK_TRUE,
++ .bRekey = CK_FALSE,
++ .pNi = Ni.ptr,
++ .ulNiLen = Ni.len,
++ .pNr = Nr.ptr,
++ .ulNrLen = Nr.len,
++ };
++ SECItem params = {
++ .data = (unsigned char *)&ike_prf_params,
++ .len = sizeof(ike_prf_params),
++ };
++
++ return PK11_Derive(dh_secret, CKM_NSS_IKE_PRF_DERIVE, ¶ms,
++ CKM_NSS_IKE1_PRF_DERIVE, CKA_DERIVE,
++ 0);
++#else
+ /* key = Ni|Nr */
+ chunk_t key = clone_chunk_chunk(Ni, Nr, "key = Ni|Nr");
+ struct crypt_prf *prf = crypt_prf_init_chunk("SKEYID sig",
+@@ -42,6 +64,7 @@
+ crypt_prf_update_symkey(prf, "g^xy", dh_secret);
+ /* generate */
+ return crypt_prf_final_symkey(&prf);
++#endif
+ }
+
+ /*
+@@ -51,6 +74,33 @@
+ chunk_t pre_shared_key,
+ chunk_t Ni, chunk_t Nr)
+ {
++#ifdef USE_NSS_PRF
++ PK11SymKey *psk = prf_key_from_bytes("psk", prf_desc,
++ pre_shared_key.ptr, pre_shared_key.len);
++ PK11SymKey *skeyid;
++ if (psk == NULL) {
++ return NULL;
++ }
++
++ CK_NSS_IKE_PRF_DERIVE_PARAMS ike_prf_params = {
++ .prfMechanism = prf_desc->nss.mechanism,
++ .bDataAsKey = CK_FALSE,
++ .bRekey = CK_FALSE,
++ .pNi = Ni.ptr,
++ .ulNiLen = Ni.len,
++ .pNr = Nr.ptr,
++ .ulNrLen = Nr.len,
++ };
++ SECItem params = {
++ .data = (unsigned char *)&ike_prf_params,
++ .len = sizeof(ike_prf_params),
++ };
++ skeyid = PK11_Derive(psk, CKM_NSS_IKE_PRF_DERIVE, ¶ms,
++ CKM_NSS_IKE1_PRF_DERIVE, CKA_DERIVE,
++ 0 );
++ release_symkey("SKEYID psk", "psk", &psk);
++ return skeyid;
++#else
+ /* key = pre-shared-key */
+ struct crypt_prf *prf = crypt_prf_init_chunk("SKEYID psk", prf_desc,
+ "psk", pre_shared_key);
+@@ -59,6 +109,7 @@
+ crypt_prf_update_chunk(prf, "Nr", Nr);
+ /* generate */
+ return crypt_prf_final_symkey(&prf);
++#endif
+ }
+
+ /*
+@@ -69,6 +120,26 @@
+ PK11SymKey *dh_secret,
+ chunk_t cky_i, chunk_t cky_r)
+ {
++#ifdef USE_NSS_PRF
++ CK_NSS_IKE1_PRF_DERIVE_PARAMS ike1_prf_params = {
++ .prfMechanism = prf_desc->nss.mechanism,
++ .bHasPrevKey = CK_FALSE,
++ .hKeygxy = PK11_GetSymKeyHandle(dh_secret),
++ .pCKYi = cky_i.ptr,
++ .ulCKYiLen = cky_i.len,
++ .pCKYr = cky_r.ptr,
++ .ulCKYrLen = cky_r.len,
++ .keyNumber = 0,
++ };
++ SECItem params = {
++ .data = (unsigned char *)&ike1_prf_params,
++ .len = sizeof(ike1_prf_params),
++ };
++
++ return PK11_Derive(skeyid, CKM_NSS_IKE1_PRF_DERIVE, ¶ms,
++ CKM_EXTRACT_KEY_FROM_KEY, CKA_DERIVE,
++ 0);
++#else
+ /* key = SKEYID */
+ struct crypt_prf *prf = crypt_prf_init_symkey("SKEYID_d", prf_desc,
+ "SKEYID", skeyid);
+@@ -79,6 +150,7 @@
+ crypt_prf_update_byte(prf, "0", 0);
+ /* generate */
+ return crypt_prf_final_symkey(&prf);
++#endif
+ }
+
+ /*
+@@ -89,6 +161,27 @@
+ PK11SymKey *skeyid_d, PK11SymKey *dh_secret,
+ chunk_t cky_i, chunk_t cky_r)
+ {
++#ifdef USE_NSS_PRF
++ CK_NSS_IKE1_PRF_DERIVE_PARAMS ike1_prf_params = {
++ .prfMechanism = prf_desc->nss.mechanism,
++ .bHasPrevKey = CK_TRUE,
++ .hKeygxy = PK11_GetSymKeyHandle(dh_secret),
++ .hPrevKey = PK11_GetSymKeyHandle(skeyid_d),
++ .pCKYi = cky_i.ptr,
++ .ulCKYiLen = cky_i.len,
++ .pCKYr = cky_r.ptr,
++ .ulCKYrLen = cky_r.len,
++ .keyNumber = 1,
++ };
++ SECItem params = {
++ .data = (unsigned char *)&ike1_prf_params,
++ .len = sizeof(ike1_prf_params),
++ };
++
++ return PK11_Derive(skeyid, CKM_NSS_IKE1_PRF_DERIVE, ¶ms,
++ CKM_EXTRACT_KEY_FROM_KEY, CKA_DERIVE,
++ 0);
++#else
+ /* key = SKEYID */
+ struct crypt_prf *prf = crypt_prf_init_symkey("SKEYID_a", prf_desc,
+ "SKEYID", skeyid);
+@@ -100,6 +193,7 @@
+ crypt_prf_update_byte(prf, "1", 1);
+ /* generate */
+ return crypt_prf_final_symkey(&prf);
++#endif
+ }
+
+ /*
+@@ -110,6 +204,27 @@
+ PK11SymKey *skeyid_a, PK11SymKey *dh_secret,
+ chunk_t cky_i, chunk_t cky_r)
+ {
++#ifdef USE_NSS_PRF
++ CK_NSS_IKE1_PRF_DERIVE_PARAMS ike1_prf_params = {
++ .prfMechanism = prf_desc->nss.mechanism,
++ .bHasPrevKey = CK_TRUE,
++ .hKeygxy = PK11_GetSymKeyHandle(dh_secret),
++ .hPrevKey = PK11_GetSymKeyHandle(skeyid_a),
++ .pCKYi = cky_i.ptr,
++ .ulCKYiLen = cky_i.len,
++ .pCKYr = cky_r.ptr,
++ .ulCKYrLen = cky_r.len,
++ .keyNumber = 2,
++ };
++ SECItem params = {
++ .data = (unsigned char *)&ike1_prf_params,
++ .len = sizeof(ike1_prf_params),
++ };
++
++ return PK11_Derive(skeyid, CKM_NSS_IKE1_PRF_DERIVE, ¶ms,
++ CKM_EXTRACT_KEY_FROM_KEY, CKA_DERIVE,
++ 0);
++#else
+ /* key = SKEYID */
+ struct crypt_prf *prf = crypt_prf_init_symkey("SKEYID_e", prf_desc,
+ "SKEYID", skeyid);
+@@ -121,6 +236,7 @@
+ crypt_prf_update_byte(prf, "2", 2);
+ /* generate */
+ return crypt_prf_final_symkey(&prf);
++#endif
+ }
+
+ PK11SymKey *appendix_b_keymat_e(const struct prf_desc *prf_desc,
+@@ -128,6 +244,20 @@
+ PK11SymKey *skeyid_e,
+ unsigned required_keymat)
+ {
++#ifdef USE_NSS_PRF
++ CK_MECHANISM_TYPE mechanism = prf_desc->nss.mechanism;
++ CK_MECHANISM_TYPE target = encrypter->nss.mechanism;
++ SECItem params = {
++ .data = (unsigned char *)&mechanism,
++ .len = sizeof(mechanism),
++ };
++ /* for when ENCRYPTER isn't NSS */
++ if (target == 0) target = CKM_EXTRACT_KEY_FROM_KEY;
++
++ return PK11_DeriveWithFlags(skeyid_e, CKM_NSS_IKE1_APP_B_PRF_DERIVE,
++ ¶ms, target, CKA_ENCRYPT,
++ required_keymat, CKF_DECRYPT);
++#else
+ if (sizeof_symkey(skeyid_e) >= required_keymat) {
+ return encrypt_key_from_symkey_bytes("keymat", encrypter,
+ 0, required_keymat,
+@@ -160,4 +290,5 @@
+ keymat);
+ release_symkey(__func__, "keymat", &keymat);
+ return cryptkey;
++#endif
+ }
+diff -Naur libreswan-3.29-orig/programs/pluto/ikev2_prf.c libreswan-3.29/programs/pluto/ikev2_prf.c
+--- libreswan-3.29-orig/programs/pluto/ikev2_prf.c 2019-06-10 10:22:04.000000000 -0400
++++ libreswan-3.29/programs/pluto/ikev2_prf.c 2019-08-11 13:33:13.680951735 -0400
+@@ -32,12 +32,44 @@
+ /*
+ * IKEv2 - RFC4306 2.14 SKEYSEED - calculation.
+ */
++#ifdef USE_NSS_PRF
++static PK11SymKey *ikev2_prfplus_key_data(
++ const struct prf_desc *prf_desc,
++ PK11SymKey *key,
++ PK11SymKey *seed_key,
++ chunk_t seed_data,
++ size_t required_keymat)
++{
++ CK_NSS_IKE_PRF_PLUS_DERIVE_PARAMS ike_prf_plus_params = {
++ .pSeedData = seed_data.ptr,
++ .ulSeedDataLen = seed_data.len,
++ .prfMechanism = prf_desc->nss.mechanism,
++ };
++ if (seed_key == NULL) {
++ ike_prf_plus_params.bHasSeedKey = CK_FALSE;
++ } else {
++ ike_prf_plus_params.bHasSeedKey = CK_TRUE;
++ ike_prf_plus_params.hSeedKey = PK11_GetSymKeyHandle(seed_key);
++ }
++ SECItem params = {
++ .data = (unsigned char *)&ike_prf_plus_params,
++ .len = sizeof(ike_prf_plus_params),
++ };
++
++ return PK11_Derive(key, CKM_NSS_IKE_PRF_PLUS_DERIVE, ¶ms,
++ CKM_EXTRACT_KEY_FROM_KEY, CKA_DERIVE,
++ required_keymat);
++}
++#endif
+
+ PK11SymKey *ikev2_prfplus(const struct prf_desc *prf_desc,
+ PK11SymKey *key,
+ PK11SymKey *seed,
+ size_t required_keymat)
+ {
++#ifdef USE_NSS_PRF
++ return ikev2_prfplus_key_data(prf_desc, key, seed, empty_chunk, required_keymat);
++#else
+ uint8_t count = 1;
+
+ /* T1(prfplus) = prf(KEY, SEED|1) */
+@@ -66,6 +98,7 @@
+ }
+ release_symkey(__func__, "old_t[final]", &old_t);
+ return prfplus;
++#endif
+ }
+
+ /*
+@@ -77,6 +110,33 @@
+ const chunk_t Ni, const chunk_t Nr,
+ PK11SymKey *dh_secret)
+ {
++
++#ifdef USE_NSS_PRF
++ int is_aes_prf = 0;
++ switch (prf_desc->common.id[IKEv2_ALG_ID]) {
++ case IKEv2_PRF_AES128_CMAC:
++ case IKEv2_PRF_AES128_XCBC:
++ is_aes_prf = 1;
++ }
++
++ CK_NSS_IKE_PRF_DERIVE_PARAMS ike_prf_params = {
++ .prfMechanism = prf_desc->nss.mechanism,
++ .bDataAsKey = CK_TRUE,
++ .bRekey = CK_FALSE,
++ .pNi = Ni.ptr,
++ .ulNiLen = is_aes_prf ? BYTES_FOR_BITS(64) : Ni.len,
++ .pNr = Nr.ptr,
++ .ulNrLen = is_aes_prf ? BYTES_FOR_BITS(64) : Nr.len,
++ };
++ SECItem params = {
++ .data = (unsigned char *)&ike_prf_params,
++ .len = sizeof(ike_prf_params),
++ };
++
++ return PK11_Derive(dh_secret, CKM_NSS_IKE_PRF_DERIVE, ¶ms,
++ CKM_NSS_IKE_PRF_PLUS_DERIVE, CKA_DERIVE,
++ 0);
++#else
+ /*
+ * 2.14. Generating Keying Material for the IKE SA
+ *
+@@ -117,6 +177,7 @@
+ crypt_prf_update_symkey(prf, "g^ir", dh_secret);
+ /* generate */
+ return crypt_prf_final_symkey(&prf);
++#endif
+ }
+
+ /*
+@@ -127,6 +188,26 @@
+ PK11SymKey *new_dh_secret,
+ const chunk_t Ni, const chunk_t Nr)
+ {
++#ifdef USE_NSS_PRF
++ CK_NSS_IKE_PRF_DERIVE_PARAMS ike_prf_params = {
++ .prfMechanism = prf_desc->nss.mechanism,
++ .bDataAsKey = CK_FALSE,
++ .bRekey = CK_TRUE,
++ .hNewKey = PK11_GetSymKeyHandle(new_dh_secret),
++ .pNi = Ni.ptr,
++ .ulNiLen = Ni.len,
++ .pNr = Nr.ptr,
++ .ulNrLen = Nr.len,
++ };
++ SECItem params = {
++ .data = (unsigned char *)&ike_prf_params,
++ .len = sizeof(ike_prf_params),
++ };
++
++ return PK11_Derive(SK_d_old, CKM_NSS_IKE_PRF_DERIVE, ¶ms,
++ CKM_NSS_IKE_PRF_PLUS_DERIVE, CKA_DERIVE,
++ 0);
++#else
+ /* key = SK_d (old) */
+ struct crypt_prf *prf = crypt_prf_init_symkey("ike sa rekey skeyseed", prf_desc,
+ "SK_d (old)", SK_d_old);
+@@ -141,6 +222,7 @@
+ crypt_prf_update_chunk(prf, "Nr", Nr);
+ /* generate */
+ return crypt_prf_final_symkey(&prf);
++#endif
+ }
+
+ /*
+@@ -152,6 +234,17 @@
+ const ike_spis_t *SPIir,
+ size_t required_bytes)
+ {
++#ifdef USE_NSS_PRF
++ chunk_t seed_data;
++ PK11SymKey *prf_plus;
++
++ seed_data = clone_chunk_chunk(Ni, Nr, "seed_data = Ni || Nr");
++ append_chunk_bytes("seed_data = Nir || SPIi", &seed_data, &SPIir->initiator, sizeof(SPIir->initiator));
++ append_chunk_bytes("seed_data = Nir || SPIir", &seed_data, &SPIir->responder, sizeof(SPIir->responder));
++ prf_plus = ikev2_prfplus_key_data(prf_desc, skeyseed, NULL, seed_data, required_bytes);
++ freeanychunk(seed_data);
++ return prf_plus;
++#else
+ PK11SymKey *data = symkey_from_chunk("data", Ni);
+ append_symkey_chunk(&data, Nr);
+ append_symkey_bytes(&data, &SPIir->initiator, sizeof(SPIir->initiator));
+@@ -161,6 +254,7 @@
+ required_bytes);
+ release_symkey(__func__, "data", &data);
+ return prfplus;
++#endif
+ }
+
+ /*
+@@ -172,6 +266,24 @@
+ const chunk_t Ni, const chunk_t Nr,
+ size_t required_bytes)
+ {
++ if (required_bytes == 0) {
++ /*
++ * For instance esp=null-none. Caller should
++ * interpret NULL to mean empty (NSS doesn't create
++ * zero length keys).
++ */
++ dbg("No CHILD SA KEMAT is required");
++ return NULL;
++ }
++#ifdef USE_NSS_PRF
++ chunk_t seed_data;
++ PK11SymKey *prf_plus;
++
++ seed_data = clone_chunk_chunk(Ni, Nr, "seed_data = Ni || Nr");
++ prf_plus = ikev2_prfplus_key_data(prf_desc, SK_d, new_dh_secret, seed_data, required_bytes);
++ freeanychunk(seed_data);
++ return prf_plus;
++#else
+ PK11SymKey *data;
+ if (new_dh_secret == NULL) {
+ data = symkey_from_chunk("data", Ni);
+@@ -185,4 +297,5 @@
+ required_bytes);
+ release_symkey(__func__, "data", &data);
+ return prfplus;
++#endif
+ }
+diff -Naur libreswan-3.29-orig/programs/pluto/ikev2_psk.c libreswan-3.29/programs/pluto/ikev2_psk.c
+--- libreswan-3.29-orig/programs/pluto/ikev2_psk.c 2019-06-10 10:22:04.000000000 -0400
++++ libreswan-3.29/programs/pluto/ikev2_psk.c 2019-08-11 13:31:13.858294817 -0400
+@@ -181,6 +181,36 @@
+ PK11SymKey *prf_psk;
+
+ {
++ static const char psk_key_pad_str[] = "Key Pad for IKEv2"; /* RFC 4306 2:15 */
++#ifdef USE_NSS_PRF
++ CK_NSS_IKE_PRF_DERIVE_PARAMS ike_prf_params;
++ SECItem params;
++ CK_MECHANISM_TYPE prf_mech = st->st_oakley.ta_prf->nss.mechanism;
++ PK11SymKey *pss_key = prf_key_from_bytes("pss", st->st_oakley.ta_prf,
++ pss->ptr, pss->len);
++ if (pss_key == NULL) {
++ if (libreswan_fipsmode()) {
++ PASSERT_FAIL("FIPS: failure creating %s PRF context for digesting PSK",
++ st->st_oakley.ta_prf->common.name);
++ }
++ loglog(RC_LOG_SERIOUS,
++ "failure creating %s PRF context for digesting PSK",
++ st->st_oakley.ta_prf->common.name);
++ return FALSE;
++ }
++
++ ike_prf_params.prfMechanism = prf_mech;
++ ike_prf_params.bDataAsKey = CK_FALSE;
++ ike_prf_params.bRekey = CK_FALSE;
++ ike_prf_params.pNi = (CK_BYTE_PTR) psk_key_pad_str;
++ ike_prf_params.ulNiLen = sizeof(psk_key_pad_str) - 1;
++ ike_prf_params.pNr = NULL;
++ ike_prf_params.ulNrLen = 0;
++ params.data = (unsigned char *)&ike_prf_params;
++ params.len = sizeof(ike_prf_params);
++ prf_psk = PK11_Derive(pss_key, CKM_NSS_IKE_PRF_DERIVE, ¶ms, prf_mech, CKA_SIGN, 0);
++ release_symkey("psk pss_key", "pss_key", &pss_key);
++#else
+ struct crypt_prf *prf =
+ crypt_prf_init_chunk(" = prf(,\"Key Pad for IKEv2\")",
+ st->st_oakley.ta_prf,
+@@ -196,12 +226,11 @@
+ return FALSE;
+ }
+
+- static const char psk_key_pad_str[] = "Key Pad for IKEv2"; /* RFC 4306 2:15 */
+-
+ crypt_prf_update_bytes(prf, psk_key_pad_str, /* name */
+ psk_key_pad_str,
+ sizeof(psk_key_pad_str) - 1);
+ prf_psk = crypt_prf_final_symkey(&prf);
++#endif
+ }
+
+ /* calculate outer prf */
+diff -Naur libreswan-3.29-orig/programs/pluto/plutomain.c libreswan-3.29/programs/pluto/plutomain.c
+--- libreswan-3.29-orig/programs/pluto/plutomain.c 2019-06-10 10:22:04.000000000 -0400
++++ libreswan-3.29/programs/pluto/plutomain.c 2019-08-11 13:31:13.859294831 -0400
+@@ -189,6 +189,11 @@
+ #ifdef NSS_IPSEC_PROFILE
+ " (IPsec profile)"
+ #endif
++#ifdef USE_NSS_PRF
++ " (NSS-PRF)"
++#else
++ " (native-PRF)"
++#endif
+ #ifdef USE_DNSSEC
+ " DNSSEC"
+ #endif
+diff -Naur libreswan-3.29-orig/programs/pluto/prf_test_vectors.c libreswan-3.29/programs/pluto/prf_test_vectors.c
+--- libreswan-3.29-orig/programs/pluto/prf_test_vectors.c 2019-06-10 10:22:04.000000000 -0400
++++ libreswan-3.29/programs/pluto/prf_test_vectors.c 2019-08-11 13:31:13.860294845 -0400
+@@ -34,6 +34,7 @@
+ * Ref: https://tools.ietf.org/html/rfc4435: Test Vectors
+ */
+
++#ifdef USE_PRF_AES_XCBC
+ const struct prf_test_vectors aes_xcbc_prf_tests = {
+ .prf = &ike_alg_prf_aes_xcbc,
+ .tests = {
+@@ -105,6 +106,10 @@
+ .message = "0x000102030405060708090a0b0c0d0e0f10111213",
+ .prf_output = "0x47f51b4564966215b8985c63055ed308",
+ },
++ /*
++ * XXX: for some reason NSS explodes when trying to
++ * create a non-standard AES_XCBC_MAC key.
++ */
+ {
+ .description = "Test Case AES-XCBC-PRF-128 with 20-byte input (key length 10)",
+ .key = "0x00010203040506070809",
+@@ -124,7 +129,9 @@
+ }
+ },
+ };
++#endif
+
++/* So far we only have AES_XCBC PRF test vectors :/ */
+ static bool test_prf_vector(const struct prf_desc *prf,
+ const struct prf_test_vector *test)
+ {
+@@ -137,7 +144,6 @@
+ : alloc_chunk(test->message_size, __func__);
+ chunk_t prf_output = decode_to_chunk(__func__, test->prf_output);
+
+-
+ /* chunk interface */
+ struct crypt_prf *chunk_prf = crypt_prf_init_chunk("PRF chunk interface", prf,
+ "key", chunk_key);
diff --git a/SOURCES/libreswan-3.29-1723957-audit.patch b/SOURCES/libreswan-3.29-1723957-audit.patch
new file mode 100644
index 0000000..785630d
--- /dev/null
+++ b/SOURCES/libreswan-3.29-1723957-audit.patch
@@ -0,0 +1,301 @@
+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-26 22:03:27.801184503 -0400
++++ libreswan-3.29/programs/pluto/ikev1.c 2019-06-27 13:26:11.443969779 -0400
+@@ -2675,6 +2675,12 @@
+ passert(st != NULL);
+ pexpect(!state_is_busy(st));
+
++ if (result > STF_OK) {
++ if (st != NULL) {
++ linux_audit_conn(md->st, IS_IKE_SA_ESTABLISHED(md->st) ? LAK_CHILD_FAIL : LAK_PARENT_FAIL);
++ }
++ }
++
+ switch (result) {
+ case STF_OK:
+ {
+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-26 22:03:27.803184531 -0400
++++ libreswan-3.29/programs/pluto/ikev1_quick.c 2019-06-27 13:23:53.787080070 -0400
+@@ -1663,6 +1663,9 @@
+ if (!install_inbound_ipsec_sa(st))
+ return STF_INTERNAL_ERROR; /* ??? we may be partly committed */
+
++ /* we only audit once for IPsec SA's, we picked the inbound SA */
++ linux_audit_conn(st, LAK_CHILD_START);
++
+ /* encrypt message, except for fixed part of header */
+
+ if (!ikev1_encrypt_message(&rbody, st)) {
+diff -Naur libreswan-3.29-orig/programs/pluto/ikev2.c libreswan-3.29/programs/pluto/ikev2.c
+--- libreswan-3.29-orig/programs/pluto/ikev2.c 2019-06-10 10:22:04.000000000 -0400
++++ libreswan-3.29/programs/pluto/ikev2.c 2019-06-27 13:25:16.529215928 -0400
+@@ -3204,6 +3204,13 @@
+ lswlog_v2_stf_status(buf, result);
+ }
+
++ /* audit log failures - success is audit logged in ikev2_ike_sa_established() */
++ if (result > STF_OK) {
++ if (st != NULL) {
++ linux_audit_conn(st, IS_IKE_SA_ESTABLISHED(st) ? LAK_CHILD_FAIL : LAK_PARENT_FAIL);
++ }
++ }
++
+ switch (result) {
+
+ case STF_SUSPEND:
+diff -Naur libreswan-3.29-orig/programs/pluto/ikev2_child.c libreswan-3.29/programs/pluto/ikev2_child.c
+--- libreswan-3.29-orig/programs/pluto/ikev2_child.c 2019-06-10 10:22:04.000000000 -0400
++++ libreswan-3.29/programs/pluto/ikev2_child.c 2019-06-27 13:23:53.788080084 -0400
+@@ -102,6 +102,10 @@
+ return STF_OK;
+ }
+
++/*
++ * The caller could have done the linux_audit_conn() call, except one case
++ * here deletes the state before returning an STF error
++ */
+ stf_status ikev2_child_sa_respond(struct msg_digest *md,
+ pb_stream *outpbs,
+ enum isakmp_xchg_types isa_xchg)
+diff -Naur libreswan-3.29-orig/programs/pluto/ikev2_parent.c libreswan-3.29/programs/pluto/ikev2_parent.c
+--- libreswan-3.29-orig/programs/pluto/ikev2_parent.c 2019-06-10 10:22:04.000000000 -0400
++++ libreswan-3.29/programs/pluto/ikev2_parent.c 2019-06-27 13:23:53.789080097 -0400
+@@ -239,6 +239,7 @@
+ c->newest_isakmp_sa = ike->sa.st_serialno;
+ v2_schedule_replace_event(&ike->sa);
+ ike->sa.st_viable_parent = TRUE;
++ linux_audit_conn(&ike->sa, LAK_PARENT_START);
+ pstat_sa_established(&ike->sa);
+ }
+
+@@ -1581,6 +1582,24 @@
+ libreswan_log("IKE_AUTH response contained an unknown error notification (%d)", n);
+ } else {
+ libreswan_log("IKE_AUTH response contained the error notification %s", name);
++ /*
++ * There won't be a child state transition, so log if error is child related.
++ * see RFC 7296 Section 1.2
++ */
++ switch(n) {
++ case v2N_NO_PROPOSAL_CHOSEN:
++ case v2N_SINGLE_PAIR_REQUIRED:
++ case v2N_NO_ADDITIONAL_SAS:
++ case v2N_INTERNAL_ADDRESS_FAILURE:
++ case v2N_FAILED_CP_REQUIRED:
++ case v2N_TS_UNACCEPTABLE:
++ case v2N_INVALID_SELECTORS:
++ /* fallthrough */
++ linux_audit_conn(st, LAK_CHILD_FAIL);
++ break;
++ default:
++ break;
++ }
+ }
+ }
+ }
+@@ -3063,10 +3082,6 @@
+ ikev2_ike_sa_established(pexpect_ike_sa(st), md->svm,
+ STATE_PARENT_R2);
+
+-#ifdef USE_LINUX_AUDIT
+- linux_audit_conn(st, LAK_PARENT_START);
+-#endif
+-
+ if (LHAS(st->hidden_variables.st_nat_traversal, NATED_HOST)) {
+ /* ensure we run keepalives if needed */
+ if (c->nat_keepalive)
+@@ -3801,10 +3816,6 @@
+ ikev2_ike_sa_established(pexpect_ike_sa(pst), md->svm,
+ STATE_PARENT_I3);
+
+-#ifdef USE_LINUX_AUDIT
+- linux_audit_conn(st, LAK_PARENT_START);
+-#endif
+-
+ if (LHAS(st->hidden_variables.st_nat_traversal, NATED_HOST)) {
+ /* ensure we run keepalives if needed */
+ if (c->nat_keepalive)
+diff -Naur libreswan-3.29-orig/programs/pluto/kernel.c libreswan-3.29/programs/pluto/kernel.c
+--- libreswan-3.29-orig/programs/pluto/kernel.c 2019-06-10 10:22:04.000000000 -0400
++++ libreswan-3.29/programs/pluto/kernel.c 2019-06-27 13:23:53.790080111 -0400
+@@ -3334,7 +3334,8 @@
+ }
+
+ #ifdef USE_LINUX_AUDIT
+- linux_audit_conn(st, LAK_CHILD_START);
++ if (inbound_also)
++ linux_audit_conn(st, LAK_CHILD_START);
+ #endif
+ statetime_stop(&start, "%s()", __func__);
+
+@@ -3378,8 +3379,13 @@
+ {
+ #ifdef USE_LINUX_AUDIT
+ /* XXX in IKEv2 we get a spurious call with a parent st :( */
+- if (IS_CHILD_SA(st))
+- linux_audit_conn(st, LAK_CHILD_DESTROY);
++ if (IS_CHILD_SA(st)) {
++ /* child destruction already logged for STATE_CHILDSA_DEL state */
++ if (st->st_esp.present || st->st_ah.present) {
++ /* ESP or AH means this was an established IPsec SA */
++ linux_audit_conn(st, LAK_CHILD_DESTROY);
++ }
++ }
+ #endif
+ switch (kern_interface) {
+ case USE_KLIPS:
+diff -Naur libreswan-3.29-orig/programs/pluto/linux_audit.c libreswan-3.29/programs/pluto/linux_audit.c
+--- libreswan-3.29-orig/programs/pluto/linux_audit.c 2019-06-10 10:22:04.000000000 -0400
++++ libreswan-3.29/programs/pluto/linux_audit.c 2019-06-27 13:24:21.474460154 -0400
+@@ -176,12 +176,16 @@
+ zero(&cipher_str); /* OK: no pointer fields */
+ zero(&spi_str); /* OK: no pointer fields */
+
++ ip_address_buf raddr_buf;
++ const char *raddr = ipstr(&c->spd.that.host_addr, &raddr_buf);
++
+ switch (op) {
+ case LAK_PARENT_START:
+ case LAK_PARENT_DESTROY:
++ case LAK_PARENT_FAIL:
+ initiator = (st->st_original_role == ORIGINAL_INITIATOR) || IS_PHASE1_INIT(st->st_state);
+ snprintf(head, sizeof(head), "op=%s direction=%s %s connstate=%lu ike-version=%s auth=%s",
+- op == LAK_PARENT_START ? "start" : "destroy",
++ op == LAK_PARENT_DESTROY ? "destroy" : "start", /* fail to start logged under op=start */
+ initiator ? "initiator" : "responder",
+ conn_encode,
+ st->st_serialno,
+@@ -191,7 +195,8 @@
+ st->st_oakley.auth, &esb));
+
+ snprintf(prfname, sizeof(prfname), "%s",
+- st->st_oakley.ta_prf->prf_ike_audit_name);
++ st->st_oakley.ta_prf == NULL ? "none" :
++ st->st_oakley.ta_prf->prf_ike_audit_name);
+
+ if (st->st_oakley.ta_integ == &ike_alg_integ_none) {
+ if (st->st_ike_version == IKEv1) {
+@@ -220,18 +225,21 @@
+ }
+
+ snprintf(cipher_str, sizeof(cipher_str),
+- "cipher=%s ksize=%d integ=%s prf=%s pfs=%s",
+- st->st_oakley.ta_encrypt->encrypt_ike_audit_name,
++ "cipher=%s ksize=%d integ=%s prf=%s pfs=%s raddr=%s",
++ st->st_oakley.ta_encrypt == NULL ? "none" :
++ st->st_oakley.ta_encrypt->encrypt_ike_audit_name,
+ st->st_oakley.enckeylen,
+ integname, prfname,
+- st->st_oakley.ta_dh->common.name);
++ st->st_oakley.ta_dh == NULL ? "none" :
++ st->st_oakley.ta_dh->common.name, raddr);
+ break;
+
+ case LAK_CHILD_START:
+ case LAK_CHILD_DESTROY:
++ case LAK_CHILD_FAIL:
+ {
+ snprintf(head, sizeof(head), "op=%s %s connstate=%lu, satype=%s samode=%s",
+- op == LAK_CHILD_START ? "start" : "destroy",
++ op == LAK_CHILD_DESTROY ? "destroy" : "start", /* fail to start logged under op=start */
+ conn_encode,
+ st->st_serialno,
+ st->st_esp.present ? "ipsec-esp" : (st->st_ah.present ? "ipsec-ah" : "ipsec-policy"),
+@@ -274,7 +282,7 @@
+
+ /* note: each arg appears twice because it is printed two ways */
+ snprintf(spi_str, sizeof(spi_str),
+- "in-spi=%" PRIu32 "(0x%08" PRIu32 ") out-spi=%" PRIu32 "(0x%08" PRIu32 ") in-ipcomp=%" PRIu32 "(0x%08" PRIu32 ") out-ipcomp=%" PRIu32 "(0x%08" PRIu32 ")",
++ "in-spi=%" PRIu32 "(0x%08" PRIu32 ") out-spi=%" PRIu32 "(0x%08" PRIu32 ") in-ipcomp=%" PRIu32 "(0x%08" PRIu32 ") out-ipcomp=%" PRIu32 "(0x%08" PRIu32 ") raddr=%s",
+ ntohl(pi->attrs.spi),
+ ntohl(pi->attrs.spi),
+ ntohl(pi->our_spi),
+@@ -282,7 +290,8 @@
+ ntohl(st->st_ipcomp.attrs.spi), /* zero if missing */
+ ntohl(st->st_ipcomp.attrs.spi), /* zero if missing */
+ ntohl(st->st_ipcomp.our_spi), /* zero if missing */
+- ntohl(st->st_ipcomp.our_spi)); /* zero if missing */
++ ntohl(st->st_ipcomp.our_spi), /* zero if missing */
++ raddr);
+ break;
+ }
+ default:
+@@ -290,21 +299,18 @@
+ }
+ free(conn_encode); /* allocated by audit_encode_nv_string() */
+
+- ip_address_buf laddr_buf;
+- const char *laddr = ipstr(&c->spd.this.host_addr, &laddr_buf);
+-
+- ip_address_buf raddr_buf;
+- const char *raddr = ipstr(&c->spd.that.host_addr, &raddr_buf);
+-
+- snprintf(audit_str, sizeof(audit_str), "%s %s %s laddr=%s",
++ snprintf(audit_str, sizeof(audit_str), "%s %s %s",
+ head,
+ cipher_str,
+- spi_str,
+- laddr);
++ spi_str);
++
++ ip_address_buf laddr_buf;
++ const char *laddr = ipstr(&c->spd.this.host_addr, &laddr_buf);
+
+- linux_audit((op == LAK_CHILD_START || op == LAK_CHILD_DESTROY) ?
++ linux_audit((op == LAK_CHILD_START || op == LAK_CHILD_DESTROY || op == LAK_CHILD_FAIL) ?
+ AUDIT_CRYPTO_IPSEC_SA : AUDIT_CRYPTO_IKE_SA,
+- audit_str, raddr, AUDIT_RESULT_OK);
++ audit_str, laddr,
++ (op == LAK_PARENT_FAIL || op == LAK_CHILD_FAIL) ? AUDIT_RESULT_FAIL : AUDIT_RESULT_OK);
+ }
+ #if __GNUC__ >= 7
+ #pragma GCC diagnostic pop
+diff -Naur libreswan-3.29-orig/programs/pluto/log.h libreswan-3.29/programs/pluto/log.h
+--- libreswan-3.29-orig/programs/pluto/log.h 2019-06-10 10:22:04.000000000 -0400
++++ libreswan-3.29/programs/pluto/log.h 2019-06-27 13:23:53.791080125 -0400
+@@ -174,7 +174,9 @@
+ LAK_PARENT_START,
+ LAK_CHILD_START,
+ LAK_PARENT_DESTROY,
+- LAK_CHILD_DESTROY
++ LAK_CHILD_DESTROY,
++ LAK_PARENT_FAIL,
++ LAK_CHILD_FAIL
+ };
+ extern void linux_audit_init(void);
+ extern void linux_audit(const int type, const char *message,
+diff -Naur libreswan-3.29-orig/programs/pluto/retry.c libreswan-3.29/programs/pluto/retry.c
+--- libreswan-3.29-orig/programs/pluto/retry.c 2019-06-10 10:22:04.000000000 -0400
++++ libreswan-3.29/programs/pluto/retry.c 2019-06-27 13:25:27.536367032 -0400
+@@ -123,6 +123,10 @@
+
+ set_cur_state(st); /* ipsecdoi_replace would reset cur_state, set it again */
+ pstat_sa_failed(st, REASON_TOO_MANY_RETRANSMITS);
++
++ /* placed here because IKEv1 doesn't do a proper state change to STF_FAIL/STF_FATAL */
++ linux_audit_conn(st, IS_IKE_SA(st) ? LAK_PARENT_FAIL : LAK_CHILD_FAIL);
++
+ delete_state(st);
+ /* note: no md->st to clear */
+ }
+diff -Naur libreswan-3.29-orig/programs/pluto/state.c libreswan-3.29/programs/pluto/state.c
+--- libreswan-3.29-orig/programs/pluto/state.c 2019-06-10 10:22:04.000000000 -0400
++++ libreswan-3.29/programs/pluto/state.c 2019-06-27 13:23:53.792080138 -0400
+@@ -875,6 +875,16 @@
+
+ #ifdef USE_LINUX_AUDIT
+ /*
++ * IKEv2 IKE failures are logged in the state transition conpletion.
++ * IKEv1 IKE failures do not go through a transition, so we catch
++ * these in delete_state()
++ */
++ if (IS_IKE_SA(st) && st->st_ike_version == IKEv1 &&
++ !IS_IKE_SA_ESTABLISHED(st)) {
++ linux_audit_conn(st, LAK_PARENT_FAIL);
++ }
++
++ /*
+ * only log parent state deletes, we log children in
+ * ipsec_delete_sa()
+ */
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
index 463f35c..4419183 100644
--- a/SPECS/libreswan.spec
+++ b/SPECS/libreswan.spec
@@ -11,7 +11,6 @@
INC_RCDEFAULT=%{_initrddir} \\\
INC_USRLOCAL=%{_prefix} \\\
INITSYSTEM=systemd \\\
- NSS_REQ_AVA_COPY=false \\\
NSS_HAS_IPSEC_PROFILE=true \\\
USE_DNSSEC=true \\\
USE_FIPSCHECK=true \\\
@@ -24,6 +23,8 @@
USE_SECCOMP=true \\\
USE_XAUTHPAM=true \\\
USE_KLIPS=false \\\
+ USE_NSS_PRF=true \\\
+ USE_PRF_AES_XCBC=true \\\
%{nil}
#global prever rc1
@@ -31,8 +32,8 @@
Name: libreswan
Summary: IPsec implementation with IKEv1 and IKEv2 keying protocols
# version is generated in the release script
-Version: 3.27
-Release: %{?prever:0.}9%{?prever:.%{prever}}%{?dist}
+Version: 3.29
+Release: %{?prever:0.}6%{?prever:.%{prever}}%{?dist}
License: GPLv2
Url: https://libreswan.org/
Source0: https://download.libreswan.org/%{?prever:with_development/}%{name}-%{version}%{?prever}.tar.gz
@@ -42,13 +43,12 @@ Source2: https://download.libreswan.org/cavs/ikev1_psk.fax.bz2
Source3: https://download.libreswan.org/cavs/ikev2.fax.bz2
%endif
-Patch1: libreswan-3.27-1645137-addconn.patch
-Patch2: libreswan-3.27-1648776-v1v2split.patch
-Patch3: libreswan-3.25-EKU-1639404.patch
-Patch4: libreswan-3.25-1664521-fips-keysize.patch
-Patch5: libreswan-3.27-outgoing-ports-1668342.patch
-Patch6: libreswan-3.27-1671793-delete.patch
-Patch7: libreswan-3.27-parser.patch
+Patch1: libreswan-3.28-maintain-different-v1v2-split.patch
+Patch2: libreswan-3.29-CVE-2019-10155-testing.patch
+Patch3: libreswan-3.29-1723957-audit.patch
+Patch4: libreswan-3.25-1724200-halfopen-shunt.patch
+Patch5: libreswan-3.29-1699318-show.patch
+Patch6: libreswan-3.29-1714331-nss-kdf.patch
Group: System Environment/Daemons
BuildRequires: bison flex pkgconfig
@@ -59,8 +59,8 @@ Requires(postun): systemd
BuildRequires: pkgconfig hostname
# minimum version for support for rhbz#1651314
-BuildRequires: nss-devel >= 3.39.0-1.4
-Requires: nss >= 3.39.0-1.4
+BuildRequires: nss-tools nss-devel >= 3.44.0-8
+Requires: nss >= 3.44.0-8
BuildRequires: nspr-devel
BuildRequires: pam-devel
BuildRequires: libevent-devel
@@ -100,6 +100,13 @@ 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}
+%patch1 -p1
+%patch2 -p1
+%patch3 -p1
+%patch4 -p1
+%patch5 -p1
+%patch6 -p1
+
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 \
@@ -114,14 +121,6 @@ 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
-%patch3 -p1
-%patch4 -p1
-%patch5 -p1
-%patch6 -p1
-%patch7 -p1
-
%build
%if 0%{with_efence}
%global efence "-lefence"
@@ -164,15 +163,13 @@ install -d %{buildroot}%{_sysconfdir}/sysctl.d
install -m 0644 packaging/fedora/libreswan-sysctl.conf \
%{buildroot}%{_sysconfdir}/sysctl.d/50-libreswan.conf
-install -d %{buildroot}%{_tmpfilesdir}
-install -m 0644 packaging/fedora/libreswan-tmpfiles.conf \
- %{buildroot}%{_tmpfilesdir}/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
@@ -193,8 +190,16 @@ bunzip2 *.fax.bz2
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
@@ -228,6 +233,37 @@ bunzip2 *.fax.bz2
%{_libdir}/fipscheck/pluto.hmac
%changelog
+* Tue Aug 13 2019 Paul Wouters - 3.29-6
+- Resolves: rhbz#1714331 support NSS based IKE KDF's [require updated nss for rhbz 1738689, memleak fix]
+
+* Thu Aug 08 2019 Paul Wouters - 3.29-5
+- Resolves: rhbz#1714331 support NSS based IKE KDF's so libreswan does not need FIPS certification
+
+* Thu Aug 01 2019 Paul Wouters - 3.29-4
+- Resolves: rhbz#1699318 'ipsec show' has python3 invalid syntax
+
+* Thu Jul 04 2019 Paul Wouters - 3.29-3
+- Resolves: rhbz#1725205 XFRM policy for OE/32 peer is deleted when shunts for previous half-open state expire
+
+* Thu Jun 27 2019 Paul Wouters - 3.29-2
+- Resolves: rhbz#1723957 libreswan is missing linux audit calls for failed IKE SAs and failed IPsec SAs required for Common Criteria
+
+* 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]