tests/krb5: Allow specifying parameters specific to the inner FAST request body
[Samba.git] / python / samba / tests / krb5 / fast_tests.py
blobfb5c0fc28f81850a54da47b728ea96955a05a73c
1 #!/usr/bin/env python3
2 # Unix SMB/CIFS implementation.
3 # Copyright (C) Stefan Metzmacher 2020
4 # Copyright (C) 2020 Catalyst.Net Ltd
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 3 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program. If not, see <http://www.gnu.org/licenses/>.
20 import functools
21 import os
22 import sys
24 import ldb
26 from samba.dcerpc import security
27 from samba.tests.krb5.raw_testcase import (
28 KerberosTicketCreds,
29 Krb5EncryptionKey
31 from samba.tests.krb5.kdc_base_test import KDCBaseTest
32 from samba.tests.krb5.rfc4120_constants import (
33 AD_FX_FAST_ARMOR,
34 AD_FX_FAST_USED,
35 AES256_CTS_HMAC_SHA1_96,
36 ARCFOUR_HMAC_MD5,
37 FX_FAST_ARMOR_AP_REQUEST,
38 KDC_ERR_ETYPE_NOSUPP,
39 KDC_ERR_GENERIC,
40 KDC_ERR_NOT_US,
41 KDC_ERR_PREAUTH_FAILED,
42 KDC_ERR_PREAUTH_REQUIRED,
43 KDC_ERR_UNKNOWN_CRITICAL_FAST_OPTIONS,
44 KRB_AS_REP,
45 KRB_TGS_REP,
46 KU_AS_REP_ENC_PART,
47 KU_TICKET,
48 NT_PRINCIPAL,
49 NT_SRV_INST,
50 NT_WELLKNOWN,
51 PADATA_FX_COOKIE,
52 PADATA_FX_FAST,
53 PADATA_PAC_OPTIONS
55 import samba.tests.krb5.rfc4120_pyasn1 as krb5_asn1
56 import samba.tests.krb5.kcrypto as kcrypto
58 sys.path.insert(0, "bin/python")
59 os.environ["PYTHONUNBUFFERED"] = "1"
61 global_asn1_print = False
62 global_hexdump = False
65 class FAST_Tests(KDCBaseTest):
66 @classmethod
67 def setUpClass(cls):
68 super().setUpClass()
70 cls.user_tgt = None
71 cls.user_enc_part = None
72 cls.user_service_ticket = None
74 cls.mach_tgt = None
75 cls.mach_enc_part = None
76 cls.mach_service_ticket = None
78 def setUp(self):
79 super().setUp()
80 self.do_asn1_print = global_asn1_print
81 self.do_hexdump = global_hexdump
83 def test_simple(self):
84 self._run_test_sequence([
86 'rep_type': KRB_AS_REP,
87 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
88 'use_fast': False
91 'rep_type': KRB_AS_REP,
92 'expected_error_mode': 0,
93 'use_fast': False,
94 'gen_padata_fn': self.generate_enc_timestamp_padata
98 def test_simple_tgs(self):
99 self._run_test_sequence([
101 'rep_type': KRB_TGS_REP,
102 'expected_error_mode': 0,
103 'use_fast': False,
104 'gen_tgt_fn': self.get_user_tgt
108 def test_simple_no_sname(self):
109 krbtgt_creds = self.get_krbtgt_creds()
110 krbtgt_username = krbtgt_creds.get_username()
111 krbtgt_realm = krbtgt_creds.get_realm()
112 expected_sname = self.PrincipalName_create(
113 name_type=NT_SRV_INST, names=[krbtgt_username, krbtgt_realm])
115 self._run_test_sequence([
117 'rep_type': KRB_AS_REP,
118 'expected_error_mode': KDC_ERR_GENERIC,
119 'use_fast': False,
120 'sname': None,
121 'expected_sname': expected_sname
125 def test_simple_tgs_no_sname(self):
126 krbtgt_creds = self.get_krbtgt_creds()
127 krbtgt_username = krbtgt_creds.get_username()
128 krbtgt_realm = krbtgt_creds.get_realm()
129 expected_sname = self.PrincipalName_create(
130 name_type=NT_SRV_INST, names=[krbtgt_username, krbtgt_realm])
132 self._run_test_sequence([
134 'rep_type': KRB_TGS_REP,
135 'expected_error_mode': KDC_ERR_GENERIC,
136 'use_fast': False,
137 'gen_tgt_fn': self.get_user_tgt,
138 'sname': None,
139 'expected_sname': expected_sname
143 def test_fast_no_sname(self):
144 krbtgt_creds = self.get_krbtgt_creds()
145 krbtgt_username = krbtgt_creds.get_username()
146 krbtgt_realm = krbtgt_creds.get_realm()
147 expected_sname = self.PrincipalName_create(
148 name_type=NT_SRV_INST, names=[krbtgt_username, krbtgt_realm])
150 self._run_test_sequence([
152 'rep_type': KRB_AS_REP,
153 'expected_error_mode': KDC_ERR_GENERIC,
154 'use_fast': True,
155 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
156 'gen_armor_tgt_fn': self.get_mach_tgt,
157 'sname': None,
158 'expected_sname': expected_sname
162 def test_fast_tgs_no_sname(self):
163 krbtgt_creds = self.get_krbtgt_creds()
164 krbtgt_username = krbtgt_creds.get_username()
165 krbtgt_realm = krbtgt_creds.get_realm()
166 expected_sname = self.PrincipalName_create(
167 name_type=NT_SRV_INST, names=[krbtgt_username, krbtgt_realm])
169 self._run_test_sequence([
171 'rep_type': KRB_TGS_REP,
172 'expected_error_mode': KDC_ERR_GENERIC,
173 'use_fast': True,
174 'gen_tgt_fn': self.get_user_tgt,
175 'fast_armor': None,
176 'sname': None,
177 'expected_sname': expected_sname
181 def test_simple_tgs_wrong_principal(self):
182 mach_creds = self.get_mach_creds()
183 mach_name = mach_creds.get_username()
184 expected_cname = self.PrincipalName_create(
185 name_type=NT_PRINCIPAL, names=[mach_name])
187 self._run_test_sequence([
189 'rep_type': KRB_TGS_REP,
190 'expected_error_mode': 0,
191 'use_fast': False,
192 'gen_tgt_fn': self.get_mach_tgt,
193 'expected_cname': expected_cname
197 def test_simple_tgs_service_ticket(self):
198 self._run_test_sequence([
200 'rep_type': KRB_TGS_REP,
201 'expected_error_mode': KDC_ERR_NOT_US,
202 'use_fast': False,
203 'gen_tgt_fn': self.get_user_service_ticket,
207 def test_simple_tgs_service_ticket_mach(self):
208 self._run_test_sequence([
210 'rep_type': KRB_TGS_REP,
211 'expected_error_mode': KDC_ERR_NOT_US,
212 'use_fast': False,
213 'gen_tgt_fn': self.get_mach_service_ticket,
217 def test_fast_no_claims(self):
218 self._run_test_sequence([
220 'rep_type': KRB_AS_REP,
221 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
222 'use_fast': True,
223 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
224 'gen_armor_tgt_fn': self.get_mach_tgt,
225 'pac_options': '0'
228 'rep_type': KRB_AS_REP,
229 'expected_error_mode': 0,
230 'use_fast': True,
231 'gen_padata_fn': self.generate_enc_challenge_padata,
232 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
233 'gen_armor_tgt_fn': self.get_mach_tgt,
234 'pac_options': '0'
238 def test_fast_tgs_no_claims(self):
239 self._run_test_sequence([
241 'rep_type': KRB_TGS_REP,
242 'expected_error_mode': 0,
243 'use_fast': True,
244 'gen_tgt_fn': self.get_user_tgt,
245 'fast_armor': None,
246 'pac_options': '0'
250 def test_fast_no_claims_or_canon(self):
251 self._run_test_sequence([
253 'rep_type': KRB_AS_REP,
254 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
255 'use_fast': True,
256 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
257 'gen_armor_tgt_fn': self.get_mach_tgt,
258 'pac_options': '0',
259 'kdc_options': '0'
262 'rep_type': KRB_AS_REP,
263 'expected_error_mode': 0,
264 'use_fast': True,
265 'gen_padata_fn': self.generate_enc_challenge_padata,
266 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
267 'gen_armor_tgt_fn': self.get_mach_tgt,
268 'pac_options': '0',
269 'kdc_options': '0'
273 def test_fast_tgs_no_claims_or_canon(self):
274 self._run_test_sequence([
276 'rep_type': KRB_TGS_REP,
277 'expected_error_mode': 0,
278 'use_fast': True,
279 'gen_tgt_fn': self.get_user_tgt,
280 'fast_armor': None,
281 'pac_options': '0',
282 'kdc_options': '0'
286 def test_fast_no_canon(self):
287 self._run_test_sequence([
289 'rep_type': KRB_AS_REP,
290 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
291 'use_fast': True,
292 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
293 'gen_armor_tgt_fn': self.get_mach_tgt,
294 'kdc_options': '0'
297 'rep_type': KRB_AS_REP,
298 'expected_error_mode': 0,
299 'use_fast': True,
300 'gen_padata_fn': self.generate_enc_challenge_padata,
301 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
302 'gen_armor_tgt_fn': self.get_mach_tgt,
303 'kdc_options': '0'
307 def test_fast_tgs_no_canon(self):
308 self._run_test_sequence([
310 'rep_type': KRB_TGS_REP,
311 'expected_error_mode': 0,
312 'use_fast': True,
313 'gen_tgt_fn': self.get_user_tgt,
314 'fast_armor': None,
315 'kdc_options': '0'
319 def test_simple_tgs_no_etypes(self):
320 self._run_test_sequence([
322 'rep_type': KRB_TGS_REP,
323 'expected_error_mode': KDC_ERR_ETYPE_NOSUPP,
324 'use_fast': False,
325 'gen_tgt_fn': self.get_mach_tgt,
326 'etypes': ()
330 def test_fast_tgs_no_etypes(self):
331 self._run_test_sequence([
333 'rep_type': KRB_TGS_REP,
334 'expected_error_mode': KDC_ERR_ETYPE_NOSUPP,
335 'use_fast': True,
336 'gen_tgt_fn': self.get_mach_tgt,
337 'fast_armor': None,
338 'etypes': ()
342 def test_simple_no_etypes(self):
343 self._run_test_sequence([
345 'rep_type': KRB_AS_REP,
346 'expected_error_mode': KDC_ERR_ETYPE_NOSUPP,
347 'use_fast': False,
348 'etypes': ()
352 def test_simple_fast_no_etypes(self):
353 self._run_test_sequence([
355 'rep_type': KRB_AS_REP,
356 'expected_error_mode': KDC_ERR_ETYPE_NOSUPP,
357 'use_fast': True,
358 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
359 'gen_armor_tgt_fn': self.get_mach_tgt,
360 'etypes': ()
364 def test_empty_fast(self):
365 # Add an empty PA-FX-FAST in the initial AS-REQ. This should get
366 # rejected with a Generic error.
367 self._run_test_sequence([
369 'rep_type': KRB_AS_REP,
370 'expected_error_mode': KDC_ERR_GENERIC,
371 'use_fast': True,
372 'gen_fast_fn': self.generate_empty_fast,
373 'fast_armor': None,
374 'gen_armor_tgt_fn': self.get_mach_tgt
378 def test_fast_unknown_critical_option(self):
379 self._run_test_sequence([
381 'rep_type': KRB_AS_REP,
382 'expected_error_mode': KDC_ERR_UNKNOWN_CRITICAL_FAST_OPTIONS,
383 'use_fast': True,
384 'fast_options': '001', # unsupported critical option
385 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
386 'gen_armor_tgt_fn': self.get_mach_tgt
390 def test_unarmored_as_req(self):
391 self._run_test_sequence([
393 'rep_type': KRB_AS_REP,
394 'expected_error_mode': KDC_ERR_GENERIC,
395 'use_fast': True,
396 'fast_armor': None, # no armor,
397 'gen_armor_tgt_fn': self.get_mach_tgt
401 def test_fast_invalid_armor_type(self):
402 self._run_test_sequence([
404 'rep_type': KRB_AS_REP,
405 'expected_error_mode': KDC_ERR_PREAUTH_FAILED,
406 'use_fast': True,
407 'fast_armor': 0, # invalid armor type
408 'gen_armor_tgt_fn': self.get_mach_tgt
412 def test_fast_invalid_armor_type2(self):
413 self._run_test_sequence([
415 'rep_type': KRB_AS_REP,
416 'expected_error_mode': KDC_ERR_PREAUTH_FAILED,
417 'use_fast': True,
418 'fast_armor': 2, # invalid armor type
419 'gen_armor_tgt_fn': self.get_mach_tgt
423 def test_fast_encrypted_challenge(self):
424 self._run_test_sequence([
426 'rep_type': KRB_AS_REP,
427 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
428 'use_fast': True,
429 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
430 'gen_armor_tgt_fn': self.get_mach_tgt
433 'rep_type': KRB_AS_REP,
434 'expected_error_mode': 0,
435 'use_fast': True,
436 'gen_padata_fn': self.generate_enc_challenge_padata,
437 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
438 'gen_armor_tgt_fn': self.get_mach_tgt
442 def test_fast_encrypted_challenge_wrong_key(self):
443 self._run_test_sequence([
445 'rep_type': KRB_AS_REP,
446 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
447 'use_fast': True,
448 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
449 'gen_armor_tgt_fn': self.get_mach_tgt
452 'rep_type': KRB_AS_REP,
453 'expected_error_mode': KDC_ERR_PREAUTH_FAILED,
454 'use_fast': True,
455 'gen_padata_fn': self.generate_enc_challenge_padata_wrong_key,
456 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
457 'gen_armor_tgt_fn': self.get_mach_tgt
461 def test_fast_encrypted_challenge_wrong_key_kdc(self):
462 self._run_test_sequence([
464 'rep_type': KRB_AS_REP,
465 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
466 'use_fast': True,
467 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
468 'gen_armor_tgt_fn': self.get_mach_tgt
471 'rep_type': KRB_AS_REP,
472 'expected_error_mode': KDC_ERR_PREAUTH_FAILED,
473 'use_fast': True,
474 'gen_padata_fn':
475 self.generate_enc_challenge_padata_wrong_key_kdc,
476 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
477 'gen_armor_tgt_fn': self.get_mach_tgt
481 def test_fast_encrypted_challenge_no_fast(self):
482 self._run_test_sequence([
484 'rep_type': KRB_AS_REP,
485 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
486 'use_fast': False
489 'rep_type': KRB_AS_REP,
490 'expected_error_mode': KDC_ERR_PREAUTH_FAILED,
491 'use_fast': False,
492 'gen_padata_fn': self.generate_enc_challenge_padata_wrong_key
496 def test_fast_encrypted_challenge_clock_skew(self):
497 # The KDC is supposed to confirm that the timestamp is within its
498 # current clock skew, and return KRB_APP_ERR_SKEW if it is not (RFC6113
499 # 5.4.6). However, Windows accepts a skewed timestamp in the encrypted
500 # challenge.
501 self._run_test_sequence([
503 'rep_type': KRB_AS_REP,
504 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
505 'use_fast': True,
506 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
507 'gen_armor_tgt_fn': self.get_mach_tgt
510 'rep_type': KRB_AS_REP,
511 'expected_error_mode': 0,
512 'use_fast': True,
513 'gen_padata_fn': functools.partial(
514 self.generate_enc_challenge_padata,
515 skew=10000),
516 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
517 'gen_armor_tgt_fn': self.get_mach_tgt
521 def test_fast_invalid_tgt(self):
522 # The armor ticket 'sname' field is required to identify the target
523 # realm TGS (RFC6113 5.4.1.1). However, Windows will still accept a
524 # service ticket identifying a different server principal.
525 self._run_test_sequence([
527 'rep_type': KRB_AS_REP,
528 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
529 'use_fast': True,
530 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
531 'gen_armor_tgt_fn': self.get_user_service_ticket
534 'rep_type': KRB_AS_REP,
535 'expected_error_mode': 0,
536 'use_fast': True,
537 'gen_padata_fn': self.generate_enc_challenge_padata,
538 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
539 'gen_armor_tgt_fn': self.get_user_service_ticket
540 # ticket not identifying TGS of current
541 # realm
545 def test_fast_invalid_tgt_mach(self):
546 self._run_test_sequence([
548 'rep_type': KRB_AS_REP,
549 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
550 'use_fast': True,
551 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
552 'gen_armor_tgt_fn': self.get_mach_service_ticket
555 'rep_type': KRB_AS_REP,
556 'expected_error_mode': 0,
557 'use_fast': True,
558 'gen_padata_fn': self.generate_enc_challenge_padata,
559 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
560 'gen_armor_tgt_fn': self.get_mach_service_ticket
561 # ticket not identifying TGS of current
562 # realm
566 def test_fast_enc_timestamp(self):
567 # Provide ENC-TIMESTAMP as FAST padata when we should be providing
568 # ENCRYPTED-CHALLENGE - ensure that we get PREAUTH_REQUIRED.
569 self._run_test_sequence([
571 'rep_type': KRB_AS_REP,
572 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
573 'use_fast': True,
574 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
575 'gen_armor_tgt_fn': self.get_mach_tgt
578 'rep_type': KRB_AS_REP,
579 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
580 'use_fast': True,
581 'gen_padata_fn': self.generate_enc_timestamp_padata,
582 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
583 'gen_armor_tgt_fn': self.get_mach_tgt
587 def test_fast(self):
588 self._run_test_sequence([
590 'rep_type': KRB_AS_REP,
591 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
592 'use_fast': True,
593 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
594 'gen_armor_tgt_fn': self.get_mach_tgt
597 'rep_type': KRB_AS_REP,
598 'expected_error_mode': 0,
599 'use_fast': True,
600 'gen_padata_fn': self.generate_enc_challenge_padata,
601 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
602 'gen_armor_tgt_fn': self.get_mach_tgt
606 def test_fast_tgs(self):
607 self._run_test_sequence([
609 'rep_type': KRB_TGS_REP,
610 'expected_error_mode': 0,
611 'use_fast': True,
612 'gen_tgt_fn': self.get_user_tgt,
613 'fast_armor': None
617 def test_fast_tgs_armor(self):
618 self._run_test_sequence([
620 'rep_type': KRB_TGS_REP,
621 'expected_error_mode': 0,
622 'use_fast': True,
623 'gen_tgt_fn': self.get_user_tgt,
624 'gen_armor_tgt_fn': self.get_mach_tgt,
625 'fast_armor': FX_FAST_ARMOR_AP_REQUEST
629 def test_fast_outer_wrong_realm(self):
630 self._run_test_sequence([
632 'rep_type': KRB_AS_REP,
633 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
634 'use_fast': True,
635 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
636 'gen_armor_tgt_fn': self.get_mach_tgt,
637 'outer_req': {
638 'realm': 'TEST' # should be ignored
642 'rep_type': KRB_AS_REP,
643 'expected_error_mode': 0,
644 'use_fast': True,
645 'gen_padata_fn': self.generate_enc_challenge_padata,
646 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
647 'gen_armor_tgt_fn': self.get_mach_tgt,
648 'outer_req': {
649 'realm': 'TEST' # should be ignored
654 def test_fast_tgs_outer_wrong_realm(self):
655 self._run_test_sequence([
657 'rep_type': KRB_TGS_REP,
658 'expected_error_mode': 0,
659 'use_fast': True,
660 'gen_tgt_fn': self.get_user_tgt,
661 'fast_armor': None,
662 'outer_req': {
663 'realm': 'TEST' # should be ignored
668 def test_fast_outer_wrong_nonce(self):
669 self._run_test_sequence([
671 'rep_type': KRB_AS_REP,
672 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
673 'use_fast': True,
674 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
675 'gen_armor_tgt_fn': self.get_mach_tgt,
676 'outer_req': {
677 'nonce': '123' # should be ignored
681 'rep_type': KRB_AS_REP,
682 'expected_error_mode': 0,
683 'use_fast': True,
684 'gen_padata_fn': self.generate_enc_challenge_padata,
685 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
686 'gen_armor_tgt_fn': self.get_mach_tgt,
687 'outer_req': {
688 'nonce': '123' # should be ignored
693 def test_fast_tgs_outer_wrong_nonce(self):
694 self._run_test_sequence([
696 'rep_type': KRB_TGS_REP,
697 'expected_error_mode': 0,
698 'use_fast': True,
699 'gen_tgt_fn': self.get_user_tgt,
700 'fast_armor': None,
701 'outer_req': {
702 'nonce': '123' # should be ignored
707 def test_fast_outer_wrong_flags(self):
708 self._run_test_sequence([
710 'rep_type': KRB_AS_REP,
711 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
712 'use_fast': True,
713 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
714 'gen_armor_tgt_fn': self.get_mach_tgt,
715 'outer_req': {
716 'kdc-options': '11111111111111111' # should be ignored
720 'rep_type': KRB_AS_REP,
721 'expected_error_mode': 0,
722 'use_fast': True,
723 'gen_padata_fn': self.generate_enc_challenge_padata,
724 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
725 'gen_armor_tgt_fn': self.get_mach_tgt,
726 'outer_req': {
727 'kdc-options': '11111111111111111' # should be ignored
732 def test_fast_tgs_outer_wrong_flags(self):
733 self._run_test_sequence([
735 'rep_type': KRB_TGS_REP,
736 'expected_error_mode': 0,
737 'use_fast': True,
738 'gen_tgt_fn': self.get_user_tgt,
739 'fast_armor': None,
740 'outer_req': {
741 'kdc-options': '11111111111111111' # should be ignored
746 def test_fast_outer_no_sname(self):
747 self._run_test_sequence([
749 'rep_type': KRB_AS_REP,
750 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
751 'use_fast': True,
752 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
753 'gen_armor_tgt_fn': self.get_mach_tgt,
754 'outer_req': {
755 'sname': None # should be ignored
759 'rep_type': KRB_AS_REP,
760 'expected_error_mode': 0,
761 'use_fast': True,
762 'gen_padata_fn': self.generate_enc_challenge_padata,
763 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
764 'gen_armor_tgt_fn': self.get_mach_tgt,
765 'outer_req': {
766 'sname': None # should be ignored
771 def test_fast_tgs_outer_no_sname(self):
772 self._run_test_sequence([
774 'rep_type': KRB_TGS_REP,
775 'expected_error_mode': 0,
776 'use_fast': True,
777 'gen_tgt_fn': self.get_user_tgt,
778 'fast_armor': None,
779 'outer_req': {
780 'sname': None # should be ignored
785 def test_fast_outer_wrong_till(self):
786 self._run_test_sequence([
788 'rep_type': KRB_AS_REP,
789 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
790 'use_fast': True,
791 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
792 'gen_armor_tgt_fn': self.get_mach_tgt,
793 'outer_req': {
794 'till': '15000101000000Z' # should be ignored
798 'rep_type': KRB_AS_REP,
799 'expected_error_mode': 0,
800 'use_fast': True,
801 'gen_padata_fn': self.generate_enc_challenge_padata,
802 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
803 'gen_armor_tgt_fn': self.get_mach_tgt,
804 'outer_req': {
805 'till': '15000101000000Z' # should be ignored
810 def test_fast_tgs_outer_wrong_till(self):
811 self._run_test_sequence([
813 'rep_type': KRB_TGS_REP,
814 'expected_error_mode': 0,
815 'use_fast': True,
816 'gen_tgt_fn': self.get_user_tgt,
817 'fast_armor': None,
818 'outer_req': {
819 'till': '15000101000000Z' # should be ignored
824 def test_fast_authdata_fast_used(self):
825 self._run_test_sequence([
827 'rep_type': KRB_TGS_REP,
828 'expected_error_mode': 0,
829 'use_fast': True,
830 'gen_authdata_fn': self.generate_fast_used_auth_data,
831 'gen_tgt_fn': self.get_user_tgt,
832 'fast_armor': None
836 def test_fast_authdata_fast_not_used(self):
837 # The AD-fx-fast-used authdata type can be included in the
838 # authenticator or the TGT authentication data to indicate that FAST
839 # must be used. The KDC must return KRB_APP_ERR_MODIFIED if it receives
840 # this authdata type in a request not using FAST (RFC6113 5.4.2).
841 self._run_test_sequence([
842 # This request works without FAST.
844 'rep_type': KRB_TGS_REP,
845 'expected_error_mode': 0,
846 'use_fast': False,
847 'gen_tgt_fn': self.get_user_tgt
849 # Add the 'FAST used' auth data and it now fails.
851 'rep_type': KRB_TGS_REP,
852 'expected_error_mode': KDC_ERR_GENERIC,
853 # should be KRB_APP_ERR_MODIFIED
854 'use_fast': False,
855 'gen_authdata_fn': self.generate_fast_used_auth_data,
856 'gen_tgt_fn': self.get_user_tgt
860 def test_fast_ad_fx_fast_armor(self):
861 # If the authenticator or TGT authentication data contains the
862 # AD-fx-fast-armor authdata type, the KDC must reject the request
863 # (RFC6113 5.4.1.1).
864 self._run_test_sequence([
865 # This request works.
867 'rep_type': KRB_TGS_REP,
868 'expected_error_mode': 0,
869 'use_fast': True,
870 'gen_tgt_fn': self.get_user_tgt,
871 'fast_armor': None
873 # Add the 'FAST armor' auth data and it now fails.
875 'rep_type': KRB_TGS_REP,
876 'expected_error_mode': KDC_ERR_GENERIC,
877 'use_fast': True,
878 'gen_authdata_fn': self.generate_fast_armor_auth_data,
879 'gen_tgt_fn': self.get_user_tgt,
880 'fast_armor': None
884 def test_fast_ad_fx_fast_armor2(self):
885 # Show that we can still use the AD-fx-fast-armor authorization data in
886 # FAST armor tickets.
887 self._run_test_sequence([
889 'rep_type': KRB_AS_REP,
890 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
891 'use_fast': True,
892 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
893 'gen_armor_tgt_fn': self.get_mach_tgt
896 'rep_type': KRB_AS_REP,
897 'expected_error_mode': 0,
898 'use_fast': True,
899 'gen_padata_fn': self.generate_enc_challenge_padata,
900 'gen_authdata_fn': self.generate_fast_armor_auth_data,
901 # include the auth data in the FAST armor.
902 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
903 'gen_armor_tgt_fn': self.get_mach_tgt
907 def test_fast_ad_fx_fast_armor_ticket(self):
908 # If the authenticator or TGT authentication data contains the
909 # AD-fx-fast-armor authdata type, the KDC must reject the request
910 # (RFC6113 5.4.2).
911 self._run_test_sequence([
912 # This request works.
914 'rep_type': KRB_TGS_REP,
915 'expected_error_mode': 0,
916 'use_fast': True,
917 'gen_tgt_fn': self.get_user_tgt,
918 'fast_armor': None
920 # Add AD-fx-fast-armor authdata element to user TGT. This request
921 # fails.
923 'rep_type': KRB_TGS_REP,
924 'expected_error_mode': KDC_ERR_GENERIC,
925 'use_fast': True,
926 'gen_tgt_fn': self.gen_tgt_fast_armor_auth_data,
927 'fast_armor': None
931 def test_fast_ad_fx_fast_armor_ticket2(self):
932 self._run_test_sequence([
933 # Show that we can still use the modified ticket as armor.
935 'rep_type': KRB_AS_REP,
936 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
937 'use_fast': True,
938 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
939 'gen_armor_tgt_fn': self.get_mach_tgt
942 'rep_type': KRB_AS_REP,
943 'expected_error_mode': 0,
944 'use_fast': True,
945 'gen_padata_fn': self.generate_enc_challenge_padata,
946 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
947 'gen_armor_tgt_fn': self.gen_tgt_fast_armor_auth_data
951 def test_fast_tgs_service_ticket(self):
952 # Try to use a non-TGT ticket to establish an armor key, which fails
953 # (RFC6113 5.4.2).
954 self._run_test_sequence([
956 'rep_type': KRB_TGS_REP,
957 'expected_error_mode': KDC_ERR_NOT_US,
958 'use_fast': True,
959 'gen_tgt_fn': self.get_user_service_ticket, # fails
960 'fast_armor': None
964 def test_fast_tgs_service_ticket_mach(self):
965 self._run_test_sequence([
967 'rep_type': KRB_TGS_REP,
968 'expected_error_mode': KDC_ERR_NOT_US, # fails
969 'use_fast': True,
970 'gen_tgt_fn': self.get_mach_service_ticket,
971 'fast_armor': None
975 def test_simple_tgs_no_subkey(self):
976 self._run_test_sequence([
978 'rep_type': KRB_TGS_REP,
979 'expected_error_mode': 0,
980 'use_fast': False,
981 'gen_tgt_fn': self.get_user_tgt,
982 'include_subkey': False
986 def test_fast_tgs_no_subkey(self):
987 # Show that omitting the subkey in the TGS-REQ authenticator fails
988 # (RFC6113 5.4.2).
989 self._run_test_sequence([
991 'rep_type': KRB_TGS_REP,
992 'expected_error_mode': KDC_ERR_GENERIC,
993 'use_fast': True,
994 'gen_tgt_fn': self.get_user_tgt,
995 'fast_armor': None,
996 'include_subkey': False
1000 def test_fast_hide_client_names(self):
1001 user_creds = self.get_client_creds()
1002 user_name = user_creds.get_username()
1003 user_cname = self.PrincipalName_create(name_type=NT_PRINCIPAL,
1004 names=[user_name])
1006 expected_cname = self.PrincipalName_create(
1007 name_type=NT_WELLKNOWN, names=['WELLKNOWN', 'ANONYMOUS'])
1009 self._run_test_sequence([
1011 'rep_type': KRB_AS_REP,
1012 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
1013 'use_fast': True,
1014 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
1015 'gen_armor_tgt_fn': self.get_mach_tgt,
1016 'fast_options': '01', # hide client names
1017 'expected_cname': expected_cname
1020 'rep_type': KRB_AS_REP,
1021 'expected_error_mode': 0,
1022 'use_fast': True,
1023 'gen_padata_fn': self.generate_enc_challenge_padata,
1024 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
1025 'gen_armor_tgt_fn': self.get_mach_tgt,
1026 'fast_options': '01', # hide client names
1027 'expected_cname': expected_cname,
1028 'expected_cname_private': user_cname
1032 def test_fast_tgs_hide_client_names(self):
1033 user_creds = self.get_client_creds()
1034 user_name = user_creds.get_username()
1035 user_cname = self.PrincipalName_create(name_type=NT_PRINCIPAL,
1036 names=[user_name])
1038 expected_cname = self.PrincipalName_create(
1039 name_type=NT_WELLKNOWN, names=['WELLKNOWN', 'ANONYMOUS'])
1041 self._run_test_sequence([
1043 'rep_type': KRB_TGS_REP,
1044 'expected_error_mode': 0,
1045 'use_fast': True,
1046 'gen_tgt_fn': self.get_user_tgt,
1047 'fast_armor': None,
1048 'fast_options': '01', # hide client names
1049 'expected_cname': expected_cname,
1050 'expected_cname_private': user_cname
1054 def test_fast_encrypted_challenge_replay(self):
1055 # The KDC is supposed to check that encrypted challenges are not
1056 # replays (RFC6113 5.4.6), but timestamps may be reused; an encrypted
1057 # challenge is only considered a replay if the ciphertext is identical
1058 # to a previous challenge. Windows does not perform this check.
1060 class GenerateEncChallengePadataReplay:
1061 def __init__(replay):
1062 replay._padata = None
1064 def __call__(replay, key, armor_key):
1065 if replay._padata is None:
1066 client_challenge_key = (
1067 self.generate_client_challenge_key(armor_key, key))
1068 replay._padata = self.get_challenge_pa_data(
1069 client_challenge_key)
1071 return replay._padata
1073 self._run_test_sequence([
1075 'rep_type': KRB_AS_REP,
1076 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
1077 'use_fast': True,
1078 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
1079 'gen_armor_tgt_fn': self.get_mach_tgt
1082 'rep_type': KRB_AS_REP,
1083 'expected_error_mode': 0,
1084 'use_fast': True,
1085 'gen_padata_fn': GenerateEncChallengePadataReplay(),
1086 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
1087 'gen_armor_tgt_fn': self.get_mach_tgt,
1088 'repeat': 2
1092 def generate_enc_timestamp_padata(self, key, _armor_key):
1093 return self.get_enc_timestamp_pa_data_from_key(key)
1095 def generate_enc_challenge_padata(self, key, armor_key, skew=0):
1096 client_challenge_key = (
1097 self.generate_client_challenge_key(armor_key, key))
1098 return self.get_challenge_pa_data(client_challenge_key, skew=skew)
1100 def generate_enc_challenge_padata_wrong_key_kdc(self, key, armor_key):
1101 kdc_challenge_key = (
1102 self.generate_kdc_challenge_key(armor_key, key))
1103 return self.get_challenge_pa_data(kdc_challenge_key)
1105 def generate_enc_challenge_padata_wrong_key(self, key, _armor_key):
1106 return self.get_challenge_pa_data(key)
1108 def generate_empty_fast(self,
1109 _kdc_exchange_dict,
1110 _callback_dict,
1111 _req_body,
1112 _fast_padata,
1113 _fast_armor,
1114 _checksum,
1115 _fast_options=''):
1116 fast_padata = self.PA_DATA_create(PADATA_FX_FAST, b'')
1118 return fast_padata
1120 def _run_test_sequence(self, test_sequence):
1121 if self.strict_checking:
1122 self.check_kdc_fast_support()
1124 kdc_options_default = str(krb5_asn1.KDCOptions('forwardable,'
1125 'renewable,'
1126 'canonicalize,'
1127 'renewable-ok'))
1129 pac_request = self.get_pa_pac_request()
1131 client_creds = self.get_client_creds()
1132 target_creds = self.get_service_creds()
1133 krbtgt_creds = self.get_krbtgt_creds()
1135 client_username = client_creds.get_username()
1136 client_realm = client_creds.get_realm()
1137 client_cname = self.PrincipalName_create(name_type=NT_PRINCIPAL,
1138 names=[client_username])
1140 krbtgt_username = krbtgt_creds.get_username()
1141 krbtgt_realm = krbtgt_creds.get_realm()
1142 krbtgt_sname = self.PrincipalName_create(
1143 name_type=NT_SRV_INST, names=[krbtgt_username, krbtgt_realm])
1144 krbtgt_decryption_key = self.TicketDecryptionKey_from_creds(
1145 krbtgt_creds)
1147 target_username = target_creds.get_username()[:-1]
1148 target_realm = target_creds.get_realm()
1149 target_service = 'host'
1150 target_sname = self.PrincipalName_create(
1151 name_type=NT_SRV_INST, names=[target_service, target_username])
1152 target_decryption_key = self.TicketDecryptionKey_from_creds(
1153 target_creds, etype=kcrypto.Enctype.RC4)
1155 fast_cookie = None
1156 preauth_etype_info2 = None
1158 preauth_key = None
1160 for kdc_dict in test_sequence:
1161 rep_type = kdc_dict.pop('rep_type')
1162 self.assertIn(rep_type, (KRB_AS_REP, KRB_TGS_REP))
1164 expected_error_mode = kdc_dict.pop('expected_error_mode')
1165 self.assertIn(expected_error_mode, range(240))
1167 use_fast = kdc_dict.pop('use_fast')
1168 self.assertIs(type(use_fast), bool)
1170 if use_fast:
1171 self.assertIn('fast_armor', kdc_dict)
1172 fast_armor_type = kdc_dict.pop('fast_armor')
1174 if fast_armor_type is not None:
1175 self.assertIn('gen_armor_tgt_fn', kdc_dict)
1176 elif expected_error_mode != KDC_ERR_GENERIC:
1177 self.assertNotIn('gen_armor_tgt_fn', kdc_dict)
1179 gen_armor_tgt_fn = kdc_dict.pop('gen_armor_tgt_fn', None)
1180 if gen_armor_tgt_fn is not None:
1181 armor_tgt = gen_armor_tgt_fn()
1182 else:
1183 armor_tgt = None
1185 fast_options = kdc_dict.pop('fast_options', '')
1186 else:
1187 fast_armor_type = None
1188 armor_tgt = None
1190 self.assertNotIn('fast_options', kdc_dict)
1191 fast_options = None
1193 if rep_type == KRB_TGS_REP:
1194 gen_tgt_fn = kdc_dict.pop('gen_tgt_fn')
1195 tgt = gen_tgt_fn()
1196 else:
1197 self.assertNotIn('gen_tgt_fn', kdc_dict)
1198 tgt = None
1200 if expected_error_mode != 0:
1201 check_error_fn = self.generic_check_kdc_error
1202 check_rep_fn = None
1203 else:
1204 check_error_fn = None
1205 check_rep_fn = self.generic_check_kdc_rep
1207 etypes = kdc_dict.pop('etypes', (AES256_CTS_HMAC_SHA1_96,
1208 ARCFOUR_HMAC_MD5))
1210 cname = client_cname if rep_type == KRB_AS_REP else None
1211 crealm = client_realm
1213 if 'sname' in kdc_dict:
1214 sname = kdc_dict.pop('sname')
1215 else:
1216 if rep_type == KRB_AS_REP:
1217 sname = krbtgt_sname
1218 else: # KRB_TGS_REP
1219 sname = target_sname
1221 if rep_type == KRB_AS_REP:
1222 srealm = krbtgt_realm
1223 else: # KRB_TGS_REP
1224 srealm = target_realm
1226 expected_cname = kdc_dict.pop('expected_cname', client_cname)
1227 expected_cname_private = kdc_dict.pop('expected_cname_private',
1228 None)
1229 expected_crealm = kdc_dict.pop('expected_crealm', client_realm)
1230 expected_sname = kdc_dict.pop('expected_sname', sname)
1231 expected_srealm = kdc_dict.pop('expected_srealm', srealm)
1233 expected_salt = client_creds.get_salt()
1235 authenticator_subkey = self.RandomKey(kcrypto.Enctype.AES256)
1236 if rep_type == KRB_AS_REP:
1237 if use_fast:
1238 armor_key = self.generate_armor_key(authenticator_subkey,
1239 armor_tgt.session_key)
1240 armor_subkey = authenticator_subkey
1241 else:
1242 armor_key = None
1243 armor_subkey = authenticator_subkey
1244 else: # KRB_TGS_REP
1245 if fast_armor_type is not None:
1246 armor_subkey = self.RandomKey(kcrypto.Enctype.AES256)
1247 explicit_armor_key = self.generate_armor_key(
1248 armor_subkey,
1249 armor_tgt.session_key)
1250 armor_key = kcrypto.cf2(explicit_armor_key.key,
1251 authenticator_subkey.key,
1252 b'explicitarmor',
1253 b'tgsarmor')
1254 armor_key = Krb5EncryptionKey(armor_key, None)
1255 else:
1256 armor_key = self.generate_armor_key(authenticator_subkey,
1257 tgt.session_key)
1258 armor_subkey = authenticator_subkey
1260 if not kdc_dict.pop('include_subkey', True):
1261 authenticator_subkey = None
1263 if use_fast:
1264 generate_fast_fn = kdc_dict.pop('gen_fast_fn', None)
1265 if generate_fast_fn is None:
1266 generate_fast_fn = functools.partial(
1267 self.generate_simple_fast,
1268 fast_options=fast_options)
1269 else:
1270 generate_fast_fn = None
1272 generate_fast_armor_fn = (
1273 self.generate_ap_req
1274 if fast_armor_type is not None
1275 else None)
1277 def _generate_padata_copy(_kdc_exchange_dict,
1278 _callback_dict,
1279 req_body,
1280 padata):
1281 return padata, req_body
1283 def _check_padata_preauth_key(_kdc_exchange_dict,
1284 _callback_dict,
1285 _rep,
1286 _padata):
1287 as_rep_usage = KU_AS_REP_ENC_PART
1288 return preauth_key, as_rep_usage
1290 pac_options = kdc_dict.pop('pac_options', '1') # claims support
1291 pac_options = self.get_pa_pac_options(pac_options)
1293 kdc_options = kdc_dict.pop('kdc_options', kdc_options_default)
1295 if rep_type == KRB_AS_REP:
1296 padata = [pac_request, pac_options]
1297 else:
1298 padata = [pac_options]
1300 gen_padata_fn = kdc_dict.pop('gen_padata_fn', None)
1301 if gen_padata_fn is not None:
1302 self.assertEqual(KRB_AS_REP, rep_type)
1303 self.assertIsNotNone(preauth_etype_info2)
1305 preauth_key = self.PasswordKey_from_etype_info2(
1306 client_creds,
1307 preauth_etype_info2[0],
1308 client_creds.get_kvno())
1309 gen_padata = gen_padata_fn(preauth_key, armor_key)
1310 padata.insert(0, gen_padata)
1311 else:
1312 preauth_key = None
1314 if rep_type == KRB_AS_REP:
1315 check_padata_fn = _check_padata_preauth_key
1316 else:
1317 check_padata_fn = self.check_simple_tgs_padata
1319 if use_fast:
1320 inner_padata = padata
1321 outer_padata = []
1322 else:
1323 inner_padata = []
1324 outer_padata = padata
1326 if use_fast and fast_cookie is not None:
1327 outer_padata.append(fast_cookie)
1329 generate_fast_padata_fn = (functools.partial(_generate_padata_copy,
1330 padata=inner_padata)
1331 if inner_padata else None)
1332 generate_padata_fn = (functools.partial(_generate_padata_copy,
1333 padata=outer_padata)
1334 if outer_padata else None)
1336 gen_authdata_fn = kdc_dict.pop('gen_authdata_fn', None)
1337 if gen_authdata_fn is not None:
1338 auth_data = [gen_authdata_fn()]
1339 else:
1340 auth_data = None
1342 if not use_fast:
1343 self.assertNotIn('inner_req', kdc_dict)
1344 self.assertNotIn('outer_req', kdc_dict)
1345 inner_req = kdc_dict.pop('inner_req', None)
1346 outer_req = kdc_dict.pop('outer_req', None)
1348 if rep_type == KRB_AS_REP:
1349 kdc_exchange_dict = self.as_exchange_dict(
1350 expected_crealm=expected_crealm,
1351 expected_cname=expected_cname,
1352 expected_cname_private=expected_cname_private,
1353 expected_srealm=expected_srealm,
1354 expected_sname=expected_sname,
1355 ticket_decryption_key=krbtgt_decryption_key,
1356 generate_fast_fn=generate_fast_fn,
1357 generate_fast_armor_fn=generate_fast_armor_fn,
1358 generate_fast_padata_fn=generate_fast_padata_fn,
1359 fast_armor_type=fast_armor_type,
1360 generate_padata_fn=generate_padata_fn,
1361 check_error_fn=check_error_fn,
1362 check_rep_fn=check_rep_fn,
1363 check_padata_fn=check_padata_fn,
1364 check_kdc_private_fn=self.generic_check_kdc_private,
1365 callback_dict={},
1366 expected_error_mode=expected_error_mode,
1367 client_as_etypes=etypes,
1368 expected_salt=expected_salt,
1369 authenticator_subkey=authenticator_subkey,
1370 auth_data=auth_data,
1371 armor_key=armor_key,
1372 armor_tgt=armor_tgt,
1373 armor_subkey=armor_subkey,
1374 kdc_options=kdc_options,
1375 inner_req=inner_req,
1376 outer_req=outer_req)
1377 else: # KRB_TGS_REP
1378 kdc_exchange_dict = self.tgs_exchange_dict(
1379 expected_crealm=expected_crealm,
1380 expected_cname=expected_cname,
1381 expected_cname_private=expected_cname_private,
1382 expected_srealm=expected_srealm,
1383 expected_sname=expected_sname,
1384 ticket_decryption_key=target_decryption_key,
1385 generate_fast_fn=generate_fast_fn,
1386 generate_fast_armor_fn=generate_fast_armor_fn,
1387 generate_fast_padata_fn=generate_fast_padata_fn,
1388 fast_armor_type=fast_armor_type,
1389 generate_padata_fn=generate_padata_fn,
1390 check_error_fn=check_error_fn,
1391 check_rep_fn=check_rep_fn,
1392 check_padata_fn=check_padata_fn,
1393 check_kdc_private_fn=self.generic_check_kdc_private,
1394 expected_error_mode=expected_error_mode,
1395 callback_dict={},
1396 tgt=tgt,
1397 armor_key=armor_key,
1398 armor_tgt=armor_tgt,
1399 armor_subkey=armor_subkey,
1400 authenticator_subkey=authenticator_subkey,
1401 auth_data=auth_data,
1402 body_checksum_type=None,
1403 kdc_options=kdc_options,
1404 inner_req=inner_req,
1405 outer_req=outer_req)
1407 repeat = kdc_dict.pop('repeat', 1)
1408 for _ in range(repeat):
1409 rep = self._generic_kdc_exchange(kdc_exchange_dict,
1410 cname=cname,
1411 realm=crealm,
1412 sname=sname,
1413 etypes=etypes)
1414 if expected_error_mode == 0:
1415 self.check_reply(rep, rep_type)
1417 fast_cookie = None
1418 preauth_etype_info2 = None
1419 else:
1420 self.check_error_rep(rep, expected_error_mode)
1422 if 'fast_cookie' in kdc_exchange_dict:
1423 fast_cookie = self.create_fast_cookie(
1424 kdc_exchange_dict['fast_cookie'])
1425 else:
1426 fast_cookie = None
1428 if expected_error_mode == KDC_ERR_PREAUTH_REQUIRED:
1429 preauth_etype_info2 = (
1430 kdc_exchange_dict['preauth_etype_info2'])
1431 else:
1432 preauth_etype_info2 = None
1434 # Ensure we used all the parameters given to us.
1435 self.assertEqual({}, kdc_dict)
1437 def generate_fast_armor_auth_data(self):
1438 auth_data = self.AuthorizationData_create(AD_FX_FAST_ARMOR, b'')
1440 return auth_data
1442 def generate_fast_used_auth_data(self):
1443 auth_data = self.AuthorizationData_create(AD_FX_FAST_USED, b'')
1445 return auth_data
1447 def gen_tgt_fast_armor_auth_data(self):
1448 user_tgt = self.get_user_tgt()
1450 ticket_decryption_key = user_tgt.decryption_key
1452 tgt_encpart = self.getElementValue(user_tgt.ticket, 'enc-part')
1453 self.assertElementEqual(tgt_encpart, 'etype',
1454 ticket_decryption_key.etype)
1455 self.assertElementKVNO(tgt_encpart, 'kvno',
1456 ticket_decryption_key.kvno)
1457 tgt_cipher = self.getElementValue(tgt_encpart, 'cipher')
1458 tgt_decpart = ticket_decryption_key.decrypt(KU_TICKET, tgt_cipher)
1459 tgt_private = self.der_decode(tgt_decpart,
1460 asn1Spec=krb5_asn1.EncTicketPart())
1462 auth_data = self.generate_fast_armor_auth_data()
1463 tgt_private['authorization-data'].append(auth_data)
1465 # Re-encrypt the user TGT.
1466 tgt_private_new = self.der_encode(
1467 tgt_private,
1468 asn1Spec=krb5_asn1.EncTicketPart())
1469 tgt_encpart = self.EncryptedData_create(ticket_decryption_key,
1470 KU_TICKET,
1471 tgt_private_new)
1472 user_ticket = user_tgt.ticket.copy()
1473 user_ticket['enc-part'] = tgt_encpart
1475 user_tgt = KerberosTicketCreds(
1476 user_ticket,
1477 session_key=user_tgt.session_key,
1478 crealm=user_tgt.crealm,
1479 cname=user_tgt.cname,
1480 srealm=user_tgt.srealm,
1481 sname=user_tgt.sname,
1482 decryption_key=user_tgt.decryption_key,
1483 ticket_private=tgt_private,
1484 encpart_private=user_tgt.encpart_private)
1486 # Use our modifed TGT to replace the one in the request.
1487 return user_tgt
1489 def create_fast_cookie(self, cookie):
1490 self.assertIsNotNone(cookie)
1491 if self.strict_checking:
1492 self.assertNotEqual(0, len(cookie))
1494 return self.PA_DATA_create(PADATA_FX_COOKIE, cookie)
1496 def get_pa_pac_request(self, request_pac=True):
1497 pac_request = self.KERB_PA_PAC_REQUEST_create(request_pac)
1499 return pac_request
1501 def get_pa_pac_options(self, options):
1502 pac_options = self.PA_PAC_OPTIONS_create(options)
1503 pac_options = self.der_encode(pac_options,
1504 asn1Spec=krb5_asn1.PA_PAC_OPTIONS())
1505 pac_options = self.PA_DATA_create(PADATA_PAC_OPTIONS, pac_options)
1507 return pac_options
1509 def check_kdc_fast_support(self):
1510 # Check that the KDC supports FAST
1512 samdb = self.get_samdb()
1514 krbtgt_rid = 502
1515 krbtgt_sid = '%s-%d' % (samdb.get_domain_sid(), krbtgt_rid)
1517 res = samdb.search(base='<SID=%s>' % krbtgt_sid,
1518 scope=ldb.SCOPE_BASE,
1519 attrs=['msDS-SupportedEncryptionTypes'])
1521 krbtgt_etypes = int(res[0]['msDS-SupportedEncryptionTypes'][0])
1523 self.assertTrue(
1524 security.KERB_ENCTYPE_FAST_SUPPORTED & krbtgt_etypes)
1525 self.assertTrue(
1526 security.KERB_ENCTYPE_COMPOUND_IDENTITY_SUPPORTED & krbtgt_etypes)
1527 self.assertTrue(
1528 security.KERB_ENCTYPE_CLAIMS_SUPPORTED & krbtgt_etypes)
1530 def get_service_ticket(self, tgt, target_creds, service='host'):
1531 etype = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5)
1533 key = tgt.session_key
1534 ticket = tgt.ticket
1536 cname = tgt.cname
1537 realm = tgt.crealm
1539 target_name = target_creds.get_username()[:-1]
1540 sname = self.PrincipalName_create(name_type=NT_PRINCIPAL,
1541 names=[service, target_name])
1543 rep, enc_part = self.tgs_req(cname, sname, realm, ticket, key, etype)
1545 service_ticket = rep['ticket']
1547 ticket_etype = service_ticket['enc-part']['etype']
1548 target_key = self.TicketDecryptionKey_from_creds(target_creds,
1549 etype=ticket_etype)
1551 session_key = self.EncryptionKey_import(enc_part['key'])
1553 service_ticket_creds = KerberosTicketCreds(service_ticket,
1554 session_key,
1555 crealm=realm,
1556 cname=cname,
1557 srealm=realm,
1558 sname=sname,
1559 decryption_key=target_key)
1561 return service_ticket_creds
1563 def get_tgt(self, creds):
1564 user_name = creds.get_username()
1565 realm = creds.get_realm()
1567 salt = creds.get_salt()
1569 etype = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5)
1570 cname = self.PrincipalName_create(name_type=NT_PRINCIPAL,
1571 names=[user_name])
1572 sname = self.PrincipalName_create(name_type=NT_SRV_INST,
1573 names=['krbtgt', realm])
1575 till = self.get_KerberosTime(offset=36000)
1577 krbtgt_creds = self.get_krbtgt_creds()
1578 ticket_decryption_key = (
1579 self.TicketDecryptionKey_from_creds(krbtgt_creds))
1581 kdc_options = str(krb5_asn1.KDCOptions('forwardable,'
1582 'renewable,'
1583 'canonicalize,'
1584 'renewable-ok'))
1586 pac_request = self.get_pa_pac_request()
1587 pac_options = self.get_pa_pac_options('1') # supports claims
1589 padata = [pac_request, pac_options]
1591 rep, kdc_exchange_dict = self._test_as_exchange(
1592 cname=cname,
1593 realm=realm,
1594 sname=sname,
1595 till=till,
1596 client_as_etypes=etype,
1597 expected_error_mode=KDC_ERR_PREAUTH_REQUIRED,
1598 expected_crealm=realm,
1599 expected_cname=cname,
1600 expected_srealm=realm,
1601 expected_sname=sname,
1602 expected_salt=salt,
1603 etypes=etype,
1604 padata=padata,
1605 kdc_options=kdc_options,
1606 preauth_key=None,
1607 ticket_decryption_key=ticket_decryption_key)
1608 self.check_pre_authentication(rep)
1610 etype_info2 = kdc_exchange_dict['preauth_etype_info2']
1612 preauth_key = self.PasswordKey_from_etype_info2(creds,
1613 etype_info2[0],
1614 creds.get_kvno())
1616 ts_enc_padata = self.get_enc_timestamp_pa_data(creds, rep)
1618 padata = [ts_enc_padata, pac_request, pac_options]
1620 expected_realm = realm.upper()
1622 expected_sname = self.PrincipalName_create(
1623 name_type=NT_SRV_INST, names=['krbtgt', realm.upper()])
1625 rep, kdc_exchange_dict = self._test_as_exchange(
1626 cname=cname,
1627 realm=realm,
1628 sname=sname,
1629 till=till,
1630 client_as_etypes=etype,
1631 expected_error_mode=0,
1632 expected_crealm=expected_realm,
1633 expected_cname=cname,
1634 expected_srealm=expected_realm,
1635 expected_sname=expected_sname,
1636 expected_salt=salt,
1637 etypes=etype,
1638 padata=padata,
1639 kdc_options=kdc_options,
1640 preauth_key=preauth_key,
1641 ticket_decryption_key=ticket_decryption_key)
1642 self.check_as_reply(rep)
1644 tgt = rep['ticket']
1646 enc_part = self.get_as_rep_enc_data(preauth_key, rep)
1647 session_key = self.EncryptionKey_import(enc_part['key'])
1649 ticket_creds = KerberosTicketCreds(
1650 tgt,
1651 session_key,
1652 crealm=realm,
1653 cname=cname,
1654 srealm=realm,
1655 sname=sname,
1656 decryption_key=ticket_decryption_key)
1658 return ticket_creds, enc_part
1660 def get_mach_tgt(self):
1661 if self.mach_tgt is None:
1662 mach_creds = self.get_mach_creds()
1663 type(self).mach_tgt, type(self).mach_enc_part = (
1664 self.get_tgt(mach_creds))
1666 return self.mach_tgt
1668 def get_user_tgt(self):
1669 if self.user_tgt is None:
1670 user_creds = self.get_client_creds()
1671 type(self).user_tgt, type(self).user_enc_part = (
1672 self.get_tgt(user_creds))
1674 return self.user_tgt
1676 def get_user_service_ticket(self):
1677 if self.user_service_ticket is None:
1678 user_tgt = self.get_user_tgt()
1679 service_creds = self.get_service_creds()
1680 type(self).user_service_ticket = (
1681 self.get_service_ticket(user_tgt, service_creds))
1683 return self.user_service_ticket
1685 def get_mach_service_ticket(self):
1686 if self.mach_service_ticket is None:
1687 mach_tgt = self.get_mach_tgt()
1688 service_creds = self.get_service_creds()
1689 type(self).mach_service_ticket = (
1690 self.get_service_ticket(mach_tgt, service_creds))
1692 return self.mach_service_ticket
1695 if __name__ == "__main__":
1696 global_asn1_print = False
1697 global_hexdump = False
1698 import unittest
1699 unittest.main()