[PATCHES] limit kerberos encryption types used by winbindd

Uri Simchoni uri at samba.org
Sun Jul 24 10:17:02 UTC 2016


Hi,

The attached patch set adds an smb.conf parameter which controls the
Kerberos etypes placed in the krb5.conf file generated by winbindd and
the net command (for some sub-commands such as net ads testjoin).

It enables:
1. limiting the encryption types to AES at the client side to prevent
downgrade attacks.

2. limiting encryption to RC4 to work around an issue with an RODC and a
mixed env of 2003R2 and 2008R2 DCs.

1/4 - adds the parameter
2/4 - modify building of private krb5.conf to use the parameter
3/4 - a Heimdal fix for GSSAPI TGS requests which ignore krb5.conf (also
sent upstream, still no resolution)
4/4 - a tshark-based test to ensure only configured etypes are being
used in the actual Kerberos exchanges.

Caveats:
- Not tested with MIT, just with Heimdal (+1 to get those MIT patches in
and have an MIT-based testenv!)
- The test suite uses tshark and silently succeeds if it's not
installed. This is so to avoid breaking people's dev env. It seems to be
installed on sn-devel-1(0|4)4 so this arrangement will cause the test to
run in autobuild, but it's not ideal and I'd appreciate suggestions on that.

Review appreciated.
Thanks,
Uri.
-------------- next part --------------
From a42435267c4914c6f88c1f3bfecb88548d848c09 Mon Sep 17 00:00:00 2001
From: Uri Simchoni <uri at samba.org>
Date: Sun, 8 May 2016 15:45:44 +0300
Subject: [PATCH 1/4] s3-param: add kerberos encryption types parameter

Signed-off-by: Uri Simchoni <uri at samba.org>
---
 .../security/kerberosencryptiontypes.xml           | 53 ++++++++++++++++++++++
 lib/param/loadparm.c                               |  2 +
 lib/param/loadparm.h                               |  4 ++
 lib/param/param_table.c                            |  9 ++++
 4 files changed, 68 insertions(+)
 create mode 100644 docs-xml/smbdotconf/security/kerberosencryptiontypes.xml

diff --git a/docs-xml/smbdotconf/security/kerberosencryptiontypes.xml b/docs-xml/smbdotconf/security/kerberosencryptiontypes.xml
new file mode 100644
index 0000000..b19a8a8
--- /dev/null
+++ b/docs-xml/smbdotconf/security/kerberosencryptiontypes.xml
@@ -0,0 +1,53 @@
+<samba:parameter name="kerberos encryption types"
+                 context="G"
+                 type="enum"
+		 enumlist="enum_kerberos_encryption_types_vals"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+<description>
+    <para>This parameter determines the encryption types to use when operating
+    as a Kerberos client. Possible values are <emphasis>all</emphasis>,
+    <emphasis>strong</emphasis>, and <emphasis>legacy</emphasis>.
+    </para>
+
+    <para>Samba uses a Kerberos library (MIT or Heimdal) to obtain Kerberos
+    tickets. This library is normally configured outside of Samba, using
+    the krb5.conf file. This file may also include directives to configure
+    the encryption types to be used. However, Samba implements Active Directory
+    protocols and algorithms to locate a domain controller. In order to
+    force the Kerberos library into using the correct domain controller,
+    some Samba processes, such as
+    <citerefentry><refentrytitle>winbindd</refentrytitle>
+    <manvolnum>8</manvolnum></citerefentry> and
+    <citerefentry><refentrytitle>net</refentrytitle>
+    <manvolnum>8</manvolnum></citerefentry>, build a private krb5.conf
+    file for use by the Kerberos library while being invoked from Samba.
+    This private file controls all aspects of the Kerberos library operation,
+    and this parameter controls how the encryption types are configured
+    within this generated file, and therefore also controls the encryption
+    types negotiable by Samba.
+    </para>
+
+    <para>When set to <constant>all</constant>, all active directory
+    encryption types are allowed.
+    </para>
+
+    <para>When set to <constant>strong</constant>, only AES-based encyption
+    types are offered. This can be used in hardened environments to prevent
+    downgrade attacks.
+    </para>
+
+    <para>When set to <constant>legacy</constant>, only RC4-HMAC-MD5
+    is allowed. Avoiding AES this way has one a very specific use.
+    Normally, the encryption type is negotiated between the peers.
+    However, there is one scenario in which a Windows read-only domain
+    controller (RODC) advertises AES encryption, but then proxies the
+    request to a writeable DC which may not support AES encryption,
+    leading to failure of the handshake. Setting this parameter to
+    <constant>legacy</constant> would cause samba not to negotiate AES
+    encryption. It is assumed of course that the weaker legacy
+    encryption types are acceptable for the setup.
+    </para>
+</description>
+
+<value type="default">all</value>
+</samba:parameter>
diff --git a/lib/param/loadparm.c b/lib/param/loadparm.c
index 515ed05..f9cba62 100644
--- a/lib/param/loadparm.c
+++ b/lib/param/loadparm.c
@@ -2898,6 +2898,8 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx)
 
 	lpcfg_do_global_parameter(lp_ctx, "aio max threads", "100");
 
+	lpcfg_do_global_parameter(lp_ctx, "kerberos encryption types", "all");
+
 	/* Allow modules to adjust defaults */
 	for (defaults_hook = defaults_hooks; defaults_hook;
 		 defaults_hook = defaults_hook->next) {
diff --git a/lib/param/loadparm.h b/lib/param/loadparm.h
index aa256c1..d8f6975 100644
--- a/lib/param/loadparm.h
+++ b/lib/param/loadparm.h
@@ -178,6 +178,10 @@ struct file_lists {
 #define KERBEROS_VERIFY_DEDICATED_KEYTAB 2
 #define KERBEROS_VERIFY_SECRETS_AND_KEYTAB 3
 
+#define KERBEROS_ETYPES_ALL 0
+#define KERBEROS_ETYPES_STRONG 1
+#define KERBEROS_ETYPES_LEGACY 2
+
 /* ACL compatibility */
 enum acl_compatibility {ACL_COMPAT_AUTO, ACL_COMPAT_WINNT, ACL_COMPAT_WIN2K};
 
diff --git a/lib/param/param_table.c b/lib/param/param_table.c
index d8d9144..c8520d2 100644
--- a/lib/param/param_table.c
+++ b/lib/param/param_table.c
@@ -208,6 +208,15 @@ static const struct enum_list enum_kerberos_method[] = {
 	{-1, NULL}
 };
 
+/* Kerberos encryption types selection options */
+
+static const struct enum_list enum_kerberos_encryption_types_vals[] = {
+	{KERBEROS_ETYPES_ALL, "all"},
+	{KERBEROS_ETYPES_STRONG, "strong"},
+	{KERBEROS_ETYPES_LEGACY, "legacy"},
+	{-1, NULL}
+};
+
 static const struct enum_list enum_printing[] = {
 	{PRINT_SYSV, "sysv"},
 	{PRINT_AIX, "aix"},
-- 
2.5.5


From 08a50587c282301423db0ddbbdd7433340c4cd27 Mon Sep 17 00:00:00 2001
From: Uri Simchoni <uri at samba.org>
Date: Mon, 30 May 2016 21:21:41 +0300
Subject: [PATCH 2/4] libads: use "kerberos encryption types" parameter

When creating the custom krb.conf file, list etypes
according to kerberos encryption types

Also use proper directives for heimdal (heimdal recognizes
the MIT etype directives, but does not act upon them)

Signed-off-by: Uri Simchoni <uri at samba.org>
---
 source3/libads/kerberos.c | 106 ++++++++++++++++++++++++++++++++++------------
 1 file changed, 80 insertions(+), 26 deletions(-)

diff --git a/source3/libads/kerberos.c b/source3/libads/kerberos.c
index 53407fa..a47ab6c 100644
--- a/source3/libads/kerberos.c
+++ b/source3/libads/kerberos.c
@@ -813,6 +813,76 @@ out:
  run as root or will fail (which is a good thing :-).
 ************************************************************************/
 
+#if !defined(SAMBA4_USES_HEIMDAL) /* MIT version */
+static char *get_enctypes(TALLOC_CTX *mem_ctx)
+{
+	char *aes_enctypes = NULL;
+	const char *legacy_enctypes = "";
+	char *enctypes = NULL;
+
+	aes_enctypes = talloc_strdup(mem_ctx, "");
+	if (aes_enctypes == NULL) {
+		goto done;
+	}
+
+	if (lp_kerberos_encryption_types() == KERBEROS_ETYPES_ALL ||
+	    lp_kerberos_encryption_types() == KERBEROS_ETYPES_STRONG) {
+#ifdef HAVE_ENCTYPE_AES256_CTS_HMAC_SHA1_96
+		aes_enctypes = talloc_asprintf_append(
+		    aes_enctypes, "%s", "aes256-cts-hmac-sha1-96 ");
+		if (aes_enctypes == NULL) {
+			goto done;
+		}
+#endif
+#ifdef HAVE_ENCTYPE_AES128_CTS_HMAC_SHA1_96
+		aes_enctypes = talloc_asprintf_append(
+		    aes_enctypes, "%s", "aes128-cts-hmac-sha1-96");
+		if (aes_enctypes == NULL) {
+			goto done;
+		}
+#endif
+	}
+
+	if (lp_kerberos_encryption_types() == KERBEROS_ETYPES_ALL ||
+	    lp_kerberos_encryption_types() == KERBEROS_ETYPES_LEGACY) {
+		legacy_enctypes = "RC4-HMAC DES-CBC-CRC DES-CBC-MD5";
+	}
+
+	enctypes =
+	    talloc_asprintf(mem_ctx, "\tdefault_tgs_enctypes = %s %s\n"
+				     "\tdefault_tkt_enctypes = %s %s\n"
+				     "\tpreferred_enctypes = %s %s\n",
+			    aes_enctypes, legacy_enctypes, aes_enctypes,
+			    legacy_enctypes, aes_enctypes, legacy_enctypes);
+done:
+	TALLOC_FREE(aes_enctypes);
+	return enctypes;
+}
+#else /* Heimdal version */
+static char *get_enctypes(TALLOC_CTX *mem_ctx)
+{
+	const char *aes_enctypes = "";
+	const char *legacy_enctypes = "";
+	char *enctypes = NULL;
+
+	if (lp_kerberos_encryption_types() == KERBEROS_ETYPES_ALL ||
+	    lp_kerberos_encryption_types() == KERBEROS_ETYPES_STRONG) {
+		aes_enctypes =
+		    "aes256-cts-hmac-sha1-96 aes128-cts-hmac-sha1-96";
+	}
+
+	if (lp_kerberos_encryption_types() == KERBEROS_ETYPES_ALL ||
+	    lp_kerberos_encryption_types() == KERBEROS_ETYPES_LEGACY) {
+		legacy_enctypes = "arcfour-hmac-md5 des-cbc-crc des-cbc-md5";
+	}
+
+	enctypes = talloc_asprintf(mem_ctx, "\tdefault_etypes = %s %s\n",
+				   aes_enctypes, legacy_enctypes);
+
+	return enctypes;
+}
+#endif
+
 bool create_local_private_krb5_conf_for_domain(const char *realm,
 						const char *domain,
 						const char *sitename,
@@ -828,7 +898,7 @@ bool create_local_private_krb5_conf_for_domain(const char *realm,
 	int fd;
 	char *realm_upper = NULL;
 	bool result = false;
-	char *aes_enctypes = NULL;
+	char *enctypes = NULL;
 	mode_t mask;
 
 	if (!lp_create_krb5_conf()) {
@@ -879,34 +949,18 @@ bool create_local_private_krb5_conf_for_domain(const char *realm,
 		goto done;
 	}
 
-	aes_enctypes = talloc_strdup(fname, "");
-	if (aes_enctypes == NULL) {
+	enctypes = get_enctypes(fname);
+	if (enctypes == NULL) {
 		goto done;
 	}
 
-#ifdef HAVE_ENCTYPE_AES256_CTS_HMAC_SHA1_96
-	aes_enctypes = talloc_asprintf_append(aes_enctypes, "%s", "aes256-cts-hmac-sha1-96 ");
-	if (aes_enctypes == NULL) {
-		goto done;
-	}
-#endif
-#ifdef HAVE_ENCTYPE_AES128_CTS_HMAC_SHA1_96
-	aes_enctypes = talloc_asprintf_append(aes_enctypes, "%s", "aes128-cts-hmac-sha1-96");
-	if (aes_enctypes == NULL) {
-		goto done;
-	}
-#endif
-
-	file_contents = talloc_asprintf(fname,
-					"[libdefaults]\n\tdefault_realm = %s\n"
-					"\tdefault_tgs_enctypes = %s RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
-					"\tdefault_tkt_enctypes = %s RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
-					"\tpreferred_enctypes = %s RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
-					"\tdns_lookup_realm = false\n\n"
-					"[realms]\n\t%s = {\n"
-					"%s\t}\n",
-					realm_upper, aes_enctypes, aes_enctypes, aes_enctypes,
-					realm_upper, kdc_ip_string);
+	file_contents =
+	    talloc_asprintf(fname, "[libdefaults]\n\tdefault_realm = %s\n"
+				   "%s"
+				   "\tdns_lookup_realm = false\n\n"
+				   "[realms]\n\t%s = {\n"
+				   "%s\t}\n",
+			    realm_upper, enctypes, realm_upper, kdc_ip_string);
 
 	if (!file_contents) {
 		goto done;
-- 
2.5.5


From edc2d4e7668ae0c8d9a79d587543741c71fb62ac Mon Sep 17 00:00:00 2001
From: Uri Simchoni <uri at samba.org>
Date: Mon, 4 Jul 2016 09:50:33 +0300
Subject: [PATCH 3/4] heimdal: honor conf enctypes when obtaining a service
 ticket

This patch removes part of what's categorized in the code as
"hideous glue", which causes Heimdal to ignore krb5.conf
encryption types, and instead use either the application-
supplied values or the default compile-time values.

Signed-off-by: Uri Simchoni <uri at samba.org>
---
 source4/heimdal/lib/gssapi/krb5/init_sec_context.c | 11 ++++-------
 1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/source4/heimdal/lib/gssapi/krb5/init_sec_context.c b/source4/heimdal/lib/gssapi/krb5/init_sec_context.c
index 0a89ae1..efc4215 100644
--- a/source4/heimdal/lib/gssapi/krb5/init_sec_context.c
+++ b/source4/heimdal/lib/gssapi/krb5/init_sec_context.c
@@ -427,15 +427,12 @@ init_auth
     /*
      * This is hideous glue for (NFS) clients that wants to limit the
      * available enctypes to what it can support (encryption in
-     * kernel). If there is no enctypes selected for this credential,
-     * reset it to the default set of enctypes.
+     * kernel).
      */
     {
-	krb5_enctype *enctypes = NULL;
-
-	if (cred && cred->enctypes)
-	    enctypes = cred->enctypes;
-	krb5_set_default_in_tkt_etypes(context, enctypes);
+	if (cred && cred->enctypes) {
+	    krb5_set_default_in_tkt_etypes(context, cred->enctypes);
+	}
     }
 
     /* canon name if needed for client + target realm */
-- 
2.5.5


From 9b68044eb5da253b8a7959a95f910f85ab98385d Mon Sep 17 00:00:00 2001
From: Uri Simchoni <uri at samba.org>
Date: Tue, 5 Jul 2016 06:07:04 +0300
Subject: [PATCH 4/4] selftest: tests for kerberos encryption types

This test uses tshark and cwrap's packet capturing capability
to observe the Kerberos handshakes and ensure the correct
encryption types are being used.

Signed-off-by: Uri Simchoni <uri at samba.org>
---
 source4/selftest/tests.py                |  3 ++
 testprogs/blackbox/test_client_etypes.sh | 54 ++++++++++++++++++++++++++++++++
 2 files changed, 57 insertions(+)
 create mode 100755 testprogs/blackbox/test_client_etypes.sh

diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py
index 8b2512f..72fc058 100755
--- a/source4/selftest/tests.py
+++ b/source4/selftest/tests.py
@@ -405,6 +405,9 @@ plantestsuite("samba4.blackbox.rfc2307_mapping(ad_dc_ntvfs:local)", "ad_dc_ntvfs
 plantestsuite("samba4.blackbox.chgdcpass", "chgdcpass", [os.path.join(bbdir, "test_chgdcpass.sh"), '$SERVER', "CHGDCPASS\$", '$REALM', '$DOMAIN', '$PREFIX', "aes256-cts-hmac-sha1-96", '$SELFTEST_PREFIX/chgdcpass', smbclient4])
 plantestsuite("samba4.blackbox.samba_upgradedns(chgdcpass:local)", "chgdcpass:local", [os.path.join(bbdir, "test_samba_upgradedns.sh"), '$SERVER', '$REALM', '$PREFIX', '$SELFTEST_PREFIX/chgdcpass'])
 plantestsuite("samba4.blackbox.net_ads(ad_dc:client)", "ad_dc:client", [os.path.join(bbdir, "test_net_ads.sh"), '$DC_SERVER', '$DC_USERNAME', '$DC_PASSWORD', '$PREFIX_ABS'])
+plantestsuite("samba4.blackbox.client_etypes_all(ad_dc:client)", "ad_dc:client", [os.path.join(bbdir, "test_client_etypes.sh"), '$DC_SERVER', '$DC_USERNAME', '$DC_PASSWORD', '$PREFIX_ABS', 'all', '17_18_23'])
+plantestsuite("samba4.blackbox.client_etypes_legacy(ad_dc:client)", "ad_dc:client", [os.path.join(bbdir, "test_client_etypes.sh"), '$DC_SERVER', '$DC_USERNAME', '$DC_PASSWORD', '$PREFIX_ABS', 'legacy', '23'])
+plantestsuite("samba4.blackbox.client_etypes_strong(ad_dc:client)", "ad_dc:client", [os.path.join(bbdir, "test_client_etypes.sh"), '$DC_SERVER', '$DC_USERNAME', '$DC_PASSWORD', '$PREFIX_ABS', 'strong', '17_18'])
 plantestsuite("samba4.blackbox.net_ads_dns(ad_member:local)", "ad_member:local", [os.path.join(bbdir, "test_net_ads_dns.sh"), '$DC_SERVER', '$DC_USERNAME', '$DC_PASSWORD', '$REALM', '$USERNAME', '$PASSWORD'])
 plantestsuite_loadlist("samba4.rpc.echo against NetBIOS alias", "ad_dc_ntvfs", [valgrindify(smbtorture4), "$LISTOPT", "$LOADLIST", 'ncacn_np:$NETBIOSALIAS', '-U$DOMAIN/$USERNAME%$PASSWORD', 'rpc.echo'])
 
diff --git a/testprogs/blackbox/test_client_etypes.sh b/testprogs/blackbox/test_client_etypes.sh
new file mode 100755
index 0000000..a878c81
--- /dev/null
+++ b/testprogs/blackbox/test_client_etypes.sh
@@ -0,0 +1,54 @@
+if [ $# -lt 6 ]; then
+cat <<EOF
+Usage: test_client_etypes.sh DC_SERVER DC_USERNAME DC_PASSWORD PREFIX_ABS ETYPE_CONF EXPECTED
+EOF
+exit 1;
+fi
+
+#requires tshark
+which tshark > /dev/null 2>&1 || exit 0
+
+DC_SERVER=$1
+DC_USERNAME=$2
+DC_PASSWORD=$3
+BASEDIR=$4
+ETYPE_CONF=$5
+EXPECTED_ETYPES="$6"
+
+HOSTNAME=`dd if=/dev/urandom bs=1 count=32 2>/dev/null | sha1sum | cut -b 1-10`
+
+RUNDIR=`pwd`
+cd $BASEDIR
+WORKDIR=`mktemp -d -p .`
+WORKDIR=`basename $WORKDIR`
+cp -a client/* $WORKDIR/
+sed -ri "s@(dir|directory) = (.*)/client/@\1 = \2/$WORKDIR/@" $WORKDIR/client.conf
+sed -ri "s/netbios name = .*/netbios name = $HOSTNAME/" $WORKDIR/client.conf
+rm -f $WORKDIR/private/secrets.tdb
+cd $RUNDIR
+
+failed=0
+
+net_tool="$BINDIR/net -s $BASEDIR/$WORKDIR/client.conf --option=security=ads --option=kerberosencryptiontypes=$ETYPE_CONF"
+pcap_file=$BASEDIR/$WORKDIR/test.pcap
+
+# Load test functions
+. `dirname $0`/subunit.sh
+
+export SOCKET_WRAPPER_PCAP_FILE=$pcap_file
+testit "join" $VALGRIND $net_tool ads join -kU$DC_USERNAME%$DC_PASSWORD || failed=`expr $failed + 1`
+
+testit "testjoin" $VALGRIND $net_tool ads testjoin -kP || failed=`expr $failed + 1`
+
+#The leave command does not use the locally-generated
+#krb5.conf
+export SOCKET_WRAPPER_PCAP_FILE=
+testit "leave" $VALGRIND $net_tool ads leave -U$DC_USERNAME%$DC_PASSWORD || failed=`expr $failed + 1`
+
+actual_types="`tshark -r $pcap_file  -nVY "kerberos" | sed -rn 's/[[:space:]]*ENCTYPE:.*\(([^\)]*)\)$/\1/p' | sort -u | tr '\n' '_' | sed s/_$//`"
+
+testit "verify types" test "x$actual_types" = "x$EXPECTED_ETYPES" || failed=`expr $failed + 1`
+
+rm -rf $BASEDIR/$WORKDIR
+
+exit $failed
-- 
2.5.5



More information about the samba-technical mailing list