python/tests/krb5: Prepare for PKINIT tests with UF_SMARTCARD_REQUIRED
authorAndrew Bartlett <abartlet@samba.org>
Tue, 19 Mar 2024 01:37:24 +0000 (14:37 +1300)
committerAndrew Bartlett <abartlet@samba.org>
Thu, 28 Mar 2024 01:50:41 +0000 (01:50 +0000)
Signed-off-by: Andrew Bartlett <abartlet@samba.org>
Reviewed-by: Jo Sutton <josutton@catalyst.net.nz>
python/samba/tests/krb5/kdc_base_test.py
python/samba/tests/krb5/pkinit_tests.py
python/samba/tests/krb5/raw_testcase.py

index fa3ee15d8d0b0074fcd5239e220a2984fd8231dc..2c278abd3f2dda626f0e9b9b7adc55fcd368c67f 100644 (file)
@@ -86,6 +86,7 @@ from samba.dsdb import (
     UF_SERVER_TRUST_ACCOUNT,
     UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION,
     UF_WORKSTATION_TRUST_ACCOUNT,
+    UF_SMARTCARD_REQUIRED
 )
 from samba.join import DCJoinContext
 from samba.ndr import ndr_pack, ndr_unpack
@@ -920,6 +921,7 @@ class KDCBaseTest(TestCaseInTempDir, RawKerberosTest):
         creds.set_upn(upn)
         creds.set_spn(spn)
         creds.set_type(account_type)
+        creds.set_user_account_control(account_control)
 
         self.creds_set_enctypes(creds)
 
@@ -2005,6 +2007,7 @@ class KDCBaseTest(TestCaseInTempDir, RawKerberosTest):
             'assigned_policy': None,
             'assigned_silo': None,
             'logon_hours': None,
+            'smartcard_required': False
         }
 
         account_opts = {
@@ -2061,7 +2064,8 @@ class KDCBaseTest(TestCaseInTempDir, RawKerberosTest):
                             force_nt4_hash,
                             assigned_policy,
                             assigned_silo,
-                            logon_hours):
+                            logon_hours,
+                            smartcard_required):
         if account_type is self.AccountType.USER:
             self.assertIsNone(delegation_to_spn)
             self.assertIsNone(delegation_from_dn)
@@ -2085,6 +2089,8 @@ class KDCBaseTest(TestCaseInTempDir, RawKerberosTest):
             user_account_control |= UF_NOT_DELEGATED
         if no_auth_data_required:
             user_account_control |= UF_NO_AUTH_DATA_REQUIRED
+        if smartcard_required:
+            user_account_control |= UF_SMARTCARD_REQUIRED
 
         if additional_details:
             details = {k: v for k, v in additional_details}
@@ -2142,7 +2148,16 @@ class KDCBaseTest(TestCaseInTempDir, RawKerberosTest):
                                         preserve=use_cache)
 
         expected_etypes = None
-        if force_nt4_hash:
+
+        # We don't force fetching the keys other than the NT hash as
+        # how the server stores the unused KDC keys for the
+        # smartcard_required case is not important and makes unrelated
+        # tests break because of differences between Samba and
+        # Windows.
+        #
+        # The NT hash is different, as it is returned to the client in
+        # the PAC so is visible in the network behaviour.
+        if force_nt4_hash or smartcard_required:
             expected_etypes = {kcrypto.Enctype.RC4}
         keys = self.get_keys(creds, expected_etypes=expected_etypes)
         self.creds_set_keys(creds, keys)
index effc691beba1ba9eb136e03e2cf0b67349ada975..6aabc08483065f6d6d3b7cf2f60ceed946c4061d 100755 (executable)
@@ -35,7 +35,8 @@ from cryptography.hazmat.primitives.asymmetric import dh, padding
 from cryptography.x509.oid import NameOID
 
 import samba.tests
-from samba.dcerpc import security
+from samba import credentials, generate_random_password, ntstatus
+from samba.dcerpc import security, netlogon
 from samba.tests.krb5 import kcrypto
 from samba.tests.krb5.kdc_base_test import KDCBaseTest
 from samba.tests.krb5.raw_testcase import PkInit, RawKerberosTest
@@ -44,6 +45,7 @@ from samba.tests.krb5.rfc4120_constants import (
     KDC_ERR_CLIENT_NOT_TRUSTED,
     KDC_ERR_ETYPE_NOSUPP,
     KDC_ERR_MODIFIED,
+    KDC_ERR_POLICY,
     KDC_ERR_PREAUTH_EXPIRED,
     KDC_ERR_PREAUTH_FAILED,
     KDC_ERR_PREAUTH_REQUIRED,
@@ -72,7 +74,7 @@ class PkInitTests(KDCBaseTest):
         self.do_asn1_print = global_asn1_print
         self.do_hexdump = global_hexdump
 
-    def _get_creds(self, account_type=KDCBaseTest.AccountType.USER):
+    def _get_creds(self, account_type=KDCBaseTest.AccountType.USER, use_cache=False, smartcard_required=False):
         """Return credentials with an account having a UPN for performing
         PK-INIT."""
         samdb = self.get_samdb()
@@ -80,7 +82,9 @@ class PkInitTests(KDCBaseTest):
 
         return self.get_cached_creds(
             account_type=account_type,
-            opts={'upn': f'{{account}}.{realm}@{realm}'})
+            opts={'upn': f'{{account}}.{realm}@{realm}',
+                  'smartcard_required': smartcard_required},
+            use_cache=use_cache)
 
     def test_pkinit_no_des3(self):
         """Test public-key PK-INIT without specifying the DES3 encryption
@@ -571,6 +575,8 @@ class PkInitTests(KDCBaseTest):
                 target_creds,
                 *,
                 expect_error=0,
+                expect_status=False,
+                expected_status=None,
                 expect_edata=False,
                 etypes=None,
                 freshness=None,
@@ -659,7 +665,9 @@ class PkInitTests(KDCBaseTest):
             expected_salt=creds.get_salt(),
             preauth_key=preauth_key,
             kdc_options=str(kdc_options),
-            expect_edata=expect_edata)
+            expect_edata=expect_edata,
+            expect_status=expect_status,
+            expected_status=expected_status)
 
         till = self.get_KerberosTime(offset=36000)
 
index 7fe11387bac02fa6d595e24be058124b949931ee..72e5f41cfaa935a9219957e8055d8e357a1921b7 100644 (file)
@@ -54,7 +54,9 @@ from samba.dcerpc.misc import (
     SEC_CHAN_WKSTA,
     SEC_CHAN_BDC,
 )
-
+from samba.dsdb import (
+    UF_SMARTCARD_REQUIRED
+)
 import samba.tests
 from samba.tests import TestCase
 
@@ -408,6 +410,7 @@ class KerberosCredentials(Credentials):
         'spn',
         'tgs_supported_enctypes',
         'upn',
+        'user_account_control'
     ]
 
     non_etype_bits = (
@@ -439,6 +442,8 @@ class KerberosCredentials(Credentials):
         self.sid = None
         self.account_type = None
 
+        self.user_account_control = None
+
         self._private_key = None
 
     def set_as_supported_enctypes(self, value):
@@ -450,6 +455,9 @@ class KerberosCredentials(Credentials):
     def set_ap_supported_enctypes(self, value):
         self.ap_supported_enctypes = int(value)
 
+    def set_user_account_control(self, value):
+        self.user_account_control = int(value)
+
     etype_map = collections.OrderedDict([
         (kcrypto.Enctype.AES256,
             security.KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96),
@@ -4772,7 +4780,10 @@ class RawKerberosTest(TestCase):
 
                 creds = kdc_exchange_dict['creds']
                 nt_password = bytes(ntlm_package.nt_password.hash)
-                self.assertEqual(creds.get_nt_hash(), nt_password)
+                if creds.user_account_control & UF_SMARTCARD_REQUIRED:
+                    self.assertNotEqual(creds.get_nt_hash(), nt_password)
+                else:
+                    self.assertEqual(creds.get_nt_hash(), nt_password)
 
                 lm_password = bytes(ntlm_package.lm_password.hash)
                 self.assertEqual(bytes(16), lm_password)