mirror of
https://github.com/samba-team/samba.git
synced 2025-01-10 01:18:15 +03:00
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 a50a2be622
)
[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.]
This commit is contained in:
parent
a9c836d044
commit
0601bb94c6
@ -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
|
||||
|
@ -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()
|
||||
|
@ -1425,7 +1425,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
|
||||
|
||||
|
@ -1593,6 +1593,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()
|
||||
@ -2604,7 +2641,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:
|
||||
@ -2623,7 +2662,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,
|
||||
@ -2638,7 +2679,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:
|
||||
@ -2677,13 +2720,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:
|
||||
|
@ -543,7 +543,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", },
|
||||
@ -637,6 +638,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:
|
||||
@ -2397,6 +2404,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,
|
||||
@ -2456,6 +2464,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,
|
||||
@ -2511,6 +2520,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,
|
||||
@ -2571,6 +2581,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,
|
||||
@ -3046,7 +3057,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:
|
||||
@ -3056,7 +3068,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
|
||||
|
||||
@ -3093,12 +3107,15 @@ 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,
|
||||
krb5pac.PAC_TYPE_DEVICE_INFO,
|
||||
krb5pac.PAC_TYPE_DEVICE_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)
|
||||
|
||||
@ -3774,7 +3791,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
|
||||
@ -3819,6 +3837,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:
|
||||
@ -3833,7 +3853,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.
|
||||
|
||||
@ -3847,6 +3869,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[
|
||||
@ -3875,6 +3908,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,
|
||||
@ -3893,6 +3927,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,
|
||||
@ -3950,6 +3997,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']
|
||||
@ -4102,6 +4157,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(
|
||||
|
@ -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__":
|
||||
|
@ -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
|
||||
|
@ -359,8 +359,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
|
||||
@ -412,6 +410,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
|
||||
@ -427,6 +426,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
|
||||
@ -446,6 +446,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
|
||||
@ -460,6 +461,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
|
||||
@ -473,6 +475,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
|
||||
@ -492,6 +495,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
|
||||
@ -567,3 +571,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
|
||||
|
@ -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;
|
||||
@ -222,7 +223,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,
|
||||
@ -434,6 +435,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;
|
||||
}
|
||||
@ -613,6 +627,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;
|
||||
|
@ -965,6 +965,7 @@ have_fast_support = 1
|
||||
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)
|
||||
check_cname = int('SAMBA4_USES_HEIMDAL' in config_hash)
|
||||
@ -980,6 +981,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,
|
||||
'CHECK_CNAME': check_cname,
|
||||
@ -1648,8 +1650,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(
|
||||
|
@ -313,7 +313,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;
|
||||
}
|
||||
@ -370,6 +370,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);
|
||||
|
||||
@ -1133,7 +1139,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");
|
||||
@ -1162,6 +1168,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");
|
||||
|
1
third_party/heimdal/kdc/kerberos5.c
vendored
1
third_party/heimdal/kdc/kerberos5.c
vendored
@ -1913,6 +1913,7 @@ generate_pac(astgs_request_t r, const Key *skey, const Key *tkey,
|
||||
rodc_id,
|
||||
NULL, /* UPN */
|
||||
canon_princ,
|
||||
false, /* add_full_sig */
|
||||
is_tgs ? &r->pac_attributes : NULL,
|
||||
&data);
|
||||
krb5_free_principal(r->context, client);
|
||||
|
2
third_party/heimdal/kdc/krb5tgs.c
vendored
2
third_party/heimdal/kdc/krb5tgs.c
vendored
@ -778,7 +778,7 @@ tgs_make_reply(astgs_request_t r,
|
||||
|
||||
ret = _krb5_kdc_pac_sign_ticket(r->context, r->pac, r->client_princ, serverkey,
|
||||
krbtgtkey, rodc_id, NULL, r->canon_client_princ,
|
||||
add_ticket_sig, et,
|
||||
add_ticket_sig, add_ticket_sig, et,
|
||||
is_tgs ? &r->pac_attributes : NULL);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
169
third_party/heimdal/lib/krb5/pac.c
vendored
169
third_party/heimdal/lib/krb5/pac.c
vendored
@ -74,6 +74,7 @@ struct krb5_pac_data {
|
||||
struct PAC_INFO_BUFFER *upn_dns_info;
|
||||
struct PAC_INFO_BUFFER *ticket_checksum;
|
||||
struct PAC_INFO_BUFFER *attributes_info;
|
||||
struct PAC_INFO_BUFFER *full_checksum;
|
||||
krb5_data ticket_sign_data;
|
||||
|
||||
/* PAC_UPN_DNS_INFO */
|
||||
@ -101,6 +102,7 @@ struct krb5_pac_data {
|
||||
#define PAC_TICKET_CHECKSUM 16
|
||||
#define PAC_ATTRIBUTES_INFO 17
|
||||
#define PAC_REQUESTOR_SID 18
|
||||
#define PAC_FULL_CHECKSUM 19
|
||||
|
||||
/* Flag in PAC_UPN_DNS_INFO */
|
||||
#define PAC_EXTRA_LOGON_INFO_FLAGS_UPN_DEFAULTED 0x1
|
||||
@ -398,6 +400,13 @@ krb5_pac_parse(krb5_context context, const void *ptr, size_t len,
|
||||
else
|
||||
p->attributes_info = &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;
|
||||
}
|
||||
}
|
||||
@ -668,7 +677,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;
|
||||
@ -726,7 +736,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));
|
||||
@ -1189,7 +1199,7 @@ parse_attributes_info(krb5_context context,
|
||||
* @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
|
||||
@ -1207,6 +1217,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");
|
||||
@ -1220,6 +1245,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,
|
||||
@ -1232,14 +1261,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, ©);
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -1252,15 +1282,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 */
|
||||
@ -1270,7 +1328,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;
|
||||
|
||||
@ -1283,7 +1342,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;
|
||||
}
|
||||
@ -1374,6 +1434,7 @@ _krb5_pac_sign(krb5_context context,
|
||||
uint16_t rodc_id,
|
||||
krb5_const_principal upn_princ,
|
||||
krb5_const_principal canon_princ,
|
||||
krb5_boolean add_full_sig,
|
||||
uint64_t *pac_attributes, /* optional */
|
||||
krb5_data *data)
|
||||
{
|
||||
@ -1381,7 +1442,7 @@ _krb5_pac_sign(krb5_context context,
|
||||
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;
|
||||
@ -1458,6 +1519,16 @@ _krb5_pac_sign(krb5_context context,
|
||||
N_("PAC has multiple attributes info buffers", ""));
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1470,6 +1541,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) {
|
||||
@ -1512,6 +1585,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 */
|
||||
@ -1644,6 +1722,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) {
|
||||
@ -1705,6 +1808,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,
|
||||
@ -1714,22 +1832,15 @@ _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);
|
||||
else
|
||||
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)
|
||||
@ -1972,6 +2083,7 @@ _krb5_kdc_pac_sign_ticket(krb5_context context,
|
||||
krb5_const_principal upn,
|
||||
krb5_const_principal canon_name,
|
||||
krb5_boolean add_ticket_sig,
|
||||
krb5_boolean add_full_sig,
|
||||
EncTicketPart *tkt,
|
||||
uint64_t *pac_attributes) /* optional */
|
||||
{
|
||||
@ -2009,6 +2121,7 @@ _krb5_kdc_pac_sign_ticket(krb5_context context,
|
||||
|
||||
ret = _krb5_pac_sign(context, pac, tkt->authtime, client, server_key,
|
||||
kdc_key, rodc_id, upn, canon_name,
|
||||
add_full_sig,
|
||||
pac_attributes, &rspac);
|
||||
if (ret == 0)
|
||||
ret = _kdc_tkt_insert_pac(context, tkt, &rspac);
|
||||
|
Loading…
Reference in New Issue
Block a user