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]