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