summaryrefslogtreecommitdiff
path: root/python/samba/tests/krb5/etype_tests.py
diff options
context:
space:
mode:
Diffstat (limited to 'python/samba/tests/krb5/etype_tests.py')
-rwxr-xr-xpython/samba/tests/krb5/etype_tests.py153
1 files changed, 139 insertions, 14 deletions
diff --git a/python/samba/tests/krb5/etype_tests.py b/python/samba/tests/krb5/etype_tests.py
index f4456c3cb4d..1a16518df94 100755
--- a/python/samba/tests/krb5/etype_tests.py
+++ b/python/samba/tests/krb5/etype_tests.py
@@ -32,6 +32,7 @@ from samba.tests.krb5.rfc4120_constants import (
ARCFOUR_HMAC_MD5,
KDC_ERR_ETYPE_NOSUPP,
)
+import samba.tests.krb5.rfc4120_pyasn1 as krb5_asn1
sys.path.insert(0, "bin/python")
os.environ["PYTHONUNBUFFERED"] = "1"
@@ -39,6 +40,7 @@ os.environ["PYTHONUNBUFFERED"] = "1"
global_asn1_print = False
global_hexdump = False
+des_bits = security.KERB_ENCTYPE_DES_CBC_MD5 | security.KERB_ENCTYPE_DES_CBC_CRC
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
@@ -62,11 +64,15 @@ class EtypeTests(KdcTgsBaseTests):
self.default_supported_enctypes = lp.get(
'kdc default domain supported enctypes')
- def _server_creds(self, supported=None):
+ def _server_creds(self, supported=None, force_nt4_hash=False,
+ account_type=None):
+ if account_type is None:
+ account_type= self.AccountType.COMPUTER
return self.get_cached_creds(
- account_type=self.AccountType.COMPUTER,
+ account_type=account_type,
opts={
'supported_enctypes': supported,
+ 'force_nt4_hash': force_nt4_hash,
})
def only_non_etype_bits_set(self, bits):
@@ -115,14 +121,38 @@ class EtypeTests(KdcTgsBaseTests):
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):
+ for _requested_etypes in requested_etype_cases:
+ _s = str(_requested_etypes)
+ _t = _s.maketrans(",", "_", "( )")
+ requested_etypes = _s.translate(_t)
+
+ for _supported_etypes in supported_etype_cases:
+ if _supported_etypes is None:
+ supported_etypes = "None"
+ else:
+ supported_etypes = f'0x{_supported_etypes:X}'
+
+ for account_type in ["member", "dc"]:
+ if account_type == "dc":
+ _account_type = cls.AccountType.SERVER
+ elif account_type == "member":
+ _account_type = cls.AccountType.COMPUTER
+
+ for stored_type in ["aes_rc4", "rc4_only"]:
+ if stored_type == "aes_rc4":
+ force_nt4_hash = False
+ elif stored_type == "rc4_only":
+ force_nt4_hash = True
+
+ tname = (f'{supported_etypes}_supported_'
+ f'{requested_etypes}_requested_'
+ f'{account_type}_account_'
+ f'stored_{stored_type}')
+ targs = _supported_etypes, _requested_etypes, _account_type, force_nt4_hash
+ cls.generate_dynamic_test('test_etype_as', tname, *targs)
+ cls.generate_dynamic_test('test_etype_tgs', tname, *targs)
+
+ def _test_etype_as_with_args(self, supported_bits, requested_etypes, account_type, force_nt4_hash):
# 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
@@ -151,10 +181,17 @@ class EtypeTests(KdcTgsBaseTests):
# If our fallback smb.conf option is set, force in RC4 support.
virtual_bits |= rc4_bit
+ if force_nt4_hash and not (virtual_bits & rc4_bit):
+ 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
+ if account_type == self.AccountType.SERVER:
+ virtual_bits |= etype_bits
+ expected_error = 0
+
virtual_etypes = KerberosCredentials.bits_to_etypes(virtual_bits)
# The enctype of the session key is the first listed in the request
@@ -169,25 +206,113 @@ class EtypeTests(KdcTgsBaseTests):
# Get the credentials of the client and server accounts.
creds = self.get_client_creds()
- target_creds = self._server_creds(supported=supported_bits)
+ target_creds = self._server_creds(supported=supported_bits,
+ account_type=account_type,
+ force_nt4_hash=force_nt4_hash)
+ if account_type == self.AccountType.SERVER:
+ target_supported_etypes = target_creds.tgs_supported_enctypes
+ target_supported_etypes |= des_bits
+ target_supported_etypes |= etype_bits
+ target_creds.set_tgs_supported_enctypes(target_supported_etypes)
+ supported_bits |= (target_supported_etypes & etype_bits)
- # Perform the TGS-REQ.
+ # 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 not force_nt4_hash and 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
+
+ # Perform the AS-REQ.
ticket = self._as_req(creds, expected_error=expected_error,
target_creds=target_creds,
- etype=requested_etypes)
+ etype=requested_etypes,
+ expected_ticket_etype=expected_etype)
if expected_error:
# There's no more to check. Return.
return
+ # 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)
+
+ def _test_etype_tgs_with_args(self, supported_bits, requested_etypes, account_type, force_nt4_hash):
+ 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 force_nt4_hash and not (virtual_bits & rc4_bit):
+ 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
+
+ if account_type == self.AccountType.SERVER:
+ virtual_bits |= etype_bits
+ expected_error = 0
+
+ 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()
+ tgt = self.get_tgt(creds)
+ target_creds = self._server_creds(supported=supported_bits,
+ account_type=account_type,
+ force_nt4_hash=force_nt4_hash)
+ if account_type == self.AccountType.SERVER:
+ target_supported_etypes = target_creds.tgs_supported_enctypes
+ target_supported_etypes |= des_bits
+ target_supported_etypes |= etype_bits
+ target_creds.set_tgs_supported_enctypes(target_supported_etypes)
+ supported_bits |= (target_supported_etypes & etype_bits)
+
# 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 not force_nt4_hash and 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
+ # Perform the TGS-REQ.
+ ticket = self._tgs_req(tgt, expected_error=expected_error,
+ target_creds=target_creds,
+ kdc_options=str(krb5_asn1.KDCOptions('canonicalize')),
+ expected_supported_etypes=target_creds.tgs_supported_enctypes,
+ expected_ticket_etype=expected_etype,
+ etypes=requested_etypes)
+ if expected_error:
+ # There's no more to check. Return.
+ return
+
# 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)