2 # Unix SMB/CIFS implementation.
3 # Copyright (C) Stefan Metzmacher 2020
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 3 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program. If not, see <http://www.gnu.org/licenses/>.
22 sys.path.insert(0, "bin/python")
23 os.environ["PYTHONUNBUFFERED"] = "1"
25 from samba.tests import DynamicTestCase
26 from samba.tests.krb5.kdc_base_test import KDCBaseTest
27 import samba.tests.krb5.kcrypto as kcrypto
28 import samba.tests.krb5.rfc4120_pyasn1 as krb5_asn1
29 from samba.tests.krb5.rfc4120_constants import (
30 KDC_ERR_S_PRINCIPAL_UNKNOWN,
32 KDC_ERR_PREAUTH_REQUIRED,
39 global_asn1_print = False
40 global_hexdump = False
43 class AsReqBaseTest(KDCBaseTest):
44 def _run_as_req_enc_timestamp(self, client_creds, sname=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()
54 cname = self.PrincipalName_create(name_type=NT_PRINCIPAL,
55 names=[client_account])
57 sname = self.PrincipalName_create(name_type=NT_SRV_INST,
58 names=[krbtgt_account, realm])
60 expected_crealm = realm
61 expected_cname = cname
62 expected_srealm = realm
63 expected_sname = sname
64 expected_salt = client_creds.get_salt()
66 till = self.get_KerberosTime(offset=36000)
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
73 initial_error_mode = KDC_ERR_PREAUTH_REQUIRED
75 rep, kdc_exchange_dict = self._test_as_exchange(cname,
91 if expected_error is not None:
94 etype_info2 = kdc_exchange_dict['preauth_etype_info2']
95 self.assertIsNotNone(etype_info2)
97 preauth_key = self.PasswordKey_from_etype_info2(client_creds,
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())
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())
109 pa_ts = self.PA_DATA_create(PADATA_ENC_TIMESTAMP, pa_ts)
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
118 krbtgt_decryption_key = (
119 self.TicketDecryptionKey_from_creds(krbtgt_creds))
121 as_rep, kdc_exchange_dict = self._test_as_exchange(
136 expect_edata=expect_pa_edata,
137 preauth_key=preauth_key,
138 ticket_decryption_key=krbtgt_decryption_key,
140 self.assertIsNotNone(as_rep)
146 class AsReqKerberosTests(AsReqBaseTest):
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)
154 cls.generate_dynamic_test("test_as_req_no_preauth", tname, *targs)
157 super(AsReqKerberosTests, self).setUp()
158 self.do_asn1_print = global_asn1_print
159 self.do_hexdump = global_hexdump
161 def _test_as_req_nopreauth(self,
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()
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])
177 expected_crealm = realm
178 expected_cname = cname
179 expected_srealm = realm
180 expected_sname = sname
181 expected_salt = client_creds.get_salt()
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
189 expected_error_mode = KDC_ERR_ETYPE_NOSUPP
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,
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),
205 self._generic_kdc_exchange(kdc_exchange_dict,
209 etypes=initial_etypes)
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(
215 initial_etypes=etypes,
216 initial_kdc_options=krb5_asn1.KDCOptions('forwardable'))
218 def test_as_req_enc_timestamp(self):
219 client_creds = self.get_client_creds()
220 self._run_as_req_enc_timestamp(client_creds)
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)
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()
231 krbtgt_creds = self.get_krbtgt_creds()
233 krbtgt_account = krbtgt_creds.get_username()
234 realm = krbtgt_creds.get_realm()
236 # Truncate the name of the krbtgt principal.
237 krbtgt_account = krbtgt_account[:3]
239 wrong_krbtgt_princ = self.PrincipalName_create(
240 name_type=NT_SRV_INST,
241 names=[krbtgt_account, realm])
243 if self.strict_checking:
244 self._run_as_req_enc_timestamp(
246 sname=wrong_krbtgt_princ,
247 expected_pa_error=KDC_ERR_S_PRINCIPAL_UNKNOWN,
248 expect_pa_edata=False)
250 self._run_as_req_enc_timestamp(
252 sname=wrong_krbtgt_princ,
253 expected_error=KDC_ERR_S_PRINCIPAL_UNKNOWN)
256 if __name__ == "__main__":
257 global_asn1_print = False
258 global_hexdump = False