summaryrefslogtreecommitdiff
path: root/python/samba
diff options
context:
space:
mode:
authorJoseph Sutton <josephsutton@catalyst.net.nz>2023-07-04 15:28:04 +1200
committerAndrew Bartlett <abartlet@samba.org>2023-07-19 01:47:33 +0000
commit5bfccbb76433f4fa035040f5305f0258f6fbcb51 (patch)
tree800e8df9d8b8283a7c0c4e8640fa635e3e7dec39 /python/samba
parentaf97579f161bf814e91f19cd495019524cc6a329 (diff)
downloadsamba-5bfccbb76433f4fa035040f5305f0258f6fbcb51.tar.gz
samba-5bfccbb76433f4fa035040f5305f0258f6fbcb51.tar.bz2
samba-5bfccbb76433f4fa035040f5305f0258f6fbcb51.zip
tests/krb5: Test Windows 2000 variant of PK-INIT
Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abartlet@samba.org>
Diffstat (limited to 'python/samba')
-rwxr-xr-xpython/samba/tests/krb5/pkinit_tests.py96
-rw-r--r--python/samba/tests/krb5/raw_testcase.py96
2 files changed, 155 insertions, 37 deletions
diff --git a/python/samba/tests/krb5/pkinit_tests.py b/python/samba/tests/krb5/pkinit_tests.py
index 1e1ff1af454..66f056b9abd 100755
--- a/python/samba/tests/krb5/pkinit_tests.py
+++ b/python/samba/tests/krb5/pkinit_tests.py
@@ -49,6 +49,7 @@ from samba.tests.krb5.rfc4120_constants import (
NT_PRINCIPAL,
PADATA_AS_FRESHNESS,
PADATA_ENC_TIMESTAMP,
+ PADATA_PK_AS_REP_19,
PADATA_PK_AS_REQ,
)
import samba.tests.krb5.rfc4120_pyasn1 as krb5_asn1
@@ -92,6 +93,13 @@ class PkInitTests(KDCBaseTest):
self._pkinit_req(client_creds, target_creds,
using_pkinit=PkInit.DIFFIE_HELLMAN)
+ def test_pkinit_win2k(self):
+ """Test public-key Windows 2000 PK-INIT."""
+ client_creds = self._get_creds()
+ target_creds = self.get_service_creds()
+
+ self._pkinit_req(client_creds, target_creds, win2k_variant=True)
+
def test_pkinit_no_des3(self):
"""Test public-key PK-INIT without specifying the DES3 encryption
type. It should fail."""
@@ -172,6 +180,13 @@ class PkInitTests(KDCBaseTest):
self._pkinit_req(client_creds, target_creds,
using_pkinit=PkInit.DIFFIE_HELLMAN)
+ def test_pkinit_computer_win2k(self):
+ """Test public-key Windows 2000 PK-INIT with a computer account."""
+ client_creds = self._get_creds(self.AccountType.COMPUTER)
+ target_creds = self.get_service_creds()
+
+ self._pkinit_req(client_creds, target_creds, win2k_variant=True)
+
def test_pkinit_service(self):
"""Test public-key PK-INIT with a service account."""
client_creds = self._get_creds(self.AccountType.MANAGED_SERVICE)
@@ -187,6 +202,13 @@ class PkInitTests(KDCBaseTest):
self._pkinit_req(client_creds, target_creds,
using_pkinit=PkInit.DIFFIE_HELLMAN)
+ def test_pkinit_service_win2k(self):
+ """Test public-key Windows 2000 PK-INIT with a service account."""
+ client_creds = self._get_creds(self.AccountType.MANAGED_SERVICE)
+ target_creds = self.get_service_creds()
+
+ self._pkinit_req(client_creds, target_creds, win2k_variant=True)
+
def test_pkinit_no_supported_cms_types(self):
"""Test public-key PK-INIT, excluding the supportedCmsTypes field. This
causes Windows to reply with differently-encoded ASN.1."""
@@ -243,6 +265,16 @@ class PkInitTests(KDCBaseTest):
using_pkinit=PkInit.DIFFIE_HELLMAN,
signature_algorithm=krb5_asn1.id_pkcs1_sha256WithRSAEncryption)
+ def test_pkinit_sha256_signature_win2k(self):
+ """Test public-key Windows 2000 PK-INIT with a SHA256 signature."""
+ client_creds = self._get_creds()
+ target_creds = self.get_service_creds()
+
+ self._pkinit_req(
+ client_creds, target_creds,
+ signature_algorithm=krb5_asn1.id_pkcs1_sha256WithRSAEncryption,
+ win2k_variant=True)
+
def test_pkinit_sha256_certificate_signature(self):
"""Test public-key PK-INIT with a SHA256 certificate signature."""
client_creds = self._get_creds()
@@ -262,6 +294,17 @@ class PkInitTests(KDCBaseTest):
using_pkinit=PkInit.DIFFIE_HELLMAN,
certificate_signature=hashes.SHA256)
+ def test_pkinit_sha256_certificate_signature_win2k(self):
+ """Test public-key Windows 2000 PK-INIT with a SHA256 certificate
+ signature."""
+ client_creds = self._get_creds()
+ target_creds = self.get_service_creds()
+
+ self._pkinit_req(
+ client_creds, target_creds,
+ certificate_signature=hashes.SHA256,
+ win2k_variant=True)
+
def test_pkinit_freshness(self):
"""Test public-key PK-INIT with the PKINIT Freshness Extension."""
client_creds = self._get_creds()
@@ -632,6 +675,7 @@ class PkInitTests(KDCBaseTest):
signature_algorithm=None,
certificate_signature=None,
freshness_token=None,
+ win2k_variant=False,
):
self.assertIsNot(using_pkinit, PkInit.NOT_USED)
@@ -843,18 +887,28 @@ class PkInitTests(KDCBaseTest):
def generate_pk_padata(_kdc_exchange_dict,
_callback_dict,
req_body):
- checksum_blob = self.der_encode(
- req_body,
- asn1Spec=krb5_asn1.KDC_REQ_BODY())
+ if win2k_variant:
+ digest = None
+ else:
+ checksum_blob = self.der_encode(
+ req_body,
+ asn1Spec=krb5_asn1.KDC_REQ_BODY())
- # Calculate the SHA1 checksum over the KDC-REQ-BODY. This checksum
- # is required to be present in the authenticator, and must be SHA1.
- digest = hashes.Hash(hashes.SHA1(), default_backend())
- digest.update(checksum_blob)
- digest = digest.finalize()
+ # Calculate the SHA1 checksum over the KDC-REQ-BODY. This checksum
+ # is required to be present in the authenticator, and must be SHA1.
+ digest = hashes.Hash(hashes.SHA1(), default_backend())
+ digest.update(checksum_blob)
+ digest = digest.finalize()
ctime, cusec = self.get_KerberosTimeWithUsec()
+ if win2k_variant:
+ krbtgt_sname = self.get_krbtgt_sname()
+ krbtgt_realm = self.get_krbtgt_creds().get_realm()
+ else:
+ krbtgt_sname = None
+ krbtgt_realm = None
+
# Create the authenticator, which shows that we had possession of
# the private key at some point.
authenticator_obj = self.PKAuthenticator_create(
@@ -862,7 +916,10 @@ class PkInitTests(KDCBaseTest):
ctime,
pk_nonce,
pa_checksum=digest,
- freshness_token=freshness_token)
+ freshness_token=freshness_token,
+ kdc_name=krbtgt_sname,
+ kdc_realm=krbtgt_realm,
+ win2k_variant=win2k_variant)
if using_pkinit is PkInit.DIFFIE_HELLMAN:
dh_public_key = dh_private_key.public_key()
@@ -899,7 +956,9 @@ class PkInitTests(KDCBaseTest):
# differently encoded ReplyKeyPack, wrapping it first in a
# ContentInfo structure.
nonlocal supported_cms_types
- if supported_cms_types is False:
+ if win2k_variant:
+ self.assertIsNone(supported_cms_types)
+ elif supported_cms_types is False:
# Exclude this field.
supported_cms_types = None
elif supported_cms_types is None:
@@ -916,10 +975,13 @@ class PkInitTests(KDCBaseTest):
authenticator_obj,
client_public_value=client_public_value,
supported_cms_types=supported_cms_types,
- client_dh_nonce=client_dh_nonce)
+ client_dh_nonce=client_dh_nonce,
+ win2k_variant=win2k_variant)
- auth_pack = self.der_encode(auth_pack_obj,
- asn1Spec=krb5_asn1.AuthPack())
+ asn1_spec = (krb5_asn1.AuthPack_Win2k
+ if win2k_variant
+ else krb5_asn1.AuthPack)
+ auth_pack = self.der_encode(auth_pack_obj, asn1Spec=asn1_spec())
signature_hash = self.hash_from_algorithm(signature_algorithm)
@@ -964,9 +1026,13 @@ class PkInitTests(KDCBaseTest):
# trusted by the client, that can
# be used to certify the KDC.
trusted_certifiers=None,
- kdc_pk_id=None)
+ kdc_pk_id=None,
+ win2k_variant=win2k_variant)
- padata = [self.PA_DATA_create(PADATA_PK_AS_REQ, pk_as_req)]
+ pa_type = (PADATA_PK_AS_REP_19
+ if win2k_variant
+ else PADATA_PK_AS_REQ)
+ padata = [self.PA_DATA_create(pa_type, pk_as_req)]
return padata, req_body
diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py
index b7d2d2a42e5..17a0fe906ac 100644
--- a/python/samba/tests/krb5/raw_testcase.py
+++ b/python/samba/tests/krb5/raw_testcase.py
@@ -1842,7 +1842,19 @@ class RawKerberosTest(TestCase):
nonce,
*,
pa_checksum=None,
- freshness_token=None):
+ freshness_token=None,
+ kdc_name=None,
+ kdc_realm=None,
+ win2k_variant=False):
+ if win2k_variant:
+ self.assertIsNone(pa_checksum)
+ self.assertIsNone(freshness_token)
+ self.assertIsNotNone(kdc_name)
+ self.assertIsNotNone(kdc_realm)
+ else:
+ self.assertIsNone(kdc_name)
+ self.assertIsNone(kdc_realm)
+
pk_authenticator_obj = {
'cusec': cusec,
'ctime': ctime,
@@ -1852,6 +1864,10 @@ class RawKerberosTest(TestCase):
pk_authenticator_obj['paChecksum'] = pa_checksum
if freshness_token is not None:
pk_authenticator_obj['freshnessToken'] = freshness_token
+ if kdc_name is not None:
+ pk_authenticator_obj['kdcName'] = kdc_name
+ if kdc_realm is not None:
+ pk_authenticator_obj['kdcRealm'] = kdc_realm
return pk_authenticator_obj
@@ -2143,7 +2159,12 @@ class RawKerberosTest(TestCase):
*,
client_public_value=None,
supported_cms_types=None,
- client_dh_nonce=None):
+ client_dh_nonce=None,
+ win2k_variant=False):
+ if win2k_variant:
+ self.assertIsNone(supported_cms_types)
+ self.assertIsNone(client_dh_nonce)
+
auth_pack_obj = {
'pkAuthenticator': pk_authenticator,
}
@@ -2161,7 +2182,18 @@ class RawKerberosTest(TestCase):
signed_auth_pack,
*,
trusted_certifiers=None,
- kdc_pk_id=None):
+ kdc_pk_id=None,
+ kdc_cert=None,
+ encryption_cert=None,
+ win2k_variant=False):
+ if win2k_variant:
+ self.assertIsNone(kdc_pk_id)
+ asn1_spec = krb5_asn1.PA_PK_AS_REQ_Win2k
+ else:
+ self.assertIsNone(kdc_cert)
+ self.assertIsNone(encryption_cert)
+ asn1_spec = krb5_asn1.PA_PK_AS_REQ
+
content_info_obj = self.ContentInfo_create(
krb5_asn1.id_signedData, signed_auth_pack)
content_info = self.der_encode(content_info_obj,
@@ -2175,9 +2207,12 @@ class RawKerberosTest(TestCase):
pk_as_req_obj['trustedCertifiers'] = trusted_certifiers
if kdc_pk_id is not None:
pk_as_req_obj['kdcPkId'] = kdc_pk_id
+ if kdc_cert is not None:
+ pk_as_req_obj['kdcCert'] = kdc_cert
+ if encryption_cert is not None:
+ pk_as_req_obj['encryptionCert'] = encryption_cert
- return self.der_encode(pk_as_req_obj,
- asn1Spec=krb5_asn1.PA_PK_AS_REQ())
+ return self.der_encode(pk_as_req_obj, asn1Spec=asn1_spec())
def SignerInfo_create(self,
signer_id,
@@ -3326,10 +3361,19 @@ class RawKerberosTest(TestCase):
pa_dict = self.get_pa_dict(padata)
- if PADATA_PK_AS_REP in pa_dict:
- pk_as_rep = pa_dict[PADATA_PK_AS_REP]
+ pk_as_rep = pa_dict.get(PADATA_PK_AS_REP)
+ if pk_as_rep is not None:
+ pk_as_rep_asn1_spec = krb5_asn1.PA_PK_AS_REP
+ reply_key_pack_asn1_spec = krb5_asn1.ReplyKeyPack
+ pk_win2k = False
+ else:
+ pk_as_rep = pa_dict.get(PADATA_PK_AS_REP_19)
+ pk_as_rep_asn1_spec = krb5_asn1.PA_PK_AS_REP_Win2k
+ reply_key_pack_asn1_spec = krb5_asn1.ReplyKeyPack_Win2k
+ pk_win2k = True
+ if pk_as_rep is not None:
pk_as_rep = self.der_decode(pk_as_rep,
- asn1Spec=krb5_asn1.PA_PK_AS_REP())
+ asn1Spec=pk_as_rep_asn1_spec())
using_pkinit = kdc_exchange_dict['using_pkinit']
if using_pkinit is PkInit.PUBLIC_KEY:
@@ -3490,9 +3534,7 @@ class RawKerberosTest(TestCase):
self.assertEqual(str(krb5_asn1.id_pkinit_rkeyData),
content_type)
reply_key_pack = self.der_decode(
- content, asn1Spec=krb5_asn1.ReplyKeyPack())
-
- as_checksum = reply_key_pack['asChecksum']
+ content, asn1Spec=reply_key_pack_asn1_spec())
req_obj = kdc_exchange_dict['req_obj']
req_asn1Spec = kdc_exchange_dict['req_asn1Spec']
@@ -3508,12 +3550,15 @@ class RawKerberosTest(TestCase):
contents=reply_key['keyvalue'],
kvno=None)
- # Verify the checksum over the AS request body.
- kcrypto.verify_checksum(as_checksum['cksumtype'],
- encpart_decryption_key.key,
- KU_PKINIT_AS_REQ,
- req_obj,
- as_checksum['checksum'])
+ if not pk_win2k:
+ as_checksum = reply_key_pack['asChecksum']
+
+ # Verify the checksum over the AS request body.
+ kcrypto.verify_checksum(as_checksum['cksumtype'],
+ encpart_decryption_key.key,
+ KU_PKINIT_AS_REQ,
+ req_obj,
+ as_checksum['checksum'])
elif using_pkinit is PkInit.DIFFIE_HELLMAN:
content_info = self.der_decode(
pk_as_rep['dhInfo']['dhSignedData'],
@@ -4387,7 +4432,8 @@ class RawKerberosTest(TestCase):
if expect_requester_sid:
expected_types.append(krb5pac.PAC_TYPE_REQUESTER_SID)
- sent_pk_as_req = self.sent_pk_as_req(kdc_exchange_dict)
+ sent_pk_as_req = self.sent_pk_as_req(kdc_exchange_dict) or (
+ self.sent_pk_as_req_win2k(kdc_exchange_dict))
if sent_pk_as_req:
expected_types.append(krb5pac.PAC_TYPE_CREDENTIAL_INFO)
@@ -4797,13 +4843,16 @@ class RawKerberosTest(TestCase):
expected_patypes = ()
sent_fast = self.sent_fast(kdc_exchange_dict)
- using_pkinit = kdc_exchange_dict.get('using_pkinit', PkInit.NOT_USED)
rep_msg_type = kdc_exchange_dict['rep_msg_type']
if sent_fast:
expected_patypes += (PADATA_FX_FAST,)
elif rep_msg_type == KRB_AS_REP:
- if using_pkinit is PkInit.NOT_USED:
+ if self.sent_pk_as_req(kdc_exchange_dict):
+ expected_patypes += PADATA_PK_AS_REP,
+ elif self.sent_pk_as_req_win2k(kdc_exchange_dict):
+ expected_patypes += PADATA_PK_AS_REP_19,
+ else:
chosen_etype = self.getElementValue(encpart, 'etype')
self.assertIsNotNone(chosen_etype)
@@ -4815,8 +4864,6 @@ class RawKerberosTest(TestCase):
self.assertIsInstance(preauth_key, Krb5EncryptionKey)
if preauth_key.etype == kcrypto.Enctype.RC4 and rep_padata is None:
rep_padata = ()
- else:
- expected_patypes += PADATA_PK_AS_REP,
elif rep_msg_type == KRB_TGS_REP:
if expected_patypes == () and rep_padata is None:
rep_padata = ()
@@ -5867,6 +5914,11 @@ class RawKerberosTest(TestCase):
return PADATA_PK_AS_REQ in fast_pa_dict
+ def sent_pk_as_req_win2k(self, kdc_exchange_dict):
+ fast_pa_dict = self.get_fast_pa_dict(kdc_exchange_dict)
+
+ return PADATA_PK_AS_REP_19 in fast_pa_dict
+
def sent_freshness(self, kdc_exchange_dict):
fast_pa_dict = self.get_fast_pa_dict(kdc_exchange_dict)