tests/krb5: Add tests for RODC-issued armor tickets
[samba.git] / python / samba / tests / krb5 / fast_tests.py
1 #!/usr/bin/env python3
2 # Unix SMB/CIFS implementation.
3 # Copyright (C) Stefan Metzmacher 2020
4 # Copyright (C) 2020 Catalyst.Net Ltd
5 #
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.
10 #
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.
15 #
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/>.
18 #
19
20 import sys
21 import os
22
23 sys.path.insert(0, "bin/python")
24 os.environ["PYTHONUNBUFFERED"] = "1"
25
26 import functools
27 import collections
28
29 import ldb
30
31 from samba.dcerpc import krb5pac, security
32 from samba.tests.krb5.raw_testcase import Krb5EncryptionKey, ZeroedChecksumKey
33 from samba.tests.krb5.kdc_base_test import KDCBaseTest
34 from samba.tests.krb5.rfc4120_constants import (
35     AD_FX_FAST_ARMOR,
36     AD_FX_FAST_USED,
37     AES256_CTS_HMAC_SHA1_96,
38     ARCFOUR_HMAC_MD5,
39     FX_FAST_ARMOR_AP_REQUEST,
40     KDC_ERR_BAD_INTEGRITY,
41     KDC_ERR_ETYPE_NOSUPP,
42     KDC_ERR_GENERIC,
43     KDC_ERR_S_PRINCIPAL_UNKNOWN,
44     KDC_ERR_MODIFIED,
45     KDC_ERR_NOT_US,
46     KDC_ERR_POLICY,
47     KDC_ERR_PREAUTH_FAILED,
48     KDC_ERR_PREAUTH_REQUIRED,
49     KDC_ERR_SKEW,
50     KDC_ERR_UNKNOWN_CRITICAL_FAST_OPTIONS,
51     KRB_AS_REP,
52     KRB_TGS_REP,
53     KU_TGS_REQ_AUTH_DAT_SESSION,
54     KU_TGS_REQ_AUTH_DAT_SUBKEY,
55     NT_PRINCIPAL,
56     NT_SRV_HST,
57     NT_SRV_INST,
58     PADATA_FX_COOKIE,
59     PADATA_FX_FAST,
60     PADATA_REQ_ENC_PA_REP,
61 )
62 import samba.tests.krb5.rfc4120_pyasn1 as krb5_asn1
63 import samba.tests.krb5.kcrypto as kcrypto
64
65 global_asn1_print = False
66 global_hexdump = False
67
68
69 class FAST_Tests(KDCBaseTest):
70     def setUp(self):
71         super().setUp()
72         self.do_asn1_print = global_asn1_print
73         self.do_hexdump = global_hexdump
74
75     def test_simple(self):
76         self._run_test_sequence([
77             {
78                 'rep_type': KRB_AS_REP,
79                 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
80                 'use_fast': False
81             },
82             {
83                 'rep_type': KRB_AS_REP,
84                 'expected_error_mode': 0,
85                 'use_fast': False,
86                 'gen_padata_fn': self.generate_enc_timestamp_padata
87             }
88         ])
89
90     def test_simple_as_req_self(self):
91         self._run_test_sequence([
92             {
93                 'rep_type': KRB_AS_REP,
94                 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
95                 'use_fast': False,
96                 'as_req_self': True
97             },
98             {
99                 'rep_type': KRB_AS_REP,
100                 'expected_error_mode': 0,
101                 'use_fast': False,
102                 'gen_padata_fn': self.generate_enc_timestamp_padata,
103                 'as_req_self': True
104             }
105         ], client_account=self.AccountType.COMPUTER)
106
107     def test_simple_as_req_self_no_auth_data(self):
108         self._run_test_sequence(
109             [
110                 {
111                     'rep_type': KRB_AS_REP,
112                     'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
113                     'use_fast': False,
114                     'as_req_self': True
115                 },
116                 {
117                     'rep_type': KRB_AS_REP,
118                     'expected_error_mode': 0,
119                     'use_fast': False,
120                     'gen_padata_fn': self.generate_enc_timestamp_padata,
121                     'as_req_self': True,
122                     'expect_pac': True
123                 }
124             ],
125             client_account=self.AccountType.COMPUTER,
126             client_opts={'no_auth_data_required': True})
127
128     def test_simple_as_req_self_pac_request_false(self):
129         self._run_test_sequence([
130             {
131                 'rep_type': KRB_AS_REP,
132                 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
133                 'use_fast': False,
134                 'as_req_self': True
135             },
136             {
137                 'rep_type': KRB_AS_REP,
138                 'expected_error_mode': 0,
139                 'use_fast': False,
140                 'gen_padata_fn': self.generate_enc_timestamp_padata,
141                 'as_req_self': True,
142                 'pac_request': False,
143                 'expect_pac': False
144             }
145         ], client_account=self.AccountType.COMPUTER)
146
147     def test_simple_as_req_self_pac_request_none(self):
148         self._run_test_sequence([
149             {
150                 'rep_type': KRB_AS_REP,
151                 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
152                 'use_fast': False,
153                 'as_req_self': True
154             },
155             {
156                 'rep_type': KRB_AS_REP,
157                 'expected_error_mode': 0,
158                 'use_fast': False,
159                 'gen_padata_fn': self.generate_enc_timestamp_padata,
160                 'as_req_self': True,
161                 'pac_request': None,
162                 'expect_pac': True
163             }
164         ], client_account=self.AccountType.COMPUTER)
165
166     def test_simple_as_req_self_pac_request_true(self):
167         self._run_test_sequence([
168             {
169                 'rep_type': KRB_AS_REP,
170                 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
171                 'use_fast': False,
172                 'as_req_self': True
173             },
174             {
175                 'rep_type': KRB_AS_REP,
176                 'expected_error_mode': 0,
177                 'use_fast': False,
178                 'gen_padata_fn': self.generate_enc_timestamp_padata,
179                 'as_req_self': True,
180                 'pac_request': True,
181                 'expect_pac': True
182             }
183         ], client_account=self.AccountType.COMPUTER)
184
185     def test_simple_tgs(self):
186         self._run_test_sequence([
187             {
188                 'rep_type': KRB_TGS_REP,
189                 'expected_error_mode': 0,
190                 'use_fast': False,
191                 'gen_tgt_fn': self.get_user_tgt
192             }
193         ])
194
195     def test_fast_rodc_issued_armor(self):
196         self._run_test_sequence([
197             {
198                 'rep_type': KRB_AS_REP,
199                 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
200                 'use_fast': True,
201                 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
202                 'gen_armor_tgt_fn': self.get_rodc_issued_mach_tgt,
203             },
204             {
205                 'rep_type': KRB_AS_REP,
206                 # Test that RODC-issued armor tickets are permitted.
207                 'expected_error_mode': 0,
208                 'use_fast': True,
209                 'gen_padata_fn': self.generate_enc_challenge_padata,
210                 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
211                 'gen_armor_tgt_fn': self.get_rodc_issued_mach_tgt,
212             }
213         ],
214         armor_opts={
215             'allowed_replication_mock': True,
216             'revealed_to_mock_rodc': True,
217         })
218
219     def test_fast_tgs_rodc_issued_armor(self):
220         self._run_test_sequence([
221             {
222                 'rep_type': KRB_TGS_REP,
223                 # Test that RODC-issued armor tickets are not permitted.
224                 'expected_error_mode': 0,
225                 'use_fast': True,
226                 'gen_tgt_fn': self.get_user_tgt,
227                 'gen_armor_tgt_fn': self.get_rodc_issued_mach_tgt,
228                 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
229             }
230         ],
231         armor_opts={
232             'allowed_replication_mock': True,
233             'revealed_to_mock_rodc': True,
234         })
235
236     def test_simple_enc_pa_rep(self):
237         self._run_test_sequence([
238             {
239                 'rep_type': KRB_AS_REP,
240                 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
241                 'use_fast': False
242             },
243             {
244                 'rep_type': KRB_AS_REP,
245                 'expected_error_mode': 0,
246                 'use_fast': False,
247                 'gen_padata_fn': self.generate_enc_pa_rep_timestamp_padata,
248                 'expected_flags': 'enc-pa-rep'
249             }
250         ])
251
252     # Currently we only send PADATA-REQ-ENC-PA-REP for AS-REQ requests.
253     def test_simple_tgs_enc_pa_rep(self):
254         self._run_test_sequence([
255             {
256                 'rep_type': KRB_TGS_REP,
257                 'expected_error_mode': 0,
258                 'use_fast': False,
259                 'gen_tgt_fn': self.get_user_tgt,
260                 'gen_padata_fn': self.generate_enc_pa_rep_padata,
261                 'expected_flags': 'enc-pa-rep'
262             }
263         ])
264
265     def test_simple_no_sname(self):
266         expected_sname = self.get_krbtgt_sname()
267
268         self._run_test_sequence([
269             {
270                 'rep_type': KRB_AS_REP,
271                 'expected_error_mode': (KDC_ERR_GENERIC, KDC_ERR_S_PRINCIPAL_UNKNOWN),
272                 'use_fast': False,
273                 'sname': None,
274                 'expected_sname': expected_sname,
275                 'expect_edata': False
276             }
277         ])
278
279     def test_simple_tgs_no_sname(self):
280         expected_sname = self.get_krbtgt_sname()
281
282         self._run_test_sequence([
283             {
284                 'rep_type': KRB_TGS_REP,
285                 'expected_error_mode': (KDC_ERR_GENERIC, KDC_ERR_S_PRINCIPAL_UNKNOWN),
286                 'use_fast': False,
287                 'gen_tgt_fn': self.get_user_tgt,
288                 'sname': None,
289                 'expected_sname': expected_sname,
290                 'expect_edata': False
291             }
292         ])
293
294     def test_fast_no_sname(self):
295         expected_sname = self.get_krbtgt_sname()
296
297         self._run_test_sequence([
298             {
299                 'rep_type': KRB_AS_REP,
300                 'expected_error_mode': (KDC_ERR_GENERIC,
301                                         KDC_ERR_S_PRINCIPAL_UNKNOWN),
302                 'use_fast': True,
303                 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
304                 'gen_armor_tgt_fn': self.get_mach_tgt,
305                 'sname': None,
306                 'expected_sname': expected_sname,
307                 'strict_edata_checking': False
308             }
309         ])
310
311     def test_fast_tgs_no_sname(self):
312         expected_sname = self.get_krbtgt_sname()
313
314         self._run_test_sequence([
315             {
316                 'rep_type': KRB_TGS_REP,
317                 'expected_error_mode': (KDC_ERR_GENERIC, KDC_ERR_S_PRINCIPAL_UNKNOWN),
318                 'use_fast': True,
319                 'gen_tgt_fn': self.get_user_tgt,
320                 'fast_armor': None,
321                 'sname': None,
322                 'expected_sname': expected_sname,
323                 'strict_edata_checking': False
324             }
325         ])
326
327     def test_fast_inner_no_sname(self):
328         expected_sname = self.get_krbtgt_sname()
329
330         self._run_test_sequence([
331             {
332                 'rep_type': KRB_AS_REP,
333                 'expected_error_mode': (KDC_ERR_GENERIC,
334                                         KDC_ERR_S_PRINCIPAL_UNKNOWN),
335                 'use_fast': True,
336                 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
337                 'gen_armor_tgt_fn': self.get_mach_tgt,
338                 'inner_req': {
339                     'sname': None  # should be ignored
340                 },
341                 'expected_sname': expected_sname,
342                 'strict_edata_checking': False
343             }
344         ])
345
346     def test_fast_tgs_inner_no_sname(self):
347         expected_sname = self.get_krbtgt_sname()
348
349         self._run_test_sequence([
350             {
351                 'rep_type': KRB_TGS_REP,
352                 'expected_error_mode': (KDC_ERR_GENERIC,
353                                         KDC_ERR_S_PRINCIPAL_UNKNOWN),
354                 'use_fast': True,
355                 'gen_tgt_fn': self.get_user_tgt,
356                 'fast_armor': None,
357                 'inner_req': {
358                     'sname': None  # should be ignored
359                 },
360                 'expected_sname': expected_sname,
361                 'strict_edata_checking': False
362             }
363         ])
364
365     def test_simple_tgs_wrong_principal(self):
366         self._run_test_sequence([
367             {
368                 'rep_type': KRB_TGS_REP,
369                 'expected_error_mode': 0,
370                 'use_fast': False,
371                 'gen_tgt_fn': self.get_mach_tgt
372             }
373         ])
374
375     def test_simple_tgs_service_ticket(self):
376         self._run_test_sequence([
377             {
378                 'rep_type': KRB_TGS_REP,
379                 'expected_error_mode': (KDC_ERR_NOT_US,
380                                         KDC_ERR_POLICY),
381                 'use_fast': False,
382                 'gen_tgt_fn': self.get_user_service_ticket,
383                 'expect_edata': False
384             }
385         ])
386
387     def test_simple_tgs_service_ticket_mach(self):
388         self._run_test_sequence([
389             {
390                 'rep_type': KRB_TGS_REP,
391                 'expected_error_mode': (KDC_ERR_NOT_US,
392                                         KDC_ERR_POLICY),
393                 'use_fast': False,
394                 'gen_tgt_fn': self.get_mach_service_ticket,
395                 'expect_edata': False
396             }
397         ])
398
399     def test_fast_no_claims(self):
400         self._run_test_sequence([
401             {
402                 'rep_type': KRB_AS_REP,
403                 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
404                 'use_fast': True,
405                 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
406                 'gen_armor_tgt_fn': self.get_mach_tgt,
407                 'pac_options': '0'
408             },
409             {
410                 'rep_type': KRB_AS_REP,
411                 'expected_error_mode': 0,
412                 'use_fast': True,
413                 'gen_padata_fn': self.generate_enc_challenge_padata,
414                 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
415                 'gen_armor_tgt_fn': self.get_mach_tgt,
416                 'pac_options': '0'
417             }
418         ])
419
420     def test_fast_tgs_no_claims(self):
421         self._run_test_sequence([
422             {
423                 'rep_type': KRB_TGS_REP,
424                 'expected_error_mode': 0,
425                 'use_fast': True,
426                 'gen_tgt_fn': self.get_user_tgt,
427                 'fast_armor': None,
428                 'pac_options': '0'
429             }
430         ])
431
432     def test_fast_no_claims_or_canon(self):
433         self._run_test_sequence([
434             {
435                 'rep_type': KRB_AS_REP,
436                 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
437                 'use_fast': True,
438                 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
439                 'gen_armor_tgt_fn': self.get_mach_tgt,
440                 'pac_options': '0',
441                 'kdc_options': '0'
442             },
443             {
444                 'rep_type': KRB_AS_REP,
445                 'expected_error_mode': 0,
446                 'use_fast': True,
447                 'gen_padata_fn': self.generate_enc_challenge_padata,
448                 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
449                 'gen_armor_tgt_fn': self.get_mach_tgt,
450                 'pac_options': '0',
451                 'kdc_options': '0'
452             }
453         ])
454
455     def test_fast_tgs_no_claims_or_canon(self):
456         self._run_test_sequence([
457             {
458                 'rep_type': KRB_TGS_REP,
459                 'expected_error_mode': 0,
460                 'use_fast': True,
461                 'gen_tgt_fn': self.get_user_tgt,
462                 'fast_armor': None,
463                 'pac_options': '0',
464                 'kdc_options': '0'
465             }
466         ])
467
468     def test_fast_no_canon(self):
469         self._run_test_sequence([
470             {
471                 'rep_type': KRB_AS_REP,
472                 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
473                 'use_fast': True,
474                 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
475                 'gen_armor_tgt_fn': self.get_mach_tgt,
476                 'kdc_options': '0'
477             },
478             {
479                 'rep_type': KRB_AS_REP,
480                 'expected_error_mode': 0,
481                 'use_fast': True,
482                 'gen_padata_fn': self.generate_enc_challenge_padata,
483                 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
484                 'gen_armor_tgt_fn': self.get_mach_tgt,
485                 'kdc_options': '0'
486             }
487         ])
488
489     def test_fast_tgs_no_canon(self):
490         self._run_test_sequence([
491             {
492                 'rep_type': KRB_TGS_REP,
493                 'expected_error_mode': 0,
494                 'use_fast': True,
495                 'gen_tgt_fn': self.get_user_tgt,
496                 'fast_armor': None,
497                 'kdc_options': '0'
498             }
499         ])
500
501     def test_simple_tgs_no_etypes(self):
502         self._run_test_sequence([
503             {
504                 'rep_type': KRB_TGS_REP,
505                 'expected_error_mode': KDC_ERR_ETYPE_NOSUPP,
506                 'use_fast': False,
507                 'gen_tgt_fn': self.get_mach_tgt,
508                 'etypes': (),
509                 'expect_edata': False
510             }
511         ])
512
513     def test_fast_tgs_no_etypes(self):
514         self._run_test_sequence([
515             {
516                 'rep_type': KRB_TGS_REP,
517                 'expected_error_mode': KDC_ERR_ETYPE_NOSUPP,
518                 'use_fast': True,
519                 'gen_tgt_fn': self.get_mach_tgt,
520                 'fast_armor': None,
521                 'etypes': (),
522                 'strict_edata_checking': False
523             }
524         ])
525
526     def test_simple_no_etypes(self):
527         self._run_test_sequence([
528             {
529                 'rep_type': KRB_AS_REP,
530                 'expected_error_mode': KDC_ERR_ETYPE_NOSUPP,
531                 'use_fast': False,
532                 'etypes': ()
533             }
534         ])
535
536     def test_simple_fast_no_etypes(self):
537         self._run_test_sequence([
538             {
539                 'rep_type': KRB_AS_REP,
540                 'expected_error_mode': KDC_ERR_ETYPE_NOSUPP,
541                 'use_fast': True,
542                 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
543                 'gen_armor_tgt_fn': self.get_mach_tgt,
544                 'etypes': (),
545                 'strict_edata_checking': False
546             }
547         ])
548
549     def test_empty_fast(self):
550         # Add an empty PA-FX-FAST in the initial AS-REQ. This should get
551         # rejected with a Generic error.
552         self._run_test_sequence([
553             {
554                 'rep_type': KRB_AS_REP,
555                 'expected_error_mode': (KDC_ERR_GENERIC,
556                                         KDC_ERR_PREAUTH_FAILED),
557                 'use_fast': True,
558                 'gen_fast_fn': self.generate_empty_fast,
559                 'fast_armor': None,
560                 'gen_armor_tgt_fn': self.get_mach_tgt,
561                 'expect_edata': False
562             }
563         ])
564
565     # Expected to fail against Windows - Windows does not produce an error.
566     def test_fast_unknown_critical_option(self):
567         self._run_test_sequence([
568             {
569                 'rep_type': KRB_AS_REP,
570                 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
571                 'use_fast': True,
572                 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
573                 'gen_armor_tgt_fn': self.get_mach_tgt
574             },
575             {
576                 'rep_type': KRB_AS_REP,
577                 'expected_error_mode': KDC_ERR_UNKNOWN_CRITICAL_FAST_OPTIONS,
578                 'use_fast': True,
579                 'gen_padata_fn': self.generate_enc_challenge_padata,
580                 'fast_options': '001',  # unsupported critical option
581                 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
582                 'gen_armor_tgt_fn': self.get_mach_tgt
583             }
584         ])
585
586     def test_unarmored_as_req(self):
587         self._run_test_sequence([
588             {
589                 'rep_type': KRB_AS_REP,
590                 'expected_error_mode': (KDC_ERR_GENERIC,
591                                         KDC_ERR_PREAUTH_FAILED),
592                 'use_fast': True,
593                 'fast_armor': None,  # no armor,
594                 'gen_armor_tgt_fn': self.get_mach_tgt,
595                 'expect_edata': False
596             }
597         ])
598
599     def test_fast_invalid_armor_type(self):
600         self._run_test_sequence([
601             {
602                 'rep_type': KRB_AS_REP,
603                 'expected_error_mode': KDC_ERR_PREAUTH_FAILED,
604                 'use_fast': True,
605                 'fast_armor': 0,  # invalid armor type
606                 'gen_armor_tgt_fn': self.get_mach_tgt
607             }
608         ])
609
610     def test_fast_invalid_armor_type2(self):
611         self._run_test_sequence([
612             {
613                 'rep_type': KRB_AS_REP,
614                 'expected_error_mode': KDC_ERR_PREAUTH_FAILED,
615                 'use_fast': True,
616                 'fast_armor': 2,  # invalid armor type
617                 'gen_armor_tgt_fn': self.get_mach_tgt
618             }
619         ])
620
621     def test_fast_encrypted_challenge(self):
622         self._run_test_sequence([
623             {
624                 'rep_type': KRB_AS_REP,
625                 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
626                 'use_fast': True,
627                 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
628                 'gen_armor_tgt_fn': self.get_mach_tgt
629             },
630             {
631                 'rep_type': KRB_AS_REP,
632                 'expected_error_mode': 0,
633                 'use_fast': True,
634                 'gen_padata_fn': self.generate_enc_challenge_padata,
635                 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
636                 'gen_armor_tgt_fn': self.get_mach_tgt
637             }
638         ])
639
640     def test_fast_encrypted_challenge_as_req_self(self):
641         self._run_test_sequence([
642             {
643                 'rep_type': KRB_AS_REP,
644                 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
645                 'use_fast': True,
646                 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
647                 'gen_armor_tgt_fn': self.get_mach_tgt,
648                 'as_req_self': True
649             },
650             {
651                 'rep_type': KRB_AS_REP,
652                 'expected_error_mode': 0,
653                 'use_fast': True,
654                 'gen_padata_fn': self.generate_enc_challenge_padata,
655                 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
656                 'gen_armor_tgt_fn': self.get_mach_tgt,
657                 'as_req_self': True
658             }
659         ], client_account=self.AccountType.COMPUTER)
660
661     def test_fast_encrypted_challenge_wrong_key(self):
662         self._run_test_sequence([
663             {
664                 'rep_type': KRB_AS_REP,
665                 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
666                 'use_fast': True,
667                 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
668                 'gen_armor_tgt_fn': self.get_mach_tgt
669             },
670             {
671                 'rep_type': KRB_AS_REP,
672                 'expected_error_mode': KDC_ERR_PREAUTH_FAILED,
673                 'use_fast': True,
674                 'gen_padata_fn': self.generate_enc_challenge_padata_wrong_key,
675                 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
676                 'gen_armor_tgt_fn': self.get_mach_tgt
677             }
678         ])
679
680     def test_fast_encrypted_challenge_wrong_key_kdc(self):
681         self._run_test_sequence([
682             {
683                 'rep_type': KRB_AS_REP,
684                 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
685                 'use_fast': True,
686                 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
687                 'gen_armor_tgt_fn': self.get_mach_tgt
688             },
689             {
690                 'rep_type': KRB_AS_REP,
691                 'expected_error_mode': KDC_ERR_PREAUTH_FAILED,
692                 'use_fast': True,
693                 'gen_padata_fn':
694                 self.generate_enc_challenge_padata_wrong_key_kdc,
695                 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
696                 'gen_armor_tgt_fn': self.get_mach_tgt
697             }
698         ])
699
700     def test_fast_encrypted_challenge_no_fast(self):
701         self._run_test_sequence([
702             {
703                 'rep_type': KRB_AS_REP,
704                 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
705                 'use_fast': False
706             },
707             {
708                 'rep_type': KRB_AS_REP,
709                 'expected_error_mode': (KDC_ERR_PREAUTH_FAILED,
710                                         KDC_ERR_PREAUTH_REQUIRED),
711                 'use_fast': False,
712                 'gen_padata_fn': self.generate_enc_challenge_padata_wrong_key
713             }
714         ])
715
716     # Expected to fail against Windows - Windows does not produce an error.
717     def test_fast_encrypted_challenge_clock_skew(self):
718         # The KDC is supposed to confirm that the timestamp is within its
719         # current clock skew, and return KRB_APP_ERR_SKEW if it is not (RFC6113
720         # 5.4.6). However, this test fails against Windows, which accepts a
721         # skewed timestamp in the encrypted challenge.
722         self._run_test_sequence([
723             {
724                 'rep_type': KRB_AS_REP,
725                 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
726                 'use_fast': True,
727                 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
728                 'gen_armor_tgt_fn': self.get_mach_tgt
729             },
730             {
731                 'rep_type': KRB_AS_REP,
732                 'expected_error_mode': KDC_ERR_SKEW,
733                 'use_fast': True,
734                 'gen_padata_fn': functools.partial(
735                     self.generate_enc_challenge_padata,
736                     skew=10000),
737                 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
738                 'gen_armor_tgt_fn': self.get_mach_tgt
739             }
740         ])
741
742     def test_fast_invalid_tgt(self):
743         # The armor ticket 'sname' field is required to identify the target
744         # realm TGS (RFC6113 5.4.1.1). However, this test fails against
745         # Windows, which will still accept a service ticket identifying a
746         # different server principal.
747         self._run_test_sequence([
748             {
749                 'rep_type': KRB_AS_REP,
750                 'expected_error_mode': (KDC_ERR_POLICY,
751                                         KDC_ERR_S_PRINCIPAL_UNKNOWN),
752                 'use_fast': True,
753                 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
754                 'gen_armor_tgt_fn': self.get_user_service_ticket
755                                     # ticket not identifying TGS of current
756                                     # realm
757             }
758         ])
759
760     # Similarly, this test fails against Windows, which accepts a service
761     # ticket identifying a different server principal.
762     def test_fast_invalid_tgt_mach(self):
763         self._run_test_sequence([
764             {
765                 'rep_type': KRB_AS_REP,
766                 'expected_error_mode': (KDC_ERR_POLICY,
767                                         KDC_ERR_S_PRINCIPAL_UNKNOWN),
768                 'use_fast': True,
769                 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
770                 'gen_armor_tgt_fn': self.get_mach_service_ticket
771                                     # ticket not identifying TGS of current
772                                     # realm
773             }
774         ])
775
776     def test_fast_invalid_checksum_tgt(self):
777         # The armor ticket 'sname' field is required to identify the target
778         # realm TGS (RFC6113 5.4.1.1). However, this test fails against
779         # Windows, which will still accept a service ticket identifying a
780         # different server principal even if the ticket checksum is invalid.
781         self._run_test_sequence([
782             {
783                 'rep_type': KRB_AS_REP,
784                 'expected_error_mode': (KDC_ERR_POLICY,
785                                         KDC_ERR_S_PRINCIPAL_UNKNOWN),
786                 'use_fast': True,
787                 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
788                 'gen_armor_tgt_fn': self.get_service_ticket_invalid_checksum
789             }
790         ])
791
792     def test_fast_enc_timestamp(self):
793         # Provide ENC-TIMESTAMP as FAST padata when we should be providing
794         # ENCRYPTED-CHALLENGE - ensure that we get PREAUTH_REQUIRED.
795         self._run_test_sequence([
796             {
797                 'rep_type': KRB_AS_REP,
798                 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
799                 'use_fast': True,
800                 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
801                 'gen_armor_tgt_fn': self.get_mach_tgt
802             },
803             {
804                 'rep_type': KRB_AS_REP,
805                 'expected_error_mode': (KDC_ERR_PREAUTH_REQUIRED,
806                                         KDC_ERR_POLICY),
807                 'use_fast': True,
808                 'gen_padata_fn': self.generate_enc_timestamp_padata,
809                 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
810                 'gen_armor_tgt_fn': self.get_mach_tgt
811             }
812         ])
813
814     def test_fast(self):
815         self._run_test_sequence([
816             {
817                 'rep_type': KRB_AS_REP,
818                 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
819                 'use_fast': True,
820                 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
821                 'gen_armor_tgt_fn': self.get_mach_tgt
822             },
823             {
824                 'rep_type': KRB_AS_REP,
825                 'expected_error_mode': 0,
826                 'use_fast': True,
827                 'gen_padata_fn': self.generate_enc_challenge_padata,
828                 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
829                 'gen_armor_tgt_fn': self.get_mach_tgt
830             }
831         ])
832
833     def test_fast_tgs(self):
834         self._run_test_sequence([
835             {
836                 'rep_type': KRB_TGS_REP,
837                 'expected_error_mode': 0,
838                 'use_fast': True,
839                 'gen_tgt_fn': self.get_user_tgt,
840                 'fast_armor': None
841             }
842         ])
843
844     def test_fast_tgs_armor(self):
845         self._run_test_sequence([
846             {
847                 'rep_type': KRB_TGS_REP,
848                 'expected_error_mode': 0,
849                 'use_fast': True,
850                 'gen_tgt_fn': self.get_user_tgt,
851                 'gen_armor_tgt_fn': self.get_mach_tgt,
852                 'fast_armor': FX_FAST_ARMOR_AP_REQUEST
853             }
854         ])
855
856     def test_fast_session_key(self):
857         # Ensure that specified APOptions are ignored.
858         self._run_test_sequence([
859             {
860                 'rep_type': KRB_AS_REP,
861                 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
862                 'use_fast': True,
863                 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
864                 'gen_armor_tgt_fn': self.get_mach_tgt,
865                 'fast_ap_options': str(krb5_asn1.APOptions('use-session-key'))
866             },
867             {
868                 'rep_type': KRB_AS_REP,
869                 'expected_error_mode': 0,
870                 'use_fast': True,
871                 'gen_padata_fn': self.generate_enc_challenge_padata,
872                 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
873                 'gen_armor_tgt_fn': self.get_mach_tgt,
874                 'fast_ap_options': str(krb5_asn1.APOptions('use-session-key'))
875             }
876         ])
877
878     def test_fast_tgs_armor_session_key(self):
879         # Ensure that specified APOptions are ignored.
880         self._run_test_sequence([
881             {
882                 'rep_type': KRB_TGS_REP,
883                 'expected_error_mode': 0,
884                 'use_fast': True,
885                 'gen_tgt_fn': self.get_user_tgt,
886                 'gen_armor_tgt_fn': self.get_mach_tgt,
887                 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
888                 'fast_ap_options': str(krb5_asn1.APOptions('use-session-key'))
889             }
890         ])
891
892     def test_fast_enc_pa_rep(self):
893         self._run_test_sequence([
894             {
895                 'rep_type': KRB_AS_REP,
896                 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
897                 'use_fast': True,
898                 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
899                 'gen_armor_tgt_fn': self.get_mach_tgt,
900                 'expected_flags': 'enc-pa-rep'
901             },
902             {
903                 'rep_type': KRB_AS_REP,
904                 'expected_error_mode': 0,
905                 'use_fast': True,
906                 'gen_padata_fn': self.generate_enc_pa_rep_challenge_padata,
907                 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
908                 'gen_armor_tgt_fn': self.get_mach_tgt,
909                 'expected_flags': 'enc-pa-rep'
910             }
911         ])
912
913     # Currently we only send PADATA-REQ-ENC-PA-REP for AS-REQ requests.
914     def test_fast_tgs_enc_pa_rep(self):
915         self._run_test_sequence([
916             {
917                 'rep_type': KRB_TGS_REP,
918                 'expected_error_mode': 0,
919                 'use_fast': True,
920                 'gen_tgt_fn': self.get_user_tgt,
921                 'fast_armor': None,
922                 'gen_padata_fn': self.generate_enc_pa_rep_padata,
923                 'expected_flags': 'enc-pa-rep'
924             }
925         ])
926
927     # Currently we only send PADATA-REQ-ENC-PA-REP for AS-REQ requests.
928     def test_fast_tgs_armor_enc_pa_rep(self):
929         self._run_test_sequence([
930             {
931                 'rep_type': KRB_TGS_REP,
932                 'expected_error_mode': 0,
933                 'use_fast': True,
934                 'gen_tgt_fn': self.get_user_tgt,
935                 'gen_armor_tgt_fn': self.get_mach_tgt,
936                 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
937                 'gen_padata_fn': self.generate_enc_pa_rep_padata,
938                 'expected_flags': 'enc-pa-rep'
939             }
940         ])
941
942     def test_fast_outer_wrong_realm(self):
943         self._run_test_sequence([
944             {
945                 'rep_type': KRB_AS_REP,
946                 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
947                 'use_fast': True,
948                 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
949                 'gen_armor_tgt_fn': self.get_mach_tgt,
950                 'outer_req': {
951                     'realm': 'TEST'  # should be ignored
952                 }
953             },
954             {
955                 'rep_type': KRB_AS_REP,
956                 'expected_error_mode': 0,
957                 'use_fast': True,
958                 'gen_padata_fn': self.generate_enc_challenge_padata,
959                 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
960                 'gen_armor_tgt_fn': self.get_mach_tgt,
961                 'outer_req': {
962                     'realm': 'TEST'  # should be ignored
963                 }
964             }
965         ])
966
967     def test_fast_tgs_outer_wrong_realm(self):
968         self._run_test_sequence([
969             {
970                 'rep_type': KRB_TGS_REP,
971                 'expected_error_mode': 0,
972                 'use_fast': True,
973                 'gen_tgt_fn': self.get_user_tgt,
974                 'fast_armor': None,
975                 'outer_req': {
976                     'realm': 'TEST'  # should be ignored
977                 }
978             }
979         ])
980
981     def test_fast_outer_wrong_nonce(self):
982         self._run_test_sequence([
983             {
984                 'rep_type': KRB_AS_REP,
985                 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
986                 'use_fast': True,
987                 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
988                 'gen_armor_tgt_fn': self.get_mach_tgt,
989                 'outer_req': {
990                     'nonce': '123'  # should be ignored
991                 }
992             },
993             {
994                 'rep_type': KRB_AS_REP,
995                 'expected_error_mode': 0,
996                 'use_fast': True,
997                 'gen_padata_fn': self.generate_enc_challenge_padata,
998                 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
999                 'gen_armor_tgt_fn': self.get_mach_tgt,
1000                 'outer_req': {
1001                     'nonce': '123'  # should be ignored
1002                 }
1003             }
1004         ])
1005
1006     def test_fast_tgs_outer_wrong_nonce(self):
1007         self._run_test_sequence([
1008             {
1009                 'rep_type': KRB_TGS_REP,
1010                 'expected_error_mode': 0,
1011                 'use_fast': True,
1012                 'gen_tgt_fn': self.get_user_tgt,
1013                 'fast_armor': None,
1014                 'outer_req': {
1015                     'nonce': '123'  # should be ignored
1016                 }
1017             }
1018         ])
1019
1020     def test_fast_outer_wrong_flags(self):
1021         self._run_test_sequence([
1022             {
1023                 'rep_type': KRB_AS_REP,
1024                 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
1025                 'use_fast': True,
1026                 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
1027                 'gen_armor_tgt_fn': self.get_mach_tgt,
1028                 'outer_req': {
1029                     'kdc-options': '11111111111111111'  # should be ignored
1030                 }
1031             },
1032             {
1033                 'rep_type': KRB_AS_REP,
1034                 'expected_error_mode': 0,
1035                 'use_fast': True,
1036                 'gen_padata_fn': self.generate_enc_challenge_padata,
1037                 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
1038                 'gen_armor_tgt_fn': self.get_mach_tgt,
1039                 'outer_req': {
1040                     'kdc-options': '11111111111111111'  # should be ignored
1041                 }
1042             }
1043         ])
1044
1045     def test_fast_tgs_outer_wrong_flags(self):
1046         self._run_test_sequence([
1047             {
1048                 'rep_type': KRB_TGS_REP,
1049                 'expected_error_mode': 0,
1050                 'use_fast': True,
1051                 'gen_tgt_fn': self.get_user_tgt,
1052                 'fast_armor': None,
1053                 'outer_req': {
1054                     'kdc-options': '11111111111111111'  # should be ignored
1055                 }
1056             }
1057         ])
1058
1059     def test_fast_outer_no_sname(self):
1060         self._run_test_sequence([
1061             {
1062                 'rep_type': KRB_AS_REP,
1063                 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
1064                 'use_fast': True,
1065                 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
1066                 'gen_armor_tgt_fn': self.get_mach_tgt,
1067                 'outer_req': {
1068                     'sname': None  # should be ignored
1069                 }
1070             },
1071             {
1072                 'rep_type': KRB_AS_REP,
1073                 'expected_error_mode': 0,
1074                 'use_fast': True,
1075                 'gen_padata_fn': self.generate_enc_challenge_padata,
1076                 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
1077                 'gen_armor_tgt_fn': self.get_mach_tgt,
1078                 'outer_req': {
1079                     'sname': None  # should be ignored
1080                 }
1081             }
1082         ])
1083
1084     def test_fast_tgs_outer_no_sname(self):
1085         self._run_test_sequence([
1086             {
1087                 'rep_type': KRB_TGS_REP,
1088                 'expected_error_mode': 0,
1089                 'use_fast': True,
1090                 'gen_tgt_fn': self.get_user_tgt,
1091                 'fast_armor': None,
1092                 'outer_req': {
1093                     'sname': None  # should be ignored
1094                 }
1095             }
1096         ])
1097
1098     def test_fast_outer_wrong_till(self):
1099         self._run_test_sequence([
1100             {
1101                 'rep_type': KRB_AS_REP,
1102                 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
1103                 'use_fast': True,
1104                 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
1105                 'gen_armor_tgt_fn': self.get_mach_tgt,
1106                 'outer_req': {
1107                     'till': '15000101000000Z'  # should be ignored
1108                 }
1109             },
1110             {
1111                 'rep_type': KRB_AS_REP,
1112                 'expected_error_mode': 0,
1113                 'use_fast': True,
1114                 'gen_padata_fn': self.generate_enc_challenge_padata,
1115                 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
1116                 'gen_armor_tgt_fn': self.get_mach_tgt,
1117                 'outer_req': {
1118                     'till': '15000101000000Z'  # should be ignored
1119                 }
1120             }
1121         ])
1122
1123     def test_fast_tgs_outer_wrong_till(self):
1124         self._run_test_sequence([
1125             {
1126                 'rep_type': KRB_TGS_REP,
1127                 'expected_error_mode': 0,
1128                 'use_fast': True,
1129                 'gen_tgt_fn': self.get_user_tgt,
1130                 'fast_armor': None,
1131                 'outer_req': {
1132                     'till': '15000101000000Z'  # should be ignored
1133                 }
1134             }
1135         ])
1136
1137     def test_fast_authdata_fast_used(self):
1138         self._run_test_sequence([
1139             {
1140                 'rep_type': KRB_TGS_REP,
1141                 'expected_error_mode': 0,
1142                 'use_fast': True,
1143                 'gen_authdata_fn': self.generate_fast_used_auth_data,
1144                 'gen_tgt_fn': self.get_user_tgt,
1145                 'fast_armor': None
1146             }
1147         ])
1148
1149     def test_fast_authdata_fast_not_used(self):
1150         # The AD-fx-fast-used authdata type can be included in the
1151         # authenticator or the TGT authentication data to indicate that FAST
1152         # must be used. The KDC must return KRB_APP_ERR_MODIFIED if it receives
1153         # this authdata type in a request not using FAST (RFC6113 5.4.2).
1154         self._run_test_sequence([
1155             # This request works without FAST.
1156             {
1157                 'rep_type': KRB_TGS_REP,
1158                 'expected_error_mode': 0,
1159                 'use_fast': False,
1160                 'gen_tgt_fn': self.get_user_tgt
1161             },
1162             # Add the 'FAST used' auth data and it now fails.
1163             {
1164                 'rep_type': KRB_TGS_REP,
1165                 'expected_error_mode': (KDC_ERR_MODIFIED,
1166                                         KDC_ERR_GENERIC),
1167                 'use_fast': False,
1168                 'gen_authdata_fn': self.generate_fast_used_auth_data,
1169                 'gen_tgt_fn': self.get_user_tgt,
1170                 'expect_edata': False
1171             }
1172         ])
1173
1174     def test_fast_ad_fx_fast_armor(self):
1175         expected_sname = self.get_krbtgt_sname()
1176
1177         # If the authenticator or TGT authentication data contains the
1178         # AD-fx-fast-armor authdata type, the KDC must reject the request
1179         # (RFC6113 5.4.1.1).
1180         self._run_test_sequence([
1181             # This request works.
1182             {
1183                 'rep_type': KRB_TGS_REP,
1184                 'expected_error_mode': 0,
1185                 'use_fast': True,
1186                 'gen_tgt_fn': self.get_user_tgt,
1187                 'fast_armor': None
1188             },
1189             # Add the 'FAST armor' auth data and it now fails.
1190             {
1191                 'rep_type': KRB_TGS_REP,
1192                 'expected_error_mode': (KDC_ERR_GENERIC,
1193                                         KDC_ERR_BAD_INTEGRITY),
1194                 'use_fast': True,
1195                 'gen_authdata_fn': self.generate_fast_armor_auth_data,
1196                 'gen_tgt_fn': self.get_user_tgt,
1197                 'fast_armor': None,
1198                 'expected_sname': expected_sname,
1199                 'expect_edata': False
1200             }
1201         ])
1202
1203     def test_fast_ad_fx_fast_armor2(self):
1204         # Show that we can still use the AD-fx-fast-armor authorization data in
1205         # FAST armor tickets.
1206         self._run_test_sequence([
1207             {
1208                 'rep_type': KRB_AS_REP,
1209                 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
1210                 'use_fast': True,
1211                 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
1212                 'gen_armor_tgt_fn': self.get_mach_tgt
1213             },
1214             {
1215                 'rep_type': KRB_AS_REP,
1216                 'expected_error_mode': 0,
1217                 'use_fast': True,
1218                 'gen_padata_fn': self.generate_enc_challenge_padata,
1219                 'gen_authdata_fn': self.generate_fast_armor_auth_data,
1220                 # include the auth data in the FAST armor.
1221                 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
1222                 'gen_armor_tgt_fn': self.get_mach_tgt
1223             }
1224         ])
1225
1226     def test_fast_ad_fx_fast_armor_ticket(self):
1227         expected_sname = self.get_krbtgt_sname()
1228
1229         # If the authenticator or TGT authentication data contains the
1230         # AD-fx-fast-armor authdata type, the KDC must reject the request
1231         # (RFC6113 5.4.2).
1232         self._run_test_sequence([
1233             # This request works.
1234             {
1235                 'rep_type': KRB_TGS_REP,
1236                 'expected_error_mode': 0,
1237                 'use_fast': True,
1238                 'gen_tgt_fn': self.get_user_tgt,
1239                 'fast_armor': None
1240             },
1241             # Add AD-fx-fast-armor authdata element to user TGT. This request
1242             # fails.
1243             {
1244                 'rep_type': KRB_TGS_REP,
1245                 'expected_error_mode': (KDC_ERR_GENERIC,
1246                                         KDC_ERR_BAD_INTEGRITY),
1247                 'use_fast': True,
1248                 'gen_tgt_fn': self.gen_tgt_fast_armor_auth_data,
1249                 'fast_armor': None,
1250                 'expected_sname': expected_sname,
1251                 'expect_edata': False
1252             }
1253         ])
1254
1255     def test_fast_ad_fx_fast_armor_enc_auth_data(self):
1256         # If the authenticator or TGT authentication data contains the
1257         # AD-fx-fast-armor authdata type, the KDC must reject the request
1258         # (RFC6113 5.4.2). However, the KDC should not reject a request that
1259         # contains this authdata type in enc-authorization-data.
1260         self._run_test_sequence([
1261             # This request works.
1262             {
1263                 'rep_type': KRB_TGS_REP,
1264                 'expected_error_mode': 0,
1265                 'use_fast': True,
1266                 'gen_tgt_fn': self.get_user_tgt,
1267                 'fast_armor': None
1268             },
1269             # Add AD-fx-fast-armor authdata element to
1270             # enc-authorization-data. This request also works.
1271             {
1272                 'rep_type': KRB_TGS_REP,
1273                 'expected_error_mode': 0,
1274                 'use_fast': True,
1275                 'gen_enc_authdata_fn': self.generate_fast_armor_auth_data,
1276                 'gen_tgt_fn': self.get_user_tgt,
1277                 'fast_armor': None
1278             }
1279         ])
1280
1281     def test_fast_ad_fx_fast_armor_ticket2(self):
1282         self._run_test_sequence([
1283             # Show that we can still use the modified ticket as armor.
1284             {
1285                 'rep_type': KRB_AS_REP,
1286                 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
1287                 'use_fast': True,
1288                 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
1289                 'gen_armor_tgt_fn': self.get_mach_tgt
1290             },
1291             {
1292                 'rep_type': KRB_AS_REP,
1293                 'expected_error_mode': 0,
1294                 'use_fast': True,
1295                 'gen_padata_fn': self.generate_enc_challenge_padata,
1296                 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
1297                 'gen_armor_tgt_fn': self.gen_tgt_fast_armor_auth_data
1298             }
1299         ])
1300
1301     def test_fast_tgs_service_ticket(self):
1302         # Try to use a non-TGT ticket to establish an armor key, which fails
1303         # (RFC6113 5.4.2).
1304         self._run_test_sequence([
1305             {
1306                 'rep_type': KRB_TGS_REP,
1307                 'expected_error_mode': (KDC_ERR_NOT_US,
1308                                         KDC_ERR_POLICY),
1309                 'use_fast': True,
1310                 'gen_tgt_fn': self.get_user_service_ticket,  # fails
1311                 'fast_armor': None
1312             }
1313         ])
1314
1315     def test_fast_tgs_service_ticket_mach(self):
1316         self._run_test_sequence([
1317             {
1318                 'rep_type': KRB_TGS_REP,
1319                 'expected_error_mode': (KDC_ERR_NOT_US,  # fails
1320                                         KDC_ERR_POLICY),
1321                 'use_fast': True,
1322                 'gen_tgt_fn': self.get_mach_service_ticket,
1323                 'fast_armor': None
1324             }
1325         ])
1326
1327     def test_simple_tgs_no_subkey(self):
1328         self._run_test_sequence([
1329             {
1330                 'rep_type': KRB_TGS_REP,
1331                 'expected_error_mode': 0,
1332                 'use_fast': False,
1333                 'gen_tgt_fn': self.get_user_tgt,
1334                 'include_subkey': False
1335             }
1336         ])
1337
1338     def test_fast_tgs_no_subkey(self):
1339         expected_sname = self.get_krbtgt_sname()
1340
1341         # Show that omitting the subkey in the TGS-REQ authenticator fails
1342         # (RFC6113 5.4.2).
1343         self._run_test_sequence([
1344             {
1345                 'rep_type': KRB_TGS_REP,
1346                 'expected_error_mode': (KDC_ERR_GENERIC,
1347                                         KDC_ERR_PREAUTH_FAILED),
1348                 'use_fast': True,
1349                 'gen_tgt_fn': self.get_user_tgt,
1350                 'fast_armor': None,
1351                 'include_subkey': False,
1352                 'expected_sname': expected_sname,
1353                 'expect_edata': False
1354             }
1355         ])
1356
1357     def test_fast_hide_client_names(self):
1358         self._run_test_sequence([
1359             {
1360                 'rep_type': KRB_AS_REP,
1361                 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
1362                 'use_fast': True,
1363                 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
1364                 'gen_armor_tgt_fn': self.get_mach_tgt,
1365                 'fast_options': str(krb5_asn1.FastOptions(
1366                     'hide-client-names')),
1367                 'expected_anon': True
1368             },
1369             {
1370                 'rep_type': KRB_AS_REP,
1371                 'expected_error_mode': 0,
1372                 'use_fast': True,
1373                 'gen_padata_fn': self.generate_enc_challenge_padata,
1374                 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
1375                 'gen_armor_tgt_fn': self.get_mach_tgt,
1376                 'fast_options': str(krb5_asn1.FastOptions(
1377                     'hide-client-names')),
1378                 'expected_anon': True
1379             }
1380         ])
1381
1382     def test_fast_tgs_hide_client_names(self):
1383         self._run_test_sequence([
1384             {
1385                 'rep_type': KRB_TGS_REP,
1386                 'expected_error_mode': 0,
1387                 'use_fast': True,
1388                 'gen_tgt_fn': self.get_user_tgt,
1389                 'fast_armor': None,
1390                 'fast_options': str(krb5_asn1.FastOptions(
1391                     'hide-client-names')),
1392                 'expected_anon': True
1393             }
1394         ])
1395
1396     def test_fast_encrypted_challenge_replay(self):
1397         # The KDC is supposed to check that encrypted challenges are not
1398         # replays (RFC6113 5.4.6), but timestamps may be reused; an encrypted
1399         # challenge is only considered a replay if the ciphertext is identical
1400         # to a previous challenge. Windows does not perform this check.
1401
1402         self._run_test_sequence([
1403             {
1404                 'rep_type': KRB_AS_REP,
1405                 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
1406                 'use_fast': True,
1407                 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
1408                 'gen_armor_tgt_fn': self.get_mach_tgt
1409             },
1410             {
1411                 'rep_type': KRB_AS_REP,
1412                 'expected_error_mode': 0,
1413                 'use_fast': True,
1414                 'gen_padata_fn': self.generate_enc_challenge_padata_replay,
1415                 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
1416                 'gen_armor_tgt_fn': self.get_mach_tgt,
1417                 'repeat': 2
1418             }
1419         ])
1420
1421     def generate_enc_timestamp_padata(self,
1422                                       kdc_exchange_dict,
1423                                       callback_dict,
1424                                       req_body):
1425         key = kdc_exchange_dict['preauth_key']
1426
1427         padata = self.get_enc_timestamp_pa_data_from_key(key)
1428         return [padata], req_body
1429
1430     def generate_enc_challenge_padata(self,
1431                                       kdc_exchange_dict,
1432                                       callback_dict,
1433                                       req_body,
1434                                       skew=0):
1435         armor_key = kdc_exchange_dict['armor_key']
1436         key = kdc_exchange_dict['preauth_key']
1437
1438         client_challenge_key = (
1439             self.generate_client_challenge_key(armor_key, key))
1440         padata = self.get_challenge_pa_data(client_challenge_key, skew=skew)
1441         return [padata], req_body
1442
1443     def generate_enc_challenge_padata_wrong_key_kdc(self,
1444                                       kdc_exchange_dict,
1445                                       callback_dict,
1446                                       req_body):
1447         armor_key = kdc_exchange_dict['armor_key']
1448         key = kdc_exchange_dict['preauth_key']
1449
1450         kdc_challenge_key = (
1451             self.generate_kdc_challenge_key(armor_key, key))
1452         padata = self.get_challenge_pa_data(kdc_challenge_key)
1453         return [padata], req_body
1454
1455     def generate_enc_challenge_padata_wrong_key(self,
1456                                                 kdc_exchange_dict,
1457                                                 callback_dict,
1458                                                 req_body):
1459         key = kdc_exchange_dict['preauth_key']
1460
1461         padata = self.get_challenge_pa_data(key)
1462         return [padata], req_body
1463
1464     def generate_enc_challenge_padata_replay(self,
1465                                              kdc_exchange_dict,
1466                                              callback_dict,
1467                                              req_body):
1468         padata = callback_dict.get('replay_padata')
1469
1470         if padata is None:
1471             armor_key = kdc_exchange_dict['armor_key']
1472             key = kdc_exchange_dict['preauth_key']
1473
1474             client_challenge_key = (
1475                 self.generate_client_challenge_key(armor_key, key))
1476             padata = self.get_challenge_pa_data(client_challenge_key)
1477             callback_dict['replay_padata'] = padata
1478
1479         return [padata], req_body
1480
1481     def generate_empty_fast(self,
1482                             _kdc_exchange_dict,
1483                             _callback_dict,
1484                             _req_body,
1485                             _fast_padata,
1486                             _fast_armor,
1487                             _checksum,
1488                             _fast_options=''):
1489         fast_padata = self.PA_DATA_create(PADATA_FX_FAST, b'')
1490
1491         return fast_padata
1492
1493     def _run_test_sequence(self, test_sequence,
1494                            client_account=KDCBaseTest.AccountType.USER,
1495                            client_opts=None,
1496                            armor_opts=None):
1497         if self.strict_checking:
1498             self.check_kdc_fast_support()
1499
1500         kdc_options_default = str(krb5_asn1.KDCOptions('forwardable,'
1501                                                        'canonicalize'))
1502
1503         client_creds = self.get_cached_creds(account_type=client_account,
1504                                              opts=client_opts)
1505         target_creds = self.get_service_creds()
1506         krbtgt_creds = self.get_krbtgt_creds()
1507
1508         client_username = client_creds.get_username()
1509         client_realm = client_creds.get_realm()
1510         client_cname = self.PrincipalName_create(name_type=NT_PRINCIPAL,
1511                                                  names=[client_username])
1512
1513         krbtgt_username = krbtgt_creds.get_username()
1514         krbtgt_realm = krbtgt_creds.get_realm()
1515         krbtgt_sname = self.PrincipalName_create(
1516             name_type=NT_SRV_INST, names=[krbtgt_username, krbtgt_realm])
1517         krbtgt_decryption_key = self.TicketDecryptionKey_from_creds(
1518             krbtgt_creds)
1519         krbtgt_etypes = krbtgt_creds.tgs_supported_enctypes
1520
1521         target_username = target_creds.get_username()[:-1]
1522         target_realm = target_creds.get_realm()
1523         target_service = 'host'
1524         target_sname = self.PrincipalName_create(
1525             name_type=NT_SRV_HST, names=[target_service, target_username])
1526         target_decryption_key = self.TicketDecryptionKey_from_creds(
1527             target_creds)
1528         target_etypes = target_creds.tgs_supported_enctypes
1529
1530         client_decryption_key = self.TicketDecryptionKey_from_creds(
1531             client_creds)
1532         client_etypes = client_creds.tgs_supported_enctypes
1533
1534         fast_cookie = None
1535         preauth_etype_info2 = None
1536
1537         for kdc_dict in test_sequence:
1538             rep_type = kdc_dict.pop('rep_type')
1539             self.assertIn(rep_type, (KRB_AS_REP, KRB_TGS_REP))
1540
1541             expected_error_mode = kdc_dict.pop('expected_error_mode')
1542             if expected_error_mode == 0:
1543                 expected_error_mode = ()
1544             elif not isinstance(expected_error_mode, collections.abc.Container):
1545                 expected_error_mode = (expected_error_mode,)
1546             for error in expected_error_mode:
1547                 self.assertIn(error, range(240))
1548
1549             use_fast = kdc_dict.pop('use_fast')
1550             self.assertIs(type(use_fast), bool)
1551
1552             if use_fast:
1553                 self.assertIn('fast_armor', kdc_dict)
1554                 fast_armor_type = kdc_dict.pop('fast_armor')
1555
1556                 if fast_armor_type is not None:
1557                     self.assertIn('gen_armor_tgt_fn', kdc_dict)
1558                 elif KDC_ERR_GENERIC not in expected_error_mode:
1559                     self.assertNotIn('gen_armor_tgt_fn', kdc_dict)
1560
1561                 gen_armor_tgt_fn = kdc_dict.pop('gen_armor_tgt_fn', None)
1562                 if gen_armor_tgt_fn is not None:
1563                     armor_tgt = gen_armor_tgt_fn(armor_opts)
1564                 else:
1565                     armor_tgt = None
1566
1567                 fast_options = kdc_dict.pop('fast_options', '')
1568             else:
1569                 fast_armor_type = None
1570                 armor_tgt = None
1571
1572                 self.assertNotIn('fast_options', kdc_dict)
1573                 fast_options = None
1574
1575             if rep_type == KRB_TGS_REP:
1576                 gen_tgt_fn = kdc_dict.pop('gen_tgt_fn')
1577                 tgt = gen_tgt_fn(opts=client_opts)
1578             else:
1579                 self.assertNotIn('gen_tgt_fn', kdc_dict)
1580                 tgt = None
1581
1582             if len(expected_error_mode) != 0:
1583                 check_error_fn = self.generic_check_kdc_error
1584                 check_rep_fn = None
1585             else:
1586                 check_error_fn = None
1587                 check_rep_fn = self.generic_check_kdc_rep
1588
1589             etypes = kdc_dict.pop('etypes', (AES256_CTS_HMAC_SHA1_96,
1590                                              ARCFOUR_HMAC_MD5))
1591
1592             cname = client_cname if rep_type == KRB_AS_REP else None
1593             crealm = client_realm
1594
1595             as_req_self = kdc_dict.pop('as_req_self', False)
1596             if as_req_self:
1597                 self.assertEqual(KRB_AS_REP, rep_type)
1598
1599             if 'sname' in kdc_dict:
1600                 sname = kdc_dict.pop('sname')
1601             else:
1602                 if as_req_self:
1603                     sname = client_cname
1604                 elif rep_type == KRB_AS_REP:
1605                     sname = krbtgt_sname
1606                 else:  # KRB_TGS_REP
1607                     sname = target_sname
1608
1609             if rep_type == KRB_AS_REP:
1610                 srealm = krbtgt_realm
1611             else:  # KRB_TGS_REP
1612                 srealm = target_realm
1613
1614             if rep_type == KRB_TGS_REP:
1615                 tgt_cname = tgt.cname
1616             else:
1617                 tgt_cname = client_cname
1618
1619             expect_edata = kdc_dict.pop('expect_edata', None)
1620             if expect_edata is not None:
1621                 self.assertTrue(expected_error_mode)
1622
1623             expected_cname = kdc_dict.pop('expected_cname', tgt_cname)
1624             expected_anon = kdc_dict.pop('expected_anon',
1625                                          False)
1626             expected_crealm = kdc_dict.pop('expected_crealm', client_realm)
1627             expected_sname = kdc_dict.pop('expected_sname', sname)
1628             expected_srealm = kdc_dict.pop('expected_srealm', srealm)
1629
1630             expected_salt = client_creds.get_salt()
1631
1632             authenticator_subkey = self.RandomKey(kcrypto.Enctype.AES256)
1633             if rep_type == KRB_AS_REP:
1634                 if use_fast:
1635                     armor_key = self.generate_armor_key(authenticator_subkey,
1636                                                         armor_tgt.session_key)
1637                     armor_subkey = authenticator_subkey
1638                 else:
1639                     armor_key = None
1640                     armor_subkey = authenticator_subkey
1641             else:  # KRB_TGS_REP
1642                 if fast_armor_type is not None:
1643                     armor_subkey = self.RandomKey(kcrypto.Enctype.AES256)
1644                     explicit_armor_key = self.generate_armor_key(
1645                         armor_subkey,
1646                         armor_tgt.session_key)
1647                     armor_key = kcrypto.cf2(explicit_armor_key.key,
1648                                             authenticator_subkey.key,
1649                                             b'explicitarmor',
1650                                             b'tgsarmor')
1651                     armor_key = Krb5EncryptionKey(armor_key, None)
1652                 else:
1653                     armor_key = self.generate_armor_key(authenticator_subkey,
1654                                                         tgt.session_key)
1655                     armor_subkey = authenticator_subkey
1656
1657             if not kdc_dict.pop('include_subkey', True):
1658                 authenticator_subkey = None
1659
1660             if use_fast:
1661                 generate_fast_fn = kdc_dict.pop('gen_fast_fn', None)
1662                 if generate_fast_fn is None:
1663                     generate_fast_fn = functools.partial(
1664                         self.generate_simple_fast,
1665                         fast_options=fast_options)
1666             else:
1667                 generate_fast_fn = None
1668
1669             generate_fast_armor_fn = (
1670                 self.generate_ap_req
1671                 if fast_armor_type is not None
1672                 else None)
1673
1674             def _generate_padata_copy(_kdc_exchange_dict,
1675                                       _callback_dict,
1676                                       req_body,
1677                                       padata):
1678                 return list(padata), req_body
1679
1680             pac_request = kdc_dict.pop('pac_request', None)
1681             expect_pac = kdc_dict.pop('expect_pac', True)
1682
1683             pac_options = kdc_dict.pop('pac_options', '1')  # claims support
1684
1685             kdc_options = kdc_dict.pop('kdc_options', kdc_options_default)
1686
1687             gen_padata_fn = kdc_dict.pop('gen_padata_fn', None)
1688
1689             if rep_type == KRB_AS_REP and gen_padata_fn is not None:
1690                 self.assertIsNotNone(preauth_etype_info2)
1691
1692                 preauth_key = self.PasswordKey_from_etype_info2(
1693                     client_creds,
1694                     preauth_etype_info2[0],
1695                     client_creds.get_kvno())
1696             else:
1697                 preauth_key = None
1698
1699             if use_fast:
1700                 generate_fast_padata_fn = gen_padata_fn
1701                 generate_padata_fn = (functools.partial(_generate_padata_copy,
1702                                                          padata=[fast_cookie])
1703                                        if fast_cookie is not None else None)
1704             else:
1705                 generate_fast_padata_fn = None
1706                 generate_padata_fn = gen_padata_fn
1707
1708             gen_authdata_fn = kdc_dict.pop('gen_authdata_fn', None)
1709             if gen_authdata_fn is not None:
1710                 auth_data = [gen_authdata_fn()]
1711             else:
1712                 auth_data = None
1713
1714             gen_enc_authdata_fn = kdc_dict.pop('gen_enc_authdata_fn', None)
1715             if gen_enc_authdata_fn is not None:
1716                 enc_auth_data = [gen_enc_authdata_fn()]
1717
1718                 enc_auth_data_key = authenticator_subkey
1719                 enc_auth_data_usage = KU_TGS_REQ_AUTH_DAT_SUBKEY
1720                 if enc_auth_data_key is None:
1721                     enc_auth_data_key = tgt.session_key
1722                     enc_auth_data_usage = KU_TGS_REQ_AUTH_DAT_SESSION
1723             else:
1724                 enc_auth_data = None
1725
1726                 enc_auth_data_key = None
1727                 enc_auth_data_usage = None
1728
1729             if not use_fast:
1730                 self.assertNotIn('inner_req', kdc_dict)
1731                 self.assertNotIn('outer_req', kdc_dict)
1732             inner_req = kdc_dict.pop('inner_req', None)
1733             outer_req = kdc_dict.pop('outer_req', None)
1734
1735             expected_flags = kdc_dict.pop('expected_flags', None)
1736             if expected_flags is not None:
1737                 expected_flags = krb5_asn1.TicketFlags(expected_flags)
1738             unexpected_flags = kdc_dict.pop('unexpected_flags', None)
1739             if unexpected_flags is not None:
1740                 unexpected_flags = krb5_asn1.TicketFlags(unexpected_flags)
1741
1742             fast_ap_options = kdc_dict.pop('fast_ap_options', None)
1743
1744             strict_edata_checking = kdc_dict.pop('strict_edata_checking', True)
1745
1746             if rep_type == KRB_AS_REP:
1747                 if as_req_self:
1748                     expected_supported_etypes = client_etypes
1749                     decryption_key = client_decryption_key
1750                 else:
1751                     expected_supported_etypes = krbtgt_etypes
1752                     decryption_key = krbtgt_decryption_key
1753
1754                 kdc_exchange_dict = self.as_exchange_dict(
1755                     expected_crealm=expected_crealm,
1756                     expected_cname=expected_cname,
1757                     expected_anon=expected_anon,
1758                     expected_srealm=expected_srealm,
1759                     expected_sname=expected_sname,
1760                     expected_supported_etypes=expected_supported_etypes,
1761                     expected_flags=expected_flags,
1762                     unexpected_flags=unexpected_flags,
1763                     ticket_decryption_key=decryption_key,
1764                     generate_fast_fn=generate_fast_fn,
1765                     generate_fast_armor_fn=generate_fast_armor_fn,
1766                     generate_fast_padata_fn=generate_fast_padata_fn,
1767                     fast_armor_type=fast_armor_type,
1768                     generate_padata_fn=generate_padata_fn,
1769                     check_error_fn=check_error_fn,
1770                     check_rep_fn=check_rep_fn,
1771                     check_kdc_private_fn=self.generic_check_kdc_private,
1772                     callback_dict={},
1773                     expected_error_mode=expected_error_mode,
1774                     expected_salt=expected_salt,
1775                     authenticator_subkey=authenticator_subkey,
1776                     preauth_key=preauth_key,
1777                     auth_data=auth_data,
1778                     armor_key=armor_key,
1779                     armor_tgt=armor_tgt,
1780                     armor_subkey=armor_subkey,
1781                     kdc_options=kdc_options,
1782                     inner_req=inner_req,
1783                     outer_req=outer_req,
1784                     expect_pac=expect_pac,
1785                     pac_request=pac_request,
1786                     pac_options=pac_options,
1787                     fast_ap_options=fast_ap_options,
1788                     strict_edata_checking=strict_edata_checking,
1789                     expect_edata=expect_edata)
1790             else:  # KRB_TGS_REP
1791                 kdc_exchange_dict = self.tgs_exchange_dict(
1792                     expected_crealm=expected_crealm,
1793                     expected_cname=expected_cname,
1794                     expected_anon=expected_anon,
1795                     expected_srealm=expected_srealm,
1796                     expected_sname=expected_sname,
1797                     expected_supported_etypes=target_etypes,
1798                     expected_flags=expected_flags,
1799                     unexpected_flags=unexpected_flags,
1800                     ticket_decryption_key=target_decryption_key,
1801                     generate_fast_fn=generate_fast_fn,
1802                     generate_fast_armor_fn=generate_fast_armor_fn,
1803                     generate_fast_padata_fn=generate_fast_padata_fn,
1804                     fast_armor_type=fast_armor_type,
1805                     generate_padata_fn=generate_padata_fn,
1806                     check_error_fn=check_error_fn,
1807                     check_rep_fn=check_rep_fn,
1808                     check_kdc_private_fn=self.generic_check_kdc_private,
1809                     expected_error_mode=expected_error_mode,
1810                     callback_dict={},
1811                     tgt=tgt,
1812                     armor_key=armor_key,
1813                     armor_tgt=armor_tgt,
1814                     armor_subkey=armor_subkey,
1815                     authenticator_subkey=authenticator_subkey,
1816                     auth_data=auth_data,
1817                     body_checksum_type=None,
1818                     kdc_options=kdc_options,
1819                     inner_req=inner_req,
1820                     outer_req=outer_req,
1821                     expect_pac=expect_pac,
1822                     pac_request=pac_request,
1823                     pac_options=pac_options,
1824                     fast_ap_options=fast_ap_options,
1825                     strict_edata_checking=strict_edata_checking,
1826                     expect_edata=expect_edata)
1827
1828             repeat = kdc_dict.pop('repeat', 1)
1829             for _ in range(repeat):
1830                 rep = self._generic_kdc_exchange(
1831                     kdc_exchange_dict,
1832                     cname=cname,
1833                     realm=crealm,
1834                     sname=sname,
1835                     etypes=etypes,
1836                     EncAuthorizationData=enc_auth_data,
1837                     EncAuthorizationData_key=enc_auth_data_key,
1838                     EncAuthorizationData_usage=enc_auth_data_usage)
1839                 if len(expected_error_mode) == 0:
1840                     self.check_reply(rep, rep_type)
1841
1842                     fast_cookie = None
1843                     preauth_etype_info2 = None
1844
1845                     # Check whether the ticket contains a PAC.
1846                     ticket = kdc_exchange_dict['rep_ticket_creds']
1847                     pac = self.get_ticket_pac(ticket, expect_pac=expect_pac)
1848                     if expect_pac:
1849                         self.assertIsNotNone(pac)
1850                     else:
1851                         self.assertIsNone(pac)
1852                 else:
1853                     self.check_error_rep(rep, expected_error_mode)
1854
1855                     if 'fast_cookie' in kdc_exchange_dict:
1856                         fast_cookie = self.create_fast_cookie(
1857                             kdc_exchange_dict['fast_cookie'])
1858                     else:
1859                         fast_cookie = None
1860
1861                     if KDC_ERR_PREAUTH_REQUIRED in expected_error_mode:
1862                         preauth_etype_info2 = (
1863                             kdc_exchange_dict['preauth_etype_info2'])
1864                     else:
1865                         preauth_etype_info2 = None
1866
1867             # Ensure we used all the parameters given to us.
1868             self.assertEqual({}, kdc_dict)
1869
1870     def generate_enc_pa_rep_padata(self,
1871                                    kdc_exchange_dict,
1872                                    callback_dict,
1873                                    req_body):
1874         padata = self.PA_DATA_create(PADATA_REQ_ENC_PA_REP, b'')
1875
1876         return [padata], req_body
1877
1878     def generate_enc_pa_rep_challenge_padata(self,
1879                                              kdc_exchange_dict,
1880                                              callback_dict,
1881                                              req_body):
1882         padata, req_body = self.generate_enc_challenge_padata(kdc_exchange_dict,
1883                                                               callback_dict,
1884                                                               req_body)
1885
1886         padata.append(self.PA_DATA_create(PADATA_REQ_ENC_PA_REP, b''))
1887
1888         return padata, req_body
1889
1890     def generate_enc_pa_rep_timestamp_padata(self,
1891                                              kdc_exchange_dict,
1892                                              callback_dict,
1893                                              req_body):
1894         padata, req_body = self.generate_enc_timestamp_padata(kdc_exchange_dict,
1895                                                               callback_dict,
1896                                                               req_body)
1897
1898         padata.append(self.PA_DATA_create(PADATA_REQ_ENC_PA_REP, b''))
1899
1900         return padata, req_body
1901
1902     def generate_fast_armor_auth_data(self):
1903         auth_data = self.AuthorizationData_create(AD_FX_FAST_ARMOR, b'')
1904
1905         return auth_data
1906
1907     def generate_fast_used_auth_data(self):
1908         auth_data = self.AuthorizationData_create(AD_FX_FAST_USED, b'')
1909
1910         return auth_data
1911
1912     def gen_tgt_fast_armor_auth_data(self, opts):
1913         user_tgt = self.get_user_tgt(opts)
1914
1915         auth_data = self.generate_fast_armor_auth_data()
1916
1917         def modify_fn(enc_part):
1918             enc_part['authorization-data'].append(auth_data)
1919
1920             return enc_part
1921
1922         checksum_keys = self.get_krbtgt_checksum_key()
1923
1924         # Use our modifed TGT to replace the one in the request.
1925         return self.modified_ticket(user_tgt,
1926                                     modify_fn=modify_fn,
1927                                     checksum_keys=checksum_keys)
1928
1929     def create_fast_cookie(self, cookie):
1930         self.assertIsNotNone(cookie)
1931         if self.strict_checking:
1932             self.assertNotEqual(0, len(cookie))
1933
1934         return self.PA_DATA_create(PADATA_FX_COOKIE, cookie)
1935
1936     def check_kdc_fast_support(self):
1937         # Check that the KDC supports FAST
1938
1939         samdb = self.get_samdb()
1940
1941         krbtgt_rid = security.DOMAIN_RID_KRBTGT
1942         krbtgt_sid = '%s-%d' % (samdb.get_domain_sid(), krbtgt_rid)
1943
1944         res = samdb.search(base='<SID=%s>' % krbtgt_sid,
1945                            scope=ldb.SCOPE_BASE,
1946                            attrs=['msDS-SupportedEncryptionTypes'])
1947
1948         krbtgt_etypes = int(res[0]['msDS-SupportedEncryptionTypes'][0])
1949
1950         self.assertTrue(
1951             security.KERB_ENCTYPE_FAST_SUPPORTED & krbtgt_etypes)
1952         self.assertTrue(
1953             security.KERB_ENCTYPE_COMPOUND_IDENTITY_SUPPORTED & krbtgt_etypes)
1954         self.assertTrue(
1955             security.KERB_ENCTYPE_CLAIMS_SUPPORTED & krbtgt_etypes)
1956
1957     def get_mach_tgt(self, opts):
1958         if opts is None:
1959             opts = {}
1960         mach_creds = self.get_cached_creds(
1961             account_type=self.AccountType.COMPUTER,
1962             opts={
1963                 **opts,
1964                 'fast_support': True,
1965                 'claims_support': True,
1966                 'compound_id_support': True,
1967                 'supported_enctypes': (
1968                     security.KERB_ENCTYPE_RC4_HMAC_MD5 |
1969                     security.KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96_SK
1970                 ),
1971             })
1972         return self.get_tgt(mach_creds)
1973
1974     def get_rodc_issued_mach_tgt(self, opts):
1975         return self.issued_by_rodc(self.get_mach_tgt(opts))
1976
1977     def get_user_tgt(self, opts):
1978         user_creds = self.get_cached_creds(
1979             account_type=self.AccountType.USER,
1980             opts=opts)
1981         return self.get_tgt(user_creds)
1982
1983     def get_user_service_ticket(self, opts):
1984         user_tgt = self.get_user_tgt(opts)
1985         service_creds = self.get_service_creds()
1986         return self.get_service_ticket(user_tgt, service_creds)
1987
1988     def get_mach_service_ticket(self, opts):
1989         mach_tgt = self.get_mach_tgt(opts)
1990         service_creds = self.get_service_creds()
1991         return self.get_service_ticket(mach_tgt, service_creds)
1992
1993     def get_service_ticket_invalid_checksum(self, opts):
1994         ticket = self.get_user_service_ticket(opts)
1995
1996         krbtgt_creds = self.get_krbtgt_creds()
1997         krbtgt_key = self.TicketDecryptionKey_from_creds(krbtgt_creds)
1998
1999         zeroed_key = ZeroedChecksumKey(krbtgt_key.key,
2000                                        krbtgt_key.kvno)
2001
2002         server_key = ticket.decryption_key
2003         checksum_keys = {
2004             krb5pac.PAC_TYPE_SRV_CHECKSUM: server_key,
2005             krb5pac.PAC_TYPE_KDC_CHECKSUM: krbtgt_key,
2006             krb5pac.PAC_TYPE_TICKET_CHECKSUM: zeroed_key,
2007         }
2008
2009         return self.modified_ticket(
2010             ticket,
2011             checksum_keys=checksum_keys,
2012             include_checksums={krb5pac.PAC_TYPE_TICKET_CHECKSUM: True})
2013
2014
2015 if __name__ == "__main__":
2016     global_asn1_print = False
2017     global_hexdump = False
2018     import unittest
2019     unittest.main()