2 # Unix SMB/CIFS implementation.
3 # Copyright (C) Stefan Metzmacher 2020
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 3 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program. If not, see <http://www.gnu.org/licenses/>.
22 sys.path.insert(0, "bin/python")
23 os.environ["PYTHONUNBUFFERED"] = "1"
25 from samba.tests import DynamicTestCase
26 from samba.tests.krb5.kdc_base_test import KDCBaseTest
27 import samba.tests.krb5.kcrypto as kcrypto
28 import samba.tests.krb5.rfc4120_pyasn1 as krb5_asn1
29 from samba.tests.krb5.rfc4120_constants import (
30 KDC_ERR_C_PRINCIPAL_UNKNOWN,
31 KDC_ERR_S_PRINCIPAL_UNKNOWN,
33 KDC_ERR_PREAUTH_REQUIRED,
35 NT_ENTERPRISE_PRINCIPAL,
41 global_asn1_print = False
42 global_hexdump = False
45 class AsReqBaseTest(KDCBaseTest):
46 def _run_as_req_enc_timestamp(self, client_creds, client_account=None,
47 expected_cname=None, sname=None,
48 name_type=NT_PRINCIPAL, etypes=None,
49 expected_error=None, expect_edata=None,
50 expected_pa_error=None, expect_pa_edata=None,
51 kdc_options=None, till=None):
52 user_name = client_creds.get_username()
53 if client_account is None:
54 client_account = user_name
55 client_as_etypes = self.get_default_enctypes()
56 client_kvno = client_creds.get_kvno()
57 krbtgt_creds = self.get_krbtgt_creds(require_strongest_key=True)
58 krbtgt_account = krbtgt_creds.get_username()
59 krbtgt_supported_etypes = krbtgt_creds.tgs_supported_enctypes
60 realm = krbtgt_creds.get_realm()
62 cname = self.PrincipalName_create(name_type=name_type,
63 names=client_account.split('/'))
65 sname = self.PrincipalName_create(name_type=NT_SRV_INST,
66 names=[krbtgt_account, realm])
68 expected_crealm = realm
69 if expected_cname is None:
70 expected_cname = cname
71 expected_srealm = realm
72 expected_sname = sname
73 expected_salt = client_creds.get_salt()
76 till = self.get_KerberosTime(offset=36000)
79 etypes = client_as_etypes
80 if kdc_options is None:
81 kdc_options = krb5_asn1.KDCOptions('forwardable')
82 if expected_error is not None:
83 initial_error_mode = expected_error
85 initial_error_mode = KDC_ERR_PREAUTH_REQUIRED
87 rep, kdc_exchange_dict = self._test_as_exchange(
102 expected_supported_etypes=krbtgt_supported_etypes,
103 expected_account_name=user_name,
105 expect_edata=expect_edata)
107 if expected_error is not None:
110 etype_info2 = kdc_exchange_dict['preauth_etype_info2']
111 self.assertIsNotNone(etype_info2)
113 preauth_key = self.PasswordKey_from_etype_info2(client_creds,
117 (patime, pausec) = self.get_KerberosTimeWithUsec()
118 pa_ts = self.PA_ENC_TS_ENC_create(patime, pausec)
119 pa_ts = self.der_encode(pa_ts, asn1Spec=krb5_asn1.PA_ENC_TS_ENC())
121 enc_pa_ts_usage = KU_PA_ENC_TIMESTAMP
122 pa_ts = self.EncryptedData_create(preauth_key, enc_pa_ts_usage, pa_ts)
123 pa_ts = self.der_encode(pa_ts, asn1Spec=krb5_asn1.EncryptedData())
125 pa_ts = self.PA_DATA_create(PADATA_ENC_TIMESTAMP, pa_ts)
127 preauth_padata = [pa_ts]
128 preauth_error_mode = 0 # AS-REP
129 if expected_pa_error is not None:
130 preauth_error_mode = expected_pa_error
132 krbtgt_decryption_key = (
133 self.TicketDecryptionKey_from_creds(krbtgt_creds))
135 as_rep, kdc_exchange_dict = self._test_as_exchange(
150 expected_supported_etypes=krbtgt_supported_etypes,
151 expected_account_name=user_name,
152 expect_edata=expect_pa_edata,
153 preauth_key=preauth_key,
154 ticket_decryption_key=krbtgt_decryption_key,
156 self.assertIsNotNone(as_rep)
162 class AsReqKerberosTests(AsReqBaseTest):
165 def setUpDynamicTestCases(cls):
166 for (name, idx) in cls.etype_test_permutation_name_idx():
167 for pac in [None, True, False]:
168 tname = "%s_pac_%s" % (name, pac)
170 cls.generate_dynamic_test("test_as_req_no_preauth", tname, *targs)
173 super(AsReqKerberosTests, self).setUp()
174 self.do_asn1_print = global_asn1_print
175 self.do_hexdump = global_hexdump
177 def _test_as_req_nopreauth(self,
180 initial_kdc_options=None):
181 client_creds = self.get_client_creds()
182 client_account = client_creds.get_username()
183 client_as_etypes = self.get_default_enctypes()
184 krbtgt_creds = self.get_krbtgt_creds(require_keys=False)
185 krbtgt_account = krbtgt_creds.get_username()
186 realm = krbtgt_creds.get_realm()
188 cname = self.PrincipalName_create(name_type=NT_PRINCIPAL,
189 names=[client_account])
190 sname = self.PrincipalName_create(name_type=NT_SRV_INST,
191 names=[krbtgt_account, realm])
193 expected_crealm = realm
194 expected_cname = cname
195 expected_srealm = realm
196 expected_sname = sname
197 expected_salt = client_creds.get_salt()
199 if any(etype in client_as_etypes and etype in initial_etypes
200 for etype in (kcrypto.Enctype.AES256,
201 kcrypto.Enctype.AES128,
202 kcrypto.Enctype.RC4)):
203 expected_error_mode = KDC_ERR_PREAUTH_REQUIRED
205 expected_error_mode = KDC_ERR_ETYPE_NOSUPP
207 kdc_exchange_dict = self.as_exchange_dict(
208 expected_crealm=expected_crealm,
209 expected_cname=expected_cname,
210 expected_srealm=expected_srealm,
211 expected_sname=expected_sname,
212 generate_padata_fn=None,
213 check_error_fn=self.generic_check_kdc_error,
215 expected_error_mode=expected_error_mode,
216 client_as_etypes=client_as_etypes,
217 expected_salt=expected_salt,
218 kdc_options=str(initial_kdc_options),
221 self._generic_kdc_exchange(kdc_exchange_dict,
225 etypes=initial_etypes)
227 def _test_as_req_no_preauth_with_args(self, etype_idx, pac):
228 name, etypes = self.etype_test_permutation_by_idx(etype_idx)
229 self._test_as_req_nopreauth(
231 initial_etypes=etypes,
232 initial_kdc_options=krb5_asn1.KDCOptions('forwardable'))
234 def test_as_req_enc_timestamp(self):
235 client_creds = self.get_client_creds()
236 self._run_as_req_enc_timestamp(client_creds)
238 def test_as_req_enc_timestamp_mac(self):
239 client_creds = self.get_mach_creds()
240 self._run_as_req_enc_timestamp(client_creds)
242 def test_as_req_enc_timestamp_rc4(self):
243 client_creds = self.get_client_creds()
244 self._run_as_req_enc_timestamp(
246 etypes=(kcrypto.Enctype.RC4,))
248 def test_as_req_enc_timestamp_mac_rc4(self):
249 client_creds = self.get_mach_creds()
250 self._run_as_req_enc_timestamp(
252 etypes=(kcrypto.Enctype.RC4,))
254 def test_as_req_enc_timestamp_rc4_dummy(self):
255 client_creds = self.get_client_creds()
256 self._run_as_req_enc_timestamp(
258 etypes=(kcrypto.Enctype.RC4,
261 def test_as_req_enc_timestamp_mac_rc4_dummy(self):
262 client_creds = self.get_mach_creds()
263 self._run_as_req_enc_timestamp(
265 etypes=(kcrypto.Enctype.RC4,
268 def test_as_req_enc_timestamp_aes128_rc4(self):
269 client_creds = self.get_client_creds()
270 self._run_as_req_enc_timestamp(
272 etypes=(kcrypto.Enctype.AES128,
273 kcrypto.Enctype.RC4))
275 def test_as_req_enc_timestamp_mac_aes128_rc4(self):
276 client_creds = self.get_mach_creds()
277 self._run_as_req_enc_timestamp(
279 etypes=(kcrypto.Enctype.AES128,
280 kcrypto.Enctype.RC4))
282 def test_as_req_enc_timestamp_spn(self):
283 client_creds = self.get_mach_creds()
284 spn = client_creds.get_spn()
285 self._run_as_req_enc_timestamp(
286 client_creds, client_account=spn,
287 expected_error=KDC_ERR_C_PRINCIPAL_UNKNOWN,
290 def test_as_req_enc_timestamp_spn_realm(self):
291 samdb = self.get_samdb()
292 realm = samdb.domain_dns_name().upper()
294 client_creds = self.get_cached_creds(
295 account_type=self.AccountType.COMPUTER,
296 opts={'upn': f'host/{{account}}.{realm}@{realm}'})
297 spn = client_creds.get_spn()
298 self._run_as_req_enc_timestamp(
299 client_creds, client_account=spn,
300 expected_error=KDC_ERR_C_PRINCIPAL_UNKNOWN,
303 def test_as_req_enc_timestamp_spn_upn(self):
304 samdb = self.get_samdb()
305 realm = samdb.domain_dns_name().upper()
307 client_creds = self.get_cached_creds(
308 account_type=self.AccountType.COMPUTER,
309 opts={'upn': f'host/{{account}}.{realm}@{realm}',
310 'spn': f'host/{{account}}.{realm}'})
311 spn = client_creds.get_spn()
312 self._run_as_req_enc_timestamp(client_creds, client_account=spn)
314 def test_as_req_enc_timestamp_spn_enterprise(self):
315 client_creds = self.get_mach_creds()
316 spn = client_creds.get_spn()
317 self._run_as_req_enc_timestamp(
318 client_creds, client_account=spn,
319 name_type=NT_ENTERPRISE_PRINCIPAL,
320 expected_error=KDC_ERR_C_PRINCIPAL_UNKNOWN,
323 def test_as_req_enc_timestamp_spn_enterprise_realm(self):
324 samdb = self.get_samdb()
325 realm = samdb.domain_dns_name().upper()
327 client_creds = self.get_cached_creds(
328 account_type=self.AccountType.COMPUTER,
329 opts={'upn': f'host/{{account}}.{realm}@{realm}'})
330 spn = client_creds.get_spn()
331 self._run_as_req_enc_timestamp(
333 name_type=NT_ENTERPRISE_PRINCIPAL,
335 expected_error=KDC_ERR_C_PRINCIPAL_UNKNOWN,
338 def test_as_req_enc_timestamp_spn_upn_enterprise(self):
339 samdb = self.get_samdb()
340 realm = samdb.domain_dns_name().upper()
342 client_creds = self.get_cached_creds(
343 account_type=self.AccountType.COMPUTER,
344 opts={'upn': f'host/{{account}}.{realm}@{realm}',
345 'spn': f'host/{{account}}.{realm}'})
346 spn = client_creds.get_spn()
347 self._run_as_req_enc_timestamp(
349 name_type=NT_ENTERPRISE_PRINCIPAL,
351 expected_error=KDC_ERR_C_PRINCIPAL_UNKNOWN,
354 def test_as_req_enterprise_canon(self):
355 upn = self.get_new_username()
356 client_creds = self.get_cached_creds(
357 account_type=self.AccountType.USER,
360 user_name = client_creds.get_username()
361 realm = client_creds.get_realm()
362 client_account = f'{user_name}@{realm}'
364 expected_cname = self.PrincipalName_create(
365 name_type=NT_PRINCIPAL,
368 self._run_as_req_enc_timestamp(
370 client_account=client_account,
371 expected_cname=expected_cname,
372 name_type=NT_ENTERPRISE_PRINCIPAL,
373 kdc_options=krb5_asn1.KDCOptions('canonicalize'))
375 def test_as_req_enterprise_canon_case(self):
376 upn = self.get_new_username()
377 client_creds = self.get_cached_creds(
378 account_type=self.AccountType.USER,
381 user_name = client_creds.get_username()
382 realm = client_creds.get_realm().lower()
383 client_account = f'{user_name}@{realm}'
385 expected_cname = self.PrincipalName_create(
386 name_type=NT_PRINCIPAL,
389 self._run_as_req_enc_timestamp(
391 client_account=client_account,
392 expected_cname=expected_cname,
393 name_type=NT_ENTERPRISE_PRINCIPAL,
394 kdc_options=krb5_asn1.KDCOptions('canonicalize'))
396 def test_as_req_enterprise_canon_mac(self):
397 upn = self.get_new_username()
398 client_creds = self.get_cached_creds(
399 account_type=self.AccountType.COMPUTER,
402 user_name = client_creds.get_username()
403 realm = client_creds.get_realm()
404 client_account = f'{user_name}@{realm}'
406 expected_cname = self.PrincipalName_create(
407 name_type=NT_PRINCIPAL,
410 self._run_as_req_enc_timestamp(
412 client_account=client_account,
413 expected_cname=expected_cname,
414 name_type=NT_ENTERPRISE_PRINCIPAL,
415 kdc_options=krb5_asn1.KDCOptions('canonicalize'))
417 def test_as_req_enterprise_canon_mac_case(self):
418 upn = self.get_new_username()
419 client_creds = self.get_cached_creds(
420 account_type=self.AccountType.COMPUTER,
423 user_name = client_creds.get_username()
424 realm = client_creds.get_realm().lower()
425 client_account = f'{user_name}@{realm}'
427 expected_cname = self.PrincipalName_create(
428 name_type=NT_PRINCIPAL,
431 self._run_as_req_enc_timestamp(
433 client_account=client_account,
434 expected_cname=expected_cname,
435 name_type=NT_ENTERPRISE_PRINCIPAL,
436 kdc_options=krb5_asn1.KDCOptions('canonicalize'))
438 def test_as_req_enterprise_no_canon(self):
439 upn = self.get_new_username()
440 client_creds = self.get_cached_creds(
441 account_type=self.AccountType.USER,
444 user_name = client_creds.get_username()
445 realm = client_creds.get_realm()
446 client_account = f'{user_name}@{realm}'
448 self._run_as_req_enc_timestamp(
450 client_account=client_account,
451 name_type=NT_ENTERPRISE_PRINCIPAL,
454 def test_as_req_enterprise_no_canon_case(self):
455 upn = self.get_new_username()
456 client_creds = self.get_cached_creds(
457 account_type=self.AccountType.USER,
460 user_name = client_creds.get_username()
461 realm = client_creds.get_realm().lower()
462 client_account = f'{user_name}@{realm}'
464 self._run_as_req_enc_timestamp(
466 client_account=client_account,
467 name_type=NT_ENTERPRISE_PRINCIPAL,
470 def test_as_req_enterprise_no_canon_mac(self):
471 upn = self.get_new_username()
472 client_creds = self.get_cached_creds(
473 account_type=self.AccountType.COMPUTER,
476 user_name = client_creds.get_username()
477 realm = client_creds.get_realm()
478 client_account = f'{user_name}@{realm}'
480 self._run_as_req_enc_timestamp(
482 client_account=client_account,
483 name_type=NT_ENTERPRISE_PRINCIPAL,
486 def test_as_req_enterprise_no_canon_mac_case(self):
487 upn = self.get_new_username()
488 client_creds = self.get_cached_creds(
489 account_type=self.AccountType.COMPUTER,
492 user_name = client_creds.get_username()
493 realm = client_creds.get_realm().lower()
494 client_account = f'{user_name}@{realm}'
496 self._run_as_req_enc_timestamp(
498 client_account=client_account,
499 name_type=NT_ENTERPRISE_PRINCIPAL,
502 # Ensure we can't use truncated well-known principals such as krb@REALM
503 # instead of krbtgt@REALM.
504 def test_krbtgt_wrong_principal(self):
505 client_creds = self.get_client_creds()
507 krbtgt_creds = self.get_krbtgt_creds()
509 krbtgt_account = krbtgt_creds.get_username()
510 realm = krbtgt_creds.get_realm()
512 # Truncate the name of the krbtgt principal.
513 krbtgt_account = krbtgt_account[:3]
515 wrong_krbtgt_princ = self.PrincipalName_create(
516 name_type=NT_SRV_INST,
517 names=[krbtgt_account, realm])
519 if self.strict_checking:
520 self._run_as_req_enc_timestamp(
522 sname=wrong_krbtgt_princ,
523 expected_pa_error=KDC_ERR_S_PRINCIPAL_UNKNOWN,
524 expect_pa_edata=False)
526 self._run_as_req_enc_timestamp(
528 sname=wrong_krbtgt_princ,
529 expected_error=KDC_ERR_S_PRINCIPAL_UNKNOWN)
531 # Test that we can make a request for a ticket expiring post-2038.
532 def test_future_till(self):
533 client_creds = self.get_client_creds()
535 self._run_as_req_enc_timestamp(
537 till='99990913024805Z')
540 if __name__ == "__main__":
541 global_asn1_print = False
542 global_hexdump = False