-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512


Release date: Monday Jul 25, 2016

CVE-2016-5391 IKEv2 bogus proposal lacking DH transform causes restart

URL: http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=2016-5391

This alert (and any possible updates) is available at the following URLs:
https://libreswan.org/security/CVE-2016-5391/

The Libreswan Project has found a vulnerability in processing IKEv2
proposals that miss a Diffie-Hellman transform for the IKE SA. A NULL
pointer dererefence causes the pluto IKE daemon to crash and restart.
No remote code execution is possible.

Vulnerable versions: libreswan 3.17
Not vulnerable     : all other versions of libreswan

If you cannot upgrade to 3.18, please see the above link for a patch for
this issue.

Vulnerability information
=========================

The IKE SA negotiation requires a Diffie-Hellman group to be agreed upon.
This payload is mandatory for all IKE SA proposals during the IKE_INIT
Exchange Type. It is only optional for the CREATE_CHILD_SA Exchange
Type, where PFS is optional.

Libreswan version 3.17 does not properly reject a proposal in IKE_INIT
Exchange that lacks a Diffie-Hellman group. It dereferences a NULL
pointer causing a crash and restart.

Exploitation
============

A denial of service can be launched by anyone repeatedly sending such
IKE packets.

No authentication credentials are required. No remote code execution is
possible through this vulnerability. Libreswan automatically restarts when
it crashes.

Workaround
==========

There is no workaround. Either upgrade or use the supplied patch in the
above listed resource URL.

Credits
=======

This vulnerability was found by the Libreswan Project when performing
interop tests with strongswan version 5.4.0 which can transmit these
bogus proposals. It has been assigned strongSwan issue #2051

About libreswan (https://libreswan.org/)
========================================

Libreswan is a free implementation of the Internet Protocol Security
(IPsec) suite and Internet Key Exchange (IKE) protocols. It is a
descendant (fork) of openswan 2.6.38.

IPsec 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
network 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 (VPN).

Patch 
======================================================================

diff --git a/programs/pluto/ikev2_spdb_struct.c b/programs/pluto/ikev2_spdb_struct.c
index 753c26e..f46b5a5 100644
- ---- a/programs/pluto/ikev2_spdb_struct.c
+++ b/programs/pluto/ikev2_spdb_struct.c
@@ -769,17 +769,44 @@ static int process_transforms(pb_stream *prop_pbs, struct print *remote_print_bu
  				DBG(DBG_CONTROL, DBG_log("allowing no NULL integrity"));
  				continue;
  			}
- --			int type_proposed = ((transform_types_found & LELEM(type)) != 0);
- --			int type_matched = matching_local_proposal->matching_transform[type]->valid;
- --			if (type_proposed != type_matched) {
- --				DBG(DBG_CONTROLMORE, DBG_log("local proposal %d type %s failed: %s and %s",
+			bool local_transform_type_present = local_transforms->transform[0].valid;
+			bool remote_transform_type_present = ((transform_types_found & LELEM(type)) != 0);
+			/*
+			* Check that the local and remote end are
+			* consistent about the transform being
+			* present.
+			*
+			* Transform matching is not optional.
+			* Instead, for something like ESP/AH, DH is
+			* made "optional" by sending two proposals.
+			* One with the transform (DH) present and one
+			* with it absent.
+			*/
+			if (local_transform_type_present != remote_transform_type_present) {
+			   DBG(DBG_CONTROLMORE, DBG_log("local proposal %d transform type %s failed: local %s and remote %s",
+				local_propnum, trans_type_name(type),
+				local_transform_type_present ?  "present" : "absent",
+				remote_transform_type_present ?  "present" : "absent"));
+			   break;
+			}
+			/*
+			* Check that when the transform type is
+			* required it also matches and vice versa.
+			*
+			* Since !local_transform_type_present implies
+			* !remote_transform_type_matched, the above
+			* test is also required.
+			*/
+			bool remote_transform_type_matched = matching_local_proposal->matching_transform[type]->valid;
+			if (local_transform_type_present != remote_transform_type_matched) {
+			    DBG(DBG_CONTROLMORE, DBG_log("local proposal %d transform type %s failed: local %s and remote %s",
  							     local_propnum, trans_type_name(type),
- --							     type_proposed ? "proposed" : "not-proposed",
- --							     type_matched ? "matched" : "not-matched"));
+								local_transform_type_present ?  "present" : "absent",
+								remote_transform_type_matched ?  "matched" : "different"));
  				break;
  			}
  		}
- --		/* loop finished? */
+		/* loop finished cleanly? */
  		if (type == IKEv2_TRANS_TYPE_ROOF) {
  			DBG(DBG_CONTROL,
  			    DBG_log("remote proposal %u matches local proposal %d",
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1


imX4qV3DazRDoHOzjkqW
=d5yb
-----END PGP SIGNATURE-----
