Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : Validate the krb5 pac generation routines
5 :
6 : Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
7 :
8 : This program is free software; you can redistribute it and/or modify
9 : it under the terms of the GNU General Public License as published by
10 : the Free Software Foundation; either version 3 of the License, or
11 : (at your option) any later version.
12 :
13 : This program is distributed in the hope that it will be useful,
14 : but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : GNU General Public License for more details.
17 :
18 :
19 : You should have received a copy of the GNU General Public License
20 : along with this program. If not, see <http://www.gnu.org/licenses/>.
21 : */
22 :
23 : #include "includes.h"
24 : #include "system/kerberos.h"
25 : #include "auth/auth.h"
26 : #include "auth/kerberos/kerberos.h"
27 : #include "samba3/samba3.h"
28 : #include "libcli/security/security.h"
29 : #include "torture/torture.h"
30 : #include "auth/auth_sam_reply.h"
31 : #include "param/param.h"
32 : #include "librpc/gen_ndr/ndr_krb5pac.h"
33 : #include "torture/auth/proto.h"
34 : #include "auth/kerberos/pac_utils.h"
35 :
36 1 : static bool torture_pac_self_check(struct torture_context *tctx)
37 : {
38 1 : NTSTATUS nt_status;
39 1 : DATA_BLOB tmp_blob;
40 1 : struct PAC_DATA *pac_data;
41 1 : struct PAC_LOGON_INFO *logon_info;
42 1 : union netr_Validation validation;
43 :
44 : /* Generate a nice, arbitrary keyblock */
45 1 : uint8_t server_bytes[16];
46 1 : uint8_t krbtgt_bytes[16];
47 1 : krb5_keyblock server_keyblock;
48 1 : krb5_keyblock krbtgt_keyblock;
49 :
50 1 : krb5_error_code ret;
51 :
52 1 : struct smb_krb5_context *smb_krb5_context;
53 :
54 1 : struct auth_user_info_dc *user_info_dc;
55 1 : struct auth_user_info_dc *user_info_dc_out;
56 :
57 1 : krb5_principal client_principal;
58 1 : time_t logon_time = time(NULL);
59 :
60 1 : TALLOC_CTX *mem_ctx = tctx;
61 :
62 1 : torture_assert(tctx, 0 == smb_krb5_init_context(mem_ctx,
63 : tctx->lp_ctx,
64 : &smb_krb5_context),
65 : "smb_krb5_init_context");
66 :
67 1 : generate_random_buffer(server_bytes, 16);
68 1 : generate_random_buffer(krbtgt_bytes, 16);
69 :
70 1 : ret = smb_krb5_keyblock_init_contents(smb_krb5_context->krb5_context,
71 : ENCTYPE_ARCFOUR_HMAC,
72 : server_bytes, sizeof(server_bytes),
73 : &server_keyblock);
74 1 : torture_assert(tctx, !ret, talloc_asprintf(tctx,
75 : "(self test) Server Keyblock encoding failed: %s",
76 : smb_get_krb5_error_message(smb_krb5_context->krb5_context,
77 : ret, mem_ctx)));
78 :
79 1 : ret = smb_krb5_keyblock_init_contents(smb_krb5_context->krb5_context,
80 : ENCTYPE_ARCFOUR_HMAC,
81 : krbtgt_bytes, sizeof(krbtgt_bytes),
82 : &krbtgt_keyblock);
83 1 : if (ret) {
84 0 : char *err = smb_get_krb5_error_message(smb_krb5_context->krb5_context,
85 : ret, mem_ctx);
86 :
87 0 : krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
88 : &server_keyblock);
89 :
90 0 : torture_fail(tctx, talloc_asprintf(tctx,
91 : "(self test) KRBTGT Keyblock encoding failed: %s", err));
92 : }
93 :
94 : /* We need an input, and this one requires no underlying database */
95 1 : nt_status = auth_anonymous_user_info_dc(mem_ctx, lpcfg_netbios_name(tctx->lp_ctx), &user_info_dc);
96 :
97 1 : if (!NT_STATUS_IS_OK(nt_status)) {
98 0 : krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
99 : &server_keyblock);
100 0 : krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
101 : &krbtgt_keyblock);
102 0 : torture_fail(tctx, "auth_anonymous_user_info_dc");
103 : }
104 :
105 2 : ret = krb5_parse_name_flags(smb_krb5_context->krb5_context,
106 1 : user_info_dc->info->account_name,
107 : KRB5_PRINCIPAL_PARSE_NO_REALM,
108 : &client_principal);
109 1 : if (ret) {
110 0 : krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
111 : &server_keyblock);
112 0 : krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
113 : &krbtgt_keyblock);
114 0 : torture_fail(tctx, "krb5_parse_name_flags(norealm)");
115 : }
116 :
117 : /* OK, go ahead and make a PAC */
118 2 : ret = kerberos_create_pac(mem_ctx,
119 : user_info_dc,
120 1 : smb_krb5_context->krb5_context,
121 : &krbtgt_keyblock,
122 : &server_keyblock,
123 : client_principal,
124 : logon_time,
125 : &tmp_blob);
126 :
127 1 : if (ret) {
128 0 : krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
129 : &krbtgt_keyblock);
130 0 : krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
131 : &server_keyblock);
132 0 : krb5_free_principal(smb_krb5_context->krb5_context,
133 : client_principal);
134 :
135 0 : torture_fail(tctx, talloc_asprintf(tctx,
136 : "(self test) PAC encoding failed: %s",
137 : smb_get_krb5_error_message(smb_krb5_context->krb5_context,
138 : ret, mem_ctx)));
139 : }
140 :
141 1 : dump_data(10,tmp_blob.data,tmp_blob.length);
142 :
143 : /* Now check that we can read it back (using full decode and validate) */
144 2 : nt_status = kerberos_decode_pac(mem_ctx,
145 : tmp_blob,
146 1 : smb_krb5_context->krb5_context,
147 : &krbtgt_keyblock,
148 : &server_keyblock,
149 : client_principal,
150 : logon_time,
151 : &pac_data);
152 :
153 1 : if (!NT_STATUS_IS_OK(nt_status)) {
154 0 : krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
155 : &krbtgt_keyblock);
156 0 : krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
157 : &server_keyblock);
158 0 : krb5_free_principal(smb_krb5_context->krb5_context,
159 : client_principal);
160 :
161 0 : torture_fail(tctx, talloc_asprintf(tctx,
162 : "(self test) PAC decoding failed: %s",
163 : nt_errstr(nt_status)));
164 : }
165 :
166 : /* Now check we can read it back (using Heimdal's pac parsing) */
167 2 : nt_status = kerberos_pac_blob_to_user_info_dc(mem_ctx,
168 : tmp_blob,
169 1 : smb_krb5_context->krb5_context,
170 : &user_info_dc_out, NULL, NULL);
171 :
172 : /* The user's SID is the first element in the list */
173 1 : if (!dom_sid_equal(&user_info_dc->sids[PRIMARY_USER_SID_INDEX].sid,
174 1 : &user_info_dc_out->sids[PRIMARY_USER_SID_INDEX].sid)) {
175 0 : krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
176 : &krbtgt_keyblock);
177 0 : krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
178 : &server_keyblock);
179 0 : krb5_free_principal(smb_krb5_context->krb5_context,
180 : client_principal);
181 :
182 0 : torture_fail(tctx,
183 : talloc_asprintf(tctx,
184 : "(self test) PAC Decode resulted in *different* domain SID: %s != %s",
185 : dom_sid_string(mem_ctx, &user_info_dc->sids[PRIMARY_USER_SID_INDEX].sid),
186 : dom_sid_string(mem_ctx, &user_info_dc_out->sids[PRIMARY_USER_SID_INDEX].sid)));
187 : }
188 1 : talloc_free(user_info_dc_out);
189 :
190 : /* Now check that we can read it back (yet again) */
191 2 : nt_status = kerberos_pac_logon_info(mem_ctx,
192 : tmp_blob,
193 1 : smb_krb5_context->krb5_context,
194 : &krbtgt_keyblock,
195 : &server_keyblock,
196 : client_principal,
197 : logon_time,
198 : &logon_info);
199 :
200 1 : if (!NT_STATUS_IS_OK(nt_status)) {
201 0 : krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
202 : &krbtgt_keyblock);
203 0 : krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
204 : &server_keyblock);
205 0 : krb5_free_principal(smb_krb5_context->krb5_context,
206 : client_principal);
207 :
208 0 : torture_fail(tctx,
209 : talloc_asprintf(tctx,
210 : "(self test) PAC decoding (for logon info) failed: %s",
211 : nt_errstr(nt_status)));
212 : }
213 :
214 1 : krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
215 : &krbtgt_keyblock);
216 1 : krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
217 : &server_keyblock);
218 1 : krb5_free_principal(smb_krb5_context->krb5_context,
219 : client_principal);
220 :
221 : /* And make a server info from the samba-parsed PAC */
222 1 : validation.sam3 = &logon_info->info3;
223 1 : nt_status = make_user_info_dc_netlogon_validation(mem_ctx,
224 : "",
225 : 3, &validation,
226 : true, /* This user was authenticated */
227 : &user_info_dc_out);
228 1 : if (!NT_STATUS_IS_OK(nt_status)) {
229 0 : torture_fail(tctx,
230 : talloc_asprintf(tctx,
231 : "(self test) PAC decoding (make server info) failed: %s",
232 : nt_errstr(nt_status)));
233 : }
234 :
235 1 : if (!dom_sid_equal(&user_info_dc->sids[PRIMARY_USER_SID_INDEX].sid,
236 1 : &user_info_dc_out->sids[PRIMARY_USER_SID_INDEX].sid)) {
237 0 : torture_fail(tctx,
238 : talloc_asprintf(tctx,
239 : "(self test) PAC Decode resulted in *different* domain SID: %s != %s",
240 : dom_sid_string(mem_ctx, &user_info_dc->sids[PRIMARY_USER_SID_INDEX].sid),
241 : dom_sid_string(mem_ctx, &user_info_dc_out->sids[PRIMARY_USER_SID_INDEX].sid)));
242 : }
243 0 : return true;
244 : }
245 :
246 :
247 : /* This is the PAC generated on my test network, by my test Win2k3 server.
248 : -- abartlet 2005-07-04
249 : */
250 :
251 : static const uint8_t saved_pac[] = {
252 : 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xd8, 0x01, 0x00, 0x00,
253 : 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
254 : 0x20, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
255 : 0x40, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
256 : 0x58, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc,
257 : 0xc8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x30, 0xdf, 0xa6, 0xcb,
258 : 0x4f, 0x7d, 0xc5, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff,
259 : 0xff, 0xff, 0xff, 0x7f, 0xc0, 0x3c, 0x4e, 0x59, 0x62, 0x73, 0xc5, 0x01, 0xc0, 0x3c, 0x4e, 0x59,
260 : 0x62, 0x73, 0xc5, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x16, 0x00, 0x16, 0x00,
261 : 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
262 : 0x0c, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
263 : 0x14, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x02, 0x00, 0x65, 0x00, 0x00, 0x00,
264 : 0xed, 0x03, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x02, 0x00,
265 : 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
266 : 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x16, 0x00, 0x20, 0x00, 0x02, 0x00, 0x16, 0x00, 0x18, 0x00,
267 : 0x24, 0x00, 0x02, 0x00, 0x28, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
268 : 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
269 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
270 : 0x01, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
271 : 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
272 : 0x57, 0x00, 0x32, 0x00, 0x30, 0x00, 0x30, 0x00, 0x33, 0x00, 0x46, 0x00, 0x49, 0x00, 0x4e, 0x00,
273 : 0x41, 0x00, 0x4c, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
274 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
275 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
276 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
277 : 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
278 : 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x57, 0x00, 0x32, 0x00,
279 : 0x30, 0x00, 0x30, 0x00, 0x33, 0x00, 0x46, 0x00, 0x49, 0x00, 0x4e, 0x00, 0x41, 0x00, 0x4c, 0x00,
280 : 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x57, 0x00, 0x49, 0x00,
281 : 0x4e, 0x00, 0x32, 0x00, 0x4b, 0x00, 0x33, 0x00, 0x54, 0x00, 0x48, 0x00, 0x49, 0x00, 0x4e, 0x00,
282 : 0x4b, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
283 : 0x15, 0x00, 0x00, 0x00, 0x11, 0x2f, 0xaf, 0xb5, 0x90, 0x04, 0x1b, 0xec, 0x50, 0x3b, 0xec, 0xdc,
284 : 0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x02, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
285 : 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
286 : 0x80, 0x66, 0x28, 0xea, 0x37, 0x80, 0xc5, 0x01, 0x16, 0x00, 0x77, 0x00, 0x32, 0x00, 0x30, 0x00,
287 : 0x30, 0x00, 0x33, 0x00, 0x66, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x24, 0x00,
288 : 0x76, 0xff, 0xff, 0xff, 0x37, 0xd5, 0xb0, 0xf7, 0x24, 0xf0, 0xd6, 0xd4, 0xec, 0x09, 0x86, 0x5a,
289 : 0xa0, 0xe8, 0xc3, 0xa9, 0x00, 0x00, 0x00, 0x00, 0x76, 0xff, 0xff, 0xff, 0xb4, 0xd8, 0xb8, 0xfe,
290 : 0x83, 0xb3, 0x13, 0x3f, 0xfc, 0x5c, 0x41, 0xad, 0xe2, 0x64, 0x83, 0xe0, 0x00, 0x00, 0x00, 0x00
291 : };
292 :
293 : /* Check with a known 'well formed' PAC, from my test server */
294 1 : static bool torture_pac_saved_check(struct torture_context *tctx)
295 : {
296 1 : NTSTATUS nt_status;
297 1 : enum ndr_err_code ndr_err;
298 1 : DATA_BLOB tmp_blob, validate_blob;
299 1 : struct PAC_DATA *pac_data, pac_data2;
300 1 : struct PAC_LOGON_INFO *logon_info;
301 1 : union netr_Validation validation;
302 1 : const char *pac_file, *pac_kdc_key, *pac_member_key;
303 1 : struct auth_user_info_dc *user_info_dc_out;
304 :
305 1 : krb5_keyblock server_keyblock;
306 1 : krb5_keyblock krbtgt_keyblock, *krbtgt_keyblock_p;
307 1 : struct samr_Password *krbtgt_bytes, *krbsrv_bytes;
308 :
309 1 : krb5_error_code ret;
310 1 : struct smb_krb5_context *smb_krb5_context;
311 :
312 1 : const char *principal_string;
313 1 : char *broken_principal_string;
314 1 : krb5_principal client_principal;
315 1 : const char *authtime_string;
316 1 : time_t authtime;
317 1 : TALLOC_CTX *mem_ctx = tctx;
318 :
319 1 : torture_assert(tctx, 0 == smb_krb5_init_context(mem_ctx,
320 : tctx->lp_ctx,
321 : &smb_krb5_context),
322 : "smb_krb5_init_context");
323 :
324 1 : pac_kdc_key = torture_setting_string(tctx, "pac_kdc_key",
325 : "B286757148AF7FD252C53603A150B7E7");
326 :
327 1 : pac_member_key = torture_setting_string(tctx, "pac_member_key",
328 : "D217FAEAE5E6B5F95CCC94077AB8A5FC");
329 :
330 1 : torture_comment(tctx, "Using pac_kdc_key '%s'\n", pac_kdc_key);
331 1 : torture_comment(tctx, "Using pac_member_key '%s'\n", pac_member_key);
332 :
333 : /* The krbtgt key in use when the above PAC was generated.
334 : * This is an arcfour-hmac-md5 key, extracted with our 'net
335 : * samdump' tool. */
336 1 : if (*pac_kdc_key == 0) {
337 0 : krbtgt_bytes = NULL;
338 : } else {
339 1 : krbtgt_bytes = smbpasswd_gethexpwd(mem_ctx, pac_kdc_key);
340 1 : if (!krbtgt_bytes) {
341 0 : torture_fail(tctx, "(saved test) Could not interpret krbtgt key");
342 : }
343 : }
344 :
345 1 : krbsrv_bytes = smbpasswd_gethexpwd(mem_ctx, pac_member_key);
346 1 : if (!krbsrv_bytes) {
347 0 : torture_fail(tctx, "(saved test) Could not interpret krbsrv key");
348 : }
349 :
350 2 : ret = smb_krb5_keyblock_init_contents(smb_krb5_context->krb5_context,
351 : ENCTYPE_ARCFOUR_HMAC,
352 1 : krbsrv_bytes->hash, sizeof(krbsrv_bytes->hash),
353 : &server_keyblock);
354 1 : torture_assert(tctx, !ret,
355 : talloc_asprintf(tctx,
356 : "(saved test) Server Keyblock encoding failed: %s",
357 : smb_get_krb5_error_message(smb_krb5_context->krb5_context,
358 : ret, mem_ctx)));
359 :
360 1 : if (krbtgt_bytes) {
361 2 : ret = smb_krb5_keyblock_init_contents(smb_krb5_context->krb5_context,
362 : ENCTYPE_ARCFOUR_HMAC,
363 1 : krbtgt_bytes->hash, sizeof(krbtgt_bytes->hash),
364 : &krbtgt_keyblock);
365 1 : if (ret) {
366 0 : krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
367 : &server_keyblock);
368 0 : torture_fail(tctx,
369 : talloc_asprintf(tctx,
370 : "(saved test) Server Keyblock encoding failed: %s",
371 : smb_get_krb5_error_message(smb_krb5_context->krb5_context,
372 : ret, mem_ctx)));
373 : }
374 0 : krbtgt_keyblock_p = &krbtgt_keyblock;
375 : } else {
376 0 : krbtgt_keyblock_p = NULL;
377 : }
378 :
379 1 : pac_file = torture_setting_string(tctx, "pac_file", NULL);
380 1 : if (pac_file) {
381 0 : tmp_blob.data = (uint8_t *)file_load(pac_file, &tmp_blob.length, 0, mem_ctx);
382 0 : torture_comment(tctx, "(saved test) Loaded pac of size %ld from %s\n", (long)tmp_blob.length, pac_file);
383 : } else {
384 1 : tmp_blob = data_blob_talloc(mem_ctx, saved_pac, sizeof(saved_pac));
385 : }
386 :
387 1 : dump_data(10,tmp_blob.data,tmp_blob.length);
388 :
389 1 : principal_string = torture_setting_string(tctx, "pac_client_principal",
390 : "w2003final$@WIN2K3.THINKER.LOCAL");
391 :
392 1 : authtime_string = torture_setting_string(tctx, "pac_authtime", "1120440609");
393 1 : authtime = strtoull(authtime_string, NULL, 0);
394 :
395 1 : ret = krb5_parse_name(smb_krb5_context->krb5_context, principal_string,
396 : &client_principal);
397 1 : if (ret) {
398 0 : krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
399 : krbtgt_keyblock_p);
400 0 : krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
401 : &server_keyblock);
402 0 : torture_fail(tctx,
403 : talloc_asprintf(tctx,
404 : "(saved test) parsing of client principal [%s] failed: %s",
405 : principal_string,
406 : smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx)));
407 : }
408 :
409 : /* Decode and verify the signaure on the PAC */
410 2 : nt_status = kerberos_decode_pac(mem_ctx,
411 : tmp_blob,
412 1 : smb_krb5_context->krb5_context,
413 : krbtgt_keyblock_p,
414 : &server_keyblock,
415 : client_principal, authtime, &pac_data);
416 1 : if (!NT_STATUS_IS_OK(nt_status)) {
417 0 : krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
418 : krbtgt_keyblock_p);
419 0 : krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
420 : &server_keyblock);
421 0 : krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
422 :
423 0 : torture_fail(tctx, talloc_asprintf(tctx,
424 : "(saved test) PAC decoding failed: %s",
425 : nt_errstr(nt_status)));
426 : }
427 :
428 : /* Now check we can read it back (using Heimdal's pac parsing) */
429 2 : nt_status = kerberos_pac_blob_to_user_info_dc(mem_ctx,
430 : tmp_blob,
431 1 : smb_krb5_context->krb5_context,
432 : &user_info_dc_out,
433 : NULL, NULL);
434 :
435 1 : if (!NT_STATUS_IS_OK(nt_status)) {
436 0 : krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
437 : krbtgt_keyblock_p);
438 0 : krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
439 : &server_keyblock);
440 0 : krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
441 :
442 0 : torture_fail(tctx, talloc_asprintf(tctx,
443 : "(saved test) Heimdal PAC decoding failed: %s",
444 : nt_errstr(nt_status)));
445 : }
446 :
447 2 : if (!pac_file &&
448 1 : !dom_sid_equal(dom_sid_parse_talloc(mem_ctx,
449 : "S-1-5-21-3048156945-3961193616-3706469200-1005"),
450 1 : &user_info_dc_out->sids[PRIMARY_USER_SID_INDEX].sid)) {
451 0 : krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
452 : krbtgt_keyblock_p);
453 0 : krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
454 : &server_keyblock);
455 0 : krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
456 :
457 0 : torture_fail(tctx,
458 : talloc_asprintf(tctx,
459 : "(saved test) Heimdal PAC Decode resulted in *different* domain SID: %s != %s",
460 : "S-1-5-21-3048156945-3961193616-3706469200-1005",
461 : dom_sid_string(mem_ctx, &user_info_dc_out->sids[PRIMARY_USER_SID_INDEX].sid)));
462 : }
463 :
464 1 : talloc_free(user_info_dc_out);
465 :
466 : /* Parse the PAC again, for the logon info this time (using Samba4's parsing) */
467 2 : nt_status = kerberos_pac_logon_info(mem_ctx,
468 : tmp_blob,
469 1 : smb_krb5_context->krb5_context,
470 : krbtgt_keyblock_p,
471 : &server_keyblock,
472 : client_principal, authtime, &logon_info);
473 :
474 1 : if (!NT_STATUS_IS_OK(nt_status)) {
475 0 : krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
476 : krbtgt_keyblock_p);
477 0 : krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
478 : &server_keyblock);
479 0 : krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
480 :
481 0 : torture_fail(tctx,
482 : talloc_asprintf(tctx,
483 : "(saved test) PAC decoding (for logon info) failed: %s",
484 : nt_errstr(nt_status)));
485 : }
486 :
487 1 : validation.sam3 = &logon_info->info3;
488 1 : nt_status = make_user_info_dc_netlogon_validation(mem_ctx,
489 : "",
490 : 3, &validation,
491 : true, /* This user was authenticated */
492 : &user_info_dc_out);
493 1 : if (!NT_STATUS_IS_OK(nt_status)) {
494 0 : krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
495 : krbtgt_keyblock_p);
496 0 : krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
497 : &server_keyblock);
498 0 : krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
499 :
500 0 : torture_fail(tctx,
501 : talloc_asprintf(tctx,
502 : "(saved test) PAC decoding (make server info) failed: %s",
503 : nt_errstr(nt_status)));
504 : }
505 :
506 2 : if (!pac_file &&
507 1 : !dom_sid_equal(dom_sid_parse_talloc(mem_ctx,
508 : "S-1-5-21-3048156945-3961193616-3706469200-1005"),
509 1 : &user_info_dc_out->sids[PRIMARY_USER_SID_INDEX].sid)) {
510 0 : krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
511 : krbtgt_keyblock_p);
512 0 : krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
513 : &server_keyblock);
514 0 : krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
515 :
516 0 : torture_fail(tctx,
517 : talloc_asprintf(tctx,
518 : "(saved test) PAC Decode resulted in *different* domain SID: %s != %s",
519 : "S-1-5-21-3048156945-3961193616-3706469200-1005",
520 : dom_sid_string(mem_ctx, &user_info_dc_out->sids[PRIMARY_USER_SID_INDEX].sid)));
521 : }
522 :
523 1 : if (krbtgt_bytes == NULL) {
524 0 : torture_comment(tctx, "skipping PAC encoding tests as non kdc key\n");
525 0 : krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
526 : &server_keyblock);
527 0 : krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
528 0 : return true;
529 : }
530 :
531 2 : ret = kerberos_encode_pac(mem_ctx,
532 : pac_data,
533 1 : smb_krb5_context->krb5_context,
534 : krbtgt_keyblock_p,
535 : &server_keyblock,
536 : &validate_blob);
537 :
538 1 : if (ret != 0) {
539 0 : krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
540 : krbtgt_keyblock_p);
541 0 : krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
542 : &server_keyblock);
543 0 : krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
544 :
545 0 : torture_fail(tctx, "(saved test) PAC push failed");
546 : }
547 :
548 1 : dump_data(10, validate_blob.data, validate_blob.length);
549 :
550 : /* compare both the length and the data bytes after a
551 : * pull/push cycle. This ensures we use the exact same
552 : * pointer, padding etc algorithms as win2k3.
553 : */
554 1 : if (tmp_blob.length != validate_blob.length) {
555 0 : krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
556 : krbtgt_keyblock_p);
557 0 : krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
558 : &server_keyblock);
559 0 : krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
560 :
561 0 : torture_fail(tctx,
562 : talloc_asprintf(tctx,
563 : "(saved test) PAC push failed: original buffer length[%u] != created buffer length[%u]",
564 : (unsigned)tmp_blob.length, (unsigned)validate_blob.length));
565 : }
566 :
567 1 : if (memcmp(tmp_blob.data, validate_blob.data, tmp_blob.length) != 0) {
568 0 : krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
569 : krbtgt_keyblock_p);
570 0 : krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
571 : &server_keyblock);
572 0 : krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
573 :
574 0 : DEBUG(0, ("tmp_data:\n"));
575 0 : dump_data(0, tmp_blob.data, tmp_blob.length);
576 0 : DEBUG(0, ("validate_blob:\n"));
577 0 : dump_data(0, validate_blob.data, validate_blob.length);
578 :
579 0 : torture_fail(tctx, talloc_asprintf(tctx, "(saved test) PAC push failed: length[%u] matches, but data does not", (unsigned)tmp_blob.length));
580 : }
581 :
582 2 : ret = kerberos_create_pac(mem_ctx,
583 : user_info_dc_out,
584 1 : smb_krb5_context->krb5_context,
585 : krbtgt_keyblock_p,
586 : &server_keyblock,
587 : client_principal, authtime,
588 : &validate_blob);
589 :
590 1 : if (ret != 0) {
591 0 : krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
592 : krbtgt_keyblock_p);
593 0 : krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
594 : &server_keyblock);
595 0 : krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
596 :
597 0 : torture_fail(tctx, "(saved test) regnerated PAC create failed");
598 : }
599 :
600 1 : dump_data(10,validate_blob.data,validate_blob.length);
601 :
602 : /* compare both the length and the data bytes after a
603 : * pull/push cycle. This ensures we use the exact same
604 : * pointer, padding etc algorithms as win2k3.
605 : */
606 1 : if (tmp_blob.length != validate_blob.length) {
607 0 : ndr_err = ndr_pull_struct_blob(&validate_blob, mem_ctx,
608 : &pac_data2,
609 : (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA);
610 0 : nt_status = ndr_map_error2ntstatus(ndr_err);
611 0 : torture_assert_ntstatus_ok(tctx, nt_status, "can't parse the PAC");
612 :
613 0 : NDR_PRINT_DEBUG(PAC_DATA, pac_data);
614 :
615 0 : NDR_PRINT_DEBUG(PAC_DATA, &pac_data2);
616 :
617 0 : krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
618 : krbtgt_keyblock_p);
619 0 : krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
620 : &server_keyblock);
621 0 : krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
622 :
623 0 : torture_fail(tctx, talloc_asprintf(tctx,
624 : "(saved test) PAC regenerate failed: original buffer length[%u] != created buffer length[%u]",
625 : (unsigned)tmp_blob.length, (unsigned)validate_blob.length));
626 : }
627 :
628 1 : if (memcmp(tmp_blob.data, validate_blob.data, tmp_blob.length) != 0) {
629 0 : ndr_err = ndr_pull_struct_blob(&validate_blob, mem_ctx,
630 : &pac_data2,
631 : (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA);
632 0 : nt_status = ndr_map_error2ntstatus(ndr_err);
633 0 : torture_assert_ntstatus_ok(tctx, nt_status, "can't parse the PAC");
634 :
635 0 : NDR_PRINT_DEBUG(PAC_DATA, pac_data);
636 :
637 0 : NDR_PRINT_DEBUG(PAC_DATA, &pac_data2);
638 :
639 0 : krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
640 : krbtgt_keyblock_p);
641 0 : krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
642 : &server_keyblock);
643 0 : krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
644 :
645 0 : DEBUG(0, ("tmp_data:\n"));
646 0 : dump_data(0, tmp_blob.data, tmp_blob.length);
647 0 : DEBUG(0, ("validate_blob:\n"));
648 0 : dump_data(0, validate_blob.data, validate_blob.length);
649 :
650 0 : torture_fail(tctx, talloc_asprintf(tctx,
651 : "(saved test) PAC regenerate failed: length[%u] matches, but data does not", (unsigned)tmp_blob.length));
652 : }
653 :
654 : /* Break the auth time, to ensure we check this vital detail (not setting this caused all the pain in the first place... */
655 2 : nt_status = kerberos_decode_pac(mem_ctx,
656 : tmp_blob,
657 1 : smb_krb5_context->krb5_context,
658 : krbtgt_keyblock_p,
659 : &server_keyblock,
660 : client_principal,
661 : authtime + 1, &pac_data);
662 1 : if (NT_STATUS_IS_OK(nt_status)) {
663 :
664 0 : krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
665 : krbtgt_keyblock_p);
666 0 : krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
667 : &server_keyblock);
668 0 : krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
669 0 : torture_fail(tctx, "(saved test) PAC decoding DID NOT fail on broken auth time (time + 1)");
670 : }
671 :
672 : /* Break the client principal */
673 1 : krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
674 :
675 1 : broken_principal_string = talloc_strdup(mem_ctx, principal_string);
676 1 : broken_principal_string[0]++;
677 :
678 1 : ret = krb5_parse_name(smb_krb5_context->krb5_context,
679 : broken_principal_string, &client_principal);
680 1 : if (ret) {
681 :
682 0 : krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
683 : krbtgt_keyblock_p);
684 0 : krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
685 : &server_keyblock);
686 0 : torture_fail(tctx, talloc_asprintf(tctx,
687 : "(saved test) parsing of broken client principal failed: %s",
688 : smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx)));
689 : }
690 :
691 2 : nt_status = kerberos_decode_pac(mem_ctx,
692 : tmp_blob,
693 1 : smb_krb5_context->krb5_context,
694 : krbtgt_keyblock_p,
695 : &server_keyblock,
696 : client_principal,
697 : authtime, &pac_data);
698 1 : if (NT_STATUS_IS_OK(nt_status)) {
699 0 : krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
700 : krbtgt_keyblock_p);
701 0 : krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
702 : &server_keyblock);
703 0 : torture_fail(tctx, "(saved test) PAC decoding DID NOT fail on modified principal");
704 : }
705 :
706 : /* Finally... Bugger up the signature, and check we fail the checksum */
707 1 : tmp_blob.data[tmp_blob.length - 2]++;
708 :
709 2 : nt_status = kerberos_decode_pac(mem_ctx,
710 : tmp_blob,
711 1 : smb_krb5_context->krb5_context,
712 : krbtgt_keyblock_p,
713 : &server_keyblock,
714 : client_principal,
715 : authtime,
716 : &pac_data);
717 1 : if (NT_STATUS_IS_OK(nt_status)) {
718 0 : krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
719 : krbtgt_keyblock_p);
720 0 : krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
721 : &server_keyblock);
722 0 : torture_fail(tctx, "(saved test) PAC decoding DID NOT fail on broken checksum");
723 : }
724 :
725 1 : krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
726 : krbtgt_keyblock_p);
727 1 : krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
728 : &server_keyblock);
729 1 : return true;
730 : }
731 :
732 2354 : struct torture_suite *torture_pac(TALLOC_CTX *mem_ctx)
733 : {
734 2354 : struct torture_suite *suite = torture_suite_create(mem_ctx, "pac");
735 :
736 2354 : torture_suite_add_simple_test(suite, "self check",
737 : torture_pac_self_check);
738 2354 : torture_suite_add_simple_test(suite, "saved check",
739 : torture_pac_saved_check);
740 2354 : return suite;
741 : }
|