diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..26f0a97 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +SOURCES/ikev1_dsa.fax.bz2 +SOURCES/ikev1_psk.fax.bz2 +SOURCES/ikev2.fax.bz2 +SOURCES/libreswan-3.27.tar.gz diff --git a/.libreswan.metadata b/.libreswan.metadata new file mode 100644 index 0000000..b2b4b4e --- /dev/null +++ b/.libreswan.metadata @@ -0,0 +1,4 @@ +b35cd50b8bc0a08b9c07713bf19c72d53bfe66bb SOURCES/ikev1_dsa.fax.bz2 +861d97bf488f9e296cad8c43ab72f111a5b1a848 SOURCES/ikev1_psk.fax.bz2 +fcaf77f3deae3d8e99cdb3b1f8abea63167a0633 SOURCES/ikev2.fax.bz2 +c2e4b418ea286168bb022620a6af6a70cecffd14 SOURCES/libreswan-3.27.tar.gz diff --git a/SOURCES/libreswan-3.25-1664521-fips-keysize.patch b/SOURCES/libreswan-3.25-1664521-fips-keysize.patch new file mode 100644 index 0000000..e382f8c --- /dev/null +++ b/SOURCES/libreswan-3.25-1664521-fips-keysize.patch @@ -0,0 +1,35 @@ +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-EKU-1639404.patch b/SOURCES/libreswan-3.25-EKU-1639404.patch new file mode 100644 index 0000000..7249f6c --- /dev/null +++ b/SOURCES/libreswan-3.25-EKU-1639404.patch @@ -0,0 +1,108 @@ +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 new file mode 100644 index 0000000..b8be440 --- /dev/null +++ b/SOURCES/libreswan-3.27-1645137-addconn.patch @@ -0,0 +1,12 @@ +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 new file mode 100644 index 0000000..c19a3e5 --- /dev/null +++ b/SOURCES/libreswan-3.27-1648776-v1v2split.patch @@ -0,0 +1,145 @@ +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 new file mode 100644 index 0000000..3ef2cd8 --- /dev/null +++ b/SOURCES/libreswan-3.27-1671793-delete.patch @@ -0,0 +1,90 @@ +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 new file mode 100644 index 0000000..2af73f5 --- /dev/null +++ b/SOURCES/libreswan-3.27-outgoing-ports-1668342.patch @@ -0,0 +1,29 @@ +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 new file mode 100644 index 0000000..ea98c90 --- /dev/null +++ b/SOURCES/libreswan-3.27-parser.patch @@ -0,0 +1,7144 @@ +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/SPECS/libreswan.spec b/SPECS/libreswan.spec new file mode 100644 index 0000000..463f35c --- /dev/null +++ b/SPECS/libreswan.spec @@ -0,0 +1,433 @@ +%global _hardened_build 1 +# These are rpm macros and are 0 or 1 +%global with_efence 0 +%global with_development 0 +%global with_cavstests 1 +# Libreswan config options +%global libreswan_config \\\ + FINALLIBEXECDIR=%{_libexecdir}/ipsec \\\ + FINALMANDIR=%{_mandir} \\\ + FIPSPRODUCTCHECK=%{_sysconfdir}/system-fips \\\ + INC_RCDEFAULT=%{_initrddir} \\\ + INC_USRLOCAL=%{_prefix} \\\ + INITSYSTEM=systemd \\\ + NSS_REQ_AVA_COPY=false \\\ + NSS_HAS_IPSEC_PROFILE=true \\\ + USE_DNSSEC=true \\\ + USE_FIPSCHECK=true \\\ + USE_LABELED_IPSEC=true \\\ + USE_LDAP=true \\\ + USE_LIBCAP_NG=true \\\ + USE_LIBCURL=true \\\ + USE_LINUX_AUDIT=true \\\ + USE_NM=true \\\ + USE_SECCOMP=true \\\ + USE_XAUTHPAM=true \\\ + USE_KLIPS=false \\\ +%{nil} + +#global prever rc1 + +Name: libreswan +Summary: IPsec implementation with IKEv1 and IKEv2 keying protocols +# version is generated in the release script +Version: 3.27 +Release: %{?prever:0.}9%{?prever:.%{prever}}%{?dist} +License: GPLv2 +Url: https://libreswan.org/ +Source0: https://download.libreswan.org/%{?prever:with_development/}%{name}-%{version}%{?prever}.tar.gz +%if 0%{with_cavstests} +Source1: https://download.libreswan.org/cavs/ikev1_dsa.fax.bz2 +Source2: https://download.libreswan.org/cavs/ikev1_psk.fax.bz2 +Source3: https://download.libreswan.org/cavs/ikev2.fax.bz2 +%endif + +Patch1: libreswan-3.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 + +Group: System Environment/Daemons +BuildRequires: bison flex pkgconfig +BuildRequires: systemd systemd-units systemd-devel +Requires(post): coreutils bash systemd +Requires(preun): systemd +Requires(postun): systemd + +BuildRequires: pkgconfig hostname +# minimum version for support for rhbz#1651314 +BuildRequires: nss-devel >= 3.39.0-1.4 +Requires: nss >= 3.39.0-1.4 +BuildRequires: nspr-devel +BuildRequires: pam-devel +BuildRequires: libevent-devel +BuildRequires: unbound-devel >= 1.6.0-6 ldns-devel +BuildRequires: libseccomp-devel +BuildRequires: libselinux-devel +BuildRequires: fipscheck-devel +Requires: fipscheck%{_isa} +Buildrequires: audit-libs-devel + +BuildRequires: libcap-ng-devel +BuildRequires: openldap-devel curl-devel +%if 0%{with_efence} +BuildRequires: ElectricFence +%endif +BuildRequires: xmlto + +Requires: nss-tools, nss-softokn +Requires: iproute >= 2.6.8 +Requires: unbound-libs >= 1.6.6 + +%description +Libreswan is a free implementation of IKE/IPsec for Linux. IPsec is +the Internet Protocol Security and uses strong cryptography to provide +both authentication and encryption services. These services allow you +to build secure tunnels through untrusted networks. Everything passing +through the untrusted net is encrypted by the ipsec gateway machine and +decrypted by the gateway at the other end of the tunnel. The resulting +tunnel is a virtual private network or VPN. + +This package contains the daemons and userland tools for setting up +Libreswan. + +Libreswan also supports IKEv2 (RFC7296) and Secure Labeling + +Libreswan is based on Openswan-2.6.38 which in turn is based on FreeS/WAN-2.04 + +%prep +%setup -q -n libreswan-%{version}%{?prever} +pathfix.py -i %{__python3} -pn programs/verify/verify.in programs/show/show.in \ + testing/cert_verify/usage_test testing/pluto/ikev1-01-fuzzer/cve-2015-3204.py \ + testing/pluto/ikev2-15-fuzzer/send_bad_packets.py testing/x509/dist_certs.py \ + programs/_unbound-hook/_unbound-hook.in + +# replace unsupported KLIPS README +echo "KLIPS is not supported with RHEL8" > README.KLIPS + +# linking to freebl is not needed +sed -i "s/-lfreebl //" mk/config.mk + +# enable crypto-policies support +sed -i "s:#[ ]*include \(.*\)\(/crypto-policies/back-ends/libreswan.config\)$:include \1\2:" programs/configs/ipsec.conf.in + +%patch1 -p1 +%patch2 -p1 +%patch3 -p1 +%patch4 -p1 +%patch5 -p1 +%patch6 -p1 +%patch7 -p1 + +%build +%if 0%{with_efence} +%global efence "-lefence" +%endif + +#796683: -fno-strict-aliasing +make %{?_smp_mflags} \ +%if 0%{with_development} + USERCOMPILE="-g -DGCC_LINT %(echo %{optflags} | sed -e s/-O[0-9]*/ /) %{?efence} -fPIE -pie -fno-strict-aliasing -Wformat-nonliteral -Wformat-security" \ +%else + USERCOMPILE="-g -DGCC_LINT %{optflags} %{?efence} -fPIE -pie -fno-strict-aliasing -Wformat-nonliteral -Wformat-security" \ +%endif + USERLINK="-g -pie -Wl,-z,relro,-z,now %{?efence}" \ + %{libreswan_config} \ + programs +FS=$(pwd) + +# Add generation of HMAC checksums of the final stripped binaries +%define __spec_install_post \ + %{?__debug_package:%{__debug_install_post}} \ + %{__arch_install_post} \ + %{__os_install_post} \ + fipshmac -d %{buildroot}%{_libdir}/fipscheck %{buildroot}%{_libexecdir}/ipsec/pluto \ +%{nil} + +%install +make \ + DESTDIR=%{buildroot} \ + %{libreswan_config} \ + install +FS=$(pwd) +rm -rf %{buildroot}/usr/share/doc/libreswan + +install -d -m 0755 %{buildroot}%{_rundir}/pluto +# used when setting --perpeerlog without --perpeerlogbase +install -d -m 0700 %{buildroot}%{_localstatedir}/log/pluto/peer +install -d %{buildroot}%{_sbindir} + +install -d %{buildroot}%{_sysconfdir}/sysctl.d +install -m 0644 packaging/fedora/libreswan-sysctl.conf \ + %{buildroot}%{_sysconfdir}/sysctl.d/50-libreswan.conf + +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* + +%if 0%{with_cavstests} +%check +# There is an elaborate upstream testing infrastructure which we do not +# run here - it takes hours and uses kvm +# We only run the CAVS tests. +cp %{SOURCE1} %{SOURCE2} %{SOURCE3} . +bunzip2 *.fax.bz2 + +: starting CAVS test for IKEv2 +%{buildroot}%{_libexecdir}/ipsec/cavp -v2 ikev2.fax | \ + diff -u ikev2.fax - > /dev/null +: starting CAVS test for IKEv1 RSASIG +%{buildroot}%{_libexecdir}/ipsec/cavp -v1dsa ikev1_dsa.fax | \ + diff -u ikev1_dsa.fax - > /dev/null +: starting CAVS test for IKEv1 PSK +%{buildroot}%{_libexecdir}/ipsec/cavp -v1psk ikev1_psk.fax | \ + diff -u ikev1_psk.fax - > /dev/null +: CAVS tests passed + +%{buildroot}%{_libexecdir}/ipsec/algparse -tp || { echo prooposal test failed; exit 1; } +%{buildroot}%{_libexecdir}/ipsec/algparse -ta || { echo algorithm test failed; exit 1; } + +%endif + +%post +%systemd_post ipsec.service + +%preun +%systemd_preun ipsec.service + +%postun +%systemd_postun_with_restart ipsec.service + +%files +%doc CHANGES COPYING CREDITS README* LICENSE +%doc docs/*.* docs/examples +%attr(0644,root,root) %config(noreplace) %{_sysconfdir}/ipsec.conf +%attr(0600,root,root) %config(noreplace) %{_sysconfdir}/ipsec.secrets +%attr(0700,root,root) %dir %{_sysconfdir}/ipsec.d +%attr(0700,root,root) %dir %{_sysconfdir}/ipsec.d/policies +%attr(0644,root,root) %config(noreplace) %{_sysconfdir}/ipsec.d/policies/* +%attr(0644,root,root) %config(noreplace) %{_sysconfdir}/sysctl.d/50-libreswan.conf +%attr(0700,root,root) %dir %{_localstatedir}/log/pluto +%attr(0700,root,root) %dir %{_localstatedir}/log/pluto/peer +%attr(0755,root,root) %dir %{_rundir}/pluto +%attr(0644,root,root) %{_tmpfilesdir}/libreswan.conf +%attr(0644,root,root) %{_unitdir}/ipsec.service +%attr(0644,root,root) %config(noreplace) %{_sysconfdir}/pam.d/pluto +%{_sbindir}/ipsec +%{_libexecdir}/ipsec +%attr(0644,root,root) %doc %{_mandir}/*/* +%{_libdir}/fipscheck/pluto.hmac + +%changelog +* Thu Feb 21 2019 Paul Wouters - 3.27-9 +- Resolves: rhbz#1648776 limit connections to be ikev1only or ikev2only and make ikev2only the default [man page update] + +* Fri Feb 15 2019 Paul Wouters - 3.27-8 +- Resolves: rhbz#1664101 system wide crypto policies causing IKE_INIT packet fragmentation + +* Tue Feb 05 2019 Paul Wouters - 3.27-7 +- Resolves: rhbz#1671793 proessing ISAKMP_NEXT_D with additional payloads causes dangling pointer to deleted state + +* Fri Feb 01 2019 Paul Wouters - 3.27-6 +- Resolves: rhbz#1668342 SELinux prevents libreswan from using some outbound ports causing DNS resolution failures at connection at load time + +* Thu Jan 10 2019 Paul Wouters - 3.27-5 +- Resolves: rhbz#1664522 libreswan 3.25 in FIPS mode is incorrectly rejecting X.509 public keys that are >= 3072 bits + +* Mon Dec 10 2018 Paul Wouters - 3.27-4 +- Resolves: rhbz#1657846 libreswan no longer needs to provide openswan in rhel8 +- Resolves: rhbz#1643388 libreswan: Unable to verify certificate with non-empty Extended Key Usage which does not include serverAuth or clientAuth +- Resolves: rhbz#1657854 remove userland support for deprecated KLIPS IPsec stack support + +* Sun Dec 09 2018 Paul Wouters - 3.27-3 +- Resolves: rhbz#1648776 limit connections to be ikev1only or ikev2only and make ikev2only the default + +* Thu Nov 08 2018 Paul Wouters - 3.27-2 +- Resolves: rhbz#1645137 Libreswan segfaults when it loads configuration file with more then 5 connections + +* Mon Oct 08 2018 Paul Wouters - 3.27-1 +- Resolves: rhbz#1566574 Rebase to libreswan 3.27 + +* Mon Sep 17 2018 Paul Wouters - 3.26-1 +- Resolves: rhbz#1566574 Rebase to libreswan 3.26 +- Resolves: rhbz#1527037 libreswan IPSEC implementation: should follow the policies of system-wide crypto policy +- Resolves: rhbz#1375779 [IKEv2 Conformance] Test IKEv2.EN.R.1.1.6.7: Sending INVALID_KE_PAYLOAD failed +- Resolves: rhbz#1085758 [TAHI][IKEv2] IKEv2.EN.I.1.2.1.1: Can't observe CREATE_CHILD_SA request for rekey +- Resolves: rhbz#1053048 [TAHI][IKEv2] IKEv2.EN.I.1.2.4.1-7: libreswan doesn't sent CREATE_CHILD_SA after IKE_SA Lifetime timeout + +* Mon Aug 13 2018 Paul Wouters - 3.25-4 +- Resolves: rhbz#1590823 libreswan: Use Python 3 in RHEL 8 + +* Wed Aug 01 2018 Charalampos Stratakis - 3.25-3.1 +- Rebuild for platform-python + +* Mon Jul 09 2018 Paul Wouters - 3.25-3 +- Cleanup shebangs for python3 +- Use the same options via macro for make programs and make install +- Remove old ifdefs +- Sync up patches to new upstream version +- Add Requires: for unbound-libs >= 1.6.6 +- Enable crypto-policies support +- Make rundir world readable for easier permission granting for socket + +* Tue Jun 26 2018 Charalampos Stratakis - 3.23-2.2 +- Make python shebangs point to python3 + +* Fri Jun 22 2018 Troy Dawson - 3.23-2.1 +- Fix python shebangs (#1580773) + +* Mon Feb 19 2018 Paul Wouters - 3.23-2 +- Support crypto-policies package +- Pull in some patches from upstream and IANA registry updates +- gcc7 format-truncate fixes and workarounds + +* Wed Feb 07 2018 Fedora Release Engineering - 3.23-1.1 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild + +* Thu Jan 25 2018 Paul Wouters - 3.23-1 +- Updated to 3.23 - support for MOBIKE, PPK, CMAC, nic offload and performance improvements + +* Sat Jan 20 2018 Björn Esser - 3.22-1.1 +- Rebuilt for switch to libxcrypt + +* Mon Oct 23 2017 Paul Wouters - 3.22-1 +- Updated to 3.22 - many bugfixes, and unbound ipsecmod support + +* Wed Aug 9 2017 Paul Wouters - 3.21-1 +- Updated to 3.21 + +* Thu Aug 03 2017 Fedora Release Engineering - 3.20-1.2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild + +* Wed Jul 26 2017 Fedora Release Engineering - 3.20-1.1 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild + +* Tue Mar 14 2017 Paul Wouters - 3.20-1 +- Updated to 3.20 + +* Fri Mar 03 2017 Paul Wouters - 3.20-0.1.dr4 +- Update to 3.20dr4 to test mozbz#1336487 export CERT_CompareAVA + +* Fri Feb 10 2017 Fedora Release Engineering - 3.19-1.1 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild + +* Fri Feb 03 2017 Paul Wouters - 3.19-2 +- Resolves: rhbz#1392191 libreswan: crash when OSX client connects +- Improved uniqueid and session replacing support +- Test Buffer warning fix on size_t +- Re-introduce --configdir for backwards compatibility + +* Sun Jan 15 2017 Paul Wouters - 3.19-1 +- Updated to 3.19 (see download.libreswan.org/CHANGES) + +* Mon Dec 19 2016 Miro Hrončok - 3.18-1.1 +- Rebuild for Python 3.6 + +* Fri Jul 29 2016 Paul Wouters - 3.18-1 +- Updated to 3.18 for CVE-2016-5391 rhbz#1361164 and VTI support +- Remove support for /etc/sysconfig/pluto (use native systemd instead) + +* Thu May 05 2016 Paul Wouters - 3.17-2 +- Resolves: rhbz#1324956 prelink is gone, /etc/prelink.conf.d/* is no longer used + +* Thu Apr 07 2016 Paul Wouters - 3.17-1 +- Updated to 3.17 for CVE-2016-3071 +- Disable LIBCAP_NG as it prevents unbound-control from working properly +- Temporarilly disable WERROR due to a few minor known issues + +* Thu Feb 04 2016 Fedora Release Engineering - 3.16-1.1 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild + +* Fri Dec 18 2015 Paul Wouters - 3.16-1 +- Updated to 3.16 (see https://download.libreswan.org/CHANGES) + +* Tue Aug 11 2015 Paul Wouters - 3.15-1 +- Updated to 3.15 (see http://download.libreswan.org/CHANGES) +- Resolves: rhbz#CVE-2015-3240 IKE daemon restart when receiving a bad DH gx +- NSS database creation moved from spec file to service file +- Run CAVS tests on package build +- Added BuildRequire systemd-units and xmlto +- Bumped minimum required nss to 3.16.1 +- Install tmpfiles +- Install sysctl file +- Update doc files to include + +* Mon Jul 13 2015 Paul Wouters - 3.13-2 +- Resolves: rhbz#1238967 Switch libreswan to use python3 + +* Wed Jun 17 2015 Fedora Release Engineering - 3.13-1.1 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild + +* Mon Jun 01 2015 Paul Wouters - 3.13-1 +- Updated to 3.13 for CVE-2015-3204 + +* Fri Nov 07 2014 Paul Wouters - 3.12-1 +- Updated to 3.12 Various IKEv2 fixes + +* Wed Oct 22 2014 Paul Wouters - 3.11-1 +- Updated to 3.11 (many fixes, including startup fixes) +- Resolves: rhbz#1144941 libreswan 3.10 upgrade breaks old ipsec.secrets configs +- Resolves: rhbz#1147072 ikev1 aggr mode connection fails after libreswan upgrade +- Resolves: rhbz#1144831 Libreswan appears to start with systemd before all the NICs are up and running + +* Tue Sep 09 2014 Paul Wouters - 3.10-3 +- Fix some coverity issues, auto=route on bootup and snprintf on 32bit machines + +* Mon Sep 01 2014 Paul Wouters - 3.10-1 +- Updated to 3.10, major bugfix release, new xauth status options + +* Sun Aug 17 2014 Fedora Release Engineering - 3.9-1.1 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild + +* Thu Jul 10 2014 Paul Wouters - 3.9-1 +- Updated to 3.9. IKEv2 enhancements, ESP/IKE algo enhancements +- Mark libreswan-fips.conf as config file +- attr modifier for man pages no longer needed +- BUGS file no longer exists upstream + +* Sat Jun 07 2014 Fedora Release Engineering - 3.8-1.1 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild + +* Sat Jan 18 2014 Paul Wouters - 3.8-1 +- Updated to 3.8, fixes rhbz#CVE-2013-6467 (rhbz#1054102) + +* Wed Dec 11 2013 Paul Wouters - 3.7-1 +- Updated to 3.7, fixes CVE-2013-4564 +- Fixes creating a bogus NSS db on startup (rhbz#1005410) + +* Thu Oct 31 2013 Paul Wouters - 3.6-1 +- Updated to 3.6 (IKEv2, MODECFG, Cisco interop fixes) +- Generate empty NSS db if none exists + +* Mon Aug 19 2013 Paul Wouters - 3.5-3 +- Add a Provides: for openswan-doc + +* Sat Aug 03 2013 Fedora Release Engineering - 3.5-1.1 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_20_Mass_Rebuild + +* Mon Jul 15 2013 Paul Wouters - 3.5-2 +- Added interop patch for (some?) Cisco VPN clients sending 16 zero + bytes of extraneous IKE data +- Removed fipscheck_version + +* Sat Jul 13 2013 Paul Wouters - 3.5-1 +- Updated to 3.5 + +* Thu Jun 06 2013 Paul Wouters - 3.4-1 +- Updated to 3.4, which only contains style changes to kernel coding style +- IN MEMORIAM: June 3rd, 2013 Hugh Daniel + +* Mon May 13 2013 Paul Wouters - 3.3-1 +- Updated to 3.3, which resolves CVE-2013-2052 + +* Sat Apr 13 2013 Paul Wouters - 3.2-1 +- Initial package for Fedora