diff options
| author | Joseph Sutton <josephsutton@catalyst.net.nz> | 2023-07-04 15:28:04 +1200 |
|---|---|---|
| committer | Andrew Bartlett <abartlet@samba.org> | 2023-07-19 01:47:33 +0000 |
| commit | 5bfccbb76433f4fa035040f5305f0258f6fbcb51 (patch) | |
| tree | 800e8df9d8b8283a7c0c4e8640fa635e3e7dec39 /python/samba | |
| parent | af97579f161bf814e91f19cd495019524cc6a329 (diff) | |
| download | samba-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-x | python/samba/tests/krb5/pkinit_tests.py | 96 | ||||
| -rw-r--r-- | python/samba/tests/krb5/raw_testcase.py | 96 |
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) |
