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