summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoseph Sutton <josephsutton@catalyst.net.nz>2022-11-09 13:45:13 +1300
committerStefan Metzmacher <metze@samba.org>2022-12-14 00:48:48 +0100
commitd775f1ed43a1c130b08636ad428a0f07fa88b31e (patch)
treec23ee07297af88e57921d63f9063be9210825c75
parent4650ce1fa5ce1f1da46829bd95bffbb748ed90ca (diff)
downloadsamba-d775f1ed43a1c130b08636ad428a0f07fa88b31e.tar.gz
CVE-2022-37967 Add new PAC checksum
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15231 Pair-Programmed-With: Andrew Bartlett <abartlet@samba.org> Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz> Signed-off-by: Andrew Bartlett <abartlet@samba.org> Reviewed-by: Stefan Metzmacher <metze@samba.org> (similar to commit a50a2be622afaa7a280312ea12f5eb9c9a0c41da) [jsutton@samba.org Fixed conflicts in krb5pac.idl and raw_testcase.py] [jsutton@samba.org Fixed conflicts in kdc_base_test.py, raw_testcase.py, knownfails, tests.py. Adapted KDC PAC changes to older function.] [jsutton@samba.org Fixed conflict in raw_testcase.py; adapted to older Heimdal version]
-rw-r--r--librpc/idl/krb5pac.idl4
-rwxr-xr-xpython/samba/tests/krb5/compatability_tests.py22
-rw-r--r--python/samba/tests/krb5/kdc_base_test.py3
-rwxr-xr-xpython/samba/tests/krb5/kdc_tgs_tests.py59
-rw-r--r--python/samba/tests/krb5/raw_testcase.py78
-rwxr-xr-xpython/samba/tests/krb5/rodc_tests.py4
-rwxr-xr-xpython/samba/tests/krb5/s4u_tests.py61
-rw-r--r--selftest/knownfail_mit_kdc13
-rw-r--r--source4/heimdal/kdc/kerberos5.c1
-rw-r--r--source4/heimdal/kdc/krb5tgs.c2
-rw-r--r--source4/heimdal/lib/krb5/pac.c172
-rw-r--r--source4/kdc/wdc-samba4.c23
-rwxr-xr-xsource4/selftest/tests.py11
-rw-r--r--source4/torture/rpc/remote_pac.c14
14 files changed, 413 insertions, 54 deletions
diff --git a/librpc/idl/krb5pac.idl b/librpc/idl/krb5pac.idl
index bbe4a253e3a..a21533fdc3c 100644
--- a/librpc/idl/krb5pac.idl
+++ b/librpc/idl/krb5pac.idl
@@ -146,7 +146,8 @@ interface krb5pac
PAC_TYPE_DEVICE_CLAIMS_INFO = 15,
PAC_TYPE_TICKET_CHECKSUM = 16,
PAC_TYPE_ATTRIBUTES_INFO = 17,
- PAC_TYPE_REQUESTER_SID = 18
+ PAC_TYPE_REQUESTER_SID = 18,
+ PAC_TYPE_FULL_CHECKSUM = 19
} PAC_TYPE;
typedef struct {
@@ -165,6 +166,7 @@ interface krb5pac
[case(PAC_TYPE_TICKET_CHECKSUM)] PAC_SIGNATURE_DATA ticket_checksum;
[case(PAC_TYPE_ATTRIBUTES_INFO)] PAC_ATTRIBUTES_INFO attributes_info;
[case(PAC_TYPE_REQUESTER_SID)] PAC_REQUESTER_SID requester_sid;
+ [case(PAC_TYPE_FULL_CHECKSUM)] PAC_SIGNATURE_DATA full_checksum;
/* when new PAC info types are added they are supposed to be done
in such a way that they are backwards compatible with existing
servers. This makes it safe to just use a [default] for
diff --git a/python/samba/tests/krb5/compatability_tests.py b/python/samba/tests/krb5/compatability_tests.py
index 65e9e3788d5..43f9c7ebcec 100755
--- a/python/samba/tests/krb5/compatability_tests.py
+++ b/python/samba/tests/krb5/compatability_tests.py
@@ -162,6 +162,28 @@ class SimpleKerberosTests(KDCBaseTest):
self.verify_ticket(service_ticket, key, service_ticket=True,
expect_ticket_checksum=False)
+ def test_full_signature(self):
+ # Ensure that a DC correctly issues tickets signed with its krbtgt key.
+ user_creds = self.get_client_creds()
+ target_creds = self.get_service_creds()
+
+ krbtgt_creds = self.get_krbtgt_creds()
+ key = self.TicketDecryptionKey_from_creds(krbtgt_creds)
+
+ # Get a TGT from the DC.
+ tgt = self.get_tgt(user_creds)
+
+ # Ensure the PAC contains the expected checksums.
+ self.verify_ticket(tgt, key, service_ticket=False)
+
+ # Get a service ticket from the DC.
+ service_ticket = self.get_service_ticket(tgt, target_creds)
+
+ # Ensure the PAC contains the expected checksums.
+ self.verify_ticket(service_ticket, key, service_ticket=True,
+ expect_ticket_checksum=True,
+ expect_full_checksum=True)
+
def as_pre_auth_req(self, creds, etypes):
user = creds.get_username()
realm = creds.get_realm()
diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py
index 0a61efef7bf..05b82a17b16 100644
--- a/python/samba/tests/krb5/kdc_base_test.py
+++ b/python/samba/tests/krb5/kdc_base_test.py
@@ -1423,7 +1423,8 @@ class KDCBaseTest(RawKerberosTest):
krbtgt_key = self.TicketDecryptionKey_from_creds(krbtgt_creds)
self.verify_ticket(service_ticket_creds, krbtgt_key,
service_ticket=True, expect_pac=expect_pac,
- expect_ticket_checksum=self.tkt_sig_support)
+ expect_ticket_checksum=self.tkt_sig_support,
+ expect_full_checksum=self.full_sig_support)
self.tkt_cache[cache_key] = service_ticket_creds
diff --git a/python/samba/tests/krb5/kdc_tgs_tests.py b/python/samba/tests/krb5/kdc_tgs_tests.py
index 7239e0be8db..78f88c0898e 100755
--- a/python/samba/tests/krb5/kdc_tgs_tests.py
+++ b/python/samba/tests/krb5/kdc_tgs_tests.py
@@ -1360,6 +1360,43 @@ class KdcTgsTests(KdcTgsBaseTests):
self._fast(tgt, creds, expected_error=KDC_ERR_TGT_REVOKED,
expected_sname=self.get_krbtgt_sname())
+ # Test making a TGS request with an RC4-encrypted TGT.
+ 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)
+
+ 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,
+ expect_pac_attrs=True,
+ expect_pac_attrs_pac_request=True,
+ expect_requester_sid=True)
+
+ 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,
+ expect_pac_attrs=True,
+ expect_pac_attrs_pac_request=True,
+ expect_requester_sid=True)
+
+ 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)
+
+ 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)
+
+ 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)
+
# Test user-to-user with incorrect service principal names.
def test_user2user_matching_sname_host(self):
creds = self._get_creds()
@@ -2370,7 +2407,9 @@ class KdcTgsTests(KdcTgsBaseTests):
can_modify_logon_info=True,
can_modify_requester_sid=True,
remove_pac_attrs=False,
- remove_requester_sid=False):
+ remove_requester_sid=False,
+ etype=None,
+ cksum_etype=None):
self.assertFalse(renewable and invalid)
if remove_pac:
@@ -2389,7 +2428,9 @@ class KdcTgsTests(KdcTgsBaseTests):
can_modify_logon_info=can_modify_logon_info,
can_modify_requester_sid=can_modify_requester_sid,
remove_pac_attrs=remove_pac_attrs,
- remove_requester_sid=remove_requester_sid)
+ remove_requester_sid=remove_requester_sid,
+ etype=None,
+ cksum_etype=cksum_etype)
def _modify_tgt(self,
tgt,
@@ -2404,7 +2445,9 @@ class KdcTgsTests(KdcTgsBaseTests):
can_modify_logon_info=True,
can_modify_requester_sid=True,
remove_pac_attrs=False,
- remove_requester_sid=False):
+ remove_requester_sid=False,
+ etype=None,
+ cksum_etype=None):
if from_rodc:
krbtgt_creds = self.get_mock_rodc_krbtgt_creds()
else:
@@ -2443,13 +2486,19 @@ class KdcTgsTests(KdcTgsBaseTests):
else:
change_sid_fn = None
- krbtgt_key = self.TicketDecryptionKey_from_creds(krbtgt_creds)
+ krbtgt_key = self.TicketDecryptionKey_from_creds(krbtgt_creds,
+ etype)
if remove_pac:
checksum_keys = None
else:
+ if etype == cksum_etype:
+ cksum_key = krbtgt_key
+ else:
+ cksum_key = self.TicketDecryptionKey_from_creds(krbtgt_creds,
+ cksum_etype)
checksum_keys = {
- krb5pac.PAC_TYPE_KDC_CHECKSUM: krbtgt_key
+ krb5pac.PAC_TYPE_KDC_CHECKSUM: cksum_key
}
if renewable:
diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py
index e530a6b17bc..bda5f31a203 100644
--- a/python/samba/tests/krb5/raw_testcase.py
+++ b/python/samba/tests/krb5/raw_testcase.py
@@ -538,7 +538,8 @@ class RawKerberosTest(TestCaseInTempDir):
pac_checksum_types = {krb5pac.PAC_TYPE_SRV_CHECKSUM,
krb5pac.PAC_TYPE_KDC_CHECKSUM,
- krb5pac.PAC_TYPE_TICKET_CHECKSUM}
+ krb5pac.PAC_TYPE_TICKET_CHECKSUM,
+ krb5pac.PAC_TYPE_FULL_CHECKSUM}
etypes_to_test = (
{"value": -1111, "name": "dummy", },
@@ -632,6 +633,12 @@ class RawKerberosTest(TestCaseInTempDir):
tkt_sig_support = '0'
cls.tkt_sig_support = bool(int(tkt_sig_support))
+ full_sig_support = samba.tests.env_get_var_value('FULL_SIG_SUPPORT',
+ allow_missing=True)
+ if full_sig_support is None:
+ full_sig_support = '0'
+ cls.full_sig_support = bool(int(full_sig_support))
+
expect_pac = samba.tests.env_get_var_value('EXPECT_PAC',
allow_missing=True)
if expect_pac is None:
@@ -2370,6 +2377,7 @@ class RawKerberosTest(TestCaseInTempDir):
unexpected_flags=None,
ticket_decryption_key=None,
expect_ticket_checksum=None,
+ expect_full_checksum=None,
generate_fast_fn=None,
generate_fast_armor_fn=None,
generate_fast_padata_fn=None,
@@ -2427,6 +2435,7 @@ class RawKerberosTest(TestCaseInTempDir):
'unexpected_flags': unexpected_flags,
'ticket_decryption_key': ticket_decryption_key,
'expect_ticket_checksum': expect_ticket_checksum,
+ 'expect_full_checksum': expect_full_checksum,
'generate_fast_fn': generate_fast_fn,
'generate_fast_armor_fn': generate_fast_armor_fn,
'generate_fast_padata_fn': generate_fast_padata_fn,
@@ -2480,6 +2489,7 @@ class RawKerberosTest(TestCaseInTempDir):
unexpected_flags=None,
ticket_decryption_key=None,
expect_ticket_checksum=None,
+ expect_full_checksum=None,
generate_fast_fn=None,
generate_fast_armor_fn=None,
generate_fast_padata_fn=None,
@@ -2538,6 +2548,7 @@ class RawKerberosTest(TestCaseInTempDir):
'unexpected_flags': unexpected_flags,
'ticket_decryption_key': ticket_decryption_key,
'expect_ticket_checksum': expect_ticket_checksum,
+ 'expect_full_checksum': expect_full_checksum,
'generate_fast_fn': generate_fast_fn,
'generate_fast_armor_fn': generate_fast_armor_fn,
'generate_fast_padata_fn': generate_fast_padata_fn,
@@ -2991,7 +3002,8 @@ class RawKerberosTest(TestCaseInTempDir):
self.check_pac_buffers(pac_data, kdc_exchange_dict)
expect_ticket_checksum = kdc_exchange_dict['expect_ticket_checksum']
- if expect_ticket_checksum:
+ expect_full_checksum = kdc_exchange_dict['expect_full_checksum']
+ if expect_ticket_checksum or expect_full_checksum:
self.assertIsNotNone(ticket_decryption_key)
if ticket_decryption_key is not None:
@@ -3001,7 +3013,9 @@ class RawKerberosTest(TestCaseInTempDir):
service_ticket=service_ticket,
expect_pac=expect_pac,
expect_ticket_checksum=expect_ticket_checksum
- or self.tkt_sig_support)
+ or self.tkt_sig_support,
+ expect_full_checksum=expect_full_checksum
+ or self.full_sig_support)
kdc_exchange_dict['rep_ticket_creds'] = ticket_creds
@@ -3038,10 +3052,13 @@ class RawKerberosTest(TestCaseInTempDir):
if not self.is_tgs(expected_sname) and rep_msg_type == KRB_TGS_REP:
expected_types.append(krb5pac.PAC_TYPE_TICKET_CHECKSUM)
+ expected_types.append(krb5pac.PAC_TYPE_FULL_CHECKSUM)
require_strict = {krb5pac.PAC_TYPE_CLIENT_CLAIMS_INFO}
if not self.tkt_sig_support:
require_strict.add(krb5pac.PAC_TYPE_TICKET_CHECKSUM)
+ if not self.full_sig_support:
+ require_strict.add(krb5pac.PAC_TYPE_FULL_CHECKSUM)
expect_extra_pac_buffers = self.is_tgs(expected_sname)
@@ -3668,7 +3685,8 @@ class RawKerberosTest(TestCaseInTempDir):
def verify_ticket(self, ticket, krbtgt_keys, service_ticket,
expect_pac=True,
- expect_ticket_checksum=True):
+ expect_ticket_checksum=True,
+ expect_full_checksum=None):
# Decrypt the ticket.
key = ticket.decryption_key
@@ -3713,6 +3731,8 @@ class RawKerberosTest(TestCaseInTempDir):
checksums = {}
+ full_checksum_buffer = None
+
for pac_buffer, raw_pac_buffer in zip(pac.buffers, raw_pac.buffers):
buffer_type = pac_buffer.type
if buffer_type in self.pac_checksum_types:
@@ -3727,7 +3747,9 @@ class RawKerberosTest(TestCaseInTempDir):
checksums[buffer_type] = checksum, ctype
- if buffer_type != krb5pac.PAC_TYPE_TICKET_CHECKSUM:
+ if buffer_type == krb5pac.PAC_TYPE_FULL_CHECKSUM:
+ full_checksum_buffer = raw_pac_buffer
+ elif buffer_type != krb5pac.PAC_TYPE_TICKET_CHECKSUM:
# Zero the checksum field so that we can later verify the
# checksums. The ticket checksum field is not zeroed.
@@ -3741,6 +3763,17 @@ class RawKerberosTest(TestCaseInTempDir):
# Re-encode the PAC.
pac_data = ndr_pack(raw_pac)
+ if full_checksum_buffer is not None:
+ signature = ndr_unpack(
+ krb5pac.PAC_SIGNATURE_DATA,
+ full_checksum_buffer.info.remaining)
+ signature.signature = bytes(len(checksum))
+ full_checksum_buffer.info.remaining = ndr_pack(
+ signature)
+
+ # Re-encode the PAC.
+ full_pac_data = ndr_pack(raw_pac)
+
# Verify the signatures.
server_checksum, server_ctype = checksums[
@@ -3769,6 +3802,7 @@ class RawKerberosTest(TestCaseInTempDir):
if not service_ticket:
self.assertNotIn(krb5pac.PAC_TYPE_TICKET_CHECKSUM, checksums)
+ self.assertNotIn(krb5pac.PAC_TYPE_FULL_CHECKSUM, checksums)
else:
ticket_checksum, ticket_ctype = checksums.get(
krb5pac.PAC_TYPE_TICKET_CHECKSUM,
@@ -3787,6 +3821,19 @@ class RawKerberosTest(TestCaseInTempDir):
ticket_ctype,
ticket_checksum)
+ full_checksum, full_ctype = checksums.get(
+ krb5pac.PAC_TYPE_FULL_CHECKSUM,
+ (None, None))
+ if expect_full_checksum:
+ self.assertIsNotNone(full_checksum)
+ elif expect_full_checksum is False:
+ self.assertIsNone(full_checksum)
+ if full_checksum is not None:
+ krbtgt_key.verify_rodc_checksum(KU_NON_KERB_CKSUM_SALT,
+ full_pac_data,
+ full_ctype,
+ full_checksum)
+
def modified_ticket(self,
ticket, *,
new_ticket_key=None,
@@ -3844,6 +3891,14 @@ class RawKerberosTest(TestCaseInTempDir):
checksum_keys[krb5pac.PAC_TYPE_TICKET_CHECKSUM] = (
kdc_checksum_key)
+ if krb5pac.PAC_TYPE_FULL_CHECKSUM not in checksum_keys:
+ # If the full signature key is not present, fall back to the key
+ # used for the KDC signature.
+ kdc_checksum_key = checksum_keys.get(krb5pac.PAC_TYPE_KDC_CHECKSUM)
+ if kdc_checksum_key is not None:
+ checksum_keys[krb5pac.PAC_TYPE_FULL_CHECKSUM] = (
+ kdc_checksum_key)
+
# Decrypt the ticket.
enc_part = ticket.ticket['enc-part']
@@ -3996,6 +4051,19 @@ class RawKerberosTest(TestCaseInTempDir):
# Add the new checksum buffers to the PAC.
pac.buffers = pac_buffers
+ # Calculate the full checksum and insert it into the PAC.
+ full_checksum_buffer = checksum_buffers.get(
+ krb5pac.PAC_TYPE_FULL_CHECKSUM)
+ if full_checksum_buffer is not None:
+ full_checksum_key = checksum_keys[krb5pac.PAC_TYPE_FULL_CHECKSUM]
+
+ pac_data = ndr_pack(pac)
+ full_checksum = full_checksum_key.make_checksum(
+ KU_NON_KERB_CKSUM_SALT,
+ pac_data)
+
+ full_checksum_buffer.info.signature = full_checksum
+
# Calculate the server and KDC checksums and insert them into the PAC.
server_checksum_buffer = checksum_buffers.get(
diff --git a/python/samba/tests/krb5/rodc_tests.py b/python/samba/tests/krb5/rodc_tests.py
index 83ee35d650a..3e0e2a7712e 100755
--- a/python/samba/tests/krb5/rodc_tests.py
+++ b/python/samba/tests/krb5/rodc_tests.py
@@ -65,7 +65,9 @@ class RodcKerberosTests(KDCBaseTest):
to_rodc=True)
# Ensure the PAC contains the expected checksums.
- self.verify_ticket(service_ticket, rodc_key, service_ticket=True)
+ self.verify_ticket(service_ticket, rodc_key, service_ticket=True,
+ expect_ticket_checksum=True,
+ expect_full_checksum=True)
if __name__ == "__main__":
diff --git a/python/samba/tests/krb5/s4u_tests.py b/python/samba/tests/krb5/s4u_tests.py
index 49dd89cd764..1d8e4ae5660 100755
--- a/python/samba/tests/krb5/s4u_tests.py
+++ b/python/samba/tests/krb5/s4u_tests.py
@@ -1024,8 +1024,8 @@ class S4UKerberosTests(KDCBaseTest):
def test_constrained_delegation_missing_service_checksum(self):
# Present the service's ticket without the required checksums.
- for checksum in filter(lambda x: x != krb5pac.PAC_TYPE_TICKET_CHECKSUM,
- self.pac_checksum_types):
+ for checksum in (krb5pac.PAC_TYPE_SRV_CHECKSUM,
+ krb5pac.PAC_TYPE_KDC_CHECKSUM):
with self.subTest(checksum=checksum):
self._run_delegation_test(
{
@@ -1059,8 +1059,8 @@ class S4UKerberosTests(KDCBaseTest):
def test_rbcd_missing_service_checksum(self):
# Present the service's ticket without the required checksums.
- for checksum in filter(lambda x: x != krb5pac.PAC_TYPE_TICKET_CHECKSUM,
- self.pac_checksum_types):
+ for checksum in (krb5pac.PAC_TYPE_SRV_CHECKSUM,
+ krb5pac.PAC_TYPE_KDC_CHECKSUM):
with self.subTest(checksum=checksum):
self._run_delegation_test(
{
@@ -1249,6 +1249,33 @@ class S4UKerberosTests(KDCBaseTest):
checksum=checksum, ctype=ctype)
})
+ def test_constrained_delegation_rc4_client_checksum(self):
+ # Present a user ticket with RC4 checksums.
+ expected_error_mode = (KDC_ERR_GENERIC,
+ KDC_ERR_INAPP_CKSUM)
+
+ self._run_delegation_test(
+ {
+ 'expected_error_mode': expected_error_mode,
+ 'allow_delegation': True,
+ 'modify_client_tkt_fn': self.rc4_pac_checksums,
+ 'expect_edata': False,
+ })
+
+ def test_rbcd_rc4_client_checksum(self):
+ # Present a user ticket with RC4 checksums.
+ expected_error_mode = (KDC_ERR_GENERIC,
+ KDC_ERR_BADOPTION)
+
+ self._run_delegation_test(
+ {
+ 'expected_error_mode': expected_error_mode,
+ 'expected_status': ntstatus.NT_STATUS_NOT_SUPPORTED,
+ 'allow_rbcd': True,
+ 'pac_options': '0001', # supports RBCD
+ 'modify_client_tkt_fn': self.rc4_pac_checksums,
+ })
+
def remove_pac_checksum(self, ticket, checksum):
checksum_keys = self.get_krbtgt_checksum_key()
@@ -1290,6 +1317,7 @@ class S4UKerberosTests(KDCBaseTest):
krb5pac.PAC_TYPE_SRV_CHECKSUM: server_key,
krb5pac.PAC_TYPE_KDC_CHECKSUM: krbtgt_key,
krb5pac.PAC_TYPE_TICKET_CHECKSUM: krbtgt_key,
+ krb5pac.PAC_TYPE_FULL_CHECKSUM: krbtgt_key,
}
# Make a copy of the existing key and change the ctype.
@@ -1302,6 +1330,31 @@ class S4UKerberosTests(KDCBaseTest):
checksum_keys=checksum_keys,
include_checksums={checksum: True})
+ def rc4_pac_checksums(self, ticket):
+ krbtgt_creds = self.get_krbtgt_creds()
+ rc4_krbtgt_key = self.TicketDecryptionKey_from_creds(
+ krbtgt_creds, etype=Enctype.RC4)
+
+ server_key = ticket.decryption_key
+
+ checksum_keys = {
+ krb5pac.PAC_TYPE_SRV_CHECKSUM: server_key,
+ krb5pac.PAC_TYPE_KDC_CHECKSUM: rc4_krbtgt_key,
+ krb5pac.PAC_TYPE_TICKET_CHECKSUM: rc4_krbtgt_key,
+ krb5pac.PAC_TYPE_FULL_CHECKSUM: rc4_krbtgt_key,
+ }
+
+ include_checksums = {
+ krb5pac.PAC_TYPE_SRV_CHECKSUM: True,
+ krb5pac.PAC_TYPE_KDC_CHECKSUM: True,
+ krb5pac.PAC_TYPE_TICKET_CHECKSUM: True,
+ krb5pac.PAC_TYPE_FULL_CHECKSUM: True,
+ }
+
+ return self.modified_ticket(ticket,
+ checksum_keys=checksum_keys,
+ include_checksums=include_checksums)
+
def add_delegation_info(self, ticket, services=None):
def modify_pac_fn(pac):
pac_buffers = pac.buffers
diff --git a/selftest/knownfail_mit_kdc b/selftest/knownfail_mit_kdc
index 4fa5fb3ba42..54af1416636 100644
--- a/selftest/knownfail_mit_kdc
+++ b/selftest/knownfail_mit_kdc
@@ -358,8 +358,6 @@ samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_
#
# PAC tests
#
-^netr-bdc-arcfour.verify-sig-arcfour
-^netr-bdc-arcfour.verify-sig-arcfour
^samba4.blackbox.pkinit_pac.STEP1 remote.pac verification.ad_dc:local
^samba4.blackbox.pkinit_pac.STEP1 remote.pac verification.ad_dc_ntvfs:local
^samba4.blackbox.pkinit_pac.netr-bdc-aes.verify-sig-aes.ad_dc:local
@@ -411,6 +409,7 @@ samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_pac_request_false
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_pac_request_none
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_pac_request_true
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_rc4.ad_dc
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_req
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_req_invalid
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_rodc_allowed_denied
@@ -426,6 +425,7 @@ samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_authdata_no_pac
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_no_pac
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_pac_request_true
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rc4.ad_dc
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_req
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_allowed_denied
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_denied
@@ -445,6 +445,7 @@ samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_rodc_validate_pac_request_true
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_authdata_no_pac
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_no_pac
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_rc4.ad_dc
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_req(?!_invalid)
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_rodc_allowed_denied
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_rodc_denied
@@ -459,6 +460,7 @@ samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_sid_mismatch_nonexisting
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_authdata_no_pac
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_no_pac
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rc4.ad_dc
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rename
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_allowed_denied
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_denied
@@ -472,6 +474,7 @@ samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_authdata_no_pac
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_no_pac
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_no_sname
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_rc4.ad_dc
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_req_invalid
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_rodc_allowed_denied
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_rodc_denied
@@ -491,6 +494,7 @@ samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_authdata_no_pac
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_no_pac
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_pac_request_true
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rc4.ad_dc
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_req
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_allowed_denied
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_denied
@@ -556,3 +560,8 @@ samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_
^samba.tests.krb5.etype_tests.samba.tests.krb5.etype_tests.EtypeTests.test_as_aes_supported_rc4_requested.ad_dc
^samba.tests.krb5.etype_tests.samba.tests.krb5.etype_tests.EtypeTests.test_as_rc4_requested.ad_dc
^samba.tests.krb5.etype_tests.samba.tests.krb5.etype_tests.EtypeTests.test_as_rc4_supported_rc4_requested.ad_dc
+#
+# KDC compatibility
+#
+^samba.tests.krb5.compatability_tests.samba.tests.krb5.compatability_tests.SimpleKerberosTests.test_full_signature.ad_dc
+^samba.tests.krb5.compatability_tests.samba.tests.krb5.compatability_tests.SimpleKerberosTests.test_full_signature.fl2003dc
diff --git a/source4/heimdal/kdc/kerberos5.c b/source4/heimdal/kdc/kerberos5.c
index bfe196c338f..e6e199d504a 100644
--- a/source4/heimdal/kdc/kerberos5.c
+++ b/source4/heimdal/kdc/kerberos5.c
@@ -1802,6 +1802,7 @@ _kdc_as_rep(krb5_context context,
&skey->key, /* Server key */
&krbtgt_key->key, /* TGS key */
rodc_id,
+ false, /* add_full_sig */
&data);
krb5_free_principal(context, client_pac);
krb5_pac_free(context, p);
diff --git a/source4/heimdal/kdc/krb5tgs.c b/source4/heimdal/kdc/krb5tgs.c
index 609649003ea..1e3405d4119 100644
--- a/source4/heimdal/kdc/krb5tgs.c
+++ b/source4/heimdal/kdc/krb5tgs.c
@@ -731,7 +731,7 @@ tgs_make_reply(krb5_context context,
/* The PAC should be the last change to the ticket. */
if (mspac != NULL) {
ret = _krb5_kdc_pac_sign_ticket(context, mspac, tgt_name, serverkey,
- krbtgtkey, rodc_id, add_ticket_sig, &et);
+ krbtgtkey, rodc_id, add_ticket_sig, add_ticket_sig, &et);
if (ret)
goto out;
}
diff --git a/source4/heimdal/lib/krb5/pac.c b/source4/heimdal/lib/krb5/pac.c
index 0641c0c57bc..6b6172196c4 100644
--- a/source4/heimdal/lib/krb5/pac.c
+++ b/source4/heimdal/lib/krb5/pac.c
@@ -69,6 +69,7 @@ struct krb5_pac_data {
struct PAC_INFO_BUFFER *privsvr_checksum;
struct PAC_INFO_BUFFER *logon_name;
struct PAC_INFO_BUFFER *ticket_checksum;
+ struct PAC_INFO_BUFFER *full_checksum;
krb5_data ticket_sign_data;
};
@@ -84,6 +85,7 @@ struct krb5_pac_data {
#define PAC_CONSTRAINED_DELEGATION 11
#define PAC_UPN_DNS_INFO 12
#define PAC_TICKET_CHECKSUM 16
+#define PAC_FULL_CHECKSUM 19
#define CHECK(r,f,l) \
do { \
@@ -325,6 +327,13 @@ krb5_pac_parse(krb5_context context, const void *ptr, size_t len,
else
p->ticket_checksum = &p->pac->buffers[i];
break;
+ case PAC_FULL_CHECKSUM:
+ if (p->full_checksum)
+ krb5_set_error_message(context, ret = EINVAL,
+ N_("PAC has multiple full checksums", ""));
+ else
+ p->full_checksum = &p->pac->buffers[i];
+ break;
default: break;
}
}
@@ -559,7 +568,8 @@ verify_checksum(krb5_context context,
const struct PAC_INFO_BUFFER *sig,
const krb5_data *data,
void *ptr, size_t len,
- const krb5_keyblock *key)
+ const krb5_keyblock *key,
+ krb5_boolean strict_cksumtype_match)
{
krb5_storage *sp = NULL;
uint32_t type;
@@ -617,7 +627,7 @@ verify_checksum(krb5_context context,
* http://blogs.msdn.com/b/openspecification/archive/2010/01/01/verifying-the-server-signature-in-kerberos-privilege-account-certificate.aspx
* for Microsoft's explaination */
- if (cksum.cksumtype == CKSUMTYPE_HMAC_MD5) {
+ if (cksum.cksumtype == CKSUMTYPE_HMAC_MD5 && !strict_cksumtype_match) {
Checksum local_checksum;
memset(&local_checksum, 0, sizeof(local_checksum));
@@ -942,7 +952,7 @@ out:
* @param pac the pac structure returned by krb5_pac_parse().
* @param authtime The time of the ticket the PAC belongs to.
* @param principal the principal to verify.
- * @param server The service key, most always be given.
+ * @param server The service key, may be given.
* @param privsvr The KDC key, may be given.
* @return Returns 0 to indicate success. Otherwise an kerberos et
@@ -960,6 +970,21 @@ krb5_pac_verify(krb5_context context,
const krb5_keyblock *privsvr)
{
krb5_error_code ret;
+ /*
+ * If we are in the KDC, we expect back a full signature in the PAC
+ *
+ * This is set up as a seperate variable to make it easier if a
+ * subsequent patch is added to make this configurable in the
+ * krb5.conf (or forced into the krb5_context via Samba)
+ */
+ krb5_boolean expect_full_sig = privsvr != NULL;
+
+ /*
+ * If we are on the KDC, then we trust we are not in a realm with
+ * buggy Windows 2008 or similar era DCs that give our HMAC-MD5
+ * sigatures over AES keys. DES is also already gone.
+ */
+ krb5_boolean strict_cksumtype_match = expect_full_sig;
if (pac->server_checksum == NULL) {
krb5_set_error_message(context, EINVAL, "PAC missing server checksum");
@@ -973,6 +998,10 @@ krb5_pac_verify(krb5_context context,
krb5_set_error_message(context, EINVAL, "PAC missing logon name");
return EINVAL;
}
+ if (expect_full_sig && pac->full_checksum == NULL) {
+ krb5_set_error_message(context, EINVAL, "PAC missing full checksum");
+ return EINVAL;
+ }
if (principal != NULL) {
ret = verify_logonname(context, pac->logon_name, &pac->data, authtime,
@@ -985,14 +1014,15 @@ krb5_pac_verify(krb5_context context,
pac->privsvr_checksum->buffersize < 4)
return EINVAL;
- /*
- * in the service case, clean out data option of the privsvr and
- * server checksum before checking the checksum.
- */
- if (server != NULL)
+ if (server != NULL || privsvr != NULL)
{
krb5_data *copy;
+ /*
+ * in the service case, clean out data option of the privsvr and
+ * server checksum before checking the checksum.
+ */
+
ret = krb5_copy_data(context, &pac->data, &copy);
if (ret)
return ret;
@@ -1010,15 +1040,43 @@ krb5_pac_verify(krb5_context context,
0,
pac->privsvr_checksum->buffersize - 4);
- ret = verify_checksum(context,
- pac->server_checksum,
- &pac->data,
- copy->data,
- copy->length,
- server);
+ if (server != NULL) {
+ ret = verify_checksum(context,
+ pac->server_checksum,
+ &pac->data,
+ copy->data,
+ copy->length,
+ server,
+ strict_cksumtype_match);
+ if (ret) {
+ krb5_free_data(context, copy);
+ return ret;
+ }
+ }
+
+ if (privsvr != NULL && pac->full_checksum != NULL) {
+ /*
+ * in the full checksum case, also clean out the full
+ * checksum before verifying it.
+ */
+ memset((char *)copy->data + pac->full_checksum->offset + 4,
+ 0,
+ pac->full_checksum->buffersize - 4);
+
+ ret = verify_checksum(context,
+ pac->full_checksum,
+ &pac->data,
+ copy->data,
+ copy->length,
+ privsvr,
+ strict_cksumtype_match);
+ if (ret) {
+ krb5_free_data(context, copy);
+ return ret;
+ }
+ }
+
krb5_free_data(context, copy);
- if (ret)
- return ret;
}
if (privsvr) {
/* The priv checksum covers the server checksum */
@@ -1028,7 +1086,8 @@ krb5_pac_verify(krb5_context context,
(char *)pac->data.data
+ pac->server_checksum->offset + 4,
pac->server_checksum->buffersize - 4,
- privsvr);
+ privsvr,
+ strict_cksumtype_match);
if (ret)
return ret;
@@ -1041,7 +1100,8 @@ krb5_pac_verify(krb5_context context,
ret = verify_checksum(context, pac->ticket_checksum, &pac->data,
pac->ticket_sign_data.data,
- pac->ticket_sign_data.length, privsvr);
+ pac->ticket_sign_data.length, privsvr,
+ strict_cksumtype_match);
if (ret)
return ret;
}
@@ -1114,13 +1174,14 @@ _krb5_pac_sign(krb5_context context,
const krb5_keyblock *server_key,
const krb5_keyblock *priv_key,
uint16_t rodc_id,
+ krb5_boolean add_full_sig,
krb5_data *data)
{
krb5_error_code ret;
krb5_storage *sp = NULL, *spdata = NULL;
uint32_t end;
size_t server_size, priv_size;
- uint32_t server_offset = 0, priv_offset = 0, ticket_offset = 0;
+ uint32_t server_offset = 0, priv_offset = 0, ticket_offset = 0, full_offset = 0;
uint32_t server_cksumtype = 0, priv_cksumtype = 0;
uint32_t num = 0;
uint32_t i, sz;
@@ -1177,6 +1238,16 @@ _krb5_pac_sign(krb5_context context,
N_("PAC has multiple ticket checksums", ""));
goto out;
}
+ } else if (p->pac->buffers[i].type == PAC_FULL_CHECKSUM) {
+ if (p->full_checksum == NULL) {
+ p->full_checksum = &p->pac->buffers[i];
+ }
+ if (p->full_checksum != &p->pac->buffers[i]) {
+ ret = KRB5KDC_ERR_BADOPTION;
+ krb5_set_error_message(context, ret,
+ N_("PAC has multiple full checksums", ""));
+ goto out;
+ }
}
}
@@ -1189,6 +1260,8 @@ _krb5_pac_sign(krb5_context context,
num++;
if (p->ticket_sign_data.length != 0 && p->ticket_checksum == NULL)
num++;
+ if (add_full_sig && p->full_checksum == NULL)
+ num++;
/* Allocate any missing-but-necessary buffers */
if (num) {
@@ -1231,6 +1304,11 @@ _krb5_pac_sign(krb5_context context,
p->ticket_checksum = &p->pac->buffers[p->pac->numbuffers++];
p->ticket_checksum->type = PAC_TICKET_CHECKSUM;
}
+ if (add_full_sig && p->full_checksum == NULL) {
+ p->full_checksum = &p->pac->buffers[p->pac->numbuffers++];
+ memset(p->full_checksum, 0, sizeof(*p->full_checksum));
+ p->full_checksum->type = PAC_FULL_CHECKSUM;
+ }
}
/* Calculate LOGON NAME */
@@ -1365,6 +1443,31 @@ _krb5_pac_sign(krb5_context context,
len += sizeof(rodc_id);
CHECK(ret, krb5_store_uint16(spdata, rodc_id), out);
}
+ } else if (add_full_sig &&
+ p->pac->buffers[i].type == PAC_FULL_CHECKSUM) {
+ if (priv_size > UINT32_MAX - 4) {
+ ret = EINVAL;
+ krb5_set_error_message(context, ret, "integer overrun");
+ goto out;
+ }
+ len = priv_size + 4;
+ if (end > UINT32_MAX - 4) {
+ ret = EINVAL;
+ krb5_set_error_message(context, ret, "integer overrun");
+ goto out;
+ }
+ full_offset = end + 4;
+ CHECK(ret, krb5_store_uint32(spdata, priv_cksumtype), out);
+ CHECK(ret, fill_zeros(context, spdata, priv_size), out);
+ if (rodc_id != 0) {
+ if (len > UINT32_MAX - sizeof(rodc_id)) {
+ ret = EINVAL;
+ krb5_set_error_message(context, ret, "integer overrun");
+ goto out;
+ }
+ len += sizeof(rodc_id);
+ CHECK(ret, fill_zeros(context, spdata, sizeof(rodc_id)), out);
+ }
} else if (p->pac->buffers[i].type == PAC_LOGON_NAME) {
len = krb5_storage_write(spdata, logon.data, logon.length);
if (logon.length != len) {
@@ -1436,6 +1539,21 @@ _krb5_pac_sign(krb5_context context,
p->ticket_sign_data.data,
p->ticket_sign_data.length,
(char *)d.data + ticket_offset, priv_size);
+ if (ret == 0 && add_full_sig)
+ ret = create_checksum(context, priv_key, priv_cksumtype,
+ d.data, d.length,
+ (char *)d.data + full_offset, priv_size);
+ if (ret == 0 && add_full_sig && rodc_id != 0) {
+ void *buf = (char *)d.data + full_offset + priv_size;
+ krb5_storage *rs = krb5_storage_from_mem(buf, sizeof(rodc_id));
+ if (rs == NULL)
+ ret = krb5_enomem(context);
+ else
+ krb5_storage_set_flags(rs, KRB5_STORAGE_BYTEORDER_LE);
+ if (ret == 0)
+ ret = krb5_store_uint16(rs, rodc_id);
+ krb5_storage_free(rs);
+ }
if (ret == 0)
ret = create_checksum(context, server_key, server_cksumtype,
d.data, d.length,
@@ -1445,21 +1563,14 @@ _krb5_pac_sign(krb5_context context,
(char *)d.data + server_offset, server_size,
(char *)d.data + priv_offset, priv_size);
if (ret == 0 && rodc_id != 0) {
- krb5_data rd;
- krb5_storage *rs = krb5_storage_emem();
+ void *buf = (char *)d.data + priv_offset + priv_size;
+ krb5_storage *rs = krb5_storage_from_mem(buf, sizeof(rodc_id));
if (rs == NULL)
ret = krb5_enomem(context);
krb5_storage_set_flags(rs, KRB5_STORAGE_BYTEORDER_LE);
if (ret == 0)
ret = krb5_store_uint16(rs, rodc_id);
- if (ret == 0)
- ret = krb5_storage_to_data(rs, &rd);
krb5_storage_free(rs);
- if (ret)
- goto out;
- heim_assert(rd.length == sizeof(rodc_id), "invalid length");
- memcpy((char *)d.data + priv_offset + priv_size, rd.data, rd.length);
- krb5_data_free(&rd);
}
if (ret)
@@ -1665,6 +1776,7 @@ _krb5_kdc_pac_sign_ticket(krb5_context context,
const krb5_keyblock *kdc_key,
uint16_t rodc_id,
krb5_boolean add_ticket_sig,
+ krb5_boolean add_full_sig,
EncTicketPart *tkt)
{
krb5_error_code ret;
@@ -1700,7 +1812,9 @@ _krb5_kdc_pac_sign_ticket(krb5_context context,
}
ret = _krb5_pac_sign(context, pac, tkt->authtime, client, server_key,
- kdc_key, rodc_id, &rspac);
+ kdc_key, rodc_id,
+ add_full_sig,
+ &rspac);
if (ret == 0)
ret = _kdc_tkt_insert_pac(context, tkt, &rspac);
krb5_data_free(&rspac);
diff --git a/source4/kdc/wdc-samba4.c b/source4/kdc/wdc-samba4.c
index d7ce34fb3a9..de69a4449f3 100644
--- a/source4/kdc/wdc-samba4.c
+++ b/source4/kdc/wdc-samba4.c
@@ -151,6 +151,7 @@ static krb5_error_code samba_wdc_reget_pac2(krb5_context context,
ssize_t tkt_checksum_idx = -1;
ssize_t attrs_info_idx = -1;
ssize_t requester_sid_idx = -1;
+ ssize_t full_checksum_idx = -1;
if (!mem_ctx) {
return ENOMEM;
@@ -221,7 +222,7 @@ static krb5_error_code samba_wdc_reget_pac2(krb5_context context,
return ret;
}
- /* Check the KDC and ticket signatures. */
+ /* Check the KDC, whole-PAC and ticket signatures. */
ret = krb5_pac_verify(context,
*pac,
0,
@@ -430,6 +431,19 @@ static krb5_error_code samba_wdc_reget_pac2(krb5_context context,
}
requester_sid_idx = i;
break;
+ case PAC_TYPE_FULL_CHECKSUM:
+ if (full_checksum_idx != -1) {
+ DBG_WARNING("full checksum type[%"PRIu32"] twice "
+ "[%zd] and [%zu]: \n",
+ types[i],
+ full_checksum_idx,
+ i);
+ SAFE_FREE(types);
+ talloc_free(mem_ctx);
+ return EINVAL;
+ }
+ full_checksum_idx = i;
+ break;
default:
continue;
}
@@ -609,6 +623,13 @@ static krb5_error_code samba_wdc_reget_pac2(krb5_context context,
} else {
continue;
}
+ case PAC_TYPE_FULL_CHECKSUM:
+ /*
+ * this is generated in the main KDC code
+ * we just add a place holder here.
+ */
+ type_blob = data_blob_const(&zero_byte, 1);
+ break;
default:
/* just copy... */
break;
diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py
index 06d4b1771c8..0b2ffcf7c88 100755
--- a/source4/selftest/tests.py
+++ b/source4/selftest/tests.py
@@ -907,6 +907,7 @@ have_fast_support = int('SAMBA_USES_MITKDC' in config_hash)
claims_support = 0
compound_id_support = 0
tkt_sig_support = int('SAMBA4_USES_HEIMDAL' in config_hash)
+full_sig_support = int('SAMBA4_USES_HEIMDAL' in config_hash)
expect_pac = int('SAMBA4_USES_HEIMDAL' in config_hash)
extra_pac_buffers = int('SAMBA4_USES_HEIMDAL' in config_hash)
krb5_environ = {
@@ -920,6 +921,7 @@ krb5_environ = {
'CLAIMS_SUPPORT': claims_support,
'COMPOUND_ID_SUPPORT': compound_id_support,
'TKT_SIG_SUPPORT': tkt_sig_support,
+ 'FULL_SIG_SUPPORT': full_sig_support,
'EXPECT_PAC': expect_pac,
'EXPECT_EXTRA_PAC_BUFFERS': extra_pac_buffers,
}
@@ -1567,8 +1569,13 @@ for env in ["rodc", "promoted_dc", "fl2000dc", "fl2008r2dc"]:
planpythontestsuite("ad_dc", "samba.tests.krb5.as_canonicalization_tests",
environ=krb5_environ)
-planpythontestsuite("ad_dc", "samba.tests.krb5.compatability_tests",
- environ=krb5_environ)
+for env, fast_support in [("ad_dc", True),
+ ("fl2003dc", False)]:
+ planpythontestsuite(env, "samba.tests.krb5.compatability_tests",
+ environ={
+ **krb5_environ,
+ 'FAST_SUPPORT': int(fast_support),
+ })
planpythontestsuite("ad_dc", "samba.tests.krb5.kdc_tests",
environ=krb5_environ)
planpythontestsuite(
diff --git a/source4/torture/rpc/remote_pac.c b/source4/torture/rpc/remote_pac.c
index 16249799e36..9145ee222aa 100644
--- a/source4/torture/rpc/remote_pac.c
+++ b/source4/torture/rpc/remote_pac.c
@@ -308,7 +308,7 @@ static bool test_PACVerify(struct torture_context *tctx,
(ndr_pull_flags_fn_t)ndr_pull_PAC_DATA);
torture_assert(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err), "ndr_pull_struct_blob of PAC_DATA structure failed");
- num_pac_buffers = 5;
+ num_pac_buffers = 6;
if (expect_pac_upn_dns_info) {
num_pac_buffers += 1;
}
@@ -365,6 +365,12 @@ static bool test_PACVerify(struct torture_context *tctx,
pac_buf->info != NULL,
"PAC_TYPE_TICKET_CHECKSUM info");
+ pac_buf = get_pac_buffer(&pac_data_struct, PAC_TYPE_FULL_CHECKSUM);
+ torture_assert_not_null(tctx, pac_buf, "PAC_TYPE_FULL_CHECKSUM");
+ torture_assert(tctx,
+ pac_buf->info != NULL,
+ "PAC_TYPE_FULL_CHECKSUM info");
+
ok = netlogon_validate_pac(tctx, p, server_creds, secure_channel_type, test_machine_name,
negotiate_flags, pac_data, session_info);
@@ -1128,7 +1134,7 @@ static bool test_S4U2Proxy(struct torture_context *tctx,
(ndr_pull_flags_fn_t)ndr_pull_PAC_DATA);
torture_assert(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err), "ndr_pull_struct_blob of PAC_DATA structure failed");
- num_pac_buffers = 7;
+ num_pac_buffers = 8;
torture_assert_int_equal(tctx, pac_data_struct.version, 0, "version");
torture_assert_int_equal(tctx, pac_data_struct.num_buffers, num_pac_buffers, "num_buffers");
@@ -1157,6 +1163,10 @@ static bool test_S4U2Proxy(struct torture_context *tctx,
torture_assert_not_null(tctx, pac_buf, "PAC_TYPE_TICKET_CHECKSUM");
torture_assert_not_null(tctx, pac_buf->info, "PAC_TYPE_TICKET_CHECKSUM info");
+ pac_buf = get_pac_buffer(&pac_data_struct, PAC_TYPE_FULL_CHECKSUM);
+ torture_assert_not_null(tctx, pac_buf, "PAC_TYPE_FULL_CHECKSUM");
+ torture_assert_not_null(tctx, pac_buf->info, "PAC_TYPE_FULL_CHECKSUM info");
+
pac_buf = get_pac_buffer(&pac_data_struct, PAC_TYPE_CONSTRAINED_DELEGATION);
torture_assert_not_null(tctx, pac_buf, "PAC_TYPE_CONSTRAINED_DELEGATION");
torture_assert_not_null(tctx, pac_buf->info, "PAC_TYPE_CONSTRAINED_DELEGATION info");