CVE-2022-37966 python:tests/krb5: fix some tests running against Windows 2022
[samba.git] / python / samba / tests / krb5 / as_req_tests.py
1 #!/usr/bin/env python3
2 # Unix SMB/CIFS implementation.
3 # Copyright (C) Stefan Metzmacher 2020
4 #
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 3 of the License, or
8 # (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 #
18
19 import sys
20 import os
21
22 sys.path.insert(0, "bin/python")
23 os.environ["PYTHONUNBUFFERED"] = "1"
24
25 from samba.tests import DynamicTestCase
26 from samba.tests.krb5.kdc_base_test import KDCBaseTest
27 import samba.tests.krb5.kcrypto as kcrypto
28 import samba.tests.krb5.rfc4120_pyasn1 as krb5_asn1
29 from samba.tests.krb5.rfc4120_constants import (
30     KDC_ERR_S_PRINCIPAL_UNKNOWN,
31     KDC_ERR_ETYPE_NOSUPP,
32     KDC_ERR_PREAUTH_REQUIRED,
33     KU_PA_ENC_TIMESTAMP,
34     NT_PRINCIPAL,
35     NT_SRV_INST,
36     PADATA_ENC_TIMESTAMP
37 )
38
39 global_asn1_print = False
40 global_hexdump = False
41
42
43 class AsReqBaseTest(KDCBaseTest):
44     def _run_as_req_enc_timestamp(self, client_creds, sname=None,
45                                   expected_error=None,
46                                   expected_pa_error=None, expect_pa_edata=None):
47         client_account = client_creds.get_username()
48         client_as_etypes = self.get_default_enctypes()
49         client_kvno = client_creds.get_kvno()
50         krbtgt_creds = self.get_krbtgt_creds(require_strongest_key=True)
51         krbtgt_account = krbtgt_creds.get_username()
52         realm = krbtgt_creds.get_realm()
53
54         cname = self.PrincipalName_create(name_type=NT_PRINCIPAL,
55                                           names=[client_account])
56         if sname is None:
57             sname = self.PrincipalName_create(name_type=NT_SRV_INST,
58                                               names=[krbtgt_account, realm])
59
60         expected_crealm = realm
61         expected_cname = cname
62         expected_srealm = realm
63         expected_sname = sname
64         expected_salt = client_creds.get_salt()
65
66         till = self.get_KerberosTime(offset=36000)
67
68         initial_etypes = client_as_etypes
69         initial_kdc_options = krb5_asn1.KDCOptions('forwardable')
70         if expected_error is not None:
71             initial_error_mode = expected_error
72         else:
73             initial_error_mode = KDC_ERR_PREAUTH_REQUIRED
74
75         rep, kdc_exchange_dict = self._test_as_exchange(cname,
76                                                         realm,
77                                                         sname,
78                                                         till,
79                                                         client_as_etypes,
80                                                         initial_error_mode,
81                                                         expected_crealm,
82                                                         expected_cname,
83                                                         expected_srealm,
84                                                         expected_sname,
85                                                         expected_salt,
86                                                         initial_etypes,
87                                                         None,
88                                                         initial_kdc_options,
89                                                         pac_request=True)
90
91         if expected_error is not None:
92             return None
93
94         etype_info2 = kdc_exchange_dict['preauth_etype_info2']
95         self.assertIsNotNone(etype_info2)
96
97         preauth_key = self.PasswordKey_from_etype_info2(client_creds,
98                                                         etype_info2[0],
99                                                         kvno=client_kvno)
100
101         (patime, pausec) = self.get_KerberosTimeWithUsec()
102         pa_ts = self.PA_ENC_TS_ENC_create(patime, pausec)
103         pa_ts = self.der_encode(pa_ts, asn1Spec=krb5_asn1.PA_ENC_TS_ENC())
104
105         enc_pa_ts_usage = KU_PA_ENC_TIMESTAMP
106         pa_ts = self.EncryptedData_create(preauth_key, enc_pa_ts_usage, pa_ts)
107         pa_ts = self.der_encode(pa_ts, asn1Spec=krb5_asn1.EncryptedData())
108
109         pa_ts = self.PA_DATA_create(PADATA_ENC_TIMESTAMP, pa_ts)
110
111         preauth_padata = [pa_ts]
112         preauth_etypes = client_as_etypes
113         preauth_kdc_options = krb5_asn1.KDCOptions('forwardable')
114         preauth_error_mode = 0 # AS-REP
115         if expected_pa_error is not None:
116             preauth_error_mode = expected_pa_error
117
118         krbtgt_decryption_key = (
119             self.TicketDecryptionKey_from_creds(krbtgt_creds))
120
121         as_rep, kdc_exchange_dict = self._test_as_exchange(
122             cname,
123             realm,
124             sname,
125             till,
126             client_as_etypes,
127             preauth_error_mode,
128             expected_crealm,
129             expected_cname,
130             expected_srealm,
131             expected_sname,
132             expected_salt,
133             preauth_etypes,
134             preauth_padata,
135             preauth_kdc_options,
136             expect_edata=expect_pa_edata,
137             preauth_key=preauth_key,
138             ticket_decryption_key=krbtgt_decryption_key,
139             pac_request=True)
140         self.assertIsNotNone(as_rep)
141
142         return etype_info2
143
144
145 @DynamicTestCase
146 class AsReqKerberosTests(AsReqBaseTest):
147
148     @classmethod
149     def setUpDynamicTestCases(cls):
150         for (name, idx) in cls.etype_test_permutation_name_idx():
151             for pac in [None, True, False]:
152                 tname = "%s_pac_%s" % (name, pac)
153                 targs = (idx, pac)
154                 cls.generate_dynamic_test("test_as_req_no_preauth", tname, *targs)
155
156     def setUp(self):
157         super(AsReqKerberosTests, self).setUp()
158         self.do_asn1_print = global_asn1_print
159         self.do_hexdump = global_hexdump
160
161     def _test_as_req_nopreauth(self,
162                                initial_etypes,
163                                pac=None,
164                                initial_kdc_options=None):
165         client_creds = self.get_client_creds()
166         client_account = client_creds.get_username()
167         client_as_etypes = self.get_default_enctypes()
168         krbtgt_creds = self.get_krbtgt_creds(require_keys=False)
169         krbtgt_account = krbtgt_creds.get_username()
170         realm = krbtgt_creds.get_realm()
171
172         cname = self.PrincipalName_create(name_type=NT_PRINCIPAL,
173                                           names=[client_account])
174         sname = self.PrincipalName_create(name_type=NT_SRV_INST,
175                                           names=[krbtgt_account, realm])
176
177         expected_crealm = realm
178         expected_cname = cname
179         expected_srealm = realm
180         expected_sname = sname
181         expected_salt = client_creds.get_salt()
182
183         if any(etype in client_as_etypes and etype in initial_etypes
184                for etype in (kcrypto.Enctype.AES256,
185                              kcrypto.Enctype.AES128,
186                              kcrypto.Enctype.RC4)):
187             expected_error_mode = KDC_ERR_PREAUTH_REQUIRED
188         else:
189             expected_error_mode = KDC_ERR_ETYPE_NOSUPP
190
191         kdc_exchange_dict = self.as_exchange_dict(
192             expected_crealm=expected_crealm,
193             expected_cname=expected_cname,
194             expected_srealm=expected_srealm,
195             expected_sname=expected_sname,
196             generate_padata_fn=None,
197             check_error_fn=self.generic_check_kdc_error,
198             check_rep_fn=None,
199             expected_error_mode=expected_error_mode,
200             client_as_etypes=client_as_etypes,
201             expected_salt=expected_salt,
202             kdc_options=str(initial_kdc_options),
203             pac_request=pac)
204
205         self._generic_kdc_exchange(kdc_exchange_dict,
206                                    cname=cname,
207                                    realm=realm,
208                                    sname=sname,
209                                    etypes=initial_etypes)
210
211     def _test_as_req_no_preauth_with_args(self, etype_idx, pac):
212         name, etypes = self.etype_test_permutation_by_idx(etype_idx)
213         self._test_as_req_nopreauth(
214                      pac=pac,
215                      initial_etypes=etypes,
216                      initial_kdc_options=krb5_asn1.KDCOptions('forwardable'))
217
218     def test_as_req_enc_timestamp(self):
219         client_creds = self.get_client_creds()
220         self._run_as_req_enc_timestamp(client_creds)
221
222     def test_as_req_enc_timestamp_mac(self):
223         client_creds = self.get_mach_creds()
224         self._run_as_req_enc_timestamp(client_creds)
225
226     # Ensure we can't use truncated well-known principals such as krb@REALM
227     # instead of krbtgt@REALM.
228     def test_krbtgt_wrong_principal(self):
229         client_creds = self.get_client_creds()
230
231         krbtgt_creds = self.get_krbtgt_creds()
232
233         krbtgt_account = krbtgt_creds.get_username()
234         realm = krbtgt_creds.get_realm()
235
236         # Truncate the name of the krbtgt principal.
237         krbtgt_account = krbtgt_account[:3]
238
239         wrong_krbtgt_princ = self.PrincipalName_create(
240             name_type=NT_SRV_INST,
241             names=[krbtgt_account, realm])
242
243         if self.strict_checking:
244             self._run_as_req_enc_timestamp(
245                 client_creds,
246                 sname=wrong_krbtgt_princ,
247                 expected_pa_error=KDC_ERR_S_PRINCIPAL_UNKNOWN,
248                 expect_pa_edata=False)
249         else:
250             self._run_as_req_enc_timestamp(
251                 client_creds,
252                 sname=wrong_krbtgt_princ,
253                 expected_error=KDC_ERR_S_PRINCIPAL_UNKNOWN)
254
255
256 if __name__ == "__main__":
257     global_asn1_print = False
258     global_hexdump = False
259     import unittest
260     unittest.main()
261