summaryrefslogtreecommitdiff
path: root/python/samba
diff options
context:
space:
mode:
authorJoseph Sutton <josephsutton@catalyst.net.nz>2022-11-18 12:11:39 +1300
committerStefan Metzmacher <metze@samba.org>2022-12-14 11:39:17 +0000
commit64bfe0ef7868b23e12f465ca9a37f8a8ee161a70 (patch)
treed614ec1af20031e5fda913ac2186af4c45782813 /python/samba
parent123b3c056af8dc3e024e22e49be6d8dd54b29b49 (diff)
downloadsamba-64bfe0ef7868b23e12f465ca9a37f8a8ee161a70.tar.gz
CVE-2022-37966 selftest: Add tests for Kerberos session key behaviour since ENC_HMAC_SHA1_96_AES256_SK was added
ENC_HMAC_SHA1_96_AES256_SK is a flag introduced for by Microsoft in this CVE to indicate that additionally, AES session keys are available. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15237 Pair-Programmed-With: Andrew Bartlett <abartlet@samba.org> Signed-off-by: Andrew Bartlett <abartlet@samba.org> Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz> Reviewed-by: Stefan Metzmacher <metze@samba.org> (similar to commit 371d7e63fcb966ab54915a3dedb888d48adbf0c0) [jsutton@samba.org Removed unneeded fast_tests.py change, added non_etype_bits in raw_testcase.py, fixed conflicts in knownfails and tests.py]
Diffstat (limited to 'python/samba')
-rwxr-xr-xpython/samba/tests/krb5/etype_tests.py418
-rw-r--r--python/samba/tests/krb5/kdc_base_test.py60
-rwxr-xr-xpython/samba/tests/krb5/kdc_tgs_tests.py45
-rw-r--r--python/samba/tests/krb5/raw_testcase.py29
-rw-r--r--python/samba/tests/krb5/rfc4120_constants.py1
-rwxr-xr-xpython/samba/tests/krb5/s4u_tests.py3
6 files changed, 424 insertions, 132 deletions
diff --git a/python/samba/tests/krb5/etype_tests.py b/python/samba/tests/krb5/etype_tests.py
index 37dab1eab8d..f4456c3cb4d 100755
--- a/python/samba/tests/krb5/etype_tests.py
+++ b/python/samba/tests/krb5/etype_tests.py
@@ -17,13 +17,17 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
+import itertools
import sys
import os
from samba.dcerpc import security
+from samba.tests import DynamicTestCase
from samba.tests.krb5.kdc_tgs_tests import KdcTgsBaseTests
+from samba.tests.krb5.raw_testcase import KerberosCredentials
from samba.tests.krb5.rfc4120_constants import (
+ AES128_CTS_HMAC_SHA1_96,
AES256_CTS_HMAC_SHA1_96,
ARCFOUR_HMAC_MD5,
KDC_ERR_ETYPE_NOSUPP,
@@ -35,48 +39,165 @@ os.environ["PYTHONUNBUFFERED"] = "1"
global_asn1_print = False
global_hexdump = False
+rc4_bit = security.KERB_ENCTYPE_RC4_HMAC_MD5
+aes128_bit = security.KERB_ENCTYPE_AES128_CTS_HMAC_SHA1_96
+aes256_bit = security.KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96
+aes256_sk_bit = security.KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96_SK
+fast_bit = security.KERB_ENCTYPE_FAST_SUPPORTED
+etype_bits = rc4_bit | aes128_bit | aes256_bit
+extra_bits = aes256_sk_bit | fast_bit
+
+
+@DynamicTestCase
class EtypeTests(KdcTgsBaseTests):
def setUp(self):
super().setUp()
self.do_asn1_print = global_asn1_print
self.do_hexdump = global_hexdump
- # Perform an AS-REQ for a service ticket, specifying AES. The request
- # should fail with an error.
- def test_as_aes_requested(self):
- creds = self.get_mach_creds()
- target_creds = self.get_service_creds()
+ self.default_supported_enctypes = self.default_etypes
+ if self.default_supported_enctypes is None:
+ lp = self.get_lp()
+ self.default_supported_enctypes = lp.get(
+ 'kdc default domain supported enctypes')
- self._as_req(creds, expected_error=KDC_ERR_ETYPE_NOSUPP,
- target_creds=target_creds,
- etype=(AES256_CTS_HMAC_SHA1_96,))
-
- # Perform an AS-REQ for a service ticket, specifying RC4. The resulting
- # ticket should be encrypted with RC4, with an RC4 session key.
- def test_as_rc4_requested(self):
- creds = self.get_mach_creds()
- target_creds = self.get_service_creds()
+ def _server_creds(self, supported=None):
+ return self.get_cached_creds(
+ account_type=self.AccountType.COMPUTER,
+ opts={
+ 'supported_enctypes': supported,
+ })
- ticket = self._as_req(creds, expected_error=0,
+ def only_non_etype_bits_set(self, bits):
+ return bits is not None and (
+ bits & extra_bits and
+ not (bits & etype_bits))
+
+ @classmethod
+ def setUpDynamicTestCases(cls):
+ all_etypes = (AES256_CTS_HMAC_SHA1_96,
+ AES128_CTS_HMAC_SHA1_96,
+ ARCFOUR_HMAC_MD5)
+
+ # An iterator yielding all permutations consisting of at least one
+ # etype.
+ requested_etype_cases = itertools.chain.from_iterable(
+ itertools.permutations(all_etypes, x)
+ for x in range(1, len(all_etypes) + 1))
+
+ # Some combinations of msDS-SupportedEncryptionTypes bits to be set on
+ # the target server.
+ supported_etype_cases = (
+ # Not set.
+ None,
+ # Every possible combination of RC4, AES128, AES256, and AES256-SK.
+ 0,
+ rc4_bit,
+ aes256_sk_bit,
+ aes256_sk_bit | rc4_bit,
+ aes256_bit,
+ aes256_bit | rc4_bit,
+ aes256_bit | aes256_sk_bit,
+ aes256_bit | aes256_sk_bit | rc4_bit,
+ aes128_bit,
+ aes128_bit | rc4_bit,
+ aes128_bit | aes256_sk_bit,
+ aes128_bit | aes256_sk_bit | rc4_bit,
+ aes128_bit | aes256_bit,
+ aes128_bit | aes256_bit | rc4_bit,
+ aes128_bit | aes256_bit | aes256_sk_bit,
+ aes128_bit | aes256_bit | aes256_sk_bit | rc4_bit,
+ # Some combinations with an extra bit (the FAST-supported bit) set.
+ fast_bit,
+ fast_bit | rc4_bit,
+ fast_bit | aes256_sk_bit,
+ fast_bit | aes256_bit,
+ )
+
+ for requested_etypes in requested_etype_cases:
+ for supported_etypes in supported_etype_cases:
+ tname = (f'{supported_etypes}_supported_'
+ f'{requested_etypes}_requested')
+ targs = supported_etypes, requested_etypes
+ cls.generate_dynamic_test('test_etype_as', tname, *targs)
+
+ def _test_etype_as_with_args(self, supported_bits, requested_etypes):
+ # The ticket will be encrypted with the strongest enctype for which the
+ # server explicitly declares support, falling back to RC4 if the server
+ # has no declared supported encryption types. The enctype of the
+ # session key is the first enctype listed in the request that the
+ # server supports, taking the AES-SK bit as an indication of support
+ # for both AES types.
+
+ # If none of the enctypes in the request are supported by the target
+ # server, implicitly or explicitly, return ETYPE_NOSUPP.
+
+ expected_error = 0
+
+ if not supported_bits:
+ # If msDS-SupportedEncryptionTypes is missing or set to zero, the
+ # default value, provided by smb.conf, is assumed.
+ supported_bits = self.default_supported_enctypes
+
+ # If msDS-SupportedEncryptionTypes specifies only non-etype bits, we
+ # expect an error.
+ if self.only_non_etype_bits_set(supported_bits):
+ expected_error = KDC_ERR_ETYPE_NOSUPP
+
+ virtual_bits = supported_bits
+
+ if self.forced_rc4 and not (virtual_bits & rc4_bit):
+ # If our fallback smb.conf option is set, force in RC4 support.
+ virtual_bits |= rc4_bit
+
+ if virtual_bits & aes256_sk_bit:
+ # If strong session keys are enabled, force in the AES bits.
+ virtual_bits |= aes256_bit | aes128_bit
+
+ virtual_etypes = KerberosCredentials.bits_to_etypes(virtual_bits)
+
+ # The enctype of the session key is the first listed in the request
+ # that the server supports, implicitly or explicitly.
+ for requested_etype in requested_etypes:
+ if requested_etype in virtual_etypes:
+ expected_session_etype = requested_etype
+ break
+ else:
+ # If there is no such enctype, expect an error.
+ expected_error = KDC_ERR_ETYPE_NOSUPP
+
+ # Get the credentials of the client and server accounts.
+ creds = self.get_client_creds()
+ target_creds = self._server_creds(supported=supported_bits)
+
+ # Perform the TGS-REQ.
+ ticket = self._as_req(creds, expected_error=expected_error,
target_creds=target_creds,
- etype=(ARCFOUR_HMAC_MD5,))
-
- self.assertEqual(ARCFOUR_HMAC_MD5, ticket.decryption_key.etype)
- self.assertEqual(ARCFOUR_HMAC_MD5, ticket.session_key.etype)
+ etype=requested_etypes)
+ if expected_error:
+ # There's no more to check. Return.
+ return
+
+ # We expect the ticket etype to be the strongest the server claims to
+ # support, with a fallback to RC4.
+ expected_etype = ARCFOUR_HMAC_MD5
+ if supported_bits is not None:
+ if supported_bits & aes256_bit:
+ expected_etype = AES256_CTS_HMAC_SHA1_96
+ elif supported_bits & aes128_bit:
+ expected_etype = AES128_CTS_HMAC_SHA1_96
+
+ # Check the etypes of the ticket and session key.
+ self.assertEqual(expected_etype, ticket.decryption_key.etype)
+ self.assertEqual(expected_session_etype, ticket.session_key.etype)
# Perform an AS-REQ for a service ticket, specifying AES, when the target
# service only supports AES. The resulting ticket should be encrypted with
# AES, with an AES session key.
def test_as_aes_supported_aes_requested(self):
- creds = self.get_mach_creds()
-
- target_creds = self.get_cached_creds(
- account_type=self.AccountType.COMPUTER,
- opts={
- 'supported_enctypes':
- security.KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96,
- })
+ creds = self.get_client_creds()
+ target_creds = self._server_creds(supported=aes256_bit)
ticket = self._as_req(creds, expected_error=0,
target_creds=target_creds,
@@ -86,36 +207,71 @@ class EtypeTests(KdcTgsBaseTests):
self.assertEqual(AES256_CTS_HMAC_SHA1_96, ticket.session_key.etype)
# Perform an AS-REQ for a service ticket, specifying RC4, when the target
- # service only supports AES. The resulting ticket should be encrypted with
- # AES, with an RC4 session key.
+ # service only supports AES. The request should fail with an error.
def test_as_aes_supported_rc4_requested(self):
- creds = self.get_mach_creds()
+ creds = self.get_client_creds()
+ target_creds = self._server_creds(supported=aes256_bit)
- target_creds = self.get_cached_creds(
- account_type=self.AccountType.COMPUTER,
- opts={
- 'supported_enctypes':
- security.KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96,
- })
+ if self.forced_rc4:
+ expected_error = 0
+ expected_session_etype = ARCFOUR_HMAC_MD5
+ else:
+ expected_error = KDC_ERR_ETYPE_NOSUPP
+ expected_session_etype = AES256_CTS_HMAC_SHA1_96
- ticket = self._as_req(creds, expected_error=0,
+ ticket = self._as_req(creds, expected_error=expected_error,
target_creds=target_creds,
etype=(ARCFOUR_HMAC_MD5,))
+ if not self.forced_rc4:
+ return
+
self.assertEqual(AES256_CTS_HMAC_SHA1_96, ticket.decryption_key.etype)
- self.assertEqual(ARCFOUR_HMAC_MD5, ticket.session_key.etype)
+ self.assertEqual(expected_session_etype, ticket.session_key.etype)
+
+ # Perform an AS-REQ for a service ticket, specifying AES, when the target
+ # service only supports AES, and supports AES256 session keys. The
+ # resulting ticket should be encrypted with AES, with an AES session key.
+ def test_as_aes_supported_aes_session_aes_requested(self):
+ creds = self.get_client_creds()
+ target_creds = self._server_creds(supported=aes256_bit | aes256_sk_bit)
+
+ ticket = self._as_req(creds, expected_error=0,
+ target_creds=target_creds,
+ etype=(AES256_CTS_HMAC_SHA1_96,))
+
+ self.assertEqual(AES256_CTS_HMAC_SHA1_96, ticket.decryption_key.etype)
+ self.assertEqual(AES256_CTS_HMAC_SHA1_96, ticket.session_key.etype)
+
+ # Perform an AS-REQ for a service ticket, specifying RC4, when the target
+ # service only supports AES, and supports AES256 session keys. The request
+ # should fail with an error.
+ def test_as_aes_supported_aes_session_rc4_requested(self):
+ creds = self.get_client_creds()
+ target_creds = self._server_creds(supported=aes256_bit | aes256_sk_bit)
+
+ if self.forced_rc4:
+ expected_error = 0
+ expected_session_etype = ARCFOUR_HMAC_MD5
+ else:
+ expected_error = KDC_ERR_ETYPE_NOSUPP
+ expected_session_etype = AES256_CTS_HMAC_SHA1_96
+
+ ticket = self._as_req(creds, expected_error=expected_error,
+ target_creds=target_creds,
+ etype=(ARCFOUR_HMAC_MD5,))
+
+ if not self.forced_rc4:
+ return
+
+ self.assertEqual(AES256_CTS_HMAC_SHA1_96, ticket.decryption_key.etype)
+ self.assertEqual(expected_session_etype, ticket.session_key.etype)
# Perform an AS-REQ for a service ticket, specifying AES, when the target
# service only supports RC4. The request should fail with an error.
def test_as_rc4_supported_aes_requested(self):
- creds = self.get_mach_creds()
-
- target_creds = self.get_cached_creds(
- account_type=self.AccountType.COMPUTER,
- opts={
- 'supported_enctypes':
- security.KERB_ENCTYPE_RC4_HMAC_MD5,
- })
+ creds = self.get_client_creds()
+ target_creds = self._server_creds(supported=rc4_bit)
self._as_req(creds, expected_error=KDC_ERR_ETYPE_NOSUPP,
target_creds=target_creds,
@@ -125,14 +281,8 @@ class EtypeTests(KdcTgsBaseTests):
# service only supports RC4. The resulting ticket should be encrypted with
# RC4, with an RC4 session key.
def test_as_rc4_supported_rc4_requested(self):
- creds = self.get_mach_creds()
-
- target_creds = self.get_cached_creds(
- account_type=self.AccountType.COMPUTER,
- opts={
- 'supported_enctypes':
- security.KERB_ENCTYPE_RC4_HMAC_MD5,
- })
+ creds = self.get_client_creds()
+ target_creds = self._server_creds(supported=rc4_bit)
ticket = self._as_req(creds, expected_error=0,
target_creds=target_creds,
@@ -141,29 +291,31 @@ class EtypeTests(KdcTgsBaseTests):
self.assertEqual(ARCFOUR_HMAC_MD5, ticket.decryption_key.etype)
self.assertEqual(ARCFOUR_HMAC_MD5, ticket.session_key.etype)
- # Perform a TGS-REQ for a service ticket, specifying AES. The request
- # should fail with an error.
- def test_tgs_aes_requested(self):
- creds = self.get_mach_creds()
- tgt = self.get_tgt(creds)
-
- target_creds = self.get_mach_creds()
+ # Perform an AS-REQ for a service ticket, specifying AES, when the target
+ # service only supports RC4, but supports AES256 session keys. The
+ # resulting ticket should be encrypted with RC4, with an AES256 session
+ # key.
+ def test_as_rc4_supported_aes_session_aes_requested(self):
+ creds = self.get_client_creds()
+ target_creds = self._server_creds(supported=rc4_bit | aes256_sk_bit)
- self._tgs_req(tgt, expected_error=KDC_ERR_ETYPE_NOSUPP,
- target_creds=target_creds,
- etypes=(AES256_CTS_HMAC_SHA1_96,))
+ ticket = self._as_req(creds, expected_error=0,
+ target_creds=target_creds,
+ etype=(AES256_CTS_HMAC_SHA1_96,))
- # Perform a TGS-REQ for a service ticket, specifying RC4. The resulting
- # ticket should be encrypted with RC4, with an RC4 session key.
- def test_tgs_rc4_requested(self):
- creds = self.get_mach_creds()
- tgt = self.get_tgt(creds)
+ self.assertEqual(ARCFOUR_HMAC_MD5, ticket.decryption_key.etype)
+ self.assertEqual(AES256_CTS_HMAC_SHA1_96, ticket.session_key.etype)
- target_creds = self.get_mach_creds()
+ # Perform an AS-REQ for a service ticket, specifying RC4, when the target
+ # service only supports RC4, but supports AES256 session keys. The
+ # resulting ticket should be encrypted with RC4, with an RC4 session key.
+ def test_as_rc4_supported_aes_session_rc4_requested(self):
+ creds = self.get_client_creds()
+ target_creds = self._server_creds(supported=rc4_bit | aes256_sk_bit)
- ticket = self._tgs_req(tgt, expected_error=0,
- target_creds=target_creds,
- etypes=(ARCFOUR_HMAC_MD5,))
+ ticket = self._as_req(creds, expected_error=0,
+ target_creds=target_creds,
+ etype=(ARCFOUR_HMAC_MD5,))
self.assertEqual(ARCFOUR_HMAC_MD5, ticket.decryption_key.etype)
self.assertEqual(ARCFOUR_HMAC_MD5, ticket.session_key.etype)
@@ -172,15 +324,10 @@ class EtypeTests(KdcTgsBaseTests):
# service only supports AES. The resulting ticket should be encrypted with
# AES, with an AES session key.
def test_tgs_aes_supported_aes_requested(self):
- creds = self.get_mach_creds()
+ creds = self.get_client_creds()
tgt = self.get_tgt(creds)
- target_creds = self.get_cached_creds(
- account_type=self.AccountType.COMPUTER,
- opts={
- 'supported_enctypes':
- security.KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96,
- })
+ target_creds = self._server_creds(supported=aes256_bit)
ticket = self._tgs_req(tgt, expected_error=0,
target_creds=target_creds,
@@ -190,38 +337,75 @@ class EtypeTests(KdcTgsBaseTests):
self.assertEqual(AES256_CTS_HMAC_SHA1_96, ticket.session_key.etype)
# Perform a TGS-REQ for a service ticket, specifying RC4, when the target
- # service only supports AES. The resulting ticket should be encrypted with
- # AES, with an RC4 session key.
+ # service only supports AES. The request should fail with an error.
def test_tgs_aes_supported_rc4_requested(self):
- creds = self.get_mach_creds()
+ creds = self.get_client_creds()
tgt = self.get_tgt(creds)
- target_creds = self.get_cached_creds(
- account_type=self.AccountType.COMPUTER,
- opts={
- 'supported_enctypes':
- security.KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96,
- })
+ target_creds = self._server_creds(supported=aes256_bit)
+
+ if self.forced_rc4:
+ expected_error = 0
+ else:
+ expected_error = KDC_ERR_ETYPE_NOSUPP
+
+ ticket = self._tgs_req(tgt, expected_error=expected_error,
+ target_creds=target_creds,
+ etypes=(ARCFOUR_HMAC_MD5,))
+
+ if not self.forced_rc4:
+ return
+
+ self.assertEqual(AES256_CTS_HMAC_SHA1_96, ticket.decryption_key.etype)
+ self.assertEqual(ARCFOUR_HMAC_MD5, ticket.session_key.etype)
+
+ # Perform a TGS-REQ for a service ticket, specifying AES, when the target
+ # service only supports AES, and supports AES256 session keys. The
+ # resulting ticket should be encrypted with AES, with an AES session key.
+ def test_tgs_aes_supported_aes_session_aes_requested(self):
+ creds = self.get_client_creds()
+ tgt = self.get_tgt(creds)
+
+ target_creds = self._server_creds(supported=aes256_bit | aes256_sk_bit)
ticket = self._tgs_req(tgt, expected_error=0,
target_creds=target_creds,
+ etypes=(AES256_CTS_HMAC_SHA1_96,))
+
+ self.assertEqual(AES256_CTS_HMAC_SHA1_96, ticket.decryption_key.etype)
+ self.assertEqual(AES256_CTS_HMAC_SHA1_96, ticket.session_key.etype)
+
+ # Perform a TGS-REQ for a service ticket, specifying RC4, when the target
+ # service only supports AES, and supports AES256 session keys. The request
+ # should fail with an error.
+ def test_tgs_aes_supported_aes_session_rc4_requested(self):
+ creds = self.get_client_creds()
+ tgt = self.get_tgt(creds)
+
+ target_creds = self._server_creds(supported=aes256_bit | aes256_sk_bit)
+
+ if self.forced_rc4:
+ expected_error = 0
+ else:
+ expected_error = KDC_ERR_ETYPE_NOSUPP
+
+ ticket = self._tgs_req(tgt, expected_error=expected_error,
+ target_creds=target_creds,
etypes=(ARCFOUR_HMAC_MD5,))
+ if not self.forced_rc4:
+ return
+
self.assertEqual(AES256_CTS_HMAC_SHA1_96, ticket.decryption_key.etype)
self.assertEqual(ARCFOUR_HMAC_MD5, ticket.session_key.etype)
# Perform a TGS-REQ for a service ticket, specifying AES, when the target
# service only supports RC4. The request should fail with an error.
def test_tgs_rc4_supported_aes_requested(self):
- creds = self.get_mach_creds()
+ creds = self.get_client_creds()
tgt = self.get_tgt(creds)
- target_creds = self.get_cached_creds(
- account_type=self.AccountType.COMPUTER,
- opts={
- 'supported_enctypes':
- security.KERB_ENCTYPE_RC4_HMAC_MD5,
- })
+ target_creds = self._server_creds(supported=rc4_bit)
self._tgs_req(tgt, expected_error=KDC_ERR_ETYPE_NOSUPP,
target_creds=target_creds,
@@ -231,15 +415,43 @@ class EtypeTests(KdcTgsBaseTests):
# service only supports RC4. The resulting ticket should be encrypted with
# RC4, with an RC4 session key.
def test_tgs_rc4_supported_rc4_requested(self):
- creds = self.get_mach_creds()
+ creds = self.get_client_creds()
tgt = self.get_tgt(creds)
- target_creds = self.get_cached_creds(
- account_type=self.AccountType.COMPUTER,
- opts={
- 'supported_enctypes':
- security.KERB_ENCTYPE_RC4_HMAC_MD5,
- })
+ target_creds = self._server_creds(supported=rc4_bit)
+
+ ticket = self._tgs_req(tgt, expected_error=0,
+ target_creds=target_creds,
+ etypes=(ARCFOUR_HMAC_MD5,))
+
+ self.assertEqual(ARCFOUR_HMAC_MD5, ticket.decryption_key.etype)
+ self.assertEqual(ARCFOUR_HMAC_MD5, ticket.session_key.etype)
+
+ # Perform a TGS-REQ for a service ticket, specifying AES, when the target
+ # service only supports RC4, but supports AES256 session keys. The
+ # resulting ticket should be encrypted with RC4, with an AES256 session
+ # key.
+ def test_tgs_rc4_supported_aes_session_aes_requested(self):
+ creds = self.get_client_creds()
+ tgt = self.get_tgt(creds)
+
+ target_creds = self._server_creds(supported=rc4_bit | aes256_sk_bit)
+
+ ticket = self._tgs_req(tgt, expected_error=0,
+ target_creds=target_creds,
+ etypes=(AES256_CTS_HMAC_SHA1_96,))
+
+ self.assertEqual(ARCFOUR_HMAC_MD5, ticket.decryption_key.etype)
+ self.assertEqual(AES256_CTS_HMAC_SHA1_96, ticket.session_key.etype)
+
+ # Perform a TGS-REQ for a service ticket, specifying RC4, when the target
+ # service only supports RC4, but supports AES256 session keys. The
+ # resulting ticket should be encrypted with RC4, with an RC4 session key.
+ def test_tgs_rc4_supported_aes_session_rc4_requested(self):
+ creds = self.get_client_creds()
+ tgt = self.get_tgt(creds)
+
+ target_creds = self._server_creds(supported=rc4_bit | aes256_sk_bit)
ticket = self._tgs_req(tgt, expected_error=0,
target_creds=target_creds,
diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py
index f5bfa68c433..e92049a2ecd 100644
--- a/python/samba/tests/krb5/kdc_base_test.py
+++ b/python/samba/tests/krb5/kdc_base_test.py
@@ -618,7 +618,9 @@ class KDCBaseTest(RawKerberosTest):
for enctype, key in keys.items():
creds.set_forced_key(enctype, key)
- def creds_set_enctypes(self, creds):
+ def creds_set_enctypes(self, creds,
+ extra_bits=None,
+ remove_bits=None):
samdb = self.get_samdb()
res = samdb.search(creds.get_dn(),
@@ -627,7 +629,20 @@ class KDCBaseTest(RawKerberosTest):
supported_enctypes = res[0].get('msDS-SupportedEncryptionTypes', idx=0)
if supported_enctypes is None:
- supported_enctypes = 0
+ supported_enctypes = self.default_etypes
+ if supported_enctypes is None:
+ lp = self.get_lp()
+ supported_enctypes = lp.get('kdc default domain supported enctypes')
+
+ supported_enctypes = int(supported_enctypes)
+
+ if extra_bits is not None:
+ # We need to add in implicit or implied encryption types.
+ supported_enctypes |= extra_bits
+ if remove_bits is not None:
+ # We also need to remove certain bits, such as the non-encryption
+ # type bit aes256-sk.
+ supported_enctypes &= ~remove_bits
creds.set_as_supported_enctypes(supported_enctypes)
creds.set_tgs_supported_enctypes(supported_enctypes)
@@ -958,8 +973,15 @@ class KDCBaseTest(RawKerberosTest):
allow_missing_password=False,
allow_missing_keys=True):
def create_mach_account():
- return self.get_cached_creds(account_type=self.AccountType.COMPUTER,
- opts={'fast_support': True})
+ return self.get_cached_creds(
+ account_type=self.AccountType.COMPUTER,
+ opts={
+ 'fast_support': True,
+ 'supported_enctypes': (
+ security.KERB_ENCTYPE_RC4_HMAC_MD5 |
+ security.KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96_SK
+ ),
+ })
c = self._get_krb5_creds(prefix='MAC',
allow_missing_password=allow_missing_password,
@@ -975,7 +997,11 @@ class KDCBaseTest(RawKerberosTest):
account_type=self.AccountType.COMPUTER,
opts={
'trusted_to_auth_for_delegation': True,
- 'fast_support': True
+ 'fast_support': True,
+ 'supported_enctypes': (
+ security.KERB_ENCTYPE_RC4_HMAC_MD5 |
+ security.KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96_SK
+ ),
})
c = self._get_krb5_creds(prefix='SERVICE',
@@ -1077,7 +1103,13 @@ class KDCBaseTest(RawKerberosTest):
keys = self.get_keys(samdb, dn)
self.creds_set_keys(creds, keys)
- self.creds_set_enctypes(creds)
+ extra_bits = (security.KERB_ENCTYPE_AES128_CTS_HMAC_SHA1_96 |
+ security.KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96)
+ remove_bits = (security.KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96_SK |
+ security.KERB_ENCTYPE_RC4_HMAC_MD5)
+ self.creds_set_enctypes(creds,
+ extra_bits=extra_bits,
+ remove_bits=remove_bits)
return creds
@@ -1170,7 +1202,12 @@ class KDCBaseTest(RawKerberosTest):
keys = self.get_keys(samdb, dn)
self.creds_set_keys(creds, keys)
- self.creds_set_enctypes(creds)
+ extra_bits = (security.KERB_ENCTYPE_AES128_CTS_HMAC_SHA1_96 |
+ security.KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96)
+ remove_bits = security.KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96_SK
+ self.creds_set_enctypes(creds,
+ extra_bits=extra_bits,
+ remove_bits=remove_bits)
return creds
@@ -1212,7 +1249,12 @@ class KDCBaseTest(RawKerberosTest):
keys = self.get_keys(samdb, dn)
self.creds_set_keys(creds, keys)
- self.creds_set_enctypes(creds)
+ extra_bits = (security.KERB_ENCTYPE_AES128_CTS_HMAC_SHA1_96 |
+ security.KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96)
+ remove_bits = security.KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96_SK
+ self.creds_set_enctypes(creds,
+ extra_bits=extra_bits,
+ remove_bits=remove_bits)
return creds
@@ -1255,6 +1297,8 @@ class KDCBaseTest(RawKerberosTest):
if pa['padata-type'] == PADATA_ETYPE_INFO2:
padata_value = pa['padata-value']
break
+ else:
+ self.fail('expected to find ETYPE-INFO2')
etype_info2 = self.der_decode(
padata_value, asn1Spec=krb5_asn1.ETYPE_INFO2())
diff --git a/python/samba/tests/krb5/kdc_tgs_tests.py b/python/samba/tests/krb5/kdc_tgs_tests.py
index f3779099596..1607818de1d 100755
--- a/python/samba/tests/krb5/kdc_tgs_tests.py
+++ b/python/samba/tests/krb5/kdc_tgs_tests.py
@@ -25,7 +25,7 @@ os.environ["PYTHONUNBUFFERED"] = "1"
import ldb
-from samba import dsdb
+from samba import dsdb, ntstatus
from samba.dcerpc import krb5pac, security
@@ -38,7 +38,9 @@ from samba.tests.krb5.rfc4120_constants import (
ARCFOUR_HMAC_MD5,
KRB_ERROR,
KRB_TGS_REP,
+ KDC_ERR_BADKEYVER,
KDC_ERR_BADMATCH,
+ KDC_ERR_ETYPE_NOSUPP,
KDC_ERR_GENERIC,
KDC_ERR_MODIFIED,
KDC_ERR_NOT_US,
@@ -1598,12 +1600,16 @@ class KdcTgsTests(KdcTgsBaseTests):
def test_tgs_rc4(self):
creds = self._get_creds()
tgt = self._get_tgt(creds, etype=kcrypto.Enctype.RC4)
- self._run_tgs(tgt, expected_error=KDC_ERR_GENERIC)
+ self._run_tgs(tgt, expected_error=(KDC_ERR_GENERIC,
+ KDC_ERR_BADKEYVER),
+ expect_edata=True,
+ expected_status=ntstatus.NT_STATUS_INSUFFICIENT_RESOURCES)
def test_renew_rc4(self):
creds = self._get_creds()
tgt = self._get_tgt(creds, renewable=True, etype=kcrypto.Enctype.RC4)
- self._renew_tgt(tgt, expected_error=KDC_ERR_GENERIC,
+ self._renew_tgt(tgt, expected_error=(KDC_ERR_GENERIC,
+ KDC_ERR_BADKEYVER),
expect_pac_attrs=True,
expect_pac_attrs_pac_request=True,
expect_requester_sid=True)
@@ -1611,7 +1617,8 @@ class KdcTgsTests(KdcTgsBaseTests):
def test_validate_rc4(self):
creds = self._get_creds()
tgt = self._get_tgt(creds, invalid=True, etype=kcrypto.Enctype.RC4)
- self._validate_tgt(tgt, expected_error=KDC_ERR_GENERIC,
+ self._validate_tgt(tgt, expected_error=(KDC_ERR_GENERIC,
+ KDC_ERR_BADKEYVER),
expect_pac_attrs=True,
expect_pac_attrs_pac_request=True,
expect_requester_sid=True)
@@ -1619,17 +1626,21 @@ class KdcTgsTests(KdcTgsBaseTests):
def test_s4u2self_rc4(self):
creds = self._get_creds()
tgt = self._get_tgt(creds, etype=kcrypto.Enctype.RC4)
- self._s4u2self(tgt, creds, expected_error=KDC_ERR_GENERIC)
+ self._s4u2self(tgt, creds, expected_error=(KDC_ERR_GENERIC,
+ KDC_ERR_BADKEYVER),
+ expect_edata=True,
+ expected_status=ntstatus.NT_STATUS_INSUFFICIENT_RESOURCES)
def test_user2user_rc4(self):
creds = self._get_creds()
tgt = self._get_tgt(creds, etype=kcrypto.Enctype.RC4)
- self._user2user(tgt, creds, expected_error=KDC_ERR_GENERIC)
+ self._user2user(tgt, creds, expected_error=KDC_ERR_ETYPE_NOSUPP)
def test_fast_rc4(self):
creds = self._get_creds()
tgt = self._get_tgt(creds, etype=kcrypto.Enctype.RC4)
- self._fast(tgt, creds, expected_error=KDC_ERR_GENERIC)
+ self._fast(tgt, creds, expected_error=KDC_ERR_GENERIC,
+ expect_edata=self.expect_padata_outer)
# Test user-to-user with incorrect service principal names.
def test_user2user_matching_sname_host(self):
@@ -2664,7 +2675,7 @@ class KdcTgsTests(KdcTgsBaseTests):
can_modify_requester_sid=can_modify_requester_sid,
remove_pac_attrs=remove_pac_attrs,
remove_requester_sid=remove_requester_sid,
- etype=None,
+ etype=etype,
cksum_etype=cksum_etype)
def _modify_tgt(self,
@@ -2886,7 +2897,8 @@ class KdcTgsTests(KdcTgsBaseTests):
def _run_tgs(self, tgt, expected_error, expect_pac=True,
expect_pac_attrs=None, expect_pac_attrs_pac_request=None,
- expect_requester_sid=None, expected_sid=None):
+ expect_requester_sid=None, expected_sid=None,
+ expect_edata=False, expected_status=None):
target_creds = self.get_service_creds()
return self._tgs_req(
tgt, expected_error, target_creds,
@@ -2894,7 +2906,9 @@ class KdcTgsTests(KdcTgsBaseTests):
expect_pac_attrs=expect_pac_attrs,
expect_pac_attrs_pac_request=expect_pac_attrs_pac_request,
expect_requester_sid=expect_requester_sid,
- expected_sid=expected_sid)
+ expected_sid=expected_sid,
+ expect_edata=expect_edata,
+ expected_status=expected_status)
# These tests fail against Windows, which does not implement ticket
# renewal.
@@ -2958,7 +2972,8 @@ class KdcTgsTests(KdcTgsBaseTests):
expect_pac=expect_pac)
def _user2user(self, tgt, tgt_creds, expected_error, sname=None,
- srealm=None, user_tgt=None, expect_pac=True):
+ srealm=None, user_tgt=None, expect_pac=True,
+ expected_status=None):
if user_tgt is None:
user_creds = self._get_mach_creds()
user_tgt = self.get_tgt(user_creds)
@@ -2969,10 +2984,11 @@ class KdcTgsTests(KdcTgsBaseTests):
additional_ticket=tgt,
sname=sname,
srealm=srealm,
- expect_pac=expect_pac)
+ expect_pac=expect_pac,
+ expected_status=expected_status)
def _fast(self, armor_tgt, armor_tgt_creds, expected_error,
- expected_sname=None, expect_pac=True):
+ expected_sname=None, expect_pac=True, expect_edata=False):
user_creds = self._get_mach_creds()
user_tgt = self.get_tgt(user_creds)
@@ -2981,7 +2997,8 @@ class KdcTgsTests(KdcTgsBaseTests):
return self._tgs_req(user_tgt, expected_error, target_creds,
armor_tgt=armor_tgt,
expected_sname=expected_sname,
- expect_pac=expect_pac)
+ expect_pac=expect_pac,
+ expect_edata=expect_edata)
if __name__ == "__main__":
diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py
index b6752fb2080..f13ada7bbf8 100644
--- a/python/samba/tests/krb5/raw_testcase.py
+++ b/python/samba/tests/krb5/raw_testcase.py
@@ -369,6 +369,10 @@ class KerberosCredentials(Credentials):
security.KERB_ENCTYPE_COMPOUND_IDENTITY_SUPPORTED |
security.KERB_ENCTYPE_CLAIMS_SUPPORTED)
+ non_etype_bits = fast_supported_bits | (
+ security.KERB_ENCTYPE_RESOURCE_SID_COMPRESSION_DISABLED) | (
+ security.KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96_SK)
+
def __init__(self):
super(KerberosCredentials, self).__init__()
all_enc_types = 0
@@ -430,7 +434,7 @@ class KerberosCredentials(Credentials):
bits &= ~bit
etypes += (etype,)
- bits &= ~cls.fast_supported_bits
+ bits &= ~cls.non_etype_bits
if bits != 0:
raise ValueError(f'Unsupported etype bits: {bits}')
@@ -557,6 +561,8 @@ class RawKerberosTest(TestCaseInTempDir):
{"value": kcrypto.Enctype.RC4, "name": "rc4", },
)
+ expect_padata_outer = object()
+
setup_etype_test_permutations_done = False
@classmethod
@@ -686,6 +692,18 @@ class RawKerberosTest(TestCaseInTempDir):
kadmin_is_tgs = '0'
cls.kadmin_is_tgs = bool(int(kadmin_is_tgs))
+ default_etypes = samba.tests.env_get_var_value('DEFAULT_ETYPES',
+ allow_missing=True)
+ if default_etypes is not None:
+ default_etypes = int(default_etypes)
+ cls.default_etypes = default_etypes
+
+ forced_rc4 = samba.tests.env_get_var_value('FORCED_RC4',
+ allow_missing=True)
+ if forced_rc4 is None:
+ forced_rc4 = '0'
+ cls.forced_rc4 = bool(int(forced_rc4))
+
def setUp(self):
super().setUp()
self.do_asn1_print = False
@@ -1299,7 +1317,8 @@ class RawKerberosTest(TestCaseInTempDir):
if etype is None:
etypes = creds.get_tgs_krb5_etypes()
- if etypes:
+ if etypes and etypes[0] not in (kcrypto.Enctype.DES_CRC,
+ kcrypto.Enctype.DES_MD5):
etype = etypes[0]
else:
etype = kcrypto.Enctype.RC4
@@ -3004,10 +3023,6 @@ class RawKerberosTest(TestCaseInTempDir):
if PADATA_SUPPORTED_ETYPES in enc_pa_dict:
expected_supported_etypes = kdc_exchange_dict[
'expected_supported_etypes']
- expected_supported_etypes |= (
- security.KERB_ENCTYPE_DES_CBC_CRC |
- security.KERB_ENCTYPE_DES_CBC_MD5 |
- security.KERB_ENCTYPE_RC4_HMAC_MD5)
(supported_etypes,) = struct.unpack(
'<L',
@@ -3347,6 +3362,8 @@ class RawKerberosTest(TestCaseInTempDir):
and (not sent_fast or fast_armor_type is None
or fast_armor_type == FX_FAST_ARMOR_AP_REQUEST)
and not inner)
+ if inner and expect_edata is self.expect_padata_outer:
+ expect_edata = False
if not expect_edata:
self.assertIsNone(expected_status)
if self.strict_checking:
diff --git a/python/samba/tests/krb5/rfc4120_constants.py b/python/samba/tests/krb5/rfc4120_constants.py
index 16527f13593..7ad336208e2 100644
--- a/python/samba/tests/krb5/rfc4120_constants.py
+++ b/python/samba/tests/krb5/rfc4120_constants.py
@@ -99,6 +99,7 @@ KDC_ERR_NOT_US = 35
KDC_ERR_BADMATCH = 36
KDC_ERR_SKEW = 37
KDC_ERR_MODIFIED = 41
+KDC_ERR_BADKEYVER = 44
KDC_ERR_INAPP_CKSUM = 50
KDC_ERR_GENERIC = 60
KDC_ERR_WRONG_REALM = 68
diff --git a/python/samba/tests/krb5/s4u_tests.py b/python/samba/tests/krb5/s4u_tests.py
index dcdd67e2b64..84b8160bb93 100755
--- a/python/samba/tests/krb5/s4u_tests.py
+++ b/python/samba/tests/krb5/s4u_tests.py
@@ -1095,7 +1095,8 @@ class S4UKerberosTests(KDCBaseTest):
# Attempt to modify the ticket without updating the PAC checksums.
self._run_delegation_test(
{
- 'expected_error_mode': KDC_ERR_MODIFIED,
+ 'expected_error_mode': (KDC_ERR_MODIFIED,
+ KDC_ERR_BAD_INTEGRITY),
'expected_status': ntstatus.NT_STATUS_NOT_SUPPORTED,
'allow_rbcd': True,
'pac_options': '0001', # supports RBCD